diff options
Diffstat (limited to 'src/Display')
-rw-r--r-- | src/Display/Display.cpp | 52 | ||||
-rw-r--r-- | src/Display/Display.h | 9 | ||||
-rw-r--r-- | src/Display/RotaryEncoder.cpp | 18 | ||||
-rw-r--r-- | src/Display/RotaryEncoder.h | 7 | ||||
-rw-r--r-- | src/Display/ST7920/lcd7920.cpp | 35 |
5 files changed, 95 insertions, 26 deletions
diff --git a/src/Display/Display.cpp b/src/Display/Display.cpp index aa8fcba6..264978ce 100644 --- a/src/Display/Display.cpp +++ b/src/Display/Display.cpp @@ -7,14 +7,18 @@ #include "Display.h" #include "GCodes/GCodes.h" +#include "IoPort.h" +#include "Pins.h" + +constexpr int DefaultPulsesPerClick = -4; // values that work with displays I have are 2 and -4 extern const LcdFont font16x16; -//extern const LcdFont font10x10; +extern const LcdFont font10x10; static int val = 0; Display::Display() - : lcd(LcdCSPin), encoder(EncoderPinA, EncoderPinB, EncoderPinSw, 4) + : lcd(LcdCSPin), encoder(EncoderPinA, EncoderPinB, EncoderPinSw), present(false) { //TODO init menus here } @@ -22,7 +26,7 @@ Display::Display() void Display::Init() { lcd.Init(); - encoder.Init(); + encoder.Init(DefaultPulsesPerClick); //TODO display top menu here // For now we just print some text to test the display @@ -35,6 +39,9 @@ void Display::Init() lcd.SetCursor(20, 5); lcd.SetRightMargin(50); lcd.print(val); + + IoPort::SetPinMode(LcdBeepPin, OUTPUT_PWM_LOW); + beepActive = false; } void Display::Spin(bool full) @@ -67,6 +74,11 @@ void Display::Spin(bool full) lcd.FlushSome(); } + + if (beepActive && millis() - whenBeepStarted > beepLength) + { + IoPort::WriteAnalog(LcdBeepPin, 0.0, 0); + } } void Display::Exit() @@ -74,4 +86,38 @@ void Display::Exit() // TODO display a "shutdown" message, or turn the display off? } +void Display::Beep(unsigned int frequency, unsigned int milliseconds) +{ + whenBeepStarted = millis(); + beepLength = milliseconds; + beepActive = true; + IoPort::WriteAnalog(LcdBeepPin, 0.5, (uint16_t)frequency); +} + +GCodeResult Display::Configure(GCodeBuffer& gb, const StringRef& reply) +{ + if (gb.Seen('P') && gb.GetUIValue() == 1) + { + // 12864 display configuration + present = true; + if (gb.Seen('E')) + { + encoder.Init(gb.GetIValue()); // configure encoder pulses per click and direction + } + } + return GCodeResult::ok; +} + +// Suspend normal operation and display an "Updating firmware" message +void Display::UpdatingFirmware() +{ + IoPort::WriteAnalog(LcdBeepPin, 0.0, 0); // stop any beep + lcd.TextInvert(false); + lcd.Clear(); + lcd.SetFont(&font10x10); + lcd.SetCursor(20, 0); + lcd.print("Updating firmware..."); + lcd.FlushAll(); +} + // End diff --git a/src/Display/Display.h b/src/Display/Display.h index fa321a1c..b7c90322 100644 --- a/src/Display/Display.h +++ b/src/Display/Display.h @@ -11,6 +11,7 @@ #include "RotaryEncoder.h" #include "ST7920/lcd7920.h" #include "Menu.h" +#include "GCodes/GCodeResult.h" class Display { @@ -18,13 +19,21 @@ public: Display(); void Init(); + GCodeResult Configure(GCodeBuffer& gb, const StringRef& reply); void Spin(bool full); void Exit(); + void Beep(unsigned int frequency, unsigned int milliseconds); + bool IsPresent() const { return present; } + void UpdatingFirmware(); private: Lcd7920 lcd; RotaryEncoder encoder; Menu *mainMenu; + uint32_t whenBeepStarted; + uint32_t beepLength; + bool present; + bool beepActive; }; #endif /* SRC_DISPLAY_DISPLAY_H_ */ diff --git a/src/Display/RotaryEncoder.cpp b/src/Display/RotaryEncoder.cpp index a862591b..33e9d702 100644 --- a/src/Display/RotaryEncoder.cpp +++ b/src/Display/RotaryEncoder.cpp @@ -4,21 +4,25 @@ #if SUPPORT_12864_LCD #include "RotaryEncoder.h" +#include "IoPorts.h" -RotaryEncoder::RotaryEncoder(Pin p0, Pin p1, Pin pb, int pulsesPerClick) - : pin0(p0), pin1(p1), pinButton(pb), ppc(pulsesPerClick), encoderChange(0), encoderState(0), newPress(false) {} +RotaryEncoder::RotaryEncoder(Pin p0, Pin p1, Pin pb) + : pin0(p0), pin1(p1), pinButton(pb), ppc(1), encoderChange(0), encoderState(0), newPress(false), reverseDirection(false) {} inline unsigned int RotaryEncoder::ReadEncoderState() const { return (digitalRead(pin0) ? 1u : 0u) | (digitalRead(pin1) ? 2u : 0u); } -void RotaryEncoder::Init() +void RotaryEncoder::Init(int pulsesPerClick) { + ppc = max<unsigned int>(abs(pulsesPerClick), 1); + reverseDirection = (pulsesPerClick < 0); + // Set up pins - pinMode(pin0, INPUT_PULLUP); - pinMode(pin1, INPUT_PULLUP); - pinMode(pinButton, INPUT_PULLUP); + IoPort::SetPinMode(pin0, INPUT_PULLUP); + IoPort::SetPinMode(pin1, INPUT_PULLUP); + IoPort::SetPinMode(pinButton, INPUT_PULLUP); delay(2); // ensure we read the initial state correctly // Initialise encoder variables @@ -88,7 +92,7 @@ int RotaryEncoder::GetChange() r = 0; } encoderChange -= (r * ppc); - return r; + return (reverseDirection) ? -r : r; } bool RotaryEncoder::GetButtonPress() diff --git a/src/Display/RotaryEncoder.h b/src/Display/RotaryEncoder.h index 79eac3db..972e7d93 100644 --- a/src/Display/RotaryEncoder.h +++ b/src/Display/RotaryEncoder.h @@ -7,11 +7,12 @@ class RotaryEncoder { const Pin pin0, pin1, pinButton; - const int ppc; + int ppc; int encoderChange; unsigned int encoderState; bool buttonState; bool newPress; + bool reverseDirection; uint32_t whenSame; unsigned int ReadEncoderState() const; @@ -19,9 +20,9 @@ class RotaryEncoder static constexpr uint32_t DebounceMillis = 5; public: - RotaryEncoder(Pin p0, Pin p1, Pin pb, int pulsesPerClick); + RotaryEncoder(Pin p0, Pin p1, Pin pb); - void Init(); + void Init(int pulsesPerClick); void Poll(); int GetChange(); bool GetButtonPress(); diff --git a/src/Display/ST7920/lcd7920.cpp b/src/Display/ST7920/lcd7920.cpp index e5b336aa..fd9a9665 100644 --- a/src/Display/ST7920/lcd7920.cpp +++ b/src/Display/ST7920/lcd7920.cpp @@ -153,7 +153,7 @@ size_t Lcd7920::writeNative(uint16_t ch) const uint8_t bytesPerColumn = (fontHeight + 7)/8; const uint8_t bytesPerChar = (bytesPerColumn * fontWidth) + 1; const uint8_t *fontPtr = currentFont->ptr + (bytesPerChar * (ch - startChar)); - uint16_t cmask = (1 << fontHeight) - 1; + const uint16_t cmask = (1u << fontHeight) - 1; uint8_t nCols = *fontPtr++; @@ -171,10 +171,10 @@ size_t Lcd7920::writeNative(uint16_t ch) // We add a space column after a space character if we would have added one between the preceding and following characters. if (column < rightMargin) { - uint16_t thisCharColData = *fontPtr & cmask; - if (thisCharColData == 0) // for characters with deliberate space row at the start, e.g. decimal point + uint16_t thisCharColData = *reinterpret_cast<const uint16_t*>(fontPtr) & cmask; + if (thisCharColData == 0) // for characters with deliberate space column at the start, e.g. decimal point { - thisCharColData = *(fontPtr + 2) & cmask; + thisCharColData = *reinterpret_cast<const uint16_t*>(fontPtr + 2) & cmask; } const bool wantSpace = ((thisCharColData | (thisCharColData << 1)) & (lastCharColData | (lastCharColData << 1))) != 0; if (wantSpace) @@ -200,7 +200,7 @@ size_t Lcd7920::writeNative(uint16_t ch) while (nCols != 0 && column < rightMargin) { - uint16_t colData = *fontPtr; + uint16_t colData = *reinterpret_cast<const uint16_t*>(fontPtr); fontPtr += bytesPerColumn; if (colData != 0) { @@ -212,7 +212,7 @@ size_t Lcd7920::writeNative(uint16_t ch) const uint16_t setPixelVal = (textInverted) ? 0 : 1; for (uint8_t i = 0; i < fontHeight && p < (image + sizeof(image)); ++i) { - if ((colData & 1) == setPixelVal) + if ((colData & 1u) == setPixelVal) { *p |= mask1; // set pixel } @@ -240,10 +240,10 @@ void Lcd7920::SetRightMargin(uint8_t r) rightMargin = (r > numCols) ? numCols : r; } -// Clear a rectangle from the current position to the right margin (graphics mode only). The height of the rectangle is the height of the current font. +// 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() { - if (currentFont != 0) + if (currentFont != nullptr) { if (column < rightMargin) { @@ -257,11 +257,20 @@ void Lcd7920::ClearToMargin() if (endRow < nextRow) { endRow = nextRow; } if (endCol < rightMargin) { endCol = rightMargin; } } + while (column < rightMargin) { - // Add space after character - uint8_t mask = 0x80 >> (column & 7); uint8_t *p = image + ((row * (numCols/8)) + (column/8)); + uint8_t mask = 0xFF >> (column & 7); + if ((column & (~7)) < (rightMargin & (~7))) + { + column = (column & (~7)) + 8; + } + else + { + mask ^= 0xFF >> (rightMargin & 7); + column = rightMargin;; + } for (uint8_t i = 0; i < fontHeight && p < (image + sizeof(image)); ++i) { if (textInverted) @@ -274,7 +283,6 @@ void Lcd7920::ClearToMargin() } p += (numCols/8); } - ++column; } } } @@ -370,7 +378,7 @@ void Lcd7920::Circle(uint8_t x0, uint8_t y0, uint8_t radius, PixelMode mode) } } -// Draw a bitmap +// Draw a bitmap. x0 and numCols must be divisible by 8. void Lcd7920::Bitmap(uint8_t x0, uint8_t y0, uint8_t width, uint8_t height, const uint8_t data[]) { for (uint8_t r = 0; r < height && r + y0 < numRows; ++r) @@ -434,7 +442,7 @@ bool Lcd7920::FlushSome() return false; } -// Set the cursor position. We can only set alternate columns. The row addressing is rather odd. +// Set the cursor position void Lcd7920::SetCursor(uint8_t r, uint8_t c) { row = r % numRows; @@ -479,6 +487,7 @@ bool Lcd7920::ReadPixel(uint8_t x, uint8_t y) const 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) { ensureExtendedMode(); |