Merge branch 'feat/update_ot_jan2026_v6.0' into 'release/v6.0'

feat(openthread): update OT to 9b887f6bd (v6.0)

See merge request espressif/esp-idf!46758
This commit is contained in:
Zhang Wen Xu
2026-03-19 13:51:55 +00:00
47 changed files with 1351 additions and 504 deletions

View File

@@ -8,8 +8,4 @@
#include "hal/ieee802154_common_ll.h"
#define IEEE802154_TXPOWER_VALUE_MAX 20
#define IEEE802154_TXPOWER_VALUE_MIN -15
#define IEEE802154_TXPOWER_INDEX_MIN 3
#define IEEE802154_RSSI_COMPENSATION_VALUE 0

View File

@@ -8,8 +8,4 @@
#include "hal/ieee802154_common_ll.h"
#define IEEE802154_TXPOWER_VALUE_MAX 20
#define IEEE802154_TXPOWER_VALUE_MIN -15
#define IEEE802154_TXPOWER_INDEX_MIN 3
#define IEEE802154_RSSI_COMPENSATION_VALUE 0

View File

@@ -14,10 +14,6 @@ extern "C" {
extern uint32_t bt_bb_get_rssi_comp(void);
#define IEEE802154_TXPOWER_VALUE_MAX 20
#define IEEE802154_TXPOWER_VALUE_MIN -24
#define IEEE802154_TXPOWER_INDEX_MIN 0
#define IEEE802154_RSSI_COMPENSATION_VALUE bt_bb_get_rssi_comp()
#ifdef __cplusplus

View File

@@ -414,6 +414,11 @@ static inline void ieee802154_ll_set_pending_mode(bool enable)
IEEE802154.conf.pending_enhance = enable;
}
static inline bool ieee802154_ll_get_pending_mode(void)
{
return IEEE802154.conf.pending_enhance;
}
FORCE_INLINE_ATTR void ieee802154_ll_set_pending_bit(bool pending)
{
IEEE802154.pending_cfg.pending = pending;

View File

@@ -72,6 +72,16 @@ menu "IEEE 802.15.4"
help
Enable IEEE802154 multi-pan
config IEEE802154_INTERFACE_NUM
int "Number of IEEE802154 interfaces"
depends on IEEE802154_ENABLED
range 1 1 if !IEEE802154_MULTI_PAN_ENABLE
range 1 4 if IEEE802154_MULTI_PAN_ENABLE
default 1 if !IEEE802154_MULTI_PAN_ENABLE
default 2 if IEEE802154_MULTI_PAN_ENABLE
help
Number of IEEE802154 interfaces
config IEEE802154_TIMING_OPTIMIZATION
bool "Enable throughput optimization"
depends on IEEE802154_ENABLED

View File

@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -15,7 +15,7 @@
#include "esp_ieee802154_types.h"
#include "esp_ieee802154_util.h"
static ieee802154_pending_table_t ieee802154_pending_table;
static ieee802154_pending_table_t ieee802154_pending_table[CONFIG_IEEE802154_INTERFACE_NUM];
#define GET_MASK_ITEM_FROM_TABLE(mask, pos) (mask[(pos) / IEEE802154_PENDING_TABLE_MASK_BITS])
@@ -23,21 +23,21 @@ static ieee802154_pending_table_t ieee802154_pending_table;
#define BIT_CLR(mask, pos) (GET_MASK_ITEM_FROM_TABLE(mask, pos) &= ~(1UL << (pos % IEEE802154_PENDING_TABLE_MASK_BITS)))
#define BIT_IST(mask, pos) (GET_MASK_ITEM_FROM_TABLE(mask, pos) & (1UL << (pos % IEEE802154_PENDING_TABLE_MASK_BITS)))
static IRAM_ATTR bool ieee802154_addr_in_pending_table(const uint8_t *addr, bool is_short)
static IRAM_ATTR bool ieee802154_addr_in_pending_table(esp_ieee802154_multipan_index_t inf_index, const uint8_t *addr, bool is_short)
{
bool ret = false;
if (is_short) {
for (uint8_t index = 0; index < CONFIG_IEEE802154_PENDING_TABLE_SIZE; index++) {
if (BIT_IST(ieee802154_pending_table.short_addr_mask, index) &&
memcmp(addr, ieee802154_pending_table.short_addr[index], IEEE802154_FRAME_SHORT_ADDR_SIZE) == 0) {
if (BIT_IST(ieee802154_pending_table[inf_index].short_addr_mask, index) &&
memcmp(addr, ieee802154_pending_table[inf_index].short_addr[index], IEEE802154_FRAME_SHORT_ADDR_SIZE) == 0) {
ret = true;
break;
}
}
} else {
for (uint8_t index = 0; index < CONFIG_IEEE802154_PENDING_TABLE_SIZE; index++) {
if (BIT_IST(ieee802154_pending_table.ext_addr_mask, index) &&
memcmp(addr, ieee802154_pending_table.ext_addr[index], IEEE802154_FRAME_EXT_ADDR_SIZE) == 0) {
if (BIT_IST(ieee802154_pending_table[inf_index].ext_addr_mask, index) &&
memcmp(addr, ieee802154_pending_table[inf_index].ext_addr[index], IEEE802154_FRAME_EXT_ADDR_SIZE) == 0) {
ret = true;
break;
}
@@ -46,63 +46,63 @@ static IRAM_ATTR bool ieee802154_addr_in_pending_table(const uint8_t *addr, bool
return ret;
}
esp_err_t ieee802154_add_pending_addr(const uint8_t *addr, bool is_short)
esp_err_t ieee802154_add_pending_addr(esp_ieee802154_multipan_index_t inf_index, const uint8_t *addr, bool is_short)
{
esp_err_t ret = ESP_FAIL;
int8_t first_empty_index = -1;
if (is_short) {
for (uint8_t index = 0; index < CONFIG_IEEE802154_PENDING_TABLE_SIZE; index++) {
if (!BIT_IST(ieee802154_pending_table.short_addr_mask, index)) {
if (!BIT_IST(ieee802154_pending_table[inf_index].short_addr_mask, index)) {
// record the first empty index
first_empty_index = (first_empty_index == -1 ? index : first_empty_index);
} else if (memcmp(addr, ieee802154_pending_table.short_addr[index], IEEE802154_FRAME_SHORT_ADDR_SIZE) == 0) {
} else if (memcmp(addr, ieee802154_pending_table[inf_index].short_addr[index], IEEE802154_FRAME_SHORT_ADDR_SIZE) == 0) {
// The address is in the table already.
ret = ESP_OK;
return ret;
}
}
if (first_empty_index != -1) {
memcpy(ieee802154_pending_table.short_addr[first_empty_index], addr, IEEE802154_FRAME_SHORT_ADDR_SIZE);
BIT_SET(ieee802154_pending_table.short_addr_mask, first_empty_index);
memcpy(ieee802154_pending_table[inf_index].short_addr[first_empty_index], addr, IEEE802154_FRAME_SHORT_ADDR_SIZE);
BIT_SET(ieee802154_pending_table[inf_index].short_addr_mask, first_empty_index);
ret = ESP_OK;
}
} else {
for (uint8_t index = 0; index < CONFIG_IEEE802154_PENDING_TABLE_SIZE; index++) {
if (!BIT_IST(ieee802154_pending_table.ext_addr_mask, index)) {
if (!BIT_IST(ieee802154_pending_table[inf_index].ext_addr_mask, index)) {
first_empty_index = (first_empty_index == -1 ? index : first_empty_index);
} else if (memcmp(addr, ieee802154_pending_table.ext_addr[index], IEEE802154_FRAME_EXT_ADDR_SIZE) == 0) {
} else if (memcmp(addr, ieee802154_pending_table[inf_index].ext_addr[index], IEEE802154_FRAME_EXT_ADDR_SIZE) == 0) {
// The address is already in the pending table.
ret = ESP_OK;
return ret;
}
}
if (first_empty_index != -1) {
memcpy(ieee802154_pending_table.ext_addr[first_empty_index], addr, IEEE802154_FRAME_EXT_ADDR_SIZE);
BIT_SET(ieee802154_pending_table.ext_addr_mask, first_empty_index);
memcpy(ieee802154_pending_table[inf_index].ext_addr[first_empty_index], addr, IEEE802154_FRAME_EXT_ADDR_SIZE);
BIT_SET(ieee802154_pending_table[inf_index].ext_addr_mask, first_empty_index);
ret = ESP_OK;
}
}
return ret;
}
esp_err_t ieee802154_clear_pending_addr(const uint8_t *addr, bool is_short)
esp_err_t ieee802154_clear_pending_addr(esp_ieee802154_multipan_index_t inf_index, const uint8_t *addr, bool is_short)
{
esp_err_t ret = ESP_FAIL;
// Consider this function may be called in ISR, only clear the mask bits for finishing the process quickly.
if (is_short) {
for (uint8_t index = 0; index < CONFIG_IEEE802154_PENDING_TABLE_SIZE; index++) {
if (BIT_IST(ieee802154_pending_table.short_addr_mask, index) &&
memcmp(addr, ieee802154_pending_table.short_addr[index], IEEE802154_FRAME_SHORT_ADDR_SIZE) == 0) {
BIT_CLR(ieee802154_pending_table.short_addr_mask, index);
if (BIT_IST(ieee802154_pending_table[inf_index].short_addr_mask, index) &&
memcmp(addr, ieee802154_pending_table[inf_index].short_addr[index], IEEE802154_FRAME_SHORT_ADDR_SIZE) == 0) {
BIT_CLR(ieee802154_pending_table[inf_index].short_addr_mask, index);
ret = ESP_OK;
break;
}
}
} else {
for (uint8_t index = 0; index < CONFIG_IEEE802154_PENDING_TABLE_SIZE; index++) {
if (BIT_IST(ieee802154_pending_table.ext_addr_mask, index) &&
memcmp(addr, ieee802154_pending_table.ext_addr[index], IEEE802154_FRAME_EXT_ADDR_SIZE) == 0) {
BIT_CLR(ieee802154_pending_table.ext_addr_mask, index);
if (BIT_IST(ieee802154_pending_table[inf_index].ext_addr_mask, index) &&
memcmp(addr, ieee802154_pending_table[inf_index].ext_addr[index], IEEE802154_FRAME_EXT_ADDR_SIZE) == 0) {
BIT_CLR(ieee802154_pending_table[inf_index].ext_addr_mask, index);
ret = ESP_OK;
break;
}
@@ -112,26 +112,42 @@ esp_err_t ieee802154_clear_pending_addr(const uint8_t *addr, bool is_short)
return ret;
}
void ieee802154_reset_pending_table(bool is_short)
void ieee802154_reset_pending_table(esp_ieee802154_multipan_index_t inf_index, bool is_short)
{
// Consider this function may be called in ISR, only clear the mask bits for finishing the process quickly.
if (is_short) {
memset(ieee802154_pending_table.short_addr_mask, 0, IEEE802154_PENDING_TABLE_MASK_SIZE);
memset(ieee802154_pending_table[inf_index].short_addr_mask, 0, IEEE802154_PENDING_TABLE_MASK_SIZE);
} else {
memset(ieee802154_pending_table.ext_addr_mask, 0, IEEE802154_PENDING_TABLE_MASK_SIZE);
memset(ieee802154_pending_table[inf_index].ext_addr_mask, 0, IEEE802154_PENDING_TABLE_MASK_SIZE);
}
}
bool ieee802154_ack_config_pending_bit(const uint8_t *frame)
bool ieee802154_ack_config_pending_bit(const uint8_t *frame, const esp_ieee802154_frame_info_t *frame_info)
{
esp_ieee802154_multipan_index_t inf_index = 0;
#if CONFIG_IEEE802154_MULTI_PAN_ENABLE
inf_index = frame_info->mpf_index;
if (inf_index >= ESP_IEEE802154_MULTIPAN_MAX || inf_index < ESP_IEEE802154_MULTIPAN_0) {
return false;
}
#endif
bool pending_bit = false;
uint8_t addr[IEEE802154_FRAME_EXT_ADDR_SIZE] = {0};
uint8_t src_mode = 0;
// Only set the HW pending bit for the frames with version 0b00 or 0b01.
bool set_to_hw = (ieee802154_frame_get_version(frame) <= IEEE802154_FRAME_VERSION_1);
ieee802154_ll_pending_mode_t pending_mode = ieee802154_pib_get_pending_mode();
// Check whether the frame is a Data Request.
if (ieee802154_ll_get_pending_mode()) {
pending_bit = ieee802154_is_data_request(frame);
}
ieee802154_ll_pending_mode_t pending_mode = ieee802154_pib_get_pending_mode(inf_index);
src_mode = ieee802154_frame_get_src_addr(frame, addr);
if (src_mode == IEEE802154_FRAME_INVALID_VALUE) {
goto exit;
}
switch (pending_mode) {
case IEEE802154_AUTO_PENDING_DISABLE:
// HW will check whether the frame is data request or not
@@ -139,19 +155,14 @@ bool ieee802154_ack_config_pending_bit(const uint8_t *frame)
break;
case IEEE802154_AUTO_PENDING_ENABLE:
case IEEE802154_AUTO_PENDING_ENHANCED:
src_mode = ieee802154_frame_get_src_addr(frame, addr);
if (src_mode == IEEE802154_FRAME_SRC_MODE_SHORT || src_mode == IEEE802154_FRAME_SRC_MODE_EXT) {
if (ieee802154_addr_in_pending_table(addr, src_mode == IEEE802154_FRAME_SRC_MODE_SHORT)) {
pending_bit = true;
}
pending_bit = ieee802154_addr_in_pending_table(inf_index, addr, src_mode == IEEE802154_FRAME_SRC_MODE_SHORT);
}
break;
case IEEE802154_AUTO_PENDING_ZIGBEE:
// If the address type is short and in pending table, set 'pending_bit' false, otherwise set true.
src_mode = ieee802154_frame_get_src_addr(frame, addr);
pending_bit = true;
if (src_mode == IEEE802154_FRAME_SRC_MODE_SHORT && ieee802154_addr_in_pending_table(addr, src_mode == IEEE802154_FRAME_SRC_MODE_SHORT)) {
if (src_mode == IEEE802154_FRAME_SRC_MODE_SHORT && ieee802154_addr_in_pending_table(inf_index, addr, src_mode == IEEE802154_FRAME_SRC_MODE_SHORT)) {
pending_bit = false;
}
break;
@@ -159,6 +170,7 @@ bool ieee802154_ack_config_pending_bit(const uint8_t *frame)
IEEE802154_ASSERT(false);
}
exit:
if (set_to_hw) {
ieee802154_ll_set_pending_bit(pending_bit);
}

View File

@@ -77,6 +77,16 @@ static char *ieee802154_state_string[] = {
"ED",
"CCA",
};
static char *ieee802154_state_to_string(ieee802154_state_t state)
{
char *state_string = "INVALID";
if (state < sizeof(ieee802154_state_string) / sizeof(ieee802154_state_string[0])) {
state_string = ieee802154_state_string[state];
}
return state_string;
}
#endif // CONFIG_IEEE802154_RECORD_STATE
#if CONFIG_IEEE802154_RECORD_CMD
@@ -126,7 +136,7 @@ static char *ieee802154_get_cmd_string(ieee802154_ll_cmd_t cmd)
#endif // CONFIG_IEEE802154_RECORD_CMD
#if CONFIG_IEEE802154_RECORD_EVENT || CONFIG_IEEE802154_RECORD_ABORT
static char *ieee80154_rx_abort_reason_string[] = {
static char *ieee802154_rx_abort_reason_string[] = {
"RSVD", // = 0,
"RX_STOP", // = 1,
"SFD_TIMEOUT", // = 2,
@@ -148,7 +158,7 @@ static char *ieee80154_rx_abort_reason_string[] = {
"ED_COEX_REJECT", // = 26,
};
static char *ieee80154_tx_abort_reason_string[] = {
static char *ieee802154_tx_abort_reason_string[] = {
"RSVD", // = 0,
"RX_ACK_STOP", // = 1,
"RX_ACK_SFD_TIMEOUT", // = 2,
@@ -169,17 +179,47 @@ static char *ieee80154_tx_abort_reason_string[] = {
"CCA_BUSY", // = 25,
};
static char *ieee802154_abort_reason_to_string(ieee802154_ll_rx_abort_reason_t reason, bool is_tx_abort)
{
char *abort_reason_string = "UNKNOWN";
if (is_tx_abort) {
if (reason < sizeof(ieee802154_tx_abort_reason_string) / sizeof(ieee802154_tx_abort_reason_string[0])) {
abort_reason_string = ieee802154_tx_abort_reason_string[reason];
}
} else {
if (reason < sizeof(ieee802154_rx_abort_reason_string) / sizeof(ieee802154_rx_abort_reason_string[0])) {
abort_reason_string = ieee802154_rx_abort_reason_string[reason];
}
}
return abort_reason_string;
}
#endif // CONFIG_IEEE802154_RECORD_EVENT
#if CONFIG_IEEE802154_RECORD
#if CONFIG_IEEE802154_RECORD_TXRX_FRAME
static void ieee802154_dump_frame_print(const uint8_t *frame)
{
if (frame == NULL) {
ESP_EARLY_LOGW(IEEE802154_TAG, "Invalid frame, frame is NULL");
return;
}
if (frame[0] < IEEE802154_FRAME_MIN_LEN) {
ESP_EARLY_LOGW(IEEE802154_TAG, "Invalid frame, frame length is %d", frame[0]);
return;
}
for (uint8_t i = 1; i < frame[0]; i+=8) {
uint8_t end = (i + 7 < frame[0]) ? i + 7 : frame[0] - 1;
ESP_EARLY_LOGW(IEEE802154_TAG, "frag(%03d:%03d~%03d): %02x %02x %02x %02x %02x %02x %02x %02x",
frame[0], i, i+7,
frame[i], frame[i+1], frame[i+2], frame[i+3],
frame[i+4], frame[i+5], frame[i+6], frame[i+7]);
frame[0], i, end,
frame[i],
(i+1 < frame[0]) ? frame[i+1] : 0,
(i+2 < frame[0]) ? frame[i+2] : 0,
(i+3 < frame[0]) ? frame[i+3] : 0,
(i+4 < frame[0]) ? frame[i+4] : 0,
(i+5 < frame[0]) ? frame[i+5] : 0,
(i+6 < frame[0]) ? frame[i+6] : 0,
(i+7 < frame[0]) ? frame[i+7] : 0);
}
}
#endif // CONFIG_IEEE802154_RECORD_TXRX_FRAME
@@ -193,14 +233,14 @@ void ieee802154_record_print(void)
char abort_log[100] = { 0 };
snprintf(event_log, 200,"index %2d: event: 0x%4x, %15s, state:%10s, timestamp: %lld", i, g_ieee802154_probe.event[i].event,
ieee802154_get_event_string(g_ieee802154_probe.event[i].event),
ieee802154_state_string[g_ieee802154_probe.event[i].state],
ieee802154_state_to_string(g_ieee802154_probe.event[i].state),
g_ieee802154_probe.event[i].timestamp);
if (g_ieee802154_probe.event[i].event == IEEE802154_EVENT_RX_ABORT) {
snprintf(abort_log, 100, "rx abort reason: %4x, %20s", g_ieee802154_probe.event[i].abort_reason.rx,
ieee80154_rx_abort_reason_string[g_ieee802154_probe.event[i].abort_reason.rx]);
ieee802154_abort_reason_to_string(g_ieee802154_probe.event[i].abort_reason.rx, false));
} else if (g_ieee802154_probe.event[i].event == IEEE802154_EVENT_TX_ABORT) {
snprintf(abort_log, 100, "tx abort reason: %4x, %20s", g_ieee802154_probe.event[i].abort_reason.tx,
ieee80154_tx_abort_reason_string[g_ieee802154_probe.event[i].abort_reason.tx]);
ieee802154_abort_reason_to_string(g_ieee802154_probe.event[i].abort_reason.tx, true));
}
ESP_EARLY_LOGW(IEEE802154_TAG, "%s %s", event_log, abort_log);
}
@@ -212,7 +252,7 @@ void ieee802154_record_print(void)
for (uint8_t i = 0; i < IEEE802154_ASSERT_RECORD_STATE_SIZE; i++) {
ESP_EARLY_LOGW(IEEE802154_TAG, "index %2d: line:%5lu, state:%10s, timestamp: %lld",
i, g_ieee802154_probe.state[i].line,
ieee802154_state_string[g_ieee802154_probe.state[i].state],
ieee802154_state_to_string(g_ieee802154_probe.state[i].state),
g_ieee802154_probe.state[i].timestamp);
}
ESP_EARLY_LOGW(IEEE802154_TAG,"Print the record state done.");
@@ -235,12 +275,12 @@ void ieee802154_record_print(void)
if (g_ieee802154_probe.abort[i].is_tx_abort) {
ESP_EARLY_LOGW(IEEE802154_TAG, "index %2d: tx abort: %4x, %15s, timestamp: %lld",
i, g_ieee802154_probe.abort[i].abort_reason.tx,
ieee80154_tx_abort_reason_string[g_ieee802154_probe.abort[i].abort_reason.tx],
ieee802154_abort_reason_to_string(g_ieee802154_probe.abort[i].abort_reason.tx, true),
g_ieee802154_probe.abort[i].timestamp);
} else {
ESP_EARLY_LOGW(IEEE802154_TAG, "index %2d: rx abort: %4x, %15s, timestamp: %lld",
i, g_ieee802154_probe.abort[i].abort_reason.rx,
ieee80154_rx_abort_reason_string[g_ieee802154_probe.abort[i].abort_reason.rx],
ieee802154_abort_reason_to_string(g_ieee802154_probe.abort[i].abort_reason.rx, false),
g_ieee802154_probe.abort[i].timestamp);
}
}
@@ -418,14 +458,19 @@ static uint64_t s_rx_buffer_used_water_level[IEEE802154_RX_BUFFER_USED_TOTAL_LEV
void ieee802154_rx_buffer_statistic_is_free(bool is_free)
{
if (is_free) {
s_rx_buffer_used_nums--;
if (s_rx_buffer_used_nums > 0) {
s_rx_buffer_used_nums--;
}
} else {
s_rx_buffer_used_nums++;
// (CONFIG_IEEE802154_RX_BUFFER_SIZE + 1) means buffer full.
if (s_rx_buffer_used_nums > (CONFIG_IEEE802154_RX_BUFFER_SIZE + 1)) {
s_rx_buffer_used_nums = CONFIG_IEEE802154_RX_BUFFER_SIZE + 1;
}
s_rx_buffer_used_water_level[IEEE802154_RX_BUFFER_GET_USED_LEVEL(s_rx_buffer_used_nums)]++;
uint8_t level = IEEE802154_RX_BUFFER_GET_USED_LEVEL(s_rx_buffer_used_nums);
if (level <= IEEE802154_RX_BUFFER_USED_TOTAL_LEVEL) {
s_rx_buffer_used_water_level[level]++;
}
}
}
@@ -437,6 +482,7 @@ void ieee802154_rx_buffer_statistic_clear(void)
void ieee802154_rx_buffer_statistic_print(void)
{
uint64_t total_times = 0;
float percentage = 0.0f;
for (uint8_t i = 0; i < (IEEE802154_RX_BUFFER_USED_TOTAL_LEVEL + 1); i++) {
total_times += s_rx_buffer_used_water_level[i];
}
@@ -445,9 +491,15 @@ void ieee802154_rx_buffer_statistic_print(void)
ESP_LOGW(IEEE802154_TAG, "|%25s|%-25llu|", "buffer alloc times:", total_times);
ESP_LOGW(IEEE802154_TAG, "+-------------------------+-------------------------+");
for (uint8_t i = 0; i < (IEEE802154_RX_BUFFER_USED_TOTAL_LEVEL); i++) {
ESP_LOGW(IEEE802154_TAG, "|%4d%%%5s%4d%%%10s|%-15llu%9.2f%%|", ((i) * 100 / IEEE802154_RX_BUFFER_USED_TOTAL_LEVEL), "~", ((i + 1) * 100 / IEEE802154_RX_BUFFER_USED_TOTAL_LEVEL), " used:", s_rx_buffer_used_water_level[i], ((float)s_rx_buffer_used_water_level[i] / (float)total_times)*100);
percentage = (total_times > 0) ? ((float)s_rx_buffer_used_water_level[i] / (float)total_times) * 100 : 0.0f;
ESP_LOGW(IEEE802154_TAG, "|%4d%%%5s%4d%%%10s|%-15llu%9.2f%%|",
((i) * 100 / IEEE802154_RX_BUFFER_USED_TOTAL_LEVEL), "~",
((i + 1) * 100 / IEEE802154_RX_BUFFER_USED_TOTAL_LEVEL), " used:",
s_rx_buffer_used_water_level[i], percentage);
}
ESP_LOGW(IEEE802154_TAG, "|%25s|%-15llu%9.2f%%|", "full used:", s_rx_buffer_used_water_level[IEEE802154_RX_BUFFER_USED_TOTAL_LEVEL], ((float)s_rx_buffer_used_water_level[IEEE802154_RX_BUFFER_USED_TOTAL_LEVEL] / (float)total_times)*100);
percentage = (total_times > 0) ? ((float)s_rx_buffer_used_water_level[IEEE802154_RX_BUFFER_USED_TOTAL_LEVEL] / (float)total_times) * 100 : 0.0f;
ESP_LOGW(IEEE802154_TAG, "|%25s|%-15llu%9.2f%%|", "full used:",
s_rx_buffer_used_water_level[IEEE802154_RX_BUFFER_USED_TOTAL_LEVEL], percentage);
ESP_LOGW(IEEE802154_TAG, "+-------------------------+-------------------------+");
}

View File

@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2023-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -48,7 +48,12 @@ extern uint32_t bt_bb_get_cur_rx_info(void);
IEEE802154_STATIC volatile ieee802154_state_t s_ieee802154_state;
static uint8_t *s_tx_frame = NULL;
#if CONFIG_IEEE802154_TEST
#define IEEE802154_RX_FRAME_SIZE (127 + 1 + 1) // +1: len, +1: for dma test
#else
#define IEEE802154_RX_FRAME_SIZE (127 + 1) // +1: len
#endif // CONFIG_IEEE802154_TEST
// +1: for the stub buffer when the valid buffers are full.
//
@@ -144,11 +149,101 @@ static IRAM_ATTR void receive_ack_timeout_timer_start(uint32_t duration)
}
#endif
#if CONFIG_IEEE802154_MULTI_PAN_ENABLE
IEEE802154_STATIC IEEE802154_NOINLINE bool is_broadcast_panid(uint8_t *target_panid)
{
if (target_panid[0] == 0xff && target_panid[1] == 0xff) {
return true;
}
return false;
}
static IEEE802154_NOINLINE bool is_broadcast_addr(uint8_t *dest_addr, uint8_t addr_mode)
{
uint8_t target[IEEE802154_FRAME_EXT_ADDR_SIZE] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
if (addr_mode == IEEE802154_FRAME_DST_MODE_NONE) {
return false;
}
size_t addr_size = (addr_mode == IEEE802154_FRAME_DST_MODE_SHORT) ? IEEE802154_FRAME_SHORT_ADDR_SIZE : IEEE802154_FRAME_EXT_ADDR_SIZE;
if (memcmp(dest_addr, target, addr_size) == 0) {
return true;
}
return false;
}
IEEE802154_STATIC IEEE802154_NOINLINE void update_mpf_index(void)
{
uint8_t *frame = s_rx_frame[s_rx_index];
uint8_t frame_type = ieee802154_frame_get_type(frame);
s_rx_frame_info[s_rx_index].mpf_index = ESP_IEEE802154_MULTIPAN_MAX;
bool is_target_panid_present = false;
uint8_t dest_addr_mode = IEEE802154_FRAME_DST_MODE_NONE;
uint8_t dest_addr[IEEE802154_FRAME_EXT_ADDR_SIZE] = {0};
uint8_t target_panid[IEEE802154_FRAME_PANID_SIZE] = {0};
// Get dest addr and panid from the raw packet.
if (frame_type == IEEE802154_FRAME_TYPE_BEACON) {
is_target_panid_present = (ieee802154_frame_get_src_panid(frame, target_panid) == ESP_OK) ? true : false;
} else {
is_target_panid_present = (ieee802154_frame_get_dest_panid(frame, target_panid) == ESP_OK) ? true : false;
}
dest_addr_mode = ieee802154_frame_get_dst_addr(frame, dest_addr);
// Check is this packet is Broadcast
if (is_broadcast_addr(dest_addr, dest_addr_mode) || (is_target_panid_present && is_broadcast_panid(target_panid))) {
return;
}
for (esp_ieee802154_multipan_index_t index = 0; index < CONFIG_IEEE802154_INTERFACE_NUM; index++) {
if (is_target_panid_present == true) {
uint16_t panid = target_panid[1];
panid = (panid << 8) | target_panid[0];
if (panid != esp_ieee802154_get_multipan_panid(index)) {
continue;
}
}
if (dest_addr_mode == IEEE802154_FRAME_DST_MODE_SHORT) {
uint16_t short_addr = dest_addr[1];
short_addr = (short_addr << 8) | dest_addr[0];
if (short_addr != esp_ieee802154_get_multipan_short_address(index)) {
continue;
} else {
s_rx_frame_info[s_rx_index].mpf_index = index;
return;
}
} else if (dest_addr_mode == IEEE802154_FRAME_DST_MODE_EXT) {
uint8_t ext_addr[IEEE802154_FRAME_EXT_ADDR_SIZE] = {0};
esp_ieee802154_get_multipan_extended_address(index, ext_addr);
if (memcmp(dest_addr, ext_addr, IEEE802154_FRAME_EXT_ADDR_SIZE) != 0) {
continue;
} else {
s_rx_frame_info[s_rx_index].mpf_index = index;
return;
}
}
}
}
#endif
static IEEE802154_NOINLINE void ieee802154_rx_frame_info_update(void)
{
uint8_t len = s_rx_frame[s_rx_index][0];
int8_t rssi = s_rx_frame[s_rx_index][len - 1]; // crc is not written to rx buffer
uint8_t lqi = s_rx_frame[s_rx_index][len];
uint8_t len = s_rx_frame[s_rx_index][0] & 0x7f;
int8_t rssi = 0;
uint8_t lqi = 0;
if (len < IEEE802154_FRAME_MIN_LEN) {
s_rx_frame_info[s_rx_index].channel = 0;
s_rx_frame_info[s_rx_index].rssi = 0;
s_rx_frame_info[s_rx_index].lqi = 0;
return;
}
rssi = s_rx_frame[s_rx_index][len - 1]; // crc is not written to rx buffer
lqi = s_rx_frame[s_rx_index][len];
#if CONFIG_IEEE802154_MULTI_PAN_ENABLE
update_mpf_index();
#endif
s_rx_frame_info[s_rx_index].channel = ieee802154_freq_to_channel(ieee802154_ll_get_freq());
s_rx_frame_info[s_rx_index].rssi = rssi + IEEE802154_RSSI_COMPENSATION_VALUE;
@@ -436,12 +531,12 @@ static IRAM_ATTR void isr_handle_rx_done(void)
&& ieee802154_ll_get_tx_auto_ack()) {
extcoex_tx_stage_start();
// auto tx ack only works for the frame with version 0b00 and 0b01
s_rx_frame_info[s_rx_index].pending = ieee802154_ack_config_pending_bit(s_rx_frame[s_rx_index]);
s_rx_frame_info[s_rx_index].pending = ieee802154_ack_config_pending_bit(s_rx_frame[s_rx_index], &s_rx_frame_info[s_rx_index]);
ieee802154_set_state(IEEE802154_STATE_TX_ACK);
NEEDS_NEXT_OPT(false);
} else if (ieee802154_frame_is_ack_required(s_rx_frame[s_rx_index]) && ieee802154_frame_get_version(s_rx_frame[s_rx_index]) == IEEE802154_FRAME_VERSION_2
&& ieee802154_ll_get_tx_enhance_ack()) {
s_rx_frame_info[s_rx_index].pending = ieee802154_ack_config_pending_bit(s_rx_frame[s_rx_index]);
s_rx_frame_info[s_rx_index].pending = ieee802154_ack_config_pending_bit(s_rx_frame[s_rx_index], &s_rx_frame_info[s_rx_index]);
// For 2015 enh-ack, SW should generate an enh-ack then send it manually
if (ieee802154_inner_enh_ack_generator(s_rx_frame[s_rx_index], &s_rx_frame_info[s_rx_index], s_enh_ack_frame) == ESP_OK) {
extcoex_tx_stage_start();
@@ -888,7 +983,6 @@ static inline esp_err_t ieee802154_transmit_internal(const uint8_t *frame, bool
esp_err_t ieee802154_transmit(const uint8_t *frame, bool cca)
{
ESP_RETURN_ON_FALSE(frame[0] <= 127, ESP_ERR_INVALID_ARG, IEEE802154_TAG, "Invalid frame length.");
#if !CONFIG_IEEE802154_TEST
ieee802154_enter_critical();
if ((s_ieee802154_state == IEEE802154_STATE_RX && ieee802154_ll_is_current_rx_frame())
@@ -910,32 +1004,23 @@ esp_err_t ieee802154_transmit(const uint8_t *frame, bool cca)
esp_err_t ieee802154_transmit_at(const uint8_t *frame, bool cca, uint32_t time)
{
ESP_RETURN_ON_FALSE(frame[0] <= 127, ESP_ERR_INVALID_ARG, IEEE802154_TAG, "Invalid frame length.");
uint32_t tx_target_time;
uint32_t rampup_time = cca ? IEEE802154_ED_TRIG_TX_RAMPUP_TIME_US : IEEE802154_TX_RAMPUP_TIME_US;
uint32_t tx_target_time = (time >= rampup_time) ? time - rampup_time : 0;
IEEE802154_RF_ENABLE();
tx_init(frame);
IEEE802154_SET_TXRX_PTI(IEEE802154_SCENE_TX_AT);
if (cca) {
ieee802154_ll_set_ed_duration(CCA_DETECTION_TIME);
tx_target_time = time - IEEE802154_ED_TRIG_TX_RAMPUP_TIME_US;
ieee802154_set_state(IEEE802154_STATE_TX_CCA);
ieee802154_enter_critical();
ieee802154_etm_set_event_task(IEEE802154_ETM_CHANNEL0, ETM_EVENT_TIMER0_OVERFLOW, ETM_TASK_ED_TRIG_TX);
ieee802154_timer0_fire_at(tx_target_time);
ieee802154_exit_critical();
} else {
tx_target_time = time - IEEE802154_TX_RAMPUP_TIME_US;
if (ieee802154_frame_get_type(frame) == IEEE802154_FRAME_TYPE_ACK && ieee802154_frame_get_version(frame) == IEEE802154_FRAME_VERSION_2) {
ieee802154_set_state(IEEE802154_STATE_TX_ENH_ACK);
} else {
ieee802154_set_state(IEEE802154_STATE_TX);
}
ieee802154_enter_critical();
ieee802154_etm_set_event_task(IEEE802154_ETM_CHANNEL0, ETM_EVENT_TIMER0_OVERFLOW, ETM_TASK_TX_START);
ieee802154_timer0_fire_at(tx_target_time);
ieee802154_exit_critical();
}
ieee802154_set_state(cca ? IEEE802154_STATE_TX_CCA : IEEE802154_STATE_TX);
ieee802154_enter_critical();
ieee802154_etm_set_event_task(IEEE802154_ETM_CHANNEL0, ETM_EVENT_TIMER0_OVERFLOW, cca ? ETM_TASK_ED_TRIG_TX : ETM_TASK_TX_START);
ieee802154_timer0_fire_at(tx_target_time);
ieee802154_exit_critical();
if (time < rampup_time) {
// First start the transmit at and then print some logs.
ESP_EARLY_LOGE(IEEE802154_TAG, "Time should be longer than %d us to account for the TX ramp-up", rampup_time);
}
return ESP_OK;
}
@@ -976,6 +1061,7 @@ IEEE802154_NOINLINE static void ieee802154_start_receive_at(void* ctx)
esp_err_t ieee802154_receive_at(uint32_t time, uint32_t duration)
{
// TODO: Light sleep current optimization, TZ-1613.
uint32_t target_time = (time >= IEEE802154_RX_RAMPUP_TIME_US) ? time - IEEE802154_RX_RAMPUP_TIME_US : 0;
IEEE802154_RF_ENABLE();
ieee802154_enter_critical();
rx_init();
@@ -984,11 +1070,15 @@ esp_err_t ieee802154_receive_at(uint32_t time, uint32_t duration)
ieee802154_set_state(IEEE802154_STATE_RX);
ieee802154_etm_set_event_task(IEEE802154_ETM_CHANNEL1, ETM_EVENT_TIMER1_OVERFLOW, ETM_TASK_RX_START);
if (duration) {
ieee802154_timer1_fire_at_with_callback(time - IEEE802154_RX_RAMPUP_TIME_US, ieee802154_start_receive_at, (void*)(time + duration));
ieee802154_timer1_fire_at_with_callback(target_time, ieee802154_start_receive_at, (void*)(time + duration));
} else {
ieee802154_timer1_fire_at(time - IEEE802154_RX_RAMPUP_TIME_US);
ieee802154_timer1_fire_at(target_time);
}
ieee802154_exit_critical();
if (time < IEEE802154_RX_RAMPUP_TIME_US) {
// First start the receive at and then print some logs.
ESP_EARLY_LOGE(IEEE802154_TAG, "Time should be longer than %d us to account for the RX ramp-up", IEEE802154_RX_RAMPUP_TIME_US);
}
return ESP_OK;
}

View File

@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2023-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -10,6 +10,7 @@
#include "esp_ieee802154_dev.h"
#include "esp_ieee802154_frame.h"
#include "esp_ieee802154_util.h"
#include "esp_rom_sys.h"
bool ieee802154_frame_is_security_enabled(const uint8_t *frame)
{
@@ -42,14 +43,29 @@ IEEE802154_STATIC IEEE802154_INLINE bool is_panid_compression(const uint8_t *fra
return frame[IEEE802154_FRAME_PANID_COMP_OFFSET] & IEEE802154_FRAME_PANID_COMP_BIT;
}
IEEE802154_STATIC IEEE802154_INLINE bool is_valid_dst_mode(uint8_t dst_mode)
{
return (dst_mode == IEEE802154_FRAME_DST_MODE_NONE ||
dst_mode == IEEE802154_FRAME_DST_MODE_SHORT ||
dst_mode == IEEE802154_FRAME_DST_MODE_EXT);
}
IEEE802154_STATIC IEEE802154_INLINE bool is_valid_src_mode(uint8_t src_mode)
{
return (src_mode == IEEE802154_FRAME_SRC_MODE_NONE ||
src_mode == IEEE802154_FRAME_SRC_MODE_SHORT ||
src_mode == IEEE802154_FRAME_SRC_MODE_EXT);
}
IEEE802154_STATIC IEEE802154_NOINLINE bool is_dst_panid_present(const uint8_t *frame)
{
uint8_t dst_mode = dst_addr_mode(frame);
uint8_t src_mode = src_addr_mode(frame);
bool dst_panid_present = false;
bool panid_compression = is_panid_compression(frame);
IEEE802154_RETURN_ON_FALSE_SILENTLY(is_valid_dst_mode(dst_mode) && is_valid_src_mode(src_mode), false);
if (ieee802154_frame_get_version(frame) == IEEE802154_FRAME_VERSION_2) {
uint8_t src_mode = src_addr_mode(frame);
bool panid_compression = is_panid_compression(frame);
if (dst_mode != IEEE802154_FRAME_DST_MODE_NONE) { // dest address is present/short/extended
if ((src_mode == IEEE802154_FRAME_SRC_MODE_NONE && panid_compression) ||
@@ -74,13 +90,13 @@ IEEE802154_STATIC IEEE802154_NOINLINE bool is_dst_panid_present(const uint8_t *f
IEEE802154_STATIC IEEE802154_NOINLINE bool is_src_panid_present(const uint8_t *frame)
{
uint8_t dst_mode = dst_addr_mode(frame);
uint8_t src_mode = src_addr_mode(frame);
bool panid_compression = is_panid_compression(frame);
bool src_panid_present = false;
bool panid_compression = is_panid_compression(frame);
IEEE802154_RETURN_ON_FALSE_SILENTLY(is_valid_dst_mode(dst_mode) && is_valid_src_mode(src_mode), false);
if (ieee802154_frame_get_version(frame) == IEEE802154_FRAME_VERSION_2) {
uint8_t dst_mode = dst_addr_mode(frame);
if (src_mode != IEEE802154_FRAME_SRC_MODE_NONE) {
if (dst_mode == IEEE802154_FRAME_DST_MODE_EXT && src_mode == IEEE802154_FRAME_SRC_MODE_EXT && !panid_compression) {
src_panid_present = false;
@@ -101,6 +117,16 @@ IEEE802154_STATIC IEEE802154_NOINLINE bool is_src_panid_present(const uint8_t *f
return src_panid_present;
}
uint8_t IEEE802154_INLINE ieee802154_frame_get_type(const uint8_t *frame)
{
return frame[IEEE802154_FRAME_TYPE_OFFSET] & IEEE802154_FRAME_TYPE_MASK;
}
uint8_t IEEE802154_INLINE ieee802154_frame_get_version(const uint8_t *frame)
{
return frame[IEEE802154_FRAME_VERSION_OFFSET] & IEEE802154_FRAME_VERSION_MASK;
}
IEEE802154_STATIC uint8_t IEEE802154_INLINE ieee802154_frame_address_offset(const uint8_t *frame)
{
return IEEE802154_FRAME_PHR_SIZE + IEEE802154_FRAME_FCF_SIZE + (is_dsn_present(frame) ? IEEE802154_FRAME_DSN_SIZE : 0);
@@ -109,12 +135,17 @@ IEEE802154_STATIC uint8_t IEEE802154_INLINE ieee802154_frame_address_offset(cons
IEEE802154_STATIC IRAM_ATTR uint8_t ieee802154_frame_address_size(const uint8_t *frame)
{
uint8_t address_size = 0;
uint8_t dst_mode = dst_addr_mode(frame);
uint8_t src_mode = src_addr_mode(frame);
ESP_RETURN_ON_FALSE_ISR(is_valid_src_mode(src_mode) && is_valid_dst_mode(dst_mode), IEEE802154_FRAME_INVALID_VALUE, IEEE802154_TAG, "invalid address mode");
if (is_dst_panid_present(frame)) {
address_size += IEEE802154_FRAME_PANID_SIZE;
}
switch (dst_addr_mode(frame)) {
switch (dst_mode) {
case IEEE802154_FRAME_DST_MODE_NONE:
break;
@@ -127,14 +158,14 @@ IEEE802154_STATIC IRAM_ATTR uint8_t ieee802154_frame_address_size(const uint8_t
break;
default:
return IEEE802154_FRAME_INVALID_OFFSET;
break;
}
if (is_src_panid_present(frame)) {
address_size += IEEE802154_FRAME_PANID_SIZE;
}
switch (src_addr_mode(frame)) {
switch (src_mode) {
case IEEE802154_FRAME_SRC_MODE_NONE:
break;
@@ -147,7 +178,7 @@ IEEE802154_STATIC IRAM_ATTR uint8_t ieee802154_frame_address_size(const uint8_t
break;
default:
return IEEE802154_FRAME_INVALID_OFFSET;
break;
}
return address_size;
@@ -155,12 +186,11 @@ IEEE802154_STATIC IRAM_ATTR uint8_t ieee802154_frame_address_size(const uint8_t
IEEE802154_STATIC IEEE802154_NOINLINE uint8_t ieee802154_frame_security_header_offset(const uint8_t *frame)
{
ESP_RETURN_ON_FALSE_ISR(ieee802154_is_supported_frame_type(ieee802154_frame_get_type(frame)), IEEE802154_FRAME_INVALID_ADDR_MODE, IEEE802154_TAG, "invalid frame type");
IEEE802154_RETURN_ON_FALSE_SILENTLY(ieee802154_is_supported_frame_type(ieee802154_frame_get_type(frame)), IEEE802154_FRAME_INVALID_VALUE);
uint8_t offset = ieee802154_frame_address_offset(frame);
IEEE802154_RETURN_ON_FALSE_SILENTLY(offset != IEEE802154_FRAME_INVALID_VALUE, IEEE802154_FRAME_INVALID_VALUE);
uint8_t address_size = ieee802154_frame_address_size(frame);
ESP_RETURN_ON_FALSE_ISR(offset != IEEE802154_FRAME_INVALID_OFFSET, IEEE802154_FRAME_INVALID_OFFSET, IEEE802154_TAG, "invalid offset");
ESP_RETURN_ON_FALSE_ISR(address_size != IEEE802154_FRAME_INVALID_OFFSET, IEEE802154_FRAME_INVALID_OFFSET, IEEE802154_TAG, "invalid offset");
IEEE802154_RETURN_ON_FALSE_SILENTLY(address_size != IEEE802154_FRAME_INVALID_VALUE, IEEE802154_FRAME_INVALID_VALUE);
offset += address_size;
@@ -169,12 +199,12 @@ IEEE802154_STATIC IEEE802154_NOINLINE uint8_t ieee802154_frame_security_header_o
IEEE802154_STATIC IEEE802154_NOINLINE uint8_t ieee802154_frame_get_security_field_len(const uint8_t *frame)
{
ESP_RETURN_ON_FALSE_ISR(ieee802154_is_supported_frame_type(ieee802154_frame_get_type(frame)), IEEE802154_FRAME_INVALID_OFFSET, IEEE802154_TAG, "invalid frame type");
ESP_RETURN_ON_FALSE_ISR(ieee802154_is_supported_frame_type(ieee802154_frame_get_type(frame)), IEEE802154_FRAME_INVALID_VALUE, IEEE802154_TAG, "invalid frame type");
uint8_t security_field_len = 0;
uint8_t offset = ieee802154_frame_security_header_offset(frame);
ESP_RETURN_ON_FALSE_ISR(offset != IEEE802154_FRAME_INVALID_OFFSET, IEEE802154_FRAME_INVALID_OFFSET, IEEE802154_TAG, "invalid offset");
ESP_RETURN_ON_FALSE_ISR(offset != IEEE802154_FRAME_INVALID_VALUE, IEEE802154_FRAME_INVALID_VALUE, IEEE802154_TAG, "invalid offset");
security_field_len += IEEE802154_FRAME_SE_HEAD_SIZE;
uint8_t security_header = frame[offset];
@@ -206,7 +236,9 @@ IEEE802154_STATIC IEEE802154_NOINLINE uint8_t ieee802154_frame_get_security_fiel
IEEE802154_STATIC uint8_t ieee802154_frame_ie_header_offset(const uint8_t *frame)
{
uint8_t offset = ieee802154_frame_security_header_offset(frame);
IEEE802154_RETURN_ON_FALSE_SILENTLY(offset != IEEE802154_FRAME_INVALID_VALUE, IEEE802154_FRAME_INVALID_VALUE);
uint8_t security_field_len = ieee802154_frame_get_security_field_len(frame);
IEEE802154_RETURN_ON_FALSE_SILENTLY(security_field_len != IEEE802154_FRAME_INVALID_VALUE, IEEE802154_FRAME_INVALID_VALUE);
offset += security_field_len;
@@ -216,6 +248,7 @@ IEEE802154_STATIC uint8_t ieee802154_frame_ie_header_offset(const uint8_t *frame
IEEE802154_STATIC uint8_t ieee802154_frame_get_mic_len(const uint8_t *frame)
{
uint8_t offset = ieee802154_frame_security_header_offset(frame);
IEEE802154_RETURN_ON_FALSE_SILENTLY(offset != IEEE802154_FRAME_INVALID_VALUE, 0);
uint8_t mic_len = 0;
uint8_t security_header = frame[offset];
@@ -242,8 +275,10 @@ IEEE802154_STATIC uint8_t ieee802154_frame_get_mic_len(const uint8_t *frame)
IEEE802154_STATIC uint8_t ieee802154_frame_get_ie_field_len(const uint8_t *frame)
{
uint8_t offset = ieee802154_frame_ie_header_offset(frame);
IEEE802154_RETURN_ON_FALSE_SILENTLY(offset != IEEE802154_FRAME_INVALID_VALUE, IEEE802154_FRAME_INVALID_VALUE);
uint8_t ie_field_len = 0;
uint8_t frame_footer_len = ieee802154_frame_get_mic_len(frame) + IEEE802154_FRAME_FCS_SIZE;
uint8_t frame_len = frame[0];
/* If the `offset + frame_footer_len == frame_len`, we exit the `while()`
loop. This covers the case where frame contains one or more Header IEs
@@ -253,6 +288,9 @@ IEEE802154_STATIC uint8_t ieee802154_frame_get_ie_field_len(const uint8_t *frame
footer length. (for details, please reference 2015 - spec table 7 - 6 in page 169) */
while (frame[0] > offset + ie_field_len + frame_footer_len) {
if (offset + ie_field_len + 1 >= frame_len) {
break;
}
uint16_t ie_header = frame[offset + ie_field_len + 1] << 8 | frame[offset + ie_field_len];
// Header Termination IE 2 is used in to signal end of the MHR and beginning of the MAC Payload.
if ((ie_header & IEEE802154_FRAME_IE_HEAD_ID_MASK) == IEEE802154_IE_TYPE_HT2) {
@@ -269,9 +307,12 @@ IEEE802154_STATIC uint8_t ieee802154_frame_get_ie_field_len(const uint8_t *frame
IEEE802154_STATIC IRAM_ATTR uint8_t ieee802154_frame_payload_offset(const uint8_t *frame)
{
uint8_t offset = ieee802154_frame_security_header_offset(frame);
IEEE802154_RETURN_ON_FALSE_SILENTLY(offset != IEEE802154_FRAME_INVALID_VALUE, IEEE802154_FRAME_INVALID_VALUE);
if (ieee802154_frame_is_security_enabled(frame)) {
// skip security field.
offset += ieee802154_frame_get_security_field_len(frame);
uint8_t security_field_len = ieee802154_frame_get_security_field_len(frame);
IEEE802154_RETURN_ON_FALSE_SILENTLY(security_field_len != IEEE802154_FRAME_INVALID_VALUE, IEEE802154_FRAME_INVALID_VALUE);
offset += security_field_len;
}
if (ieee802154_frame_get_version(frame) == IEEE802154_FRAME_VERSION_2 && is_ie_present(frame)) {
@@ -290,31 +331,44 @@ IEEE802154_STATIC IRAM_ATTR uint8_t ieee802154_frame_payload_offset(const uint8_
return offset - 1;
}
uint8_t IEEE802154_INLINE ieee802154_frame_get_type(const uint8_t *frame)
bool ieee802154_is_data_request(const uint8_t *frame)
{
return frame[IEEE802154_FRAME_TYPE_OFFSET] & IEEE802154_FRAME_TYPE_MASK;
}
if (ieee802154_frame_get_type(frame) != IEEE802154_FRAME_TYPE_COMMAND) {
return false;
}
uint8_t offset = ieee802154_frame_security_header_offset(frame);
if (ieee802154_frame_is_security_enabled(frame)) {
// skip security field.
offset += ieee802154_frame_get_security_field_len(frame);
}
uint8_t IEEE802154_INLINE ieee802154_frame_get_version(const uint8_t *frame)
{
return frame[IEEE802154_FRAME_VERSION_OFFSET] & IEEE802154_FRAME_VERSION_MASK;
if (ieee802154_frame_get_version(frame) == IEEE802154_FRAME_VERSION_2 && is_ie_present(frame)) {
// skip IE fields.
offset += ieee802154_frame_get_ie_field_len(frame);
}
if (frame[offset] == IEEE802154_CMD_DATA_REQ) {
return true;
}
return false;
}
bool IEEE802154_INLINE ieee802154_frame_is_ack_required(const uint8_t *frame)
{
return (ieee802154_is_supported_frame_type(ieee802154_frame_get_type(frame))) && (frame[IEEE802154_FRAME_AR_OFFSET] & IEEE802154_FRAME_AR_BIT);
IEEE802154_RETURN_ON_FALSE_SILENTLY(ieee802154_is_supported_frame_type(ieee802154_frame_get_type(frame)), false);
return (frame[IEEE802154_FRAME_AR_OFFSET] & IEEE802154_FRAME_AR_BIT);
}
uint8_t ieee802154_frame_get_dst_addr(const uint8_t *frame, uint8_t *addr)
{
ESP_RETURN_ON_FALSE_ISR(ieee802154_is_supported_frame_type(ieee802154_frame_get_type(frame)), IEEE802154_FRAME_INVALID_ADDR_MODE, IEEE802154_TAG, "invalid frame type");
ESP_RETURN_ON_FALSE_ISR(ieee802154_is_supported_frame_type(ieee802154_frame_get_type(frame)), IEEE802154_FRAME_INVALID_VALUE, IEEE802154_TAG, "invalid frame type");
uint8_t offset = ieee802154_frame_address_offset(frame);
uint8_t dst_mode = dst_addr_mode(frame);
uint8_t addr_size;
ESP_RETURN_ON_FALSE_ISR(dst_mode == IEEE802154_FRAME_DST_MODE_SHORT || dst_mode == IEEE802154_FRAME_DST_MODE_EXT, dst_mode, IEEE802154_TAG, "invalid address mode");
uint8_t addr_size = 0;
ESP_RETURN_ON_FALSE_ISR(is_valid_dst_mode(dst_mode), IEEE802154_FRAME_INVALID_VALUE, IEEE802154_TAG, "invalid destination address mode");
IEEE802154_RETURN_ON_FALSE_SILENTLY(dst_mode != IEEE802154_FRAME_DST_MODE_NONE, IEEE802154_FRAME_DST_MODE_NONE);
addr_size = (dst_mode == IEEE802154_FRAME_DST_MODE_SHORT) ? IEEE802154_FRAME_SHORT_ADDR_SIZE : IEEE802154_FRAME_EXT_ADDR_SIZE;
if (is_dst_panid_present(frame)) {
@@ -328,15 +382,16 @@ uint8_t ieee802154_frame_get_dst_addr(const uint8_t *frame, uint8_t *addr)
uint8_t ieee802154_frame_get_src_addr(const uint8_t *frame, uint8_t *addr)
{
ESP_RETURN_ON_FALSE_ISR(ieee802154_is_supported_frame_type(ieee802154_frame_get_type(frame)), IEEE802154_FRAME_INVALID_ADDR_MODE, IEEE802154_TAG, "invalid frame type");
ESP_RETURN_ON_FALSE_ISR(ieee802154_is_supported_frame_type(ieee802154_frame_get_type(frame)), IEEE802154_FRAME_INVALID_VALUE, IEEE802154_TAG, "invalid frame type");
uint8_t offset = ieee802154_frame_address_offset(frame);
uint8_t dst_mode = dst_addr_mode(frame);
uint8_t src_mode = src_addr_mode(frame);
uint8_t addr_size;
uint8_t addr_size = 0;
ESP_RETURN_ON_FALSE_ISR(src_mode == IEEE802154_FRAME_SRC_MODE_SHORT || src_mode == IEEE802154_FRAME_SRC_MODE_EXT, src_mode, IEEE802154_TAG, "invalid address mode");
ESP_RETURN_ON_FALSE_ISR(is_valid_src_mode(src_mode) && is_valid_dst_mode(dst_mode), IEEE802154_FRAME_INVALID_VALUE, IEEE802154_TAG, "invalid address mode");
IEEE802154_RETURN_ON_FALSE_SILENTLY(src_mode != IEEE802154_FRAME_SRC_MODE_NONE, IEEE802154_FRAME_SRC_MODE_NONE);
addr_size = (src_mode == IEEE802154_FRAME_SRC_MODE_SHORT) ? IEEE802154_FRAME_SHORT_ADDR_SIZE : IEEE802154_FRAME_EXT_ADDR_SIZE;
if (is_dst_panid_present(frame)) {
@@ -367,7 +422,9 @@ uint8_t ieee802154_frame_get_src_addr(const uint8_t *frame, uint8_t *addr)
uint8_t ieee802154_frame_get_security_payload_offset(uint8_t *frame)
{
return ieee802154_frame_payload_offset(frame);
uint8_t offset = ieee802154_frame_payload_offset(frame);
ESP_RETURN_ON_FALSE_ISR(offset != IEEE802154_FRAME_INVALID_VALUE, IEEE802154_FRAME_INVALID_VALUE, IEEE802154_TAG, "invalid offset");
return offset;
}
esp_err_t ieee802154_frame_get_dest_panid(const uint8_t *frame, uint8_t *panid)
@@ -385,6 +442,7 @@ esp_err_t ieee802154_frame_get_src_panid(const uint8_t *frame, uint8_t *panid)
{
uint8_t offset = ieee802154_frame_address_offset(frame);
uint8_t dst_mode = dst_addr_mode(frame);
IEEE802154_RETURN_ON_FALSE_SILENTLY(is_valid_dst_mode(dst_mode), ESP_FAIL);
if (is_src_panid_present(frame)) {
if (is_dst_panid_present(frame)) {

View File

@@ -1,11 +1,12 @@
/*
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2023-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdint.h>
#include <string.h>
#include "sdkconfig.h"
#include "hal/ieee802154_ll.h"
#include "esp_check.h"
#include "esp_ieee802154_pib.h"
@@ -14,6 +15,30 @@
static ieee802154_pib_t s_ieee802154_pib;
static bool is_pending = false;
extern const int8_t* bt_bb_get_tx_pwr_table(uint8_t *length);
static inline int8_t IEEE802154_TXPOWER_VALUE_MAX(void)
{
uint8_t length = 0;
const int8_t *tx_pwr_table = bt_bb_get_tx_pwr_table(&length);
if (!tx_pwr_table || length == 0) {
ESP_LOGE(IEEE802154_TAG, "Failed to get tx power table");
return 0;
}
return tx_pwr_table[length - 1];
}
static inline int8_t IEEE802154_TXPOWER_VALUE_MIN(void)
{
uint8_t length = 0;
const int8_t *tx_pwr_table = bt_bb_get_tx_pwr_table(&length);
if (!tx_pwr_table || length == 0) {
ESP_LOGE(IEEE802154_TAG, "Failed to get tx power table");
return 0;
}
return tx_pwr_table[0];
}
static inline void set_pending(void)
{
is_pending = true;
@@ -24,7 +49,7 @@ static inline void clr_pending(void)
is_pending = false;
}
bool inline ieee802154_pib_is_pending(void)
inline bool ieee802154_pib_is_pending(void)
{
return is_pending;
}
@@ -41,22 +66,38 @@ void ieee802154_pib_init(void)
s_ieee802154_pib.channel = 11;
s_ieee802154_pib.cca_threshold = CONFIG_IEEE802154_CCA_THRESHOLD;
s_ieee802154_pib.cca_mode = CONFIG_IEEE802154_CCA_MODE;
memset(&s_ieee802154_pib.power_table, IEEE802154_TXPOWER_VALUE_MAX, sizeof(s_ieee802154_pib.power_table));
for (int i = 0; i < 16; i++) {
s_ieee802154_pib.power_table.channel[i] = IEEE802154_TXPOWER_VALUE_MAX();
}
set_pending();
}
IEEE802154_NOINLINE static uint8_t ieee802154_txpower_convert(int8_t txpower)
{
uint8_t ieee820154_txpower_index = 0;
if (txpower >= IEEE802154_TXPOWER_VALUE_MAX) {
ieee820154_txpower_index = 15;
} else if (txpower <= IEEE802154_TXPOWER_VALUE_MIN) {
ieee820154_txpower_index = IEEE802154_TXPOWER_INDEX_MIN;
} else {
ieee820154_txpower_index = (uint8_t)((txpower - IEEE802154_TXPOWER_VALUE_MIN) / 3) + IEEE802154_TXPOWER_INDEX_MIN;
uint8_t ieee802154_txpower_index = 0;
uint8_t length = 0;
const int8_t *tx_pwr_table = bt_bb_get_tx_pwr_table(&length);
if (!tx_pwr_table || length == 0) {
ESP_LOGE(IEEE802154_TAG, "Failed to get tx power table");
return 0;
}
return ieee820154_txpower_index;
if (txpower <= tx_pwr_table[0]) {
ieee802154_txpower_index = 0;
} else if (txpower >= tx_pwr_table[length - 1]) {
ieee802154_txpower_index = length - 1;
} else {
uint8_t i = 0;
for (i = length-1; i != 0; i--) {
if (tx_pwr_table[i] <= txpower) {
break;
}
}
ieee802154_txpower_index = i;
}
return ieee802154_txpower_index;
}
void ieee802154_pib_update(void)
@@ -74,7 +115,14 @@ void ieee802154_pib_update(void)
ieee802154_ll_set_coordinator(s_ieee802154_pib.coordinator);
ieee802154_ll_set_promiscuous(s_ieee802154_pib.promiscuous);
ieee802154_ll_set_pending_mode(s_ieee802154_pib.pending_mode == IEEE802154_AUTO_PENDING_ENHANCED);
bool target_mode = false;
for (int i = 0; i < CONFIG_IEEE802154_INTERFACE_NUM; i++) {
if (s_ieee802154_pib.pending_mode[i] == IEEE802154_AUTO_PENDING_ENHANCED || s_ieee802154_pib.pending_mode[i] == IEEE802154_AUTO_PENDING_ZIGBEE) {
target_mode = true;
break;
}
}
ieee802154_ll_set_pending_mode(target_mode);
clr_pending();
}
@@ -87,7 +135,7 @@ uint8_t ieee802154_pib_get_channel(void)
void ieee802154_pib_set_channel(uint8_t channel)
{
ESP_RETURN_ON_FALSE(ieee802154_is_valid_channel(channel), , IEEE802154_TAG, "Failed to set channel, reason: Invalid channel: %d", channel);
ESP_RETURN_VOID_ON_FALSE(ieee802154_is_valid_channel(channel), IEEE802154_TAG, "Failed to set channel, reason: Invalid channel: %d", channel);
if (s_ieee802154_pib.channel != channel) {
s_ieee802154_pib.channel = channel;
set_pending();
@@ -231,15 +279,15 @@ void ieee802154_pib_set_coordinator(bool enable)
}
}
ieee802154_ll_pending_mode_t ieee802154_pib_get_pending_mode(void)
ieee802154_ll_pending_mode_t ieee802154_pib_get_pending_mode(esp_ieee802154_multipan_index_t inf_index)
{
return s_ieee802154_pib.pending_mode;
return s_ieee802154_pib.pending_mode[inf_index];
}
void ieee802154_pib_set_pending_mode(ieee802154_ll_pending_mode_t pending_mode)
void ieee802154_pib_set_pending_mode(esp_ieee802154_multipan_index_t inf_index, ieee802154_ll_pending_mode_t pending_mode)
{
if (s_ieee802154_pib.pending_mode != pending_mode) {
s_ieee802154_pib.pending_mode = pending_mode;
if (s_ieee802154_pib.pending_mode[inf_index] != pending_mode) {
s_ieee802154_pib.pending_mode[inf_index] = pending_mode;
set_pending();
}
}

View File

@@ -30,10 +30,7 @@ void ieee802154_timer0_stop(void)
esp_err_t ieee802154_timer0_set_threshold(uint32_t value)
{
ESP_RETURN_ON_FALSE((value < IEEE802154_TIMER0_THRESHOLD), ESP_ERR_INVALID_ARG, IEEE802154_TAG, "invalid timer0 threshold");
ieee802154_ll_timer0_set_threshold(value);
return ESP_OK;
}
@@ -56,10 +53,7 @@ void ieee802154_timer1_stop(void)
esp_err_t ieee802154_timer1_set_threshold(uint32_t value)
{
ESP_RETURN_ON_FALSE((value < IEEE802154_TIMER1_THRESHOLD), ESP_ERR_INVALID_ARG, IEEE802154_TAG, "invalid timer1 threshold");
ieee802154_ll_timer1_set_threshold(value);
return ESP_OK;
}

View File

@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2023-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -8,16 +8,21 @@
#include "soc/soc.h"
#include "soc/periph_defs.h"
#include "hal/ieee802154_ll.h"
#include "esp_check.h"
#include "esp_coex_i154.h"
#include "esp_ieee802154_util.h"
uint8_t ieee802154_freq_to_channel(uint8_t freq)
{
return (freq - 3) / 5 + IEEE802154_OQPSK_2P4G_CHANNEL_MIN;
assert(((freq - 3) % 5) == 0);
uint8_t channel = (freq - 3) / 5 + IEEE802154_OQPSK_2P4G_CHANNEL_MIN;
assert(ieee802154_is_valid_channel(channel));
return channel;
}
uint8_t ieee802154_channel_to_freq(uint8_t channel)
{
assert(ieee802154_is_valid_channel(channel));
return (channel - IEEE802154_OQPSK_2P4G_CHANNEL_MIN) * 5 + 3;
}
@@ -43,7 +48,6 @@ esp_ieee802154_coex_config_t ieee802154_get_coex_config(void)
void ieee802154_set_txrx_pti(ieee802154_txrx_scene_t txrx_scene)
{
switch (txrx_scene) {
case IEEE802154_SCENE_IDLE:
esp_coex_ieee802154_txrx_pti_set(s_coex_config.idle);
@@ -66,8 +70,9 @@ void ieee802154_set_txrx_pti(ieee802154_txrx_scene_t txrx_scene)
// TZ-97: implement these two functions using ETM common interface
void ieee802154_etm_channel_clear(uint32_t channel)
{
assert(channel < 16);
if ((REG_READ(ETM_CHEN_AD0_REG) & (1 << channel))) {
REG_WRITE(ETM_CHENCLR_AD0_REG, (REG_READ(ETM_CHENCLR_AD0_REG)) | 1 << channel);
REG_WRITE(ETM_CHENCLR_AD0_REG, (REG_READ(ETM_CHENCLR_AD0_REG)) | (1 << channel));
}
}
@@ -78,5 +83,11 @@ void ieee802154_etm_set_event_task(uint32_t channel, uint32_t event, uint32_t ta
REG_WRITE((ETM_CH0_EVT_ID_REG + ETM_CH_OFFSET * channel), event);
REG_WRITE((ETM_CH0_TASK_ID_REG + ETM_CH_OFFSET * channel), task);
REG_WRITE(ETM_CHENSET_AD0_REG, (REG_READ(ETM_CHENSET_AD0_REG) | 1 << channel));
REG_WRITE(ETM_CHENSET_AD0_REG, (REG_READ(ETM_CHENSET_AD0_REG) | (1 << channel)));
}
__attribute__((weak)) const int8_t* bt_bb_get_tx_pwr_table(uint8_t *length)
{
ESP_LOGE(IEEE802154_TAG, "bt_bb_get_tx_pwr_table is not implemented");
return NULL;
}

View File

@@ -8,6 +8,7 @@
#include <string.h>
#include "sdkconfig.h"
#include "esp_ieee802154.h"
#include "esp_check.h"
#include "esp_err.h"
#include "esp_phy_init.h"
#include "esp_ieee802154_ack.h"
@@ -26,6 +27,7 @@ esp_err_t esp_ieee802154_event_callback_list_register(esp_ieee802154_event_cb_li
{
return ieee802154_event_callback_list_register(cb_list);
}
esp_err_t esp_ieee802154_event_callback_list_unregister(void)
{
return ieee802154_event_callback_list_unregister();
@@ -54,6 +56,7 @@ uint8_t esp_ieee802154_get_channel(void)
esp_err_t esp_ieee802154_set_channel(uint8_t channel)
{
assert(ieee802154_is_valid_channel(channel));
ieee802154_pib_set_channel(channel);
return ESP_OK;
}
@@ -66,7 +69,9 @@ int8_t esp_ieee802154_get_txpower(void)
esp_err_t esp_ieee802154_set_txpower(int8_t power)
{
esp_ieee802154_txpower_table_t power_table;
memset(&power_table, power, sizeof(power_table));
for (int i = 0; i < 16; i++) {
power_table.channel[i] = power;
}
return ieee802154_pib_set_power_table(power_table);
}
@@ -77,6 +82,7 @@ esp_err_t esp_ieee802154_set_power_table(esp_ieee802154_txpower_table_t power_ta
esp_err_t esp_ieee802154_get_power_table(esp_ieee802154_txpower_table_t *out_power_table)
{
assert(out_power_table != NULL);
return ieee802154_pib_get_power_table(out_power_table);
}
@@ -87,6 +93,7 @@ esp_err_t esp_ieee802154_set_power_with_channel(uint8_t channel, int8_t power)
esp_err_t esp_ieee802154_get_power_with_channel(uint8_t channel, int8_t *out_power)
{
assert(out_power != NULL);
return ieee802154_pib_get_power_with_channel(channel, out_power);
}
@@ -163,40 +170,42 @@ esp_err_t esp_ieee802154_set_coordinator(bool enable)
uint16_t esp_ieee802154_get_multipan_panid(esp_ieee802154_multipan_index_t index)
{
assert(index < ESP_IEEE802154_MULTIPAN_MAX);
assert(index < CONFIG_IEEE802154_INTERFACE_NUM);
return ieee802154_ll_get_multipan_panid(index);
}
esp_err_t esp_ieee802154_set_multipan_panid(esp_ieee802154_multipan_index_t index, uint16_t panid)
{
assert(index < ESP_IEEE802154_MULTIPAN_MAX);
assert(index < CONFIG_IEEE802154_INTERFACE_NUM);
ieee802154_ll_set_multipan_panid(index, panid);
return ESP_OK;
}
uint16_t esp_ieee802154_get_multipan_short_address(esp_ieee802154_multipan_index_t index)
{
assert(index < ESP_IEEE802154_MULTIPAN_MAX);
assert(index < CONFIG_IEEE802154_INTERFACE_NUM);
return ieee802154_ll_get_multipan_short_addr(index);
}
esp_err_t esp_ieee802154_set_multipan_short_address(esp_ieee802154_multipan_index_t index, uint16_t short_address)
{
assert(index < ESP_IEEE802154_MULTIPAN_MAX);
assert(index < CONFIG_IEEE802154_INTERFACE_NUM);
ieee802154_ll_set_multipan_short_addr(index, short_address);
return ESP_OK;
}
esp_err_t esp_ieee802154_get_multipan_extended_address(esp_ieee802154_multipan_index_t index, uint8_t *ext_addr)
{
assert(index < ESP_IEEE802154_MULTIPAN_MAX);
assert(index < CONFIG_IEEE802154_INTERFACE_NUM);
assert(ext_addr != NULL);
ieee802154_ll_get_multipan_ext_addr(index, ext_addr);
return ESP_OK;
}
esp_err_t esp_ieee802154_set_multipan_extended_address(esp_ieee802154_multipan_index_t index, const uint8_t *ext_addr)
{
assert(index < ESP_IEEE802154_MULTIPAN_MAX);
assert(index < CONFIG_IEEE802154_INTERFACE_NUM);
assert(ext_addr != NULL);
ieee802154_ll_set_multipan_ext_addr(index, ext_addr);
return ESP_OK;
}
@@ -208,17 +217,50 @@ uint8_t esp_ieee802154_get_multipan_enable(void)
esp_err_t esp_ieee802154_set_multipan_enable(uint8_t mask)
{
assert(mask < (1 << ESP_IEEE802154_MULTIPAN_MAX));
assert(mask < (1 << CONFIG_IEEE802154_INTERFACE_NUM));
ieee802154_ll_set_multipan_enable_mask(mask);
return ESP_OK;
}
esp_ieee802154_pending_mode_t esp_ieee802154_multipan_get_pending_mode(esp_ieee802154_multipan_index_t index)
{
assert(index < CONFIG_IEEE802154_INTERFACE_NUM);
return ieee802154_pib_get_pending_mode(index);
}
esp_err_t esp_ieee802154_multipan_set_pending_mode(esp_ieee802154_multipan_index_t inf_index, esp_ieee802154_pending_mode_t pending_mode)
{
assert(inf_index < CONFIG_IEEE802154_INTERFACE_NUM);
ieee802154_pib_set_pending_mode(inf_index, pending_mode);
return ESP_OK;
}
esp_err_t esp_ieee802154_multipan_add_pending_addr(esp_ieee802154_multipan_index_t inf_index, const uint8_t *addr, bool is_short)
{
assert(inf_index < CONFIG_IEEE802154_INTERFACE_NUM);
return ieee802154_add_pending_addr(inf_index, addr, is_short);
}
esp_err_t esp_ieee802154_multipan_clear_pending_addr(esp_ieee802154_multipan_index_t inf_index, const uint8_t *addr, bool is_short)
{
assert(inf_index < CONFIG_IEEE802154_INTERFACE_NUM);
return ieee802154_clear_pending_addr(inf_index, addr, is_short);
}
esp_err_t esp_ieee802154_multipan_reset_pending_table(esp_ieee802154_multipan_index_t inf_index, bool is_short)
{
assert(inf_index < CONFIG_IEEE802154_INTERFACE_NUM);
ieee802154_reset_pending_table(inf_index, is_short);
return ESP_OK;
}
#endif // CONFIG_IEEE802154_MULTI_PAN_ENABLE
esp_err_t esp_ieee802154_set_ack_timeout(uint32_t timeout)
{
// Divide by 16 and round it up.
uint32_t target_reg_value = (timeout + 15) / 16;
if((timeout % 16) != 0) {
if ((timeout % 16) != 0) {
ESP_LOGW(IEEE802154_TAG, "Ack timeout should be a multiple of 16, input %"PRIu32", will be replaced by %"PRIu32"", timeout, (target_reg_value * 16));
}
ieee802154_ll_set_ack_timeout(target_reg_value);
@@ -254,24 +296,26 @@ esp_err_t esp_ieee802154_set_short_address(uint16_t short_address)
esp_err_t esp_ieee802154_get_extended_address(uint8_t *ext_addr)
{
assert(ext_addr != NULL);
ieee802154_ll_get_multipan_ext_addr(ESP_IEEE802154_MULTIPAN_0, ext_addr);
return ESP_OK;
}
esp_err_t esp_ieee802154_set_extended_address(const uint8_t *ext_addr)
{
assert(ext_addr != NULL);
ieee802154_ll_set_multipan_ext_addr(ESP_IEEE802154_MULTIPAN_0, ext_addr);
return ESP_OK;
}
esp_ieee802154_pending_mode_t esp_ieee802154_get_pending_mode(void)
{
return ieee802154_pib_get_pending_mode();
return ieee802154_pib_get_pending_mode(ESP_IEEE802154_MULTIPAN_0);
}
esp_err_t esp_ieee802154_set_pending_mode(esp_ieee802154_pending_mode_t pending_mode)
{
ieee802154_pib_set_pending_mode(pending_mode);
ieee802154_pib_set_pending_mode(ESP_IEEE802154_MULTIPAN_0, pending_mode);
return ESP_OK;
}
@@ -288,11 +332,15 @@ bool esp_ieee802154_get_rx_when_idle(void)
esp_err_t esp_ieee802154_transmit(const uint8_t *frame, bool cca)
{
assert(frame != NULL);
assert(frame[0] <= 127);
return ieee802154_transmit(frame, cca);
}
esp_err_t esp_ieee802154_transmit_at(const uint8_t *frame, bool cca, uint32_t time)
{
assert(frame != NULL);
assert(frame[0] <= 127);
return ieee802154_transmit_at(frame, cca, time);
}
@@ -342,10 +390,12 @@ esp_ieee802154_state_t esp_ieee802154_get_state(void)
case IEEE802154_STATE_TX_CCA:
case IEEE802154_STATE_CCA:
case IEEE802154_STATE_TX:
case IEEE802154_STATE_TEST_TX:
case IEEE802154_STATE_RX_ACK:
return ESP_IEEE802154_RADIO_TRANSMIT;
default:
ESP_LOGE(IEEE802154_TAG, "Invalid state: %d", ieee802154_get_state());
assert(false);
return ESP_IEEE802154_RADIO_DISABLE;
}
@@ -353,23 +403,28 @@ esp_ieee802154_state_t esp_ieee802154_get_state(void)
esp_err_t esp_ieee802154_set_transmit_security(uint8_t *frame, uint8_t *key, uint8_t *addr)
{
assert(frame != NULL);
assert(key != NULL);
assert(addr != NULL);
ieee802154_transmit_security_config(frame, key, addr);
return ESP_OK;
}
esp_err_t esp_ieee802154_add_pending_addr(const uint8_t *addr, bool is_short)
{
return ieee802154_add_pending_addr(addr, is_short);
assert(addr != NULL);
return ieee802154_add_pending_addr(ESP_IEEE802154_MULTIPAN_0, addr, is_short);
}
esp_err_t esp_ieee802154_clear_pending_addr(const uint8_t *addr, bool is_short)
{
return ieee802154_clear_pending_addr(addr, is_short);
assert(addr != NULL);
return ieee802154_clear_pending_addr(ESP_IEEE802154_MULTIPAN_0, addr, is_short);
}
esp_err_t esp_ieee802154_reset_pending_table(bool is_short)
{
ieee802154_reset_pending_table(is_short);
ieee802154_reset_pending_table(ESP_IEEE802154_MULTIPAN_0, is_short);
return ESP_OK;
}
@@ -432,6 +487,7 @@ __attribute__((weak)) void esp_ieee802154_ed_failed(uint16_t error)
{
}
__attribute__((weak)) void esp_ieee802154_receive_at_done(void)
{
@@ -439,7 +495,7 @@ __attribute__((weak)) void esp_ieee802154_receive_at_done(void)
__attribute__((weak)) esp_err_t esp_ieee802154_enh_ack_generator(uint8_t *frame, esp_ieee802154_frame_info_t *frame_info, uint8_t* enhack_frame)
{
ESP_EARLY_LOGE(IEEE802154_TAG, "Not implement for the enh-ack generating handler");
ESP_EARLY_LOGE(IEEE802154_TAG, "Not implemented for the enh-ack generating handler");
return ESP_FAIL;
}

View File

@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2021-2025 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2021-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -257,10 +257,11 @@ esp_err_t esp_ieee802154_set_short_address(uint16_t short_address);
/**
* @brief Get the device extended address.
*
* @param[out] ext_addr The pointer to the device extended address.
* @param[out] ext_addr The pointer to the device extended address. Must not be NULL.
*
* @return
* - ESP_OK on success.
* - ESP_ERR_INVALID_ARG if ext_addr is NULL.
* - ESP_FAIL on failure.
*/
esp_err_t esp_ieee802154_get_extended_address(uint8_t *ext_addr);
@@ -268,10 +269,11 @@ esp_err_t esp_ieee802154_get_extended_address(uint8_t *ext_addr);
/**
* @brief Set the device extended address.
*
* @param[in] ext_addr The pointer to the device extended address.
* @param[in] ext_addr The pointer to the device extended address. Must not be NULL.
*
* @return
* - ESP_OK on success.
* - ESP_ERR_INVALID_ARG if ext_addr is NULL.
* - ESP_FAIL on failure.
*/
esp_err_t esp_ieee802154_set_extended_address(const uint8_t *ext_addr);
@@ -324,10 +326,11 @@ esp_err_t esp_ieee802154_set_multipan_short_address(esp_ieee802154_multipan_inde
* @brief Get the device extended address for specific interface.
*
* @param[in] index The interface index.
* @param[out] ext_addr The pointer to the device extended address.
* @param[out] ext_addr The pointer to the device extended address. Must not be NULL.
*
* @return
* - ESP_OK on success.
* - ESP_ERR_INVALID_ARG if ext_addr is NULL.
* - ESP_FAIL on failure.
*/
esp_err_t esp_ieee802154_get_multipan_extended_address(esp_ieee802154_multipan_index_t index, uint8_t *ext_addr);
@@ -336,10 +339,11 @@ esp_err_t esp_ieee802154_get_multipan_extended_address(esp_ieee802154_multipan_i
* @brief Set the device extended address for specific interface.
*
* @param[in] index The interface index.
* @param[in] ext_addr The pointer to the device extended address.
* @param[in] ext_addr The pointer to the device extended address. Must not be NULL.
*
* @return
* - ESP_OK on success.
* - ESP_ERR_INVALID_ARG if addr is NULL.
* - ESP_FAIL on failure.
*/
esp_err_t esp_ieee802154_set_multipan_extended_address(esp_ieee802154_multipan_index_t index, const uint8_t *ext_addr);
@@ -409,12 +413,13 @@ esp_err_t esp_ieee802154_set_pending_mode(esp_ieee802154_pending_mode_t pending_
/**
* @brief Add address to the source matching table.
*
* @param[in] addr The pointer to the address.
* @param[in] addr The pointer to the address. Must not be NULL.
* @param[in] is_short Short address or Extended address.
*
* @return
* - ESP_OK on success.
* - ESP_ERR_NO_MEM if the pending table is full.
* - ESP_ERR_INVALID_ARG if addr is NULL.
*
*/
esp_err_t esp_ieee802154_add_pending_addr(const uint8_t *addr, bool is_short);
@@ -422,12 +427,13 @@ esp_err_t esp_ieee802154_add_pending_addr(const uint8_t *addr, bool is_short);
/**
* @brief Remove address from the source matching table.
*
* @param[in] addr The pointer to the address.
* @param[in] addr The pointer to the address. Must not be NULL.
* @param[in] is_short Short address or Extended address.
*
* @return
* - ESP_OK on success.
* - ESP_ERR_NOT_FOUND if the address was not found from the source matching table.
* - ESP_ERR_INVALID_ARG if addr is NULL.
*
*/
esp_err_t esp_ieee802154_clear_pending_addr(const uint8_t *addr, bool is_short);
@@ -440,6 +446,7 @@ esp_err_t esp_ieee802154_clear_pending_addr(const uint8_t *addr, bool is_short);
* @return
* - ESP_OK on success.
* - ESP_FAIL on failure.
*
*/
esp_err_t esp_ieee802154_reset_pending_table(bool is_short);
@@ -459,6 +466,7 @@ int8_t esp_ieee802154_get_cca_threshold(void);
* @return
* - ESP_OK on success.
* - ESP_FAIL on failure.
*
*/
esp_err_t esp_ieee802154_set_cca_threshold(int8_t cca_threshold);
@@ -478,6 +486,7 @@ esp_ieee802154_cca_mode_t esp_ieee802154_get_cca_mode(void);
* @return
* - ESP_OK on success.
* - ESP_FAIL on failure.
*
*/
esp_err_t esp_ieee802154_set_cca_mode(esp_ieee802154_cca_mode_t cca_mode);
@@ -489,6 +498,7 @@ esp_err_t esp_ieee802154_set_cca_mode(esp_ieee802154_cca_mode_t cca_mode);
* @return
* - ESP_OK on success.
* - ESP_FAIL on failure.
*
*/
esp_err_t esp_ieee802154_set_rx_when_idle(bool enable);
@@ -643,12 +653,13 @@ uint8_t esp_ieee802154_get_recent_lqi(void);
/**
* @brief Set the key and addr for a frame needs to be encrypted by HW.
*
* @param[in] frame A frame needs to be encrypted. Refer to `esp_ieee802154_transmit()`.
* @param[in] key A 16-bytes key for encryption.
* @param[in] addr An 8-bytes addr for HW to generate nonce, in general, is the device extended address.
* @param[in] frame A frame needs to be encrypted. Refer to `esp_ieee802154_transmit()`. Must not be NULL.
* @param[in] key A 16-bytes key for encryption. Must not be NULL.
* @param[in] addr An 8-bytes addr for HW to generate nonce, in general, is the device extended address. Must not be NULL.
*
* @return
* - ESP_OK on success.
* - ESP_ERR_INVALID_ARG if frame, key, or addr is NULL.
* - ESP_FAIL on failure.
*/
esp_err_t esp_ieee802154_set_transmit_security(uint8_t *frame, uint8_t *key, uint8_t *addr);
@@ -657,7 +668,7 @@ esp_err_t esp_ieee802154_set_transmit_security(uint8_t *frame, uint8_t *key, uin
* @brief This function will be called when a received frame needs to be acked with Enh-Ack, the upper
* layer should generate the Enh-Ack frame in this callback function.
*
* @param[in] frame The received frame.
* @param[in] frame The received frame. Must not be NULL.
* @param[in] frame_info The frame information. Refer to `esp_ieee802154_frame_info_t`.
* @param[out] enhack_frame The Enh-ack frame need to be generated via this function, HW will send it back after AIFS.
*
@@ -741,6 +752,7 @@ esp_ieee802154_coex_config_t esp_ieee802154_get_coex_config(void);
* @return
* - ESP_OK on success.
* - ESP_FAIL on failure.
*
*/
esp_err_t esp_ieee802154_event_callback_list_register(esp_ieee802154_event_cb_list_t cb_list);
@@ -753,9 +765,84 @@ esp_err_t esp_ieee802154_event_callback_list_register(esp_ieee802154_event_cb_li
* @return
* - ESP_OK on success.
* - ESP_FAIL on failure.
*
*/
esp_err_t esp_ieee802154_event_callback_list_unregister(void);
/**
* @brief Add a pending address to the multipan table for the specified interface.
*
* @note This API should be called only when the IEEE 802.15.4 subsystem is enabled.
*
* @param inf_index Index of the interface.
* @param addr Pointer to the address to add.
* @param is_short True if the address is a short address, false if extended.
*
* @return
* - ESP_OK on success.
* - ESP_FAIL on failure.
*/
esp_err_t esp_ieee802154_multipan_add_pending_addr(esp_ieee802154_multipan_index_t inf_index, const uint8_t *addr, bool is_short);
/**
* @brief Remove a pending address from the multipan table for the specified interface.
*
* @note This API should be called only when the IEEE 802.15.4 subsystem is enabled.
*
* @param inf_index Index of the interface.
* @param addr Pointer to the address to remove.
* @param is_short True if the address is a short address, false if extended.
*
* @return
* - ESP_OK on success.
* - ESP_FAIL on failure.
*/
esp_err_t esp_ieee802154_multipan_clear_pending_addr(esp_ieee802154_multipan_index_t inf_index, const uint8_t *addr, bool is_short);
/**
* @brief Reset the pending address table for the specified interface.
*
* @note This API clears all pending addresses of the specified type (short or extended) for the interface.
*
* @param inf_index Index of the interface.
* @param is_short True to reset short addresses, false to reset extended addresses.
*
* @return
* - ESP_OK on success.
* - ESP_FAIL on failure.
*/
esp_err_t esp_ieee802154_multipan_reset_pending_table(esp_ieee802154_multipan_index_t inf_index, bool is_short);
/**
* @brief Get the auto frame pending mode of the specified multipan interface.
*
* @note This API returns the logical pending mode configured for a given multipan
* interface. The value is used by the ACK generation logic together with the
* per-interface pending address table.
*
* @param inf_index Index of the multipan interface.
*
* @return
* - The auto frame pending mode, refer to esp_ieee802154_pending_mode_t.
*/
esp_ieee802154_pending_mode_t esp_ieee802154_multipan_get_pending_mode(esp_ieee802154_multipan_index_t inf_index);
/**
* @brief Set the auto frame pending mode of the specified multipan interface.
*
* @note This API configures the logical pending mode for a given multipan interface.
* The configured mode is used by the ACK generation logic together with the
* per-interface pending address table.
*
* @param inf_index Index of the multipan interface.
* @param pending_mode Pending mode to set for this interface.
*
* @return
* - ESP_OK on success.
* - ESP_FAIL on failure.
*/
esp_err_t esp_ieee802154_multipan_set_pending_mode(esp_ieee802154_multipan_index_t inf_index, esp_ieee802154_pending_mode_t pending_mode);
#ifdef __cplusplus
}
#endif

View File

@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2021-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -10,7 +10,7 @@
#include <stdbool.h>
#include "esp_err.h"
#define US_PER_SYMBLE 16
#define US_PER_SYMBOL 16
#ifdef __cplusplus
extern "C" {
@@ -61,8 +61,8 @@ typedef enum {
} esp_ieee802154_pending_mode_t;
/**
* @brief The four groups of mac filter interface index.
*/
* @brief The four groups of mac filter interface index.
*/
typedef enum {
ESP_IEEE802154_MULTIPAN_0 = 0,
ESP_IEEE802154_MULTIPAN_1 = 1,
@@ -82,6 +82,7 @@ typedef struct {
int8_t rssi; /*!< RSSI */
uint8_t lqi; /*!< LQI */
uint64_t timestamp; /*!< The timestamp when the frame's SFD field was received */
esp_ieee802154_multipan_index_t mpf_index; /*!< Multipan interface that matches the frame, ESP_IEEE802154_MULTIPAN_MAX if none */
} esp_ieee802154_frame_info_t;
/**
@@ -142,13 +143,13 @@ typedef esp_err_t (*esp_ieee802154_enh_ack_generator_cb_t)(uint8_t *frame, esp_i
*
*/
typedef struct {
esp_ieee802154_receive_done_cb_t rx_done_cb; /*!<The callback to process Rx Done event */
esp_ieee802154_receive_sfd_done_cb_t rx_sfd_done_cb; /*!<The callback to process Rx SFD Done event */
esp_ieee802154_transmit_done_cb_t tx_done_cb; /*!<The callback to process Tx Done event */
esp_ieee802154_transmit_failed_cb_t tx_failed_cb; /*!<The callback to process Tx Failed event */
esp_ieee802154_transmit_sfd_done_cb_t tx_sfd_done_cb; /*!<The callback to process Tx SFD Done event */
esp_ieee802154_energy_detect_done_cb_t ed_done_cb; /*!<The callback to process ED Done event */
esp_ieee802154_enh_ack_generator_cb_t enh_ack_generator_cb; /*!<The callback to process enh-ack generating */
esp_ieee802154_receive_done_cb_t rx_done_cb; /*!< The callback to process Rx Done event */
esp_ieee802154_receive_sfd_done_cb_t rx_sfd_done_cb; /*!< The callback to process Rx SFD Done event */
esp_ieee802154_transmit_done_cb_t tx_done_cb; /*!< The callback to process Tx Done event */
esp_ieee802154_transmit_failed_cb_t tx_failed_cb; /*!< The callback to process Tx Failed event */
esp_ieee802154_transmit_sfd_done_cb_t tx_sfd_done_cb; /*!< The callback to process Tx SFD Done event */
esp_ieee802154_energy_detect_done_cb_t ed_done_cb; /*!< The callback to process ED Done event */
esp_ieee802154_enh_ack_generator_cb_t enh_ack_generator_cb; /*!< The callback to process Enh-ack generating */
} esp_ieee802154_event_cb_list_t;
#ifdef __cplusplus

View File

@@ -17,7 +17,11 @@ entries:
esp_ieee802154_frame: ieee802154_frame_get_security_payload_offset (noflash)
esp_ieee802154_frame: ieee802154_frame_get_src_addr (noflash)
esp_ieee802154_frame: ieee802154_frame_security_header_offset (noflash)
esp_ieee802154_frame: ieee802154_frame_get_dest_panid (noflash)
esp_ieee802154_frame: ieee802154_frame_get_dst_addr (noflash)
esp_ieee802154_frame: ieee802154_frame_get_src_panid (noflash)
esp_ieee802154_frame: ieee802154_frame_is_security_enabled(noflash)
esp_ieee802154_frame: ieee802154_is_data_request (noflash)
esp_ieee802154_frame: is_dst_panid_present (noflash)
esp_ieee802154_frame: is_src_panid_present (noflash)
esp_ieee802154_pib: ieee802154_pib_get_pending_mode (noflash)
@@ -73,3 +77,11 @@ entries:
esp_ieee802154_timer: isr_handle_timer0_done (noflash)
esp_ieee802154_timer: isr_handle_timer1_done (noflash)
esp_ieee802154_util: ieee802154_channel_to_freq (noflash)
if IEEE802154_MULTI_PAN_ENABLE = y:
esp_ieee802154: esp_ieee802154_get_multipan_extended_address (noflash)
esp_ieee802154: esp_ieee802154_get_multipan_panid (noflash)
esp_ieee802154: esp_ieee802154_get_multipan_short_address (noflash)
esp_ieee802154_dev: is_broadcast_addr (noflash)
esp_ieee802154_dev: is_broadcast_panid (noflash)
esp_ieee802154_dev: update_mpf_index (noflash)

View File

@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -10,6 +10,7 @@
#include <stdbool.h>
#include "sdkconfig.h"
#include "esp_err.h"
#include "esp_ieee802154_types.h"
#include "esp_ieee802154_frame.h"
#ifdef __cplusplus
@@ -25,35 +26,37 @@ extern "C" {
typedef struct {
uint8_t short_addr[CONFIG_IEEE802154_PENDING_TABLE_SIZE][IEEE802154_FRAME_SHORT_ADDR_SIZE]; /*!< Short address table */
uint8_t ext_addr[CONFIG_IEEE802154_PENDING_TABLE_SIZE][IEEE802154_FRAME_EXT_ADDR_SIZE]; /*!< Extend address table */
uint8_t short_addr_mask[IEEE802154_PENDING_TABLE_MASK_SIZE]; /*!< The mask which the index of short address table is used */
uint8_t ext_addr_mask[IEEE802154_PENDING_TABLE_MASK_SIZE]; /*!< The mask which the index of extended address table is used */
uint8_t short_addr_mask[IEEE802154_PENDING_TABLE_MASK_SIZE]; /*!< Bit mask to track which indices of the short address table are used */
uint8_t ext_addr_mask[IEEE802154_PENDING_TABLE_MASK_SIZE]; /*!< Bit mask to track which indices of the extended address table are used */
} ieee802154_pending_table_t;
/**
* @brief Add an address to the pending table.
*
* @param[in] addr The pointer to the address needs to be added.
* @param[in] addr The pointer to the address needs to be added. Must not be NULL.
* @param[in] is_short The type of address, true for short address, false for extended.
*
* @return
* - ESP_OK on success.
* - ESP_FAIL on failure due to the table is full.
* - ESP_ERR_INVALID_ARG if addr is NULL.
*
*/
esp_err_t ieee802154_add_pending_addr(const uint8_t *addr, bool is_short);
esp_err_t ieee802154_add_pending_addr(esp_ieee802154_multipan_index_t inf_index, const uint8_t *addr, bool is_short);
/**
* @brief Remove an address in pending table.
*
* @param[in] addr The pointer to the address needs to be cleared.
* @param[in] addr The pointer to the address needs to be cleared. Must not be NULL.
* @param[in] is_short The type of address, true for short address, false for extended.
*
* @return
* - ESP_OK on success.
* - ESP_FAIL on failure if the given address is not present in the pending table.
* - ESP_ERR_INVALID_ARG if addr is NULL.
*
*/
esp_err_t ieee802154_clear_pending_addr(const uint8_t *addr, bool is_short);
esp_err_t ieee802154_clear_pending_addr(esp_ieee802154_multipan_index_t inf_index, const uint8_t *addr, bool is_short);
/**
* @brief Reset the pending table, only clear the mask bits for finishing the process quickly.
@@ -61,18 +64,18 @@ esp_err_t ieee802154_clear_pending_addr(const uint8_t *addr, bool is_short);
* @param[in] is_short The type of address, true for resetting short address table, false for extended.
*
*/
void ieee802154_reset_pending_table(bool is_short);
void ieee802154_reset_pending_table(esp_ieee802154_multipan_index_t inf_index, bool is_short);
/**
* @brief Check whether the pending bit should be set or not in the ack frame.
*
* @param[in] frame The pointer to the received frame.
* @param[in] frame The pointer to the received frame. Must not be NULL.
*
* @return
* - True The pending bit should be set, otherwise False.
* - True if the pending bit should be set, otherwise false.
*
*/
bool ieee802154_ack_config_pending_bit(const uint8_t *frame);
bool ieee802154_ack_config_pending_bit(const uint8_t *frame, const esp_ieee802154_frame_info_t *frame_info);
#ifdef __cplusplus
}

View File

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

View File

@@ -15,9 +15,9 @@ extern "C" {
#endif
#define IEEE802154_FRAME_MAX_LEN 127
#define IEEE802154_FRAME_MIN_LEN 3
#define IEEE802154_FRAME_INVALID_OFFSET 0xff
#define IEEE802154_FRAME_INVALID_ADDR_MODE 0xff
#define IEEE802154_FRAME_INVALID_VALUE 0xff
#define IEEE802154_FRAME_TYPE_OFFSET 1
#define IEEE802154_FRAME_TYPE_MASK 0x07
@@ -111,7 +111,7 @@ static inline bool ieee802154_is_supported_frame_type(uint8_t frame_type)
/**
* @brief Get the frame type.
*
* @param[in] frame The pointer to the frame.
* @param[in] frame The pointer to the frame. Must not be NULL.
*
* @return
* - The type of the frame.
@@ -122,7 +122,7 @@ uint8_t ieee802154_frame_get_type(const uint8_t *frame);
/**
* @brief Get the frame version.
*
* @param[in] frame The pointer to the frame.
* @param[in] frame The pointer to the frame. Must not be NULL.
*
* @return
* - The version of the frame.
@@ -133,7 +133,7 @@ uint8_t ieee802154_frame_get_version(const uint8_t *frame);
/**
* @brief Is the frame ack required.
*
* @param[in] frame The pointer to the frame.
* @param[in] frame The pointer to the frame. Must not be NULL.
*
* @return
* - True if the frame is ack required, otherwise false.
@@ -154,13 +154,14 @@ bool ieee802154_frame_is_security_enabled(const uint8_t *frame);
/**
* @brief Get the destination address of the frame.
*
* @param[in] frame The pointer to the frame.
* @param[out] addr The pointer to the address.
* @param[in] frame The pointer to the frame. Must not be NULL.
* @param[out] addr The pointer to the address. Must not be NULL.
*
* @return
* - IEEE802154_FRAME_DST_MODE_NONE if destination address mode is none.
* - IEEE802154_FRAME_DST_MODE_SHORT if destination address mode is short.
* - IEEE802154_FRAME_DST_MODE_EXT if destination address mode is extended.
* - IEEE802154_FRAME_INVALID_VALUE if frame is NULL, addr is NULL, or frame type is invalid.
*
*/
uint8_t ieee802154_frame_get_dst_addr(const uint8_t *frame, uint8_t *addr);
@@ -168,51 +169,60 @@ uint8_t ieee802154_frame_get_dst_addr(const uint8_t *frame, uint8_t *addr);
/**
* @brief Get the source address of the frame.
*
* @param[in] frame The pointer to the frame.
* @param[out] addr The pointer to the address.
* @param[in] frame The pointer to the frame. Must not be NULL.
* @param[out] addr The pointer to the address. Must not be NULL.
*
* @return
* - IEEE802154_FRAME_SRC_MODE_NONE if source address mode is none.
* - IEEE802154_FRAME_SRC_MODE_SHORT if source address mode is short.
* - IEEE802154_FRAME_SRC_MODE_EXT if source address mode is extended.
*
* - IEEE802154_FRAME_INVALID_VALUE if frame is NULL, addr is NULL, or frame type is invalid.
*/
uint8_t ieee802154_frame_get_src_addr(const uint8_t *frame, uint8_t *addr);
/**
* @brief Get the offset of the private payload.
*
* @param[in] frame The pointer to the frame.
* @param[in] frame The pointer to the frame. Must not be NULL.
*
* @return
* - The offset of the private payload
*
* - IEEE802154_FRAME_INVALID_VALUE if frame is NULL, or frame type is invalid.
*/
uint8_t ieee802154_frame_get_security_payload_offset(uint8_t *frame);
/**
* @brief Get the destination PAN ID of the frame.
*
* @param[in] frame The pointer to the frame.
* @param[out] panid The pointer to the destination PAN ID.
* @param[in] frame The pointer to the frame. Must not be NULL.
* @param[out] panid The pointer to the destination PAN ID. Must not be NULL.
*
* @return
* - ESP_OK if destination PAN ID is present, otherwise ESP_FAIL.
*
* - ESP_FAIL if frame is NULL, panid is NULL, or frame type is invalid.
*/
esp_err_t ieee802154_frame_get_dest_panid(const uint8_t *frame, uint8_t *panid);
/**
* @brief Get the source PAN ID of the frame.
*
* @param[in] frame The pointer to the frame.
* @param[out] panid The pointer to the source PAN ID.
* @param[in] frame The pointer to the frame. Must not be NULL.
* @param[out] panid The pointer to the source PAN ID. Must not be NULL.
*
* @return
* - ESP_OK if source PAN ID is present, otherwise ESP_FAIL.
*
* - ESP_FAIL if frame is NULL, panid is NULL, or frame type is invalid.
*/
esp_err_t ieee802154_frame_get_src_panid(const uint8_t *frame, uint8_t *panid);
/**
* @brief Check whether the given frame is a MAC Data Request command.
*
* @param[in] frame Pointer to the raw MAC frame buffer.
*
* @return true if the frame is a Data Request command, false otherwise.
*/
bool ieee802154_is_data_request(const uint8_t *frame);
#ifdef __cplusplus
}
#endif

View File

@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -8,6 +8,7 @@
#include <stdbool.h>
#include <stdint.h>
#include "sdkconfig.h"
#include "hal/ieee802154_ll.h"
#include "esp_ieee802154_frame.h"
#include "esp_ieee802154_types.h"
@@ -28,7 +29,7 @@ typedef struct {
bool rx_when_idle; /*!< A flag indicates the device is rx on when idle or not */
esp_ieee802154_txpower_table_t power_table; /*!< The power table configuration */
uint8_t channel; /*!< Channel configuration */
ieee802154_ll_pending_mode_t pending_mode; /*!< Pending mode configuration */
ieee802154_ll_pending_mode_t pending_mode[CONFIG_IEEE802154_INTERFACE_NUM]; /*!< Pending mode configuration */
int8_t cca_threshold; /*!< CCA threshold */
ieee802154_ll_cca_mode_t cca_mode; /*!< CCA mode */
} ieee802154_pib_t;
@@ -160,7 +161,7 @@ void ieee802154_pib_set_cca_threshold(int8_t cca_threshold);
* @return
* - The CCA threshold has been set in the PIB.
*/
int8_t ieee802154_pib_get_cca_threshold(void);
int8_t ieee802154_pib_get_cca_threshold(void);
/**
* @brief Set the CCA mode to the PIB.
@@ -248,7 +249,7 @@ bool ieee802154_pib_get_coordinator(void);
* @param[in] pending_mode The pending mode.
*
*/
void ieee802154_pib_set_pending_mode(ieee802154_ll_pending_mode_t pending_mode);
void ieee802154_pib_set_pending_mode(esp_ieee802154_multipan_index_t inf_index, ieee802154_ll_pending_mode_t pending_mode);
/**
* @brief Get the pending mode from the PIB.
@@ -256,21 +257,21 @@ void ieee802154_pib_set_pending_mode(ieee802154_ll_pending_mode_t pending_mode);
* @return
* - The pending mode has been set in the PIB.
*/
ieee802154_ll_pending_mode_t ieee802154_pib_get_pending_mode(void);
ieee802154_ll_pending_mode_t ieee802154_pib_get_pending_mode(esp_ieee802154_multipan_index_t inf_index);
/**
* @brief Configure the radio mode when the radio is going to enter idle to the PIB.
*
* @param[in] enable True for continuing to receive when the radio is going to enter ilde, otherwise false.
* @param[in] enable True for continuing to receive when the radio is going to enter idle, otherwise false.
*
*/
void ieee802154_pib_set_rx_when_idle(bool enable);
/**
* @brief Get the radio mode when the radio is going to enter ilde to the PIB.
* @brief Get the radio mode when the radio is going to enter idle to the PIB.
*
* @return
* - True for continuing to receive when the radio is going to enter ilde, otherwise false.
* - True for continuing to receive when the radio is going to enter idle, otherwise false.
*
*/
bool ieee802154_pib_get_rx_when_idle(void);

View File

@@ -23,6 +23,12 @@ extern "C" {
#define IEEE802154_OQPSK_2P4G_CHANNEL_MIN 11
#define IEEE802154_OQPSK_2P4G_CHANNEL_MAX 26
#define IEEE802154_RETURN_ON_FALSE_SILENTLY(a, ret) do { \
if (unlikely(!(a))) { \
return ret; \
} \
} while(0)
static inline bool ieee802154_is_valid_channel(uint8_t channel)
{
return ((channel <= IEEE802154_OQPSK_2P4G_CHANNEL_MAX) && (channel >= IEEE802154_OQPSK_2P4G_CHANNEL_MIN));

View File

@@ -5,14 +5,12 @@ if(${idf_target} STREQUAL "linux")
endif()
if(CONFIG_OPENTHREAD_ENABLED OR CONFIG_IDF_DOC_BUILD OR CONFIG_OPENTHREAD_SPINEL_ONLY)
set(public_include_dirs
"include"
"openthread/include")
endif()
if(CONFIG_OPENTHREAD_ENABLED)
set(private_include_dirs
"openthread/examples/platforms"
"openthread/src"
@@ -24,243 +22,18 @@ if(CONFIG_OPENTHREAD_ENABLED)
"openthread/src/ncp"
"private_include")
set(src_dirs
"src"
"src/port"
"openthread/examples/platforms/utils"
"openthread/src/core/api"
"openthread/src/core/common"
"openthread/src/core/crypto"
"openthread/src/core/diags"
"openthread/src/core/instance"
"openthread/src/core/mac"
"openthread/src/core/radio"
"openthread/src/core/thread"
"openthread/src/core/utils"
"openthread/src/lib/hdlc"
"openthread/src/lib/spinel")
set(exclude_srcs
"openthread/examples/platforms/utils/logging_rtt.c"
"openthread/examples/platforms/utils/soft_source_match_table.c"
"openthread/src/core/instance/extension_example.cpp"
"openthread/src/core/crypto/crypto_platform_mbedtls.cpp"
"openthread/src/core/api/random_crypto_api.cpp"
)
if(CONFIG_OPENTHREAD_FTD OR CONFIG_OPENTHREAD_MTD)
list(APPEND src_dirs
"openthread/src/core/backbone_router"
"openthread/src/core/coap"
"openthread/src/core/meshcop"
"openthread/src/core/net"
"openthread/src/lib/platform")
if(CONFIG_OPENTHREAD_CLI)
list(APPEND src_dirs
"openthread/examples/apps/cli"
"openthread/src/cli")
list(APPEND exclude_srcs
"openthread/examples/apps/cli/main.c")
endif()
elseif(CONFIG_OPENTHREAD_RADIO)
list(APPEND src_dirs
"openthread/src/ncp"
"openthread/examples/apps/ncp")
list(APPEND exclude_srcs
"src/port/esp_openthread_state.c"
"openthread/examples/apps/ncp/main.c"
"openthread/src/core/api/backbone_router_api.cpp"
"openthread/src/core/api/child_supervision_api.cpp"
"openthread/src/core/api/dataset_api.cpp"
"openthread/src/core/api/dns_api.cpp"
"openthread/src/core/api/entropy_api.cpp"
"openthread/src/core/api/heap_api.cpp"
"openthread/src/core/api/icmp6_api.cpp"
"openthread/src/core/api/ip6_api.cpp"
"openthread/src/core/api/link_api.cpp"
"openthread/src/core/api/link_metrics_api.cpp"
"openthread/src/core/api/message_api.cpp"
"openthread/src/core/api/nat64_api.cpp"
"openthread/src/core/api/netdata_api.cpp"
"openthread/src/core/api/netdiag_api.cpp"
"openthread/src/core/api/network_time_api.cpp"
"openthread/src/core/api/random_crypto_api.cpp"
"openthread/src/core/api/tcp_api.cpp"
"openthread/src/core/api/udp_api.cpp"
"openthread/src/core/common/heap.cpp"
"openthread/src/core/common/heap_string.cpp"
"openthread/src/core/common/notifier.cpp"
"openthread/src/core/common/settings.cpp"
"openthread/src/core/common/time_ticker.cpp"
"openthread/src/core/mac/channel_mask.cpp"
"openthread/src/core/mac/data_poll_handler.cpp"
"openthread/src/core/mac/data_poll_sender.cpp"
"openthread/src/core/mac/mac.cpp"
"openthread/src/core/mac/mac_filter.cpp"
"openthread/src/core/mac/mac_links.cpp"
"openthread/src/core/thread/announce_begin_server.cpp"
"openthread/src/core/thread/announce_sender.cpp"
"openthread/src/core/thread/address_resolver.cpp"
"openthread/src/core/thread/child.cpp"
"openthread/src/core/thread/child_supervision.cpp"
"openthread/src/core/thread/csl_tx_scheduler.cpp"
"openthread/src/core/thread/discover_scanner.cpp"
"openthread/src/core/thread/energy_scan_server.cpp"
"openthread/src/core/thread/indirect_sender.cpp"
"openthread/src/core/thread/key_manager.cpp"
"openthread/src/core/thread/link_metrics.cpp"
"openthread/src/core/thread/lowpan.cpp"
"openthread/src/core/thread/mesh_forwarder.cpp"
"openthread/src/core/thread/mesh_forwarder_ftd.cpp"
"openthread/src/core/thread/mesh_forwarder_mtd.cpp"
"openthread/src/core/thread/message_framer.cpp"
"openthread/src/core/thread/mle.cpp"
"openthread/src/core/thread/mle_ftd.cpp"
"openthread/src/core/thread/mle_p2p.cpp"
"openthread/src/core/thread/mle_router.cpp"
"openthread/src/core/thread/mle_types.cpp"
"openthread/src/core/thread/neighbor.cpp"
"openthread/src/core/thread/neighbor_table.cpp"
"openthread/src/core/thread/network_data.cpp"
"openthread/src/core/thread/network_data_leader.cpp"
"openthread/src/core/thread/network_data_leader_ftd.cpp"
"openthread/src/core/thread/network_data_types.cpp"
"openthread/src/core/thread/network_data_service.cpp"
"openthread/src/core/thread/network_diagnostic.cpp"
"openthread/src/core/thread/network_diagnostic_tlvs.cpp"
"openthread/src/core/thread/panid_query_server.cpp"
"openthread/src/core/thread/router.cpp"
"openthread/src/core/thread/thread_netif.cpp"
"openthread/src/core/thread/time_sync_service.cpp"
"openthread/src/core/thread/tmf.cpp"
"openthread/src/core/thread/topology.cpp"
"openthread/src/core/utils/child_supervision.cpp")
endif()
if(CONFIG_OPENTHREAD_RADIO_NATIVE)
list(APPEND exclude_srcs
"src/port/esp_openthread_radio_spinel.cpp"
"src/port/esp_spi_spinel_interface.cpp"
"src/port/esp_uart_spinel_interface.cpp"
)
elseif(CONFIG_OPENTHREAD_RADIO_SPINEL_UART OR CONFIG_OPENTHREAD_RADIO_SPINEL_SPI)
list(APPEND exclude_srcs
"src/port/esp_openthread_radio.c"
"src/port/esp_openthread_sleep.c")
elseif(CONFIG_OPENTHREAD_RADIO_154_NONE)
list(APPEND exclude_srcs
"src/port/esp_openthread_radio_spinel.cpp"
"src/port/esp_spi_spinel_interface.cpp"
"src/port/esp_uart_spinel_interface.cpp"
"src/port/esp_openthread_radio.c"
"src/port/esp_openthread_sleep.c"
)
endif()
if(NOT CONFIG_OPENTHREAD_RADIO_TREL)
list(APPEND exclude_srcs
"src/port/esp_openthread_trel.c")
endif()
if(CONFIG_OPENTHREAD_BORDER_ROUTER)
list(APPEND src_dirs
"openthread/src/core/border_router")
endif()
if(CONFIG_OPENTHREAD_FTD)
set_source_files_properties("openthread/src/core/net/srp_server.cpp"
PROPERTIES COMPILE_FLAGS
-Wno-maybe-uninitialized)
endif()
if(CONFIG_OPENTHREAD_NCP_VENDOR_HOOK)
list(APPEND src_dirs
"src/ncp")
if(CONFIG_OPENTHREAD_RCP_UART OR CONFIG_OPENTHREAD_RCP_USB_SERIAL_JTAG)
list(APPEND exclude_srcs
"src/ncp/esp_openthread_ncp_spi.cpp")
elseif(CONFIG_OPENTHREAD_RCP_SPI)
list(APPEND exclude_srcs
"src/ncp/esp_openthread_ncp_hdlc.cpp")
endif()
endif()
if(NOT CONFIG_OPENTHREAD_DNS64_CLIENT)
list(APPEND exclude_srcs
"src/esp_openthread_dns64.c")
endif()
if(NOT CONFIG_FREERTOS_USE_TICKLESS_IDLE)
list(APPEND exclude_srcs
"src/port/esp_openthread_sleep.c")
endif()
if(NOT CONFIG_OPENTHREAD_PLATFORM_MSGPOOL_MANAGEMENT)
list(APPEND exclude_srcs
"src/port/esp_openthread_messagepool.c")
endif()
if(NOT CONFIG_OPENTHREAD_RCP_SPINEL_CONSOLE)
list(APPEND exclude_srcs
"src/ncp/esp_openthread_ncp_console.cpp")
endif()
if(CONFIG_OPENTHREAD_FTD)
include(srcs_ftd_mtd.cmake)
set(device_type "OPENTHREAD_FTD=1")
elseif(CONFIG_OPENTHREAD_MTD)
include(srcs_ftd_mtd.cmake)
set(device_type "OPENTHREAD_MTD=1")
elseif(CONFIG_OPENTHREAD_RADIO)
include(srcs_radio.cmake)
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/include"
"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})
include(srcs_spinel.cmake)
endif()
if(CONFIG_OPENTHREAD_HEADER_CUSTOM)
@@ -287,14 +60,49 @@ string(CONCAT OT_FULL_VERSION_STRING
"${IDF_VERSION_FOR_OPENTHREAD_PACKAGE}-${OPENTHREAD_VERSION}\; "
"${CONFIG_OPENTHREAD_PLATFORM_INFO}\; ${OT_BUILD_TIMESTAMP}")
idf_component_register(SRC_DIRS "${src_dirs}"
EXCLUDE_SRCS "${exclude_srcs}"
INCLUDE_DIRS "${public_include_dirs}"
PRIV_INCLUDE_DIRS "${private_include_dirs}"
REQUIRES esp_netif lwip esp_driver_uart esp_driver_gpio esp_driver_spi esp_driver_usb_serial_jtag
LDFRAGMENTS linker.lf
PRIV_REQUIRES console esp_coex esp_event esp_partition esp_timer
ieee802154 mbedtls nvs_flash)
# Register component based on mode
if(CONFIG_OPENTHREAD_FTD OR CONFIG_OPENTHREAD_MTD)
# FTD/MTD modes use directory-based collection from srcs_ftd_mtd.cmake
idf_component_register(SRC_DIRS "${src_dirs}"
EXCLUDE_SRCS "${exclude_srcs}"
INCLUDE_DIRS "${public_include_dirs}"
PRIV_INCLUDE_DIRS "${private_include_dirs}"
REQUIRES esp_netif lwip esp_driver_uart esp_driver_gpio esp_driver_spi
esp_driver_usb_serial_jtag
LDFRAGMENTS linker.lf
PRIV_REQUIRES console esp_coex esp_event esp_partition esp_timer
ieee802154 mbedtls nvs_flash esp_psram)
elseif(CONFIG_OPENTHREAD_RADIO)
# RCP mode uses explicit source list from srcs_radio.cmake
idf_component_register(SRCS ${rcp_srcs}
INCLUDE_DIRS "${public_include_dirs}"
PRIV_INCLUDE_DIRS "${private_include_dirs}"
REQUIRES esp_netif lwip esp_driver_uart esp_driver_gpio esp_driver_spi
esp_driver_usb_serial_jtag
LDFRAGMENTS linker.lf
PRIV_REQUIRES console esp_coex esp_event esp_partition esp_timer
ieee802154 mbedtls nvs_flash esp_psram)
elseif(CONFIG_OPENTHREAD_SPINEL_ONLY)
# SPINEL_ONLY mode uses explicit source list from srcs_spinel.cmake
idf_component_register(SRCS ${spinel_srcs}
INCLUDE_DIRS "${public_include_dirs}"
PRIV_INCLUDE_DIRS "${private_include_dirs}"
REQUIRES esp_netif lwip esp_driver_uart esp_driver_gpio esp_driver_spi
esp_driver_usb_serial_jtag
LDFRAGMENTS linker.lf
PRIV_REQUIRES console esp_coex esp_event esp_partition esp_timer
ieee802154 mbedtls nvs_flash esp_psram)
else()
# This is not supposed to happen, but in older versions of IDF components couldn't be selectively
# enabled based on KConfig options so some examples just included openthread for all configs.
idf_component_register(INCLUDE_DIRS "${public_include_dirs}"
PRIV_INCLUDE_DIRS "${private_include_dirs}"
REQUIRES esp_netif lwip esp_driver_uart esp_driver_gpio esp_driver_spi
esp_driver_usb_serial_jtag
LDFRAGMENTS linker.lf
PRIV_REQUIRES console esp_coex esp_event esp_partition esp_timer
ieee802154 mbedtls nvs_flash esp_psram)
endif()
if(CONFIG_OPENTHREAD_RADIO_TREL)
idf_component_optional_requires(PRIVATE espressif__mdns)

View File

@@ -436,6 +436,7 @@ menu "OpenThread"
config OPENTHREAD_PLATFORM_MSGPOOL_MANAGEMENT
bool 'Allocate message pool buffer from PSRAM'
depends on OPENTHREAD_PLATFORM_MALLOC_CAP_SPIRAM
default y
help
If enabled, the message pool is managed by platform defined logic.
@@ -622,5 +623,27 @@ menu "OpenThread"
information whenever an OpenThread assert occurs. This can help developers
analyze unexpected failures by providing additional MAC layer context.
config OPENTHREAD_TASK_BLOCK_MONITOR
depends on OPENTHREAD_DEBUG
bool "Enable OpenThread Task Block Monitor"
default n
help
Enable monitoring of OpenThread tasks to detect if a task is blocked
and unable to continue its normal execution loop. Useful for debugging
issues where tasks stop progressing due to deadlocks or resource waits.
On RISC-V targets, in order to get meaningful backtraces when a task is
detected as blocked, ESP_SYSTEM_USE_FRAME_POINTER must be enabled in
ESP System Settings -> Backtracing method.
config OPENTHREAD_TASK_BLOCK_MONITOR_TIMEOUT
depends on OPENTHREAD_TASK_BLOCK_MONITOR
int "Task Block Monitor Timeout (seconds)"
range 1 60
default 20
help
Set the timeout (in seconds) for detecting a blocked task.
The timer is started at the beginning of each task main loop
and stopped at the end. If the timer expires, the task is considered blocked.
endmenu

View File

@@ -2,13 +2,13 @@
archive: libopenthread.a
entries:
if OPENTHREAD_TIMING_OPTIMIZATION = y:
link_metrics (noflash)
link_quality (noflash)
mac_frame (noflash)
radio (noflash)
sub_mac (noflash)
if OPENTHREAD_TIMING_OPTIMIZATION = y && OPENTHREAD_RADIO = n:
link_metrics (noflash)
mesh_forwarder (noflash)
csl_tx_scheduler (noflash)
mac (noflash)

View File

@@ -0,0 +1,55 @@
/*
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <esp_err.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#ifdef __cplusplus
extern "C" {
#endif
#if CONFIG_OPENTHREAD_TASK_BLOCK_MONITOR
/**
* @brief This function creates the OpenThread task block monitor.
* The monitor task periodically checks whether the OpenThread mainloop
* has been blocked for more than `CONFIG_OPENTHREAD_TASK_BLOCK_MONITOR_TIMEOUT`
* seconds and prints backtraces when a block is detected.
*
* @return
* - ESP_OK on success
* - ESP_FAIL if the monitor task cannot be created
*
*/
esp_err_t esp_openthread_task_block_monitor_create(void);
/**
* @brief This function deletes the OpenThread task block monitor.
*
* @return
* - ESP_OK on success
*
*/
esp_err_t esp_openthread_task_block_monitor_delete(void);
/**
* @brief This function enables or disables the OpenThread task block monitor.
*
* @note When enabled, the latest mainloop activity timestamp is updated and the
* monitor task starts checking for blocking. When disabled, monitoring is
* temporarily stopped.
*
* @param[in] enable True to enable the monitor, false to disable it.
*
*/
void esp_openthread_task_block_monitor_set(bool enable);
#endif // CONFIG_OPENTHREAD_TASK_BLOCK_MONITOR
#ifdef __cplusplus
}
#endif

View File

@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2021-2025 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2021-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -99,6 +99,16 @@
#define OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE 0
#endif // CONFIG_OPENTHREAD_RADIO_TREL
#if CONFIG_OPENTHREAD_RADIO_TREL
/**
* @def OPENTHREAD_CONFIG_TREL_USE_HEAP_ENABLE
*
* Set to 1 to allow TREL modules to use heap allocated objects (e.g. for the TREL peer table).
*
*/
#define OPENTHREAD_CONFIG_TREL_USE_HEAP_ENABLE 1
#endif // CONFIG_OPENTHREAD_RADIO_TREL
/**
* @def OPENTHREAD_CONFIG_RADIO_LINK_IEEE_802_15_4_ENABLE
*
@@ -879,7 +889,7 @@
#endif
/**
* @OPENTHREAD_CONFIG_DELAY_AWARE_QUEUE_MANAGEMENT_MARK_ECN_INTERVAL
* @def OPENTHREAD_CONFIG_DELAY_AWARE_QUEUE_MANAGEMENT_MARK_ECN_INTERVAL
*
* Specifies the time-in-queue threshold interval in milliseconds to mark ECN on a message if it is ECN-capable or
* drop the message if not ECN-capable.
@@ -888,10 +898,34 @@
#define OPENTHREAD_CONFIG_DELAY_AWARE_QUEUE_MANAGEMENT_MARK_ECN_INTERVAL 1000
#endif
/**
* @def OPENTHREAD_CONFIG_PLATFORM_MAC_KEYS_EXPORTABLE_ENABLE
*
* Define to 1 if you want to make MAC keys exportable.
*/
#define OPENTHREAD_CONFIG_PLATFORM_MAC_KEYS_EXPORTABLE_ENABLE 1
/**
* @def OPENTHREAD_CONFIG_CRYPTO_LIB
*
* Selects the crypto backend library for OpenThread.
*
* There are several options available
* - @sa OPENTHREAD_CONFIG_CRYPTO_LIB_MBEDTLS
* - @sa OPENTHREAD_CONFIG_CRYPTO_LIB_PSA
* - @sa OPENTHREAD_CONFIG_CRYPTO_LIB_PLATFORM
*/
#define OPENTHREAD_CONFIG_CRYPTO_LIB OPENTHREAD_CONFIG_CRYPTO_LIB_PSA
// TODO: Remove when https://github.com/openthread/openthread/pull/12638 is merged
#define OPENTHREAD_CONFIG_PLATFORM_KEY_REFERENCES_ENABLE 1
/**
* @def OPENTHREAD_CONFIG_MESHCOP_STEERING_DATA_API_ENABLE
*
* Define as 1 to enable the MeshCoP Steering Data public APIs (in `openthread/steering_data.h`).
*/
#define OPENTHREAD_CONFIG_MESHCOP_STEERING_DATA_API_ENABLE 1
#ifndef OPENTHREAD_CONFIG_THREAD_VERSION
#define OPENTHREAD_CONFIG_THREAD_VERSION OT_THREAD_VERSION_1_4
#endif
#define OPENTHREAD_CONFIG_PLATFORM_MAC_KEYS_EXPORTABLE_ENABLE 1
#define OPENTHREAD_CONFIG_CRYPTO_LIB OPENTHREAD_CONFIG_CRYPTO_LIB_PSA

View File

@@ -494,6 +494,34 @@
#define OPENTHREAD_CONFIG_PARENT_SEARCH_RSS_THRESHOLD CONFIG_OPENTHREAD_PARENT_SEARCH_RSS_THRESHOLD
#endif
/**
* @def OPENTHREAD_CONFIG_PLATFORM_MAC_KEYS_EXPORTABLE_ENABLE
*
* Define to 1 if you want to make MAC keys exportable.
*/
#define OPENTHREAD_CONFIG_PLATFORM_MAC_KEYS_EXPORTABLE_ENABLE 1
/**
* @def OPENTHREAD_CONFIG_CRYPTO_LIB
*
* Selects the crypto backend library for OpenThread.
*
* There are several options available
* - @sa OPENTHREAD_CONFIG_CRYPTO_LIB_MBEDTLS
* - @sa OPENTHREAD_CONFIG_CRYPTO_LIB_PSA
* - @sa OPENTHREAD_CONFIG_CRYPTO_LIB_PLATFORM
*/
#define OPENTHREAD_CONFIG_CRYPTO_LIB OPENTHREAD_CONFIG_CRYPTO_LIB_PSA
// TODO: Remove when https://github.com/openthread/openthread/pull/12638 is merged
#define OPENTHREAD_CONFIG_PLATFORM_KEY_REFERENCES_ENABLE 1
/**
* @def OPENTHREAD_CONFIG_MESHCOP_STEERING_DATA_API_ENABLE
*
* Define as 1 to enable the MeshCoP Steering Data public APIs (in `openthread/steering_data.h`).
*/
#define OPENTHREAD_CONFIG_MESHCOP_STEERING_DATA_API_ENABLE 1
#ifndef OPENTHREAD_CONFIG_THREAD_VERSION
#define OPENTHREAD_CONFIG_THREAD_VERSION OT_THREAD_VERSION_1_4
#endif

View File

@@ -5,4 +5,4 @@ supplier: 'Organization: Espressif Systems (Shanghai) CO LTD'
originator: 'Organization: Google LLC'
description: OpenThread released by Google is an open-source implementation of the Thread networking
url: https://github.com/espressif/openthread
hash: 03933d9b76cb7075cc29a6648b42b217971f82a5
hash: 9b887f6bd1437170fc9bcb726f32185ccb3cb841

View File

@@ -18,6 +18,7 @@
#include "esp_openthread_platform.h"
#include "esp_openthread_sleep.h"
#include "esp_openthread_state.h"
#include "esp_openthread_debug.h"
#include "esp_openthread_task_queue.h"
#include "esp_openthread_types.h"
#include "freertos/FreeRTOS.h"
@@ -27,7 +28,6 @@
#include "openthread/netdata.h"
#include "openthread/tasklet.h"
#include "openthread/thread.h"
#include <cstddef>
#if CONFIG_OPENTHREAD_FTD
#include "openthread/dataset_ftd.h"
@@ -186,6 +186,10 @@ esp_err_t esp_openthread_launch_mainloop(void)
esp_err_t error = ESP_OK;
s_ot_mainloop_running = true;
#if CONFIG_OPENTHREAD_TASK_BLOCK_MONITOR
ESP_ERROR_CHECK(esp_openthread_task_block_monitor_create());
#endif
while (s_ot_mainloop_running) {
FD_ZERO(&mainloop.read_fds);
FD_ZERO(&mainloop.write_fds);
@@ -206,8 +210,14 @@ esp_err_t esp_openthread_launch_mainloop(void)
#endif /* CONFIG_FREERTOS_USE_TICKLESS_IDLE && CONFIG_OPENTHREAD_RADIO_NATIVE */
esp_openthread_lock_release();
if (select(mainloop.max_fd + 1, &mainloop.read_fds, &mainloop.write_fds, &mainloop.error_fds,
&mainloop.timeout) >= 0) {
#if CONFIG_OPENTHREAD_TASK_BLOCK_MONITOR
esp_openthread_task_block_monitor_set(false);
#endif
int result = select(mainloop.max_fd + 1, &mainloop.read_fds, &mainloop.write_fds, &mainloop.error_fds, &mainloop.timeout);
#if CONFIG_OPENTHREAD_TASK_BLOCK_MONITOR
esp_openthread_task_block_monitor_set(true);
#endif
if (result >= 0) {
esp_openthread_lock_acquire(portMAX_DELAY);
error = esp_openthread_platform_process(instance, &mainloop);
while (otTaskletsArePending(instance)) {
@@ -224,6 +234,9 @@ esp_err_t esp_openthread_launch_mainloop(void)
break;
}
}
#if CONFIG_OPENTHREAD_TASK_BLOCK_MONITOR
ESP_ERROR_CHECK(esp_openthread_task_block_monitor_delete());
#endif
return error;
}

View File

@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2021-2025 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2021-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -183,7 +183,21 @@ static esp_err_t openthread_netif_transmit(void *handle, void *buffer, size_t le
otError ot_error = OT_ERROR_NONE;
esp_openthread_task_switching_lock_acquire(portMAX_DELAY);
otMessage *message = otIp6NewMessage(esp_openthread_get_instance(), NULL);
otMessageSettings settings = {};
switch (otThreadGetDeviceRole(esp_openthread_get_instance()))
{
case OT_DEVICE_ROLE_DISABLED:
settings.mLinkSecurityEnabled = false;
settings.mPriority = OT_MESSAGE_PRIORITY_LOW;
break;
default:
settings.mLinkSecurityEnabled = true;
settings.mPriority = OT_MESSAGE_PRIORITY_NORMAL;
break;
}
otMessage *message = otIp6NewMessage(esp_openthread_get_instance(), &settings);
if (message == NULL) {
ESP_LOGE(OT_PLAT_LOG_TAG, "Failed to allocate OpenThread message");
ExitNow(error = ESP_ERR_NO_MEM);

View File

@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2021-2025 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2021-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -179,11 +179,21 @@ esp_err_t esp_openthread_platform_deinit(void)
esp_openthread_task_queue_deinit();
esp_openthread_radio_deinit();
if (get_host_connection_mode() == HOST_CONNECTION_MODE_RCP_SPI){
esp_openthread_host_connection_mode_t host_mode = get_host_connection_mode();
switch (host_mode) {
#if CONFIG_OPENTHREAD_RCP_SPI
case HOST_CONNECTION_MODE_RCP_SPI:
esp_openthread_spi_slave_deinit();
} else if (get_host_connection_mode() == HOST_CONNECTION_MODE_CLI_UART ||
get_host_connection_mode() == HOST_CONNECTION_MODE_RCP_UART) {
break;
#endif
#if CONFIG_OPENTHREAD_RCP_UART || CONFIG_OPENTHREAD_CONSOLE_TYPE_UART
case HOST_CONNECTION_MODE_RCP_UART:
case HOST_CONNECTION_MODE_CLI_UART:
esp_openthread_uart_deinit();
break;
#endif
default:
break;
}
esp_openthread_lock_deinit();
@@ -217,6 +227,6 @@ uint32_t esp_openthread_get_alloc_caps(void)
#if CONFIG_OPENTHREAD_PLATFORM_MALLOC_CAP_SPIRAM
(MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT);
#else
(MALLOC_CAP_DEFAULT | MALLOC_CAP_8BIT);
(MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT);
#endif
}

View File

@@ -0,0 +1,133 @@
/*
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "sdkconfig.h"
#include <stdatomic.h>
#include <stdbool.h>
#include "esp_check.h"
#include "esp_log.h"
#include "esp_timer.h"
#include "esp_debug_helpers.h"
#include "esp_openthread_debug.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#if CONFIG_OPENTHREAD_TASK_BLOCK_MONITOR
#include "esp_private/eh_frame_parser.h"
#include "esp_private/esp_system_attr.h"
#include "esp_private/esp_cpu_internal.h"
#include "esp_private/fp_unwind.h"
#include "esp_private/panic_internal.h"
#include "freertos/freertos_debug.h"
static const char *TAG = "OT_DEBUG";
static TaskHandle_t s_ot_task_block_monitor_task = NULL;
static atomic_llong s_ot_task_block_monitor_latest_time = 0;
static atomic_bool s_ot_task_block_monitor_active = false;
static const int64_t s_ot_task_block_monitor_timeout = CONFIG_OPENTHREAD_TASK_BLOCK_MONITOR_TIMEOUT * 1000000;
static bool is_backtrace_printed = false;
#if CONFIG_IDF_TARGET_ARCH_RISCV
static esp_err_t ESP_SYSTEM_IRAM_ATTR esp_task_backtrace_print(TaskHandle_t target_task)
{
TaskSnapshot_t snapshot = {};
void *frame = NULL;
vTaskGetSnapshot(target_task, &snapshot);
frame = snapshot.pxTopOfStack;
char *name = pcTaskGetName(target_task);
ESP_LOGI(TAG, "Target Task Backtrace: %s", name ? name : "No Name");
#if CONFIG_ESP_SYSTEM_USE_EH_FRAME
esp_eh_frame_print_backtrace(frame);
#elif CONFIG_ESP_SYSTEM_USE_FRAME_POINTER
esp_fp_print_backtrace(frame);
#else
esp_cpu_frame_t backtrace_frame = {};
const int current_core = xPortGetCoreID();
memset(&backtrace_frame, 0, sizeof(esp_cpu_frame_t));
memcpy(&backtrace_frame, frame, sizeof(esp_cpu_frame_t));
panic_prepare_frame_from_ctx(&backtrace_frame);
panic_print_registers(&backtrace_frame, current_core);
esp_rom_printf("\r\n");
esp_rom_printf("Please enable CONFIG_ESP_SYSTEM_USE_FRAME_POINTER option to have a full backtrace.\r\n");
#endif
return ESP_OK;
}
#endif
static void ot_debug_monitor_task(void *arg)
{
(void)arg;
while (true) {
if (atomic_load(&s_ot_task_block_monitor_active)) {
int64_t elapsed = esp_timer_get_time() - atomic_load(&s_ot_task_block_monitor_latest_time);
if (elapsed > s_ot_task_block_monitor_timeout && !is_backtrace_printed) {
is_backtrace_printed = true;
ESP_LOGW(TAG,
"OpenThread mainloop blocked for more than %d seconds, printing all tasks backtrace",
CONFIG_OPENTHREAD_TASK_BLOCK_MONITOR_TIMEOUT);
#if CONFIG_IDF_TARGET_ARCH_XTENSA
esp_backtrace_print_all_tasks(10);
#elif CONFIG_IDF_TARGET_ARCH_RISCV
TaskHandle_t handle = xTaskGetHandle(CONFIG_OPENTHREAD_TASK_NAME);
if (handle) {
esp_task_backtrace_print(handle);
}
#endif
} else if (elapsed <= s_ot_task_block_monitor_timeout) {
is_backtrace_printed = false;
}
}
vTaskDelay(pdMS_TO_TICKS(1000));
}
}
esp_err_t esp_openthread_task_block_monitor_create(void)
{
ESP_RETURN_ON_FALSE(s_ot_task_block_monitor_task == NULL, ESP_OK, TAG, "Task block monitor already created");
BaseType_t ret = xTaskCreate(ot_debug_monitor_task, "ot_task_monitor", 3072, NULL, CONFIG_OPENTHREAD_TASK_PRIORITY, &s_ot_task_block_monitor_task);
ESP_RETURN_ON_FALSE(ret == pdPASS, ESP_FAIL, TAG, "Failed to create OpenThread task block monitor");
ESP_LOGI(TAG, "OpenThread task block monitor created");
esp_openthread_task_block_monitor_set(true);
return ESP_OK;
}
esp_err_t esp_openthread_task_block_monitor_delete(void)
{
ESP_RETURN_ON_FALSE(s_ot_task_block_monitor_task != NULL, ESP_OK, TAG, "Task block monitor not created");
esp_openthread_task_block_monitor_set(false);
vTaskDelete(s_ot_task_block_monitor_task);
s_ot_task_block_monitor_task = NULL;
ESP_LOGI(TAG, "OpenThread task block monitor deleted");
return ESP_OK;
}
void esp_openthread_task_block_monitor_set(bool enable)
{
if (enable) {
atomic_store(&s_ot_task_block_monitor_latest_time, esp_timer_get_time());
atomic_store(&s_ot_task_block_monitor_active, true);
} else {
atomic_store(&s_ot_task_block_monitor_active, false);
}
}
#endif // CONFIG_OPENTHREAD_TASK_BLOCK_MONITOR

View File

@@ -1,10 +1,11 @@
/*
* SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2021-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "esp_openthread.h"
#include "esp_openthread_platform.h"
#include "openthread/platform/memory.h"
@@ -12,10 +13,10 @@
void *otPlatCAlloc(size_t num, size_t size)
{
return calloc(num, size);
return heap_caps_calloc_prefer(num, size, 3, esp_openthread_get_alloc_caps(), MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT, MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT);
}
void otPlatFree(void *ptr)
{
free(ptr);
heap_caps_free(ptr);
}

View File

@@ -1,35 +1,48 @@
/*
* SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2023-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "openthread-core-config.h"
#include "esp_openthread_common_macro.h"
#include "esp_openthread_platform.h"
#include "esp_err.h"
#include "esp_log.h"
#include "esp_heap_caps.h"
#include "esp_psram.h"
#include "openthread/instance.h"
#include "openthread/platform/messagepool.h"
int s_buffer_pool_head = -1;
otMessageBuffer **s_buffer_pool_pointer = NULL;
otMessageBuffer *s_buffer_pool = NULL;
// Fallback buffer count at runtime for non-PSRAM targets (matches Kconfig default)
#define OT_MSGPOOL_NUM_BUFFERS_NO_PSRAM 65
static int s_buffer_pool_head = -1;
static otMessageBuffer **s_buffer_pool_pointer = NULL;
static otMessageBuffer *s_buffer_pool = NULL;
void otPlatMessagePoolInit(otInstance *aInstance, uint16_t aMinNumFreeBuffers, size_t aBufferSize)
{
otMessageBuffer *buffer_pool = (otMessageBuffer *)heap_caps_calloc(aMinNumFreeBuffers, aBufferSize, MALLOC_CAP_SPIRAM);
s_buffer_pool_pointer = (otMessageBuffer **)heap_caps_calloc(aMinNumFreeBuffers, sizeof(otMessageBuffer **), MALLOC_CAP_SPIRAM);
uint16_t num_buffers = aMinNumFreeBuffers;
if (!esp_psram_is_initialized() && num_buffers > OT_MSGPOOL_NUM_BUFFERS_NO_PSRAM) {
ESP_LOGW(OT_PLAT_LOG_TAG, "PSRAM not available, reducing message pool from %u to %u buffers",
num_buffers, OT_MSGPOOL_NUM_BUFFERS_NO_PSRAM);
num_buffers = OT_MSGPOOL_NUM_BUFFERS_NO_PSRAM;
}
otMessageBuffer *buffer_pool = (otMessageBuffer *)heap_caps_calloc_prefer(num_buffers, aBufferSize, 3, esp_openthread_get_alloc_caps(), MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT, MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT);
s_buffer_pool_pointer = (otMessageBuffer **)heap_caps_calloc_prefer(num_buffers, sizeof(otMessageBuffer **), 3, esp_openthread_get_alloc_caps(), MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT, MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT);
if (buffer_pool == NULL || s_buffer_pool_pointer == NULL) {
ESP_LOGE(OT_PLAT_LOG_TAG, "Failed to create message buffer pool");
assert(false);
}
for (uint16_t i = 0; i < aMinNumFreeBuffers; i++) {
for (uint16_t i = 0; i < num_buffers; i++) {
s_buffer_pool_pointer[i] = buffer_pool + i * aBufferSize / sizeof(otMessageBuffer);
}
s_buffer_pool_head = aMinNumFreeBuffers - 1;
s_buffer_pool_head = num_buffers - 1;
s_buffer_pool = buffer_pool;
ESP_LOGI(OT_PLAT_LOG_TAG, "Create message buffer pool successfully, size %d", aMinNumFreeBuffers*aBufferSize);
ESP_LOGI(OT_PLAT_LOG_TAG, "Create message buffer pool successfully, size %d", num_buffers * aBufferSize);
}
otMessageBuffer *otPlatMessagePoolNew(otInstance *aInstance)

View File

@@ -413,7 +413,7 @@ void otPlatRadioClearSrcMatchExtEntries(otInstance *aInstance)
otError otPlatRadioEnergyScan(otInstance *aInstance, uint8_t aScanChannel, uint16_t aScanDuration)
{
esp_ieee802154_set_channel(aScanChannel);
esp_ieee802154_energy_detect(aScanDuration * US_PER_MS / US_PER_SYMBLE);
esp_ieee802154_energy_detect(aScanDuration * US_PER_MS / US_PER_SYMBOL);
return OT_ERROR_NONE;
}

View File

@@ -0,0 +1,116 @@
# SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
# SPDX-License-Identifier: Apache-2.0
# Source files for FTD (Full Thread Device) and MTD (Minimal Thread Device) modes.
# Uses directory-based collection with exclusions.
set(src_dirs
"src"
"src/port"
"openthread/examples/platforms/utils"
"openthread/src/core/api"
"openthread/src/core/common"
"openthread/src/core/crypto"
"openthread/src/core/diags"
"openthread/src/core/instance"
"openthread/src/core/mac"
"openthread/src/core/radio"
"openthread/src/core/thread"
"openthread/src/core/utils"
"openthread/src/lib/hdlc"
"openthread/src/lib/spinel"
"openthread/src/core/backbone_router"
"openthread/src/core/coap"
"openthread/src/core/meshcop"
"openthread/src/core/net"
"openthread/src/lib/platform"
)
set(exclude_srcs
"openthread/examples/platforms/utils/logging_rtt.c"
"openthread/examples/platforms/utils/soft_source_match_table.c"
"openthread/src/core/instance/extension_example.cpp"
"openthread/src/core/crypto/crypto_platform_mbedtls.cpp"
"openthread/src/core/api/random_crypto_api.cpp"
)
# CLI sources
if(CONFIG_OPENTHREAD_CLI)
list(APPEND src_dirs
"openthread/examples/apps/cli"
"openthread/src/cli")
list(APPEND exclude_srcs
"openthread/examples/apps/cli/main.c")
endif()
# Radio interface exclusions
if(CONFIG_OPENTHREAD_RADIO_NATIVE)
list(APPEND exclude_srcs
"src/port/esp_openthread_radio_spinel.cpp"
"src/port/esp_spi_spinel_interface.cpp"
"src/port/esp_uart_spinel_interface.cpp")
elseif(CONFIG_OPENTHREAD_RADIO_SPINEL_UART OR CONFIG_OPENTHREAD_RADIO_SPINEL_SPI)
list(APPEND exclude_srcs
"src/port/esp_openthread_radio.c"
"src/port/esp_openthread_sleep.c")
elseif(CONFIG_OPENTHREAD_RADIO_154_NONE)
list(APPEND exclude_srcs
"src/port/esp_openthread_radio_spinel.cpp"
"src/port/esp_spi_spinel_interface.cpp"
"src/port/esp_uart_spinel_interface.cpp"
"src/port/esp_openthread_radio.c"
"src/port/esp_openthread_sleep.c")
endif()
# TREL
if(NOT CONFIG_OPENTHREAD_RADIO_TREL)
list(APPEND exclude_srcs
"src/port/esp_openthread_trel.c")
endif()
# Border router
if(CONFIG_OPENTHREAD_BORDER_ROUTER)
list(APPEND src_dirs
"openthread/src/core/border_router")
endif()
# FTD-specific
if(CONFIG_OPENTHREAD_FTD)
set_source_files_properties("openthread/src/core/net/srp_server.cpp"
PROPERTIES COMPILE_FLAGS
-Wno-maybe-uninitialized)
endif()
# NCP vendor hook
if(CONFIG_OPENTHREAD_NCP_VENDOR_HOOK)
list(APPEND src_dirs
"src/ncp")
if(CONFIG_OPENTHREAD_RCP_UART OR CONFIG_OPENTHREAD_RCP_USB_SERIAL_JTAG)
list(APPEND exclude_srcs
"src/ncp/esp_openthread_ncp_spi.cpp")
elseif(CONFIG_OPENTHREAD_RCP_SPI)
list(APPEND exclude_srcs
"src/ncp/esp_openthread_ncp_hdlc.cpp")
endif()
endif()
# Optional features
if(NOT CONFIG_OPENTHREAD_DNS64_CLIENT)
list(APPEND exclude_srcs
"src/esp_openthread_dns64.c")
endif()
if(NOT CONFIG_FREERTOS_USE_TICKLESS_IDLE)
list(APPEND exclude_srcs
"src/port/esp_openthread_sleep.c")
endif()
if(NOT CONFIG_OPENTHREAD_PLATFORM_MSGPOOL_MANAGEMENT)
list(APPEND exclude_srcs
"src/port/esp_openthread_messagepool.c")
endif()
if(NOT CONFIG_OPENTHREAD_RCP_SPINEL_CONSOLE)
list(APPEND exclude_srcs
"src/ncp/esp_openthread_ncp_console.cpp")
endif()

View File

@@ -0,0 +1,97 @@
# SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
# SPDX-License-Identifier: Apache-2.0
# Source files for RCP (Radio Co-Processor) mode.
# Uses explicit whitelist to avoid including non-RCP-compatible files.
# This prevents new OpenThread files from breaking RCP builds.
set(rcp_srcs
# OpenThread core - RADIO_COMMON_SOURCES from openthread/src/core/CMakeLists.txt
# No need for crypto/crypto_platform_mbedtls.cpp because we use esp-idf implementation
openthread/src/core/api/diags_api.cpp
openthread/src/core/api/error_api.cpp
openthread/src/core/api/instance_api.cpp
openthread/src/core/api/link_raw_api.cpp
openthread/src/core/api/logging_api.cpp
openthread/src/core/api/random_noncrypto_api.cpp
openthread/src/core/api/tasklet_api.cpp
openthread/src/core/common/binary_search.cpp
openthread/src/core/common/error.cpp
openthread/src/core/common/frame_builder.cpp
openthread/src/core/common/log.cpp
openthread/src/core/common/random.cpp
openthread/src/core/common/string.cpp
openthread/src/core/common/tasklet.cpp
openthread/src/core/common/timer.cpp
openthread/src/core/common/uptime.cpp
openthread/src/core/crypto/aes_ccm.cpp
openthread/src/core/crypto/aes_ecb.cpp
openthread/src/core/crypto/crypto_platform_psa.cpp
openthread/src/core/crypto/storage.cpp
openthread/src/core/diags/factory_diags.cpp
openthread/src/core/instance/instance.cpp
openthread/src/core/mac/link_raw.cpp
openthread/src/core/mac/mac_frame.cpp
openthread/src/core/mac/mac_header_ie.cpp
openthread/src/core/mac/mac_types.cpp
openthread/src/core/mac/sub_mac.cpp
openthread/src/core/mac/sub_mac_callbacks.cpp
openthread/src/core/mac/sub_mac_csl_receiver.cpp
openthread/src/core/mac/sub_mac_wed.cpp
openthread/src/core/radio/radio.cpp
openthread/src/core/radio/radio_callbacks.cpp
openthread/src/core/radio/radio_platform.cpp
openthread/src/core/thread/link_quality.cpp
openthread/src/core/utils/otns.cpp
openthread/src/core/utils/parse_cmdline.cpp
openthread/src/core/utils/power_calibration.cpp
# Platform utils
openthread/examples/platforms/utils/mac_frame.cpp
# HDLC library
openthread/src/lib/hdlc/hdlc.cpp
# Spinel library
openthread/src/lib/spinel/spinel.c
openthread/src/lib/spinel/spinel_buffer.cpp
openthread/src/lib/spinel/spinel_decoder.cpp
openthread/src/lib/spinel/spinel_encoder.cpp
# NCP
openthread/src/ncp/changed_props_set.cpp
openthread/src/ncp/ncp_base.cpp
openthread/src/ncp/ncp_base_dispatcher.cpp
openthread/src/ncp/ncp_base_radio.cpp
openthread/examples/apps/ncp/ncp.c
# ESP port
src/port/esp_openthread_alarm.c
src/port/esp_openthread_logging.c
src/port/esp_openthread_misc.c
src/port/esp_openthread_radio.c
src/port/esp_openthread_settings.c
# ESP sources
src/esp_openthread.cpp
src/esp_openthread_lock.c
src/esp_openthread_platform.cpp
src/esp_openthread_task_queue.c
# ESP NCP
src/ncp/esp_openthread_ncp.cpp
)
# Conditional sources based on host connection mode
if(CONFIG_OPENTHREAD_RCP_UART OR CONFIG_OPENTHREAD_RCP_USB_SERIAL_JTAG)
list(APPEND rcp_srcs
openthread/src/ncp/ncp_hdlc.cpp
src/port/esp_openthread_uart.c)
if(CONFIG_OPENTHREAD_NCP_VENDOR_HOOK)
list(APPEND rcp_srcs src/ncp/esp_openthread_ncp_hdlc.cpp)
endif()
elseif(CONFIG_OPENTHREAD_RCP_SPI)
list(APPEND rcp_srcs
openthread/src/ncp/ncp_spi.cpp
src/port/esp_openthread_spi_slave.c)
if(CONFIG_OPENTHREAD_NCP_VENDOR_HOOK)
list(APPEND rcp_srcs src/ncp/esp_openthread_ncp_spi.cpp)
endif()
endif()
if(CONFIG_OPENTHREAD_NCP_VENDOR_HOOK AND CONFIG_OPENTHREAD_RCP_SPINEL_CONSOLE)
list(APPEND rcp_srcs src/ncp/esp_openthread_ncp_console.cpp)
endif()

View File

@@ -0,0 +1,45 @@
# SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
# SPDX-License-Identifier: Apache-2.0
# Source files for SPINEL_ONLY mode.
# Minimal build for host-side spinel communication.
# Uses explicit whitelist for clarity.
set(private_include_dirs
"private_include"
"openthread/src"
"openthread/src/core"
"openthread/src/include"
"openthread/src/lib"
"openthread/src/lib/hdlc"
"openthread/src/lib/spinel"
)
set(spinel_srcs
# ESP spinel sources
src/spinel/esp_radio_spinel.cpp
src/spinel/esp_radio_spinel_uart_interface.cpp
# ESP port (minimal)
src/port/esp_openthread_alarm.c
src/port/esp_openthread_logging.c
# OpenThread spinel library
openthread/src/lib/spinel/spinel.c
openthread/src/lib/spinel/spinel_buffer.cpp
openthread/src/lib/spinel/spinel_decoder.cpp
openthread/src/lib/spinel/spinel_encoder.cpp
openthread/src/lib/spinel/spinel_helper.cpp
openthread/src/lib/spinel/radio_spinel.cpp
openthread/src/lib/spinel/spinel_driver.cpp
openthread/src/lib/spinel/logger.cpp
# OpenThread HDLC library
openthread/src/lib/hdlc/hdlc.cpp
# OpenThread platform library
openthread/src/lib/platform/exit_code.c
# OpenThread core (minimal)
openthread/src/core/api/error_api.cpp
openthread/src/core/api/logging_api.cpp
openthread/src/core/common/error.cpp
openthread/src/core/common/log.cpp
openthread/src/core/common/string.cpp
openthread/src/core/mac/mac_frame.cpp
)

View File

@@ -25,6 +25,8 @@ examples/openthread/ot_br:
enable:
- if: ((SOC_WIFI_SUPPORTED == 1 and IDF_TARGET != "esp32c61") or IDF_TARGET == "esp32p4") and CONFIG_NAME != "native_radio"
- if: SOC_WIFI_SUPPORTED == 1 and (SOC_IEEE802154_SUPPORTED == 1 and CONFIG_NAME == "native_radio")
disable:
- if: IDF_TARGET in ["esp32", "esp32s2", "esp32s3"] and CONFIG_NAME == "br_debug_riscv"
disable_test:
- if: IDF_TARGET not in ["esp32s3"]
reason: only test on esp32s3

View File

@@ -1,5 +1,5 @@
# Name, Type, SubType, Offset, Size, Flags
# 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, 1900K,
nvs, data, nvs, , 0x6000,
phy_init, data, phy, , 0x1000,
factory, app, factory, , 2000K,
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, nvs, data, nvs, , 0x6000,
4 phy_init, data, phy, 0xf000, 0x1000, phy_init, data, phy, , 0x1000,
5 factory, app, factory, 0x10000, 1900K, factory, app, factory, , 2000K,

View File

@@ -0,0 +1,2 @@
CONFIG_OPENTHREAD_DEBUG=y
CONFIG_OPENTHREAD_TASK_BLOCK_MONITOR=y

View File

@@ -0,0 +1,3 @@
CONFIG_ESP_SYSTEM_USE_FRAME_POINTER=y
CONFIG_OPENTHREAD_DEBUG=y
CONFIG_OPENTHREAD_TASK_BLOCK_MONITOR=y

View File

@@ -4,7 +4,6 @@
CONFIG_PARTITION_TABLE_CUSTOM=y
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv"
CONFIG_PARTITION_TABLE_FILENAME="partitions.csv"
CONFIG_PARTITION_TABLE_OFFSET=0x8000
CONFIG_PARTITION_TABLE_MD5=y
# end of Partition Table
@@ -58,3 +57,8 @@ CONFIG_EXAMPLE_CONNECT_THREAD=n
CONFIG_ESP_SYSTEM_EVENT_TASK_STACK_SIZE=3584
CONFIG_ESP_MAIN_TASK_STACK_SIZE=6144
# end of ESP System Settings
#
# Serial flasher config
#
CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y

View File

@@ -5,3 +5,5 @@ CONFIG_OPENTHREAD_BORDER_ROUTER_AUTO_START=y
# Enable PPP support as a workaround to ensure LWIP thread-lib compatibility for Ethernet builds
CONFIG_LWIP_PPP_SUPPORT=y
CONFIG_LWIP_PPP_SERVER_SUPPORT=y
# Increase size of bootloader due to frame pointer. Only overflowed on P4.
CONFIG_PARTITION_TABLE_OFFSET=0x9000