Merge branch 'feat/add_callback_for_esp_ot_radio_spinel_init_v5.2' into 'release/v5.2'

feat(openthread): add an API to set rcp version string(v5.2)

See merge request espressif/esp-idf!36598
This commit is contained in:
Jiang Jiang Jian 2025-03-03 11:54:20 +08:00
commit dc1e3c7265
6 changed files with 109 additions and 116 deletions

View File

@ -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.
*

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -25,6 +25,9 @@
#include "openthread/platform/time.h"
#include "platform/exit_code.h"
#include "spinel_driver.hpp"
#include <cstring>
#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)
@ -515,39 +510,3 @@ uint32_t otPlatRadioGetSupportedChannelMask(otInstance *aInstance)
// Refer to `GetRadioChannelMask(bool aPreferred)`: FALSE to get supported channel mask
return s_radio.GetRadioChannelMask(false);
}
#if CONFIG_EXTERNAL_COEX_ENABLE
void esp_openthread_set_coex_config(esp_ieee802154_coex_config_t config)
{
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;
}
esp_ieee802154_coex_config_t esp_openthread_get_coex_config(void)
{
return s_coex_config;
}
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

View File

@ -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;