From da4fcc7ef1ab81908f46961faf9fe20e25ffce20 Mon Sep 17 00:00:00 2001 From: cyberman54 Date: Fri, 12 Mar 2021 21:23:31 +0100 Subject: [PATCH 1/2] maintenance mode (improved error handling) --- src/boot.cpp | 96 ++++++++++++++++++++++++++++------------------------ 1 file changed, 52 insertions(+), 44 deletions(-) diff --git a/src/boot.cpp b/src/boot.cpp index 272fd512..b1855623 100644 --- a/src/boot.cpp +++ b/src/boot.cpp @@ -11,6 +11,7 @@ void start_boot_menu(void) { uint8_t mac[6]; char clientId[20]; + unsigned long timeout = millis(); // hash 6 byte MAC to 4 byte hash esp_eth_get_mac(mac); @@ -21,13 +22,15 @@ void start_boot_menu(void) { const char *ssid = WIFI_SSID; const char *password = WIFI_PASS; + // set runmode normal makes watchdog booting to production if triggered RTC_runmode = RUNMODE_NORMAL; + // setup watchdog, based on esp32 timer2 interrupt hw_timer_t *timer = NULL; timer = timerBegin(2, 80, true); // timer 2, div 80, countup - timerAttachInterrupt(timer, &esp_restart, true); // callback device reset - timerAlarmWrite(timer, BOOTDELAY * 1000000, false); // set time in us - timerAlarmEnable(timer); // enable interrupt + timerAttachInterrupt(timer, &esp_restart, true); // callback for device reset + timerAlarmWrite(timer, BOOTTIMEOUT * 1000000, false); // set time in us + timerAlarmEnable(timer); // enable watchdog WebServer server(80); @@ -102,86 +105,91 @@ void start_boot_menu(void) { // Connect to WiFi network // workaround applied here to avoid WIFI_AUTH failure // see https://github.com/espressif/arduino-esp32/issues/2501 + // 1st try WiFi.begin(ssid, password); while (WiFi.status() == WL_DISCONNECTED) { - delay(500); + if ((long)(millis() - timeout) > (BOOTDELAY * 1000)) + esp_restart(); + else + delay(500); } // 2nd try if (WiFi.status() != WL_CONNECTED) { WiFi.begin(ssid, password); while (WiFi.status() != WL_CONNECTED) { - delay(500); + if ((long)(millis() - timeout) > (BOOTDELAY * 1000)) + esp_restart(); + else + delay(500); } } MDNS.begin(host); + timerWrite(timer, 0); // reset timer (feed watchdog) server.on("/", HTTP_GET, [&server, &loginMenu]() { - server.sendHeader("Connection", "close"); + server.sendHeader("Connection", "keep-alive"); server.send(200, "text/html", loginMenu); }); server.on("/serverIndex", HTTP_GET, [&server, &serverIndex, &timer]() { - timerAlarmWrite(timer, BOOTTIMEOUT * 1000000, false); - server.sendHeader("Connection", "close"); + timerWrite(timer, 0); // reset timer (feed watchdog) + server.sendHeader("Connection", "keep-alive"); server.send(200, "text/html", serverIndex); }); - server.onNotFound([&server, &loginMenu]() { - server.sendHeader("Connection", "close"); - server.send(200, "text/html", loginMenu); - }); - - // handling uploading firmware file server.on( "/update", HTTP_POST, [&server]() { server.sendHeader("Connection", "close"); server.send(200, "text/plain", (Update.hasError()) ? "FAIL" : "OK"); WiFi.disconnect(true); - if (!Update.hasError()) - RTC_runmode = RUNMODE_POWERCYCLE; esp_restart(); }, + // handling uploading firmware file [&server, &timer]() { bool success = false; HTTPUpload &upload = server.upload(); - switch (upload.status) { + // did we get a file name? + if (upload.filename != NULL) { - case UPLOAD_FILE_START: - // start file transfer - ESP_LOGI(TAG, "Uploading %s", upload.filename.c_str()); - success = Update.begin(); - break; + switch (upload.status) { - case UPLOAD_FILE_WRITE: - // flashing firmware to ESP - success = (Update.write(upload.buf, upload.currentSize) == - upload.currentSize); - break; + case UPLOAD_FILE_START: + // start file transfer + ESP_LOGI(TAG, "Uploading %s", upload.filename.c_str()); + success = Update.begin(); + break; - case UPLOAD_FILE_END: - success = Update.end(true); // true to set the size to the current - if (success) - ESP_LOGI(TAG, "Upload finished, %u bytes written", - upload.totalSize); - else - ESP_LOGE(TAG, "Upload failed, status=%d", upload.status); - break; + case UPLOAD_FILE_WRITE: + // flashing firmware to ESP + success = (Update.write(upload.buf, upload.currentSize) == + upload.currentSize); + break; - case UPLOAD_FILE_ABORTED: - default: - break; + case UPLOAD_FILE_END: + success = Update.end(true); // true to set the size to the current + if (success) + ESP_LOGI(TAG, "Upload finished, %u bytes written", + upload.totalSize); + else + ESP_LOGE(TAG, "Upload failed, status=%d", upload.status); + break; - } // switch + case UPLOAD_FILE_ABORTED: + default: + break; - if (!success) { - ESP_LOGE(TAG, "Error: %s", Update.errorString()); - WiFi.disconnect(true); - esp_restart(); + } // switch + + // don't boot to production if update failed + if (!success) { + ESP_LOGE(TAG, "Error: %s", Update.errorString()); + RTC_runmode = RUNMODE_POWERCYCLE; + } } }); @@ -194,6 +202,6 @@ void start_boot_menu(void) { while (1) { server.handleClient(); - delay(1); + delay(2); } } \ No newline at end of file From cabdb4da21b1f50a860fe2507666aeb16d66edd9 Mon Sep 17 00:00:00 2001 From: cyberman54 Date: Fri, 12 Mar 2021 23:31:57 +0100 Subject: [PATCH 2/2] maintenance mode (timeout watchdog reworked) --- src/boot.cpp | 174 ++++++++++++++++++++++++++------------------------- src/main.cpp | 1 - 2 files changed, 89 insertions(+), 86 deletions(-) diff --git a/src/boot.cpp b/src/boot.cpp index b1855623..224d37e6 100644 --- a/src/boot.cpp +++ b/src/boot.cpp @@ -4,6 +4,73 @@ // Local logging tag static const char TAG[] = __FILE__; +static hw_timer_t *wdTimer = NULL; +static WebServer server(80); +static TaskHandle_t RestartHandle; + +static const char *loginMenu = + "
" + "" + "" + "" + "
" + "
" + "" + "" + "" + "" + "
" + "
Maintenance Menu
" + "
" + "
" + "
" + ""; + +static const char *serverIndex = + "" + "
" + "" + "" + "
" + "
progress: 0%
" + ""; + +void IRAM_ATTR watchdog() { xTaskResumeFromISR(RestartHandle); } + // start local web server with user interface for maintenance mode // used for manually uploading a firmware file via wifi @@ -11,7 +78,6 @@ void start_boot_menu(void) { uint8_t mac[6]; char clientId[20]; - unsigned long timeout = millis(); // hash 6 byte MAC to 4 byte hash esp_eth_get_mac(mac); @@ -25,75 +91,21 @@ void start_boot_menu(void) { // set runmode normal makes watchdog booting to production if triggered RTC_runmode = RUNMODE_NORMAL; + // setup restart handle task for resetting ESP32, which is callable from ISR + // (because esp_restart() from ISR would trigger the ESP32 task watchdog) + xTaskCreate( + [](void *p) { + vTaskSuspend(NULL); + ESP.restart(); + }, + "Restart", configMINIMAL_STACK_SIZE, NULL, (3 | portPRIVILEGE_BIT), + &RestartHandle); + // setup watchdog, based on esp32 timer2 interrupt - hw_timer_t *timer = NULL; - timer = timerBegin(2, 80, true); // timer 2, div 80, countup - timerAttachInterrupt(timer, &esp_restart, true); // callback for device reset - timerAlarmWrite(timer, BOOTTIMEOUT * 1000000, false); // set time in us - timerAlarmEnable(timer); // enable watchdog - - WebServer server(80); - - const char *loginMenu = - "
" - "" - "" - "" - "
" - "
" - "" - "" - "" - "" - "
" - "
Maintenance Menu
" - "
" - "
" - "
" - ""; - - const char *serverIndex = - "" - "
" - "" - "" - "
" - "
progress: 0%
" - ""; + wdTimer = timerBegin(0, 80, true); // timer 0, div 80, countup + timerAttachInterrupt(wdTimer, &watchdog, true); // callback for device reset + timerAlarmWrite(wdTimer, BOOTDELAY * 1000000, false); // set time in us + timerAlarmEnable(wdTimer); // enable watchdog WiFi.disconnect(true); WiFi.config(INADDR_NONE, INADDR_NONE, @@ -109,39 +121,31 @@ void start_boot_menu(void) { // 1st try WiFi.begin(ssid, password); while (WiFi.status() == WL_DISCONNECTED) { - if ((long)(millis() - timeout) > (BOOTDELAY * 1000)) - esp_restart(); - else - delay(500); + delay(500); } // 2nd try if (WiFi.status() != WL_CONNECTED) { WiFi.begin(ssid, password); - while (WiFi.status() != WL_CONNECTED) { - if ((long)(millis() - timeout) > (BOOTDELAY * 1000)) - esp_restart(); - else - delay(500); - } + delay(500); } MDNS.begin(host); - timerWrite(timer, 0); // reset timer (feed watchdog) + timerWrite(wdTimer, 0); // reset timer (feed watchdog) - server.on("/", HTTP_GET, [&server, &loginMenu]() { + server.on("/", HTTP_GET, []() { server.sendHeader("Connection", "keep-alive"); server.send(200, "text/html", loginMenu); }); - server.on("/serverIndex", HTTP_GET, [&server, &serverIndex, &timer]() { - timerWrite(timer, 0); // reset timer (feed watchdog) + server.on("/serverIndex", HTTP_GET, []() { + timerAlarmWrite(wdTimer, BOOTTIMEOUT * 1000000, false); // set time in us server.sendHeader("Connection", "keep-alive"); server.send(200, "text/html", serverIndex); }); server.on( "/update", HTTP_POST, - [&server]() { + []() { server.sendHeader("Connection", "close"); server.send(200, "text/plain", (Update.hasError()) ? "FAIL" : "OK"); WiFi.disconnect(true); @@ -149,7 +153,7 @@ void start_boot_menu(void) { }, // handling uploading firmware file - [&server, &timer]() { + []() { bool success = false; HTTPUpload &upload = server.upload(); diff --git a/src/main.cpp b/src/main.cpp index 35ec4e06..01b1b949 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -51,7 +51,6 @@ So don't do it if you do not own a digital oscilloscope. ------------------------------------------------------------------------------- 0 displayIRQ -> display refresh -> 40ms (DISPLAYREFRESH_MS) 1 ppsIRQ -> pps clock irq -> 1sec -2 watchdog -> used in boot.cpp 3 MatrixDisplayIRQ -> matrix mux cycle -> 0,5ms (MATRIX_DISPLAY_SCAN_US)