2023-11-07 00:11:12 +00:00
|
|
|
#include "epd.hpp"
|
|
|
|
|
|
|
|
Native_Pin EPD_CS[NUM_SCREENS] = {
|
|
|
|
Native_Pin(2),
|
|
|
|
Native_Pin(4),
|
|
|
|
Native_Pin(6),
|
|
|
|
Native_Pin(10),
|
|
|
|
Native_Pin(33),
|
|
|
|
Native_Pin(21),
|
|
|
|
Native_Pin(17),
|
|
|
|
#if NUM_SCREENS == 9
|
|
|
|
// MCP23X17_Pin(mcp2, 7),
|
|
|
|
Native_Pin(-1),
|
|
|
|
Native_Pin(-1),
|
|
|
|
#endif
|
|
|
|
};
|
|
|
|
Native_Pin EPD_BUSY[NUM_SCREENS] = {
|
|
|
|
Native_Pin(3),
|
|
|
|
Native_Pin(5),
|
|
|
|
Native_Pin(7),
|
|
|
|
Native_Pin(9),
|
|
|
|
Native_Pin(37),
|
|
|
|
Native_Pin(18),
|
|
|
|
Native_Pin(16),
|
|
|
|
};
|
|
|
|
MCP23X17_Pin EPD_RESET_MPD[NUM_SCREENS] = {
|
|
|
|
MCP23X17_Pin(mcp, 8),
|
|
|
|
MCP23X17_Pin(mcp, 9),
|
|
|
|
MCP23X17_Pin(mcp, 10),
|
|
|
|
MCP23X17_Pin(mcp, 11),
|
|
|
|
MCP23X17_Pin(mcp, 12),
|
|
|
|
MCP23X17_Pin(mcp, 13),
|
|
|
|
MCP23X17_Pin(mcp, 14),
|
|
|
|
};
|
|
|
|
|
|
|
|
Native_Pin EPD_DC = Native_Pin(14);
|
|
|
|
|
|
|
|
GxEPD2_BW<GxEPD2_213_B74, GxEPD2_213_B74::HEIGHT> displays[NUM_SCREENS] = {
|
|
|
|
GxEPD2_213_B74(&EPD_CS[0], &EPD_DC, &EPD_RESET_MPD[0], &EPD_BUSY[0]),
|
|
|
|
GxEPD2_213_B74(&EPD_CS[1], &EPD_DC, &EPD_RESET_MPD[1], &EPD_BUSY[1]),
|
|
|
|
GxEPD2_213_B74(&EPD_CS[2], &EPD_DC, &EPD_RESET_MPD[2], &EPD_BUSY[2]),
|
|
|
|
GxEPD2_213_B74(&EPD_CS[3], &EPD_DC, &EPD_RESET_MPD[3], &EPD_BUSY[3]),
|
|
|
|
GxEPD2_213_B74(&EPD_CS[4], &EPD_DC, &EPD_RESET_MPD[4], &EPD_BUSY[4]),
|
|
|
|
GxEPD2_213_B74(&EPD_CS[5], &EPD_DC, &EPD_RESET_MPD[5], &EPD_BUSY[5]),
|
|
|
|
GxEPD2_213_B74(&EPD_CS[6], &EPD_DC, &EPD_RESET_MPD[6], &EPD_BUSY[6]),
|
|
|
|
#if NUM_SCREENS == 9
|
|
|
|
GxEPD2_213_B74(&EPD8_CS, &EPD_DC, &EPD_RESET_MPD[7], &EPD8_BUSY),
|
|
|
|
GxEPD2_213_B74(&EPD9_CS, &EPD_DC, &EPD_RESET_MPD[8], &EPD9_BUSY),
|
|
|
|
#endif
|
|
|
|
};
|
|
|
|
|
|
|
|
std::array<String, NUM_SCREENS> currentEpdContent;
|
|
|
|
std::array<String, NUM_SCREENS> epdContent;
|
|
|
|
uint32_t lastFullRefresh[NUM_SCREENS];
|
|
|
|
TaskHandle_t tasks[NUM_SCREENS];
|
2023-11-12 11:38:28 +00:00
|
|
|
// TaskHandle_t epdTaskHandle = NULL;
|
|
|
|
|
|
|
|
#define UPDATE_QUEUE_SIZE 14
|
|
|
|
QueueHandle_t updateQueue;
|
2023-11-08 19:29:06 +00:00
|
|
|
|
2023-11-13 15:37:48 +00:00
|
|
|
// SemaphoreHandle_t epdUpdateSemaphore[NUM_SCREENS];
|
2023-11-07 00:11:12 +00:00
|
|
|
|
|
|
|
int fgColor = GxEPD_WHITE;
|
|
|
|
int bgColor = GxEPD_BLACK;
|
|
|
|
|
|
|
|
#define FONT_SMALL Antonio_SemiBold20pt7b
|
|
|
|
#define FONT_BIG Antonio_SemiBold90pt7b
|
|
|
|
|
2023-11-13 11:27:34 +00:00
|
|
|
std::mutex epdUpdateMutex;
|
2023-11-13 16:51:10 +00:00
|
|
|
std::mutex epdMutex[NUM_SCREENS];
|
2023-11-13 11:27:34 +00:00
|
|
|
|
2023-11-10 12:02:05 +00:00
|
|
|
uint8_t qrcode[800];
|
|
|
|
|
2023-11-12 23:33:48 +00:00
|
|
|
void forceFullRefresh()
|
|
|
|
{
|
|
|
|
for (uint i = 0; i < NUM_SCREENS; i++)
|
|
|
|
{
|
|
|
|
lastFullRefresh[i] = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-11-13 16:33:09 +00:00
|
|
|
void refreshFromMemory()
|
|
|
|
{
|
|
|
|
for (uint i = 0; i < NUM_SCREENS; i++)
|
|
|
|
{
|
|
|
|
int *taskParam = new int;
|
|
|
|
*taskParam = i;
|
|
|
|
|
|
|
|
xTaskCreate([](void *pvParameters)
|
|
|
|
{
|
|
|
|
const int epdIndex = *(int *)pvParameters;
|
|
|
|
delete (int *)pvParameters;
|
|
|
|
displays[epdIndex].refresh(false);
|
|
|
|
vTaskDelete(NULL); },
|
|
|
|
"PrepareUpd", 4096, taskParam, tskIDLE_PRIORITY, NULL);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-11-07 00:11:12 +00:00
|
|
|
void setupDisplays()
|
|
|
|
{
|
|
|
|
for (uint i = 0; i < NUM_SCREENS; i++)
|
|
|
|
{
|
2023-11-13 16:33:09 +00:00
|
|
|
displays[i].init(0, true, 30);
|
2023-11-07 00:11:12 +00:00
|
|
|
}
|
|
|
|
|
2023-11-12 11:38:28 +00:00
|
|
|
updateQueue = xQueueCreate(UPDATE_QUEUE_SIZE, sizeof(UpdateDisplayTaskItem));
|
|
|
|
|
2023-11-12 23:33:48 +00:00
|
|
|
xTaskCreate(prepareDisplayUpdateTask, "PrepareUpd", 4096, NULL, 11, NULL);
|
2023-11-12 11:38:28 +00:00
|
|
|
|
2023-11-07 00:11:12 +00:00
|
|
|
for (uint i = 0; i < NUM_SCREENS; i++)
|
|
|
|
{
|
2023-11-13 11:27:34 +00:00
|
|
|
// epdUpdateSemaphore[i] = xSemaphoreCreateBinary();
|
|
|
|
// xSemaphoreGive(epdUpdateSemaphore[i]);
|
2023-11-07 00:11:12 +00:00
|
|
|
|
|
|
|
int *taskParam = new int;
|
|
|
|
*taskParam = i;
|
2023-11-13 15:37:48 +00:00
|
|
|
|
2023-11-12 23:33:48 +00:00
|
|
|
xTaskCreate(updateDisplay, ("EpdUpd" + String(i)).c_str(), 2048, taskParam, 11, &tasks[i]); // create task
|
2023-11-07 00:11:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
epdContent = {"B",
|
|
|
|
"T",
|
|
|
|
"C",
|
|
|
|
"L",
|
|
|
|
"O",
|
|
|
|
"C",
|
|
|
|
"K"};
|
|
|
|
|
2023-11-08 19:29:06 +00:00
|
|
|
setEpdContent(epdContent);
|
2023-11-12 11:38:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void setEpdContent(std::array<String, NUM_SCREENS> newEpdContent)
|
|
|
|
{
|
2023-11-12 23:33:48 +00:00
|
|
|
setEpdContent(newEpdContent, false);
|
|
|
|
}
|
2023-11-12 11:38:28 +00:00
|
|
|
|
2023-11-12 23:33:48 +00:00
|
|
|
void setEpdContent(std::array<String, NUM_SCREENS> newEpdContent, bool forceUpdate)
|
|
|
|
{
|
2023-11-13 11:27:34 +00:00
|
|
|
std::lock_guard<std::mutex> lock(epdUpdateMutex);
|
|
|
|
|
2023-11-13 16:14:11 +00:00
|
|
|
waitUntilNoneBusy();
|
|
|
|
|
2023-11-10 12:02:05 +00:00
|
|
|
for (uint i = 0; i < NUM_SCREENS; i++)
|
|
|
|
{
|
2023-11-12 23:33:48 +00:00
|
|
|
if (newEpdContent[i].compareTo(currentEpdContent[i]) != 0 || forceUpdate)
|
2023-11-12 11:38:28 +00:00
|
|
|
{
|
2023-11-12 23:33:48 +00:00
|
|
|
epdContent[i] = newEpdContent[i];
|
2023-11-12 11:38:28 +00:00
|
|
|
UpdateDisplayTaskItem dispUpdate = {i};
|
|
|
|
xQueueSend(updateQueue, &dispUpdate, portMAX_DELAY);
|
|
|
|
}
|
2023-11-10 12:02:05 +00:00
|
|
|
}
|
2023-11-07 00:11:12 +00:00
|
|
|
}
|
|
|
|
|
2023-11-12 11:38:28 +00:00
|
|
|
void prepareDisplayUpdateTask(void *pvParameters)
|
2023-11-07 00:11:12 +00:00
|
|
|
{
|
2023-11-12 11:38:28 +00:00
|
|
|
UpdateDisplayTaskItem receivedItem;
|
|
|
|
|
2023-11-07 00:11:12 +00:00
|
|
|
while (1)
|
|
|
|
{
|
2023-11-12 11:38:28 +00:00
|
|
|
// Wait for a work item to be available in the queue
|
|
|
|
if (xQueueReceive(updateQueue, &receivedItem, portMAX_DELAY))
|
|
|
|
{
|
|
|
|
uint epdIndex = receivedItem.dispNum;
|
2023-11-13 16:51:10 +00:00
|
|
|
std::lock_guard<std::mutex> lock(epdMutex[epdIndex]);
|
2023-11-13 16:33:09 +00:00
|
|
|
// displays[epdIndex].init(0, false); // Little longer reset duration because of MCP
|
2023-11-07 00:11:12 +00:00
|
|
|
|
2023-11-12 11:38:28 +00:00
|
|
|
bool updatePartial = true;
|
|
|
|
|
|
|
|
if (strstr(epdContent[epdIndex].c_str(), "/") != NULL)
|
|
|
|
{
|
|
|
|
String top = epdContent[epdIndex].substring(0, epdContent[epdIndex].indexOf("/"));
|
|
|
|
String bottom = epdContent[epdIndex].substring(epdContent[epdIndex].indexOf("/") + 1);
|
|
|
|
splitText(epdIndex, top, bottom, updatePartial);
|
|
|
|
}
|
|
|
|
else if (epdContent[epdIndex].startsWith(F("qr")))
|
|
|
|
{
|
|
|
|
renderQr(epdIndex, epdContent[epdIndex], updatePartial);
|
|
|
|
}
|
|
|
|
else if (epdContent[epdIndex].length() > 5)
|
|
|
|
{
|
|
|
|
renderText(epdIndex, epdContent[epdIndex], updatePartial);
|
|
|
|
}
|
|
|
|
else
|
2023-11-07 00:11:12 +00:00
|
|
|
{
|
|
|
|
|
2023-11-12 11:38:28 +00:00
|
|
|
if (epdContent[epdIndex].length() > 1)
|
2023-11-07 00:11:12 +00:00
|
|
|
{
|
2023-11-12 11:38:28 +00:00
|
|
|
showChars(epdIndex, epdContent[epdIndex], updatePartial, &Antonio_SemiBold30pt7b);
|
2023-11-07 00:11:12 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2023-11-12 11:38:28 +00:00
|
|
|
showDigit(epdIndex, epdContent[epdIndex].c_str()[0], updatePartial, &FONT_BIG);
|
2023-11-07 00:11:12 +00:00
|
|
|
}
|
|
|
|
}
|
2023-11-12 11:38:28 +00:00
|
|
|
|
2023-11-12 23:33:48 +00:00
|
|
|
xTaskNotifyGive(tasks[epdIndex]);
|
2023-11-07 00:11:12 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
extern "C" void updateDisplay(void *pvParameters) noexcept
|
|
|
|
{
|
|
|
|
const int epdIndex = *(int *)pvParameters;
|
|
|
|
delete (int *)pvParameters;
|
|
|
|
|
|
|
|
for (;;)
|
|
|
|
{
|
|
|
|
// Wait for the task notification
|
|
|
|
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
|
|
|
|
|
2023-11-13 16:51:10 +00:00
|
|
|
std::lock_guard<std::mutex> lock(epdMutex[epdIndex]);
|
|
|
|
|
2023-11-13 15:37:48 +00:00
|
|
|
uint count = 0;
|
|
|
|
while (EPD_BUSY[epdIndex].digitalRead() == HIGH || count < 10)
|
|
|
|
{
|
|
|
|
vTaskDelay(pdMS_TO_TICKS(100));
|
|
|
|
count++;
|
|
|
|
}
|
2023-11-07 00:11:12 +00:00
|
|
|
|
2023-11-13 15:37:48 +00:00
|
|
|
bool updatePartial = true;
|
2023-11-07 00:11:12 +00:00
|
|
|
|
2023-11-13 15:37:48 +00:00
|
|
|
// Full Refresh every x minutes
|
|
|
|
if (!lastFullRefresh[epdIndex] || (millis() - lastFullRefresh[epdIndex]) > (preferences.getUInt("fullRefreshMin", 30) * 60 * 1000))
|
|
|
|
{
|
|
|
|
updatePartial = false;
|
|
|
|
}
|
2023-11-08 19:29:06 +00:00
|
|
|
|
2023-11-13 15:37:48 +00:00
|
|
|
char tries = 0;
|
|
|
|
while (tries < 3)
|
|
|
|
{
|
|
|
|
if (displays[epdIndex].displayWithReturn(updatePartial))
|
2023-11-08 23:15:04 +00:00
|
|
|
{
|
2023-11-13 15:37:48 +00:00
|
|
|
displays[epdIndex].powerOff();
|
|
|
|
currentEpdContent[epdIndex] = epdContent[epdIndex];
|
|
|
|
if (!updatePartial)
|
|
|
|
lastFullRefresh[epdIndex] = millis();
|
2023-11-13 11:27:34 +00:00
|
|
|
|
2023-11-13 15:37:48 +00:00
|
|
|
if (eventSourceTaskHandle != NULL)
|
|
|
|
xTaskNotifyGive(eventSourceTaskHandle);
|
2023-11-13 11:27:34 +00:00
|
|
|
|
2023-11-13 15:37:48 +00:00
|
|
|
break;
|
2023-11-08 23:15:04 +00:00
|
|
|
}
|
2023-11-13 15:37:48 +00:00
|
|
|
|
|
|
|
vTaskDelay(pdMS_TO_TICKS(100));
|
|
|
|
tries++;
|
|
|
|
}
|
2023-11-07 00:11:12 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-11-10 12:02:05 +00:00
|
|
|
void splitText(const uint dispNum, const String &top, const String &bottom, bool partial)
|
2023-11-07 00:11:12 +00:00
|
|
|
{
|
|
|
|
displays[dispNum].setRotation(2);
|
|
|
|
displays[dispNum].setFont(&FONT_SMALL);
|
|
|
|
displays[dispNum].setTextColor(getFgColor());
|
|
|
|
|
|
|
|
// 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;
|
|
|
|
|
|
|
|
// 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;
|
|
|
|
|
|
|
|
// Make separator as wide as the shortest text.
|
|
|
|
uint16_t lineWidth, lineX;
|
|
|
|
if (tbbw < ttbh)
|
|
|
|
lineWidth = tbbw;
|
|
|
|
else
|
|
|
|
lineWidth = ttbw;
|
|
|
|
lineX = round((displays[dispNum].width() - lineWidth) / 2);
|
|
|
|
|
|
|
|
displays[dispNum].fillScreen(getBgColor());
|
|
|
|
displays[dispNum].setCursor(tx, ty);
|
|
|
|
displays[dispNum].print(top);
|
|
|
|
displays[dispNum].fillRoundRect(lineX, displays[dispNum].height() / 2 - 3, lineWidth, 6, 3, getFgColor());
|
|
|
|
displays[dispNum].setCursor(bx, by);
|
|
|
|
displays[dispNum].print(bottom);
|
|
|
|
}
|
|
|
|
|
|
|
|
void showDigit(const uint dispNum, char chr, bool partial, const GFXfont *font)
|
|
|
|
{
|
|
|
|
String str(chr);
|
|
|
|
displays[dispNum].setRotation(2);
|
|
|
|
displays[dispNum].setFont(font);
|
|
|
|
displays[dispNum].setTextColor(getFgColor());
|
|
|
|
int16_t tbx, tby;
|
|
|
|
uint16_t tbw, tbh;
|
|
|
|
displays[dispNum].getTextBounds(str, 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;
|
|
|
|
displays[dispNum].fillScreen(getBgColor());
|
|
|
|
displays[dispNum].setCursor(x, y);
|
|
|
|
displays[dispNum].print(str);
|
|
|
|
}
|
|
|
|
|
2023-11-12 11:38:28 +00:00
|
|
|
void showChars(const uint dispNum, const String &chars, bool partial, const GFXfont *font)
|
|
|
|
{
|
2023-11-10 18:52:06 +00:00
|
|
|
displays[dispNum].setRotation(2);
|
|
|
|
displays[dispNum].setFont(font);
|
|
|
|
displays[dispNum].setTextColor(getFgColor());
|
|
|
|
int16_t tbx, tby;
|
|
|
|
uint16_t tbw, tbh;
|
|
|
|
displays[dispNum].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;
|
|
|
|
displays[dispNum].fillScreen(getBgColor());
|
|
|
|
displays[dispNum].setCursor(x, y);
|
|
|
|
displays[dispNum].print(chars);
|
|
|
|
}
|
|
|
|
|
2023-11-07 00:11:12 +00:00
|
|
|
int getBgColor()
|
|
|
|
{
|
|
|
|
return bgColor;
|
|
|
|
}
|
|
|
|
|
|
|
|
int getFgColor()
|
|
|
|
{
|
|
|
|
return fgColor;
|
|
|
|
}
|
|
|
|
|
|
|
|
void setBgColor(int color)
|
|
|
|
{
|
|
|
|
bgColor = color;
|
|
|
|
}
|
|
|
|
|
|
|
|
void setFgColor(int color)
|
|
|
|
{
|
|
|
|
fgColor = color;
|
|
|
|
}
|
2023-11-07 20:26:15 +00:00
|
|
|
|
|
|
|
std::array<String, NUM_SCREENS> getCurrentEpdContent()
|
|
|
|
{
|
|
|
|
return currentEpdContent;
|
|
|
|
}
|
2023-11-10 12:02:05 +00:00
|
|
|
void renderText(const 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);
|
|
|
|
|
|
|
|
std::stringstream ss;
|
|
|
|
ss.str(text.c_str());
|
|
|
|
|
|
|
|
std::string line;
|
|
|
|
|
|
|
|
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);
|
|
|
|
displays[dispNum].println(line.c_str());
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
displays[dispNum].setFont(&FreeSans9pt7b);
|
|
|
|
displays[dispNum].println(line.c_str());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void renderQr(const uint dispNum, const String &text, bool partial)
|
|
|
|
{
|
2023-11-12 11:38:28 +00:00
|
|
|
#ifdef USE_QR
|
2023-11-10 18:52:06 +00:00
|
|
|
|
2023-11-10 12:02:05 +00:00
|
|
|
uint8_t tempBuffer[800];
|
|
|
|
bool ok = qrcodegen_encodeText(text.substring(2).c_str(), tempBuffer, qrcode, qrcodegen_Ecc_LOW,
|
|
|
|
qrcodegen_VERSION_MIN, qrcodegen_VERSION_MAX, qrcodegen_Mask_AUTO, true);
|
|
|
|
|
|
|
|
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);
|
|
|
|
displays[dispNum].setRotation(2);
|
|
|
|
|
|
|
|
displays[dispNum].setPartialWindow(0, 0, displays[dispNum].width(), displays[dispNum].height());
|
|
|
|
displays[dispNum].fillScreen(GxEPD_WHITE);
|
|
|
|
const int border = 0;
|
|
|
|
|
|
|
|
for (int y = -border; y < size * 4 + border; y++)
|
|
|
|
{
|
|
|
|
for (int x = -border; x < size * 4 + border; x++)
|
|
|
|
{
|
|
|
|
displays[dispNum].drawPixel(padding + x, paddingY + y, qrcodegen_getModule(qrcode, floor(float(x) / 4), floor(float(y) / 4)) ? GxEPD_BLACK : GxEPD_WHITE);
|
|
|
|
}
|
|
|
|
}
|
2023-11-12 11:38:28 +00:00
|
|
|
#endif
|
2023-11-10 12:02:05 +00:00
|
|
|
}
|
2023-11-10 18:52:06 +00:00
|
|
|
|
2023-11-12 11:38:28 +00:00
|
|
|
void waitUntilNoneBusy()
|
|
|
|
{
|
|
|
|
for (int i = 0; i < NUM_SCREENS; i++)
|
|
|
|
{
|
2023-11-12 23:33:48 +00:00
|
|
|
uint count = 0;
|
2023-11-12 11:38:28 +00:00
|
|
|
while (EPD_BUSY[i].digitalRead())
|
|
|
|
{
|
2023-11-12 23:33:48 +00:00
|
|
|
count++;
|
2023-11-10 18:52:06 +00:00
|
|
|
vTaskDelay(10);
|
2023-11-13 15:37:48 +00:00
|
|
|
if (count == 200)
|
|
|
|
{
|
2023-11-13 16:33:09 +00:00
|
|
|
// displays[i].init(0, false);
|
2023-11-13 11:27:34 +00:00
|
|
|
vTaskDelay(100);
|
2023-11-13 15:37:48 +00:00
|
|
|
}
|
|
|
|
else if (count > 205)
|
|
|
|
{
|
2023-11-13 16:51:10 +00:00
|
|
|
Serial.printf("Busy timeout %d", i);
|
2023-11-13 11:27:34 +00:00
|
|
|
break;
|
2023-11-12 23:33:48 +00:00
|
|
|
}
|
2023-11-10 18:52:06 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|