From f5d5e7c6fc784c4a93ae69c9da6d80cd0bff3e1f Mon Sep 17 00:00:00 2001 From: cyberman54 Date: Wed, 3 Mar 2021 16:20:21 +0100 Subject: [PATCH 01/16] maintenance mode (experimental) --- README.md | 1 + include/globals.h | 5 +- include/ota.h | 5 ++ src/cyclic.cpp | 8 ++-- src/main.cpp | 11 +++++ src/mqttclient.cpp | 7 --- src/ota.cpp | 113 +++++++++++++++++++++++++++++++++++++++++++++ src/rcommand.cpp | 6 ++- src/reset.cpp | 2 +- 9 files changed, 142 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index cdf271e0..91b514fc 100644 --- a/README.md +++ b/README.md @@ -437,6 +437,7 @@ Send for example `8386` as Downlink on Port 2 to get battery status and time/dat 2 = reset device to factory settings 3 = flush send queues 4 = restart device (warmstart) + 8 = reboot device to maintenance mode (local web server) 9 = reboot device to OTA update via Wifi mode 0x0A set LoRaWAN payload send cycle diff --git a/include/globals.h b/include/globals.h index adddd3ab..e236998f 100644 --- a/include/globals.h +++ b/include/globals.h @@ -58,7 +58,8 @@ enum runmode_t { RUNMODE_NORMAL, RUNMODE_WAKEUP, RUNMODE_UPDATE, - RUNMODE_SLEEP + RUNMODE_SLEEP, + RUNMODE_MAINTENANCE }; // Struct holding devices's runtime configuration @@ -83,7 +84,6 @@ typedef struct __attribute__((packed)) { uint8_t macfilter; // 0=disabled, 1=enabled uint8_t rgblum; // RGB Led luminosity (0..100%) uint8_t monitormode; // 0=disabled, 1=enabled - uint8_t runmode; // 0=normal, 1=update uint8_t payloadmask; // bitswitches for payload data uint8_t enscount; // 0=disabled 1= enabled @@ -149,5 +149,6 @@ extern TaskHandle_t irqHandlerTask, ClockTask, macProcessTask; extern TimerHandle_t WifiChanTimer; extern Timezone myTZ; extern RTC_DATA_ATTR runmode_t RTC_runmode; +extern char clientId[20]; // generated device name #endif \ No newline at end of file diff --git a/include/ota.h b/include/ota.h index 9e53cae1..5018d3ea 100644 --- a/include/ota.h +++ b/include/ota.h @@ -13,8 +13,13 @@ #include #include +#include +#include +#include + int do_ota_update(); void start_ota_update(); +void start_maintenance(); void ota_display(const uint8_t row, const std::string status, const std::string msg); void show_progress(unsigned long current, unsigned long size); diff --git a/src/cyclic.cpp b/src/cyclic.cpp index 8ccc3086..3876ea0c 100644 --- a/src/cyclic.cpp +++ b/src/cyclic.cpp @@ -13,15 +13,13 @@ Ticker cyclicTimer; extern boolean isSDS011Active; #endif -void setCyclicIRQ() { - xTaskNotify(irqHandlerTask, CYCLIC_IRQ, eSetBits); -} +void setCyclicIRQ() { xTaskNotify(irqHandlerTask, CYCLIC_IRQ, eSetBits); } // do all housekeeping void doHousekeeping() { - // check if update mode trigger switch was set by rcommand - if (RTC_runmode == RUNMODE_UPDATE) + // check if update or maintenance mode trigger switch was set by rcommand + if ((RTC_runmode == RUNMODE_UPDATE) || (RTC_runmode == RUNMODE_MAINTENANCE)) do_reset(true); // heap and task storage debugging diff --git a/src/main.cpp b/src/main.cpp index 3fb5c60b..e3b2b59f 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -93,6 +93,7 @@ uint8_t batt_level = 0; // display value uint8_t volatile channel = WIFI_CHANNEL_MIN; // channel rotation counter uint8_t volatile rf_load = 0; // RF traffic indicator uint16_t volatile macs_wifi = 0, macs_ble = 0; // globals for display +char clientId[20]; // generated device name hw_timer_t *ppsIRQ = NULL, *displayIRQ = NULL, *matrixDisplayIRQ = NULL; @@ -142,6 +143,12 @@ void setup() { do_after_reset(); + // generate unique clientId from device's MAC + uint8_t mac[6]; + esp_eth_get_mac(mac); + const uint32_t hashedmac = hash((const char *)mac, 6); + snprintf(clientId, 20, "paxcounter_%08x", hashedmac); + // print chip information on startup if in verbose mode after coldstart #if (VERBOSE) @@ -290,6 +297,10 @@ void setup() { start_ota_update(); #endif + // start local webserver if maintenance trigger switch is set + if (RTC_runmode == RUNMODE_MAINTENANCE) + start_maintenance(); + // start mac processing task ESP_LOGI(TAG, "Starting MAC processor..."); macQueueInit(); diff --git a/src/mqttclient.cpp b/src/mqttclient.cpp index 89d54fde..4948409b 100644 --- a/src/mqttclient.cpp +++ b/src/mqttclient.cpp @@ -43,13 +43,6 @@ esp_err_t mqtt_init(void) { int mqtt_connect(const char *my_host, const uint16_t my_port) { IPAddress mqtt_server_ip; - uint8_t mac[6]; - char clientId[20]; - - // hash 6 byte MAC to 4 byte hash - esp_eth_get_mac(mac); - const uint32_t hashedmac = hash((const char *)mac, 6); - snprintf(clientId, 20, "paxcounter_%08x", hashedmac); ESP_LOGI(TAG, "MQTT name is %s", MQTT_CLIENTNAME); diff --git a/src/ota.cpp b/src/ota.cpp index bf4a41e0..ae46d42f 100644 --- a/src/ota.cpp +++ b/src/ota.cpp @@ -330,4 +330,117 @@ void show_progress(unsigned long current, unsigned long size) { #endif } +// start local web user with user interface for maintenance mode +// currently used only for manually uploading a firmware file via wifi + +void start_maintenance(void) { + + // code snippets taken from + // https://github.com/espressif/arduino-esp32/blob/master/libraries/ArduinoOTA/examples/OTAWebUpdater/OTAWebUpdater.ino + + const char *host = MQTT_CLIENTNAME; + const char *ssid = WIFI_SSID; + const char *password = WIFI_PASS; + + WebServer server(80); + + const char *serverIndex = + "" + "
" + "" + "" + "
" + "
progress: 0%
" + ""; + + // Connect to WiFi network + WiFi.begin(ssid, password); + + // Wait for connection + while (WiFi.status() != WL_CONNECTED) { + delay(500); + } + ESP_LOGI(TAG, "Connected to %s", ssid); + + // use mdns for host name resolution + if (!MDNS.begin(host)) { + ESP_LOGI(TAG, "Error setting up mDNS responder!"); + delay(3000); + do_reset(false); + } + server.on("/", HTTP_GET, [&server, &serverIndex]() { + server.sendHeader("Connection", "close"); + server.send(200, "text/html", serverIndex); + }); + // handling uploading firmware file + server.on( + "/update", HTTP_POST, + [&server]() { + server.sendHeader("Connection", "close"); + server.send(200, "text/plain", (Update.hasError()) ? "FAIL" : "OK"); + do_reset(false); + }, + [&server]() { + HTTPUpload &upload = server.upload(); + if (upload.status == UPLOAD_FILE_START) { + ESP_LOGI(TAG, "Update: %s\n", upload.filename.c_str()); + if (!Update.begin( + UPDATE_SIZE_UNKNOWN)) { // start with max available size + ESP_LOGE(TAG, "Error: %s", Update.errorString()); + } + } else if (upload.status == UPLOAD_FILE_WRITE) { + // flashing firmware to ESP + if (Update.write(upload.buf, upload.currentSize) != + upload.currentSize) { + ESP_LOGE(TAG, "Error: %s", Update.errorString()); + } + } else if (upload.status == UPLOAD_FILE_END) { + if (Update.end( + true)) { // true to set the size to the current progress + ESP_LOGI(TAG, "Update Success: %u\nRebooting...\n", + upload.totalSize); + } else { + ESP_LOGE(TAG, "Update failed"); + } + } + }); + server.begin(); + + while (1) { + server.handleClient(); + delay(1); + } +} + #endif // USE_OTA \ No newline at end of file diff --git a/src/rcommand.cpp b/src/rcommand.cpp index c902a9d5..23ff0d98 100644 --- a/src/rcommand.cpp +++ b/src/rcommand.cpp @@ -31,7 +31,11 @@ void set_reset(uint8_t val[]) { ESP_LOGI(TAG, "Remote command: restart device warm"); do_reset(true); break; - case 9: // reset and ask for software update via Wifi OTA + case 8: // reset and start local web server for manual software update + ESP_LOGI(TAG, "Remote command: software update via user interface"); + RTC_runmode = RUNMODE_MAINTENANCE; + break; + case 9: // reset and ask OTA server via Wifi for automated software update ESP_LOGI(TAG, "Remote command: software update via Wifi"); #if (USE_OTA) // check power status before scheduling ota update diff --git a/src/reset.cpp b/src/reset.cpp index 7c0b0d48..77323e40 100644 --- a/src/reset.cpp +++ b/src/reset.cpp @@ -14,7 +14,7 @@ RTC_DATA_ATTR struct timeval RTC_sleep_start_time; RTC_DATA_ATTR unsigned long long RTC_millis = 0; timeval sleep_stop_time; -const char *runmode[5] = {"powercycle", "normal", "wakeup", "update", "sleep"}; +const char *runmode[6] = {"powercycle", "normal", "wakeup", "update", "sleep", "maintenance"}; void do_reset(bool warmstart) { if (warmstart) { From 439ea0c0576628197c2c3d60fde017f60a5aa775 Mon Sep 17 00:00:00 2001 From: cyberman54 Date: Wed, 3 Mar 2021 18:46:41 +0100 Subject: [PATCH 02/16] maintenance mode adjustments --- src/ota.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/ota.cpp b/src/ota.cpp index ae46d42f..bfc1d4a9 100644 --- a/src/ota.cpp +++ b/src/ota.cpp @@ -403,6 +403,7 @@ void start_maintenance(void) { server.sendHeader("Connection", "close"); server.send(200, "text/html", serverIndex); }); + // handling uploading firmware file server.on( "/update", HTTP_POST, @@ -428,11 +429,14 @@ void start_maintenance(void) { } else if (upload.status == UPLOAD_FILE_END) { if (Update.end( true)) { // true to set the size to the current progress - ESP_LOGI(TAG, "Update Success: %u\nRebooting...\n", + ESP_LOGI(TAG, "Update finished, %u bytes written", upload.totalSize); + } else { ESP_LOGE(TAG, "Update failed"); } + delay(3000); + do_reset(false); } }); server.begin(); From ad2c8898890f6cb90c272d4117e8a9ada197c895 Mon Sep 17 00:00:00 2001 From: cyberman54 Date: Wed, 3 Mar 2021 19:16:14 +0100 Subject: [PATCH 03/16] maintenance mode adjustments --- include/globals.h | 1 - src/main.cpp | 7 ------- src/mqttclient.cpp | 7 +++++++ src/ota.cpp | 16 ++++++++++------ 4 files changed, 17 insertions(+), 14 deletions(-) diff --git a/include/globals.h b/include/globals.h index e236998f..1cb8b349 100644 --- a/include/globals.h +++ b/include/globals.h @@ -149,6 +149,5 @@ extern TaskHandle_t irqHandlerTask, ClockTask, macProcessTask; extern TimerHandle_t WifiChanTimer; extern Timezone myTZ; extern RTC_DATA_ATTR runmode_t RTC_runmode; -extern char clientId[20]; // generated device name #endif \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index e3b2b59f..850a0123 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -93,7 +93,6 @@ uint8_t batt_level = 0; // display value uint8_t volatile channel = WIFI_CHANNEL_MIN; // channel rotation counter uint8_t volatile rf_load = 0; // RF traffic indicator uint16_t volatile macs_wifi = 0, macs_ble = 0; // globals for display -char clientId[20]; // generated device name hw_timer_t *ppsIRQ = NULL, *displayIRQ = NULL, *matrixDisplayIRQ = NULL; @@ -143,12 +142,6 @@ void setup() { do_after_reset(); - // generate unique clientId from device's MAC - uint8_t mac[6]; - esp_eth_get_mac(mac); - const uint32_t hashedmac = hash((const char *)mac, 6); - snprintf(clientId, 20, "paxcounter_%08x", hashedmac); - // print chip information on startup if in verbose mode after coldstart #if (VERBOSE) diff --git a/src/mqttclient.cpp b/src/mqttclient.cpp index 4948409b..89d54fde 100644 --- a/src/mqttclient.cpp +++ b/src/mqttclient.cpp @@ -43,6 +43,13 @@ esp_err_t mqtt_init(void) { int mqtt_connect(const char *my_host, const uint16_t my_port) { IPAddress mqtt_server_ip; + uint8_t mac[6]; + char clientId[20]; + + // hash 6 byte MAC to 4 byte hash + esp_eth_get_mac(mac); + const uint32_t hashedmac = hash((const char *)mac, 6); + snprintf(clientId, 20, "paxcounter_%08x", hashedmac); ESP_LOGI(TAG, "MQTT name is %s", MQTT_CLIENTNAME); diff --git a/src/ota.cpp b/src/ota.cpp index bfc1d4a9..215d72d6 100644 --- a/src/ota.cpp +++ b/src/ota.cpp @@ -330,15 +330,15 @@ void show_progress(unsigned long current, unsigned long size) { #endif } -// start local web user with user interface for maintenance mode -// currently used only for manually uploading a firmware file via wifi +// start local web server with user interface for maintenance mode +// used for manually uploading a firmware file via wifi void start_maintenance(void) { // code snippets taken from - // https://github.com/espressif/arduino-esp32/blob/master/libraries/ArduinoOTA/examples/OTAWebUpdater/OTAWebUpdater.ino + // github.com/espressif/arduino-esp32/blob/master/libraries/ArduinoOTA/examples/OTAWebUpdater/OTAWebUpdater.ino - const char *host = MQTT_CLIENTNAME; + const char *host = "paxcounter"; const char *ssid = WIFI_SSID; const char *password = WIFI_PASS; @@ -388,10 +388,11 @@ void start_maintenance(void) { WiFi.begin(ssid, password); // Wait for connection - while (WiFi.status() != WL_CONNECTED) { + while (WiFi.status() != WL_CONNECTED) delay(500); - } + ESP_LOGI(TAG, "Connected to %s", ssid); + ESP_LOGI(TAG, "Open http://%s.local in your browser", host); // use mdns for host name resolution if (!MDNS.begin(host)) { @@ -399,6 +400,7 @@ void start_maintenance(void) { delay(3000); do_reset(false); } + server.on("/", HTTP_GET, [&server, &serverIndex]() { server.sendHeader("Connection", "close"); server.send(200, "text/html", serverIndex); @@ -439,7 +441,9 @@ void start_maintenance(void) { do_reset(false); } }); + server.begin(); + MDNS.addService("http", "tcp", 80); while (1) { server.handleClient(); From b1e08f0269f67bea0403f18d4beb4757c5a7d0b6 Mon Sep 17 00:00:00 2001 From: cyberman54 Date: Thu, 4 Mar 2021 21:22:49 +0100 Subject: [PATCH 04/16] maintenance mode (experimental) --- include/boot.h | 17 +++++ include/hash.h | 2 +- include/main.h | 1 + include/mqttclient.h | 1 + include/ota.h | 7 +-- src/boot.cpp | 145 +++++++++++++++++++++++++++++++++++++++++++ src/cyclic.cpp | 2 +- src/hash.cpp | 2 +- src/macsniff.cpp | 2 +- src/main.cpp | 12 +++- src/mqttclient.cpp | 2 +- src/ota.cpp | 121 ------------------------------------ src/rcommand.cpp | 4 +- src/reset.cpp | 6 +- 14 files changed, 186 insertions(+), 138 deletions(-) create mode 100644 include/boot.h create mode 100644 src/boot.cpp diff --git a/include/boot.h b/include/boot.h new file mode 100644 index 00000000..f354d631 --- /dev/null +++ b/include/boot.h @@ -0,0 +1,17 @@ +#ifndef BOOT_H +#define BOOT_H + +#include "globals.h" +#include "hash.h" + +#include +#include +#include +#include +#include +#include + +void IRAM_ATTR exit_boot_menu(void); +void start_boot_menu(void); + +#endif // BOOT_H diff --git a/include/hash.h b/include/hash.h index cfd96ce7..fe756ec3 100644 --- a/include/hash.h +++ b/include/hash.h @@ -4,6 +4,6 @@ #include #include -uint32_t IRAM_ATTR hash(const char *data, int len); +uint32_t IRAM_ATTR myhash(const char *data, int len); #endif \ No newline at end of file diff --git a/include/main.h b/include/main.h index 397d6ad6..2a5bd104 100644 --- a/include/main.h +++ b/include/main.h @@ -20,5 +20,6 @@ #include "lorawan.h" #include "timekeeper.h" #include "corona.h" +#include "boot.h" #endif \ No newline at end of file diff --git a/include/mqttclient.h b/include/mqttclient.h index 1c797a01..6151dd52 100644 --- a/include/mqttclient.h +++ b/include/mqttclient.h @@ -3,6 +3,7 @@ #include "globals.h" #include "rcommand.h" +#include "hash.h" #include #include #include diff --git a/include/ota.h b/include/ota.h index 5018d3ea..274cd786 100644 --- a/include/ota.h +++ b/include/ota.h @@ -13,17 +13,12 @@ #include #include -#include -#include -#include - int do_ota_update(); void start_ota_update(); -void start_maintenance(); void ota_display(const uint8_t row, const std::string status, const std::string msg); void show_progress(unsigned long current, unsigned long size); #endif // USE_OTA -#endif // OTA_H +#endif // OTA_H \ No newline at end of file diff --git a/src/boot.cpp b/src/boot.cpp new file mode 100644 index 00000000..0c216eeb --- /dev/null +++ b/src/boot.cpp @@ -0,0 +1,145 @@ +#include "boot.h" +#include "reset.h" + +// Local logging tag +static const char TAG[] = __FILE__; + +void IRAM_ATTR exit_boot_menu() { + RTC_runmode = RUNMODE_NORMAL; + esp_restart(); +} + +// start local web server with user interface for maintenance mode +// used for manually uploading a firmware file via wifi + +void start_boot_menu(void) { + + uint8_t mac[6]; + char clientId[20]; + + // hash 6 byte MAC to 4 byte hash + esp_eth_get_mac(mac); + const uint32_t hashedmac = myhash((const char *)mac, 6); + snprintf(clientId, 20, "paxcounter_%08x", hashedmac); + + const char *host = clientId; + const char *ssid = WIFI_SSID; + const char *password = WIFI_PASS; + + hw_timer_t *timer = NULL; + timer = timerBegin(2, 80, true); // timer 2, div 80, countup + timerAttachInterrupt(timer, &exit_boot_menu, true); // attach callback + timerAlarmWrite(timer, BOOTDELAY * 1000000, false); // set time in us + timerAlarmEnable(timer); // enable interrupt + + WebServer server(80); + + /* + const char *serverIndex = + "
"; + */ + + const char *serverIndex = + "" + "
" + "" + "" + "
" + "
progress: 0%
" + ""; + + // Connect to WiFi network + // WiFi.mode(WIFI_STA); + WiFi.begin(ssid, password); + + // Wait for connection + while (WiFi.status() != WL_CONNECTED) { + delay(500); + } + + MDNS.begin(host); + + server.on("/", HTTP_GET, [&server, &serverIndex]() { + server.sendHeader("Connection", "close"); + server.send(200, "text/html", serverIndex); + }); + + // handling uploading firmware file + server.on( + "/update", HTTP_POST, + [&server]() { + server.sendHeader("Connection", "close"); + server.send(200, "text/plain", (Update.hasError()) ? "FAIL" : "OK"); + }, + [&server, &timer]() { + HTTPUpload &upload = server.upload(); + if (upload.status == UPLOAD_FILE_START) { + timerAlarmWrite(timer, BOOTTIMEOUT * 1000000, false); + ESP_LOGI(TAG, "Update: %s\n", upload.filename.c_str()); + if (!Update.begin( + UPDATE_SIZE_UNKNOWN)) { // start with max available size + ESP_LOGE(TAG, "Error: %s", Update.errorString()); + } + } else if (upload.status == UPLOAD_FILE_WRITE) { + // flashing firmware to ESP + if (Update.write(upload.buf, upload.currentSize) != + upload.currentSize) { + ESP_LOGE(TAG, "Error: %s", Update.errorString()); + } + } else if (upload.status == UPLOAD_FILE_END) { + if (Update.end( + true)) { // true to set the size to the current progress + ESP_LOGI(TAG, "Update finished, %u bytes written", + upload.totalSize); + WiFi.disconnect(true, true); + do_reset(false); // coldstart + } else { + ESP_LOGE(TAG, "Update failed"); + } + } + }); + + server.begin(); + MDNS.addService("http", "tcp", 80); + ESP_LOGI(TAG, "WiFi connected to '%s', open http://%s in your browser", + WiFi.SSID().c_str(), WiFi.localIP().toString().c_str()); + + while (1) { + server.handleClient(); + timerWrite(timer, 0); // reset timer (feed watchdog) + delay(1); + } +} \ No newline at end of file diff --git a/src/cyclic.cpp b/src/cyclic.cpp index 3876ea0c..db0e9d2f 100644 --- a/src/cyclic.cpp +++ b/src/cyclic.cpp @@ -20,7 +20,7 @@ void doHousekeeping() { // check if update or maintenance mode trigger switch was set by rcommand if ((RTC_runmode == RUNMODE_UPDATE) || (RTC_runmode == RUNMODE_MAINTENANCE)) - do_reset(true); + do_reset(true); // warmstart // heap and task storage debugging ESP_LOGD(TAG, "Heap: Free:%d, Min:%d, Size:%d, Alloc:%d, StackHWM:%d", diff --git a/src/hash.cpp b/src/hash.cpp index 32e8b1c5..78f31d03 100644 --- a/src/hash.cpp +++ b/src/hash.cpp @@ -40,6 +40,6 @@ #undef ROKKIT_ENABLE_8BIT_OPTIMIZATIONS #endif -uint32_t IRAM_ATTR hash(const char *data, int len) { +uint32_t IRAM_ATTR myhash(const char *data, int len) { return rokkit(data, len); } diff --git a/src/macsniff.cpp b/src/macsniff.cpp index 3bce9453..e031d36e 100644 --- a/src/macsniff.cpp +++ b/src/macsniff.cpp @@ -141,7 +141,7 @@ uint16_t mac_analyze(MacBuffer_t MacBuffer) { // hashed 4 byte MAC // to save RAM, we use only lower 2 bytes of hash, since collisions don't // matter in our use case - hashedmac = hash((const char *)&saltedmac, 4); + hashedmac = myhash((const char *)&saltedmac, 4); auto newmac = macs.insert(hashedmac); // add hashed MAC, if new unique bool added = diff --git a/src/main.cpp b/src/main.cpp index 850a0123..bc063d85 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -51,6 +51,7 @@ 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) @@ -290,9 +291,16 @@ void setup() { start_ota_update(); #endif - // start local webserver if maintenance trigger switch is set +#if (BOOTMENU) + // start local webserver after device powers up or on rcommand request + if ((RTC_runmode == RUNMODE_POWERCYCLE) || + (RTC_runmode == RUNMODE_MAINTENANCE)) + start_boot_menu(); +#else + // start local webserver on rcommand request only if (RTC_runmode == RUNMODE_MAINTENANCE) - start_maintenance(); + start_boot_menu(); +#endif // start mac processing task ESP_LOGI(TAG, "Starting MAC processor..."); diff --git a/src/mqttclient.cpp b/src/mqttclient.cpp index 89d54fde..caba854f 100644 --- a/src/mqttclient.cpp +++ b/src/mqttclient.cpp @@ -48,7 +48,7 @@ int mqtt_connect(const char *my_host, const uint16_t my_port) { // hash 6 byte MAC to 4 byte hash esp_eth_get_mac(mac); - const uint32_t hashedmac = hash((const char *)mac, 6); + const uint32_t hashedmac = myhash((const char *)mac, 6); snprintf(clientId, 20, "paxcounter_%08x", hashedmac); ESP_LOGI(TAG, "MQTT name is %s", MQTT_CLIENTNAME); diff --git a/src/ota.cpp b/src/ota.cpp index 215d72d6..bf4a41e0 100644 --- a/src/ota.cpp +++ b/src/ota.cpp @@ -330,125 +330,4 @@ void show_progress(unsigned long current, unsigned long size) { #endif } -// start local web server with user interface for maintenance mode -// used for manually uploading a firmware file via wifi - -void start_maintenance(void) { - - // code snippets taken from - // github.com/espressif/arduino-esp32/blob/master/libraries/ArduinoOTA/examples/OTAWebUpdater/OTAWebUpdater.ino - - const char *host = "paxcounter"; - const char *ssid = WIFI_SSID; - const char *password = WIFI_PASS; - - WebServer server(80); - - const char *serverIndex = - "" - "
" - "" - "" - "
" - "
progress: 0%
" - ""; - - // Connect to WiFi network - WiFi.begin(ssid, password); - - // Wait for connection - while (WiFi.status() != WL_CONNECTED) - delay(500); - - ESP_LOGI(TAG, "Connected to %s", ssid); - ESP_LOGI(TAG, "Open http://%s.local in your browser", host); - - // use mdns for host name resolution - if (!MDNS.begin(host)) { - ESP_LOGI(TAG, "Error setting up mDNS responder!"); - delay(3000); - do_reset(false); - } - - server.on("/", HTTP_GET, [&server, &serverIndex]() { - server.sendHeader("Connection", "close"); - server.send(200, "text/html", serverIndex); - }); - - // handling uploading firmware file - server.on( - "/update", HTTP_POST, - [&server]() { - server.sendHeader("Connection", "close"); - server.send(200, "text/plain", (Update.hasError()) ? "FAIL" : "OK"); - do_reset(false); - }, - [&server]() { - HTTPUpload &upload = server.upload(); - if (upload.status == UPLOAD_FILE_START) { - ESP_LOGI(TAG, "Update: %s\n", upload.filename.c_str()); - if (!Update.begin( - UPDATE_SIZE_UNKNOWN)) { // start with max available size - ESP_LOGE(TAG, "Error: %s", Update.errorString()); - } - } else if (upload.status == UPLOAD_FILE_WRITE) { - // flashing firmware to ESP - if (Update.write(upload.buf, upload.currentSize) != - upload.currentSize) { - ESP_LOGE(TAG, "Error: %s", Update.errorString()); - } - } else if (upload.status == UPLOAD_FILE_END) { - if (Update.end( - true)) { // true to set the size to the current progress - ESP_LOGI(TAG, "Update finished, %u bytes written", - upload.totalSize); - - } else { - ESP_LOGE(TAG, "Update failed"); - } - delay(3000); - do_reset(false); - } - }); - - server.begin(); - MDNS.addService("http", "tcp", 80); - - while (1) { - server.handleClient(); - delay(1); - } -} - #endif // USE_OTA \ No newline at end of file diff --git a/src/rcommand.cpp b/src/rcommand.cpp index 23ff0d98..c22ad0b7 100644 --- a/src/rcommand.cpp +++ b/src/rcommand.cpp @@ -32,11 +32,11 @@ void set_reset(uint8_t val[]) { do_reset(true); break; case 8: // reset and start local web server for manual software update - ESP_LOGI(TAG, "Remote command: software update via user interface"); + ESP_LOGI(TAG, "Remote command: reboot to maintenance mode"); RTC_runmode = RUNMODE_MAINTENANCE; break; case 9: // reset and ask OTA server via Wifi for automated software update - ESP_LOGI(TAG, "Remote command: software update via Wifi"); + ESP_LOGI(TAG, "Remote command: reboot to ota update mode"); #if (USE_OTA) // check power status before scheduling ota update if (batt_sufficient()) diff --git a/src/reset.cpp b/src/reset.cpp index 77323e40..167af2f1 100644 --- a/src/reset.cpp +++ b/src/reset.cpp @@ -14,7 +14,8 @@ RTC_DATA_ATTR struct timeval RTC_sleep_start_time; RTC_DATA_ATTR unsigned long long RTC_millis = 0; timeval sleep_stop_time; -const char *runmode[6] = {"powercycle", "normal", "wakeup", "update", "sleep", "maintenance"}; +const char *runmode[6] = {"powercycle", "normal", "wakeup", + "update", "sleep", "maintenance"}; void do_reset(bool warmstart) { if (warmstart) { @@ -45,7 +46,8 @@ void do_after_reset(void) { break; case SW_CPU_RESET: // 0x0c Software reset CPU - // keep previous runmode (could be RUNMODE_UPDATE) + // keep previous runmode + // (i.e. RUNMODE_UPDATE or RUNMODE_MAINTENANCE) break; case DEEPSLEEP_RESET: // 0x05 Deep Sleep reset digital core From e864977b0d395e7dd1b806c34aa060a4eeddddbd Mon Sep 17 00:00:00 2001 From: cyberman54 Date: Thu, 4 Mar 2021 21:24:00 +0100 Subject: [PATCH 05/16] maintenance mode (experimental) --- src/paxcounter_orig.conf | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/paxcounter_orig.conf b/src/paxcounter_orig.conf index 14481f22..5b9732c4 100644 --- a/src/paxcounter_orig.conf +++ b/src/paxcounter_orig.conf @@ -6,8 +6,11 @@ // // Note: After editing, before "build", use "clean" button in PlatformIO! -// Verbose enables additional serial debug output -#define VERBOSE 1 // set to 0 to silence the device, for mute use build option +// Device options +#define VERBOSE 1 // set to 0 to silence the device, 1 enables additional debug output +#define BOOTMENU 1 // 0 = no bootmenu, 1 = device brings up boot menu before starting application +#define BOOTDELAY 10 // time [seconds] while devices waits in boot menue for input +#define BOOTTIMEOUT 300 // time [seconds] while devices waits to finish upload a firmware file // Payload send cycle and encoding #define SENDCYCLE 30 // payload send cycle [seconds/2], 0 .. 255 From 88774d13e922b70723b71597d0f623f399fe545d Mon Sep 17 00:00:00 2001 From: cyberman54 Date: Fri, 5 Mar 2021 17:00:28 +0100 Subject: [PATCH 06/16] maintenance mode (1st full version) --- include/globals.h | 2 +- src/boot.cpp | 55 ++++++++++++++++++++++++++++++---------- src/display.cpp | 4 ++- src/paxcounter_orig.conf | 6 ++--- 4 files changed, 48 insertions(+), 19 deletions(-) diff --git a/include/globals.h b/include/globals.h index 1cb8b349..b9e24d46 100644 --- a/include/globals.h +++ b/include/globals.h @@ -148,6 +148,6 @@ extern SemaphoreHandle_t I2Caccess; extern TaskHandle_t irqHandlerTask, ClockTask, macProcessTask; extern TimerHandle_t WifiChanTimer; extern Timezone myTZ; -extern RTC_DATA_ATTR runmode_t RTC_runmode; +extern RTC_NOINIT_ATTR runmode_t RTC_runmode; #endif \ No newline at end of file diff --git a/src/boot.cpp b/src/boot.cpp index 0c216eeb..df2decb8 100644 --- a/src/boot.cpp +++ b/src/boot.cpp @@ -34,12 +34,25 @@ void start_boot_menu(void) { WebServer server(80); - /* - const char *serverIndex = - "
"; - */ + const char *loginMenu = + "
" + "" + "" + "" + "
" + "
" + "" + "" + "" + "" + "
" + "
Maintenance Menu
" + "
" + "
" + "
" + ""; const char *serverIndex = ""; // Connect to WiFi network - WiFi.mode(WIFI_STA); - WiFi.begin(ssid, password); + // workaround applied here to avoid WIFI_AUTH failure + // see https://github.com/espressif/arduino-esp32/issues/2501 - // Wait for connection - while (WiFi.status() != WL_CONNECTED) { + WiFi.disconnect(true, true); + WiFi.mode(WIFI_STA); + + // 1st try + WiFi.begin(ssid, password); + while (WiFi.status() == WL_DISCONNECTED) { delay(500); } + // 2nd try + if (WiFi.status() != WL_CONNECTED) { + WiFi.begin(ssid, password); + while (WiFi.status() != WL_CONNECTED) { + delay(500); + } + } + MDNS.begin(host); server.on("/", HTTP_GET, [&server, &loginMenu]() { @@ -122,8 +132,9 @@ void start_boot_menu(void) { [&server]() { server.sendHeader("Connection", "close"); server.send(200, "text/plain", (Update.hasError()) ? "FAIL" : "OK"); + RTC_runmode = Update.hasError() ? RUNMODE_NORMAL : RUNMODE_POWERCYCLE; WiFi.disconnect(true, true); - do_reset(false); // coldstart + esp_restart(); }, [&server, &timer]() { HTTPUpload &upload = server.upload(); From dceab074cad0a337af8aca97cbd338e729b0b8da Mon Sep 17 00:00:00 2001 From: cyberman54 Date: Sat, 6 Mar 2021 16:20:26 +0100 Subject: [PATCH 10/16] BT/WiFi coex fix needed for IDF4.1 --- src/wifiscan.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/wifiscan.cpp b/src/wifiscan.cpp index f57aab90..4e25d542 100644 --- a/src/wifiscan.cpp +++ b/src/wifiscan.cpp @@ -82,7 +82,12 @@ void wifi_sniffer_init(void) { void switch_wifi_sniffer(uint8_t state) { if (state) { - // start sniffer +// start sniffer +#if (BLECOUNTER) + // workaround needed for IDF 4.1 + // see https://github.com/espressif/esp-idf/issues/5427 + esp_wifi_set_ps(WIFI_PS_MIN_MODEM); +#endif esp_wifi_start(); esp_wifi_set_promiscuous(true); esp_wifi_set_channel(WIFI_CHANNEL_MIN, WIFI_SECOND_CHAN_NONE); From bc87dcb20565e2158afef5021faf86e7eccaf9ce Mon Sep 17 00:00:00 2001 From: cyberman54 Date: Sat, 6 Mar 2021 16:23:28 +0100 Subject: [PATCH 11/16] maintenance mode (set wifi hostname) --- src/boot.cpp | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/boot.cpp b/src/boot.cpp index bda99554..47a73af3 100644 --- a/src/boot.cpp +++ b/src/boot.cpp @@ -92,19 +92,21 @@ void start_boot_menu(void) { "});" ""; + WiFi.disconnect(true); + WiFi.config(INADDR_NONE, INADDR_NONE, + INADDR_NONE); // call is only a workaround for bug in WiFi class + // see https://github.com/espressif/arduino-esp32/issues/806 + WiFi.setHostname(host); + WiFi.mode(WIFI_STA); + // Connect to WiFi network // workaround applied here to avoid WIFI_AUTH failure // see https://github.com/espressif/arduino-esp32/issues/2501 - - WiFi.disconnect(true, true); - WiFi.mode(WIFI_STA); - // 1st try WiFi.begin(ssid, password); while (WiFi.status() == WL_DISCONNECTED) { delay(500); } - // 2nd try if (WiFi.status() != WL_CONNECTED) { WiFi.begin(ssid, password); @@ -133,7 +135,7 @@ void start_boot_menu(void) { server.sendHeader("Connection", "close"); server.send(200, "text/plain", (Update.hasError()) ? "FAIL" : "OK"); RTC_runmode = Update.hasError() ? RUNMODE_NORMAL : RUNMODE_POWERCYCLE; - WiFi.disconnect(true, true); + WiFi.disconnect(true); esp_restart(); }, [&server, &timer]() { From cd3195ec9b8e0cf0f772328337166a5c984b8909 Mon Sep 17 00:00:00 2001 From: cyberman54 Date: Sat, 6 Mar 2021 16:24:39 +0100 Subject: [PATCH 12/16] maintenance mode (display logic adjustment) --- src/display.cpp | 2 +- src/main.cpp | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/display.cpp b/src/display.cpp index e756ab47..65331bf6 100644 --- a/src/display.cpp +++ b/src/display.cpp @@ -159,7 +159,7 @@ void dp_init(bool verbose) { #if !(BOOTMENU) delay(8000); #endif - dp_contrast(DISPLAYCONTRAST); + #endif // HAS_LORA } // verbose diff --git a/src/main.cpp b/src/main.cpp index bc063d85..757d546c 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -540,6 +540,8 @@ void setup() { // set runmode to normal RTC_runmode = RUNMODE_NORMAL; + dp_clear(); + dp_contrast(DISPLAYCONTRAST); vTaskDelete(NULL); From 6cd6b5335793554e316b245240ab863b824ed11a Mon Sep 17 00:00:00 2001 From: cyberman54 Date: Sat, 6 Mar 2021 16:25:08 +0100 Subject: [PATCH 13/16] lib upgrades & increase version to 2.4.0 --- platformio_orig.ini | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/platformio_orig.ini b/platformio_orig.ini index c74a189d..bc0d8f68 100644 --- a/platformio_orig.ini +++ b/platformio_orig.ini @@ -49,7 +49,7 @@ description = Paxcounter is a device for metering passenger flows in realtime. I [common] ; for release_version use max. 10 chars total, use any decimal format like "a.b.c" -release_version = 2.3.0 +release_version = 2.4.0 ; DEBUG LEVEL: For production run set to 0, otherwise device will leak RAM while running! ; 0=None, 1=Error, 2=Warn, 3=Info, 4=Debug, 5=Verbose debug_level = 3 @@ -57,7 +57,7 @@ extra_scripts = pre:build.py otakeyfile = ota.conf lorakeyfile = loraconf.h lmicconfigfile = lmic_config.h -platform_espressif32 = espressif32@3.0.0 +platform_espressif32 = espressif32@3.1.0 monitor_speed = 115200 upload_speed = 115200 ; set by build.py and taken from hal file display_library = ; set by build.py and taken from hal file @@ -86,8 +86,7 @@ lib_deps_basic = jchristensen/Timezone @ ^1.2.4 makuna/RTC @ ^2.3.5 spacehuhn/SimpleButton - ;lewisxhe/AXP202X_Library @ ^1.1.2 - https://github.com/lewisxhe/AXP202X_Library.git + lewisxhe/AXP202X_Library @ ^1.1.3 geeksville/esp32-micro-sdcard @ ^0.1.1 256dpi/MQTT @ ^2.4.7 lib_deps_all = From e604db49d644ee2b978b4c937afe56cfdf0891e8 Mon Sep 17 00:00:00 2001 From: cyberman54 Date: Sat, 6 Mar 2021 16:32:10 +0100 Subject: [PATCH 14/16] maintenance mode (fix display logic) --- src/main.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 757d546c..35ec4e06 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -482,6 +482,8 @@ void setup() { // display interrupt #ifdef HAS_DISPLAY + dp_clear(); + dp_contrast(DISPLAYCONTRAST); // https://techtutorialsx.com/2017/10/07/esp32-arduino-timer-interrupts/ // prescaler 80 -> divides 80 MHz CPU freq to 1 MHz, timer 0, count up displayIRQ = timerBegin(0, 80, true); @@ -540,8 +542,6 @@ void setup() { // set runmode to normal RTC_runmode = RUNMODE_NORMAL; - dp_clear(); - dp_contrast(DISPLAYCONTRAST); vTaskDelete(NULL); From 6775faa87d977c185cec18ced666366fbe5dee25 Mon Sep 17 00:00:00 2001 From: cyberman54 Date: Sat, 6 Mar 2021 19:24:22 +0100 Subject: [PATCH 15/16] wifiscan.cpp comment edit --- src/wifiscan.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wifiscan.cpp b/src/wifiscan.cpp index 4e25d542..a4399a05 100644 --- a/src/wifiscan.cpp +++ b/src/wifiscan.cpp @@ -84,7 +84,7 @@ void switch_wifi_sniffer(uint8_t state) { if (state) { // start sniffer #if (BLECOUNTER) - // workaround needed for IDF 4.1 + // workaround needed for ESP-IDF v3.3 // see https://github.com/espressif/esp-idf/issues/5427 esp_wifi_set_ps(WIFI_PS_MIN_MODEM); #endif From e54c386e9edbdbe44dc6bed896dcf768b0f048b1 Mon Sep 17 00:00:00 2001 From: cyberman54 Date: Sat, 6 Mar 2021 19:24:42 +0100 Subject: [PATCH 16/16] maintenance mode (code sanitization) --- src/boot.cpp | 67 ++++++++++++++++++++++++++++++++-------------------- 1 file changed, 41 insertions(+), 26 deletions(-) diff --git a/src/boot.cpp b/src/boot.cpp index 47a73af3..272fd512 100644 --- a/src/boot.cpp +++ b/src/boot.cpp @@ -128,45 +128,60 @@ void start_boot_menu(void) { 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"); - RTC_runmode = Update.hasError() ? RUNMODE_NORMAL : RUNMODE_POWERCYCLE; WiFi.disconnect(true); + if (!Update.hasError()) + RTC_runmode = RUNMODE_POWERCYCLE; esp_restart(); }, + [&server, &timer]() { + bool success = false; HTTPUpload &upload = server.upload(); - if (upload.status == UPLOAD_FILE_START) { - ESP_LOGI(TAG, "Update: %s\n", upload.filename.c_str()); -#if (HAS_LED != NOT_A_PIN) -#ifndef LED_ACTIVE_LOW - if (!Update.begin(UPDATE_SIZE_UNKNOWN, U_FLASH, HAS_LED, HIGH)) { -#else - if (!Update.begin(UPDATE_SIZE_UNKNOWN, U_FLASH, HAS_LED, LOW)) { -#endif -#else - if (!Update.begin(UPDATE_SIZE_UNKNOWN)) { -#endif - ESP_LOGE(TAG, "Error: %s", Update.errorString()); - } - } else if (upload.status == UPLOAD_FILE_WRITE) { + + switch (upload.status) { + + case UPLOAD_FILE_START: + // start file transfer + ESP_LOGI(TAG, "Uploading %s", upload.filename.c_str()); + success = Update.begin(); + break; + + case UPLOAD_FILE_WRITE: // flashing firmware to ESP - if (Update.write(upload.buf, upload.currentSize) != - upload.currentSize) { - ESP_LOGE(TAG, "Error: %s", Update.errorString()); - } - } else if (upload.status == UPLOAD_FILE_END) { - if (Update.end( - true)) { // true to set the size to the current progress - ESP_LOGI(TAG, "Update finished, %u bytes written", + success = (Update.write(upload.buf, upload.currentSize) == + upload.currentSize); + 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, "Update failed, status=%d", upload.status); - } + else + ESP_LOGE(TAG, "Upload failed, status=%d", upload.status); + break; + + case UPLOAD_FILE_ABORTED: + default: + break; + + } // switch + + if (!success) { + ESP_LOGE(TAG, "Error: %s", Update.errorString()); + WiFi.disconnect(true); + esp_restart(); } });