From d836b8018e44f880f581913afc1606f12c8cdb66 Mon Sep 17 00:00:00 2001 From: liyashuai <liyashuai@espressif.com> Date: Tue, 3 Sep 2024 16:35:19 +0800 Subject: [PATCH 1/6] esp32: add thread border router ota function --- examples/thread-br-app/esp32/README.md | 13 + examples/thread-br-app/esp32/partitions.csv | 6 +- .../thread-br-app/esp32/sdkconfig.defaults | 25 +- .../thread-br-common/thread-br-app.matter | 172 +++++++++++++ .../thread-br-common/thread-br-app.zap | 237 ++++++++++++++++++ src/platform/ESP32/OTAImageProcessorImpl.cpp | 191 +++++++++++++- src/platform/ESP32/OTAImageProcessorImpl.h | 4 + src/platform/ESP32/OpenthreadLauncher.cpp | 14 +- 8 files changed, 653 insertions(+), 9 deletions(-) diff --git a/examples/thread-br-app/esp32/README.md b/examples/thread-br-app/esp32/README.md index 2578a106abeb3b..f684c01e9241e6 100644 --- a/examples/thread-br-app/esp32/README.md +++ b/examples/thread-br-app/esp32/README.md @@ -16,6 +16,7 @@ guides to get started. - [OpenThread CLI](#openthread-cli) - [Setup Thread Network](#setup-thread-network) - [Commissioning Thread End Devices](#commissioning-thread-end-devices) +- [Generate OTA Firmware For BR](#generate-ota-firmware-for-br) --- @@ -92,3 +93,15 @@ the Thread network. ``` ./chip-tool pairing ble-wifi 2 hex:<dataset_tlvs> <pincode> <discriminator> ``` + +### Generate OTA Firmware For BR + +Can use this python +[script](https://github.com/espressif/esp-thread-br/blob/main/components/esp_rcp_update/create_ota_image.py) +to merge thread border router firmware and the RCP firmware + +``` +python create_ota_image.py --rcp-build-dir /path/to/rcp_image/dir --br-firmware /path/to/br_image --target-file ota_target_file.bin +``` + +Then can use the generated bin file to create a Matter OTA file normally. diff --git a/examples/thread-br-app/esp32/partitions.csv b/examples/thread-br-app/esp32/partitions.csv index 745321df3785fc..b4a53561b00e43 100644 --- a/examples/thread-br-app/esp32/partitions.csv +++ b/examples/thread-br-app/esp32/partitions.csv @@ -3,6 +3,6 @@ nvs, data, nvs, , 0xC000, otadata, data, ota, , 0x2000, phy_init, data, phy, , 0x1000, -ota_0, app, ota_0, , 1800K, -ota_1, app, ota_1, , 1800K, -rcp_fw, data, spiffs, , 300K, +ota_0, app, ota_0, , 1700k, +ota_1, app, ota_1, , 1600k, +rcp_fw, data, spiffs, , 640k, diff --git a/examples/thread-br-app/esp32/sdkconfig.defaults b/examples/thread-br-app/esp32/sdkconfig.defaults index 498081c21f8c47..f79e26cf0bdf86 100644 --- a/examples/thread-br-app/esp32/sdkconfig.defaults +++ b/examples/thread-br-app/esp32/sdkconfig.defaults @@ -29,8 +29,9 @@ CONFIG_BT_NIMBLE_ENABLE_CONN_REATTEMPT=n # Increase some stack size CONFIG_ESP_SYSTEM_EVENT_TASK_STACK_SIZE=7200 -CONFIG_ESP_MAIN_TASK_STACK_SIZE=5120 +CONFIG_ESP_MAIN_TASK_STACK_SIZE=10240 CONFIG_ESP_TIMER_TASK_STACK_SIZE=5120 +CONFIG_CHIP_TASK_STACK_SIZE=10240 # USB console for Thread border board CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG=y @@ -69,9 +70,27 @@ CONFIG_THREAD_NETWORK_COMMISSIONING_DRIVER=n # Auto update RCP firmware CONFIG_AUTO_UPDATE_RCP=y +CONFIG_ENABLE_OTA_REQUESTOR=y +CONFIG_CREATE_OTA_IMAGE_WITH_RCP_FW=y # Use platform mDNS CONFIG_USE_MINIMAL_MDNS=n -# Enable Matter shell -CONFIG_ENABLE_CHIP_SHELL=y +# Reduce flash size +CONFIG_ENABLE_CHIP_SHELL=n +CONFIG_OPENTHREAD_CLI=n +CONFIG_NEWLIB_NANO_FORMAT=y + +CONFIG_NIMBLE_MAX_CONNECTIONS=1 +CONFIG_BTDM_CTRL_BLE_MAX_CONN=1 +CONFIG_BT_NIMBLE_ROLE_CENTRAL=n +CONFIG_BT_NIMBLE_ROLE_OBSERVER=n + +CONFIG_EVENT_LOGGING_CRIT_BUFFER_SIZE=1024 + +#CONFIG_LOG_DEFAULT_LEVEL_ERROR=y + +CONFIG_COMPILER_OPTIMIZATION_SIZE=y +CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_SILENT=y +CONFIG_COMPILER_OPTIMIZATION_CHECKS_SILENT=y +CONFIG_ESP_ERR_TO_NAME_LOOKUP=n diff --git a/examples/thread-br-app/thread-br-common/thread-br-app.matter b/examples/thread-br-app/thread-br-common/thread-br-app.matter index 035c36d52b2dab..971bfe34dbe169 100644 --- a/examples/thread-br-app/thread-br-common/thread-br-app.matter +++ b/examples/thread-br-app/thread-br-common/thread-br-app.matter @@ -496,6 +496,160 @@ cluster BasicInformation = 40 { command MfgSpecificPing(): DefaultSuccess = 0; } +/** Provides an interface for providing OTA software updates */ +cluster OtaSoftwareUpdateProvider = 41 { + revision 1; // NOTE: Default/not specifically set + + enum ApplyUpdateActionEnum : enum8 { + kProceed = 0; + kAwaitNextAction = 1; + kDiscontinue = 2; + } + + enum DownloadProtocolEnum : enum8 { + kBDXSynchronous = 0; + kBDXAsynchronous = 1; + kHTTPS = 2; + kVendorSpecific = 3; + } + + enum StatusEnum : enum8 { + kUpdateAvailable = 0; + kBusy = 1; + kNotAvailable = 2; + kDownloadProtocolNotSupported = 3; + } + + readonly attribute command_id generatedCommandList[] = 65528; + readonly attribute command_id acceptedCommandList[] = 65529; + readonly attribute event_id eventList[] = 65530; + readonly attribute attrib_id attributeList[] = 65531; + readonly attribute bitmap32 featureMap = 65532; + readonly attribute int16u clusterRevision = 65533; + + request struct QueryImageRequest { + vendor_id vendorID = 0; + int16u productID = 1; + int32u softwareVersion = 2; + DownloadProtocolEnum protocolsSupported[] = 3; + optional int16u hardwareVersion = 4; + optional char_string<2> location = 5; + optional boolean requestorCanConsent = 6; + optional octet_string<512> metadataForProvider = 7; + } + + response struct QueryImageResponse = 1 { + StatusEnum status = 0; + optional int32u delayedActionTime = 1; + optional char_string<256> imageURI = 2; + optional int32u softwareVersion = 3; + optional char_string<64> softwareVersionString = 4; + optional octet_string<32> updateToken = 5; + optional boolean userConsentNeeded = 6; + optional octet_string<512> metadataForRequestor = 7; + } + + request struct ApplyUpdateRequestRequest { + octet_string<32> updateToken = 0; + int32u newVersion = 1; + } + + response struct ApplyUpdateResponse = 3 { + ApplyUpdateActionEnum action = 0; + int32u delayedActionTime = 1; + } + + request struct NotifyUpdateAppliedRequest { + octet_string<32> updateToken = 0; + int32u softwareVersion = 1; + } + + /** Determine availability of a new Software Image */ + command QueryImage(QueryImageRequest): QueryImageResponse = 0; + /** Determine next action to take for a downloaded Software Image */ + command ApplyUpdateRequest(ApplyUpdateRequestRequest): ApplyUpdateResponse = 2; + /** Notify OTA Provider that an update was applied */ + command NotifyUpdateApplied(NotifyUpdateAppliedRequest): DefaultSuccess = 4; +} + +/** Provides an interface for downloading and applying OTA software updates */ +cluster OtaSoftwareUpdateRequestor = 42 { + revision 1; // NOTE: Default/not specifically set + + enum AnnouncementReasonEnum : enum8 { + kSimpleAnnouncement = 0; + kUpdateAvailable = 1; + kUrgentUpdateAvailable = 2; + } + + enum ChangeReasonEnum : enum8 { + kUnknown = 0; + kSuccess = 1; + kFailure = 2; + kTimeOut = 3; + kDelayByProvider = 4; + } + + enum UpdateStateEnum : enum8 { + kUnknown = 0; + kIdle = 1; + kQuerying = 2; + kDelayedOnQuery = 3; + kDownloading = 4; + kApplying = 5; + kDelayedOnApply = 6; + kRollingBack = 7; + kDelayedOnUserConsent = 8; + } + + fabric_scoped struct ProviderLocation { + node_id providerNodeID = 1; + endpoint_no endpoint = 2; + fabric_idx fabricIndex = 254; + } + + info event StateTransition = 0 { + UpdateStateEnum previousState = 0; + UpdateStateEnum newState = 1; + ChangeReasonEnum reason = 2; + nullable int32u targetSoftwareVersion = 3; + } + + critical event VersionApplied = 1 { + int32u softwareVersion = 0; + int16u productID = 1; + } + + info event DownloadError = 2 { + int32u softwareVersion = 0; + int64u bytesDownloaded = 1; + nullable int8u progressPercent = 2; + nullable int64s platformCode = 3; + } + + attribute access(write: administer) ProviderLocation defaultOTAProviders[] = 0; + readonly attribute boolean updatePossible = 1; + readonly attribute UpdateStateEnum updateState = 2; + readonly attribute nullable int8u updateStateProgress = 3; + readonly attribute command_id generatedCommandList[] = 65528; + readonly attribute command_id acceptedCommandList[] = 65529; + readonly attribute event_id eventList[] = 65530; + readonly attribute attrib_id attributeList[] = 65531; + readonly attribute bitmap32 featureMap = 65532; + readonly attribute int16u clusterRevision = 65533; + + request struct AnnounceOTAProviderRequest { + node_id providerNodeID = 0; + vendor_id vendorID = 1; + AnnouncementReasonEnum announcementReason = 2; + optional octet_string<512> metadataForNode = 3; + endpoint_no endpoint = 4; + } + + /** Announce the presence of an OTA Provider */ + command AnnounceOTAProvider(AnnounceOTAProviderRequest): DefaultSuccess = 0; +} + /** This cluster is used to manage global aspects of the Commissioning flow. */ cluster GeneralCommissioning = 48 { revision 1; // NOTE: Default/not specifically set @@ -1426,6 +1580,7 @@ cluster ThreadBorderRouterManagement = 1106 { endpoint 0 { device type ma_rootdevice = 22, version 1; + binding cluster OtaSoftwareUpdateProvider; server cluster Descriptor { callback attribute deviceTypeList; @@ -1481,6 +1636,23 @@ endpoint 0 { ram attribute clusterRevision default = 3; } + server cluster OtaSoftwareUpdateRequestor { + emits event StateTransition; + emits event VersionApplied; + emits event DownloadError; + callback attribute defaultOTAProviders; + ram attribute updatePossible default = true; + ram attribute updateState default = 0; + ram attribute updateStateProgress; + callback attribute generatedCommandList; + callback attribute acceptedCommandList; + callback attribute attributeList; + ram attribute featureMap default = 0; + ram attribute clusterRevision default = 1; + + handle command AnnounceOTAProvider; + } + server cluster GeneralCommissioning { ram attribute breadcrumb default = 0x0000000000000000; callback attribute basicCommissioningInfo; diff --git a/examples/thread-br-app/thread-br-common/thread-br-app.zap b/examples/thread-br-app/thread-br-common/thread-br-app.zap index ba281bf59209dd..17902190fb0559 100644 --- a/examples/thread-br-app/thread-br-common/thread-br-app.zap +++ b/examples/thread-br-app/thread-br-common/thread-br-app.zap @@ -772,6 +772,243 @@ } ] }, + { + "name": "OTA Software Update Provider", + "code": 41, + "mfgCode": null, + "define": "OTA_SOFTWARE_UPDATE_PROVIDER_CLUSTER", + "side": "client", + "enabled": 1, + "commands": [ + { + "name": "QueryImage", + "code": 0, + "mfgCode": null, + "source": "client", + "isIncoming": 0, + "isEnabled": 1 + }, + { + "name": "QueryImageResponse", + "code": 1, + "mfgCode": null, + "source": "server", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "ApplyUpdateRequest", + "code": 2, + "mfgCode": null, + "source": "client", + "isIncoming": 0, + "isEnabled": 1 + }, + { + "name": "ApplyUpdateResponse", + "code": 3, + "mfgCode": null, + "source": "server", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "NotifyUpdateApplied", + "code": 4, + "mfgCode": null, + "source": "client", + "isIncoming": 0, + "isEnabled": 1 + } + ] + }, + { + "name": "OTA Software Update Requestor", + "code": 42, + "mfgCode": null, + "define": "OTA_SOFTWARE_UPDATE_REQUESTOR_CLUSTER", + "side": "server", + "enabled": 1, + "commands": [ + { + "name": "AnnounceOTAProvider", + "code": 0, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + } + ], + "attributes": [ + { + "name": "DefaultOTAProviders", + "code": 0, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "UpdatePossible", + "code": 1, + "mfgCode": null, + "side": "server", + "type": "boolean", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "true", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "UpdateState", + "code": 2, + "mfgCode": null, + "side": "server", + "type": "UpdateStateEnum", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "UpdateStateProgress", + "code": 3, + "mfgCode": null, + "side": "server", + "type": "int8u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "GeneratedCommandList", + "code": 65528, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AcceptedCommandList", + "code": 65529, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AttributeList", + "code": 65531, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "FeatureMap", + "code": 65532, + "mfgCode": null, + "side": "server", + "type": "bitmap32", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "1", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + } + ], + "events": [ + { + "name": "StateTransition", + "code": 0, + "mfgCode": null, + "side": "server", + "included": 1 + }, + { + "name": "VersionApplied", + "code": 1, + "mfgCode": null, + "side": "server", + "included": 1 + }, + { + "name": "DownloadError", + "code": 2, + "mfgCode": null, + "side": "server", + "included": 1 + } + ] + }, { "name": "General Commissioning", "code": 48, diff --git a/src/platform/ESP32/OTAImageProcessorImpl.cpp b/src/platform/ESP32/OTAImageProcessorImpl.cpp index 284f21c0639eec..ed4b99bbccb8f5 100644 --- a/src/platform/ESP32/OTAImageProcessorImpl.cpp +++ b/src/platform/ESP32/OTAImageProcessorImpl.cpp @@ -36,6 +36,12 @@ #include <esp_delta_ota.h> #endif // CONFIG_ENABLE_DELTA_OTA +#if defined(CONFIG_AUTO_UPDATE_RCP) && defined(CONFIG_OPENTHREAD_BORDER_ROUTER) +#include "esp_br_firmware.h" +#include "esp_check.h" +#include "esp_rcp_update.h" +#endif + #define TAG "OTAImageProcessor" #ifdef CONFIG_ENABLE_DELTA_OTA @@ -43,6 +49,11 @@ #define DIGEST_SIZE 32 #endif // CONFIG_ENABLE_DELTA_OTA +#if defined(CONFIG_AUTO_UPDATE_RCP) && defined(CONFIG_OPENTHREAD_BORDER_ROUTER) +#define MAX_WRITE_RETRY_COUNT 5 +#define OTA_MAX_WRITE_SIZE 16 +#endif // defined(CONFIG_AUTO_UPDATE_RCP) && defined(CONFIG_OPENTHREAD_BORDER_ROUTER) + using namespace chip::System; using namespace ::chip::DeviceLayer::Internal; @@ -280,6 +291,182 @@ esp_err_t OTAImageProcessorImpl::DeltaOTAWriteCallback(const uint8_t * buf, size } #endif // CONFIG_ENABLE_DELTA_OTA +#if defined(CONFIG_AUTO_UPDATE_RCP) && defined(CONFIG_OPENTHREAD_BORDER_ROUTER) +typedef enum rcpImageState +{ + BR_OTA_INIT = 0, + RCP_DOWNLOAD, + BR_FW_DOWNLOAD, +} RcpImageState_t; + +static int WriteFileForLength(FILE * fp, const void * buf, size_t size) +{ + int retryCount = 0; + int offset = 0; + const uint8_t * data = (const uint8_t *) buf; + while (offset < size) + { + int ret = fwrite(data + offset, 1, ((size - offset) < OTA_MAX_WRITE_SIZE ? (size - offset) : OTA_MAX_WRITE_SIZE), fp); + if (ret < 0) + { + return ret; + } + if (ret == 0) + { + retryCount++; + } + else + { + offset += ret; + retryCount = 0; + } + + if (retryCount > MAX_WRITE_RETRY_COUNT) + { + return -1; + } + } + return size; +} + +esp_err_t OTAImageProcessorImpl::ProcessRcpImage(esp_ota_handle_t handle, const uint8_t * buffer, uint32_t bufLengthen) +{ + static char rcpTargetPath[RCP_FILENAME_MAX_SIZE]; + static RcpImageState_t state = BR_OTA_INIT; + static const char * rcpFirmwareDir = esp_rcp_get_firmware_dir(); + static int8_t rcpUpdateSeq = esp_rcp_get_next_update_seq(); + static uint32_t headerSize = 0; + static uint32_t totalRevSize = 0; + static uint32_t brFirmwareOffset = 0; + static uint32_t brFirmwareSize = 0; + static FILE * fp = NULL; + + switch (state) + { + case BR_OTA_INIT: { + sprintf(rcpTargetPath, "%s_%d/" ESP_BR_RCP_IMAGE_FILENAME, rcpFirmwareDir, rcpUpdateSeq); + ESP_LOGI(TAG, "Downloading RCP target file %s", rcpTargetPath); + + fp = fopen(rcpTargetPath, "w"); + if (!fp) + { + ESP_LOGE(TAG, "Fail to open %s, will delete it", rcpTargetPath); + remove(rcpTargetPath); + return ESP_FAIL; + } + + esp_br_subfile_info_t subFileInfo[7]; + if (sizeof(subFileInfo) > bufLengthen) + { + ESP_LOGE(TAG, "Packet len is less than the RCP header len"); + if (fp != NULL) + { + fclose(fp); + } + return ESP_FAIL; + } + + memcpy((char *) subFileInfo, buffer, sizeof(subFileInfo)); + for (int i = 0; i < 7; i++) + { + ESP_LOGD(TAG, "subFileInfo[%d].tag:0x%lx--offset:0x%lx---size:0x%lx\n", i, subFileInfo[i].tag, subFileInfo[i].offset, + subFileInfo[i].size); + if (subFileInfo[i].tag == FILETAG_IMAGE_HEADER) + { + headerSize = subFileInfo[i].size; + ESP_LOGI(TAG, "RCP image header-----headerSize:%ld\n", headerSize); + } + else if (subFileInfo[i].tag == FILETAG_BR_FIRMWARE) + { + brFirmwareOffset = subFileInfo[i].offset; + brFirmwareSize = subFileInfo[i].size; + ESP_LOGI(TAG, "Border Router image--offset:%ld--size:%ld\n", brFirmwareOffset, brFirmwareSize); + } + } + + if ((headerSize != sizeof(subFileInfo)) || (brFirmwareOffset == 0) || (brFirmwareSize == 0)) + { + ESP_LOGE(TAG, "RCP header error"); + fclose(fp); + return ESP_FAIL; + } + + if (WriteFileForLength(fp, buffer, bufLengthen) != bufLengthen) + { + ESP_LOGE(TAG, "Failed to write data"); + fclose(fp); + return ESP_FAIL; + } + + state = RCP_DOWNLOAD; + totalRevSize = bufLengthen; + break; + } + case RCP_DOWNLOAD: { + if (totalRevSize + bufLengthen >= brFirmwareOffset) + { + uint32_t len = brFirmwareOffset - totalRevSize; + if (WriteFileForLength(fp, buffer, len) == len) + { + ESP_LOGI(TAG, "RCP receive done, total size %ld bytes", brFirmwareOffset); + state = BR_FW_DOWNLOAD; + fclose(fp); + if (esp_rcp_submit_new_image() != ESP_OK) + { + ESP_LOGI(TAG, "Failed to submit RCP image"); + state = BR_OTA_INIT; + return ESP_FAIL; + } + } + else + { + ESP_LOGE(TAG, "Failed to write data"); + fclose(fp); + state = BR_OTA_INIT; + return ESP_FAIL; + } + + if (esp_ota_write(handle, buffer + len, bufLengthen - len) != ESP_OK) + { + ESP_LOGE(TAG, "OTA write failed"); + state = BR_OTA_INIT; + return ESP_FAIL; + } + + totalRevSize = bufLengthen - len; + } + else + { + if (WriteFileForLength(fp, buffer, bufLengthen) != bufLengthen) + { + ESP_LOGE(TAG, "Failed to write data"); + fclose(fp); + state = BR_OTA_INIT; + return ESP_FAIL; + } + totalRevSize += bufLengthen; + } + break; + } + case BR_FW_DOWNLOAD: { + if (esp_ota_write(handle, buffer, bufLengthen) != ESP_OK) + { + ESP_LOGE(TAG, "OTA write failed"); + state = BR_OTA_INIT; + return ESP_FAIL; + ESP_LOGI(TAG, "Thread BR image receive done"); + } + break; + } + default: { + return ESP_FAIL; + } + } + + return ESP_OK; +} +#endif + void OTAImageProcessorImpl::HandlePrepareDownload(intptr_t context) { auto * imageProcessor = reinterpret_cast<OTAImageProcessorImpl *>(context); @@ -483,8 +670,10 @@ void OTAImageProcessorImpl::HandleProcessBlock(intptr_t context) // Apply the patch and writes that data to the passive partition. err = esp_delta_ota_feed_patch(imageProcessor->mDeltaOTAUpdateHandle, blockToWrite.data() + index, blockToWrite.size() - index); +#elif defined(CONFIG_AUTO_UPDATE_RCP) && defined(CONFIG_OPENTHREAD_BORDER_ROUTER) + err = imageProcessor->ProcessRcpImage(imageProcessor->mOTAUpdateHandle, blockToWrite.data(), blockToWrite.size()); #else - err = esp_ota_write(imageProcessor->mOTAUpdateHandle, blockToWrite.data(), blockToWrite.size()); + err = esp_ota_write(imageProcessor->mOTAUpdateHandle, blockToWrite.data(), blockToWrite.size()); #endif // CONFIG_ENABLE_DELTA_OTA #ifdef CONFIG_ENABLE_ENCRYPTED_OTA diff --git a/src/platform/ESP32/OTAImageProcessorImpl.h b/src/platform/ESP32/OTAImageProcessorImpl.h index 3414f90b425505..058935b8d70cc8 100644 --- a/src/platform/ESP32/OTAImageProcessorImpl.h +++ b/src/platform/ESP32/OTAImageProcessorImpl.h @@ -99,6 +99,10 @@ class OTAImageProcessorImpl : public OTAImageProcessorInterface bool mEncryptedOTAEnabled = false; esp_decrypt_handle_t mOTADecryptionHandle = nullptr; #endif // CONFIG_ENABLE_ENCRYPTED_OTA + +#if defined(CONFIG_AUTO_UPDATE_RCP) && defined(CONFIG_OPENTHREAD_BORDER_ROUTER) + esp_err_t ProcessRcpImage(esp_ota_handle_t handle, const uint8_t * buffer, uint32_t bufLengthen); +#endif }; } // namespace chip diff --git a/src/platform/ESP32/OpenthreadLauncher.cpp b/src/platform/ESP32/OpenthreadLauncher.cpp index 0ab3dadf6862cb..575e583eeb8bbd 100644 --- a/src/platform/ESP32/OpenthreadLauncher.cpp +++ b/src/platform/ESP32/OpenthreadLauncher.cpp @@ -196,8 +196,18 @@ static void try_update_ot_rcp(const esp_openthread_platform_config_t * config) static void rcp_failure_handler(void) { esp_rcp_mark_image_unusable(); - try_update_ot_rcp(s_platform_config); - esp_rcp_reset(); + char internal_rcp_version[kRcpVersionMaxSize]; + if (esp_rcp_load_version_in_storage(internal_rcp_version, sizeof(internal_rcp_version)) == ESP_OK) + { + ESP_LOGI(TAG, "Internal RCP Version: %s", internal_rcp_version); + update_rcp(); + } + else + { + ESP_LOGI(TAG, "RCP firmware not found in storage, will reboot to try next image"); + esp_rcp_mark_image_verified(false); + esp_restart(); + } } #endif // CONFIG_OPENTHREAD_BORDER_ROUTER && CONFIG_AUTO_UPDATE_RCP From b88108f4ef1991d1e233c0545f74c30a23016667 Mon Sep 17 00:00:00 2001 From: liyashuai <liyashuai@espressif.com> Date: Mon, 10 Mar 2025 14:01:00 +0800 Subject: [PATCH 2/6] Update the implementation of some APIs --- .../esp32/components/chip/idf_component.yml | 2 +- examples/thread-br-app/esp32/README.md | 25 +- examples/thread-br-app/esp32/partitions.csv | 2 +- .../thread-br-app/esp32/sdkconfig.defaults | 6 +- src/platform/ESP32/OTAImageProcessorImpl.cpp | 218 ++++-------------- src/platform/ESP32/OTAImageProcessorImpl.h | 11 +- src/platform/ESP32/OpenthreadLauncher.cpp | 4 +- 7 files changed, 74 insertions(+), 194 deletions(-) diff --git a/config/esp32/components/chip/idf_component.yml b/config/esp32/components/chip/idf_component.yml index e2b68574fc8bb7..6d5f2c2e38425c 100644 --- a/config/esp32/components/chip/idf_component.yml +++ b/config/esp32/components/chip/idf_component.yml @@ -26,7 +26,7 @@ dependencies: - if: "target != esp32h2" espressif/esp_rcp_update: - version: "1.2.0" + version: "~1.3.0" rules: - if: "idf_version >=5.0" diff --git a/examples/thread-br-app/esp32/README.md b/examples/thread-br-app/esp32/README.md index f684c01e9241e6..46eabfe5ed0689 100644 --- a/examples/thread-br-app/esp32/README.md +++ b/examples/thread-br-app/esp32/README.md @@ -11,12 +11,13 @@ guides to get started. --- -- [OpenThread Border Router Board](#openthread-border-router-board) -- [OpenThread RCP](#openthread-rcp) -- [OpenThread CLI](#openthread-cli) -- [Setup Thread Network](#setup-thread-network) -- [Commissioning Thread End Devices](#commissioning-thread-end-devices) -- [Generate OTA Firmware For BR](#generate-ota-firmware-for-br) +- [Matter ESP32 Thread Border Router Example](#matter-esp32-thread-border-router-example) + - [OpenThread Border Router Board](#openthread-border-router-board) + - [OpenThread RCP](#openthread-rcp) + - [OpenThread CLI](#openthread-cli) + - [Setup Thread Network](#setup-thread-network) + - [Commissioning Thread End Devices](#commissioning-thread-end-devices) + - [Generate OTA Firmware For BR](#generate-ota-firmware-for-br) --- @@ -96,12 +97,10 @@ the Thread network. ### Generate OTA Firmware For BR -Can use this python -[script](https://github.com/espressif/esp-thread-br/blob/main/components/esp_rcp_update/create_ota_image.py) -to merge thread border router firmware and the RCP firmware +After enable the option `CONFIG_CREATE_OTA_IMAGE_WITH_RCP_FW` in menuconfig, will generate +OTA image with rcp firmware in build process, named `ota_with_rcp_image` in build folder. +Then can add a Matter OTA header for the ota_with_rcp_image file. ``` -python create_ota_image.py --rcp-build-dir /path/to/rcp_image/dir --br-firmware /path/to/br_image --target-file ota_target_file.bin -``` - -Then can use the generated bin file to create a Matter OTA file normally. +./ota_image_tool.py create -v 65521 -p 32768 --version 1 --version-str "v1.0" -da sha256 build/ota_with_rcp_image ota_with_rcp_image.ota +``` \ No newline at end of file diff --git a/examples/thread-br-app/esp32/partitions.csv b/examples/thread-br-app/esp32/partitions.csv index b4a53561b00e43..2b951b15d1e388 100644 --- a/examples/thread-br-app/esp32/partitions.csv +++ b/examples/thread-br-app/esp32/partitions.csv @@ -3,6 +3,6 @@ nvs, data, nvs, , 0xC000, otadata, data, ota, , 0x2000, phy_init, data, phy, , 0x1000, -ota_0, app, ota_0, , 1700k, +ota_0, app, ota_0, , 1600k, ota_1, app, ota_1, , 1600k, rcp_fw, data, spiffs, , 640k, diff --git a/examples/thread-br-app/esp32/sdkconfig.defaults b/examples/thread-br-app/esp32/sdkconfig.defaults index f79e26cf0bdf86..e4780664e7692e 100644 --- a/examples/thread-br-app/esp32/sdkconfig.defaults +++ b/examples/thread-br-app/esp32/sdkconfig.defaults @@ -29,9 +29,9 @@ CONFIG_BT_NIMBLE_ENABLE_CONN_REATTEMPT=n # Increase some stack size CONFIG_ESP_SYSTEM_EVENT_TASK_STACK_SIZE=7200 -CONFIG_ESP_MAIN_TASK_STACK_SIZE=10240 +CONFIG_ESP_MAIN_TASK_STACK_SIZE=5120 CONFIG_ESP_TIMER_TASK_STACK_SIZE=5120 -CONFIG_CHIP_TASK_STACK_SIZE=10240 +CONFIG_CHIP_TASK_STACK_SIZE=9216 # USB console for Thread border board CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG=y @@ -88,7 +88,7 @@ CONFIG_BT_NIMBLE_ROLE_OBSERVER=n CONFIG_EVENT_LOGGING_CRIT_BUFFER_SIZE=1024 -#CONFIG_LOG_DEFAULT_LEVEL_ERROR=y +CONFIG_LOG_DEFAULT_LEVEL_ERROR=y CONFIG_COMPILER_OPTIMIZATION_SIZE=y CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_SILENT=y diff --git a/src/platform/ESP32/OTAImageProcessorImpl.cpp b/src/platform/ESP32/OTAImageProcessorImpl.cpp index ed4b99bbccb8f5..3ae22f168b62a7 100644 --- a/src/platform/ESP32/OTAImageProcessorImpl.cpp +++ b/src/platform/ESP32/OTAImageProcessorImpl.cpp @@ -36,12 +36,6 @@ #include <esp_delta_ota.h> #endif // CONFIG_ENABLE_DELTA_OTA -#if defined(CONFIG_AUTO_UPDATE_RCP) && defined(CONFIG_OPENTHREAD_BORDER_ROUTER) -#include "esp_br_firmware.h" -#include "esp_check.h" -#include "esp_rcp_update.h" -#endif - #define TAG "OTAImageProcessor" #ifdef CONFIG_ENABLE_DELTA_OTA @@ -49,11 +43,6 @@ #define DIGEST_SIZE 32 #endif // CONFIG_ENABLE_DELTA_OTA -#if defined(CONFIG_AUTO_UPDATE_RCP) && defined(CONFIG_OPENTHREAD_BORDER_ROUTER) -#define MAX_WRITE_RETRY_COUNT 5 -#define OTA_MAX_WRITE_SIZE 16 -#endif // defined(CONFIG_AUTO_UPDATE_RCP) && defined(CONFIG_OPENTHREAD_BORDER_ROUTER) - using namespace chip::System; using namespace ::chip::DeviceLayer::Internal; @@ -292,178 +281,33 @@ esp_err_t OTAImageProcessorImpl::DeltaOTAWriteCallback(const uint8_t * buf, size #endif // CONFIG_ENABLE_DELTA_OTA #if defined(CONFIG_AUTO_UPDATE_RCP) && defined(CONFIG_OPENTHREAD_BORDER_ROUTER) -typedef enum rcpImageState +esp_err_t OTAImageProcessorImpl::ProcessRcpImage(intptr_t context, const uint8_t * buffer, uint32_t bufLen) { - BR_OTA_INIT = 0, - RCP_DOWNLOAD, - BR_FW_DOWNLOAD, -} RcpImageState_t; + esp_err_t err = ESP_OK; + auto * imageProcessor = reinterpret_cast<OTAImageProcessorImpl *>(context); -static int WriteFileForLength(FILE * fp, const void * buf, size_t size) -{ - int retryCount = 0; - int offset = 0; - const uint8_t * data = (const uint8_t *) buf; - while (offset < size) + if (!imageProcessor->mRcpDone) { - int ret = fwrite(data + offset, 1, ((size - offset) < OTA_MAX_WRITE_SIZE ? (size - offset) : OTA_MAX_WRITE_SIZE), fp); - if (ret < 0) - { - return ret; - } - if (ret == 0) - { - retryCount++; - } - else - { - offset += ret; - retryCount = 0; - } - - if (retryCount > MAX_WRITE_RETRY_COUNT) - { - return -1; - } - } - return size; -} - -esp_err_t OTAImageProcessorImpl::ProcessRcpImage(esp_ota_handle_t handle, const uint8_t * buffer, uint32_t bufLengthen) -{ - static char rcpTargetPath[RCP_FILENAME_MAX_SIZE]; - static RcpImageState_t state = BR_OTA_INIT; - static const char * rcpFirmwareDir = esp_rcp_get_firmware_dir(); - static int8_t rcpUpdateSeq = esp_rcp_get_next_update_seq(); - static uint32_t headerSize = 0; - static uint32_t totalRevSize = 0; - static uint32_t brFirmwareOffset = 0; - static uint32_t brFirmwareSize = 0; - static FILE * fp = NULL; - - switch (state) - { - case BR_OTA_INIT: { - sprintf(rcpTargetPath, "%s_%d/" ESP_BR_RCP_IMAGE_FILENAME, rcpFirmwareDir, rcpUpdateSeq); - ESP_LOGI(TAG, "Downloading RCP target file %s", rcpTargetPath); - - fp = fopen(rcpTargetPath, "w"); - if (!fp) - { - ESP_LOGE(TAG, "Fail to open %s, will delete it", rcpTargetPath); - remove(rcpTargetPath); - return ESP_FAIL; - } - - esp_br_subfile_info_t subFileInfo[7]; - if (sizeof(subFileInfo) > bufLengthen) - { - ESP_LOGE(TAG, "Packet len is less than the RCP header len"); - if (fp != NULL) - { - fclose(fp); - } - return ESP_FAIL; - } - - memcpy((char *) subFileInfo, buffer, sizeof(subFileInfo)); - for (int i = 0; i < 7; i++) - { - ESP_LOGD(TAG, "subFileInfo[%d].tag:0x%lx--offset:0x%lx---size:0x%lx\n", i, subFileInfo[i].tag, subFileInfo[i].offset, - subFileInfo[i].size); - if (subFileInfo[i].tag == FILETAG_IMAGE_HEADER) - { - headerSize = subFileInfo[i].size; - ESP_LOGI(TAG, "RCP image header-----headerSize:%ld\n", headerSize); - } - else if (subFileInfo[i].tag == FILETAG_BR_FIRMWARE) - { - brFirmwareOffset = subFileInfo[i].offset; - brFirmwareSize = subFileInfo[i].size; - ESP_LOGI(TAG, "Border Router image--offset:%ld--size:%ld\n", brFirmwareOffset, brFirmwareSize); - } - } - - if ((headerSize != sizeof(subFileInfo)) || (brFirmwareOffset == 0) || (brFirmwareSize == 0)) - { - ESP_LOGE(TAG, "RCP header error"); - fclose(fp); - return ESP_FAIL; - } + size_t rcpOtaReceivedLen = 0; + err = esp_rcp_ota_receive(imageProcessor->mRcpOtaHandle, buffer, bufLen, &rcpOtaReceivedLen); - if (WriteFileForLength(fp, buffer, bufLengthen) != bufLengthen) + if (esp_rcp_ota_get_state(imageProcessor->mRcpOtaHandle) == ESP_RCP_OTA_STATE_FINISHED) { - ESP_LOGE(TAG, "Failed to write data"); - fclose(fp); - return ESP_FAIL; + imageProcessor->mBrFirmwareSize = esp_rcp_ota_get_subfile_size(imageProcessor->mRcpOtaHandle, FILETAG_HOST_FIRMWARE); + err = esp_ota_write(imageProcessor->mOTAUpdateHandle, buffer + rcpOtaReceivedLen, bufLen - rcpOtaReceivedLen); + imageProcessor->mRcpDone = true; } - - state = RCP_DOWNLOAD; - totalRevSize = bufLengthen; - break; - } - case RCP_DOWNLOAD: { - if (totalRevSize + bufLengthen >= brFirmwareOffset) - { - uint32_t len = brFirmwareOffset - totalRevSize; - if (WriteFileForLength(fp, buffer, len) == len) - { - ESP_LOGI(TAG, "RCP receive done, total size %ld bytes", brFirmwareOffset); - state = BR_FW_DOWNLOAD; - fclose(fp); - if (esp_rcp_submit_new_image() != ESP_OK) - { - ESP_LOGI(TAG, "Failed to submit RCP image"); - state = BR_OTA_INIT; - return ESP_FAIL; - } - } - else - { - ESP_LOGE(TAG, "Failed to write data"); - fclose(fp); - state = BR_OTA_INIT; - return ESP_FAIL; - } - - if (esp_ota_write(handle, buffer + len, bufLengthen - len) != ESP_OK) - { - ESP_LOGE(TAG, "OTA write failed"); - state = BR_OTA_INIT; - return ESP_FAIL; - } - - totalRevSize = bufLengthen - len; - } - else - { - if (WriteFileForLength(fp, buffer, bufLengthen) != bufLengthen) - { - ESP_LOGE(TAG, "Failed to write data"); - fclose(fp); - state = BR_OTA_INIT; - return ESP_FAIL; - } - totalRevSize += bufLengthen; - } - break; - } - case BR_FW_DOWNLOAD: { - if (esp_ota_write(handle, buffer, bufLengthen) != ESP_OK) - { - ESP_LOGE(TAG, "OTA write failed"); - state = BR_OTA_INIT; - return ESP_FAIL; - ESP_LOGI(TAG, "Thread BR image receive done"); - } - break; } - default: { - return ESP_FAIL; + else if (imageProcessor->mBrFirmwareSize > 0) + { + err = esp_ota_write(imageProcessor->mOTAUpdateHandle, buffer, bufLen); } + else + { + err = ESP_FAIL; } - return ESP_OK; + return err; } #endif @@ -524,6 +368,16 @@ void OTAImageProcessorImpl::HandlePrepareDownload(intptr_t context) } #endif // CONFIG_ENABLE_ENCRYPTED_OTA +#if defined(CONFIG_AUTO_UPDATE_RCP) && defined(CONFIG_OPENTHREAD_BORDER_ROUTER) + imageProcessor->mRcpOtaHandle = 0; + imageProcessor->mBrFirmwareSize = 0; + imageProcessor->mRcpDone = false; + if (esp_rcp_ota_begin(&imageProcessor->mRcpOtaHandle) != ESP_OK) + { + return; + } +#endif + imageProcessor->mHeaderParser.Init(); imageProcessor->mDownloader->OnPreparedForDownload(CHIP_NO_ERROR); PostOTAStateChangeEvent(DeviceLayer::kOtaDownloadInProgress); @@ -567,6 +421,12 @@ void OTAImageProcessorImpl::HandleFinalize(intptr_t context) err = esp_ota_end(imageProcessor->mOTAUpdateHandle); DeltaOTACleanUp(reinterpret_cast<intptr_t>(imageProcessor)); +#elif defined(CONFIG_AUTO_UPDATE_RCP) && defined(CONFIG_OPENTHREAD_BORDER_ROUTER) + esp_err_t err = esp_rcp_ota_end(imageProcessor->mRcpOtaHandle); + err |= esp_ota_end(imageProcessor->mOTAUpdateHandle); + imageProcessor->mRcpOtaHandle = 0; + imageProcessor->mBrFirmwareSize = 0; + imageProcessor->mRcpDone = false; #else esp_err_t err = esp_ota_end(imageProcessor->mOTAUpdateHandle); #endif // CONFIG_ENABLE_DELTA_OTA @@ -608,6 +468,16 @@ void OTAImageProcessorImpl::HandleAbort(intptr_t context) DeltaOTACleanUp(reinterpret_cast<intptr_t>(imageProcessor)); #endif // CONFIG_ENABLE_DELTA_OTA +#if defined(CONFIG_AUTO_UPDATE_RCP) && defined(CONFIG_OPENTHREAD_BORDER_ROUTER) + if (esp_rcp_ota_abort(imageProcessor->mRcpOtaHandle) != ESP_OK) + { + ESP_LOGE(TAG, "ESP RCP OTA abort failed"); + } + imageProcessor->mRcpOtaHandle = 0; + imageProcessor->mBrFirmwareSize = 0; + imageProcessor->mRcpDone = false; +#endif + if (esp_ota_abort(imageProcessor->mOTAUpdateHandle) != ESP_OK) { ESP_LOGE(TAG, "ESP OTA abort failed"); @@ -671,7 +541,7 @@ void OTAImageProcessorImpl::HandleProcessBlock(intptr_t context) // Apply the patch and writes that data to the passive partition. err = esp_delta_ota_feed_patch(imageProcessor->mDeltaOTAUpdateHandle, blockToWrite.data() + index, blockToWrite.size() - index); #elif defined(CONFIG_AUTO_UPDATE_RCP) && defined(CONFIG_OPENTHREAD_BORDER_ROUTER) - err = imageProcessor->ProcessRcpImage(imageProcessor->mOTAUpdateHandle, blockToWrite.data(), blockToWrite.size()); + err = imageProcessor->ProcessRcpImage(context, blockToWrite.data(), blockToWrite.size()); #else err = esp_ota_write(imageProcessor->mOTAUpdateHandle, blockToWrite.data(), blockToWrite.size()); #endif // CONFIG_ENABLE_DELTA_OTA diff --git a/src/platform/ESP32/OTAImageProcessorImpl.h b/src/platform/ESP32/OTAImageProcessorImpl.h index 058935b8d70cc8..206b38d8067ab7 100644 --- a/src/platform/ESP32/OTAImageProcessorImpl.h +++ b/src/platform/ESP32/OTAImageProcessorImpl.h @@ -33,6 +33,12 @@ #define IMG_HEADER_LEN sizeof(esp_image_header_t) #endif // CONFIG_ENABLE_DELTA_OTA +#if defined(CONFIG_AUTO_UPDATE_RCP) && defined(CONFIG_OPENTHREAD_BORDER_ROUTER) +#include "esp_check.h" +#include "esp_rcp_update.h" +#include "esp_rcp_ota.h" +#endif + namespace chip { class OTAImageProcessorImpl : public OTAImageProcessorInterface @@ -101,7 +107,10 @@ class OTAImageProcessorImpl : public OTAImageProcessorInterface #endif // CONFIG_ENABLE_ENCRYPTED_OTA #if defined(CONFIG_AUTO_UPDATE_RCP) && defined(CONFIG_OPENTHREAD_BORDER_ROUTER) - esp_err_t ProcessRcpImage(esp_ota_handle_t handle, const uint8_t * buffer, uint32_t bufLengthen); + esp_rcp_ota_handle_t mRcpOtaHandle; + bool mRcpDone; + uint32_t mBrFirmwareSize; + esp_err_t ProcessRcpImage(intptr_t context, const uint8_t * buffer, uint32_t bufLen); #endif }; diff --git a/src/platform/ESP32/OpenthreadLauncher.cpp b/src/platform/ESP32/OpenthreadLauncher.cpp index 575e583eeb8bbd..99434675a6927e 100644 --- a/src/platform/ESP32/OpenthreadLauncher.cpp +++ b/src/platform/ESP32/OpenthreadLauncher.cpp @@ -156,7 +156,9 @@ static void update_rcp(void) { // Deinit uart to transfer UART to the serial loader esp_openthread_rcp_deinit(); - if (esp_rcp_update() == ESP_OK) + + esp_err_t err = esp_rcp_update(); + if (err == ESP_OK) { esp_rcp_mark_image_verified(true); } From 90244890309d1aad8d5bf7f14f9a2f1fe9e5b144 Mon Sep 17 00:00:00 2001 From: liyashuai <liyashuai@espressif.com> Date: Tue, 11 Mar 2025 17:56:42 +0800 Subject: [PATCH 3/6] restyled update --- examples/thread-br-app/esp32/README.md | 22 +++++++++++--------- src/platform/ESP32/OTAImageProcessorImpl.cpp | 20 +++++++++--------- src/platform/ESP32/OTAImageProcessorImpl.h | 2 +- 3 files changed, 23 insertions(+), 21 deletions(-) diff --git a/examples/thread-br-app/esp32/README.md b/examples/thread-br-app/esp32/README.md index 46eabfe5ed0689..4911db92f03987 100644 --- a/examples/thread-br-app/esp32/README.md +++ b/examples/thread-br-app/esp32/README.md @@ -11,13 +11,13 @@ guides to get started. --- -- [Matter ESP32 Thread Border Router Example](#matter-esp32-thread-border-router-example) - - [OpenThread Border Router Board](#openthread-border-router-board) - - [OpenThread RCP](#openthread-rcp) - - [OpenThread CLI](#openthread-cli) - - [Setup Thread Network](#setup-thread-network) - - [Commissioning Thread End Devices](#commissioning-thread-end-devices) - - [Generate OTA Firmware For BR](#generate-ota-firmware-for-br) +- [Matter ESP32 Thread Border Router Example](#matter-esp32-thread-border-router-example) + - [OpenThread Border Router Board](#openthread-border-router-board) + - [OpenThread RCP](#openthread-rcp) + - [OpenThread CLI](#openthread-cli) + - [Setup Thread Network](#setup-thread-network) + - [Commissioning Thread End Devices](#commissioning-thread-end-devices) + - [Generate OTA Firmware For BR](#generate-ota-firmware-for-br) --- @@ -97,10 +97,12 @@ the Thread network. ### Generate OTA Firmware For BR -After enable the option `CONFIG_CREATE_OTA_IMAGE_WITH_RCP_FW` in menuconfig, will generate -OTA image with rcp firmware in build process, named `ota_with_rcp_image` in build folder. +After enable the option `CONFIG_CREATE_OTA_IMAGE_WITH_RCP_FW` in menuconfig, +will generate OTA image with rcp firmware in build process, named +`ota_with_rcp_image` in build folder. Then can add a Matter OTA header for the ota_with_rcp_image file. + ``` ./ota_image_tool.py create -v 65521 -p 32768 --version 1 --version-str "v1.0" -da sha256 build/ota_with_rcp_image ota_with_rcp_image.ota -``` \ No newline at end of file +``` diff --git a/src/platform/ESP32/OTAImageProcessorImpl.cpp b/src/platform/ESP32/OTAImageProcessorImpl.cpp index 3ae22f168b62a7..656fe6d55f58ba 100644 --- a/src/platform/ESP32/OTAImageProcessorImpl.cpp +++ b/src/platform/ESP32/OTAImageProcessorImpl.cpp @@ -283,13 +283,13 @@ esp_err_t OTAImageProcessorImpl::DeltaOTAWriteCallback(const uint8_t * buf, size #if defined(CONFIG_AUTO_UPDATE_RCP) && defined(CONFIG_OPENTHREAD_BORDER_ROUTER) esp_err_t OTAImageProcessorImpl::ProcessRcpImage(intptr_t context, const uint8_t * buffer, uint32_t bufLen) { - esp_err_t err = ESP_OK; + esp_err_t err = ESP_OK; auto * imageProcessor = reinterpret_cast<OTAImageProcessorImpl *>(context); if (!imageProcessor->mRcpDone) { size_t rcpOtaReceivedLen = 0; - err = esp_rcp_ota_receive(imageProcessor->mRcpOtaHandle, buffer, bufLen, &rcpOtaReceivedLen); + err = esp_rcp_ota_receive(imageProcessor->mRcpOtaHandle, buffer, bufLen, &rcpOtaReceivedLen); if (esp_rcp_ota_get_state(imageProcessor->mRcpOtaHandle) == ESP_RCP_OTA_STATE_FINISHED) { @@ -369,9 +369,9 @@ void OTAImageProcessorImpl::HandlePrepareDownload(intptr_t context) #endif // CONFIG_ENABLE_ENCRYPTED_OTA #if defined(CONFIG_AUTO_UPDATE_RCP) && defined(CONFIG_OPENTHREAD_BORDER_ROUTER) - imageProcessor->mRcpOtaHandle = 0; + imageProcessor->mRcpOtaHandle = 0; imageProcessor->mBrFirmwareSize = 0; - imageProcessor->mRcpDone = false; + imageProcessor->mRcpDone = false; if (esp_rcp_ota_begin(&imageProcessor->mRcpOtaHandle) != ESP_OK) { return; @@ -424,9 +424,9 @@ void OTAImageProcessorImpl::HandleFinalize(intptr_t context) #elif defined(CONFIG_AUTO_UPDATE_RCP) && defined(CONFIG_OPENTHREAD_BORDER_ROUTER) esp_err_t err = esp_rcp_ota_end(imageProcessor->mRcpOtaHandle); err |= esp_ota_end(imageProcessor->mOTAUpdateHandle); - imageProcessor->mRcpOtaHandle = 0; + imageProcessor->mRcpOtaHandle = 0; imageProcessor->mBrFirmwareSize = 0; - imageProcessor->mRcpDone = false; + imageProcessor->mRcpDone = false; #else esp_err_t err = esp_ota_end(imageProcessor->mOTAUpdateHandle); #endif // CONFIG_ENABLE_DELTA_OTA @@ -473,9 +473,9 @@ void OTAImageProcessorImpl::HandleAbort(intptr_t context) { ESP_LOGE(TAG, "ESP RCP OTA abort failed"); } - imageProcessor->mRcpOtaHandle = 0; + imageProcessor->mRcpOtaHandle = 0; imageProcessor->mBrFirmwareSize = 0; - imageProcessor->mRcpDone = false; + imageProcessor->mRcpDone = false; #endif if (esp_ota_abort(imageProcessor->mOTAUpdateHandle) != ESP_OK) @@ -541,9 +541,9 @@ void OTAImageProcessorImpl::HandleProcessBlock(intptr_t context) // Apply the patch and writes that data to the passive partition. err = esp_delta_ota_feed_patch(imageProcessor->mDeltaOTAUpdateHandle, blockToWrite.data() + index, blockToWrite.size() - index); #elif defined(CONFIG_AUTO_UPDATE_RCP) && defined(CONFIG_OPENTHREAD_BORDER_ROUTER) - err = imageProcessor->ProcessRcpImage(context, blockToWrite.data(), blockToWrite.size()); + err = imageProcessor->ProcessRcpImage(context, blockToWrite.data(), blockToWrite.size()); #else - err = esp_ota_write(imageProcessor->mOTAUpdateHandle, blockToWrite.data(), blockToWrite.size()); + err = esp_ota_write(imageProcessor->mOTAUpdateHandle, blockToWrite.data(), blockToWrite.size()); #endif // CONFIG_ENABLE_DELTA_OTA #ifdef CONFIG_ENABLE_ENCRYPTED_OTA diff --git a/src/platform/ESP32/OTAImageProcessorImpl.h b/src/platform/ESP32/OTAImageProcessorImpl.h index 206b38d8067ab7..4d0ded9c222441 100644 --- a/src/platform/ESP32/OTAImageProcessorImpl.h +++ b/src/platform/ESP32/OTAImageProcessorImpl.h @@ -35,8 +35,8 @@ #if defined(CONFIG_AUTO_UPDATE_RCP) && defined(CONFIG_OPENTHREAD_BORDER_ROUTER) #include "esp_check.h" -#include "esp_rcp_update.h" #include "esp_rcp_ota.h" +#include "esp_rcp_update.h" #endif namespace chip { From 1a51dfe72fe61fb00a3f96e548b5cf97be7afbc2 Mon Sep 17 00:00:00 2001 From: liyashuai <liyashuai@espressif.com> Date: Tue, 18 Mar 2025 14:16:08 +0800 Subject: [PATCH 4/6] add thread br ota file generate and fix some issue --- config/esp32/components/chip/CMakeLists.txt | 25 ++++++++---- examples/thread-br-app/esp32/README.md | 12 ++---- src/platform/ESP32/OTAImageProcessorImpl.cpp | 41 ++++++++++---------- src/platform/ESP32/OTAImageProcessorImpl.h | 4 +- 4 files changed, 42 insertions(+), 40 deletions(-) diff --git a/config/esp32/components/chip/CMakeLists.txt b/config/esp32/components/chip/CMakeLists.txt index c1b0e0b6440cbe..7d3cc5440d4653 100644 --- a/config/esp32/components/chip/CMakeLists.txt +++ b/config/esp32/components/chip/CMakeLists.txt @@ -345,8 +345,8 @@ endif() set(args_gn "${CMAKE_CURRENT_BINARY_DIR}/args.gn") add_custom_command(OUTPUT "${args_gn}" - COMMAND ${python} - ${CMAKE_CURRENT_LIST_DIR}/create_args_gn.py + COMMAND ${python} + ${CMAKE_CURRENT_LIST_DIR}/create_args_gn.py "${CMAKE_BINARY_DIR}" "${idf_path}" "${CMAKE_CURRENT_LIST_DIR}/chip.c" @@ -468,10 +468,19 @@ endif() # Build Matter OTA image if (CONFIG_CHIP_OTA_IMAGE_BUILD) - chip_ota_image(chip-ota-image - INPUT_FILES ${BUILD_DIR}/${CMAKE_PROJECT_NAME}.bin - OUTPUT_FILE ${BUILD_DIR}/${CMAKE_PROJECT_NAME}-ota.bin - ) - # Adding dependecy as app target so that this runs after images are ready - add_dependencies(chip-ota-image app) + if (CONFIG_OPENTHREAD_BORDER_ROUTER AND CONFIG_AUTO_UPDATE_RCP) + chip_ota_image(chip-ota-image + INPUT_FILES ${BUILD_DIR}/ota_with_rcp_image + OUTPUT_FILE ${BUILD_DIR}/ota_with_rcp_image-ota.bin + ) + # Adding dependecy as app target so that this runs after images are ready + add_dependencies(chip-ota-image gen_ota_image) + else() + chip_ota_image(chip-ota-image + INPUT_FILES ${BUILD_DIR}/${CMAKE_PROJECT_NAME}.bin + OUTPUT_FILE ${BUILD_DIR}/${CMAKE_PROJECT_NAME}-ota.bin + ) + # Adding dependecy as app target so that this runs after images are ready + add_dependencies(chip-ota-image app) + endif() endif() diff --git a/examples/thread-br-app/esp32/README.md b/examples/thread-br-app/esp32/README.md index 4911db92f03987..138f18a13cab3c 100644 --- a/examples/thread-br-app/esp32/README.md +++ b/examples/thread-br-app/esp32/README.md @@ -97,12 +97,6 @@ the Thread network. ### Generate OTA Firmware For BR -After enable the option `CONFIG_CREATE_OTA_IMAGE_WITH_RCP_FW` in menuconfig, -will generate OTA image with rcp firmware in build process, named -`ota_with_rcp_image` in build folder. - -Then can add a Matter OTA header for the ota_with_rcp_image file. - -``` -./ota_image_tool.py create -v 65521 -p 32768 --version 1 --version-str "v1.0" -da sha256 build/ota_with_rcp_image ota_with_rcp_image.ota -``` +After enable the option `CONFIG_CREATE_OTA_IMAGE_WITH_RCP_FW` and +`CONFIG_CHIP_OTA_IMAGE_BUILD` in menuconfig, will generate OTA image with rcp +firmware, named `ota_with_rcp_image_ota.bin` in build folder. diff --git a/src/platform/ESP32/OTAImageProcessorImpl.cpp b/src/platform/ESP32/OTAImageProcessorImpl.cpp index 656fe6d55f58ba..539dfb0def5216 100644 --- a/src/platform/ESP32/OTAImageProcessorImpl.cpp +++ b/src/platform/ESP32/OTAImageProcessorImpl.cpp @@ -281,26 +281,25 @@ esp_err_t OTAImageProcessorImpl::DeltaOTAWriteCallback(const uint8_t * buf, size #endif // CONFIG_ENABLE_DELTA_OTA #if defined(CONFIG_AUTO_UPDATE_RCP) && defined(CONFIG_OPENTHREAD_BORDER_ROUTER) -esp_err_t OTAImageProcessorImpl::ProcessRcpImage(intptr_t context, const uint8_t * buffer, uint32_t bufLen) +esp_err_t OTAImageProcessorImpl::ProcessRcpImage(const uint8_t * buffer, uint32_t bufLen) { - esp_err_t err = ESP_OK; - auto * imageProcessor = reinterpret_cast<OTAImageProcessorImpl *>(context); + esp_err_t err = ESP_OK; - if (!imageProcessor->mRcpDone) + if (!this->mRcpFirmwareDownloaded) { size_t rcpOtaReceivedLen = 0; - err = esp_rcp_ota_receive(imageProcessor->mRcpOtaHandle, buffer, bufLen, &rcpOtaReceivedLen); + err = esp_rcp_ota_receive(this->mRcpOtaHandle, buffer, bufLen, &rcpOtaReceivedLen); - if (esp_rcp_ota_get_state(imageProcessor->mRcpOtaHandle) == ESP_RCP_OTA_STATE_FINISHED) + if (esp_rcp_ota_get_state(this->mRcpOtaHandle) == ESP_RCP_OTA_STATE_FINISHED) { - imageProcessor->mBrFirmwareSize = esp_rcp_ota_get_subfile_size(imageProcessor->mRcpOtaHandle, FILETAG_HOST_FIRMWARE); - err = esp_ota_write(imageProcessor->mOTAUpdateHandle, buffer + rcpOtaReceivedLen, bufLen - rcpOtaReceivedLen); - imageProcessor->mRcpDone = true; + this->mBrFirmwareSize = esp_rcp_ota_get_subfile_size(this->mRcpOtaHandle, FILETAG_HOST_FIRMWARE); + err = esp_ota_write(this->mOTAUpdateHandle, buffer + rcpOtaReceivedLen, bufLen - rcpOtaReceivedLen); + this->mRcpFirmwareDownloaded = true; } } - else if (imageProcessor->mBrFirmwareSize > 0) + else if (this->mBrFirmwareSize > 0) { - err = esp_ota_write(imageProcessor->mOTAUpdateHandle, buffer, bufLen); + err = esp_ota_write(this->mOTAUpdateHandle, buffer, bufLen); } else { @@ -369,9 +368,9 @@ void OTAImageProcessorImpl::HandlePrepareDownload(intptr_t context) #endif // CONFIG_ENABLE_ENCRYPTED_OTA #if defined(CONFIG_AUTO_UPDATE_RCP) && defined(CONFIG_OPENTHREAD_BORDER_ROUTER) - imageProcessor->mRcpOtaHandle = 0; - imageProcessor->mBrFirmwareSize = 0; - imageProcessor->mRcpDone = false; + imageProcessor->mRcpOtaHandle = 0; + imageProcessor->mBrFirmwareSize = 0; + imageProcessor->mRcpFirmwareDownloaded = false; if (esp_rcp_ota_begin(&imageProcessor->mRcpOtaHandle) != ESP_OK) { return; @@ -424,9 +423,9 @@ void OTAImageProcessorImpl::HandleFinalize(intptr_t context) #elif defined(CONFIG_AUTO_UPDATE_RCP) && defined(CONFIG_OPENTHREAD_BORDER_ROUTER) esp_err_t err = esp_rcp_ota_end(imageProcessor->mRcpOtaHandle); err |= esp_ota_end(imageProcessor->mOTAUpdateHandle); - imageProcessor->mRcpOtaHandle = 0; - imageProcessor->mBrFirmwareSize = 0; - imageProcessor->mRcpDone = false; + imageProcessor->mRcpOtaHandle = 0; + imageProcessor->mBrFirmwareSize = 0; + imageProcessor->mRcpFirmwareDownloaded = false; #else esp_err_t err = esp_ota_end(imageProcessor->mOTAUpdateHandle); #endif // CONFIG_ENABLE_DELTA_OTA @@ -473,9 +472,9 @@ void OTAImageProcessorImpl::HandleAbort(intptr_t context) { ESP_LOGE(TAG, "ESP RCP OTA abort failed"); } - imageProcessor->mRcpOtaHandle = 0; - imageProcessor->mBrFirmwareSize = 0; - imageProcessor->mRcpDone = false; + imageProcessor->mRcpOtaHandle = 0; + imageProcessor->mBrFirmwareSize = 0; + imageProcessor->mRcpFirmwareDownloaded = false; #endif if (esp_ota_abort(imageProcessor->mOTAUpdateHandle) != ESP_OK) @@ -541,7 +540,7 @@ void OTAImageProcessorImpl::HandleProcessBlock(intptr_t context) // Apply the patch and writes that data to the passive partition. err = esp_delta_ota_feed_patch(imageProcessor->mDeltaOTAUpdateHandle, blockToWrite.data() + index, blockToWrite.size() - index); #elif defined(CONFIG_AUTO_UPDATE_RCP) && defined(CONFIG_OPENTHREAD_BORDER_ROUTER) - err = imageProcessor->ProcessRcpImage(context, blockToWrite.data(), blockToWrite.size()); + err = imageProcessor->ProcessRcpImage(blockToWrite.data(), blockToWrite.size()); #else err = esp_ota_write(imageProcessor->mOTAUpdateHandle, blockToWrite.data(), blockToWrite.size()); #endif // CONFIG_ENABLE_DELTA_OTA diff --git a/src/platform/ESP32/OTAImageProcessorImpl.h b/src/platform/ESP32/OTAImageProcessorImpl.h index 4d0ded9c222441..ac607768e905d8 100644 --- a/src/platform/ESP32/OTAImageProcessorImpl.h +++ b/src/platform/ESP32/OTAImageProcessorImpl.h @@ -108,9 +108,9 @@ class OTAImageProcessorImpl : public OTAImageProcessorInterface #if defined(CONFIG_AUTO_UPDATE_RCP) && defined(CONFIG_OPENTHREAD_BORDER_ROUTER) esp_rcp_ota_handle_t mRcpOtaHandle; - bool mRcpDone; + bool mRcpFirmwareDownloaded; uint32_t mBrFirmwareSize; - esp_err_t ProcessRcpImage(intptr_t context, const uint8_t * buffer, uint32_t bufLen); + esp_err_t ProcessRcpImage(const uint8_t * buffer, uint32_t bufLen); #endif }; From c6a1c74d63cd3705a602e62387869c43588cf948 Mon Sep 17 00:00:00 2001 From: liyashuai <liyashuai@espressif.com> Date: Wed, 19 Mar 2025 10:31:03 +0800 Subject: [PATCH 5/6] fix restyled error --- examples/thread-br-app/esp32/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/thread-br-app/esp32/README.md b/examples/thread-br-app/esp32/README.md index 138f18a13cab3c..3fdcfa5899659b 100644 --- a/examples/thread-br-app/esp32/README.md +++ b/examples/thread-br-app/esp32/README.md @@ -97,6 +97,6 @@ the Thread network. ### Generate OTA Firmware For BR -After enable the option `CONFIG_CREATE_OTA_IMAGE_WITH_RCP_FW` and -`CONFIG_CHIP_OTA_IMAGE_BUILD` in menuconfig, will generate OTA image with rcp +After enable the option `CONFIG_CREATE_OTA_IMAGE_WITH_RCP_FW` and +`CONFIG_CHIP_OTA_IMAGE_BUILD` in menuconfig, will generate OTA image with rcp firmware, named `ota_with_rcp_image_ota.bin` in build folder. From 9ef3c3e63603c2c53c8413961a59e0168aaeb1b1 Mon Sep 17 00:00:00 2001 From: Jerry-ESP <107675966+Jerry-ESP@users.noreply.github.com> Date: Thu, 20 Mar 2025 10:16:16 +0800 Subject: [PATCH 6/6] Update src/platform/ESP32/OTAImageProcessorImpl.cpp Co-authored-by: Wang Qixiang <43193572+wqx6@users.noreply.github.com> --- src/platform/ESP32/OTAImageProcessorImpl.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/platform/ESP32/OTAImageProcessorImpl.cpp b/src/platform/ESP32/OTAImageProcessorImpl.cpp index 539dfb0def5216..839b84134b6680 100644 --- a/src/platform/ESP32/OTAImageProcessorImpl.cpp +++ b/src/platform/ESP32/OTAImageProcessorImpl.cpp @@ -285,7 +285,7 @@ esp_err_t OTAImageProcessorImpl::ProcessRcpImage(const uint8_t * buffer, uint32_ { esp_err_t err = ESP_OK; - if (!this->mRcpFirmwareDownloaded) + if (!mRcpFirmwareDownloaded) { size_t rcpOtaReceivedLen = 0; err = esp_rcp_ota_receive(this->mRcpOtaHandle, buffer, bufLen, &rcpOtaReceivedLen);