From f798e08bc471cfbd694e4b05ab31209a632e41c9 Mon Sep 17 00:00:00 2001 From: Xu Si Yu Date: Thu, 4 Dec 2025 17:33:56 +0800 Subject: [PATCH] feat(802.15.4): add multipan pending table support --- components/ieee802154/Kconfig | 10 +++ .../ieee802154/driver/esp_ieee802154_ack.c | 65 +++++++------- .../ieee802154/driver/esp_ieee802154_dev.c | 87 ++++++++++++++++++- .../ieee802154/driver/esp_ieee802154_frame.c | 7 ++ .../ieee802154/driver/esp_ieee802154_pib.c | 22 +++-- components/ieee802154/esp_ieee802154.c | 57 +++++++++--- .../ieee802154/include/esp_ieee802154.h | 76 +++++++++++++++- .../ieee802154/include/esp_ieee802154_types.h | 1 + .../private_include/esp_ieee802154_ack.h | 11 +-- .../private_include/esp_ieee802154_dev.h | 2 +- .../private_include/esp_ieee802154_pib.h | 9 +- 11 files changed, 285 insertions(+), 62 deletions(-) diff --git a/components/ieee802154/Kconfig b/components/ieee802154/Kconfig index 54e7229aff..0948408932 100644 --- a/components/ieee802154/Kconfig +++ b/components/ieee802154/Kconfig @@ -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 diff --git a/components/ieee802154/driver/esp_ieee802154_ack.c b/components/ieee802154/driver/esp_ieee802154_ack.c index 5b03c7e707..60302a1dd1 100644 --- a/components/ieee802154/driver/esp_ieee802154_ack.c +++ b/components/ieee802154/driver/esp_ieee802154_ack.c @@ -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,18 +112,25 @@ 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; @@ -137,7 +144,7 @@ bool ieee802154_ack_config_pending_bit(const uint8_t *frame) pending_bit = ieee802154_is_data_request(frame); } - ieee802154_ll_pending_mode_t pending_mode = ieee802154_pib_get_pending_mode(); + ieee802154_ll_pending_mode_t pending_mode = ieee802154_pib_get_pending_mode(inf_index); switch (pending_mode) { case IEEE802154_AUTO_PENDING_DISABLE: @@ -148,13 +155,13 @@ bool ieee802154_ack_config_pending_bit(const uint8_t *frame) 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) { - pending_bit = ieee802154_addr_in_pending_table(addr, src_mode == IEEE802154_FRAME_SRC_MODE_SHORT); + 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 = !(src_mode == IEEE802154_FRAME_SRC_MODE_SHORT && ieee802154_addr_in_pending_table(addr, src_mode == IEEE802154_FRAME_SRC_MODE_SHORT)); + pending_bit = !(src_mode == IEEE802154_FRAME_SRC_MODE_SHORT && ieee802154_addr_in_pending_table(inf_index, addr, src_mode == IEEE802154_FRAME_SRC_MODE_SHORT)); break; default: IEEE802154_ASSERT(false); diff --git a/components/ieee802154/driver/esp_ieee802154_dev.c b/components/ieee802154/driver/esp_ieee802154_dev.c index 9e17e39c94..9ba3f81b31 100644 --- a/components/ieee802154/driver/esp_ieee802154_dev.c +++ b/components/ieee802154/driver/esp_ieee802154_dev.c @@ -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 */ @@ -144,12 +144,93 @@ 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]; +#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; s_rx_frame_info[s_rx_index].lqi = lqi; @@ -436,12 +517,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(); diff --git a/components/ieee802154/driver/esp_ieee802154_frame.c b/components/ieee802154/driver/esp_ieee802154_frame.c index 7485e1fd33..35e4eb5b84 100644 --- a/components/ieee802154/driver/esp_ieee802154_frame.c +++ b/components/ieee802154/driver/esp_ieee802154_frame.c @@ -333,6 +333,9 @@ uint8_t ieee802154_frame_get_dst_addr(const uint8_t *frame, uint8_t *addr) uint8_t offset = ieee802154_frame_address_offset(frame); uint8_t dst_mode = dst_addr_mode(frame); + if (dst_mode == IEEE802154_FRAME_DST_MODE_NONE) { + return dst_mode; + } 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"); @@ -357,6 +360,10 @@ uint8_t ieee802154_frame_get_src_addr(const uint8_t *frame, uint8_t *addr) uint8_t src_mode = src_addr_mode(frame); uint8_t addr_size; + if (src_mode == IEEE802154_FRAME_SRC_MODE_NONE) { + return src_mode; + } + 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"); addr_size = (src_mode == IEEE802154_FRAME_SRC_MODE_SHORT) ? IEEE802154_FRAME_SHORT_ADDR_SIZE : IEEE802154_FRAME_EXT_ADDR_SIZE; diff --git a/components/ieee802154/driver/esp_ieee802154_pib.c b/components/ieee802154/driver/esp_ieee802154_pib.c index 57204949c1..bcfc13d290 100644 --- a/components/ieee802154/driver/esp_ieee802154_pib.c +++ b/components/ieee802154/driver/esp_ieee802154_pib.c @@ -1,11 +1,12 @@ /* - * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ #include #include +#include "sdkconfig.h" #include "hal/ieee802154_ll.h" #include "esp_check.h" #include "esp_ieee802154_pib.h" @@ -74,7 +75,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(); } @@ -231,15 +239,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(); } } diff --git a/components/ieee802154/esp_ieee802154.c b/components/ieee802154/esp_ieee802154.c index 39342eba8f..6f6f4282fc 100644 --- a/components/ieee802154/esp_ieee802154.c +++ b/components/ieee802154/esp_ieee802154.c @@ -163,40 +163,40 @@ 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); 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); ieee802154_ll_set_multipan_ext_addr(index, ext_addr); return ESP_OK; } @@ -208,10 +208,43 @@ 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) @@ -266,12 +299,12 @@ esp_err_t esp_ieee802154_set_extended_address(const uint8_t *ext_addr) 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; } @@ -359,17 +392,17 @@ esp_err_t esp_ieee802154_set_transmit_security(uint8_t *frame, uint8_t *key, uin esp_err_t esp_ieee802154_add_pending_addr(const uint8_t *addr, bool is_short) { - return ieee802154_add_pending_addr(addr, is_short); + return ieee802154_add_pending_addr(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); + return ieee802154_clear_pending_addr(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(0, is_short); return ESP_OK; } diff --git a/components/ieee802154/include/esp_ieee802154.h b/components/ieee802154/include/esp_ieee802154.h index 2971cc22c6..63cab50d2d 100644 --- a/components/ieee802154/include/esp_ieee802154.h +++ b/components/ieee802154/include/esp_ieee802154.h @@ -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 */ @@ -756,6 +756,80 @@ esp_err_t esp_ieee802154_event_callback_list_register(esp_ieee802154_event_cb_li */ 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 diff --git a/components/ieee802154/include/esp_ieee802154_types.h b/components/ieee802154/include/esp_ieee802154_types.h index bf52ed91a4..ce01937fb9 100644 --- a/components/ieee802154/include/esp_ieee802154_types.h +++ b/components/ieee802154/include/esp_ieee802154_types.h @@ -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; /** diff --git a/components/ieee802154/private_include/esp_ieee802154_ack.h b/components/ieee802154/private_include/esp_ieee802154_ack.h index 2910a561b4..83154e409f 100644 --- a/components/ieee802154/private_include/esp_ieee802154_ack.h +++ b/components/ieee802154/private_include/esp_ieee802154_ack.h @@ -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 #include "sdkconfig.h" #include "esp_err.h" +#include "esp_ieee802154_types.h" #include "esp_ieee802154_frame.h" #ifdef __cplusplus @@ -40,7 +41,7 @@ typedef struct { * - ESP_FAIL on failure due to the table is full. * */ -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. @@ -53,7 +54,7 @@ esp_err_t ieee802154_add_pending_addr(const uint8_t *addr, bool is_short); * - ESP_FAIL on failure if the given address is not present in the pending table. * */ -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,7 +62,7 @@ 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. @@ -72,7 +73,7 @@ void ieee802154_reset_pending_table(bool is_short); * - True 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 } diff --git a/components/ieee802154/private_include/esp_ieee802154_dev.h b/components/ieee802154/private_include/esp_ieee802154_dev.h index 1d53af66f0..aaeed472ee 100644 --- a/components/ieee802154/private_include/esp_ieee802154_dev.h +++ b/components/ieee802154/private_include/esp_ieee802154_dev.h @@ -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 */ diff --git a/components/ieee802154/private_include/esp_ieee802154_pib.h b/components/ieee802154/private_include/esp_ieee802154_pib.h index c6edcde134..3824852b9c 100644 --- a/components/ieee802154/private_include/esp_ieee802154_pib.h +++ b/components/ieee802154/private_include/esp_ieee802154_pib.h @@ -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 #include +#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; @@ -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,7 +257,7 @@ 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.