Skip to content
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

Notecard OTA #508

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
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
74 changes: 39 additions & 35 deletions src/AIoTC_Config.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,40 +60,6 @@

#if !defined(HAS_NOTECARD)

#if defined(ARDUINO_SAMD_MKRWIFI1010) || defined(ARDUINO_SAMD_NANO_33_IOT)
#define OTA_STORAGE_SNU (1)
#else
#define OTA_STORAGE_SNU (0)
#endif

#if defined(ARDUINO_NANO_RP2040_CONNECT)
#define OTA_STORAGE_SFU (1)
#else
#define OTA_STORAGE_SFU (0)
#endif

#ifdef ARDUINO_SAMD_MKRGSM1400
#define OTA_STORAGE_SSU (1) // OTA_STORAGE_SSU is not implemented yet in OTASamd
#else
#define OTA_STORAGE_SSU (0)
#endif

#if defined(ARDUINO_PORTENTA_H7_M7) || defined(ARDUINO_NICLA_VISION) || defined(ARDUINO_OPTA) || defined(ARDUINO_GIGA)
#define OTA_STORAGE_PORTENTA_QSPI (1)
#else
#define OTA_STORAGE_PORTENTA_QSPI (0)
#endif

#if defined(ARDUINO_ARCH_ESP32) || defined(ARDUINO_UNOR4_WIFI)
#define OTA_STORAGE_ESP (1)
#endif

#if (OTA_STORAGE_SFU || OTA_STORAGE_SNU || OTA_STORAGE_PORTENTA_QSPI || OTA_STORAGE_ESP)
#define OTA_ENABLED (1)
#else
#define OTA_ENABLED (0)
#endif

#if defined(ARDUINO_SAMD_MKRGSM1400) || defined(ARDUINO_SAMD_MKR1000) || \
defined(ARDUINO_SAMD_MKRNB1500) || defined(ARDUINO_PORTENTA_H7_M7) || \
defined (ARDUINO_NANO_RP2040_CONNECT) || defined(ARDUINO_OPTA) || \
Expand Down Expand Up @@ -141,7 +107,45 @@
#define BOARD_HAS_SECURE_ELEMENT
#endif

#endif // HAS_NOTECARD
#if defined(ARDUINO_SAMD_MKRWIFI1010) || defined(ARDUINO_SAMD_NANO_33_IOT)
#define OTA_STORAGE_SNU (1)
#else
#define OTA_STORAGE_SNU (0)
#endif

#if defined(ARDUINO_UNOR4_WIFI)
#define OTA_STORAGE_ESP (1)
#endif

#ifdef ARDUINO_SAMD_MKRGSM1400
#define OTA_STORAGE_SSU (1) // OTA_STORAGE_SSU is not implemented yet in OTASamd
#else
#define OTA_STORAGE_SSU (0)
#endif

#endif // !defined(HAS_NOTECARD)

#if defined(ARDUINO_NANO_RP2040_CONNECT)
#define OTA_STORAGE_SFU (1)
#else
#define OTA_STORAGE_SFU (0)
#endif

#if defined(ARDUINO_PORTENTA_H7_M7) || defined(ARDUINO_NICLA_VISION) || defined(ARDUINO_OPTA) || defined(ARDUINO_GIGA)
#define OTA_STORAGE_PORTENTA_QSPI (1)
#else
#define OTA_STORAGE_PORTENTA_QSPI (0)
#endif

#if defined(ARDUINO_ARCH_ESP32)
#define OTA_STORAGE_ESP (1)
#endif

#if (OTA_STORAGE_SFU || OTA_STORAGE_SNU || OTA_STORAGE_PORTENTA_QSPI || OTA_STORAGE_ESP)
#define OTA_ENABLED (1)
#else
#define OTA_ENABLED (0)
#endif

#if defined(ARDUINO_PORTENTA_H7_M7) || defined(ARDUINO_NICLA_VISION) || defined(ARDUINO_OPTA) || defined(ARDUINO_GIGA)
#define BEAR_SSL_CLIENT_IBUF_SIZE (16384 + 325) // Allows download from storage API
Expand Down
9 changes: 9 additions & 0 deletions src/ArduinoIoTCloudNotecard.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,10 @@ ArduinoIoTCloudNotecard::ArduinoIoTCloudNotecard()
,_notecard_polling_interval_ms{DEFAULT_READ_INTERVAL_MS}
,_interrupt_pin{-1}
,_data_available{false}
#if OTA_ENABLED
,_ota(&_message_stream)
,_get_ota_confirmation{nullptr}
#endif
{

}
Expand Down Expand Up @@ -99,6 +103,11 @@ int ArduinoIoTCloudNotecard::begin(ConnectionHandler &connection_, int interrupt
// Begin the Notecard time service
_time_service.begin(&connection_);

#if OTA_ENABLED
// Configure the OTA interface
_ota.setConnection(&connection_);
#endif

// Setup retry timers
_connection_attempt.begin(AIOT_CONFIG_RECONNECTION_RETRY_DELAY_ms, AIOT_CONFIG_MAX_RECONNECTION_RETRY_DELAY_ms);

Expand Down
29 changes: 29 additions & 0 deletions src/ArduinoIoTCloudNotecard.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@
#include "ArduinoIoTCloudThing.h"
#include "ArduinoIoTCloudDevice.h"

#if OTA_ENABLED
#include "ota/OTA.h"
#endif /* OTA_ENABLED */

/******************************************************************************
* DEFINES
******************************************************************************/
Expand All @@ -33,6 +37,10 @@
* TYPEDEF
******************************************************************************/

#if OTA_ENABLED
typedef bool (*onOTARequestCallbackFunc)(void);
#endif /* OTA_ENABLED */

/******************************************************************************
* CLASS DECLARATION
******************************************************************************/
Expand Down Expand Up @@ -82,6 +90,22 @@ class ArduinoIoTCloudNotecard : public ArduinoIoTCloudClass
*/
inline void setNotecardPollingInterval(uint32_t interval_ms) { _notecard_polling_interval_ms = ((interval_ms < 250) ? 250 : interval_ms); }

#if OTA_ENABLED
/* The callback is triggered when the OTA is initiated and it gets executed until _ota_req flag is cleared.
* It should return true when the OTA can be applied or false otherwise.
* See example ArduinoIoTCloud-DeferredOTA.ino
*/
inline void onOTARequestCb(onOTARequestCallbackFunc cb) {
_get_ota_confirmation = cb;

if(_get_ota_confirmation) {
_ota.setOtaPolicies(OTACloudProcessInterface::ApprovalRequired);
} else {
_ota.setOtaPolicies(OTACloudProcessInterface::None);
}
}
#endif /* OTA_ENABLED */

private:

enum class State
Expand All @@ -104,6 +128,11 @@ class ArduinoIoTCloudNotecard : public ArduinoIoTCloudClass
int _interrupt_pin;
volatile bool _data_available;

#if OTA_ENABLED
ArduinoCloudOTA _ota;
onOTARequestCallbackFunc _get_ota_confirmation;
#endif /* OTA_ENABLED */

inline virtual PropertyContainer &getThingPropertyContainer() override { return _thing.getPropertyContainer(); }

State handle_ConnectPhy();
Expand Down
4 changes: 4 additions & 0 deletions src/ota/implementation/OTAEsp32.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,11 @@

#pragma once

#ifndef HAS_NOTECARD
#include "ota/interface/OTAInterfaceDefault.h"
#else
#include "ota/interface/OTAInterfaceNotecard.h"
#endif

class ESP32OTACloudProcess: public OTADefaultCloudProcessInterface {
public:
Expand Down
4 changes: 4 additions & 0 deletions src/ota/implementation/OTANanoRP2040.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,11 @@

#pragma once

#ifndef HAS_NOTECARD
#include "ota/interface/OTAInterfaceDefault.h"
#else
#include "ota/interface/OTAInterfaceNotecard.h"
#endif

#include "FATFileSystem.h"
#include "FlashIAPBlockDevice.h"
Expand Down
7 changes: 6 additions & 1 deletion src/ota/implementation/OTASTM32H7.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,12 @@
*/

#pragma once

#ifndef HAS_NOTECARD
#include "ota/interface/OTAInterfaceDefault.h"
#else
#include "ota/interface/OTAInterfaceNotecard.h"
#endif

#include <QSPIFBlockDevice.h>

Expand Down Expand Up @@ -47,7 +52,7 @@ class STM32H7OTACloudProcess: public OTADefaultCloudProcessInterface {
// we are overriding the method of startOTA in order to open the destination file for the ota download
virtual OTACloudProcessInterface::State startOTA() override;

// whene the download is correctly finished we set the mcu to use the newly downloaded binary
// when the download is correctly finished we set the mcu to use the newly downloaded binary
virtual OTACloudProcessInterface::State flashOTA() override;

// we reboot the device
Expand Down
3 changes: 2 additions & 1 deletion src/ota/implementation/OTASamd.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,10 @@

#pragma once

#include "ota/interface/OTAInterface.h"
#include <Arduino_DebugUtils.h>

#include "ota/interface/OTAInterface.h"

class SAMDOTACloudProcess: public OTACloudProcessInterface {
public:
SAMDOTACloudProcess(MessageStream *ms);
Expand Down
28 changes: 15 additions & 13 deletions src/ota/interface/OTAInterfaceDefault.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
*/
#include <AIoTC_Config.h>

#if OTA_ENABLED && ! defined(OFFLOADED_DOWNLOAD)
#if OTA_ENABLED && ! defined(OFFLOADED_DOWNLOAD) && ! defined(HAS_NOTECARD)
#include "OTAInterfaceDefault.h"
#include "../OTA.h"

Expand All @@ -32,6 +32,8 @@ OTACloudProcessInterface::State OTADefaultCloudProcessInterface::startOTA() {
assert(OTACloudProcessInterface::context != nullptr);
assert(context == nullptr);

DEBUG_DEBUG("OTADefaultCloudProcessInterface::%s initializing download from \"%s\"", __FUNCTION__, OTACloudProcessInterface::context->url);

context = new Context(
OTACloudProcessInterface::context->url,
[this](uint8_t c) {
Expand All @@ -58,27 +60,27 @@ OTACloudProcessInterface::State OTADefaultCloudProcessInterface::startOTA() {
http_client->endRequest();

if(res == HTTP_ERROR_CONNECTION_FAILED) {
DEBUG_VERBOSE("OTA ERROR: http client error connecting to server \"%s:%d\"",
DEBUG_ERROR("OTA ERROR: HTTP client error connecting to server \"%s:%d\"",
context->parsed_url.host(), context->parsed_url.port());
return ServerConnectErrorFail;
} else if(res == HTTP_ERROR_TIMED_OUT) {
DEBUG_VERBOSE("OTA ERROR: http client timeout \"%s\"", OTACloudProcessInterface::context->url);
DEBUG_ERROR("OTA ERROR: HTTP client timeout \"%s\"", OTACloudProcessInterface::context->url);
return OtaHeaderTimeoutFail;
} else if(res != HTTP_SUCCESS) {
DEBUG_VERBOSE("OTA ERROR: http client returned %d on get \"%s\"", res, OTACloudProcessInterface::context->url);
DEBUG_ERROR("OTA ERROR: HTTP client returned %d on GET \"%s\"", res, OTACloudProcessInterface::context->url);
return OtaDownloadFail;
}

int statusCode = http_client->responseStatusCode();

if(statusCode != 200) {
DEBUG_VERBOSE("OTA ERROR: get response on \"%s\" returned status %d", OTACloudProcessInterface::context->url, statusCode);
DEBUG_ERROR("OTA ERROR: GET response on \"%s\" returned status %d", OTACloudProcessInterface::context->url, statusCode);
return HttpResponseFail;
}

// The following call is required to save the header value , keep it
// The following call is required to save the header value (keep it)
if(http_client->contentLength() == HttpClient::kNoContentLengthHeader) {
DEBUG_VERBOSE("OTA ERROR: the response header doesn't contain \"ContentLength\" field");
DEBUG_ERROR("OTA ERROR: The response header doesn't contain \"ContentLength\" field");
return HttpHeaderErrorFail;
}

Expand Down Expand Up @@ -107,15 +109,15 @@ OTACloudProcessInterface::State OTADefaultCloudProcessInterface::fetch() {
http_res = http_client->read(context->buffer, context->buf_len);

if(http_res < 0) {
DEBUG_VERBOSE("OTA ERROR: Download read error %d", http_res);
DEBUG_ERROR("OTA ERROR: Download read error %d", http_res);
res = OtaDownloadFail;
goto exit;
}

parseOta(context->buffer, http_res);

if(context->writeError) {
DEBUG_VERBOSE("OTA ERROR: File write error");
DEBUG_ERROR("OTA ERROR: File write error");
res = ErrorWriteUpdateFileFail;
goto exit;
}
Expand All @@ -130,17 +132,17 @@ OTACloudProcessInterface::State OTADefaultCloudProcessInterface::fetch() {
// validate CRC
context->calculatedCrc32 ^= 0xFFFFFFFF; // finalize CRC
if(context->header.header.crc32 == context->calculatedCrc32) {
DEBUG_VERBOSE("Ota download completed successfully");
DEBUG_DEBUG("OTADefaultCloudProcessInterface::%s OTA download completed successfully", __FUNCTION__);
res = FlashOTA;
} else {
res = OtaHeaderCrcFail;
}
} else if(context->downloadState == OtaDownloadError) {
DEBUG_VERBOSE("OTA ERROR: OtaDownloadError");
DEBUG_ERROR("OTA ERROR: OtaDownloadError");

res = OtaDownloadFail;
} else if(context->downloadState == OtaDownloadMagicNumberMismatch) {
DEBUG_VERBOSE("OTA ERROR: Magic number mismatch");
DEBUG_ERROR("OTA ERROR: Magic number mismatch");
res = OtaHeaderMagicNumberFail;
}

Expand Down Expand Up @@ -196,7 +198,7 @@ void OTADefaultCloudProcessInterface::parseOta(uint8_t* buffer, size_t buf_len)
context->downloadedSize += (cursor-buffer);

if((millis() - context->lastReportTime) > 10000) { // Report the download progress each X millisecond
DEBUG_VERBOSE("OTA Download Progress %d/%d", context->downloadedSize, contentLength);
DEBUG_VERBOSE("OTADefaultCloudProcessInterface::%s [%d] OTA Download Progress %d/%d", __FUNCTION__, ::millis(), context->downloadedSize, contentLength);

reportStatus(context->downloadedSize);
context->lastReportTime = millis();
Expand Down
2 changes: 1 addition & 1 deletion src/ota/interface/OTAInterfaceDefault.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

#include <AIoTC_Config.h>

#if OTA_ENABLED && ! defined(OFFLOADED_DOWNLOAD)
#if OTA_ENABLED && ! defined(OFFLOADED_DOWNLOAD) && ! defined(HAS_NOTECARD)
#include <Arduino.h>

#include <ArduinoHttpClient.h>
Expand Down
Loading
Loading