diff --git a/components/esp_coex/include/esp_coex_i154.h b/components/esp_coex/include/esp_coex_i154.h index 8bd181eeb5c..942de356139 100644 --- a/components/esp_coex/include/esp_coex_i154.h +++ b/components/esp_coex/include/esp_coex_i154.h @@ -17,6 +17,7 @@ typedef enum { 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_coex_break_notify(void); #endif #endif diff --git a/components/esp_coex/lib b/components/esp_coex/lib index b5da84bed42..667353cc7a0 160000 --- a/components/esp_coex/lib +++ b/components/esp_coex/lib @@ -1 +1 @@ -Subproject commit b5da84bed42578946162241cfc6b37449bd2c251 +Subproject commit 667353cc7a0520924135ce50b798f495cd308e47 diff --git a/components/hal/include/hal/ieee802154_common_ll.h b/components/hal/include/hal/ieee802154_common_ll.h index 45f077bb4a0..60c31b04339 100644 --- a/components/hal/include/hal/ieee802154_common_ll.h +++ b/components/hal/include/hal/ieee802154_common_ll.h @@ -449,6 +449,86 @@ static inline void ieee802154_ll_disable_coex(void) 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; +} + #ifdef __cplusplus } #endif diff --git a/components/ieee802154/Kconfig b/components/ieee802154/Kconfig index cfb51714e31..9c5d18e2375 100644 --- a/components/ieee802154/Kconfig +++ b/components/ieee802154/Kconfig @@ -166,4 +166,11 @@ menu "IEEE 802.15.4" default 10 help 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 diff --git a/components/ieee802154/driver/esp_ieee802154_debug.c b/components/ieee802154/driver/esp_ieee802154_debug.c index 6398a05dd64..2b172ad9521 100644 --- a/components/ieee802154/driver/esp_ieee802154_debug.c +++ b/components/ieee802154/driver/esp_ieee802154_debug.c @@ -5,6 +5,7 @@ */ #include +#include #include "hal/ieee802154_ll.h" #include "esp_ieee802154_util.h" #include "esp_log.h" @@ -237,4 +238,122 @@ void ieee802154_assert_print(void) } #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 diff --git a/components/ieee802154/driver/esp_ieee802154_dev.c b/components/ieee802154/driver/esp_ieee802154_dev.c index 2c95c192a49..67074f56cde 100644 --- a/components/ieee802154/driver/esp_ieee802154_dev.c +++ b/components/ieee802154/driver/esp_ieee802154_dev.c @@ -455,7 +455,11 @@ static IRAM_ATTR void isr_handle_tx_abort(void) next_operation(); 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_TX_BREAK_COEX_NUMS_UPDATE(); esp_ieee802154_transmit_failed(s_tx_frame, ESP_IEEE802154_TX_ERR_COEXIST); next_operation(); break; @@ -628,6 +632,7 @@ esp_err_t ieee802154_mac_init(void) esp_err_t ret = ESP_OK; modem_clock_module_mac_reset(PERIPH_IEEE802154_MODULE); // reset ieee802154 MAC ieee802154_pib_init(); + IEEE802154_TXRX_STATISTIC_CLEAR(); ieee802154_ll_enable_events(IEEE802154_EVENT_MASK); #if !CONFIG_IEEE802154_TEST @@ -682,6 +687,7 @@ IEEE802154_STATIC void start_ed(uint32_t duration) IEEE802154_STATIC void tx_init(const uint8_t *frame) { + IEEE802154_TX_NUMS_UPDATE(); s_tx_frame = (uint8_t *)frame; stop_current_operation(); ieee802154_pib_update(); diff --git a/components/ieee802154/esp_ieee802154.c b/components/ieee802154/esp_ieee802154.c index 5414b18d025..c97c32f582d 100644 --- a/components/ieee802154/esp_ieee802154.c +++ b/components/ieee802154/esp_ieee802154.c @@ -395,3 +395,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 diff --git a/components/ieee802154/include/esp_ieee802154.h b/components/ieee802154/include/esp_ieee802154.h index 96de1a07758..0cb1cb272df 100644 --- a/components/ieee802154/include/esp_ieee802154.h +++ b/components/ieee802154/include/esp_ieee802154.h @@ -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); +/** + * 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 } #endif diff --git a/components/ieee802154/private_include/esp_ieee802154_util.h b/components/ieee802154/private_include/esp_ieee802154_util.h index a34d0df7aed..3288ac9e800 100644 --- a/components/ieee802154/private_include/esp_ieee802154_util.h +++ b/components/ieee802154/private_include/esp_ieee802154_util.h @@ -25,6 +25,7 @@ extern "C" { #define IEEE802154_PROBE(a) do { \ IEEE802154_RECORD_EVENT(a); \ ieee802154_record_abort(a); \ + IEEE802154_TXRX_STATISTIC(a); \ } while(0) #if CONFIG_IEEE802154_RECORD_EVENT @@ -180,6 +181,62 @@ void ieee802154_assert_print(void); #define IEEE802154_ASSERT(a) assert(a) #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 diff --git a/components/openthread/CMakeLists.txt b/components/openthread/CMakeLists.txt index 455b346924e..64025c75dbb 100644 --- a/components/openthread/CMakeLists.txt +++ b/components/openthread/CMakeLists.txt @@ -10,6 +10,7 @@ if(CONFIG_OPENTHREAD_ENABLED) "openthread/include/openthread" "openthread/src" "openthread/src/core" + "openthread/src/lib" "openthread/src/lib/hdlc" "openthread/src/lib/spinel" "openthread/src/ncp" @@ -23,6 +24,7 @@ if(CONFIG_OPENTHREAD_ENABLED) "openthread/src/core/common" "openthread/src/core/crypto" "openthread/src/core/diags" + "openthread/src/core/instance" "openthread/src/core/mac" "openthread/src/core/radio" "openthread/src/core/thread" @@ -33,7 +35,7 @@ if(CONFIG_OPENTHREAD_ENABLED) set(exclude_srcs "openthread/examples/platforms/utils/logging_rtt.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) list(APPEND src_dirs diff --git a/components/openthread/Kconfig b/components/openthread/Kconfig index d18ec6b8924..c298ca40e5f 100644 --- a/components/openthread/Kconfig +++ b/components/openthread/Kconfig @@ -163,6 +163,7 @@ menu "OpenThread" config OPENTHREAD_RCP_SPI bool "SPI RCP" + select GPIO_CTRL_FUNC_IN_IRAM help Select this to enable SPI connection to host. endchoice diff --git a/components/openthread/include/esp_openthread_border_router.h b/components/openthread/include/esp_openthread_border_router.h index 33f9244eb7d..3a6c6e96387 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-2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2021-2023 Espressif Systems (Shanghai) CO LTD * * 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. * + * @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 conneciton to RCP. + * + * @return + * - ESP_OK on success + * - ESP_FAIL if fail to initialize RCP + * */ -void esp_openthread_rcp_deinit(void); +esp_err_t esp_openthread_rcp_init(void); #ifdef __cplusplus } diff --git a/components/openthread/lib b/components/openthread/lib index 12f563ee490..648c28e7925 160000 --- a/components/openthread/lib +++ b/components/openthread/lib @@ -1 +1 @@ -Subproject commit 12f563ee490236f7332eb22f568e71c7c1d4a3b7 +Subproject commit 648c28e792567bc00602c92e43518c1784599251 diff --git a/components/openthread/openthread b/components/openthread/openthread index af5938e389b..41ef80717f4 160000 --- a/components/openthread/openthread +++ b/components/openthread/openthread @@ -1 +1 @@ -Subproject commit af5938e389be40650507748272bb6c6b3a2de2cf +Subproject commit 41ef80717f4b757440125932723cc8721ef42f7f diff --git a/components/openthread/private_include/esp_openthread_radio.h b/components/openthread/private_include/esp_openthread_radio.h index 7cf41a559b7..d3fa70aa2cc 100644 --- a/components/openthread/private_include/esp_openthread_radio.h +++ b/components/openthread/private_include/esp_openthread_radio.h @@ -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 */ diff --git a/components/openthread/private_include/esp_spi_spinel_interface.hpp b/components/openthread/private_include/esp_spi_spinel_interface.hpp index 6b8ae2833e1..e5b0976e1fd 100644 --- a/components/openthread/private_include/esp_spi_spinel_interface.hpp +++ b/components/openthread/private_include/esp_spi_spinel_interface.hpp @@ -14,18 +14,12 @@ namespace esp { namespace openthread { -class SpiSpinelInterface { +class SpiSpinelInterface : public ot::Spinel::SpinelInterface { public: /** * @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, - ot::Spinel::SpinelInterface::RxFrameBuffer &frame_buffer); + SpiSpinelInterface(); /** * @brief This destructor of the object. @@ -34,24 +28,26 @@ class SpiSpinelInterface { ~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. @@ -80,20 +76,42 @@ class SpiSpinelInterface { 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. @@ -111,10 +129,33 @@ class SpiSpinelInterface { 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: static constexpr uint8_t kSPIFrameHeaderSize = 5; @@ -130,14 +171,16 @@ class SpiSpinelInterface { int m_event_fd; 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; - ot::Spinel::SpinelInterface::RxFrameBuffer &m_receive_frame_buffer; + RxFrameBuffer *m_receive_frame_buffer; bool m_has_pending_device_frame; spi_device_handle_t m_device; esp_openthread_rcp_failure_handler mRcpFailureHandler; + + otRcpInterfaceMetrics mInterfaceMetrics; }; } // namespace openthread diff --git a/components/openthread/private_include/esp_spinel_interface.hpp b/components/openthread/private_include/esp_spinel_interface.hpp new file mode 100644 index 00000000000..7a393e570d7 --- /dev/null +++ b/components/openthread/private_include/esp_spinel_interface.hpp @@ -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 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 diff --git a/components/openthread/private_include/esp_uart_spinel_interface.hpp b/components/openthread/private_include/esp_uart_spinel_interface.hpp index d21c16a23bc..8926ab7fc13 100644 --- a/components/openthread/private_include/esp_uart_spinel_interface.hpp +++ b/components/openthread/private_include/esp_uart_spinel_interface.hpp @@ -21,18 +21,12 @@ namespace openthread { * This class defines an UART interface to the Radio Co-processor (RCP). * */ -class UartSpinelInterface { +class UartSpinelInterface : public ot::Spinel::SpinelInterface { public: /** * @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, - ot::Spinel::SpinelInterface::RxFrameBuffer &frame_buffer); + UartSpinelInterface(void); /** * @brief This destructor of the object. @@ -41,80 +35,101 @@ class UartSpinelInterface { ~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 - * for up to `kMaxWaitTime` interval. + * @param[in] aFrame A pointer to buffer containing the spinel frame to send. + * @param[in] aLength The length (number of bytes) in the frame. * - * @param[in] frame A pointer to buffer containing the spinel frame to send. - * @param[in] length The length (number of bytes) in the frame. - * - * @return - * -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`. + * @retval OT_ERROR_NONE Successfully encoded and sent the spinel 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. + * @retval OT_ERROR_FAILED Failed to call the SPI driver to send the frame. * */ - 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 - * -OT_ERROR_NONE Part or all of spinel frame is received. - * -OT_ERROR_RESPONSE_TIMEOUT No spinel frame is received within @p timeout_us. + * @retval OT_ERROR_NONE Part or all of spinel frame is received. + * @retval OT_ERROR_RESPONSE_TIMEOUT No spinel frame is received within @p aTimeout. * */ - 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); /** - * This methods registers the callback for RCP failure. + * Returns the bus speed between the host and the radio. * - * @param[in] handler The RCP failure handler. + * @returns Bus speed in bits/second. * */ - void RegisterRcpFailureHandler(esp_openthread_rcp_failure_handler handler) { mRcpFailureHandler = handler; } + uint32_t GetBusSpeed(void) const; /** - * This method is called when RCP failure detected and resets internal states of the interface. + * 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. + * + * @param[in] handler The RCP failure handler. + * + */ + void RegisterRcpFailureHandler(esp_openthread_rcp_failure_handler handler) { mRcpFailureHandler = handler; } + /** * This method is called when RCP is reset to recreate the connection with it. * Intentionally empty. @@ -122,14 +137,25 @@ class UartSpinelInterface { */ otError ResetConnection(void) { return OT_ERROR_NONE; } + /** + * @brief This method enable the HDLC interface. + * + * @return + * - ESP_OK on success + * - ESP_ERR_NO_MEM if allocation has failed + * - 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 spinel frame size. - * - */ - kMaxFrameSize = ot::Spinel::SpinelInterface::kMaxFrameSize, + enum { /** * Maximum wait time in Milliseconds for socket to become writable (see `SendFrame`). * @@ -152,9 +178,9 @@ class UartSpinelInterface { static void HandleHdlcFrame(void *context, otError error); void HandleHdlcFrame(otError error); - ot::Spinel::SpinelInterface::ReceiveFrameCallback m_receiver_frame_callback; + ReceiveFrameCallback m_receiver_frame_callback; void *m_receiver_frame_context; - ot::Spinel::SpinelInterface::RxFrameBuffer &m_receive_frame_buffer; + RxFrameBuffer *m_receive_frame_buffer; ot::Hdlc::Decoder m_hdlc_decoder; uint8_t *m_uart_rx_buffer; @@ -162,6 +188,8 @@ class UartSpinelInterface { esp_openthread_uart_config_t m_uart_config; int m_uart_fd; + otRcpInterfaceMetrics mInterfaceMetrics; + // Non-copyable, intentionally not implemented. UartSpinelInterface(const UartSpinelInterface &); UartSpinelInterface &operator=(const UartSpinelInterface &); diff --git a/components/openthread/src/esp_openthread_platform.cpp b/components/openthread/src/esp_openthread_platform.cpp index ef46800a78c..f6f29e278e5 100644 --- a/components/openthread/src/esp_openthread_platform.cpp +++ b/components/openthread/src/esp_openthread_platform.cpp @@ -20,7 +20,7 @@ #include "esp_partition.h" #include "common/code_utils.hpp" #include "common/logging.hpp" -#include "core/common/instance.hpp" +#include "core/instance/instance.hpp" #include "freertos/FreeRTOS.h" #include "freertos/queue.h" #include "openthread/cli.h" diff --git a/components/openthread/src/port/esp_openthread_radio_spinel.cpp b/components/openthread/src/port/esp_openthread_radio_spinel.cpp index 2e0cab92f7a..83fdf9b006a 100644 --- a/components/openthread/src/port/esp_openthread_radio_spinel.cpp +++ b/components/openthread/src/port/esp_openthread_radio_spinel.cpp @@ -13,6 +13,7 @@ #include "esp_openthread_platform.h" #include "esp_openthread_types.h" #include "esp_system.h" +#include "esp_spinel_interface.hpp" #include "esp_spi_spinel_interface.hpp" #include "esp_uart_spinel_interface.hpp" #include "openthread-core-config.h" @@ -20,41 +21,100 @@ #include "lib/spinel/spinel.h" #include "openthread/platform/diag.h" #include "openthread/platform/radio.h" +#include "platform/exit_code.h" 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; -static RadioSpinel s_radio; +static SpinelInterfaceAdapter s_spinel_interface; #else // CONFIG_OPENTHREAD_RADIO_SPINEL_SPI using esp::openthread::SpiSpinelInterface; -static RadioSpinel s_radio; -#endif // CONFIG_OPENTHREAD_RADIO_SPINEL_UART +static SpinelInterfaceAdapter s_spinel_interface; +#endif + +static RadioSpinel s_radio; 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) { -#if CONFIG_OPENTHREAD_RADIO_SPINEL_UART - ESP_RETURN_ON_ERROR(s_radio.GetSpinelInterface().Init(config->radio_config.radio_uart_config), OT_PLAT_LOG_TAG, + spinel_iid_t iidList[ot::Spinel::kSpinelHeaderMaxNumIid]; + 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"); -#else // CONFIG_OPENTHREAD_RADIO_SPINEL_SPI - ESP_RETURN_ON_ERROR(s_radio.GetSpinelInterface().Init(config->radio_config.radio_spi_config), OT_PLAT_LOG_TAG, +#else // CONFIG_OPENTHREAD_RADIO_SPINEL_SPI + ESP_RETURN_ON_ERROR(s_spinel_interface.GetSpinelInterface().Enable(config->radio_config.radio_spi_config), OT_PLAT_LOG_TAG, "Spinel interface init failed"); -#endif // CONFIG_OPENTHREAD_RADIO_SPINEL_UART - s_radio.Init(/*reset_radio=*/true, /*skip_rcp_compatibility_check=*/false); +#endif + 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, radiospinel_workflow); } void esp_openthread_register_rcp_failure_handler(esp_openthread_rcp_failure_handler handler) { - s_radio.GetSpinelInterface().RegisterRcpFailureHandler(handler); + s_spinel_interface.GetSpinelInterface().RegisterRcpFailureHandler(handler); +} + +esp_err_t esp_openthread_rcp_deinit(void) +{ + 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; } -void esp_openthread_rcp_deinit(void) +esp_err_t esp_openthread_rcp_init(void) { - s_radio.GetSpinelInterface().Deinit(); + 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) @@ -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) { - s_radio.GetSpinelInterface().Update((void *)mainloop); + s_spinel_interface.GetSpinelInterface().UpdateFdSet((void *)mainloop); } void otPlatRadioGetIeeeEui64(otInstance *instance, uint8_t *ieee_eui64) diff --git a/components/openthread/src/port/esp_openthread_spi_slave.c b/components/openthread/src/port/esp_openthread_spi_slave.c index 33268bb8c5b..979e6067e79 100644 --- a/components/openthread/src/port/esp_openthread_spi_slave.c +++ b/components/openthread/src/port/esp_openthread_spi_slave.c @@ -17,10 +17,10 @@ #include "esp_attr.h" #include "esp_check.h" #include "esp_err.h" +#include "esp_heap_caps.h" #include "esp_openthread_common_macro.h" #include "esp_openthread_task_queue.h" #include "esp_openthread_types.h" -#include "esp_rom_sys.h" #include #include #include "driver/gpio.h" @@ -33,37 +33,38 @@ static const char *SPI_SLAVE_TAG = "spi_slave"; static void *s_context = NULL; -static uint8_t *s_prev_output_buf; -static uint16_t s_prev_output_len; -static uint8_t *s_prev_input_buf; -static uint16_t s_prev_input_len; +static uint8_t *s_output_buf; +static uint16_t s_output_len; +static uint8_t *s_input_buf; +static uint16_t s_input_len; 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 { uint16_t output_buf_len; uint16_t input_buf_len; } 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) { 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) { - gpio_set_level(s_spi_config.intr_pin, 1); - pending_transaction_t *pending_transaction = (pending_transaction_t *)&(trans->user); + gpio_set_level(s_spi_config->intr_pin, 1); + pending_transaction_t *pending_transaction = (pending_transaction_t *)(trans->user); trans->trans_len /= CHAR_BIT; 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)) { 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) { - 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 = { .intr_type = GPIO_INTR_DISABLE, .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"); - 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.slave_config.spics_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->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 */ - s_spi_config.slave_config.post_setup_cb = handle_spi_setup_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, - &s_spi_config.slave_config, SPI_DMA_CH_AUTO), + s_spi_config->slave_config.post_setup_cb = handle_spi_setup_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, + &s_spi_config->slave_config, SPI_DMA_CH_AUTO), OT_PLAT_LOG_TAG, "fail to initialize SPI slave"); 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) { - spi_slave_free(s_spi_config.host_device); - s_spi_config.slave_config.post_setup_cb = NULL; - s_spi_config.slave_config.post_trans_cb = NULL; + spi_slave_free(s_spi_config->host_device); + s_spi_config->slave_config.post_setup_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; } @@ -115,43 +137,38 @@ otError IRAM_ATTR otPlatSpiSlavePrepareTransaction(uint8_t *aOutputBuf, uint16_t uint16_t aInputBufLen, bool aRequestTransactionFlag) { esp_err_t trans_state = ESP_OK; - pending_transaction_t *pending_transaction = NULL; - if (aOutputBuf == NULL) { - aOutputBuf = s_prev_output_buf; - aOutputBufLen = s_prev_output_len; + uint16_t trans_length = 0; + + if (aOutputBuf != NULL) { + s_output_buf = aOutputBuf; + s_output_len = aOutputBufLen; } - if (aInputBuf == NULL) { - aInputBuf = s_prev_input_buf; - aInputBufLen = s_prev_input_len; + if (aInputBuf != NULL) { + s_input_buf = aInputBuf; + 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; - s_spi_transaction.length *= CHAR_BIT; - s_spi_transaction.rx_buffer = aInputBuf; - 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)) { + trans_length = s_output_len > s_input_len ? s_output_len : s_input_len; + trans_length *= CHAR_BIT; + if ((gpio_get_level(s_spi_config->slave_config.spics_io_num) == 0)) { ESP_EARLY_LOGE(SPI_SLAVE_TAG, "SPI 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()) { - spi_slave_queue_reset(s_spi_config.host_device); - trans_state = spi_slave_queue_trans(s_spi_config.host_device, &s_spi_transaction, 0); + spi_slave_queue_reset(s_spi_config->host_device); + trans_state = spi_slave_queue_trans(s_spi_config->host_device, s_spi_transaction, 0); } else { - 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); + 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); } if (trans_state == ESP_OK) { diff --git a/components/openthread/src/port/esp_openthread_udp.c b/components/openthread/src/port/esp_openthread_udp.c index 08c8e12e6c8..852c0a920a0 100644 --- a/components/openthread/src/port/esp_openthread_udp.c +++ b/components/openthread/src/port/esp_openthread_udp.c @@ -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 */ @@ -57,6 +57,7 @@ typedef struct { TaskHandle_t source_task; struct udp_pcb *pcb; uint8_t netif_index; + esp_err_t err; } udp_bind_netif_task_t; typedef struct { @@ -255,7 +256,6 @@ otError otPlatUdpBind(otUdpSocket *udp_socket) static void udp_bind_netif_task(void *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)); 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 err = OT_ERROR_NONE; udp_bind_netif_task_t task = { .source_task = xTaskGetCurrentTaskHandle(), .pcb = (struct udp_pcb *)udp_socket->mHandle, .netif_index = get_netif_index(netif_identifier), + .err = ESP_OK, }; tcpip_callback(udp_bind_netif_task, &task); wait_for_task_notification(); - - return OT_ERROR_NONE; + if (task.err != ESP_OK) { + err = OT_ERROR_FAILED; + } + return err; } static void udp_connect_task(void *ctx) @@ -424,14 +428,20 @@ otError otPlatUdpSend(otUdpSocket *udp_socket, otMessage *message, const otMessa static void udp_multicast_join_leave_task(void *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 (mld6_joingroup_netif(netif_get_by_index(task->netif_index), &task->addr) != ERR_OK) { - ESP_LOGE(OT_PLAT_LOG_TAG, "Failed to join multicast group"); - } + if (target == NULL) { + ESP_LOGE(OT_PLAT_LOG_TAG, "Failed to %s multicast group, index%d netif is not ready", + task->is_join ? "join" : "leave", task->netif_index); } else { - if (mld6_leavegroup_netif(netif_get_by_index(task->netif_index), &task->addr) != ERR_OK) { - ESP_LOGE(OT_PLAT_LOG_TAG, "Failed to leave multicast group"); + if (task->is_join) { + 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); diff --git a/components/openthread/src/port/esp_spi_spinel_interface.cpp b/components/openthread/src/port/esp_spi_spinel_interface.cpp index adaa09ecc09..64c6efd6b67 100644 --- a/components/openthread/src/port/esp_spi_spinel_interface.cpp +++ b/components/openthread/src/port/esp_spi_spinel_interface.cpp @@ -25,17 +25,39 @@ using ot::Spinel::SpinelInterface; namespace esp { namespace openthread { -SpiSpinelInterface::SpiSpinelInterface(SpinelInterface::ReceiveFrameCallback callback, void *callback_context, - SpinelInterface::RxFrameBuffer &frame_buffer) +SpiSpinelInterface::SpiSpinelInterface(void) : m_event_fd(-1) - , m_receiver_frame_callback(callback) - , m_receiver_frame_context(callback_context) - , m_receive_frame_buffer(frame_buffer) + , m_receiver_frame_callback(nullptr) + , m_receiver_frame_context(nullptr) + , m_receive_frame_buffer(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"); 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"); + return ESP_OK; +} + +esp_err_t SpiSpinelInterface::AfterRadioInit(void) +{ return ConductSPITransaction(true, 0, 0); } -esp_err_t SpiSpinelInterface::Deinit(void) + +esp_err_t SpiSpinelInterface::Disable(void) { if (m_event_fd >= 0) { close(m_event_fd); @@ -80,11 +108,6 @@ esp_err_t SpiSpinelInterface::Deinit(void) return ESP_OK; } -SpiSpinelInterface::~SpiSpinelInterface(void) -{ - Deinit(); -} - 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"); @@ -113,13 +136,13 @@ esp_err_t SpiSpinelInterface::ConductSPITransaction(bool reset, uint16_t tx_data tx_frame.SetHeaderAcceptLen(rx_data_size); 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"); - rx_buffer = m_receive_frame_buffer.GetFrame() - kSPIFrameHeaderSize; - if (m_receive_frame_buffer.GetFrameMaxLength() < rx_data_size) { - rx_data_size = m_receive_frame_buffer.GetFrameMaxLength(); + rx_buffer = m_receive_frame_buffer->GetFrame() - kSPIFrameHeaderSize; + if (m_receive_frame_buffer->GetFrameMaxLength() < rx_data_size) { + rx_data_size = m_receive_frame_buffer->GetFrameMaxLength(); } uint16_t data_size = tx_data_size > rx_data_size ? tx_data_size : rx_data_size; data_size += kSPIFrameHeaderSize; @@ -143,7 +166,7 @@ esp_err_t SpiSpinelInterface::ConductSPITransaction(bool reset, uint16_t tx_data if (rx_frame.IsResetFlagSet()) { ESP_LOGW(OT_PLAT_LOG_TAG, "RCP Reset"); - m_receive_frame_buffer.DiscardFrame(); + m_receive_frame_buffer->DiscardFrame(); return ESP_OK; } 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) { 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...", rx_frame.GetHeaderDataLen()); - m_receive_frame_buffer.DiscardFrame(); + m_receive_frame_buffer->DiscardFrame(); return ESP_ERR_NO_MEM; } m_receiver_frame_callback(m_receiver_frame_context); } else { m_pending_data_len = 0; - m_receive_frame_buffer.DiscardFrame(); + m_receive_frame_buffer->DiscardFrame(); } m_pending_data_len = 0; @@ -180,26 +203,26 @@ void SpiSpinelInterface::GpioIntrHandler(void *arg) write(instance->m_event_fd, &event, sizeof(event)); } -void SpiSpinelInterface::Update(void *mainloop) +void SpiSpinelInterface::UpdateFdSet(void *aMainloopContext) { if (m_pending_data_len > 0) { - ((esp_openthread_mainloop_context_t *)mainloop)->timeout.tv_sec = 0; - ((esp_openthread_mainloop_context_t *)mainloop)->timeout.tv_usec = 0; + ((esp_openthread_mainloop_context_t *)aMainloopContext)->timeout.tv_sec = 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 *)mainloop)->error_fds); - if (m_event_fd > ((esp_openthread_mainloop_context_t *)mainloop)->max_fd) { - ((esp_openthread_mainloop_context_t *)mainloop)->max_fd = m_event_fd; + FD_SET(m_event_fd, &((esp_openthread_mainloop_context_t *)aMainloopContext)->read_fds); + FD_SET(m_event_fd, &((esp_openthread_mainloop_context_t *)aMainloopContext)->error_fds); + if (m_event_fd > ((esp_openthread_mainloop_context_t *)aMainloopContext)->max_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"); 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; read(m_event_fd, &event, sizeof(event)); m_pending_data_len = SpinelInterface::kMaxFrameSize; @@ -249,5 +272,10 @@ otError SpiSpinelInterface::HardwareReset(void) return OT_ERROR_NONE; } +uint32_t SpiSpinelInterface::GetBusSpeed(void) const +{ + return m_spi_config.spi_device.clock_speed_hz; +} + } // namespace openthread } // namespace esp diff --git a/components/openthread/src/port/esp_uart_spinel_interface.cpp b/components/openthread/src/port/esp_uart_spinel_interface.cpp index 6389d8f8daa..bb0dc186b89 100644 --- a/components/openthread/src/port/esp_uart_spinel_interface.cpp +++ b/components/openthread/src/port/esp_uart_spinel_interface.cpp @@ -27,13 +27,10 @@ namespace esp { namespace openthread { -UartSpinelInterface::UartSpinelInterface(ot::Spinel::SpinelInterface::ReceiveFrameCallback callback, - void *callback_context, - ot::Spinel::SpinelInterface::RxFrameBuffer &frame_buffer) - : m_receiver_frame_callback(callback) - , m_receiver_frame_context(callback_context) - , m_receive_frame_buffer(frame_buffer) - , m_hdlc_decoder(frame_buffer, HandleHdlcFrame, this) +UartSpinelInterface::UartSpinelInterface(void) + : m_receiver_frame_callback(nullptr) + , m_receiver_frame_context(nullptr) + , m_receive_frame_buffer(nullptr) , m_uart_fd(-1) , mRcpFailureHandler(nullptr) { @@ -41,9 +38,29 @@ UartSpinelInterface::UartSpinelInterface(ot::Spinel::SpinelInterface::ReceiveFra 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; m_uart_rx_buffer = static_cast(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; } -esp_err_t UartSpinelInterface::Deinit(void) +esp_err_t UartSpinelInterface::Disable(void) { if (m_uart_rx_buffer) { heap_caps_free(m_uart_rx_buffer); @@ -88,24 +105,14 @@ otError UartSpinelInterface::SendFrame(const uint8_t *frame, uint16_t length) 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"); 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) { uint8_t buffer[UART_FIFO_LEN]; @@ -246,7 +253,7 @@ void UartSpinelInterface::HandleHdlcFrame(otError error) m_receiver_frame_callback(m_receiver_frame_context); } else { 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; } +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 esp diff --git a/components/soc/esp32c6/include/soc/ieee802154_reg.h b/components/soc/esp32c6/include/soc/ieee802154_reg.h index 978ef141bc7..db8e6e12bfe 100644 --- a/components/soc/esp32c6/include/soc/ieee802154_reg.h +++ b/components/soc/esp32c6/include/soc/ieee802154_reg.h @@ -471,32 +471,32 @@ extern "C" { #define IEEE802154_SFD_TIMEOUT_CNT_CLEAR_S 14 #define IEEE802154_CRC_ERROR_CNT_CLEAR (BIT(13)) #define IEEE802154_CRC_ERROR_CNT_CLEAR_S 13 -#define IEEE802154_ED_ABORT_CNT_CLEAR (BIT(12)) -#define IEEE802154_ED_ABORT_CNT_CLEAR_S 12 -#define IEEE802154_CCA_FAIL_CNT_CLEAR (BIT(11)) -#define IEEE802154_CCA_FAIL_CNT_CLEAR_S 11 -#define IEEE802154_RX_FILTER_FAIL_CNT_CLEAR (BIT(10)) -#define IEEE802154_RX_FILTER_FAIL_CNT_CLEAR_S 10 -#define IEEE802154_NO_RSS_DETECT_CNT_CLEAR (BIT(9)) -#define IEEE802154_NO_RSS_DETECT_CNT_CLEAR_S 9 -#define IEEE802154_RX_ABORT_COEX_CNT_CLEAR (BIT(8)) -#define IEEE802154_RX_ABORT_COEX_CNT_CLEAR_S 8 -#define IEEE802154_RX_RESTART_CNT_CLEAR (BIT(7)) -#define IEEE802154_RX_RESTART_CNT_CLEAR_S 7 +#define IEEE802154_RX_FILTER_FAIL_CNT_CLEAR (BIT(12)) +#define IEEE802154_RX_FILTER_FAIL_CNT_CLEAR_S 12 +#define IEEE802154_NO_RSS_DETECT_CNT_CLEAR (BIT(11)) +#define IEEE802154_NO_RSS_DETECT_CNT_CLEAR_S 11 +#define IEEE802154_RX_ABORT_COEX_CNT_CLEAR (BIT(10)) +#define IEEE802154_RX_ABORT_COEX_CNT_CLEAR_S 10 +#define IEEE802154_RX_ACK_ABORT_COEX_CNT_CLEAR (BIT(9)) +#define IEEE802154_RX_ACK_ABORT_COEX_CNT_CLEAR_S 9 +#define IEEE802154_RX_RESTART_CNT_CLEAR (BIT(8)) +#define IEEE802154_RX_RESTART_CNT_CLEAR_S 8 +#define IEEE802154_RX_ACK_TIMEOUT_CNT_CLEAR (BIT(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_S 6 -#define IEEE802154_ED_SCAN_COEX_CNT_CLEAR (BIT(5)) -#define IEEE802154_ED_SCAN_COEX_CNT_CLEAR_S 5 -#define IEEE802154_RX_ACK_ABORT_COEX_CNT_CLEAR (BIT(4)) -#define IEEE802154_RX_ACK_ABORT_COEX_CNT_CLEAR_S 4 -#define IEEE802154_RX_ACK_TIMEOUT_CNT_CLEAR (BIT(3)) -#define IEEE802154_RX_ACK_TIMEOUT_CNT_CLEAR_S 3 -#define IEEE802154_TX_BREAK_COEX_CNT_CLEAR (BIT(2)) -#define IEEE802154_TX_BREAK_COEX_CNT_CLEAR_S 2 -#define IEEE802154_TX_SECURITY_ERROR_CNT_CLEAR (BIT(1)) -#define IEEE802154_TX_SECURITY_ERROR_CNT_CLEAR_S 1 -#define IEEE802154_CCA_BUSY_CNT_CLEAR (BIT(0)) -#define IEEE802154_CCA_BUSY_CNT_CLEAR_S 0 +#define IEEE802154_TX_BREAK_COEX_CNT_CLEAR (BIT(5)) +#define IEEE802154_TX_BREAK_COEX_CNT_CLEAR_S 5 +#define IEEE802154_TX_SECURITY_ERROR_CNT_CLEAR (BIT(4)) +#define IEEE802154_TX_SECURITY_ERROR_CNT_CLEAR_S 4 +#define IEEE802154_ED_ABORT_CNT_CLEAR (BIT(3)) +#define IEEE802154_ED_ABORT_CNT_CLEAR_S 3 +#define IEEE802154_CCA_FAIL_CNT_CLEAR (BIT(2)) +#define IEEE802154_CCA_FAIL_CNT_CLEAR_S 2 +#define IEEE802154_CCA_BUSY_CNT_CLEAR (BIT(1)) +#define IEEE802154_CCA_BUSY_CNT_CLEAR_S 1 +#define IEEE802154_ED_SCAN_COEX_CNT_CLEAR (BIT(0)) +#define IEEE802154_ED_SCAN_COEX_CNT_CLEAR_S 0 #define IEEE802154_MAC_DATE_REG (IEEE802154_REG_BASE + 0x0184) #define IEEE802154_MAC_DATE 0xFFFFFFFF diff --git a/components/soc/esp32h2/include/soc/ieee802154_reg.h b/components/soc/esp32h2/include/soc/ieee802154_reg.h index 275ee980285..3c480348bae 100644 --- a/components/soc/esp32h2/include/soc/ieee802154_reg.h +++ b/components/soc/esp32h2/include/soc/ieee802154_reg.h @@ -472,32 +472,32 @@ extern "C" { #define IEEE802154_SFD_TIMEOUT_CNT_CLEAR_S 14 #define IEEE802154_CRC_ERROR_CNT_CLEAR (BIT(13)) #define IEEE802154_CRC_ERROR_CNT_CLEAR_S 13 -#define IEEE802154_ED_ABORT_CNT_CLEAR (BIT(12)) -#define IEEE802154_ED_ABORT_CNT_CLEAR_S 12 -#define IEEE802154_CCA_FAIL_CNT_CLEAR (BIT(11)) -#define IEEE802154_CCA_FAIL_CNT_CLEAR_S 11 -#define IEEE802154_RX_FILTER_FAIL_CNT_CLEAR (BIT(10)) -#define IEEE802154_RX_FILTER_FAIL_CNT_CLEAR_S 10 -#define IEEE802154_NO_RSS_DETECT_CNT_CLEAR (BIT(9)) -#define IEEE802154_NO_RSS_DETECT_CNT_CLEAR_S 9 -#define IEEE802154_RX_ABORT_COEX_CNT_CLEAR (BIT(8)) -#define IEEE802154_RX_ABORT_COEX_CNT_CLEAR_S 8 -#define IEEE802154_RX_RESTART_CNT_CLEAR (BIT(7)) -#define IEEE802154_RX_RESTART_CNT_CLEAR_S 7 +#define IEEE802154_RX_FILTER_FAIL_CNT_CLEAR (BIT(12)) +#define IEEE802154_RX_FILTER_FAIL_CNT_CLEAR_S 12 +#define IEEE802154_NO_RSS_DETECT_CNT_CLEAR (BIT(11)) +#define IEEE802154_NO_RSS_DETECT_CNT_CLEAR_S 11 +#define IEEE802154_RX_ABORT_COEX_CNT_CLEAR (BIT(10)) +#define IEEE802154_RX_ABORT_COEX_CNT_CLEAR_S 10 +#define IEEE802154_RX_ACK_ABORT_COEX_CNT_CLEAR (BIT(9)) +#define IEEE802154_RX_ACK_ABORT_COEX_CNT_CLEAR_S 9 +#define IEEE802154_RX_RESTART_CNT_CLEAR (BIT(8)) +#define IEEE802154_RX_RESTART_CNT_CLEAR_S 8 +#define IEEE802154_RX_ACK_TIMEOUT_CNT_CLEAR (BIT(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_S 6 -#define IEEE802154_ED_SCAN_COEX_CNT_CLEAR (BIT(5)) -#define IEEE802154_ED_SCAN_COEX_CNT_CLEAR_S 5 -#define IEEE802154_RX_ACK_ABORT_COEX_CNT_CLEAR (BIT(4)) -#define IEEE802154_RX_ACK_ABORT_COEX_CNT_CLEAR_S 4 -#define IEEE802154_RX_ACK_TIMEOUT_CNT_CLEAR (BIT(3)) -#define IEEE802154_RX_ACK_TIMEOUT_CNT_CLEAR_S 3 -#define IEEE802154_TX_BREAK_COEX_CNT_CLEAR (BIT(2)) -#define IEEE802154_TX_BREAK_COEX_CNT_CLEAR_S 2 -#define IEEE802154_TX_SECURITY_ERROR_CNT_CLEAR (BIT(1)) -#define IEEE802154_TX_SECURITY_ERROR_CNT_CLEAR_S 1 -#define IEEE802154_CCA_BUSY_CNT_CLEAR (BIT(0)) -#define IEEE802154_CCA_BUSY_CNT_CLEAR_S 0 +#define IEEE802154_TX_BREAK_COEX_CNT_CLEAR (BIT(5)) +#define IEEE802154_TX_BREAK_COEX_CNT_CLEAR_S 5 +#define IEEE802154_TX_SECURITY_ERROR_CNT_CLEAR (BIT(4)) +#define IEEE802154_TX_SECURITY_ERROR_CNT_CLEAR_S 4 +#define IEEE802154_ED_ABORT_CNT_CLEAR (BIT(3)) +#define IEEE802154_ED_ABORT_CNT_CLEAR_S 3 +#define IEEE802154_CCA_FAIL_CNT_CLEAR (BIT(2)) +#define IEEE802154_CCA_FAIL_CNT_CLEAR_S 2 +#define IEEE802154_CCA_BUSY_CNT_CLEAR (BIT(1)) +#define IEEE802154_CCA_BUSY_CNT_CLEAR_S 1 +#define IEEE802154_ED_SCAN_COEX_CNT_CLEAR (BIT(0)) +#define IEEE802154_ED_SCAN_COEX_CNT_CLEAR_S 0 #define DEBUG_SEL_CFG0_REG (IEEE802154_REG_BASE + 0x184) #define DEBUG_FIELD3_SEL 0x0000001F diff --git a/examples/openthread/ot_br/main/esp_ot_br.c b/examples/openthread/ot_br/main/esp_ot_br.c index 18dea1cec4c..4996935c2ce 100644 --- a/examples/openthread/ot_br/main/esp_ot_br.c +++ b/examples/openthread/ot_br/main/esp_ot_br.c @@ -92,8 +92,8 @@ static void ot_task_worker(void *aContext) esp_openthread_launch_mainloop(); // Clean up - esp_netif_destroy(openthread_netif); esp_openthread_netif_glue_deinit(); + esp_netif_destroy(openthread_netif); esp_vfs_eventfd_unregister(); vTaskDelete(NULL); } diff --git a/examples/openthread/ot_cli/main/esp_ot_cli.c b/examples/openthread/ot_cli/main/esp_ot_cli.c index 7baf80062d8..912881c362a 100644 --- a/examples/openthread/ot_cli/main/esp_ot_cli.c +++ b/examples/openthread/ot_cli/main/esp_ot_cli.c @@ -95,8 +95,8 @@ static void ot_task_worker(void *aContext) esp_openthread_launch_mainloop(); // Clean up - esp_netif_destroy(openthread_netif); esp_openthread_netif_glue_deinit(); + esp_netif_destroy(openthread_netif); esp_vfs_eventfd_unregister(); vTaskDelete(NULL); diff --git a/examples/openthread/ot_sleepy_device/deep_sleep/main/esp_ot_sleepy_device.c b/examples/openthread/ot_sleepy_device/deep_sleep/main/esp_ot_sleepy_device.c index 4c2e5924854..0c5d6d3508d 100644 --- a/examples/openthread/ot_sleepy_device/deep_sleep/main/esp_ot_sleepy_device.c +++ b/examples/openthread/ot_sleepy_device/deep_sleep/main/esp_ot_sleepy_device.c @@ -193,8 +193,8 @@ static void ot_task_worker(void *aContext) esp_openthread_launch_mainloop(); // Clean up - esp_netif_destroy(openthread_netif); esp_openthread_netif_glue_deinit(); + esp_netif_destroy(openthread_netif); esp_vfs_eventfd_unregister(); vTaskDelete(NULL); diff --git a/examples/openthread/ot_sleepy_device/light_sleep/main/esp_ot_sleepy_device.c b/examples/openthread/ot_sleepy_device/light_sleep/main/esp_ot_sleepy_device.c index 42e53f0f098..6d20b50ea5d 100644 --- a/examples/openthread/ot_sleepy_device/light_sleep/main/esp_ot_sleepy_device.c +++ b/examples/openthread/ot_sleepy_device/light_sleep/main/esp_ot_sleepy_device.c @@ -94,8 +94,8 @@ static void ot_task_worker(void *aContext) esp_openthread_launch_mainloop(); // Clean up - esp_netif_destroy(openthread_netif); esp_openthread_netif_glue_deinit(); + esp_netif_destroy(openthread_netif); esp_vfs_eventfd_unregister(); vTaskDelete(NULL);