diff --git a/.gitlab/ci/rules.yml b/.gitlab/ci/rules.yml index 440f93972f..68c5f62161 100644 --- a/.gitlab/ci/rules.yml +++ b/.gitlab/ci/rules.yml @@ -182,7 +182,6 @@ - "components/esp_phy/lib" - "components/esp_wifi/lib" - "components/esp_coex/lib" - - "components/ieee802154/lib" - "components/json/cJSON" - "components/lwip/lwip" - "components/mbedtls/mbedtls" diff --git a/.gitmodules b/.gitmodules index 05d02873c8..09afec2008 100644 --- a/.gitmodules +++ b/.gitmodules @@ -120,10 +120,6 @@ path = components/openthread/lib url = ../../espressif/esp-thread-lib.git -[submodule "components/ieee802154/lib"] - path = components/ieee802154/lib - url = ../../espressif/esp-ieee802154-lib.git - [submodule "components/bt/controller/lib_esp32h2/esp32h2-bt-lib"] path = components/bt/controller/lib_esp32h2/esp32h2-bt-lib url = ../../espressif/esp32h2-bt-lib.git diff --git a/components/hal/include/hal/ieee802154_common_ll.h b/components/hal/include/hal/ieee802154_common_ll.h index 7520761b77..865b53cf5c 100644 --- a/components/hal/include/hal/ieee802154_common_ll.h +++ b/components/hal/include/hal/ieee802154_common_ll.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -95,6 +95,7 @@ typedef enum { } ieee802154_ll_rx_abort_reason_t; typedef uint32_t ieee802154_ll_rx_abort_events; +#define IEEE802154_RX_ABORT_ALL 0x7fffffff /** * @brief IEEE802154 transmission failed reason. @@ -118,6 +119,7 @@ typedef enum { } ieee802154_ll_tx_abort_reason_t; typedef uint32_t ieee802154_ll_tx_abort_events; +#define IEEE802154_TX_ABORT_ALL 0x7fffffff /** * @brief IEEE802154 CCA mode. @@ -168,6 +170,8 @@ typedef enum { IEEE802154_ED_SAMPLE_AVG = 0x01, } ieee802154_ll_ed_sample_mode_t; +#define IEEE802154_RX_STATUS_RECEIVE_SFD 0x1 + FORCE_INLINE_ATTR void ieee802154_ll_set_cmd(ieee802154_ll_cmd_t cmd) { IEEE802154.cmd.cmd = cmd; @@ -193,6 +197,11 @@ FORCE_INLINE_ATTR ieee802154_ll_events ieee802154_ll_get_events(void) return (ieee802154_ll_events)(IEEE802154.event_status.events); } +FORCE_INLINE_ATTR bool ieee802154_ll_is_current_rx_frame(void) +{ + return (IEEE802154.rx_status.rx_state > IEEE802154_RX_STATUS_RECEIVE_SFD); +} + static inline void ieee802154_ll_enable_rx_abort_events(ieee802154_ll_rx_abort_events events) { IEEE802154.rx_abort_event_en.rx_abort_en |= events; diff --git a/components/ieee802154/Kconfig b/components/ieee802154/Kconfig index 488e8e05d6..9c5d18e237 100644 --- a/components/ieee802154/Kconfig +++ b/components/ieee802154/Kconfig @@ -41,14 +41,6 @@ menu "IEEE 802.15.4" configure the CCA mode to Carrier sense AND energy above threshold endchoice - config IEEE802154_RECEIVE_DONE_HANDLER - bool "Enable the receive done handler feature" - default n - help - configure the receive done handler feature, when enabled, the user must call the - function `esp_ieee802154_receive_handle_done` to inform the 802.15.4 driver that - the received frame has been processed, so the frame space could be freed. - config IEEE802154_CCA_MODE depends on IEEE802154_ENABLED int diff --git a/components/ieee802154/driver/esp_ieee802154_debug.c b/components/ieee802154/driver/esp_ieee802154_debug.c index 2b172ad952..c8472c8315 100644 --- a/components/ieee802154/driver/esp_ieee802154_debug.c +++ b/components/ieee802154/driver/esp_ieee802154_debug.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -289,6 +289,11 @@ void ieee802154_tx_nums_update(void) s_ieee802154_txrx_statistic.tx.nums++; } +void ieee802154_tx_deferred_nums_update(void) +{ + s_ieee802154_txrx_statistic.tx.deferred_nums++; +} + void ieee802154_tx_break_coex_nums_update(void) { s_ieee802154_txrx_statistic.tx.abort.tx_coex_break_nums++; @@ -302,9 +307,15 @@ void ieee802154_txrx_statistic_print(void) 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; + uint64_t tx_direct_num = tx_nums - s_ieee802154_txrx_statistic.tx.deferred_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_direct_num_ratio = (tx_nums > 0 ? ((float)tx_direct_num / tx_nums) : 0); + float tx_deferred_num_ratio = (tx_nums > 0 ? ((float)s_ieee802154_txrx_statistic.tx.deferred_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); @@ -321,6 +332,10 @@ void ieee802154_txrx_statistic_print(void) 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%%|", "", "", "tx_direct_num:", tx_direct_num, tx_direct_num_ratio*100); + ESP_LOGW(TAG, "+ + +--------------------------------------------------+"); + ESP_LOGW(TAG, "|%-20s|%-35s|%-25s%-15llu%9.2f%%|", "", "", "tx_deferred_num:", s_ieee802154_txrx_statistic.tx.deferred_nums, tx_deferred_num_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, "+ + +--------------------------------------------------+"); diff --git a/components/ieee802154/driver/esp_ieee802154_dev.c b/components/ieee802154/driver/esp_ieee802154_dev.c index 172f51532d..803d387246 100644 --- a/components/ieee802154/driver/esp_ieee802154_dev.c +++ b/components/ieee802154/driver/esp_ieee802154_dev.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -47,7 +47,6 @@ IEEE802154_STATIC volatile ieee802154_state_t s_ieee802154_state; static uint8_t *s_tx_frame = NULL; #define IEEE802154_RX_FRAME_SIZE (127 + 1 + 1) // +1: len, +1: for dma test -#if CONFIG_IEEE802154_RECEIVE_DONE_HANDLER // +1: for the stub buffer when the valid buffers are full. // // |--------------------VB[0]--------------------| @@ -62,10 +61,6 @@ static uint8_t *s_tx_frame = NULL; // STUB : Stub buffer, used when all valid buffers are under processing, the received frame will be dropped. static uint8_t s_rx_frame[CONFIG_IEEE802154_RX_BUFFER_SIZE + 1][IEEE802154_RX_FRAME_SIZE]; static esp_ieee802154_frame_info_t s_rx_frame_info[CONFIG_IEEE802154_RX_BUFFER_SIZE + 1]; -#else -static uint8_t s_rx_frame[CONFIG_IEEE802154_RX_BUFFER_SIZE][IEEE802154_RX_FRAME_SIZE]; -static esp_ieee802154_frame_info_t s_rx_frame_info[CONFIG_IEEE802154_RX_BUFFER_SIZE]; -#endif static uint8_t s_rx_index = 0; static uint8_t s_enh_ack_frame[128]; @@ -75,8 +70,16 @@ static intr_handle_t s_ieee802154_isr_handle = NULL; static esp_err_t ieee802154_sleep_init(void); static void next_operation(void); +static esp_err_t ieee802154_transmit_internal(const uint8_t *frame, bool cca); + +#if !CONFIG_IEEE802154_TEST +typedef struct { + const uint8_t *frame; + bool cca; +} pending_tx_t; +static pending_tx_t s_pending_tx = { 0 }; +#endif -#if CONFIG_IEEE802154_RECEIVE_DONE_HANDLER static void ieee802154_receive_done(uint8_t *data, esp_ieee802154_frame_info_t *frame_info) { // If the RX done packet is written in the stub buffer, drop it silently. @@ -104,7 +107,7 @@ static void ieee802154_transmit_done(const uint8_t *frame, const uint8_t *ack, e } } -esp_err_t ieee802154_receive_handle_done(uint8_t *data) +esp_err_t ieee802154_receive_handle_done(const uint8_t *data) { uint16_t size = data - &s_rx_frame[0][0]; if ((size % IEEE802154_RX_FRAME_SIZE) != 0 @@ -114,18 +117,6 @@ esp_err_t ieee802154_receive_handle_done(uint8_t *data) s_rx_frame_info[size / IEEE802154_RX_FRAME_SIZE].process = false; return ESP_OK; } -#else -static void ieee802154_receive_done(uint8_t *data, esp_ieee802154_frame_info_t *frame_info) -{ - esp_ieee802154_receive_done(data, frame_info); -} - -static void ieee802154_transmit_done(const uint8_t *frame, const uint8_t *ack, esp_ieee802154_frame_info_t *ack_frame_info) -{ - esp_ieee802154_transmit_done(frame, ack, ack_frame_info); -} - -#endif static IRAM_ATTR void event_end_process(void) { @@ -170,8 +161,8 @@ uint8_t ieee802154_get_recent_lqi(void) IEEE802154_STATIC void set_next_rx_buffer(void) { uint8_t* next_rx_buffer = NULL; -#if CONFIG_IEEE802154_RECEIVE_DONE_HANDLER uint8_t index = 0; + if (s_rx_index != CONFIG_IEEE802154_RX_BUFFER_SIZE && s_rx_frame_info[s_rx_index].process == false) { // If buffer is not full, and current index is empty, set it to hardware. next_rx_buffer = s_rx_frame[s_rx_index]; @@ -195,16 +186,7 @@ IEEE802154_STATIC void set_next_rx_buffer(void) s_rx_index = CONFIG_IEEE802154_RX_BUFFER_SIZE; next_rx_buffer = s_rx_frame[CONFIG_IEEE802154_RX_BUFFER_SIZE]; } -#else - if (s_rx_frame[s_rx_index][0] != 0) { - s_rx_index++; - if (s_rx_index == CONFIG_IEEE802154_RX_BUFFER_SIZE) { - s_rx_index = 0; - memset(s_rx_frame[s_rx_index], 0, sizeof(s_rx_frame[s_rx_index])); - } - } - next_rx_buffer = (uint8_t *)&s_rx_frame[s_rx_index]; -#endif + ieee802154_ll_set_rx_addr(next_rx_buffer); } @@ -367,10 +349,21 @@ static void enable_rx(void) static IRAM_ATTR void next_operation(void) { - if (ieee802154_pib_get_rx_when_idle()) { - enable_rx(); - } else { - ieee802154_set_state(IEEE802154_STATE_IDLE); +#if !CONFIG_IEEE802154_TEST + if (s_pending_tx.frame) { + // Here the driver needs to recover the setting of rx aborts, see function `ieee802154_transmit`. + ieee802154_ll_enable_rx_abort_events(BIT(IEEE802154_RX_ABORT_BY_TX_ACK_TIMEOUT - 1) | BIT(IEEE802154_RX_ABORT_BY_TX_ACK_COEX_BREAK - 1)); + ieee802154_transmit_internal(s_pending_tx.frame, s_pending_tx.cca); + s_pending_tx.frame = NULL; + } else +#endif + { + if (ieee802154_pib_get_rx_when_idle()) { + enable_rx(); + } else { + ieee802154_set_state(IEEE802154_STATE_IDLE); + ieee802154_sleep(); + } } } @@ -491,25 +484,24 @@ static IRAM_ATTR void isr_handle_rx_abort(void) IEEE802154_ASSERT(s_ieee802154_state == IEEE802154_STATE_RX); #if CONFIG_IEEE802154_TEST esp_ieee802154_receive_failed(rx_status); - next_operation(); #endif break; case IEEE802154_RX_ABORT_BY_COEX_BREAK: IEEE802154_ASSERT(s_ieee802154_state == IEEE802154_STATE_RX); +#if CONFIG_IEEE802154_TEST esp_ieee802154_receive_failed(rx_status); +#endif break; case IEEE802154_RX_ABORT_BY_ED_ABORT: case IEEE802154_RX_ABORT_BY_ED_COEX_REJECT: IEEE802154_ASSERT(s_ieee802154_state == IEEE802154_STATE_ED || s_ieee802154_state == IEEE802154_STATE_CCA); esp_ieee802154_ed_failed(rx_status); - next_operation(); break; case IEEE802154_RX_ABORT_BY_TX_ACK_TIMEOUT: case IEEE802154_RX_ABORT_BY_TX_ACK_COEX_BREAK: IEEE802154_ASSERT(s_ieee802154_state == IEEE802154_STATE_TX_ACK || s_ieee802154_state == IEEE802154_STATE_TX_ENH_ACK); #if !CONFIG_IEEE802154_TEST ieee802154_receive_done((uint8_t *)s_rx_frame[s_rx_index], &s_rx_frame_info[s_rx_index]); - next_operation(); #else esp_ieee802154_receive_failed(rx_status); #endif @@ -518,7 +510,6 @@ static IRAM_ATTR void isr_handle_rx_abort(void) IEEE802154_ASSERT(s_ieee802154_state == IEEE802154_STATE_TX_ENH_ACK); #if !CONFIG_IEEE802154_TEST ieee802154_receive_done((uint8_t *)s_rx_frame[s_rx_index], &s_rx_frame_info[s_rx_index]); - next_operation(); #else esp_ieee802154_receive_failed(rx_status); #endif @@ -526,6 +517,7 @@ static IRAM_ATTR void isr_handle_rx_abort(void) default: IEEE802154_ASSERT(false); } + next_operation(); } static IRAM_ATTR void isr_handle_tx_abort(void) @@ -802,7 +794,7 @@ IEEE802154_STATIC void tx_init(const uint8_t *frame) } } -esp_err_t ieee802154_transmit(const uint8_t *frame, bool cca) +static inline esp_err_t ieee802154_transmit_internal(const uint8_t *frame, bool cca) { IEEE802154_RF_ENABLE(); ieee802154_enter_critical(); @@ -819,10 +811,32 @@ esp_err_t ieee802154_transmit(const uint8_t *frame, bool cca) } ieee802154_exit_critical(); - return ESP_OK; } +esp_err_t ieee802154_transmit(const uint8_t *frame, bool cca) +{ +#if !CONFIG_IEEE802154_TEST + ieee802154_enter_critical(); + if ((s_ieee802154_state == IEEE802154_STATE_RX && ieee802154_ll_is_current_rx_frame()) + || s_ieee802154_state == IEEE802154_STATE_TX_ACK || s_ieee802154_state == IEEE802154_STATE_TX_ENH_ACK) { + // If the current radio is processing an RX frame or sending an ACK, do not shut down the ongoing process. + // Instead, defer the transmission of the pending TX frame. + // Once the current process is completed, the pending transmit frame will be initiated. + s_pending_tx.frame = frame; + s_pending_tx.cca = cca; + IEEE802154_TX_DEFERRED_NUMS_UPDATE(); + // Here we enable all rx interrupts due to the driver needs to know when the current RX has finished. + // Will recover the setting of rx abort in function `next_operation`. + ieee802154_ll_enable_rx_abort_events(IEEE802154_RX_ABORT_ALL); + ieee802154_exit_critical(); + return ESP_OK; + } + ieee802154_exit_critical(); +#endif + return ieee802154_transmit_internal(frame, cca); +} + static inline bool is_target_time_expired(uint32_t target, uint32_t now) { return (((now - target) & (1 << 31)) == 0); diff --git a/components/ieee802154/esp_ieee802154.c b/components/ieee802154/esp_ieee802154.c index 2167dbdaa3..796b161a7b 100644 --- a/components/ieee802154/esp_ieee802154.c +++ b/components/ieee802154/esp_ieee802154.c @@ -338,12 +338,10 @@ uint8_t esp_ieee802154_get_recent_lqi(void) return ieee802154_get_recent_lqi(); } -#if CONFIG_IEEE802154_RECEIVE_DONE_HANDLER -esp_err_t esp_ieee802154_receive_handle_done(uint8_t *frame) +esp_err_t esp_ieee802154_receive_handle_done(const uint8_t *frame) { return ieee802154_receive_handle_done(frame); } -#endif __attribute__((weak)) void esp_ieee802154_receive_done(uint8_t *data, esp_ieee802154_frame_info_t *frame_info) { diff --git a/components/ieee802154/include/esp_ieee802154.h b/components/ieee802154/include/esp_ieee802154.h index a7bb1598ee..df923dfc2e 100644 --- a/components/ieee802154/include/esp_ieee802154.h +++ b/components/ieee802154/include/esp_ieee802154.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2021-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -115,18 +115,20 @@ esp_err_t esp_ieee802154_sleep(void); /** * @brief Set the IEEE 802.15.4 Radio to receive state. * + * @note Radio will continue receiving until it receives a valid frame. + * Refer to `esp_ieee802154_receive_done()`. + * * @return * - ESP_OK on success * - ESP_FAIL on failure due to invalid state. * - * Note: Radio will continue receiving until it receives a valid frame. - * Ref to esp_ieee802154_receive_done(). - * */ esp_err_t esp_ieee802154_receive(void); /** * @brief Transmit the given frame. + * The transmit result will be reported via `esp_ieee802154_transmit_done()` + * or `esp_ieee802154_transmit_failed()`. * * @param[in] frame The pointer to the frame, the frame format: * |-----------------------------------------------------------------------| @@ -138,9 +140,6 @@ esp_err_t esp_ieee802154_receive(void); * - ESP_OK on success. * - ESP_FAIL on failure due to invalid state. * - * Note: The transmit result will be reported via esp_ieee802154_transmit_done() - * or esp_ieee802154_transmit_failed(). - * */ esp_err_t esp_ieee802154_transmit(const uint8_t *frame, bool cca); @@ -453,35 +452,31 @@ bool esp_ieee802154_get_rx_when_idle(void); */ esp_err_t esp_ieee802154_energy_detect(uint32_t duration); -#if CONFIG_IEEE802154_RECEIVE_DONE_HANDLER /** * @brief Notify the IEEE 802.15.4 Radio that the frame is handled done by upper layer. * - * @param[in] frame The pointer to the frame which was passed from the function esp_ieee802154_receive_done. - * or ack frame from esp_ieee802154_transmit_done. + * @param[in] frame The pointer to the frame which was passed from the function `esp_ieee802154_receive_done()` + * or ack frame from `esp_ieee802154_transmit_done()`. * * @return * - ESP_OK on success * - ESP_FAIL if frame is invalid. * */ -esp_err_t esp_ieee802154_receive_handle_done(uint8_t *frame); -#endif +esp_err_t esp_ieee802154_receive_handle_done(const uint8_t *frame); /** Below are the events generated by IEEE 802.15.4 subsystem, which are in ISR context **/ /** * @brief A Frame was received. * + * @note User must call the function `esp_ieee802154_receive_handle_done()` to notify 802.15.4 driver after the received frame is handled. + * * @param[in] frame The point to the received frame, frame format: * |-----------------------------------------------------------------------| * | Len | MHR | MAC Payload (no FCS) | * |-----------------------------------------------------------------------| * @param[in] frame_info More information of the received frame, refer to esp_ieee802154_frame_info_t. * - * Note: If configuration `IEEE802154_RECEIVE_DONE_HANDLER` is enabled, then the user must call the function - * `esp_ieee802154_receive_handle_done()` to inform 802.15.4 driver that the received frame is handled. - * See `esp_ieee802154_receive_handle_done()` for more informations. - * */ extern void esp_ieee802154_receive_done(uint8_t *frame, esp_ieee802154_frame_info_t *frame_info); @@ -494,27 +489,22 @@ extern void esp_ieee802154_receive_sfd_done(void); /** * @brief The Frame Transmission succeeded. * + * @note If the ack frame is not null, user must call the function `esp_ieee802154_receive_handle_done()` to notify 802.15.4 driver + * after the ack frame is handled. + * * @param[in] frame The pointer to the transmitted frame. * @param[in] ack The received ACK frame, it could be NULL if the transmitted frame's AR bit is not set. * @param[in] ack_frame_info More information of the ACK frame, refer to esp_ieee802154_frame_info_t. * - * Note: refer to esp_ieee802154_transmit(). - * - * If configuration `IEEE802154_RECEIVE_DONE_HANDLER` is enabled and ack frame is not null, then after the upper layer has processed the frame, - * the user must call the function `esp_ieee802154_receive_handle_done()` to inform 802.15.4 driver that the ack frame is handled. - * See `esp_ieee802154_receive_handle_done()` for more informations. - * */ extern void esp_ieee802154_transmit_done(const uint8_t *frame, const uint8_t *ack, esp_ieee802154_frame_info_t *ack_frame_info); /** - * @brief The Frame Transmission failed. + * @brief The Frame Transmission failed. Refer to `esp_ieee802154_transmit()`. * * @param[in] frame The pointer to the frame. * @param[in] error The transmission failure reason, refer to esp_ieee802154_tx_error_t. * - * Note: refer to esp_ieee802154_transmit(). - * */ extern void esp_ieee802154_transmit_failed(const uint8_t *frame, esp_ieee802154_tx_error_t error); @@ -525,32 +515,31 @@ extern void esp_ieee802154_transmit_failed(const uint8_t *frame, esp_ieee802154_ extern void esp_ieee802154_transmit_sfd_done(uint8_t *frame); /** - * @brief The energy detection done. + * @brief The energy detection done. Refer to `esp_ieee802154_energy_detect()`. * * @param[in] power The detected power level, in dBm. * - * Note: refer to esp_ieee802154_energy_detect(). - * */ extern void esp_ieee802154_energy_detect_done(int8_t power); /** * @brief Set the IEEE 802.15.4 Radio to receive state at a specific time. * + * @note Radio will start receiving after the timestamp, and continue receiving until it receives a valid frame. + * Refer to `esp_ieee802154_receive_done()`. * * @param[in] time A specific timestamp for starting receiving. * @return * - ESP_OK on success * - ESP_FAIL on failure due to invalid state. * - * Note: Radio will start receiving after the timestamp, and continue receiving until it receives a valid frame. - * Ref to esp_ieee802154_receive_done(). - * */ esp_err_t esp_ieee802154_receive_at(uint32_t time); /** * @brief Transmit the given frame at a specific time. + * The transmit result will be reported via `esp_ieee802154_transmit_done()` + * or `esp_ieee802154_transmit_failed()`. * * @param[in] frame The pointer to the frame. Refer to `esp_ieee802154_transmit()`. * @param[in] cca Perform CCA before transmission if it's true, otherwise transmit the frame directly. @@ -560,9 +549,6 @@ esp_err_t esp_ieee802154_receive_at(uint32_t time); * - ESP_OK on success. * - ESP_FAIL on failure due to invalid state. * - * Note: The transmit result will be reported via esp_ieee802154_transmit_done() - * or esp_ieee802154_transmit_failed(). - * */ esp_err_t esp_ieee802154_transmit_at(const uint8_t *frame, bool cca, uint32_t time); diff --git a/components/ieee802154/lib b/components/ieee802154/lib deleted file mode 160000 index 102b03c809..0000000000 --- a/components/ieee802154/lib +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 102b03c8095de8a337c293f79dce189be63186f3 diff --git a/components/ieee802154/linker.lf b/components/ieee802154/linker.lf index 3c32c33352..b0a01b70c0 100644 --- a/components/ieee802154/linker.lf +++ b/components/ieee802154/linker.lf @@ -22,6 +22,10 @@ entries: esp_ieee802154_timer: ieee802154_timer0_stop (noflash) esp_ieee802154_timer: ieee802154_timer1_stop (noflash) esp_ieee802154_util: ieee802154_etm_channel_clear (noflash) + + if IEEE802154_DEBUG = y: + esp_ieee802154_debug (noflash) + if IEEE802154_TIMING_OPTIMIZATION = y: esp_ieee802154_dev: set_next_rx_buffer (noflash) esp_ieee802154_dev: stop_rx (noflash) diff --git a/components/ieee802154/private_include/esp_ieee802154_dev.h b/components/ieee802154/private_include/esp_ieee802154_dev.h index 988d6fecb8..6dada29c56 100644 --- a/components/ieee802154/private_include/esp_ieee802154_dev.h +++ b/components/ieee802154/private_include/esp_ieee802154_dev.h @@ -110,7 +110,6 @@ esp_err_t ieee802154_transmit(const uint8_t *frame, bool cca); */ esp_err_t ieee802154_receive(void); -#if CONFIG_IEEE802154_RECEIVE_DONE_HANDLER /** * @brief Notify the IEEE 802.15.4 Radio that the frame is handled done by upper layer. * @@ -122,8 +121,7 @@ esp_err_t ieee802154_receive(void); * - ESP_FAIL if frame is invalid. * */ -esp_err_t ieee802154_receive_handle_done(uint8_t* frame); -#endif +esp_err_t ieee802154_receive_handle_done(const uint8_t* frame); /** * @brief Transmit the given frame at a specific time. diff --git a/components/ieee802154/private_include/esp_ieee802154_util.h b/components/ieee802154/private_include/esp_ieee802154_util.h index 3288ac9e80..0d0268f422 100644 --- a/components/ieee802154/private_include/esp_ieee802154_util.h +++ b/components/ieee802154/private_include/esp_ieee802154_util.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -185,6 +185,7 @@ void ieee802154_assert_print(void); typedef struct ieee802154_txrx_statistic{ struct { uint64_t nums; + uint64_t deferred_nums; uint64_t done_nums; struct { uint64_t rx_ack_coex_break_nums; // IEEE802154_RX_ACK_ABORT_COEX_CNT_REG @@ -218,6 +219,10 @@ typedef struct ieee802154_txrx_statistic{ ieee802154_txrx_statistic(a);\ } while(0) +#define IEEE802154_TX_DEFERRED_NUMS_UPDATE() do { \ + ieee802154_tx_deferred_nums_update();\ + } while(0) + #define IEEE802154_TX_NUMS_UPDATE() do { \ ieee802154_tx_nums_update();\ } while(0) @@ -230,10 +235,12 @@ 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_deferred_nums_update(void); void ieee802154_tx_break_coex_nums_update(void); #else #define IEEE802154_TXRX_STATISTIC(a) #define IEEE802154_TX_NUMS_UPDATE() +#define IEEE802154_TX_DEFERRED_NUMS_UPDATE() #define IEEE802154_TXRX_STATISTIC_CLEAR() #define IEEE802154_TX_BREAK_COEX_NUMS_UPDATE() #endif // CONFIG_IEEE802154_TXRX_STATISTIC diff --git a/components/ieee802154/test_apps/test_ieee802154/main/src/ieee802154_cmd.c b/components/ieee802154/test_apps/test_ieee802154/main/src/ieee802154_cmd.c index 2a56811f47..9d05d57c44 100644 --- a/components/ieee802154/test_apps/test_ieee802154/main/src/ieee802154_cmd.c +++ b/components/ieee802154/test_apps/test_ieee802154/main/src/ieee802154_cmd.c @@ -875,6 +875,7 @@ void esp_ieee802154_transmit_done(const uint8_t *frame, const uint8_t *ack, esp_ ack[idx], ack[idx+1], ack[idx+2], ack[idx+3], ack[idx+4], ack[idx+5], ack[idx+6], ack[idx+7]); } + esp_ieee802154_receive_handle_done(ack); } } @@ -886,6 +887,7 @@ void esp_ieee802154_receive_done(uint8_t *frame, esp_ieee802154_frame_info_t *fr frame[idx], frame[idx+1], frame[idx+2], frame[idx+3], frame[idx+4], frame[idx+5], frame[idx+6], frame[idx+7]); } + esp_ieee802154_receive_handle_done(frame); } void esp_ieee802154_energy_detect_done(int8_t power) diff --git a/components/openthread/CMakeLists.txt b/components/openthread/CMakeLists.txt index b878ce0e6d..7e63836f80 100644 --- a/components/openthread/CMakeLists.txt +++ b/components/openthread/CMakeLists.txt @@ -4,7 +4,7 @@ if(${idf_target} STREQUAL "linux") return() # This component is not supported by the POSIX/Linux simulator endif() -if(CONFIG_OPENTHREAD_ENABLED OR CONFIG_IDF_DOC_BUILD) +if(CONFIG_OPENTHREAD_ENABLED OR CONFIG_IDF_DOC_BUILD OR CONFIG_OPENTHREAD_SPINEL_ONLY) set(public_include_dirs "include" @@ -149,6 +149,11 @@ if(CONFIG_OPENTHREAD_ENABLED) -Wno-maybe-uninitialized) endif() + if(CONFIG_OPENTHREAD_NCP_VENDOR_HOOK) + list(APPEND src_dirs + "src/ncp") + endif() + if(NOT CONFIG_OPENTHREAD_DNS64_CLIENT) list(APPEND exclude_srcs "src/esp_openthread_dns64.c") @@ -171,6 +176,48 @@ if(CONFIG_OPENTHREAD_ENABLED) elseif(CONFIG_OPENTHREAD_RADIO) set(device_type "OPENTHREAD_RADIO=1") endif() +elseif(CONFIG_OPENTHREAD_SPINEL_ONLY) + + set(src_dirs + "src/spinel" + "src/port" + "openthread/src/lib/spinel" + "openthread/src/lib/hdlc" + "openthread/src/lib/platform" + "openthread/src/core/api" + "openthread/src/core/common" + "openthread/src/core/mac") + + set(private_include_dirs + "private_include" + "openthread/src" + "openthread/src/core" + "openthread/src/lib" + "openthread/src/lib/hdlc" + "openthread/src/lib/spinel") + + file(GLOB_RECURSE exclude_srcs_list + "src/port/*" + "openthread/src/core/api/*.cpp" + "openthread/src/core/common/*" + "openthread/src/core/mac/*") + + list(REMOVE_ITEM exclude_srcs_list + "${CMAKE_CURRENT_SOURCE_DIR}/src/port/esp_openthread_alarm.c" + "${CMAKE_CURRENT_SOURCE_DIR}/src/port/esp_openthread_logging.c" + "${CMAKE_CURRENT_SOURCE_DIR}/openthread/src/core/api/error_api.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/openthread/src/core/api/logging_api.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/openthread/src/core/common/error.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/openthread/src/core/common/error.hpp" + "${CMAKE_CURRENT_SOURCE_DIR}/openthread/src/core/common/log.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/openthread/src/core/common/log.hpp" + "${CMAKE_CURRENT_SOURCE_DIR}/openthread/src/core/common/logging.hpp" + "${CMAKE_CURRENT_SOURCE_DIR}/openthread/src/core/common/string.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/openthread/src/core/common/string.hpp" + "${CMAKE_CURRENT_SOURCE_DIR}/openthread/src/core/mac/mac_frame.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/openthread/src/core/mac/mac_frame.hpp") + + list(APPEND exclude_srcs ${exclude_srcs_list}) endif() @@ -201,13 +248,15 @@ idf_component_register(SRC_DIRS "${src_dirs}" PRIV_REQUIRES console esp_event esp_partition esp_timer ieee802154 mbedtls nvs_flash) -if(CONFIG_OPENTHREAD_ENABLED) +if(CONFIG_OPENTHREAD_ENABLED OR CONFIG_OPENTHREAD_SPINEL_ONLY) if(CONFIG_OPENTHREAD_RADIO) set(CONFIG_FILE_TYPE "radio") elseif(CONFIG_OPENTHREAD_FTD) set(CONFIG_FILE_TYPE "ftd") elseif(CONFIG_OPENTHREAD_MTD) set(CONFIG_FILE_TYPE "mtd") + elseif(CONFIG_OPENTHREAD_SPINEL_ONLY) + set(CONFIG_FILE_TYPE "spinel") endif() target_compile_definitions( diff --git a/components/openthread/Kconfig b/components/openthread/Kconfig index c298ca40e5..c291ede131 100644 --- a/components/openthread/Kconfig +++ b/components/openthread/Kconfig @@ -114,6 +114,7 @@ menu "OpenThread" Select this to use the native 15.4 radio. config OPENTHREAD_RADIO_SPINEL_UART + select UART_ISR_IN_IRAM bool "Connect via UART" help Select this to connect to a Radio Co-Processor via UART. @@ -157,6 +158,7 @@ menu "OpenThread" default OPENTHREAD_RCP_UART config OPENTHREAD_RCP_UART + select UART_ISR_IN_IRAM bool "UART RCP" help Select this to enable UART connection to host. @@ -168,6 +170,13 @@ menu "OpenThread" Select this to enable SPI connection to host. endchoice + config OPENTHREAD_NCP_VENDOR_HOOK + bool "Enable vendor command for RCP" + depends on OPENTHREAD_RADIO + default n + help + Select this to enable OpenThread NCP vendor commands. + config OPENTHREAD_CLI bool "Enable Openthread Command-Line Interface" depends on OPENTHREAD_ENABLED @@ -253,7 +262,7 @@ menu "OpenThread" config OPENTHREAD_SPINEL_RX_FRAME_BUFFER_SIZE int "The size of openthread spinel rx frame buffer" - depends on OPENTHREAD_ENABLED + depends on OPENTHREAD_ENABLED || OPENTHREAD_SPINEL_ONLY default 1024 range 512 8192 @@ -286,7 +295,7 @@ menu "OpenThread" config OPENTHREAD_UART_BUFFER_SIZE int "The uart received buffer size of openthread" depends on OPENTHREAD_ENABLED - default 256 + default 768 range 128 1024 help Set the OpenThread UART buffer size. @@ -362,4 +371,38 @@ menu "OpenThread" Select this option to enable the radio statistics feature, you can use radio command to print some radio Statistics informations. + config OPENTHREAD_SPINEL_ONLY + bool "Enable OpenThread External Radio Spinel feature" + default n + help + Select this option to enable the OpenThread Radio Spinel for external protocol stack, such as Zigbee. + + config OPENTHREAD_RX_ON_WHEN_IDLE + bool "Enable OpenThread radio capibility rx on when idle" + default y if !ESP_COEX_SW_COEXIST_ENABLE + default n if ESP_COEX_SW_COEXIST_ENABLE + help + Select this option to enable OpenThread radio capibility rx on when idle. Do not support this feature when + SW coexistence is enabled. + + menu "Thread Address Query Config" + config OPENTHREAD_ADDRESS_QUERY_TIMEOUT + int "Timeout value (in seconds) for a address notification response after sending an address query." + depends on OPENTHREAD_FTD || OPENTHREAD_MTD + default 3 + range 1 10 + + config OPENTHREAD_ADDRESS_QUERY_RETRY_DELAY + int "Initial retry delay for address query (in seconds)." + depends on OPENTHREAD_FTD || OPENTHREAD_MTD + default 15 + range 1 120 + + config OPENTHREAD_ADDRESS_QUERY_MAX_RETRY_DELAY + int "Maximum retry delay for address query (in seconds)." + depends on OPENTHREAD_FTD || OPENTHREAD_MTD + default 120 + range OPENTHREAD_ADDRESS_QUERY_RETRY_DELAY 960 + endmenu + endmenu diff --git a/components/openthread/include/esp_radio_spinel.h b/components/openthread/include/esp_radio_spinel.h new file mode 100644 index 0000000000..e8edef1fa6 --- /dev/null +++ b/components/openthread/include/esp_radio_spinel.h @@ -0,0 +1,395 @@ +/* + * SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include "esp_ieee802154_types.h" +#include "driver/uart.h" +#include "soc/gpio_num.h" + +#define ESP_SPINEL_LOG_TAG "ESP_RADIO_SPINEL" + +#define SPINEL_PROP_VENDOR_ESP_SET_COORDINATOR (SPINEL_PROP_VENDOR_ESP__BEGIN + 1) /* Vendor command for coordinator.*/ + +#define SPINEL_PROP_VENDOR_ESP_SET_PENDINGMODE (SPINEL_PROP_VENDOR_ESP__BEGIN + 2) /* Vendor command for pending mode.*/ + +typedef enum { + ESP_RADIO_SPINEL_ZIGBEE = 0x0, /* The index of Zigbee.*/ + ESP_RADIO_SPINEL_OPENTHREAD = 0x1, /* The index of OpenThread.*/ + ESP_RADIO_SPINEL_MAX, +} esp_radio_spinel_idx_t; /* The index of 802.15.4 related protocol stack for ESP radio spinel.*/ + +typedef struct { + fd_set read_fds; /* The read file descriptors.*/ + fd_set write_fds; /* The write file descriptors.*/ + fd_set error_fds; /* The error file descriptors.*/ + int max_fd; /* The max file descriptor.*/ + struct timeval timeout; /* The timeout.*/ +} esp_radio_spinel_mainloop_context_t; + +typedef struct { + uart_port_t port; /*!< UART port number */ + uart_config_t uart_config; /*!< UART configuration, see uart_config_t docs */ + gpio_num_t rx_pin; /*!< UART RX pin */ + gpio_num_t tx_pin; /*!< UART TX pin */ +} esp_radio_spinel_uart_config_t; /*This structure represents a context for ESP radio spinel. */ + +typedef void (*esp_radio_spinel_rcp_failure_handler)(void); /* The handler for rcp failure.*/ +typedef esp_err_t (*esp_radio_spinel_uart_init_handler)(const esp_radio_spinel_uart_config_t *uart_config_t, int *uart_fd); /* The handler for UART initialization.*/ +typedef esp_err_t (*esp_radio_spinel_uart_deinit_handler)(const esp_radio_spinel_uart_config_t *uart_config_t, int *uart_fd); /* The handler for UART deinitialization.*/ + +typedef struct +{ + void (*receive_done)(const uint8_t *frame, esp_ieee802154_frame_info_t *frame_info); /* Callback for Receive Done.*/ + void (*transmit_done)(const uint8_t *frame, const uint8_t *ack, esp_ieee802154_frame_info_t *ack_frame_info); /* Callback for Transmit Done.*/ + void (*transmit_failed)(esp_ieee802154_tx_error_t error); /* Callback for Transmit Failed.*/ + void (*energy_scan_done)(int8_t max_rssi); /* Callback for Energy Scan Done.*/ + void (*transmit_started)(const uint8_t *frame); /* Callback for Transmit Started.*/ + void (*switchover_done)(bool success); /* Callback for Switchover Done.*/ + +#if OPENTHREAD_CONFIG_DIAG_ENABLE + void (*diag_receive_done)(const uint8_t *frame, esp_ieee802154_frame_info_t *frame_info); /* Callback for Receive Done (diag).*/ + void (*diag_transmit_done)(const uint8_t *frame, esp_ieee802154_frame_info_t *frame_info); /* Callback for Transmit Done (diag).*/ + void (*diag_transmit_failed)(esp_ieee802154_tx_error_t error); /* Callback for Transmit Failed (diag).*/ +#endif // OPENTHREAD_CONFIG_DIAG_ENABLE +} esp_radio_spinel_callbacks_t; /* ESP Radio Spinel Callbacks.*/ + +/** + * @brief Set callkbacks of ESP radio spinel. + * + * @note This function should be called before `esp_radio_spinel_init`. + * + * @param[in] aCallbacks The callbacks struct. + * @param[in] idx The index of 802.15.4 related protocol stack. + * + */ +void esp_radio_spinel_set_callbacks(const esp_radio_spinel_callbacks_t aCallbacks, esp_radio_spinel_idx_t idx); + +/** + * @brief Enable the UART interface for ESP radio spinel + * + * @note This function should be called before `esp_radio_spinel_init`. + * + * @param[in] radio_uart_config The config of UART for radio spinel. + * @param[in] aUartInitHandler The function for UART initialization + * @param[in] aUartDeinitHandler The function for UART deinitialization + * @param[in] idx The index of 802.15.4 related protocol stack. + * + * @return + * - ESP_OK on success + * - ESP_FAIL on failures + * + */ +esp_err_t esp_radio_spinel_uart_interface_enable(const esp_radio_spinel_uart_config_t *radio_uart_config, + esp_radio_spinel_uart_init_handler aUartInitHandler, + esp_radio_spinel_uart_deinit_handler aUartDeinitHandler, + esp_radio_spinel_idx_t idx); + +/** + * @brief Initialize ESP radio spinel. + * + * @note This function should be called after `esp_radio_spinel_set_callbacks` and `esp_radio_spinel_uart_interface_enable`. + * + * @param[in] idx The index of 802.15.4 related protocol stack. + * + */ +void esp_radio_spinel_init(esp_radio_spinel_idx_t idx); + +/** + * @brief Enavle ESP radio spinel. + * + * @note This function should be called after `esp_radio_spinel_init`. + * + * @param[in] idx The index of 802.15.4 related protocol stack. + * + * @return + * - ESP_OK on success + * - ESP_FAIL on failures + * + */ +esp_err_t esp_radio_spinel_enable(esp_radio_spinel_idx_t idx); + +/** + * @brief Set the pending mode. + * + * @param[in] pending_mode The pending mode. + * @param[in] idx The index of 802.15.4 related protocol stack. + * + * @return + * - ESP_OK on success + * - ESP_FAIL on failures + * + */ +esp_err_t esp_radio_spinel_set_pending_mode(esp_ieee802154_pending_mode_t pending_mode, esp_radio_spinel_idx_t idx); + +/** + * @brief Get the EUI-64. + * + * @param[in] eui64 A pointer to the EUI-64. + * @param[in] idx The index of 802.15.4 related protocol stack. + * + * @return + * - ESP_OK on success + * - ESP_FAIL on failures + * + */ +esp_err_t esp_radio_spinel_get_eui64(uint8_t *eui64, esp_radio_spinel_idx_t idx); + +/** + * @brief Set the panid. + * + * @param[in] panid The panid. + * @param[in] idx The index of 802.15.4 related protocol stack. + * + * @return + * - ESP_OK on success + * - ESP_FAIL on failures + * + */ +esp_err_t esp_radio_spinel_set_panid(uint16_t panid, esp_radio_spinel_idx_t idx); + +/** + * @brief Set the short address. + * + * @param[in] short_address The short address. + * @param[in] idx The index of 802.15.4 related protocol stack. + * + * @return + * - ESP_OK on success + * - ESP_FAIL on failures + * + */ +esp_err_t esp_radio_spinel_set_short_address(uint16_t short_address, esp_radio_spinel_idx_t idx); + +/** + * @brief Set the extended address. + * + * @param[in] ext_address The extended address. + * @param[in] idx The index of 802.15.4 related protocol stack. + * + * @return + * - ESP_OK on success + * - ESP_FAIL on failures + * + */ +esp_err_t esp_radio_spinel_set_extended_address(uint8_t *ext_address, esp_radio_spinel_idx_t idx); + +/** + * @brief Set the coordinator mode. + * + * @param[in] enable Enable or disable the coordinator mode. + * @param[in] idx The index of 802.15.4 related protocol stack. + * + * @return + * - ESP_OK on success + * - ESP_FAIL on failures + * + */ +esp_err_t esp_radio_spinel_set_pan_coord(bool enable, esp_radio_spinel_idx_t idx); + +/** + * @brief Enable the RCP reception. + * + * @param[in] channel The channel of reception. + * @param[in] idx The index of 802.15.4 related protocol stack. + * + * @return + * - ESP_OK on success + * - ESP_FAIL on failures + * + */ +esp_err_t esp_radio_spinel_receive(uint8_t channel, esp_radio_spinel_idx_t idx); + +/** + * @brief Perform the energy scan. + * + * @param[in] scan_channel The channel of energy scan (usually the range is 11~26, scan all channels if it's set to 0). + * @param[in] scan_duration The duration for energy scan. + * @param[in] idx The index of 802.15.4 related protocol stack. + * + * @return + * - ESP_OK on success + * - ESP_FAIL on failures + * + */ +esp_err_t esp_radio_spinel_energy_scan(uint8_t scan_channel, uint16_t scan_duration, esp_radio_spinel_idx_t idx); + +/** + * @brief Perform the transmission. + * + * @param[in] frame A pointer to the frame. + * @param[in] channel The channel to use for transmitting. + * @param[in] cca Perform clear channel assessment(if it's true) or not(if it's false) + * @param[in] idx The index of 802.15.4 related protocol stack. + * + * @return + * - ESP_OK on success + * - ESP_FAIL on failures + * + */ +esp_err_t esp_radio_spinel_transmit(uint8_t *frame, uint8_t channel, bool cca, esp_radio_spinel_idx_t idx); + +/** + * @brief Clear all short addresses from the source address match table. + * + * @param[in] idx The index of 802.15.4 related protocol stack. + * + * @return + * - ESP_OK on success + * - ESP_FAIL on failures + * + */ +esp_err_t esp_radio_spinel_clear_short_entries(esp_radio_spinel_idx_t idx); + +/** + * @brief Add a short address to the source address match table. + * + * @param[in] short_address The short address to be added. + * @param[in] idx The index of 802.15.4 related protocol stack. + * + * @return + * - ESP_OK on success + * - ESP_FAIL on failures + * + */ +esp_err_t esp_radio_spinel_add_short_entry(uint16_t short_address, esp_radio_spinel_idx_t idx); + +/** + * @brief Clear the pending table, remove all extended/long addresses. + * + * @param[in] idx The index of 802.15.4 related protocol stack. + * + * @return + * - ESP_OK on success + * - ESP_FAIL on failures + * + */ +esp_err_t esp_radio_spinel_clear_extended_entries(esp_radio_spinel_idx_t idx); + +/** + * @brief Add an extended address to the source address match table. + * + * @param[in] ext_address The extended address to be added. + * @param[in] idx The index of 802.15.4 related protocol stack. + * + * @return + * - ESP_OK on success + * - ESP_FAIL on failures + * + */ +esp_err_t esp_radio_spinel_add_extended_entry(uint8_t *ext_address, esp_radio_spinel_idx_t idx); + +/** + * @brief Sets the status of promiscuous mode. + * + * @param[in] enable Whether to enable or disable promiscuous mode. + * @param[in] idx The index of 802.15.4 related protocol stack. + * + * @return + * - ESP_OK on success + * - ESP_FAIL on failures + * + */ +esp_err_t esp_radio_spinel_set_promiscuous_mode(bool enable, esp_radio_spinel_idx_t idx); + +/** + * @brief Update the ESP radio spinel. + * + * @param[in] mainloop_context The context for ESP radio spinel. + * @param[in] idx The index of 802.15.4 related protocol stack. + * + */ +void esp_radio_spinel_radio_update(esp_radio_spinel_mainloop_context_t *mainloop_context, esp_radio_spinel_idx_t idx); + +/** + * @brief Process the ESP radio spinel. + * + * @param[in] mainloop_context The context for ESP radio spinel. + * @param[in] idx The index of 802.15.4 related protocol stack. + * + */ +void esp_radio_spinel_radio_process(esp_radio_spinel_mainloop_context_t *mainloop_context, esp_radio_spinel_idx_t idx); + +/** + * @brief Switch the radio state to Sleep. + * + * @param[in] idx The index of 802.15.4 related protocol stack. + * + * @return + * - ESP_OK on success + * - ESP_FAIL on failures + * + */ +esp_err_t esp_radio_spinel_sleep(esp_radio_spinel_idx_t idx); + +/** + * @brief Set the radio's transmit power in dBm. + * + * @param[in] power The transmit power in dBm. + * @param[in] idx The index of 802.15.4 related protocol stack. + * + * @return + * - ESP_OK on success + * - ESP_FAIL on failures + * + */ +esp_err_t esp_radio_spinel_set_tx_power(int8_t power, esp_radio_spinel_idx_t idx); + +/** + * @brief Get the radio's transmit power in dBm. + * + * @param[in] power A pointer to the transmit power. + * @param[in] idx The index of 802.15.4 related protocol stack. + * + * @return + * - ESP_OK on success + * - ESP_FAIL on failures + * + */ +esp_err_t esp_radio_spinel_get_tx_power(int8_t *power, esp_radio_spinel_idx_t idx); + +/** + * @brief Register a handler to process the RCP failure. + * + * @param[in] handler The RCP failure handler. + * @param[in] idx The index of 802.15.4 related protocol stack. + * + */ +void esp_radio_spinel_register_rcp_failure_handler(esp_radio_spinel_rcp_failure_handler handler, esp_radio_spinel_idx_t idx); + +/** + * @brief Deinitialize the RCP. + * + * @param[in] idx The index of 802.15.4 related protocol stack. + * + * @return + * - ESP_OK on success + * - ESP_FAIL on failures + * + */ +esp_err_t esp_radio_spinel_rcp_deinit(esp_radio_spinel_idx_t idx); + +/** + * @brief Get the version of RCP. + * + * @param[in] running_rcp_version A pointer to the RCP version string. + * @param[in] idx The index of 802.15.4 related protocol stack. + * + * @return + * - ESP_OK on success + * - ESP_FAIL on failures + * + */ +esp_err_t esp_radio_spinel_rcp_version_get(char *running_rcp_version, esp_radio_spinel_idx_t idx); + +#ifdef __cplusplus +} +#endif diff --git a/components/openthread/lib b/components/openthread/lib index e0969fc15c..fcee30db4b 160000 --- a/components/openthread/lib +++ b/components/openthread/lib @@ -1 +1 @@ -Subproject commit e0969fc15c1991d91446a0dc5e4625ed2c0bb014 +Subproject commit fcee30db4b7342de4df9105bdd049a09d2d63187 diff --git a/components/openthread/openthread b/components/openthread/openthread index 41ef80717f..456c448284 160000 --- a/components/openthread/openthread +++ b/components/openthread/openthread @@ -1 +1 @@ -Subproject commit 41ef80717f4b757440125932723cc8721ef42f7f +Subproject commit 456c448284486abe2a9118a9fdaa468fe2383fcd diff --git a/components/openthread/private_include/esp_openthread_ncp.h b/components/openthread/private_include/esp_openthread_ncp.h new file mode 100644 index 0000000000..39f9e9532d --- /dev/null +++ b/components/openthread/private_include/esp_openthread_ncp.h @@ -0,0 +1,15 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +#if CONFIG_OPENTHREAD_NCP_VENDOR_HOOK + +#define SPINEL_PROP_VENDOR_ESP_SET_COORDINATOR (SPINEL_PROP_VENDOR_ESP__BEGIN + 1) + +#define SPINEL_PROP_VENDOR_ESP_SET_PENDINGMODE (SPINEL_PROP_VENDOR_ESP__BEGIN + 2) + +#endif diff --git a/components/openthread/private_include/esp_radio_spinel_adapter.hpp b/components/openthread/private_include/esp_radio_spinel_adapter.hpp new file mode 100644 index 0000000000..50ba3c540f --- /dev/null +++ b/components/openthread/private_include/esp_radio_spinel_adapter.hpp @@ -0,0 +1,29 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +namespace esp { +namespace radio_spinel { + +/** + * This class defines an template to adapt both UartSpinelInterface and SpiSpinelInterface. + * + */ +template class SpinelInterfaceAdapter { +public: + SpinelInterfaceAdapter(void) {} + + ~SpinelInterfaceAdapter(void) {} + + InterfaceType &GetSpinelInterface(void) { return mSpinelInterface; } + +private: + InterfaceType mSpinelInterface; +}; + +} // namespace radio_spinel +} // namespace esp diff --git a/components/openthread/private_include/esp_radio_spinel_uart_interface.hpp b/components/openthread/private_include/esp_radio_spinel_uart_interface.hpp new file mode 100644 index 0000000000..70f7440b01 --- /dev/null +++ b/components/openthread/private_include/esp_radio_spinel_uart_interface.hpp @@ -0,0 +1,206 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include "esp_radio_spinel.h" +#include "lib/spinel/spinel_interface.hpp" +#include "lib/hdlc/hdlc.hpp" +#include "openthread/error.h" + +namespace esp { +namespace radio_spinel { + +/** + * This class defines an UART interface to the Radio Co-processor (RCP). + * + */ +class UartSpinelInterface : public ot::Spinel::SpinelInterface { +public: + /** + * @brief This constructor of object. + */ + UartSpinelInterface(void); + + /** + * @brief This destructor of the object. + * + */ + ~UartSpinelInterface(void); + + /** + * 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. + * + */ + otError Init(ReceiveFrameCallback aCallback, void *aCallbackContext, RxFrameBuffer &aFrameBuffer); + + /** + * Deinitializes the interface to the RCP. + * + */ + void Deinit(void); + + /** + * Encodes and sends a spinel frame to Radio Co-processor (RCP) over the socket. + * + * @param[in] aFrame A pointer to buffer containing the spinel frame to send. + * @param[in] aLength The length (number of bytes) in the frame. + * + * @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 *aFrame, uint16_t aLength); + + /** + * Waits for receiving part or all of spinel frame within specified interval. + * + * @param[in] aTimeout The timeout value in microseconds. + * + * @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 aTimeoutUs); + + /** + * Updates the file descriptor sets with file descriptors used by the radio driver. + * + * @param[in,out] aMainloopContext A pointer to the mainloop context. + * + */ + void UpdateFdSet(void *aMainloopContext); + + /** + * Performs radio driver processing. + * + * @param[in] aMainloopContext A pointer to the mainloop context. + * + */ + void Process(const void *aMainloopContext); + + /** + * Returns the bus speed between the host and the radio. + * + * @returns Bus speed in bits/second. + * + */ + uint32_t GetBusSpeed(void) const; + + /** + * Hardware resets the RCP. + * + * @retval OT_ERROR_NONE Successfully reset the RCP. + * @retval OT_ERROR_NOT_IMPLEMENT The hardware reset is not implemented. + * + */ + otError HardwareReset(void); + + /** + * Returns the RCP interface metrics. + * + * @returns The RCP interface metrics. + * + */ + const otRcpInterfaceMetrics *GetRcpInterfaceMetrics(void) const { return &mInterfaceMetrics; } + + /** + * This methods registers the callback for RCP failure. + * + * @param[in] handler The RCP failure handler. + * + */ + void RegisterRcpFailureHandler(esp_radio_spinel_rcp_failure_handler handler) { mRcpFailureHandler = handler; } + + /** + * This method is called when RCP is reset to recreate the connection with it. + * Intentionally empty. + * + */ + 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_radio_spinel_uart_config_t &radio_uart_config); + + /** + * @brief This method disable the HDLC interface. + * + */ + esp_err_t Disable(void); + + void RegisterUartInitHandler(esp_radio_spinel_uart_init_handler handler) { mUartInitHandler = handler; } + + void RegisterUartDeinitHandler(esp_radio_spinel_uart_deinit_handler handler) { mUartDeinitHandler = handler; } + +private: + + enum { + /** + * Maximum wait time in Milliseconds for socket to become writable (see `SendFrame`). + * + */ + kMaxWaitTime = 2000, + }; + + esp_err_t InitUart(const esp_radio_spinel_uart_config_t &radio_uart_config); + + esp_err_t DeinitUart(void); + + int TryReadAndDecode(void); + + otError WaitForWritable(void); + + otError Write(const uint8_t *frame, uint16_t length); + + esp_err_t TryRecoverUart(void); + + static void HandleHdlcFrame(void *context, otError error); + void HandleHdlcFrame(otError error); + + ReceiveFrameCallback m_receiver_frame_callback; + void *m_receiver_frame_context; + RxFrameBuffer *m_receive_frame_buffer; + + ot::Hdlc::Decoder m_hdlc_decoder; + uint8_t *m_uart_rx_buffer; + + esp_radio_spinel_uart_config_t m_uart_config; + int m_uart_fd; + + otRcpInterfaceMetrics mInterfaceMetrics; + + // Non-copyable, intentionally not implemented. + UartSpinelInterface(const UartSpinelInterface &); + UartSpinelInterface &operator=(const UartSpinelInterface &); + + esp_radio_spinel_rcp_failure_handler mRcpFailureHandler; + esp_radio_spinel_uart_init_handler mUartInitHandler; + esp_radio_spinel_uart_deinit_handler mUartDeinitHandler; + + ot::Spinel::FrameBuffer encoder_buffer; +}; + +} // namespace radio_spinel +} // 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 8926ab7fc1..5cd1de7137 100644 --- a/components/openthread/private_include/esp_uart_spinel_interface.hpp +++ b/components/openthread/private_include/esp_uart_spinel_interface.hpp @@ -195,6 +195,8 @@ private: UartSpinelInterface &operator=(const UartSpinelInterface &); esp_openthread_rcp_failure_handler mRcpFailureHandler; + + ot::Spinel::FrameBuffer encoder_buffer; }; } // namespace openthread diff --git a/components/openthread/private_include/openthread-core-esp32x-ftd-config.h b/components/openthread/private_include/openthread-core-esp32x-ftd-config.h index b27bc53963..6043159bf3 100644 --- a/components/openthread/private_include/openthread-core-esp32x-ftd-config.h +++ b/components/openthread/private_include/openthread-core-esp32x-ftd-config.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2021-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -590,4 +590,34 @@ #define OPENTHREAD_CONFIG_RADIO_STATS_ENABLE 1 #endif +/** + * @def OPENTHREAD_CONFIG_TMF_ADDRESS_QUERY_TIMEOUT + * + * The timeout value (in seconds) waiting for a address notification response after sending an address query. + * + */ +#ifndef OPENTHREAD_CONFIG_TMF_ADDRESS_QUERY_TIMEOUT +#define OPENTHREAD_CONFIG_TMF_ADDRESS_QUERY_TIMEOUT CONFIG_OPENTHREAD_ADDRESS_QUERY_TIMEOUT +#endif + +/** + * @def OPENTHREAD_CONFIG_TMF_ADDRESS_QUERY_INITIAL_RETRY_DELAY + * + * Initial retry delay for address query (in seconds). + * + */ +#ifndef OPENTHREAD_CONFIG_TMF_ADDRESS_QUERY_INITIAL_RETRY_DELAY +#define OPENTHREAD_CONFIG_TMF_ADDRESS_QUERY_INITIAL_RETRY_DELAY CONFIG_OPENTHREAD_ADDRESS_QUERY_RETRY_DELAY +#endif + +/** + * @def OPENTHREAD_CONFIG_TMF_ADDRESS_QUERY_MAX_RETRY_DELAY + * + * Maximum retry delay for address query (in seconds). + * + */ +#ifndef OPENTHREAD_CONFIG_TMF_ADDRESS_QUERY_MAX_RETRY_DELAY +#define OPENTHREAD_CONFIG_TMF_ADDRESS_QUERY_MAX_RETRY_DELAY CONFIG_OPENTHREAD_ADDRESS_QUERY_MAX_RETRY_DELAY +#endif + #define OPENTHREAD_FTD 1 diff --git a/components/openthread/private_include/openthread-core-esp32x-mtd-config.h b/components/openthread/private_include/openthread-core-esp32x-mtd-config.h index f706d364e2..a008afcca6 100644 --- a/components/openthread/private_include/openthread-core-esp32x-mtd-config.h +++ b/components/openthread/private_include/openthread-core-esp32x-mtd-config.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2021-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -274,4 +274,34 @@ #define OPENTHREAD_CONFIG_RADIO_STATS_ENABLE 1 #endif +/** + * @def OPENTHREAD_CONFIG_TMF_ADDRESS_QUERY_TIMEOUT + * + * The timeout value (in seconds) waiting for a address notification response after sending an address query. + * + */ +#ifndef OPENTHREAD_CONFIG_TMF_ADDRESS_QUERY_TIMEOUT +#define OPENTHREAD_CONFIG_TMF_ADDRESS_QUERY_TIMEOUT CONFIG_OPENTHREAD_ADDRESS_QUERY_TIMEOUT +#endif + +/** + * @def OPENTHREAD_CONFIG_TMF_ADDRESS_QUERY_INITIAL_RETRY_DELAY + * + * Initial retry delay for address query (in seconds). + * + */ +#ifndef OPENTHREAD_CONFIG_TMF_ADDRESS_QUERY_INITIAL_RETRY_DELAY +#define OPENTHREAD_CONFIG_TMF_ADDRESS_QUERY_INITIAL_RETRY_DELAY CONFIG_OPENTHREAD_ADDRESS_QUERY_RETRY_DELAY +#endif + +/** + * @def OPENTHREAD_CONFIG_TMF_ADDRESS_QUERY_MAX_RETRY_DELAY + * + * Maximum retry delay for address query (in seconds). + * + */ +#ifndef OPENTHREAD_CONFIG_TMF_ADDRESS_QUERY_MAX_RETRY_DELAY +#define OPENTHREAD_CONFIG_TMF_ADDRESS_QUERY_MAX_RETRY_DELAY CONFIG_OPENTHREAD_ADDRESS_QUERY_MAX_RETRY_DELAY +#endif + #define OPENTHREAD_MTD 1 diff --git a/components/openthread/private_include/openthread-core-esp32x-radio-config.h b/components/openthread/private_include/openthread-core-esp32x-radio-config.h index 6a292f2d6e..2f34b61ef1 100644 --- a/components/openthread/private_include/openthread-core-esp32x-radio-config.h +++ b/components/openthread/private_include/openthread-core-esp32x-radio-config.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 */ @@ -218,3 +218,15 @@ #define OPENTHREAD_CONFIG_MLE_LINK_METRICS_SUBJECT_ENABLE 1 #endif #endif //CONFIG_OPENTHREAD_LINK_METRICS + +#if CONFIG_OPENTHREAD_NCP_VENDOR_HOOK +/** + * @def OPENTHREAD_ENABLE_NCP_VENDOR_HOOK + * + * Define as 1 to support ESP OpenThread NCP vendor commands + * + */ +#ifndef OPENTHREAD_ENABLE_NCP_VENDOR_HOOK +#define OPENTHREAD_ENABLE_NCP_VENDOR_HOOK 1 +#endif +#endif //CONFIG_OPENTHREAD_NCP_VENDOR_HOOK diff --git a/components/openthread/private_include/openthread-spinel-config.h b/components/openthread/private_include/openthread-core-esp32x-spinel-config.h similarity index 63% rename from components/openthread/private_include/openthread-spinel-config.h rename to components/openthread/private_include/openthread-core-esp32x-spinel-config.h index 2911ee3df6..ab6da83d84 100644 --- a/components/openthread/private_include/openthread-spinel-config.h +++ b/components/openthread/private_include/openthread-core-esp32x-spinel-config.h @@ -1,16 +1,10 @@ /* - * SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ -/** - * @file - * This file includes compile-time configuration constants for OpenThread. - */ - -#ifndef OPENTHREAD_SPINEL_CONFIG_H_ -#define OPENTHREAD_SPINEL_CONFIG_H_ +#pragma once /** * @def OPENTHREAD_SPINEL_CONFIG_OPENTHREAD_MESSAGE_ENABLE @@ -30,6 +24,7 @@ * */ #ifndef OPENTHREAD_SPINEL_CONFIG_RCP_RESTORATION_MAX_COUNT +// TZ-567: Set OPENTHREAD_SPINEL_CONFIG_RCP_RESTORATION_MAX_COUNT to 3 after adding rcp failure notification mechanism #define OPENTHREAD_SPINEL_CONFIG_RCP_RESTORATION_MAX_COUNT 0 #endif @@ -43,4 +38,11 @@ #define OPENTHREAD_SPINEL_CONFIG_RCP_CUSTOM_RESTORATION 0 #endif -#endif // OPENTHREAD_SPINEL_CONFIG_H_ +/** + * @def OPENTHREAD_CONFIG_PLATFORM_RADIO_SPINEL_RX_FRAME_BUFFER_SIZE + * + * Specifies the rx frame buffer size used by `SpinelInterface` in RCP host code. This is applicable/used when + * `RadioSpinel` platform is used. + * + */ +#define OPENTHREAD_CONFIG_PLATFORM_RADIO_SPINEL_RX_FRAME_BUFFER_SIZE CONFIG_OPENTHREAD_SPINEL_RX_FRAME_BUFFER_SIZE diff --git a/components/openthread/src/esp_openthread_cli.c b/components/openthread/src/esp_openthread_cli.c index 947bf892b9..6ce998a430 100644 --- a/components/openthread/src/esp_openthread_cli.c +++ b/components/openthread/src/esp_openthread_cli.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -20,8 +20,10 @@ #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "linenoise/linenoise.h" - -#define OT_CLI_MAX_LINE_LENGTH 256 +#include "esp_console.h" +#define OT_CLI_MAX_LINE_LENGTH 256 +#define ESP_CONSOLE_PREFIX "esp " +#define ESP_CONSOLE_PREFIX_LENGTH 4 static TaskHandle_t s_cli_task; @@ -63,7 +65,13 @@ esp_err_t esp_openthread_cli_input(const char *line) static void ot_cli_loop(void *context) { + int ret = 0; const char *prompt = "> "; + esp_console_config_t console_config = ESP_CONSOLE_CONFIG_DEFAULT(); + console_config.max_cmdline_length = OT_CLI_MAX_LINE_LENGTH; + + console_config.hint_color = -1; + ret = esp_console_init(&console_config); linenoiseSetMultiLine(true); linenoiseHistorySetMaxLen(100); @@ -78,9 +86,23 @@ static void ot_cli_loop(void *context) char *line = linenoise(prompt); if (line && strnlen(line, OT_CLI_MAX_LINE_LENGTH)) { printf("\r\n"); - esp_openthread_cli_input(line); + if (memcmp(line, ESP_CONSOLE_PREFIX, ESP_CONSOLE_PREFIX_LENGTH) == 0) { + esp_err_t err = esp_console_run(line + ESP_CONSOLE_PREFIX_LENGTH, &ret); + if (err == ESP_ERR_NOT_FOUND) { + printf("Unrecognized command\n"); + } else if (err == ESP_ERR_INVALID_ARG) { + // command was empty + printf("Command is empty\n"); + } else if (err == ESP_OK && ret != ESP_OK) { + printf("Command returned non-zero error code: 0x%x (%s)\n", ret, esp_err_to_name(ret)); + } else if (err != ESP_OK) { + printf("Internal error: %s\n", esp_err_to_name(err)); + } + } else { + esp_openthread_cli_input(line); + xTaskNotifyWait(0, 0, NULL, portMAX_DELAY); + } linenoiseHistoryAdd(line); - xTaskNotifyWait(0, 0, NULL, portMAX_DELAY); } linenoiseFree(line); } diff --git a/components/openthread/src/ncp/esp_openthread_ncp.cpp b/components/openthread/src/ncp/esp_openthread_ncp.cpp new file mode 100644 index 0000000000..7e5127f869 --- /dev/null +++ b/components/openthread/src/ncp/esp_openthread_ncp.cpp @@ -0,0 +1,111 @@ +/* + * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "esp_ieee802154.h" +#include "esp_openthread_ncp.h" +#include "ncp_base.hpp" + +#if OPENTHREAD_ENABLE_NCP_VENDOR_HOOK + +#if CONFIG_OPENTHREAD_RCP_UART +#include "utils/uart.h" +#endif + +#if CONFIG_OPENTHREAD_RCP_UART +extern "C" { + static int NcpSend(const uint8_t *aBuf, uint16_t aBufLength) + { + IgnoreError(otPlatUartSend(aBuf, aBufLength)); + return aBufLength; + } +} +#endif + +extern "C" void otAppNcpInit(otInstance *aInstance) +{ +#if CONFIG_OPENTHREAD_RCP_SPI + otNcpSpiInit(aInstance); +#else + IgnoreError(otPlatUartEnable()); + + otNcpHdlcInit(aInstance, NcpSend); +#endif +} + +namespace ot { +namespace Ncp { + +otError NcpBase::VendorCommandHandler(uint8_t aHeader, unsigned int aCommand) +{ + otError error = OT_ERROR_NONE; + + otPlatLog(OT_LOG_LEVEL_WARN, OT_LOG_REGION_NCP, "VendorCommandHandler Not Implemented"); + + switch (aCommand) + { + + default: + error = PrepareLastStatusResponse(aHeader, SPINEL_STATUS_INVALID_COMMAND); + break; + } + + return error; +} + +void NcpBase::VendorHandleFrameRemovedFromNcpBuffer(Spinel::Buffer::FrameTag aFrameTag) +{ + OT_UNUSED_VARIABLE(aFrameTag); +} + +otError NcpBase::VendorGetPropertyHandler(spinel_prop_key_t aPropKey) +{ + otError error = OT_ERROR_NONE; + + switch (aPropKey) + { + + default: + error = OT_ERROR_NOT_FOUND; + break; + } + + return error; +} + +otError NcpBase::VendorSetPropertyHandler(spinel_prop_key_t aPropKey) +{ + otError error = OT_ERROR_NONE; + + switch (aPropKey) + { + + // TZ-566: Add mechanism to allow users to register callback functions. + case SPINEL_PROP_VENDOR_ESP_SET_COORDINATOR: { + bool coordinator = false; + mDecoder.ReadBool(coordinator); + esp_ieee802154_set_coordinator(coordinator); + break; + } + case SPINEL_PROP_VENDOR_ESP_SET_PENDINGMODE: { + + int32_t pending_mode = 0; + mDecoder.ReadInt32(pending_mode); + esp_ieee802154_set_pending_mode(static_cast(pending_mode)); + break; + } + + default: + error = OT_ERROR_NOT_FOUND; + break; + } + + return error; +} + +} // namespace Ncp +} // namespace ot + +#endif // #if OPENTHREAD_ENABLE_NCP_VENDOR_HOOK diff --git a/components/openthread/src/ncp/esp_openthread_ncp_hdlc.cpp b/components/openthread/src/ncp/esp_openthread_ncp_hdlc.cpp new file mode 100644 index 0000000000..0e8a3dbb88 --- /dev/null +++ b/components/openthread/src/ncp/esp_openthread_ncp_hdlc.cpp @@ -0,0 +1,33 @@ +/* + * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "common/new.hpp" +#include "ncp_hdlc.hpp" + +#if OPENTHREAD_ENABLE_NCP_VENDOR_HOOK + +namespace ot { +namespace Ncp { + +static OT_DEFINE_ALIGNED_VAR(sNcpRaw, sizeof(NcpHdlc), uint64_t); + +extern "C" void otNcpHdlcInit(otInstance *aInstance, otNcpHdlcSendCallback aSendCallback) +{ + NcpHdlc *ncpHdlc = nullptr; + Instance *instance = static_cast(aInstance); + + ncpHdlc = new (&sNcpRaw) NcpHdlc(instance, aSendCallback); + + if (ncpHdlc == nullptr || ncpHdlc != NcpBase::GetNcpInstance()) + { + OT_ASSERT(false); + } +} + +} // namespace Ncp +} // namespace ot + +#endif // #if OPENTHREAD_ENABLE_NCP_VENDOR_HOOK diff --git a/components/openthread/src/port/esp_openthread_radio.c b/components/openthread/src/port/esp_openthread_radio.c index a5013a5c4b..3079d75e16 100644 --- a/components/openthread/src/port/esp_openthread_radio.c +++ b/components/openthread/src/port/esp_openthread_radio.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2021-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -174,9 +174,7 @@ esp_err_t esp_openthread_radio_process(otInstance *aInstance, const esp_openthre otPlatRadioTxDone(aInstance, &s_transmit_frame, NULL, OT_ERROR_NONE); } else { otPlatRadioTxDone(aInstance, &s_transmit_frame, &s_ack_frame, OT_ERROR_NONE); -#if CONFIG_IEEE802154_RECEIVE_DONE_HANDLER - esp_ieee802154_receive_handle_done(s_ack_frame.mPsdu - 1); -#endif + esp_ieee802154_receive_handle_done(s_ack_frame.mPsdu - 1); s_ack_frame.mPsdu = NULL; } } @@ -228,9 +226,7 @@ esp_err_t esp_openthread_radio_process(otInstance *aInstance, const esp_openthre { otPlatRadioReceiveDone(aInstance, &s_receive_frame[s_recv_queue.head], OT_ERROR_NONE); } -#if CONFIG_IEEE802154_RECEIVE_DONE_HANDLER esp_ieee802154_receive_handle_done(s_receive_frame[s_recv_queue.head].mPsdu - 1); -#endif s_receive_frame[s_recv_queue.head].mPsdu = NULL; s_recv_queue.head = (s_recv_queue.head + 1) % CONFIG_IEEE802154_RX_BUFFER_SIZE; s_recv_queue.used--; @@ -347,7 +343,11 @@ int8_t otPlatRadioGetRssi(otInstance *aInstance) otRadioCaps otPlatRadioGetCaps(otInstance *aInstance) { +// FIXME: Remove `CONFIG_OPENTHREAD_RX_ON_WHEN_IDLE` when JIRA: TZ-609 fixed. return (otRadioCaps)(OT_RADIO_CAPS_ENERGY_SCAN | +#if CONFIG_OPENTHREAD_RX_ON_WHEN_IDLE + OT_RADIO_CAPS_RX_ON_WHEN_IDLE | +#endif OT_RADIO_CAPS_TRANSMIT_SEC | OT_RADIO_CAPS_RECEIVE_TIMING | OT_RADIO_CAPS_TRANSMIT_TIMING | OT_RADIO_CAPS_ACK_TIMEOUT | OT_RADIO_CAPS_SLEEP_TO_TX); } @@ -774,3 +774,11 @@ otError otPlatRadioSetChannelMaxTransmitPower(otInstance *aInstance, uint8_t aCh return OT_ERROR_NONE; } + +#if CONFIG_OPENTHREAD_RX_ON_WHEN_IDLE +void otPlatRadioSetRxOnWhenIdle(otInstance *aInstance, bool aEnable) +{ + OT_UNUSED_VARIABLE(aInstance); + esp_ieee802154_set_rx_when_idle(aEnable); +} +#endif diff --git a/components/openthread/src/port/esp_openthread_radio_spinel.cpp b/components/openthread/src/port/esp_openthread_radio_spinel.cpp index 83fdf9b006..a926138f9a 100644 --- a/components/openthread/src/port/esp_openthread_radio_spinel.cpp +++ b/components/openthread/src/port/esp_openthread_radio_spinel.cpp @@ -1,11 +1,12 @@ /* - * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ #include "esp_openthread_radio.h" +#include "sdkconfig.h" #include "esp_check.h" #include "esp_err.h" #include "esp_openthread_border_router.h" @@ -112,7 +113,9 @@ esp_err_t esp_openthread_rcp_init(void) #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"); +#if OPENTHREAD_SPINEL_CONFIG_RCP_RESTORATION_MAX_COUNT > 0 s_radio.RestoreProperties(); +#endif return esp_openthread_platform_workflow_register(&esp_openthread_radio_update, &esp_openthread_radio_process, radiospinel_workflow); } @@ -410,3 +413,10 @@ otError otPlatRadioConfigureEnhAckProbing(otInstance *aInstance, otLinkMetrics a return s_radio.ConfigureEnhAckProbing(aLinkMetrics, aShortAddress, *aExtAddress); } #endif + +#if CONFIG_OPENTHREAD_RX_ON_WHEN_IDLE +void otPlatRadioSetRxOnWhenIdle(otInstance *aInstance, bool aEnable) +{ + s_radio.SetRxOnWhenIdle(aEnable); +} +#endif diff --git a/components/openthread/src/port/esp_uart_spinel_interface.cpp b/components/openthread/src/port/esp_uart_spinel_interface.cpp index ec07bd6d80..9b9ab2478b 100644 --- a/components/openthread/src/port/esp_uart_spinel_interface.cpp +++ b/components/openthread/src/port/esp_uart_spinel_interface.cpp @@ -86,7 +86,7 @@ esp_err_t UartSpinelInterface::Disable(void) otError UartSpinelInterface::SendFrame(const uint8_t *frame, uint16_t length) { otError error = OT_ERROR_NONE; - ot::Spinel::FrameBuffer encoder_buffer; + encoder_buffer.Clear(); ot::Hdlc::Encoder hdlc_encoder(encoder_buffer); SuccessOrExit(error = hdlc_encoder.BeginFrame()); diff --git a/components/openthread/src/spinel/esp_radio_spinel.cpp b/components/openthread/src/spinel/esp_radio_spinel.cpp new file mode 100644 index 0000000000..c9895ff00a --- /dev/null +++ b/components/openthread/src/spinel/esp_radio_spinel.cpp @@ -0,0 +1,354 @@ +/* + * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "esp_check.h" +#include "esp_log.h" +#include "platform/exit_code.h" +#include "radio_spinel.hpp" +#include "esp_radio_spinel.h" +#include "esp_radio_spinel_adapter.hpp" +#include "esp_radio_spinel_uart_interface.hpp" + +using ot::Spinel::RadioSpinel; +using ot::Spinel::RadioSpinelCallbacks; +using esp::radio_spinel::SpinelInterfaceAdapter; +using esp::radio_spinel::UartSpinelInterface; + +static SpinelInterfaceAdapter s_spinel_interface[ot::Spinel::kSpinelHeaderMaxNumIid]; +static RadioSpinel s_radio[ot::Spinel::kSpinelHeaderMaxNumIid]; +static esp_radio_spinel_callbacks_t s_esp_radio_spinel_callbacks[ot::Spinel::kSpinelHeaderMaxNumIid]; +otRadioFrame s_transmit_frame; + +static esp_radio_spinel_idx_t get_index_from_instance(otInstance *instance) +{ + // TZ-563: Implement the function to get the esp radio spinel idx from otInstance for multipan rcp + return ESP_RADIO_SPINEL_ZIGBEE; +} + +static otInstance* get_instance_from_index(esp_radio_spinel_idx_t idx) +{ + // TZ-563: Implement the function to get otInstance pointer from esp radio spinel idx + return nullptr; +} + +void ReceiveDone(otInstance *aInstance, otRadioFrame *aFrame, otError aError) +{ + esp_radio_spinel_idx_t idx = get_index_from_instance(aInstance); + assert(s_esp_radio_spinel_callbacks[idx].receive_done); + uint8_t *frame = (uint8_t *)malloc(aFrame->mLength + 1); + esp_ieee802154_frame_info_t frame_info; + if (frame) { + frame[0] = aFrame->mLength; + memcpy((void *)(frame + 1), aFrame->mPsdu, frame[0]); + frame_info.rssi = aFrame->mInfo.mRxInfo.mRssi; + frame_info.timestamp = aFrame->mInfo.mRxInfo.mTimestamp; + frame_info.pending = aFrame->mInfo.mRxInfo.mAckedWithFramePending; + s_esp_radio_spinel_callbacks[idx].receive_done(frame, &frame_info); + free(frame); + } else { + ESP_LOGE(ESP_SPINEL_LOG_TAG, "Fail to alloc memory for frame"); + } +} + +void TransmitDone(otInstance *aInstance, otRadioFrame *aFrame, otRadioFrame *aAckFrame, otError aError) +{ + esp_radio_spinel_idx_t idx = get_index_from_instance(aInstance); + assert(s_esp_radio_spinel_callbacks[idx].transmit_done && s_esp_radio_spinel_callbacks[idx].transmit_failed); + if (aError == OT_ERROR_NONE) { + uint8_t *frame = (uint8_t *)malloc(aFrame->mLength + 1); + uint8_t *ack = nullptr; + if (frame) { + esp_ieee802154_frame_info_t ack_info; + frame[0] = aFrame->mLength; + memcpy((void *)(frame + 1), aFrame->mPsdu, frame[0]); + if (aAckFrame) { + ack = (uint8_t *)malloc(aAckFrame->mLength + 1); + if (ack) { + ack[0] = aAckFrame->mLength; + memcpy((void *)(ack + 1), aAckFrame->mPsdu, ack[0]); + } else { + ESP_LOGE(ESP_SPINEL_LOG_TAG, "Fail to alloc memory for ack"); + } + } + s_esp_radio_spinel_callbacks[idx].transmit_done(frame, ack, &ack_info); + free(frame); + free(ack); + } else { + ESP_LOGE(ESP_SPINEL_LOG_TAG, "Fail to alloc memory for frame"); + } + } else { + switch (aError) { + case OT_ERROR_CHANNEL_ACCESS_FAILURE: + s_esp_radio_spinel_callbacks[idx].transmit_failed(ESP_IEEE802154_TX_ERR_CCA_BUSY); + break; + case OT_ERROR_NO_ACK: + s_esp_radio_spinel_callbacks[idx].transmit_failed(ESP_IEEE802154_TX_ERR_NO_ACK); + break; + default: + s_esp_radio_spinel_callbacks[idx].transmit_failed(ESP_IEEE802154_TX_ERR_ABORT); + break; + } + } +} + +void EnergyScanDone(otInstance *aInstance, int8_t aMaxRssi) +{ + esp_radio_spinel_idx_t idx = get_index_from_instance(aInstance); + assert(s_esp_radio_spinel_callbacks[idx].energy_scan_done); + s_esp_radio_spinel_callbacks[idx].energy_scan_done(aMaxRssi); +} + +void TxStarted(otInstance *aInstance, otRadioFrame *aFrame) +{ + esp_radio_spinel_idx_t idx = get_index_from_instance(aInstance); + assert(s_esp_radio_spinel_callbacks[idx].transmit_started); + uint8_t *frame = (uint8_t *)malloc(aFrame->mLength + 1); + if (frame) { + frame[0] = aFrame->mLength; + memcpy((void *)(frame + 1), aFrame->mPsdu, frame[0]); + s_esp_radio_spinel_callbacks[idx].transmit_started(frame); + free(frame); + } else { + ESP_LOGE(ESP_SPINEL_LOG_TAG, "Fail to alloc memory for frame"); + } +} + +void SwitchoverDone(otInstance *aInstance, bool aSuccess) +{ + esp_radio_spinel_idx_t idx = get_index_from_instance(aInstance); + assert(s_esp_radio_spinel_callbacks[idx].switchover_done); + s_esp_radio_spinel_callbacks[idx].switchover_done(aSuccess); +} + +#if OPENTHREAD_CONFIG_DIAG_ENABLE +void DiagReceiveDone(otInstance *aInstance, otRadioFrame *aFrame, otError aError) +{ + esp_radio_spinel_idx_t idx = get_index_from_instance(aInstance); + assert(s_esp_radio_spinel_callbacks[idx].diag_receive_done); + uint8_t *frame = (uint8_t *)malloc(aFrame->mLength + 1); + esp_ieee802154_frame_info_t frame_info; + if (frame) { + frame[0] = aFrame->mLength; + memcpy((void *)(frame + 1), aFrame->mPsdu, frame[0]); + frame_info.rssi = aFrame->mInfo.mRxInfo.mRssi; + frame_info.timestamp = aFrame->mInfo.mRxInfo.mTimestamp; + frame_info.pending = aFrame->mInfo.mRxInfo.mAckedWithFramePending; + s_esp_radio_spinel_callbacks[idx].diag_receive_done(frame, &frame_info); + free(frame); + } else { + ESP_LOGE(ESP_SPINEL_LOG_TAG, "Fail to alloc memory for frame"); + } +} + +void DiagTransmitDone(otInstance *aInstance, otRadioFrame *aFrame, otError aError) +{ + esp_radio_spinel_idx_t idx = get_index_from_instance(aInstance); + assert(s_esp_radio_spinel_callbacks[idx].diag_transmit_done && s_esp_radio_spinel_callbacks[idx].diag_transmit_failed); + if (aError == OT_ERROR_NONE) { + uint8_t *frame = (uint8_t *)malloc(aFrame->mLength + 1); + if (frame) { + esp_ieee802154_frame_info_t ack_info; + frame[0] = aFrame->mLength; + memcpy((void *)(frame + 1), aFrame->mPsdu, frame[0]); + s_esp_radio_spinel_callbacks[idx].diag_transmit_done(frame, &ack_info); + free(frame); + } else { + ESP_LOGE(ESP_SPINEL_LOG_TAG, "Fail to alloc memory for frame"); + } + } else { + switch (aError) { + case OT_ERROR_CHANNEL_ACCESS_FAILURE: + s_esp_radio_spinel_callbacks[idx].diag_transmit_failed(ESP_IEEE802154_TX_ERR_CCA_BUSY); + break; + case OT_ERROR_NO_ACK: + s_esp_radio_spinel_callbacks[idx].diag_transmit_failed(ESP_IEEE802154_TX_ERR_NO_ACK); + break; + default: + s_esp_radio_spinel_callbacks[idx].diag_transmit_failed(ESP_IEEE802154_TX_ERR_CCA_BUSY); + break; + } + } +} +#endif // OPENTHREAD_CONFIG_DIAG_ENABLE + + +void esp_radio_spinel_set_callbacks(const esp_radio_spinel_callbacks_t aCallbacks, esp_radio_spinel_idx_t idx) +{ + s_esp_radio_spinel_callbacks[idx] = aCallbacks; + RadioSpinelCallbacks Callbacks; + Callbacks.mReceiveDone = ReceiveDone; + Callbacks.mTransmitDone = TransmitDone; + Callbacks.mEnergyScanDone = EnergyScanDone; + Callbacks.mTxStarted = TxStarted; + Callbacks.mSwitchoverDone = SwitchoverDone; +#if OPENTHREAD_CONFIG_DIAG_ENABLE + Callbacks.mDiagReceiveDone = DiagReceiveDone; + Callbacks.mDiagTransmitDone = DiagTransmitDone; +#endif // OPENTHREAD_CONFIG_DIAG_ENABLE + + s_radio[idx].SetCallbacks(Callbacks); +} + +esp_err_t esp_radio_spinel_uart_interface_enable(const esp_radio_spinel_uart_config_t *radio_uart_config, + esp_radio_spinel_uart_init_handler aUartInitHandler, + esp_radio_spinel_uart_deinit_handler aUartDeinitHandler, + esp_radio_spinel_idx_t idx) +{ + ESP_RETURN_ON_FALSE(aUartInitHandler != nullptr, ESP_FAIL, ESP_SPINEL_LOG_TAG, "UartInitHandler can not be set to NULL"); + ESP_RETURN_ON_FALSE(aUartDeinitHandler != nullptr, ESP_FAIL, ESP_SPINEL_LOG_TAG, "UartDeinitHandler can not be set to NULL"); + s_spinel_interface[idx].GetSpinelInterface().RegisterUartInitHandler(aUartInitHandler); + s_spinel_interface[idx].GetSpinelInterface().RegisterUartDeinitHandler(aUartDeinitHandler); + ESP_RETURN_ON_FALSE(s_spinel_interface[idx].GetSpinelInterface().Enable(*radio_uart_config) == OT_ERROR_NONE, ESP_FAIL, ESP_SPINEL_LOG_TAG, "Spinel UART interface failed to enable"); + ESP_LOGI(ESP_SPINEL_LOG_TAG, "Spinel UART interface has been successfully enabled"); + return ESP_OK; +} + +void esp_radio_spinel_init(esp_radio_spinel_idx_t idx) +{ + spinel_iid_t iidList[ot::Spinel::kSpinelHeaderMaxNumIid]; + + // Multipan is not currently supported + iidList[0] = 0; + s_radio[idx].Init(s_spinel_interface[idx].GetSpinelInterface(), /*reset_radio=*/true, /*skip_rcp_compatibility_check=*/false, iidList, ot::Spinel::kSpinelHeaderMaxNumIid); +} + +esp_err_t esp_radio_spinel_enable(esp_radio_spinel_idx_t idx) +{ + otInstance *instance = get_instance_from_index(idx); + return (s_radio[idx].Enable(instance) == OT_ERROR_NONE) ? ESP_OK : ESP_FAIL; +} + +esp_err_t esp_radio_spinel_set_pending_mode(esp_ieee802154_pending_mode_t pending_mode, esp_radio_spinel_idx_t idx) +{ + return (s_radio[idx].Set(SPINEL_PROP_VENDOR_ESP_SET_PENDINGMODE, SPINEL_DATATYPE_INT32_S, static_cast(pending_mode)) == OT_ERROR_NONE) ? ESP_OK : ESP_FAIL; +} + +esp_err_t esp_radio_spinel_get_eui64(uint8_t *eui64, esp_radio_spinel_idx_t idx) +{ + return (s_radio[idx].GetIeeeEui64(eui64) == OT_ERROR_NONE) ? ESP_OK : ESP_FAIL; +} + +esp_err_t esp_radio_spinel_set_panid(uint16_t panid, esp_radio_spinel_idx_t idx) +{ + return (s_radio[idx].SetPanId(panid) == OT_ERROR_NONE) ? ESP_OK : ESP_FAIL; +} + +esp_err_t esp_radio_spinel_set_short_address(uint16_t short_address, esp_radio_spinel_idx_t idx) +{ + return (s_radio[idx].SetShortAddress(short_address) == OT_ERROR_NONE) ? ESP_OK : ESP_FAIL; +} + +esp_err_t esp_radio_spinel_set_extended_address(uint8_t *ext_address, esp_radio_spinel_idx_t idx) +{ + otExtAddress aExtAddress; + memcpy(aExtAddress.m8, (void *)ext_address, OT_EXT_ADDRESS_SIZE); + return (s_radio[idx].SetExtendedAddress(aExtAddress) == OT_ERROR_NONE) ? ESP_OK : ESP_FAIL; +} + +esp_err_t esp_radio_spinel_set_pan_coord(bool enable, esp_radio_spinel_idx_t idx) +{ + return (s_radio[idx].Set(SPINEL_PROP_VENDOR_ESP_SET_COORDINATOR, SPINEL_DATATYPE_BOOL_S, enable) == OT_ERROR_NONE) ? ESP_OK : ESP_FAIL; +} + +esp_err_t esp_radio_spinel_receive(uint8_t channel, esp_radio_spinel_idx_t idx) +{ + return (s_radio[idx].Receive(channel) == OT_ERROR_NONE) ? ESP_OK : ESP_FAIL; +} + +esp_err_t esp_radio_spinel_energy_scan(uint8_t scan_channel, uint16_t scan_duration, esp_radio_spinel_idx_t idx) +{ + return (s_radio[idx].EnergyScan(scan_channel, scan_duration) == OT_ERROR_NONE) ? ESP_OK : ESP_FAIL; +} + +esp_err_t esp_radio_spinel_transmit(uint8_t *frame, uint8_t channel, bool cca, esp_radio_spinel_idx_t idx) +{ + s_transmit_frame.mLength = frame[0]; + s_transmit_frame.mPsdu = frame + 1; + s_transmit_frame.mInfo.mTxInfo.mCsmaCaEnabled = cca; + s_transmit_frame.mChannel = channel; + s_transmit_frame.mInfo.mTxInfo.mRxChannelAfterTxDone = channel; + return (s_radio[idx].Transmit(s_transmit_frame) == OT_ERROR_NONE) ? ESP_OK : ESP_FAIL; +} + +esp_err_t esp_radio_spinel_clear_short_entries(esp_radio_spinel_idx_t idx) +{ + return (s_radio[idx].ClearSrcMatchShortEntries() == OT_ERROR_NONE) ? ESP_OK : ESP_FAIL; +} + +esp_err_t esp_radio_spinel_add_short_entry(uint16_t short_address, esp_radio_spinel_idx_t idx) +{ + return (s_radio[idx].AddSrcMatchShortEntry(short_address) == OT_ERROR_NONE) ? ESP_OK : ESP_FAIL; +} + +esp_err_t esp_radio_spinel_clear_extended_entries(esp_radio_spinel_idx_t idx) +{ + return (s_radio[idx].ClearSrcMatchExtEntries() == OT_ERROR_NONE) ? ESP_OK : ESP_FAIL; +} + +esp_err_t esp_radio_spinel_add_extended_entry(uint8_t *ext_address, esp_radio_spinel_idx_t idx) +{ + otExtAddress aExtAddress; + memcpy(aExtAddress.m8, (void *)ext_address, OT_EXT_ADDRESS_SIZE); + return (s_radio[idx].AddSrcMatchExtEntry(aExtAddress) == OT_ERROR_NONE) ? ESP_OK : ESP_FAIL; +} + +esp_err_t esp_radio_spinel_set_promiscuous_mode(bool enable, esp_radio_spinel_idx_t idx) +{ + return (s_radio[idx].SetPromiscuous(enable) == OT_ERROR_NONE) ? ESP_OK : ESP_FAIL; +} + +void esp_radio_spinel_radio_update(esp_radio_spinel_mainloop_context_t *mainloop_context, esp_radio_spinel_idx_t idx) +{ + s_spinel_interface[idx].GetSpinelInterface().UpdateFdSet(static_cast(mainloop_context)); +} + +void esp_radio_spinel_radio_process(esp_radio_spinel_mainloop_context_t *mainloop_context, esp_radio_spinel_idx_t idx) +{ + s_radio[idx].Process(static_cast(mainloop_context)); +} + +esp_err_t esp_radio_spinel_sleep(esp_radio_spinel_idx_t idx) +{ + return (s_radio[idx].Sleep() == OT_ERROR_NONE) ? ESP_OK : ESP_FAIL; +} + +esp_err_t esp_radio_spinel_set_tx_power(int8_t power, esp_radio_spinel_idx_t idx) +{ + return (s_radio[idx].SetTransmitPower(power) == OT_ERROR_NONE) ? ESP_OK : ESP_FAIL; +} + +esp_err_t esp_radio_spinel_get_tx_power(int8_t *power, esp_radio_spinel_idx_t idx) +{ + otError error = OT_ERROR_NONE; + int8_t aPower; + error = s_radio[idx].GetTransmitPower(aPower); + *power = aPower; + return (error == OT_ERROR_NONE) ? ESP_OK : ESP_FAIL; +} + +void esp_radio_spinel_register_rcp_failure_handler(esp_radio_spinel_rcp_failure_handler handler, esp_radio_spinel_idx_t idx) +{ + s_spinel_interface[idx].GetSpinelInterface().RegisterRcpFailureHandler(handler); +} + +esp_err_t esp_radio_spinel_rcp_deinit(esp_radio_spinel_idx_t idx) +{ + if (s_radio[idx].IsEnabled()) { + ESP_RETURN_ON_FALSE(s_radio[idx].Sleep() == OT_ERROR_NONE, ESP_ERR_INVALID_STATE, ESP_SPINEL_LOG_TAG, "Radio fails to sleep"); + ESP_RETURN_ON_FALSE(s_radio[idx].Disable() == OT_ERROR_NONE, ESP_ERR_INVALID_STATE, ESP_SPINEL_LOG_TAG, "Fail to disable radio"); + } + ESP_RETURN_ON_FALSE(s_spinel_interface[idx].GetSpinelInterface().Disable() == OT_ERROR_NONE, ESP_ERR_INVALID_STATE, ESP_SPINEL_LOG_TAG, "Fail to deinitialize UART"); + return ESP_OK; +} + + +esp_err_t esp_radio_spinel_rcp_version_get(char *running_rcp_version, esp_radio_spinel_idx_t idx) +{ + const char *rcp_version = s_radio[idx].GetVersion(); + ESP_RETURN_ON_FALSE(rcp_version != nullptr, ESP_FAIL, ESP_SPINEL_LOG_TAG, "Fail to get rcp version"); + strcpy(running_rcp_version, rcp_version); + return ESP_OK; +} diff --git a/components/openthread/src/spinel/esp_radio_spinel_uart_interface.cpp b/components/openthread/src/spinel/esp_radio_spinel_uart_interface.cpp new file mode 100644 index 0000000000..d07a67065b --- /dev/null +++ b/components/openthread/src/spinel/esp_radio_spinel_uart_interface.cpp @@ -0,0 +1,300 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "esp_radio_spinel_uart_interface.hpp" +#include +#include +#include "esp_check.h" +#include "esp_openthread_common_macro.h" +#include "openthread/platform/time.h" +#include "hdlc.hpp" + +namespace esp { +namespace radio_spinel { + +UartSpinelInterface::UartSpinelInterface(void) + : m_receiver_frame_callback(nullptr) + , m_receiver_frame_context(nullptr) + , m_receive_frame_buffer(nullptr) + , m_uart_fd(-1) + , mRcpFailureHandler(nullptr) +{ +} + +UartSpinelInterface::~UartSpinelInterface(void) +{ + Deinit(); +} + +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_radio_spinel_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)); + if (m_uart_rx_buffer == NULL) { + return ESP_ERR_NO_MEM; + } + + error = InitUart(radio_uart_config); + if (error == ESP_OK) { + ESP_LOGI(ESP_SPINEL_LOG_TAG, "spinel UART interface initialization completed"); + } + return error; +} + +esp_err_t UartSpinelInterface::Disable(void) +{ + if (m_uart_rx_buffer) { + heap_caps_free(m_uart_rx_buffer); + } + m_uart_rx_buffer = NULL; + + return DeinitUart(); +} + +otError UartSpinelInterface::SendFrame(const uint8_t *frame, uint16_t length) +{ + otError error = OT_ERROR_NONE; + encoder_buffer.Clear(); + ot::Hdlc::Encoder hdlc_encoder(encoder_buffer); + + SuccessOrExit(error = hdlc_encoder.BeginFrame()); + SuccessOrExit(error = hdlc_encoder.Encode(frame, length)); + SuccessOrExit(error = hdlc_encoder.EndFrame()); + + SuccessOrExit(error = Write(encoder_buffer.GetFrame(), encoder_buffer.GetLength())); + +exit: + if (error != OT_ERROR_NONE) { + ESP_LOGE(ESP_SPINEL_LOG_TAG, "send radio frame failed"); + } else { + ESP_LOGD(ESP_SPINEL_LOG_TAG, "sent radio frame"); + } + + return error; +} + +void UartSpinelInterface::Process(const void *aMainloopContext) +{ + if (FD_ISSET(m_uart_fd, &((esp_radio_spinel_mainloop_context_t *)aMainloopContext)->read_fds)) { + ESP_LOGD(ESP_SPINEL_LOG_TAG, "radio uart read event"); + TryReadAndDecode(); + } +} + +int UartSpinelInterface::TryReadAndDecode(void) +{ + uint8_t buffer[UART_HW_FIFO_LEN(m_uart_config.port)]; + ssize_t rval; + do { + rval = read(m_uart_fd, buffer, sizeof(buffer)); + if (rval > 0) { + m_hdlc_decoder.Decode(buffer, static_cast(rval)); + } + } while (rval > 0); + + if ((rval < 0) && (errno != EAGAIN) && (errno != EWOULDBLOCK)) { + ESP_ERROR_CHECK(TryRecoverUart()); + } + return rval; +} + +otError UartSpinelInterface::WaitForWritable(void) +{ + otError error = OT_ERROR_NONE; + struct timeval timeout = {kMaxWaitTime / MS_PER_S, (kMaxWaitTime % MS_PER_S) * US_PER_MS}; + uint64_t now = otPlatTimeGet(); + uint64_t end = now + kMaxWaitTime * US_PER_MS; + fd_set write_fds; + fd_set error_fds; + int rval; + + while (true) { + FD_ZERO(&write_fds); + FD_ZERO(&error_fds); + FD_SET(m_uart_fd, &write_fds); + FD_SET(m_uart_fd, &error_fds); + + rval = select(m_uart_fd + 1, NULL, &write_fds, &error_fds, &timeout); + + if (rval > 0) { + if (FD_ISSET(m_uart_fd, &write_fds)) { + ExitNow(); + } else if (FD_ISSET(m_uart_fd, &error_fds)) { + ExitNow(error = OT_ERROR_FAILED); + } + } else if ((rval < 0) && (errno != EINTR)) { + ESP_ERROR_CHECK(TryRecoverUart()); + ExitNow(error = OT_ERROR_FAILED); + } + + now = otPlatTimeGet(); + + if (end > now) { + uint64_t remain = end - now; + + timeout.tv_sec = static_cast(remain / 1000000); + timeout.tv_usec = static_cast(remain % 1000000); + } else { + break; + } + } + + error = OT_ERROR_FAILED; + +exit: + return error; +} + +otError UartSpinelInterface::Write(const uint8_t *aFrame, uint16_t length) +{ + otError error = OT_ERROR_NONE; + + while (length) { + ssize_t rval; + + rval = write(m_uart_fd, aFrame, length); + + if (rval > 0) { + assert(rval <= length); + length -= static_cast(rval); + aFrame += static_cast(rval); + continue; + } else if (rval < 0) { + ESP_ERROR_CHECK(TryRecoverUart()); + ExitNow(error = OT_ERROR_FAILED); + } + + SuccessOrExit(error = WaitForWritable()); + } + +exit: + return error; +} + +otError UartSpinelInterface::WaitForFrame(uint64_t timeout_us) +{ + otError error = OT_ERROR_NONE; + struct timeval timeout; + fd_set read_fds; + fd_set error_fds; + int rval; + + FD_ZERO(&read_fds); + FD_ZERO(&error_fds); + FD_SET(m_uart_fd, &read_fds); + FD_SET(m_uart_fd, &error_fds); + + timeout.tv_sec = static_cast(timeout_us / US_PER_S); + timeout.tv_usec = static_cast(timeout_us % US_PER_S); + + rval = select(m_uart_fd + 1, &read_fds, NULL, &error_fds, &timeout); + + if (rval > 0) { + if (FD_ISSET(m_uart_fd, &read_fds)) { + TryReadAndDecode(); + } else if (FD_ISSET(m_uart_fd, &error_fds)) { + ESP_ERROR_CHECK(TryRecoverUart()); + ExitNow(error = OT_ERROR_FAILED); + } + } else if (rval == 0) { + ExitNow(error = OT_ERROR_RESPONSE_TIMEOUT); + } else { + ESP_ERROR_CHECK(TryRecoverUart()); + ExitNow(error = OT_ERROR_FAILED); + } + +exit: + return error; +} + +void UartSpinelInterface::HandleHdlcFrame(void *context, otError error) +{ + static_cast(context)->HandleHdlcFrame(error); +} + +void UartSpinelInterface::HandleHdlcFrame(otError error) +{ + if (error == OT_ERROR_NONE) { + ESP_LOGD(ESP_SPINEL_LOG_TAG, "received hdlc radio frame"); + m_receiver_frame_callback(m_receiver_frame_context); + } else { + ESP_LOGE(ESP_SPINEL_LOG_TAG, "dropping radio frame: %s", otThreadErrorToString(error)); + m_receive_frame_buffer->DiscardFrame(); + } +} + +esp_err_t UartSpinelInterface::InitUart(const esp_radio_spinel_uart_config_t &radio_uart_config) +{ + if (mUartInitHandler) { + m_uart_config = radio_uart_config; + return mUartInitHandler(&m_uart_config, &m_uart_fd); + } else { + ESP_LOGE(ESP_SPINEL_LOG_TAG, "None mUartInitHandler"); + return ESP_FAIL; + } +} + +esp_err_t UartSpinelInterface::DeinitUart(void) +{ + if (mUartDeinitHandler) { + return mUartDeinitHandler(&m_uart_config, &m_uart_fd); + } else { + ESP_LOGE(ESP_SPINEL_LOG_TAG, "None mUartDeinitHandler"); + return ESP_FAIL; + } +} + +esp_err_t UartSpinelInterface::TryRecoverUart(void) +{ + ESP_RETURN_ON_ERROR(DeinitUart(), ESP_SPINEL_LOG_TAG, "DeInitUart failed"); + ESP_RETURN_ON_ERROR(InitUart(m_uart_config), ESP_SPINEL_LOG_TAG, "InitUart failed"); + return ESP_OK; +} + +otError UartSpinelInterface::HardwareReset(void) +{ + if (mRcpFailureHandler) { + mRcpFailureHandler(); + TryRecoverUart(); + } + 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_radio_spinel_mainloop_context_t *)aMainloopContext)->read_fds); + if (m_uart_fd > ((esp_radio_spinel_mainloop_context_t *)aMainloopContext)->max_fd) { + ((esp_radio_spinel_mainloop_context_t *)aMainloopContext)->max_fd = m_uart_fd; + } +} + +uint32_t UartSpinelInterface::GetBusSpeed(void) const +{ + return m_uart_config.uart_config.baud_rate; +} +} // namespace radio_spinel +} // namespace esp diff --git a/docs/conf_common.py b/docs/conf_common.py index 5c696b8f70..1d8cab4e93 100644 --- a/docs/conf_common.py +++ b/docs/conf_common.py @@ -65,6 +65,9 @@ WIFI_DOCS = ['api-guides/wifi.rst', 'api-reference/network/esp_dpp.rst', 'migration-guides/release-5.x/5.2/wifi.rst'] +IEEE802154_DOCS = ['migration-guides/release-5.x/5.1/ieee802154.rst', + 'migration-guides/release-5.x/5.2/ieee802154.rst'] + NAN_DOCS = ['api-reference/network/esp_nan.rst'] WIFI_MESH_DOCS = ['api-guides/esp-wifi-mesh.rst', @@ -187,6 +190,7 @@ conditional_include_dict = {'SOC_BT_SUPPORTED':BT_DOCS, 'SOC_BLUFI_SUPPORTED':BLUFI_DOCS, 'SOC_WIFI_SUPPORTED':WIFI_DOCS, 'SOC_BT_CLASSIC_SUPPORTED':CLASSIC_BT_DOCS, + 'SOC_IEEE802154_SUPPORTED':IEEE802154_DOCS, 'SOC_SUPPORT_COEXISTENCE':COEXISTENCE_DOCS, 'SOC_PSRAM_DMA_CAPABLE':MM_SYNC_DOCS, 'SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE':MM_SYNC_DOCS, diff --git a/docs/en/migration-guides/release-5.x/5.1/ieee802154.rst b/docs/en/migration-guides/release-5.x/5.1/ieee802154.rst new file mode 100644 index 0000000000..ac31b1cdd4 --- /dev/null +++ b/docs/en/migration-guides/release-5.x/5.1/ieee802154.rst @@ -0,0 +1,13 @@ +IEEE 802.15.4 +============= + +:link_to_translation:`zh_CN:[中文]` + +Receive Handle Done +------------------- + +.. note:: + + It is required since IDF v5.1.3 release. + +User must call the function :cpp:func:`esp_ieee802154_receive_handle_done` to notify 802.15.4 driver after the received frame is handled. Otherwise the frame buffer will not be freed for future use. diff --git a/docs/en/migration-guides/release-5.x/5.1/index.rst b/docs/en/migration-guides/release-5.x/5.1/index.rst index 4a3c4b65d7..55037853db 100644 --- a/docs/en/migration-guides/release-5.x/5.1/index.rst +++ b/docs/en/migration-guides/release-5.x/5.1/index.rst @@ -7,6 +7,7 @@ Migration from 5.0 to 5.1 :maxdepth: 1 gcc + :SOC_IEEE802154_SUPPORTED: ieee802154 peripherals storage networking diff --git a/docs/en/migration-guides/release-5.x/5.2/ieee802154.rst b/docs/en/migration-guides/release-5.x/5.2/ieee802154.rst new file mode 100644 index 0000000000..13c0f38d76 --- /dev/null +++ b/docs/en/migration-guides/release-5.x/5.2/ieee802154.rst @@ -0,0 +1,9 @@ +IEEE 802.15.4 +============= + +:link_to_translation:`zh_CN:[中文]` + +Receive Handle Done +------------------- + +User must call the function :cpp:func:`esp_ieee802154_receive_handle_done` to notify 802.15.4 driver after the received frame is handled. Otherwise the frame buffer will not be freed for future use. diff --git a/docs/en/migration-guides/release-5.x/5.2/index.rst b/docs/en/migration-guides/release-5.x/5.2/index.rst index a4634a8ddb..b8d55b1ace 100644 --- a/docs/en/migration-guides/release-5.x/5.2/index.rst +++ b/docs/en/migration-guides/release-5.x/5.2/index.rst @@ -8,6 +8,7 @@ Migration from 5.1 to 5.2 bluetooth-classic gcc + :SOC_IEEE802154_SUPPORTED: ieee802154 peripherals protocols storage diff --git a/docs/zh_CN/migration-guides/release-5.x/5.1/ieee802154.rst b/docs/zh_CN/migration-guides/release-5.x/5.1/ieee802154.rst new file mode 100644 index 0000000000..e8d5672a4d --- /dev/null +++ b/docs/zh_CN/migration-guides/release-5.x/5.1/ieee802154.rst @@ -0,0 +1,13 @@ +IEEE 802.15.4 +============= + +:link_to_translation:`en:[English]` + +Receive Handle Done +------------------- + +.. note:: + + 这个功能仅包括在 IDF v5.1.3 以及之后的发布中。 + +当收到的数据帧被处理后, 用户需要调用函数 :cpp:func:`esp_ieee802154_receive_handle_done` 通知 802.15.4 驱动层,否则这个数据空间将不会被释放。 diff --git a/docs/zh_CN/migration-guides/release-5.x/5.1/index.rst b/docs/zh_CN/migration-guides/release-5.x/5.1/index.rst index c95cac366c..53a848060a 100644 --- a/docs/zh_CN/migration-guides/release-5.x/5.1/index.rst +++ b/docs/zh_CN/migration-guides/release-5.x/5.1/index.rst @@ -7,6 +7,7 @@ :maxdepth: 1 gcc + :SOC_IEEE802154_SUPPORTED: ieee802154 peripherals storage networking diff --git a/docs/zh_CN/migration-guides/release-5.x/5.2/ieee802154.rst b/docs/zh_CN/migration-guides/release-5.x/5.2/ieee802154.rst new file mode 100644 index 0000000000..46b1fe87d1 --- /dev/null +++ b/docs/zh_CN/migration-guides/release-5.x/5.2/ieee802154.rst @@ -0,0 +1,9 @@ +IEEE 802.15.4 +============= + +:link_to_translation:`en:[English]` + +Receive Handle Done +------------------- + +当收到的数据帧被处理后, 用户需要调用函数 :cpp:func:`esp_ieee802154_receive_handle_done` 通知 802.15.4 驱动层,否则这个数据空间将不会被释放。 diff --git a/docs/zh_CN/migration-guides/release-5.x/5.2/index.rst b/docs/zh_CN/migration-guides/release-5.x/5.2/index.rst index 46f38b0d1e..acdbb5246e 100644 --- a/docs/zh_CN/migration-guides/release-5.x/5.2/index.rst +++ b/docs/zh_CN/migration-guides/release-5.x/5.2/index.rst @@ -8,6 +8,7 @@ bluetooth-classic gcc + :SOC_IEEE802154_SUPPORTED: ieee802154 peripherals protocols storage diff --git a/examples/openthread/ot_ci_function.py b/examples/openthread/ot_ci_function.py index b29b32464f..3561f4ad1d 100644 --- a/examples/openthread/ot_ci_function.py +++ b/examples/openthread/ot_ci_function.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD +# SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD # SPDX-License-Identifier: Unlicense OR CC0-1.0 # !/usr/bin/env python3 # this file defines some functions for testing cli and br under pytest framework diff --git a/examples/openthread/ot_cli/main/idf_component.yml b/examples/openthread/ot_cli/main/idf_component.yml index ea2b951115..6cb24e1008 100644 --- a/examples/openthread/ot_cli/main/idf_component.yml +++ b/examples/openthread/ot_cli/main/idf_component.yml @@ -1,7 +1,7 @@ ## IDF Component Manager Manifest File dependencies: espressif/esp_ot_cli_extension: - version: "~0.4.0" + version: "~1.0.0" idf: version: ">=4.1.0" iperf: diff --git a/examples/openthread/ot_cli/sdkconfig.defaults b/examples/openthread/ot_cli/sdkconfig.defaults index 7a1d93e740..7b724c1c89 100644 --- a/examples/openthread/ot_cli/sdkconfig.defaults +++ b/examples/openthread/ot_cli/sdkconfig.defaults @@ -33,10 +33,3 @@ CONFIG_LWIP_IPV6_NUM_ADDRESSES=8 CONFIG_LWIP_MULTICAST_PING=y CONFIG_LWIP_HOOK_IP6_SELECT_SRC_ADDR_CUSTOM=y # end of lwIP - -# -# IEEE 802.15.4 -# -CONFIG_IEEE802154_ENABLED=y -CONFIG_IEEE802154_RECEIVE_DONE_HANDLER=y -# end of IEEE 802.15.4 diff --git a/examples/openthread/ot_rcp/sdkconfig.defaults b/examples/openthread/ot_rcp/sdkconfig.defaults index 9dea0be01d..002c6f9f30 100644 --- a/examples/openthread/ot_rcp/sdkconfig.defaults +++ b/examples/openthread/ot_rcp/sdkconfig.defaults @@ -30,12 +30,6 @@ CONFIG_LOG_BOOTLOADER_LEVEL_ERROR=y CONFIG_LOG_BOOTLOADER_LEVEL_INFO=n # End of deprecated options -# -# IEEE 802.15.4 -# -CONFIG_IEEE802154_RECEIVE_DONE_HANDLER=y -# end of IEEE 802.15.4 - # # Configurations for optimizing the size of ot_rcp firmware # diff --git a/examples/openthread/pytest_otbr.py b/examples/openthread/pytest_otbr.py index 23c267e30b..2f1f103989 100644 --- a/examples/openthread/pytest_otbr.py +++ b/examples/openthread/pytest_otbr.py @@ -1,10 +1,12 @@ -# SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD +# SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD # SPDX-License-Identifier: Unlicense OR CC0-1.0 # !/usr/bin/env python3 +import copy import os.path import re +import secrets import subprocess import threading import time @@ -94,9 +96,9 @@ def test_thread_connect(dut:Tuple[IdfDut, IdfDut, IdfDut]) -> None: ocf.init_thread(br) for cli in cli_list: ocf.init_thread(cli) - br_ot_para = default_br_ot_para + br_ot_para = copy.copy(default_br_ot_para) ocf.joinThreadNetwork(br, br_ot_para) - cli_ot_para = default_cli_ot_para + cli_ot_para = copy.copy(default_cli_ot_para) cli_ot_para.dataset = ocf.getDataset(br) try: order = 0 @@ -127,12 +129,14 @@ def test_thread_connect(dut:Tuple[IdfDut, IdfDut, IdfDut]) -> None: def formBasicWiFiThreadNetwork(br:IdfDut, cli:IdfDut) -> None: ocf.init_thread(br) ocf.init_thread(cli) - ocf.joinWiFiNetwork(br, default_br_wifi_para) - ocf.joinThreadNetwork(br, default_br_ot_para) - ot_para = default_cli_ot_para - ot_para.dataset = ocf.getDataset(br) - ot_para.exaddr = '7766554433221101' - ocf.joinThreadNetwork(cli, ot_para) + otbr_wifi_para = copy.copy(default_br_wifi_para) + ocf.joinWiFiNetwork(br, otbr_wifi_para) + otbr_thread_para = copy.copy(default_br_ot_para) + ocf.joinThreadNetwork(br, otbr_thread_para) + otcli_thread_para = copy.copy(default_cli_ot_para) + otcli_thread_para.dataset = ocf.getDataset(br) + otcli_thread_para.exaddr = '7766554433221101' + ocf.joinThreadNetwork(cli, otcli_thread_para) ocf.wait(cli,10) @@ -572,6 +576,7 @@ def test_TCP_NAT64(Init_interface:bool, dut: Tuple[IdfDut, IdfDut, IdfDut]) -> N def test_ot_sleepy_device(dut: Tuple[IdfDut, IdfDut]) -> None: leader = dut[0] sleepy_device = dut[1] + fail_info = re.compile(r'Core\W*?\d\W*?register dump') try: ocf.init_thread(leader) time.sleep(3) @@ -583,13 +588,22 @@ def test_ot_sleepy_device(dut: Tuple[IdfDut, IdfDut]) -> None: leader_para.setpskc('104810e2315100afd6bc9215a6bfac53') ocf.joinThreadNetwork(leader, leader_para) ocf.wait(leader, 5) + output = sleepy_device.expect(pexpect.TIMEOUT, timeout=5) + assert not bool(fail_info.search(str(output))) ocf.clean_buffer(sleepy_device) sleepy_device.serial.hard_reset() - sleepy_device.expect('detached -> child', timeout=20) - sleepy_device.expect('PMU_SLEEP_PD_TOP: True', timeout=10) - sleepy_device.expect('PMU_SLEEP_PD_MODEM: True', timeout=20) + info = sleepy_device.expect(r'(.+)detached -> child', timeout=20)[1].decode(errors='replace') + assert not bool(fail_info.search(str(info))) + info = sleepy_device.expect(r'(.+)PMU_SLEEP_PD_TOP: True', timeout=10)[1].decode(errors='replace') + assert not bool(fail_info.search(str(info))) + info = sleepy_device.expect(r'(.+)PMU_SLEEP_PD_MODEM: True', timeout=20)[1].decode(errors='replace') + assert not bool(fail_info.search(str(info))) + output = sleepy_device.expect(pexpect.TIMEOUT, timeout=20) + assert not bool(fail_info.search(str(output))) + ocf.clean_buffer(sleepy_device) + ocf.execute_command(leader, 'factoryreset') output = sleepy_device.expect(pexpect.TIMEOUT, timeout=5) - assert 'rst:' not in str(output) and 'boot:' not in str(output) + assert not bool(fail_info.search(str(output))) finally: ocf.execute_command(leader, 'factoryreset') time.sleep(3) @@ -670,3 +684,60 @@ def test_NAT64_DNS(Init_interface:bool, dut: Tuple[IdfDut, IdfDut, IdfDut]) -> N ocf.execute_command(br, 'factoryreset') ocf.execute_command(cli, 'factoryreset') time.sleep(3) + + +# Case 13: Meshcop discovery of Border Router +@pytest.mark.supported_targets +@pytest.mark.esp32c6 +@pytest.mark.openthread_br +@pytest.mark.flaky(reruns=1, reruns_delay=1) +@pytest.mark.parametrize( + 'config, count, app_path, target', [ + ('rcp|br', 2, + f'{os.path.join(os.path.dirname(__file__), "ot_rcp")}' + f'|{os.path.join(os.path.dirname(__file__), "ot_br")}', + 'esp32c6|esp32s3'), + ], + indirect=True, +) +def test_br_meshcop(Init_interface:bool, Init_avahi:bool, dut: Tuple[IdfDut, IdfDut]) -> None: + br = dut[1] + assert Init_interface + assert Init_avahi + dut[0].serial.stop_redirect_thread() + + result = None + output_bytes = b'' + try: + ocf.init_thread(br) + br_wifi_para = copy.copy(default_br_wifi_para) + ipv4_address = ocf.joinWiFiNetwork(br, br_wifi_para)[0] + br_thread_para = copy.copy(default_br_ot_para) + networkname = 'OTCI-' + str(secrets.token_hex(1)) + br_thread_para.setnetworkname(networkname) + ocf.joinThreadNetwork(br, br_thread_para) + ocf.wait(br, 10) + assert ocf.is_joined_wifi_network(br) + command = 'timeout 3 avahi-browse -r _meshcop._udp' + try: + result = subprocess.run(command, capture_output=True, check=True, shell=True) + if result: + output_bytes = result.stdout + except subprocess.CalledProcessError as e: + output_bytes = e.stdout + finally: + print('out_bytes: ', output_bytes) + output_str = str(output_bytes) + print('out_str: ', output_str) + + assert 'hostname = [esp-ot-br.local]' in str(output_str) + assert ('address = [' + ipv4_address + ']') in str(output_str) + assert 'dn=DefaultDomain' in str(output_str) + assert 'tv=1.3.0' in str(output_str) + assert ('nn=' + networkname) in str(output_str) + assert 'mn=BorderRouter' in str(output_str) + assert 'vn=OpenThread' in str(output_str) + assert 'rv=1' in str(output_str) + finally: + ocf.execute_command(br, 'factoryreset') + time.sleep(3) diff --git a/examples/zigbee/esp_zigbee_gateway/README.md b/examples/zigbee/esp_zigbee_gateway/README.md index 40aa4be56b..1a6fadfe8f 100644 --- a/examples/zigbee/esp_zigbee_gateway/README.md +++ b/examples/zigbee/esp_zigbee_gateway/README.md @@ -54,7 +54,7 @@ I (660) ESP_ZB_GATEWAY: status: -1 I (670) ESP_ZB_GATEWAY: Zigbee stack initialized I (680) ESP_ZB_GATEWAY: Zigbee rcp device booted I (1280) ESP_ZB_GATEWAY: Start network formation -I (3060) ESP_ZB_GATEWAY: Formed network successfully (ieee extended address: f9:54:2d:01:a0:03:f7:84, PAN ID: 0x8651) +I (3060) ESP_ZB_GATEWAY: Formed network successfully (Extended PAN ID: f9:54:2d:01:a0:03:f7:84, PAN ID: 0x8651, Channel:13, Short Address: 0x0000) I (4060) ESP_ZB_GATEWAY: status: 0 I (4400) ESP_ZB_GATEWAY: Network steering started ``` diff --git a/examples/zigbee/esp_zigbee_gateway/main/esp_zigbee_gateway.c b/examples/zigbee/esp_zigbee_gateway/main/esp_zigbee_gateway.c index 4c034b2e05..2da5f23226 100644 --- a/examples/zigbee/esp_zigbee_gateway/main/esp_zigbee_gateway.c +++ b/examples/zigbee/esp_zigbee_gateway/main/esp_zigbee_gateway.c @@ -1,38 +1,15 @@ /* - * SPDX-FileCopyrightText: 2021-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: LicenseRef-Included * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: + * Zigbee Gateway Example * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. + * This example code is in the Public Domain (or CC0 licensed, at your option.) * - * 2. Redistributions in binary form, except as embedded into a Espressif Systems - * integrated circuit in a product or a software update for such product, - * must reproduce the above copyright notice, this list of conditions and - * the following disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * 3. Neither the name of the copyright holder nor the names of its contributors - * may be used to endorse or promote products derived from this software without - * specific prior written permission. - * - * 4. Any software provided in binary form under this license must not be reverse - * engineered, decompiled, modified and/or disassembled. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. + * Unless required by applicable law or agreed to in writing, this + * software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. */ #include #include @@ -108,8 +85,13 @@ void esp_zb_app_signal_handler(esp_zb_app_signal_t *signal_struct) case ESP_ZB_BDB_SIGNAL_DEVICE_FIRST_START: case ESP_ZB_BDB_SIGNAL_DEVICE_REBOOT: if (err_status == ESP_OK) { - ESP_LOGI(TAG, "Start network formation"); - esp_zb_bdb_start_top_level_commissioning(ESP_ZB_BDB_MODE_NETWORK_FORMATION); + ESP_LOGI(TAG, "Device started up in %s factory-reset mode", esp_zb_bdb_is_factory_new() ? "" : "non"); + if (esp_zb_bdb_is_factory_new()) { + ESP_LOGI(TAG, "Start network formation"); + esp_zb_bdb_start_top_level_commissioning(ESP_ZB_BDB_MODE_NETWORK_FORMATION); + } else { + ESP_LOGI(TAG, "Device rebooted"); + } } else { ESP_LOGE(TAG, "Failed to initialize Zigbee stack (status: %s)", esp_err_to_name(err_status)); } @@ -118,10 +100,10 @@ void esp_zb_app_signal_handler(esp_zb_app_signal_t *signal_struct) if (err_status == ESP_OK) { esp_zb_ieee_addr_t ieee_address; esp_zb_get_long_address(ieee_address); - ESP_LOGI(TAG, "Formed network successfully (ieee_address: %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x, PAN ID: 0x%04hx, Channel:%d)", + ESP_LOGI(TAG, "Formed network successfully (Extended PAN ID: %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x, PAN ID: 0x%04hx, Channel:%d, Short Address: 0x%04hx)", ieee_address[7], ieee_address[6], ieee_address[5], ieee_address[4], ieee_address[3], ieee_address[2], ieee_address[1], ieee_address[0], - esp_zb_get_pan_id(), esp_zb_get_current_channel()); + esp_zb_get_pan_id(), esp_zb_get_current_channel(), esp_zb_get_short_address()); esp_zb_bdb_start_top_level_commissioning(ESP_ZB_BDB_MODE_NETWORK_STEERING); } else { ESP_LOGI(TAG, "Restart network formation (status: %s)", esp_err_to_name(err_status)); @@ -137,6 +119,15 @@ void esp_zb_app_signal_handler(esp_zb_app_signal_t *signal_struct) dev_annce_params = (esp_zb_zdo_signal_device_annce_params_t *)esp_zb_app_signal_get_params(p_sg_p); ESP_LOGI(TAG, "New device commissioned or rejoined (short: 0x%04hx)", dev_annce_params->device_short_addr); break; + case ESP_ZB_NWK_SIGNAL_PERMIT_JOIN_STATUS: + if (err_status == ESP_OK) { + if (*(uint8_t *)esp_zb_app_signal_get_params(p_sg_p)) { + ESP_LOGI(TAG, "Network(0x%04hx) is open for %d seconds", esp_zb_get_pan_id(), *(uint8_t *)esp_zb_app_signal_get_params(p_sg_p)); + } else { + ESP_LOGW(TAG, "Network(0x%04hx) closed, devices joining not allowed.", esp_zb_get_pan_id()); + } + } + break; default: ESP_LOGI(TAG, "ZDO signal: %s (0x%x), status: %s", esp_zb_zdo_signal_to_string(sig_type), sig_type, esp_err_to_name(err_status)); @@ -146,10 +137,9 @@ void esp_zb_app_signal_handler(esp_zb_app_signal_t *signal_struct) static void esp_zb_task(void *pvParameters) { - /* initialize Zigbee stack with Zigbee coordinator config */ + /* initialize Zigbee stack */ esp_zb_cfg_t zb_nwk_cfg = ESP_ZB_ZC_CONFIG(); esp_zb_init(&zb_nwk_cfg); - /* initiate Zigbee Stack start without zb_send_no_autostart_signal auto-start */ esp_zb_set_primary_network_channel_set(ESP_ZB_PRIMARY_CHANNEL_MASK); ESP_ERROR_CHECK(esp_zb_start(false)); esp_zb_main_loop_iteration(); @@ -161,7 +151,7 @@ void app_main(void) .radio_config = ESP_ZB_DEFAULT_RADIO_CONFIG(), .host_config = ESP_ZB_DEFAULT_HOST_CONFIG(), }; - /* load Zigbee gateway platform config to initialization */ + ESP_ERROR_CHECK(esp_zb_platform_config(&config)); ESP_ERROR_CHECK(nvs_flash_init()); ESP_ERROR_CHECK(esp_netif_init()); diff --git a/examples/zigbee/esp_zigbee_gateway/main/esp_zigbee_gateway.h b/examples/zigbee/esp_zigbee_gateway/main/esp_zigbee_gateway.h index d73745035a..31cba49590 100644 --- a/examples/zigbee/esp_zigbee_gateway/main/esp_zigbee_gateway.h +++ b/examples/zigbee/esp_zigbee_gateway/main/esp_zigbee_gateway.h @@ -1,38 +1,15 @@ /* - * SPDX-FileCopyrightText: 2021-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: LicenseRef-Included * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: + * Zigbee Gateway Example * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. + * This example code is in the Public Domain (or CC0 licensed, at your option.) * - * 2. Redistributions in binary form, except as embedded into a Espressif Systems - * integrated circuit in a product or a software update for such product, - * must reproduce the above copyright notice, this list of conditions and - * the following disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * 3. Neither the name of the copyright holder nor the names of its contributors - * may be used to endorse or promote products derived from this software without - * specific prior written permission. - * - * 4. Any software provided in binary form under this license must not be reverse - * engineered, decompiled, modified and/or disassembled. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. + * Unless required by applicable law or agreed to in writing, this + * software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. */ #include "esp_err.h" diff --git a/examples/zigbee/esp_zigbee_gateway/main/idf_component.yml b/examples/zigbee/esp_zigbee_gateway/main/idf_component.yml index aa8c8ed77d..5346a089ab 100644 --- a/examples/zigbee/esp_zigbee_gateway/main/idf_component.yml +++ b/examples/zigbee/esp_zigbee_gateway/main/idf_component.yml @@ -1,7 +1,7 @@ ## IDF Component Manager Manifest File dependencies: - espressif/esp-zboss-lib: "~0.7.0" - espressif/esp-zigbee-lib: "~0.9.0" + espressif/esp-zboss-lib: "1.0.9" + espressif/esp-zigbee-lib: "1.0.9" ## Required IDF version idf: version: ">=5.0.0" diff --git a/examples/zigbee/esp_zigbee_gateway/partitions.csv b/examples/zigbee/esp_zigbee_gateway/partitions.csv index c6e1d03bfa..055152f11a 100644 --- a/examples/zigbee/esp_zigbee_gateway/partitions.csv +++ b/examples/zigbee/esp_zigbee_gateway/partitions.csv @@ -2,6 +2,7 @@ # Note: if you have increased the bootloader size, make sure to update the offsets to avoid overlap nvs, data, nvs, 0x9000, 0x6000, phy_init, data, phy, 0xf000, 0x1000, -factory, app, factory, 0x10000, 1150K, -zb_storage, data, fat, , 16K, -zb_fct, data, fat, , 1K, +factory, app, factory, 0x10000, 1400K, +zb_storage, data, fat, 0x16e000,16K, +zb_fct, data, fat, 0x172000,1K, +rcp_fw, data, spiffs, 0x173000,500k, diff --git a/examples/zigbee/esp_zigbee_gateway/sdkconfig.defaults b/examples/zigbee/esp_zigbee_gateway/sdkconfig.defaults index 6e62dede3e..25d3d36dcc 100644 --- a/examples/zigbee/esp_zigbee_gateway/sdkconfig.defaults +++ b/examples/zigbee/esp_zigbee_gateway/sdkconfig.defaults @@ -22,8 +22,7 @@ CONFIG_MBEDTLS_KEY_EXCHANGE_ECJPAKE=y CONFIG_MBEDTLS_ECJPAKE_C=y # end of mbedTLS -CONFIG_ESP_TASK_WDT_CHECK_IDLE_TASK_CPU0=n -CONFIG_ESP_TASK_WDT_CHECK_IDLE_TASK_CPU1=n +CONFIG_ESP_SYSTEM_EVENT_TASK_STACK_SIZE=4096 # # Zboss diff --git a/examples/zigbee/esp_zigbee_rcp/main/esp_zigbee_rcp.c b/examples/zigbee/esp_zigbee_rcp/main/esp_zigbee_rcp.c index d264f25e43..ff01495cde 100644 --- a/examples/zigbee/esp_zigbee_rcp/main/esp_zigbee_rcp.c +++ b/examples/zigbee/esp_zigbee_rcp/main/esp_zigbee_rcp.c @@ -1,38 +1,15 @@ /* - * SPDX-FileCopyrightText: 2021-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: LicenseRef-Included * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: + * Zigbee RCP Example * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. + * This example code is in the Public Domain (or CC0 licensed, at your option.) * - * 2. Redistributions in binary form, except as embedded into a Espressif Systems - * integrated circuit in a product or a software update for such product, - * must reproduce the above copyright notice, this list of conditions and - * the following disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * 3. Neither the name of the copyright holder nor the names of its contributors - * may be used to endorse or promote products derived from this software without - * specific prior written permission. - * - * 4. Any software provided in binary form under this license must not be reverse - * engineered, decompiled, modified and/or disassembled. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. + * Unless required by applicable law or agreed to in writing, this + * software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. */ #include "freertos/FreeRTOS.h" diff --git a/examples/zigbee/esp_zigbee_rcp/main/esp_zigbee_rcp.h b/examples/zigbee/esp_zigbee_rcp/main/esp_zigbee_rcp.h index 50f708a541..68050036c3 100644 --- a/examples/zigbee/esp_zigbee_rcp/main/esp_zigbee_rcp.h +++ b/examples/zigbee/esp_zigbee_rcp/main/esp_zigbee_rcp.h @@ -1,38 +1,15 @@ /* - * SPDX-FileCopyrightText: 2021-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: LicenseRef-Included * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: + * Zigbee RCP Example * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. + * This example code is in the Public Domain (or CC0 licensed, at your option.) * - * 2. Redistributions in binary form, except as embedded into a Espressif Systems - * integrated circuit in a product or a software update for such product, - * must reproduce the above copyright notice, this list of conditions and - * the following disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * 3. Neither the name of the copyright holder nor the names of its contributors - * may be used to endorse or promote products derived from this software without - * specific prior written permission. - * - * 4. Any software provided in binary form under this license must not be reverse - * engineered, decompiled, modified and/or disassembled. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. + * Unless required by applicable law or agreed to in writing, this + * software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. */ #include "esp_zigbee_core.h" diff --git a/examples/zigbee/esp_zigbee_rcp/main/idf_component.yml b/examples/zigbee/esp_zigbee_rcp/main/idf_component.yml index aa99452a45..c186c3c8ca 100644 --- a/examples/zigbee/esp_zigbee_rcp/main/idf_component.yml +++ b/examples/zigbee/esp_zigbee_rcp/main/idf_component.yml @@ -1,7 +1,7 @@ ## IDF Component Manager Manifest File dependencies: - espressif/esp-zboss-lib: "~0.7.0" - espressif/esp-zigbee-lib: "~0.9.0" + espressif/esp-zboss-lib: "1.0.9" + espressif/esp-zigbee-lib: "1.0.9" ## Required IDF version idf: version: ">=5.0.0" diff --git a/examples/zigbee/esp_zigbee_rcp/partitions.csv b/examples/zigbee/esp_zigbee_rcp/partitions.csv index 43c1fae4b5..e72a9f10a2 100644 --- a/examples/zigbee/esp_zigbee_rcp/partitions.csv +++ b/examples/zigbee/esp_zigbee_rcp/partitions.csv @@ -2,5 +2,5 @@ # Note: if you have increased the bootloader size, make sure to update the offsets to avoid overlap nvs, data, nvs, 0x9000, 0x6000, phy_init, data, phy, 0xf000, 0x1000, -factory, app, factory, 0x10000, 550K, +factory, app, factory, 0x10000, 548K, zb_storage, data, fat, 0x9a000, 16K, diff --git a/examples/zigbee/esp_zigbee_rcp/sdkconfig.defaults b/examples/zigbee/esp_zigbee_rcp/sdkconfig.defaults index 693d709e85..b337975d5c 100644 --- a/examples/zigbee/esp_zigbee_rcp/sdkconfig.defaults +++ b/examples/zigbee/esp_zigbee_rcp/sdkconfig.defaults @@ -1,7 +1,7 @@ # # Partition Table # -CONFIG_PARTITION_TABLE_SINGLE_APP=y +CONFIG_PARTITION_TABLE_CUSTOM=y CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv" CONFIG_PARTITION_TABLE_FILENAME="partitions.csv" CONFIG_PARTITION_TABLE_OFFSET=0x8000 diff --git a/examples/zigbee/light_sample/HA_on_off_light/README.md b/examples/zigbee/light_sample/HA_on_off_light/README.md index 28eaf8d327..a22052d608 100644 --- a/examples/zigbee/light_sample/HA_on_off_light/README.md +++ b/examples/zigbee/light_sample/HA_on_off_light/README.md @@ -11,7 +11,7 @@ The ESP Zigbee SDK provides more examples and tools for productization: ## Hardware Required -* One development board with ESP32-H2 SoC acting as Zigbee end device (loaded with HA_on_off_light example) +* One development board with ESP32-H2 SoC acting as Zigbee end-device (loaded with HA_on_off_light example) * A USB cable for power supply and programming * Choose another ESP32-H2 as Zigbee coordinator (see [HA_on_off_switch example](../HA_on_off_switch)) @@ -33,18 +33,25 @@ Build the project, flash it to the board, and start the monitor tool to view the As you run the example, you will see the following log: -light bulb: ``` -I (918) ESP_ZB_LIGHT: status: 255 -I (901) ESP_ZB_LIGHT: Zigbee stack initialized -I (901) ESP_ZB_LIGHT: Start network steering -I (2611) ESP_ZB_LIGHT: Joined network successfully (Extended PAN ID: aa:98:48:01:a0:03:f7:84, PAN ID: 0x0e8b) -I (5651) ESP_ZB_LIGHT: on/off light set to 1 -I (6631) ESP_ZB_LIGHT: on/off light set to 0 -I (7331) ESP_ZB_LIGHT: on/off light set to 1 -I (8251) ESP_ZB_LIGHT: on/off light set to 0 -I (9111) ESP_ZB_LIGHT: on/off light set to 1 -I (9671) ESP_ZB_LIGHT: on/off light set to 0 +I (394) main_task: Calling app_main() +I (404) gpio: GPIO[8]| InputEn: 0| OutputEn: 1| OpenDrain: 0| Pullup: 1| Pulldown: 0| Intr:0 +I (404) phy_init: phy_version 220,2dbbbe7,Sep 25 2023,20:39:25 +I (464) phy: libbtbb version: 90c587c, Sep 25 2023, 20:39:57 +I (474) ESP_ZB_COLOR_DIMM_LIGHT: ZDO signal: ZDO Config Ready (0x17), status: ESP_FAIL +I (474) ESP_ZB_COLOR_DIMM_LIGHT: Zigbee stack initialized +I (484) ESP_ZB_COLOR_DIMM_LIGHT: Start network steering +I (484) main_task: Returned from app_main() +I (9614) ESP_ZB_COLOR_DIMM_LIGHT: ZDO signal: NWK Permit Join (0x36), status: ESP_OK +I (9834) ESP_ZB_COLOR_DIMM_LIGHT: ZDO signal: NWK Permit Join (0x36), status: ESP_OK +I (9834) ESP_ZB_COLOR_DIMM_LIGHT: Joined network successfully (Extended PAN ID: 60:55:f9:00:00:f6:07:b4, PAN ID: 0x2a74, Channel:13) +I (32944) ESP_ZB_COLOR_DIMM_LIGHT: Received message: endpoint(10), cluster(0x6), attribute(0x0), data size(1) +I (32944) ESP_ZB_COLOR_DIMM_LIGHT: Light sets to On +I (33984) ESP_ZB_COLOR_DIMM_LIGHT: Received message: endpoint(10), cluster(0x6), attribute(0x0), data size(1) +I (33984) ESP_ZB_COLOR_DIMM_LIGHT: Light sets to Off +I (35304) ESP_ZB_COLOR_DIMM_LIGHT: ZDO signal: NLME Status Indication (0x32), status: ESP_OK +I (35534) ESP_ZB_COLOR_DIMM_LIGHT: Received message: endpoint(10), cluster(0x6), attribute(0x0), data size(1) +I (35534) ESP_ZB_COLOR_DIMM_LIGHT: Light sets to On ``` ## Light Control Functions diff --git a/examples/zigbee/light_sample/HA_on_off_light/main/esp_zb_light.c b/examples/zigbee/light_sample/HA_on_off_light/main/esp_zb_light.c index e2fef6a8fa..36463fcbfd 100644 --- a/examples/zigbee/light_sample/HA_on_off_light/main/esp_zb_light.c +++ b/examples/zigbee/light_sample/HA_on_off_light/main/esp_zb_light.c @@ -1,38 +1,15 @@ /* - * SPDX-FileCopyrightText: 2021-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: LicenseRef-Included * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: + * Zigbee HA_on_off_light Example * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. + * This example code is in the Public Domain (or CC0 licensed, at your option.) * - * 2. Redistributions in binary form, except as embedded into a Espressif Systems - * integrated circuit in a product or a software update for such product, - * must reproduce the above copyright notice, this list of conditions and - * the following disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * 3. Neither the name of the copyright holder nor the names of its contributors - * may be used to endorse or promote products derived from this software without - * specific prior written permission. - * - * 4. Any software provided in binary form under this license must not be reverse - * engineered, decompiled, modified and/or disassembled. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. + * Unless required by applicable law or agreed to in writing, this + * software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. */ #include "freertos/FreeRTOS.h" @@ -67,8 +44,13 @@ void esp_zb_app_signal_handler(esp_zb_app_signal_t *signal_struct) case ESP_ZB_BDB_SIGNAL_DEVICE_FIRST_START: case ESP_ZB_BDB_SIGNAL_DEVICE_REBOOT: if (err_status == ESP_OK) { - ESP_LOGI(TAG, "Start network steering"); - esp_zb_bdb_start_top_level_commissioning(ESP_ZB_BDB_MODE_NETWORK_STEERING); + ESP_LOGI(TAG, "Device started up in %s factory-reset mode", esp_zb_bdb_is_factory_new() ? "" : "non"); + if (esp_zb_bdb_is_factory_new()) { + ESP_LOGI(TAG, "Start network steering"); + esp_zb_bdb_start_top_level_commissioning(ESP_ZB_BDB_MODE_NETWORK_STEERING); + } else { + ESP_LOGI(TAG, "Device rebooted"); + } } else { /* commissioning failed */ ESP_LOGW(TAG, "Failed to initialize Zigbee stack (status: %s)", esp_err_to_name(err_status)); @@ -78,10 +60,10 @@ void esp_zb_app_signal_handler(esp_zb_app_signal_t *signal_struct) if (err_status == ESP_OK) { esp_zb_ieee_addr_t extended_pan_id; esp_zb_get_extended_pan_id(extended_pan_id); - ESP_LOGI(TAG, "Joined network successfully (Extended PAN ID: %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x, PAN ID: 0x%04hx, Channel:%d)", + ESP_LOGI(TAG, "Joined network successfully (Extended PAN ID: %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x, PAN ID: 0x%04hx, Channel:%d, Short Address: 0x%04hx)", extended_pan_id[7], extended_pan_id[6], extended_pan_id[5], extended_pan_id[4], extended_pan_id[3], extended_pan_id[2], extended_pan_id[1], extended_pan_id[0], - esp_zb_get_pan_id(), esp_zb_get_current_channel()); + esp_zb_get_pan_id(), esp_zb_get_current_channel(), esp_zb_get_short_address()); } else { ESP_LOGI(TAG, "Network steering was not successful (status: %s)", esp_err_to_name(err_status)); esp_zb_scheduler_alarm((esp_zb_callback_t)bdb_start_top_level_commissioning_cb, ESP_ZB_BDB_MODE_NETWORK_STEERING, 1000); @@ -100,14 +82,13 @@ static esp_err_t zb_attribute_handler(const esp_zb_zcl_set_attr_value_message_t bool light_state = 0; ESP_RETURN_ON_FALSE(message, ESP_FAIL, TAG, "Empty message"); - ESP_RETURN_ON_FALSE(message->info.status == ESP_ZB_ZCL_STATUS_SUCCESS, ESP_ERR_INVALID_ARG, TAG, - "Received message: error status(%d)", message->info.status); - ESP_LOGI(TAG, "Received message: endpoint(%d), cluster(0x%x), attribute(0x%x), data size(%d)", - message->info.dst_endpoint, message->info.cluster, message->attribute.id, message->attribute.data.size); + ESP_RETURN_ON_FALSE(message->info.status == ESP_ZB_ZCL_STATUS_SUCCESS, ESP_ERR_INVALID_ARG, TAG, "Received message: error status(%d)", + message->info.status); + ESP_LOGI(TAG, "Received message: endpoint(%d), cluster(0x%x), attribute(0x%x), data size(%d)", message->info.dst_endpoint, message->info.cluster, + message->attribute.id, message->attribute.data.size); if (message->info.dst_endpoint == HA_ESP_LIGHT_ENDPOINT) { if (message->info.cluster == ESP_ZB_ZCL_CLUSTER_ID_ON_OFF) { - if (message->attribute.id == ESP_ZB_ZCL_ATTR_ON_OFF_ON_OFF_ID && - message->attribute.data.type == ESP_ZB_ZCL_ATTR_TYPE_BOOL) { + if (message->attribute.id == ESP_ZB_ZCL_ATTR_ON_OFF_ON_OFF_ID && message->attribute.data.type == ESP_ZB_ZCL_ATTR_TYPE_BOOL) { light_state = message->attribute.data.value ? *(bool *)message->attribute.data.value : light_state; ESP_LOGI(TAG, "Light sets to %s", light_state ? "On" : "Off"); light_driver_set_power(light_state); diff --git a/examples/zigbee/light_sample/HA_on_off_light/main/esp_zb_light.h b/examples/zigbee/light_sample/HA_on_off_light/main/esp_zb_light.h index 7885b50009..571be5c8a5 100644 --- a/examples/zigbee/light_sample/HA_on_off_light/main/esp_zb_light.h +++ b/examples/zigbee/light_sample/HA_on_off_light/main/esp_zb_light.h @@ -1,49 +1,27 @@ /* - * SPDX-FileCopyrightText: 2021-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: LicenseRef-Included * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: + * Zigbee HA_on_off_light Example * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. + * This example code is in the Public Domain (or CC0 licensed, at your option.) * - * 2. Redistributions in binary form, except as embedded into a Espressif Systems - * integrated circuit in a product or a software update for such product, - * must reproduce the above copyright notice, this list of conditions and - * the following disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * 3. Neither the name of the copyright holder nor the names of its contributors - * may be used to endorse or promote products derived from this software without - * specific prior written permission. - * - * 4. Any software provided in binary form under this license must not be reverse - * engineered, decompiled, modified and/or disassembled. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. + * Unless required by applicable law or agreed to in writing, this + * software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. */ #include "esp_zigbee_core.h" #include "light_driver.h" /* Zigbee configuration */ -#define INSTALLCODE_POLICY_ENABLE false /* enable the install code policy for security */ +#define INSTALLCODE_POLICY_ENABLE false /* enable the install code policy for security */ #define ED_AGING_TIMEOUT ESP_ZB_ED_AGING_TIMEOUT_64MIN #define ED_KEEP_ALIVE 3000 /* 3000 millisecond */ -#define HA_ESP_LIGHT_ENDPOINT 10 /* esp light bulb device endpoint, used to process light controlling commands */ +#define HA_ESP_LIGHT_ENDPOINT 10 /* esp light bulb device endpoint, used to process light controlling commands */ #define ESP_ZB_PRIMARY_CHANNEL_MASK ESP_ZB_TRANSCEIVER_ALL_CHANNELS_MASK /* Zigbee primary channel mask use in the example */ + #define ESP_ZB_ZED_CONFIG() \ { \ .esp_zb_role = ESP_ZB_DEVICE_TYPE_ED, \ diff --git a/examples/zigbee/light_sample/HA_on_off_light/main/idf_component.yml b/examples/zigbee/light_sample/HA_on_off_light/main/idf_component.yml index 0fb287d698..8578e73e67 100644 --- a/examples/zigbee/light_sample/HA_on_off_light/main/idf_component.yml +++ b/examples/zigbee/light_sample/HA_on_off_light/main/idf_component.yml @@ -1,7 +1,7 @@ ## IDF Component Manager Manifest File dependencies: - espressif/esp-zigbee-lib: "~0.9.0" - espressif/esp-zboss-lib: "~0.7.0" + espressif/esp-zboss-lib: "1.0.9" + espressif/esp-zigbee-lib: "1.0.9" espressif/led_strip: "~2.0.0" ## Required IDF version idf: diff --git a/examples/zigbee/light_sample/HA_on_off_light/partitions.csv b/examples/zigbee/light_sample/HA_on_off_light/partitions.csv index 24bb3132a4..a56c0be780 100644 --- a/examples/zigbee/light_sample/HA_on_off_light/partitions.csv +++ b/examples/zigbee/light_sample/HA_on_off_light/partitions.csv @@ -2,6 +2,6 @@ # Note: if you have increased the bootloader size, make sure to update the offsets to avoid overlap nvs, data, nvs, 0x9000, 0x6000, phy_init, data, phy, 0xf000, 0x1000, -factory, app, factory, 0x10000, 650K, -zb_storage, data, fat, 0xb3000, 16K, -zb_fct, data, fat, 0xb7000, 1K, +factory, app, factory, 0x10000, 900K, +zb_storage, data, fat, 0xf1000, 16K, +zb_fct, data, fat, 0xf5000, 1K, diff --git a/examples/zigbee/light_sample/HA_on_off_light/sdkconfig.defaults b/examples/zigbee/light_sample/HA_on_off_light/sdkconfig.defaults index 6099bd9436..51a266bdd0 100644 --- a/examples/zigbee/light_sample/HA_on_off_light/sdkconfig.defaults +++ b/examples/zigbee/light_sample/HA_on_off_light/sdkconfig.defaults @@ -22,8 +22,6 @@ CONFIG_MBEDTLS_KEY_EXCHANGE_ECJPAKE=y CONFIG_MBEDTLS_ECJPAKE_C=y # end of mbedTLS -CONFIG_ESP_TASK_WDT_CHECK_IDLE_TASK_CPU0=n - # # Zboss # diff --git a/examples/zigbee/light_sample/HA_on_off_switch/README.md b/examples/zigbee/light_sample/HA_on_off_switch/README.md index 2b5ffc21e1..b02dc682ec 100644 --- a/examples/zigbee/light_sample/HA_on_off_switch/README.md +++ b/examples/zigbee/light_sample/HA_on_off_switch/README.md @@ -33,30 +33,32 @@ Build the project, flash it to the board, and start the monitor tool to view the As you run the example, you will see the following log: -light switch: ``` -I (318) gpio: GPIO[9]| InputEn: 1| OutputEn: 0| OpenDrain: 0| Pullup: 1| Pulldown: 0| Intr:2 -I (328) system_api: Base MAC address is not set -I (328) system_api: read default base MAC address from EFUSE -I (408) phy: libbtbb version: 6c47ec3, Mar 16 2022, 18:54:24 -I (408) phy: phy_version: 101, bb2a234, Mar 16 2022, 18:54:11 -I (818) ESP_ZB_ON_OFF_SWITCH: status: 255 -I (818) ESP_ZB_ON_OFF_SWITCH: Zigbee stack initialized -I (818) ESP_ZB_ON_OFF_SWITCH: Start network formation -I (1318) ESP_ZB_ON_OFF_SWITCH: Formed network successfully (Extended PAN ID: ff:fc:7c:c0:f0:bd:97:10, PAN ID: 0x88e7) -I (1778) ESP_ZB_ON_OFF_SWITCH: status: 0 -I (5528) ESP_ZB_ON_OFF_SWITCH: status: 0 -I (6038) ESP_ZB_ON_OFF_SWITCH: status: 0 -I (6068) ESP_ZB_ON_OFF_SWITCH: New device commissioned or rejoined (short: 0x2878) -I (6098) ESP_ZB_ON_OFF_SWITCH: User find cb: address:0x2878, endpoint:10 -I (6638) ESP_ZB_ON_OFF_SWITCH: status: 0 -I (6678) ESP_ZB_ON_OFF_SWITCH: status: 0 -I (8168) ESP_ZB_ON_OFF_SWITCH: send move to on_off toggle command -I (8898) ESP_ZB_ON_OFF_SWITCH: send move to on_off toggle command -I (9458) ESP_ZB_ON_OFF_SWITCH: send move to on_off toggle command -I (10088) ESP_ZB_ON_OFF_SWITCH: send move to on_off toggle command -I (10588) ESP_ZB_ON_OFF_SWITCH: send move to on_off toggle command -I (11098) ESP_ZB_ON_OFF_SWITCH: send move to on_off toggle command +I (388) main_task: Calling app_main() +I (398) gpio: GPIO[9]| InputEn: 1| OutputEn: 0| OpenDrain: 0| Pullup: 1| Pulldown: 0| Intr:2 +I (398) phy_init: phy_version 220,2dbbbe7,Sep 25 2023,20:39:25 +I (478) phy: libbtbb version: 90c587c, Sep 25 2023, 20:39:57 +I (488) ESP_ZB_ON_OFF_SWITCH: ZDO signal: ZDO Config Ready (0x17), status: ESP_FAIL +I (488) ESP_ZB_ON_OFF_SWITCH: Zigbee stack initialized +I (488) ESP_ZB_ON_OFF_SWITCH: Start network formation +I (498) main_task: Returned from app_main() +I (998) ESP_ZB_ON_OFF_SWITCH: ZDO signal: NWK Permit Join (0x36), status: ESP_OK +I (998) ESP_ZB_ON_OFF_SWITCH: Formed network successfully (Extended PAN ID: 60:55:f9:00:00:f6:07:b4, PAN ID: 0x2a74, Channel:13) +I (1468) ESP_ZB_ON_OFF_SWITCH: ZDO signal: NWK Permit Join (0x36), status: ESP_OK +I (1468) ESP_ZB_ON_OFF_SWITCH: Network steering started +I (14228) ESP_ZB_ON_OFF_SWITCH: ZDO signal: NWK Device Associated (0x12), status: ESP_OK +I (14728) ESP_ZB_ON_OFF_SWITCH: ZDO signal: ZDO Device Update (0x30), status: ESP_OK +I (14788) ESP_ZB_ON_OFF_SWITCH: New device commissioned or rejoined (short: 0xe399) +I (14858) ESP_ZB_ON_OFF_SWITCH: Found light +I (14858) ESP_ZB_ON_OFF_SWITCH: Try to bind On/Off +I (14858) ESP_ZB_ON_OFF_SWITCH: Bound successfully! +I (14858) ESP_ZB_ON_OFF_SWITCH: The light originating from address(0xe399) on endpoint(10) +I (15338) ESP_ZB_ON_OFF_SWITCH: ZDO signal: ZDO Device Authorized (0x2f), status: ESP_OK +I (15408) ESP_ZB_ON_OFF_SWITCH: ZDO signal: NWK Permit Join (0x36), status: ESP_OK +I (35838) ESP_ZB_ON_OFF_SWITCH: ZDO signal: NLME Status Indication (0x32), status: ESP_OK +I (38548) ESP_ZB_ON_OFF_SWITCH: Send 'on_off toggle' command +I (39598) ESP_ZB_ON_OFF_SWITCH: Send 'on_off toggle' command +I (41148) ESP_ZB_ON_OFF_SWITCH: Send 'on_off toggle' command ``` ## Light Control Functions diff --git a/examples/zigbee/light_sample/HA_on_off_switch/main/esp_zb_switch.c b/examples/zigbee/light_sample/HA_on_off_switch/main/esp_zb_switch.c index 2fdaa82172..d961c6bff0 100644 --- a/examples/zigbee/light_sample/HA_on_off_switch/main/esp_zb_switch.c +++ b/examples/zigbee/light_sample/HA_on_off_switch/main/esp_zb_switch.c @@ -1,38 +1,15 @@ /* - * SPDX-FileCopyrightText: 2021-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: LicenseRef-Included * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: + * Zigbee HA_on_off_switch Example * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. + * This example code is in the Public Domain (or CC0 licensed, at your option.) * - * 2. Redistributions in binary form, except as embedded into a Espressif Systems - * integrated circuit in a product or a software update for such product, - * must reproduce the above copyright notice, this list of conditions and - * the following disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * 3. Neither the name of the copyright holder nor the names of its contributors - * may be used to endorse or promote products derived from this software without - * specific prior written permission. - * - * 4. Any software provided in binary form under this license must not be reverse - * engineered, decompiled, modified and/or disassembled. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. + * Unless required by applicable law or agreed to in writing, this + * software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. */ #include "string.h" @@ -82,8 +59,7 @@ static void bind_cb(esp_zb_zdp_status_t zdo_status, void *user_ctx) ESP_LOGI(TAG, "Bound successfully!"); if (user_ctx) { light_bulb_device_params_t *light = (light_bulb_device_params_t *)user_ctx; - ESP_LOGI(TAG, "The light originating from address(0x%x) on endpoint(%d)", light->short_addr, - light->endpoint); + ESP_LOGI(TAG, "The light originating from address(0x%x) on endpoint(%d)", light->short_addr, light->endpoint); free(light); } } @@ -124,8 +100,13 @@ void esp_zb_app_signal_handler(esp_zb_app_signal_t *signal_struct) case ESP_ZB_BDB_SIGNAL_DEVICE_FIRST_START: case ESP_ZB_BDB_SIGNAL_DEVICE_REBOOT: if (err_status == ESP_OK) { - ESP_LOGI(TAG, "Start network formation"); - esp_zb_bdb_start_top_level_commissioning(ESP_ZB_BDB_MODE_NETWORK_FORMATION); + ESP_LOGI(TAG, "Device started up in %s factory-reset mode", esp_zb_bdb_is_factory_new() ? "" : "non"); + if (esp_zb_bdb_is_factory_new()) { + ESP_LOGI(TAG, "Start network formation"); + esp_zb_bdb_start_top_level_commissioning(ESP_ZB_BDB_MODE_NETWORK_FORMATION); + } else { + ESP_LOGI(TAG, "Device rebooted"); + } } else { ESP_LOGE(TAG, "Failed to initialize Zigbee stack (status: %s)", esp_err_to_name(err_status)); } @@ -134,10 +115,10 @@ void esp_zb_app_signal_handler(esp_zb_app_signal_t *signal_struct) if (err_status == ESP_OK) { esp_zb_ieee_addr_t extended_pan_id; esp_zb_get_extended_pan_id(extended_pan_id); - ESP_LOGI(TAG, "Formed network successfully (Extended PAN ID: %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x, PAN ID: 0x%04hx, Channel:%d)", + ESP_LOGI(TAG, "Formed network successfully (Extended PAN ID: %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x, PAN ID: 0x%04hx, Channel:%d, Short Address: 0x%04hx)", extended_pan_id[7], extended_pan_id[6], extended_pan_id[5], extended_pan_id[4], extended_pan_id[3], extended_pan_id[2], extended_pan_id[1], extended_pan_id[0], - esp_zb_get_pan_id(), esp_zb_get_current_channel()); + esp_zb_get_pan_id(), esp_zb_get_current_channel(), esp_zb_get_short_address()); esp_zb_bdb_start_top_level_commissioning(ESP_ZB_BDB_MODE_NETWORK_STEERING); } else { ESP_LOGI(TAG, "Restart network formation (status: %s)", esp_err_to_name(err_status)); @@ -157,6 +138,15 @@ void esp_zb_app_signal_handler(esp_zb_app_signal_t *signal_struct) cmd_req.addr_of_interest = dev_annce_params->device_short_addr; esp_zb_zdo_find_on_off_light(&cmd_req, user_find_cb, NULL); break; + case ESP_ZB_NWK_SIGNAL_PERMIT_JOIN_STATUS: + if (err_status == ESP_OK) { + if (*(uint8_t *)esp_zb_app_signal_get_params(p_sg_p)) { + ESP_LOGI(TAG, "Network(0x%04hx) is open for %d seconds", esp_zb_get_pan_id(), *(uint8_t *)esp_zb_app_signal_get_params(p_sg_p)); + } else { + ESP_LOGW(TAG, "Network(0x%04hx) closed, devices joining not allowed.", esp_zb_get_pan_id()); + } + } + break; default: ESP_LOGI(TAG, "ZDO signal: %s (0x%x), status: %s", esp_zb_zdo_signal_to_string(sig_type), sig_type, esp_err_to_name(err_status)); diff --git a/examples/zigbee/light_sample/HA_on_off_switch/main/esp_zb_switch.h b/examples/zigbee/light_sample/HA_on_off_switch/main/esp_zb_switch.h index 3a14d46637..4de8684ece 100644 --- a/examples/zigbee/light_sample/HA_on_off_switch/main/esp_zb_switch.h +++ b/examples/zigbee/light_sample/HA_on_off_switch/main/esp_zb_switch.h @@ -1,47 +1,24 @@ /* - * SPDX-FileCopyrightText: 2021-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: LicenseRef-Included * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: + * Zigbee HA_on_off_switch Example * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. + * This example code is in the Public Domain (or CC0 licensed, at your option.) * - * 2. Redistributions in binary form, except as embedded into a Espressif Systems - * integrated circuit in a product or a software update for such product, - * must reproduce the above copyright notice, this list of conditions and - * the following disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * 3. Neither the name of the copyright holder nor the names of its contributors - * may be used to endorse or promote products derived from this software without - * specific prior written permission. - * - * 4. Any software provided in binary form under this license must not be reverse - * engineered, decompiled, modified and/or disassembled. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. + * Unless required by applicable law or agreed to in writing, this + * software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. */ #include "esp_zigbee_core.h" #include "switch_driver.h" /* Zigbee configuration */ #define MAX_CHILDREN 10 /* the max amount of connected devices */ -#define INSTALLCODE_POLICY_ENABLE false /* enable the install code policy for security */ -#define HA_ONOFF_SWITCH_ENDPOINT 1 /* esp light switch device endpoint */ -#define ESP_ZB_PRIMARY_CHANNEL_MASK ESP_ZB_TRANSCEIVER_ALL_CHANNELS_MASK /* Zigbee primary channel mask use in the example */ +#define INSTALLCODE_POLICY_ENABLE false /* enable the install code policy for security */ +#define HA_ONOFF_SWITCH_ENDPOINT 1 /* esp light switch device endpoint */ +#define ESP_ZB_PRIMARY_CHANNEL_MASK (1l << 13) /* Zigbee primary channel mask use in the example */ #define ESP_ZB_ZC_CONFIG() \ { \ diff --git a/examples/zigbee/light_sample/HA_on_off_switch/main/idf_component.yml b/examples/zigbee/light_sample/HA_on_off_switch/main/idf_component.yml index 479a89e4fc..c186c3c8ca 100644 --- a/examples/zigbee/light_sample/HA_on_off_switch/main/idf_component.yml +++ b/examples/zigbee/light_sample/HA_on_off_switch/main/idf_component.yml @@ -1,7 +1,7 @@ ## IDF Component Manager Manifest File dependencies: - espressif/esp-zigbee-lib: "~0.9.0" - espressif/esp-zboss-lib: "~0.7.0" + espressif/esp-zboss-lib: "1.0.9" + espressif/esp-zigbee-lib: "1.0.9" ## Required IDF version idf: version: ">=5.0.0" diff --git a/examples/zigbee/light_sample/HA_on_off_switch/partitions.csv b/examples/zigbee/light_sample/HA_on_off_switch/partitions.csv index 24bb3132a4..a56c0be780 100644 --- a/examples/zigbee/light_sample/HA_on_off_switch/partitions.csv +++ b/examples/zigbee/light_sample/HA_on_off_switch/partitions.csv @@ -2,6 +2,6 @@ # Note: if you have increased the bootloader size, make sure to update the offsets to avoid overlap nvs, data, nvs, 0x9000, 0x6000, phy_init, data, phy, 0xf000, 0x1000, -factory, app, factory, 0x10000, 650K, -zb_storage, data, fat, 0xb3000, 16K, -zb_fct, data, fat, 0xb7000, 1K, +factory, app, factory, 0x10000, 900K, +zb_storage, data, fat, 0xf1000, 16K, +zb_fct, data, fat, 0xf5000, 1K, diff --git a/examples/zigbee/light_sample/HA_on_off_switch/sdkconfig.defaults b/examples/zigbee/light_sample/HA_on_off_switch/sdkconfig.defaults index 24f8636e5e..79fcc61b2c 100644 --- a/examples/zigbee/light_sample/HA_on_off_switch/sdkconfig.defaults +++ b/examples/zigbee/light_sample/HA_on_off_switch/sdkconfig.defaults @@ -22,8 +22,6 @@ CONFIG_MBEDTLS_KEY_EXCHANGE_ECJPAKE=y CONFIG_MBEDTLS_ECJPAKE_C=y # end of mbedTLS -CONFIG_ESP_TASK_WDT_CHECK_IDLE_TASK_CPU0=n - # # Zboss # diff --git a/tools/ci/astyle-rules.yml b/tools/ci/astyle-rules.yml index ba24f97d86..5eff0873d9 100644 --- a/tools/ci/astyle-rules.yml +++ b/tools/ci/astyle-rules.yml @@ -20,7 +20,6 @@ submodules: - "/components/esp_phy/lib/" - "/components/esp_wifi/lib/" - "/components/heap/tlsf/" - - "/components/ieee802154/lib/" - "/components/json/cJSON/" - "/components/lwip/lwip/" - "/components/mbedtls/mbedtls/" diff --git a/tools/ci/static-analysis-rules.yml b/tools/ci/static-analysis-rules.yml index 4af09b1297..16f71ee224 100644 --- a/tools/ci/static-analysis-rules.yml +++ b/tools/ci/static-analysis-rules.yml @@ -18,7 +18,6 @@ skip: - "components/esp_phy/lib" - "components/esp_wifi/lib" - "components/esp_wifi/lib_esp32" - - "components/ieee802154/lib" - "components/json/cJSON" - "components/lwip/lwip" - "components/mbedtls/mbedtls"