Merge branch 'backport/openthread_related_feature_v52' into 'release/v5.2'

Backport some openthread related features (backport v5.2)

See merge request espressif/esp-idf!28053
This commit is contained in:
Jiang Jiang Jian 2023-12-25 20:37:03 +08:00
commit 3139ae0f0e
30 changed files with 849 additions and 275 deletions

View File

@ -17,6 +17,7 @@ typedef enum {
void esp_coex_ieee802154_txrx_pti_set(ieee802154_coex_event_t event); void esp_coex_ieee802154_txrx_pti_set(ieee802154_coex_event_t event);
void esp_coex_ieee802154_ack_pti_set(ieee802154_coex_event_t event); void esp_coex_ieee802154_ack_pti_set(ieee802154_coex_event_t event);
void esp_coex_ieee802154_coex_break_notify(void);
#endif #endif
#endif #endif

@ -1 +1 @@
Subproject commit b5da84bed42578946162241cfc6b37449bd2c251 Subproject commit 667353cc7a0520924135ce50b798f495cd308e47

View File

@ -455,6 +455,85 @@ static inline void ieee802154_ll_disable_coex(void)
IEEE802154.pti.hw_ack_pti = 1; IEEE802154.pti.hw_ack_pti = 1;
} }
static inline void ieee802154_ll_clear_debug_cnt(uint32_t clear_bits)
{
IEEE802154.debug_cnt_clr.val = clear_bits;
}
static inline uint32_t ieee802154_ll_get_sfd_timeout_cnt(void)
{
return IEEE802154.debug_sfd_timeout_cnt;
}
static inline uint32_t ieee802154_ll_get_crc_error_cnt(void)
{
return IEEE802154.debug_crc_error_cnt;
}
static inline uint32_t ieee802154_ll_get_ed_abort_cnt(void)
{
return IEEE802154.debug_ed_abort_cnt;
}
static inline uint32_t ieee802154_ll_get_cca_fail_cnt(void)
{
return IEEE802154.debug_cca_fail_cnt;
}
static inline uint32_t ieee802154_ll_get_rx_fliter_fail_cnt(void)
{
return IEEE802154.debug_rx_filter_fail_cnt;
}
static inline uint32_t ieee802154_ll_get_no_rss_detect_cnt(void)
{
return IEEE802154.debug_no_rss_detect_cnt;
}
static inline uint32_t ieee802154_ll_get_rx_abort_coex_cnt(void)
{
return IEEE802154.debug_rx_abort_coex_cnt;
}
static inline uint32_t ieee802154_ll_get_rx_restart_cnt(void)
{
return IEEE802154.debug_rx_restart_cnt;
}
static inline uint32_t ieee802154_ll_get_tx_ack_abort_coex_cnt(void)
{
return IEEE802154.debug_tx_ack_abort_coex_cnt;
}
static inline uint32_t ieee802154_ll_get_ed_scan_coex_cnt(void)
{
return IEEE802154.debug_ed_scan_break_coex_cnt;
}
static inline uint32_t ieee802154_ll_get_rx_ack_abort_coex_cnt(void)
{
return IEEE802154.debug_rx_ack_abort_coex_cnt;
}
static inline uint32_t ieee802154_ll_get_rx_ack_timeout_cnt(void)
{
return IEEE802154.debug_rx_ack_timeout_cnt;
}
static inline uint32_t ieee802154_ll_get_tx_break_coex_cnt(void)
{
return IEEE802154.debug_tx_break_coex_cnt;
}
static inline uint32_t ieee802154_ll_get_tx_security_error_cnt(void)
{
return IEEE802154.debug_tx_security_error_cnt;
}
static inline uint32_t ieee802154_ll_get_cca_busy_cnt(void)
{
return IEEE802154.debug_cca_busy_cnt;
}
#endif #endif
#ifdef __cplusplus #ifdef __cplusplus

View File

@ -159,4 +159,11 @@ menu "IEEE 802.15.4"
default 10 default 10
help help
set the record abort table size set the record abort table size
config IEEE802154_TXRX_STATISTIC
bool "Enable record tx/rx packets information for debugging"
depends on IEEE802154_DEBUG
default n
help
Enabling this option to record the tx and rx
endmenu # IEEE 802.15.4 endmenu # IEEE 802.15.4

View File

@ -5,6 +5,7 @@
*/ */
#include <stdio.h> #include <stdio.h>
#include <string.h>
#include "hal/ieee802154_ll.h" #include "hal/ieee802154_ll.h"
#include "esp_ieee802154_util.h" #include "esp_ieee802154_util.h"
#include "esp_log.h" #include "esp_log.h"
@ -237,4 +238,122 @@ void ieee802154_assert_print(void)
} }
#endif // CONFIG_IEEE802154_ASSERT #endif // CONFIG_IEEE802154_ASSERT
#if CONFIG_IEEE802154_TXRX_STATISTIC
static ieee802154_txrx_statistic_t s_ieee802154_txrx_statistic;
void ieee802154_txrx_statistic_clear(void)
{
memset(&s_ieee802154_txrx_statistic, 0, sizeof(ieee802154_txrx_statistic_t));
}
void ieee802154_txrx_statistic(ieee802154_ll_events events)
{
if (events == IEEE802154_EVENT_TX_DONE) {
s_ieee802154_txrx_statistic.tx.done_nums++;
} else if (events == IEEE802154_EVENT_RX_DONE) {
s_ieee802154_txrx_statistic.rx.done_nums++;
}
s_ieee802154_txrx_statistic.tx.abort.cca_busy_nums += ieee802154_ll_get_cca_busy_cnt();
ieee802154_ll_clear_debug_cnt(IEEE802154_CCA_BUSY_CNT_CLEAR);
s_ieee802154_txrx_statistic.tx.abort.tx_security_error_nums += ieee802154_ll_get_tx_security_error_cnt();
ieee802154_ll_clear_debug_cnt(IEEE802154_TX_SECURITY_ERROR_CNT_CLEAR);
// Do not record TX_BREAK_COEX_ERR due to ZB-105.
s_ieee802154_txrx_statistic.tx.abort.rx_ack_timeout_nums += ieee802154_ll_get_rx_ack_timeout_cnt();
ieee802154_ll_clear_debug_cnt(IEEE802154_RX_ACK_TIMEOUT_CNT_CLEAR);
s_ieee802154_txrx_statistic.tx.abort.rx_ack_coex_break_nums += ieee802154_ll_get_rx_ack_abort_coex_cnt();
ieee802154_ll_clear_debug_cnt(IEEE802154_RX_ACK_ABORT_COEX_CNT_CLEAR);
s_ieee802154_txrx_statistic.tx.abort.cca_failed_nums += ieee802154_ll_get_cca_fail_cnt();
ieee802154_ll_clear_debug_cnt(IEEE802154_CCA_FAIL_CNT_CLEAR);
s_ieee802154_txrx_statistic.rx.abort.tx_ack_coex_break_nums += ieee802154_ll_get_tx_ack_abort_coex_cnt();
ieee802154_ll_clear_debug_cnt(IEEE802154_TX_ACK_ABORT_COEX_CNT_CLEAR);
s_ieee802154_txrx_statistic.rx.abort.rx_restart_nums += ieee802154_ll_get_rx_restart_cnt();
ieee802154_ll_clear_debug_cnt(IEEE802154_RX_RESTART_CNT_CLEAR);
s_ieee802154_txrx_statistic.rx.abort.rx_coex_break_nums += ieee802154_ll_get_rx_abort_coex_cnt();
ieee802154_ll_clear_debug_cnt(IEEE802154_RX_ABORT_COEX_CNT_CLEAR);
s_ieee802154_txrx_statistic.rx.abort.no_rss_nums += ieee802154_ll_get_no_rss_detect_cnt();
ieee802154_ll_clear_debug_cnt(IEEE802154_NO_RSS_DETECT_CNT_CLEAR);
s_ieee802154_txrx_statistic.rx.abort.filter_fail_nums += ieee802154_ll_get_rx_fliter_fail_cnt();
ieee802154_ll_clear_debug_cnt(IEEE802154_RX_FILTER_FAIL_CNT_CLEAR);
s_ieee802154_txrx_statistic.rx.abort.ed_abort_nums += ieee802154_ll_get_ed_abort_cnt();
ieee802154_ll_clear_debug_cnt(IEEE802154_ED_ABORT_CNT_CLEAR);
s_ieee802154_txrx_statistic.rx.abort.crc_error_nums += ieee802154_ll_get_crc_error_cnt();
ieee802154_ll_clear_debug_cnt(IEEE802154_CRC_ERROR_CNT_CLEAR);
s_ieee802154_txrx_statistic.rx.abort.sfd_timeout_nums += ieee802154_ll_get_sfd_timeout_cnt();
ieee802154_ll_clear_debug_cnt(IEEE802154_SFD_TIMEOUT_CNT_CLEAR);
}
void ieee802154_tx_nums_update(void)
{
s_ieee802154_txrx_statistic.tx.nums++;
}
void ieee802154_tx_break_coex_nums_update(void)
{
s_ieee802154_txrx_statistic.tx.abort.tx_coex_break_nums++;
}
void ieee802154_txrx_statistic_print(void)
{
uint64_t tx_success_nums = s_ieee802154_txrx_statistic.tx.done_nums - s_ieee802154_txrx_statistic.tx.abort.rx_ack_coex_break_nums - s_ieee802154_txrx_statistic.tx.abort.rx_ack_timeout_nums;
uint64_t tx_abort_nums = s_ieee802154_txrx_statistic.tx.abort.rx_ack_coex_break_nums + s_ieee802154_txrx_statistic.tx.abort.rx_ack_timeout_nums +
s_ieee802154_txrx_statistic.tx.abort.tx_coex_break_nums + s_ieee802154_txrx_statistic.tx.abort.tx_security_error_nums +
s_ieee802154_txrx_statistic.tx.abort.cca_failed_nums + s_ieee802154_txrx_statistic.tx.abort.cca_busy_nums;
uint64_t tx_nums = s_ieee802154_txrx_statistic.tx.nums;
float tx_success_ratio = (tx_nums > 0 ? ((float)tx_success_nums / tx_nums) : 0);
float tx_done_ratio = (tx_nums > 0 ? ((float)s_ieee802154_txrx_statistic.tx.done_nums / tx_nums) : 0);
float tx_abort_ratio = (tx_nums > 0 ? ((float)tx_abort_nums / tx_nums) : 0);
float tx_abort_rx_ack_coex_break_ratio = (tx_nums > 0 ? ((float)s_ieee802154_txrx_statistic.tx.abort.rx_ack_coex_break_nums / tx_nums) : 0);
float tx_abort_rx_ack_timeout_ratio = (tx_nums > 0 ? ((float)s_ieee802154_txrx_statistic.tx.abort.rx_ack_timeout_nums / tx_nums) : 0);
float tx_abort_tx_coex_break_ratio = (tx_nums > 0 ? ((float)s_ieee802154_txrx_statistic.tx.abort.tx_coex_break_nums / tx_nums) : 0);
float tx_abort_tx_security_error_ratio = (tx_nums > 0 ? ((float)s_ieee802154_txrx_statistic.tx.abort.tx_security_error_nums / tx_nums) : 0);
float tx_abort_cca_failed_ratio = (tx_nums > 0 ? ((float)s_ieee802154_txrx_statistic.tx.abort.cca_failed_nums / tx_nums) : 0);
float tx_abort_cca_busy_ratio = (tx_nums > 0 ? ((float)s_ieee802154_txrx_statistic.tx.abort.cca_busy_nums / tx_nums) : 0);
uint64_t rx_abort_nums = s_ieee802154_txrx_statistic.rx.abort.tx_ack_coex_break_nums + s_ieee802154_txrx_statistic.rx.abort.sfd_timeout_nums +
s_ieee802154_txrx_statistic.rx.abort.crc_error_nums + s_ieee802154_txrx_statistic.rx.abort.filter_fail_nums +
s_ieee802154_txrx_statistic.rx.abort.no_rss_nums + s_ieee802154_txrx_statistic.rx.abort.rx_coex_break_nums +
s_ieee802154_txrx_statistic.rx.abort.rx_restart_nums + s_ieee802154_txrx_statistic.rx.abort.ed_abort_nums;
uint64_t rx_success_nums = s_ieee802154_txrx_statistic.rx.done_nums - s_ieee802154_txrx_statistic.rx.abort.tx_ack_coex_break_nums;
ESP_LOGW(TAG, "+--------------------+-----------------------------------+--------------------------------------------------+");
ESP_LOGW(TAG, "|%-20s|%-10s%-15llu%9.2f%%|%-25s%-15llu%9.2f%%|", "", "Done:", s_ieee802154_txrx_statistic.tx.done_nums, tx_done_ratio*100, "Success:", tx_success_nums, tx_success_ratio*100);
ESP_LOGW(TAG, "+ +-----------------------------------+--------------------------------------------------+");
ESP_LOGW(TAG, "|%-20s|%-35s|%-25s%-15llu%9.2f%%|", "", "", "rx_ack_coex_break:", s_ieee802154_txrx_statistic.tx.abort.rx_ack_coex_break_nums, tx_abort_rx_ack_coex_break_ratio*100);
ESP_LOGW(TAG, "+ + +--------------------------------------------------+");
ESP_LOGW(TAG, "|%-20s|%-35s|%-25s%-15llu%9.2f%%|", "", "", "rx_ack_timeout:", s_ieee802154_txrx_statistic.tx.abort.rx_ack_timeout_nums, tx_abort_rx_ack_timeout_ratio*100);
ESP_LOGW(TAG, "+ + +--------------------------------------------------+");
ESP_LOGW(TAG, "|%-5s%-15llu|%-10s%-15llu%9.2f%%|%-25s%-15llu%9.2f%%|", "TX:", s_ieee802154_txrx_statistic.tx.nums, "Abort", tx_abort_nums, tx_abort_ratio*100, "tx_coex_break:", s_ieee802154_txrx_statistic.tx.abort.tx_coex_break_nums, tx_abort_tx_coex_break_ratio*100);
ESP_LOGW(TAG, "+ + +--------------------------------------------------+");
ESP_LOGW(TAG, "|%-20s|%-35s|%-25s%-15llu%9.2f%%|", "", "", "tx_security_error:", s_ieee802154_txrx_statistic.tx.abort.tx_security_error_nums, tx_abort_tx_security_error_ratio*100);
ESP_LOGW(TAG, "+ + +--------------------------------------------------+");
ESP_LOGW(TAG, "|%-20s|%-35s|%-25s%-15llu%9.2f%%|", "", "", "cca_failed:", s_ieee802154_txrx_statistic.tx.abort.cca_failed_nums, tx_abort_cca_failed_ratio*100);
ESP_LOGW(TAG, "+ + +--------------------------------------------------+");
ESP_LOGW(TAG, "|%-20s|%-35s|%-25s%-15llu%9.2f%%|", "", "", "cca_busy:", s_ieee802154_txrx_statistic.tx.abort.cca_busy_nums, tx_abort_cca_busy_ratio*100);
ESP_LOGW(TAG, "+--------------------+-----------------------------------+--------------------------------------------------+");
ESP_LOGW(TAG, "|%-20s|%-10s%-25llu|%-25s%-25llu|", "", "Done:", s_ieee802154_txrx_statistic.rx.done_nums, "Success:", rx_success_nums);
ESP_LOGW(TAG, "+ +-----------------------------------+--------------------------------------------------+");
ESP_LOGW(TAG, "|%-20s|%-35s|%-25s%-25llu|", "", "", "tx_ack_coex_break:", s_ieee802154_txrx_statistic.rx.abort.tx_ack_coex_break_nums);
ESP_LOGW(TAG, "+ + +--------------------------------------------------+");
ESP_LOGW(TAG, "|%-20s|%-35s|%-25s%-25llu|", "", "", "sfd_timeout:", s_ieee802154_txrx_statistic.rx.abort.sfd_timeout_nums);
ESP_LOGW(TAG, "+ + +--------------------------------------------------+");
ESP_LOGW(TAG, "|%-20s|%-35s|%-25s%-25llu|", "", "", "crc_error:", s_ieee802154_txrx_statistic.rx.abort.crc_error_nums);
ESP_LOGW(TAG, "+ + +--------------------------------------------------+");
ESP_LOGW(TAG, "|%-20s|%-10s%-25llu|%-25s%-25llu|", "RX", "Abort", rx_abort_nums, "filter_fail:", s_ieee802154_txrx_statistic.rx.abort.filter_fail_nums);
ESP_LOGW(TAG, "+ + +--------------------------------------------------+");
ESP_LOGW(TAG, "|%-20s|%-35s|%-25s%-25llu|", "", "", "no_rss:", s_ieee802154_txrx_statistic.rx.abort.no_rss_nums);
ESP_LOGW(TAG, "+ + +--------------------------------------------------+");
ESP_LOGW(TAG, "|%-20s|%-35s|%-25s%-25llu|", "", "", "rx_coex_break:", s_ieee802154_txrx_statistic.rx.abort.rx_coex_break_nums);
ESP_LOGW(TAG, "+ + +--------------------------------------------------+");
ESP_LOGW(TAG, "|%-20s|%-35s|%-25s%-25llu|", "", "", "rx_restart:", s_ieee802154_txrx_statistic.rx.abort.rx_restart_nums);
ESP_LOGW(TAG, "+ + +--------------------------------------------------+");
ESP_LOGW(TAG, "|%-20s|%-35s|%-25s%-25llu|", "", "", "ed_abort:", s_ieee802154_txrx_statistic.rx.abort.ed_abort_nums);
ESP_LOGW(TAG, "+--------------------+-----------------------------------+--------------------------------------------------+");
}
#endif // CONFIG_IEEE802154_TXRX_STATISTIC
#endif // CONFIG_IEEE802154_DEBUG #endif // CONFIG_IEEE802154_DEBUG

View File

@ -455,7 +455,11 @@ static IRAM_ATTR void isr_handle_tx_abort(void)
next_operation(); next_operation();
break; break;
case IEEE802154_TX_ABORT_BY_TX_COEX_BREAK: case IEEE802154_TX_ABORT_BY_TX_COEX_BREAK:
#if CONFIG_ESP_COEX_SW_COEXIST_ENABLE || CONFIG_EXTERNAL_COEX_ENABLE
esp_coex_ieee802154_coex_break_notify();
#endif
IEEE802154_ASSERT(s_ieee802154_state == IEEE802154_STATE_TX || s_ieee802154_state == IEEE802154_STATE_TX_CCA); IEEE802154_ASSERT(s_ieee802154_state == IEEE802154_STATE_TX || s_ieee802154_state == IEEE802154_STATE_TX_CCA);
IEEE802154_TX_BREAK_COEX_NUMS_UPDATE();
esp_ieee802154_transmit_failed(s_tx_frame, ESP_IEEE802154_TX_ERR_COEXIST); esp_ieee802154_transmit_failed(s_tx_frame, ESP_IEEE802154_TX_ERR_COEXIST);
next_operation(); next_operation();
break; break;
@ -628,6 +632,7 @@ esp_err_t ieee802154_mac_init(void)
esp_err_t ret = ESP_OK; esp_err_t ret = ESP_OK;
modem_clock_module_mac_reset(PERIPH_IEEE802154_MODULE); // reset ieee802154 MAC modem_clock_module_mac_reset(PERIPH_IEEE802154_MODULE); // reset ieee802154 MAC
ieee802154_pib_init(); ieee802154_pib_init();
IEEE802154_TXRX_STATISTIC_CLEAR();
ieee802154_ll_enable_events(IEEE802154_EVENT_MASK); ieee802154_ll_enable_events(IEEE802154_EVENT_MASK);
#if !CONFIG_IEEE802154_TEST #if !CONFIG_IEEE802154_TEST
@ -672,6 +677,7 @@ IEEE802154_STATIC void start_ed(uint32_t duration)
IEEE802154_STATIC void tx_init(const uint8_t *frame) IEEE802154_STATIC void tx_init(const uint8_t *frame)
{ {
IEEE802154_TX_NUMS_UPDATE();
s_tx_frame = (uint8_t *)frame; s_tx_frame = (uint8_t *)frame;
stop_current_operation(); stop_current_operation();
ieee802154_pib_update(); ieee802154_pib_update();

View File

@ -393,3 +393,15 @@ __attribute__((weak)) void esp_ieee802154_timer1_done(void)
{ {
} }
#if CONFIG_IEEE802154_TXRX_STATISTIC
void esp_ieee802154_txrx_statistic_clear(void)
{
ieee802154_txrx_statistic_clear();
}
void esp_ieee802154_txrx_statistic_print(void)
{
ieee802154_txrx_statistic_print();
}
#endif // CONFIG_IEEE802154_TXRX_STATISTIC

View File

@ -586,6 +586,24 @@ esp_err_t esp_ieee802154_set_transmit_security(uint8_t *frame, uint8_t *key, uin
*/ */
esp_err_t esp_ieee802154_enh_ack_generator(uint8_t *frame, esp_ieee802154_frame_info_t *frame_info, uint8_t* enhack_frame); esp_err_t esp_ieee802154_enh_ack_generator(uint8_t *frame, esp_ieee802154_frame_info_t *frame_info, uint8_t* enhack_frame);
/**
* The configurable definitions via Kconfig
*/
#if CONFIG_IEEE802154_TXRX_STATISTIC
/**
* @brief Clear the current IEEE802.15.4 statistic.
*
*/
void esp_ieee802154_txrx_statistic_clear(void);
/**
* @brief Print the current IEEE802.15.4 statistic.
*
*/
void esp_ieee802154_txrx_statistic_print(void);
#endif // CONFIG_IEEE802154_TXRX_STATISTIC
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View File

@ -18,6 +18,7 @@ extern "C" {
#define IEEE802154_PROBE(a) do { \ #define IEEE802154_PROBE(a) do { \
IEEE802154_RECORD_EVENT(a); \ IEEE802154_RECORD_EVENT(a); \
ieee802154_record_abort(a); \ ieee802154_record_abort(a); \
IEEE802154_TXRX_STATISTIC(a); \
} while(0) } while(0)
#if CONFIG_IEEE802154_RECORD_EVENT #if CONFIG_IEEE802154_RECORD_EVENT
@ -173,6 +174,62 @@ void ieee802154_assert_print(void);
#define IEEE802154_ASSERT(a) assert(a) #define IEEE802154_ASSERT(a) assert(a)
#endif // CONFIG_IEEE802154_ASSERT #endif // CONFIG_IEEE802154_ASSERT
#if CONFIG_IEEE802154_TXRX_STATISTIC
typedef struct ieee802154_txrx_statistic{
struct {
uint64_t nums;
uint64_t done_nums;
struct {
uint64_t rx_ack_coex_break_nums; // IEEE802154_RX_ACK_ABORT_COEX_CNT_REG
uint64_t rx_ack_timeout_nums; // IEEE802154_RX_ACK_TIMEOUT_CNT_REG
uint64_t tx_coex_break_nums; // IEEE802154_TX_BREAK_COEX_CNT_REG
uint64_t tx_security_error_nums; // IEEE802154_TX_SECURITY_ERROR_CNT_REG
uint64_t cca_failed_nums; // IEEE802154_CCA_FAIL_CNT_REG
uint64_t cca_busy_nums; // IEEE802154_CCA_BUSY_CNT_REG
} abort;
} tx;
struct {
uint64_t done_nums;
struct {
uint64_t sfd_timeout_nums; // IEEE802154_SFD_TIMEOUT_CNT_REG
uint64_t crc_error_nums; // IEEE802154_CRC_ERROR_CNT_REG
uint64_t filter_fail_nums; // IEEE802154_RX_FILTER_FAIL_CNT_REG
uint64_t no_rss_nums; // IEEE802154_NO_RSS_DETECT_CNT_REG
uint64_t rx_coex_break_nums; // IEEE802154_RX_ABORT_COEX_CNT_REG
uint64_t rx_restart_nums; // IEEE802154_RX_RESTART_CNT_REG
uint64_t tx_ack_coex_break_nums; // IEEE802154_TX_ACK_ABORT_COEX_CNT_REG
uint64_t ed_abort_nums; // IEEE802154_ED_ABORT_CNT_REG
} abort;
} rx;
} ieee802154_txrx_statistic_t;
#define IEEE802154_TXRX_STATISTIC_CLEAR() do { \
ieee802154_txrx_statistic_clear();\
} while(0)
#define IEEE802154_TXRX_STATISTIC(a) do { \
ieee802154_txrx_statistic(a);\
} while(0)
#define IEEE802154_TX_NUMS_UPDATE() do { \
ieee802154_tx_nums_update();\
} while(0)
#define IEEE802154_TX_BREAK_COEX_NUMS_UPDATE() do { \
ieee802154_tx_break_coex_nums_update();\
} while(0)
void ieee802154_txrx_statistic_clear(void);
void ieee802154_txrx_statistic_print(void);
void ieee802154_txrx_statistic(ieee802154_ll_events events);
void ieee802154_tx_nums_update(void);
void ieee802154_tx_break_coex_nums_update(void);
#else
#define IEEE802154_TXRX_STATISTIC(a)
#define IEEE802154_TX_NUMS_UPDATE()
#define IEEE802154_TXRX_STATISTIC_CLEAR()
#define IEEE802154_TX_BREAK_COEX_NUMS_UPDATE()
#endif // CONFIG_IEEE802154_TXRX_STATISTIC
// TODO: replace etm code using common interface // TODO: replace etm code using common interface

View File

@ -18,6 +18,7 @@ if(CONFIG_OPENTHREAD_ENABLED)
"openthread/include/openthread" "openthread/include/openthread"
"openthread/src" "openthread/src"
"openthread/src/core" "openthread/src/core"
"openthread/src/lib"
"openthread/src/lib/hdlc" "openthread/src/lib/hdlc"
"openthread/src/lib/spinel" "openthread/src/lib/spinel"
"openthread/src/ncp" "openthread/src/ncp"
@ -31,6 +32,7 @@ if(CONFIG_OPENTHREAD_ENABLED)
"openthread/src/core/common" "openthread/src/core/common"
"openthread/src/core/crypto" "openthread/src/core/crypto"
"openthread/src/core/diags" "openthread/src/core/diags"
"openthread/src/core/instance"
"openthread/src/core/mac" "openthread/src/core/mac"
"openthread/src/core/radio" "openthread/src/core/radio"
"openthread/src/core/thread" "openthread/src/core/thread"
@ -41,7 +43,7 @@ if(CONFIG_OPENTHREAD_ENABLED)
set(exclude_srcs set(exclude_srcs
"openthread/examples/platforms/utils/logging_rtt.c" "openthread/examples/platforms/utils/logging_rtt.c"
"openthread/examples/platforms/utils/soft_source_match_table.c" "openthread/examples/platforms/utils/soft_source_match_table.c"
"openthread/src/core/common/extension_example.cpp") "openthread/src/core/instance/extension_example.cpp")
if(CONFIG_OPENTHREAD_FTD OR CONFIG_OPENTHREAD_MTD) if(CONFIG_OPENTHREAD_FTD OR CONFIG_OPENTHREAD_MTD)
list(APPEND src_dirs list(APPEND src_dirs

View File

@ -163,6 +163,7 @@ menu "OpenThread"
config OPENTHREAD_RCP_SPI config OPENTHREAD_RCP_SPI
bool "SPI RCP" bool "SPI RCP"
select GPIO_CTRL_FUNC_IN_IRAM
help help
Select this to enable SPI connection to host. Select this to enable SPI connection to host.
endchoice endchoice

View File

@ -1,5 +1,5 @@
/* /*
* SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD * SPDX-FileCopyrightText: 2021-2023 Espressif Systems (Shanghai) CO LTD
* *
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*/ */
@ -69,8 +69,22 @@ void esp_openthread_register_rcp_failure_handler(esp_openthread_rcp_failure_hand
/** /**
* @brief Deinitializes the conneciton to RCP. * @brief Deinitializes the conneciton to RCP.
* *
* @return
* - ESP_OK on success
* - ESP_ERR_INVALID_STATE if fail to deinitialize RCP
*
*/ */
void esp_openthread_rcp_deinit(void); esp_err_t esp_openthread_rcp_deinit(void);
/**
* @brief Initializes the conneciton to RCP.
*
* @return
* - ESP_OK on success
* - ESP_FAIL if fail to initialize RCP
*
*/
esp_err_t esp_openthread_rcp_init(void);
#ifdef __cplusplus #ifdef __cplusplus
} }

@ -1 +1 @@
Subproject commit 12f563ee490236f7332eb22f568e71c7c1d4a3b7 Subproject commit 648c28e792567bc00602c92e43518c1784599251

@ -1 +1 @@
Subproject commit af5938e389be40650507748272bb6c6b3a2de2cf Subproject commit 41ef80717f4b757440125932723cc8721ef42f7f

View File

@ -1,5 +1,5 @@
/* /*
* SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD * SPDX-FileCopyrightText: 2021-2023 Espressif Systems (Shanghai) CO LTD
* *
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*/ */

View File

@ -14,18 +14,12 @@
namespace esp { namespace esp {
namespace openthread { namespace openthread {
class SpiSpinelInterface { class SpiSpinelInterface : public ot::Spinel::SpinelInterface {
public: public:
/** /**
* @brief This constructor of object. * @brief This constructor of object.
*
* @param[in] callback Callback on frame received
* @param[in] callback_context Callback context
* @param[in] frame_buffer A reference to a `RxFrameBuffer` object.
*
*/ */
SpiSpinelInterface(ot::Spinel::SpinelInterface::ReceiveFrameCallback callback, void *callback_context, SpiSpinelInterface();
ot::Spinel::SpinelInterface::RxFrameBuffer &frame_buffer);
/** /**
* @brief This destructor of the object. * @brief This destructor of the object.
@ -34,24 +28,26 @@ public:
~SpiSpinelInterface(void); ~SpiSpinelInterface(void);
/** /**
* @brief This method initializes the spinel interface. * Initializes the interface to the Radio Co-processor (RCP).
*
* @note This method should be called before reading and sending spinel frames to the interface.
*
* @param[in] aCallback Callback on frame received
* @param[in] aCallbackContext Callback context
* @param[in] aFrameBuffer A reference to a `RxFrameBuffer` object.
*
* @retval OT_ERROR_NONE The interface is initialized successfully
* @retval OT_ERROR_ALREADY The interface is already initialized.
* @retval OT_ERROR_FAILED Failed to initialize the interface.
* *
* @return
* - ESP_OK on success
* - ESP_ERR_INVALID_STATE if already initialized
* - ESP_ERR_NO_MEM if allocation has failed
* - ESP_FAIL on failure
*/ */
esp_err_t Init(const esp_openthread_spi_host_config_t &spi_config); otError Init(ReceiveFrameCallback aCallback, void *aCallbackContext, RxFrameBuffer &aFrameBuffer);
/** /**
* @brief This method deinitializes the HDLC interface. * Deinitializes the interface to the RCP.
* *
* @return
* - ESP_OK on success
* - ESP_FAIL on failure
*/ */
esp_err_t Deinit(void); void Deinit(void);
/** /**
* @brief This method encodes and sends a spinel frame to Radio Co-processor (RCP) over the socket. * @brief This method encodes and sends a spinel frame to Radio Co-processor (RCP) over the socket.
@ -80,20 +76,42 @@ public:
otError WaitForFrame(uint64_t timeout_us); otError WaitForFrame(uint64_t timeout_us);
/** /**
* This method performs spi processing to the RCP. * Updates the file descriptor sets with file descriptors used by the radio driver.
* *
* @param[in] mainloop The mainloop context * @param[in,out] aMainloopContext A pointer to the mainloop context.
* *
*/ */
void Process(const void *mainloop); void UpdateFdSet(void *aMainloopContext);
/** /**
* This methods updates the mainloop context. * Performs radio driver processing.
* *
* @param[inout] mainloop The mainloop context. * @param[in] aMainloopContext A pointer to the mainloop context.
* *
*/ */
void Update(void *mainloop); void Process(const void *aMainloopContext);
/**
* Returns the bus speed between the host and the radio.
*
* @returns Bus speed in bits/second.
*
*/
uint32_t GetBusSpeed(void) const;
/**
* This method is called when RCP failure detected and resets internal states of the interface.
*
*/
otError HardwareReset(void);
/**
* Returns the RCP interface metrics.
*
* @returns The RCP interface metrics.
*
*/
const otRcpInterfaceMetrics *GetRcpInterfaceMetrics(void) const { return &mInterfaceMetrics; }
/** /**
* This methods registers the callback for RCP failure. * This methods registers the callback for RCP failure.
@ -111,10 +129,33 @@ public:
otError ResetConnection(void) { return OT_ERROR_NONE; } otError ResetConnection(void) { return OT_ERROR_NONE; }
/** /**
* This method is called when RCP failure detected and resets internal states of the interface. * @brief This method enable the spinel interface.
* *
* @return
* - ESP_OK on success
* - ESP_ERR_INVALID_STATE if already initialized
* - ESP_ERR_NO_MEM if allocation has failed
* - ESP_FAIL on failure
*/ */
otError HardwareReset(void); esp_err_t Enable(const esp_openthread_spi_host_config_t &spi_config);
/**
* @brief This method disable the spinel interface.
*
* @return
* - ESP_OK on success
* - ESP_FAIL on failure
*/
esp_err_t Disable(void);
/**
* @brief This method should be called after radio is initialized.
*
* @return
* - ESP_OK on success
* - ESP_FAIL on failure
*/
esp_err_t AfterRadioInit(void);
private: private:
static constexpr uint8_t kSPIFrameHeaderSize = 5; static constexpr uint8_t kSPIFrameHeaderSize = 5;
@ -130,14 +171,16 @@ private:
int m_event_fd; int m_event_fd;
volatile uint16_t m_pending_data_len; volatile uint16_t m_pending_data_len;
ot::Spinel::SpinelInterface::ReceiveFrameCallback m_receiver_frame_callback; ReceiveFrameCallback m_receiver_frame_callback;
void *m_receiver_frame_context; void *m_receiver_frame_context;
ot::Spinel::SpinelInterface::RxFrameBuffer &m_receive_frame_buffer; RxFrameBuffer *m_receive_frame_buffer;
bool m_has_pending_device_frame; bool m_has_pending_device_frame;
spi_device_handle_t m_device; spi_device_handle_t m_device;
esp_openthread_rcp_failure_handler mRcpFailureHandler; esp_openthread_rcp_failure_handler mRcpFailureHandler;
otRcpInterfaceMetrics mInterfaceMetrics;
}; };
} // namespace openthread } // namespace openthread

View File

@ -0,0 +1,50 @@
/*
* SPDX-FileCopyrightText: 2021-2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include "esp_err.h"
#include "esp_openthread.h"
#include "esp_openthread_types.h"
#include "hal/uart_types.h"
#include "lib/spinel/spinel_interface.hpp"
#include "lib/hdlc/hdlc.hpp"
#include "openthread/error.h"
namespace esp {
namespace openthread {
/**
* This class defines an template to adapt both UartSpinelInterface and SpiSpinelInterface.
*
*/
template <typename InterfaceType> class SpinelInterfaceAdapter {
public:
/**
* @brief This constructor of object.
*/
SpinelInterfaceAdapter(void) {}
/**
* @brief This destructor of the object.
*
*/
~SpinelInterfaceAdapter(void) {}
/**
* @brief This method return the underlying spinel interface.
*
* @return The underlying spinel interface.
*
*/
InterfaceType &GetSpinelInterface(void) { return mSpinelInterface; }
private:
InterfaceType mSpinelInterface;
};
} // namespace openthread
} // namespace esp

View File

@ -21,18 +21,12 @@ namespace openthread {
* This class defines an UART interface to the Radio Co-processor (RCP). * This class defines an UART interface to the Radio Co-processor (RCP).
* *
*/ */
class UartSpinelInterface { class UartSpinelInterface : public ot::Spinel::SpinelInterface {
public: public:
/** /**
* @brief This constructor of object. * @brief This constructor of object.
*
* @param[in] callback Callback on frame received
* @param[in] callback_context Callback context
* @param[in] frame_buffer A reference to a `RxFrameBuffer` object.
*
*/ */
UartSpinelInterface(ot::Spinel::SpinelInterface::ReceiveFrameCallback callback, void *callback_context, UartSpinelInterface(void);
ot::Spinel::SpinelInterface::RxFrameBuffer &frame_buffer);
/** /**
* @brief This destructor of the object. * @brief This destructor of the object.
@ -41,65 +35,92 @@ public:
~UartSpinelInterface(void); ~UartSpinelInterface(void);
/** /**
* @brief This method initializes the HDLC interface. * Initializes the interface to the Radio Co-processor (RCP).
*
* @note This method should be called before reading and sending spinel frames to the interface.
*
* @param[in] aCallback Callback on frame received
* @param[in] aCallbackContext Callback context
* @param[in] aFrameBuffer A reference to a `RxFrameBuffer` object.
*
* @retval OT_ERROR_NONE The interface is initialized successfully
* @retval OT_ERROR_ALREADY The interface is already initialized.
* @retval OT_ERROR_FAILED Failed to initialize the interface.
* *
* @return
* - ESP_OK on success
* - ESP_ERR_NO_MEM if allocation has failed
* - ESP_ERROR on failure
*/ */
esp_err_t Init(const esp_openthread_uart_config_t &radio_uart_config); otError Init(ReceiveFrameCallback aCallback, void *aCallbackContext, RxFrameBuffer &aFrameBuffer);
/** /**
* @brief This method deinitializes the HDLC interface. * Deinitializes the interface to the RCP.
* *
*/ */
esp_err_t Deinit(void); void Deinit(void);
/** /**
* @brief This method encodes and sends a spinel frame to Radio Co-processor (RCP) over the socket. * Encodes and sends a spinel frame to Radio Co-processor (RCP) over the socket.
* *
* @note This is blocking call, i.e., if the socket is not writable, this method waits for it to become writable * @param[in] aFrame A pointer to buffer containing the spinel frame to send.
* for up to `kMaxWaitTime` interval. * @param[in] aLength The length (number of bytes) in the frame.
* *
* @param[in] frame A pointer to buffer containing the spinel frame to send. * @retval OT_ERROR_NONE Successfully encoded and sent the spinel frame.
* @param[in] length The length (number of bytes) in the frame. * @retval OT_ERROR_BUSY Failed due to another operation is on going.
* * @retval OT_ERROR_NO_BUFS Insufficient buffer space available to encode the frame.
* @return * @retval OT_ERROR_FAILED Failed to call the SPI driver to send the frame.
* -OT_ERROR_NONE Successfully encoded and sent the spinel frame.
* -OT_ERROR_NO_BUFS Insufficient buffer space available to encode the frame.
* -OT_ERROR_FAILED Failed to send due to socket not becoming writable within `kMaxWaitTime`.
* *
*/ */
otError SendFrame(const uint8_t *frame, uint16_t length); otError SendFrame(const uint8_t *aFrame, uint16_t aLength);
/** /**
* This method waits for receiving part or all of spinel frame within specified timeout. * Waits for receiving part or all of spinel frame within specified interval.
* *
* @param[in] timeout_us The timeout value in microseconds. * @param[in] aTimeout The timeout value in microseconds.
* *
* @return * @retval OT_ERROR_NONE Part or all of spinel frame is received.
* -OT_ERROR_NONE Part or all of spinel frame is received. * @retval OT_ERROR_RESPONSE_TIMEOUT No spinel frame is received within @p aTimeout.
* -OT_ERROR_RESPONSE_TIMEOUT No spinel frame is received within @p timeout_us.
* *
*/ */
otError WaitForFrame(uint64_t timeout_us); otError WaitForFrame(uint64_t aTimeoutUs);
/** /**
* This method performs uart processing to the RCP. * Updates the file descriptor sets with file descriptors used by the radio driver.
* *
* @param[in] mainloop The mainloop context * @param[in,out] aMainloopContext A pointer to the mainloop context.
* *
*/ */
void Process(const void *mainloop); void UpdateFdSet(void *aMainloopContext);
/** /**
* This methods updates the mainloop context. * Performs radio driver processing.
* *
* @param[inout] mainloop The mainloop context. * @param[in] aMainloopContext A pointer to the mainloop context.
* *
*/ */
void Update(void *mainloop); void Process(const void *aMainloopContext);
/**
* Returns the bus speed between the host and the radio.
*
* @returns Bus speed in bits/second.
*
*/
uint32_t GetBusSpeed(void) const;
/**
* Hardware resets the RCP.
*
* @retval OT_ERROR_NONE Successfully reset the RCP.
* @retval OT_ERROR_NOT_IMPLEMENT The hardware reset is not implemented.
*
*/
otError HardwareReset(void);
/**
* Returns the RCP interface metrics.
*
* @returns The RCP interface metrics.
*
*/
const otRcpInterfaceMetrics *GetRcpInterfaceMetrics(void) const { return &mInterfaceMetrics; }
/** /**
* This methods registers the callback for RCP failure. * This methods registers the callback for RCP failure.
@ -109,12 +130,6 @@ public:
*/ */
void RegisterRcpFailureHandler(esp_openthread_rcp_failure_handler handler) { mRcpFailureHandler = handler; } void RegisterRcpFailureHandler(esp_openthread_rcp_failure_handler handler) { mRcpFailureHandler = handler; }
/**
* This method is called when RCP failure detected and resets internal states of the interface.
*
*/
otError HardwareReset(void);
/** /**
* This method is called when RCP is reset to recreate the connection with it. * This method is called when RCP is reset to recreate the connection with it.
* Intentionally empty. * Intentionally empty.
@ -122,14 +137,25 @@ public:
*/ */
otError ResetConnection(void) { return OT_ERROR_NONE; } otError ResetConnection(void) { return OT_ERROR_NONE; }
private: /**
enum { * @brief This method enable the HDLC interface.
/** *
* Maximum spinel frame size. * @return
* * - ESP_OK on success
*/ * - ESP_ERR_NO_MEM if allocation has failed
kMaxFrameSize = ot::Spinel::SpinelInterface::kMaxFrameSize, * - ESP_ERROR on failure
*/
esp_err_t Enable(const esp_openthread_uart_config_t &radio_uart_config);
/**
* @brief This method disable the HDLC interface.
*
*/
esp_err_t Disable(void);
private:
enum {
/** /**
* Maximum wait time in Milliseconds for socket to become writable (see `SendFrame`). * Maximum wait time in Milliseconds for socket to become writable (see `SendFrame`).
* *
@ -152,9 +178,9 @@ private:
static void HandleHdlcFrame(void *context, otError error); static void HandleHdlcFrame(void *context, otError error);
void HandleHdlcFrame(otError error); void HandleHdlcFrame(otError error);
ot::Spinel::SpinelInterface::ReceiveFrameCallback m_receiver_frame_callback; ReceiveFrameCallback m_receiver_frame_callback;
void *m_receiver_frame_context; void *m_receiver_frame_context;
ot::Spinel::SpinelInterface::RxFrameBuffer &m_receive_frame_buffer; RxFrameBuffer *m_receive_frame_buffer;
ot::Hdlc::Decoder m_hdlc_decoder; ot::Hdlc::Decoder m_hdlc_decoder;
uint8_t *m_uart_rx_buffer; uint8_t *m_uart_rx_buffer;
@ -162,6 +188,8 @@ private:
esp_openthread_uart_config_t m_uart_config; esp_openthread_uart_config_t m_uart_config;
int m_uart_fd; int m_uart_fd;
otRcpInterfaceMetrics mInterfaceMetrics;
// Non-copyable, intentionally not implemented. // Non-copyable, intentionally not implemented.
UartSpinelInterface(const UartSpinelInterface &); UartSpinelInterface(const UartSpinelInterface &);
UartSpinelInterface &operator=(const UartSpinelInterface &); UartSpinelInterface &operator=(const UartSpinelInterface &);

View File

@ -20,7 +20,7 @@
#include "esp_partition.h" #include "esp_partition.h"
#include "common/code_utils.hpp" #include "common/code_utils.hpp"
#include "common/logging.hpp" #include "common/logging.hpp"
#include "core/common/instance.hpp" #include "core/instance/instance.hpp"
#include "freertos/FreeRTOS.h" #include "freertos/FreeRTOS.h"
#include "freertos/queue.h" #include "freertos/queue.h"
#include "openthread/cli.h" #include "openthread/cli.h"

View File

@ -13,6 +13,7 @@
#include "esp_openthread_platform.h" #include "esp_openthread_platform.h"
#include "esp_openthread_types.h" #include "esp_openthread_types.h"
#include "esp_system.h" #include "esp_system.h"
#include "esp_spinel_interface.hpp"
#include "esp_spi_spinel_interface.hpp" #include "esp_spi_spinel_interface.hpp"
#include "esp_uart_spinel_interface.hpp" #include "esp_uart_spinel_interface.hpp"
#include "openthread-core-config.h" #include "openthread-core-config.h"
@ -20,41 +21,100 @@
#include "lib/spinel/spinel.h" #include "lib/spinel/spinel.h"
#include "openthread/platform/diag.h" #include "openthread/platform/diag.h"
#include "openthread/platform/radio.h" #include "openthread/platform/radio.h"
#include "platform/exit_code.h"
using ot::Spinel::RadioSpinel; using ot::Spinel::RadioSpinel;
using esp::openthread::SpinelInterfaceAdapter;
#if CONFIG_OPENTHREAD_RADIO_SPINEL_UART #if CONFIG_OPENTHREAD_RADIO_SPINEL_UART // CONFIG_OPENTHREAD_RADIO_SPINEL_UART
using esp::openthread::UartSpinelInterface; using esp::openthread::UartSpinelInterface;
static RadioSpinel<UartSpinelInterface> s_radio; static SpinelInterfaceAdapter<UartSpinelInterface> s_spinel_interface;
#else // CONFIG_OPENTHREAD_RADIO_SPINEL_SPI #else // CONFIG_OPENTHREAD_RADIO_SPINEL_SPI
using esp::openthread::SpiSpinelInterface; using esp::openthread::SpiSpinelInterface;
static RadioSpinel<SpiSpinelInterface> s_radio; static SpinelInterfaceAdapter<SpiSpinelInterface> s_spinel_interface;
#endif // CONFIG_OPENTHREAD_RADIO_SPINEL_UART #endif
static RadioSpinel s_radio;
static const char *radiospinel_workflow = "radio_spinel"; static const char *radiospinel_workflow = "radio_spinel";
static const esp_openthread_radio_config_t *s_esp_openthread_radio_config = NULL;
static void esp_openthread_radio_config_set(const esp_openthread_radio_config_t *config)
{
s_esp_openthread_radio_config = config;
}
static const esp_openthread_radio_config_t *esp_openthread_radio_config_get(void)
{
return s_esp_openthread_radio_config;
}
esp_err_t esp_openthread_radio_init(const esp_openthread_platform_config_t *config) esp_err_t esp_openthread_radio_init(const esp_openthread_platform_config_t *config)
{ {
#if CONFIG_OPENTHREAD_RADIO_SPINEL_UART spinel_iid_t iidList[ot::Spinel::kSpinelHeaderMaxNumIid];
ESP_RETURN_ON_ERROR(s_radio.GetSpinelInterface().Init(config->radio_config.radio_uart_config), OT_PLAT_LOG_TAG, iidList[0] = 0;
ot::Spinel::RadioSpinelCallbacks callbacks;
#if CONFIG_OPENTHREAD_DIAG
callbacks.mDiagReceiveDone = otPlatDiagRadioReceiveDone;
callbacks.mDiagTransmitDone = otPlatDiagRadioTransmitDone;
#endif // OPENTHREAD_CONFIG_DIAG_ENABLE
callbacks.mEnergyScanDone = otPlatRadioEnergyScanDone;
callbacks.mReceiveDone = otPlatRadioReceiveDone;
callbacks.mTransmitDone = otPlatRadioTxDone;
callbacks.mTxStarted = otPlatRadioTxStarted;
s_radio.SetCallbacks(callbacks);
esp_openthread_radio_config_set(&config->radio_config);
#if CONFIG_OPENTHREAD_RADIO_SPINEL_UART // CONFIG_OPENTHREAD_RADIO_SPINEL_UART
ESP_RETURN_ON_ERROR(s_spinel_interface.GetSpinelInterface().Enable(config->radio_config.radio_uart_config), OT_PLAT_LOG_TAG,
"Spinel interface init falied"); "Spinel interface init falied");
#else // CONFIG_OPENTHREAD_RADIO_SPINEL_SPI #else // CONFIG_OPENTHREAD_RADIO_SPINEL_SPI
ESP_RETURN_ON_ERROR(s_radio.GetSpinelInterface().Init(config->radio_config.radio_spi_config), OT_PLAT_LOG_TAG, ESP_RETURN_ON_ERROR(s_spinel_interface.GetSpinelInterface().Enable(config->radio_config.radio_spi_config), OT_PLAT_LOG_TAG,
"Spinel interface init failed"); "Spinel interface init failed");
#endif // CONFIG_OPENTHREAD_RADIO_SPINEL_UART #endif
s_radio.Init(/*reset_radio=*/true, /*skip_rcp_compatibility_check=*/false); s_radio.Init(s_spinel_interface.GetSpinelInterface(), /*reset_radio=*/true, /*skip_rcp_compatibility_check=*/false, iidList, ot::Spinel::kSpinelHeaderMaxNumIid);
#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 falied");
#endif
return esp_openthread_platform_workflow_register(&esp_openthread_radio_update, &esp_openthread_radio_process, return esp_openthread_platform_workflow_register(&esp_openthread_radio_update, &esp_openthread_radio_process,
radiospinel_workflow); radiospinel_workflow);
} }
void esp_openthread_register_rcp_failure_handler(esp_openthread_rcp_failure_handler handler) void esp_openthread_register_rcp_failure_handler(esp_openthread_rcp_failure_handler handler)
{ {
s_radio.GetSpinelInterface().RegisterRcpFailureHandler(handler); s_spinel_interface.GetSpinelInterface().RegisterRcpFailureHandler(handler);
} }
void esp_openthread_rcp_deinit(void) esp_err_t esp_openthread_rcp_deinit(void)
{ {
s_radio.GetSpinelInterface().Deinit(); ESP_RETURN_ON_FALSE(otThreadGetDeviceRole(esp_openthread_get_instance()) == OT_DEVICE_ROLE_DISABLED, ESP_ERR_INVALID_STATE, OT_PLAT_LOG_TAG, "Thread is enabled, failed to deinitialize RCP");
ESP_RETURN_ON_FALSE(!otIp6IsEnabled(esp_openthread_get_instance()), ESP_ERR_INVALID_STATE, OT_PLAT_LOG_TAG, "OT interface is up, failed to deinitialize RCP");
if (s_radio.IsEnabled()) {
ESP_RETURN_ON_FALSE(s_radio.Sleep() == OT_ERROR_NONE, ESP_ERR_INVALID_STATE, OT_PLAT_LOG_TAG, "Radio fails to sleep");
ESP_RETURN_ON_FALSE(s_radio.Disable() == OT_ERROR_NONE, ESP_ERR_INVALID_STATE, OT_PLAT_LOG_TAG, "Fail to disable radio");
}
ESP_RETURN_ON_FALSE(s_spinel_interface.GetSpinelInterface().Disable() == OT_ERROR_NONE, ESP_ERR_INVALID_STATE, OT_PLAT_LOG_TAG, "Fail to deinitialize UART");
esp_openthread_platform_workflow_unregister(radiospinel_workflow);
return ESP_OK;
}
esp_err_t esp_openthread_rcp_init(void)
{
const esp_openthread_radio_config_t *radio_config = esp_openthread_radio_config_get();
#if CONFIG_OPENTHREAD_RADIO_SPINEL_UART
ESP_RETURN_ON_ERROR(s_spinel_interface.GetSpinelInterface().Enable(radio_config->radio_uart_config), OT_PLAT_LOG_TAG,
"Spinel interface init falied");
#else // CONFIG_OPENTHREAD_RADIO_SPINEL_SPI
ESP_RETURN_ON_ERROR(s_spinel_interface.GetSpinelInterface().Enable(radio_config->radio_spi_config), OT_PLAT_LOG_TAG,
"Spinel interface init failed");
#endif // CONFIG_OPENTHREAD_RADIO_SPINEL_UART
ESP_RETURN_ON_FALSE(s_radio.Enable(esp_openthread_get_instance()) == OT_ERROR_NONE, ESP_FAIL, OT_PLAT_LOG_TAG, "Fail to enable radio");
s_radio.RestoreProperties();
return esp_openthread_platform_workflow_register(&esp_openthread_radio_update, &esp_openthread_radio_process,
radiospinel_workflow);
} }
void esp_openthread_radio_deinit(void) void esp_openthread_radio_deinit(void)
@ -72,7 +132,7 @@ esp_err_t esp_openthread_radio_process(otInstance *instance, const esp_openthrea
void esp_openthread_radio_update(esp_openthread_mainloop_context_t *mainloop) void esp_openthread_radio_update(esp_openthread_mainloop_context_t *mainloop)
{ {
s_radio.GetSpinelInterface().Update((void *)mainloop); s_spinel_interface.GetSpinelInterface().UpdateFdSet((void *)mainloop);
} }
void otPlatRadioGetIeeeEui64(otInstance *instance, uint8_t *ieee_eui64) void otPlatRadioGetIeeeEui64(otInstance *instance, uint8_t *ieee_eui64)

View File

@ -17,10 +17,10 @@
#include "esp_attr.h" #include "esp_attr.h"
#include "esp_check.h" #include "esp_check.h"
#include "esp_err.h" #include "esp_err.h"
#include "esp_heap_caps.h"
#include "esp_openthread_common_macro.h" #include "esp_openthread_common_macro.h"
#include "esp_openthread_task_queue.h" #include "esp_openthread_task_queue.h"
#include "esp_openthread_types.h" #include "esp_openthread_types.h"
#include "esp_rom_sys.h"
#include <stdint.h> #include <stdint.h>
#include <string.h> #include <string.h>
#include "driver/gpio.h" #include "driver/gpio.h"
@ -33,37 +33,38 @@
static const char *SPI_SLAVE_TAG = "spi_slave"; static const char *SPI_SLAVE_TAG = "spi_slave";
static void *s_context = NULL; static void *s_context = NULL;
static uint8_t *s_prev_output_buf; static uint8_t *s_output_buf;
static uint16_t s_prev_output_len; static uint16_t s_output_len;
static uint8_t *s_prev_input_buf; static uint8_t *s_input_buf;
static uint16_t s_prev_input_len; static uint16_t s_input_len;
static bool s_request_transaction = false; static bool s_request_transaction = false;
static esp_openthread_spi_slave_config_t s_spi_config;
static otPlatSpiSlaveTransactionProcessCallback s_process_callback = NULL;
static otPlatSpiSlaveTransactionCompleteCallback s_complete_callback = NULL;
static spi_slave_transaction_t s_spi_transaction;
typedef struct { typedef struct {
uint16_t output_buf_len; uint16_t output_buf_len;
uint16_t input_buf_len; uint16_t input_buf_len;
} pending_transaction_t; } pending_transaction_t;
static otPlatSpiSlaveTransactionProcessCallback s_process_callback = NULL;
static otPlatSpiSlaveTransactionCompleteCallback s_complete_callback = NULL;
static DRAM_ATTR esp_openthread_spi_slave_config_t *s_spi_config;
static DRAM_ATTR spi_slave_transaction_t *s_spi_transaction;
static DRAM_ATTR pending_transaction_t *s_pending_transaction;
static void IRAM_ATTR handle_spi_setup_done(spi_slave_transaction_t *trans) static void IRAM_ATTR handle_spi_setup_done(spi_slave_transaction_t *trans)
{ {
if (s_request_transaction) { if (s_request_transaction) {
gpio_set_level(s_spi_config.intr_pin, 0); gpio_set_level(s_spi_config->intr_pin, 0);
} }
} }
static void IRAM_ATTR handle_spi_transaction_done(spi_slave_transaction_t *trans) static void IRAM_ATTR handle_spi_transaction_done(spi_slave_transaction_t *trans)
{ {
gpio_set_level(s_spi_config.intr_pin, 1); gpio_set_level(s_spi_config->intr_pin, 1);
pending_transaction_t *pending_transaction = (pending_transaction_t *)&(trans->user); pending_transaction_t *pending_transaction = (pending_transaction_t *)(trans->user);
trans->trans_len /= CHAR_BIT; trans->trans_len /= CHAR_BIT;
if (s_complete_callback && if (s_complete_callback &&
s_complete_callback(s_context, (uint8_t *)trans->tx_buffer, pending_transaction->output_buf_len, s_complete_callback(s_context, (void*)trans->tx_buffer, pending_transaction->output_buf_len,
trans->rx_buffer, pending_transaction->input_buf_len, trans->trans_len)) { trans->rx_buffer, pending_transaction->input_buf_len, trans->trans_len)) {
esp_openthread_task_queue_post(s_process_callback, s_context); esp_openthread_task_queue_post(s_process_callback, s_context);
} }
@ -72,23 +73,38 @@ static void IRAM_ATTR handle_spi_transaction_done(spi_slave_transaction_t *trans
esp_err_t esp_openthread_host_rcp_spi_init(const esp_openthread_platform_config_t *config) esp_err_t esp_openthread_host_rcp_spi_init(const esp_openthread_platform_config_t *config)
{ {
s_spi_config = config->host_config.spi_slave_config; s_spi_config = heap_caps_malloc(sizeof(esp_openthread_spi_slave_config_t), MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT);
ESP_RETURN_ON_FALSE(s_spi_config != NULL, ESP_ERR_NO_MEM, OT_PLAT_LOG_TAG,
"failed to allocate memory for SPI transaction on internal heap");
memcpy(s_spi_config, &(config->host_config.spi_slave_config), sizeof(esp_openthread_spi_slave_config_t));
gpio_config_t io_conf = { gpio_config_t io_conf = {
.intr_type = GPIO_INTR_DISABLE, .intr_type = GPIO_INTR_DISABLE,
.mode = GPIO_MODE_OUTPUT, .mode = GPIO_MODE_OUTPUT,
.pin_bit_mask = (1 << s_spi_config.intr_pin), .pin_bit_mask = (1 << s_spi_config->intr_pin),
}; };
ESP_RETURN_ON_ERROR(gpio_config(&io_conf), OT_PLAT_LOG_TAG, "fail to configure SPI gpio"); ESP_RETURN_ON_ERROR(gpio_config(&io_conf), OT_PLAT_LOG_TAG, "fail to configure SPI gpio");
gpio_set_pull_mode(s_spi_config.bus_config.mosi_io_num, GPIO_PULLUP_ONLY); gpio_set_pull_mode(s_spi_config->bus_config.mosi_io_num, GPIO_PULLUP_ONLY);
gpio_set_pull_mode(s_spi_config.bus_config.sclk_io_num, GPIO_PULLUP_ONLY); gpio_set_pull_mode(s_spi_config->bus_config.sclk_io_num, GPIO_PULLUP_ONLY);
gpio_set_pull_mode(s_spi_config.slave_config.spics_io_num, GPIO_PULLUP_ONLY); gpio_set_pull_mode(s_spi_config->slave_config.spics_io_num, GPIO_PULLUP_ONLY);
s_spi_transaction = heap_caps_malloc(sizeof(spi_slave_transaction_t), MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT);
s_pending_transaction = heap_caps_malloc(sizeof(pending_transaction_t), MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT);
if (s_spi_transaction == NULL || s_pending_transaction == NULL) {
heap_caps_free(s_spi_config);
heap_caps_free(s_spi_transaction);
heap_caps_free(s_pending_transaction);
ESP_LOGE(OT_PLAT_LOG_TAG, "failed to allocate memory for SPI transaction on internal heap");
return ESP_ERR_NO_MEM;
}
s_spi_transaction->user = (void *)s_pending_transaction;
/* Initialize SPI slave interface */ /* Initialize SPI slave interface */
s_spi_config.slave_config.post_setup_cb = handle_spi_setup_done; s_spi_config->slave_config.post_setup_cb = handle_spi_setup_done;
s_spi_config.slave_config.post_trans_cb = handle_spi_transaction_done; s_spi_config->slave_config.post_trans_cb = handle_spi_transaction_done;
ESP_RETURN_ON_ERROR(spi_slave_initialize(s_spi_config.host_device, &s_spi_config.bus_config, ESP_RETURN_ON_ERROR(spi_slave_initialize(s_spi_config->host_device, &s_spi_config->bus_config,
&s_spi_config.slave_config, SPI_DMA_CH_AUTO), &s_spi_config->slave_config, SPI_DMA_CH_AUTO),
OT_PLAT_LOG_TAG, "fail to initialize SPI slave"); OT_PLAT_LOG_TAG, "fail to initialize SPI slave");
return ESP_OK; return ESP_OK;
@ -96,9 +112,15 @@ esp_err_t esp_openthread_host_rcp_spi_init(const esp_openthread_platform_config_
void esp_openthread_spi_slave_deinit(void) void esp_openthread_spi_slave_deinit(void)
{ {
spi_slave_free(s_spi_config.host_device); spi_slave_free(s_spi_config->host_device);
s_spi_config.slave_config.post_setup_cb = NULL; s_spi_config->slave_config.post_setup_cb = NULL;
s_spi_config.slave_config.post_trans_cb = NULL; s_spi_config->slave_config.post_trans_cb = NULL;
heap_caps_free(s_spi_config);
heap_caps_free(s_spi_transaction);
heap_caps_free(s_pending_transaction);
s_spi_config = NULL;
s_spi_transaction = NULL;
s_pending_transaction = NULL;
return; return;
} }
@ -115,43 +137,38 @@ otError IRAM_ATTR otPlatSpiSlavePrepareTransaction(uint8_t *aOutputBuf, uint16_t
uint16_t aInputBufLen, bool aRequestTransactionFlag) uint16_t aInputBufLen, bool aRequestTransactionFlag)
{ {
esp_err_t trans_state = ESP_OK; esp_err_t trans_state = ESP_OK;
pending_transaction_t *pending_transaction = NULL; uint16_t trans_length = 0;
if (aOutputBuf == NULL) {
aOutputBuf = s_prev_output_buf; if (aOutputBuf != NULL) {
aOutputBufLen = s_prev_output_len; s_output_buf = aOutputBuf;
s_output_len = aOutputBufLen;
} }
if (aInputBuf == NULL) { if (aInputBuf != NULL) {
aInputBuf = s_prev_input_buf; s_input_buf = aInputBuf;
aInputBufLen = s_prev_input_len; s_input_len = aInputBufLen;
} }
s_prev_output_buf = aOutputBuf;
s_prev_output_len = aOutputBufLen;
s_prev_input_buf = aInputBuf;
s_prev_input_len = aInputBufLen;
s_spi_transaction.length = aOutputBufLen > aInputBufLen ? aOutputBufLen : aInputBufLen; trans_length = s_output_len > s_input_len ? s_output_len : s_input_len;
s_spi_transaction.length *= CHAR_BIT; trans_length *= CHAR_BIT;
s_spi_transaction.rx_buffer = aInputBuf; if ((gpio_get_level(s_spi_config->slave_config.spics_io_num) == 0)) {
s_spi_transaction.tx_buffer = aOutputBuf;
assert(sizeof(s_spi_transaction.user) >= sizeof(pending_transaction_t));
pending_transaction = (pending_transaction_t *)&(s_spi_transaction.user);
pending_transaction->input_buf_len = aInputBufLen;
pending_transaction->output_buf_len = aOutputBufLen;
s_spi_transaction.user = pending_transaction;
s_request_transaction = aRequestTransactionFlag;
if ((gpio_get_level(s_spi_config.slave_config.spics_io_num) == 0)) {
ESP_EARLY_LOGE(SPI_SLAVE_TAG, "SPI busy"); ESP_EARLY_LOGE(SPI_SLAVE_TAG, "SPI busy");
return OT_ERROR_BUSY; return OT_ERROR_BUSY;
} }
s_spi_transaction->length = trans_length;
s_spi_transaction->rx_buffer = s_input_buf;
s_spi_transaction->tx_buffer = s_output_buf;
pending_transaction_t *pending_transaction = (pending_transaction_t *)s_spi_transaction->user;
pending_transaction->input_buf_len = s_input_len;
pending_transaction->output_buf_len = s_output_len;
s_request_transaction = aRequestTransactionFlag;
if (xPortCanYield()) { if (xPortCanYield()) {
spi_slave_queue_reset(s_spi_config.host_device); spi_slave_queue_reset(s_spi_config->host_device);
trans_state = spi_slave_queue_trans(s_spi_config.host_device, &s_spi_transaction, 0); trans_state = spi_slave_queue_trans(s_spi_config->host_device, s_spi_transaction, 0);
} else { } else {
spi_slave_queue_reset_isr(s_spi_config.host_device); spi_slave_queue_reset_isr(s_spi_config->host_device);
trans_state = spi_slave_queue_trans_isr(s_spi_config.host_device, &s_spi_transaction); trans_state = spi_slave_queue_trans_isr(s_spi_config->host_device, s_spi_transaction);
} }
if (trans_state == ESP_OK) { if (trans_state == ESP_OK) {

View File

@ -1,5 +1,5 @@
/* /*
* SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD * SPDX-FileCopyrightText: 2021-2023 Espressif Systems (Shanghai) CO LTD
* *
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*/ */
@ -57,6 +57,7 @@ typedef struct {
TaskHandle_t source_task; TaskHandle_t source_task;
struct udp_pcb *pcb; struct udp_pcb *pcb;
uint8_t netif_index; uint8_t netif_index;
esp_err_t err;
} udp_bind_netif_task_t; } udp_bind_netif_task_t;
typedef struct { typedef struct {
@ -255,7 +256,6 @@ otError otPlatUdpBind(otUdpSocket *udp_socket)
static void udp_bind_netif_task(void *ctx) static void udp_bind_netif_task(void *ctx)
{ {
udp_bind_netif_task_t *task = (udp_bind_netif_task_t *)ctx; udp_bind_netif_task_t *task = (udp_bind_netif_task_t *)ctx;
udp_bind_netif(task->pcb, netif_get_by_index(task->netif_index)); udp_bind_netif(task->pcb, netif_get_by_index(task->netif_index));
xTaskNotifyGive(task->source_task); xTaskNotifyGive(task->source_task);
} }
@ -276,16 +276,20 @@ static uint8_t get_netif_index(otNetifIdentifier netif_identifier)
otError otPlatUdpBindToNetif(otUdpSocket *udp_socket, otNetifIdentifier netif_identifier) otError otPlatUdpBindToNetif(otUdpSocket *udp_socket, otNetifIdentifier netif_identifier)
{ {
otError err = OT_ERROR_NONE;
udp_bind_netif_task_t task = { udp_bind_netif_task_t task = {
.source_task = xTaskGetCurrentTaskHandle(), .source_task = xTaskGetCurrentTaskHandle(),
.pcb = (struct udp_pcb *)udp_socket->mHandle, .pcb = (struct udp_pcb *)udp_socket->mHandle,
.netif_index = get_netif_index(netif_identifier), .netif_index = get_netif_index(netif_identifier),
.err = ESP_OK,
}; };
tcpip_callback(udp_bind_netif_task, &task); tcpip_callback(udp_bind_netif_task, &task);
wait_for_task_notification(); wait_for_task_notification();
if (task.err != ESP_OK) {
return OT_ERROR_NONE; err = OT_ERROR_FAILED;
}
return err;
} }
static void udp_connect_task(void *ctx) static void udp_connect_task(void *ctx)
@ -424,14 +428,20 @@ exit:
static void udp_multicast_join_leave_task(void *ctx) static void udp_multicast_join_leave_task(void *ctx)
{ {
udp_multicast_join_leave_task_t *task = (udp_multicast_join_leave_task_t *)ctx; udp_multicast_join_leave_task_t *task = (udp_multicast_join_leave_task_t *)ctx;
struct netif *target = netif_get_by_index(task->netif_index);
if (task->is_join) { if (target == NULL) {
if (mld6_joingroup_netif(netif_get_by_index(task->netif_index), &task->addr) != ERR_OK) { ESP_LOGE(OT_PLAT_LOG_TAG, "Failed to %s multicast group, index%d netif is not ready",
ESP_LOGE(OT_PLAT_LOG_TAG, "Failed to join multicast group"); task->is_join ? "join" : "leave", task->netif_index);
}
} else { } else {
if (mld6_leavegroup_netif(netif_get_by_index(task->netif_index), &task->addr) != ERR_OK) { if (task->is_join) {
ESP_LOGE(OT_PLAT_LOG_TAG, "Failed to leave multicast group"); if (mld6_joingroup_netif(target, &task->addr) != ERR_OK) {
ESP_LOGE(OT_PLAT_LOG_TAG, "Failed to join multicast group");
}
} else {
if (mld6_leavegroup_netif(target, &task->addr) != ERR_OK) {
ESP_LOGE(OT_PLAT_LOG_TAG, "Failed to leave multicast group");
}
} }
} }
free(task); free(task);

View File

@ -25,17 +25,39 @@ using ot::Spinel::SpinelInterface;
namespace esp { namespace esp {
namespace openthread { namespace openthread {
SpiSpinelInterface::SpiSpinelInterface(SpinelInterface::ReceiveFrameCallback callback, void *callback_context, SpiSpinelInterface::SpiSpinelInterface(void)
SpinelInterface::RxFrameBuffer &frame_buffer)
: m_event_fd(-1) : m_event_fd(-1)
, m_receiver_frame_callback(callback) , m_receiver_frame_callback(nullptr)
, m_receiver_frame_context(callback_context) , m_receiver_frame_context(nullptr)
, m_receive_frame_buffer(frame_buffer) , m_receive_frame_buffer(nullptr)
, mRcpFailureHandler(nullptr) , mRcpFailureHandler(nullptr)
{ {
} }
esp_err_t SpiSpinelInterface::Init(const esp_openthread_spi_host_config_t &spi_config) SpiSpinelInterface::~SpiSpinelInterface(void)
{
Deinit();
}
otError SpiSpinelInterface::Init(ReceiveFrameCallback aCallback, void *aCallbackContext, RxFrameBuffer &aFrameBuffer)
{
otError error = OT_ERROR_NONE;
m_receiver_frame_callback = aCallback;
m_receiver_frame_context = aCallbackContext;
m_receive_frame_buffer = &aFrameBuffer;
return error;
}
void SpiSpinelInterface::Deinit(void)
{
m_receiver_frame_callback = nullptr;
m_receiver_frame_context = nullptr;
m_receive_frame_buffer = nullptr;
}
esp_err_t SpiSpinelInterface::Enable(const esp_openthread_spi_host_config_t &spi_config)
{ {
ESP_RETURN_ON_FALSE(m_event_fd < 0, ESP_ERR_INVALID_STATE, OT_PLAT_LOG_TAG, "event fd was initialized"); ESP_RETURN_ON_FALSE(m_event_fd < 0, ESP_ERR_INVALID_STATE, OT_PLAT_LOG_TAG, "event fd was initialized");
m_spi_config = spi_config; m_spi_config = spi_config;
@ -62,10 +84,16 @@ esp_err_t SpiSpinelInterface::Init(const esp_openthread_spi_host_config_t &spi_c
ESP_LOGI(OT_PLAT_LOG_TAG, "spinel SPI interface initialization completed"); ESP_LOGI(OT_PLAT_LOG_TAG, "spinel SPI interface initialization completed");
return ESP_OK;
}
esp_err_t SpiSpinelInterface::AfterRadioInit(void)
{
return ConductSPITransaction(true, 0, 0); return ConductSPITransaction(true, 0, 0);
} }
esp_err_t SpiSpinelInterface::Deinit(void)
esp_err_t SpiSpinelInterface::Disable(void)
{ {
if (m_event_fd >= 0) { if (m_event_fd >= 0) {
close(m_event_fd); close(m_event_fd);
@ -80,11 +108,6 @@ esp_err_t SpiSpinelInterface::Deinit(void)
return ESP_OK; return ESP_OK;
} }
SpiSpinelInterface::~SpiSpinelInterface(void)
{
Deinit();
}
otError SpiSpinelInterface::SendFrame(const uint8_t *frame, uint16_t length) otError SpiSpinelInterface::SendFrame(const uint8_t *frame, uint16_t length)
{ {
ESP_RETURN_ON_FALSE(frame, OT_ERROR_INVALID_ARGS, OT_PLAT_LOG_TAG, "empty frame"); ESP_RETURN_ON_FALSE(frame, OT_ERROR_INVALID_ARGS, OT_PLAT_LOG_TAG, "empty frame");
@ -113,13 +136,13 @@ esp_err_t SpiSpinelInterface::ConductSPITransaction(bool reset, uint16_t tx_data
tx_frame.SetHeaderAcceptLen(rx_data_size); tx_frame.SetHeaderAcceptLen(rx_data_size);
uint8_t *rx_buffer; uint8_t *rx_buffer;
otError err = m_receive_frame_buffer.SetSkipLength(kSPIFrameHeaderSize); otError err = m_receive_frame_buffer->SetSkipLength(kSPIFrameHeaderSize);
ESP_RETURN_ON_FALSE(err == OT_ERROR_NONE, ESP_ERR_NO_MEM, OT_PLAT_LOG_TAG, "buffer space is insufficient"); ESP_RETURN_ON_FALSE(err == OT_ERROR_NONE, ESP_ERR_NO_MEM, OT_PLAT_LOG_TAG, "buffer space is insufficient");
rx_buffer = m_receive_frame_buffer.GetFrame() - kSPIFrameHeaderSize; rx_buffer = m_receive_frame_buffer->GetFrame() - kSPIFrameHeaderSize;
if (m_receive_frame_buffer.GetFrameMaxLength() < rx_data_size) { if (m_receive_frame_buffer->GetFrameMaxLength() < rx_data_size) {
rx_data_size = m_receive_frame_buffer.GetFrameMaxLength(); rx_data_size = m_receive_frame_buffer->GetFrameMaxLength();
} }
uint16_t data_size = tx_data_size > rx_data_size ? tx_data_size : rx_data_size; uint16_t data_size = tx_data_size > rx_data_size ? tx_data_size : rx_data_size;
data_size += kSPIFrameHeaderSize; data_size += kSPIFrameHeaderSize;
@ -143,7 +166,7 @@ esp_err_t SpiSpinelInterface::ConductSPITransaction(bool reset, uint16_t tx_data
if (rx_frame.IsResetFlagSet()) { if (rx_frame.IsResetFlagSet()) {
ESP_LOGW(OT_PLAT_LOG_TAG, "RCP Reset"); ESP_LOGW(OT_PLAT_LOG_TAG, "RCP Reset");
m_receive_frame_buffer.DiscardFrame(); m_receive_frame_buffer->DiscardFrame();
return ESP_OK; return ESP_OK;
} }
if (rx_frame.GetHeaderDataLen() == 0 && rx_frame.GetHeaderAcceptLen() == 0) { if (rx_frame.GetHeaderDataLen() == 0 && rx_frame.GetHeaderAcceptLen() == 0) {
@ -156,16 +179,16 @@ esp_err_t SpiSpinelInterface::ConductSPITransaction(bool reset, uint16_t tx_data
if (gpio_get_level(m_spi_config.intr_pin) == 1) { if (gpio_get_level(m_spi_config.intr_pin) == 1) {
m_pending_data_len = 0; m_pending_data_len = 0;
} }
if (m_receive_frame_buffer.SetLength(rx_frame.GetHeaderDataLen()) != OT_ERROR_NONE) { if (m_receive_frame_buffer->SetLength(rx_frame.GetHeaderDataLen()) != OT_ERROR_NONE) {
ESP_LOGW(OT_PLAT_LOG_TAG, "insufficient buffer space to hold a frame of length %d...", ESP_LOGW(OT_PLAT_LOG_TAG, "insufficient buffer space to hold a frame of length %d...",
rx_frame.GetHeaderDataLen()); rx_frame.GetHeaderDataLen());
m_receive_frame_buffer.DiscardFrame(); m_receive_frame_buffer->DiscardFrame();
return ESP_ERR_NO_MEM; return ESP_ERR_NO_MEM;
} }
m_receiver_frame_callback(m_receiver_frame_context); m_receiver_frame_callback(m_receiver_frame_context);
} else { } else {
m_pending_data_len = 0; m_pending_data_len = 0;
m_receive_frame_buffer.DiscardFrame(); m_receive_frame_buffer->DiscardFrame();
} }
m_pending_data_len = 0; m_pending_data_len = 0;
@ -180,26 +203,26 @@ void SpiSpinelInterface::GpioIntrHandler(void *arg)
write(instance->m_event_fd, &event, sizeof(event)); write(instance->m_event_fd, &event, sizeof(event));
} }
void SpiSpinelInterface::Update(void *mainloop) void SpiSpinelInterface::UpdateFdSet(void *aMainloopContext)
{ {
if (m_pending_data_len > 0) { if (m_pending_data_len > 0) {
((esp_openthread_mainloop_context_t *)mainloop)->timeout.tv_sec = 0; ((esp_openthread_mainloop_context_t *)aMainloopContext)->timeout.tv_sec = 0;
((esp_openthread_mainloop_context_t *)mainloop)->timeout.tv_usec = 0; ((esp_openthread_mainloop_context_t *)aMainloopContext)->timeout.tv_usec = 0;
} }
FD_SET(m_event_fd, &((esp_openthread_mainloop_context_t *)mainloop)->read_fds); FD_SET(m_event_fd, &((esp_openthread_mainloop_context_t *)aMainloopContext)->read_fds);
FD_SET(m_event_fd, &((esp_openthread_mainloop_context_t *)mainloop)->error_fds); FD_SET(m_event_fd, &((esp_openthread_mainloop_context_t *)aMainloopContext)->error_fds);
if (m_event_fd > ((esp_openthread_mainloop_context_t *)mainloop)->max_fd) { if (m_event_fd > ((esp_openthread_mainloop_context_t *)aMainloopContext)->max_fd) {
((esp_openthread_mainloop_context_t *)mainloop)->max_fd = m_event_fd; ((esp_openthread_mainloop_context_t *)aMainloopContext)->max_fd = m_event_fd;
} }
} }
void SpiSpinelInterface::Process(const void *mainloop) void SpiSpinelInterface::Process(const void *aMainloopContext)
{ {
if (FD_ISSET(m_event_fd, &((esp_openthread_mainloop_context_t *)mainloop)->error_fds)) { if (FD_ISSET(m_event_fd, &((esp_openthread_mainloop_context_t *)aMainloopContext)->error_fds)) {
ESP_LOGE(OT_PLAT_LOG_TAG, "SPI INTR GPIO error event"); ESP_LOGE(OT_PLAT_LOG_TAG, "SPI INTR GPIO error event");
return; return;
} }
if (FD_ISSET(m_event_fd, &((esp_openthread_mainloop_context_t *)mainloop)->read_fds)) { if (FD_ISSET(m_event_fd, &((esp_openthread_mainloop_context_t *)aMainloopContext)->read_fds)) {
uint64_t event; uint64_t event;
read(m_event_fd, &event, sizeof(event)); read(m_event_fd, &event, sizeof(event));
m_pending_data_len = SpinelInterface::kMaxFrameSize; m_pending_data_len = SpinelInterface::kMaxFrameSize;
@ -249,5 +272,10 @@ otError SpiSpinelInterface::HardwareReset(void)
return OT_ERROR_NONE; return OT_ERROR_NONE;
} }
uint32_t SpiSpinelInterface::GetBusSpeed(void) const
{
return m_spi_config.spi_device.clock_speed_hz;
}
} // namespace openthread } // namespace openthread
} // namespace esp } // namespace esp

View File

@ -27,13 +27,10 @@
namespace esp { namespace esp {
namespace openthread { namespace openthread {
UartSpinelInterface::UartSpinelInterface(ot::Spinel::SpinelInterface::ReceiveFrameCallback callback, UartSpinelInterface::UartSpinelInterface(void)
void *callback_context, : m_receiver_frame_callback(nullptr)
ot::Spinel::SpinelInterface::RxFrameBuffer &frame_buffer) , m_receiver_frame_context(nullptr)
: m_receiver_frame_callback(callback) , m_receive_frame_buffer(nullptr)
, m_receiver_frame_context(callback_context)
, m_receive_frame_buffer(frame_buffer)
, m_hdlc_decoder(frame_buffer, HandleHdlcFrame, this)
, m_uart_fd(-1) , m_uart_fd(-1)
, mRcpFailureHandler(nullptr) , mRcpFailureHandler(nullptr)
{ {
@ -41,9 +38,29 @@ UartSpinelInterface::UartSpinelInterface(ot::Spinel::SpinelInterface::ReceiveFra
UartSpinelInterface::~UartSpinelInterface(void) UartSpinelInterface::~UartSpinelInterface(void)
{ {
Deinit();
} }
esp_err_t UartSpinelInterface::Init(const esp_openthread_uart_config_t &radio_uart_config) otError UartSpinelInterface::Init(ReceiveFrameCallback aCallback, void *aCallbackContext, RxFrameBuffer &aFrameBuffer)
{
otError error = OT_ERROR_NONE;
m_receiver_frame_callback = aCallback;
m_receiver_frame_context = aCallbackContext;
m_receive_frame_buffer = &aFrameBuffer;
m_hdlc_decoder.Init(aFrameBuffer, HandleHdlcFrame, this);
return error;
}
void UartSpinelInterface::Deinit(void)
{
m_receiver_frame_callback = nullptr;
m_receiver_frame_context = nullptr;
m_receive_frame_buffer = nullptr;
}
esp_err_t UartSpinelInterface::Enable(const esp_openthread_uart_config_t &radio_uart_config)
{ {
esp_err_t error = ESP_OK; esp_err_t error = ESP_OK;
m_uart_rx_buffer = static_cast<uint8_t *>(heap_caps_malloc(kMaxFrameSize, MALLOC_CAP_8BIT)); m_uart_rx_buffer = static_cast<uint8_t *>(heap_caps_malloc(kMaxFrameSize, MALLOC_CAP_8BIT));
@ -56,7 +73,7 @@ esp_err_t UartSpinelInterface::Init(const esp_openthread_uart_config_t &radio_ua
return error; return error;
} }
esp_err_t UartSpinelInterface::Deinit(void) esp_err_t UartSpinelInterface::Disable(void)
{ {
if (m_uart_rx_buffer) { if (m_uart_rx_buffer) {
heap_caps_free(m_uart_rx_buffer); heap_caps_free(m_uart_rx_buffer);
@ -88,24 +105,14 @@ exit:
return error; return error;
} }
void UartSpinelInterface::Process(const void *mainloop) void UartSpinelInterface::Process(const void *aMainloopContext)
{ {
if (FD_ISSET(m_uart_fd, &((esp_openthread_mainloop_context_t *)mainloop)->read_fds)) { if (FD_ISSET(m_uart_fd, &((esp_openthread_mainloop_context_t *)aMainloopContext)->read_fds)) {
ESP_LOGD(OT_PLAT_LOG_TAG, "radio uart read event"); ESP_LOGD(OT_PLAT_LOG_TAG, "radio uart read event");
TryReadAndDecode(); TryReadAndDecode();
} }
} }
void UartSpinelInterface::Update(void *mainloop)
{
// Register only READ events for radio UART and always wait
// for a radio WRITE to complete.
FD_SET(m_uart_fd, &((esp_openthread_mainloop_context_t *)mainloop)->read_fds);
if (m_uart_fd > ((esp_openthread_mainloop_context_t *)mainloop)->max_fd) {
((esp_openthread_mainloop_context_t *)mainloop)->max_fd = m_uart_fd;
}
}
int UartSpinelInterface::TryReadAndDecode(void) int UartSpinelInterface::TryReadAndDecode(void)
{ {
uint8_t buffer[UART_HW_FIFO_LEN(m_uart_config.port)]; uint8_t buffer[UART_HW_FIFO_LEN(m_uart_config.port)];
@ -246,7 +253,7 @@ void UartSpinelInterface::HandleHdlcFrame(otError error)
m_receiver_frame_callback(m_receiver_frame_context); m_receiver_frame_callback(m_receiver_frame_context);
} else { } else {
ESP_LOGE(OT_PLAT_LOG_TAG, "dropping radio frame: %s", otThreadErrorToString(error)); ESP_LOGE(OT_PLAT_LOG_TAG, "dropping radio frame: %s", otThreadErrorToString(error));
m_receive_frame_buffer.DiscardFrame(); m_receive_frame_buffer->DiscardFrame();
} }
} }
@ -294,5 +301,20 @@ otError UartSpinelInterface::HardwareReset(void)
return OT_ERROR_NONE; return OT_ERROR_NONE;
} }
void UartSpinelInterface::UpdateFdSet(void *aMainloopContext)
{
// Register only READ events for radio UART and always wait
// for a radio WRITE to complete.
FD_SET(m_uart_fd, &((esp_openthread_mainloop_context_t *)aMainloopContext)->read_fds);
if (m_uart_fd > ((esp_openthread_mainloop_context_t *)aMainloopContext)->max_fd) {
((esp_openthread_mainloop_context_t *)aMainloopContext)->max_fd = m_uart_fd;
}
}
uint32_t UartSpinelInterface::GetBusSpeed(void) const
{
return m_uart_config.uart_config.baud_rate;
}
} // namespace openthread } // namespace openthread
} // namespace esp } // namespace esp

View File

@ -471,32 +471,32 @@ extern "C" {
#define IEEE802154_SFD_TIMEOUT_CNT_CLEAR_S 14 #define IEEE802154_SFD_TIMEOUT_CNT_CLEAR_S 14
#define IEEE802154_CRC_ERROR_CNT_CLEAR (BIT(13)) #define IEEE802154_CRC_ERROR_CNT_CLEAR (BIT(13))
#define IEEE802154_CRC_ERROR_CNT_CLEAR_S 13 #define IEEE802154_CRC_ERROR_CNT_CLEAR_S 13
#define IEEE802154_ED_ABORT_CNT_CLEAR (BIT(12)) #define IEEE802154_RX_FILTER_FAIL_CNT_CLEAR (BIT(12))
#define IEEE802154_ED_ABORT_CNT_CLEAR_S 12 #define IEEE802154_RX_FILTER_FAIL_CNT_CLEAR_S 12
#define IEEE802154_CCA_FAIL_CNT_CLEAR (BIT(11)) #define IEEE802154_NO_RSS_DETECT_CNT_CLEAR (BIT(11))
#define IEEE802154_CCA_FAIL_CNT_CLEAR_S 11 #define IEEE802154_NO_RSS_DETECT_CNT_CLEAR_S 11
#define IEEE802154_RX_FILTER_FAIL_CNT_CLEAR (BIT(10)) #define IEEE802154_RX_ABORT_COEX_CNT_CLEAR (BIT(10))
#define IEEE802154_RX_FILTER_FAIL_CNT_CLEAR_S 10 #define IEEE802154_RX_ABORT_COEX_CNT_CLEAR_S 10
#define IEEE802154_NO_RSS_DETECT_CNT_CLEAR (BIT(9)) #define IEEE802154_RX_ACK_ABORT_COEX_CNT_CLEAR (BIT(9))
#define IEEE802154_NO_RSS_DETECT_CNT_CLEAR_S 9 #define IEEE802154_RX_ACK_ABORT_COEX_CNT_CLEAR_S 9
#define IEEE802154_RX_ABORT_COEX_CNT_CLEAR (BIT(8)) #define IEEE802154_RX_RESTART_CNT_CLEAR (BIT(8))
#define IEEE802154_RX_ABORT_COEX_CNT_CLEAR_S 8 #define IEEE802154_RX_RESTART_CNT_CLEAR_S 8
#define IEEE802154_RX_RESTART_CNT_CLEAR (BIT(7)) #define IEEE802154_RX_ACK_TIMEOUT_CNT_CLEAR (BIT(7))
#define IEEE802154_RX_RESTART_CNT_CLEAR_S 7 #define IEEE802154_RX_ACK_TIMEOUT_CNT_CLEAR_S 7
#define IEEE802154_TX_ACK_ABORT_COEX_CNT_CLEAR (BIT(6)) #define IEEE802154_TX_ACK_ABORT_COEX_CNT_CLEAR (BIT(6))
#define IEEE802154_TX_ACK_ABORT_COEX_CNT_CLEAR_S 6 #define IEEE802154_TX_ACK_ABORT_COEX_CNT_CLEAR_S 6
#define IEEE802154_ED_SCAN_COEX_CNT_CLEAR (BIT(5)) #define IEEE802154_TX_BREAK_COEX_CNT_CLEAR (BIT(5))
#define IEEE802154_ED_SCAN_COEX_CNT_CLEAR_S 5 #define IEEE802154_TX_BREAK_COEX_CNT_CLEAR_S 5
#define IEEE802154_RX_ACK_ABORT_COEX_CNT_CLEAR (BIT(4)) #define IEEE802154_TX_SECURITY_ERROR_CNT_CLEAR (BIT(4))
#define IEEE802154_RX_ACK_ABORT_COEX_CNT_CLEAR_S 4 #define IEEE802154_TX_SECURITY_ERROR_CNT_CLEAR_S 4
#define IEEE802154_RX_ACK_TIMEOUT_CNT_CLEAR (BIT(3)) #define IEEE802154_ED_ABORT_CNT_CLEAR (BIT(3))
#define IEEE802154_RX_ACK_TIMEOUT_CNT_CLEAR_S 3 #define IEEE802154_ED_ABORT_CNT_CLEAR_S 3
#define IEEE802154_TX_BREAK_COEX_CNT_CLEAR (BIT(2)) #define IEEE802154_CCA_FAIL_CNT_CLEAR (BIT(2))
#define IEEE802154_TX_BREAK_COEX_CNT_CLEAR_S 2 #define IEEE802154_CCA_FAIL_CNT_CLEAR_S 2
#define IEEE802154_TX_SECURITY_ERROR_CNT_CLEAR (BIT(1)) #define IEEE802154_CCA_BUSY_CNT_CLEAR (BIT(1))
#define IEEE802154_TX_SECURITY_ERROR_CNT_CLEAR_S 1 #define IEEE802154_CCA_BUSY_CNT_CLEAR_S 1
#define IEEE802154_CCA_BUSY_CNT_CLEAR (BIT(0)) #define IEEE802154_ED_SCAN_COEX_CNT_CLEAR (BIT(0))
#define IEEE802154_CCA_BUSY_CNT_CLEAR_S 0 #define IEEE802154_ED_SCAN_COEX_CNT_CLEAR_S 0
#define IEEE802154_MAC_DATE_REG (IEEE802154_REG_BASE + 0x0184) #define IEEE802154_MAC_DATE_REG (IEEE802154_REG_BASE + 0x0184)
#define IEEE802154_MAC_DATE 0xFFFFFFFF #define IEEE802154_MAC_DATE 0xFFFFFFFF

View File

@ -472,32 +472,32 @@ extern "C" {
#define IEEE802154_SFD_TIMEOUT_CNT_CLEAR_S 14 #define IEEE802154_SFD_TIMEOUT_CNT_CLEAR_S 14
#define IEEE802154_CRC_ERROR_CNT_CLEAR (BIT(13)) #define IEEE802154_CRC_ERROR_CNT_CLEAR (BIT(13))
#define IEEE802154_CRC_ERROR_CNT_CLEAR_S 13 #define IEEE802154_CRC_ERROR_CNT_CLEAR_S 13
#define IEEE802154_ED_ABORT_CNT_CLEAR (BIT(12)) #define IEEE802154_RX_FILTER_FAIL_CNT_CLEAR (BIT(12))
#define IEEE802154_ED_ABORT_CNT_CLEAR_S 12 #define IEEE802154_RX_FILTER_FAIL_CNT_CLEAR_S 12
#define IEEE802154_CCA_FAIL_CNT_CLEAR (BIT(11)) #define IEEE802154_NO_RSS_DETECT_CNT_CLEAR (BIT(11))
#define IEEE802154_CCA_FAIL_CNT_CLEAR_S 11 #define IEEE802154_NO_RSS_DETECT_CNT_CLEAR_S 11
#define IEEE802154_RX_FILTER_FAIL_CNT_CLEAR (BIT(10)) #define IEEE802154_RX_ABORT_COEX_CNT_CLEAR (BIT(10))
#define IEEE802154_RX_FILTER_FAIL_CNT_CLEAR_S 10 #define IEEE802154_RX_ABORT_COEX_CNT_CLEAR_S 10
#define IEEE802154_NO_RSS_DETECT_CNT_CLEAR (BIT(9)) #define IEEE802154_RX_ACK_ABORT_COEX_CNT_CLEAR (BIT(9))
#define IEEE802154_NO_RSS_DETECT_CNT_CLEAR_S 9 #define IEEE802154_RX_ACK_ABORT_COEX_CNT_CLEAR_S 9
#define IEEE802154_RX_ABORT_COEX_CNT_CLEAR (BIT(8)) #define IEEE802154_RX_RESTART_CNT_CLEAR (BIT(8))
#define IEEE802154_RX_ABORT_COEX_CNT_CLEAR_S 8 #define IEEE802154_RX_RESTART_CNT_CLEAR_S 8
#define IEEE802154_RX_RESTART_CNT_CLEAR (BIT(7)) #define IEEE802154_RX_ACK_TIMEOUT_CNT_CLEAR (BIT(7))
#define IEEE802154_RX_RESTART_CNT_CLEAR_S 7 #define IEEE802154_RX_ACK_TIMEOUT_CNT_CLEAR_S 7
#define IEEE802154_TX_ACK_ABORT_COEX_CNT_CLEAR (BIT(6)) #define IEEE802154_TX_ACK_ABORT_COEX_CNT_CLEAR (BIT(6))
#define IEEE802154_TX_ACK_ABORT_COEX_CNT_CLEAR_S 6 #define IEEE802154_TX_ACK_ABORT_COEX_CNT_CLEAR_S 6
#define IEEE802154_ED_SCAN_COEX_CNT_CLEAR (BIT(5)) #define IEEE802154_TX_BREAK_COEX_CNT_CLEAR (BIT(5))
#define IEEE802154_ED_SCAN_COEX_CNT_CLEAR_S 5 #define IEEE802154_TX_BREAK_COEX_CNT_CLEAR_S 5
#define IEEE802154_RX_ACK_ABORT_COEX_CNT_CLEAR (BIT(4)) #define IEEE802154_TX_SECURITY_ERROR_CNT_CLEAR (BIT(4))
#define IEEE802154_RX_ACK_ABORT_COEX_CNT_CLEAR_S 4 #define IEEE802154_TX_SECURITY_ERROR_CNT_CLEAR_S 4
#define IEEE802154_RX_ACK_TIMEOUT_CNT_CLEAR (BIT(3)) #define IEEE802154_ED_ABORT_CNT_CLEAR (BIT(3))
#define IEEE802154_RX_ACK_TIMEOUT_CNT_CLEAR_S 3 #define IEEE802154_ED_ABORT_CNT_CLEAR_S 3
#define IEEE802154_TX_BREAK_COEX_CNT_CLEAR (BIT(2)) #define IEEE802154_CCA_FAIL_CNT_CLEAR (BIT(2))
#define IEEE802154_TX_BREAK_COEX_CNT_CLEAR_S 2 #define IEEE802154_CCA_FAIL_CNT_CLEAR_S 2
#define IEEE802154_TX_SECURITY_ERROR_CNT_CLEAR (BIT(1)) #define IEEE802154_CCA_BUSY_CNT_CLEAR (BIT(1))
#define IEEE802154_TX_SECURITY_ERROR_CNT_CLEAR_S 1 #define IEEE802154_CCA_BUSY_CNT_CLEAR_S 1
#define IEEE802154_CCA_BUSY_CNT_CLEAR (BIT(0)) #define IEEE802154_ED_SCAN_COEX_CNT_CLEAR (BIT(0))
#define IEEE802154_CCA_BUSY_CNT_CLEAR_S 0 #define IEEE802154_ED_SCAN_COEX_CNT_CLEAR_S 0
#define DEBUG_SEL_CFG0_REG (IEEE802154_REG_BASE + 0x184) #define DEBUG_SEL_CFG0_REG (IEEE802154_REG_BASE + 0x184)
#define DEBUG_FIELD3_SEL 0x0000001F #define DEBUG_FIELD3_SEL 0x0000001F

View File

@ -92,8 +92,8 @@ static void ot_task_worker(void *aContext)
esp_openthread_launch_mainloop(); esp_openthread_launch_mainloop();
// Clean up // Clean up
esp_netif_destroy(openthread_netif);
esp_openthread_netif_glue_deinit(); esp_openthread_netif_glue_deinit();
esp_netif_destroy(openthread_netif);
esp_vfs_eventfd_unregister(); esp_vfs_eventfd_unregister();
vTaskDelete(NULL); vTaskDelete(NULL);
} }

View File

@ -95,8 +95,8 @@ static void ot_task_worker(void *aContext)
esp_openthread_launch_mainloop(); esp_openthread_launch_mainloop();
// Clean up // Clean up
esp_netif_destroy(openthread_netif);
esp_openthread_netif_glue_deinit(); esp_openthread_netif_glue_deinit();
esp_netif_destroy(openthread_netif);
esp_vfs_eventfd_unregister(); esp_vfs_eventfd_unregister();
vTaskDelete(NULL); vTaskDelete(NULL);

View File

@ -193,8 +193,8 @@ static void ot_task_worker(void *aContext)
esp_openthread_launch_mainloop(); esp_openthread_launch_mainloop();
// Clean up // Clean up
esp_netif_destroy(openthread_netif);
esp_openthread_netif_glue_deinit(); esp_openthread_netif_glue_deinit();
esp_netif_destroy(openthread_netif);
esp_vfs_eventfd_unregister(); esp_vfs_eventfd_unregister();
vTaskDelete(NULL); vTaskDelete(NULL);

View File

@ -129,8 +129,8 @@ static void ot_task_worker(void *aContext)
esp_openthread_launch_mainloop(); esp_openthread_launch_mainloop();
// Clean up // Clean up
esp_netif_destroy(openthread_netif);
esp_openthread_netif_glue_deinit(); esp_openthread_netif_glue_deinit();
esp_netif_destroy(openthread_netif);
esp_vfs_eventfd_unregister(); esp_vfs_eventfd_unregister();
vTaskDelete(NULL); vTaskDelete(NULL);