Refactor EPD code to EPDManager class
This commit is contained in:
parent
d023643090
commit
a6a8b5a071
11 changed files with 532 additions and 638 deletions
|
@ -181,20 +181,19 @@ void onWebsocketBlockMessage(esp_websocket_event_data_t *event_data)
|
|||
}
|
||||
|
||||
void processNewBlock(uint32_t newBlockHeight) {
|
||||
if (newBlockHeight < currentBlockHeight)
|
||||
if (currentBlockHeight == newBlockHeight)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
currentBlockHeight = newBlockHeight;
|
||||
|
||||
// Serial.printf("New block found: %d\r\n", block["height"].as<uint>());
|
||||
preferences.putUInt("blockHeight", currentBlockHeight);
|
||||
lastBlockUpdate = esp_timer_get_time() / 1000000;
|
||||
|
||||
if (workQueue != nullptr)
|
||||
{
|
||||
WorkItem blockUpdate = {TASK_BLOCK_UPDATE, 0};
|
||||
xQueueSend(workQueue, &blockUpdate, portMAX_DELAY);
|
||||
// xTaskNotifyGive(blockUpdateTaskHandle);
|
||||
}
|
||||
|
||||
if (ScreenHandler::getCurrentScreen() != SCREEN_BLOCK_HEIGHT &&
|
||||
preferences.getBool("stealFocus", DEFAULT_STEAL_FOCUS))
|
||||
|
@ -202,7 +201,6 @@ void processNewBlock(uint32_t newBlockHeight) {
|
|||
uint64_t timerPeriod = 0;
|
||||
if (isTimerActive())
|
||||
{
|
||||
// store timer periode before making inactive to prevent artifacts
|
||||
timerPeriod = getTimerSeconds();
|
||||
esp_timer_stop(screenRotateTimer);
|
||||
}
|
||||
|
@ -221,7 +219,6 @@ void processNewBlock(uint32_t newBlockHeight) {
|
|||
getLedHandler().queueEffect(LED_FLASH_BLOCK_NOTIFY);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void processNewBlockFee(uint16_t newBlockFee) {
|
||||
if (blockMedianFee == newBlockFee)
|
||||
|
|
|
@ -48,7 +48,7 @@ void setup()
|
|||
setupPreferences();
|
||||
setupHardware();
|
||||
|
||||
setupDisplays();
|
||||
EPDManager::getInstance().initialize();
|
||||
if (preferences.getBool("ledTestOnPower", DEFAULT_LED_TEST_ON_POWER))
|
||||
{
|
||||
auto& ledHandler = getLedHandler();
|
||||
|
@ -115,7 +115,7 @@ void setup()
|
|||
ButtonHandler::setup();
|
||||
setupOTA();
|
||||
|
||||
waitUntilNoneBusy();
|
||||
EPDManager::getInstance().waitUntilNoneBusy();
|
||||
|
||||
#ifdef HAS_FRONTLIGHT
|
||||
if (!preferences.getBool("flAlwaysOn", DEFAULT_FL_ALWAYS_ON))
|
||||
|
@ -126,7 +126,7 @@ void setup()
|
|||
}
|
||||
#endif
|
||||
|
||||
forceFullRefresh();
|
||||
EPDManager::getInstance().forceFullRefresh();
|
||||
}
|
||||
|
||||
void setupWifi()
|
||||
|
@ -181,8 +181,8 @@ void setupWifi()
|
|||
wifiManager->getConfigPortalSSID().c_str(),
|
||||
softAP_password.c_str());
|
||||
// delay(6000);
|
||||
setFgColor(GxEPD_BLACK);
|
||||
setBgColor(GxEPD_WHITE);
|
||||
EPDManager::getInstance().setForegroundColor(GxEPD_BLACK);
|
||||
EPDManager::getInstance().setBackgroundColor(GxEPD_WHITE);
|
||||
const String qrText = "qrWIFI:S:" + wifiManager->getConfigPortalSSID() +
|
||||
";T:WPA;P:" + softAP_password.c_str() + ";;";
|
||||
const String explainText = "*SSID: *\r\n" +
|
||||
|
@ -212,58 +212,22 @@ void setupWifi()
|
|||
#endif
|
||||
"\r\n\r\n*FW build date:*\r\n" + formattedDate,
|
||||
qrText};
|
||||
setEpdContent(epdContent); });
|
||||
|
||||
EPDManager::getInstance().setContent(epdContent); });
|
||||
|
||||
wm.setSaveConfigCallback([]()
|
||||
{
|
||||
preferences.putBool("wifiConfigured", true);
|
||||
|
||||
delay(1000);
|
||||
// just restart after succes
|
||||
// just restart after success
|
||||
ESP.restart(); });
|
||||
|
||||
bool ac = wm.autoConnect(softAP_SSID.c_str(), softAP_password.c_str());
|
||||
|
||||
// waitUntilNoneBusy();
|
||||
// std::array<String, NUM_SCREENS> epdContent = {"Welcome!",
|
||||
// "Bienvenidos!", "Use\r\nweb-interface\r\npara configurar", "Use\r\nla
|
||||
// interfaz web\r\npara configurar", "Or
|
||||
// restart\r\nwhile\r\nholding\r\n2nd button\r\r\nto start\r\n QR-config",
|
||||
// "O reinicie\r\nmientras\r\n mantiene presionado\r\nel segundo
|
||||
// botón\r\r\npara iniciar\r\nQR-config", ""}; setEpdContent(epdContent);
|
||||
// esp_task_wdt_init(30, false);
|
||||
// uint count = 0;
|
||||
// while (WiFi.status() != WL_CONNECTED)
|
||||
// {
|
||||
// if (Serial.available() > 0)
|
||||
// {
|
||||
// uint8_t b = Serial.read();
|
||||
|
||||
// if (parse_improv_serial_byte(x_position, b, x_buffer,
|
||||
// onImprovCommandCallback, onImprovErrorCallback))
|
||||
// {
|
||||
// x_buffer[x_position++] = b;
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// x_position = 0;
|
||||
// }
|
||||
// }
|
||||
// count++;
|
||||
|
||||
// if (count > 2000000) {
|
||||
// queueLedEffect(LED_EFFECT_HEARTBEAT);
|
||||
// count = 0;
|
||||
// }
|
||||
// }
|
||||
// esp_task_wdt_deinit();
|
||||
// esp_task_wdt_reset();
|
||||
}
|
||||
|
||||
|
||||
|
||||
setFgColor(preferences.getUInt("fgColor", isWhiteVersion() ? GxEPD_BLACK : GxEPD_WHITE));
|
||||
setBgColor(preferences.getUInt("bgColor", isWhiteVersion() ? GxEPD_WHITE : GxEPD_BLACK));
|
||||
EPDManager::getInstance().setForegroundColor(preferences.getUInt("fgColor", isWhiteVersion() ? GxEPD_BLACK : GxEPD_WHITE));
|
||||
EPDManager::getInstance().setBackgroundColor(preferences.getUInt("bgColor", isWhiteVersion() ? GxEPD_WHITE : GxEPD_BLACK));
|
||||
}
|
||||
// else
|
||||
// {
|
||||
|
@ -299,8 +263,8 @@ void setupPreferences()
|
|||
{
|
||||
preferences.begin("btclock", false);
|
||||
|
||||
setFgColor(preferences.getUInt("fgColor", DEFAULT_FG_COLOR));
|
||||
setBgColor(preferences.getUInt("bgColor", DEFAULT_BG_COLOR));
|
||||
EPDManager::getInstance().setForegroundColor(preferences.getUInt("fgColor", DEFAULT_FG_COLOR));
|
||||
EPDManager::getInstance().setBackgroundColor(preferences.getUInt("bgColor", DEFAULT_BG_COLOR));
|
||||
setBlockHeight(preferences.getUInt("blockHeight", INITIAL_BLOCK_HEIGHT));
|
||||
setPrice(preferences.getUInt("lastPrice", INITIAL_LAST_PRICE), CURRENCY_USD);
|
||||
|
||||
|
|
795
src/lib/epd.cpp
795
src/lib/epd.cpp
|
@ -1,213 +1,146 @@
|
|||
#include "epd.hpp"
|
||||
|
||||
// Initialize static members
|
||||
#ifdef IS_BTCLOCK_REV_B
|
||||
Native_Pin EPD_CS[NUM_SCREENS] = {
|
||||
Native_Pin(2),
|
||||
Native_Pin(4),
|
||||
Native_Pin(6),
|
||||
Native_Pin(10),
|
||||
Native_Pin(38),
|
||||
Native_Pin(21),
|
||||
Native_Pin(17),
|
||||
Native_Pin EPDManager::EPD_DC(14);
|
||||
std::array<Native_Pin, NUM_SCREENS> EPDManager::EPD_CS = {
|
||||
Native_Pin(2), Native_Pin(4), Native_Pin(6), Native_Pin(10),
|
||||
Native_Pin(38), Native_Pin(21), Native_Pin(17)
|
||||
};
|
||||
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),
|
||||
std::array<Native_Pin, NUM_SCREENS> EPDManager::EPD_BUSY = {
|
||||
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(mcp1, 8),
|
||||
MCP23X17_Pin(mcp1, 9),
|
||||
MCP23X17_Pin(mcp1, 10),
|
||||
MCP23X17_Pin(mcp1, 11),
|
||||
MCP23X17_Pin(mcp1, 12),
|
||||
MCP23X17_Pin(mcp1, 13),
|
||||
MCP23X17_Pin(mcp1, 14),
|
||||
std::array<MCP23X17_Pin, NUM_SCREENS> EPDManager::EPD_RESET = {
|
||||
MCP23X17_Pin(mcp1, 8), MCP23X17_Pin(mcp1, 9), MCP23X17_Pin(mcp1, 10),
|
||||
MCP23X17_Pin(mcp1, 11), MCP23X17_Pin(mcp1, 12), MCP23X17_Pin(mcp1, 13),
|
||||
MCP23X17_Pin(mcp1, 14)
|
||||
};
|
||||
|
||||
Native_Pin EPD_DC = Native_Pin(14);
|
||||
#elif IS_BTCLOCK_V8
|
||||
Native_Pin EPD_DC = Native_Pin(38);
|
||||
|
||||
MCP23X17_Pin EPD_BUSY[NUM_SCREENS] = {
|
||||
MCP23X17_Pin(mcp1, 8),
|
||||
MCP23X17_Pin(mcp1, 9),
|
||||
MCP23X17_Pin(mcp1, 10),
|
||||
MCP23X17_Pin(mcp1, 11),
|
||||
MCP23X17_Pin(mcp1, 12),
|
||||
MCP23X17_Pin(mcp1, 13),
|
||||
MCP23X17_Pin(mcp1, 14),
|
||||
MCP23X17_Pin(mcp1, 4),
|
||||
#elif defined(IS_BTCLOCK_V8)
|
||||
Native_Pin EPDManager::EPD_DC(38);
|
||||
std::array<MCP23X17_Pin, NUM_SCREENS> EPDManager::EPD_BUSY = {
|
||||
MCP23X17_Pin(mcp1, 8), MCP23X17_Pin(mcp1, 9), MCP23X17_Pin(mcp1, 10),
|
||||
MCP23X17_Pin(mcp1, 11), MCP23X17_Pin(mcp1, 12), MCP23X17_Pin(mcp1, 13),
|
||||
MCP23X17_Pin(mcp1, 14), MCP23X17_Pin(mcp1, 4)
|
||||
};
|
||||
|
||||
MCP23X17_Pin EPD_CS[NUM_SCREENS] = {
|
||||
std::array<MCP23X17_Pin, NUM_SCREENS> EPDManager::EPD_CS = {
|
||||
MCP23X17_Pin(mcp2, 8), MCP23X17_Pin(mcp2, 10), MCP23X17_Pin(mcp2, 12),
|
||||
MCP23X17_Pin(mcp2, 14), MCP23X17_Pin(mcp2, 0), MCP23X17_Pin(mcp2, 2),
|
||||
MCP23X17_Pin(mcp2, 4), MCP23X17_Pin(mcp2, 6)};
|
||||
|
||||
MCP23X17_Pin EPD_RESET_MPD[NUM_SCREENS] = {
|
||||
MCP23X17_Pin(mcp2, 9),
|
||||
MCP23X17_Pin(mcp2, 11),
|
||||
MCP23X17_Pin(mcp2, 13),
|
||||
MCP23X17_Pin(mcp2, 15),
|
||||
MCP23X17_Pin(mcp2, 1),
|
||||
MCP23X17_Pin(mcp2, 3),
|
||||
MCP23X17_Pin(mcp2, 5),
|
||||
MCP23X17_Pin(mcp2, 7),
|
||||
MCP23X17_Pin(mcp2, 4), MCP23X17_Pin(mcp2, 6)
|
||||
};
|
||||
std::array<MCP23X17_Pin, NUM_SCREENS> EPDManager::EPD_RESET = {
|
||||
MCP23X17_Pin(mcp2, 9), MCP23X17_Pin(mcp2, 11), MCP23X17_Pin(mcp2, 13),
|
||||
MCP23X17_Pin(mcp2, 15), MCP23X17_Pin(mcp2, 1), MCP23X17_Pin(mcp2, 3),
|
||||
MCP23X17_Pin(mcp2, 5), MCP23X17_Pin(mcp2, 7)
|
||||
};
|
||||
#else
|
||||
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 EPDManager::EPD_DC(14);
|
||||
std::array<Native_Pin, NUM_SCREENS> EPDManager::EPD_CS = {
|
||||
Native_Pin(2), Native_Pin(4), Native_Pin(6), Native_Pin(10),
|
||||
Native_Pin(33), Native_Pin(21), Native_Pin(17)
|
||||
};
|
||||
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),
|
||||
std::array<Native_Pin, NUM_SCREENS> EPDManager::EPD_BUSY = {
|
||||
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(mcp1, 8),
|
||||
MCP23X17_Pin(mcp1, 9),
|
||||
MCP23X17_Pin(mcp1, 10),
|
||||
MCP23X17_Pin(mcp1, 11),
|
||||
MCP23X17_Pin(mcp1, 12),
|
||||
MCP23X17_Pin(mcp1, 13),
|
||||
MCP23X17_Pin(mcp1, 14),
|
||||
std::array<MCP23X17_Pin, NUM_SCREENS> EPDManager::EPD_RESET = {
|
||||
MCP23X17_Pin(mcp1, 8), MCP23X17_Pin(mcp1, 9), MCP23X17_Pin(mcp1, 10),
|
||||
MCP23X17_Pin(mcp1, 11), MCP23X17_Pin(mcp1, 12), MCP23X17_Pin(mcp1, 13),
|
||||
MCP23X17_Pin(mcp1, 14)
|
||||
};
|
||||
|
||||
Native_Pin EPD_DC = Native_Pin(14);
|
||||
#endif
|
||||
|
||||
GxEPD2_BW<EPD_CLASS, EPD_CLASS::HEIGHT> displays[NUM_SCREENS] = {
|
||||
EPD_CLASS(&EPD_CS[0], &EPD_DC, &EPD_RESET_MPD[0], &EPD_BUSY[0]),
|
||||
EPD_CLASS(&EPD_CS[1], &EPD_DC, &EPD_RESET_MPD[1], &EPD_BUSY[1]),
|
||||
EPD_CLASS(&EPD_CS[2], &EPD_DC, &EPD_RESET_MPD[2], &EPD_BUSY[2]),
|
||||
EPD_CLASS(&EPD_CS[3], &EPD_DC, &EPD_RESET_MPD[3], &EPD_BUSY[3]),
|
||||
EPD_CLASS(&EPD_CS[4], &EPD_DC, &EPD_RESET_MPD[4], &EPD_BUSY[4]),
|
||||
EPD_CLASS(&EPD_CS[5], &EPD_DC, &EPD_RESET_MPD[5], &EPD_BUSY[5]),
|
||||
EPD_CLASS(&EPD_CS[6], &EPD_DC, &EPD_RESET_MPD[6], &EPD_BUSY[6]),
|
||||
EPDManager& EPDManager::getInstance() {
|
||||
static EPDManager instance;
|
||||
return instance;
|
||||
}
|
||||
|
||||
EPDManager::EPDManager()
|
||||
: currentContent{}
|
||||
, content{}
|
||||
, lastFullRefresh{}
|
||||
, tasks{}
|
||||
, updateQueue{nullptr}
|
||||
, antonioFonts{nullptr, nullptr, nullptr}
|
||||
, oswaldFonts{nullptr, nullptr, nullptr}
|
||||
, fontSmall{nullptr}
|
||||
, fontBig{nullptr}
|
||||
, fontMedium{nullptr}
|
||||
, fontSatsymbol{nullptr}
|
||||
, bgColor{GxEPD_BLACK}
|
||||
, fgColor{GxEPD_WHITE}
|
||||
, displays{
|
||||
#ifdef IS_BTCLOCK_V8
|
||||
EPD_CLASS(&EPD_CS[7], &EPD_DC, &EPD_RESET_MPD[7], &EPD_BUSY[7]),
|
||||
#endif
|
||||
};
|
||||
|
||||
std::array<String, NUM_SCREENS> currentEpdContent;
|
||||
std::array<String, NUM_SCREENS> epdContent;
|
||||
uint32_t lastFullRefresh[NUM_SCREENS];
|
||||
TaskHandle_t tasks[NUM_SCREENS];
|
||||
// TaskHandle_t epdTaskHandle = NULL;
|
||||
|
||||
#define UPDATE_QUEUE_SIZE 14
|
||||
QueueHandle_t updateQueue;
|
||||
|
||||
// SemaphoreHandle_t epdUpdateSemaphore[NUM_SCREENS];
|
||||
|
||||
int fgColor = GxEPD_WHITE;
|
||||
int bgColor = GxEPD_BLACK;
|
||||
|
||||
struct FontFamily {
|
||||
GFXfont* big;
|
||||
GFXfont* medium;
|
||||
GFXfont* small;
|
||||
};
|
||||
|
||||
FontFamily antonioFonts = {nullptr, nullptr, nullptr};
|
||||
FontFamily oswaldFonts = {nullptr, nullptr, nullptr};
|
||||
|
||||
const GFXfont *FONT_SMALL;
|
||||
const GFXfont *FONT_BIG;
|
||||
const GFXfont *FONT_MEDIUM;
|
||||
const GFXfont *FONT_SATSYMBOL;
|
||||
|
||||
std::mutex epdUpdateMutex;
|
||||
std::mutex epdMutex[NUM_SCREENS];
|
||||
|
||||
#ifdef IS_BTCLOCK_V8
|
||||
#define EPD_TASK_STACK_SIZE 4096
|
||||
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
|
||||
#define EPD_TASK_STACK_SIZE 2048
|
||||
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
|
||||
|
||||
#define BUSY_TIMEOUT_COUNT 200
|
||||
#define BUSY_RETRY_DELAY pdMS_TO_TICKS(10)
|
||||
|
||||
void forceFullRefresh()
|
||||
}
|
||||
{
|
||||
for (uint i = 0; i < NUM_SCREENS; i++)
|
||||
{
|
||||
lastFullRefresh[i] = NULL;
|
||||
}
|
||||
|
||||
EPDManager::~EPDManager() {
|
||||
// Clean up tasks
|
||||
for (auto& task : tasks) {
|
||||
if (task != nullptr) {
|
||||
vTaskDelete(task);
|
||||
}
|
||||
}
|
||||
|
||||
void loadFonts(const String& fontName) {
|
||||
if (fontName == FontNames::ANTONIO) {
|
||||
// Load Antonio fonts
|
||||
antonioFonts.big = FontLoader::loadCompressedFont(Antonio_SemiBold90pt7b_Properties);
|
||||
antonioFonts.medium = FontLoader::loadCompressedFont(Antonio_SemiBold40pt7b_Properties);
|
||||
antonioFonts.small = FontLoader::loadCompressedFont(Antonio_SemiBold20pt7b_Properties);
|
||||
|
||||
FONT_BIG = antonioFonts.big;
|
||||
FONT_MEDIUM = antonioFonts.medium;
|
||||
FONT_SMALL = antonioFonts.small;
|
||||
} else if (fontName == FontNames::OSWALD) {
|
||||
// Load Oswald fonts
|
||||
oswaldFonts.big = FontLoader::loadCompressedFont(Oswald_Medium80pt7b_Properties);
|
||||
oswaldFonts.medium = FontLoader::loadCompressedFont(Oswald_Medium30pt7b_Properties);
|
||||
oswaldFonts.small = FontLoader::loadCompressedFont(Oswald_Medium20pt7b_Properties);
|
||||
|
||||
FONT_BIG = oswaldFonts.big;
|
||||
FONT_MEDIUM = oswaldFonts.medium;
|
||||
FONT_SMALL = oswaldFonts.small;
|
||||
// Clean up queue
|
||||
if (updateQueue != nullptr) {
|
||||
vQueueDelete(updateQueue);
|
||||
}
|
||||
|
||||
FONT_SATSYMBOL = FontLoader::loadCompressedFont(Satoshi_Symbol90pt7b_Properties);
|
||||
// Clean up fonts
|
||||
delete antonioFonts.big;
|
||||
delete antonioFonts.medium;
|
||||
delete antonioFonts.small;
|
||||
delete oswaldFonts.big;
|
||||
delete oswaldFonts.medium;
|
||||
delete oswaldFonts.small;
|
||||
}
|
||||
|
||||
void setupDisplays() {
|
||||
void EPDManager::initialize() {
|
||||
// Load fonts based on preference
|
||||
String fontName = preferences.getString("fontName", DEFAULT_FONT_NAME);
|
||||
loadFonts(fontName);
|
||||
|
||||
// Initialize displays
|
||||
std::lock_guard<std::mutex> lockMcp(mcpMutex);
|
||||
for (uint i = 0; i < NUM_SCREENS; i++) {
|
||||
displays[i].init(0, true, 30);
|
||||
for (auto& display : displays) {
|
||||
display.init(0, true, 30);
|
||||
}
|
||||
|
||||
// Create update queue and task
|
||||
updateQueue = xQueueCreate(UPDATE_QUEUE_SIZE, sizeof(UpdateDisplayTaskItem));
|
||||
xTaskCreate(prepareDisplayUpdateTask, "PrepareUpd", EPD_TASK_STACK_SIZE * 2, NULL, 11, NULL);
|
||||
xTaskCreate(prepareDisplayUpdateTask, "PrepareUpd", EPD_TASK_STACK_SIZE * 2, nullptr, 11, nullptr);
|
||||
|
||||
// Create display update tasks
|
||||
for (uint i = 0; i < NUM_SCREENS; i++) {
|
||||
int *taskParam = new int;
|
||||
*taskParam = i;
|
||||
xTaskCreate(updateDisplay, ("EpdUpd" + String(i)).c_str(), EPD_TASK_STACK_SIZE, taskParam, 11, &tasks[i]);
|
||||
for (size_t i = 0; i < NUM_SCREENS; i++) {
|
||||
auto* taskParam = new int(i);
|
||||
xTaskCreate(updateDisplayTask, ("EpdUpd" + String(i)).c_str(), EPD_TASK_STACK_SIZE,
|
||||
taskParam, 11, &tasks[i]);
|
||||
}
|
||||
|
||||
// Check for storage mode (prevents burn-in)
|
||||
if (mcp1.read1(0) == LOW) {
|
||||
setFgColor(GxEPD_BLACK);
|
||||
setBgColor(GxEPD_WHITE);
|
||||
epdContent.fill("");
|
||||
setForegroundColor(GxEPD_BLACK);
|
||||
setBackgroundColor(GxEPD_WHITE);
|
||||
content.fill("");
|
||||
} else {
|
||||
// Initialize with custom text or default
|
||||
String customText = preferences.getString("displayText", DEFAULT_BOOT_TEXT);
|
||||
|
@ -218,238 +151,128 @@ void setupDisplays() {
|
|||
newContent[i] = String(customText[i]);
|
||||
}
|
||||
|
||||
epdContent = newContent;
|
||||
content = newContent;
|
||||
}
|
||||
|
||||
setEpdContent(epdContent);
|
||||
setContent(content);
|
||||
}
|
||||
|
||||
void setEpdContent(std::array<String, NUM_SCREENS> newEpdContent)
|
||||
{
|
||||
setEpdContent(newEpdContent, false);
|
||||
void EPDManager::loadFonts(const String& fontName) {
|
||||
if (fontName == FontNames::ANTONIO) {
|
||||
// Load Antonio fonts
|
||||
antonioFonts.big = FontLoader::loadCompressedFont(Antonio_SemiBold90pt7b_Properties);
|
||||
antonioFonts.medium = FontLoader::loadCompressedFont(Antonio_SemiBold40pt7b_Properties);
|
||||
antonioFonts.small = FontLoader::loadCompressedFont(Antonio_SemiBold20pt7b_Properties);
|
||||
|
||||
fontBig = antonioFonts.big;
|
||||
fontMedium = antonioFonts.medium;
|
||||
fontSmall = antonioFonts.small;
|
||||
} else if (fontName == FontNames::OSWALD) {
|
||||
// Load Oswald fonts
|
||||
oswaldFonts.big = FontLoader::loadCompressedFont(Oswald_Medium80pt7b_Properties);
|
||||
oswaldFonts.medium = FontLoader::loadCompressedFont(Oswald_Medium30pt7b_Properties);
|
||||
oswaldFonts.small = FontLoader::loadCompressedFont(Oswald_Medium20pt7b_Properties);
|
||||
|
||||
fontBig = oswaldFonts.big;
|
||||
fontMedium = oswaldFonts.medium;
|
||||
fontSmall = oswaldFonts.small;
|
||||
}
|
||||
|
||||
void setEpdContent(std::array<std::string, NUM_SCREENS> newEpdContent)
|
||||
{
|
||||
std::array<String, NUM_SCREENS> conv;
|
||||
|
||||
for (size_t i = 0; i < newEpdContent.size(); ++i)
|
||||
{
|
||||
conv[i] = String(newEpdContent[i].c_str());
|
||||
fontSatsymbol = FontLoader::loadCompressedFont(Satoshi_Symbol90pt7b_Properties);
|
||||
}
|
||||
|
||||
return setEpdContent(conv);
|
||||
void EPDManager::forceFullRefresh() {
|
||||
std::fill(lastFullRefresh.begin(), lastFullRefresh.end(), 0);
|
||||
}
|
||||
|
||||
void setEpdContent(std::array<String, NUM_SCREENS> newEpdContent,
|
||||
bool forceUpdate)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(epdUpdateMutex);
|
||||
|
||||
void EPDManager::setContent(const std::array<String, NUM_SCREENS>& newContent, bool forceUpdate) {
|
||||
std::lock_guard<std::mutex> lock(updateMutex);
|
||||
waitUntilNoneBusy();
|
||||
|
||||
for (uint i = 0; i < NUM_SCREENS; i++)
|
||||
{
|
||||
if (newEpdContent[i].compareTo(currentEpdContent[i]) != 0 || forceUpdate)
|
||||
{
|
||||
epdContent[i] = newEpdContent[i];
|
||||
UpdateDisplayTaskItem dispUpdate = {i};
|
||||
for (size_t i = 0; i < NUM_SCREENS; i++) {
|
||||
if (newContent[i].compareTo(currentContent[i]) != 0 || forceUpdate) {
|
||||
content[i] = newContent[i];
|
||||
UpdateDisplayTaskItem dispUpdate{static_cast<char>(i)};
|
||||
xQueueSend(updateQueue, &dispUpdate, portMAX_DELAY);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void prepareDisplayUpdateTask(void *pvParameters)
|
||||
{
|
||||
UpdateDisplayTaskItem receivedItem;
|
||||
|
||||
while (1)
|
||||
{
|
||||
// Wait for a work item to be available in the queue
|
||||
if (xQueueReceive(updateQueue, &receivedItem, portMAX_DELAY))
|
||||
{
|
||||
uint epdIndex = receivedItem.dispNum;
|
||||
std::lock_guard<std::mutex> lock(epdMutex[epdIndex]);
|
||||
// displays[epdIndex].init(0, false); // Little longer reset duration
|
||||
// because of MCP
|
||||
|
||||
bool updatePartial = true;
|
||||
|
||||
if (epdContent[epdIndex].length() > 1 && 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].startsWith(F("mdi")))
|
||||
{
|
||||
bool updated = renderIcon(epdIndex, epdContent[epdIndex], updatePartial);
|
||||
if (!updated)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else if (epdContent[epdIndex].length() > 5)
|
||||
{
|
||||
renderText(epdIndex, epdContent[epdIndex], updatePartial);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (epdContent[epdIndex].length() == 2)
|
||||
{
|
||||
showChars(epdIndex, epdContent[epdIndex], updatePartial, FONT_BIG);
|
||||
}
|
||||
else if (epdContent[epdIndex].length() > 1 && epdContent[epdIndex].indexOf(".") == -1)
|
||||
{
|
||||
if (epdContent[epdIndex].equals("STS"))
|
||||
{
|
||||
showDigit(epdIndex, 'S', updatePartial,
|
||||
FONT_SATSYMBOL);
|
||||
}
|
||||
else
|
||||
{
|
||||
showChars(epdIndex, epdContent[epdIndex], updatePartial,
|
||||
FONT_MEDIUM);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
showDigit(epdIndex, epdContent[epdIndex].c_str()[0], updatePartial,
|
||||
FONT_BIG);
|
||||
void EPDManager::setContent(const std::array<std::string, NUM_SCREENS>& newContent) {
|
||||
std::array<String, NUM_SCREENS> conv;
|
||||
for (size_t i = 0; i < newContent.size(); ++i) {
|
||||
conv[i] = String(newContent[i].c_str());
|
||||
}
|
||||
setContent(conv);
|
||||
}
|
||||
|
||||
xTaskNotifyGive(tasks[epdIndex]);
|
||||
}
|
||||
}
|
||||
std::array<String, NUM_SCREENS> EPDManager::getCurrentContent() const {
|
||||
return currentContent;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
std::lock_guard<std::mutex> lock(epdMutex[epdIndex]);
|
||||
|
||||
{
|
||||
std::lock_guard<std::mutex> lockMcp(mcpMutex);
|
||||
|
||||
displays[epdIndex].init(0, false, 40);
|
||||
}
|
||||
uint count = 0;
|
||||
while (EPD_BUSY[epdIndex].digitalRead() == HIGH || count < 10)
|
||||
{
|
||||
vTaskDelay(pdMS_TO_TICKS(100));
|
||||
void EPDManager::waitUntilNoneBusy() {
|
||||
for (size_t i = 0; i < NUM_SCREENS; i++) {
|
||||
uint32_t count = 0;
|
||||
while (EPD_BUSY[i].digitalRead()) {
|
||||
count++;
|
||||
}
|
||||
|
||||
bool updatePartial = true;
|
||||
|
||||
// Full Refresh every x minutes
|
||||
if (!lastFullRefresh[epdIndex] ||
|
||||
(millis() - lastFullRefresh[epdIndex]) >
|
||||
(preferences.getUInt("fullRefreshMin",
|
||||
DEFAULT_MINUTES_FULL_REFRESH) *
|
||||
60 * 1000))
|
||||
{
|
||||
updatePartial = false;
|
||||
}
|
||||
|
||||
char tries = 0;
|
||||
while (tries < 3)
|
||||
{
|
||||
if (displays[epdIndex].displayWithReturn(updatePartial))
|
||||
{
|
||||
displays[epdIndex].powerOff();
|
||||
currentEpdContent[epdIndex] = epdContent[epdIndex];
|
||||
if (!updatePartial)
|
||||
lastFullRefresh[epdIndex] = millis();
|
||||
|
||||
if (eventSourceTaskHandle != NULL)
|
||||
xTaskNotifyGive(eventSourceTaskHandle);
|
||||
vTaskDelay(BUSY_RETRY_DELAY);
|
||||
|
||||
if (count == BUSY_TIMEOUT_COUNT) {
|
||||
vTaskDelay(pdMS_TO_TICKS(100));
|
||||
} else if (count > BUSY_TIMEOUT_COUNT + 5) {
|
||||
log_e("Display %d busy timeout", i);
|
||||
break;
|
||||
}
|
||||
|
||||
vTaskDelay(pdMS_TO_TICKS(100));
|
||||
tries++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void splitText(const uint dispNum, const String &top, const String &bottom,
|
||||
bool partial)
|
||||
{
|
||||
if (preferences.getBool("verticalDesc", DEFAULT_VERTICAL_DESC) && dispNum == 0)
|
||||
{
|
||||
void EPDManager::setupDisplay(uint dispNum, const GFXfont* font) {
|
||||
displays[dispNum].setRotation(2);
|
||||
displays[dispNum].setFont(font);
|
||||
displays[dispNum].setTextColor(fgColor);
|
||||
displays[dispNum].fillScreen(bgColor);
|
||||
}
|
||||
|
||||
void EPDManager::splitText(uint dispNum, const String& top, const String& bottom, bool partial) {
|
||||
if (preferences.getBool("verticalDesc", DEFAULT_VERTICAL_DESC) && dispNum == 0) {
|
||||
displays[dispNum].setRotation(1);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
displays[dispNum].setRotation(2);
|
||||
}
|
||||
displays[dispNum].setFont(FONT_SMALL);
|
||||
displays[dispNum].setTextColor(getFgColor());
|
||||
displays[dispNum].setFont(fontSmall);
|
||||
displays[dispNum].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;
|
||||
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;
|
||||
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);
|
||||
// Make separator as wide as the shortest text
|
||||
uint16_t lineWidth = (tbbw < ttbh) ? tbbw : ttbw;
|
||||
uint16_t lineX = round((displays[dispNum].width() - lineWidth) / 2);
|
||||
|
||||
displays[dispNum].fillScreen(getBgColor());
|
||||
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, getFgColor());
|
||||
lineWidth, 6, 3, fgColor);
|
||||
displays[dispNum].setCursor(bx, by);
|
||||
displays[dispNum].print(bottom);
|
||||
}
|
||||
|
||||
// Consolidate common display setup code into a helper function
|
||||
void setupDisplay(const uint dispNum, const GFXfont *font)
|
||||
{
|
||||
displays[dispNum].setRotation(2);
|
||||
displays[dispNum].setFont(font);
|
||||
displays[dispNum].setTextColor(getFgColor());
|
||||
displays[dispNum].fillScreen(getBgColor());
|
||||
}
|
||||
|
||||
void showDigit(const uint dispNum, char chr, bool partial, const GFXfont *font)
|
||||
{
|
||||
void EPDManager::showDigit(uint dispNum, char chr, bool partial, const GFXfont* font) {
|
||||
String str(chr);
|
||||
if (chr == '.')
|
||||
{
|
||||
if (chr == '.') {
|
||||
str = "!";
|
||||
}
|
||||
|
||||
|
@ -465,46 +288,26 @@ void showDigit(const uint dispNum, char chr, bool partial, const GFXfont *font)
|
|||
displays[dispNum].setCursor(x, y);
|
||||
displays[dispNum].print(str);
|
||||
|
||||
if (chr == '.')
|
||||
{
|
||||
if (chr == '.') {
|
||||
displays[dispNum].fillRect(0, 0, displays[dispNum].width(),
|
||||
round(displays[dispNum].height() * 0.67), getBgColor());
|
||||
round(displays[dispNum].height() * 0.67), bgColor);
|
||||
}
|
||||
}
|
||||
|
||||
int16_t calculateDescent(const GFXfont *font)
|
||||
{
|
||||
int16_t maxDescent = 0;
|
||||
for (uint16_t i = font->first; i <= font->last; i++)
|
||||
{
|
||||
GFXglyph *glyph = &font->glyph[i - font->first];
|
||||
int16_t descent = glyph->yOffset;
|
||||
if (descent > maxDescent)
|
||||
{
|
||||
maxDescent = descent;
|
||||
}
|
||||
}
|
||||
return maxDescent;
|
||||
}
|
||||
|
||||
void showChars(const uint dispNum, const String &chars, bool partial,
|
||||
const GFXfont *font)
|
||||
{
|
||||
void EPDManager::showChars(uint dispNum, const String& chars, bool partial, const GFXfont* font) {
|
||||
setupDisplay(dispNum, font);
|
||||
|
||||
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:
|
||||
// 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;
|
||||
|
||||
for (int i = 0; i < chars.length(); i++)
|
||||
{
|
||||
for (size_t i = 0; i < chars.length(); i++) {
|
||||
char c = chars[i];
|
||||
if (c == '.' || c == ',')
|
||||
{
|
||||
if (c == '.' || c == ',') {
|
||||
// For the dot, calculate its specific descent
|
||||
GFXglyph* dotGlyph = &font->glyph[c - font->first];
|
||||
int16_t dotDescent = dotGlyph->yOffset;
|
||||
|
@ -512,9 +315,7 @@ void showChars(const uint dispNum, const String &chars, bool partial,
|
|||
// Draw the dot with adjusted y-position
|
||||
displays[dispNum].setCursor(x, y + dotDescent + dotGlyph->height + 8);
|
||||
displays[dispNum].print(c);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
// For other characters, use the original y-position
|
||||
displays[dispNum].setCursor(x, y);
|
||||
displays[dispNum].print(c);
|
||||
|
@ -525,20 +326,47 @@ void showChars(const uint dispNum, const String &chars, bool partial,
|
|||
}
|
||||
}
|
||||
|
||||
int getBgColor() { return bgColor; }
|
||||
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);
|
||||
|
||||
int getFgColor() { return fgColor; }
|
||||
uint iconIndex = 0;
|
||||
uint width = 122;
|
||||
uint height = 122;
|
||||
|
||||
void setBgColor(int color) { bgColor = color; }
|
||||
|
||||
void setFgColor(int color) { fgColor = color; }
|
||||
|
||||
std::array<String, NUM_SCREENS> getCurrentEpdContent()
|
||||
{
|
||||
return currentEpdContent;
|
||||
if (text.endsWith("rocket")) {
|
||||
iconIndex = 1;
|
||||
} else if (text.endsWith("lnbolt")) {
|
||||
iconIndex = 2;
|
||||
} else if (text.endsWith("bitaxe")) {
|
||||
width = 88;
|
||||
height = 220;
|
||||
iconIndex = 3;
|
||||
} else if (text.endsWith("miningpool")) {
|
||||
LogoData logo = MiningPoolStatsFetch::getInstance().getLogo();
|
||||
if (logo.size == 0) {
|
||||
Serial.println(F("No logo found"));
|
||||
return false;
|
||||
}
|
||||
void renderText(const uint dispNum, const String &text, bool partial)
|
||||
{
|
||||
|
||||
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);
|
||||
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);
|
||||
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());
|
||||
|
@ -548,81 +376,20 @@ void renderText(const uint dispNum, const String &text, bool partial)
|
|||
|
||||
std::stringstream ss;
|
||||
ss.str(text.c_str());
|
||||
|
||||
std::string line;
|
||||
|
||||
while (std::getline(ss, line, '\n'))
|
||||
{
|
||||
if (line.rfind("*", 0) == 0)
|
||||
{
|
||||
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
|
||||
{
|
||||
} else {
|
||||
displays[dispNum].setFont(&FreeSans9pt7b);
|
||||
}
|
||||
displays[dispNum].println(line.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool renderIcon(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(getBgColor());
|
||||
displays[dispNum].setTextColor(getFgColor());
|
||||
|
||||
uint iconIndex = 0;
|
||||
uint width = 122;
|
||||
uint height = 122;
|
||||
if (text.endsWith("rocket"))
|
||||
{
|
||||
iconIndex = 1;
|
||||
}
|
||||
else if (text.endsWith("lnbolt"))
|
||||
{
|
||||
iconIndex = 2;
|
||||
}
|
||||
else if (text.endsWith("bitaxe"))
|
||||
{
|
||||
width = 88;
|
||||
height = 220;
|
||||
iconIndex = 3;
|
||||
}
|
||||
else if (text.endsWith("miningpool"))
|
||||
{
|
||||
LogoData logo = MiningPoolStatsFetch::getInstance().getLogo();
|
||||
|
||||
if (logo.size == 0)
|
||||
{
|
||||
Serial.println(F("No logo found"));
|
||||
return false;
|
||||
}
|
||||
|
||||
int x_offset = (displays[dispNum].width() - logo.width) / 2;
|
||||
int y_offset = (displays[dispNum].height() - logo.height) / 2;
|
||||
// Close the file
|
||||
|
||||
displays[dispNum].drawInvertedBitmap(x_offset, y_offset, logo.data, logo.width, logo.height, getFgColor());
|
||||
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, getFgColor());
|
||||
|
||||
return true;
|
||||
// displays[dispNum].drawInvertedBitmap(0,0, getOceanIcon(), 122, 250, getFgColor());
|
||||
}
|
||||
|
||||
void renderQr(const uint dispNum, const String &text, bool partial)
|
||||
{
|
||||
void EPDManager::renderQr(uint dispNum, const String& text, bool partial) {
|
||||
#ifdef USE_QR
|
||||
// Dynamically allocate QR buffer
|
||||
uint8_t* qrcode = (uint8_t*)malloc(qrcodegen_BUFFER_LEN_MAX);
|
||||
|
@ -639,19 +406,15 @@ void renderQr(const 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);
|
||||
displays[dispNum].setRotation(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++)
|
||||
{
|
||||
for (int y = 0; y < size * 4; y++) {
|
||||
for (int x = 0; x < size * 4; x++) {
|
||||
displays[dispNum].drawPixel(
|
||||
padding + x, paddingY + y,
|
||||
qrcodegen_getModule(qrcode, floor(float(x) / 4), floor(float(y) / 4))
|
||||
|
@ -661,30 +424,114 @@ void renderQr(const uint dispNum, const String &text, bool partial)
|
|||
}
|
||||
}
|
||||
|
||||
// Free the buffer after we're done
|
||||
free(qrcode);
|
||||
#endif
|
||||
}
|
||||
|
||||
void waitUntilNoneBusy()
|
||||
{
|
||||
for (int i = 0; i < NUM_SCREENS; i++)
|
||||
{
|
||||
uint count = 0;
|
||||
while (EPD_BUSY[i].digitalRead())
|
||||
{
|
||||
count++;
|
||||
vTaskDelay(BUSY_RETRY_DELAY);
|
||||
|
||||
if (count == BUSY_TIMEOUT_COUNT)
|
||||
{
|
||||
vTaskDelay(pdMS_TO_TICKS(100));
|
||||
int16_t EPDManager::calculateDescent(const GFXfont* font) {
|
||||
int16_t maxDescent = 0;
|
||||
for (uint16_t i = font->first; i <= font->last; i++) {
|
||||
GFXglyph* glyph = &font->glyph[i - font->first];
|
||||
int16_t descent = glyph->yOffset;
|
||||
if (descent > maxDescent) {
|
||||
maxDescent = descent;
|
||||
}
|
||||
else if (count > BUSY_TIMEOUT_COUNT + 5)
|
||||
}
|
||||
return maxDescent;
|
||||
}
|
||||
|
||||
void EPDManager::updateDisplayTask(void* pvParameters) noexcept {
|
||||
auto& instance = EPDManager::getInstance();
|
||||
const int epdIndex = *(int*)pvParameters;
|
||||
delete (int*)pvParameters;
|
||||
|
||||
for (;;) {
|
||||
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
|
||||
|
||||
std::lock_guard<std::mutex> lock(instance.displayMutexes[epdIndex]);
|
||||
{
|
||||
log_e("Display %d busy timeout", i);
|
||||
std::lock_guard<std::mutex> lockMcp(mcpMutex);
|
||||
instance.displays[epdIndex].init(0, false, 40);
|
||||
}
|
||||
|
||||
uint32_t count = 0;
|
||||
while (instance.EPD_BUSY[epdIndex].digitalRead() == HIGH || count < 10) {
|
||||
vTaskDelay(pdMS_TO_TICKS(100));
|
||||
count++;
|
||||
}
|
||||
|
||||
bool updatePartial = true;
|
||||
if (!instance.lastFullRefresh[epdIndex] ||
|
||||
(millis() - instance.lastFullRefresh[epdIndex]) >
|
||||
(preferences.getUInt("fullRefreshMin", DEFAULT_MINUTES_FULL_REFRESH) * 60 * 1000)) {
|
||||
updatePartial = false;
|
||||
}
|
||||
|
||||
char tries = 0;
|
||||
while (tries < 3) {
|
||||
if (instance.displays[epdIndex].displayWithReturn(updatePartial)) {
|
||||
instance.displays[epdIndex].powerOff();
|
||||
instance.currentContent[epdIndex] = instance.content[epdIndex];
|
||||
if (!updatePartial) {
|
||||
instance.lastFullRefresh[epdIndex] = millis();
|
||||
}
|
||||
|
||||
if (eventSourceTaskHandle != nullptr) {
|
||||
xTaskNotifyGive(eventSourceTaskHandle);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
vTaskDelay(pdMS_TO_TICKS(100));
|
||||
tries++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void EPDManager::prepareDisplayUpdateTask(void* pvParameters) {
|
||||
auto& instance = EPDManager::getInstance();
|
||||
UpdateDisplayTaskItem receivedItem;
|
||||
|
||||
for (;;) {
|
||||
if (xQueueReceive(instance.updateQueue, &receivedItem, portMAX_DELAY)) {
|
||||
uint epdIndex = receivedItem.dispNum;
|
||||
std::lock_guard<std::mutex> lock(instance.displayMutexes[epdIndex]);
|
||||
|
||||
bool updatePartial = true;
|
||||
|
||||
if (instance.content[epdIndex].length() > 1 &&
|
||||
strstr(instance.content[epdIndex].c_str(), "/") != nullptr) {
|
||||
String top = instance.content[epdIndex].substring(
|
||||
0, instance.content[epdIndex].indexOf("/"));
|
||||
String bottom = instance.content[epdIndex].substring(
|
||||
instance.content[epdIndex].indexOf("/") + 1);
|
||||
instance.splitText(epdIndex, top, bottom, updatePartial);
|
||||
} else if (instance.content[epdIndex].startsWith(F("qr"))) {
|
||||
instance.renderQr(epdIndex, instance.content[epdIndex], updatePartial);
|
||||
} else if (instance.content[epdIndex].startsWith(F("mdi"))) {
|
||||
if (!instance.renderIcon(epdIndex, instance.content[epdIndex], updatePartial)) {
|
||||
continue;
|
||||
}
|
||||
} else if (instance.content[epdIndex].length() > 5) {
|
||||
instance.renderText(epdIndex, instance.content[epdIndex], updatePartial);
|
||||
} else {
|
||||
if (instance.content[epdIndex].length() == 2) {
|
||||
instance.showChars(epdIndex, instance.content[epdIndex], updatePartial, instance.fontBig);
|
||||
} else if (instance.content[epdIndex].length() > 1 &&
|
||||
instance.content[epdIndex].indexOf(".") == -1) {
|
||||
if (instance.content[epdIndex].equals("STS")) {
|
||||
instance.showDigit(epdIndex, 'S', updatePartial, instance.fontSatsymbol);
|
||||
} else {
|
||||
instance.showChars(epdIndex, instance.content[epdIndex], updatePartial,
|
||||
instance.fontMedium);
|
||||
}
|
||||
} else {
|
||||
instance.showDigit(epdIndex, instance.content[epdIndex].c_str()[0],
|
||||
updatePartial, instance.fontBig);
|
||||
}
|
||||
}
|
||||
|
||||
xTaskNotifyGive(instance.tasks[epdIndex]);
|
||||
}
|
||||
}
|
||||
}
|
125
src/lib/epd.hpp
125
src/lib/epd.hpp
|
@ -9,6 +9,8 @@
|
|||
#include <mutex>
|
||||
#include <native_pin.hpp>
|
||||
#include <regex>
|
||||
#include <array>
|
||||
#include <memory>
|
||||
|
||||
#include "fonts/fonts.hpp"
|
||||
#include "lib/config.hpp"
|
||||
|
@ -32,39 +34,102 @@
|
|||
#include "qrcodegen.h"
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
struct UpdateDisplayTaskItem {
|
||||
char dispNum;
|
||||
} UpdateDisplayTaskItem;
|
||||
};
|
||||
|
||||
struct FontFamily {
|
||||
GFXfont* big;
|
||||
GFXfont* medium;
|
||||
GFXfont* small;
|
||||
};
|
||||
|
||||
class EPDManager {
|
||||
public:
|
||||
static EPDManager& getInstance();
|
||||
|
||||
// Delete copy constructor and assignment operator
|
||||
EPDManager(const EPDManager&) = delete;
|
||||
EPDManager& operator=(const EPDManager&) = delete;
|
||||
|
||||
void initialize();
|
||||
void forceFullRefresh();
|
||||
void setupDisplays();
|
||||
void loadFonts(const String& fontName);
|
||||
void setContent(const std::array<String, NUM_SCREENS>& newContent, bool forceUpdate = false);
|
||||
void setContent(const std::array<std::string, NUM_SCREENS>& newContent);
|
||||
std::array<String, NUM_SCREENS> getCurrentContent() const;
|
||||
|
||||
void splitText(const uint dispNum, const String &top, const String &bottom,
|
||||
bool partial);
|
||||
|
||||
void showDigit(const uint dispNum, char chr, bool partial, const GFXfont *font);
|
||||
void showChars(const uint dispNum, const String &chars, bool partial,
|
||||
const GFXfont *font);
|
||||
|
||||
extern "C" void updateDisplay(void *pvParameters) noexcept;
|
||||
void updateDisplayAlt(int epdIndex);
|
||||
void prepareDisplayUpdateTask(void *pvParameters);
|
||||
|
||||
int getBgColor();
|
||||
int getFgColor();
|
||||
void setBgColor(int color);
|
||||
void setFgColor(int color);
|
||||
|
||||
bool renderIcon(const uint dispNum, const String &text, bool partial);
|
||||
void renderText(const uint dispNum, const String &text, bool partial);
|
||||
void renderQr(const uint dispNum, const String &text, bool partial);
|
||||
|
||||
void setEpdContent(std::array<String, NUM_SCREENS> newEpdContent,
|
||||
bool forceUpdate);
|
||||
void setEpdContent(std::array<String, NUM_SCREENS> newEpdContent);
|
||||
|
||||
void setEpdContent(std::array<std::string, NUM_SCREENS> newEpdContent);
|
||||
|
||||
std::array<String, NUM_SCREENS> getCurrentEpdContent();
|
||||
int getBackgroundColor() const { return bgColor; }
|
||||
int getForegroundColor() const { return fgColor; }
|
||||
void setBackgroundColor(int color) { bgColor = color; }
|
||||
void setForegroundColor(int color) { fgColor = color; }
|
||||
void waitUntilNoneBusy();
|
||||
|
||||
private:
|
||||
EPDManager(); // Private constructor for singleton
|
||||
~EPDManager(); // Private destructor
|
||||
|
||||
void setupDisplay(uint dispNum, const GFXfont* font);
|
||||
void splitText(uint dispNum, const String& top, const String& bottom, bool partial);
|
||||
void showDigit(uint dispNum, char chr, bool partial, const GFXfont* font);
|
||||
void showChars(uint dispNum, const String& chars, bool partial, const GFXfont* font);
|
||||
bool renderIcon(uint dispNum, const String& text, bool partial);
|
||||
void renderText(uint dispNum, const String& text, bool partial);
|
||||
void renderQr(uint dispNum, const String& text, bool partial);
|
||||
int16_t calculateDescent(const GFXfont* font);
|
||||
|
||||
static void updateDisplayTask(void* pvParameters) noexcept;
|
||||
static void prepareDisplayUpdateTask(void* pvParameters);
|
||||
|
||||
// Member variables
|
||||
std::array<String, NUM_SCREENS> currentContent;
|
||||
std::array<String, NUM_SCREENS> content;
|
||||
std::array<uint32_t, NUM_SCREENS> lastFullRefresh;
|
||||
std::array<TaskHandle_t, NUM_SCREENS> tasks;
|
||||
QueueHandle_t updateQueue;
|
||||
|
||||
FontFamily antonioFonts;
|
||||
FontFamily oswaldFonts;
|
||||
const GFXfont* fontSmall;
|
||||
const GFXfont* fontBig;
|
||||
const GFXfont* fontMedium;
|
||||
const GFXfont* fontSatsymbol;
|
||||
|
||||
int bgColor;
|
||||
int fgColor;
|
||||
|
||||
std::mutex updateMutex;
|
||||
std::array<std::mutex, NUM_SCREENS> displayMutexes;
|
||||
|
||||
// Pin configurations based on board version
|
||||
#ifdef IS_BTCLOCK_REV_B
|
||||
static Native_Pin EPD_DC;
|
||||
static std::array<Native_Pin, NUM_SCREENS> EPD_CS;
|
||||
static std::array<Native_Pin, NUM_SCREENS> EPD_BUSY;
|
||||
static std::array<MCP23X17_Pin, NUM_SCREENS> EPD_RESET;
|
||||
#elif defined(IS_BTCLOCK_V8)
|
||||
static Native_Pin EPD_DC;
|
||||
static std::array<MCP23X17_Pin, NUM_SCREENS> EPD_BUSY;
|
||||
static std::array<MCP23X17_Pin, NUM_SCREENS> EPD_CS;
|
||||
static std::array<MCP23X17_Pin, NUM_SCREENS> EPD_RESET;
|
||||
#else
|
||||
static Native_Pin EPD_DC;
|
||||
static std::array<Native_Pin, NUM_SCREENS> EPD_CS;
|
||||
static std::array<Native_Pin, NUM_SCREENS> EPD_BUSY;
|
||||
static std::array<MCP23X17_Pin, NUM_SCREENS> EPD_RESET;
|
||||
#endif
|
||||
|
||||
// Display array
|
||||
std::array<GxEPD2_BW<EPD_CLASS, EPD_CLASS::HEIGHT>, NUM_SCREENS> displays;
|
||||
|
||||
static constexpr size_t UPDATE_QUEUE_SIZE = 14;
|
||||
static constexpr uint32_t BUSY_TIMEOUT_COUNT = 200;
|
||||
static constexpr TickType_t BUSY_RETRY_DELAY = pdMS_TO_TICKS(10);
|
||||
static constexpr size_t EPD_TASK_STACK_SIZE =
|
||||
#ifdef IS_BTCLOCK_V8
|
||||
4096
|
||||
#else
|
||||
2048
|
||||
#endif
|
||||
;
|
||||
};
|
|
@ -283,7 +283,7 @@ void handleNostrZapCallback(const String &subId, nostr::SignedNostrEvent *event)
|
|||
}
|
||||
ScreenHandler::setCurrentScreen(SCREEN_CUSTOM);
|
||||
|
||||
setEpdContent(textEpdContent);
|
||||
EPDManager::getInstance().setContent(textEpdContent);
|
||||
vTaskDelay(pdMS_TO_TICKS(315 * NUM_SCREENS) + pdMS_TO_TICKS(250));
|
||||
if (preferences.getBool("ledFlashOnZap", DEFAULT_LED_FLASH_ON_ZAP))
|
||||
{
|
||||
|
@ -295,3 +295,19 @@ void handleNostrZapCallback(const String &subId, nostr::SignedNostrEvent *event)
|
|||
timerPeriod * usPerSecond);
|
||||
}
|
||||
}
|
||||
|
||||
// void onNostrEvent(const String &subId, const nostr::Event &event) {
|
||||
// // This is the callback that will be called when a new event is received
|
||||
// if (event.kind == 9735) {
|
||||
// // Parse the zap amount from the event
|
||||
// uint16_t amount = parseZapAmount(event);
|
||||
// if (amount > 0) {
|
||||
// std::array<std::string, NUM_SCREENS> zapContent = parseZapNotify(amount, true);
|
||||
// EPDManager::getInstance().setContent(zapContent);
|
||||
|
||||
// if (preferences.getBool("ledFlashOnUpd", DEFAULT_LED_FLASH_ON_UPD)) {
|
||||
// getLedHandler().queueEffect(LED_FLASH_BLOCK_NOTIFY);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
|
@ -57,10 +57,10 @@ void onOTAProgress(unsigned int progress, unsigned int total)
|
|||
|
||||
void onOTAStart()
|
||||
{
|
||||
forceFullRefresh();
|
||||
EPDManager::getInstance().forceFullRefresh();
|
||||
std::array<String, NUM_SCREENS> epdContent = {"U", "P", "D", "A",
|
||||
"T", "E", "!"};
|
||||
setEpdContent(epdContent);
|
||||
EPDManager::getInstance().setContent(epdContent);
|
||||
// Stop all timers
|
||||
esp_timer_stop(screenRotateTimer);
|
||||
esp_timer_stop(minuteTimer);
|
||||
|
|
|
@ -203,7 +203,7 @@ void ScreenHandler::showSystemStatusScreen() {
|
|||
String((int)round(ESP.getFreeHeap() / 1024)) + "/" +
|
||||
(int)round(ESP.getHeapSize() / 1024);
|
||||
setCurrentScreen(SCREEN_CUSTOM);
|
||||
setEpdContent(sysStatusEpdContent);
|
||||
EPDManager::getInstance().setContent(sysStatusEpdContent);
|
||||
}
|
||||
|
||||
// Keep these as free functions
|
||||
|
@ -222,7 +222,7 @@ void workerTask(void *pvParameters) {
|
|||
taskEpdContent = (currentScreenValue == SCREEN_BITAXE_HASHRATE) ?
|
||||
parseBitaxeHashRate(BitAxeFetch::getInstance().getHashRate()) :
|
||||
parseBitaxeBestDiff(BitAxeFetch::getInstance().getBestDiff());
|
||||
setEpdContent(taskEpdContent);
|
||||
EPDManager::getInstance().setContent(taskEpdContent);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -235,7 +235,7 @@ void workerTask(void *pvParameters) {
|
|||
parseMiningPoolStatsDailyEarnings(MiningPoolStatsFetch::getInstance().getDailyEarnings(),
|
||||
MiningPoolStatsFetch::getInstance().getPool()->getDailyEarningsLabel(),
|
||||
*MiningPoolStatsFetch::getInstance().getPool());
|
||||
setEpdContent(taskEpdContent);
|
||||
EPDManager::getInstance().setContent(taskEpdContent);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -256,13 +256,13 @@ void workerTask(void *pvParameters) {
|
|||
preferences.getBool("mcapBigChar", DEFAULT_MCAP_BIG_CHAR));
|
||||
}
|
||||
|
||||
setEpdContent(taskEpdContent);
|
||||
EPDManager::getInstance().setContent(taskEpdContent);
|
||||
break;
|
||||
}
|
||||
case TASK_FEE_UPDATE: {
|
||||
if (currentScreenValue == SCREEN_BLOCK_FEE_RATE) {
|
||||
taskEpdContent = parseBlockFees(static_cast<std::uint16_t>(getBlockMedianFee()));
|
||||
setEpdContent(taskEpdContent);
|
||||
EPDManager::getInstance().setContent(taskEpdContent);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -275,7 +275,7 @@ void workerTask(void *pvParameters) {
|
|||
|
||||
if (currentScreenValue == SCREEN_HALVING_COUNTDOWN ||
|
||||
currentScreenValue == SCREEN_BLOCK_HEIGHT) {
|
||||
setEpdContent(taskEpdContent);
|
||||
EPDManager::getInstance().setContent(taskEpdContent);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -302,7 +302,7 @@ void workerTask(void *pvParameters) {
|
|||
for (uint i = 1; i < NUM_SCREENS; i++) {
|
||||
taskEpdContent[i] = timeString[i];
|
||||
}
|
||||
setEpdContent(taskEpdContent);
|
||||
EPDManager::getInstance().setContent(taskEpdContent);
|
||||
}
|
||||
|
||||
break;
|
||||
|
@ -330,8 +330,6 @@ void setupTasks() {
|
|||
xTaskCreate(taskScreenRotate, "rotateScreen", 4096, NULL, tskIDLE_PRIORITY,
|
||||
&taskScreenRotateTaskHandle);
|
||||
|
||||
waitUntilNoneBusy();
|
||||
|
||||
if (findScreenIndexByValue(preferences.getUInt("currentScreen", DEFAULT_CURRENT_SCREEN)) != -1)
|
||||
ScreenHandler::setCurrentScreen(preferences.getUInt("currentScreen", DEFAULT_CURRENT_SCREEN));
|
||||
}
|
||||
|
|
|
@ -180,3 +180,4 @@ void HttpHelper::end(HTTPClient* http) {
|
|||
delete http;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -16,6 +16,8 @@
|
|||
|
||||
#include <mutex>
|
||||
#include <utils.hpp>
|
||||
#include <array>
|
||||
#include <string>
|
||||
|
||||
#include "defaults.hpp"
|
||||
|
||||
|
@ -119,3 +121,4 @@ private:
|
|||
static bool certBundleSet;
|
||||
static WiFiClient insecureClient;
|
||||
};
|
||||
|
||||
|
|
|
@ -106,6 +106,11 @@ namespace V2Notify
|
|||
JsonDocument doc;
|
||||
DeserializationError error = deserializeMsgPack(doc, payload, length);
|
||||
|
||||
if (error) {
|
||||
Serial.println(F("Error deserializing message"));
|
||||
break;
|
||||
}
|
||||
|
||||
V2Notify::handleV2Message(doc);
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -309,7 +309,7 @@ void eventSourceUpdate() {
|
|||
doc["leds"] = getLedStatusObject()["data"];
|
||||
|
||||
// Get current EPD content directly as array
|
||||
std::array<String, NUM_SCREENS> epdContent = getCurrentEpdContent();
|
||||
std::array<String, NUM_SCREENS> epdContent = EPDManager::getInstance().getCurrentContent();
|
||||
|
||||
// Add EPD content arrays
|
||||
JsonArray data = doc["data"].to<JsonArray>();
|
||||
|
@ -336,7 +336,7 @@ void onApiStatus(AsyncWebServerRequest *request)
|
|||
JsonDocument root = getStatusObject();
|
||||
|
||||
// Get current EPD content directly as array
|
||||
std::array<String, NUM_SCREENS> epdContent = getCurrentEpdContent();
|
||||
std::array<String, NUM_SCREENS> epdContent = EPDManager::getInstance().getCurrentContent();
|
||||
|
||||
// Add EPD content arrays
|
||||
JsonArray data = root["data"].to<JsonArray>();
|
||||
|
@ -378,11 +378,9 @@ void onApiActionTimerRestart(AsyncWebServerRequest *request)
|
|||
*/
|
||||
void onApiFullRefresh(AsyncWebServerRequest *request)
|
||||
{
|
||||
forceFullRefresh();
|
||||
std::array<String, NUM_SCREENS> newEpdContent = getCurrentEpdContent();
|
||||
|
||||
setEpdContent(newEpdContent, true);
|
||||
|
||||
EPDManager::getInstance().forceFullRefresh();
|
||||
std::array<String, NUM_SCREENS> newEpdContent = EPDManager::getInstance().getCurrentContent();
|
||||
EPDManager::getInstance().setContent(newEpdContent, true);
|
||||
request->send(HTTP_OK);
|
||||
}
|
||||
|
||||
|
@ -429,7 +427,7 @@ void onApiShowText(AsyncWebServerRequest *request)
|
|||
textEpdContent[i] = t[i];
|
||||
}
|
||||
|
||||
setEpdContent(textEpdContent);
|
||||
EPDManager::getInstance().setContent(textEpdContent);
|
||||
}
|
||||
ScreenHandler::setCurrentScreen(SCREEN_CUSTOM);
|
||||
request->send(HTTP_OK);
|
||||
|
@ -447,7 +445,7 @@ void onApiShowTextAdvanced(AsyncWebServerRequest *request, JsonVariant &json)
|
|||
i++;
|
||||
}
|
||||
|
||||
setEpdContent(epdContent);
|
||||
EPDManager::getInstance().setContent(epdContent);
|
||||
|
||||
ScreenHandler::setCurrentScreen(SCREEN_CUSTOM);
|
||||
request->send(HTTP_OK);
|
||||
|
@ -475,13 +473,13 @@ void onApiSettingsPatch(AsyncWebServerRequest *request, JsonVariant &json)
|
|||
if (inverted) {
|
||||
preferences.putUInt("fgColor", GxEPD_WHITE);
|
||||
preferences.putUInt("bgColor", GxEPD_BLACK);
|
||||
setFgColor(GxEPD_WHITE);
|
||||
setBgColor(GxEPD_BLACK);
|
||||
EPDManager::getInstance().setForegroundColor(GxEPD_WHITE);
|
||||
EPDManager::getInstance().setBackgroundColor(GxEPD_BLACK);
|
||||
} else {
|
||||
preferences.putUInt("fgColor", GxEPD_BLACK);
|
||||
preferences.putUInt("bgColor", GxEPD_WHITE);
|
||||
setFgColor(GxEPD_BLACK);
|
||||
setBgColor(GxEPD_WHITE);
|
||||
EPDManager::getInstance().setForegroundColor(GxEPD_BLACK);
|
||||
EPDManager::getInstance().setBackgroundColor(GxEPD_WHITE);
|
||||
}
|
||||
Serial.printf("Setting invertedColor to %d\r\n", inverted);
|
||||
settingsChanged = true;
|
||||
|
@ -680,7 +678,7 @@ void onApiSettingsGet(AsyncWebServerRequest *request)
|
|||
|
||||
JsonDocument root;
|
||||
root["numScreens"] = NUM_SCREENS;
|
||||
root["invertedColor"] = preferences.getBool("invertedColor", getFgColor() == GxEPD_WHITE);
|
||||
root["invertedColor"] = preferences.getBool("invertedColor", EPDManager::getInstance().getForegroundColor() == GxEPD_WHITE);
|
||||
root["timerSeconds"] = getTimerSeconds();
|
||||
root["timerRunning"] = isTimerActive();
|
||||
root["minSecPriceUpd"] = preferences.getUInt(
|
||||
|
@ -818,7 +816,7 @@ bool processEpdColorSettings(AsyncWebServerRequest *request)
|
|||
const AsyncWebParameter *fgColor = request->getParam("fgColor", true);
|
||||
uint32_t color = strtol(fgColor->value().c_str(), NULL, 16);
|
||||
preferences.putUInt("fgColor", color);
|
||||
setFgColor(color);
|
||||
EPDManager::getInstance().setForegroundColor(color);
|
||||
// Serial.print(F("Setting foreground color to "));
|
||||
// Serial.println(fgColor->value().c_str());
|
||||
settingsChanged = true;
|
||||
|
@ -829,7 +827,7 @@ bool processEpdColorSettings(AsyncWebServerRequest *request)
|
|||
|
||||
uint32_t color = strtol(bgColor->value().c_str(), NULL, 16);
|
||||
preferences.putUInt("bgColor", color);
|
||||
setBgColor(color);
|
||||
EPDManager::getInstance().setBackgroundColor(color);
|
||||
// Serial.print(F("Setting background color to "));
|
||||
// Serial.println(bgColor->value().c_str());
|
||||
settingsChanged = true;
|
||||
|
@ -1202,7 +1200,7 @@ void onApiLightsGet(AsyncWebServerRequest *request)
|
|||
auto& ledHandler = getLedHandler();
|
||||
auto& pixels = ledHandler.getPixels();
|
||||
|
||||
DynamicJsonDocument doc(1024);
|
||||
JsonDocument doc;
|
||||
JsonArray lights = doc.createNestedArray("lights");
|
||||
|
||||
for (uint i = 0; i < pixels.numPixels(); i++)
|
||||
|
@ -1225,7 +1223,7 @@ void onApiLightsPost(AsyncWebServerRequest *request, uint8_t *data, size_t len,
|
|||
auto& ledHandler = getLedHandler();
|
||||
auto& pixels = ledHandler.getPixels();
|
||||
|
||||
DynamicJsonDocument doc(1024);
|
||||
JsonDocument doc;
|
||||
DeserializationError error = deserializeJson(doc, data);
|
||||
if (error)
|
||||
{
|
||||
|
|
Loading…
Reference in a new issue