Compare commits
1 commit
main
...
feature/ep
Author | SHA1 | Date | |
---|---|---|---|
8906bbee10 |
2 changed files with 96 additions and 98 deletions
188
src/lib/epd.cpp
188
src/lib/epd.cpp
|
@ -69,26 +69,7 @@ EPDManager::EPDManager()
|
|||
, fontSatsymbol{nullptr}
|
||||
, bgColor{GxEPD_BLACK}
|
||||
, fgColor{GxEPD_WHITE}
|
||||
, displays{
|
||||
#ifdef IS_BTCLOCK_V8
|
||||
EPD_CLASS(&EPD_CS[0], &EPD_DC, &EPD_RESET[0], &EPD_BUSY[0]),
|
||||
EPD_CLASS(&EPD_CS[1], &EPD_DC, &EPD_RESET[1], &EPD_BUSY[1]),
|
||||
EPD_CLASS(&EPD_CS[2], &EPD_DC, &EPD_RESET[2], &EPD_BUSY[2]),
|
||||
EPD_CLASS(&EPD_CS[3], &EPD_DC, &EPD_RESET[3], &EPD_BUSY[3]),
|
||||
EPD_CLASS(&EPD_CS[4], &EPD_DC, &EPD_RESET[4], &EPD_BUSY[4]),
|
||||
EPD_CLASS(&EPD_CS[5], &EPD_DC, &EPD_RESET[5], &EPD_BUSY[5]),
|
||||
EPD_CLASS(&EPD_CS[6], &EPD_DC, &EPD_RESET[6], &EPD_BUSY[6]),
|
||||
EPD_CLASS(&EPD_CS[7], &EPD_DC, &EPD_RESET[7], &EPD_BUSY[7])
|
||||
#else
|
||||
EPD_CLASS(&EPD_CS[0], &EPD_DC, &EPD_RESET[0], &EPD_BUSY[0]),
|
||||
EPD_CLASS(&EPD_CS[1], &EPD_DC, &EPD_RESET[1], &EPD_BUSY[1]),
|
||||
EPD_CLASS(&EPD_CS[2], &EPD_DC, &EPD_RESET[2], &EPD_BUSY[2]),
|
||||
EPD_CLASS(&EPD_CS[3], &EPD_DC, &EPD_RESET[3], &EPD_BUSY[3]),
|
||||
EPD_CLASS(&EPD_CS[4], &EPD_DC, &EPD_RESET[4], &EPD_BUSY[4]),
|
||||
EPD_CLASS(&EPD_CS[5], &EPD_DC, &EPD_RESET[5], &EPD_BUSY[5]),
|
||||
EPD_CLASS(&EPD_CS[6], &EPD_DC, &EPD_RESET[6], &EPD_BUSY[6])
|
||||
#endif
|
||||
}
|
||||
, display{EPD_CLASS(&EPD_CS[0], &EPD_DC, &EPD_RESET[0], &EPD_BUSY[0])}
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -119,11 +100,10 @@ void EPDManager::initialize() {
|
|||
String fontName = preferences.getString("fontName", DEFAULT_FONT_NAME);
|
||||
loadFonts(fontName);
|
||||
|
||||
// Initialize displays
|
||||
// Initialize first display
|
||||
switchToDisplay(0);
|
||||
std::lock_guard<std::mutex> lockMcp(mcpMutex);
|
||||
for (auto& display : displays) {
|
||||
display.init(0, true, 30);
|
||||
}
|
||||
display.init(0, true, 30);
|
||||
|
||||
// Create update queue and task
|
||||
updateQueue = xQueueCreate(UPDATE_QUEUE_SIZE, sizeof(UpdateDisplayTaskItem));
|
||||
|
@ -228,46 +208,48 @@ void EPDManager::waitUntilNoneBusy() {
|
|||
}
|
||||
|
||||
void EPDManager::setupDisplay(uint dispNum, const GFXfont* font) {
|
||||
displays[dispNum].setRotation(2);
|
||||
displays[dispNum].setFont(font);
|
||||
displays[dispNum].setTextColor(fgColor);
|
||||
displays[dispNum].fillScreen(bgColor);
|
||||
switchToDisplay(dispNum);
|
||||
display.setRotation(2);
|
||||
display.setFont(font);
|
||||
display.setTextColor(fgColor);
|
||||
display.fillScreen(bgColor);
|
||||
}
|
||||
|
||||
void EPDManager::splitText(uint dispNum, const String& top, const String& bottom, bool partial) {
|
||||
switchToDisplay(dispNum);
|
||||
if (preferences.getBool("verticalDesc", DEFAULT_VERTICAL_DESC) && dispNum == 0) {
|
||||
displays[dispNum].setRotation(1);
|
||||
display.setRotation(1);
|
||||
} else {
|
||||
displays[dispNum].setRotation(2);
|
||||
display.setRotation(2);
|
||||
}
|
||||
displays[dispNum].setFont(fontSmall);
|
||||
displays[dispNum].setTextColor(fgColor);
|
||||
display.setFont(fontSmall);
|
||||
display.setTextColor(fgColor);
|
||||
|
||||
// Top text
|
||||
int16_t ttbx, ttby;
|
||||
uint16_t ttbw, ttbh;
|
||||
displays[dispNum].getTextBounds(top, 0, 0, &ttbx, &ttby, &ttbw, &ttbh);
|
||||
uint16_t tx = ((displays[dispNum].width() - ttbw) / 2) - ttbx;
|
||||
uint16_t ty = ((displays[dispNum].height() - ttbh) / 2) - ttby - ttbh / 2 - 12;
|
||||
display.getTextBounds(top, 0, 0, &ttbx, &ttby, &ttbw, &ttbh);
|
||||
uint16_t tx = ((display.width() - ttbw) / 2) - ttbx;
|
||||
uint16_t ty = ((display.height() - ttbh) / 2) - ttby - ttbh / 2 - 12;
|
||||
|
||||
// Bottom text
|
||||
int16_t tbbx, tbby;
|
||||
uint16_t tbbw, tbbh;
|
||||
displays[dispNum].getTextBounds(bottom, 0, 0, &tbbx, &tbby, &tbbw, &tbbh);
|
||||
uint16_t bx = ((displays[dispNum].width() - tbbw) / 2) - tbbx;
|
||||
uint16_t by = ((displays[dispNum].height() - tbbh) / 2) - tbby + tbbh / 2 + 12;
|
||||
display.getTextBounds(bottom, 0, 0, &tbbx, &tbby, &tbbw, &tbbh);
|
||||
uint16_t bx = ((display.width() - tbbw) / 2) - tbbx;
|
||||
uint16_t by = ((display.height() - tbbh) / 2) - tbby + tbbh / 2 + 12;
|
||||
|
||||
// Make separator as wide as the shortest text
|
||||
uint16_t lineWidth = (tbbw < ttbh) ? tbbw : ttbw;
|
||||
uint16_t lineX = round((displays[dispNum].width() - lineWidth) / 2);
|
||||
uint16_t lineX = round((display.width() - lineWidth) / 2);
|
||||
|
||||
displays[dispNum].fillScreen(bgColor);
|
||||
displays[dispNum].setCursor(tx, ty);
|
||||
displays[dispNum].print(top);
|
||||
displays[dispNum].fillRoundRect(lineX, displays[dispNum].height() / 2 - 3,
|
||||
lineWidth, 6, 3, fgColor);
|
||||
displays[dispNum].setCursor(bx, by);
|
||||
displays[dispNum].print(bottom);
|
||||
display.fillScreen(bgColor);
|
||||
display.setCursor(tx, ty);
|
||||
display.print(top);
|
||||
display.fillRoundRect(lineX, display.height() / 2 - 3,
|
||||
lineWidth, 6, 3, fgColor);
|
||||
display.setCursor(bx, by);
|
||||
display.print(bottom);
|
||||
}
|
||||
|
||||
void EPDManager::showDigit(uint dispNum, char chr, bool partial, const GFXfont* font) {
|
||||
|
@ -280,17 +262,17 @@ void EPDManager::showDigit(uint dispNum, char chr, bool partial, const GFXfont*
|
|||
|
||||
int16_t tbx, tby;
|
||||
uint16_t tbw, tbh;
|
||||
displays[dispNum].getTextBounds(str, 0, 0, &tbx, &tby, &tbw, &tbh);
|
||||
display.getTextBounds(str, 0, 0, &tbx, &tby, &tbw, &tbh);
|
||||
|
||||
uint16_t x = ((displays[dispNum].width() - tbw) / 2) - tbx;
|
||||
uint16_t y = ((displays[dispNum].height() - tbh) / 2) - tby;
|
||||
uint16_t x = ((display.width() - tbw) / 2) - tbx;
|
||||
uint16_t y = ((display.height() - tbh) / 2) - tby;
|
||||
|
||||
displays[dispNum].setCursor(x, y);
|
||||
displays[dispNum].print(str);
|
||||
display.setCursor(x, y);
|
||||
display.print(str);
|
||||
|
||||
if (chr == '.') {
|
||||
displays[dispNum].fillRect(0, 0, displays[dispNum].width(),
|
||||
round(displays[dispNum].height() * 0.67), bgColor);
|
||||
display.fillRect(0, 0, display.width(),
|
||||
round(display.height() * 0.67), bgColor);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -299,11 +281,11 @@ void EPDManager::showChars(uint dispNum, const String& chars, bool partial, cons
|
|||
|
||||
int16_t tbx, tby;
|
||||
uint16_t tbw, tbh;
|
||||
displays[dispNum].getTextBounds(chars, 0, 0, &tbx, &tby, &tbw, &tbh);
|
||||
display.getTextBounds(chars, 0, 0, &tbx, &tby, &tbw, &tbh);
|
||||
|
||||
// Center the bounding box by transposition of the origin
|
||||
uint16_t x = ((displays[dispNum].width() - tbw) / 2) - tbx;
|
||||
uint16_t y = ((displays[dispNum].height() - tbh) / 2) - tby;
|
||||
uint16_t x = ((display.width() - tbw) / 2) - tbx;
|
||||
uint16_t y = ((display.height() - tbh) / 2) - tby;
|
||||
|
||||
for (size_t i = 0; i < chars.length(); i++) {
|
||||
char c = chars[i];
|
||||
|
@ -313,12 +295,12 @@ void EPDManager::showChars(uint dispNum, const String& chars, bool partial, cons
|
|||
int16_t dotDescent = dotGlyph->yOffset;
|
||||
|
||||
// Draw the dot with adjusted y-position
|
||||
displays[dispNum].setCursor(x, y + dotDescent + dotGlyph->height + 8);
|
||||
displays[dispNum].print(c);
|
||||
display.setCursor(x, y + dotDescent + dotGlyph->height + 8);
|
||||
display.print(c);
|
||||
} else {
|
||||
// For other characters, use the original y-position
|
||||
displays[dispNum].setCursor(x, y);
|
||||
displays[dispNum].print(c);
|
||||
display.setCursor(x, y);
|
||||
display.print(c);
|
||||
}
|
||||
|
||||
// Move x-position for the next character
|
||||
|
@ -327,11 +309,12 @@ void EPDManager::showChars(uint dispNum, const String& chars, bool partial, cons
|
|||
}
|
||||
|
||||
bool EPDManager::renderIcon(uint dispNum, const String& text, bool partial) {
|
||||
displays[dispNum].setRotation(2);
|
||||
displays[dispNum].setPartialWindow(0, 0, displays[dispNum].width(),
|
||||
displays[dispNum].height());
|
||||
displays[dispNum].fillScreen(bgColor);
|
||||
displays[dispNum].setTextColor(fgColor);
|
||||
switchToDisplay(dispNum);
|
||||
display.setRotation(2);
|
||||
display.setPartialWindow(0, 0, display.width(),
|
||||
display.height());
|
||||
display.fillScreen(bgColor);
|
||||
display.setTextColor(fgColor);
|
||||
|
||||
uint iconIndex = 0;
|
||||
uint width = 122;
|
||||
|
@ -352,27 +335,28 @@ bool EPDManager::renderIcon(uint dispNum, const String& text, bool partial) {
|
|||
return false;
|
||||
}
|
||||
|
||||
int x_offset = (displays[dispNum].width() - logo.width) / 2;
|
||||
int y_offset = (displays[dispNum].height() - logo.height) / 2;
|
||||
displays[dispNum].drawInvertedBitmap(x_offset, y_offset, logo.data,
|
||||
logo.width, logo.height, fgColor);
|
||||
int x_offset = (display.width() - logo.width) / 2;
|
||||
int y_offset = (display.height() - logo.height) / 2;
|
||||
display.drawInvertedBitmap(x_offset, y_offset, logo.data,
|
||||
logo.width, logo.height, fgColor);
|
||||
return true;
|
||||
}
|
||||
|
||||
int x_offset = (displays[dispNum].width() - width) / 2;
|
||||
int y_offset = (displays[dispNum].height() - height) / 2;
|
||||
displays[dispNum].drawInvertedBitmap(x_offset, y_offset, epd_icons_allArray[iconIndex],
|
||||
width, height, fgColor);
|
||||
int x_offset = (display.width() - width) / 2;
|
||||
int y_offset = (display.height() - height) / 2;
|
||||
display.drawInvertedBitmap(x_offset, y_offset, epd_icons_allArray[iconIndex],
|
||||
width, height, fgColor);
|
||||
return true;
|
||||
}
|
||||
|
||||
void EPDManager::renderText(uint dispNum, const String& text, bool partial) {
|
||||
displays[dispNum].setRotation(2);
|
||||
displays[dispNum].setPartialWindow(0, 0, displays[dispNum].width(),
|
||||
displays[dispNum].height());
|
||||
displays[dispNum].fillScreen(GxEPD_WHITE);
|
||||
displays[dispNum].setTextColor(GxEPD_BLACK);
|
||||
displays[dispNum].setCursor(0, 50);
|
||||
switchToDisplay(dispNum);
|
||||
display.setRotation(2);
|
||||
display.setPartialWindow(0, 0, display.width(),
|
||||
display.height());
|
||||
display.fillScreen(GxEPD_WHITE);
|
||||
display.setTextColor(GxEPD_BLACK);
|
||||
display.setCursor(0, 50);
|
||||
|
||||
std::stringstream ss;
|
||||
ss.str(text.c_str());
|
||||
|
@ -381,16 +365,17 @@ void EPDManager::renderText(uint dispNum, const String& text, bool partial) {
|
|||
while (std::getline(ss, line, '\n')) {
|
||||
if (line.rfind("*", 0) == 0) {
|
||||
line.erase(std::remove(line.begin(), line.end(), '*'), line.end());
|
||||
displays[dispNum].setFont(&FreeSansBold9pt7b);
|
||||
display.setFont(&FreeSansBold9pt7b);
|
||||
} else {
|
||||
displays[dispNum].setFont(&FreeSans9pt7b);
|
||||
display.setFont(&FreeSans9pt7b);
|
||||
}
|
||||
displays[dispNum].println(line.c_str());
|
||||
display.println(line.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
void EPDManager::renderQr(uint dispNum, const String& text, bool partial) {
|
||||
#ifdef USE_QR
|
||||
switchToDisplay(dispNum);
|
||||
// Dynamically allocate QR buffer
|
||||
uint8_t* qrcode = (uint8_t*)malloc(qrcodegen_BUFFER_LEN_MAX);
|
||||
if (!qrcode) {
|
||||
|
@ -405,17 +390,17 @@ void EPDManager::renderQr(uint dispNum, const String& text, bool partial) {
|
|||
|
||||
if (ok) {
|
||||
const int size = qrcodegen_getSize(qrcode);
|
||||
const int padding = floor(float(displays[dispNum].width() - (size * 4)) / 2);
|
||||
const int paddingY = floor(float(displays[dispNum].height() - (size * 4)) / 2);
|
||||
const int padding = floor(float(display.width() - (size * 4)) / 2);
|
||||
const int paddingY = floor(float(display.height() - (size * 4)) / 2);
|
||||
|
||||
displays[dispNum].setRotation(2);
|
||||
displays[dispNum].setPartialWindow(0, 0, displays[dispNum].width(),
|
||||
displays[dispNum].height());
|
||||
displays[dispNum].fillScreen(GxEPD_WHITE);
|
||||
display.setRotation(2);
|
||||
display.setPartialWindow(0, 0, display.width(),
|
||||
display.height());
|
||||
display.fillScreen(GxEPD_WHITE);
|
||||
|
||||
for (int y = 0; y < size * 4; y++) {
|
||||
for (int x = 0; x < size * 4; x++) {
|
||||
displays[dispNum].drawPixel(
|
||||
display.drawPixel(
|
||||
padding + x, paddingY + y,
|
||||
qrcodegen_getModule(qrcode, floor(float(x) / 4), floor(float(y) / 4))
|
||||
? GxEPD_BLACK
|
||||
|
@ -449,10 +434,10 @@ void EPDManager::updateDisplayTask(void* pvParameters) noexcept {
|
|||
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
|
||||
|
||||
std::lock_guard<std::mutex> lock(instance.displayMutexes[epdIndex]);
|
||||
{
|
||||
std::lock_guard<std::mutex> lockMcp(mcpMutex);
|
||||
instance.displays[epdIndex].init(0, false, 40);
|
||||
}
|
||||
|
||||
std::lock_guard<std::mutex> lockMcp(mcpMutex);
|
||||
instance.initializeDisplay(epdIndex);
|
||||
|
||||
|
||||
uint32_t count = 0;
|
||||
while (instance.EPD_BUSY[epdIndex].digitalRead() == HIGH || count < 10) {
|
||||
|
@ -469,8 +454,8 @@ void EPDManager::updateDisplayTask(void* pvParameters) noexcept {
|
|||
|
||||
char tries = 0;
|
||||
while (tries < 3) {
|
||||
if (instance.displays[epdIndex].displayWithReturn(updatePartial)) {
|
||||
instance.displays[epdIndex].powerOff();
|
||||
if (instance.display.displayWithReturn(updatePartial)) {
|
||||
instance.display.powerOff();
|
||||
instance.currentContent[epdIndex] = instance.content[epdIndex];
|
||||
if (!updatePartial) {
|
||||
instance.lastFullRefresh[epdIndex] = millis();
|
||||
|
@ -534,4 +519,15 @@ void EPDManager::prepareDisplayUpdateTask(void* pvParameters) {
|
|||
xTaskNotifyGive(instance.tasks[epdIndex]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void EPDManager::switchToDisplay(uint dispNum) {
|
||||
display.setCSPin(&EPD_CS[dispNum]);
|
||||
display.setRSTPin(&EPD_RESET[dispNum]);
|
||||
display.setBusyPin(&EPD_BUSY[dispNum]);
|
||||
}
|
||||
|
||||
void EPDManager::initializeDisplay(uint dispNum) {
|
||||
switchToDisplay(dispNum);
|
||||
display.init(0, false, 40);
|
||||
}
|
||||
|
|
|
@ -80,6 +80,8 @@ private:
|
|||
|
||||
static void updateDisplayTask(void* pvParameters) noexcept;
|
||||
static void prepareDisplayUpdateTask(void* pvParameters);
|
||||
void switchToDisplay(uint dispNum);
|
||||
void initializeDisplay(uint dispNum);
|
||||
|
||||
// Member variables
|
||||
std::array<String, NUM_SCREENS> currentContent;
|
||||
|
@ -119,8 +121,8 @@ private:
|
|||
static std::array<MCP23X17_Pin, NUM_SCREENS> EPD_RESET;
|
||||
#endif
|
||||
|
||||
// Display array
|
||||
std::array<GxEPD2_BW<EPD_CLASS, EPD_CLASS::HEIGHT>, NUM_SCREENS> displays;
|
||||
// Single display instance
|
||||
GxEPD2_BW<EPD_CLASS, EPD_CLASS::HEIGHT> display;
|
||||
|
||||
static constexpr size_t UPDATE_QUEUE_SIZE = 14;
|
||||
static constexpr uint32_t BUSY_TIMEOUT_COUNT = 200;
|
||||
|
|
Loading…
Add table
Reference in a new issue