MeshCore/src/helpers/ui/GxEPDDisplay.cpp

180 lines
4.8 KiB
C++
Raw Normal View History

2025-04-15 22:37:50 +02:00
#include "GxEPDDisplay.h"
2025-11-28 10:33:19 +01:00
#ifdef EXP_PIN_BACKLIGHT
#include <PCA9557.h>
extern PCA9557 expander;
#endif
2025-04-29 17:32:08 +02:00
#ifndef DISPLAY_ROTATION
#define DISPLAY_ROTATION 3
#endif
2025-11-27 21:49:04 +01:00
#ifdef ESP32
SPIClass SPI1 = SPIClass(FSPI);
#endif
2025-04-15 22:37:50 +02:00
bool GxEPDDisplay::begin() {
display.epd2.selectSPI(SPI1, SPISettings(4000000, MSBFIRST, SPI_MODE0));
2025-11-27 21:49:04 +01:00
#ifdef ESP32
SPI1.begin(PIN_DISPLAY_SCLK, PIN_DISPLAY_MISO, PIN_DISPLAY_MOSI, PIN_DISPLAY_CS);
#else
2025-04-15 22:37:50 +02:00
SPI1.begin();
2025-11-27 21:49:04 +01:00
#endif
2025-04-15 22:37:50 +02:00
display.init(115200, true, 2, false);
2025-04-29 17:32:08 +02:00
display.setRotation(DISPLAY_ROTATION);
2025-05-31 15:22:59 -07:00
setTextSize(1); // Default to size 1
2025-04-15 22:37:50 +02:00
display.setPartialWindow(0, 0, display.width(), display.height());
display.fillScreen(GxEPD_WHITE);
2025-04-20 16:44:30 +02:00
display.display(true);
2025-04-20 17:10:57 +02:00
#if DISP_BACKLIGHT
2025-09-02 11:43:48 +02:00
digitalWrite(DISP_BACKLIGHT, LOW);
2025-04-20 17:10:57 +02:00
pinMode(DISP_BACKLIGHT, OUTPUT);
#endif
2025-04-15 22:37:50 +02:00
_init = true;
return true;
}
void GxEPDDisplay::turnOn() {
if (!_init) begin();
2025-09-03 17:22:11 +02:00
#if defined(DISP_BACKLIGHT) && !defined(BACKLIGHT_BTN)
2025-04-20 17:10:57 +02:00
digitalWrite(DISP_BACKLIGHT, HIGH);
2025-11-28 10:33:19 +01:00
#elif defined(EXP_PIN_BACKLIGHT) && !defined(BACKLIGHT_BTN)
expander.digitalWrite(EXP_PIN_BACKLIGHT, HIGH);
2025-04-20 17:10:57 +02:00
#endif
2025-08-16 18:13:50 +02:00
_isOn = true;
2025-04-15 22:37:50 +02:00
}
void GxEPDDisplay::turnOff() {
2025-09-02 11:43:48 +02:00
#if defined(DISP_BACKLIGHT) && !defined(BACKLIGHT_BTN)
2025-04-20 17:10:57 +02:00
digitalWrite(DISP_BACKLIGHT, LOW);
2025-11-28 10:33:19 +01:00
#elif defined(EXP_PIN_BACKLIGHT) && !defined(BACKLIGHT_BTN)
expander.digitalWrite(EXP_PIN_BACKLIGHT, LOW);
2025-04-20 17:10:57 +02:00
#endif
_isOn = false;
2025-04-15 22:37:50 +02:00
}
void GxEPDDisplay::clear() {
display.fillScreen(GxEPD_WHITE);
display.setTextColor(GxEPD_BLACK);
2025-09-03 18:17:37 +02:00
display_crc.reset();
2025-04-15 22:37:50 +02:00
}
void GxEPDDisplay::startFrame(Color bkg) {
display.fillScreen(GxEPD_WHITE);
2025-08-08 20:01:31 +10:00
display.setTextColor(_curr_color = GxEPD_BLACK);
2025-09-03 18:17:37 +02:00
display_crc.reset();
2025-04-15 22:37:50 +02:00
}
void GxEPDDisplay::setTextSize(int sz) {
2025-09-03 18:17:37 +02:00
display_crc.update<int>(sz);
2025-05-31 15:22:59 -07:00
switch(sz) {
case 1: // Small
display.setFont(&FreeSans9pt7b);
break;
case 2: // Medium Bold
display.setFont(&FreeSansBold12pt7b);
break;
case 3: // Large
display.setFont(&FreeSans18pt7b);
break;
default:
display.setFont(&FreeSans9pt7b);
break;
}
2025-04-15 22:37:50 +02:00
}
void GxEPDDisplay::setColor(Color c) {
2025-09-03 18:17:37 +02:00
display_crc.update<Color> (c);
// colours need to be inverted for epaper displays
2025-08-08 20:01:31 +10:00
if (c == DARK) {
display.setTextColor(_curr_color = GxEPD_WHITE);
} else {
display.setTextColor(_curr_color = GxEPD_BLACK);
2025-08-08 20:01:31 +10:00
}
2025-04-15 22:37:50 +02:00
}
void GxEPDDisplay::setCursor(int x, int y) {
2025-09-03 18:17:37 +02:00
display_crc.update<int>(x);
display_crc.update<int>(y);
2025-09-02 13:56:24 +08:00
display.setCursor((x+offset_x)*scale_x, (y+offset_y)*scale_y);
2025-04-15 22:37:50 +02:00
}
void GxEPDDisplay::print(const char* str) {
2025-09-03 18:17:37 +02:00
display_crc.update<char>(str, strlen(str));
2025-04-15 22:37:50 +02:00
display.print(str);
}
void GxEPDDisplay::fillRect(int x, int y, int w, int h) {
2025-09-03 18:17:37 +02:00
display_crc.update<int>(x);
display_crc.update<int>(y);
display_crc.update<int>(w);
display_crc.update<int>(h);
display.fillRect(x*scale_x, y*scale_y, w*scale_x, h*scale_y, _curr_color);
2025-04-15 22:37:50 +02:00
}
void GxEPDDisplay::drawRect(int x, int y, int w, int h) {
2025-09-03 18:17:37 +02:00
display_crc.update<int>(x);
display_crc.update<int>(y);
display_crc.update<int>(w);
display_crc.update<int>(h);
display.drawRect(x*scale_x, y*scale_y, w*scale_x, h*scale_y, _curr_color);
2025-04-15 22:37:50 +02:00
}
void GxEPDDisplay::drawXbm(int x, int y, const uint8_t* bits, int w, int h) {
2025-09-03 18:17:37 +02:00
display_crc.update<int>(x);
display_crc.update<int>(y);
display_crc.update<int>(w);
display_crc.update<int>(h);
display_crc.update<uint8_t>(bits, w * h / 8);
// Calculate the base position in display coordinates
2025-09-02 13:56:24 +08:00
uint16_t startX = x * scale_x;
uint16_t startY = y * scale_y;
// Width in bytes for bitmap processing
uint16_t widthInBytes = (w + 7) / 8;
// Process the bitmap row by row
for (uint16_t by = 0; by < h; by++) {
// Calculate the target y-coordinates for this logical row
2025-09-02 13:56:24 +08:00
int y1 = startY + (int)(by * scale_y);
int y2 = startY + (int)((by + 1) * scale_y);
int block_h = y2 - y1;
// Scan across the row bit by bit
for (uint16_t bx = 0; bx < w; bx++) {
// Calculate the target x-coordinates for this logical column
2025-09-02 13:56:24 +08:00
int x1 = startX + (int)(bx * scale_x);
int x2 = startX + (int)((bx + 1) * scale_x);
int block_w = x2 - x1;
// Get the current bit
uint16_t byteOffset = (by * widthInBytes) + (bx / 8);
uint8_t bitMask = 0x80 >> (bx & 7);
bool bitSet = pgm_read_byte(bits + byteOffset) & bitMask;
// If the bit is set, draw a block of pixels
if (bitSet) {
// Draw the block as a filled rectangle
2025-08-08 20:01:31 +10:00
display.fillRect(x1, y1, block_w, block_h, _curr_color);
}
}
}
2025-04-15 22:37:50 +02:00
}
uint16_t GxEPDDisplay::getTextWidth(const char* str) {
int16_t x1, y1;
uint16_t w, h;
display.getTextBounds(str, 0, 0, &x1, &y1, &w, &h);
2025-09-02 13:56:24 +08:00
return ceil((w + 1) / scale_x);
}
2025-04-15 22:37:50 +02:00
void GxEPDDisplay::endFrame() {
2025-09-03 18:17:37 +02:00
uint32_t crc = display_crc.finalize();
if (crc != last_display_crc_value) {
display.display(true);
last_display_crc_value = crc;
}
2025-04-15 22:37:50 +02:00
}