Merge branch 'backport5.2/openthread_backport' into 'release/v5.2'

some openthread changes backport to release/v5.2

See merge request espressif/esp-idf!28637
This commit is contained in:
Shu Chen 2024-02-20 17:01:36 +08:00
commit dbbe2cf173
73 changed files with 2110 additions and 480 deletions

View File

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

4
.gitmodules vendored
View File

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

View File

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

View File

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

View File

@ -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, "+ + +--------------------------------------------------+");

View File

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

View File

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

View File

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

@ -1 +0,0 @@
Subproject commit 102b03c8095de8a337c293f79dce189be63186f3

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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 <sys/select.h>
#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

@ -1 +1 @@
Subproject commit e0969fc15c1991d91446a0dc5e4625ed2c0bb014
Subproject commit fcee30db4b7342de4df9105bdd049a09d2d63187

@ -1 +1 @@
Subproject commit 41ef80717f4b757440125932723cc8721ef42f7f
Subproject commit 456c448284486abe2a9118a9fdaa468fe2383fcd

View File

@ -0,0 +1,15 @@
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <spinel.h>
#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

View File

@ -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 <typename InterfaceType> class SpinelInterfaceAdapter {
public:
SpinelInterfaceAdapter(void) {}
~SpinelInterfaceAdapter(void) {}
InterfaceType &GetSpinelInterface(void) { return mSpinelInterface; }
private:
InterfaceType mSpinelInterface;
};
} // namespace radio_spinel
} // namespace esp

View File

@ -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<kMaxFrameSize> encoder_buffer;
};
} // namespace radio_spinel
} // namespace esp

View File

@ -195,6 +195,8 @@ private:
UartSpinelInterface &operator=(const UartSpinelInterface &);
esp_openthread_rcp_failure_handler mRcpFailureHandler;
ot::Spinel::FrameBuffer<kMaxFrameSize> encoder_buffer;
};
} // namespace openthread

View File

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

View File

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

View File

@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2021-2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -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

View File

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

View File

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

View File

@ -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<esp_ieee802154_pending_mode_t>(pending_mode));
break;
}
default:
error = OT_ERROR_NOT_FOUND;
break;
}
return error;
}
} // namespace Ncp
} // namespace ot
#endif // #if OPENTHREAD_ENABLE_NCP_VENDOR_HOOK

View File

@ -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<Instance *>(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

View File

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

View File

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

View File

@ -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<kMaxFrameSize> encoder_buffer;
encoder_buffer.Clear();
ot::Hdlc::Encoder hdlc_encoder(encoder_buffer);
SuccessOrExit(error = hdlc_encoder.BeginFrame());

View File

@ -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<UartSpinelInterface> 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<int32_t>(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<void *>(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<void *>(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;
}

View File

@ -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 <errno.h>
#include <sys/unistd.h>
#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<uint8_t *>(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<uint16_t>(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<time_t>(remain / 1000000);
timeout.tv_usec = static_cast<suseconds_t>(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<uint16_t>(rval);
aFrame += static_cast<uint16_t>(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<time_t>(timeout_us / US_PER_S);
timeout.tv_usec = static_cast<suseconds_t>(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<UartSpinelInterface *>(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

View File

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

View File

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

View File

@ -7,6 +7,7 @@ Migration from 5.0 to 5.1
:maxdepth: 1
gcc
:SOC_IEEE802154_SUPPORTED: ieee802154
peripherals
storage
networking

View File

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

View File

@ -8,6 +8,7 @@ Migration from 5.1 to 5.2
bluetooth-classic
gcc
:SOC_IEEE802154_SUPPORTED: ieee802154
peripherals
protocols
storage

View File

@ -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 驱动层,否则这个数据空间将不会被释放。

View File

@ -7,6 +7,7 @@
:maxdepth: 1
gcc
:SOC_IEEE802154_SUPPORTED: ieee802154
peripherals
storage
networking

View File

@ -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 驱动层,否则这个数据空间将不会被释放。

View File

@ -8,6 +8,7 @@
bluetooth-classic
gcc
:SOC_IEEE802154_SUPPORTED: ieee802154
peripherals
protocols
storage

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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 <fcntl.h>
#include <string.h>
@ -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());

View File

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

View File

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

View File

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

1 # Name, Type, SubType, Offset, Size, Flags
2 # Note: if you have increased the bootloader size, make sure to update the offsets to avoid overlap
3 nvs, data, nvs, 0x9000, 0x6000,
4 phy_init, data, phy, 0xf000, 0x1000,
5 factory, app, factory, 0x10000, 1150K, factory, app, factory, 0x10000, 1400K,
6 zb_storage, data, fat, , 16K, zb_storage, data, fat, 0x16e000,16K,
7 zb_fct, data, fat, , 1K, zb_fct, data, fat, 0x172000,1K,
8 rcp_fw, data, spiffs, 0x173000,500k,

View File

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

View File

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

View File

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

View File

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

View File

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

1 # Name, Type, SubType, Offset, Size, Flags
2 # Note: if you have increased the bootloader size, make sure to update the offsets to avoid overlap
3 nvs, data, nvs, 0x9000, 0x6000,
4 phy_init, data, phy, 0xf000, 0x1000,
5 factory, app, factory, 0x10000, 550K, factory, app, factory, 0x10000, 548K,
6 zb_storage, data, fat, 0x9a000, 16K,

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

1 # Name, Type, SubType, Offset, Size, Flags
2 # Note: if you have increased the bootloader size, make sure to update the offsets to avoid overlap
3 nvs, data, nvs, 0x9000, 0x6000,
4 phy_init, data, phy, 0xf000, 0x1000,
5 factory, app, factory, 0x10000, 650K, factory, app, factory, 0x10000, 900K,
6 zb_storage, data, fat, 0xb3000, 16K, zb_storage, data, fat, 0xf1000, 16K,
7 zb_fct, data, fat, 0xb7000, 1K, zb_fct, data, fat, 0xf5000, 1K,

View File

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

View File

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

View File

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

View File

@ -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() \
{ \

View File

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

View File

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

1 # Name, Type, SubType, Offset, Size, Flags
2 # Note: if you have increased the bootloader size, make sure to update the offsets to avoid overlap
3 nvs, data, nvs, 0x9000, 0x6000,
4 phy_init, data, phy, 0xf000, 0x1000,
5 factory, app, factory, 0x10000, 650K, factory, app, factory, 0x10000, 900K,
6 zb_storage, data, fat, 0xb3000, 16K, zb_storage, data, fat, 0xf1000, 16K,
7 zb_fct, data, fat, 0xb7000, 1K, zb_fct, data, fat, 0xf5000, 1K,

View File

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

View File

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

View File

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