From b42f2bec5a6e50025735afb254aa3672d3f0144f Mon Sep 17 00:00:00 2001 From: Coscolin Date: Thu, 23 May 2024 03:19:04 +0200 Subject: [PATCH] Implement GxEPD2Out.h library to adapt menu with EPD2 displays --- CO2_Gadget_EINK.h | 21 +++++--- CO2_Gadget_Menu.h | 40 +++++++++++++-- GxEPD2Out.h | 122 ++++++++++++++++++++++++++++++++++++++++++++++ platformio.ini | 2 + 4 files changed, 175 insertions(+), 10 deletions(-) create mode 100644 GxEPD2Out.h diff --git a/CO2_Gadget_EINK.h b/CO2_Gadget_EINK.h index ded83446..5cdb2b11 100644 --- a/CO2_Gadget_EINK.h +++ b/CO2_Gadget_EINK.h @@ -40,7 +40,8 @@ const GFXfont BigFont = NotoSans_Bold46pt7b; int displayWidth = 250; int displayHeight = 122; uint16_t resetDuration = 2; -GxEPD2_BW display(GxEPD2_213_BN(EPD_CS, EPD_DC, EPD_RST, EPD_BUSY)); // DEPG0213BN https://s.click.aliexpress.com/e/_DDFb2gl +#define GxEPD2_DRIVER GxEPD2_BW +GxEPD2_DRIVER display(GxEPD2_213_BN(EPD_CS, EPD_DC, EPD_RST, EPD_BUSY)); // DEPG0213BN https://s.click.aliexpress.com/e/_DDFb2gl #endif #ifdef EINKBOARDGDEM0213B74 #include @@ -50,7 +51,8 @@ const GFXfont BigFont = NotoSans_Bold46pt7b; int displayWidth = 250; int displayHeight = 122; uint16_t resetDuration = 2; -GxEPD2_BW display(GxEPD2_213_B74(EPD_CS, EPD_DC, EPD_RST, EPD_BUSY)); // GDEM0213B74 https://s.click.aliexpress.com/e/_DDFb2gl +#define GxEPD2_DRIVER GxEPD2_BW // Ajusta esto a tu pantalla +GxEPD2_DRIVER display(GxEPD2_213_B74(EPD_CS, EPD_DC, EPD_RST, EPD_BUSY)); // GDEM0213B74 https://s.click.aliexpress.com/e/_DDFb2gl #endif #ifdef EINKBOARDGDEW0213M21 #include @@ -62,7 +64,8 @@ int displayHeight = 104; uint16_t resetDuration = 2; // GxEPD2_BW display(GxEPD2_213_flex(EPD_CS, EPD_DC, EPD_RST, EPD_BUSY)); // GxEPD2_BW display(GxEPD2_213_T5D(EPD_CS, EPD_DC, EPD_RST, EPD_BUSY)); -GxEPD2_BW display(GxEPD2_213_M21(EPD_CS, EPD_DC, EPD_RST, EPD_BUSY)); // GDEW0213M21 104x212, SSD1608 (GDEW0213Z16LW) https://s.click.aliexpress.com/e/_DDFb2gl +#define GxEPD2_DRIVER GxEPD2_BW +GxEPD2_DRIVER display(GxEPD2_213_M21(EPD_CS, EPD_DC, EPD_RST, EPD_BUSY)); // GDEW0213M21 104x212, SSD1608 (GDEW0213Z16LW) https://s.click.aliexpress.com/e/_DDFb2gl #endif #endif @@ -85,7 +88,8 @@ uint16_t resetDuration = 2; // #define EPD_DC 27 // #define EPD_RST 25 // #define EPD_BUSY 32 -GxEPD2_BW display(GxEPD2_290_T94(EPD_CS, EPD_DC, EPD_RST, EPD_BUSY)); // GDEM029T94 +#define GxEPD2_DRIVER GxEPD2_BW +GxEPD2_DRIVER display(GxEPD2_290_T94(EPD_CS, EPD_DC, EPD_RST, EPD_BUSY)); // GDEM029T94 // GxEPD2_BW display(GxEPD2_290_T94_V2(EPD_CS, EPD_DC, EPD_RST, EPD_BUSY)); // GDEM029T94 V2 GDEM029T94 128x296, SSD1680, (FPC-7519 rev.b), Waveshare 2.9" V2 variant // GxEPD2_BW display(GxEPD2_290_BS(EPD_CS, EPD_DC, EPD_RST, EPD_BUSY)); // GDEM029T94 BS // GxEPD2_BW display(GxEPD2_290_GDEY029T94(EPD_CS, EPD_DC, EPD_RST, EPD_BUSY)); // GDEY029T94 128x296, SSD1680, (FPC-A005 20.06.15) @@ -105,7 +109,8 @@ uint16_t resetDuration = 50; #include "bootlogo.h" // Made with https://javl.github.io/image2cpp/ #include "icons.h" -GxEPD2_BW display(GxEPD2_213_BN(EPD_CS, EPD_DC, EPD_RST, EPD_BUSY)); // DEPG0213BN https://s.click.aliexpress.com/e/_DDvVZ4N +#define GxEPD2_DRIVER GxEPD2_BW +GxEPD2_DRIVER display(GxEPD2_213_BN(EPD_CS, EPD_DC, EPD_RST, EPD_BUSY)); // DEPG0213BN https://s.click.aliexpress.com/e/_DDvVZ4N #endif #ifdef EINKBOARD_WEACT_GDEH0154D67 @@ -120,7 +125,8 @@ uint16_t resetDuration = 50; #include "bootlogo.h" // Made with https://javl.github.io/image2cpp/ #include "icons.h" -GxEPD2_BW display(GxEPD2_154_D67(EPD_CS, EPD_DC, EPD_RST, EPD_BUSY)); // GDEH0154D67 200x200, SSD1681 https://s.click.aliexpress.com/e/_DDvVZ4N +#define GxEPD2_DRIVER GxEPD2_BW +GxEPD2_DRIVER display(GxEPD2_154_D67(EPD_CS, EPD_DC, EPD_RST, EPD_BUSY)); // GDEH0154D67 200x200, SSD1681 https://s.click.aliexpress.com/e/_DDvVZ4N #endif #ifdef EINKBOARD_WEACT_GxEPD2_290_BS @@ -135,7 +141,8 @@ uint16_t resetDuration = 50; #include "bootlogo.h" // Made with https://javl.github.io/image2cpp/ #include "icons.h" -GxEPD2_BW display(GxEPD2_290_BS(EPD_CS, EPD_DC, EPD_RST, EPD_BUSY)); // GDEM029C90 As WeAct Studio 2.9" 296x128 E-Ink Display +#define GxEPD2_DRIVER GxEPD2_BW +GxEPD2_DRIVER display(GxEPD2_290_BS(EPD_CS, EPD_DC, EPD_RST, EPD_BUSY)); // GDEM029C90 As WeAct Studio 2.9" 296x128 E-Ink Display #endif // Define a structure for the locations of elements diff --git a/CO2_Gadget_Menu.h b/CO2_Gadget_Menu.h index 3cb7d161..01fcb968 100644 --- a/CO2_Gadget_Menu.h +++ b/CO2_Gadget_Menu.h @@ -18,6 +18,10 @@ #include #endif +#ifdef SUPPORT_EINK +#include +#endif + #ifdef SUPPORT_OLED #include #include @@ -954,7 +958,36 @@ menuOut* outputs[]{&outSerial,&oledOut};//list of output devices MENU_INPUTS(in,&serial); #endif // SUPPORT_OLED -#if (!SUPPORT_OLED && !SUPPORT_TFT) +#ifdef SUPPORT_EINK +// define menu colors -------------------------------------------------------- +const colorDef colors[6] MEMMODE = { + // {{disabled normal, disabled selected}, {enabled normal, enabled selected, enabled editing}} + {{0, 1}, {1, 0, 0}}, // bgColor + {{1, 0}, {0, 1, 1}}, // fgColor + {{1, 0}, {0, 1, 1}}, // valColor + {{1, 0}, {0, 1, 1}}, // unitColor + {{0, 1}, {0, 0, 0}}, // cursorColor + {{1, 0}, {1, 0, 0}}, // titleColor +}; + +#define fontW 10 +#define fontH 20 +#define offsetX 1 +#define offsetY -2 +#define fontMarginX 2 +#define fontMarginY 2 + +//define output device oled +idx_t gfx_tops[MAX_DEPTH]; +PANELS(gfxPanels,{0, 0, displayWidth/fontW,displayHeight/fontH}); +// Crear la instancia de salida para GxEPD2 +Menu::GxEPD2Out displayOut(display, colors, gfx_tops, gfxPanels, fontW, fontH, offsetX, offsetY, fontMarginX, fontMarginY); + +//define outputs controller +menuOut* outputs[]{&outSerial,&displayOut};//list of output devices +#endif // SUPPORT_EINK + +#if (!SUPPORT_OLED && !SUPPORT_TFT && !SUPPORT_EINK) menuOut* outputs[]{&outSerial};//No display, only serial output #endif @@ -1033,7 +1066,7 @@ result idle(menuOut &o, idleEvent e) { setInMenu(false); // nav.poll(); -#if defined(SUPPORT_TFT) || defined(SUPPORT_OLED) +#if defined(SUPPORT_TFT) || defined(SUPPORT_OLED) || defined(SUPPORT_EINK) displayShowValues(true); #endif break; @@ -1041,7 +1074,7 @@ result idle(menuOut &o, idleEvent e) { #ifdef DEBUG_ARDUINOMENU Serial.println("-->[MENU] Event iddling"); #endif -#if defined(SUPPORT_TFT) || defined(SUPPORT_OLED) +#if defined(SUPPORT_TFT) || defined(SUPPORT_OLED) || defined(SUPPORT_EINK) displayShowValues(shouldRedrawDisplay); shouldRedrawDisplay = false; #endif @@ -1113,6 +1146,7 @@ void menuLoopEINK() { } else { if (nav.changed(0)) { nav.doOutput(); + display.displayWindow(0, 0, display.width(), display.height()); // Refresh screen in partial mode } } #endif diff --git a/GxEPD2Out.h b/GxEPD2Out.h new file mode 100644 index 00000000..b66710a2 --- /dev/null +++ b/GxEPD2Out.h @@ -0,0 +1,122 @@ +/******************** +May. 2024 Sergio CoscolĂ­n https://github.com/Coscolin +with special help from ChatGPT 4o + +Based on U8GLibOut.h from Rui Azevedo - ruihfazevedo(@rrob@)gmail.com +and TFT_eSPIOut.H from https://github.com/fa1ke5 (Jan. 2019) +Original from: https://github.com/christophepersoz + +Adaptaded for GxEPD2 displays use +***/ +#ifndef RSITE_ARDUINOP_MENU_GXEPD2 +#define RSITE_ARDUINOP_MENU_GXEPD2 +#include + +#include "menuDefs.h" + +namespace Menu { + +template +class GxEPD2Out : public gfxOut { + public: + int8_t offsetX = 0; + int8_t offsetY = 0; + GxEPD2_Type& gfx; + const colorDef (&colors)[nColors]; + + GxEPD2Out( + GxEPD2_Type& gfx, + const colorDef (&c)[nColors], + idx_t* t, + panelsList& p, + idx_t resX = 6, + idx_t resY = 9, + idx_t offsetX = 0, + idx_t offsetY = 0, + int fontMarginY = 1, + int fontMarginX = 1) : gfxOut(resX, resY, t, p, (styles)(menuOut::redraw | menuOut::rasterDraw)), gfx(gfx), colors(c) { + gfx.setTextWrap(false); + this->offsetX = offsetX; + this->offsetY = offsetY; + this->fontMarginY = fontMarginY; + this->fontMarginX = fontMarginX; + } + + size_t write(uint8_t ch) override { return gfx.write(ch); } + + inline uint8_t getColor(colorDefs color = bgColor, bool selected = false, status stat = enabledStatus, bool edit = false) const { + return memByte(&(stat == enabledStatus ? colors[color].enabled[selected + edit] : colors[color].disabled[selected])); + } + + void setColor(colorDefs c, bool selected = false, status s = enabledStatus, bool edit = false) override { + if (c == titleColor) { + gfx.setTextColor(getColor(titleColor, selected, s, edit), getColor(titleColor, false, s, edit)); + } else { + gfx.setTextColor(getColor(c, selected, s, edit), getColor(bgColor, selected, s, edit)); + } + } + + void clearLine(idx_t ln, idx_t panelNr = 0, colorDefs color = bgColor, bool selected = false, status stat = enabledStatus, bool edit = false) override { + const panel p = panels[panelNr]; + setColor(color, selected, stat, edit); + gfx.fillRect(p.x * resX + offsetX, (p.y + ln) * resY + offsetY, maxX() * resX, resY, getColor(color, selected, stat, edit)); + } + + void clear() override { + setCursor(0, 0); + display.fillScreen(getColor(bgColor, false, enabledStatus, false)); + setColor(fgColor); + panels.reset(); + } + + void clear(idx_t panelNr) override { + const panel p = panels[panelNr]; + gfx.fillRect(p.x * resX + offsetX, p.y * resY + offsetY, p.w * resX, p.h * resY, getColor(bgColor, false, enabledStatus, false)); + panels.nodes[panelNr] = NULL; + } + + void box(idx_t panelNr, idx_t x, idx_t y, idx_t w = 1, idx_t h = 1, colorDefs c = bgColor, bool selected = false, status stat = enabledStatus, bool edit = false) override { + const panel p = panels[panelNr]; + gfx.drawRect((p.x + x) * resX, (p.y + y) * resY, w * resX, h * resY, getColor(c, selected, stat, edit)); + } + + void rect(idx_t panelNr, idx_t x, idx_t y, idx_t w = 1, idx_t h = 1, colorDefs c = bgColor, bool selected = false, status stat = enabledStatus, bool edit = false) override { + const panel p = panels[panelNr]; + gfx.fillRect((p.x + x) * resX, (p.y + y) * resY, w * resX, h * resY, getColor(c, selected, stat, edit)); + } + + void setCursor(idx_t x, idx_t y, idx_t panelNr = 0) override { + const panel p = panels[panelNr]; + gfx.setCursor((p.x + x) * resX + fontMarginX + offsetX, (p.y + y + 1) * resY - fontMarginY + offsetY); + } + + idx_t startCursor(navRoot& root, idx_t x, idx_t y, bool charEdit, idx_t panelNr) override { + if (charEdit) { + const panel p = panels[panelNr]; + gfx.fillRect((p.x + x) * resX + offsetX + fontMarginX, (p.y + y) * resY + offsetY, resX, resY, getColor(fgColor, false, enabledStatus, false)); + } + return 0; + } + + idx_t editCursor(navRoot& root, idx_t x, idx_t y, bool editing, bool charEdit, idx_t panelNr = 0) override { + if (editing) { + const panel p = panels[panelNr]; + _trace(Serial << "editCursor" << endl); + gfx.drawRect((x + p.x - 1) * resX + offsetX + fontMarginX - 1, (p.y + y) * resY + offsetY, resX + 1, resY, cursorColor); + } + return 0; + } + + void drawCursor(idx_t ln, bool selected, status stat, bool edit = false, idx_t panelNr = 0) override { + const panel p = panels[panelNr]; + gfx.drawRect(p.x * resX, (p.y + ln) * resY, maxX() * resX, resY, getColor(cursorColor, selected, enabledStatus, false)); + } + + idx_t printRaw(const char* at, idx_t len) override { + trace(Serial << "GxEPD2Out::printRaw" << endl); + trace(Serial << "[" << at << "]"); + return print((__FlashStringHelper*)at); + } +}; +} // namespace Menu +#endif // RSITE_ARDUINOP_MENU_GxEPD2 diff --git a/platformio.ini b/platformio.ini index 93dfe40e..94f40f37 100644 --- a/platformio.ini +++ b/platformio.ini @@ -416,6 +416,8 @@ build_flags = ${t5-board-eink_pins.build_flags} -DSUPPORT_EINK -DEINKBOARDGDEM0213B74 + -DBTN_UP=39 + -DBTN_DWN=19 -DUNITHOSTNAME="\"CO2-Gadget-GDEM0213B74"\" -DFLAVOUR="\"GDEM0213B74"\"