diff options
22 files changed, 553 insertions, 338 deletions
@@ -1438,7 +1438,7 @@ </toolChain> </folderInfo> <sourceEntries> - <entry excluding="src/SAME70xpld|src/Duet3_V03|src/Duet|src/Hardware/SAME70|src/DuetNG|src/Networking/W5500Ethernet|src/Alligator|src/Pccb|src/Networking/LwipEthernet/Lwip/src/apps/mqtt|src/Networking/LwipEthernet/Lwip/doc|src/Networking/LwipEthernet/Lwip/src/apps/snmp|src/Networking/LwipEthernet/Lwip/src/apps/smtp|src/Duet3_V05|src/Networking/LwipEthernet/Lwip/src/apps/tftp|src/Networking/LwipEthernet/Lwip/src/netif/ppp|src/Networking/LwipEthernet/Lwip/src/apps/lwiperf|src/Networking/LwipEthernet/Lwip/src/apps/altcp_tls|src/Networking/LwipEthernet/Lwip/src/apps/sntp|src/Networking/LwipEthernet/Lwip/src/apps/http|src/Duet3_V06|src/DuetM|src/RADDS" flags="VALUE_WORKSPACE_PATH|RESOLVED" kind="sourcePath" name=""/> + <entry excluding="src/SAME70xpld|src/Networking/LwipEthernet/Lwip/src/apps/snmp|src/Networking/LwipEthernet/Lwip/src/apps/smtp|src/Duet3_V03|src/Duet|src/Duet3_V05|src/Hardware/SAME70|src/DuetNG|src/Networking/LwipEthernet/Lwip/src/apps/tftp|src/Networking/W5500Ethernet|src/Alligator|src/Networking/LwipEthernet/Lwip/src/netif/ppp|src/Networking/LwipEthernet/Lwip/src/apps/lwiperf|src/Networking/LwipEthernet/Lwip/src/apps/altcp_tls|src/Networking/LwipEthernet/Lwip/src/apps/sntp|src/Networking/LwipEthernet/Lwip/src/apps/http|src/Duet3_V06|src/Pccb|src/Networking/LwipEthernet/Lwip/src/apps/mqtt|src/DuetM|src/RADDS|src/Networking/LwipEthernet/Lwip/doc" flags="VALUE_WORKSPACE_PATH|RESOLVED" kind="sourcePath" name=""/> </sourceEntries> </configuration> </storageModule> @@ -1583,7 +1583,7 @@ </toolChain> </folderInfo> <sourceEntries> - <entry excluding="src/SAME70xpld|src/Duet3_V03|src/Duet|src/Hardware/SAME70|src/DuetNG|src/Networking/W5500Ethernet|src/Alligator|src/Pccb|src/Networking/LwipEthernet/Lwip/src/apps/mqtt|src/Networking/LwipEthernet/Lwip/doc|src/Networking/LwipEthernet/Lwip/src/apps/snmp|src/Networking/LwipEthernet/Lwip/src/apps/smtp|src/Duet3_V05|src/Networking/LwipEthernet/Lwip/src/apps/tftp|src/Networking/LwipEthernet/Lwip/src/netif/ppp|src/Networking/LwipEthernet/Lwip/src/apps/lwiperf|src/Networking/LwipEthernet/Lwip/src/apps/altcp_tls|src/Networking/LwipEthernet/Lwip/src/apps/sntp|src/Networking/LwipEthernet/Lwip/src/apps/http|src/Duet3_V06|src/DuetM|src/RADDS" flags="VALUE_WORKSPACE_PATH|RESOLVED" kind="sourcePath" name=""/> + <entry excluding="src/SAME70xpld|src/Networking/LwipEthernet/Lwip/src/apps/snmp|src/Networking/LwipEthernet/Lwip/src/apps/smtp|src/Duet3_V03|src/Duet|src/Duet3_V05|src/Hardware/SAME70|src/DuetNG|src/Networking/LwipEthernet/Lwip/src/apps/tftp|src/Networking/W5500Ethernet|src/Alligator|src/Networking/LwipEthernet/Lwip/src/netif/ppp|src/Networking/LwipEthernet/Lwip/src/apps/lwiperf|src/Networking/LwipEthernet/Lwip/src/apps/altcp_tls|src/Networking/LwipEthernet/Lwip/src/apps/sntp|src/Networking/LwipEthernet/Lwip/src/apps/http|src/Duet3_V06|src/Pccb|src/Networking/LwipEthernet/Lwip/src/apps/mqtt|src/DuetM|src/RADDS|src/Networking/LwipEthernet/Lwip/doc" flags="VALUE_WORKSPACE_PATH|RESOLVED" kind="sourcePath" name=""/> </sourceEntries> </configuration> </storageModule> @@ -1727,7 +1727,7 @@ </toolChain> </folderInfo> <sourceEntries> - <entry excluding="src/SAME70xpld|src/Duet3_V03|src/Duet|src/Hardware/SAME70|src/DuetNG|src/Networking/W5500Ethernet|src/Alligator|src/Pccb|src/Networking/LwipEthernet/Lwip/src/apps/mqtt|src/Networking/LwipEthernet/Lwip/doc|src/Networking/LwipEthernet/Lwip/src/apps/snmp|src/Networking/LwipEthernet/Lwip/src/apps/smtp|src/Duet3_V05|src/Networking/LwipEthernet/Lwip/src/apps/tftp|src/Networking/LwipEthernet/Lwip/src/netif/ppp|src/Networking/LwipEthernet/Lwip/src/apps/lwiperf|src/Networking/LwipEthernet/Lwip/src/apps/altcp_tls|src/Networking/LwipEthernet/Lwip/src/apps/sntp|src/Networking/LwipEthernet/Lwip/src/apps/http|src/Duet3_V06|src/DuetM|src/RADDS" flags="VALUE_WORKSPACE_PATH|RESOLVED" kind="sourcePath" name=""/> + <entry excluding="src/SAME70xpld|src/Networking/LwipEthernet/Lwip/src/apps/snmp|src/Networking/LwipEthernet/Lwip/src/apps/smtp|src/Duet3_V03|src/Duet|src/Duet3_V05|src/Hardware/SAME70|src/DuetNG|src/Networking/LwipEthernet/Lwip/src/apps/tftp|src/Networking/W5500Ethernet|src/Alligator|src/Networking/LwipEthernet/Lwip/src/netif/ppp|src/Networking/LwipEthernet/Lwip/src/apps/lwiperf|src/Networking/LwipEthernet/Lwip/src/apps/altcp_tls|src/Networking/LwipEthernet/Lwip/src/apps/sntp|src/Networking/LwipEthernet/Lwip/src/apps/http|src/Duet3_V06|src/Pccb|src/Networking/LwipEthernet/Lwip/src/apps/mqtt|src/DuetM|src/RADDS|src/Networking/LwipEthernet/Lwip/doc" flags="VALUE_WORKSPACE_PATH|RESOLVED" kind="sourcePath" name=""/> </sourceEntries> </configuration> </storageModule> diff --git a/.settings/org.eclipse.core.resources.prefs b/.settings/org.eclipse.core.resources.prefs index 6ebe5254..52a88ec0 100644 --- a/.settings/org.eclipse.core.resources.prefs +++ b/.settings/org.eclipse.core.resources.prefs @@ -1,4 +1,4 @@ eclipse.preferences.version=1 -encoding//src/Display/ST7920/glcd11x14.cpp=UTF-8 -encoding//src/Display/ST7920/glcd7x11.cpp=UTF-8 +encoding//src/Display/Lcd/Fonts/glcd11x14.cpp=UTF-8 +encoding//src/Display/Lcd/Fonts/glcd7x11.cpp=UTF-8 encoding//src/Movement/StepperDrivers/TMC51xx.cpp=UTF-8 diff --git a/src/Display/Display.cpp b/src/Display/Display.cpp index 2b7a1350..3e80de22 100644 --- a/src/Display/Display.cpp +++ b/src/Display/Display.cpp @@ -9,6 +9,8 @@ #if SUPPORT_12864_LCD +#include "Lcd/ST7920/Lcd7920.h" +#include "Lcd/ST7567/Lcd7567.h" #include "GCodes/GCodes.h" #include "GCodes/GCodeBuffer/GCodeBuffer.h" #include "Hardware/IoPorts.h" @@ -144,38 +146,45 @@ void Display::ErrorBeep() noexcept Beep(500, 1000); } -GCodeResult Display::Configure(GCodeBuffer& gb, const StringRef& reply) noexcept +void Display::InitDisplay(GCodeBuffer& gb, Lcd *newLcd, bool defaultCsPolarity) THROWS(GCodeException) +{ + newLcd->Init(LcdCSPin, LcdA0Pin, defaultCsPolarity, (gb.Seen('F')) ? gb.GetUIValue() : LcdSpiClockFrequency); + IoPort::SetPinMode(LcdBeepPin, OUTPUT_PWM_LOW); + newLcd->SetFont(SmallFontNumber); + IoPort::SetPinMode(LcdBeepPin, OUTPUT_PWM_LOW); + newLcd->SetFont(SmallFontNumber); + + if (encoder == nullptr) + { + encoder = new RotaryEncoder(EncoderPinA, EncoderPinB, EncoderPinSw); + encoder->Init(DefaultPulsesPerClick); + } + menu = new Menu(*newLcd); + menu->Load("main"); + lcd = newLcd; +} + +GCodeResult Display::Configure(GCodeBuffer& gb, const StringRef& reply) THROWS(GCodeException) { bool seen = false; if (gb.Seen('P')) { + Lcd *tempLcd = nullptr; + std::swap(lcd, tempLcd); + delete tempLcd; + delete menu; + menu = nullptr; + seen = true; - const unsigned int displayType = gb.GetUIValue(); - switch (displayType) + switch (gb.GetUIValue()) { case 1: // 12864 display, ST7920 controller - case 2: // 12864 display, ST7567 controller - if (lcd == nullptr) - { - lcd = new Lcd7920(fonts, ARRAY_SIZE(fonts)); - } - lcd->Init(displayType - 1, LcdCSPin, LcdA0Pin, (gb.Seen('F')) ? gb.GetUIValue() : LcdSpiClockFrequency); - IoPort::SetPinMode(LcdBeepPin, OUTPUT_PWM_LOW); - lcd->SetFont(SmallFontNumber); - IoPort::SetPinMode(LcdBeepPin, OUTPUT_PWM_LOW); - lcd->SetFont(SmallFontNumber); + InitDisplay(gb, new Lcd7920(fonts, ARRAY_SIZE(fonts)), true); + break; - if (encoder == nullptr) - { - encoder = new RotaryEncoder(EncoderPinA, EncoderPinB, EncoderPinSw); - encoder->Init(DefaultPulsesPerClick); - } - if (menu == nullptr) - { - menu = new Menu(*lcd); - } - menu->Load("main"); + case 2: // 12864 display, ST7567 controller + InitDisplay(gb, new Lcd7567(fonts, ARRAY_SIZE(fonts)), false); break; default: diff --git a/src/Display/Display.h b/src/Display/Display.h index 1fe5a0d1..c15a255d 100644 --- a/src/Display/Display.h +++ b/src/Display/Display.h @@ -13,7 +13,7 @@ #if SUPPORT_12864_LCD #include "RotaryEncoder.h" -#include "ST7920/lcd7920.h" +#include "Lcd/Lcd.h" #include "Menu.h" #include "GCodes/GCodeResult.h" @@ -23,7 +23,7 @@ public: Display() noexcept; void Init() noexcept { } - GCodeResult Configure(GCodeBuffer& gb, const StringRef& reply) noexcept; + GCodeResult Configure(GCodeBuffer& gb, const StringRef& reply); void Spin() noexcept; void Exit() noexcept; void Beep(unsigned int frequency, unsigned int milliseconds) noexcept; @@ -33,7 +33,9 @@ public: void UpdatingFirmware() noexcept; private: - Lcd7920 *lcd; + void InitDisplay(GCodeBuffer& gb, Lcd *newLcd, bool defaultCsPolarity); + + Lcd *lcd; Menu *menu; RotaryEncoder *encoder; uint32_t whenBeepStarted; diff --git a/src/Display/Lcd/Fonts/LcdFont.h b/src/Display/Lcd/Fonts/LcdFont.h new file mode 100644 index 00000000..a102426e --- /dev/null +++ b/src/Display/Lcd/Fonts/LcdFont.h @@ -0,0 +1,24 @@ +/* + * LcdFont.h + * + * Created on: 15 Jul 2020 + * Author: David + */ + +#ifndef SRC_DISPLAY_LCD_FONTS_LCDFONT_H_ +#define SRC_DISPLAY_LCD_FONTS_LCDFONT_H_ + +#include <cstdint> + +// Struct for describing a font table, always held in PROGMEM +struct LcdFont +{ + const uint8_t *ptr; // pointer to font table + uint16_t startCharacter; // Unicode code point of the first character in the font + uint16_t endCharacter; // Unicode code point of the last character in the font + uint8_t height; // row height in pixels - only this number of pixels will be fetched and drawn - maximum 16 in this version of the software + uint8_t width; // max character width in pixels (the font table contains this number of bytes or words per character, plus 1 for the active width) + uint8_t numSpaces; // number of space columns between characters before kerning +}; + +#endif /* SRC_DISPLAY_LCD_FONTS_LCDFONT_H_ */ diff --git a/src/Display/ST7920/glcd11x14.cpp b/src/Display/Lcd/Fonts/glcd11x14.cpp index 18e1d9fa..4f7e9235 100644 --- a/src/Display/ST7920/glcd11x14.cpp +++ b/src/Display/Lcd/Fonts/glcd11x14.cpp @@ -5,10 +5,12 @@ * Author: David */ -#include "lcd7920.h" +#include "RepRapFirmware.h" #if SUPPORT_12864_LCD +#include "LcdFont.h" + //Font Generated by MikroElektronika GLCD Font Creator 1.2.0.0 //MikroElektronika 2011 //http://www.mikroe.com diff --git a/src/Display/ST7920/glcd7x11.cpp b/src/Display/Lcd/Fonts/glcd7x11.cpp index cd7e5c1e..368353e0 100644 --- a/src/Display/ST7920/glcd7x11.cpp +++ b/src/Display/Lcd/Fonts/glcd7x11.cpp @@ -5,10 +5,11 @@ * Author: David */ -#include "lcd7920.h" +#include "RepRapFirmware.h" #if SUPPORT_12864_LCD +#include "LcdFont.h" //Font Generated by MikroElektronika GLCD Font Creator 1.2.0.0 //MikroElektronika 2011 diff --git a/src/Display/ST7920/lcd7920.cpp b/src/Display/Lcd/Lcd.cpp index 3f914fb8..c6cb2aa8 100644 --- a/src/Display/ST7920/lcd7920.cpp +++ b/src/Display/Lcd/Lcd.cpp @@ -1,7 +1,7 @@ // Driver for 128x64 graphical LCD with ST7920 controller // D Crocker, Escher Technologies Ltd. -#include "lcd7920.h" +#include "Lcd.h" #if SUPPORT_12864_LCD @@ -10,88 +10,42 @@ // The LCD SPI clock frequency is now defined in the Pins.h file for the configuration being built -// LCD basic instructions. These all take 72us to execute except LcdDisplayClear, which takes 1.6ms -constexpr uint8_t LcdDisplayClear = 0x01; -constexpr uint8_t LcdHome = 0x02; -constexpr uint8_t LcdEntryModeSet = 0x06; // move cursor right and increment address when writing data -constexpr uint8_t LcdDisplayOff = 0x08; -constexpr uint8_t LcdDisplayOn = 0x0C; // add 0x02 for cursor on and/or 0x01 for cursor blink on -constexpr uint8_t LcdFunctionSetBasicAlpha = 0x20; -constexpr uint8_t LcdFunctionSetBasicGraphic = 0x22; -constexpr uint8_t LcdFunctionSetExtendedAlpha = 0x24; -constexpr uint8_t LcdFunctionSetExtendedGraphic = 0x26; -constexpr uint8_t LcdSetDdramAddress = 0x80; // add the address we want to set - -// LCD extended instructions -constexpr uint8_t LcdSetGdramAddress = 0x80; - -constexpr unsigned int LcdCommandDelayMicros = 72 - 8; // 72us required, less 7us time to send the command @ 2.0MHz -constexpr unsigned int LcdDataDelayMicros = 4; // delay between sending data bytes -constexpr unsigned int LcdDisplayClearDelayMillis = 3; // 1.6ms should be enough - -inline void Lcd7920::CommandDelay() noexcept +Lcd::Lcd(PixelNumber nr, PixelNumber nc, const LcdFont * const fnts[], size_t nFonts) noexcept + : fonts(fnts), numFonts(nFonts), + device(SharedSpiDevice::GetMainSharedSpiDevice(), LcdSpiClockFrequency, SpiMode::mode0, NoPin, true), + numRows(nr), numCols(nc) { - delayMicroseconds(LcdCommandDelayMicros); + imageSize = nr * ((nc + 7)/8); + image = new uint8_t[imageSize]; } -inline void Lcd7920::DataDelay() noexcept -{ - delayMicroseconds(LcdDataDelayMicros); -} - -Lcd7920::Lcd7920(const LcdFont * const fnts[], size_t nFonts) noexcept - : fonts(fnts), numFonts(nFonts), device(SharedSpiDevice::GetMainSharedSpiDevice(), LcdSpiClockFrequency, SpiMode::mode0, NoPin, true) +Lcd::~Lcd() { + delete image; } // Initialise. cControllerType is 1 for ST7567 controller, 0 for ST7920. a0Pin is only used by the ST7567. -void Lcd7920::Init(uint8_t p_controllerType, Pin csPin, Pin p_a0Pin, uint32_t freq) noexcept +void Lcd::Init(Pin csPin, Pin p_a0Pin, bool csPolarity, uint32_t freq) noexcept { - controllerType = p_controllerType; a0Pin = p_a0Pin; - if (p_controllerType == 1) - { - pinMode(p_a0Pin, OUTPUT_HIGH); - } device.SetClockFrequency(freq); device.SetCsPin(csPin); - device.SetCsPolarity(controllerType == 0); // active high chip select for ST7920, active low for ST7567 + device.SetCsPolarity(csPolarity); // normally active high chip select for ST7920, active low for ST7567 #ifdef __LPC17xx__ device.sspChannel = LcdSpiChannel; #endif numContinuationBytesLeft = 0; textInverted = false; - startRow = NumRows; - startCol = NumCols; + startRow = numRows; + startCol = numCols; endRow = endCol = nextFlushRow = 0; - device.Select(); - delayMicroseconds(1); - sendLcdCommand(LcdFunctionSetBasicAlpha); - delay(2); - sendLcdCommand(LcdFunctionSetBasicAlpha); - CommandDelay(); - sendLcdCommand(LcdEntryModeSet); - CommandDelay(); - sendLcdCommand(LcdDisplayClear); // need this on some displays to ensure that the alpha RAM is clear (M3D Kanji problem) - delay(LcdDisplayClearDelayMillis); - sendLcdCommand(LcdFunctionSetExtendedGraphic); - CommandDelay(); - device.Deselect(); - - Clear(); - FlushAll(); - - device.Select(); - delayMicroseconds(1); - sendLcdCommand(LcdDisplayOn); - CommandDelay(); - device.Deselect(); + HardwareInit(); currentFontNumber = 0; } -void Lcd7920::SetFont(size_t newFont) noexcept +void Lcd::SetFont(size_t newFont) noexcept { if (newFont < numFonts) { @@ -100,13 +54,13 @@ void Lcd7920::SetFont(size_t newFont) noexcept } // Get the current font height -PixelNumber Lcd7920::GetFontHeight() const noexcept +PixelNumber Lcd::GetFontHeight() const noexcept { return fonts[currentFontNumber]->height; } // Get the height of a specified font -PixelNumber Lcd7920::GetFontHeight(size_t fontNumber) const noexcept +PixelNumber Lcd::GetFontHeight(size_t fontNumber) const noexcept { if (fontNumber >= numFonts) { @@ -117,7 +71,7 @@ PixelNumber Lcd7920::GetFontHeight(size_t fontNumber) const noexcept // Flag a pixel as dirty. The r and c parameters must be no greater than NumRows-1 and NumCols-1 respectively. // Only one pixel in each 16-bit word needs to be flagged dirty for the whole word to get refreshed. -void Lcd7920::SetDirty(PixelNumber r, PixelNumber c) noexcept +void Lcd::SetDirty(PixelNumber r, PixelNumber c) noexcept { // if (r >= NumRows) { debugPrintf("r=%u\n", r); return; } // if (c >= NumCols) { debugPrintf("c=%u\n", c); return; } @@ -130,7 +84,7 @@ void Lcd7920::SetDirty(PixelNumber r, PixelNumber c) noexcept // Write a UTF8 byte. // If textYpos is off the end of the display, then don't write anything, just update textXpos and lastCharColData -size_t Lcd7920::write(uint8_t c) noexcept +size_t Lcd::write(uint8_t c) noexcept { if (numContinuationBytesLeft == 0) { @@ -194,7 +148,7 @@ size_t Lcd7920::write(uint8_t c) noexcept } } -size_t Lcd7920::writeNative(uint16_t ch) noexcept +size_t Lcd::writeNative(uint16_t ch) noexcept { const LcdFont * const currentFont = fonts[currentFontNumber]; if (ch == '\n') @@ -213,13 +167,13 @@ size_t Lcd7920::writeNative(uint16_t ch) noexcept uint8_t ySize = currentFont->height; const uint8_t bytesPerColumn = (ySize + 7)/8; - if (row >= NumRows) + if (row >= numRows) { ySize = 0; // we still execute the code, so that the caller can tell how many columns the text will occupy by writing it off-screen } - else if (row + ySize > NumRows) + else if (row + ySize > numRows) { - ySize = NumRows - row; + ySize = numRows - row; } const uint8_t bytesPerChar = (bytesPerColumn * currentFont->width) + 1; @@ -253,8 +207,8 @@ size_t Lcd7920::writeNative(uint16_t ch) noexcept if (ySize != 0) { const uint8_t mask = 0x80 >> (column & 7); - uint8_t *p = image + ((row * (NumCols/8)) + (column/8)); - for (uint8_t i = 0; i < ySize && p < (image + sizeof(image)); ++i) + uint8_t *p = image + ((row * (numCols/8)) + (column/8)); + for (uint8_t i = 0; i < ySize && p < (image + imageSize); ++i) { const uint8_t oldVal = *p; const uint8_t newVal = (textInverted) ? oldVal | mask : oldVal & ~mask; @@ -263,7 +217,7 @@ size_t Lcd7920::writeNative(uint16_t ch) noexcept *p = newVal; SetDirty(row + i, column); } - p += (NumCols/8); + p += (numCols/8); } } ++column; @@ -282,7 +236,7 @@ size_t Lcd7920::writeNative(uint16_t ch) noexcept { const uint8_t mask1 = 0x80 >> (column & 7); const uint8_t mask2 = ~mask1; - uint8_t *p = image + ((row * (NumCols/8)) + (column/8)); + uint8_t *p = image + ((row * (numCols/8)) + (column/8)); const uint16_t setPixelVal = (textInverted) ? 0 : 1; for (uint8_t i = 0; i < ySize; ++i) { @@ -294,7 +248,7 @@ size_t Lcd7920::writeNative(uint16_t ch) noexcept SetDirty(row + i, column); } colData >>= 1; - p += (NumCols/8); + p += (numCols/8); } } --nCols; @@ -307,26 +261,26 @@ size_t Lcd7920::writeNative(uint16_t ch) noexcept } // Write a space -void Lcd7920::WriteSpaces(PixelNumber numPixels) noexcept +void Lcd::WriteSpaces(PixelNumber numPixels) noexcept { const LcdFont * const currentFont = fonts[currentFontNumber]; uint8_t ySize = currentFont->height; - if (row >= NumRows) + if (row >= numRows) { ySize = 0; // we still execute the code, so that the caller can tell how many columns the text will occupy by writing it off-screen } - else if (row + ySize > NumRows) + else if (row + ySize > numRows) { - ySize = NumRows - row; + ySize = numRows - row; } - while (numPixels != 0 && column < NumCols) + while (numPixels != 0 && column < numCols) { if (ySize != 0) { const uint8_t mask = 0x80 >> (column & 7); - uint8_t *p = image + ((row * (NumCols/8)) + (column/8)); - for (uint8_t i = 0; i < ySize && p < (image + sizeof(image)); ++i) + uint8_t *p = image + ((row * (numCols/8)) + (column/8)); + for (uint8_t i = 0; i < ySize && p < (image + imageSize); ++i) { const uint8_t oldVal = *p; const uint8_t newVal = (textInverted) ? oldVal | mask : oldVal & ~mask; @@ -335,7 +289,7 @@ void Lcd7920::WriteSpaces(PixelNumber numPixels) noexcept *p = newVal; SetDirty(row + i, column); } - p += (NumCols/8); + p += (numCols/8); } } --numPixels; @@ -347,24 +301,24 @@ void Lcd7920::WriteSpaces(PixelNumber numPixels) noexcept } // Set the left margin. This is where the cursor goes to when we print newline. -void Lcd7920::SetLeftMargin(PixelNumber c) noexcept +void Lcd::SetLeftMargin(PixelNumber c) noexcept { - leftMargin = min<uint8_t>(c, NumCols); + leftMargin = min<PixelNumber>(c, numCols); } // Set the right margin. In graphics mode, anything written will be truncated at the right margin. Defaults to the right hand edge of the display. -void Lcd7920::SetRightMargin(PixelNumber r) noexcept +void Lcd::SetRightMargin(PixelNumber r) noexcept { - rightMargin = min<uint8_t>(r, NumCols); + rightMargin = min<PixelNumber>(r, numCols); } // Clear a rectangle from the current position to the right margin. The height of the rectangle is the height of the current font. -void Lcd7920::ClearToMargin() noexcept +void Lcd::ClearToMargin() noexcept { const uint8_t fontHeight = fonts[currentFontNumber]->height; while (column < rightMargin) { - uint8_t *p = image + ((row * (NumCols/8)) + (column/8)); + uint8_t *p = image + ((row * (numCols/8)) + (column/8)); uint8_t mask = 0xFF >> (column & 7); PixelNumber nextColumn; if ((column & (~7)) < (rightMargin & (~7))) @@ -377,7 +331,7 @@ void Lcd7920::ClearToMargin() noexcept nextColumn = rightMargin;; } - for (uint8_t i = 0; i < fontHeight && p < (image + sizeof(image)); ++i) + for (uint8_t i = 0; i < fontHeight && p < (image + imageSize); ++i) { const uint8_t oldVal = *p; const uint8_t newVal = (textInverted) ? oldVal | mask : oldVal & ~mask; @@ -386,14 +340,14 @@ void Lcd7920::ClearToMargin() noexcept *p = newVal; SetDirty(row + i, column); // we refresh 16-bit words, so setting 1 pixel dirty in byte will suffice } - p += (NumCols/8); + p += (numCols/8); } column = nextColumn; } } // Select normal or inverted text -void Lcd7920::TextInvert(bool b) noexcept +void Lcd::TextInvert(bool b) noexcept { if (b != textInverted) { @@ -406,10 +360,10 @@ void Lcd7920::TextInvert(bool b) noexcept } // Clear a rectangular block of pixels starting at rows, scol ending just before erow, ecol -void Lcd7920::Clear(PixelNumber sRow, PixelNumber sCol, PixelNumber eRow, PixelNumber eCol) noexcept +void Lcd::Clear(PixelNumber sRow, PixelNumber sCol, PixelNumber eRow, PixelNumber eCol) noexcept { - if (eCol > NumCols) { eCol = NumCols; } - if (eRow > NumRows) { eRow = NumRows; } + if (eCol > numCols) { eCol = numCols; } + if (eRow > numRows) { eRow = numRows; } if (sCol < eCol && sRow < eRow) { uint8_t sMask = ~(0xFF >> (sCol & 7)); // mask of bits we want to keep in the first byte of each row that we modify @@ -420,8 +374,8 @@ void Lcd7920::Clear(PixelNumber sRow, PixelNumber sCol, PixelNumber eRow, PixelN } for (PixelNumber row = sRow; row < eRow; ++row) { - uint8_t * p = image + ((row * (NumCols/8)) + (sCol/8)); - uint8_t * const endp = image + ((row * (NumCols/8)) + (eCol/8)); + uint8_t * p = image + ((row * (numCols/8)) + (sCol/8)); + uint8_t * const endp = image + ((row * (numCols/8)) + (eCol/8)); *p &= sMask; if (p != endp) { @@ -450,7 +404,7 @@ void Lcd7920::Clear(PixelNumber sRow, PixelNumber sCol, PixelNumber eRow, PixelN } // Draw a line using the Bresenham Algorithm (thanks Wikipedia) -void Lcd7920::Line(PixelNumber y0, PixelNumber x0, PixelNumber y1, PixelNumber x1, PixelMode mode) noexcept +void Lcd::Line(PixelNumber y0, PixelNumber x0, PixelNumber y1, PixelNumber x1, PixelMode mode) noexcept { int dx = (x1 >= x0) ? x1 - x0 : x0 - x1; int dy = (y1 >= y0) ? y1 - y0 : y0 - y1; @@ -480,7 +434,7 @@ void Lcd7920::Line(PixelNumber y0, PixelNumber x0, PixelNumber y1, PixelNumber x } // Draw a circle using the Bresenham Algorithm (thanks Wikipedia) -void Lcd7920::Circle(PixelNumber x0, PixelNumber y0, PixelNumber radius, PixelMode mode) noexcept +void Lcd::Circle(PixelNumber x0, PixelNumber y0, PixelNumber radius, PixelMode mode) noexcept { int f = 1 - (int)radius; int ddF_x = 1; @@ -519,13 +473,13 @@ void Lcd7920::Circle(PixelNumber x0, PixelNumber y0, PixelNumber radius, PixelMo } // Draw a bitmap. x0 and numCols must be divisible by 8. -void Lcd7920::Bitmap(PixelNumber x0, PixelNumber y0, PixelNumber width, PixelNumber height, const uint8_t data[]) noexcept +void Lcd::Bitmap(PixelNumber x0, PixelNumber y0, PixelNumber width, PixelNumber height, const uint8_t data[]) noexcept { - for (PixelNumber r = 0; r < height && r + y0 < NumRows; ++r) + for (PixelNumber r = 0; r < height && r + y0 < numRows; ++r) { - uint8_t *p = image + (((r + y0) * (NumCols/8)) + (x0/8)); + uint8_t *p = image + (((r + y0) * (numCols/8)) + (x0/8)); uint16_t bitMapOffset = r * (width/8); - for (PixelNumber c = 0; c < (width/8) && c + (x0/8) < NumCols/8; ++c) + for (PixelNumber c = 0; c < (width/8) && c + (x0/8) < numCols/8; ++c) { *p++ = data[bitMapOffset++]; } @@ -539,7 +493,7 @@ void Lcd7920::Bitmap(PixelNumber x0, PixelNumber y0, PixelNumber width, PixelNum } // Draw a single bitmap row. 'left' and 'width' do not need to be divisible by 8. -void Lcd7920::BitmapRow(PixelNumber top, PixelNumber left, PixelNumber width, const uint8_t data[], bool invert) noexcept +void Lcd::BitmapRow(PixelNumber top, PixelNumber left, PixelNumber width, const uint8_t data[], bool invert) noexcept { if (width != 0) // avoid possible arithmetic underflow { @@ -547,7 +501,7 @@ void Lcd7920::BitmapRow(PixelNumber top, PixelNumber left, PixelNumber width, co uint8_t firstColIndex = left/8; // column index of the first byte to write const uint8_t lastColIndex = (left + width - 1)/8; // column index of the last byte to write const unsigned int firstDataShift = left % 8; // number of bits in the first byte that we leave alone - uint8_t *p = image + (top * NumCols/8) + firstColIndex; + uint8_t *p = image + (top * numCols/8) + firstColIndex; // Do all bytes except the last one uint8_t accumulator = *p & (0xFF << (8 - firstDataShift)); // prime the accumulator @@ -581,7 +535,7 @@ void Lcd7920::BitmapRow(PixelNumber top, PixelNumber left, PixelNumber width, co } // Flush all of the dirty part of the image to the lcd. Only called during startup and shutdown. -void Lcd7920::FlushAll() noexcept +void Lcd::FlushAll() noexcept { while (FlushSome()) { @@ -589,59 +543,8 @@ void Lcd7920::FlushAll() noexcept } } -// Flush some of the dirty part of the image to the LCD, returning true if there is more to do -bool Lcd7920::FlushSome() noexcept -{ - // See if there is anything to flush - if (endCol > startCol && endRow > startRow) - { - // Decide which row to flush next - if (nextFlushRow < startRow || nextFlushRow >= endRow) - { - nextFlushRow = startRow; // start from the beginning - } - - if (nextFlushRow == startRow) // if we are starting form the beginning - { - ++startRow; // flag this row as flushed because it will be soon - } - - // Flush that row - { - uint8_t startColNum = startCol/16; - const uint8_t endColNum = (endCol + 15)/16; -// debugPrintf("flush %u %u %u\n", nextFlushRow, startColNum, endColNum); - - device.Select(); - delayMicroseconds(1); - - setGraphicsAddress(nextFlushRow, startColNum); - uint8_t *ptr = image + (((NumCols/8) * nextFlushRow) + (2 * startColNum)); - while (startColNum < endColNum) - { - sendLcdData(*ptr++); - sendLcdData(*ptr++); - ++startColNum; - DataDelay(); - } - device.Deselect(); - } - - if (startRow != endRow) - { - ++nextFlushRow; - return true; - } - - startRow = NumRows; - startCol = NumCols; - endCol = endRow = nextFlushRow = 0; - } - return false; -} - // Set the cursor position -void Lcd7920::SetCursor(PixelNumber r, PixelNumber c) noexcept +void Lcd::SetCursor(PixelNumber r, PixelNumber c) noexcept { row = r; column = c; @@ -649,11 +552,11 @@ void Lcd7920::SetCursor(PixelNumber r, PixelNumber c) noexcept justSetCursor = true; } -void Lcd7920::SetPixel(PixelNumber y, PixelNumber x, PixelMode mode) noexcept +void Lcd::SetPixel(PixelNumber y, PixelNumber x, PixelMode mode) noexcept { - if (y < NumRows && x < rightMargin) + if (y < numRows && x < rightMargin) { - uint8_t * const p = image + ((y * (NumCols/8)) + (x/8)); + uint8_t * const p = image + ((y * (numCols/8)) + (x/8)); const uint8_t mask = 0x80u >> (x%8); const uint8_t oldVal = *p; uint8_t newVal; @@ -681,41 +584,16 @@ void Lcd7920::SetPixel(PixelNumber y, PixelNumber x, PixelMode mode) noexcept } } -bool Lcd7920::ReadPixel(PixelNumber x, PixelNumber y) const noexcept +bool Lcd::ReadPixel(PixelNumber x, PixelNumber y) const noexcept { - if (y < NumRows && x < NumCols) + if (y < numRows && x < numCols) { - const uint8_t * const p = image + ((y * (NumCols/8)) + (x/8)); + const uint8_t * const p = image + ((y * (numCols/8)) + (x/8)); return (*p & (0x80u >> (x%8))) != 0; } return false; } -// Set the address to write to. The column address is in 16-bit words, so it ranges from 0 to 7. -void Lcd7920::setGraphicsAddress(unsigned int r, unsigned int c) noexcept -{ - sendLcdCommand(LcdSetGdramAddress | (r & 31)); - //commandDelay(); // don't seem to need this one - sendLcdCommand(LcdSetGdramAddress | c | ((r & 32) >> 2)); - CommandDelay(); // we definitely need this one -} - -// Send a command or data to the lcd. The SPI mutex is already owned -void Lcd7920::sendLcd(uint8_t byteToSend, bool isData) noexcept -{ - if (controllerType == 1) // if ST7567 - { - digitalWrite(a0Pin, isData); - uint8_t data[1] = { byteToSend }; - device.TransceivePacket(data, nullptr, 1); - } - else // ST7960 - { - uint8_t data[3] = { (isData) ? (uint8_t)0xFA : (uint8_t)0xF8, (uint8_t)(byteToSend & 0xF0), (uint8_t)(byteToSend << 4) }; - device.TransceivePacket(data, nullptr, 3); - } -} - #endif // End diff --git a/src/Display/ST7920/lcd7920.h b/src/Display/Lcd/Lcd.h index ba0d5164..c4e62af0 100644 --- a/src/Display/ST7920/lcd7920.h +++ b/src/Display/Lcd/Lcd.h @@ -1,11 +1,12 @@ -#ifndef LCD7920_H -#define LCD7920_H +#ifndef SRC_DISPLAY_LCD_LCD_H +#define SRC_DISPLAY_LCD_LCD_H #include "RepRapFirmware.h" #if SUPPORT_12864_LCD #include <Print.h> +#include "Fonts/LcdFont.h" #include <Hardware/SharedSpi/SharedSpiClient.h> // Enumeration for specifying drawing modes @@ -16,38 +17,27 @@ enum class PixelMode : uint8_t PixelFlip = 2 // invert the pixel(s) }; -// Struct for describing a font table, always held in PROGMEM -struct LcdFont -{ - const uint8_t *ptr; // pointer to font table - uint16_t startCharacter; // Unicode code point of the first character in the font - uint16_t endCharacter; // Unicode code point of the last character in the font - uint8_t height; // row height in pixels - only this number of pixels will be fetched and drawn - maximum 16 in this version of the software - uint8_t width; // max character width in pixels (the font table contains this number of bytes or words per character, plus 1 for the active width) - uint8_t numSpaces; // number of space columns between characters before kerning -}; - typedef uint8_t PixelNumber; -const PixelNumber NumRows = 64, NumCols = 128; // Class for driving 128x64 graphical LCD fitted with ST7920 controller // This drives the GLCD in serial mode so that it needs just 2 pins. // Derive the LCD class from the Print class so that we can print stuff to it in alpha mode -class Lcd7920 : public Print +class Lcd : public Print { public: // Construct a GLCD driver. - Lcd7920(const LcdFont * const fnts[], size_t nFonts) noexcept; + Lcd(PixelNumber nr, PixelNumber nc, const LcdFont * const fnts[], size_t nFonts) noexcept; + virtual ~Lcd(); // Initialize the display - void Init(uint8_t p_controllerType, Pin csPin, Pin p_a0Pin, uint32_t freq) noexcept; + void Init(Pin csPin, Pin p_a0Pin, bool csPolarity, uint32_t freq) noexcept; // Select the font to use for subsequent calls to write() in graphics mode void SetFont(size_t newFont) noexcept; - constexpr PixelNumber GetNumRows() const noexcept { return NumRows; } - constexpr PixelNumber GetNumCols() const noexcept { return NumCols; } + const PixelNumber GetNumRows() const noexcept { return numRows; } + const PixelNumber GetNumCols() const noexcept { return numCols; } // Write a single character in the current font. Called by the 'print' functions. // c = character to write @@ -69,8 +59,14 @@ public: // Select normal or inverted text (only works in graphics mode) void TextInvert(bool b) noexcept; - // Clear the display and select non-inverted text. - void Clear(PixelNumber top = 0, PixelNumber left = 0, PixelNumber bottom = NumRows, PixelNumber right = NumCols) noexcept; + // Clear part of the display and select non-inverted text. + void Clear(PixelNumber top, PixelNumber left, PixelNumber bottom, PixelNumber right) noexcept; + + // Clear the whole display and select non-inverted text. + void Clear() noexcept + { + Clear(0, 0, numRows, numCols); + } // Set the cursor position // r = row, the number of pixels from the top of the display to the top of the character. @@ -96,7 +92,7 @@ public: void FlushAll() noexcept; // Flush just some data, returning true if this needs to be called again - bool FlushSome() noexcept; + virtual bool FlushSome() noexcept = 0; // Set, clear or invert a pixel // x = x-coordinate of the pixel, measured from left hand edge of the display @@ -138,36 +134,35 @@ public: // data = bitmap image, must be ((width + 7)/8) bytes long void BitmapRow(PixelNumber top, PixelNumber left, PixelNumber width, const uint8_t data[], bool invert) noexcept; -private: +protected: const LcdFont * const *fonts; const size_t numFonts; size_t currentFontNumber; // index of the current font uint32_t charVal; + size_t imageSize; + uint8_t *image; // image buffer SharedSpiClient device; uint16_t lastCharColData; // data for the last non-space column, used for kerning - uint8_t controllerType; + const PixelNumber numRows, numCols; Pin a0Pin; uint8_t numContinuationBytesLeft; PixelNumber row, column; PixelNumber startRow, startCol, endRow, endCol; // coordinates of the dirty rectangle PixelNumber nextFlushRow; // which row we need to flush next PixelNumber leftMargin, rightMargin; - uint8_t image[(NumRows * NumCols)/8]; // image buffer, 1K in size bool textInverted; bool justSetCursor; - void sendLcdCommand(uint8_t command) noexcept { sendLcd(command, false); } - void sendLcdData(uint8_t data) noexcept { sendLcd(data, true); } - void sendLcd(uint8_t byteToSend, bool isData) noexcept; - - void CommandDelay() noexcept; - void DataDelay() noexcept; + virtual void HardwareInit() noexcept = 0; + virtual void CommandDelay() noexcept = 0; + virtual void DataDelay() noexcept = 0; + virtual void SendLcdCommand(uint8_t byteToSend) noexcept = 0; + virtual void SendLcdData(uint8_t byteToSend) noexcept = 0; - void setGraphicsAddress(unsigned int r, unsigned int c) noexcept; size_t writeNative(uint16_t c) noexcept; // write a decoded character void SetDirty(PixelNumber r, PixelNumber c) noexcept; }; #endif -#endif +#endif // SRC_DISPLAY_LCD_LCD_H diff --git a/src/Display/Lcd/ST7567/Lcd7567.cpp b/src/Display/Lcd/ST7567/Lcd7567.cpp new file mode 100644 index 00000000..af8085cd --- /dev/null +++ b/src/Display/Lcd/ST7567/Lcd7567.cpp @@ -0,0 +1,56 @@ +/* + * Lcd7567.cpp + * + * Created on: 15 Jul 2020 + * Author: David + */ + +#include "Lcd7567.h" + +#if SUPPORT_12864_LCD + +Lcd7567::Lcd7567(const LcdFont * const fnts[], size_t nFonts) noexcept + : Lcd(128, 64, fnts, nFonts) +{ +} + +// Flush just some data, returning true if this needs to be called again +bool Lcd7567::FlushSome() noexcept +{ + //TODO + return true; +} + +void Lcd7567::HardwareInit() noexcept +{ + pinMode(a0Pin, OUTPUT_HIGH); + //TODO +} + +void Lcd7567::CommandDelay() noexcept +{ + //TODO +} + +void Lcd7567::DataDelay() noexcept +{ + //TODO +} + +void Lcd7567::SendLcdCommand(uint8_t byteToSend) noexcept +{ + digitalWrite(a0Pin, false); + uint8_t data[1] = { byteToSend }; + device.TransceivePacket(data, nullptr, 1); +} + +void Lcd7567::SendLcdData(uint8_t byteToSend) noexcept +{ + digitalWrite(a0Pin, true); + uint8_t data[1] = { byteToSend }; + device.TransceivePacket(data, nullptr, 1); +} + +#endif + +// End diff --git a/src/Display/Lcd/ST7567/Lcd7567.h b/src/Display/Lcd/ST7567/Lcd7567.h new file mode 100644 index 00000000..a5532d72 --- /dev/null +++ b/src/Display/Lcd/ST7567/Lcd7567.h @@ -0,0 +1,38 @@ +/* + * Lcd7567.h + * + * Created on: 15 Jul 2020 + * Author: David + */ + +#ifndef SRC_DISPLAY_LCD_ST7567_LCD7567_H_ +#define SRC_DISPLAY_LCD_ST7567_LCD7567_H_ + +#include "RepRapFirmware.h" + +#if SUPPORT_12864_LCD + +#include <Display/Lcd/Lcd.h> + +class Lcd7567 : public Lcd +{ +public: + // Construct a GLCD driver. + Lcd7567(const LcdFont * const fnts[], size_t nFonts) noexcept; + + // Flush just some data, returning true if this needs to be called again + bool FlushSome() noexcept override; + +protected: + void HardwareInit() noexcept override; + void CommandDelay() noexcept override; + void DataDelay() noexcept override; + void SendLcdCommand(uint8_t byteToSend) noexcept override; + void SendLcdData(uint8_t byteToSend) noexcept override; + +private: +}; + +#endif + +#endif /* SRC_DISPLAY_LCD_ST7567_LCD7567_H_ */ diff --git a/src/Display/Lcd/ST7920/Lcd7920.cpp b/src/Display/Lcd/ST7920/Lcd7920.cpp new file mode 100644 index 00000000..a2054739 --- /dev/null +++ b/src/Display/Lcd/ST7920/Lcd7920.cpp @@ -0,0 +1,144 @@ +// Driver for 128x64 graphical LCD with ST7920 controller +// D Crocker, Escher Technologies Ltd. + +#include "Lcd7920.h" + +#if SUPPORT_12864_LCD + +#include "Pins.h" + +// LCD basic instructions. These all take 72us to execute except LcdDisplayClear, which takes 1.6ms +constexpr uint8_t LcdDisplayClear = 0x01; +constexpr uint8_t LcdHome = 0x02; +constexpr uint8_t LcdEntryModeSet = 0x06; // move cursor right and increment address when writing data +constexpr uint8_t LcdDisplayOff = 0x08; +constexpr uint8_t LcdDisplayOn = 0x0C; // add 0x02 for cursor on and/or 0x01 for cursor blink on +constexpr uint8_t LcdFunctionSetBasicAlpha = 0x20; +constexpr uint8_t LcdFunctionSetBasicGraphic = 0x22; +constexpr uint8_t LcdFunctionSetExtendedAlpha = 0x24; +constexpr uint8_t LcdFunctionSetExtendedGraphic = 0x26; +constexpr uint8_t LcdSetDdramAddress = 0x80; // add the address we want to set + +// LCD extended instructions +constexpr uint8_t LcdSetGdramAddress = 0x80; + +constexpr unsigned int LcdCommandDelayMicros = 72 - 8; // 72us required, less 7us time to send the command @ 2.0MHz +constexpr unsigned int LcdDataDelayMicros = 4; // delay between sending data bytes +constexpr unsigned int LcdDisplayClearDelayMillis = 3; // 1.6ms should be enough + +Lcd7920::Lcd7920(const LcdFont * const fnts[], size_t nFonts) noexcept + : Lcd(64, 128, fnts, nFonts) +{ +} + +void Lcd7920::HardwareInit() noexcept +{ + device.Select(); + delayMicroseconds(1); + SendLcdCommand(LcdFunctionSetBasicAlpha); + delay(2); + SendLcdCommand(LcdFunctionSetBasicAlpha); + CommandDelay(); + SendLcdCommand(LcdEntryModeSet); + CommandDelay(); + SendLcdCommand(LcdDisplayClear); // need this on some displays to ensure that the alpha RAM is clear (M3D Kanji problem) + delay(LcdDisplayClearDelayMillis); + SendLcdCommand(LcdFunctionSetExtendedGraphic); + CommandDelay(); + device.Deselect(); + + Clear(); + FlushAll(); + + device.Select(); + delayMicroseconds(1); + SendLcdCommand(LcdDisplayOn); + CommandDelay(); + device.Deselect(); +} + +void Lcd7920::CommandDelay() noexcept +{ + delayMicroseconds(LcdCommandDelayMicros); +} + +void Lcd7920::DataDelay() noexcept +{ + delayMicroseconds(LcdDataDelayMicros); +} + +// Flush some of the dirty part of the image to the LCD, returning true if there is more to do +bool Lcd7920::FlushSome() noexcept +{ + // See if there is anything to flush + if (endCol > startCol && endRow > startRow) + { + // Decide which row to flush next + if (nextFlushRow < startRow || nextFlushRow >= endRow) + { + nextFlushRow = startRow; // start from the beginning + } + + if (nextFlushRow == startRow) // if we are starting form the beginning + { + ++startRow; // flag this row as flushed because it will be soon + } + + // Flush that row + { + uint8_t startColNum = startCol/16; + const uint8_t endColNum = (endCol + 15)/16; +// debugPrintf("flush %u %u %u\n", nextFlushRow, startColNum, endColNum); + + device.Select(); + delayMicroseconds(1); + + SetGraphicsAddress(nextFlushRow, startColNum); + uint8_t *ptr = image + (((numCols/8) * nextFlushRow) + (2 * startColNum)); + while (startColNum < endColNum) + { + SendLcdData(*ptr++); + SendLcdData(*ptr++); + ++startColNum; + DataDelay(); + } + device.Deselect(); + } + + if (startRow != endRow) + { + ++nextFlushRow; + return true; + } + + startRow = numRows; + startCol = numCols; + endCol = endRow = nextFlushRow = 0; + } + return false; +} + +// Set the address to write to. The column address is in 16-bit words, so it ranges from 0 to 7. +void Lcd7920::SetGraphicsAddress(unsigned int r, unsigned int c) noexcept +{ + SendLcdCommand(LcdSetGdramAddress | (r & 31)); + //commandDelay(); // don't seem to need this one + SendLcdCommand(LcdSetGdramAddress | c | ((r & 32) >> 2)); + CommandDelay(); // we definitely need this one +} + +void Lcd7920::SendLcdCommand(uint8_t byteToSend) noexcept +{ + uint8_t data[3] = { (uint8_t)0xF8, (uint8_t)(byteToSend & 0xF0), (uint8_t)(byteToSend << 4) }; + device.TransceivePacket(data, nullptr, 3); +} + +void Lcd7920::SendLcdData(uint8_t byteToSend) noexcept +{ + uint8_t data[3] = { (uint8_t)0xFA, (uint8_t)(byteToSend & 0xF0), (uint8_t)(byteToSend << 4) }; + device.TransceivePacket(data, nullptr, 3); +} + +#endif + +// End diff --git a/src/Display/Lcd/ST7920/Lcd7920.h b/src/Display/Lcd/ST7920/Lcd7920.h new file mode 100644 index 00000000..c1dbf480 --- /dev/null +++ b/src/Display/Lcd/ST7920/Lcd7920.h @@ -0,0 +1,36 @@ +#ifndef LCD7920_H +#define LCD7920_H + +#include "RepRapFirmware.h" + +#if SUPPORT_12864_LCD + +#include <Display/Lcd/Lcd.h> + +// Class for driving 128x64 graphical LCD fitted with ST7920 controller +// This drives the GLCD in serial mode so that it needs just 2 pins. + +// Derive the LCD class from the Print class so that we can print stuff to it in alpha mode +class Lcd7920 : public Lcd +{ +public: + // Construct a GLCD driver. + Lcd7920(const LcdFont * const fnts[], size_t nFonts) noexcept; + + // Flush just some data, returning true if this needs to be called again + bool FlushSome() noexcept override; + +protected: + void HardwareInit() noexcept override; + void CommandDelay() noexcept override; + void DataDelay() noexcept override; + void SendLcdCommand(uint8_t byteToSend) noexcept override; + void SendLcdData(uint8_t byteToSend) noexcept override; + +private: + void SetGraphicsAddress(unsigned int r, unsigned int c) noexcept; +}; + +#endif + +#endif diff --git a/src/Display/Menu.cpp b/src/Display/Menu.cpp index 6a707800..0787355e 100644 --- a/src/Display/Menu.cpp +++ b/src/Display/Menu.cpp @@ -69,7 +69,7 @@ #if SUPPORT_12864_LCD -#include "ST7920/lcd7920.h" +#include "Lcd/Lcd.h" #include "RepRap.h" #include "Platform.h" #include "Display/Display.h" @@ -81,7 +81,7 @@ const uint32_t InactivityTimeout = 20000; // inactivity timeout const uint32_t ErrorTimeout = 6000; // how long we display an error message for -Menu::Menu(Lcd7920& refLcd) noexcept +Menu::Menu(Lcd& refLcd) noexcept : lcd(refLcd), timeoutValue(0), lastActionTime(0), selectableItems(nullptr), unSelectableItems(nullptr), highlightedItem(nullptr), numNestedMenus(0), @@ -110,7 +110,7 @@ void Menu::LoadFixedMenu() noexcept lcd.Clear(); // Instead of Reload(): - lcd.SetRightMargin(NumCols - currentMargin); + lcd.SetRightMargin(lcd.GetNumCols() - currentMargin); ResetCache(); @@ -149,12 +149,13 @@ void Menu::DisplayMessageBox(const MessageBox& mbox) noexcept const PixelNumber sideMargin = 4; // Draw and a box and clear the interior - lcd.SetRightMargin(NumCols); - lcd.Line(topBottomMargin, sideMargin, topBottomMargin, NumCols - sideMargin - 1, PixelMode::PixelSet); - lcd.Line(topBottomMargin, NumCols - sideMargin - 1, NumRows - topBottomMargin - 1, NumCols - sideMargin - 1, PixelMode::PixelSet); - lcd.Line(NumRows - topBottomMargin - 1, sideMargin, NumRows - topBottomMargin - 1, NumCols - sideMargin - 1, PixelMode::PixelSet); - lcd.Line(topBottomMargin, sideMargin, NumRows - topBottomMargin - 1, sideMargin, PixelMode::PixelSet); - lcd.Clear(topBottomMargin + 1, sideMargin + 1, NumRows - topBottomMargin - 1, NumCols - sideMargin - 1); + const PixelNumber nr = lcd.GetNumRows(), nc = lcd.GetNumCols(); + lcd.SetRightMargin(nc); + lcd.Line(topBottomMargin, sideMargin, topBottomMargin, nc - sideMargin - 1, PixelMode::PixelSet); + lcd.Line(topBottomMargin, nc - sideMargin - 1, nr - topBottomMargin - 1, nc - sideMargin - 1, PixelMode::PixelSet); + lcd.Line(nr - topBottomMargin - 1, sideMargin, nr - topBottomMargin - 1, nc - sideMargin - 1, PixelMode::PixelSet); + lcd.Line(topBottomMargin, sideMargin, nr - topBottomMargin - 1, sideMargin, PixelMode::PixelSet); + lcd.Clear(topBottomMargin + 1, sideMargin + 1, nr - topBottomMargin - 1, nc - sideMargin - 1); // We could draw the static text directly, but it is easier to use the existing classes const uint8_t fontToUse = 0; @@ -162,7 +163,7 @@ void Menu::DisplayMessageBox(const MessageBox& mbox) noexcept const PixelNumber rowHeight = lcd.GetFontHeight(fontToUse) + 1; const PixelNumber top = topBottomMargin + 1 + insideMargin; const PixelNumber left = sideMargin + 1 + insideMargin; - const PixelNumber right = NumCols - left; + const PixelNumber right = nc - left; const PixelNumber availableWidth = right - left; AddItem(new TextMenuItem(top, left, availableWidth, MenuItem::CentreAlign, fontToUse, MenuItem::AlwaysVisible, mbox.title.c_str()), false); AddItem(new TextMenuItem(top + rowHeight, left, availableWidth, MenuItem::CentreAlign, fontToUse, MenuItem::AlwaysVisible, mbox.message.c_str()), false); // only 1 row for now @@ -393,7 +394,7 @@ const char *Menu::ParseMenuLine(char * const commandWord) noexcept const char * const actionString = AppendString(action); const char *const dir = AppendString(dirpath); const char *const acFileString = AppendString(fname); - AddItem(new FilesMenuItem(row, 0, NumCols, fontNumber, xVis, actionString, dir, acFileString, nparam), true); + AddItem(new FilesMenuItem(row, 0, lcd.GetNumCols(), fontNumber, xVis, actionString, dir, acFileString, nparam), true); row += nparam * lcd.GetFontHeight(fontNumber); column = 0; } @@ -436,8 +437,8 @@ void Menu::Reload() noexcept else { currentMargin = 0; - const PixelNumber right = NumCols; - const PixelNumber bottom = NumRows; + const PixelNumber right = lcd.GetNumCols(); + const PixelNumber bottom = lcd.GetNumRows(); lcd.Clear(currentMargin, currentMargin, bottom, right); // Draw the outline @@ -452,7 +453,7 @@ void Menu::Reload() noexcept ResetCache(); displayingErrorMessage = false; - lcd.SetRightMargin(NumCols - currentMargin); + lcd.SetRightMargin(lcd.GetNumCols() - currentMargin); const char * const fname = filenames[numNestedMenus - 1].c_str(); FileStore * const file = reprap.GetPlatform().OpenFile(MENU_DIR, fname, OpenMode::read); if (file == nullptr) @@ -698,7 +699,7 @@ void Menu::DrawAll() noexcept } // Now draw items - const PixelNumber rightMargin = NumCols - currentMargin; + const PixelNumber rightMargin = lcd.GetNumCols() - currentMargin; for (MenuItem *item = selectableItems; item != nullptr; item = item->GetNext()) { item->Draw(lcd, rightMargin, (item == highlightedItem), rowOffset); diff --git a/src/Display/Menu.h b/src/Display/Menu.h index 27ae884b..02d64a1a 100644 --- a/src/Display/Menu.h +++ b/src/Display/Menu.h @@ -21,7 +21,7 @@ class MessageBox; class Menu { public: - Menu(Lcd7920& refLcd) noexcept; + Menu(Lcd& refLcd) noexcept; void Load(const char* filename) noexcept; // load a menu file void Pop() noexcept; void EncoderAction(int action) noexcept; @@ -63,7 +63,7 @@ private: static const PixelNumber InnerMargin = 2; // how many pixels we keep clear inside the border static const PixelNumber OuterMargin = 8 + InnerMargin; // how many pixels of the previous menu we leave on each side - Lcd7920& lcd; + Lcd& lcd; uint32_t timeoutValue; // how long to time out after 0 = no timeout uint32_t lastActionTime; diff --git a/src/Display/MenuItem.cpp b/src/Display/MenuItem.cpp index 0fc25b9e..bfc9b9e2 100644 --- a/src/Display/MenuItem.cpp +++ b/src/Display/MenuItem.cpp @@ -40,7 +40,7 @@ MenuItem::MenuItem(PixelNumber r, PixelNumber c, PixelNumber w, Alignment a, Fon } // Print the item at the correct place with the correct alignment -void MenuItem::PrintAligned(Lcd7920& lcd, PixelNumber tOffset, PixelNumber rightMargin) noexcept +void MenuItem::PrintAligned(Lcd& lcd, PixelNumber tOffset, PixelNumber rightMargin) noexcept { PixelNumber colsToSkip = 0; lcd.SetFont(fontNumber); @@ -97,7 +97,7 @@ bool MenuItem::IsVisible() const noexcept } // Erase this item if it is drawn but should not be visible -void MenuItem::EraseIfInvisible(Lcd7920& lcd, PixelNumber tOffset) noexcept +void MenuItem::EraseIfInvisible(Lcd& lcd, PixelNumber tOffset) noexcept { if (drawn && !IsVisible()) { @@ -111,12 +111,12 @@ TextMenuItem::TextMenuItem(PixelNumber r, PixelNumber c, PixelNumber w, Alignmen { } -void TextMenuItem::CorePrint(Lcd7920& lcd) noexcept +void TextMenuItem::CorePrint(Lcd& lcd) noexcept { lcd.print(text); } -void TextMenuItem::Draw(Lcd7920& lcd, PixelNumber rightMargin, bool highlight, PixelNumber tOffset) noexcept +void TextMenuItem::Draw(Lcd& lcd, PixelNumber rightMargin, bool highlight, PixelNumber tOffset) noexcept { // We ignore the 'highlight' parameter because text items are not selectable if (IsVisible() && (!drawn || itemChanged)) @@ -127,7 +127,7 @@ void TextMenuItem::Draw(Lcd7920& lcd, PixelNumber rightMargin, bool highlight, P } } -void TextMenuItem::UpdateWidthAndHeight(Lcd7920& lcd) noexcept +void TextMenuItem::UpdateWidthAndHeight(Lcd& lcd) noexcept { if (width == 0) { @@ -154,14 +154,14 @@ ButtonMenuItem::ButtonMenuItem(PixelNumber r, PixelNumber c, PixelNumber w, Font { } -void ButtonMenuItem::CorePrint(Lcd7920& lcd) noexcept +void ButtonMenuItem::CorePrint(Lcd& lcd) noexcept { lcd.WriteSpaces(1); // space at start in case highlighted lcd.print(text); lcd.WriteSpaces(1); // space at end to allow for highlighting } -void ButtonMenuItem::Draw(Lcd7920& lcd, PixelNumber rightMargin, bool highlight, PixelNumber tOffset) noexcept +void ButtonMenuItem::Draw(Lcd& lcd, PixelNumber rightMargin, bool highlight, PixelNumber tOffset) noexcept { if (IsVisible() && (itemChanged || !drawn || highlight != highlighted) && column < lcd.GetNumCols()) { @@ -172,7 +172,7 @@ void ButtonMenuItem::Draw(Lcd7920& lcd, PixelNumber rightMargin, bool highlight, } } -void ButtonMenuItem::UpdateWidthAndHeight(Lcd7920& lcd) noexcept +void ButtonMenuItem::UpdateWidthAndHeight(Lcd& lcd) noexcept { if (width == 0) { @@ -237,7 +237,7 @@ ValueMenuItem::ValueMenuItem(PixelNumber r, PixelNumber c, PixelNumber w, Alignm { } -void ValueMenuItem::CorePrint(Lcd7920& lcd) noexcept +void ValueMenuItem::CorePrint(Lcd& lcd) noexcept { if (adjustable) { @@ -312,7 +312,7 @@ void ValueMenuItem::CorePrint(Lcd7920& lcd) noexcept } } -void ValueMenuItem::Draw(Lcd7920& lcd, PixelNumber rightMargin, bool highlight, PixelNumber tOffset) noexcept +void ValueMenuItem::Draw(Lcd& lcd, PixelNumber rightMargin, bool highlight, PixelNumber tOffset) noexcept { if (IsVisible()) { @@ -501,7 +501,7 @@ bool ValueMenuItem::Select(const StringRef& cmd) noexcept return false; } -void ValueMenuItem::UpdateWidthAndHeight(Lcd7920& lcd) noexcept +void ValueMenuItem::UpdateWidthAndHeight(Lcd& lcd) noexcept { // The width is always set for a ValueMenuItem so we just need to determine the height if (height == 0) @@ -768,7 +768,7 @@ unsigned int FilesMenuItem::uListingEntries() const noexcept return bInSubdirectory() ? (1 + m_uHardItemsInDirectory) : m_uHardItemsInDirectory; } -void FilesMenuItem::Draw(Lcd7920& lcd, PixelNumber rightMargin, bool highlight, PixelNumber tOffset) noexcept +void FilesMenuItem::Draw(Lcd& lcd, PixelNumber rightMargin, bool highlight, PixelNumber tOffset) noexcept { // The 'highlight' parameter is not used to highlight this item, but it is still used to tell whether this item is selected or not if (!IsVisible()) @@ -831,7 +831,7 @@ void FilesMenuItem::Draw(Lcd7920& lcd, PixelNumber rightMargin, bool highlight, } } -void FilesMenuItem::ListFiles(Lcd7920& lcd, PixelNumber rightMargin, bool highlight, PixelNumber tOffset) noexcept +void FilesMenuItem::ListFiles(Lcd& lcd, PixelNumber rightMargin, bool highlight, PixelNumber tOffset) noexcept { lcd.SetFont(fontNumber); lcd.SetRightMargin(rightMargin); @@ -1079,7 +1079,7 @@ bool FilesMenuItem::Select(const StringRef& cmd) noexcept return false; } -void FilesMenuItem::UpdateWidthAndHeight(Lcd7920& lcd) noexcept +void FilesMenuItem::UpdateWidthAndHeight(Lcd& lcd) noexcept { // The width is always set for a FilesMenuItem so we just need to determine the height if (height == 0) @@ -1106,7 +1106,7 @@ ImageMenuItem::ImageMenuItem(PixelNumber r, PixelNumber c, Visibility vis, const fileName.copy(pFileName); } -void ImageMenuItem::Draw(Lcd7920& lcd, PixelNumber rightMargin, bool highlight, PixelNumber tOffset) noexcept +void ImageMenuItem::Draw(Lcd& lcd, PixelNumber rightMargin, bool highlight, PixelNumber tOffset) noexcept { if (IsVisible() && (!drawn || itemChanged || highlight != highlighted)) { @@ -1140,7 +1140,7 @@ void ImageMenuItem::Draw(Lcd7920& lcd, PixelNumber rightMargin, bool highlight, } } -void ImageMenuItem::UpdateWidthAndHeight(Lcd7920& lcd) noexcept +void ImageMenuItem::UpdateWidthAndHeight(Lcd& lcd) noexcept { if (width == 0 || height == 0) { diff --git a/src/Display/MenuItem.h b/src/Display/MenuItem.h index 02f72dc6..cdd754f3 100644 --- a/src/Display/MenuItem.h +++ b/src/Display/MenuItem.h @@ -13,7 +13,7 @@ #if SUPPORT_12864_LCD #include "General/FreelistManager.h" -#include "ST7920/lcd7920.h" +#include "Lcd/Lcd.h" #include "Storage/MassStorage.h" // Menu item class hierarchy @@ -28,7 +28,7 @@ public: static constexpr Visibility AlwaysVisible = 0; // Draw this element on the LCD respecting 'maxWidth' and 'highlight' - virtual void Draw(Lcd7920& lcd, PixelNumber maxWidth, bool highlight, PixelNumber tOffset) noexcept = 0; + virtual void Draw(Lcd& lcd, PixelNumber maxWidth, bool highlight, PixelNumber tOffset) noexcept = 0; // Select this element with a push of the encoder. // If it returns nullptr false go into adjustment mode, if we can adjust the item. @@ -50,7 +50,7 @@ public: virtual bool Adjust(int clicks) noexcept { return true; } // If the width was specified as zero, update it with the actual width. Also update the height. - virtual void UpdateWidthAndHeight(Lcd7920& lcd) noexcept = 0; + virtual void UpdateWidthAndHeight(Lcd& lcd) noexcept = 0; // DC: I don't know what this one is for, the person who wrote it didn't document it virtual PixelNumber GetVisibilityRowOffset(PixelNumber tCurrentOffset, PixelNumber fontHeight) const noexcept { return 0; } @@ -63,7 +63,7 @@ public: bool IsVisible() const noexcept; // Erase this item if it is drawn but should not be visible - void EraseIfInvisible(Lcd7920& lcd, PixelNumber tOffset) noexcept; + void EraseIfInvisible(Lcd& lcd, PixelNumber tOffset) noexcept; // Return the width of this item in pixels PixelNumber GetWidth() const noexcept { return width; } @@ -76,10 +76,10 @@ protected: // Print the item starting at the current cursor position, which may be off screen. Used to find the width and also to really print the item. // Overridden for items that support variable alignment - virtual void CorePrint(Lcd7920& lcd) noexcept { } + virtual void CorePrint(Lcd& lcd) noexcept { } // Print the item at the correct place with the correct alignment - void PrintAligned(Lcd7920& lcd, PixelNumber tOffset, PixelNumber rightMargin) noexcept; + void PrintAligned(Lcd& lcd, PixelNumber tOffset, PixelNumber rightMargin) noexcept; const PixelNumber row, column; PixelNumber width, height; @@ -102,11 +102,11 @@ public: void operator delete(void* p) noexcept { FreelistManager::Release<TextMenuItem>(p); } TextMenuItem(PixelNumber r, PixelNumber c, PixelNumber w, Alignment a, FontNumber fn, Visibility vis, const char *t) noexcept; - void Draw(Lcd7920& lcd, PixelNumber maxWidth, bool highlight, PixelNumber tOffset) noexcept override; - void UpdateWidthAndHeight(Lcd7920& lcd) noexcept override; + void Draw(Lcd& lcd, PixelNumber maxWidth, bool highlight, PixelNumber tOffset) noexcept override; + void UpdateWidthAndHeight(Lcd& lcd) noexcept override; protected: - void CorePrint(Lcd7920& lcd) noexcept override; + void CorePrint(Lcd& lcd) noexcept override; private: const char *text; @@ -119,14 +119,14 @@ public: void operator delete(void* p) noexcept { FreelistManager::Release<ButtonMenuItem>(p); } ButtonMenuItem(PixelNumber r, PixelNumber c, PixelNumber w, FontNumber fn, Visibility vis, const char *t, const char *cmd, const char *acFile) noexcept; - void Draw(Lcd7920& lcd, PixelNumber maxWidth, bool highlight, PixelNumber tOffset) noexcept override; - void UpdateWidthAndHeight(Lcd7920& lcd) noexcept override; + void Draw(Lcd& lcd, PixelNumber maxWidth, bool highlight, PixelNumber tOffset) noexcept override; + void UpdateWidthAndHeight(Lcd& lcd) noexcept override; bool Select(const StringRef& cmd) noexcept override; PixelNumber GetVisibilityRowOffset(PixelNumber tCurrentOffset, PixelNumber fontHeight) const noexcept override; protected: - void CorePrint(Lcd7920& lcd) noexcept override; + void CorePrint(Lcd& lcd) noexcept override; private: const char *text; @@ -141,18 +141,18 @@ public: void operator delete(void* p) noexcept { FreelistManager::Release<ValueMenuItem>(p); } ValueMenuItem(PixelNumber r, PixelNumber c, PixelNumber w, Alignment a, FontNumber fn, Visibility vis, bool adj, unsigned int v, unsigned int d) noexcept; - void Draw(Lcd7920& lcd, PixelNumber maxWidth, bool highlight, PixelNumber tOffset) noexcept override; + void Draw(Lcd& lcd, PixelNumber maxWidth, bool highlight, PixelNumber tOffset) noexcept override; bool Select(const StringRef& cmd) noexcept override; bool CanAdjust() const noexcept override { return true; } bool Adjust(int clicks) noexcept override; - void UpdateWidthAndHeight(Lcd7920& lcd) noexcept override; + void UpdateWidthAndHeight(Lcd& lcd) noexcept override; PixelNumber GetVisibilityRowOffset(PixelNumber tCurrentOffset, PixelNumber fontHeight) const noexcept override; unsigned int GetReferencedToolNumber() const noexcept; protected: - void CorePrint(Lcd7920& lcd) noexcept override; + void CorePrint(Lcd& lcd) noexcept override; private: enum class AdjustMode : uint8_t { displaying, adjusting, liveAdjusting }; @@ -188,11 +188,11 @@ public: void operator delete(void* p) noexcept { FreelistManager::Release<FilesMenuItem>(p); } FilesMenuItem(PixelNumber r, PixelNumber c, PixelNumber w, FontNumber fn, Visibility vis, const char *cmd, const char *dir, const char *acFile, unsigned int nf) noexcept; - void Draw(Lcd7920& lcd, PixelNumber rightMargin, bool highlight, PixelNumber tOffset) noexcept override; + void Draw(Lcd& lcd, PixelNumber rightMargin, bool highlight, PixelNumber tOffset) noexcept override; void Enter(bool bForwardDirection) noexcept override; int Advance(int nCounts) noexcept override; bool Select(const StringRef& cmd) noexcept override; - void UpdateWidthAndHeight(Lcd7920& lcd) noexcept override; + void UpdateWidthAndHeight(Lcd& lcd) noexcept override; PixelNumber GetVisibilityRowOffset(PixelNumber tCurrentOffset, PixelNumber fontHeight) const noexcept override; @@ -202,7 +202,7 @@ protected: void vResetViewState() noexcept; private: - void ListFiles(Lcd7920& lcd, PixelNumber rightMargin, bool highlight, PixelNumber tOffset) noexcept; + void ListFiles(Lcd& lcd, PixelNumber rightMargin, bool highlight, PixelNumber tOffset) noexcept; uint8_t GetDirectoryNesting() const noexcept; const unsigned int numDisplayLines; @@ -236,8 +236,8 @@ public: ImageMenuItem(PixelNumber r, PixelNumber c, Visibility vis, const char *pFileName) noexcept; - void Draw(Lcd7920& lcd, PixelNumber rightMargin, bool highlight, PixelNumber tOffset) noexcept override; - void UpdateWidthAndHeight(Lcd7920& lcd) noexcept override; + void Draw(Lcd& lcd, PixelNumber rightMargin, bool highlight, PixelNumber tOffset) noexcept override; + void UpdateWidthAndHeight(Lcd& lcd) noexcept override; private: String<MaxFilenameLength> fileName; diff --git a/src/GCodes/GCodeBuffer/BinaryParser.cpp b/src/GCodes/GCodeBuffer/BinaryParser.cpp index f6423ae2..980f2e6f 100644 --- a/src/GCodes/GCodeBuffer/BinaryParser.cpp +++ b/src/GCodes/GCodeBuffer/BinaryParser.cpp @@ -219,6 +219,18 @@ uint32_t BinaryParser::GetUIValue() THROWS(GCodeException) return value; } +void BinaryParser::SetDriverIdFromBinary(DriverId& did, uint32_t val) THROWS(GCodeException) +{ +#if SUPPORT_CAN_EXPANSION + did.SetFromBinary(val); +#else + if (did.SetFromBinary(val)) + { + throw ConstructParseException("Board address of driver must be 0"); + } +#endif +} + // Get a driver ID DriverId BinaryParser::GetDriverId() THROWS(GCodeException) { @@ -233,7 +245,7 @@ DriverId BinaryParser::GetDriverId() THROWS(GCodeException) case DataType::Int: case DataType::UInt: case DataType::DriverId: - value.SetFromBinary(seenParameter->uintValue); + SetDriverIdFromBinary(value, seenParameter->uintValue); break; default: @@ -462,7 +474,7 @@ void BinaryParser::GetDriverIdArray(DriverId arr[], size_t& length) THROWS(GCode case DataType::Int: case DataType::UInt: case DataType::DriverId: - arr[0].SetFromBinary(seenParameter->uintValue); + SetDriverIdFromBinary(arr[0], seenParameter->uintValue); length = 1; break; @@ -472,7 +484,7 @@ void BinaryParser::GetDriverIdArray(DriverId arr[], size_t& length) THROWS(GCode CheckArrayLength(length); for (int i = 0; i < seenParameter->intValue; i++) { - arr[i].SetFromBinary(reinterpret_cast<const uint32_t*>(seenParameterValue)[i]); + SetDriverIdFromBinary(arr[i], reinterpret_cast<const uint32_t*>(seenParameterValue)[i]); } length = seenParameter->intValue; break; diff --git a/src/GCodes/GCodeBuffer/BinaryParser.h b/src/GCodes/GCodeBuffer/BinaryParser.h index 3320fb28..897a5c7a 100644 --- a/src/GCodes/GCodeBuffer/BinaryParser.h +++ b/src/GCodes/GCodeBuffer/BinaryParser.h @@ -64,6 +64,7 @@ private: GCodeBuffer& gb; void CheckArrayLength(size_t maxLength) THROWS(GCodeException); + void SetDriverIdFromBinary(DriverId& did, uint32_t val) THROWS(GCodeException); GCodeException ConstructParseException(const char *str) const noexcept; GCodeException ConstructParseException(const char *str, const char *param) const noexcept; GCodeException ConstructParseException(const char *str, uint32_t param) const noexcept; diff --git a/src/GCodes/GCodeBuffer/GCodeBuffer.cpp b/src/GCodes/GCodeBuffer/GCodeBuffer.cpp index e6d4de9e..c1bf3e8d 100644 --- a/src/GCodes/GCodeBuffer/GCodeBuffer.cpp +++ b/src/GCodes/GCodeBuffer/GCodeBuffer.cpp @@ -302,7 +302,7 @@ bool GCodeBuffer::Seen(char c) noexcept } // Test for character present, throw error if not -void GCodeBuffer::MustSee(char c) +void GCodeBuffer::MustSee(char c) THROWS(GCodeException) { if (!Seen(c)) { @@ -311,19 +311,19 @@ void GCodeBuffer::MustSee(char c) } // Get a float after a key letter -float GCodeBuffer::GetFValue() +float GCodeBuffer::GetFValue() THROWS(GCodeException) { return PARSER_OPERATION(GetFValue()); } // Get a distance or coordinate and convert it from inches to mm if necessary -float GCodeBuffer::GetDistance() +float GCodeBuffer::GetDistance() THROWS(GCodeException) { return ConvertDistance(GetFValue()); } // Get an integer after a key letter -int32_t GCodeBuffer::GetIValue() +int32_t GCodeBuffer::GetIValue() THROWS(GCodeException) { return PARSER_OPERATION(GetIValue()); } @@ -345,7 +345,7 @@ int32_t GCodeBuffer::GetLimitedIValue(char c, int32_t minValue, int32_t maxValue } // Get an unsigned integer value -uint32_t GCodeBuffer::GetUIValue() +uint32_t GCodeBuffer::GetUIValue() THROWS(GCodeException) { return PARSER_OPERATION(GetUIValue()); } @@ -363,54 +363,54 @@ uint32_t GCodeBuffer::GetLimitedUIValue(char c, uint32_t maxValuePlusOne) THROWS } // Get an IP address quad after a key letter -void GCodeBuffer::GetIPAddress(IPAddress& returnedIp) +void GCodeBuffer::GetIPAddress(IPAddress& returnedIp) THROWS(GCodeException) { PARSER_OPERATION(GetIPAddress(returnedIp)); } // Get a MAC address sextet after a key letter -void GCodeBuffer::GetMacAddress(MacAddress& mac) +void GCodeBuffer::GetMacAddress(MacAddress& mac) THROWS(GCodeException) { PARSER_OPERATION(GetMacAddress(mac)); } // Get a string with no preceding key letter -void GCodeBuffer::GetUnprecedentedString(const StringRef& str, bool allowEmpty) +void GCodeBuffer::GetUnprecedentedString(const StringRef& str, bool allowEmpty) THROWS(GCodeException) { PARSER_OPERATION(GetUnprecedentedString(str, allowEmpty)); } // Get and copy a quoted string -void GCodeBuffer::GetQuotedString(const StringRef& str) +void GCodeBuffer::GetQuotedString(const StringRef& str) THROWS(GCodeException) { PARSER_OPERATION(GetQuotedString(str)); } // Get and copy a string which may or may not be quoted -void GCodeBuffer::GetPossiblyQuotedString(const StringRef& str) +void GCodeBuffer::GetPossiblyQuotedString(const StringRef& str) THROWS(GCodeException) { PARSER_OPERATION(GetPossiblyQuotedString(str)); } -void GCodeBuffer::GetReducedString(const StringRef& str) +void GCodeBuffer::GetReducedString(const StringRef& str) THROWS(GCodeException) { PARSER_OPERATION(GetReducedString(str)); } // Get a colon-separated list of floats after a key letter -void GCodeBuffer::GetFloatArray(float arr[], size_t& length, bool doPad) +void GCodeBuffer::GetFloatArray(float arr[], size_t& length, bool doPad) THROWS(GCodeException) { PARSER_OPERATION(GetFloatArray(arr, length, doPad)); } // Get a :-separated list of ints after a key letter -void GCodeBuffer::GetIntArray(int32_t arr[], size_t& length, bool doPad) +void GCodeBuffer::GetIntArray(int32_t arr[], size_t& length, bool doPad) THROWS(GCodeException) { PARSER_OPERATION(GetIntArray(arr, length, doPad)); } // Get a :-separated list of unsigned ints after a key letter -void GCodeBuffer::GetUnsignedArray(uint32_t arr[], size_t& length, bool doPad) +void GCodeBuffer::GetUnsignedArray(uint32_t arr[], size_t& length, bool doPad) THROWS(GCodeException) { PARSER_OPERATION(GetUnsignedArray(arr, length, doPad)); } @@ -422,7 +422,7 @@ void GCodeBuffer::GetDriverIdArray(DriverId arr[], size_t& length) } // If the specified parameter character is found, fetch 'value' and set 'seen'. Otherwise leave val and seen alone. -bool GCodeBuffer::TryGetFValue(char c, float& val, bool& seen) +bool GCodeBuffer::TryGetFValue(char c, float& val, bool& seen) THROWS(GCodeException) { const bool ret = Seen(c); if (ret) @@ -434,7 +434,7 @@ bool GCodeBuffer::TryGetFValue(char c, float& val, bool& seen) } // If the specified parameter character is found, fetch 'value' and set 'seen'. Otherwise leave val and seen alone. -bool GCodeBuffer::TryGetIValue(char c, int32_t& val, bool& seen) +bool GCodeBuffer::TryGetIValue(char c, int32_t& val, bool& seen) THROWS(GCodeException) { const bool ret = Seen(c); if (ret) @@ -464,7 +464,7 @@ bool GCodeBuffer::TryGetLimitedIValue(char c, int32_t& val, bool& seen, int32_t } // If the specified parameter character is found, fetch 'value' and set 'seen'. Otherwise leave val and seen alone. -bool GCodeBuffer::TryGetUIValue(char c, uint32_t& val, bool& seen) +bool GCodeBuffer::TryGetUIValue(char c, uint32_t& val, bool& seen) THROWS(GCodeException) { const bool ret = Seen(c); if (ret) @@ -487,7 +487,7 @@ bool GCodeBuffer::TryGetLimitedUIValue(char c, uint32_t& val, bool& seen, uint32 } // If the specified parameter character is found, fetch 'value' as a Boolean and set 'seen'. Otherwise leave val and seen alone. -bool GCodeBuffer::TryGetBValue(char c, bool& val, bool& seen) +bool GCodeBuffer::TryGetBValue(char c, bool& val, bool& seen) THROWS(GCodeException) { const bool ret = Seen(c); if (ret) @@ -501,7 +501,7 @@ bool GCodeBuffer::TryGetBValue(char c, bool& val, bool& seen) // Try to get an int array exactly 'numVals' long after parameter letter 'c'. // If the wrong number of values is provided, generate an error message and return true. // Else set 'seen' if we saw the letter and value, and return false. -bool GCodeBuffer::TryGetUIArray(char c, size_t numVals, uint32_t vals[], const StringRef& reply, bool& seen, bool doPad) +bool GCodeBuffer::TryGetUIArray(char c, size_t numVals, uint32_t vals[], const StringRef& reply, bool& seen, bool doPad) THROWS(GCodeException) { if (Seen(c)) { @@ -523,7 +523,7 @@ bool GCodeBuffer::TryGetUIArray(char c, size_t numVals, uint32_t vals[], const S // Try to get a float array exactly 'numVals' long after parameter letter 'c'. // If the wrong number of values is provided, generate an error message and return true. // Else set 'seen' if we saw the letter and value, and return false. -bool GCodeBuffer::TryGetFloatArray(char c, size_t numVals, float vals[], const StringRef& reply, bool& seen, bool doPad) +bool GCodeBuffer::TryGetFloatArray(char c, size_t numVals, float vals[], const StringRef& reply, bool& seen, bool doPad) THROWS(GCodeException) { if (Seen(c)) { @@ -544,7 +544,7 @@ bool GCodeBuffer::TryGetFloatArray(char c, size_t numVals, float vals[], const S // Try to get a quoted string after parameter letter. // If we found it then set 'seen' true and return true, else leave 'seen' alone and return false -bool GCodeBuffer::TryGetQuotedString(char c, const StringRef& str, bool& seen) +bool GCodeBuffer::TryGetQuotedString(char c, const StringRef& str, bool& seen) THROWS(GCodeException) { if (Seen(c)) { @@ -557,7 +557,7 @@ bool GCodeBuffer::TryGetQuotedString(char c, const StringRef& str, bool& seen) // Try to get a string, which may be quoted, after parameter letter. // If we found it then set 'seen' true and return true, else leave 'seen' alone and return false -bool GCodeBuffer::TryGetPossiblyQuotedString(char c, const StringRef& str, bool& seen) +bool GCodeBuffer::TryGetPossiblyQuotedString(char c, const StringRef& str, bool& seen) THROWS(GCodeException) { if (Seen(c)) { @@ -569,13 +569,13 @@ bool GCodeBuffer::TryGetPossiblyQuotedString(char c, const StringRef& str, bool& } // Get a PWM frequency -PwmFrequency GCodeBuffer::GetPwmFrequency() +PwmFrequency GCodeBuffer::GetPwmFrequency() THROWS(GCodeException) { return (PwmFrequency)constrain<uint32_t>(GetUIValue(), 1, 65535); } // Get a PWM value. If may be in the old style 0..255 in which case convert it to be in the range 0.0..1.0 -float GCodeBuffer::GetPwmValue() +float GCodeBuffer::GetPwmValue() THROWS(GCodeException) { float v = GetFValue(); if (v > 1.0) @@ -586,7 +586,7 @@ float GCodeBuffer::GetPwmValue() } // Get a driver ID -DriverId GCodeBuffer::GetDriverId() +DriverId GCodeBuffer::GetDriverId() THROWS(GCodeException) { return PARSER_OPERATION(GetDriverId()); } diff --git a/src/GCodes/GCodeBuffer/StringParser.cpp b/src/GCodes/GCodeBuffer/StringParser.cpp index c058b2c5..2d375b25 100644 --- a/src/GCodes/GCodeBuffer/StringParser.cpp +++ b/src/GCodes/GCodeBuffer/StringParser.cpp @@ -1656,7 +1656,20 @@ DriverId StringParser::ReadDriverIdValue() THROWS(GCodeException) result.boardAddress = 0; } #else - result.localDriver = v1; + // We now allow driver names of the form "0.x" on boards without CAN expansion + if (gb.buffer[readPointer] == '.') + { + if (v1 != 0) + { + throw ConstructParseException("Board address of driver must be 0"); + } + ++readPointer; + result.localDriver = ReadUIValue(); + } + else + { + result.localDriver = v1; + } #endif return result; } diff --git a/src/RepRapFirmware.h b/src/RepRapFirmware.h index b44a2825..a52fb204 100644 --- a/src/RepRapFirmware.h +++ b/src/RepRapFirmware.h @@ -186,9 +186,12 @@ struct DriverId #else - void SetFromBinary(uint32_t val) noexcept + // Set the driver ID from the binary value, returning true if there was a nonzero board number so that the caller knows the address is not valid + bool SetFromBinary(uint32_t val) noexcept { - localDriver = (uint8_t)val; + localDriver = val & 0x000000FF; + const uint32_t brdNum = val >> 16; + return (brdNum != 0); } void SetLocal(unsigned int driver) noexcept |