From 90f3beda369ae7e714b5ac2cc6f2ce5346483ff5 Mon Sep 17 00:00:00 2001 From: Martino Facchin Date: Thu, 20 May 2021 17:52:45 +0200 Subject: [PATCH 01/37] INITIAL: support OTA on Nano RP2040 COnnect --- src/AIoTC_Config.h | 7 +++ src/ArduinoIoTCloudTCP.cpp | 14 +++++- src/utility/ota/OTA-nano-rp2040.cpp | 72 +++++++++++++++++++++++++++++ src/utility/ota/OTA.h | 4 ++ 4 files changed, 95 insertions(+), 2 deletions(-) create mode 100644 src/utility/ota/OTA-nano-rp2040.cpp diff --git a/src/AIoTC_Config.h b/src/AIoTC_Config.h index 7c54d1751..56d430d7a 100644 --- a/src/AIoTC_Config.h +++ b/src/AIoTC_Config.h @@ -94,6 +94,13 @@ #define OTA_STORAGE_SNU (0) #endif +#if defined(ARDUINO_NANO_RP2040_CONNECT) + #undef OTA_STORAGE_SFU + #define OTA_STORAGE_SFU (1) +#else + #define OTA_STORAGE_SFU (0) +#endif + #ifdef ARDUINO_SAMD_MKRGSM1400 #define OTA_STORAGE_SSU (1) #else diff --git a/src/ArduinoIoTCloudTCP.cpp b/src/ArduinoIoTCloudTCP.cpp index 653952e42..be744294e 100644 --- a/src/ArduinoIoTCloudTCP.cpp +++ b/src/ArduinoIoTCloudTCP.cpp @@ -171,7 +171,13 @@ int ArduinoIoTCloudTCP::begin(bool const enable_watchdog, String brokerAddress, * The bootloader is excluded from the calculation and occupies flash address * range 0 to 0x2000, total flash size of 0x40000 bytes (256 kByte). */ - String const sha256_str = FlashSHA256::calc(0x2000, 0x40000 - 0x2000); +#if defined(ARDUINO_NANO_RP2040_CONNECT) +#define FLASH_BASE XIP_BASE + _ota_cap = true; +#else +#define FLASH_BASE 0 +#endif + String const sha256_str = FlashSHA256::calc(FLASH_BASE + 0x2000, 0x40000 - 0x2000); #endif DEBUG_VERBOSE("SHA256: HASH(%d) = %s", strlen(sha256_str.c_str()), sha256_str.c_str()); _ota_img_sha256 = sha256_str; @@ -581,12 +587,16 @@ int ArduinoIoTCloudTCP::write(String const topic, byte const data[], int const l #if OTA_ENABLED void ArduinoIoTCloudTCP::onOTARequest() { - DEBUG_VERBOSE("ArduinoIoTCloudTCP::%s _ota_url = %s", __FUNCTION__, _ota_url.c_str()); + DEBUG_INFO("ArduinoIoTCloudTCP::%s _ota_url = %s", __FUNCTION__, _ota_url.c_str()); #ifdef ARDUINO_ARCH_SAMD _ota_error = samd_onOTARequest(_ota_url.c_str()); #endif +#ifdef ARDUINO_NANO_RP2040_CONNECT + _ota_error = rp2040_connect_onOTARequest(_ota_url.c_str()); +#endif + #if defined(ARDUINO_PORTENTA_H7_M7) || defined(ARDUINO_PORTENTA_H7_M4) _ota_error = portenta_h7_onOTARequest(_ota_url.c_str()); #endif diff --git a/src/utility/ota/OTA-nano-rp2040.cpp b/src/utility/ota/OTA-nano-rp2040.cpp new file mode 100644 index 000000000..426bb5fb0 --- /dev/null +++ b/src/utility/ota/OTA-nano-rp2040.cpp @@ -0,0 +1,72 @@ +/* + This file is part of ArduinoIoTCloud. + + Copyright 2020 ARDUINO SA (http://www.arduino.cc/) + + This software is released under the GNU General Public License version 3, + which covers the main part of arduino-cli. + The terms of this license can be found at: + https://www.gnu.org/licenses/gpl-3.0.en.html + + You can be released from the requirements of the above licenses by purchasing + a commercial license. Buying such a license is mandatory if you want to modify or + otherwise use the software for commercial activities involving the Arduino + software without disclosing the source code of your own applications. To purchase + a commercial license, send an email to license@arduino.cc. +*/ + +#if defined(ARDUINO_NANO_RP2040_CONNECT) + +/****************************************************************************** + * INCLUDE + ******************************************************************************/ + +#include "OTA.h" + +#include + +/****************************************************************************** + * FUNCTION DEFINITION + ******************************************************************************/ + +int rp2040_connect_onOTARequest(char const * ota_url) +{ + SFU::begin(); + + /* Just to be safe delete any remains from previous updates. */ + WiFiStorage.remove("/fs/UPDATE.BIN"); + struct stat st; + int err = stat("/ota/UPDATE.BIN", &st); + if (err == 0) { + remove("/ota/UPDATE.BIN"); + } + + /* TODO: FIXME: Download into NINA then transfer to /fs/UPDATE.BIN */ + uint8_t nina_ota_err_code = 0; + if (!WiFiStorage.downloadOTA(ota_url, &nina_ota_err_code)) + { + DEBUG_ERROR("ArduinoIoTCloudTCP::%s error download to nina: %d", __FUNCTION__, nina_ota_err_code); + return static_cast(OTAError::DownloadFailed); + } + + FILE* update = fopen("/ota/UPDATE.BIN", "w"); + + uint8_t tempbuf[128]; + + WiFiStorageFile nina_update = WiFiStorage.open("/fs/UPDATE.BIN"); + + while (true) { + int ret = nina_update.read(tempbuf, sizeof(tempbuf)); + if (ret == 0) { + break; + } + fwrite(tempbuf, ret, 1, update); + } + + fclose(update); + + /* Perform the reset to reboot to SxU. */ + NVIC_SystemReset(); +} + +#endif /* ARDUINO_NANO_RP2040_CONNECT */ diff --git a/src/utility/ota/OTA.h b/src/utility/ota/OTA.h index 6a9b2312f..9d103d053 100644 --- a/src/utility/ota/OTA.h +++ b/src/utility/ota/OTA.h @@ -50,6 +50,10 @@ enum class OTAError : int int samd_onOTARequest(char const * ota_url); #endif +#ifdef ARDUINO_NANO_RP2040_CONNECT +int rp2040_connect_onOTARequest(char const * ota_url); +#endif + #if defined(ARDUINO_PORTENTA_H7_M7) || defined(ARDUINO_PORTENTA_H7_M4) int portenta_h7_onOTARequest(char const * ota_url); #endif From b27e30b85b20769abfa280b167be5279333cf5ba Mon Sep 17 00:00:00 2001 From: Martino Facchin Date: Tue, 25 May 2021 15:05:44 +0200 Subject: [PATCH 02/37] TEMP: add proper download via WiFi/WiFiSSL client --- src/AIoTC_Config.h | 2 +- src/ArduinoIoTCloudTCP.cpp | 5 +- src/utility/ota/OTA-nano-rp2040.cpp | 138 +++++++++++++++++++++++++--- 3 files changed, 127 insertions(+), 18 deletions(-) diff --git a/src/AIoTC_Config.h b/src/AIoTC_Config.h index 56d430d7a..70af6b716 100644 --- a/src/AIoTC_Config.h +++ b/src/AIoTC_Config.h @@ -66,7 +66,7 @@ # if defined(ARDUINO_AVR_UNO_WIFI_REV2) # define DEBUG_VERBOSE(fmt, ...) # else -# define DEBUG_VERBOSE(fmt, ...) //Debug.print(DBG_VERBOSE, fmt, ## __VA_ARGS__) +# define DEBUG_VERBOSE(fmt, ...) Debug.print(DBG_VERBOSE, fmt, ## __VA_ARGS__) # endif #endif diff --git a/src/ArduinoIoTCloudTCP.cpp b/src/ArduinoIoTCloudTCP.cpp index be744294e..7f38bd024 100644 --- a/src/ArduinoIoTCloudTCP.cpp +++ b/src/ArduinoIoTCloudTCP.cpp @@ -92,8 +92,8 @@ ArduinoIoTCloudTCP::ArduinoIoTCloudTCP() , _ota_cap{false} , _ota_error{static_cast(OTAError::None)} , _ota_img_sha256{"Inv."} -, _ota_url{""} -, _ota_req{false} +, _ota_url{"http://10.130.22.65/UPDATE.BIN"} +, _ota_req{true} #endif /* OTA_ENABLED */ { @@ -497,6 +497,7 @@ ArduinoIoTCloudTCP::State ArduinoIoTCloudTCP::handle_Connected() /* Request a OTA download if the hidden property * OTA request has been set. */ + if (_ota_req) { /* Clear the error flag. */ diff --git a/src/utility/ota/OTA-nano-rp2040.cpp b/src/utility/ota/OTA-nano-rp2040.cpp index 426bb5fb0..72da2f78d 100644 --- a/src/utility/ota/OTA-nano-rp2040.cpp +++ b/src/utility/ota/OTA-nano-rp2040.cpp @@ -23,47 +23,155 @@ #include "OTA.h" +#include "../watchdog/Watchdog.h" + #include +#include /****************************************************************************** * FUNCTION DEFINITION ******************************************************************************/ +static rtos::Thread t(osPriorityHigh); + +void kick_watchdog() { + while (1) { + mbed_watchdog_reset(); + delay(2000); + } +} + +/* Original code: http://stackoverflow.com/questions/2616011/easy-way-to-parse-a-url-in-c-cross-platform */ +#include +struct URI { + public: + URI(const std::string& url_s) { + this->parse(url_s); + } + std::string protocol_, host_, path_, query_; + private: + void parse(const std::string& url_s); +}; + +#include +#include +#include +#include +#include + +using namespace std; + +// ctors, copy, equality, ... + +void URI::parse(const string& url_s) +{ + const string prot_end("://"); + string::const_iterator prot_i = search(url_s.begin(), url_s.end(), + prot_end.begin(), prot_end.end()); + protocol_.reserve(distance(url_s.begin(), prot_i)); + transform(url_s.begin(), prot_i, + back_inserter(protocol_), + ptr_fun(tolower)); // protocol is icase + if( prot_i == url_s.end() ) + return; + advance(prot_i, prot_end.length()); + string::const_iterator path_i = find(prot_i, url_s.end(), '/'); + host_.reserve(distance(prot_i, path_i)); + transform(prot_i, path_i, + back_inserter(host_), + ptr_fun(tolower)); // host is icase + string::const_iterator query_i = find(path_i, url_s.end(), '?'); + path_.assign(path_i, query_i); + if( query_i != url_s.end() ) + ++query_i; + query_.assign(query_i, url_s.end()); +} + int rp2040_connect_onOTARequest(char const * ota_url) { SFU::begin(); + t.start(kick_watchdog); + +#if 0 /* Just to be safe delete any remains from previous updates. */ - WiFiStorage.remove("/fs/UPDATE.BIN"); struct stat st; int err = stat("/ota/UPDATE.BIN", &st); if (err == 0) { remove("/ota/UPDATE.BIN"); } +#endif + + Client* client; + + URI url(ota_url); + + if (url.protocol_ == "http") { + client = new WiFiClient(); + } else { + client = new WiFiSSLClient(); + } + + const char* host = url.host_.c_str(); - /* TODO: FIXME: Download into NINA then transfer to /fs/UPDATE.BIN */ - uint8_t nina_ota_err_code = 0; - if (!WiFiStorage.downloadOTA(ota_url, &nina_ota_err_code)) + IPAddress ip; + ip.fromString(host); + + int ret = client->connect(ip, 80); + if (!ret) { - DEBUG_ERROR("ArduinoIoTCloudTCP::%s error download to nina: %d", __FUNCTION__, nina_ota_err_code); - return static_cast(OTAError::DownloadFailed); + DEBUG_ERROR("%s: Connection failure with OTA storage server %s", __FUNCTION__, host); + return -1; /* TODO: Implement better error codes. */ } - FILE* update = fopen("/ota/UPDATE.BIN", "w"); + client->println(String("GET ") + url.path_.c_str() + " HTTP/1.1"); + client->println(String("Host: ") + host); + client->println("Connection: close"); + client->println(); - uint8_t tempbuf[128]; + FILE * file = fopen("/ota/UPDATE.BIN", "wb"); + if (!file) + { + DEBUG_ERROR("%s: fopen() failed", __FUNCTION__); + fclose(file); + return errno; + } - WiFiStorageFile nina_update = WiFiStorage.open("/fs/UPDATE.BIN"); + String http_header; + bool is_header_complete = false; - while (true) { - int ret = nina_update.read(tempbuf, sizeof(tempbuf)); - if (ret == 0) { - break; + while (!client->available()) { + delay(10); + } + + while (client->available()) + { + char const c = client->read(); + + if(!is_header_complete) + { + http_header += c; + if (http_header.endsWith("\r\n\r\n")) + is_header_complete = true; + } + else + { + if (fwrite(&c, 1, sizeof(c), file) != sizeof(c)) + { + DEBUG_ERROR("%s: Writing of firmware image to flash failed", __FUNCTION__); + return -2; /* TODO: Find better error codes. */ + } } - fwrite(tempbuf, ret, 1, update); } - fclose(update); + int const file_len = ftell(file); + DEBUG_DEBUG("%s: %d bytes received", __FUNCTION__, file_len); + + while (file_len == 0) { + delay(1000); + } + + fclose(file); /* Perform the reset to reboot to SxU. */ NVIC_SystemReset(); From cc1aeba51a9e64d76a73d59cb4ac13e2866d88eb Mon Sep 17 00:00:00 2001 From: Martino Facchin Date: Wed, 26 May 2021 15:43:42 +0200 Subject: [PATCH 03/37] tools/bin2ota: add nano rp2040 asupport --- extras/tools/bin2ota.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/extras/tools/bin2ota.py b/extras/tools/bin2ota.py index 648aa2395..ffb21a856 100755 --- a/extras/tools/bin2ota.py +++ b/extras/tools/bin2ota.py @@ -24,6 +24,8 @@ magic_number = 0x23418057.to_bytes(4,byteorder='little') elif board == "PORTENTA_H7_M7": magic_number = 0x2341025B.to_bytes(4,byteorder='little') +elif board == "NANO_RP2040_CONNECT": + magic_number = 0x2341005E.to_bytes(4,byteorder='little') else: print ("Error,", board, "is not a supported board type") sys.exit() From 26d989f58525694547668cb8e04a9ac51157a190 Mon Sep 17 00:00:00 2001 From: Martino Facchin Date: Thu, 27 May 2021 14:25:40 +0200 Subject: [PATCH 04/37] Add comments and TODO --- src/utility/ota/OTA-nano-rp2040.cpp | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/src/utility/ota/OTA-nano-rp2040.cpp b/src/utility/ota/OTA-nano-rp2040.cpp index 72da2f78d..f91cdb6a5 100644 --- a/src/utility/ota/OTA-nano-rp2040.cpp +++ b/src/utility/ota/OTA-nano-rp2040.cpp @@ -43,6 +43,11 @@ void kick_watchdog() { /* Original code: http://stackoverflow.com/questions/2616011/easy-way-to-parse-a-url-in-c-cross-platform */ #include +#include +#include +#include +#include + struct URI { public: URI(const std::string& url_s) { @@ -53,16 +58,10 @@ struct URI { void parse(const std::string& url_s); }; -#include -#include -#include -#include -#include - using namespace std; // ctors, copy, equality, ... - +// TODO: change me into something embedded friendly (this function adds ~100KB to flash) void URI::parse(const string& url_s) { const string prot_end("://"); @@ -104,20 +103,27 @@ int rp2040_connect_onOTARequest(char const * ota_url) Client* client; + // TODO: eventually parse port in URL + int port; + URI url(ota_url); if (url.protocol_ == "http") { client = new WiFiClient(); + port = 80; } else { client = new WiFiSSLClient(); + port = 443; } const char* host = url.host_.c_str(); - IPAddress ip; - ip.fromString(host); + // TODO: find if the host is an IP address and treat accordingly + // IPAddress ip; + // ip.fromString(host); + //int ret = client->connect(ip, port); - int ret = client->connect(ip, 80); + int ret = client->connect(host, port); if (!ret) { DEBUG_ERROR("%s: Connection failure with OTA storage server %s", __FUNCTION__, host); From 6359f8a02af55e8bcc2d5723c4a839ac33745c85 Mon Sep 17 00:00:00 2001 From: Martino Facchin Date: Thu, 27 May 2021 14:27:20 +0200 Subject: [PATCH 05/37] squashme: don't automatically trigger an OTA --- src/ArduinoIoTCloudTCP.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ArduinoIoTCloudTCP.cpp b/src/ArduinoIoTCloudTCP.cpp index 7f38bd024..842279856 100644 --- a/src/ArduinoIoTCloudTCP.cpp +++ b/src/ArduinoIoTCloudTCP.cpp @@ -92,8 +92,8 @@ ArduinoIoTCloudTCP::ArduinoIoTCloudTCP() , _ota_cap{false} , _ota_error{static_cast(OTAError::None)} , _ota_img_sha256{"Inv."} -, _ota_url{"http://10.130.22.65/UPDATE.BIN"} -, _ota_req{true} +, _ota_url{} +, _ota_req{false} #endif /* OTA_ENABLED */ { From 08142e7dfe18e6c97905e0b7ff4ce58f2378f859 Mon Sep 17 00:00:00 2001 From: Alexander Entinger Date: Mon, 31 May 2021 07:14:42 +0200 Subject: [PATCH 06/37] Revert initialisation of _ota_url to empty string. --- src/ArduinoIoTCloudTCP.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ArduinoIoTCloudTCP.cpp b/src/ArduinoIoTCloudTCP.cpp index 842279856..7c9f9ef32 100644 --- a/src/ArduinoIoTCloudTCP.cpp +++ b/src/ArduinoIoTCloudTCP.cpp @@ -92,7 +92,7 @@ ArduinoIoTCloudTCP::ArduinoIoTCloudTCP() , _ota_cap{false} , _ota_error{static_cast(OTAError::None)} , _ota_img_sha256{"Inv."} -, _ota_url{} +, _ota_url{""} , _ota_req{false} #endif /* OTA_ENABLED */ { From 171ac6d23ea56f7e739e6ca6b44c293bc9d6b55c Mon Sep 17 00:00:00 2001 From: Alexander Entinger Date: Mon, 31 May 2021 07:18:56 +0200 Subject: [PATCH 07/37] Cleaning up SHA256 calculation logic for better maintainability. --- src/ArduinoIoTCloudTCP.cpp | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/ArduinoIoTCloudTCP.cpp b/src/ArduinoIoTCloudTCP.cpp index 7c9f9ef32..b8c1c7246 100644 --- a/src/ArduinoIoTCloudTCP.cpp +++ b/src/ArduinoIoTCloudTCP.cpp @@ -160,7 +160,7 @@ int ArduinoIoTCloudTCP::begin(bool const enable_watchdog, String brokerAddress, sha256_str += buf; }); DEBUG_VERBOSE("SHA256: %d bytes (of %d) read", bytes_read, app_size); -#else +#elif defined(ARDUINO_ARCH_SAMD) /* Calculate the SHA256 checksum over the firmware stored in the flash of the * MCU. Note: As we don't know the length per-se we read chunks of the flash * until we detect one containing only 0xFF (= flash erased). This only works @@ -171,13 +171,11 @@ int ArduinoIoTCloudTCP::begin(bool const enable_watchdog, String brokerAddress, * The bootloader is excluded from the calculation and occupies flash address * range 0 to 0x2000, total flash size of 0x40000 bytes (256 kByte). */ -#if defined(ARDUINO_NANO_RP2040_CONNECT) -#define FLASH_BASE XIP_BASE - _ota_cap = true; + String const sha256_str = FlashSHA256::calc(0x2000, 0x40000 - 0x2000); +#elif defined(ARDUINO_NANO_RP2040_CONNECT) + String const sha256_str = FlashSHA256::calc(XIP_BASE + 0x2000, 0x40000 - 0x2000); #else -#define FLASH_BASE 0 -#endif - String const sha256_str = FlashSHA256::calc(FLASH_BASE + 0x2000, 0x40000 - 0x2000); +# error "No method for SHA256 checksum calculation over application image defined for this architecture." #endif DEBUG_VERBOSE("SHA256: HASH(%d) = %s", strlen(sha256_str.c_str()), sha256_str.c_str()); _ota_img_sha256 = sha256_str; From 48e340583dba27e9e6afb479b07870f48a59e2a3 Mon Sep 17 00:00:00 2001 From: Alexander Entinger Date: Mon, 31 May 2021 07:20:18 +0200 Subject: [PATCH 08/37] Signal unconditionally that the RP2040 supports OTA to the cloud. --- src/ArduinoIoTCloudTCP.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/ArduinoIoTCloudTCP.cpp b/src/ArduinoIoTCloudTCP.cpp index b8c1c7246..998bb9898 100644 --- a/src/ArduinoIoTCloudTCP.cpp +++ b/src/ArduinoIoTCloudTCP.cpp @@ -263,6 +263,10 @@ int ArduinoIoTCloudTCP::begin(bool const enable_watchdog, String brokerAddress, } #endif /* OTA_STORAGE_SNU */ +#if defined(ARDUINO_NANO_RP2040_CONNECT) + _ota_cap = true; +#endif + #ifdef BOARD_HAS_OFFLOADED_ECCX08 if (String(WiFi.firmwareVersion()) < String("1.4.4")) { DEBUG_ERROR("ArduinoIoTCloudTCP::%s In order to connect to Arduino IoT Cloud, NINA firmware needs to be >= 1.4.4, current %s", __FUNCTION__, WiFi.firmwareVersion()); From e14a7816e085fe21aa6c6b4ed2124c563121a1f8 Mon Sep 17 00:00:00 2001 From: Alexander Entinger Date: Mon, 31 May 2021 07:49:43 +0200 Subject: [PATCH 09/37] Fix parameters for flash checksum calculation (used parameters were for samd architecture). --- src/ArduinoIoTCloudTCP.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/ArduinoIoTCloudTCP.cpp b/src/ArduinoIoTCloudTCP.cpp index 998bb9898..9988fd6eb 100644 --- a/src/ArduinoIoTCloudTCP.cpp +++ b/src/ArduinoIoTCloudTCP.cpp @@ -173,7 +173,10 @@ int ArduinoIoTCloudTCP::begin(bool const enable_watchdog, String brokerAddress, */ String const sha256_str = FlashSHA256::calc(0x2000, 0x40000 - 0x2000); #elif defined(ARDUINO_NANO_RP2040_CONNECT) - String const sha256_str = FlashSHA256::calc(XIP_BASE + 0x2000, 0x40000 - 0x2000); + /* The maximum size of a RP2040 OTA update image is 1 MByte (that is 1024 * + * 1024 bytes or 0x100'000 bytes). + */ + String const sha256_str = FlashSHA256::calc(XIP_BASE, 0x100000); #else # error "No method for SHA256 checksum calculation over application image defined for this architecture." #endif From 1c783f50293a826f753e210af445dde345df8c6b Mon Sep 17 00:00:00 2001 From: Alexander Entinger Date: Mon, 31 May 2021 08:04:54 +0200 Subject: [PATCH 10/37] Bugfix: Ensure that the watchdog timer thread does not run forever. In the current implementation if the OTA process fails (no reset) then the thread started to kick the watchdog timer would run forever. This does defeat the purpose of the watchdog which is only supposed to be kicked within ArduinoIoTCloud.update(). It should be enough to strategically sprinkle watchdog calls throughout the code. --- src/utility/ota/OTA-nano-rp2040.cpp | 29 +++++++++++++---------------- 1 file changed, 13 insertions(+), 16 deletions(-) diff --git a/src/utility/ota/OTA-nano-rp2040.cpp b/src/utility/ota/OTA-nano-rp2040.cpp index f91cdb6a5..2f7cd4515 100644 --- a/src/utility/ota/OTA-nano-rp2040.cpp +++ b/src/utility/ota/OTA-nano-rp2040.cpp @@ -26,21 +26,11 @@ #include "../watchdog/Watchdog.h" #include -#include /****************************************************************************** * FUNCTION DEFINITION ******************************************************************************/ -static rtos::Thread t(osPriorityHigh); - -void kick_watchdog() { - while (1) { - mbed_watchdog_reset(); - delay(2000); - } -} - /* Original code: http://stackoverflow.com/questions/2616011/easy-way-to-parse-a-url-in-c-cross-platform */ #include #include @@ -90,7 +80,7 @@ int rp2040_connect_onOTARequest(char const * ota_url) { SFU::begin(); - t.start(kick_watchdog); + mbed_watchdog_reset(); #if 0 /* Just to be safe delete any remains from previous updates. */ @@ -118,10 +108,7 @@ int rp2040_connect_onOTARequest(char const * ota_url) const char* host = url.host_.c_str(); - // TODO: find if the host is an IP address and treat accordingly - // IPAddress ip; - // ip.fromString(host); - //int ret = client->connect(ip, port); + mbed_watchdog_reset(); int ret = client->connect(host, port); if (!ret) @@ -130,11 +117,15 @@ int rp2040_connect_onOTARequest(char const * ota_url) return -1; /* TODO: Implement better error codes. */ } + mbed_watchdog_reset(); + client->println(String("GET ") + url.path_.c_str() + " HTTP/1.1"); client->println(String("Host: ") + host); client->println("Connection: close"); client->println(); + mbed_watchdog_reset(); + FILE * file = fopen("/ota/UPDATE.BIN", "wb"); if (!file) { @@ -146,12 +137,16 @@ int rp2040_connect_onOTARequest(char const * ota_url) String http_header; bool is_header_complete = false; - while (!client->available()) { + while (!client->available()) + { delay(10); + mbed_watchdog_reset(); } while (client->available()) { + mbed_watchdog_reset(); + char const c = client->read(); if(!is_header_complete) @@ -173,6 +168,8 @@ int rp2040_connect_onOTARequest(char const * ota_url) int const file_len = ftell(file); DEBUG_DEBUG("%s: %d bytes received", __FUNCTION__, file_len); + mbed_watchdog_reset(); + while (file_len == 0) { delay(1000); } From 1aafd84db6b305aa1088244550e1269e3d23a341 Mon Sep 17 00:00:00 2001 From: Alexander Entinger Date: Mon, 31 May 2021 08:09:15 +0200 Subject: [PATCH 11/37] Remove manually definition of SFU. In the early days of OTA development the SFU was used to perform a application update using a binary stored on an external SPI flash. However, this method was discarded, because it would have required for the users to purchase a MKR MEM shield additionally to their connected board. Therefore it is safe to remove the manual SFU defines from above which prevents any name collissions with the (unfortunately nambed) Nano RP2040 Connect SFU. --- src/AIoTC_Config.h | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/AIoTC_Config.h b/src/AIoTC_Config.h index 70af6b716..d76e96922 100644 --- a/src/AIoTC_Config.h +++ b/src/AIoTC_Config.h @@ -22,10 +22,6 @@ * USER CONFIGURABLE DEFINES ******************************************************************************/ -#ifndef OTA_STORAGE_SFU - #define OTA_STORAGE_SFU (0) -#endif - #ifndef NTP_USE_RANDOM_PORT #define NTP_USE_RANDOM_PORT (1) #endif @@ -95,7 +91,6 @@ #endif #if defined(ARDUINO_NANO_RP2040_CONNECT) - #undef OTA_STORAGE_SFU #define OTA_STORAGE_SFU (1) #else #define OTA_STORAGE_SFU (0) From 0dc6c4cc5b69941a9e51f78fbb245fa143b6e754 Mon Sep 17 00:00:00 2001 From: Alexander Entinger Date: Mon, 31 May 2021 08:19:06 +0200 Subject: [PATCH 12/37] Provide more meaningful (and distinct for RP2040) OTA error codes. --- src/utility/ota/OTA-nano-rp2040.cpp | 13 +++++++++---- src/utility/ota/OTA.h | 10 ++++++++++ 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/src/utility/ota/OTA-nano-rp2040.cpp b/src/utility/ota/OTA-nano-rp2040.cpp index 2f7cd4515..9e61f08fc 100644 --- a/src/utility/ota/OTA-nano-rp2040.cpp +++ b/src/utility/ota/OTA-nano-rp2040.cpp @@ -101,9 +101,12 @@ int rp2040_connect_onOTARequest(char const * ota_url) if (url.protocol_ == "http") { client = new WiFiClient(); port = 80; - } else { + } else if (url.protocol_ == "https") { client = new WiFiSSLClient(); port = 443; + } else { + DEBUG_ERROR("%s: Failed to parse OTA URL %s", __FUNCTION__, ota_url); + return static_cast(OTAError::RP2040_UrlParseError); } const char* host = url.host_.c_str(); @@ -114,7 +117,7 @@ int rp2040_connect_onOTARequest(char const * ota_url) if (!ret) { DEBUG_ERROR("%s: Connection failure with OTA storage server %s", __FUNCTION__, host); - return -1; /* TODO: Implement better error codes. */ + return static_cast(OTAError::RP2040_ServerConnectError); } mbed_watchdog_reset(); @@ -131,7 +134,7 @@ int rp2040_connect_onOTARequest(char const * ota_url) { DEBUG_ERROR("%s: fopen() failed", __FUNCTION__); fclose(file); - return errno; + return static_cast(OTAError::RP2040_ErrorOpenUpdateFile); } String http_header; @@ -160,7 +163,7 @@ int rp2040_connect_onOTARequest(char const * ota_url) if (fwrite(&c, 1, sizeof(c), file) != sizeof(c)) { DEBUG_ERROR("%s: Writing of firmware image to flash failed", __FUNCTION__); - return -2; /* TODO: Find better error codes. */ + return static_cast(OTAError::RP2040_ErrorWriteUpdateFile); } } } @@ -178,6 +181,8 @@ int rp2040_connect_onOTARequest(char const * ota_url) /* Perform the reset to reboot to SxU. */ NVIC_SystemReset(); + + return static_cast(OTAError::None); } #endif /* ARDUINO_NANO_RP2040_CONNECT */ diff --git a/src/utility/ota/OTA.h b/src/utility/ota/OTA.h index 9d103d053..f653c45b9 100644 --- a/src/utility/ota/OTA.h +++ b/src/utility/ota/OTA.h @@ -32,6 +32,12 @@ #include #endif /* OTA_STORAGE_SFU */ +/****************************************************************************** + * DEFINES + ******************************************************************************/ + +#define RP2040_OTA_ERROR_BASE (-100) + /****************************************************************************** * TYPEDEF ******************************************************************************/ @@ -40,6 +46,10 @@ enum class OTAError : int { None = 0, DownloadFailed = 1, + RP2040_UrlParseError = RP2040_OTA_ERROR_BASE - 0, + RP2040_ServerConnectError = RP2040_OTA_ERROR_BASE - 1, + RP2040_ErrorOpenUpdateFile = RP2040_OTA_ERROR_BASE - 2, + RP2040_ErrorWriteUpdateFile = RP2040_OTA_ERROR_BASE - 3, }; /****************************************************************************** From 5db1b978e450aad179b40ddc1c7339ef54a36dd1 Mon Sep 17 00:00:00 2001 From: Alexander Entinger Date: Mon, 31 May 2021 08:21:42 +0200 Subject: [PATCH 13/37] Ensure initialisation with relevant default parameters. --- src/utility/ota/OTA-nano-rp2040.cpp | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/utility/ota/OTA-nano-rp2040.cpp b/src/utility/ota/OTA-nano-rp2040.cpp index 9e61f08fc..2afde19e2 100644 --- a/src/utility/ota/OTA-nano-rp2040.cpp +++ b/src/utility/ota/OTA-nano-rp2040.cpp @@ -91,12 +91,9 @@ int rp2040_connect_onOTARequest(char const * ota_url) } #endif - Client* client; - - // TODO: eventually parse port in URL - int port; - URI url(ota_url); + Client * client = nullptr; + int port = 0; if (url.protocol_ == "http") { client = new WiFiClient(); From 163f84c7b54b9513a5186a4dad45ca46fc3fb458 Mon Sep 17 00:00:00 2001 From: Alexander Entinger Date: Mon, 31 May 2021 08:22:34 +0200 Subject: [PATCH 14/37] Replace local variable with direct access to class member string. --- src/utility/ota/OTA-nano-rp2040.cpp | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/utility/ota/OTA-nano-rp2040.cpp b/src/utility/ota/OTA-nano-rp2040.cpp index 2afde19e2..89dfea318 100644 --- a/src/utility/ota/OTA-nano-rp2040.cpp +++ b/src/utility/ota/OTA-nano-rp2040.cpp @@ -106,21 +106,19 @@ int rp2040_connect_onOTARequest(char const * ota_url) return static_cast(OTAError::RP2040_UrlParseError); } - const char* host = url.host_.c_str(); - mbed_watchdog_reset(); - int ret = client->connect(host, port); + int ret = client->connect(url.host_.c_str(), port); if (!ret) { - DEBUG_ERROR("%s: Connection failure with OTA storage server %s", __FUNCTION__, host); + DEBUG_ERROR("%s: Connection failure with OTA storage server %s", __FUNCTION__, url.host_.c_str()); return static_cast(OTAError::RP2040_ServerConnectError); } mbed_watchdog_reset(); client->println(String("GET ") + url.path_.c_str() + " HTTP/1.1"); - client->println(String("Host: ") + host); + client->println(String("Host: ") + url.host_.c_str()); client->println("Connection: close"); client->println(); From 0a60df55ffd142bf212af279c034af9ceed09f9e Mon Sep 17 00:00:00 2001 From: Alexander Entinger Date: Mon, 31 May 2021 09:39:05 +0200 Subject: [PATCH 15/37] Split HTTPS-GET in 3 parts - receive header -> extract content length -> download binary. --- src/utility/ota/OTA-nano-rp2040.cpp | 55 ++++++++++++++++++++--------- src/utility/ota/OTA.h | 1 + 2 files changed, 39 insertions(+), 17 deletions(-) diff --git a/src/utility/ota/OTA-nano-rp2040.cpp b/src/utility/ota/OTA-nano-rp2040.cpp index 89dfea318..6e0370bd3 100644 --- a/src/utility/ota/OTA-nano-rp2040.cpp +++ b/src/utility/ota/OTA-nano-rp2040.cpp @@ -124,7 +124,7 @@ int rp2040_connect_onOTARequest(char const * ota_url) mbed_watchdog_reset(); - FILE * file = fopen("/ota/UPDATE.BIN", "wb"); + FILE * file = fopen("/ota/UPDATE.BIN.LZSS", "wb"); if (!file) { DEBUG_ERROR("%s: fopen() failed", __FUNCTION__); @@ -132,34 +132,59 @@ int rp2040_connect_onOTARequest(char const * ota_url) return static_cast(OTAError::RP2040_ErrorOpenUpdateFile); } + /* Receive HTTP header. */ String http_header; - bool is_header_complete = false; - while (!client->available()) + for (bool is_header_complete = false; client->connected() && !is_header_complete; ) { - delay(10); mbed_watchdog_reset(); - } - - while (client->available()) - { - mbed_watchdog_reset(); - - char const c = client->read(); - if(!is_header_complete) + if (client->available()) { + char const c = client->read(); + Serial.print(c); + http_header += c; if (http_header.endsWith("\r\n\r\n")) is_header_complete = true; } - else + } + + /* Extract concent length from HTTP header. */ + int content_length_val = 0; + int const content_length_index = http_header.indexOf("Content-Length: "); + if (content_length_index > 0) + { + /* Attention: The following code is extremely ugly and needs major cleaning up. */ + String content_length; + for (char * ptr = &(http_header[content_length_index + 16]); isDigit(*ptr); ptr++) + content_length += *ptr; + + content_length_val = atoi(content_length.c_str()); + DEBUG_VERBOSE("%s: Length of OTA binary according to HTTP header = %d bytes", __FUNCTION__, content_length_val); + } + else + { + DEBUG_ERROR("%s: Failure to extract content length from http header", __FUNCTION__); + return static_cast(OTAError::RP2040_ErrorParseHttpHeader); + } + + for(int bytes_received = 0; + (bytes_received < content_length_val) && client->connected();) + { + mbed_watchdog_reset(); + + if (client->available()) { + char const c = client->read(); + if (fwrite(&c, 1, sizeof(c), file) != sizeof(c)) { DEBUG_ERROR("%s: Writing of firmware image to flash failed", __FUNCTION__); return static_cast(OTAError::RP2040_ErrorWriteUpdateFile); } + + bytes_received++; } } @@ -168,10 +193,6 @@ int rp2040_connect_onOTARequest(char const * ota_url) mbed_watchdog_reset(); - while (file_len == 0) { - delay(1000); - } - fclose(file); /* Perform the reset to reboot to SxU. */ diff --git a/src/utility/ota/OTA.h b/src/utility/ota/OTA.h index f653c45b9..e96dc6f36 100644 --- a/src/utility/ota/OTA.h +++ b/src/utility/ota/OTA.h @@ -50,6 +50,7 @@ enum class OTAError : int RP2040_ServerConnectError = RP2040_OTA_ERROR_BASE - 1, RP2040_ErrorOpenUpdateFile = RP2040_OTA_ERROR_BASE - 2, RP2040_ErrorWriteUpdateFile = RP2040_OTA_ERROR_BASE - 3, + RP2040_ErrorParseHttpHeader = RP2040_OTA_ERROR_BASE - 4, }; /****************************************************************************** From 81d68e443cc59f654a32e570cc36d6027d04ed2f Mon Sep 17 00:00:00 2001 From: Alexander Entinger Date: Mon, 31 May 2021 13:44:46 +0200 Subject: [PATCH 16/37] Move watchdog feeding within the if(client->available()) check ... otherwise we might loop forever in case no data becomes available any more. --- src/utility/ota/OTA-nano-rp2040.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/utility/ota/OTA-nano-rp2040.cpp b/src/utility/ota/OTA-nano-rp2040.cpp index 6e0370bd3..c3c21768e 100644 --- a/src/utility/ota/OTA-nano-rp2040.cpp +++ b/src/utility/ota/OTA-nano-rp2040.cpp @@ -137,10 +137,10 @@ int rp2040_connect_onOTARequest(char const * ota_url) for (bool is_header_complete = false; client->connected() && !is_header_complete; ) { - mbed_watchdog_reset(); - if (client->available()) { + mbed_watchdog_reset(); + char const c = client->read(); Serial.print(c); @@ -172,10 +172,10 @@ int rp2040_connect_onOTARequest(char const * ota_url) for(int bytes_received = 0; (bytes_received < content_length_val) && client->connected();) { - mbed_watchdog_reset(); - if (client->available()) { + mbed_watchdog_reset(); + char const c = client->read(); if (fwrite(&c, 1, sizeof(c), file) != sizeof(c)) From 364319d97748fc774ae0fd21f2678a05cb0fd343 Mon Sep 17 00:00:00 2001 From: Alexander Entinger Date: Mon, 31 May 2021 13:46:17 +0200 Subject: [PATCH 17/37] Remove SSU (2nd stage bootloader for MKR GSM 1400) as OTA for MKR GSM has never been completed and may need a complete overhaul, mofe SFU into nano specific OTA module. --- src/utility/ota/OTA-nano-rp2040.cpp | 2 ++ src/utility/ota/OTA.h | 8 -------- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/src/utility/ota/OTA-nano-rp2040.cpp b/src/utility/ota/OTA-nano-rp2040.cpp index c3c21768e..f27a65934 100644 --- a/src/utility/ota/OTA-nano-rp2040.cpp +++ b/src/utility/ota/OTA-nano-rp2040.cpp @@ -27,6 +27,8 @@ #include +#include + /****************************************************************************** * FUNCTION DEFINITION ******************************************************************************/ diff --git a/src/utility/ota/OTA.h b/src/utility/ota/OTA.h index e96dc6f36..e49ba9de9 100644 --- a/src/utility/ota/OTA.h +++ b/src/utility/ota/OTA.h @@ -24,14 +24,6 @@ #include -#if OTA_STORAGE_SSU - #include -#endif /* OTA_STORAGE_SSU */ - -#if OTA_STORAGE_SFU - #include -#endif /* OTA_STORAGE_SFU */ - /****************************************************************************** * DEFINES ******************************************************************************/ From 48afe743148e63ce36de22ec88f9af88bb93f38c Mon Sep 17 00:00:00 2001 From: Alexander Entinger Date: Tue, 1 Jun 2021 09:30:40 +0200 Subject: [PATCH 18/37] Bugfix: Function was not working correctly when start of flash was != 0. --- src/utility/ota/FlashSHA256.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/utility/ota/FlashSHA256.cpp b/src/utility/ota/FlashSHA256.cpp index 3bdc034c9..cac4db619 100644 --- a/src/utility/ota/FlashSHA256.cpp +++ b/src/utility/ota/FlashSHA256.cpp @@ -45,11 +45,12 @@ String FlashSHA256::calc(uint32_t const start_addr, uint32_t const max_flash_siz sha256.begin(); /* Read the first two chunks of flash. */ - uint32_t flash_addr = start_addr; + uint32_t flash_addr = start_addr; + uint32_t bytes_read = 0; memcpy(chunk, reinterpret_cast(flash_addr), FLASH_READ_CHUNK_SIZE); flash_addr += FLASH_READ_CHUNK_SIZE; - for(; flash_addr < max_flash_size; flash_addr += FLASH_READ_CHUNK_SIZE) + for(; bytes_read < max_flash_size; flash_addr += FLASH_READ_CHUNK_SIZE) { /* Read the next chunk of memory. */ memcpy(next_chunk, reinterpret_cast(flash_addr), FLASH_READ_CHUNK_SIZE); @@ -75,6 +76,7 @@ String FlashSHA256::calc(uint32_t const start_addr, uint32_t const max_flash_siz } /* Update with the remaining bytes. */ sha256.update(chunk, valid_bytes_in_chunk); + bytes_read += valid_bytes_in_chunk; break; } @@ -82,6 +84,7 @@ String FlashSHA256::calc(uint32_t const start_addr, uint32_t const max_flash_siz * any erased elements, just update the SHA256 hash calcultion. */ sha256.update(chunk, FLASH_READ_CHUNK_SIZE); + bytes_read += FLASH_READ_CHUNK_SIZE; /* Copy next_chunk to chunk. */ memcpy(chunk, next_chunk, FLASH_READ_CHUNK_SIZE); @@ -100,7 +103,7 @@ String FlashSHA256::calc(uint32_t const start_addr, uint32_t const max_flash_siz sha256_str += buf; }); /* Do some debug printout. */ - DEBUG_VERBOSE("SHA256: %d bytes read", flash_addr); + DEBUG_VERBOSE("SHA256: %d bytes read", bytes_read); return sha256_str; } From cdadeffcd27e622c6d38d5bb92d945f97e591a6f Mon Sep 17 00:00:00 2001 From: Alexander Entinger Date: Tue, 1 Jun 2021 09:38:07 +0200 Subject: [PATCH 19/37] Cleaning up. --- src/utility/ota/OTA-nano-rp2040.cpp | 20 +++++--------------- 1 file changed, 5 insertions(+), 15 deletions(-) diff --git a/src/utility/ota/OTA-nano-rp2040.cpp b/src/utility/ota/OTA-nano-rp2040.cpp index f27a65934..82a3a32a4 100644 --- a/src/utility/ota/OTA-nano-rp2040.cpp +++ b/src/utility/ota/OTA-nano-rp2040.cpp @@ -82,16 +82,7 @@ int rp2040_connect_onOTARequest(char const * ota_url) { SFU::begin(); - mbed_watchdog_reset(); - -#if 0 - /* Just to be safe delete any remains from previous updates. */ - struct stat st; - int err = stat("/ota/UPDATE.BIN", &st); - if (err == 0) { - remove("/ota/UPDATE.BIN"); - } -#endif + mbed_watchdog_reset(); URI url(ota_url); Client * client = nullptr; @@ -136,7 +127,6 @@ int rp2040_connect_onOTARequest(char const * ota_url) /* Receive HTTP header. */ String http_header; - for (bool is_header_complete = false; client->connected() && !is_header_complete; ) { if (client->available()) @@ -168,6 +158,7 @@ int rp2040_connect_onOTARequest(char const * ota_url) else { DEBUG_ERROR("%s: Failure to extract content length from http header", __FUNCTION__); + fclose(file); return static_cast(OTAError::RP2040_ErrorParseHttpHeader); } @@ -183,6 +174,7 @@ int rp2040_connect_onOTARequest(char const * ota_url) if (fwrite(&c, 1, sizeof(c), file) != sizeof(c)) { DEBUG_ERROR("%s: Writing of firmware image to flash failed", __FUNCTION__); + fclose(file); return static_cast(OTAError::RP2040_ErrorWriteUpdateFile); } @@ -190,12 +182,10 @@ int rp2040_connect_onOTARequest(char const * ota_url) } } + /* Determine length. */ int const file_len = ftell(file); - DEBUG_DEBUG("%s: %d bytes received", __FUNCTION__, file_len); - - mbed_watchdog_reset(); - fclose(file); + DEBUG_DEBUG("%s: %d bytes received", __FUNCTION__, file_len); /* Perform the reset to reboot to SxU. */ NVIC_SystemReset(); From fc64b0a385a561dff824f20f45226b365a68e8d1 Mon Sep 17 00:00:00 2001 From: Alexander Entinger Date: Tue, 1 Jun 2021 10:07:39 +0200 Subject: [PATCH 20/37] Simplify extraction logic for HTTP header content length. --- src/utility/ota/OTA-nano-rp2040.cpp | 33 ++++++++++++++--------------- 1 file changed, 16 insertions(+), 17 deletions(-) diff --git a/src/utility/ota/OTA-nano-rp2040.cpp b/src/utility/ota/OTA-nano-rp2040.cpp index 82a3a32a4..cb85e9508 100644 --- a/src/utility/ota/OTA-nano-rp2040.cpp +++ b/src/utility/ota/OTA-nano-rp2040.cpp @@ -134,7 +134,6 @@ int rp2040_connect_onOTARequest(char const * ota_url) mbed_watchdog_reset(); char const c = client->read(); - Serial.print(c); http_header += c; if (http_header.endsWith("\r\n\r\n")) @@ -142,26 +141,26 @@ int rp2040_connect_onOTARequest(char const * ota_url) } } - /* Extract concent length from HTTP header. */ - int content_length_val = 0; - int const content_length_index = http_header.indexOf("Content-Length: "); - if (content_length_index > 0) + /* Extract concent length from HTTP header. A typical entry looks like + * "Content-Length: 123456" + */ + char const * content_length_ptr = strstr(http_header.c_str(), "Content-Length"); + if (!content_length_ptr) { - /* Attention: The following code is extremely ugly and needs major cleaning up. */ - String content_length; - for (char * ptr = &(http_header[content_length_index + 16]); isDigit(*ptr); ptr++) - content_length += *ptr; - - content_length_val = atoi(content_length.c_str()); - DEBUG_VERBOSE("%s: Length of OTA binary according to HTTP header = %d bytes", __FUNCTION__, content_length_val); - } - else - { - DEBUG_ERROR("%s: Failure to extract content length from http header", __FUNCTION__); fclose(file); + DEBUG_ERROR("%s: Failure to extract content length from http header", __FUNCTION__); return static_cast(OTAError::RP2040_ErrorParseHttpHeader); } - + /* Find start of numerical value. */ + char * ptr = const_cast(content_length_ptr); + for (; (*ptr != '\0') && !isDigit(*ptr); ptr++) { } + /* Extract numerical value. */ + String content_length_str; + for (; isDigit(*ptr); ptr++) content_length_str += *ptr; + int const content_length_val = atoi(content_length_str.c_str()); + DEBUG_VERBOSE("%s: Length of OTA binary according to HTTP header = %d bytes", __FUNCTION__, content_length_val); + + /* Receive as many bytes as are indicated by the HTTP header - or die trying. */ for(int bytes_received = 0; (bytes_received < content_length_val) && client->connected();) { From 421eb9d7a26924f0f1fa3110a623446543c95976 Mon Sep 17 00:00:00 2001 From: Alexander Entinger Date: Tue, 1 Jun 2021 10:11:19 +0200 Subject: [PATCH 21/37] Disable verbose debug output in production. --- src/AIoTC_Config.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/AIoTC_Config.h b/src/AIoTC_Config.h index d76e96922..94297350f 100644 --- a/src/AIoTC_Config.h +++ b/src/AIoTC_Config.h @@ -62,7 +62,7 @@ # if defined(ARDUINO_AVR_UNO_WIFI_REV2) # define DEBUG_VERBOSE(fmt, ...) # else -# define DEBUG_VERBOSE(fmt, ...) Debug.print(DBG_VERBOSE, fmt, ## __VA_ARGS__) +# define DEBUG_VERBOSE(fmt, ...) //Debug.print(DBG_VERBOSE, fmt, ## __VA_ARGS__) # endif #endif From 6b1e802b52856cde89ff790624ce6b49318b47b7 Mon Sep 17 00:00:00 2001 From: Alexander Entinger Date: Wed, 2 Jun 2021 09:15:50 +0200 Subject: [PATCH 22/37] Replace verification if connected() with a time-out check. Otherwise it might happen that the connection has been terminated by the server, although not all available data has been read from the NINA. --- src/utility/ota/OTA-nano-rp2040.cpp | 31 +++++++++++++++++++++++++---- src/utility/ota/OTA.h | 8 +++++--- 2 files changed, 32 insertions(+), 7 deletions(-) diff --git a/src/utility/ota/OTA-nano-rp2040.cpp b/src/utility/ota/OTA-nano-rp2040.cpp index cb85e9508..74d702593 100644 --- a/src/utility/ota/OTA-nano-rp2040.cpp +++ b/src/utility/ota/OTA-nano-rp2040.cpp @@ -82,6 +82,8 @@ int rp2040_connect_onOTARequest(char const * ota_url) { SFU::begin(); + remove("/ota/UPDATE.BIN.LZSS"); + mbed_watchdog_reset(); URI url(ota_url); @@ -127,8 +129,13 @@ int rp2040_connect_onOTARequest(char const * ota_url) /* Receive HTTP header. */ String http_header; - for (bool is_header_complete = false; client->connected() && !is_header_complete; ) + bool is_header_complete = false, + is_http_header_timeout = false; + for (unsigned long const start = millis(); !is_header_complete;) { + is_http_header_timeout = (millis() - start) > (10*1000); + if (is_http_header_timeout) break; + if (client->available()) { mbed_watchdog_reset(); @@ -141,6 +148,12 @@ int rp2040_connect_onOTARequest(char const * ota_url) } } + if (!is_header_complete) { + fclose(file); + DEBUG_ERROR("%s: Error receiving HTTP header %s", __FUNCTION__, is_http_header_timeout ? "(timeout)":""); + return static_cast(OTAError::RP2040_HttpHeaderError); + } + /* Extract concent length from HTTP header. A typical entry looks like * "Content-Length: 123456" */ @@ -161,9 +174,13 @@ int rp2040_connect_onOTARequest(char const * ota_url) DEBUG_VERBOSE("%s: Length of OTA binary according to HTTP header = %d bytes", __FUNCTION__, content_length_val); /* Receive as many bytes as are indicated by the HTTP header - or die trying. */ - for(int bytes_received = 0; - (bytes_received < content_length_val) && client->connected();) + int bytes_received = 0; + bool is_http_data_timeout = false; + for(unsigned long const start = millis(); bytes_received < content_length_val;) { + is_http_data_timeout = (millis() - start) > (60*1000); + if (is_http_data_timeout) break; + if (client->available()) { mbed_watchdog_reset(); @@ -181,10 +198,16 @@ int rp2040_connect_onOTARequest(char const * ota_url) } } + if (bytes_received != content_length_val) { + fclose(file); + DEBUG_ERROR("%s: Error receiving HTTP data %s (%d bytes received, %d expected)", __FUNCTION__, is_http_data_timeout ? "(timeout)":"", bytes_received, content_length_val); + return static_cast(OTAError::RP2040_HttpDataError); + } + /* Determine length. */ int const file_len = ftell(file); fclose(file); - DEBUG_DEBUG("%s: %d bytes received", __FUNCTION__, file_len); + DEBUG_DEBUG("%s: %d bytes received (%d expected)", __FUNCTION__, file_len, content_length_val); /* Perform the reset to reboot to SxU. */ NVIC_SystemReset(); diff --git a/src/utility/ota/OTA.h b/src/utility/ota/OTA.h index e49ba9de9..cb0d7183e 100644 --- a/src/utility/ota/OTA.h +++ b/src/utility/ota/OTA.h @@ -40,9 +40,11 @@ enum class OTAError : int DownloadFailed = 1, RP2040_UrlParseError = RP2040_OTA_ERROR_BASE - 0, RP2040_ServerConnectError = RP2040_OTA_ERROR_BASE - 1, - RP2040_ErrorOpenUpdateFile = RP2040_OTA_ERROR_BASE - 2, - RP2040_ErrorWriteUpdateFile = RP2040_OTA_ERROR_BASE - 3, - RP2040_ErrorParseHttpHeader = RP2040_OTA_ERROR_BASE - 4, + RP2040_HttpHeaderError = RP2040_OTA_ERROR_BASE - 2, + RP2040_HttpDataError = RP2040_OTA_ERROR_BASE - 3, + RP2040_ErrorOpenUpdateFile = RP2040_OTA_ERROR_BASE - 4, + RP2040_ErrorWriteUpdateFile = RP2040_OTA_ERROR_BASE - 5, + RP2040_ErrorParseHttpHeader = RP2040_OTA_ERROR_BASE - 6, }; /****************************************************************************** From 756a64af30faa7481008a59d25dca1931fcbec02 Mon Sep 17 00:00:00 2001 From: Alexander Entinger Date: Wed, 2 Jun 2021 09:17:09 +0200 Subject: [PATCH 23/37] After the implementation of a time-out logic in the previous commit it makes sense to feed the watchdog within the main-loop body since the timeout will terminate the loop anyway. --- src/utility/ota/OTA-nano-rp2040.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/utility/ota/OTA-nano-rp2040.cpp b/src/utility/ota/OTA-nano-rp2040.cpp index 74d702593..14bbee2ed 100644 --- a/src/utility/ota/OTA-nano-rp2040.cpp +++ b/src/utility/ota/OTA-nano-rp2040.cpp @@ -136,10 +136,10 @@ int rp2040_connect_onOTARequest(char const * ota_url) is_http_header_timeout = (millis() - start) > (10*1000); if (is_http_header_timeout) break; + mbed_watchdog_reset(); + if (client->available()) { - mbed_watchdog_reset(); - char const c = client->read(); http_header += c; @@ -181,10 +181,10 @@ int rp2040_connect_onOTARequest(char const * ota_url) is_http_data_timeout = (millis() - start) > (60*1000); if (is_http_data_timeout) break; + mbed_watchdog_reset(); + if (client->available()) { - mbed_watchdog_reset(); - char const c = client->read(); if (fwrite(&c, 1, sizeof(c), file) != sizeof(c)) From b13a560668d400398767692359c5de52c9861de4 Mon Sep 17 00:00:00 2001 From: Alexander Entinger Date: Wed, 2 Jun 2021 09:21:20 +0200 Subject: [PATCH 24/37] Replace magic RP2040 OTA timeout values with sensibly named constants. --- src/utility/ota/OTA-nano-rp2040.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/utility/ota/OTA-nano-rp2040.cpp b/src/utility/ota/OTA-nano-rp2040.cpp index 14bbee2ed..8d17c8289 100644 --- a/src/utility/ota/OTA-nano-rp2040.cpp +++ b/src/utility/ota/OTA-nano-rp2040.cpp @@ -133,7 +133,7 @@ int rp2040_connect_onOTARequest(char const * ota_url) is_http_header_timeout = false; for (unsigned long const start = millis(); !is_header_complete;) { - is_http_header_timeout = (millis() - start) > (10*1000); + is_http_header_timeout = (millis() - start) > AIOT_CONFIG_RP2040_OTA_HTTP_HEADER_RECEIVE_TIMEOUT_ms; if (is_http_header_timeout) break; mbed_watchdog_reset(); @@ -178,7 +178,7 @@ int rp2040_connect_onOTARequest(char const * ota_url) bool is_http_data_timeout = false; for(unsigned long const start = millis(); bytes_received < content_length_val;) { - is_http_data_timeout = (millis() - start) > (60*1000); + is_http_data_timeout = (millis() - start) > AIOT_CONFIG_RP2040_OTA_HTTP_DATA_RECEIVE_TIMEOUT_ms; if (is_http_data_timeout) break; mbed_watchdog_reset(); From 867a6acb9234cfd90e6156f4254ead7e0c65ae53 Mon Sep 17 00:00:00 2001 From: Alexander Entinger Date: Wed, 2 Jun 2021 09:24:17 +0200 Subject: [PATCH 25/37] Replace magic RP2040 OTA timeout values with sensibly named constants. --- src/AIoTC_Config.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/AIoTC_Config.h b/src/AIoTC_Config.h index 94297350f..60f5b5296 100644 --- a/src/AIoTC_Config.h +++ b/src/AIoTC_Config.h @@ -145,4 +145,7 @@ #define AIOT_CONFIG_TIMEOUT_FOR_LASTVALUES_SYNC_ms (30000UL) #define AIOT_CONFIG_LASTVALUES_SYNC_MAX_RETRY_CNT (10UL) +#define AIOT_CONFIG_RP2040_OTA_HTTP_HEADER_RECEIVE_TIMEOUT_ms (10000UL) +#define AIOT_CONFIG_RP2040_OTA_HTTP_DATA_RECEIVE_TIMEOUT_ms (60000UL) + #endif /* ARDUINO_AIOTC_CONFIG_H_ */ From c65bd2b444c07d48d06774713a4b419448967ae8 Mon Sep 17 00:00:00 2001 From: Alexander Entinger Date: Wed, 2 Jun 2021 09:26:55 +0200 Subject: [PATCH 26/37] Move opening of update file to the very beginning of the OTA function (makes error handling easier - see next step). --- src/utility/ota/OTA-nano-rp2040.cpp | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/src/utility/ota/OTA-nano-rp2040.cpp b/src/utility/ota/OTA-nano-rp2040.cpp index 8d17c8289..f09e59cd8 100644 --- a/src/utility/ota/OTA-nano-rp2040.cpp +++ b/src/utility/ota/OTA-nano-rp2040.cpp @@ -80,9 +80,19 @@ void URI::parse(const string& url_s) int rp2040_connect_onOTARequest(char const * ota_url) { + mbed_watchdog_reset(); + SFU::begin(); - remove("/ota/UPDATE.BIN.LZSS"); + mbed_watchdog_reset(); + + FILE * file = fopen("/ota/UPDATE.BIN.LZSS", "wb"); + if (!file) + { + DEBUG_ERROR("%s: fopen() failed", __FUNCTION__); + fclose(file); + return static_cast(OTAError::RP2040_ErrorOpenUpdateFile); + } mbed_watchdog_reset(); @@ -103,9 +113,9 @@ int rp2040_connect_onOTARequest(char const * ota_url) mbed_watchdog_reset(); - int ret = client->connect(url.host_.c_str(), port); - if (!ret) + if (!client->connect(url.host_.c_str(), port)) { + fclose(file); DEBUG_ERROR("%s: Connection failure with OTA storage server %s", __FUNCTION__, url.host_.c_str()); return static_cast(OTAError::RP2040_ServerConnectError); } @@ -119,14 +129,6 @@ int rp2040_connect_onOTARequest(char const * ota_url) mbed_watchdog_reset(); - FILE * file = fopen("/ota/UPDATE.BIN.LZSS", "wb"); - if (!file) - { - DEBUG_ERROR("%s: fopen() failed", __FUNCTION__); - fclose(file); - return static_cast(OTAError::RP2040_ErrorOpenUpdateFile); - } - /* Receive HTTP header. */ String http_header; bool is_header_complete = false, From 6672d0e8e4a0d1909b4ca98e348f841b925c04c1 Mon Sep 17 00:00:00 2001 From: Alexander Entinger Date: Wed, 2 Jun 2021 09:38:13 +0200 Subject: [PATCH 27/37] Cleanup error handling to follow the same format in the whole function (debug message, fclose, return error) --- src/utility/ota/OTA-nano-rp2040.cpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/utility/ota/OTA-nano-rp2040.cpp b/src/utility/ota/OTA-nano-rp2040.cpp index f09e59cd8..d49fe8a42 100644 --- a/src/utility/ota/OTA-nano-rp2040.cpp +++ b/src/utility/ota/OTA-nano-rp2040.cpp @@ -108,6 +108,7 @@ int rp2040_connect_onOTARequest(char const * ota_url) port = 443; } else { DEBUG_ERROR("%s: Failed to parse OTA URL %s", __FUNCTION__, ota_url); + fclose(file); return static_cast(OTAError::RP2040_UrlParseError); } @@ -115,8 +116,8 @@ int rp2040_connect_onOTARequest(char const * ota_url) if (!client->connect(url.host_.c_str(), port)) { - fclose(file); DEBUG_ERROR("%s: Connection failure with OTA storage server %s", __FUNCTION__, url.host_.c_str()); + fclose(file); return static_cast(OTAError::RP2040_ServerConnectError); } @@ -150,9 +151,10 @@ int rp2040_connect_onOTARequest(char const * ota_url) } } - if (!is_header_complete) { - fclose(file); + if (!is_header_complete) + { DEBUG_ERROR("%s: Error receiving HTTP header %s", __FUNCTION__, is_http_header_timeout ? "(timeout)":""); + fclose(file); return static_cast(OTAError::RP2040_HttpHeaderError); } @@ -162,8 +164,8 @@ int rp2040_connect_onOTARequest(char const * ota_url) char const * content_length_ptr = strstr(http_header.c_str(), "Content-Length"); if (!content_length_ptr) { - fclose(file); DEBUG_ERROR("%s: Failure to extract content length from http header", __FUNCTION__); + fclose(file); return static_cast(OTAError::RP2040_ErrorParseHttpHeader); } /* Find start of numerical value. */ @@ -201,8 +203,8 @@ int rp2040_connect_onOTARequest(char const * ota_url) } if (bytes_received != content_length_val) { - fclose(file); DEBUG_ERROR("%s: Error receiving HTTP data %s (%d bytes received, %d expected)", __FUNCTION__, is_http_data_timeout ? "(timeout)":"", bytes_received, content_length_val); + fclose(file); return static_cast(OTAError::RP2040_HttpDataError); } From 4a3ff5e63cb358ea21570f3c01737397123d8e03 Mon Sep 17 00:00:00 2001 From: Alexander Entinger Date: Wed, 2 Jun 2021 10:22:44 +0200 Subject: [PATCH 28/37] Increase timeout values for HTTPS-GET data download to flash. --- src/AIoTC_Config.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/AIoTC_Config.h b/src/AIoTC_Config.h index 60f5b5296..9ceb2ac62 100644 --- a/src/AIoTC_Config.h +++ b/src/AIoTC_Config.h @@ -145,7 +145,7 @@ #define AIOT_CONFIG_TIMEOUT_FOR_LASTVALUES_SYNC_ms (30000UL) #define AIOT_CONFIG_LASTVALUES_SYNC_MAX_RETRY_CNT (10UL) -#define AIOT_CONFIG_RP2040_OTA_HTTP_HEADER_RECEIVE_TIMEOUT_ms (10000UL) -#define AIOT_CONFIG_RP2040_OTA_HTTP_DATA_RECEIVE_TIMEOUT_ms (60000UL) +#define AIOT_CONFIG_RP2040_OTA_HTTP_HEADER_RECEIVE_TIMEOUT_ms (10*1000UL) +#define AIOT_CONFIG_RP2040_OTA_HTTP_DATA_RECEIVE_TIMEOUT_ms (4*60*1000UL) #endif /* ARDUINO_AIOTC_CONFIG_H_ */ From 92168d0a6bea40bac70e8e5f31dee2abe1854b46 Mon Sep 17 00:00:00 2001 From: Alexander Entinger Date: Wed, 2 Jun 2021 10:23:26 +0200 Subject: [PATCH 29/37] Removing irrelevant debug output. --- src/utility/ota/OTA-nano-rp2040.cpp | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/utility/ota/OTA-nano-rp2040.cpp b/src/utility/ota/OTA-nano-rp2040.cpp index d49fe8a42..419849967 100644 --- a/src/utility/ota/OTA-nano-rp2040.cpp +++ b/src/utility/ota/OTA-nano-rp2040.cpp @@ -208,12 +208,9 @@ int rp2040_connect_onOTARequest(char const * ota_url) return static_cast(OTAError::RP2040_HttpDataError); } - /* Determine length. */ - int const file_len = ftell(file); + /* Perform the reset to reboot to SFU. */ + DEBUG_INFO("%s: %d bytes received", __FUNCTION__, ftell(file)); fclose(file); - DEBUG_DEBUG("%s: %d bytes received (%d expected)", __FUNCTION__, file_len, content_length_val); - - /* Perform the reset to reboot to SxU. */ NVIC_SystemReset(); return static_cast(OTAError::None); From 0e386a1faa80a39a02623ee4b582d66f485efeb3 Mon Sep 17 00:00:00 2001 From: Alexander Entinger Date: Wed, 2 Jun 2021 11:55:51 +0200 Subject: [PATCH 30/37] Temp - Remove later - erase flash within OTA handler. --- src/AIoTC_Config.h | 2 +- src/utility/ota/OTA-nano-rp2040.cpp | 28 +++++++++++++++++++++++++++- 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/src/AIoTC_Config.h b/src/AIoTC_Config.h index 9ceb2ac62..6df348af8 100644 --- a/src/AIoTC_Config.h +++ b/src/AIoTC_Config.h @@ -62,7 +62,7 @@ # if defined(ARDUINO_AVR_UNO_WIFI_REV2) # define DEBUG_VERBOSE(fmt, ...) # else -# define DEBUG_VERBOSE(fmt, ...) //Debug.print(DBG_VERBOSE, fmt, ## __VA_ARGS__) +# define DEBUG_VERBOSE(fmt, ...) Debug.print(DBG_VERBOSE, fmt, ## __VA_ARGS__) # endif #endif diff --git a/src/utility/ota/OTA-nano-rp2040.cpp b/src/utility/ota/OTA-nano-rp2040.cpp index 419849967..972c2718f 100644 --- a/src/utility/ota/OTA-nano-rp2040.cpp +++ b/src/utility/ota/OTA-nano-rp2040.cpp @@ -29,6 +29,10 @@ #include +#include "mbed.h" +#include "FATFileSystem.h" +#include "FlashIAPBlockDevice.h" + /****************************************************************************** * FUNCTION DEFINITION ******************************************************************************/ @@ -82,7 +86,28 @@ int rp2040_connect_onOTARequest(char const * ota_url) { mbed_watchdog_reset(); - SFU::begin(); + //SFU::begin(); + + int err = -1; + FlashIAPBlockDevice flash(XIP_BASE + 0xF00000, 0x100000); + if ((err = flash.init()) < 0) + { + DEBUG_ERROR("%s: flash.init() failed with %d", __FUNCTION__, err); + return err; + } + + mbed_watchdog_reset(); + + flash.erase(XIP_BASE + 0xF00000, 0x100000); + + mbed_watchdog_reset(); + + mbed::FATFileSystem fs("ota"); + if ((err = fs.mount(&flash)) != 0) + { + DEBUG_ERROR("%s: fs.mount() failed with %d", __FUNCTION__, err); + return err; + } mbed_watchdog_reset(); @@ -199,6 +224,7 @@ int rp2040_connect_onOTARequest(char const * ota_url) } bytes_received++; + DEBUG_VERBOSE("%d", bytes_received); } } From 4f89f35e6b81d24cf58939117cc1344829ab8bf9 Mon Sep 17 00:00:00 2001 From: pennam Date: Thu, 3 Jun 2021 22:56:58 +0200 Subject: [PATCH 31/37] Trigger a watchdog reset to start SFU --- src/utility/ota/OTA-nano-rp2040.cpp | 3 ++- src/utility/watchdog/Watchdog.cpp | 21 +++++++++++++++++++++ src/utility/watchdog/Watchdog.h | 1 + 3 files changed, 24 insertions(+), 1 deletion(-) diff --git a/src/utility/ota/OTA-nano-rp2040.cpp b/src/utility/ota/OTA-nano-rp2040.cpp index 972c2718f..2226e7d62 100644 --- a/src/utility/ota/OTA-nano-rp2040.cpp +++ b/src/utility/ota/OTA-nano-rp2040.cpp @@ -237,7 +237,8 @@ int rp2040_connect_onOTARequest(char const * ota_url) /* Perform the reset to reboot to SFU. */ DEBUG_INFO("%s: %d bytes received", __FUNCTION__, ftell(file)); fclose(file); - NVIC_SystemReset(); + //NVIC_SystemReset(); + mbed_watchdog_trigger_reset(); return static_cast(OTAError::None); } diff --git a/src/utility/watchdog/Watchdog.cpp b/src/utility/watchdog/Watchdog.cpp index 14c5d68e6..edf2be5ca 100644 --- a/src/utility/watchdog/Watchdog.cpp +++ b/src/utility/watchdog/Watchdog.cpp @@ -110,4 +110,25 @@ void mbed_watchdog_reset() hal_watchdog_kick(); } } + +void mbed_watchdog_trigger_reset() +{ + watchdog_config_t cfg; +#if defined(ARDUINO_PORTENTA_H7_M7) || defined(ARDUINO_PORTENTA_H7_M4) + cfg.timeout_ms = 1; +#elif defined(ARDUINO_NANO_RP2040_CONNECT) + cfg.timeout_ms = 1; +#else +# error "You need to define the maximum possible timeout for this architecture." +#endif + + if (hal_watchdog_init(&cfg) == WATCHDOG_STATUS_OK) { + is_watchdog_enabled = true; + } + else { + DEBUG_WARNING("%s: watchdog could not be reconfigured", __FUNCTION__); + } + + while(1){} +} #endif /* ARDUINO_ARCH_MBED */ diff --git a/src/utility/watchdog/Watchdog.h b/src/utility/watchdog/Watchdog.h index 91161d072..e1c8d2c27 100644 --- a/src/utility/watchdog/Watchdog.h +++ b/src/utility/watchdog/Watchdog.h @@ -30,6 +30,7 @@ void samd_watchdog_reset(); #ifdef ARDUINO_ARCH_MBED void mbed_watchdog_enable(); void mbed_watchdog_reset(); +void mbed_watchdog_trigger_reset(); #endif /* ARDUINO_ARCH_MBED */ #endif /* ARDUINO_AIOTC_UTILITY_WATCHDOG_H_ */ From fc5dd4f3ef4715efe5a476b08fa31c5bceca48eb Mon Sep 17 00:00:00 2001 From: Alexander Entinger Date: Fri, 4 Jun 2021 08:11:47 +0200 Subject: [PATCH 32/37] Cleaning up missing comments. --- src/utility/ota/OTA-nano-rp2040.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/utility/ota/OTA-nano-rp2040.cpp b/src/utility/ota/OTA-nano-rp2040.cpp index 2226e7d62..dd9938cec 100644 --- a/src/utility/ota/OTA-nano-rp2040.cpp +++ b/src/utility/ota/OTA-nano-rp2040.cpp @@ -86,8 +86,6 @@ int rp2040_connect_onOTARequest(char const * ota_url) { mbed_watchdog_reset(); - //SFU::begin(); - int err = -1; FlashIAPBlockDevice flash(XIP_BASE + 0xF00000, 0x100000); if ((err = flash.init()) < 0) @@ -224,7 +222,6 @@ int rp2040_connect_onOTARequest(char const * ota_url) } bytes_received++; - DEBUG_VERBOSE("%d", bytes_received); } } @@ -237,7 +234,6 @@ int rp2040_connect_onOTARequest(char const * ota_url) /* Perform the reset to reboot to SFU. */ DEBUG_INFO("%s: %d bytes received", __FUNCTION__, ftell(file)); fclose(file); - //NVIC_SystemReset(); mbed_watchdog_trigger_reset(); return static_cast(OTAError::None); From 06267fbf1f27fb20d8419fb5f01bf746eb75fd29 Mon Sep 17 00:00:00 2001 From: Alexander Entinger Date: Fri, 4 Jun 2021 08:30:15 +0200 Subject: [PATCH 33/37] Unmount before performing a reset. --- src/utility/ota/OTA-nano-rp2040.cpp | 14 +++++++++++--- src/utility/ota/OTA.h | 3 +++ 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/src/utility/ota/OTA-nano-rp2040.cpp b/src/utility/ota/OTA-nano-rp2040.cpp index dd9938cec..8d228cc01 100644 --- a/src/utility/ota/OTA-nano-rp2040.cpp +++ b/src/utility/ota/OTA-nano-rp2040.cpp @@ -91,7 +91,7 @@ int rp2040_connect_onOTARequest(char const * ota_url) if ((err = flash.init()) < 0) { DEBUG_ERROR("%s: flash.init() failed with %d", __FUNCTION__, err); - return err; + return static_cast(OTAError::RP2040_ErrorFlashInit); } mbed_watchdog_reset(); @@ -104,7 +104,7 @@ int rp2040_connect_onOTARequest(char const * ota_url) if ((err = fs.mount(&flash)) != 0) { DEBUG_ERROR("%s: fs.mount() failed with %d", __FUNCTION__, err); - return err; + return static_cast(OTAError::RP2040_ErrorMount); } mbed_watchdog_reset(); @@ -231,9 +231,17 @@ int rp2040_connect_onOTARequest(char const * ota_url) return static_cast(OTAError::RP2040_HttpDataError); } - /* Perform the reset to reboot to SFU. */ DEBUG_INFO("%s: %d bytes received", __FUNCTION__, ftell(file)); fclose(file); + + /* Unmount the filesystem. */ + if ((err = fs.unmount()) != 0) + { + DEBUG_ERROR("%s: fs.unmount() failed with %d", __FUNCTION__, err); + return static_cast(OTAError::RP2040_ErrorUnmount); + } + + /* Perform the reset to reboot to SFU. */ mbed_watchdog_trigger_reset(); return static_cast(OTAError::None); diff --git a/src/utility/ota/OTA.h b/src/utility/ota/OTA.h index cb0d7183e..6926c2e36 100644 --- a/src/utility/ota/OTA.h +++ b/src/utility/ota/OTA.h @@ -45,6 +45,9 @@ enum class OTAError : int RP2040_ErrorOpenUpdateFile = RP2040_OTA_ERROR_BASE - 4, RP2040_ErrorWriteUpdateFile = RP2040_OTA_ERROR_BASE - 5, RP2040_ErrorParseHttpHeader = RP2040_OTA_ERROR_BASE - 6, + RP2040_ErrorFlashInit = RP2040_OTA_ERROR_BASE - 7, + RP2040_ErrorMount = RP2040_OTA_ERROR_BASE - 8, + RP2040_ErrorUnmount = RP2040_OTA_ERROR_BASE - 9, }; /****************************************************************************** From 94ff8979b1607448b2674a8fe99f9bcd2d98df4d Mon Sep 17 00:00:00 2001 From: Alexander Entinger Date: Fri, 4 Jun 2021 08:36:55 +0200 Subject: [PATCH 34/37] Replace mount() with reformat() which results in a reformatted and mounted file-format - now we can be super sure to have a clean set-up. https://os.mbed.com/docs/mbed-os/v6.11/mbed-os-api-doxy/classmbed_1_1_f_a_t_file_system.html#a6bb5160b6665359b9411ebc65aaa5308 --- src/utility/ota/OTA-nano-rp2040.cpp | 6 +++--- src/utility/ota/OTA.h | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/utility/ota/OTA-nano-rp2040.cpp b/src/utility/ota/OTA-nano-rp2040.cpp index 8d228cc01..e47a4dcea 100644 --- a/src/utility/ota/OTA-nano-rp2040.cpp +++ b/src/utility/ota/OTA-nano-rp2040.cpp @@ -101,10 +101,10 @@ int rp2040_connect_onOTARequest(char const * ota_url) mbed_watchdog_reset(); mbed::FATFileSystem fs("ota"); - if ((err = fs.mount(&flash)) != 0) + if ((err = fs.reformat(&flash)) != 0) { - DEBUG_ERROR("%s: fs.mount() failed with %d", __FUNCTION__, err); - return static_cast(OTAError::RP2040_ErrorMount); + DEBUG_ERROR("%s: fs.reformat() failed with %d", __FUNCTION__, err); + return static_cast(OTAError::RP2040_ErrorReformat); } mbed_watchdog_reset(); diff --git a/src/utility/ota/OTA.h b/src/utility/ota/OTA.h index 6926c2e36..bc92dede1 100644 --- a/src/utility/ota/OTA.h +++ b/src/utility/ota/OTA.h @@ -46,7 +46,7 @@ enum class OTAError : int RP2040_ErrorWriteUpdateFile = RP2040_OTA_ERROR_BASE - 5, RP2040_ErrorParseHttpHeader = RP2040_OTA_ERROR_BASE - 6, RP2040_ErrorFlashInit = RP2040_OTA_ERROR_BASE - 7, - RP2040_ErrorMount = RP2040_OTA_ERROR_BASE - 8, + RP2040_ErrorReformat = RP2040_OTA_ERROR_BASE - 8, RP2040_ErrorUnmount = RP2040_OTA_ERROR_BASE - 9, }; From 679118cef0bd7bb00877651a0216c8f3a02c2d29 Mon Sep 17 00:00:00 2001 From: pennam Date: Fri, 4 Jun 2021 11:58:24 +0200 Subject: [PATCH 35/37] Avoid infinite loop if we fail to enable/reconfigure watchdog --- src/utility/ota/OTA-nano-rp2040.cpp | 2 ++ src/utility/watchdog/Watchdog.cpp | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/utility/ota/OTA-nano-rp2040.cpp b/src/utility/ota/OTA-nano-rp2040.cpp index e47a4dcea..8e0c3106b 100644 --- a/src/utility/ota/OTA-nano-rp2040.cpp +++ b/src/utility/ota/OTA-nano-rp2040.cpp @@ -243,6 +243,8 @@ int rp2040_connect_onOTARequest(char const * ota_url) /* Perform the reset to reboot to SFU. */ mbed_watchdog_trigger_reset(); + /* If watchdog is enabled we should not reach this point */ + NVIC_SystemReset(); return static_cast(OTAError::None); } diff --git a/src/utility/watchdog/Watchdog.cpp b/src/utility/watchdog/Watchdog.cpp index edf2be5ca..314e12e18 100644 --- a/src/utility/watchdog/Watchdog.cpp +++ b/src/utility/watchdog/Watchdog.cpp @@ -124,11 +124,11 @@ void mbed_watchdog_trigger_reset() if (hal_watchdog_init(&cfg) == WATCHDOG_STATUS_OK) { is_watchdog_enabled = true; + while(1){} } else { DEBUG_WARNING("%s: watchdog could not be reconfigured", __FUNCTION__); } - while(1){} } #endif /* ARDUINO_ARCH_MBED */ From 5ee73f7eed0fc9bc6a67a8ee7233b95397d50a11 Mon Sep 17 00:00:00 2001 From: pennam Date: Mon, 7 Jun 2021 11:39:59 +0200 Subject: [PATCH 36/37] Add watchdog reset after each step of CloudTCP state machine to avoid unwanted resets --- src/ArduinoIoTCloudTCP.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/ArduinoIoTCloudTCP.cpp b/src/ArduinoIoTCloudTCP.cpp index 9988fd6eb..68347d97c 100644 --- a/src/ArduinoIoTCloudTCP.cpp +++ b/src/ArduinoIoTCloudTCP.cpp @@ -320,6 +320,16 @@ void ArduinoIoTCloudTCP::update() } _state = next_state; + /* This watchdog feed is actually needed only by the RP2040 CONNECT cause its + * maximum watchdog window is 8388ms; despite this we feed it for all + * supported ARCH to keep code aligned. + */ +#ifdef ARDUINO_ARCH_SAMD + samd_watchdog_reset(); +#elif defined(ARDUINO_ARCH_MBED) + mbed_watchdog_reset(); +#endif + /* Check for new data from the MQTT client. */ if (_mqttClient.connected()) _mqttClient.poll(); From a212ef81332df7b667db60f9896a2968ee471777 Mon Sep 17 00:00:00 2001 From: Alexander Entinger Date: Mon, 7 Jun 2021 14:21:52 +0200 Subject: [PATCH 37/37] Disable verbose debug output in production. --- src/AIoTC_Config.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/AIoTC_Config.h b/src/AIoTC_Config.h index 6df348af8..9ceb2ac62 100644 --- a/src/AIoTC_Config.h +++ b/src/AIoTC_Config.h @@ -62,7 +62,7 @@ # if defined(ARDUINO_AVR_UNO_WIFI_REV2) # define DEBUG_VERBOSE(fmt, ...) # else -# define DEBUG_VERBOSE(fmt, ...) Debug.print(DBG_VERBOSE, fmt, ## __VA_ARGS__) +# define DEBUG_VERBOSE(fmt, ...) //Debug.print(DBG_VERBOSE, fmt, ## __VA_ARGS__) # endif #endif