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