From 3f466658733ac1b152af1f029c67201674dadd17 Mon Sep 17 00:00:00 2001 From: Alexander Entinger Date: Fri, 21 May 2021 07:13:41 +0200 Subject: [PATCH] Initial draft for OTA via RP2040. --- src/AIoTC_Config.h | 2 +- src/ArduinoIoTCloudTCP.cpp | 14 ++- src/ArduinoIoTCloudTCP.h | 2 +- src/utility/ota/OTA-rp2040-connect.cpp | 159 +++++++++++++++++++++++++ src/utility/ota/OTA.h | 4 + 5 files changed, 178 insertions(+), 3 deletions(-) create mode 100644 src/utility/ota/OTA-rp2040-connect.cpp diff --git a/src/AIoTC_Config.h b/src/AIoTC_Config.h index 7c54d1751..01d2119f6 100644 --- a/src/AIoTC_Config.h +++ b/src/AIoTC_Config.h @@ -106,7 +106,7 @@ #define OTA_STORAGE_PORTENTA_QSPI (0) #endif -#if (OTA_STORAGE_SFU || OTA_STORAGE_SSU || OTA_STORAGE_SNU || OTA_STORAGE_PORTENTA_QSPI) && !defined(ARDUINO_AVR_UNO_WIFI_REV2) +#if (OTA_STORAGE_SFU || OTA_STORAGE_SSU || OTA_STORAGE_SNU || OTA_STORAGE_PORTENTA_QSPI || ARDUINO_NANO_RP2040_CONNECT) && !defined(ARDUINO_AVR_UNO_WIFI_REV2) #define OTA_ENABLED (1) #else #define OTA_ENABLED (0) diff --git a/src/ArduinoIoTCloudTCP.cpp b/src/ArduinoIoTCloudTCP.cpp index 653952e42..a689f7539 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 @@ -172,6 +172,10 @@ int ArduinoIoTCloudTCP::begin(bool const enable_watchdog, String brokerAddress, * range 0 to 0x2000, total flash size of 0x40000 bytes (256 kByte). */ String const sha256_str = FlashSHA256::calc(0x2000, 0x40000 - 0x2000); +#elif defined(ARDUINO_NANO_RP2040_CONNECT) + String const sha256_str = "TODO"; /* TODO !!! */ +#else +# error "You need to implement the SHA256 checksum calculation for this architecture" #endif DEBUG_VERBOSE("SHA256: HASH(%d) = %s", strlen(sha256_str.c_str()), sha256_str.c_str()); _ota_img_sha256 = sha256_str; @@ -259,6 +263,10 @@ int ArduinoIoTCloudTCP::begin(bool const enable_watchdog, String brokerAddress, } #endif /* OTA_STORAGE_SNU */ +#ifdef ARDUINO_NANO_RP2040_CONNECT + _ota_cap = true; +#endif /* ARDUINO_NANO_RP2040_CONNECT */ + #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()); @@ -590,6 +598,10 @@ void ArduinoIoTCloudTCP::onOTARequest() #if defined(ARDUINO_PORTENTA_H7_M7) || defined(ARDUINO_PORTENTA_H7_M4) _ota_error = portenta_h7_onOTARequest(_ota_url.c_str()); #endif + +#if defined(ARDUINO_NANO_RP2040_CONNECT) + _ota_error = nano_rp2040_connect_onOTARequest(_ota_url.c_str()); +#endif } #endif diff --git a/src/ArduinoIoTCloudTCP.h b/src/ArduinoIoTCloudTCP.h index f29aafde7..c66123102 100644 --- a/src/ArduinoIoTCloudTCP.h +++ b/src/ArduinoIoTCloudTCP.h @@ -161,4 +161,4 @@ class ArduinoIoTCloudTCP: public ArduinoIoTCloudClass extern ArduinoIoTCloudTCP ArduinoCloud; -#endif \ No newline at end of file +#endif diff --git a/src/utility/ota/OTA-rp2040-connect.cpp b/src/utility/ota/OTA-rp2040-connect.cpp new file mode 100644 index 000000000..56c4b214b --- /dev/null +++ b/src/utility/ota/OTA-rp2040-connect.cpp @@ -0,0 +1,159 @@ +/* + 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. +*/ + +#ifdef ARDUINO_NANO_RP2040_CONNECT + +/****************************************************************************** + * INCLUDE + ******************************************************************************/ + +#include "OTA.h" + +#include + +/* This library resides within the Nano RP2040 Connect Arduino Core + * and provides a 2nd stage bootloader which upon booting checks + * for the existence of a firmware update image and then performs + * a firmware update. + */ +#include + +/* The Arduino Nano RP2040 Connect has a NINA-W102 WiFi module + * mounted for connectivity. Therefore its library needs to be + * included here in order to access the WiFi module for downloading + * the firmware update image. + */ +#include + +#include "../watchdog/Watchdog.h" + + +#include "mbed.h" +#include "FlashIAPBlockDevice.h" +#include "FATFileSystem.h" + +/****************************************************************************** + * FUNCTION DEFINITION + ******************************************************************************/ + +int nano_rp2040_connect_onOTARequest(char const * ota_url) +{ + int err = 0; + + mbed_watchdog_reset(); + + /* As a first step prepare everything for the pending + * firmware image download. Initialize the flash, + * mount a filesystem and clean-up any left-overs from + * previous (and possibly failed) update attempts. + */ + + FlashIAPBlockDevice sd(XIP_BASE + 0x100000, 0x100000); + if ((err = sd.init()) < 0) + { + DEBUG_ERROR("%s: sd.init() failed with %d", __FUNCTION__, err); + return err; + } + + mbed_watchdog_reset(); + + mbed::FATFileSystem fs("ota"); + if ((err = fs.mount(&sd)) != 0) + { + DEBUG_ERROR("%s: fs.mount() failed with %d", __FUNCTION__, err); + return err; + } + + mbed_watchdog_reset(); + + remove("/ota/UPDATE.BIN"); + remove("/ota/UPDATE.BIN.LZSS"); + remove("/ota/UPDATE.BIN.LZSS.TMP"); + + mbed_watchdog_reset(); + + FILE * file = fopen("/ota/UPDATE.BIN.LZSS.TMP", "wb"); + if (!file) + { + DEBUG_ERROR("%s: fopen() failed", __FUNCTION__); + fclose(file); + return errno; + } + + /* Now its time to actually download the firmware + * image from the server and store it on the filesystem. + */ + //WiFiSSLClient client; + WiFiClient client; + +// if (!client.connect("api2.arduino.cc", 443)) + if (!client.connect("107-systems.org", 80)) + { + DEBUG_ERROR("%s: Connection failure with OTA storage server", __FUNCTION__, err); + return -1; /* TODO: Implement better error codes. */ + } + + mbed_watchdog_reset(); + +/* + client.println("GET iot/ota/8ea3d719-0df0-4a7f-b469-896d61fe42db HTTP/1.1"); + client.println("Host: api2.arduino.cc"); + client.println("Connection: close"); + client.println(); +*/ + + client.println("GET ota/rp2040-led-red.bin HTTP/1.1"); + client.println("Host: 107-systems.org"); + client.println("Connection: close"); + client.println(); + + String http_header; + bool is_header_complete = false; + + while (client.available()) + { + mbed_watchdog_reset(); + + 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. */ + } + } + } + + int const file_len = ftell(file); + DEBUG_DEBUG("%s: %d bytes received", __FUNCTION__, file_len); + + fclose(file); + + /* TODO: Check CRC and header data and decompress. */ + + return 0; +} + +#endif /* ARDUINO_NANO_RP2040_CONNECT */ diff --git a/src/utility/ota/OTA.h b/src/utility/ota/OTA.h index 6a9b2312f..b48323c59 100644 --- a/src/utility/ota/OTA.h +++ b/src/utility/ota/OTA.h @@ -54,4 +54,8 @@ int samd_onOTARequest(char const * ota_url); int portenta_h7_onOTARequest(char const * ota_url); #endif +#if defined(ARDUINO_NANO_RP2040_CONNECT) +int nano_rp2040_connect_onOTARequest(char const * ota_url); +#endif + #endif /* ARDUINO_OTA_LOGIC_H_ */