From cc0d3504b155c6ccb20efce1c39e2690535f6f27 Mon Sep 17 00:00:00 2001 From: pennam Date: Mon, 9 Dec 2024 17:22:39 +0100 Subject: [PATCH 01/18] OTA: rename buf_len to bufLen --- src/ota/interface/OTAInterfaceDefault.cpp | 10 +++++----- src/ota/interface/OTAInterfaceDefault.h | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/ota/interface/OTAInterfaceDefault.cpp b/src/ota/interface/OTAInterfaceDefault.cpp index 82bfd9e8..c43963b5 100644 --- a/src/ota/interface/OTAInterfaceDefault.cpp +++ b/src/ota/interface/OTAInterfaceDefault.cpp @@ -104,7 +104,7 @@ OTACloudProcessInterface::State OTADefaultCloudProcessInterface::fetch() { continue; } - http_res = http_client->read(context->buffer, context->buf_len); + http_res = http_client->read(context->buffer, context->bufLen); if(http_res < 0) { DEBUG_VERBOSE("OTA ERROR: Download read error %d", http_res); @@ -153,13 +153,13 @@ OTACloudProcessInterface::State OTADefaultCloudProcessInterface::fetch() { return res; } -void OTADefaultCloudProcessInterface::parseOta(uint8_t* buffer, size_t buf_len) { +void OTADefaultCloudProcessInterface::parseOta(uint8_t* buffer, size_t bufLen) { assert(context != nullptr); // This should never fail - for(uint8_t* cursor=(uint8_t*)buffer; cursordownloadState) { case OtaDownloadHeader: { - const uint32_t headerLeft = context->headerCopiedBytes + buf_len <= sizeof(context->header.buf) ? buf_len : sizeof(context->header.buf) - context->headerCopiedBytes; + const uint32_t headerLeft = context->headerCopiedBytes + bufLen <= sizeof(context->header.buf) ? bufLen : sizeof(context->header.buf) - context->headerCopiedBytes; memcpy(context->header.buf+context->headerCopiedBytes, buffer, headerLeft); cursor += headerLeft; context->headerCopiedBytes += headerLeft; @@ -185,7 +185,7 @@ void OTADefaultCloudProcessInterface::parseOta(uint8_t* buffer, size_t buf_len) } case OtaDownloadFile: { const uint32_t contentLength = http_client->contentLength(); - const uint32_t dataLeft = buf_len - (cursor-buffer); + const uint32_t dataLeft = bufLen - (cursor-buffer); context->decoder.decompress(cursor, dataLeft); // TODO verify return value context->calculatedCrc32 = crc_update( diff --git a/src/ota/interface/OTAInterfaceDefault.h b/src/ota/interface/OTAInterfaceDefault.h index 95384817..62dba34a 100644 --- a/src/ota/interface/OTAInterfaceDefault.h +++ b/src/ota/interface/OTAInterfaceDefault.h @@ -42,7 +42,7 @@ class OTADefaultCloudProcessInterface: public OTACloudProcessInterface { virtual int writeFlash(uint8_t* const buffer, size_t len) = 0; private: - void parseOta(uint8_t* buffer, size_t buf_len); + void parseOta(uint8_t* buffer, size_t bufLen); Client* client; HttpClient* http_client; @@ -79,7 +79,7 @@ class OTADefaultCloudProcessInterface: public OTACloudProcessInterface { // LZSS decoder LZSSDecoder decoder; - const size_t buf_len = 64; + const size_t bufLen = 64; uint8_t buffer[64]; } *context; }; From 51e6568ceaa300cc0741d7ba7d85efa295846b3d Mon Sep 17 00:00:00 2001 From: pennam Date: Mon, 9 Dec 2024 17:28:33 +0100 Subject: [PATCH 02/18] OTA: add context contentLength --- src/ota/interface/OTAInterfaceDefault.cpp | 12 +++++++----- src/ota/interface/OTAInterfaceDefault.h | 1 + 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/ota/interface/OTAInterfaceDefault.cpp b/src/ota/interface/OTAInterfaceDefault.cpp index c43963b5..335e031c 100644 --- a/src/ota/interface/OTAInterfaceDefault.cpp +++ b/src/ota/interface/OTAInterfaceDefault.cpp @@ -76,8 +76,10 @@ OTACloudProcessInterface::State OTADefaultCloudProcessInterface::startOTA() { return HttpResponseFail; } + context->contentLength = http_client->contentLength(); + // The following call is required to save the header value , keep it - if(http_client->contentLength() == HttpClient::kNoContentLengthHeader) { + if(context->contentLength == HttpClient::kNoContentLengthHeader) { DEBUG_VERBOSE("OTA ERROR: the response header doesn't contain \"ContentLength\" field"); return HttpHeaderErrorFail; } @@ -184,7 +186,6 @@ void OTADefaultCloudProcessInterface::parseOta(uint8_t* buffer, size_t bufLen) { break; } case OtaDownloadFile: { - const uint32_t contentLength = http_client->contentLength(); const uint32_t dataLeft = bufLen - (cursor-buffer); context->decoder.decompress(cursor, dataLeft); // TODO verify return value @@ -198,18 +199,18 @@ void OTADefaultCloudProcessInterface::parseOta(uint8_t* buffer, size_t bufLen) { context->downloadedSize += dataLeft; if((millis() - context->lastReportTime) > 10000) { // Report the download progress each X millisecond - DEBUG_VERBOSE("OTA Download Progress %d/%d", context->downloadedSize, contentLength); + DEBUG_VERBOSE("OTA Download Progress %d/%d", context->downloadedSize, context->contentLength); reportStatus(context->downloadedSize); context->lastReportTime = millis(); } // TODO there should be no more bytes available when the download is completed - if(context->downloadedSize == contentLength) { + if(context->downloadedSize == context->contentLength) { context->downloadState = OtaDownloadCompleted; } - if(context->downloadedSize > contentLength) { + if(context->downloadedSize > context->contentLength) { context->downloadState = OtaDownloadError; } // TODO fail if we exceed a timeout? and available is 0 (client is broken) @@ -250,6 +251,7 @@ OTADefaultCloudProcessInterface::Context::Context( , headerCopiedBytes(0) , downloadedSize(0) , lastReportTime(0) + , contentLength(0) , writeError(false) , decoder(putc) { } diff --git a/src/ota/interface/OTAInterfaceDefault.h b/src/ota/interface/OTAInterfaceDefault.h index 62dba34a..41fd1cc4 100644 --- a/src/ota/interface/OTAInterfaceDefault.h +++ b/src/ota/interface/OTAInterfaceDefault.h @@ -74,6 +74,7 @@ class OTADefaultCloudProcessInterface: public OTACloudProcessInterface { uint32_t headerCopiedBytes; uint32_t downloadedSize; uint32_t lastReportTime; + uint32_t contentLength; bool writeError; // LZSS decoder From 1f6dc8abc0915126d39cac2172aa204ec7f90930 Mon Sep 17 00:00:00 2001 From: pennam Date: Mon, 9 Dec 2024 18:02:46 +0100 Subject: [PATCH 03/18] OTA: create fetchTime() and fetchChunk() --- src/ota/interface/OTAInterfaceDefault.cpp | 12 ++++++++++++ src/ota/interface/OTAInterfaceDefault.h | 2 ++ 2 files changed, 14 insertions(+) diff --git a/src/ota/interface/OTAInterfaceDefault.cpp b/src/ota/interface/OTAInterfaceDefault.cpp index 335e031c..53148922 100644 --- a/src/ota/interface/OTAInterfaceDefault.cpp +++ b/src/ota/interface/OTAInterfaceDefault.cpp @@ -90,6 +90,18 @@ OTACloudProcessInterface::State OTADefaultCloudProcessInterface::startOTA() { } OTACloudProcessInterface::State OTADefaultCloudProcessInterface::fetch() { + if(downloadTime > 0) { + return fetchTime(); + } else { + return fetchChunk(); + } +} + +OTACloudProcessInterface::State OTADefaultCloudProcessInterface::fetchChunk() { + return OtaDownloadFail; +} + +OTACloudProcessInterface::State OTADefaultCloudProcessInterface::fetchTime() { OTACloudProcessInterface::State res = Fetch; int http_res = 0; uint32_t start = millis(); diff --git a/src/ota/interface/OTAInterfaceDefault.h b/src/ota/interface/OTAInterfaceDefault.h index 41fd1cc4..cec37ad4 100644 --- a/src/ota/interface/OTAInterfaceDefault.h +++ b/src/ota/interface/OTAInterfaceDefault.h @@ -43,6 +43,8 @@ class OTADefaultCloudProcessInterface: public OTACloudProcessInterface { private: void parseOta(uint8_t* buffer, size_t bufLen); + State fetchTime(); + State fetchChunk(); Client* client; HttpClient* http_client; From ce3e5afad558107450b3e01f35e6bacee999999a Mon Sep 17 00:00:00 2001 From: pennam Date: Tue, 10 Dec 2024 10:31:38 +0100 Subject: [PATCH 04/18] OTA: implement fetchChunk --- src/ota/interface/OTAInterfaceDefault.cpp | 109 +++++++++++++++++++++- src/ota/interface/OTAInterfaceDefault.h | 3 + 2 files changed, 111 insertions(+), 1 deletion(-) diff --git a/src/ota/interface/OTAInterfaceDefault.cpp b/src/ota/interface/OTAInterfaceDefault.cpp index 53148922..0d7d7ff4 100644 --- a/src/ota/interface/OTAInterfaceDefault.cpp +++ b/src/ota/interface/OTAInterfaceDefault.cpp @@ -98,7 +98,113 @@ OTACloudProcessInterface::State OTADefaultCloudProcessInterface::fetch() { } OTACloudProcessInterface::State OTADefaultCloudProcessInterface::fetchChunk() { - return OtaDownloadFail; + OTACloudProcessInterface::State res = Fetch; + int http_res = 0; + uint32_t start = millis(); + char range[128] = {0}; + + /* stop connected client */ + http_client->stop(); + + /* request chunk */ + http_client->beginRequest(); + http_res = http_client->get(context->parsed_url.path()); + + if(username != nullptr && password != nullptr) { + http_client->sendBasicAuth(username, password); + } + + size_t rangeSize = context->downloadedSize + context->maxChunkSize > context->contentLength ? context->contentLength - context->downloadedSize : context->maxChunkSize; + sprintf(range, "bytes=%d-%d", context->downloadedSize, context->downloadedSize + rangeSize); + DEBUG_VERBOSE("OTA downloading range: %s", range); + http_client->sendHeader("Range", range); + http_client->endRequest(); + + if(http_res == HTTP_ERROR_CONNECTION_FAILED) { + DEBUG_VERBOSE("OTA ERROR: http client error connecting to server \"%s:%d\"", + context->parsed_url.host(), context->parsed_url.port()); + return ServerConnectErrorFail; + } else if(http_res == HTTP_ERROR_TIMED_OUT) { + DEBUG_VERBOSE("OTA ERROR: http client timeout \"%s\"", OTACloudProcessInterface::context->url); + return OtaHeaderTimeoutFail; + } else if(http_res != HTTP_SUCCESS) { + DEBUG_VERBOSE("OTA ERROR: http client returned %d on get \"%s\"", res, OTACloudProcessInterface::context->url); + return OtaDownloadFail; + } + + int statusCode = http_client->responseStatusCode(); + + if(statusCode != 206) { + DEBUG_VERBOSE("OTA ERROR: get response on \"%s\" returned status %d", OTACloudProcessInterface::context->url, statusCode); + return HttpResponseFail; + } + + http_client->skipResponseHeaders(); + + /* download chunk */ + context->downloadedChunkSize = 0; + do { + if(!http_client->connected()) { + res = OtaDownloadFail; + goto exit; + } + + if(http_client->available() == 0) { + /* Avoid tight loop and allow yield */ + delay(1); + continue; + } + + http_res = http_client->read(context->buffer, context->bufLen); + + if(http_res < 0) { + DEBUG_VERBOSE("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"); + res = ErrorWriteUpdateFileFail; + goto exit; + } + + context->downloadedChunkSize += http_res; + + } while((context->downloadState == OtaDownloadFile || context->downloadState == OtaDownloadHeader) && + (context->downloadedChunkSize < rangeSize)); + + // TODO verify that the information present in the ota header match the info in context + if(context->downloadState == OtaDownloadCompleted) { + // Verify that the downloaded file size is matching the expected size ?? + // this could distinguish between consistency of the downloaded bytes and filesize + + // validate CRC + context->calculatedCrc32 ^= 0xFFFFFFFF; // finalize CRC + if(context->header.header.crc32 == context->calculatedCrc32) { + DEBUG_VERBOSE("Ota download completed successfully"); + res = FlashOTA; + } else { + res = OtaHeaderCrcFail; + } + } else if(context->downloadState == OtaDownloadError) { + DEBUG_VERBOSE("OTA ERROR: OtaDownloadError"); + + res = OtaDownloadFail; + } else if(context->downloadState == OtaDownloadMagicNumberMismatch) { + DEBUG_VERBOSE("OTA ERROR: Magic number mismatch"); + res = OtaHeaderMagicNumberFail; + } + +exit: + if(res != Fetch) { + http_client->stop(); // close the connection + delete http_client; + http_client = nullptr; + } + return res; } OTACloudProcessInterface::State OTADefaultCloudProcessInterface::fetchTime() { @@ -265,6 +371,7 @@ OTADefaultCloudProcessInterface::Context::Context( , lastReportTime(0) , contentLength(0) , writeError(false) + , downloadedChunkSize(0) , decoder(putc) { } static const uint32_t crc_table[256] = { diff --git a/src/ota/interface/OTAInterfaceDefault.h b/src/ota/interface/OTAInterfaceDefault.h index cec37ad4..ae4f808f 100644 --- a/src/ota/interface/OTAInterfaceDefault.h +++ b/src/ota/interface/OTAInterfaceDefault.h @@ -79,6 +79,9 @@ class OTADefaultCloudProcessInterface: public OTACloudProcessInterface { uint32_t contentLength; bool writeError; + uint32_t downloadedChunkSize; + static constexpr size_t maxChunkSize = 1024 * 10; + // LZSS decoder LZSSDecoder decoder; From 7e89f55764d55d2674aeb4a95cb1be43e7bcf75d Mon Sep 17 00:00:00 2001 From: pennam Date: Tue, 10 Dec 2024 12:21:17 +0100 Subject: [PATCH 05/18] OTA: add setFetchmode --- src/ArduinoIoTCloudTCP.cpp | 3 +++ src/ota/interface/OTAInterfaceDefault.cpp | 4 +++- src/ota/interface/OTAInterfaceDefault.h | 8 ++++++++ 3 files changed, 14 insertions(+), 1 deletion(-) diff --git a/src/ArduinoIoTCloudTCP.cpp b/src/ArduinoIoTCloudTCP.cpp index 121e2632..6a49e867 100644 --- a/src/ArduinoIoTCloudTCP.cpp +++ b/src/ArduinoIoTCloudTCP.cpp @@ -168,6 +168,9 @@ int ArduinoIoTCloudTCP::begin(bool const enable_watchdog, String brokerAddress, #if OTA_ENABLED && !defined(OFFLOADED_DOWNLOAD) _ota.setClient(&_otaClient); + if (_connection->getInterface() == NetworkAdapter::ETHERNET) { + _ota.setFetchMode(OTADefaultCloudProcessInterface::OtaFetchChunk); + } #endif // OTA_ENABLED && !defined(OFFLOADED_DOWNLOAD) #if OTA_ENABLED && defined(OTA_BASIC_AUTH) diff --git a/src/ota/interface/OTAInterfaceDefault.cpp b/src/ota/interface/OTAInterfaceDefault.cpp index 0d7d7ff4..e18461c2 100644 --- a/src/ota/interface/OTAInterfaceDefault.cpp +++ b/src/ota/interface/OTAInterfaceDefault.cpp @@ -20,6 +20,7 @@ OTADefaultCloudProcessInterface::OTADefaultCloudProcessInterface(MessageStream * , client(client) , http_client(nullptr) , username(nullptr), password(nullptr) +, fetchMode(OtaFetchTime) , context(nullptr) { } @@ -85,12 +86,13 @@ OTACloudProcessInterface::State OTADefaultCloudProcessInterface::startOTA() { } context->lastReportTime = millis(); + DEBUG_VERBOSE("OTA file length: %d", context->contentLength); return Fetch; } OTACloudProcessInterface::State OTADefaultCloudProcessInterface::fetch() { - if(downloadTime > 0) { + if(fetchMode == OtaFetchTime) { return fetchTime(); } else { return fetchChunk(); diff --git a/src/ota/interface/OTAInterfaceDefault.h b/src/ota/interface/OTAInterfaceDefault.h index ae4f808f..aa441148 100644 --- a/src/ota/interface/OTAInterfaceDefault.h +++ b/src/ota/interface/OTAInterfaceDefault.h @@ -35,6 +35,13 @@ class OTADefaultCloudProcessInterface: public OTACloudProcessInterface { this->password = password; } + enum OTAFetchMode: uint8_t { + OtaFetchTime, + OtaFetchChunk + }; + + inline virtual void setFetchMode(OTAFetchMode mode) { this->fetchMode = mode; } + protected: State startOTA(); State fetch(); @@ -50,6 +57,7 @@ class OTADefaultCloudProcessInterface: public OTACloudProcessInterface { HttpClient* http_client; const char *username, *password; + OTAFetchMode fetchMode; // The amount of time that each iteration of Fetch has to take at least // This mitigate the issues arising from tasks run in main loop that are using all the computing time From 74b1f1765851150c7da4b3759e38e7f99486d6c6 Mon Sep 17 00:00:00 2001 From: pennam Date: Wed, 11 Dec 2024 08:42:40 +0100 Subject: [PATCH 06/18] OTA: chunked/timed download, improve code reuse --- src/ota/interface/OTAInterfaceDefault.cpp | 148 +++++++--------------- src/ota/interface/OTAInterfaceDefault.h | 8 +- 2 files changed, 53 insertions(+), 103 deletions(-) diff --git a/src/ota/interface/OTAInterfaceDefault.cpp b/src/ota/interface/OTAInterfaceDefault.cpp index e18461c2..f2ab5380 100644 --- a/src/ota/interface/OTAInterfaceDefault.cpp +++ b/src/ota/interface/OTAInterfaceDefault.cpp @@ -92,59 +92,20 @@ OTACloudProcessInterface::State OTADefaultCloudProcessInterface::startOTA() { } OTACloudProcessInterface::State OTADefaultCloudProcessInterface::fetch() { - if(fetchMode == OtaFetchTime) { - return fetchTime(); - } else { - return fetchChunk(); - } -} - -OTACloudProcessInterface::State OTADefaultCloudProcessInterface::fetchChunk() { OTACloudProcessInterface::State res = Fetch; - int http_res = 0; - uint32_t start = millis(); - char range[128] = {0}; - - /* stop connected client */ - http_client->stop(); - - /* request chunk */ - http_client->beginRequest(); - http_res = http_client->get(context->parsed_url.path()); - if(username != nullptr && password != nullptr) { - http_client->sendBasicAuth(username, password); + if(fetchMode == OtaFetchChunk) { + res = requestChunk(); } - size_t rangeSize = context->downloadedSize + context->maxChunkSize > context->contentLength ? context->contentLength - context->downloadedSize : context->maxChunkSize; - sprintf(range, "bytes=%d-%d", context->downloadedSize, context->downloadedSize + rangeSize); - DEBUG_VERBOSE("OTA downloading range: %s", range); - http_client->sendHeader("Range", range); - http_client->endRequest(); - - if(http_res == HTTP_ERROR_CONNECTION_FAILED) { - DEBUG_VERBOSE("OTA ERROR: http client error connecting to server \"%s:%d\"", - context->parsed_url.host(), context->parsed_url.port()); - return ServerConnectErrorFail; - } else if(http_res == HTTP_ERROR_TIMED_OUT) { - DEBUG_VERBOSE("OTA ERROR: http client timeout \"%s\"", OTACloudProcessInterface::context->url); - return OtaHeaderTimeoutFail; - } else if(http_res != HTTP_SUCCESS) { - DEBUG_VERBOSE("OTA ERROR: http client returned %d on get \"%s\"", res, OTACloudProcessInterface::context->url); - return OtaDownloadFail; - } - - int statusCode = http_client->responseStatusCode(); + context->downloadedChunkSize = 0; + context->downloadedChunkStartTime = millis(); - if(statusCode != 206) { - DEBUG_VERBOSE("OTA ERROR: get response on \"%s\" returned status %d", OTACloudProcessInterface::context->url, statusCode); - return HttpResponseFail; + if(res != Fetch) { + goto exit; } - http_client->skipResponseHeaders(); - - /* download chunk */ - context->downloadedChunkSize = 0; + /* download chunked or timed */ do { if(!http_client->connected()) { res = OtaDownloadFail; @@ -157,7 +118,7 @@ OTACloudProcessInterface::State OTADefaultCloudProcessInterface::fetchChunk() { continue; } - http_res = http_client->read(context->buffer, context->bufLen); + int http_res = http_client->read(context->buffer, context->bufLen); if(http_res < 0) { DEBUG_VERBOSE("OTA ERROR: Download read error %d", http_res); @@ -175,8 +136,7 @@ OTACloudProcessInterface::State OTADefaultCloudProcessInterface::fetchChunk() { context->downloadedChunkSize += http_res; - } while((context->downloadState == OtaDownloadFile || context->downloadState == OtaDownloadHeader) && - (context->downloadedChunkSize < rangeSize)); + } while(context->downloadState < OtaDownloadCompleted && fetchMore()); // TODO verify that the information present in the ota header match the info in context if(context->downloadState == OtaDownloadCompleted) { @@ -209,70 +169,58 @@ OTACloudProcessInterface::State OTADefaultCloudProcessInterface::fetchChunk() { return res; } -OTACloudProcessInterface::State OTADefaultCloudProcessInterface::fetchTime() { - OTACloudProcessInterface::State res = Fetch; +OTACloudProcessInterface::State OTADefaultCloudProcessInterface::requestChunk() { int http_res = 0; uint32_t start = millis(); + char range[128] = {0}; - do { - if(!http_client->connected()) { - res = OtaDownloadFail; - goto exit; - } + /* stop connected client */ + http_client->stop(); - if(http_client->available() == 0) { - /* Avoid tight loop and allow yield */ - delay(1); - continue; - } + /* request chunk */ + http_client->beginRequest(); + http_res = http_client->get(context->parsed_url.path()); - http_res = http_client->read(context->buffer, context->bufLen); + if(username != nullptr && password != nullptr) { + http_client->sendBasicAuth(username, password); + } - if(http_res < 0) { - DEBUG_VERBOSE("OTA ERROR: Download read error %d", http_res); - res = OtaDownloadFail; - goto exit; - } + size_t rangeSize = context->downloadedSize + maxChunkSize > context->contentLength ? context->contentLength - context->downloadedSize : maxChunkSize; + sprintf(range, "bytes=%d-%d", context->downloadedSize, context->downloadedSize + rangeSize); + DEBUG_VERBOSE("OTA downloading range: %s", range); + http_client->sendHeader("Range", range); + http_client->endRequest(); - parseOta(context->buffer, http_res); + if(http_res == HTTP_ERROR_CONNECTION_FAILED) { + DEBUG_VERBOSE("OTA ERROR: http client error connecting to server \"%s:%d\"", + context->parsed_url.host(), context->parsed_url.port()); + return ServerConnectErrorFail; + } else if(http_res == HTTP_ERROR_TIMED_OUT) { + DEBUG_VERBOSE("OTA ERROR: http client timeout \"%s\"", OTACloudProcessInterface::context->url); + return OtaHeaderTimeoutFail; + } else if(http_res != HTTP_SUCCESS) { + DEBUG_VERBOSE("OTA ERROR: http client returned %d on get \"%s\"", http_res, OTACloudProcessInterface::context->url); + return OtaDownloadFail; + } - if(context->writeError) { - DEBUG_VERBOSE("OTA ERROR: File write error"); - res = ErrorWriteUpdateFileFail; - goto exit; - } - } while((context->downloadState == OtaDownloadFile || context->downloadState == OtaDownloadHeader) && - millis() - start < downloadTime); + int statusCode = http_client->responseStatusCode(); - // TODO verify that the information present in the ota header match the info in context - if(context->downloadState == OtaDownloadCompleted) { - // Verify that the downloaded file size is matching the expected size ?? - // this could distinguish between consistency of the downloaded bytes and filesize + if(statusCode != 206) { + DEBUG_VERBOSE("OTA ERROR: get response on \"%s\" returned status %d", OTACloudProcessInterface::context->url, statusCode); + return HttpResponseFail; + } - // validate CRC - context->calculatedCrc32 ^= 0xFFFFFFFF; // finalize CRC - if(context->header.header.crc32 == context->calculatedCrc32) { - DEBUG_VERBOSE("Ota download completed successfully"); - res = FlashOTA; - } else { - res = OtaHeaderCrcFail; - } - } else if(context->downloadState == OtaDownloadError) { - DEBUG_VERBOSE("OTA ERROR: OtaDownloadError"); + http_client->skipResponseHeaders(); - res = OtaDownloadFail; - } else if(context->downloadState == OtaDownloadMagicNumberMismatch) { - DEBUG_VERBOSE("OTA ERROR: Magic number mismatch"); - res = OtaHeaderMagicNumberFail; - } + return Fetch; +} -exit: - if(res != Fetch) { - http_client->stop(); // close the connection - delete http_client; - http_client = nullptr; +bool OTADefaultCloudProcessInterface::fetchMore() { + if (fetchMode == OtaFetchChunk) { + return context->downloadedChunkSize < maxChunkSize; + } else { + return (millis() - context->downloadedChunkStartTime) < downloadTime; } - return res; } void OTADefaultCloudProcessInterface::parseOta(uint8_t* buffer, size_t bufLen) { diff --git a/src/ota/interface/OTAInterfaceDefault.h b/src/ota/interface/OTAInterfaceDefault.h index aa441148..d58616a6 100644 --- a/src/ota/interface/OTAInterfaceDefault.h +++ b/src/ota/interface/OTAInterfaceDefault.h @@ -50,8 +50,8 @@ class OTADefaultCloudProcessInterface: public OTACloudProcessInterface { private: void parseOta(uint8_t* buffer, size_t bufLen); - State fetchTime(); - State fetchChunk(); + State requestChunk(); + bool fetchMore(); Client* client; HttpClient* http_client; @@ -63,6 +63,8 @@ class OTADefaultCloudProcessInterface: public OTACloudProcessInterface { // This mitigate the issues arising from tasks run in main loop that are using all the computing time static constexpr uint32_t downloadTime = 2000; + static constexpr size_t maxChunkSize = 1024 * 10; + enum OTADownloadState: uint8_t { OtaDownloadHeader, OtaDownloadFile, @@ -87,8 +89,8 @@ class OTADefaultCloudProcessInterface: public OTACloudProcessInterface { uint32_t contentLength; bool writeError; + uint32_t downloadedChunkStartTime; uint32_t downloadedChunkSize; - static constexpr size_t maxChunkSize = 1024 * 10; // LZSS decoder LZSSDecoder decoder; From 3b4265b2335bf9cf6d783b2a05b20845ee7d3fdf Mon Sep 17 00:00:00 2001 From: pennam Date: Wed, 11 Dec 2024 09:41:35 +0100 Subject: [PATCH 07/18] OTA: rename requestChunk to requestOta and allow reusing --- src/ota/interface/OTAInterfaceDefault.cpp | 55 +++++++---------------- src/ota/interface/OTAInterfaceDefault.h | 2 +- 2 files changed, 16 insertions(+), 41 deletions(-) diff --git a/src/ota/interface/OTAInterfaceDefault.cpp b/src/ota/interface/OTAInterfaceDefault.cpp index f2ab5380..041d0c7e 100644 --- a/src/ota/interface/OTAInterfaceDefault.cpp +++ b/src/ota/interface/OTAInterfaceDefault.cpp @@ -42,44 +42,18 @@ OTACloudProcessInterface::State OTADefaultCloudProcessInterface::startOTA() { } ); - // make the http get request + // check url if(strcmp(context->parsed_url.schema(), "https") == 0) { http_client = new HttpClient(*client, context->parsed_url.host(), context->parsed_url.port()); } else { return UrlParseErrorFail; } - http_client->beginRequest(); - auto res = http_client->get(context->parsed_url.path()); - - if(username != nullptr && password != nullptr) { - http_client->sendBasicAuth(username, password); - } - - http_client->endRequest(); - - if(res == HTTP_ERROR_CONNECTION_FAILED) { - DEBUG_VERBOSE("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); - return OtaHeaderTimeoutFail; - } else if(res != HTTP_SUCCESS) { - DEBUG_VERBOSE("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); - return HttpResponseFail; - } - - context->contentLength = http_client->contentLength(); + // make the http get request + requestOta(OtaFetchTime); // The following call is required to save the header value , keep it + context->contentLength = http_client->contentLength(); if(context->contentLength == HttpClient::kNoContentLengthHeader) { DEBUG_VERBOSE("OTA ERROR: the response header doesn't contain \"ContentLength\" field"); return HttpHeaderErrorFail; @@ -87,7 +61,6 @@ OTACloudProcessInterface::State OTADefaultCloudProcessInterface::startOTA() { context->lastReportTime = millis(); DEBUG_VERBOSE("OTA file length: %d", context->contentLength); - return Fetch; } @@ -95,7 +68,7 @@ OTACloudProcessInterface::State OTADefaultCloudProcessInterface::fetch() { OTACloudProcessInterface::State res = Fetch; if(fetchMode == OtaFetchChunk) { - res = requestChunk(); + res = requestOta(OtaFetchChunk); } context->downloadedChunkSize = 0; @@ -169,10 +142,8 @@ OTACloudProcessInterface::State OTADefaultCloudProcessInterface::fetch() { return res; } -OTACloudProcessInterface::State OTADefaultCloudProcessInterface::requestChunk() { +OTACloudProcessInterface::State OTADefaultCloudProcessInterface::requestOta(OTAFetchMode mode) { int http_res = 0; - uint32_t start = millis(); - char range[128] = {0}; /* stop connected client */ http_client->stop(); @@ -185,10 +156,14 @@ OTACloudProcessInterface::State OTADefaultCloudProcessInterface::requestChunk() http_client->sendBasicAuth(username, password); } - size_t rangeSize = context->downloadedSize + maxChunkSize > context->contentLength ? context->contentLength - context->downloadedSize : maxChunkSize; - sprintf(range, "bytes=%d-%d", context->downloadedSize, context->downloadedSize + rangeSize); - DEBUG_VERBOSE("OTA downloading range: %s", range); - http_client->sendHeader("Range", range); + if(mode == OtaFetchChunk) { + char range[128] = {0}; + size_t rangeSize = context->downloadedSize + maxChunkSize > context->contentLength ? context->contentLength - context->downloadedSize : maxChunkSize; + sprintf(range, "bytes=%d-%d", context->downloadedSize, context->downloadedSize + rangeSize); + DEBUG_VERBOSE("OTA downloading range: %s", range); + http_client->sendHeader("Range", range); + } + http_client->endRequest(); if(http_res == HTTP_ERROR_CONNECTION_FAILED) { @@ -205,7 +180,7 @@ OTACloudProcessInterface::State OTADefaultCloudProcessInterface::requestChunk() int statusCode = http_client->responseStatusCode(); - if(statusCode != 206) { + if(((mode == OtaFetchChunk) && (statusCode != 206)) || ((mode == OtaFetchTime) && (statusCode != 200))) { DEBUG_VERBOSE("OTA ERROR: get response on \"%s\" returned status %d", OTACloudProcessInterface::context->url, statusCode); return HttpResponseFail; } diff --git a/src/ota/interface/OTAInterfaceDefault.h b/src/ota/interface/OTAInterfaceDefault.h index d58616a6..07ea94af 100644 --- a/src/ota/interface/OTAInterfaceDefault.h +++ b/src/ota/interface/OTAInterfaceDefault.h @@ -50,7 +50,7 @@ class OTADefaultCloudProcessInterface: public OTACloudProcessInterface { private: void parseOta(uint8_t* buffer, size_t bufLen); - State requestChunk(); + State requestOta(OTAFetchMode mode); bool fetchMore(); Client* client; From 89dddf7695485a766b54a4f481f35074e3411e37 Mon Sep 17 00:00:00 2001 From: pennam Date: Wed, 11 Dec 2024 15:25:28 +0100 Subject: [PATCH 08/18] OTA: handle requestOta return value --- src/ota/interface/OTAInterfaceDefault.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/ota/interface/OTAInterfaceDefault.cpp b/src/ota/interface/OTAInterfaceDefault.cpp index 041d0c7e..55303381 100644 --- a/src/ota/interface/OTAInterfaceDefault.cpp +++ b/src/ota/interface/OTAInterfaceDefault.cpp @@ -50,7 +50,10 @@ OTACloudProcessInterface::State OTADefaultCloudProcessInterface::startOTA() { } // make the http get request - requestOta(OtaFetchTime); + OTACloudProcessInterface::State res = requestOta(OtaFetchTime); + if(res != Fetch) { + return res; + } // The following call is required to save the header value , keep it context->contentLength = http_client->contentLength(); From fd0dd1f7739d8844f8cc6f3500e69332b61164e2 Mon Sep 17 00:00:00 2001 From: pennam Date: Thu, 12 Dec 2024 09:08:22 +0100 Subject: [PATCH 09/18] OTA: add setOTAChunkMode() --- src/ArduinoIoTCloudTCP.cpp | 3 --- src/ArduinoIoTCloudTCP.h | 9 +++++++++ 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/ArduinoIoTCloudTCP.cpp b/src/ArduinoIoTCloudTCP.cpp index 6a49e867..121e2632 100644 --- a/src/ArduinoIoTCloudTCP.cpp +++ b/src/ArduinoIoTCloudTCP.cpp @@ -168,9 +168,6 @@ int ArduinoIoTCloudTCP::begin(bool const enable_watchdog, String brokerAddress, #if OTA_ENABLED && !defined(OFFLOADED_DOWNLOAD) _ota.setClient(&_otaClient); - if (_connection->getInterface() == NetworkAdapter::ETHERNET) { - _ota.setFetchMode(OTADefaultCloudProcessInterface::OtaFetchChunk); - } #endif // OTA_ENABLED && !defined(OFFLOADED_DOWNLOAD) #if OTA_ENABLED && defined(OTA_BASIC_AUTH) diff --git a/src/ArduinoIoTCloudTCP.h b/src/ArduinoIoTCloudTCP.h index 29dfc754..16d7fe16 100644 --- a/src/ArduinoIoTCloudTCP.h +++ b/src/ArduinoIoTCloudTCP.h @@ -101,6 +101,15 @@ class ArduinoIoTCloudTCP: public ArduinoIoTCloudClass _ota.setOtaPolicies(OTACloudProcessInterface::None); } } + + /* Slower but more reliable in some corner cases */ + void setOTAChunkMode(bool enable = true) { + if(enable) { + _ota.setFetchMode(OTADefaultCloudProcessInterface::OtaFetchChunk); + } else { + _ota.setFetchMode(OTADefaultCloudProcessInterface::OtaFetchTime); + } + } #endif private: From a5015e9e7880841b951624e50257efcce3c5930e Mon Sep 17 00:00:00 2001 From: pennam Date: Thu, 12 Dec 2024 10:01:13 +0100 Subject: [PATCH 10/18] OTA: add API to enable/disable Ota policies --- src/ota/interface/OTAInterface.h | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/ota/interface/OTAInterface.h b/src/ota/interface/OTAInterface.h index a62b7cb2..697d297a 100644 --- a/src/ota/interface/OTAInterface.h +++ b/src/ota/interface/OTAInterface.h @@ -88,9 +88,13 @@ class OTACloudProcessInterface: public CloudProcess { // virtual void hook(State s, void* action); virtual void update() { handleMessage(nullptr); } - inline void approveOta() { policies |= Approved; } + inline void approveOta() { this->policies |= Approved; } inline void setOtaPolicies(uint16_t policies) { this->policies = policies; } + inline void enableOtaPolicy(OtaFlags policyFlag) { this->policies |= policyFlag; } + inline void disableOtaPolicy(OtaFlags policyFlag) { this->policies &= ~policyFlag; } + inline bool getOtaPolicy(OtaFlags policyFlag) { return (this->policies & policyFlag) != 0;} + inline State getState() { return state; } virtual bool isOtaCapable() = 0; From ef73a653ffbae66331013a8cb881ac44f3224142 Mon Sep 17 00:00:00 2001 From: pennam Date: Thu, 12 Dec 2024 10:07:07 +0100 Subject: [PATCH 11/18] OTA: use OtaFlags to enable Chunked download mode --- src/ArduinoIoTCloudTCP.h | 4 ++-- src/ota/interface/OTAInterface.h | 3 ++- src/ota/interface/OTAInterfaceDefault.cpp | 17 ++++++++--------- src/ota/interface/OTAInterfaceDefault.h | 12 +++--------- 4 files changed, 15 insertions(+), 21 deletions(-) diff --git a/src/ArduinoIoTCloudTCP.h b/src/ArduinoIoTCloudTCP.h index 16d7fe16..78aec2cd 100644 --- a/src/ArduinoIoTCloudTCP.h +++ b/src/ArduinoIoTCloudTCP.h @@ -105,9 +105,9 @@ class ArduinoIoTCloudTCP: public ArduinoIoTCloudClass /* Slower but more reliable in some corner cases */ void setOTAChunkMode(bool enable = true) { if(enable) { - _ota.setFetchMode(OTADefaultCloudProcessInterface::OtaFetchChunk); + _ota.enableOtaPolicy(OTADefaultCloudProcessInterface::ChunkDownload); } else { - _ota.setFetchMode(OTADefaultCloudProcessInterface::OtaFetchTime); + _ota.disableOtaPolicy(OTADefaultCloudProcessInterface::ChunkDownload); } } #endif diff --git a/src/ota/interface/OTAInterface.h b/src/ota/interface/OTAInterface.h index 697d297a..d9624c3b 100644 --- a/src/ota/interface/OTAInterface.h +++ b/src/ota/interface/OTAInterface.h @@ -80,7 +80,8 @@ class OTACloudProcessInterface: public CloudProcess { enum OtaFlags: uint16_t { None = 0, ApprovalRequired = 1, - Approved = 1<<1 + Approved = 1<<1, + ChunkDownload = 1<<2 }; virtual void handleMessage(Message*); diff --git a/src/ota/interface/OTAInterfaceDefault.cpp b/src/ota/interface/OTAInterfaceDefault.cpp index 55303381..c8a51b42 100644 --- a/src/ota/interface/OTAInterfaceDefault.cpp +++ b/src/ota/interface/OTAInterfaceDefault.cpp @@ -20,7 +20,6 @@ OTADefaultCloudProcessInterface::OTADefaultCloudProcessInterface(MessageStream * , client(client) , http_client(nullptr) , username(nullptr), password(nullptr) -, fetchMode(OtaFetchTime) , context(nullptr) { } @@ -50,7 +49,7 @@ OTACloudProcessInterface::State OTADefaultCloudProcessInterface::startOTA() { } // make the http get request - OTACloudProcessInterface::State res = requestOta(OtaFetchTime); + OTACloudProcessInterface::State res = requestOta(); if(res != Fetch) { return res; } @@ -70,8 +69,8 @@ OTACloudProcessInterface::State OTADefaultCloudProcessInterface::startOTA() { OTACloudProcessInterface::State OTADefaultCloudProcessInterface::fetch() { OTACloudProcessInterface::State res = Fetch; - if(fetchMode == OtaFetchChunk) { - res = requestOta(OtaFetchChunk); + if(getOtaPolicy(ChunkDownload)) { + res = requestOta(ChunkDownload); } context->downloadedChunkSize = 0; @@ -145,7 +144,7 @@ OTACloudProcessInterface::State OTADefaultCloudProcessInterface::fetch() { return res; } -OTACloudProcessInterface::State OTADefaultCloudProcessInterface::requestOta(OTAFetchMode mode) { +OTACloudProcessInterface::State OTADefaultCloudProcessInterface::requestOta(OtaFlags mode) { int http_res = 0; /* stop connected client */ @@ -159,7 +158,7 @@ OTACloudProcessInterface::State OTADefaultCloudProcessInterface::requestOta(OTAF http_client->sendBasicAuth(username, password); } - if(mode == OtaFetchChunk) { + if((mode & ChunkDownload) == ChunkDownload) { char range[128] = {0}; size_t rangeSize = context->downloadedSize + maxChunkSize > context->contentLength ? context->contentLength - context->downloadedSize : maxChunkSize; sprintf(range, "bytes=%d-%d", context->downloadedSize, context->downloadedSize + rangeSize); @@ -183,18 +182,18 @@ OTACloudProcessInterface::State OTADefaultCloudProcessInterface::requestOta(OTAF int statusCode = http_client->responseStatusCode(); - if(((mode == OtaFetchChunk) && (statusCode != 206)) || ((mode == OtaFetchTime) && (statusCode != 200))) { + if((((mode & ChunkDownload) == ChunkDownload) && (statusCode != 206)) || + (((mode & ChunkDownload) != ChunkDownload) && (statusCode != 200))) { DEBUG_VERBOSE("OTA ERROR: get response on \"%s\" returned status %d", OTACloudProcessInterface::context->url, statusCode); return HttpResponseFail; } http_client->skipResponseHeaders(); - return Fetch; } bool OTADefaultCloudProcessInterface::fetchMore() { - if (fetchMode == OtaFetchChunk) { + if (getOtaPolicy(ChunkDownload)) { return context->downloadedChunkSize < maxChunkSize; } else { return (millis() - context->downloadedChunkStartTime) < downloadTime; diff --git a/src/ota/interface/OTAInterfaceDefault.h b/src/ota/interface/OTAInterfaceDefault.h index 07ea94af..6b432f4a 100644 --- a/src/ota/interface/OTAInterfaceDefault.h +++ b/src/ota/interface/OTAInterfaceDefault.h @@ -35,13 +35,6 @@ class OTADefaultCloudProcessInterface: public OTACloudProcessInterface { this->password = password; } - enum OTAFetchMode: uint8_t { - OtaFetchTime, - OtaFetchChunk - }; - - inline virtual void setFetchMode(OTAFetchMode mode) { this->fetchMode = mode; } - protected: State startOTA(); State fetch(); @@ -50,19 +43,20 @@ class OTADefaultCloudProcessInterface: public OTACloudProcessInterface { private: void parseOta(uint8_t* buffer, size_t bufLen); - State requestOta(OTAFetchMode mode); + State requestOta(OtaFlags mode = None); bool fetchMore(); Client* client; HttpClient* http_client; const char *username, *password; - OTAFetchMode fetchMode; // The amount of time that each iteration of Fetch has to take at least // This mitigate the issues arising from tasks run in main loop that are using all the computing time static constexpr uint32_t downloadTime = 2000; + // The amount of data that each iteration of Fetch has to take at least + // This should be enabled setting ChunkDownload OtaFlag to 1 and mitigate some Ota corner cases static constexpr size_t maxChunkSize = 1024 * 10; enum OTADownloadState: uint8_t { From bf24d449fb16d00899026e61a6061128ffcc4bc6 Mon Sep 17 00:00:00 2001 From: pennam Date: Thu, 12 Dec 2024 10:18:38 +0100 Subject: [PATCH 12/18] OTA: fix Ota flags handling for deferred Ota --- src/ArduinoIoTCloudTCP.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ArduinoIoTCloudTCP.h b/src/ArduinoIoTCloudTCP.h index 78aec2cd..67c206a9 100644 --- a/src/ArduinoIoTCloudTCP.h +++ b/src/ArduinoIoTCloudTCP.h @@ -96,9 +96,9 @@ class ArduinoIoTCloudTCP: public ArduinoIoTCloudClass _get_ota_confirmation = cb; if(_get_ota_confirmation) { - _ota.setOtaPolicies(OTACloudProcessInterface::ApprovalRequired); + _ota.enableOtaPolicy(OTACloudProcessInterface::ApprovalRequired); } else { - _ota.setOtaPolicies(OTACloudProcessInterface::None); + _ota.disableOtaPolicy(OTACloudProcessInterface::ApprovalRequired); } } From beedce283d95fca0351cdb8d7c09b1f16ddfe133 Mon Sep 17 00:00:00 2001 From: pennam Date: Thu, 12 Dec 2024 10:19:35 +0100 Subject: [PATCH 13/18] OTA: uniform handling of Ota flags --- src/ota/interface/OTAInterface.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ota/interface/OTAInterface.cpp b/src/ota/interface/OTAInterface.cpp index b659917b..e72d062d 100644 --- a/src/ota/interface/OTAInterface.cpp +++ b/src/ota/interface/OTAInterface.cpp @@ -167,10 +167,10 @@ OTACloudProcessInterface::State OTACloudProcessInterface::idle(Message* msg) { OTACloudProcessInterface::State OTACloudProcessInterface::otaAvailable() { // depending on the policy decided on this device the ota process can start immediately // or wait for confirmation from the user - if((policies & (ApprovalRequired | Approved)) == ApprovalRequired ) { + if(getOtaPolicy(ApprovalRequired) && !getOtaPolicy(Approved)) { return OtaAvailable; } else { - policies &= ~Approved; + disableOtaPolicy(Approved); return StartOTA; } // TODO add an abortOTA command? in this case delete the context } From 3cf10b469caa00d53c61f8da67ae0234e17d3537 Mon Sep 17 00:00:00 2001 From: pennam Date: Thu, 12 Dec 2024 11:25:01 +0100 Subject: [PATCH 14/18] OTA: fix sprintf warning --- src/ota/interface/OTAInterfaceDefault.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ota/interface/OTAInterfaceDefault.cpp b/src/ota/interface/OTAInterfaceDefault.cpp index c8a51b42..90cbd213 100644 --- a/src/ota/interface/OTAInterfaceDefault.cpp +++ b/src/ota/interface/OTAInterfaceDefault.cpp @@ -161,7 +161,7 @@ OTACloudProcessInterface::State OTADefaultCloudProcessInterface::requestOta(OtaF if((mode & ChunkDownload) == ChunkDownload) { char range[128] = {0}; size_t rangeSize = context->downloadedSize + maxChunkSize > context->contentLength ? context->contentLength - context->downloadedSize : maxChunkSize; - sprintf(range, "bytes=%d-%d", context->downloadedSize, context->downloadedSize + rangeSize); + sprintf(range, "bytes=%lu-%lu", context->downloadedSize, context->downloadedSize + rangeSize); DEBUG_VERBOSE("OTA downloading range: %s", range); http_client->sendHeader("Range", range); } From 087a3e9b9fb214eca888d19d5366b50efb52e093 Mon Sep 17 00:00:00 2001 From: pennam Date: Thu, 12 Dec 2024 11:24:29 +0100 Subject: [PATCH 15/18] OTA: fix content length comparison warning --- src/ota/interface/OTAInterfaceDefault.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ota/interface/OTAInterfaceDefault.cpp b/src/ota/interface/OTAInterfaceDefault.cpp index 90cbd213..97cb8257 100644 --- a/src/ota/interface/OTAInterfaceDefault.cpp +++ b/src/ota/interface/OTAInterfaceDefault.cpp @@ -55,12 +55,12 @@ OTACloudProcessInterface::State OTADefaultCloudProcessInterface::startOTA() { } // The following call is required to save the header value , keep it - context->contentLength = http_client->contentLength(); - if(context->contentLength == HttpClient::kNoContentLengthHeader) { + if(http_client->contentLength() == HttpClient::kNoContentLengthHeader) { DEBUG_VERBOSE("OTA ERROR: the response header doesn't contain \"ContentLength\" field"); return HttpHeaderErrorFail; } + context->contentLength = http_client->contentLength(); context->lastReportTime = millis(); DEBUG_VERBOSE("OTA file length: %d", context->contentLength); return Fetch; From 428cee49ca457044f9eafee854da492a4e29f43d Mon Sep 17 00:00:00 2001 From: pennam Date: Thu, 12 Dec 2024 11:26:22 +0100 Subject: [PATCH 16/18] OTA: use constexpr for buffer size --- src/ota/interface/OTAInterfaceDefault.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ota/interface/OTAInterfaceDefault.h b/src/ota/interface/OTAInterfaceDefault.h index 6b432f4a..b45c14dd 100644 --- a/src/ota/interface/OTAInterfaceDefault.h +++ b/src/ota/interface/OTAInterfaceDefault.h @@ -89,8 +89,8 @@ class OTADefaultCloudProcessInterface: public OTACloudProcessInterface { // LZSS decoder LZSSDecoder decoder; - const size_t bufLen = 64; - uint8_t buffer[64]; + static constexpr size_t bufLen = 64; + uint8_t buffer[bufLen]; } *context; }; From 8152c4b0791273f31f58b2fe0b17b3a4303cf6ab Mon Sep 17 00:00:00 2001 From: pennam Date: Thu, 12 Dec 2024 12:26:09 +0100 Subject: [PATCH 17/18] OTA: fix build with boards using offloaded Ota --- src/ArduinoIoTCloudTCP.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ArduinoIoTCloudTCP.h b/src/ArduinoIoTCloudTCP.h index 67c206a9..f1682164 100644 --- a/src/ArduinoIoTCloudTCP.h +++ b/src/ArduinoIoTCloudTCP.h @@ -105,9 +105,9 @@ class ArduinoIoTCloudTCP: public ArduinoIoTCloudClass /* Slower but more reliable in some corner cases */ void setOTAChunkMode(bool enable = true) { if(enable) { - _ota.enableOtaPolicy(OTADefaultCloudProcessInterface::ChunkDownload); + _ota.enableOtaPolicy(OTACloudProcessInterface::ChunkDownload); } else { - _ota.disableOtaPolicy(OTADefaultCloudProcessInterface::ChunkDownload); + _ota.disableOtaPolicy(OTACloudProcessInterface::ChunkDownload); } } #endif From 0f534597e60c9bb80227c3beb1d908dbac7267fc Mon Sep 17 00:00:00 2001 From: pennam Date: Thu, 12 Dec 2024 17:36:07 +0100 Subject: [PATCH 18/18] OTA: better (esp32) fix for sprintf warning --- src/ota/interface/OTAInterfaceDefault.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ota/interface/OTAInterfaceDefault.cpp b/src/ota/interface/OTAInterfaceDefault.cpp index 97cb8257..a641595b 100644 --- a/src/ota/interface/OTAInterfaceDefault.cpp +++ b/src/ota/interface/OTAInterfaceDefault.cpp @@ -161,7 +161,7 @@ OTACloudProcessInterface::State OTADefaultCloudProcessInterface::requestOta(OtaF if((mode & ChunkDownload) == ChunkDownload) { char range[128] = {0}; size_t rangeSize = context->downloadedSize + maxChunkSize > context->contentLength ? context->contentLength - context->downloadedSize : maxChunkSize; - sprintf(range, "bytes=%lu-%lu", context->downloadedSize, context->downloadedSize + rangeSize); + sprintf(range, "bytes=%" PRIu32 "-%" PRIu32, context->downloadedSize, context->downloadedSize + rangeSize); DEBUG_VERBOSE("OTA downloading range: %s", range); http_client->sendHeader("Range", range); }