From 6d28fb78cd0e3ca4510f6567ff595deea52dc458 Mon Sep 17 00:00:00 2001 From: zwx Date: Mon, 30 Dec 2024 23:08:58 +0800 Subject: [PATCH] feat(802.15.4): introduced a feature for registering 802.15.4 ISR callbacks --- components/ieee802154/CMakeLists.txt | 1 + .../ieee802154/driver/esp_ieee802154_dev.c | 46 +++++---- .../ieee802154/driver/esp_ieee802154_event.c | 94 +++++++++++++++++++ components/ieee802154/esp_ieee802154.c | 10 ++ .../ieee802154/include/esp_ieee802154.h | 26 +++++ .../ieee802154/include/esp_ieee802154_types.h | 60 ++++++++++++ components/ieee802154/linker.lf | 7 ++ .../private_include/esp_ieee802154_dev.h | 24 ++++- .../private_include/esp_ieee802154_event.h | 79 ++++++++++++++++ 9 files changed, 326 insertions(+), 21 deletions(-) create mode 100644 components/ieee802154/driver/esp_ieee802154_event.c create mode 100644 components/ieee802154/private_include/esp_ieee802154_event.h diff --git a/components/ieee802154/CMakeLists.txt b/components/ieee802154/CMakeLists.txt index 4aa5b58430..c7474e6c74 100644 --- a/components/ieee802154/CMakeLists.txt +++ b/components/ieee802154/CMakeLists.txt @@ -8,6 +8,7 @@ if(CONFIG_IEEE802154_ENABLED) list(APPEND srcs "esp_ieee802154.c" "driver/esp_ieee802154_ack.c" "driver/esp_ieee802154_dev.c" + "driver/esp_ieee802154_event.c" "driver/esp_ieee802154_frame.c" "driver/esp_ieee802154_pib.c" "driver/esp_ieee802154_util.c" diff --git a/components/ieee802154/driver/esp_ieee802154_dev.c b/components/ieee802154/driver/esp_ieee802154_dev.c index 86bdf3d0f2..fded0fcac4 100644 --- a/components/ieee802154/driver/esp_ieee802154_dev.c +++ b/components/ieee802154/driver/esp_ieee802154_dev.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -18,6 +18,7 @@ #include "esp_timer.h" #include "esp_ieee802154_ack.h" #include "esp_ieee802154_dev.h" +#include "esp_ieee802154_event.h" #include "esp_ieee802154_frame.h" #include "esp_ieee802154_pib.h" #include "esp_ieee802154_sec.h" @@ -93,7 +94,7 @@ static void ieee802154_receive_done(uint8_t *data, esp_ieee802154_frame_info_t * // Ignore bit8 for the frame length, due to the max frame length is 127 based 802.15.4 spec. data[0] = data[0] & 0x7f; frame_info->process = true; - esp_ieee802154_receive_done(data, frame_info); + ieee802154_inner_receive_done(data, frame_info); } } @@ -102,13 +103,13 @@ static void ieee802154_transmit_done(const uint8_t *frame, const uint8_t *ack, e if (ack && ack_frame_info) { IEEE802154_RX_BUFFER_STAT_IS_FREE(false); if (s_rx_index == CONFIG_IEEE802154_RX_BUFFER_SIZE) { - esp_ieee802154_transmit_failed(frame, ESP_IEEE802154_TX_ERR_NO_ACK); + ieee802154_inner_transmit_failed(frame, ESP_IEEE802154_TX_ERR_NO_ACK); } else { ack_frame_info->process = true; - esp_ieee802154_transmit_done(frame, ack, ack_frame_info); + ieee802154_inner_transmit_done(frame, ack, ack_frame_info); } } else { - esp_ieee802154_transmit_done(frame, ack, ack_frame_info); + ieee802154_inner_transmit_done(frame, ack, ack_frame_info); } } @@ -240,7 +241,7 @@ IEEE802154_NOINLINE static bool stop_tx(void) // if the tx is already done, and the frame is not ack request OR auto ack rx is disabled. ieee802154_transmit_done(s_tx_frame, NULL, NULL); } else { - esp_ieee802154_transmit_failed(s_tx_frame, ESP_IEEE802154_TX_ERR_ABORT); + ieee802154_inner_transmit_failed(s_tx_frame, ESP_IEEE802154_TX_ERR_ABORT); } ieee802154_ll_clear_events(IEEE802154_EVENT_TX_DONE | IEEE802154_EVENT_TX_ABORT | IEEE802154_EVENT_TX_SFD_DONE); @@ -276,7 +277,7 @@ IEEE802154_NOINLINE static bool stop_rx_ack(void) if (events & IEEE802154_EVENT_ACK_RX_DONE) { ieee802154_transmit_done(s_tx_frame, (uint8_t *)&s_rx_frame[s_rx_index], &s_rx_frame_info[s_rx_index]); } else { - esp_ieee802154_transmit_failed(s_tx_frame, ESP_IEEE802154_TX_ERR_NO_ACK); + ieee802154_inner_transmit_failed(s_tx_frame, ESP_IEEE802154_TX_ERR_NO_ACK); } ieee802154_ll_clear_events(IEEE802154_EVENT_ACK_RX_DONE | IEEE802154_EVENT_RX_SFD_DONE | IEEE802154_EVENT_TX_ABORT); @@ -397,7 +398,7 @@ static void isr_handle_timer0_done(void) { #if !CONFIG_IEEE802154_TEST if (s_ieee802154_state == IEEE802154_STATE_RX_ACK) { - esp_ieee802154_transmit_failed(s_tx_frame, ESP_IEEE802154_TX_ERR_NO_ACK); + ieee802154_inner_transmit_failed(s_tx_frame, ESP_IEEE802154_TX_ERR_NO_ACK); NEEDS_NEXT_OPT(true); } #else @@ -451,7 +452,7 @@ static IRAM_ATTR void isr_handle_rx_done(void) && ieee802154_ll_get_tx_enhance_ack()) { s_rx_frame_info[s_rx_index].pending = ieee802154_ack_config_pending_bit(s_rx_frame[s_rx_index]); // For 2015 enh-ack, SW should generate an enh-ack then send it manually - if (esp_ieee802154_enh_ack_generator(s_rx_frame[s_rx_index], &s_rx_frame_info[s_rx_index], s_enh_ack_frame) == ESP_OK) { + if (ieee802154_inner_enh_ack_generator(s_rx_frame[s_rx_index], &s_rx_frame_info[s_rx_index], s_enh_ack_frame) == ESP_OK) { extcoex_tx_stage_start(); #if !CONFIG_IEEE802154_TEST // Send the Enh-Ack frame if generator succeeds. @@ -590,14 +591,14 @@ static IRAM_ATTR void isr_handle_tx_abort(ieee802154_ll_tx_abort_reason_t tx_abo case IEEE802154_TX_ABORT_BY_RX_ACK_TYPE_NOT_ACK: case IEEE802154_TX_ABORT_BY_RX_ACK_RESTART: IEEE802154_ASSERT(s_ieee802154_state == IEEE802154_STATE_RX_ACK); - esp_ieee802154_transmit_failed(s_tx_frame, ESP_IEEE802154_TX_ERR_INVALID_ACK); + ieee802154_inner_transmit_failed(s_tx_frame, ESP_IEEE802154_TX_ERR_INVALID_ACK); NEEDS_NEXT_OPT(false); break; // The above events are only used in test mode. case IEEE802154_TX_ABORT_BY_RX_ACK_TIMEOUT: IEEE802154_ASSERT(s_ieee802154_state == IEEE802154_STATE_RX_ACK); ieee802154_ll_disable_events(IEEE802154_EVENT_TIMER0_OVERFLOW); - esp_ieee802154_transmit_failed(s_tx_frame, ESP_IEEE802154_TX_ERR_NO_ACK); + ieee802154_inner_transmit_failed(s_tx_frame, ESP_IEEE802154_TX_ERR_NO_ACK); NEEDS_NEXT_OPT(true); break; case IEEE802154_TX_ABORT_BY_TX_COEX_BREAK: @@ -606,22 +607,22 @@ static IRAM_ATTR void isr_handle_tx_abort(ieee802154_ll_tx_abort_reason_t tx_abo #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); + ieee802154_inner_transmit_failed(s_tx_frame, ESP_IEEE802154_TX_ERR_COEXIST); NEEDS_NEXT_OPT(true); break; case IEEE802154_TX_ABORT_BY_TX_SECURITY_ERROR: IEEE802154_ASSERT(s_ieee802154_state == IEEE802154_STATE_TX || s_ieee802154_state == IEEE802154_STATE_TX_CCA); - esp_ieee802154_transmit_failed(s_tx_frame, ESP_IEEE802154_TX_ERR_SECURITY); + ieee802154_inner_transmit_failed(s_tx_frame, ESP_IEEE802154_TX_ERR_SECURITY); NEEDS_NEXT_OPT(true); break; case IEEE802154_TX_ABORT_BY_CCA_FAILED: IEEE802154_ASSERT(s_ieee802154_state == IEEE802154_STATE_TX_CCA); - esp_ieee802154_transmit_failed(s_tx_frame, ESP_IEEE802154_TX_ERR_ABORT); + ieee802154_inner_transmit_failed(s_tx_frame, ESP_IEEE802154_TX_ERR_ABORT); NEEDS_NEXT_OPT(true); break; case IEEE802154_TX_ABORT_BY_CCA_BUSY: IEEE802154_ASSERT(s_ieee802154_state == IEEE802154_STATE_TX_CCA); - esp_ieee802154_transmit_failed(s_tx_frame, ESP_IEEE802154_TX_ERR_CCA_BUSY); + ieee802154_inner_transmit_failed(s_tx_frame, ESP_IEEE802154_TX_ERR_CCA_BUSY); NEEDS_NEXT_OPT(true); break; default: @@ -635,18 +636,18 @@ static IRAM_ATTR void isr_handle_ed_done(void) if (s_ieee802154_state == IEEE802154_STATE_CCA) { esp_ieee802154_cca_done(ieee802154_ll_is_cca_busy()); } else if (s_ieee802154_state == IEEE802154_STATE_ED) { - esp_ieee802154_energy_detect_done(ieee802154_ll_get_ed_rss()); + ieee802154_inner_energy_detect_done(ieee802154_ll_get_ed_rss()); } NEEDS_NEXT_OPT(true); } -IEEE802154_STATIC IRAM_ATTR void ieee802154_enter_critical(void) +IRAM_ATTR void ieee802154_enter_critical(void) { portENTER_CRITICAL(&s_ieee802154_spinlock); } -IEEE802154_STATIC IRAM_ATTR void ieee802154_exit_critical(void) +IRAM_ATTR void ieee802154_exit_critical(void) { portEXIT_CRITICAL(&s_ieee802154_spinlock); } @@ -672,7 +673,7 @@ IEEE802154_NOINLINE static void ieee802154_isr(void *arg) IEEE802154_ASSERT(s_ieee802154_state == IEEE802154_STATE_RX || s_ieee802154_state == IEEE802154_STATE_RX_ACK || s_ieee802154_state == IEEE802154_STATE_TX || s_ieee802154_state == IEEE802154_STATE_TX_CCA || s_ieee802154_state == IEEE802154_STATE_TX_ENH_ACK); s_rx_frame_info[s_rx_index].timestamp = esp_timer_get_time(); - esp_ieee802154_receive_sfd_done(); + ieee802154_inner_receive_sfd_done(); events &= (uint16_t)(~IEEE802154_EVENT_RX_SFD_DONE); } @@ -681,7 +682,7 @@ IEEE802154_NOINLINE static void ieee802154_isr(void *arg) // ZB-81: IEEE802154_STATE_TX_ACK is also a possible state IEEE802154_ASSERT(s_ieee802154_state == IEEE802154_STATE_TX || s_ieee802154_state == IEEE802154_STATE_TX_CCA || s_ieee802154_state == IEEE802154_STATE_TEST_TX || s_ieee802154_state == IEEE802154_STATE_TX_ENH_ACK || s_ieee802154_state == IEEE802154_STATE_TX_ACK); - esp_ieee802154_transmit_sfd_done(s_tx_frame); + ieee802154_inner_transmit_sfd_done(s_tx_frame); events &= (uint16_t)(~IEEE802154_EVENT_TX_SFD_DONE); } @@ -832,6 +833,11 @@ esp_err_t ieee802154_mac_deinit(void) return ret; } +bool ieee802154_mac_is_inited(void) +{ + return s_ieee802154_isr_handle != NULL; +} + IEEE802154_STATIC void start_ed(uint32_t duration) { ieee802154_ll_enable_events(IEEE802154_EVENT_ED_DONE); diff --git a/components/ieee802154/driver/esp_ieee802154_event.c b/components/ieee802154/driver/esp_ieee802154_event.c new file mode 100644 index 0000000000..5690677d03 --- /dev/null +++ b/components/ieee802154/driver/esp_ieee802154_event.c @@ -0,0 +1,94 @@ +/* + * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include "esp_check.h" +#include "esp_ieee802154_dev.h" +#include "esp_ieee802154_event.h" +#include "esp_ieee802154_types.h" +#include "esp_ieee802154_util.h" + +static esp_ieee802154_event_cb_list_t s_event_cb_list; + +esp_err_t ieee802154_event_callback_list_register(esp_ieee802154_event_cb_list_t cb_list) +{ + ESP_RETURN_ON_FALSE(!ieee802154_mac_is_inited(), ESP_FAIL, IEEE802154_TAG, + "The event callback register function should be called when the IEEE 802.15.4 subsystem is disabled"); + memcpy((void*)(&s_event_cb_list), (void*)(&cb_list), sizeof(esp_ieee802154_event_cb_list_t)); + return ESP_OK; +} +esp_err_t ieee802154_event_callback_list_unregister(void) +{ + ESP_RETURN_ON_FALSE(!ieee802154_mac_is_inited(), ESP_FAIL, IEEE802154_TAG, + "The event callback unregister function should be called when the IEEE 802.15.4 subsystem is disabled"); + memset((void*)(&s_event_cb_list), 0, sizeof(esp_ieee802154_event_cb_list_t)); + return ESP_OK; +} + +void ieee802154_inner_receive_done(uint8_t *data, esp_ieee802154_frame_info_t *frame_info) +{ + if (s_event_cb_list.rx_done_cb) { + s_event_cb_list.rx_done_cb(data, frame_info); + } else { + esp_ieee802154_receive_done(data, frame_info); + } +} + +void ieee802154_inner_receive_sfd_done(void) +{ + if (s_event_cb_list.rx_sfd_done_cb) { + s_event_cb_list.rx_sfd_done_cb(); + } else { + esp_ieee802154_receive_sfd_done(); + } +} + +void ieee802154_inner_transmit_done(const uint8_t *frame, const uint8_t *ack, esp_ieee802154_frame_info_t *ack_frame_info) +{ + if (s_event_cb_list.tx_done_cb) { + s_event_cb_list.tx_done_cb(frame, ack, ack_frame_info); + } else { + esp_ieee802154_transmit_done(frame, ack, ack_frame_info); + } +} + +void ieee802154_inner_transmit_failed(const uint8_t *frame, esp_ieee802154_tx_error_t error) +{ + if (s_event_cb_list.tx_failed_cb) { + s_event_cb_list.tx_failed_cb(frame, error); + } else { + esp_ieee802154_transmit_failed(frame, error); + } +} + +void ieee802154_inner_transmit_sfd_done(uint8_t *frame) +{ + if (s_event_cb_list.tx_sfd_done_cb) { + s_event_cb_list.tx_sfd_done_cb(frame); + } else { + esp_ieee802154_transmit_sfd_done(frame); + } +} + +void ieee802154_inner_energy_detect_done(int8_t power) +{ + if (s_event_cb_list.ed_done_cb) { + s_event_cb_list.ed_done_cb(power); + } else { + esp_ieee802154_energy_detect_done(power); + } +} + +esp_err_t ieee802154_inner_enh_ack_generator(uint8_t *frame, esp_ieee802154_frame_info_t *frame_info, uint8_t* enhack_frame) +{ + esp_err_t err = ESP_FAIL; + if (s_event_cb_list.enh_ack_generator_cb) { + err = s_event_cb_list.enh_ack_generator_cb(frame, frame_info, enhack_frame); + } else { + err = esp_ieee802154_enh_ack_generator(frame, frame_info, enhack_frame); + } + return err; +} diff --git a/components/ieee802154/esp_ieee802154.c b/components/ieee802154/esp_ieee802154.c index b55643ee78..4cc1805441 100644 --- a/components/ieee802154/esp_ieee802154.c +++ b/components/ieee802154/esp_ieee802154.c @@ -12,6 +12,7 @@ #include "esp_phy_init.h" #include "esp_ieee802154_ack.h" #include "esp_ieee802154_dev.h" +#include "esp_ieee802154_event.h" #include "esp_ieee802154_frame.h" #include "esp_ieee802154_pib.h" #include "esp_ieee802154_sec.h" @@ -21,6 +22,15 @@ #include "hal/ieee802154_ll.h" #include "hal/ieee802154_common_ll.h" +esp_err_t esp_ieee802154_event_callback_list_register(esp_ieee802154_event_cb_list_t cb_list) +{ + return ieee802154_event_callback_list_register(cb_list); +} +esp_err_t esp_ieee802154_event_callback_list_unregister(void) +{ + return ieee802154_event_callback_list_unregister(); +} + esp_err_t esp_ieee802154_enable(void) { ieee802154_enable(); diff --git a/components/ieee802154/include/esp_ieee802154.h b/components/ieee802154/include/esp_ieee802154.h index 29fbbeb708..881206803c 100644 --- a/components/ieee802154/include/esp_ieee802154.h +++ b/components/ieee802154/include/esp_ieee802154.h @@ -724,6 +724,32 @@ void esp_ieee802154_set_coex_config(esp_ieee802154_coex_config_t config); esp_ieee802154_coex_config_t esp_ieee802154_get_coex_config(void); #endif +/** + * @brief Register process callbacks for events generated by the IEEE 802.15.4 subsystem. + * + * @param[in] cb_list The event process callback list, please refer to `esp_ieee802154_event_cb_list_t`. + * + * @note This API should be called only when IEEE 802.15.4 subsystem is not enabled + * or after IEEE 802.15.4 subsystem is disabled (refer to `esp_ieee802154_disable`). + * + * @return + * - ESP_OK on success. + * - ESP_FAIL on failure. + */ +esp_err_t esp_ieee802154_event_callback_list_register(esp_ieee802154_event_cb_list_t cb_list); + +/** + * @brief Unregister process callbacks for events generated by the IEEE 802.15.4 subsystem. + * + * @note This API should be called only when IEEE 802.15.4 subsystem is not enabled + * or after IEEE 802.15.4 subsystem is disabled (refer to `esp_ieee802154_disable`). + * + * @return + * - ESP_OK on success. + * - ESP_FAIL on failure. + */ +esp_err_t esp_ieee802154_event_callback_list_unregister(void); + #ifdef __cplusplus } #endif diff --git a/components/ieee802154/include/esp_ieee802154_types.h b/components/ieee802154/include/esp_ieee802154_types.h index a43662e2c0..bf52ed91a4 100644 --- a/components/ieee802154/include/esp_ieee802154_types.h +++ b/components/ieee802154/include/esp_ieee802154_types.h @@ -8,6 +8,7 @@ #include #include +#include "esp_err.h" #define US_PER_SYMBLE 16 @@ -91,6 +92,65 @@ typedef struct { int8_t channel[16]; /*!< Index 0 -> Channel 11, Index 1 -> Channel 12 ... Index 15 -> Channel 26 */ } esp_ieee802154_txpower_table_t; +// These callbacks will be processed in ISR context, please locate them in IRAM, see `IRAM_ATTR`. +/** + * @brief The callback to process Rx Done event, refer to `esp_ieee802154_receive_done`. + * + */ +typedef void (*esp_ieee802154_receive_done_cb_t)(uint8_t *data, esp_ieee802154_frame_info_t *frame_info); + +/** + * @brief The callback to process Rx SFD Done event, refer to `esp_ieee802154_receive_sfd_done`. + * + */ +typedef void (*esp_ieee802154_receive_sfd_done_cb_t)(void); + +/** + * @brief The callback to process Tx Done event, refer to `esp_ieee802154_transmit_done`. + * + */ +typedef void (*esp_ieee802154_transmit_done_cb_t)(const uint8_t *frame, const uint8_t *ack, esp_ieee802154_frame_info_t *ack_frame_info); + +/** + * @brief The callback to process Tx Failed event, refer to `esp_ieee802154_transmit_failed`. + * + */ +typedef void (*esp_ieee802154_transmit_failed_cb_t)(const uint8_t *frame, esp_ieee802154_tx_error_t error); + +/** + * @brief The callback to process Tx SFD Done event, refer to `esp_ieee802154_transmit_sfd_done`. + * + */ +typedef void (*esp_ieee802154_transmit_sfd_done_cb_t)(uint8_t *frame); + +/** + * @brief The callback to process ED Done event, refer to `esp_ieee802154_energy_detect_done`. + * + */ +typedef void (*esp_ieee802154_energy_detect_done_cb_t)(int8_t power); + +/** + * @brief The callback to process enh-ack generating, refer to `esp_ieee802154_enh_ack_generator`. + * + */ +typedef esp_err_t (*esp_ieee802154_enh_ack_generator_cb_t)(uint8_t *frame, esp_ieee802154_frame_info_t *frame_info, uint8_t* enhack_frame); + +/** + * @brief The callback list for event process. + * + * @note These callbacks might be called in ISR context. + * + */ +typedef struct { + esp_ieee802154_receive_done_cb_t rx_done_cb; /*! +#include +#include "sdkconfig.h" +#include "esp_ieee802154_types.h" +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Register the process callbacks for the event generated by IEEE 802.15.4 subsystem. + * + * @param[in] cb_list The event process callback list, please refer to `esp_ieee802154_event_cb_list_t`. + * + * @return + * - ESP_OK on success. + */ +esp_err_t ieee802154_event_callback_list_register(esp_ieee802154_event_cb_list_t cb_list); + +/** + * @brief Unregister the process callbacks for the event generated by IEEE 802.15.4 subsystem. + * + * @return + * - ESP_OK on success. + */ +esp_err_t ieee802154_event_callback_list_unregister(void); + +/** + * @brief The inner handler when reception successfully. + * + */ +void ieee802154_inner_receive_done(uint8_t *data, esp_ieee802154_frame_info_t *frame_info); + +/** + * @brief The inner handler when the SFD field of the frame was received. + * + */ +void ieee802154_inner_receive_sfd_done(void); + +/** + * @brief The inner handler when transmission finished successfully. + * + */ +void ieee802154_inner_transmit_done(const uint8_t *frame, const uint8_t *ack, esp_ieee802154_frame_info_t *ack_frame_info); + +/** + * @brief The inner handler when transmission failed. + * + */ +void ieee802154_inner_transmit_failed(const uint8_t *frame, esp_ieee802154_tx_error_t error); + +/** + * @brief The inner handler when the SFD field of the frame was transmitted. + * + */ +void ieee802154_inner_transmit_sfd_done(uint8_t *frame); + +/** + * @brief The inner handler when ED processed done. + * + */ +void ieee802154_inner_energy_detect_done(int8_t power); + +/** + * @brief The inner wrapper for enh-ack generation. + * + */ +esp_err_t ieee802154_inner_enh_ack_generator(uint8_t *frame, esp_ieee802154_frame_info_t *frame_info, uint8_t* enhack_frame); + +#ifdef __cplusplus +} +#endif