diff --git a/components/esp_matter_thread_br/CMakeLists.txt b/components/esp_matter_thread_br/CMakeLists.txt index 243e29500..f0826fddc 100644 --- a/components/esp_matter_thread_br/CMakeLists.txt +++ b/components/esp_matter_thread_br/CMakeLists.txt @@ -10,3 +10,7 @@ endif() idf_component_register(SRCS ${SRCS_LIST} INCLUDE_DIRS "." REQUIRES esp_matter openthread esp_netif vfs) + +if(CONFIG_OPENTHREAD_BR_AUTO_UPDATE_RCP) + idf_component_optional_requires(PRIVATE spiffs esp_rcp_update) +endif() \ No newline at end of file diff --git a/components/esp_matter_thread_br/Kconfig b/components/esp_matter_thread_br/Kconfig new file mode 100644 index 000000000..875c9fafd --- /dev/null +++ b/components/esp_matter_thread_br/Kconfig @@ -0,0 +1,11 @@ +menu "ESP Matter with Thread BR" + depends on OPENTHREAD_BORDER_ROUTER + + config OPENTHREAD_BR_AUTO_UPDATE_RCP + bool 'Update RCP automatically' + default n + help + If enabled, the Thread Border Router will store the RCP image in its firmware and + compare the stored image version with the running RCP image upon boot. The RCP + will be automatically updated upon version mismatch. +endmenu diff --git a/components/esp_matter_thread_br/esp_matter_thread_br_launcher.cpp b/components/esp_matter_thread_br/esp_matter_thread_br_launcher.cpp index d0a58ec09..202087bf2 100644 --- a/components/esp_matter_thread_br/esp_matter_thread_br_launcher.cpp +++ b/components/esp_matter_thread_br/esp_matter_thread_br_launcher.cpp @@ -20,6 +20,9 @@ #include #include #include +#if CONFIG_OPENTHREAD_BR_AUTO_UPDATE_RCP +#include +#endif #include #include #include @@ -82,6 +85,56 @@ esp_err_t cli_transmit_task_post(ot_cli_buffer_t &cli_buf) } #endif // CONFIG_OPENTHREAD_CLI +#if CONFIG_OPENTHREAD_BR_AUTO_UPDATE_RCP +#define RCP_VERSION_MAX_SIZE 100 + +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_rcp_mark_image_verified(true); + } else { + esp_rcp_mark_image_verified(false); + } + esp_restart(); +} + +static void try_update_ot_rcp(void) +{ + ESP_LOGW(TAG, "Try to update openthread rcp"); + char internal_rcp_version[RCP_VERSION_MAX_SIZE]; + const char *running_rcp_version = otPlatRadioGetVersionString(esp_openthread_get_instance()); + + 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); + ESP_LOGI(TAG, "Running RCP Version: %s", running_rcp_version); + if (strcmp(internal_rcp_version, running_rcp_version) == 0) { + esp_rcp_mark_image_verified(true); + } else { + 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(); + } +} + +static void rcp_failure_handler(void) +{ + esp_rcp_mark_image_unusable(); + try_update_ot_rcp(); + esp_rcp_reset(); +} + +esp_err_t thread_rcp_update_init(const esp_rcp_update_config_t *update_config) +{ + return esp_rcp_update_init(update_config); +} + +#endif // CONFIG_OPENTHREAD_BR_AUTO_UPDATE_RCP + static void ot_task_worker(void *aContext) { esp_openthread_platform_config_t *config = static_cast(aContext); @@ -90,12 +143,18 @@ static void ot_task_worker(void *aContext) assert(openthread_netif != NULL); // Initialize the OpenThread stack +#if CONFIG_OPENTHREAD_BR_AUTO_UPDATE_RCP + esp_openthread_register_rcp_failure_handler(rcp_failure_handler); +#endif ESP_ERROR_CHECK(esp_openthread_init(config)); #if CONFIG_OPENTHREAD_CLI otCliInit(esp_openthread_get_instance(), cli_output_callback, NULL); #endif // Initialize border routing features esp_openthread_lock_acquire(portMAX_DELAY); +#if CONFIG_OPENTHREAD_BR_AUTO_UPDATE_RCP + try_update_ot_rcp(); +#endif ESP_ERROR_CHECK(esp_netif_attach(openthread_netif, esp_openthread_netif_glue_init(config))); ESP_ERROR_CHECK(esp_openthread_border_router_init()); #if CONFIG_OPENTHREAD_LOG_LEVEL_DYNAMIC @@ -120,6 +179,16 @@ static void ot_task_worker(void *aContext) vTaskDelete(NULL); } +static esp_err_t init_spiffs(void) +{ +#if CONFIG_OPENTHREAD_BR_AUTO_UPDATE_RCP + esp_vfs_spiffs_conf_t rcp_fw_conf = { + .base_path = "/rcp_fw", .partition_label = "rcp_fw", .max_files = 10, .format_if_mount_failed = false}; + ESP_RETURN_ON_ERROR(esp_vfs_spiffs_register(&rcp_fw_conf), TAG, "Failed to mount rcp firmware storage"); +#endif + return ESP_OK; +} + esp_err_t thread_br_init(esp_openthread_platform_config_t *config) { static bool thread_br_initialized = false; @@ -139,6 +208,7 @@ esp_err_t thread_br_init(esp_openthread_platform_config_t *config) #endif }; ESP_RETURN_ON_ERROR(esp_vfs_eventfd_register(&eventfd_config), TAG, "Failed to register eventfd"); + ESP_ERROR_CHECK(init_spiffs()); esp_openthread_set_backbone_netif(esp_netif_get_handle_from_ifkey("WIFI_STA_DEF")); esp_openthread_platform_config_t *config_copy = diff --git a/components/esp_matter_thread_br/esp_matter_thread_br_launcher.h b/components/esp_matter_thread_br/esp_matter_thread_br_launcher.h index da2c8124f..b8e7a10d9 100644 --- a/components/esp_matter_thread_br/esp_matter_thread_br_launcher.h +++ b/components/esp_matter_thread_br/esp_matter_thread_br_launcher.h @@ -15,6 +15,9 @@ #pragma once #include +#if CONFIG_OPENTHREAD_BR_AUTO_UPDATE_RCP +#include +#endif #define OPENTHREAD_CLI_BUFFER_LENGTH 255 @@ -27,6 +30,10 @@ typedef struct { esp_err_t thread_br_init(esp_openthread_platform_config_t *config); +#if CONFIG_OPENTHREAD_BR_AUTO_UPDATE_RCP +esp_err_t thread_rcp_update_init(const esp_rcp_update_config_t *update_config); +#endif + esp_err_t set_thread_enabled(bool enabled); esp_err_t set_thread_dataset_tlvs(otOperationalDatasetTlvs *dataset_tlvs); diff --git a/components/esp_matter_thread_br/idf_component.yml b/components/esp_matter_thread_br/idf_component.yml new file mode 100644 index 000000000..46c8b2b32 --- /dev/null +++ b/components/esp_matter_thread_br/idf_component.yml @@ -0,0 +1,10 @@ +## IDF Component Manager Manifest File +dependencies: + espressif/esp_rcp_update: + version: "~1.0.0" + rules: + - if: "idf_version >=5.0" + espressif/esp-serial-flasher: + version: "~0.0.0" + rules: + - if: "idf_version >=5.0"