From 6230239619e3942054fe219157403315e8db4fe8 Mon Sep 17 00:00:00 2001 From: tyeth Date: Fri, 11 Oct 2024 21:06:31 +0100 Subject: [PATCH 01/15] Change createBootFile to only if needed --- src/provisioning/tinyusb/Wippersnapper_FS.cpp | 64 +++++++++++-------- 1 file changed, 36 insertions(+), 28 deletions(-) diff --git a/src/provisioning/tinyusb/Wippersnapper_FS.cpp b/src/provisioning/tinyusb/Wippersnapper_FS.cpp index d99c6098b..7c4bcfded 100644 --- a/src/provisioning/tinyusb/Wippersnapper_FS.cpp +++ b/src/provisioning/tinyusb/Wippersnapper_FS.cpp @@ -269,44 +269,52 @@ void Wippersnapper_FS::eraseBootFile() { bool Wippersnapper_FS::createBootFile() { bool is_success = false; char sMAC[18] = {0}; + String newContent; - File32 bootFile = wipperFatFs.open("/wipper_boot_out.txt", FILE_WRITE); - if (bootFile) { - bootFile.println("Adafruit.io WipperSnapper"); - - bootFile.print("Firmware Version: "); - bootFile.println(WS_VERSION); - - bootFile.print("Board ID: "); - bootFile.println(BOARD_ID); - - sprintf(sMAC, "%02X:%02X:%02X:%02X:%02X:%02X", WS._macAddr[0], - WS._macAddr[1], WS._macAddr[2], WS._macAddr[3], WS._macAddr[4], - WS._macAddr[5]); - bootFile.print("MAC Address: "); - bootFile.println(sMAC); + // Generate new content + newContent += "Adafruit.io WipperSnapper\n"; + newContent += "Firmware Version: " + String(WS_VERSION) + "\n"; + newContent += "Board ID: " + String(BOARD_ID) + "\n"; + sprintf(sMAC, "%02X:%02X:%02X:%02X:%02X:%02X", WS._macAddr[0], + WS._macAddr[1], WS._macAddr[2], WS._macAddr[3], WS._macAddr[4], + WS._macAddr[5]); + newContent += "MAC Address: " + String(sMAC) + "\n"; #if PRINT_DEPENDENCIES - bootFile.println("Build dependencies:"); - bootFile.println(project_dependencies); + newContent += ("Build dependencies:\n"); + newContent += (project_dependencies); + newContent += ("\n"); #endif - // Print ESP-specific info to boot file - #ifdef ARDUINO_ARCH_ESP32 - // Get version of ESP-IDF - bootFile.print("ESP-IDF Version: "); - bootFile.println(ESP.getSdkVersion()); - // Get version of this core - bootFile.print("ESP32 Core Version: "); - bootFile.println(ESP.getCoreVersion()); - #endif + #ifdef ARDUINO_ARCH_ESP32 + newContent += "ESP-IDF Version: " + String(ESP.getSdkVersion()) + "\n"; + newContent += "ESP32 Core Version: " + String(ESP.getCoreVersion()) + "\n"; + #endif + + // Check if the file exists and read its content + File32 bootFile = wipperFatFs.open("/wipper_boot_out.txt", FILE_READ); + if (bootFile) { + String existingContent; + while (bootFile.available()) { + existingContent += char(bootFile.read()); + } + bootFile.close(); + + // Compare existing content with new content + if (existingContent == newContent) { + return true; // No need to overwrite + } + } + // Overwrite the file with new content + bootFile = wipperFatFs.open("/wipper_boot_out.txt", FILE_WRITE); + if (bootFile) { + bootFile.print(newContent); bootFile.flush(); bootFile.close(); is_success = true; - } else { - bootFile.close(); } + return is_success; } From 623a835834949ebb22fbf9a3238b0bcbd1c856fa Mon Sep 17 00:00:00 2001 From: tyeth Date: Fri, 11 Oct 2024 21:18:56 +0100 Subject: [PATCH 02/15] Only create "don't index" files if not there --- src/provisioning/tinyusb/Wippersnapper_FS.cpp | 43 ++++++++++++------- testplan.md | 13 ++++++ 2 files changed, 40 insertions(+), 16 deletions(-) create mode 100644 testplan.md diff --git a/src/provisioning/tinyusb/Wippersnapper_FS.cpp b/src/provisioning/tinyusb/Wippersnapper_FS.cpp index 7c4bcfded..26cc4b85b 100644 --- a/src/provisioning/tinyusb/Wippersnapper_FS.cpp +++ b/src/provisioning/tinyusb/Wippersnapper_FS.cpp @@ -105,7 +105,7 @@ Wippersnapper_FS::Wippersnapper_FS() { // If a filesystem does not already exist - attempt to initialize a new // filesystem - if (!initFilesystem() && !initFilesystem(true)) { + if (!initFilesystem()){ //} && !initFilesystem(true)) { setStatusLEDColor(RED); fsHalt("ERROR Initializing Filesystem"); } @@ -115,7 +115,7 @@ Wippersnapper_FS::Wippersnapper_FS() { // If we created a new filesystem, halt until user RESETs device. if (_freshFS) - fsHalt("New filesystem created! Press the reset button on your board."); + fsHalt("New filesystem created! Press the reset button on your board."); // TODO: just reset here after printing message then a delay/countdown. } /************************************************************/ @@ -159,29 +159,40 @@ bool Wippersnapper_FS::initFilesystem(bool force_format) { if (!wipperFatFs.begin(&flash)) return false; + //TODO: Don't do this unless we need the space and createSecrets fails // If CircuitPython was previously installed - erase CPY FS eraseCPFS(); + //TODO: don't do this every time, only if content differs? // If WipperSnapper was previously installed - remove the // wippersnapper_boot_out.txt file eraseBootFile(); + //TODO: don't do this every time, only if missing (less power usage? less block wear) // No file indexing on macOS - wipperFatFs.mkdir("/.fseventsd/"); - File32 writeFile = wipperFatFs.open("/.fseventsd/no_log", FILE_WRITE); - if (!writeFile) - return false; - writeFile.close(); - - writeFile = wipperFatFs.open("/.metadata_never_index", FILE_WRITE); - if (!writeFile) - return false; - writeFile.close(); + if (!wipperFatFs.exists("/.fseventsd/no_log")) + { + wipperFatFs.mkdir("/.fseventsd/"); + File32 writeFile = wipperFatFs.open("/.fseventsd/no_log", FILE_WRITE); + if (!writeFile) + return false; + writeFile.close(); + } - writeFile = wipperFatFs.open("/.Trashes", FILE_WRITE); - if (!writeFile) - return false; - writeFile.close(); + if (!wipperFatFs.exists("/.metadata_never_index")) + { + File32 writeFile = wipperFatFs.open("/.metadata_never_index", FILE_WRITE); + if (!writeFile) + return false; + writeFile.close(); + } + if (!wipperFatFs.exists("/.Trashes")) + { + File32 writeFile = wipperFatFs.open("/.Trashes", FILE_WRITE); + if (!writeFile) + return false; + writeFile.close(); + } // Create wippersnapper_boot_out.txt file if (!createBootFile()) diff --git a/testplan.md b/testplan.md new file mode 100644 index 000000000..41783fbd7 --- /dev/null +++ b/testplan.md @@ -0,0 +1,13 @@ +copy and analyse the hex difference for a corrupted file system versus freshly saved secrets + hunky dorey + +retest first secrets.json acces on a new device on tinyUF2 0.18.2 and WS 88, versus tinyUF2 0.20.1 and WS88, then with no-ds-format-nor-file-recreation instead of WS88 + +then add the metro-s3 +Update step images in ws_boards for metro-s3 + +then add FT usb-to-gpio to ws_python + + +Test ws_boards c6-aVref branch (esp32 aref=1.1 instead of 3.3, and C6 from 1.1 to 2.5v) + +Fix pin numbers + names for Metro S2 (all digital etc, tx/rx and D1 [etc] seem wrong, analog5 is wrong etc) \ No newline at end of file From 55be38cd79663d00d76a57acbcbeedb7638e33ed Mon Sep 17 00:00:00 2001 From: tyeth Date: Wed, 16 Oct 2024 14:42:44 +0100 Subject: [PATCH 03/15] dont erase bootlog unnecessarily, skip erase Circuitpython stuff --- platformio.ini | 2 +- src/provisioning/tinyusb/Wippersnapper_FS.cpp | 22 ++++++++++++++---- testplan.md | 23 ++++++++++++++++++- 3 files changed, 41 insertions(+), 6 deletions(-) diff --git a/platformio.ini b/platformio.ini index dd4acafc2..308148189 100644 --- a/platformio.ini +++ b/platformio.ini @@ -91,7 +91,7 @@ lib_deps = ; Common build environment for ESP32 platform [common:esp32] platform = https://github.com/pioarduino/platform-espressif32/releases/download/51.03.07/platform-espressif32.zip -; This is needed for occasional new features and bug fixes +; develop branch is needed for occasional new features and bug fixes, main may be preferred ; platform = https://github.com/pioarduino/platform-espressif32#develop lib_ignore = WiFiNINA, WiFi101, OneWire monitor_filters = esp32_exception_decoder, time diff --git a/src/provisioning/tinyusb/Wippersnapper_FS.cpp b/src/provisioning/tinyusb/Wippersnapper_FS.cpp index 26cc4b85b..346f295b5 100644 --- a/src/provisioning/tinyusb/Wippersnapper_FS.cpp +++ b/src/provisioning/tinyusb/Wippersnapper_FS.cpp @@ -159,14 +159,15 @@ bool Wippersnapper_FS::initFilesystem(bool force_format) { if (!wipperFatFs.begin(&flash)) return false; +if (false) { //TODO: reinstate after discussion over utility. Restest a full fs. + //TODO: Don't do this unless we need the space and createSecrets fails // If CircuitPython was previously installed - erase CPY FS eraseCPFS(); + // Also, should probably relabel drive to WIPPER if CIRCUITPY was there + // using setVolumeLabel(), but note the FS must be unmounted first +} - //TODO: don't do this every time, only if content differs? - // If WipperSnapper was previously installed - remove the - // wippersnapper_boot_out.txt file - eraseBootFile(); //TODO: don't do this every time, only if missing (less power usage? less block wear) // No file indexing on macOS @@ -313,10 +314,21 @@ bool Wippersnapper_FS::createBootFile() { // Compare existing content with new content if (existingContent == newContent) { + WS_DEBUG_PRINTLN("INFO: wipper_boot_out.txt already exists with the " + "same content."); return true; // No need to overwrite + } else { + WS_DEBUG_PRINTLN("INFO: wipper_boot_out.txt exists but with different " + "content. Overwriting..."); } + } else { + WS_DEBUG_PRINTLN("INFO: could not open wipper_boot_out.txt for reading. " + "Creating new file..."); } + // We probably don't need to erase first! + eraseBootFile(); + // Overwrite the file with new content bootFile = wipperFatFs.open("/wipper_boot_out.txt", FILE_WRITE); if (bootFile) { @@ -324,6 +336,8 @@ bool Wippersnapper_FS::createBootFile() { bootFile.flush(); bootFile.close(); is_success = true; + } else { + WS_DEBUG_PRINTLN("ERROR: Unable to open wipper_boot_out.txt for writing!"); } return is_success; diff --git a/testplan.md b/testplan.md index 41783fbd7..37f25f812 100644 --- a/testplan.md +++ b/testplan.md @@ -1,6 +1,18 @@ copy and analyse the hex difference for a corrupted file system versus freshly saved secrets + hunky dorey +-- nulls for file entry - like we've erased the file and then rebooted (before writing the replacement) +-- we do a lot of unnecessary file writing each boot, I'm optimising that to only if needed so normally there will be no file writes retest first secrets.json acces on a new device on tinyUF2 0.18.2 and WS 88, versus tinyUF2 0.20.1 and WS88, then with no-ds-format-nor-file-recreation instead of WS88 +-- no-fs-format-nor-file-recreation branch has eliminated the issue + +Cleanup eraseCPFS and retest with full file system and no secrets + different bootlog contents. also move write bootlog after secrets processing if not already + +Add boot reason detection for brownouts, if so and corrupt secrets/FS then fsHalt with appropriate message for 30s then reboot. + Bad USB cables on first boot should be accounted for - brownout serial message / fsHalt + +As part of boot protection add message when write or erase attempt and suggest user manually perform action. + Secondly consider moving all serial debug output to after usb reattach so user sees it, or at least repeat? + then add the metro-s3 Update step images in ws_boards for metro-s3 @@ -10,4 +22,13 @@ then add FT usb-to-gpio to ws_python Test ws_boards c6-aVref branch (esp32 aref=1.1 instead of 3.3, and C6 from 1.1 to 2.5v) -Fix pin numbers + names for Metro S2 (all digital etc, tx/rx and D1 [etc] seem wrong, analog5 is wrong etc) \ No newline at end of file +Fix pin numbers + names for Metro S2 (all digital etc, tx/rx and D1 [etc] seem wrong, analog5 is wrong etc) +Add guide pages for wippersnapper on metro s2 +Add guide pages for WS on C6 + +Check in on Marty's code / local mqtt issue. +Look at exception handling in mqtt library which seems biggest user hurdle +- consider capturing OSError etc and return mqtt exception? +- look at how IO fails too +- catch gai dns errors +- see what happens when no response / waiting message during loop call (people report exception but actually valid to have empty response) \ No newline at end of file From 7718455e3601b1020413a1407e85a7a34e57ddbb Mon Sep 17 00:00:00 2001 From: tyeth Date: Thu, 24 Oct 2024 10:47:05 +0100 Subject: [PATCH 04/15] Fix printing of ESP reset reason --- src/Wippersnapper.cpp | 32 +++++++++++++++++++++++++++++--- 1 file changed, 29 insertions(+), 3 deletions(-) diff --git a/src/Wippersnapper.cpp b/src/Wippersnapper.cpp index a4c190825..3c93f5850 100644 --- a/src/Wippersnapper.cpp +++ b/src/Wippersnapper.cpp @@ -2644,9 +2644,34 @@ void Wippersnapper::publish(const char *topic, uint8_t *payload, uint16_t bLen, } } +#ifdef ARDUINO_ARCH_ESP32 + +#if CONFIG_IDF_TARGET_ESP32 // ESP32/PICO-D4 +#include "esp32/rom/rtc.h" +#elif CONFIG_IDF_TARGET_ESP32S2 +#include "esp32s2/rom/rtc.h" +#elif CONFIG_IDF_TARGET_ESP32C2 +#include "esp32c2/rom/rtc.h" +#elif CONFIG_IDF_TARGET_ESP32C3 +#include "esp32c3/rom/rtc.h" +#elif CONFIG_IDF_TARGET_ESP32S3 +#include "esp32s3/rom/rtc.h" +#elif CONFIG_IDF_TARGET_ESP32C6 +#include "esp32c6/rom/rtc.h" +#elif CONFIG_IDF_TARGET_ESP32H2 +#include "esp32h2/rom/rtc.h" +#else +#error Target CONFIG_IDF_TARGET is not supported +#endif + +void get_and_print_reset_reason_for_cpu(int cpuCore) { + print_reset_reason(rtc_get_reset_reason(cpuCore)); +} + + /**************************************************************/ /*! - @brief Prints last reset reason of ESP32 + @brief Prints string reset reason of ESP32 @param reason The return code of rtc_get_reset_reason(coreNum) */ @@ -2704,6 +2729,7 @@ void print_reset_reason(int reason) { WS_DEBUG_PRINTLN("NO_MEAN"); } } +#endif /**************************************************************************/ /*! @@ -2731,9 +2757,9 @@ void printDeviceInfo() { // (ESP32-Only) Print reason why device was reset #ifdef ARDUINO_ARCH_ESP32 WS_DEBUG_PRINT("ESP32 CPU0 RESET REASON: "); - print_reset_reason(0); + get_and_print_reset_reason_for_cpu(0); WS_DEBUG_PRINT("ESP32 CPU1 RESET REASON: "); - print_reset_reason(1); + get_and_print_reset_reason_for_cpu(1); #endif } From 3156688b133cd52a9315d4b2d3b41c94ac8ed19d Mon Sep 17 00:00:00 2001 From: tyeth Date: Thu, 24 Oct 2024 10:54:36 +0100 Subject: [PATCH 05/15] Store if brownout boot --- src/Wippersnapper.cpp | 1 + src/Wippersnapper.h | 7 ++++--- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/Wippersnapper.cpp b/src/Wippersnapper.cpp index 3c93f5850..770e1d24d 100644 --- a/src/Wippersnapper.cpp +++ b/src/Wippersnapper.cpp @@ -2721,6 +2721,7 @@ void print_reset_reason(int reason) { break; /**<14, for APP CPU, reseted by PRO CPU*/ case 15: WS_DEBUG_PRINTLN("RTCWDT_BROWN_OUT_RESET"); + WS.brownOutCausedReset = true; break; /**<15, Reset when the vdd voltage is not stable*/ case 16: WS_DEBUG_PRINTLN("RTCWDT_RTC_RESET"); diff --git a/src/Wippersnapper.h b/src/Wippersnapper.h index 0c418eab2..98afbf09f 100644 --- a/src/Wippersnapper.h +++ b/src/Wippersnapper.h @@ -254,9 +254,10 @@ class Wippersnapper { void provision(); - bool lockStatusNeoPixel; ///< True if status LED is using the status neopixel - bool lockStatusDotStar; ///< True if status LED is using the status dotstar - bool lockStatusLED; ///< True if status LED is using the built-in LED + bool brownOutCausedReset = false; ///< True if low power reset - flash write issues + bool lockStatusNeoPixel; ///< True if status LED is using the status neopixel + bool lockStatusDotStar; ///< True if status LED is using the status dotstar + bool lockStatusLED; ///< True if status LED is using the built-in LED float status_pixel_brightness = STATUS_PIXEL_BRIGHTNESS_DEFAULT; ///< Global status pixel's brightness ///< (from 0.0 to 1.0) From 058fc242e6bb494d9e2737cd162df2357c6cfd75 Mon Sep 17 00:00:00 2001 From: tyeth Date: Fri, 25 Oct 2024 15:43:42 +0100 Subject: [PATCH 06/15] Minimum change if brownout (don't erase CPYFS) --- src/provisioning/tinyusb/Wippersnapper_FS.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/provisioning/tinyusb/Wippersnapper_FS.cpp b/src/provisioning/tinyusb/Wippersnapper_FS.cpp index 346f295b5..49d318a6f 100644 --- a/src/provisioning/tinyusb/Wippersnapper_FS.cpp +++ b/src/provisioning/tinyusb/Wippersnapper_FS.cpp @@ -97,6 +97,7 @@ Wippersnapper_FS::Wippersnapper_FS() { WS_DEBUG_PRINTLN(project_dependencies); WS_DEBUG_PRINTLN("*********************"); WS_PRINTER.flush(); + delay(50); // give host a chance to finish reading serial buffer #endif // Detach USB device during init. TinyUSBDevice.detach(); @@ -159,17 +160,12 @@ bool Wippersnapper_FS::initFilesystem(bool force_format) { if (!wipperFatFs.begin(&flash)) return false; -if (false) { //TODO: reinstate after discussion over utility. Restest a full fs. - //TODO: Don't do this unless we need the space and createSecrets fails // If CircuitPython was previously installed - erase CPY FS eraseCPFS(); // Also, should probably relabel drive to WIPPER if CIRCUITPY was there // using setVolumeLabel(), but note the FS must be unmounted first -} - - //TODO: don't do this every time, only if missing (less power usage? less block wear) // No file indexing on macOS if (!wipperFatFs.exists("/.fseventsd/no_log")) { @@ -196,7 +192,7 @@ if (false) { //TODO: reinstate after discussion over utility. Restest a full fs. } // Create wippersnapper_boot_out.txt file - if (!createBootFile()) + if (!createBootFile() && !WS.brownOutCausedReset) return false; // Check if secrets.json file already exists @@ -253,6 +249,9 @@ bool Wippersnapper_FS::configFileExists() { */ /**************************************************************************/ void Wippersnapper_FS::eraseCPFS() { + if (WS.brownOutCausedReset){ + return; // Can't serial print here, in next PR check we're not out of space + } if (wipperFatFs.exists("/boot_out.txt")) { wipperFatFs.remove("/boot_out.txt"); wipperFatFs.remove("/code.py"); @@ -326,8 +325,9 @@ bool Wippersnapper_FS::createBootFile() { "Creating new file..."); } - // We probably don't need to erase first! - eraseBootFile(); + if (WS.brownOutCausedReset){ + return false; + } // Overwrite the file with new content bootFile = wipperFatFs.open("/wipper_boot_out.txt", FILE_WRITE); From 02984e9bc4aae33b4147ed15866655983c05f1e8 Mon Sep 17 00:00:00 2001 From: tyeth Date: Fri, 25 Oct 2024 16:10:36 +0100 Subject: [PATCH 07/15] Doxgen + reorder methods --- src/Wippersnapper.cpp | 54 ++++++++++++++++++++++++------------------- 1 file changed, 30 insertions(+), 24 deletions(-) diff --git a/src/Wippersnapper.cpp b/src/Wippersnapper.cpp index 770e1d24d..c75861300 100644 --- a/src/Wippersnapper.cpp +++ b/src/Wippersnapper.cpp @@ -2645,30 +2645,6 @@ void Wippersnapper::publish(const char *topic, uint8_t *payload, uint16_t bLen, } #ifdef ARDUINO_ARCH_ESP32 - -#if CONFIG_IDF_TARGET_ESP32 // ESP32/PICO-D4 -#include "esp32/rom/rtc.h" -#elif CONFIG_IDF_TARGET_ESP32S2 -#include "esp32s2/rom/rtc.h" -#elif CONFIG_IDF_TARGET_ESP32C2 -#include "esp32c2/rom/rtc.h" -#elif CONFIG_IDF_TARGET_ESP32C3 -#include "esp32c3/rom/rtc.h" -#elif CONFIG_IDF_TARGET_ESP32S3 -#include "esp32s3/rom/rtc.h" -#elif CONFIG_IDF_TARGET_ESP32C6 -#include "esp32c6/rom/rtc.h" -#elif CONFIG_IDF_TARGET_ESP32H2 -#include "esp32h2/rom/rtc.h" -#else -#error Target CONFIG_IDF_TARGET is not supported -#endif - -void get_and_print_reset_reason_for_cpu(int cpuCore) { - print_reset_reason(rtc_get_reset_reason(cpuCore)); -} - - /**************************************************************/ /*! @brief Prints string reset reason of ESP32 @@ -2730,8 +2706,38 @@ void print_reset_reason(int reason) { WS_DEBUG_PRINTLN("NO_MEAN"); } } + +#if CONFIG_IDF_TARGET_ESP32 // ESP32/PICO-D4 +#include "esp32/rom/rtc.h" +#elif CONFIG_IDF_TARGET_ESP32S2 +#include "esp32s2/rom/rtc.h" +#elif CONFIG_IDF_TARGET_ESP32C2 +#include "esp32c2/rom/rtc.h" +#elif CONFIG_IDF_TARGET_ESP32C3 +#include "esp32c3/rom/rtc.h" +#elif CONFIG_IDF_TARGET_ESP32S3 +#include "esp32s3/rom/rtc.h" +#elif CONFIG_IDF_TARGET_ESP32C6 +#include "esp32c6/rom/rtc.h" +#elif CONFIG_IDF_TARGET_ESP32H2 +#include "esp32h2/rom/rtc.h" +#else +#error Target CONFIG_IDF_TARGET is not supported #endif +/**************************************************************************/ +/*! + @brief Prints the reason why the ESP32 CPU was reset. + @param cpuCore + The core number to print the reset reason for. +*/ +/**************************************************************************/ +void get_and_print_reset_reason_for_cpu(int cpuCore) { + print_reset_reason(rtc_get_reset_reason(cpuCore)); +} + +#endif // ARDUINO_ARCH_ESP32 + /**************************************************************************/ /*! @brief Prints information about the WS device to the serial monitor. From b8ea2316b09efc3220f16dcdd63cb75e42948c87 Mon Sep 17 00:00:00 2001 From: tyeth Date: Fri, 25 Oct 2024 17:03:50 +0100 Subject: [PATCH 08/15] Reinitialise Mass Storage Device after createSecrets --- src/provisioning/tinyusb/Wippersnapper_FS.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/provisioning/tinyusb/Wippersnapper_FS.cpp b/src/provisioning/tinyusb/Wippersnapper_FS.cpp index 49d318a6f..5083e2c47 100644 --- a/src/provisioning/tinyusb/Wippersnapper_FS.cpp +++ b/src/provisioning/tinyusb/Wippersnapper_FS.cpp @@ -371,6 +371,7 @@ void Wippersnapper_FS::createSecretsFile() { secretsFile.flush(); secretsFile.close(); delay(2500); + initUSBMSC(); // re-init USB MSC to show new file to user for editing // Signal to user that action must be taken (edit secrets.json) writeToBootOut( From 5ef81f2da0a857b49d1589e0f0a5abcfc494e89f Mon Sep 17 00:00:00 2001 From: tyeth Date: Fri, 25 Oct 2024 17:07:16 +0100 Subject: [PATCH 09/15] Clang format and remove ESP32-H2 ifdef --- src/Wippersnapper.cpp | 4 +--- src/Wippersnapper.h | 9 +++++---- testplan.md | 34 ---------------------------------- 3 files changed, 6 insertions(+), 41 deletions(-) delete mode 100644 testplan.md diff --git a/src/Wippersnapper.cpp b/src/Wippersnapper.cpp index c75861300..d3c7b94b2 100644 --- a/src/Wippersnapper.cpp +++ b/src/Wippersnapper.cpp @@ -2707,7 +2707,7 @@ void print_reset_reason(int reason) { } } -#if CONFIG_IDF_TARGET_ESP32 // ESP32/PICO-D4 +#if CONFIG_IDF_TARGET_ESP32 // ESP32/PICO-D4 #include "esp32/rom/rtc.h" #elif CONFIG_IDF_TARGET_ESP32S2 #include "esp32s2/rom/rtc.h" @@ -2719,8 +2719,6 @@ void print_reset_reason(int reason) { #include "esp32s3/rom/rtc.h" #elif CONFIG_IDF_TARGET_ESP32C6 #include "esp32c6/rom/rtc.h" -#elif CONFIG_IDF_TARGET_ESP32H2 -#include "esp32h2/rom/rtc.h" #else #error Target CONFIG_IDF_TARGET is not supported #endif diff --git a/src/Wippersnapper.h b/src/Wippersnapper.h index 98afbf09f..730a9749b 100644 --- a/src/Wippersnapper.h +++ b/src/Wippersnapper.h @@ -254,10 +254,11 @@ class Wippersnapper { void provision(); - bool brownOutCausedReset = false; ///< True if low power reset - flash write issues - bool lockStatusNeoPixel; ///< True if status LED is using the status neopixel - bool lockStatusDotStar; ///< True if status LED is using the status dotstar - bool lockStatusLED; ///< True if status LED is using the built-in LED + bool brownOutCausedReset = + false; ///< True if low power reset - flash write issues + bool lockStatusNeoPixel; ///< True if status LED is using the status neopixel + bool lockStatusDotStar; ///< True if status LED is using the status dotstar + bool lockStatusLED; ///< True if status LED is using the built-in LED float status_pixel_brightness = STATUS_PIXEL_BRIGHTNESS_DEFAULT; ///< Global status pixel's brightness ///< (from 0.0 to 1.0) diff --git a/testplan.md b/testplan.md deleted file mode 100644 index 37f25f812..000000000 --- a/testplan.md +++ /dev/null @@ -1,34 +0,0 @@ -copy and analyse the hex difference for a corrupted file system versus freshly saved secrets + hunky dorey --- nulls for file entry - like we've erased the file and then rebooted (before writing the replacement) --- we do a lot of unnecessary file writing each boot, I'm optimising that to only if needed so normally there will be no file writes - -retest first secrets.json acces on a new device on tinyUF2 0.18.2 and WS 88, versus tinyUF2 0.20.1 and WS88, then with no-ds-format-nor-file-recreation instead of WS88 --- no-fs-format-nor-file-recreation branch has eliminated the issue - -Cleanup eraseCPFS and retest with full file system and no secrets + different bootlog contents. also move write bootlog after secrets processing if not already - -Add boot reason detection for brownouts, if so and corrupt secrets/FS then fsHalt with appropriate message for 30s then reboot. - Bad USB cables on first boot should be accounted for - brownout serial message / fsHalt - -As part of boot protection add message when write or erase attempt and suggest user manually perform action. - Secondly consider moving all serial debug output to after usb reattach so user sees it, or at least repeat? - - -then add the metro-s3 -Update step images in ws_boards for metro-s3 - -then add FT usb-to-gpio to ws_python - - -Test ws_boards c6-aVref branch (esp32 aref=1.1 instead of 3.3, and C6 from 1.1 to 2.5v) - -Fix pin numbers + names for Metro S2 (all digital etc, tx/rx and D1 [etc] seem wrong, analog5 is wrong etc) -Add guide pages for wippersnapper on metro s2 -Add guide pages for WS on C6 - -Check in on Marty's code / local mqtt issue. -Look at exception handling in mqtt library which seems biggest user hurdle -- consider capturing OSError etc and return mqtt exception? -- look at how IO fails too -- catch gai dns errors -- see what happens when no response / waiting message during loop call (people report exception but actually valid to have empty response) \ No newline at end of file From 2dbb8c6aeb032a651d9b9197b523911c902b45e2 Mon Sep 17 00:00:00 2001 From: tyeth Date: Fri, 8 Nov 2024 16:59:31 +0000 Subject: [PATCH 10/15] Disallow format file system if brownout, allow otherwise --- src/provisioning/tinyusb/Wippersnapper_FS.cpp | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/provisioning/tinyusb/Wippersnapper_FS.cpp b/src/provisioning/tinyusb/Wippersnapper_FS.cpp index 5083e2c47..061f2880c 100644 --- a/src/provisioning/tinyusb/Wippersnapper_FS.cpp +++ b/src/provisioning/tinyusb/Wippersnapper_FS.cpp @@ -106,9 +106,18 @@ Wippersnapper_FS::Wippersnapper_FS() { // If a filesystem does not already exist - attempt to initialize a new // filesystem - if (!initFilesystem()){ //} && !initFilesystem(true)) { - setStatusLEDColor(RED); - fsHalt("ERROR Initializing Filesystem"); + if (!initFilesystem()) { + if (WS.brownOutCausedReset) { + // try once more for good measure + delay(10); // let power stablise after failure + if (!initFilesystem()) { + // no lights, save power as we're probably on a low battery + fsHalt("Brownout detected. Couldn't initialise filesystem."); + } + } else if (!WS.brownOutCausedReset && !initFilesystem(true)) { + setStatusLEDColor(RED); + fsHalt("ERROR Initializing Filesystem"); + } } // Initialize USB-MSD From ec3cc781fb184bd4384689263c7e27dd45895639 Mon Sep 17 00:00:00 2001 From: tyeth Date: Fri, 8 Nov 2024 17:22:11 +0000 Subject: [PATCH 11/15] Change _freshFS to self reboot --- src/provisioning/tinyusb/Wippersnapper_FS.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/provisioning/tinyusb/Wippersnapper_FS.cpp b/src/provisioning/tinyusb/Wippersnapper_FS.cpp index 061f2880c..f24050745 100644 --- a/src/provisioning/tinyusb/Wippersnapper_FS.cpp +++ b/src/provisioning/tinyusb/Wippersnapper_FS.cpp @@ -125,7 +125,15 @@ Wippersnapper_FS::Wippersnapper_FS() { // If we created a new filesystem, halt until user RESETs device. if (_freshFS) - fsHalt("New filesystem created! Press the reset button on your board."); // TODO: just reset here after printing message then a delay/countdown. + { + WS_DEBUG_PRINTLN("New filesystem created! Resetting the board shortly..."); + WS_PRINTER.flush(); + WS.enableWDT(500); + while (1) + { + delay(1000); + } + } } /************************************************************/ From 397e3d28a1300d6cd10f54aad77fe19df8caa5c1 Mon Sep 17 00:00:00 2001 From: tyeth Date: Fri, 8 Nov 2024 18:21:29 +0000 Subject: [PATCH 12/15] Add RP2040/2350 reset reason / brownout detection --- src/Wippersnapper.cpp | 37 +++++++++++++++++++++++++++++++++++-- 1 file changed, 35 insertions(+), 2 deletions(-) diff --git a/src/Wippersnapper.cpp b/src/Wippersnapper.cpp index d3c7b94b2..85b3a2e3c 100644 --- a/src/Wippersnapper.cpp +++ b/src/Wippersnapper.cpp @@ -2734,7 +2734,38 @@ void get_and_print_reset_reason_for_cpu(int cpuCore) { print_reset_reason(rtc_get_reset_reason(cpuCore)); } -#endif // ARDUINO_ARCH_ESP32 +// end of ARDUINO_ARCH_ESP32 +#elif defined(ARDUINO_ARCH_RP2040) + +void print_reset_reason() +{ + RP2040::resetReason_t reason = rp2040.getResetReason(); + WS_DEBUG_PRINT("RP2040 RESET REASON: "); + switch (reason) + { + case RP2040::resetReason_t::UNKNOWN_RESET: + WS_DEBUG_PRINTLN("Unknown Reset"); + case RP2040::resetReason_t::PWRON_RESET: + WS_DEBUG_PRINTLN("Power-On Reset"); + case RP2040::resetReason_t::RUN_PIN_RESET: + WS_DEBUG_PRINTLN("Run Pin Reset"); + case RP2040::resetReason_t::SOFT_RESET: + WS_DEBUG_PRINTLN("Soft Reset"); + case RP2040::resetReason_t::WDT_RESET: + WS_DEBUG_PRINTLN("Watchdog Timer Reset"); + case RP2040::resetReason_t::DEBUG_RESET: + WS_DEBUG_PRINTLN("Debug Reset"); + case RP2040::resetReason_t::GLITCH_RESET: + WS_DEBUG_PRINTLN("Glitch Reset"); + case RP2040::resetReason_t::BROWNOUT_RESET: + WS.brownOutCausedReset = true; + WS_DEBUG_PRINTLN("Brownout Reset"); + default: + WS_DEBUG_PRINTLN("Unknown Reset Reason"); + } +} + +#endif /**************************************************************************/ /*! @@ -2765,12 +2796,14 @@ void printDeviceInfo() { get_and_print_reset_reason_for_cpu(0); WS_DEBUG_PRINT("ESP32 CPU1 RESET REASON: "); get_and_print_reset_reason_for_cpu(1); +#elif defined(ARDUINO_ARCH_RP2040) || defined(PICO_RP2350) + print_reset_reason(); #endif } /**************************************************************************/ /*! - @brief Connects to Adafruit IO+ Wippersnapper broker. + @brief Connects to Adafruit IO Wippersnapper broker. */ /**************************************************************************/ void Wippersnapper::connect() { From 2505177e7678d879f89b2439e5e709a625693b5c Mon Sep 17 00:00:00 2001 From: tyeth Date: Fri, 8 Nov 2024 18:34:53 +0000 Subject: [PATCH 13/15] Reinitialise secrets if empty, otherwise leave as-is --- src/provisioning/tinyusb/Wippersnapper_FS.cpp | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/src/provisioning/tinyusb/Wippersnapper_FS.cpp b/src/provisioning/tinyusb/Wippersnapper_FS.cpp index f24050745..4b9423778 100644 --- a/src/provisioning/tinyusb/Wippersnapper_FS.cpp +++ b/src/provisioning/tinyusb/Wippersnapper_FS.cpp @@ -418,7 +418,23 @@ void Wippersnapper_FS::parseSecrets() { // Attempt to deserialize the file's JSON document JsonDocument doc; DeserializationError error = deserializeJson(doc, secretsFile); - if (error) { + if (error == DeserializationError::EmptyInput) + { + if (WS.brownOutCausedReset) + { + fsHalt("ERROR: Empty secrets.json file, can't recreate due to brownout - recharge or must be fixed manually."); + } + else + { + // TODO: Can't serial print here, in next PR check we're not out of space + WS_DEBUG_PRINTLN("ERROR: Empty secrets.json file, recreating..."); + secretsFile.close(); + wipperFatFs.remove("/secrets.json"); + createSecretsFile(); // calls fsHalt + } + } + else if (error) + { fsHalt(String("ERROR: Unable to parse secrets.json file - " "deserializeJson() failed with code") + error.c_str()); From b8babfedc9a6e8956842009cfb8e27ad48df829b Mon Sep 17 00:00:00 2001 From: tyeth Date: Tue, 12 Nov 2024 22:48:32 +0000 Subject: [PATCH 14/15] clang format --- src/Wippersnapper.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/Wippersnapper.cpp b/src/Wippersnapper.cpp index 85b3a2e3c..fc0b2a36f 100644 --- a/src/Wippersnapper.cpp +++ b/src/Wippersnapper.cpp @@ -2737,12 +2737,10 @@ void get_and_print_reset_reason_for_cpu(int cpuCore) { // end of ARDUINO_ARCH_ESP32 #elif defined(ARDUINO_ARCH_RP2040) -void print_reset_reason() -{ +void print_reset_reason() { RP2040::resetReason_t reason = rp2040.getResetReason(); WS_DEBUG_PRINT("RP2040 RESET REASON: "); - switch (reason) - { + switch (reason) { case RP2040::resetReason_t::UNKNOWN_RESET: WS_DEBUG_PRINTLN("Unknown Reset"); case RP2040::resetReason_t::PWRON_RESET: From 3403744ef4457632b6f9a96bdf6573148b43a247 Mon Sep 17 00:00:00 2001 From: tyeth Date: Fri, 15 Nov 2024 15:03:05 +0000 Subject: [PATCH 15/15] Reduce delay + don't reinit USB MSC until after writeToBootOut --- src/provisioning/tinyusb/Wippersnapper_FS.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/provisioning/tinyusb/Wippersnapper_FS.cpp b/src/provisioning/tinyusb/Wippersnapper_FS.cpp index 4b9423778..2f6326af5 100644 --- a/src/provisioning/tinyusb/Wippersnapper_FS.cpp +++ b/src/provisioning/tinyusb/Wippersnapper_FS.cpp @@ -127,7 +127,6 @@ Wippersnapper_FS::Wippersnapper_FS() { if (_freshFS) { WS_DEBUG_PRINTLN("New filesystem created! Resetting the board shortly..."); - WS_PRINTER.flush(); WS.enableWDT(500); while (1) { @@ -387,8 +386,6 @@ void Wippersnapper_FS::createSecretsFile() { // Flush and close file secretsFile.flush(); secretsFile.close(); - delay(2500); - initUSBMSC(); // re-init USB MSC to show new file to user for editing // Signal to user that action must be taken (edit secrets.json) writeToBootOut( @@ -400,6 +397,8 @@ void Wippersnapper_FS::createSecretsFile() { "Please edit it to reflect your Adafruit IO and network credentials. " "When you're done, press RESET on the board."); #endif + delay(500); // previously 2500 + initUSBMSC(); // re-init USB MSC to show new file to user for editing fsHalt("ERROR: Please edit the secrets.json file. Then, reset your board."); }