diff --git a/src/lib/block_notify.cpp b/src/lib/block_notify.cpp index ffbc15f..a7a6751 100644 --- a/src/lib/block_notify.cpp +++ b/src/lib/block_notify.cpp @@ -2,21 +2,67 @@ char *wsServer; esp_websocket_client_handle_t blockNotifyClient = NULL; -unsigned long int currentBlockHeight = 816000; +uint currentBlockHeight = 816000; + +// const char *mempoolWsCert = R"(-----BEGIN CERTIFICATE----- +// MIIHfTCCBmWgAwIBAgIRANFX3mhqRYDt1NFuENoSyaAwDQYJKoZIhvcNAQELBQAw +// gZUxCzAJBgNVBAYTAkdCMRswGQYDVQQIExJHcmVhdGVyIE1hbmNoZXN0ZXIxEDAO +// BgNVBAcTB1NhbGZvcmQxGDAWBgNVBAoTD1NlY3RpZ28gTGltaXRlZDE9MDsGA1UE +// AxM0U2VjdGlnbyBSU0EgT3JnYW5pemF0aW9uIFZhbGlkYXRpb24gU2VjdXJlIFNl +// cnZlciBDQTAeFw0yMzA3MjQwMDAwMDBaFw0yNDA4MjIyMzU5NTlaMFcxCzAJBgNV +// BAYTAkpQMQ4wDAYDVQQIEwVUb2t5bzEgMB4GA1UEChMXTUVNUE9PTCBTUEFDRSBD +// Ty4sIExURC4xFjAUBgNVBAMTDW1lbXBvb2wuc3BhY2UwggEiMA0GCSqGSIb3DQEB +// AQUAA4IBDwAwggEKAoIBAQCqmiPRWgo58d25R0biQjAksXMq5ciH7z7ZQo2w2AbB +// rHxpnlIry74b9S4wRY5UJeYmd6ZwA76NdSioDvxTJc29bLplY+Ftmfc4ET0zYb2k +// Fi86z7GOWb6Ezor/qez9uMM9cxd021Bvcs0/2OrL6Sgp66u9keDZv9NyvFPpXfuR +// tdV2r4HF57VJqZn105PN4k80kNWgDbae8aw+BuUNvQYKEe71yfB7Bh6zSh9pCSfM +// I6pIJdQzoada2uY1dQMoJeIq8qKNKqAPKGsH5McemUT5ZIKU/tjk3nfX0pz/sQa4 +// CN7tLH6UeUlctei92GFd6Xtn7RbKLhDUbc4Sq02Cc9iXAgMBAAGjggQDMIID/zAf +// BgNVHSMEGDAWgBQX2dYlJ2f5McJJQ9kwNkSMbKlP6zAdBgNVHQ4EFgQUXkxoddJ6 +// rKobsbmDdtuCK1ywXuIwDgYDVR0PAQH/BAQDAgWgMAwGA1UdEwEB/wQCMAAwHQYD +// VR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMEoGA1UdIARDMEEwNQYMKwYBBAGy +// MQECAQMEMCUwIwYIKwYBBQUHAgEWF2h0dHBzOi8vc2VjdGlnby5jb20vQ1BTMAgG +// BmeBDAECAjBaBgNVHR8EUzBRME+gTaBLhklodHRwOi8vY3JsLnNlY3RpZ28uY29t +// L1NlY3RpZ29SU0FPcmdhbml6YXRpb25WYWxpZGF0aW9uU2VjdXJlU2VydmVyQ0Eu +// Y3JsMIGKBggrBgEFBQcBAQR+MHwwVQYIKwYBBQUHMAKGSWh0dHA6Ly9jcnQuc2Vj +// dGlnby5jb20vU2VjdGlnb1JTQU9yZ2FuaXphdGlvblZhbGlkYXRpb25TZWN1cmVT +// ZXJ2ZXJDQS5jcnQwIwYIKwYBBQUHMAGGF2h0dHA6Ly9vY3NwLnNlY3RpZ28uY29t +// MIIBgAYKKwYBBAHWeQIEAgSCAXAEggFsAWoAdwB2/4g/Crb7lVHCYcz1h7o0tKTN +// uyncaEIKn+ZnTFo6dAAAAYmc9m/gAAAEAwBIMEYCIQD8XOozx411S/bnZambGjTB +// yTcr2fCmggUfQLSmqksD5gIhAIjiEMg0o1VSuQW31gWzfzL6idCkIZeSKN104cdp +// xa4SAHcA2ra/az+1tiKfm8K7XGvocJFxbLtRhIU0vaQ9MEjX+6sAAAGJnPZwPwAA +// BAMASDBGAiEA2sPTZTzvxewzQ8vk36+BWAKuJS7AvJ5W3clvfwCa8OUCIQC74ekT +// Ged2fqQE4sVy74aS6HRA2ihC9VLtNrASJx1YjQB2AO7N0GTV2xrOxVy3nbTNE6Iy +// h0Z8vOzew1FIWUZxH7WbAAABiZz2cA8AAAQDAEcwRQIgEklH7wYCFuuJIFUHX5PY +// /vZ3bDoxOp+061PT3caa+rICIQC0abgfGlBKiHxp47JZxnW3wcVqWdiYX4ViLm9H +// xfx4ljCBxgYDVR0RBIG+MIG7gg1tZW1wb29sLnNwYWNlghMqLmZtdC5tZW1wb29s +// LnNwYWNlghMqLmZyYS5tZW1wb29sLnNwYWNlgg8qLm1lbXBvb2wuc3BhY2WCEyou +// dGs3Lm1lbXBvb2wuc3BhY2WCEyoudmExLm1lbXBvb2wuc3BhY2WCDGJpc3EubWFy +// a2V0c4IKYmlzcS5uaW5qYYIObGlxdWlkLm5ldHdvcmuCDGxpcXVpZC5wbGFjZYIN +// bWVtcG9vbC5uaW5qYTANBgkqhkiG9w0BAQsFAAOCAQEAFvOSRnlHDfq9C8acjZEG +// 5XIqjNYigyWyjOvx83of6Z3PBKkAZB5D/UHBPp+jBDJiEb/QXC7Z7Y7kpuvnoVib +// b4jDc0RjGEsxL+3F7cSw26m3wILJhhHooGZRmFY4GOAeCZtYCOTzJsiZvFpDoQjU +// hTBxtaps05z0Ly9/eYvkXnjnBNROZJVR+KYHlq4TIoGNc4q4KvpfHv2I/vhS2M1e +// bECNNPEyRxHGKdXXO3huocE7aVKpy+JDR6cWwDu6hpdc1j/SCDqdTDFQ7McHOrqA +// fpPh4FcfePMh7Mqxtg2pSs5pXPtiP0ZjLgxd7HbAXct8Y+/jGk+k3sx3SeYXVimr +// ew== +// -----END CERTIFICATE-----)"; void setupBlockNotify() { - currentBlockHeight = preferences.getULong("blockHeight", 816000); + //currentBlockHeight = preferences.getUInt("blockHeight", 816000); IPAddress result; int dnsErr = -1; String mempoolInstance = preferences.getString("mempoolInstance", DEFAULT_MEMPOOL_INSTANCE); - while (dnsErr != 1) { + while (dnsErr != 1) + { dnsErr = WiFi.hostByName(mempoolInstance.c_str(), result); - if (dnsErr != 1) { + if (dnsErr != 1) + { Serial.print(mempoolInstance); Serial.println(F("mempool DNS could not be resolved")); WiFi.reconnect(); @@ -33,13 +79,20 @@ void setupBlockNotify() { String blockHeightStr = http->getString(); currentBlockHeight = blockHeightStr.toInt(); - xTaskNotifyGive(blockUpdateTaskHandle); + // xTaskNotifyGive(blockUpdateTaskHandle); + if (workQueue != nullptr) + { + WorkItem blockUpdate = {TASK_BLOCK_UPDATE, 0}; + xQueueSend(workQueue, &blockUpdate, portMAX_DELAY); + } } - // std::strcpy(wsServer, String("wss://" + mempoolInstance + "/api/v1/ws").c_str()); + // std::strcpy(wsServer, String("wss://" + mempoolInstance + "/api/v1/ws").c_str()); esp_websocket_client_config_t config = { .uri = "wss://mempool.space/api/v1/ws", + // .task_stack = (6*1024), + // .cert_pem = mempoolWsCert, .user_agent = USER_AGENT, }; @@ -56,7 +109,7 @@ void onWebsocketEvent(void *handler_args, esp_event_base_t base, int32_t event_i { case WEBSOCKET_EVENT_CONNECTED: Serial.println(F("Connected to Mempool.space WebSocket")); - + Serial.println(sub); if (esp_websocket_client_send_text(blockNotifyClient, sub.c_str(), sub.length(), portMAX_DELAY) == -1) { @@ -87,40 +140,53 @@ void onWebsocketMessage(esp_websocket_event_data_t *event_data) { JsonObject block = doc["block"]; - currentBlockHeight = block["height"].as(); + currentBlockHeight = block["height"].as(); - Serial.printf("New block found: %d\r\n", block["height"].as()); - preferences.putULong("blockHeight", currentBlockHeight); + Serial.printf("New block found: %d\r\n", block["height"].as()); + size_t prefWrite = preferences.putUInt("blockHeight", currentBlockHeight); + Serial.printf("Wrote %d for block\r\n", prefWrite); - if (blockUpdateTaskHandle != nullptr) { - xTaskNotifyGive(blockUpdateTaskHandle); + if (workQueue != nullptr) + { + WorkItem blockUpdate = {TASK_BLOCK_UPDATE, 0}; + xQueueSend(workQueue, &blockUpdate, portMAX_DELAY); + // xTaskNotifyGive(blockUpdateTaskHandle); - if (getCurrentScreen() != SCREEN_BLOCK_HEIGHT && preferences.getBool("stealFocus", true)) { + if (getCurrentScreen() != SCREEN_BLOCK_HEIGHT && preferences.getBool("stealFocus", true)) + { setCurrentScreen(SCREEN_BLOCK_HEIGHT); } - if (getCurrentScreen() == SCREEN_BLOCK_HEIGHT && preferences.getBool("ledFlashOnUpd", false)) { + if (getCurrentScreen() == SCREEN_BLOCK_HEIGHT && preferences.getBool("ledFlashOnUpd", false)) + { vTaskDelay(pdMS_TO_TICKS(250)); // Wait until screens are updated queueLedEffect(LED_FLASH_BLOCK_NOTIFY); } } - } - + } + doc.clear(); } -unsigned long getBlockHeight() +uint getBlockHeight() { return currentBlockHeight; } -bool isBlockNotifyConnected() { +void setBlockHeight(uint newBlockHeight) +{ + currentBlockHeight = newBlockHeight; +} + +bool isBlockNotifyConnected() +{ if (blockNotifyClient == NULL) return false; return esp_websocket_client_is_connected(blockNotifyClient); } -void stopBlockNotify() { +void stopBlockNotify() +{ esp_websocket_client_stop(blockNotifyClient); esp_websocket_client_destroy(blockNotifyClient); } \ No newline at end of file diff --git a/src/lib/block_notify.hpp b/src/lib/block_notify.hpp index fc41d1c..2783c2b 100644 --- a/src/lib/block_notify.hpp +++ b/src/lib/block_notify.hpp @@ -18,6 +18,7 @@ void setupBlockNotify(); void onWebsocketEvent(void *handler_args, esp_event_base_t base, int32_t event_id, void *event_data); void onWebsocketMessage(esp_websocket_event_data_t* event_data); -unsigned long getBlockHeight(); +void setBlockHeight(uint newBlockHeight); +uint getBlockHeight(); bool isBlockNotifyConnected(); void stopBlockNotify(); \ No newline at end of file diff --git a/src/lib/config.cpp b/src/lib/config.cpp index e4e5c1d..ed96c1b 100644 --- a/src/lib/config.cpp +++ b/src/lib/config.cpp @@ -71,16 +71,13 @@ void tryImprovSetup() WiFi.softAPIP().toString().c_str(), wifiManager->getConfigPortalSSID().c_str(), softAP_password.c_str()); -// vTaskDelay(pdMS_TO_TICKS(1000)); delay(6000); const String qrText = "qrWIFI:S:" + wifiManager->getConfigPortalSSID() + ";T:WPA;P:" + softAP_password.c_str() + ";;"; const String explainText = "*SSID: *\r\n" + wifiManager->getConfigPortalSSID() + "\r\n\r\n*Password:*\r\n" + softAP_password; std::array epdContent = {"Welcome!", "", "To setup\r\nscan QR or\r\nconnect\r\nmanually", "", explainText, "", qrText}; setEpdContent(epdContent); - delay(3000); - Serial.println("xTask"); - xTaskNotifyGive(epdTaskHandle); }); + }); wm.setSaveConfigCallback([]() { @@ -143,8 +140,6 @@ void setupTime() delay(500); Serial.println(F("Retry set time")); } - - Serial.println(&timeinfo, "%A, %B %d %Y %H:%M:%S"); } void setupPreferences() @@ -154,6 +149,8 @@ void setupPreferences() setFgColor(preferences.getUInt("fgColor", DEFAULT_FG_COLOR)); setBgColor(preferences.getUInt("bgColor", DEFAULT_BG_COLOR)); + setBlockHeight(preferences.getUInt("blockHeight", 816000)); + setPrice(preferences.getUInt("lastPrice", 30000)); screenNameMap[SCREEN_BLOCK_HEIGHT] = "Block Height"; screenNameMap[SCREEN_MSCW_TIME] = "Sats per dollar"; @@ -201,12 +198,8 @@ void setupHardware() WiFi.setHostname(getMyHostname().c_str()); ; - if (psramInit()) - { - Serial.println(F("PSRAM is correctly initialized")); - } - else - { + if (!psramInit()) + { Serial.println(F("PSRAM not available")); } diff --git a/src/lib/epd.cpp b/src/lib/epd.cpp index 75b0ab0..248a035 100644 --- a/src/lib/epd.cpp +++ b/src/lib/epd.cpp @@ -53,7 +53,10 @@ std::array currentEpdContent; std::array epdContent; uint32_t lastFullRefresh[NUM_SCREENS]; TaskHandle_t tasks[NUM_SCREENS]; -TaskHandle_t epdTaskHandle = NULL; +// TaskHandle_t epdTaskHandle = NULL; + +#define UPDATE_QUEUE_SIZE 14 +QueueHandle_t updateQueue; SemaphoreHandle_t epdUpdateSemaphore[NUM_SCREENS]; @@ -72,6 +75,10 @@ void setupDisplays() displays[i].init(); } + updateQueue = xQueueCreate(UPDATE_QUEUE_SIZE, sizeof(UpdateDisplayTaskItem)); + + xTaskCreate(prepareDisplayUpdateTask, "PrepareUpd", 4096, NULL, tskIDLE_PRIORITY, NULL); + for (uint i = 0; i < NUM_SCREENS; i++) { epdUpdateSemaphore[i] = xSemaphoreCreateBinary(); @@ -80,11 +87,9 @@ void setupDisplays() int *taskParam = new int; *taskParam = i; - xTaskCreate(updateDisplay, ("EpdUpd" + String(i)).c_str(), 4096, taskParam, tskIDLE_PRIORITY, &tasks[i]); // create task + xTaskCreate(updateDisplay, ("EpdUpd" + String(i)).c_str(), 2048, taskParam, tskIDLE_PRIORITY, &tasks[i]); // create task } - xTaskCreate(taskEpd, "epd_task", 2048, NULL, tskIDLE_PRIORITY, &epdTaskHandle); - epdContent = {"B", "T", "C", @@ -94,99 +99,59 @@ void setupDisplays() "K"}; setEpdContent(epdContent); - for (uint i = 0; i < NUM_SCREENS; i++) - { - xTaskNotifyGive(tasks[i]); - } -} - -void taskEpd(void *pvParameters) -{ - while (1) - { - ulTaskNotifyTake(pdTRUE, portMAX_DELAY); - - bool updatedThisCycle = false; - - for (uint i = 0; i < NUM_SCREENS; i++) - { - if (epdContent[i].compareTo(currentEpdContent[i]) != 0) - { - if (!updatedThisCycle) - { - updatedThisCycle = true; - } - - if (xSemaphoreTake(epdUpdateSemaphore[i], pdMS_TO_TICKS(5000)) == pdTRUE) - { - xTaskNotifyGive(tasks[i]); - } - else - { - Serial.println("Couldnt get screen" + String(i)); - } - } - } - } } void setEpdContent(std::array newEpdContent) { epdContent = newEpdContent; - if (epdTaskHandle != NULL) - xTaskNotifyGive(epdTaskHandle); + + for (uint i = 0; i < NUM_SCREENS; i++) + { + if (epdContent[i].compareTo(currentEpdContent[i]) != 0) + { + UpdateDisplayTaskItem dispUpdate = {i}; + xQueueSend(updateQueue, &dispUpdate, portMAX_DELAY); + // if (xSemaphoreTake(epdUpdateSemaphore[i], pdMS_TO_TICKS(5000)) == pdTRUE) + // { + // xTaskNotifyGive(tasks[i]); + // } + } + } + if (eventSourceTaskHandle != NULL) xTaskNotifyGive(eventSourceTaskHandle); } -extern "C" void updateDisplay(void *pvParameters) noexcept +void prepareDisplayUpdateTask(void *pvParameters) { - const int epdIndex = *(int *)pvParameters; - delete (int *)pvParameters; + UpdateDisplayTaskItem receivedItem; - for (;;) + while (1) { - // Wait for the task notification - ulTaskNotifyTake(pdTRUE, portMAX_DELAY); - - if (epdContent[epdIndex].compareTo(currentEpdContent[epdIndex]) != 0) + // Wait for a work item to be available in the queue + if (xQueueReceive(updateQueue, &receivedItem, portMAX_DELAY)) { - - displays[epdIndex].init(0, false); // Little longer reset duration because of MCP - uint count = 0; - while (EPD_BUSY[epdIndex].digitalRead() == HIGH || count < 10) + uint epdIndex = receivedItem.dispNum; + if (epdContent[epdIndex].compareTo(currentEpdContent[epdIndex]) != 0) { - vTaskDelay(pdMS_TO_TICKS(100)); - if (count >= 9) - { - displays[epdIndex].init(0, false); - } - count++; + + displays[epdIndex].init(0, false); // Little longer reset duration because of MCP } bool updatePartial = true; - // Full Refresh every half hour - if (!lastFullRefresh[epdIndex] || (millis() - lastFullRefresh[epdIndex]) > (preferences.getUInt("fullRefreshMin", 30) * 60 * 1000)) - { - updatePartial = false; - lastFullRefresh[epdIndex] = millis(); - } - - // if (updatePartial) + // // Full Refresh every half hour + // if (!lastFullRefresh[epdIndex] || (millis() - lastFullRefresh[epdIndex]) > (preferences.getUInt("fullRefreshMin", 30) * 60 * 1000)) // { - // displays[epdIndex].setPartialWindow(0, 0, displays[i].width(), display[i].height()); + // updatePartial = false; + // lastFullRefresh[epdIndex] = millis(); // } 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); -#ifdef PAGED_WRITE - splitTextPaged(epdIndex, top, bottom, updatePartial); -#else splitText(epdIndex, top, bottom, updatePartial); -#endif } else if (epdContent[epdIndex].startsWith(F("qr"))) { @@ -199,20 +164,101 @@ extern "C" void updateDisplay(void *pvParameters) noexcept else { -#ifdef PAGED_WRITE - showDigitPaged(epdIndex, epdContent[epdIndex].c_str()[0], updatePartial, &FONT_BIG); -#else - if (epdContent[epdIndex].length() > 1) { - showChars(epdIndex, epdContent[epdIndex], updatePartial, &Antonio_SemiBold30pt7b); - } else { - showDigit(epdIndex, epdContent[epdIndex].c_str()[0], updatePartial, &FONT_BIG); + if (epdContent[epdIndex].length() > 1) + { + showChars(epdIndex, epdContent[epdIndex], updatePartial, &Antonio_SemiBold30pt7b); + } + else + { + showDigit(epdIndex, epdContent[epdIndex].c_str()[0], updatePartial, &FONT_BIG); } -#endif } -#ifdef PAGED_WRITE - currentEpdContent[epdIndex] = epdContent[epdIndex]; -#else + if (xSemaphoreTake(epdUpdateSemaphore[epdIndex], pdMS_TO_TICKS(5000)) == pdTRUE) + { + xTaskNotifyGive(tasks[epdIndex]); + } + } + } +} + +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); + + // if (epdContent[epdIndex].compareTo(currentEpdContent[epdIndex]) != 0) + // { + + // displays[epdIndex].init(0, false); // Little longer reset duration because of MCP + uint count = 0; + while (EPD_BUSY[epdIndex].digitalRead() == HIGH || count < 10) + { + vTaskDelay(pdMS_TO_TICKS(100)); + // if (count >= 9) + // { + // displays[epdIndex].init(0, false); + // } + count++; + } + + bool updatePartial = true; + + // Full Refresh every half hour + if (!lastFullRefresh[epdIndex] || (millis() - lastFullRefresh[epdIndex]) > (preferences.getUInt("fullRefreshMin", 30) * 60 * 1000)) + { + updatePartial = false; + lastFullRefresh[epdIndex] = millis(); + } + +// // if (updatePartial) +// // { +// // displays[epdIndex].setPartialWindow(0, 0, displays[i].width(), display[i].height()); +// // } + +// 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); +// #ifdef PAGED_WRITE +// splitTextPaged(epdIndex, top, bottom, updatePartial); +// #else +// splitText(epdIndex, top, bottom, updatePartial); +// #endif +// } +// else if (epdContent[epdIndex].startsWith(F("qr"))) +// { +// renderQr(epdIndex, epdContent[epdIndex], updatePartial); +// } +// else if (epdContent[epdIndex].length() > 5) +// { +// renderText(epdIndex, epdContent[epdIndex], updatePartial); +// } +// else +// { + +// #ifdef PAGED_WRITE +// showDigitPaged(epdIndex, epdContent[epdIndex].c_str()[0], updatePartial, &FONT_BIG); +// #else +// if (epdContent[epdIndex].length() > 1) +// { +// showChars(epdIndex, epdContent[epdIndex], updatePartial, &Antonio_SemiBold30pt7b); +// } +// else +// { +// showDigit(epdIndex, epdContent[epdIndex].c_str()[0], updatePartial, &FONT_BIG); +// } +// #endif +// } + +// #ifdef PAGED_WRITE +// currentEpdContent[epdIndex] = epdContent[epdIndex]; +// #else char tries = 0; while (tries < 3) { @@ -227,8 +273,8 @@ extern "C" void updateDisplay(void *pvParameters) noexcept } currentEpdContent[epdIndex] = epdContent[epdIndex]; -#endif - } +// #endif + // } xSemaphoreGive(epdUpdateSemaphore[epdIndex]); } } @@ -273,54 +319,54 @@ void splitText(const uint dispNum, const String &top, const String &bottom, bool displays[dispNum].print(bottom); } -void splitTextPaged(const uint dispNum, String top, String bottom, bool partial) -{ - displays[dispNum].setRotation(2); - displays[dispNum].setFont(&FONT_SMALL); - displays[dispNum].setTextColor(getFgColor()); +// void splitTextPaged(const uint dispNum, String top, String bottom, bool partial) +// { +// 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; +// // 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; +// // 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); +// // 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); - if (partial) - { - displays[dispNum].setPartialWindow(0, 0, displays[dispNum].width(), displays[dispNum].height()); - } - else - { - displays[dispNum].setFullWindow(); - } - displays[dispNum].firstPage(); +// if (partial) +// { +// displays[dispNum].setPartialWindow(0, 0, displays[dispNum].width(), displays[dispNum].height()); +// } +// else +// { +// displays[dispNum].setFullWindow(); +// } +// displays[dispNum].firstPage(); - do - { - 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); - } while (displays[dispNum].nextPage()); -} +// do +// { +// 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); +// } while (displays[dispNum].nextPage()); +// } void showDigit(const uint dispNum, char chr, bool partial, const GFXfont *font) { @@ -339,7 +385,8 @@ void showDigit(const uint dispNum, char chr, bool partial, const GFXfont *font) displays[dispNum].print(str); } -void showChars(const uint dispNum, const String& chars, bool partial, const GFXfont *font) { +void showChars(const uint dispNum, const String &chars, bool partial, const GFXfont *font) +{ displays[dispNum].setRotation(2); displays[dispNum].setFont(font); displays[dispNum].setTextColor(getFgColor()); @@ -354,35 +401,35 @@ void showChars(const uint dispNum, const String& chars, bool partial, const GFXf displays[dispNum].print(chars); } -void showDigitPaged(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; - if (partial) - { - displays[dispNum].setPartialWindow(0, 0, displays[dispNum].width(), displays[dispNum].height()); - } - else - { - displays[dispNum].setFullWindow(); - } - displays[dispNum].firstPage(); +// void showDigitPaged(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; +// if (partial) +// { +// displays[dispNum].setPartialWindow(0, 0, displays[dispNum].width(), displays[dispNum].height()); +// } +// else +// { +// displays[dispNum].setFullWindow(); +// } +// displays[dispNum].firstPage(); - do - { - displays[dispNum].fillScreen(getBgColor()); - displays[dispNum].setCursor(x, y); - displays[dispNum].print(str); - } while (displays[dispNum].nextPage()); -} +// do +// { +// displays[dispNum].fillScreen(getBgColor()); +// displays[dispNum].setCursor(x, y); +// displays[dispNum].print(str); +// } while (displays[dispNum].nextPage()); +// } int getBgColor() { @@ -406,11 +453,6 @@ void setFgColor(int color) std::array getCurrentEpdContent() { - // Serial.println("currentEpdContent"); - - // for (int i = 0; i < NUM_SCREENS; i++) { - // Serial.printf("%d = %s", i, currentEpdContent[i]); - // } return currentEpdContent; } void renderText(const uint dispNum, const String &text, bool partial) @@ -445,12 +487,12 @@ void renderText(const uint dispNum, const String &text, bool partial) } } - //displays[dispNum].display(partial); + // displays[dispNum].display(partial); } void renderQr(const uint dispNum, const String &text, bool partial) { - #ifdef USE_QR +#ifdef USE_QR uint8_t tempBuffer[800]; bool ok = qrcodegen_encodeText(text.substring(2).c_str(), tempBuffer, qrcode, qrcodegen_Ecc_LOW, @@ -473,16 +515,19 @@ void renderQr(const uint dispNum, const String &text, bool partial) displays[dispNum].drawPixel(padding + x, paddingY + y, qrcodegen_getModule(qrcode, floor(float(x) / 4), floor(float(y) / 4)) ? GxEPD_BLACK : GxEPD_WHITE); } } - //displays[dispNum].display(partial); +// displays[dispNum].display(partial); - //free(tempBuffer); - //free(qrcode); - #endif +// free(tempBuffer); +// free(qrcode); +#endif } -void waitUntilNoneBusy() { - for (int i = 0; i < NUM_SCREENS; i++) { - while (EPD_BUSY[i].digitalRead()) { +void waitUntilNoneBusy() +{ + for (int i = 0; i < NUM_SCREENS; i++) + { + while (EPD_BUSY[i].digitalRead()) + { vTaskDelay(10); } } diff --git a/src/lib/epd.hpp b/src/lib/epd.hpp index f679021..b4601fc 100644 --- a/src/lib/epd.hpp +++ b/src/lib/epd.hpp @@ -13,21 +13,27 @@ #ifdef USE_QR #include "qrcodegen.h" #endif -extern TaskHandle_t epdTaskHandle; +// extern TaskHandle_t epdTaskHandle; + +typedef struct +{ + char dispNum; +} UpdateDisplayTaskItem; void setupDisplays(); -void taskEpd(void *pvParameters); +// void taskEpd(void *pvParameters); void splitText(const uint dispNum, const String& top, const String& bottom, bool partial); -void splitTextPaged(const uint dispNum, String top, String bottom, bool partial); +//void splitTextPaged(const uint dispNum, String top, 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); -void showDigitPaged(const uint dispNum, char chr, bool partial, const GFXfont *font); +//void showDigitPaged(const uint dispNum, char chr, bool partial, const GFXfont *font); extern "C" void updateDisplay(void *pvParameters) noexcept; void updateDisplayAlt(int epdIndex); +void prepareDisplayUpdateTask(void *pvParameters); int getBgColor(); int getFgColor(); diff --git a/src/lib/ota.cpp b/src/lib/ota.cpp index bf6394c..ad5800d 100644 --- a/src/lib/ota.cpp +++ b/src/lib/ota.cpp @@ -29,9 +29,9 @@ void onOTAStart() esp_timer_stop(minuteTimer); // Stop or suspend all tasks - vTaskSuspend(priceUpdateTaskHandle); - vTaskSuspend(blockUpdateTaskHandle); - vTaskSuspend(timeUpdateTaskHandle); + // vTaskSuspend(priceUpdateTaskHandle); +// vTaskSuspend(blockUpdateTaskHandle); + vTaskSuspend(workerTaskHandle); vTaskSuspend(taskScreenRotateTaskHandle); vTaskSuspend(ledTaskHandle); @@ -48,4 +48,7 @@ void handleOTATask(void *parameter) { ArduinoOTA.handle(); // Allow OTA updates to occur vTaskDelay(pdMS_TO_TICKS(2500)); } +} + +void downloadUpdate() { } \ No newline at end of file diff --git a/src/lib/ota.hpp b/src/lib/ota.hpp index 4ecdf5d..7a6ec81 100644 --- a/src/lib/ota.hpp +++ b/src/lib/ota.hpp @@ -5,4 +5,5 @@ void setupOTA(); void onOTAStart(); -void handleOTATask(void *parameter); \ No newline at end of file +void handleOTATask(void *parameter); +void downloadUpdate(); \ No newline at end of file diff --git a/src/lib/price_notify.cpp b/src/lib/price_notify.cpp index 0cf6129..107dd09 100644 --- a/src/lib/price_notify.cpp +++ b/src/lib/price_notify.cpp @@ -1,16 +1,52 @@ #include "price_notify.hpp" const char *wsServerPrice = "wss://ws.coincap.io/prices?assets=bitcoin"; + +// const char* coinCapWsCert = R"(-----BEGIN CERTIFICATE----- +// MIIFMjCCBNmgAwIBAgIQBtgXvFyc28MsvQ1HjCnXJTAKBggqhkjOPQQDAjBKMQsw +// CQYDVQQGEwJVUzEZMBcGA1UEChMQQ2xvdWRmbGFyZSwgSW5jLjEgMB4GA1UEAxMX +// Q2xvdWRmbGFyZSBJbmMgRUNDIENBLTMwHhcNMjMwNTEwMDAwMDAwWhcNMjQwNTA5 +// MjM1OTU5WjB1MQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQG +// A1UEBxMNU2FuIEZyYW5jaXNjbzEZMBcGA1UEChMQQ2xvdWRmbGFyZSwgSW5jLjEe +// MBwGA1UEAxMVc25pLmNsb3VkZmxhcmVzc2wuY29tMFkwEwYHKoZIzj0CAQYIKoZI +// zj0DAQcDQgAEpvFIXzQKHuqTo+IE6c6sB4p0PMXK1KsseEGf2UN/CNRhG5hO7lr8 +// JtXrPZkawWBysZxOsEoetkPrDHMugCLfXKOCA3QwggNwMB8GA1UdIwQYMBaAFKXO +// N+rrsHUOlGeItEX62SQQh5YfMB0GA1UdDgQWBBShsZDJohaR1a5E0Qj7yblZjKDC +// gDA6BgNVHREEMzAxggwqLmNvaW5jYXAuaW+CCmNvaW5jYXAuaW+CFXNuaS5jbG91 +// ZGZsYXJlc3NsLmNvbTAOBgNVHQ8BAf8EBAMCB4AwHQYDVR0lBBYwFAYIKwYBBQUH +// AwEGCCsGAQUFBwMCMHsGA1UdHwR0MHIwN6A1oDOGMWh0dHA6Ly9jcmwzLmRpZ2lj +// ZXJ0LmNvbS9DbG91ZGZsYXJlSW5jRUNDQ0EtMy5jcmwwN6A1oDOGMWh0dHA6Ly9j +// cmw0LmRpZ2ljZXJ0LmNvbS9DbG91ZGZsYXJlSW5jRUNDQ0EtMy5jcmwwPgYDVR0g +// BDcwNTAzBgZngQwBAgIwKTAnBggrBgEFBQcCARYbaHR0cDovL3d3dy5kaWdpY2Vy +// dC5jb20vQ1BTMHYGCCsGAQUFBwEBBGowaDAkBggrBgEFBQcwAYYYaHR0cDovL29j +// c3AuZGlnaWNlcnQuY29tMEAGCCsGAQUFBzAChjRodHRwOi8vY2FjZXJ0cy5kaWdp +// Y2VydC5jb20vQ2xvdWRmbGFyZUluY0VDQ0NBLTMuY3J0MAwGA1UdEwEB/wQCMAAw +// ggF+BgorBgEEAdZ5AgQCBIIBbgSCAWoBaAB1AO7N0GTV2xrOxVy3nbTNE6Iyh0Z8 +// vOzew1FIWUZxH7WbAAABiAPnoRAAAAQDAEYwRAIgAP2W09OozuhmKeKKMsaVBcae +// o+nPHF1WUWk0i387YYYCIDIM1Wll7/4O3GNx2/Fx9bC6pi69Uya4pLxsCfW3fZMe +// AHYASLDja9qmRzQP5WoC+p0w6xxSActW3SyB2bu/qznYhHMAAAGIA+eg+QAABAMA +// RzBFAiEAuNpSqrbx47gYBgBMz5M6q0CnV/WMJqWQOxYFKrwfwVACIH3nCs4bKToT +// e+MiBrqSDaekixk4kPFEQESO9qHCkWY5AHcA2ra/az+1tiKfm8K7XGvocJFxbLtR +// hIU0vaQ9MEjX+6sAAAGIA+eg1gAABAMASDBGAiEAolCFl2IfbOHUPAOxoi4BLclS +// v9FVXb7LwIvTuCfyrEQCIQDcvehwhV9XGopKGl17F2LYYKI7hvlO3RmpPZQJt1da +// MDAKBggqhkjOPQQDAgNHADBEAiAXRWZ/JVMsfpSFFTHQHUSqRnQ/7cCOWx+9svIy +// mYnFZQIgHMEG0Cm7O4cn5KUzKOsTwwK+2U15s/jPUQi2n2IDTEM= +// -----END CERTIFICATE-----)"; + // WebsocketsClient client; esp_websocket_client_handle_t clientPrice = NULL; -unsigned long int currentPrice = 30000; +uint currentPrice = 30000; unsigned long int lastPriceUpdate; void setupPriceNotify() { +// currentPrice = preferences.get("lastPrice", 30000); + esp_websocket_client_config_t config = { .uri = wsServerPrice, - .user_agent = USER_AGENT, + // .task_stack = (7*1024), + // .cert_pem = coinCapWsCert, + .user_agent = USER_AGENT }; clientPrice = esp_websocket_client_init(&config); @@ -53,22 +89,28 @@ void onWebsocketPriceMessage(esp_websocket_event_data_t* event_data) if (lastPriceUpdate == 0 || (currentTime - lastPriceUpdate) > minSecPriceUpd) { // const unsigned long oldPrice = currentPrice; - currentPrice = doc["bitcoin"].as(); - + currentPrice = doc["bitcoin"].as(); + preferences.putUInt("lastPrice", currentPrice); lastPriceUpdate = currentTime; // if (abs((int)(oldPrice-currentPrice)) > round(0.0015*oldPrice)) { - if (priceUpdateTaskHandle != nullptr && (getCurrentScreen() == SCREEN_BTC_TICKER || getCurrentScreen() == SCREEN_MSCW_TIME || getCurrentScreen() == SCREEN_MARKET_CAP)) - xTaskNotifyGive(priceUpdateTaskHandle); + if (workQueue != nullptr && (getCurrentScreen() == SCREEN_BTC_TICKER || getCurrentScreen() == SCREEN_MSCW_TIME || getCurrentScreen() == SCREEN_MARKET_CAP)) { + WorkItem priceUpdate = {TASK_PRICE_UPDATE, 0}; + xQueueSend(workQueue, &priceUpdate, portMAX_DELAY); + } //} } } } } -unsigned long getPrice() { +uint getPrice() { return currentPrice; } +void setPrice(uint newPrice) { + currentPrice = newPrice; +} + bool isPriceNotifyConnected() { if (clientPrice == NULL) return false; diff --git a/src/lib/price_notify.hpp b/src/lib/price_notify.hpp index 0694cce..9ac9573 100644 --- a/src/lib/price_notify.hpp +++ b/src/lib/price_notify.hpp @@ -14,6 +14,8 @@ void setupPriceNotify(); void onWebsocketPriceEvent(void *handler_args, esp_event_base_t base, int32_t event_id, void *event_data); void onWebsocketPriceMessage(esp_websocket_event_data_t* event_data); -unsigned long getPrice(); +uint getPrice(); +void setPrice(uint newPrice); + bool isPriceNotifyConnected(); void stopPriceNotify(); \ No newline at end of file diff --git a/src/lib/screen_handler.cpp b/src/lib/screen_handler.cpp index 71a6213..2005442 100644 --- a/src/lib/screen_handler.cpp +++ b/src/lib/screen_handler.cpp @@ -1,9 +1,10 @@ #include "screen_handler.hpp" -TaskHandle_t priceUpdateTaskHandle; -TaskHandle_t blockUpdateTaskHandle; -TaskHandle_t timeUpdateTaskHandle; +// TaskHandle_t priceUpdateTaskHandle; +// TaskHandle_t blockUpdateTaskHandle; +// TaskHandle_t timeUpdateTaskHandle; TaskHandle_t taskScreenRotateTaskHandle; +TaskHandle_t workerTaskHandle; esp_timer_handle_t screenRotateTimer; esp_timer_handle_t minuteTimer; @@ -11,89 +12,196 @@ std::array taskEpdContent = {"", "", "", "", "", "", ""}; std::string priceString; const int usPerSecond = 1000000; const int usPerMinute = 60 * usPerSecond; -int64_t next_callback_time = 0; + +// typedef enum +// { +// TASK_PRICE_UPDATE, +// TASK_BLOCK_UPDATE, +// TASK_TIME_UPDATE +// } TaskType; + +// typedef struct +// { +// TaskType type; +// unsigned long data; +// } WorkItem; + +#define WORK_QUEUE_SIZE 10 +QueueHandle_t workQueue; uint currentScreen; -void taskPriceUpdate(void *pvParameters) +void workerTask(void *pvParameters) { - for (;;) + WorkItem receivedItem; + + while (1) { - ulTaskNotifyTake(pdTRUE, portMAX_DELAY); - - unsigned long price = getPrice(); - uint firstIndex = 0; - if (getCurrentScreen() == SCREEN_BTC_TICKER) + // Wait for a work item to be available in the queue + if (xQueueReceive(workQueue, &receivedItem, portMAX_DELAY)) { - priceString = ("$" + String(price)).c_str(); + uint firstIndex = 0; - if (priceString.length() < (NUM_SCREENS)) + // Process the work item based on its type + switch (receivedItem.type) { - priceString.insert(priceString.begin(), NUM_SCREENS - priceString.length(), ' '); - taskEpdContent[0] = "BTC/USD"; - firstIndex = 1; - } - } - else if (getCurrentScreen() == SCREEN_MSCW_TIME) - { - priceString = String(int(round(1 / float(price) * 10e7))).c_str(); - - if (priceString.length() < (NUM_SCREENS)) + case TASK_PRICE_UPDATE: { - priceString.insert(priceString.begin(), NUM_SCREENS - priceString.length(), ' '); - taskEpdContent[0] = "MSCW/TIME"; - firstIndex = 1; - } - } - else - { - double supply = getSupplyAtBlock(getBlockHeight()); - int64_t marketCap = static_cast(supply * double(price)); - - - taskEpdContent[0] = "USD/MCAP"; - - if (preferences.getBool("mcapBigChar", true)) { - firstIndex = 1; - - priceString = "$" + formatNumberWithSuffix(marketCap); - priceString.insert(priceString.begin(), NUM_SCREENS - priceString.length(), ' '); - - } else { - std::string stringValue = std::to_string(marketCap); - size_t mcLength = stringValue.length(); - size_t leadingSpaces = (3 - mcLength % 3) % 3; - stringValue = std::string(leadingSpaces, ' ') + stringValue; - - uint groups = (mcLength + leadingSpaces) / 3; - - if (groups < NUM_SCREENS) { - firstIndex = 1; - } - - for (int i = firstIndex; i < NUM_SCREENS-groups-1; i++) { - taskEpdContent[i] = ""; - } - - taskEpdContent[NUM_SCREENS-groups-1] = " $ "; - for (uint i = 0; i < groups; i ++) + firstIndex = 0; + uint price = getPrice(); + if (getCurrentScreen() == SCREEN_BTC_TICKER) { - taskEpdContent[(NUM_SCREENS-groups+i)] = stringValue.substr(i*3, 3).c_str(); + priceString = ("$" + String(price)).c_str(); + + if (priceString.length() < (NUM_SCREENS)) + { + priceString.insert(priceString.begin(), NUM_SCREENS - priceString.length(), ' '); + taskEpdContent[0] = "BTC/USD"; + firstIndex = 1; + } } - } - } + else if (getCurrentScreen() == SCREEN_MSCW_TIME) + { + priceString = String(int(round(1 / float(price) * 10e7))).c_str(); - if (!(getCurrentScreen() == SCREEN_MARKET_CAP && !preferences.getBool("mcapBigChar", true))) { - for (uint i = firstIndex; i < NUM_SCREENS; i++) + if (priceString.length() < (NUM_SCREENS)) + { + priceString.insert(priceString.begin(), NUM_SCREENS - priceString.length(), ' '); + taskEpdContent[0] = "MSCW/TIME"; + firstIndex = 1; + } + } + else + { + double supply = getSupplyAtBlock(getBlockHeight()); + int64_t marketCap = static_cast(supply * double(price)); + + taskEpdContent[0] = "USD/MCAP"; + + if (preferences.getBool("mcapBigChar", true)) + { + firstIndex = 1; + + priceString = "$" + formatNumberWithSuffix(marketCap); + priceString.insert(priceString.begin(), NUM_SCREENS - priceString.length(), ' '); + } + else + { + std::string stringValue = std::to_string(marketCap); + size_t mcLength = stringValue.length(); + size_t leadingSpaces = (3 - mcLength % 3) % 3; + stringValue = std::string(leadingSpaces, ' ') + stringValue; + + uint groups = (mcLength + leadingSpaces) / 3; + + if (groups < NUM_SCREENS) + { + firstIndex = 1; + } + + for (int i = firstIndex; i < NUM_SCREENS - groups - 1; i++) + { + taskEpdContent[i] = ""; + } + + taskEpdContent[NUM_SCREENS - groups - 1] = " $ "; + for (uint i = 0; i < groups; i++) + { + taskEpdContent[(NUM_SCREENS - groups + i)] = stringValue.substr(i * 3, 3).c_str(); + } + } + } + + if (!(getCurrentScreen() == SCREEN_MARKET_CAP && !preferences.getBool("mcapBigChar", true))) + { + for (uint i = firstIndex; i < NUM_SCREENS; i++) + { + taskEpdContent[i] = priceString[i]; + } + } + + setEpdContent(taskEpdContent); + break; + } + case TASK_BLOCK_UPDATE: { - taskEpdContent[i] = priceString[i]; + std::string blockNrString = String(getBlockHeight()).c_str(); + firstIndex = 0; + + if (getCurrentScreen() != SCREEN_HALVING_COUNTDOWN) + { + if (blockNrString.length() < NUM_SCREENS) + { + blockNrString.insert(blockNrString.begin(), NUM_SCREENS - blockNrString.length(), ' '); + taskEpdContent[0] = "BLOCK/HEIGHT"; + firstIndex = 1; + } + + for (uint i = firstIndex; i < NUM_SCREENS; i++) + { + taskEpdContent[i] = blockNrString[i]; + } + } + else + { + const uint nextHalvingBlock = 210000 - (getBlockHeight() % 210000); + const uint minutesToHalving = nextHalvingBlock * 10; + + const int years = floor(minutesToHalving / 525600); + const int days = floor((minutesToHalving - (years * 525600)) / (24 * 60)); + const int hours = floor((minutesToHalving - (years * 525600) - (days * (24 * 60))) / 60); + const int mins = floor(minutesToHalving - (years * 525600) - (days * (24 * 60)) - (hours * 60)); + taskEpdContent[0] = "BIT/COIN"; + taskEpdContent[1] = "HALV/ING"; + taskEpdContent[(NUM_SCREENS - 5)] = String(years) + "/YRS"; + taskEpdContent[(NUM_SCREENS - 4)] = String(days) + "/DAYS"; + taskEpdContent[(NUM_SCREENS - 3)] = String(days) + "/HRS"; + taskEpdContent[(NUM_SCREENS - 2)] = String(mins) + "/MINS"; + taskEpdContent[(NUM_SCREENS - 1)] = "TO/GO"; + } + + if (getCurrentScreen() == SCREEN_HALVING_COUNTDOWN || getCurrentScreen() == SCREEN_BLOCK_HEIGHT) + { + setEpdContent(taskEpdContent); + } + break; + } + case TASK_TIME_UPDATE: + { + if (getCurrentScreen() == SCREEN_TIME) + { + time_t currentTime; + struct tm timeinfo; + time(¤tTime); + localtime_r(¤tTime, &timeinfo); + std::string timeString; + + String minute = String(timeinfo.tm_min); + if (minute.length() < 2) + { + minute = "0" + minute; + } + + timeString = std::to_string(timeinfo.tm_hour) + ":" + minute.c_str(); + timeString.insert(timeString.begin(), NUM_SCREENS - timeString.length(), ' '); + taskEpdContent[0] = String(timeinfo.tm_mday) + "/" + String(timeinfo.tm_mon + 1); + + for (uint i = 1; i < NUM_SCREENS; i++) + { + taskEpdContent[i] = timeString[i]; + } + setEpdContent(taskEpdContent); + } + + break; + } + // Add more cases for additional task types } } - - setEpdContent(taskEpdContent); } } + void taskScreenRotate(void *pvParameters) { for (;;) @@ -113,97 +221,16 @@ void taskScreenRotate(void *pvParameters) } } -void taskBlockUpdate(void *pvParameters) -{ - for (;;) - { - ulTaskNotifyTake(pdTRUE, portMAX_DELAY); - - std::string blockNrString = String(getBlockHeight()).c_str(); - uint firstIndex = 0; - - if (getCurrentScreen() != SCREEN_HALVING_COUNTDOWN) - { - if (blockNrString.length() < NUM_SCREENS) - { - blockNrString.insert(blockNrString.begin(), NUM_SCREENS - blockNrString.length(), ' '); - taskEpdContent[0] = "BLOCK/HEIGHT"; - firstIndex = 1; - } - - for (uint i = firstIndex; i < NUM_SCREENS; i++) - { - taskEpdContent[i] = blockNrString[i]; - } - } - else - { - const uint nextHalvingBlock = 210000 - (getBlockHeight() % 210000); - const uint minutesToHalving = nextHalvingBlock * 10; - - const int years = floor(minutesToHalving / 525600); - const int days = floor((minutesToHalving - (years * 525600)) / (24 * 60)); - const int hours = floor((minutesToHalving - (years * 525600) - (days * (24 * 60))) / 60); - const int mins = floor(minutesToHalving - (years * 525600) - (days * (24 * 60)) - (hours * 60)); - taskEpdContent[0] = "BIT/COIN"; - taskEpdContent[1] = "HALV/ING"; - taskEpdContent[(NUM_SCREENS - 5)] = String(years) + "/YRS"; - taskEpdContent[(NUM_SCREENS - 4)] = String(days) + "/DAYS"; - taskEpdContent[(NUM_SCREENS - 3)] = String(days) + "/HRS"; - taskEpdContent[(NUM_SCREENS - 2)] = String(mins) + "/MINS"; - taskEpdContent[(NUM_SCREENS - 1)] = "TO/GO"; - } - - if (getCurrentScreen() == SCREEN_HALVING_COUNTDOWN || getCurrentScreen() == SCREEN_BLOCK_HEIGHT) - { - setEpdContent(taskEpdContent); - } - } -} - -void taskTimeUpdate(void *pvParameters) -{ - for (;;) - { - if (getCurrentScreen() == SCREEN_TIME) - { - time_t currentTime; - struct tm timeinfo; - time(¤tTime); - localtime_r(¤tTime, &timeinfo); - std::string timeString; - - String minute = String(timeinfo.tm_min); - if (minute.length() < 2) - { - minute = "0" + minute; - } - - timeString = std::to_string(timeinfo.tm_hour) + ":" + minute.c_str(); - timeString.insert(timeString.begin(), NUM_SCREENS - timeString.length(), ' '); - taskEpdContent[0] = String(timeinfo.tm_mday) + "/" + String(timeinfo.tm_mon + 1); - - for (uint i = 1; i < NUM_SCREENS; i++) - { - taskEpdContent[i] = timeString[i]; - } - setEpdContent(taskEpdContent); - } - - ulTaskNotifyTake(pdTRUE, portMAX_DELAY); - } -} - void IRAM_ATTR minuteTimerISR(void *arg) { BaseType_t xHigherPriorityTaskWoken = pdFALSE; - vTaskNotifyGiveFromISR(timeUpdateTaskHandle, &xHigherPriorityTaskWoken); +// vTaskNotifyGiveFromISR(timeUpdateTaskHandle, &xHigherPriorityTaskWoken); + WorkItem timeUpdate = {TASK_TIME_UPDATE, 0}; + xQueueSendFromISR(workQueue, &timeUpdate, &xHigherPriorityTaskWoken); if (xHigherPriorityTaskWoken == pdTRUE) { portYIELD_FROM_ISR(); } - int64_t current_time = esp_timer_get_time(); - next_callback_time = current_time + usPerMinute; } void IRAM_ATTR screenRotateTimerISR(void *arg) @@ -218,9 +245,13 @@ void IRAM_ATTR screenRotateTimerISR(void *arg) void setupTasks() { - xTaskCreate(taskPriceUpdate, "updatePrice", 3072, NULL, tskIDLE_PRIORITY, &priceUpdateTaskHandle); - xTaskCreate(taskBlockUpdate, "updateBlock", 2048, NULL, tskIDLE_PRIORITY, &blockUpdateTaskHandle); - xTaskCreate(taskTimeUpdate, "updateTime", 4096, NULL, tskIDLE_PRIORITY, &timeUpdateTaskHandle); + workQueue = xQueueCreate(WORK_QUEUE_SIZE, sizeof(WorkItem)); + + // xTaskCreate(taskPriceUpdate, "updatePrice", 1024, NULL, tskIDLE_PRIORITY, &priceUpdateTaskHandle); + // xTaskCreate(taskBlockUpdate, "updateBlock", 1024, NULL, tskIDLE_PRIORITY, &blockUpdateTaskHandle); + // xTaskCreate(taskTimeUpdate, "updateTime", 1024, NULL, tskIDLE_PRIORITY, &timeUpdateTaskHandle); + xTaskCreate(workerTask, "workerTask", 4096, NULL, tskIDLE_PRIORITY, &workerTaskHandle); + xTaskCreate(taskScreenRotate, "rotateScreen", 2048, NULL, tskIDLE_PRIORITY, &taskScreenRotateTaskHandle); setCurrentScreen(preferences.getUInt("currentScreen", 0)); @@ -244,7 +275,10 @@ void setupTimeUpdateTimer(void *pvParameters) vTaskDelay(pdMS_TO_TICKS((secondsUntilNextMinute * 1000))); esp_timer_start_periodic(minuteTimer, usPerMinute); - xTaskNotifyGive(timeUpdateTaskHandle); + + WorkItem timeUpdate = {TASK_TIME_UPDATE, 0}; + xQueueSend(workQueue, &timeUpdate, portMAX_DELAY); +// xTaskNotifyGive(timeUpdateTaskHandle); vTaskDelete(NULL); } @@ -316,18 +350,30 @@ void setCurrentScreen(uint newScreen) switch (currentScreen) { case SCREEN_TIME: - xTaskNotifyGive(timeUpdateTaskHandle); + { + WorkItem timeUpdate = {TASK_TIME_UPDATE, 0}; + xQueueSend(workQueue, &timeUpdate, portMAX_DELAY); + // xTaskNotifyGive(timeUpdateTaskHandle); break; + } case SCREEN_HALVING_COUNTDOWN: case SCREEN_BLOCK_HEIGHT: - xTaskNotifyGive(blockUpdateTaskHandle); + { + WorkItem blockUpdate = {TASK_BLOCK_UPDATE, 0}; + xQueueSend(workQueue, &blockUpdate, portMAX_DELAY); + //xTaskNotifyGive(blockUpdateTaskHandle); break; + } case SCREEN_MARKET_CAP: case SCREEN_MSCW_TIME: case SCREEN_BTC_TICKER: - xTaskNotifyGive(priceUpdateTaskHandle); + { + WorkItem priceUpdate = {TASK_PRICE_UPDATE, 0}; + xQueueSend(workQueue, &priceUpdate, portMAX_DELAY); + //xTaskNotifyGive(priceUpdateTaskHandle); break; } + } if (eventSourceTaskHandle != NULL) xTaskNotifyGive(eventSourceTaskHandle); diff --git a/src/lib/screen_handler.hpp b/src/lib/screen_handler.hpp index 3437597..45a6d61 100644 --- a/src/lib/screen_handler.hpp +++ b/src/lib/screen_handler.hpp @@ -8,15 +8,31 @@ #include "shared.hpp" #include "lib/epd.hpp" -extern TaskHandle_t priceUpdateTaskHandle; -extern TaskHandle_t blockUpdateTaskHandle; -extern TaskHandle_t timeUpdateTaskHandle; +// extern TaskHandle_t priceUpdateTaskHandle; +// extern TaskHandle_t blockUpdateTaskHandle; +// extern TaskHandle_t timeUpdateTaskHandle; +extern TaskHandle_t workerTaskHandle; extern TaskHandle_t taskScreenRotateTaskHandle; extern esp_timer_handle_t screenRotateTimer; extern esp_timer_handle_t minuteTimer; +extern QueueHandle_t workQueue; +typedef enum +{ + TASK_PRICE_UPDATE, + TASK_BLOCK_UPDATE, + TASK_TIME_UPDATE +} TaskType; + +typedef struct +{ + TaskType type; + char data; +} WorkItem; + +void workerTask(void *pvParameters); uint getCurrentScreen(); void setCurrentScreen(uint newScreen); void nextScreen(); @@ -30,9 +46,9 @@ void setupScreenRotateTimer(void *pvParameters); void IRAM_ATTR minuteTimerISR(void* arg); void IRAM_ATTR screenRotateTimerISR(void* arg); -void taskPriceUpdate(void *pvParameters); -void taskBlockUpdate(void *pvParameters); -void taskTimeUpdate(void *pvParameters); +// void taskPriceUpdate(void *pvParameters); +// void taskBlockUpdate(void *pvParameters); +// void taskTimeUpdate(void *pvParameters); void taskScreenRotate(void *pvParameters); uint getTimerSeconds(); diff --git a/src/lib/webserver.cpp b/src/lib/webserver.cpp index 1341450..d94c129 100644 --- a/src/lib/webserver.cpp +++ b/src/lib/webserver.cpp @@ -13,14 +13,7 @@ void setupWebserver() } events.onConnect([](AsyncEventSourceClient *client) - { - if (client->lastId()) - { - Serial.printf("Client reconnected! Last message ID that it gat is: %u\n", client->lastId()); - } - // send event with message "hello!", id current millis - // and set reconnect delay to 1 second - client->send("welcome",NULL,millis(),1000); }); + { client->send("welcome", NULL, millis(), 1000); }); server.addHandler(&events); server.serveStatic("/css", LittleFS, "/css/"); @@ -70,7 +63,8 @@ void setupWebserver() xTaskCreate(eventSourceTask, "eventSourceTask", 4096, NULL, tskIDLE_PRIORITY, &eventSourceTaskHandle); } -void stopWebServer() { +void stopWebServer() +{ server.end(); } @@ -145,8 +139,6 @@ void onApiStatus(AsyncWebServerRequest *request) void onApiActionPause(AsyncWebServerRequest *request) { setTimerActive(false); - Serial.println(F("Update timer paused")); - request->send(200); }; @@ -156,10 +148,7 @@ void onApiActionPause(AsyncWebServerRequest *request) */ void onApiActionTimerRestart(AsyncWebServerRequest *request) { - // moment = millis(); setTimerActive(true); - Serial.println(F("Update timer restarted")); - request->send(200); } @@ -290,13 +279,13 @@ void onApiSettingsPost(AsyncWebServerRequest *request) AsyncWebParameter *ledFlashOnUpdate = request->getParam("ledFlashOnUpd", true); preferences.putBool("ledFlashOnUpd", ledFlashOnUpdate->value().toInt()); - Serial.printf("Setting led flash on update to %d\r\n", ledFlashOnUpdate->value().toInt()); +// Serial.printf("Setting led flash on update to %d\r\n", ledFlashOnUpdate->value().toInt()); settingsChanged = true; } else { preferences.putBool("ledFlashOnUpd", 0); - Serial.print("Setting led flash on update to false"); +// Serial.print("Setting led flash on update to false"); settingsChanged = true; } @@ -305,13 +294,13 @@ void onApiSettingsPost(AsyncWebServerRequest *request) AsyncWebParameter *stealFocusOnBlock = request->getParam("stealFocusOnBlock", true); preferences.putBool("stealFocus", stealFocusOnBlock->value().toInt()); - Serial.printf("Setting steal focus on new block to %d\r\n", stealFocusOnBlock->value().toInt()); +// Serial.printf("Setting steal focus on new block to %d\r\n", stealFocusOnBlock->value().toInt()); settingsChanged = true; } else { preferences.putBool("stealFocus", 0); - Serial.print("Setting steal focus on new block to false"); +// Serial.print("Setting steal focus on new block to false"); settingsChanged = true; } @@ -326,7 +315,7 @@ void onApiSettingsPost(AsyncWebServerRequest *request) else { preferences.putBool("mcapBigChar", 0); - Serial.print("Setting big characters for market cap to false"); +// Serial.print("Setting big characters for market cap to false"); settingsChanged = true; } @@ -335,7 +324,7 @@ void onApiSettingsPost(AsyncWebServerRequest *request) AsyncWebParameter *mempoolInstance = request->getParam("mempoolInstance", true); preferences.putString("mempoolInstance", mempoolInstance->value().c_str()); - Serial.printf("Setting mempool instance to %s\r\n", mempoolInstance->value().c_str()); +// Serial.printf("Setting mempool instance to %s\r\n", mempoolInstance->value().c_str()); settingsChanged = true; } @@ -344,7 +333,7 @@ void onApiSettingsPost(AsyncWebServerRequest *request) AsyncWebParameter *ledBrightness = request->getParam("ledBrightness", true); preferences.putUInt("ledBrightness", ledBrightness->value().toInt()); - Serial.printf("Setting brightness to %d\r\n", ledBrightness->value().toInt()); +// Serial.printf("Setting brightness to %d\r\n", ledBrightness->value().toInt()); settingsChanged = true; } @@ -353,7 +342,7 @@ void onApiSettingsPost(AsyncWebServerRequest *request) AsyncWebParameter *fullRefreshMin = request->getParam("fullRefreshMin", true); preferences.putUInt("fullRefreshMin", fullRefreshMin->value().toInt()); - Serial.printf("Set full refresh minutes to %d\r\n", fullRefreshMin->value().toInt()); +// Serial.printf("Set full refresh minutes to %d\r\n", fullRefreshMin->value().toInt()); settingsChanged = true; } @@ -362,7 +351,7 @@ void onApiSettingsPost(AsyncWebServerRequest *request) AsyncWebParameter *wpTimeout = request->getParam("wpTimeout", true); preferences.putUInt("wpTimeout", wpTimeout->value().toInt()); - Serial.printf("Set WiFi portal timeout seconds to %d\r\n", wpTimeout->value().toInt()); +// Serial.printf("Set WiFi portal timeout seconds to %ld\r\n", wpTimeout->value().toInt()); settingsChanged = true; } @@ -378,7 +367,7 @@ void onApiSettingsPost(AsyncWebServerRequest *request) AsyncWebParameter *screenParam = request->getParam(key, true); visible = screenParam->value().toInt(); } - Serial.printf("Setting screen %d to %d\r\n", i, visible); +// Serial.printf("Setting screen %d to %d\r\n", i, visible); preferences.putBool(prefKey.c_str(), visible); } @@ -388,7 +377,7 @@ void onApiSettingsPost(AsyncWebServerRequest *request) AsyncWebParameter *p = request->getParam("tzOffset", true); int tzOffsetSeconds = p->value().toInt() * 60; preferences.putInt("gmtOffset", tzOffsetSeconds); - Serial.printf("Setting tz offset to %d\r\n", tzOffsetSeconds); +// Serial.printf("Setting tz offset to %d\r\n", tzOffsetSeconds); settingsChanged = true; } @@ -397,7 +386,7 @@ void onApiSettingsPost(AsyncWebServerRequest *request) AsyncWebParameter *p = request->getParam("minSecPriceUpd", true); int minSecPriceUpd = p->value().toInt(); preferences.putUInt("minSecPriceUpd", minSecPriceUpd); - Serial.printf("Setting minSecPriceUpd to %d\r\n", minSecPriceUpd); +// Serial.printf("Setting minSecPriceUpd to %d\r\n", minSecPriceUpd); settingsChanged = true; } @@ -441,8 +430,6 @@ void onApiSettingsPost(AsyncWebServerRequest *request) if (settingsChanged) { queueLedEffect(LED_FLASH_SUCCESS); - - Serial.println(F("Settings changed")); } }