Skip to content

Initial draft for OTA via RP2040. #257

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/AIoTC_Config.h
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
14 changes: 13 additions & 1 deletion src/ArduinoIoTCloudTCP.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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;
Expand Down Expand Up @@ -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());
Expand Down Expand Up @@ -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

Expand Down
2 changes: 1 addition & 1 deletion src/ArduinoIoTCloudTCP.h
Original file line number Diff line number Diff line change
Expand Up @@ -161,4 +161,4 @@ class ArduinoIoTCloudTCP: public ArduinoIoTCloudClass

extern ArduinoIoTCloudTCP ArduinoCloud;

#endif
#endif
159 changes: 159 additions & 0 deletions src/utility/ota/OTA-rp2040-connect.cpp
Original file line number Diff line number Diff line change
@@ -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 [email protected].
*/

#ifdef ARDUINO_NANO_RP2040_CONNECT

/******************************************************************************
* INCLUDE
******************************************************************************/

#include "OTA.h"

#include <Arduino_DebugUtils.h>

/* 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 <SFU.h>

/* 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 <WiFiNINA.h>

#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 */
4 changes: 4 additions & 0 deletions src/utility/ota/OTA.h
Original file line number Diff line number Diff line change
Expand Up @@ -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_ */