From 77fb4e42bd256e66d066d8137dc9eeb4e16c818f Mon Sep 17 00:00:00 2001 From: Xu Si Yu Date: Thu, 23 Jan 2025 21:08:26 +0800 Subject: [PATCH] feat(openthread): add an API to set rcp version string --- .../include/esp_openthread_border_router.h | 39 +------- .../include/esp_openthread_spinel.h | 71 ++++++++++++++ .../openthread/include/esp_openthread_types.h | 10 +- .../openthread-core-esp32x-ftd-config.h | 10 -- .../src/port/esp_openthread_radio_spinel.cpp | 94 +++++++------------ .../src/port/esp_openthread_state.c | 2 +- 6 files changed, 117 insertions(+), 109 deletions(-) create mode 100644 components/openthread/include/esp_openthread_spinel.h diff --git a/components/openthread/include/esp_openthread_border_router.h b/components/openthread/include/esp_openthread_border_router.h index 8960fc861d..6fe915bc53 100644 --- a/components/openthread/include/esp_openthread_border_router.h +++ b/components/openthread/include/esp_openthread_border_router.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2021-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -9,6 +9,7 @@ #include "esp_netif.h" #include "esp_netif_types.h" #include "esp_openthread.h" +#include "esp_openthread_spinel.h" #include "openthread/instance.h" #ifdef __cplusplus @@ -60,42 +61,6 @@ esp_err_t esp_openthread_border_router_deinit(void); */ esp_netif_t *esp_openthread_get_backbone_netif(void); -/** - * @brief Registers the callback for RCP failure. - * - */ -void esp_openthread_register_rcp_failure_handler(esp_openthread_rcp_failure_handler handler); - -/** - * @brief Registers the callback for spinel compatibility error. - * - * @note This function must be called before esp_openthread_init. - * - * @param[in] callback The callback. - * - */ -void esp_openthread_set_compatibility_error_callback(esp_openthread_compatibility_error_callback callback); - -/** - * @brief Deinitializes the connection to RCP. - * - * @return - * - ESP_OK on success - * - ESP_ERR_INVALID_STATE if fail to deinitialize RCP - * - */ -esp_err_t esp_openthread_rcp_deinit(void); - -/** - * @brief Initializes the connection to RCP. - * - * @return - * - ESP_OK on success - * - ESP_FAIL if fail to initialize RCP - * - */ -esp_err_t esp_openthread_rcp_init(void); - /** * @brief Sets the meshcop(e) instance name. * diff --git a/components/openthread/include/esp_openthread_spinel.h b/components/openthread/include/esp_openthread_spinel.h new file mode 100644 index 0000000000..70c74413e2 --- /dev/null +++ b/components/openthread/include/esp_openthread_spinel.h @@ -0,0 +1,71 @@ +/* + * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include "sdkconfig.h" +#include "esp_openthread_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Registers the callback for RCP failure. + * + */ +void esp_openthread_register_rcp_failure_handler(esp_openthread_rcp_failure_handler handler); + +/** + * @brief Registers the callback for spinel compatibility error. + * + * @note This function should be called before esp_openthread_init. + * + * @param[in] callback The callback. + * + */ +void esp_openthread_set_compatibility_error_callback(esp_openthread_compatibility_error_callback callback); + +/** + * @brief Deinitializes the connection to RCP. + * + * @return + * - ESP_OK on success + * - ESP_ERR_INVALID_STATE if fail to deinitialize RCP + * + */ +esp_err_t esp_openthread_rcp_deinit(void); + +/** + * @brief Initializes the connection to RCP. + * + * @return + * - ESP_OK on success + * - ESP_FAIL if fail to initialize RCP + * + */ +esp_err_t esp_openthread_rcp_init(void); + +/** + * @brief Set the RCP version string. + * + * @note This function should be called before esp_openthread_init. When the RCP version string is not an empty string, + * compatibility checks will be performed during the initialization of the ESP OpenThread radio spinel. + * The `esp_openthread_compatibility_error_callback` will be triggered if the desired RCP version does not match + * the actual version running on the RCP. If needed, a NULL parameter can be passed to clear the version string. + * + * @param[in] version_str The pointer to RCP version string. + * + * @return + * - ESP_OK on success + * - ESP_FAIL if fail to set RCP version string + * + */ +esp_err_t esp_openthread_rcp_version_set(const char *version_str); + +#ifdef __cplusplus +} +#endif diff --git a/components/openthread/include/esp_openthread_types.h b/components/openthread/include/esp_openthread_types.h index ce1d258a3d..df552ed142 100644 --- a/components/openthread/include/esp_openthread_types.h +++ b/components/openthread/include/esp_openthread_types.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2021-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -198,8 +198,16 @@ typedef struct { esp_openthread_port_config_t port_config; /*!< The port configuration */ } esp_openthread_platform_config_t; +/** + * @brief The OpenThread rcp failure handler + * + */ typedef void (*esp_openthread_rcp_failure_handler)(void); +/** + * @brief The OpenThread compatibility error callback + * + */ typedef void (*esp_openthread_compatibility_error_callback)(void); #ifdef __cplusplus diff --git a/components/openthread/private_include/openthread-core-esp32x-ftd-config.h b/components/openthread/private_include/openthread-core-esp32x-ftd-config.h index 1386dff4a3..4f3b1f7fd6 100644 --- a/components/openthread/private_include/openthread-core-esp32x-ftd-config.h +++ b/components/openthread/private_include/openthread-core-esp32x-ftd-config.h @@ -494,16 +494,6 @@ #define OPENTHREAD_POSIX_CONFIG_RCP_TIME_SYNC_INTERVAL (60 * 1000 * 1000) #endif -#if CONFIG_EXTERNAL_COEX_ENABLE -/** - * @def OPENTHREAD_SPINEL_CONFIG_VENDOR_HOOK_ENABLE - * - * Enables compilation of vendor specific code for Spinel - */ -#ifndef OPENTHREAD_SPINEL_CONFIG_VENDOR_HOOK_ENABLE -#define OPENTHREAD_SPINEL_CONFIG_VENDOR_HOOK_ENABLE 1 -#endif -#endif #endif // CONFIG_OPENTHREAD_RADIO_SPINEL_UART || CONFIG_OPENTHREAD_RADIO_SPINEL_SPI #if CONFIG_OPENTHREAD_LINK_METRICS diff --git a/components/openthread/src/port/esp_openthread_radio_spinel.cpp b/components/openthread/src/port/esp_openthread_radio_spinel.cpp index 63049e86f8..066bf8b5c6 100644 --- a/components/openthread/src/port/esp_openthread_radio_spinel.cpp +++ b/components/openthread/src/port/esp_openthread_radio_spinel.cpp @@ -25,6 +25,9 @@ #include "openthread/platform/time.h" #include "platform/exit_code.h" #include "spinel_driver.hpp" +#include + +#define OT_SPINEL_RCP_VERSION_MAX_SIZE 100 using ot::Spinel::RadioSpinel; using esp::openthread::SpinelInterfaceAdapter; @@ -56,34 +59,7 @@ static const esp_openthread_radio_config_t *s_esp_openthread_radio_config = NULL static esp_openthread_compatibility_error_callback s_compatibility_error_callback = NULL; -#if CONFIG_EXTERNAL_COEX_ENABLE - -#define SPINEL_PROP_VENDOR_ESP_COEX_EVENT (SPINEL_PROP_VENDOR_ESP__BEGIN + 3) - -static esp_ieee802154_coex_config_t s_coex_config = { - .idle = IEEE802154_IDLE, - .txrx = IEEE802154_LOW, - .txrx_at = IEEE802154_MIDDLE, -}; - -static void esp_openthread_restore_coex_config(void *context) -{ - esp_openthread_set_coex_config(s_coex_config); -} - -static esp_err_t esp_openthread_radio_spinel_coex_config_init(void) -{ - s_radio.SetVendorRestorePropertiesCallback(esp_openthread_restore_coex_config, esp_openthread_get_instance()); - esp_ieee802154_coex_config_t coex_config; - uint16_t coex_config_len = 0; - ESP_RETURN_ON_ERROR(s_radio.Get(SPINEL_PROP_VENDOR_ESP_COEX_EVENT, SPINEL_DATATYPE_DATA_WLEN_S, &coex_config, &coex_config_len), - OT_PLAT_LOG_TAG, "Fail to get coex config"); - ESP_RETURN_ON_FALSE(coex_config_len == sizeof(esp_ieee802154_coex_config_t), ESP_FAIL, OT_PLAT_LOG_TAG, - "Fail to get coex config"); - s_coex_config = coex_config; - return ESP_OK; -} -#endif +static char s_internal_rcp_version[OT_SPINEL_RCP_VERSION_MAX_SIZE] = {'\0'}; static void esp_openthread_radio_config_set(const esp_openthread_radio_config_t *config) { @@ -136,11 +112,18 @@ esp_err_t esp_openthread_radio_init(const esp_openthread_platform_config_t *conf "Spinel interface init failed"); #endif s_spinel_driver.Init(s_spinel_interface.GetSpinelInterface(), true, iidList, ot::Spinel::kSpinelHeaderMaxNumIid); + if (strlen(s_internal_rcp_version) > 0) { + const char *running_rcp_version = s_spinel_driver.GetVersion(); + if (strcmp(s_internal_rcp_version, running_rcp_version) != 0) { + if (s_compatibility_error_callback) { + s_compatibility_error_callback(); + } else { + ESP_LOGW(OT_PLAT_LOG_TAG, "The running rcp does not match the provided rcp"); + } + } + } s_radio.SetCompatibilityErrorCallback(ot_spinel_compatibility_error_callback, esp_openthread_get_instance()); s_radio.Init(/*skip_rcp_compatibility_check=*/false, /*reset_radio=*/true, &s_spinel_driver, s_radio_caps, /*RCP_time_sync=*/true); -#if CONFIG_EXTERNAL_COEX_ENABLE - ESP_RETURN_ON_ERROR(esp_openthread_radio_spinel_coex_config_init(), OT_PLAT_LOG_TAG, "Coex config init failed"); -#endif #if CONFIG_OPENTHREAD_RADIO_SPINEL_SPI // CONFIG_OPENTHREAD_RADIO_SPINEL_SPI ESP_RETURN_ON_ERROR(s_spinel_interface.GetSpinelInterface().AfterRadioInit(), OT_PLAT_LOG_TAG, "Spinel interface init failed"); #endif @@ -185,12 +168,24 @@ esp_err_t esp_openthread_rcp_init(void) radiospinel_workflow); } +esp_err_t esp_openthread_rcp_version_set(const char *version_str) +{ + if (version_str == NULL) { + memset(s_internal_rcp_version, 0, OT_SPINEL_RCP_VERSION_MAX_SIZE); + return ESP_OK; + } + ESP_RETURN_ON_FALSE(strlen(version_str) > 0 && strlen(version_str) < OT_SPINEL_RCP_VERSION_MAX_SIZE, ESP_FAIL, OT_PLAT_LOG_TAG, "Invalid rcp version"); + strcpy(s_internal_rcp_version, version_str); + return ESP_OK; +} + void esp_openthread_radio_deinit(void) { s_radio.Deinit(); s_spinel_driver.Deinit(); s_spinel_interface.GetSpinelInterface().Disable(); esp_openthread_platform_workflow_unregister(radiospinel_workflow); + s_compatibility_error_callback = NULL; } esp_err_t esp_openthread_radio_process(otInstance *instance, const esp_openthread_mainloop_context_t *mainloop) @@ -502,37 +497,16 @@ uint16_t otPlatTimeGetXtalAccuracy(void) return CONFIG_OPENTHREAD_XTAL_ACCURACY; } -#if CONFIG_EXTERNAL_COEX_ENABLE -void esp_openthread_set_coex_config(esp_ieee802154_coex_config_t config) +uint32_t otPlatRadioGetPreferredChannelMask(otInstance *aInstance) { - otError err = s_radio.Set(SPINEL_PROP_VENDOR_ESP_COEX_EVENT, SPINEL_DATATYPE_DATA_WLEN_S, &s_coex_config, sizeof(esp_ieee802154_coex_config_t)); - ESP_RETURN_ON_FALSE(err == OT_ERROR_NONE, , OT_PLAT_LOG_TAG, "Fail to set coex config"); - s_coex_config = config; + OT_UNUSED_VARIABLE(aInstance); + // Refer to `GetRadioChannelMask(bool aPreferred)`: TRUE to get preferred channel mask + return s_radio.GetRadioChannelMask(true); } -esp_ieee802154_coex_config_t esp_openthread_get_coex_config(void) +uint32_t otPlatRadioGetSupportedChannelMask(otInstance *aInstance) { - return s_coex_config; + OT_UNUSED_VARIABLE(aInstance); + // Refer to `GetRadioChannelMask(bool aPreferred)`: FALSE to get supported channel mask + return s_radio.GetRadioChannelMask(false); } - -namespace ot { -namespace Spinel { - -otError RadioSpinel::VendorHandleValueIs(spinel_prop_key_t aPropKey) -{ - otError error = OT_ERROR_NONE; - - switch (aPropKey) - { - default: - ESP_LOGW(OT_PLAT_LOG_TAG, "Not Implemented!"); - error = OT_ERROR_NOT_FOUND; - break; - } - return error; -} - -} // namespace Spinel -} // namespace ot - -#endif diff --git a/components/openthread/src/port/esp_openthread_state.c b/components/openthread/src/port/esp_openthread_state.c index 7f89304060..7dac89c3ef 100644 --- a/components/openthread/src/port/esp_openthread_state.c +++ b/components/openthread/src/port/esp_openthread_state.c @@ -63,7 +63,7 @@ static void handle_ot_netdata_change(void) static void handle_ot_role_change(otInstance* instance) { -#if ((CONFIG_ESP_COEX_SW_COEXIST_ENABLE && OPENTHREAD_RADIO_NATIVE) || CONFIG_EXTERNAL_COEX_ENABLE) +#if ((CONFIG_ESP_COEX_SW_COEXIST_ENABLE || CONFIG_EXTERNAL_COEX_ENABLE) && OPENTHREAD_RADIO_NATIVE) otLinkModeConfig linkmode = otThreadGetLinkMode(instance); esp_ieee802154_coex_config_t config = esp_openthread_get_coex_config(); config.txrx = (linkmode.mRxOnWhenIdle) ? IEEE802154_LOW : IEEE802154_MIDDLE;