diff --git a/components/esp_phy/src/btbb_init.c b/components/esp_phy/src/btbb_init.c index 41d78dd83a..114c2f2bde 100644 --- a/components/esp_phy/src/btbb_init.c +++ b/components/esp_phy/src/btbb_init.c @@ -7,12 +7,13 @@ #include #include "esp_check.h" #include "esp_log.h" -#include "freertos/FreeRTOS.h" #include "esp_private/btbb.h" +#include + #define BTBB_ENABLE_VERSION_PRINT 1 -static _lock_t s_btbb_access_lock; +static struct k_spinlock s_btbb_access_lock; /* Reference count of enabling BT BB */ static uint8_t s_btbb_access_ref = 0; @@ -57,7 +58,7 @@ static void btbb_sleep_retention_deinit(void) void esp_btbb_enable(void) { - _lock_acquire(&s_btbb_access_lock); + k_spinlock_key_t key = k_spin_lock(&s_btbb_access_lock); if (s_btbb_access_ref == 0) { bt_bb_v2_init_cmplx(BTBB_ENABLE_VERSION_PRINT); #if SOC_PM_MODEM_RETENTION_BY_REGDMA && CONFIG_FREERTOS_USE_TICKLESS_IDLE @@ -77,16 +78,16 @@ void esp_btbb_enable(void) #endif // SOC_PM_MODEM_RETENTION_BY_REGDMA && CONFIG_FREERTOS_USE_TICKLESS_IDLE } s_btbb_access_ref++; - _lock_release(&s_btbb_access_lock); + k_spin_unlock(&s_btbb_access_lock, key); } void esp_btbb_disable(void) { - _lock_acquire(&s_btbb_access_lock); + k_spinlock_key_t key = k_spin_lock(&s_btbb_access_lock); if (s_btbb_access_ref && (--s_btbb_access_ref == 0)) { #if SOC_PM_MODEM_RETENTION_BY_REGDMA && CONFIG_FREERTOS_USE_TICKLESS_IDLE btbb_sleep_retention_deinit(); #endif // SOC_PM_MODEM_RETENTION_BY_REGDMA && CONFIG_FREERTOS_USE_TICKLESS_IDLE } - _lock_release(&s_btbb_access_lock); + k_spin_unlock(&s_btbb_access_lock, key); } diff --git a/components/esp_timer/src/esp_timer.c b/components/esp_timer/src/esp_timer.c index f7f4609d2c..9102b6e33d 100644 --- a/components/esp_timer/src/esp_timer.c +++ b/components/esp_timer/src/esp_timer.c @@ -586,7 +586,7 @@ esp_err_t esp_timer_init(void) return err; } -#if defined(CONFIG_WIFI_ESP32) || defined(CONFIG_BT_ESP32) +#if defined(CONFIG_WIFI_ESP32) || defined(CONFIG_BT_ESP32) || defined(CONFIG_IEEE802154_ESP32) SYS_INIT(esp_timer_init, POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT); #endif diff --git a/components/ieee802154/CMakeLists.txt b/components/ieee802154/CMakeLists.txt new file mode 100644 index 0000000000..901db1b534 --- /dev/null +++ b/components/ieee802154/CMakeLists.txt @@ -0,0 +1,39 @@ +idf_build_get_property(target IDF_TARGET) + +if(${target} STREQUAL "linux") + return() # This component is not supported by the POSIX/Linux simulator +endif() + +set(srcs "") +set(include "include") +set(private_include "") + +if(CONFIG_IEEE802154_ENABLED) + list(APPEND srcs "esp_ieee802154.c" + "driver/esp_ieee802154_ack.c" + "driver/esp_ieee802154_dev.c" + "driver/esp_ieee802154_frame.c" + "driver/esp_ieee802154_pib.c" + "driver/esp_ieee802154_util.c" + "driver/esp_ieee802154_sec.c" + "driver/esp_ieee802154_timer.c") + list(APPEND private_include "private_include") + + if(CONFIG_IEEE802154_TEST) + list(REMOVE_ITEM private_include "private_include") + list(APPEND include "private_include") + endif() + +endif() + +if(CONFIG_IEEE802154_DEBUG) + list(APPEND srcs "driver/esp_ieee802154_debug.c") +endif() + +idf_component_register( + SRCS "${srcs}" + INCLUDE_DIRS "${include}" + PRIV_INCLUDE_DIRS "${private_include}" + LDFRAGMENTS linker.lf + PRIV_REQUIRES esp_phy esp_timer esp_coex soc hal esp_pm +) diff --git a/components/ieee802154/Kconfig b/components/ieee802154/Kconfig new file mode 100644 index 0000000000..9c5d18e237 --- /dev/null +++ b/components/ieee802154/Kconfig @@ -0,0 +1,176 @@ +menu "IEEE 802.15.4" + visible if SOC_IEEE802154_SUPPORTED + + config IEEE802154_ENABLED + bool "IEEE802154 Enable" + default "y" if SOC_IEEE802154_SUPPORTED + + config IEEE802154_RX_BUFFER_SIZE + int "The number of 802.15.4 receive buffers" + depends on IEEE802154_ENABLED + default 20 + range 2 100 + help + The number of 802.15.4 receive buffers + + choice IEEE802154_CCA_MODE + depends on IEEE802154_ENABLED + prompt "Clear Channel Assessment (CCA) mode" + default IEEE802154_CCA_ED + help + configure the CCA mode + + config IEEE802154_CCA_CARRIER + bool "Carrier sense only" + help + configure the CCA mode to Energy above threshold + + config IEEE802154_CCA_ED + bool "Energy above threshold" + help + configure the CCA mode to Energy above threshold + + config IEEE802154_CCA_CARRIER_OR_ED + bool "Carrier sense OR energy above threshold" + help + configure the CCA mode to Carrier sense OR energy above threshold + + config IEEE802154_CCA_CARRIER_AND_ED + bool "Carrier sense AND energy above threshold" + help + configure the CCA mode to Carrier sense AND energy above threshold + endchoice + + config IEEE802154_CCA_MODE + depends on IEEE802154_ENABLED + int + default 0 if IEEE802154_CCA_CARRIER + default 1 if IEEE802154_CCA_ED + default 2 if IEEE802154_CCA_CARRIER_OR_ED + default 3 if IEEE802154_CCA_CARRIER_AND_ED + + config IEEE802154_CCA_THRESHOLD + int "CCA detection threshold" + depends on IEEE802154_ENABLED + range -120 0 + default -60 + help + set the CCA threshold, in dB + + config IEEE802154_PENDING_TABLE_SIZE + int "Pending table size" + depends on IEEE802154_ENABLED + range 1 100 + default 20 + help + set the pending table size + + config IEEE802154_MULTI_PAN_ENABLE + bool "Enable multi-pan feature for frame filter" + depends on IEEE802154_ENABLED + default n + help + Enable IEEE802154 multi-pan + + config IEEE802154_TIMING_OPTIMIZATION + bool "Enable throughput optimization" + depends on IEEE802154_ENABLED + default n + help + Enabling this option increases throughput by ~5% at the expense of ~2.1k + IRAM code size increase. + + config IEEE802154_SLEEP_ENABLE + # Todo: Remove when support safe power-down of the power domain (IDF-7317) + bool "Enable IEEE802154 light sleep" + depends on PM_ENABLE && IEEE802154_ENABLED + default n + help + Enabling this option allows the IEEE802.15.4 module to be powered down during automatic light sleep, + which reduces current consumption. + + menuconfig IEEE802154_DEBUG + bool "Enable IEEE802154 Debug" + depends on IEEE802154_ENABLED + default n + help + Enabling this option allows different kinds of IEEE802154 debug output. + All IEEE802154 debug features increase the size of the final binary. + + config IEEE802154_ASSERT + bool "Enrich the assert information with IEEE802154 state and event" + depends on IEEE802154_DEBUG + default n + help + Enabling this option to add some probe codes in the driver, and these informations + will be printed when assert. + + config IEEE802154_RECORD_EVENT + bool "Enable record event information for debugging" + depends on IEEE802154_DEBUG + default n + help + Enabling this option to record event, when assert, the recorded event will be printed. + + config IEEE802154_RECORD_EVENT_SIZE + int "Record event table size" + depends on IEEE802154_RECORD_EVENT + range 1 50 + default 30 + help + set the record event table size + + config IEEE802154_RECORD_STATE + bool "Enable record state information for debugging" + depends on IEEE802154_DEBUG + default n + help + Enabling this option to record state, when assert, the recorded state will be printed. + + config IEEE802154_RECORD_STATE_SIZE + int "Record state table size" + depends on IEEE802154_RECORD_STATE + range 1 50 + default 10 + help + set the record state table size + + config IEEE802154_RECORD_CMD + bool "Enable record command information for debugging" + depends on IEEE802154_DEBUG + default n + help + Enabling this option to record the command, when assert, the recorded + command will be printed. + + config IEEE802154_RECORD_CMD_SIZE + int "Record command table size" + depends on IEEE802154_RECORD_CMD + range 1 50 + default 10 + help + set the record command table size + + config IEEE802154_RECORD_ABORT + bool "Enable record abort information for debugging" + depends on IEEE802154_DEBUG + default n + help + Enabling this option to record the abort, when assert, the recorded + abort will be printed. + + config IEEE802154_RECORD_ABORT_SIZE + int "Record abort table size" + depends on IEEE802154_RECORD_ABORT + range 1 50 + default 10 + help + set the record abort table size + + config IEEE802154_TXRX_STATISTIC + bool "Enable record tx/rx packets information for debugging" + depends on IEEE802154_DEBUG + default n + help + Enabling this option to record the tx and rx +endmenu # IEEE 802.15.4 diff --git a/components/ieee802154/driver/esp_ieee802154_ack.c b/components/ieee802154/driver/esp_ieee802154_ack.c new file mode 100644 index 0000000000..cb21dd72a0 --- /dev/null +++ b/components/ieee802154/driver/esp_ieee802154_ack.c @@ -0,0 +1,167 @@ +/* + * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include "hal/ieee802154_ll.h" +#include "esp_attr.h" +#include "esp_err.h" +#include "esp_ieee802154_ack.h" +#include "esp_ieee802154_dev.h" +#include "esp_ieee802154_frame.h" +#include "esp_ieee802154_pib.h" +#include "esp_ieee802154_types.h" +#include "esp_ieee802154_util.h" + +static ieee802154_pending_table_t ieee802154_pending_table; + +#define GET_MASK_ITEM_FROM_TABLE(mask, pos) (mask[(pos) / IEEE802154_PENDING_TABLE_MASK_BITS]) + +#define BIT_SET(mask, pos) (GET_MASK_ITEM_FROM_TABLE(mask, pos) |= (1UL << (pos % IEEE802154_PENDING_TABLE_MASK_BITS))) +#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) +{ + 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) { + 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) { + ret = true; + break; + } + } + } + return ret; +} + +esp_err_t ieee802154_add_pending_addr(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)) { + // 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) { + // 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); + 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)) { + 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) { + // 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); + ret = ESP_OK; + } + } + return ret; +} + +esp_err_t ieee802154_clear_pending_addr(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); + 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); + ret = ESP_OK; + break; + } + } + } + + return ret; +} + +void ieee802154_reset_pending_table(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); + } else { + memset(ieee802154_pending_table.ext_addr_mask, 0, IEEE802154_PENDING_TABLE_MASK_SIZE); + } +} + +bool ieee802154_ack_config_pending_bit(const uint8_t *frame) +{ + 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(); + + switch (pending_mode) { + case IEEE802154_AUTO_PENDING_DISABLE: + // HW will check whether the frame is data request or not + pending_bit = true; + 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; + } + } + 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)) { + pending_bit = false; + } + break; + default: + IEEE802154_ASSERT(false); + } + + if (set_to_hw) { + ieee802154_ll_set_pending_bit(pending_bit); + } + + return pending_bit; +} diff --git a/components/ieee802154/driver/esp_ieee802154_debug.c b/components/ieee802154/driver/esp_ieee802154_debug.c new file mode 100644 index 0000000000..0dbfd4bc59 --- /dev/null +++ b/components/ieee802154/driver/esp_ieee802154_debug.c @@ -0,0 +1,373 @@ +/* + * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include "hal/ieee802154_ll.h" +#include "esp_ieee802154_util.h" +#include "esp_log.h" + +#if CONFIG_IEEE802154_DEBUG +ieee802154_probe_info_t g_ieee802154_probe; + +#if CONFIG_IEEE802154_RECORD_EVENT +static char *ieee802154_get_event_string(ieee802154_ll_event_t events) +{ + char *event_string = ""; + switch (events) { + case IEEE802154_EVENT_TX_DONE: + event_string = "TX_DONE"; + break; + case IEEE802154_EVENT_RX_DONE: + event_string = "RX_DONE"; + break; + case IEEE802154_EVENT_ACK_TX_DONE: + event_string = "ACK_TX_DONE"; + break; + case IEEE802154_EVENT_ACK_RX_DONE: + event_string = "ACK_RX_DONE"; + break; + case IEEE802154_EVENT_RX_ABORT: + event_string = "RX_ABORT"; + break; + case IEEE802154_EVENT_TX_ABORT: + event_string = "TX_ABORT"; + break; + case IEEE802154_EVENT_ED_DONE: + event_string = "ED_DONE"; + break; + case IEEE802154_EVENT_TIMER0_OVERFLOW: + event_string = "TIMER0_OVERFLOW"; + break; + case IEEE802154_EVENT_TIMER1_OVERFLOW: + event_string = "TIMER1_OVERFLOW"; + break; + case IEEE802154_EVENT_CLOCK_COUNT_MATCH: + event_string = "CLOCK_COUNT_MATCH"; + break; + case IEEE802154_EVENT_TX_SFD_DONE: + event_string = "TX_SFD_DONE"; + break; + case IEEE802154_EVENT_RX_SFD_DONE: + event_string = "RX_SFD_DONE"; + break; + default: + event_string = "Multi events"; + break; + } + return event_string; +} +#endif // CONFIG_IEEE802154_RECORD_EVENT + +#if CONFIG_IEEE802154_RECORD_STATE || CONFIG_IEEE802154_RECORD_EVENT +static char *ieee802154_state_string[] = { + "DISABLE", + "IDLE", + "SLEEP", + "RX", + "TX_ACK", + "TX_ENH_ACK", + "TX_CCA", + "TX", + "DTM_TX", + "RX_ACK", + "ED", + "CCA", +}; +#endif // CONFIG_IEEE802154_RECORD_STATE + +#if CONFIG_IEEE802154_RECORD_CMD +static char *ieee802154_get_cmd_string(ieee802154_ll_cmd_t cmd) +{ + char *cmd_string = ""; + switch (cmd) { + case IEEE802154_CMD_TX_START: + cmd_string = "tx"; + break; + case IEEE802154_CMD_RX_START: + cmd_string = "rx"; + break; + case IEEE802154_CMD_CCA_TX_START: + cmd_string = "tx cca"; + break; + case IEEE802154_CMD_ED_START: + cmd_string = "ed"; + break; + case IEEE802154_CMD_STOP: + cmd_string = "stop"; + break; + case IEEE802154_CMD_TEST_TX_START: + cmd_string = "test tx"; + break; + case IEEE802154_CMD_TEST_RX_START: + cmd_string = "test rx"; + break; + case IEEE802154_CMD_TEST_STOP: + cmd_string = "test stop"; + break; + case IEEE802154_CMD_TIMER0_START: + cmd_string = "timer0 start"; + break; + case IEEE802154_CMD_TIMER0_STOP: + cmd_string = "timer0 stop"; + break; + case IEEE802154_CMD_TIMER1_START: + cmd_string = "timer1 start"; + break; + case IEEE802154_CMD_TIMER1_STOP: + cmd_string = "timer1 stop"; + break; + } + return cmd_string; +} +#endif // CONFIG_IEEE802154_RECORD_CMD + +#if CONFIG_IEEE802154_RECORD_EVENT || CONFIG_IEEE802154_RECORD_ABORT +static char *ieee80154_rx_abort_reason_string[] = { + "RSVD", // = 0, + "RX_STOP", // = 1, + "SFD_TIMEOUT", // = 2, + "CRC_ERROR ", // = 3, + "INVALID_LEN", // = 4, + "FILTER_FAIL", // = 5, + "NO_RSS ", // = 6, + "COEX_BREAK ", // = 7, + "UNEXPECTED_ACK", // = 8, + "RX_RESTART", // = 9, + "RSVD", "RSVD", "RSVD", "RSVD", "RSVD", "RSVD", // = 10~15, + "TX_ACK_TIMEOUT", // = 16, + "TX_ACK_STOP", // = 17, + "TX_ACK_COEX_BREAK", // = 18, + "ENHACK_SECURITY_ERROR", // = 19, + "RSVD", "RSVD", "RSVD", "RSVD", // = 20~23 + "ED_ABORT", // = 24, + "ED_STOP", // = 25, + "ED_COEX_REJECT", // = 26, +}; + +static char *ieee80154_tx_abort_reason_string[] = { + "RSVD", // = 0, + "RX_ACK_STOP", // = 1, + "RX_ACK_SFD_TIMEOUT", // = 2, + "RX_ACK_CRC_ERROR", // = 3, + "RX_ACK_INVALID_LEN", // = 4, + "RX_ACK_FILTER_FAIL", // = 5, + "RX_ACK_NO_RSS", // = 6, + "RX_ACK_COEX_BREAK", // = 7, + "RX_ACK_TYPE_NOT_ACK", // = 8, + "RX_ACK_RESTART", // = 9, + "RSVD", "RSVD", "RSVD", "RSVD", "RSVD", "RSVD", // = 10~15, + "RX_ACK_TIMEOUT", // = 16, + "TX_STOP", // = 17, + "TX_COEX_BREAK", // = 18, + "TX_SECURITY_ERROR", // = 19, + "RSVD", "RSVD", "RSVD", "RSVD", // = 20~23 + "CCA_FAILED", // = 24, + "CCA_BUSY", // = 25, +}; + +#endif // CONFIG_IEEE802154_RECORD_EVENT + +#if CONFIG_IEEE802154_ASSERT +void ieee802154_assert_print(void) +{ +#if CONFIG_IEEE802154_RECORD_EVENT + ESP_EARLY_LOGW(IEEE802154_TAG, "Print the record event, current event index: %d", g_ieee802154_probe.event_index); + for (uint8_t i = 0; i < IEEE802154_ASSERT_RECORD_EVENT_SIZE; i++) { + char event_log[200] = { 0 }; + 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], + 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]); + } 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]); + } + ESP_EARLY_LOGW(IEEE802154_TAG, "%s %s", event_log, abort_log); + } + ESP_EARLY_LOGW(IEEE802154_TAG,"Print the record event done."); +#endif // CONFIG_IEEE802154_RECORD_EVENT + +#if CONFIG_IEEE802154_RECORD_STATE + ESP_EARLY_LOGW(IEEE802154_TAG, "Print the record state, current state index: %d", g_ieee802154_probe.state_index); + for (uint8_t i = 0; i < IEEE802154_ASSERT_RECORD_STATE_SIZE; i++) { + ESP_EARLY_LOGW(IEEE802154_TAG, "index %2d: line:%5s, state:%10s, timestamp: %lld", + i, g_ieee802154_probe.state[i].line_str, + ieee802154_state_string[g_ieee802154_probe.state[i].state], + g_ieee802154_probe.state[i].timestamp); + } + ESP_EARLY_LOGW(IEEE802154_TAG,"Print the record state done."); +#endif // CONFIG_IEEE802154_RECORD_STATE + +#if CONFIG_IEEE802154_RECORD_CMD + ESP_EARLY_LOGW(IEEE802154_TAG, "Print the record cmd, current cmd index: %d", g_ieee802154_probe.cmd_index); + for (uint8_t i = 0; i < IEEE802154_ASSERT_RECORD_CMD_SIZE; i++) { + ESP_EARLY_LOGW(IEEE802154_TAG, "index %2d: line:%5s, cmd:%10s, timestamp: %lld", + i, g_ieee802154_probe.cmd[i].line_str, + ieee802154_get_cmd_string(g_ieee802154_probe.cmd[i].cmd), + g_ieee802154_probe.cmd[i].timestamp); + } + ESP_EARLY_LOGW(IEEE802154_TAG,"Print the record cmd done."); +#endif // CONFIG_IEEE802154_RECORD_CMD + +#if CONFIG_IEEE802154_RECORD_ABORT + ESP_EARLY_LOGW(IEEE802154_TAG, "Print the record abort, current abort index: %d", g_ieee802154_probe.abort_index); + for (uint8_t i = 0; i < IEEE802154_ASSERT_RECORD_ABORT_SIZE; i++) { + 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], + 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], + g_ieee802154_probe.abort[i].timestamp); + } + } + ESP_EARLY_LOGW(IEEE802154_TAG,"Print the record abort done."); +#endif // CONFIG_IEEE802154_RECORD_ABORT +} +#endif // CONFIG_IEEE802154_ASSERT + +#if CONFIG_IEEE802154_TXRX_STATISTIC +static ieee802154_txrx_statistic_t s_ieee802154_txrx_statistic; + +void ieee802154_txrx_statistic_clear(void) +{ + memset(&s_ieee802154_txrx_statistic, 0, sizeof(ieee802154_txrx_statistic_t)); +} + +void ieee802154_txrx_statistic(ieee802154_ll_events events) +{ + if (events == IEEE802154_EVENT_TX_DONE) { + s_ieee802154_txrx_statistic.tx.done_nums++; + } else if (events == IEEE802154_EVENT_RX_DONE) { + s_ieee802154_txrx_statistic.rx.done_nums++; + } + s_ieee802154_txrx_statistic.tx.abort.cca_busy_nums += ieee802154_ll_get_cca_busy_cnt(); + ieee802154_ll_clear_debug_cnt(IEEE802154_CCA_BUSY_CNT_CLEAR); + s_ieee802154_txrx_statistic.tx.abort.tx_security_error_nums += ieee802154_ll_get_tx_security_error_cnt(); + ieee802154_ll_clear_debug_cnt(IEEE802154_TX_SECURITY_ERROR_CNT_CLEAR); + + // Do not record TX_BREAK_COEX_ERR due to ZB-105. + + s_ieee802154_txrx_statistic.tx.abort.rx_ack_timeout_nums += ieee802154_ll_get_rx_ack_timeout_cnt(); + ieee802154_ll_clear_debug_cnt(IEEE802154_RX_ACK_TIMEOUT_CNT_CLEAR); + s_ieee802154_txrx_statistic.tx.abort.rx_ack_coex_break_nums += ieee802154_ll_get_rx_ack_abort_coex_cnt(); + ieee802154_ll_clear_debug_cnt(IEEE802154_RX_ACK_ABORT_COEX_CNT_CLEAR); + s_ieee802154_txrx_statistic.tx.abort.cca_failed_nums += ieee802154_ll_get_cca_fail_cnt(); + ieee802154_ll_clear_debug_cnt(IEEE802154_CCA_FAIL_CNT_CLEAR); + s_ieee802154_txrx_statistic.rx.abort.tx_ack_coex_break_nums += ieee802154_ll_get_tx_ack_abort_coex_cnt(); + ieee802154_ll_clear_debug_cnt(IEEE802154_TX_ACK_ABORT_COEX_CNT_CLEAR); + s_ieee802154_txrx_statistic.rx.abort.rx_restart_nums += ieee802154_ll_get_rx_restart_cnt(); + ieee802154_ll_clear_debug_cnt(IEEE802154_RX_RESTART_CNT_CLEAR); + s_ieee802154_txrx_statistic.rx.abort.rx_coex_break_nums += ieee802154_ll_get_rx_abort_coex_cnt(); + ieee802154_ll_clear_debug_cnt(IEEE802154_RX_ABORT_COEX_CNT_CLEAR); + s_ieee802154_txrx_statistic.rx.abort.no_rss_nums += ieee802154_ll_get_no_rss_detect_cnt(); + ieee802154_ll_clear_debug_cnt(IEEE802154_NO_RSS_DETECT_CNT_CLEAR); + s_ieee802154_txrx_statistic.rx.abort.filter_fail_nums += ieee802154_ll_get_rx_fliter_fail_cnt(); + ieee802154_ll_clear_debug_cnt(IEEE802154_RX_FILTER_FAIL_CNT_CLEAR); + s_ieee802154_txrx_statistic.rx.abort.ed_abort_nums += ieee802154_ll_get_ed_abort_cnt(); + ieee802154_ll_clear_debug_cnt(IEEE802154_ED_ABORT_CNT_CLEAR); + s_ieee802154_txrx_statistic.rx.abort.crc_error_nums += ieee802154_ll_get_crc_error_cnt(); + ieee802154_ll_clear_debug_cnt(IEEE802154_CRC_ERROR_CNT_CLEAR); + s_ieee802154_txrx_statistic.rx.abort.sfd_timeout_nums += ieee802154_ll_get_sfd_timeout_cnt(); + ieee802154_ll_clear_debug_cnt(IEEE802154_SFD_TIMEOUT_CNT_CLEAR); +} + +void ieee802154_tx_nums_update(void) +{ + s_ieee802154_txrx_statistic.tx.nums++; +} + +void ieee802154_tx_deferred_nums_update(void) +{ + s_ieee802154_txrx_statistic.tx.deferred_nums++; +} + +void ieee802154_tx_break_coex_nums_update(void) +{ + s_ieee802154_txrx_statistic.tx.abort.tx_coex_break_nums++; +} + +void ieee802154_txrx_statistic_print(void) +{ + uint64_t tx_success_nums = s_ieee802154_txrx_statistic.tx.done_nums - s_ieee802154_txrx_statistic.tx.abort.rx_ack_coex_break_nums - s_ieee802154_txrx_statistic.tx.abort.rx_ack_timeout_nums; + uint64_t tx_abort_nums = s_ieee802154_txrx_statistic.tx.abort.rx_ack_coex_break_nums + s_ieee802154_txrx_statistic.tx.abort.rx_ack_timeout_nums + + s_ieee802154_txrx_statistic.tx.abort.tx_coex_break_nums + s_ieee802154_txrx_statistic.tx.abort.tx_security_error_nums + + s_ieee802154_txrx_statistic.tx.abort.cca_failed_nums + s_ieee802154_txrx_statistic.tx.abort.cca_busy_nums; + + uint64_t tx_nums = s_ieee802154_txrx_statistic.tx.nums; + uint64_t tx_direct_num = tx_nums - s_ieee802154_txrx_statistic.tx.deferred_nums; + + float tx_success_ratio = (tx_nums > 0 ? ((float)tx_success_nums / tx_nums) : 0); + float tx_done_ratio = (tx_nums > 0 ? ((float)s_ieee802154_txrx_statistic.tx.done_nums / tx_nums) : 0); + float tx_abort_ratio = (tx_nums > 0 ? ((float)tx_abort_nums / tx_nums) : 0); + + float tx_direct_num_ratio = (tx_nums > 0 ? ((float)tx_direct_num / tx_nums) : 0); + float tx_deferred_num_ratio = (tx_nums > 0 ? ((float)s_ieee802154_txrx_statistic.tx.deferred_nums / tx_nums) : 0); + + float tx_abort_rx_ack_coex_break_ratio = (tx_nums > 0 ? ((float)s_ieee802154_txrx_statistic.tx.abort.rx_ack_coex_break_nums / tx_nums) : 0); + float tx_abort_rx_ack_timeout_ratio = (tx_nums > 0 ? ((float)s_ieee802154_txrx_statistic.tx.abort.rx_ack_timeout_nums / tx_nums) : 0); + float tx_abort_tx_coex_break_ratio = (tx_nums > 0 ? ((float)s_ieee802154_txrx_statistic.tx.abort.tx_coex_break_nums / tx_nums) : 0); + float tx_abort_tx_security_error_ratio = (tx_nums > 0 ? ((float)s_ieee802154_txrx_statistic.tx.abort.tx_security_error_nums / tx_nums) : 0); + float tx_abort_cca_failed_ratio = (tx_nums > 0 ? ((float)s_ieee802154_txrx_statistic.tx.abort.cca_failed_nums / tx_nums) : 0); + float tx_abort_cca_busy_ratio = (tx_nums > 0 ? ((float)s_ieee802154_txrx_statistic.tx.abort.cca_busy_nums / tx_nums) : 0); + + uint64_t rx_abort_nums = s_ieee802154_txrx_statistic.rx.abort.tx_ack_coex_break_nums + s_ieee802154_txrx_statistic.rx.abort.sfd_timeout_nums + + s_ieee802154_txrx_statistic.rx.abort.crc_error_nums + s_ieee802154_txrx_statistic.rx.abort.filter_fail_nums + + s_ieee802154_txrx_statistic.rx.abort.no_rss_nums + s_ieee802154_txrx_statistic.rx.abort.rx_coex_break_nums + + s_ieee802154_txrx_statistic.rx.abort.rx_restart_nums + s_ieee802154_txrx_statistic.rx.abort.ed_abort_nums; + uint64_t rx_success_nums = s_ieee802154_txrx_statistic.rx.done_nums - s_ieee802154_txrx_statistic.rx.abort.tx_ack_coex_break_nums; + + + ESP_LOGW(IEEE802154_TAG, "+--------------------+-----------------------------------+--------------------------------------------------+"); + ESP_LOGW(IEEE802154_TAG, "|%-20s|%-10s%-15llu%9.2f%%|%-25s%-15llu%9.2f%%|", "", "Done:", s_ieee802154_txrx_statistic.tx.done_nums, tx_done_ratio*100, "Success:", tx_success_nums, tx_success_ratio*100); + ESP_LOGW(IEEE802154_TAG, "+ + +--------------------------------------------------+"); + ESP_LOGW(IEEE802154_TAG, "|%-20s|%-35s|%-25s%-15llu%9.2f%%|", "", "", "tx_direct_num:", tx_direct_num, tx_direct_num_ratio*100); + ESP_LOGW(IEEE802154_TAG, "+ + +--------------------------------------------------+"); + ESP_LOGW(IEEE802154_TAG, "|%-20s|%-35s|%-25s%-15llu%9.2f%%|", "", "", "tx_deferred_num:", s_ieee802154_txrx_statistic.tx.deferred_nums, tx_deferred_num_ratio*100); + ESP_LOGW(IEEE802154_TAG, "+ +-----------------------------------+--------------------------------------------------+"); + ESP_LOGW(IEEE802154_TAG, "|%-20s|%-35s|%-25s%-15llu%9.2f%%|", "", "", "rx_ack_coex_break:", s_ieee802154_txrx_statistic.tx.abort.rx_ack_coex_break_nums, tx_abort_rx_ack_coex_break_ratio*100); + ESP_LOGW(IEEE802154_TAG, "+ + +--------------------------------------------------+"); + ESP_LOGW(IEEE802154_TAG, "|%-20s|%-35s|%-25s%-15llu%9.2f%%|", "", "", "rx_ack_timeout:", s_ieee802154_txrx_statistic.tx.abort.rx_ack_timeout_nums, tx_abort_rx_ack_timeout_ratio*100); + ESP_LOGW(IEEE802154_TAG, "+ + +--------------------------------------------------+"); + ESP_LOGW(IEEE802154_TAG, "|%-5s%-15llu|%-10s%-15llu%9.2f%%|%-25s%-15llu%9.2f%%|", "TX:", s_ieee802154_txrx_statistic.tx.nums, "Abort", tx_abort_nums, tx_abort_ratio*100, "tx_coex_break:", s_ieee802154_txrx_statistic.tx.abort.tx_coex_break_nums, tx_abort_tx_coex_break_ratio*100); + ESP_LOGW(IEEE802154_TAG, "+ + +--------------------------------------------------+"); + ESP_LOGW(IEEE802154_TAG, "|%-20s|%-35s|%-25s%-15llu%9.2f%%|", "", "", "tx_security_error:", s_ieee802154_txrx_statistic.tx.abort.tx_security_error_nums, tx_abort_tx_security_error_ratio*100); + ESP_LOGW(IEEE802154_TAG, "+ + +--------------------------------------------------+"); + ESP_LOGW(IEEE802154_TAG, "|%-20s|%-35s|%-25s%-15llu%9.2f%%|", "", "", "cca_failed:", s_ieee802154_txrx_statistic.tx.abort.cca_failed_nums, tx_abort_cca_failed_ratio*100); + ESP_LOGW(IEEE802154_TAG, "+ + +--------------------------------------------------+"); + ESP_LOGW(IEEE802154_TAG, "|%-20s|%-35s|%-25s%-15llu%9.2f%%|", "", "", "cca_busy:", s_ieee802154_txrx_statistic.tx.abort.cca_busy_nums, tx_abort_cca_busy_ratio*100); + ESP_LOGW(IEEE802154_TAG, "+--------------------+-----------------------------------+--------------------------------------------------+"); + ESP_LOGW(IEEE802154_TAG, "|%-20s|%-10s%-25llu|%-25s%-25llu|", "", "Done:", s_ieee802154_txrx_statistic.rx.done_nums, "Success:", rx_success_nums); + ESP_LOGW(IEEE802154_TAG, "+ +-----------------------------------+--------------------------------------------------+"); + ESP_LOGW(IEEE802154_TAG, "|%-20s|%-35s|%-25s%-25llu|", "", "", "tx_ack_coex_break:", s_ieee802154_txrx_statistic.rx.abort.tx_ack_coex_break_nums); + ESP_LOGW(IEEE802154_TAG, "+ + +--------------------------------------------------+"); + ESP_LOGW(IEEE802154_TAG, "|%-20s|%-35s|%-25s%-25llu|", "", "", "sfd_timeout:", s_ieee802154_txrx_statistic.rx.abort.sfd_timeout_nums); + ESP_LOGW(IEEE802154_TAG, "+ + +--------------------------------------------------+"); + ESP_LOGW(IEEE802154_TAG, "|%-20s|%-35s|%-25s%-25llu|", "", "", "crc_error:", s_ieee802154_txrx_statistic.rx.abort.crc_error_nums); + ESP_LOGW(IEEE802154_TAG, "+ + +--------------------------------------------------+"); + ESP_LOGW(IEEE802154_TAG, "|%-20s|%-10s%-25llu|%-25s%-25llu|", "RX", "Abort", rx_abort_nums, "filter_fail:", s_ieee802154_txrx_statistic.rx.abort.filter_fail_nums); + ESP_LOGW(IEEE802154_TAG, "+ + +--------------------------------------------------+"); + ESP_LOGW(IEEE802154_TAG, "|%-20s|%-35s|%-25s%-25llu|", "", "", "no_rss:", s_ieee802154_txrx_statistic.rx.abort.no_rss_nums); + ESP_LOGW(IEEE802154_TAG, "+ + +--------------------------------------------------+"); + ESP_LOGW(IEEE802154_TAG, "|%-20s|%-35s|%-25s%-25llu|", "", "", "rx_coex_break:", s_ieee802154_txrx_statistic.rx.abort.rx_coex_break_nums); + ESP_LOGW(IEEE802154_TAG, "+ + +--------------------------------------------------+"); + ESP_LOGW(IEEE802154_TAG, "|%-20s|%-35s|%-25s%-25llu|", "", "", "rx_restart:", s_ieee802154_txrx_statistic.rx.abort.rx_restart_nums); + ESP_LOGW(IEEE802154_TAG, "+ + +--------------------------------------------------+"); + ESP_LOGW(IEEE802154_TAG, "|%-20s|%-35s|%-25s%-25llu|", "", "", "ed_abort:", s_ieee802154_txrx_statistic.rx.abort.ed_abort_nums); + ESP_LOGW(IEEE802154_TAG, "+--------------------+-----------------------------------+--------------------------------------------------+"); +} + +#endif // CONFIG_IEEE802154_TXRX_STATISTIC + +#endif // CONFIG_IEEE802154_DEBUG diff --git a/components/ieee802154/driver/esp_ieee802154_dev.c b/components/ieee802154/driver/esp_ieee802154_dev.c new file mode 100644 index 0000000000..27b0c29ea0 --- /dev/null +++ b/components/ieee802154/driver/esp_ieee802154_dev.c @@ -0,0 +1,1094 @@ +/* + * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include "sdkconfig.h" +#include "soc/periph_defs.h" +#include "soc/soc.h" +#include "soc/ieee802154_periph.h" +#include "esp_private/esp_modem_clock.h" +#include "esp_check.h" +#include "esp_coex_i154.h" +#include "esp_err.h" +#include "esp_log.h" +#include "esp_timer.h" +#include "esp_ieee802154_ack.h" +#include "esp_ieee802154_dev.h" +#include "esp_ieee802154_frame.h" +#include "esp_ieee802154_pib.h" +#include "esp_ieee802154_sec.h" +#include "esp_ieee802154_util.h" +#include "esp_ieee802154_timer.h" +#include "hal/ieee802154_ll.h" +#include "esp_attr.h" +#include "esp_phy_init.h" + +#if CONFIG_PM_ENABLE +#include "esp_pm.h" +#include "esp_private/esp_clk.h" +#include "esp_private/sleep_retention.h" +#include "esp_private/sleep_modem.h" +#if SOC_PM_RETENTION_HAS_CLOCK_BUG +#define IEEE802154_LINK_OWNER ENTRY(3) +#else +#define IEEE802154_LINK_OWNER ENTRY(0) | ENTRY(2) +#endif // SOC_PM_RETENTION_HAS_CLOCK_BUG +#endif // CONFIG_PM_ENABLE + +#include +#include + +static bool s_rf_closed = true; +#define CCA_DETECTION_TIME 8 + +extern void bt_bb_set_zb_tx_on_delay(uint16_t time); + +IEEE802154_STATIC volatile ieee802154_state_t s_ieee802154_state; +static uint8_t *s_tx_frame = NULL; +#define IEEE802154_RX_FRAME_SIZE (127 + 1 + 1) // +1: len, +1: for dma test + +// +1: for the stub buffer when the valid buffers are full. +// +// |--------------------VB[0]--------------------| +// |--------------------VB[1]--------------------| +// |--------------------VB[2]--------------------| +// |--------------------VB[3]--------------------| +// |--------------------.....--------------------| +// |-----VB[CONFIG_IEEE802154_RX_BUFFER_SIZE]----| +// |---------------------STUB--------------------| +// +// VB: Valid buffer, used for storing the frame received by HW. +// STUB : Stub buffer, used when all valid buffers are under processing, the received frame will be dropped. +static uint8_t s_rx_frame[CONFIG_IEEE802154_RX_BUFFER_SIZE + 1][IEEE802154_RX_FRAME_SIZE]; +static esp_ieee802154_frame_info_t s_rx_frame_info[CONFIG_IEEE802154_RX_BUFFER_SIZE + 1]; + +static bool s_needs_next_operation = false; + +static uint8_t s_rx_index = 0; +static uint8_t s_enh_ack_frame[128]; +static uint8_t s_recent_rx_frame_info_index; +static struct k_spinlock s_ieee802154_spinlock; +static k_spinlock_key_t s_ieee802154_key; + +static esp_err_t ieee802154_sleep_init(void); +static esp_err_t ieee802154_sleep_deinit(void); +#define NEEDS_NEXT_OPT(a) do {s_needs_next_operation = a;} while(0) +static esp_err_t ieee802154_transmit_internal(const uint8_t *frame, bool cca); + +#if !CONFIG_IEEE802154_TEST +typedef struct { + const uint8_t *frame; + bool cca; +} pending_tx_t; +static pending_tx_t s_pending_tx = { 0 }; +#endif + +static void ieee802154_receive_done(uint8_t *data, esp_ieee802154_frame_info_t *frame_info) +{ + // If the RX done packet is written in the stub buffer, drop it silently. + if (s_rx_index != CONFIG_IEEE802154_RX_BUFFER_SIZE) { + // Otherwise, post it to the upper layer. + // Ignore bit8 for the frame length, due to the max frame length is 127 based 802.15.4 spec. + data[0] = data[0] & 0x7f; + frame_info->process = true; + esp_ieee802154_receive_done(data, frame_info); + } +} + +static void ieee802154_transmit_done(const uint8_t *frame, const uint8_t *ack, esp_ieee802154_frame_info_t *ack_frame_info) +{ + if (ack && ack_frame_info) { + if (s_rx_index == CONFIG_IEEE802154_RX_BUFFER_SIZE) { + esp_ieee802154_transmit_failed(frame, ESP_IEEE802154_TX_ERR_NO_ACK); + } else { + ack_frame_info->process = true; + esp_ieee802154_transmit_done(frame, ack, ack_frame_info); + } + } else { + esp_ieee802154_transmit_done(frame, ack, ack_frame_info); + } +} + +esp_err_t ieee802154_receive_handle_done(const uint8_t *data) +{ + uint16_t size = data - &s_rx_frame[0][0]; + if ((size % IEEE802154_RX_FRAME_SIZE) != 0 + || (size / IEEE802154_RX_FRAME_SIZE) >= CONFIG_IEEE802154_RX_BUFFER_SIZE) { + return ESP_FAIL; + } + s_rx_frame_info[size / IEEE802154_RX_FRAME_SIZE].process = false; + return ESP_OK; +} + +static IRAM_ATTR void event_end_process(void) +{ + ieee802154_etm_channel_clear(IEEE802154_ETM_CHANNEL0); + ieee802154_etm_channel_clear(IEEE802154_ETM_CHANNEL1); + ieee802154_ll_set_transmit_security(false); + ieee802154_timer0_stop(); +} + +#if !CONFIG_IEEE802154_TEST +static IRAM_ATTR void receive_ack_timeout_timer_start(uint32_t duration) +{ + ieee802154_ll_enable_events(IEEE802154_EVENT_TIMER0_OVERFLOW); + ieee802154_timer0_set_threshold(duration); + ieee802154_timer0_start(); +} +#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]; + + 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; + + s_recent_rx_frame_info_index = s_rx_index; +} + +int8_t ieee802154_get_recent_rssi(void) +{ + return s_rx_frame_info[s_recent_rx_frame_info_index].rssi; +} + +uint8_t ieee802154_get_recent_lqi(void) +{ + return s_rx_frame_info[s_recent_rx_frame_info_index].lqi; +} + +IEEE802154_STATIC IEEE802154_NOINLINE void set_next_rx_buffer(void) +{ + uint8_t* next_rx_buffer = NULL; + uint8_t index = 0; + if (s_rx_index != CONFIG_IEEE802154_RX_BUFFER_SIZE && s_rx_frame_info[s_rx_index].process == false) { + // If buffer is not full, and current index is empty, set it to hardware. + next_rx_buffer = s_rx_frame[s_rx_index]; + } else { + // Otherwise, trave the buffer to find an empty one. + // Notice, the s_rx_index + 1 is more like an empty one, so check it first. + for (uint8_t i = 1; i <= CONFIG_IEEE802154_RX_BUFFER_SIZE; i++) { + index = (i + s_rx_index) % CONFIG_IEEE802154_RX_BUFFER_SIZE; + if (s_rx_frame_info[index].process == true) { + continue; + } else { + s_rx_index = index; + next_rx_buffer = s_rx_frame[s_rx_index]; + break; + } + } + } + // If all buffer is under processing by the upper layer, we set the stub buffer, and + // will not post the received frame to the upper layer. + if (!next_rx_buffer) { + s_rx_index = CONFIG_IEEE802154_RX_BUFFER_SIZE; + next_rx_buffer = s_rx_frame[CONFIG_IEEE802154_RX_BUFFER_SIZE]; +#if CONFIG_IEEE802154_DEBUG + ESP_EARLY_LOGW(IEEE802154_TAG, "Rx buffer full."); +#endif + } + ieee802154_ll_set_rx_addr(next_rx_buffer); +} + +IEEE802154_NOINLINE static bool stop_rx(void) +{ + ieee802154_ll_events events; + + ieee802154_set_cmd(IEEE802154_CMD_STOP); + + events = ieee802154_ll_get_events(); + if (events & IEEE802154_EVENT_RX_DONE) { + ieee802154_receive_done((uint8_t *)s_rx_frame[s_rx_index], &s_rx_frame_info[s_rx_index]); + } + + ieee802154_ll_clear_events(IEEE802154_EVENT_RX_DONE | IEEE802154_EVENT_RX_ABORT | IEEE802154_EVENT_RX_SFD_DONE); + + return true; +} + +IEEE802154_NOINLINE static bool stop_tx_ack(void) +{ + ieee802154_set_cmd(IEEE802154_CMD_STOP); + + ieee802154_receive_done((uint8_t *)s_rx_frame[s_rx_index], &s_rx_frame_info[s_rx_index]); + + ieee802154_ll_clear_events(IEEE802154_EVENT_ACK_TX_DONE | IEEE802154_EVENT_RX_ABORT | IEEE802154_EVENT_TX_SFD_DONE); // ZB-81: clear TX_SFD_DONE event + + return true; +} + +IEEE802154_NOINLINE static bool stop_tx(void) +{ + ieee802154_ll_events events; + + ieee802154_set_cmd(IEEE802154_CMD_STOP); + + events = ieee802154_ll_get_events(); + + if (s_ieee802154_state == IEEE802154_STATE_TX_ENH_ACK) { + // if current operation is sending 2015 Enh-ack, SW should create the receive-done event. + ieee802154_receive_done((uint8_t *)s_rx_frame[s_rx_index], &s_rx_frame_info[s_rx_index]); + ieee802154_ll_clear_events(IEEE802154_EVENT_ACK_TX_DONE); + } else if ((events & IEEE802154_EVENT_TX_DONE) && (!ieee802154_frame_is_ack_required(s_tx_frame) || !ieee802154_ll_get_rx_auto_ack())) { + // if the tx is already done, and the frame is not ack request OR auto ack rx is disabled. + ieee802154_transmit_done(s_tx_frame, NULL, NULL); + } else { + esp_ieee802154_transmit_failed(s_tx_frame, ESP_IEEE802154_TX_ERR_ABORT); + } + + ieee802154_ll_clear_events(IEEE802154_EVENT_TX_DONE | IEEE802154_EVENT_TX_ABORT | IEEE802154_EVENT_TX_SFD_DONE); + + return true; +} + +IEEE802154_NOINLINE static bool stop_cca(void) +{ + ieee802154_set_cmd(IEEE802154_CMD_STOP); + ieee802154_ll_clear_events(IEEE802154_EVENT_ED_DONE | IEEE802154_EVENT_RX_ABORT); + return true; +} + +IEEE802154_NOINLINE static bool stop_tx_cca(void) +{ + stop_tx(); // in case the transmission already started + ieee802154_ll_clear_events(IEEE802154_EVENT_TX_ABORT); + return true; +} + +IEEE802154_NOINLINE static bool stop_rx_ack(void) +{ + ieee802154_ll_events events; + + ieee802154_set_cmd(IEEE802154_CMD_STOP); + + events = ieee802154_ll_get_events(); + + ieee802154_timer0_stop(); + ieee802154_ll_disable_events(IEEE802154_EVENT_TIMER0_OVERFLOW); + + if (events & IEEE802154_EVENT_ACK_RX_DONE) { + ieee802154_transmit_done(s_tx_frame, (uint8_t *)&s_rx_frame[s_rx_index], &s_rx_frame_info[s_rx_index]); + } else { + esp_ieee802154_transmit_failed(s_tx_frame, ESP_IEEE802154_TX_ERR_NO_ACK); + } + + ieee802154_ll_clear_events(IEEE802154_EVENT_ACK_RX_DONE | IEEE802154_EVENT_RX_SFD_DONE | IEEE802154_EVENT_TX_ABORT); + + return true; +} + +IEEE802154_NOINLINE static bool stop_ed(void) +{ + ieee802154_set_cmd(IEEE802154_CMD_STOP); + + ieee802154_ll_clear_events(IEEE802154_EVENT_ED_DONE | IEEE802154_EVENT_RX_ABORT); + + return true; +} + +IEEE802154_NOINLINE IEEE802154_STATIC bool stop_current_operation(void) +{ + event_end_process(); + switch (s_ieee802154_state) { + case IEEE802154_STATE_DISABLE: + break; + + case IEEE802154_STATE_IDLE: + ieee802154_ll_set_cmd(IEEE802154_CMD_STOP); + break; + + case IEEE802154_STATE_SLEEP: + // Do nothing + break; + + case IEEE802154_STATE_RX: + stop_rx(); + break; + + case IEEE802154_STATE_TX_ACK: + stop_tx_ack(); + break; + + case IEEE802154_STATE_TX_CCA: + stop_tx_cca(); + break; + case IEEE802154_STATE_CCA: + stop_cca(); + break; + + case IEEE802154_STATE_TX: + case IEEE802154_STATE_TX_ENH_ACK: + stop_tx(); + break; + + case IEEE802154_STATE_RX_ACK: + stop_rx_ack(); + break; + + case IEEE802154_STATE_ED: + stop_ed(); + break; + + default: + IEEE802154_ASSERT(false); + break; + } + + return true; +} + +FORCE_INLINE_ATTR void extcoex_tx_stage_start(void) +{ +#if CONFIG_ESP_COEX_EXTERNAL_COEXIST_ENABLE + esp_coex_ieee802154_extcoex_tx_stage(); +#endif +} + +FORCE_INLINE_ATTR void extcoex_rx_stage_start(void) +{ +#if CONFIG_ESP_COEX_EXTERNAL_COEXIST_ENABLE + esp_coex_ieee802154_extcoex_rx_stage(); +#endif +} + +static void enable_rx(void) +{ + extcoex_rx_stage_start(); + set_next_rx_buffer(); + IEEE802154_SET_TXRX_PTI(IEEE802154_SCENE_RX); + + ieee802154_set_cmd(IEEE802154_CMD_RX_START); + + ieee802154_set_state(IEEE802154_STATE_RX); +} + +static IRAM_ATTR void next_operation(void) +{ +#if !CONFIG_IEEE802154_TEST + if (s_pending_tx.frame) { + // Here the driver needs to recover the setting of rx aborts, see function `ieee802154_transmit`. + ieee802154_ll_enable_rx_abort_events(BIT(IEEE802154_RX_ABORT_BY_TX_ACK_TIMEOUT - 1) | BIT(IEEE802154_RX_ABORT_BY_TX_ACK_COEX_BREAK - 1)); + // Clear the RX abort event again for avoiding the risk if there are still some rx abort events created after last isr process. + ieee802154_ll_clear_events(IEEE802154_EVENT_RX_ABORT); + ieee802154_transmit_internal(s_pending_tx.frame, s_pending_tx.cca); + s_pending_tx.frame = NULL; + } else +#endif + { + if (ieee802154_pib_get_rx_when_idle()) { + enable_rx(); + } else { + ieee802154_set_state(IEEE802154_STATE_IDLE); +#if !CONFIG_IEEE802154_TEST + ieee802154_sleep(); +#endif + } + } +} + +static void isr_handle_timer0_done(void) +{ +#if !CONFIG_IEEE802154_TEST + if (s_ieee802154_state == IEEE802154_STATE_RX_ACK) { + esp_ieee802154_transmit_failed(s_tx_frame, ESP_IEEE802154_TX_ERR_NO_ACK); + NEEDS_NEXT_OPT(true); + } +#else + esp_ieee802154_timer0_done(); +#endif +} + +static void isr_handle_timer1_done(void) +{ + // timer 1 is now unused. +#if CONFIG_IEEE802154_TEST + esp_ieee802154_timer1_done(); +#endif +} + +static IRAM_ATTR void isr_handle_tx_done(void) +{ + event_end_process(); + if (s_ieee802154_state == IEEE802154_STATE_TEST_TX) { + ieee802154_transmit_done(s_tx_frame, NULL, NULL); + NEEDS_NEXT_OPT(true); + } else if (s_ieee802154_state == IEEE802154_STATE_TX || s_ieee802154_state == IEEE802154_STATE_TX_CCA) { + if (ieee802154_frame_is_ack_required(s_tx_frame) && ieee802154_ll_get_rx_auto_ack()) { + extcoex_rx_stage_start(); + ieee802154_set_state(IEEE802154_STATE_RX_ACK); +#if !CONFIG_IEEE802154_TEST + receive_ack_timeout_timer_start(200000); // 200ms for receive ack timeout +#endif + NEEDS_NEXT_OPT(false); + } else { + ieee802154_transmit_done(s_tx_frame, NULL, NULL); + NEEDS_NEXT_OPT(true); + } + } +} + +static IRAM_ATTR void isr_handle_rx_done(void) +{ + event_end_process(); + ieee802154_rx_frame_info_update(); + + if (s_ieee802154_state == IEEE802154_STATE_RX) { + 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_1 + && 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]); + 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]); + // For 2015 enh-ack, SW should generate an enh-ack then send it manually + if (esp_ieee802154_enh_ack_generator(s_rx_frame[s_rx_index], &s_rx_frame_info[s_rx_index], s_enh_ack_frame) == ESP_OK) { + extcoex_tx_stage_start(); +#if !CONFIG_IEEE802154_TEST + // Send the Enh-Ack frame if generator succeeds. + ieee802154_ll_set_tx_addr(s_enh_ack_frame); + s_tx_frame = s_enh_ack_frame; + ieee802154_sec_update(); + ieee802154_ll_enhack_generate_done_notify(); + ieee802154_set_state(IEEE802154_STATE_TX_ENH_ACK); +#endif + NEEDS_NEXT_OPT(false); + } else { + // Stop current process if generator returns errors. + ieee802154_set_cmd(IEEE802154_CMD_STOP); + ieee802154_receive_done((uint8_t *)s_rx_frame[s_rx_index], &s_rx_frame_info[s_rx_index]); + NEEDS_NEXT_OPT(true); + } + } else { + ieee802154_receive_done((uint8_t *)s_rx_frame[s_rx_index], &s_rx_frame_info[s_rx_index]); + NEEDS_NEXT_OPT(true); + } + } +} + +static IRAM_ATTR void isr_handle_ack_tx_done(void) +{ + extcoex_rx_stage_start(); + ieee802154_receive_done((uint8_t *)s_rx_frame[s_rx_index], &s_rx_frame_info[s_rx_index]); + NEEDS_NEXT_OPT(true); +} + +static IRAM_ATTR void isr_handle_ack_rx_done(void) +{ + ieee802154_timer0_stop(); + ieee802154_ll_disable_events(IEEE802154_EVENT_TIMER0_OVERFLOW); + ieee802154_rx_frame_info_update(); + ieee802154_transmit_done(s_tx_frame, (uint8_t *)&s_rx_frame[s_rx_index], &s_rx_frame_info[s_rx_index]); + NEEDS_NEXT_OPT(true); +} + +static IRAM_ATTR void isr_handle_rx_phase_rx_abort(ieee802154_ll_rx_abort_reason_t rx_abort_reason) +{ + event_end_process(); + uint32_t rx_status = ieee802154_ll_get_rx_status(); + switch (rx_abort_reason) { + case IEEE802154_RX_ABORT_BY_RX_STOP: + case IEEE802154_RX_ABORT_BY_TX_ACK_STOP: + case IEEE802154_RX_ABORT_BY_ED_STOP: + // do nothing + break; + case IEEE802154_RX_ABORT_BY_SFD_TIMEOUT: + case IEEE802154_RX_ABORT_BY_CRC_ERROR: + case IEEE802154_RX_ABORT_BY_INVALID_LEN: + case IEEE802154_RX_ABORT_BY_FILTER_FAIL: + case IEEE802154_RX_ABORT_BY_NO_RSS: + case IEEE802154_RX_ABORT_BY_UNEXPECTED_ACK: + case IEEE802154_RX_ABORT_BY_RX_RESTART: + case IEEE802154_RX_ABORT_BY_COEX_BREAK: + IEEE802154_ASSERT(s_ieee802154_state == IEEE802154_STATE_RX); +#if CONFIG_IEEE802154_TEST + esp_ieee802154_receive_failed(rx_status); +#endif + break; + case IEEE802154_RX_ABORT_BY_ED_ABORT: + case IEEE802154_RX_ABORT_BY_ED_COEX_REJECT: + IEEE802154_ASSERT(s_ieee802154_state == IEEE802154_STATE_ED || s_ieee802154_state == IEEE802154_STATE_CCA); + esp_ieee802154_ed_failed(rx_status); + break; + case IEEE802154_RX_ABORT_BY_TX_ACK_TIMEOUT: + case IEEE802154_RX_ABORT_BY_TX_ACK_COEX_BREAK: + case IEEE802154_RX_ABORT_BY_ENHACK_SECURITY_ERROR: + return; + default: + IEEE802154_ASSERT(false); + } + NEEDS_NEXT_OPT(true); +} + +static IRAM_ATTR void isr_handle_tx_ack_phase_rx_abort(ieee802154_ll_rx_abort_reason_t rx_abort_reason) +{ + event_end_process(); +#if CONFIG_IEEE802154_TEST + uint32_t rx_status = ieee802154_ll_get_rx_status(); +#endif + switch (rx_abort_reason) { + case IEEE802154_RX_ABORT_BY_RX_STOP: + case IEEE802154_RX_ABORT_BY_TX_ACK_STOP: + case IEEE802154_RX_ABORT_BY_ED_STOP: + case IEEE802154_RX_ABORT_BY_SFD_TIMEOUT: + case IEEE802154_RX_ABORT_BY_CRC_ERROR: + case IEEE802154_RX_ABORT_BY_INVALID_LEN: + case IEEE802154_RX_ABORT_BY_FILTER_FAIL: + case IEEE802154_RX_ABORT_BY_NO_RSS: + case IEEE802154_RX_ABORT_BY_UNEXPECTED_ACK: + case IEEE802154_RX_ABORT_BY_RX_RESTART: + case IEEE802154_RX_ABORT_BY_COEX_BREAK: + case IEEE802154_RX_ABORT_BY_ED_ABORT: + case IEEE802154_RX_ABORT_BY_ED_COEX_REJECT: + return; + case IEEE802154_RX_ABORT_BY_TX_ACK_TIMEOUT: + case IEEE802154_RX_ABORT_BY_TX_ACK_COEX_BREAK: + IEEE802154_ASSERT(s_ieee802154_state == IEEE802154_STATE_TX_ACK || s_ieee802154_state == IEEE802154_STATE_TX_ENH_ACK); +#if !CONFIG_IEEE802154_TEST + ieee802154_receive_done((uint8_t *)s_rx_frame[s_rx_index], &s_rx_frame_info[s_rx_index]); +#else + esp_ieee802154_receive_failed(rx_status); +#endif + break; + case IEEE802154_RX_ABORT_BY_ENHACK_SECURITY_ERROR: + IEEE802154_ASSERT(s_ieee802154_state == IEEE802154_STATE_TX_ENH_ACK); +#if !CONFIG_IEEE802154_TEST + ieee802154_receive_done((uint8_t *)s_rx_frame[s_rx_index], &s_rx_frame_info[s_rx_index]); +#else + esp_ieee802154_receive_failed(rx_status); +#endif + break; + default: + IEEE802154_ASSERT(false); + } + NEEDS_NEXT_OPT(true); +} + +static IRAM_ATTR void isr_handle_tx_abort(ieee802154_ll_tx_abort_reason_t tx_abort_reason) +{ + event_end_process(); + switch (tx_abort_reason) { + case IEEE802154_TX_ABORT_BY_RX_ACK_STOP: + case IEEE802154_TX_ABORT_BY_TX_STOP: + // do nothing + break; + case IEEE802154_TX_ABORT_BY_RX_ACK_SFD_TIMEOUT: + case IEEE802154_TX_ABORT_BY_RX_ACK_CRC_ERROR: + case IEEE802154_TX_ABORT_BY_RX_ACK_INVALID_LEN: + case IEEE802154_TX_ABORT_BY_RX_ACK_FILTER_FAIL: + case IEEE802154_TX_ABORT_BY_RX_ACK_NO_RSS: + case IEEE802154_TX_ABORT_BY_RX_ACK_COEX_BREAK: + case IEEE802154_TX_ABORT_BY_RX_ACK_TYPE_NOT_ACK: + case IEEE802154_TX_ABORT_BY_RX_ACK_RESTART: + IEEE802154_ASSERT(s_ieee802154_state == IEEE802154_STATE_RX_ACK); + esp_ieee802154_transmit_failed(s_tx_frame, ESP_IEEE802154_TX_ERR_INVALID_ACK); + NEEDS_NEXT_OPT(false); + break; + // The above events are only used in test mode. + case IEEE802154_TX_ABORT_BY_RX_ACK_TIMEOUT: + IEEE802154_ASSERT(s_ieee802154_state == IEEE802154_STATE_RX_ACK); + ieee802154_ll_disable_events(IEEE802154_EVENT_TIMER0_OVERFLOW); + esp_ieee802154_transmit_failed(s_tx_frame, ESP_IEEE802154_TX_ERR_NO_ACK); + NEEDS_NEXT_OPT(true); + break; + case IEEE802154_TX_ABORT_BY_TX_COEX_BREAK: +#if CONFIG_ESP_COEX_SW_COEXIST_ENABLE || CONFIG_EXTERNAL_COEX_ENABLE + esp_coex_ieee802154_coex_break_notify(); +#endif + IEEE802154_ASSERT(s_ieee802154_state == IEEE802154_STATE_TX || s_ieee802154_state == IEEE802154_STATE_TX_CCA); + IEEE802154_TX_BREAK_COEX_NUMS_UPDATE(); + esp_ieee802154_transmit_failed(s_tx_frame, ESP_IEEE802154_TX_ERR_COEXIST); + NEEDS_NEXT_OPT(true); + break; + case IEEE802154_TX_ABORT_BY_TX_SECURITY_ERROR: + IEEE802154_ASSERT(s_ieee802154_state == IEEE802154_STATE_TX || s_ieee802154_state == IEEE802154_STATE_TX_CCA); + esp_ieee802154_transmit_failed(s_tx_frame, ESP_IEEE802154_TX_ERR_SECURITY); + NEEDS_NEXT_OPT(true); + break; + case IEEE802154_TX_ABORT_BY_CCA_FAILED: + IEEE802154_ASSERT(s_ieee802154_state == IEEE802154_STATE_TX_CCA); + esp_ieee802154_transmit_failed(s_tx_frame, ESP_IEEE802154_TX_ERR_ABORT); + NEEDS_NEXT_OPT(true); + break; + case IEEE802154_TX_ABORT_BY_CCA_BUSY: + IEEE802154_ASSERT(s_ieee802154_state == IEEE802154_STATE_TX_CCA); + esp_ieee802154_transmit_failed(s_tx_frame, ESP_IEEE802154_TX_ERR_CCA_BUSY); + NEEDS_NEXT_OPT(true); + break; + default: + IEEE802154_ASSERT(false); + break; + } +} + +static IRAM_ATTR void isr_handle_ed_done(void) +{ + if (s_ieee802154_state == IEEE802154_STATE_CCA) { + esp_ieee802154_cca_done(ieee802154_ll_is_cca_busy()); + } else if (s_ieee802154_state == IEEE802154_STATE_ED) { + esp_ieee802154_energy_detect_done(ieee802154_ll_get_ed_rss()); + } + + NEEDS_NEXT_OPT(true); +} + +IEEE802154_STATIC IRAM_ATTR void ieee802154_enter_critical(void) +{ + s_ieee802154_key = k_spin_lock(&s_ieee802154_spinlock); +} + +IEEE802154_STATIC IRAM_ATTR void ieee802154_exit_critical(void) +{ + k_spin_unlock(&s_ieee802154_spinlock, s_ieee802154_key); +} + +IEEE802154_NOINLINE static void ieee802154_isr(const void *arg) +{ + ieee802154_enter_critical(); + ieee802154_ll_events events = ieee802154_ll_get_events(); + ieee802154_ll_rx_abort_reason_t rx_abort_reason = ieee802154_ll_get_rx_abort_reason(); + ieee802154_ll_tx_abort_reason_t tx_abort_reason = ieee802154_ll_get_tx_abort_reason(); + + IEEE802154_PROBE(events); + + ieee802154_ll_clear_events(events); + + if (events & IEEE802154_EVENT_RX_ABORT) { + // First phase rx abort process, will clear RX_ABORT event in second. + isr_handle_rx_phase_rx_abort(rx_abort_reason); + } + + if (events & IEEE802154_EVENT_RX_SFD_DONE) { + // IEEE802154_STATE_TX && IEEE802154_STATE_TX_CCA && IEEE802154_STATE_TX_ENH_ACK for isr processing delay + IEEE802154_ASSERT(s_ieee802154_state == IEEE802154_STATE_RX || s_ieee802154_state == IEEE802154_STATE_RX_ACK || s_ieee802154_state == IEEE802154_STATE_TX || s_ieee802154_state == IEEE802154_STATE_TX_CCA || s_ieee802154_state == IEEE802154_STATE_TX_ENH_ACK); + + s_rx_frame_info[s_rx_index].timestamp = esp_timer_get_time(); + esp_ieee802154_receive_sfd_done(); + + events &= (uint16_t)(~IEEE802154_EVENT_RX_SFD_DONE); + } + + if (events & IEEE802154_EVENT_TX_SFD_DONE) { + // ZB-81: IEEE802154_STATE_TX_ACK is also a possible state + IEEE802154_ASSERT(s_ieee802154_state == IEEE802154_STATE_TX || s_ieee802154_state == IEEE802154_STATE_TX_CCA || s_ieee802154_state == IEEE802154_STATE_TEST_TX || s_ieee802154_state == IEEE802154_STATE_TX_ENH_ACK || s_ieee802154_state == IEEE802154_STATE_TX_ACK); + + esp_ieee802154_transmit_sfd_done(s_tx_frame); + + events &= (uint16_t)(~IEEE802154_EVENT_TX_SFD_DONE); + } + + if (events & IEEE802154_EVENT_TX_DONE) { + IEEE802154_ASSERT(s_ieee802154_state == IEEE802154_STATE_TX || s_ieee802154_state == IEEE802154_STATE_TX_CCA || s_ieee802154_state == IEEE802154_STATE_TEST_TX); + + isr_handle_tx_done(); + + events &= (uint16_t)(~IEEE802154_EVENT_TX_DONE); + } + + if (events & IEEE802154_EVENT_RX_DONE) { + IEEE802154_ASSERT(s_ieee802154_state == IEEE802154_STATE_RX); + + isr_handle_rx_done(); + + events &= (uint16_t)(~IEEE802154_EVENT_RX_DONE); + } + + if (events & IEEE802154_EVENT_ACK_TX_DONE) { + // IEEE802154_STATE_RX for isr processing delay + IEEE802154_ASSERT(s_ieee802154_state == IEEE802154_STATE_TX_ACK || s_ieee802154_state == IEEE802154_STATE_RX || s_ieee802154_state == IEEE802154_STATE_TX_ENH_ACK); + + isr_handle_ack_tx_done(); + + events &= (uint16_t)(~IEEE802154_EVENT_ACK_TX_DONE); + } + + if (events & IEEE802154_EVENT_ACK_RX_DONE) { + // IEEE802154_STATE_TX && IEEE802154_STATE_TX_CCA && IEEE802154_STATE_TX_ENH_ACK for isr processing delay + IEEE802154_ASSERT(s_ieee802154_state == IEEE802154_STATE_RX_ACK || s_ieee802154_state == IEEE802154_STATE_TX || s_ieee802154_state == IEEE802154_STATE_TX_CCA || s_ieee802154_state == IEEE802154_STATE_TX_ENH_ACK); + + isr_handle_ack_rx_done(); + + events &= (uint16_t)(~IEEE802154_EVENT_ACK_RX_DONE); + } + + if (events & IEEE802154_EVENT_RX_ABORT) { + // Second phase rx abort process, clears RX_ABORT event. + isr_handle_tx_ack_phase_rx_abort(rx_abort_reason); + events &= (uint16_t)(~IEEE802154_EVENT_RX_ABORT); + } + + if (events & IEEE802154_EVENT_TX_ABORT) { + isr_handle_tx_abort(tx_abort_reason); + + events &= (uint16_t)(~IEEE802154_EVENT_TX_ABORT); + } + + if (events & IEEE802154_EVENT_ED_DONE) { + IEEE802154_ASSERT(s_ieee802154_state == IEEE802154_STATE_ED || s_ieee802154_state == IEEE802154_STATE_CCA); + + isr_handle_ed_done(); + + events &= (uint16_t)(~IEEE802154_EVENT_ED_DONE); + } + + if (events & IEEE802154_EVENT_TIMER0_OVERFLOW) { +#if !CONFIG_IEEE802154_TEST + IEEE802154_ASSERT(s_ieee802154_state == IEEE802154_STATE_RX_ACK); +#else + extern bool ieee802154_timer0_test; + IEEE802154_ASSERT(ieee802154_timer0_test || s_ieee802154_state == IEEE802154_STATE_RX_ACK); +#endif + isr_handle_timer0_done(); + + events &= (uint16_t)(~IEEE802154_EVENT_TIMER0_OVERFLOW); + } + + if (events & IEEE802154_EVENT_TIMER1_OVERFLOW) { + isr_handle_timer1_done(); + + events &= (uint16_t)(~IEEE802154_EVENT_TIMER1_OVERFLOW); + } + if (s_needs_next_operation) { + next_operation(); + s_needs_next_operation = false; + } + + // all events should be handled + IEEE802154_ASSERT(events == 0); + ieee802154_exit_critical(); +} + +void ieee802154_enable(void) +{ + modem_clock_module_enable(ieee802154_periph.module); + s_ieee802154_state = IEEE802154_STATE_IDLE; +} + +void ieee802154_disable(void) +{ + modem_clock_module_disable(ieee802154_periph.module); + ieee802154_set_state(IEEE802154_STATE_DISABLE); +} + +esp_err_t ieee802154_mac_init(void) +{ + esp_err_t ret = ESP_OK; + modem_clock_module_mac_reset(PERIPH_IEEE802154_MODULE); // reset ieee802154 MAC + ieee802154_pib_init(); + IEEE802154_TXRX_STATISTIC_CLEAR(); + + ieee802154_ll_enable_events(IEEE802154_EVENT_MASK); +#if !CONFIG_IEEE802154_TEST + ieee802154_ll_disable_events((IEEE802154_EVENT_TIMER0_OVERFLOW) | (IEEE802154_EVENT_TIMER1_OVERFLOW)); +#endif + ieee802154_ll_enable_tx_abort_events(BIT(IEEE802154_TX_ABORT_BY_RX_ACK_TIMEOUT - 1) | BIT(IEEE802154_TX_ABORT_BY_TX_COEX_BREAK - 1) | BIT(IEEE802154_TX_ABORT_BY_TX_SECURITY_ERROR - 1) | BIT(IEEE802154_TX_ABORT_BY_CCA_FAILED - 1) | BIT(IEEE802154_TX_ABORT_BY_CCA_BUSY - 1)); + ieee802154_ll_enable_rx_abort_events(BIT(IEEE802154_RX_ABORT_BY_TX_ACK_TIMEOUT - 1) | BIT(IEEE802154_RX_ABORT_BY_TX_ACK_COEX_BREAK - 1)); + + ieee802154_ll_set_ed_sample_mode(IEEE802154_ED_SAMPLE_AVG); +#if !CONFIG_IEEE802154_TEST && (CONFIG_ESP_COEX_SW_COEXIST_ENABLE || CONFIG_EXTERNAL_COEX_ENABLE) + esp_coex_ieee802154_ack_pti_set(IEEE802154_MIDDLE); + IEEE802154_SET_TXRX_PTI(IEEE802154_SCENE_IDLE); +#else + ieee802154_ll_disable_coex(); +#endif + +#if CONFIG_IDF_ENV_FPGA + bt_bb_set_zb_tx_on_delay(80); +#else + bt_bb_set_zb_tx_on_delay(50); + REG_WRITE(IEEE802154_RXON_DELAY_REG, 50); +#endif + + memset(s_rx_frame, 0, sizeof(s_rx_frame)); + + ieee802154_set_state(IEEE802154_STATE_IDLE); + + // TODO: Add flags for IEEE802154 ISR allocating. TZ-102 + ret = esp_intr_alloc(ieee802154_periph.irq_id, 0, ieee802154_isr, NULL, NULL); + ESP_RETURN_ON_FALSE(ret == ESP_OK, ESP_FAIL, IEEE802154_TAG, "IEEE802154 MAC init failed"); + + ESP_RETURN_ON_FALSE(ieee802154_sleep_init() == ESP_OK, ESP_FAIL, IEEE802154_TAG, "IEEE802154 MAC sleep init failed"); + + return ret; +} + +esp_err_t ieee802154_mac_deinit(void) +{ + esp_err_t ret = esp_intr_disable(ieee802154_periph.irq_id); + ESP_RETURN_ON_FALSE(ret == ESP_OK, ESP_FAIL, IEEE802154_TAG, "IEEE802154 MAC ISR deinit failed"); + ESP_RETURN_ON_FALSE(ieee802154_sleep_deinit() == ESP_OK, ESP_FAIL, IEEE802154_TAG, "IEEE802154 MAC sleep deinit failed"); + return ret; +} + +IEEE802154_STATIC void start_ed(uint32_t duration) +{ + ieee802154_ll_enable_events(IEEE802154_EVENT_ED_DONE); + ieee802154_ll_set_ed_duration(duration); + ieee802154_set_cmd(IEEE802154_CMD_ED_START); +} + +IEEE802154_STATIC void tx_init(const uint8_t *frame) +{ + IEEE802154_TX_NUMS_UPDATE(); + s_tx_frame = (uint8_t *)frame; + stop_current_operation(); + ieee802154_pib_update(); + ieee802154_sec_update(); + + ieee802154_ll_set_tx_addr(s_tx_frame); + + if (ieee802154_frame_is_ack_required(frame)) { + // set rx pointer for ack frame + set_next_rx_buffer(); + } + extcoex_tx_stage_start(); +} + +static inline esp_err_t ieee802154_transmit_internal(const uint8_t *frame, bool cca) +{ + IEEE802154_RF_ENABLE(); + ieee802154_enter_critical(); + tx_init(frame); + + IEEE802154_SET_TXRX_PTI(IEEE802154_SCENE_TX); + + if (cca) { + ieee802154_set_cmd(IEEE802154_CMD_CCA_TX_START); + ieee802154_set_state(IEEE802154_STATE_TX_CCA); + } else { + ieee802154_set_cmd(IEEE802154_CMD_TX_START); + ieee802154_set_state(IEEE802154_STATE_TX); + } + + ieee802154_exit_critical(); + return ESP_OK; +} + +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()) + || s_ieee802154_state == IEEE802154_STATE_TX_ACK || s_ieee802154_state == IEEE802154_STATE_TX_ENH_ACK) { + // If the current radio is processing an RX frame or sending an ACK, do not shut down the ongoing process. + // Instead, defer the transmission of the pending TX frame. + // Once the current process is completed, the pending transmit frame will be initiated. + s_pending_tx.frame = frame; + s_pending_tx.cca = cca; + IEEE802154_TX_DEFERRED_NUMS_UPDATE(); + // Here we enable all rx interrupts due to the driver needs to know when the current RX has finished. + // Will recover the setting of rx abort in function `next_operation`. + ieee802154_ll_enable_rx_abort_events(IEEE802154_RX_ABORT_ALL); + ieee802154_exit_critical(); + return ESP_OK; + } + ieee802154_exit_critical(); +#endif + return ieee802154_transmit_internal(frame, cca); +} + +IEEE802154_NOINLINE static bool is_target_time_expired(uint32_t target, uint32_t now) +{ + return (((now - target) & (1 << 31)) == 0); +} + +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 current_time; + IEEE802154_RF_ENABLE(); + tx_init(frame); + IEEE802154_SET_TXRX_PTI(IEEE802154_SCENE_TX_AT); + if (cca) { + 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); + current_time = (uint32_t)esp_timer_get_time(); + ieee802154_timer0_set_threshold((is_target_time_expired(tx_target_time, current_time) ? 0 : (tx_target_time - current_time))); //uint: 1us + ieee802154_timer0_start(); + 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); + current_time = (uint32_t)esp_timer_get_time(); + ieee802154_timer0_set_threshold((is_target_time_expired(tx_target_time, current_time) ? 0 : (tx_target_time - current_time))); //uint: 1us + ieee802154_timer0_start(); + ieee802154_exit_critical(); + } + + return ESP_OK; +} + +IEEE802154_STATIC void rx_init(void) +{ + stop_current_operation(); + ieee802154_pib_update(); +} + +esp_err_t ieee802154_receive(void) +{ + if (((s_ieee802154_state == IEEE802154_STATE_RX) || (s_ieee802154_state == IEEE802154_STATE_TX_ACK)) && (!ieee802154_pib_is_pending())) { + // already in rx state, don't abort current rx operation + return ESP_OK; + } + IEEE802154_RF_ENABLE(); + + ieee802154_enter_critical(); + rx_init(); + enable_rx(); + ieee802154_exit_critical(); + return ESP_OK; +} + +esp_err_t ieee802154_receive_at(uint32_t time) +{ + uint32_t rx_target_time = time - IEEE802154_RX_RAMPUP_TIME_US; + uint32_t current_time; + IEEE802154_RF_ENABLE(); + ieee802154_enter_critical(); + rx_init(); + IEEE802154_SET_TXRX_PTI(IEEE802154_SCENE_RX_AT); + set_next_rx_buffer(); + ieee802154_set_state(IEEE802154_STATE_RX); + ieee802154_etm_set_event_task(IEEE802154_ETM_CHANNEL1, ETM_EVENT_TIMER0_OVERFLOW, ETM_TASK_RX_START); + current_time = (uint32_t)esp_timer_get_time(); + ieee802154_timer0_set_threshold((is_target_time_expired(rx_target_time, current_time) ? 0 : (rx_target_time - current_time))); //uint: 1us + ieee802154_timer0_start(); + ieee802154_exit_critical(); + return ESP_OK; +} + +#if CONFIG_PM_ENABLE +static esp_err_t ieee802154_sleep_retention_init(void *arg) +{ + esp_err_t err = ESP_OK; +#if SOC_PM_MODEM_RETENTION_BY_REGDMA && CONFIG_FREERTOS_USE_TICKLESS_IDLE + #define N_REGS_IEEE802154() (((IEEE802154_MAC_DATE_REG - IEEE802154_REG_BASE) / 4) + 1) + const static sleep_retention_entries_config_t ieee802154_mac_regs_retention[] = { + [0] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_MODEM_IEEE802154_LINK(0x00), IEEE802154_REG_BASE, IEEE802154_REG_BASE, N_REGS_IEEE802154(), 0, 0), .owner = IEEE802154_LINK_OWNER }, + }; + err = sleep_retention_entries_create(ieee802154_mac_regs_retention, ARRAY_SIZE(ieee802154_mac_regs_retention), REGDMA_LINK_PRI_IEEE802154, SLEEP_RETENTION_MODULE_802154_MAC); + ESP_RETURN_ON_ERROR(err, IEEE802154_TAG, "failed to allocate memory for ieee802154 mac retention"); + ESP_LOGD(IEEE802154_TAG, "ieee802154 mac sleep retention initialization"); +#endif + return err; +} +#endif // CONFIG_PM_ENABLE + +static esp_err_t ieee802154_sleep_init(void) +{ + esp_err_t err = ESP_OK; +#if CONFIG_PM_ENABLE + sleep_retention_module_init_param_t init_param = { .cbs = { .create = { .handle = ieee802154_sleep_retention_init, .arg = NULL } } }; + init_param.depends.bitmap[SLEEP_RETENTION_MODULE_BT_BB >> 5] |= BIT(SLEEP_RETENTION_MODULE_BT_BB % 32); + init_param.depends.bitmap[SLEEP_RETENTION_MODULE_CLOCK_MODEM >> 5] |= BIT(SLEEP_RETENTION_MODULE_CLOCK_MODEM % 32); + err = sleep_retention_module_init(SLEEP_RETENTION_MODULE_802154_MAC, &init_param); + if (err == ESP_OK) { + err = sleep_retention_module_allocate(SLEEP_RETENTION_MODULE_802154_MAC); + } + ESP_RETURN_ON_ERROR(err, IEEE802154_TAG, "failed to create sleep retention linked list for ieee802154 mac retention"); +#if SOC_PM_RETENTION_HAS_CLOCK_BUG && CONFIG_MAC_BB_PD + sleep_modem_register_mac_bb_module_prepare_callback(sleep_modem_mac_bb_power_down_prepare, + sleep_modem_mac_bb_power_up_prepare); +#endif // SOC_PM_RETENTION_HAS_CLOCK_BUG && CONFIG_MAC_BB_PD +#endif // CONFIG_PM_ENABLE + return err; +} + +static esp_err_t ieee802154_sleep_deinit(void) +{ + esp_err_t err = ESP_OK; +#if CONFIG_PM_ENABLE + err = sleep_retention_module_free(SLEEP_RETENTION_MODULE_802154_MAC); + if (err == ESP_OK) { + err = sleep_retention_module_deinit(SLEEP_RETENTION_MODULE_802154_MAC); + } +#if SOC_PM_RETENTION_HAS_CLOCK_BUG && CONFIG_MAC_BB_PD + sleep_modem_unregister_mac_bb_module_prepare_callback(sleep_modem_mac_bb_power_down_prepare, + sleep_modem_mac_bb_power_up_prepare); +#endif // SOC_PM_RETENTION_HAS_CLOCK_BUG && CONFIG_MAC_BB_PD +#endif // CONFIG_PM_ENABLE + return err; +} + +IRAM_ATTR void ieee802154_rf_disable(void) +{ + if (s_rf_closed == false) { + esp_phy_disable(PHY_MODEM_IEEE802154); + s_rf_closed = true; + } +} + +IRAM_ATTR void ieee802154_rf_enable(void) +{ + if (s_rf_closed) { + esp_phy_enable(PHY_MODEM_IEEE802154); + s_rf_closed = false; + } +} + +esp_err_t ieee802154_sleep(void) +{ + if (ieee802154_get_state() != IEEE802154_STATE_SLEEP) { + ieee802154_enter_critical(); + stop_current_operation(); + ieee802154_set_state(IEEE802154_STATE_SLEEP); + ieee802154_exit_critical(); + IEEE802154_RF_DISABLE(); + } + return ESP_OK; +} + +esp_err_t ieee802154_energy_detect(uint32_t duration) +{ + IEEE802154_RF_ENABLE(); + ieee802154_enter_critical(); + + stop_current_operation(); + + ieee802154_pib_update(); + + start_ed(duration); + ieee802154_set_state(IEEE802154_STATE_ED); + + ieee802154_exit_critical(); + return ESP_OK; +} + +esp_err_t ieee802154_cca(void) +{ + IEEE802154_RF_ENABLE(); + ieee802154_enter_critical(); + + stop_current_operation(); + + ieee802154_pib_update(); + + start_ed(CCA_DETECTION_TIME); + ieee802154_set_state(IEEE802154_STATE_CCA); + + ieee802154_exit_critical(); + return ESP_OK; +} + +ieee802154_state_t ieee802154_get_state(void) +{ + return s_ieee802154_state; +} diff --git a/components/ieee802154/driver/esp_ieee802154_frame.c b/components/ieee802154/driver/esp_ieee802154_frame.c new file mode 100644 index 0000000000..6a55909e2d --- /dev/null +++ b/components/ieee802154/driver/esp_ieee802154_frame.c @@ -0,0 +1,417 @@ +/* + * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include "esp_check.h" +#include "esp_attr.h" +#include "esp_ieee802154_dev.h" +#include "esp_ieee802154_frame.h" +#include "esp_ieee802154_util.h" + +IEEE802154_STATIC IEEE802154_INLINE bool is_security_enabled(const uint8_t *frame) +{ + return frame[IEEE802154_FRAME_SECURITY_OFFSET] & IEEE802154_FRAME_SECURITY_BIT; +} + +IEEE802154_STATIC IEEE802154_INLINE bool is_ie_present(const uint8_t *frame) +{ + return frame[IEEE802154_FRAME_IE_OFFSET] & IEEE802154_FRAME_IE_BIT; +} + +IEEE802154_STATIC IEEE802154_INLINE bool is_dsn_present(const uint8_t *frame) +{ + return ((ieee802154_frame_get_version(frame) != IEEE802154_FRAME_VERSION_2) || + !(frame[IEEE802154_FRAME_DSN_OFFSET] & IEEE802154_FRAME_DSN_BIT)); +} + +IEEE802154_STATIC IEEE802154_INLINE uint8_t dst_addr_mode(const uint8_t *frame) +{ + return frame[IEEE802154_FRAME_DST_MODE_OFFSET] & IEEE802154_FRAME_DST_MODE_MASK; +} + +IEEE802154_STATIC IEEE802154_INLINE uint8_t src_addr_mode(const uint8_t *frame) +{ + return frame[IEEE802154_FRAME_SRC_MODE_OFFSET] & IEEE802154_FRAME_SRC_MODE_MASK; +} + +IEEE802154_STATIC IEEE802154_INLINE bool is_panid_compression(const uint8_t *frame) +{ + return frame[IEEE802154_FRAME_PANID_COMP_OFFSET] & IEEE802154_FRAME_PANID_COMP_BIT; +} + +IEEE802154_STATIC IEEE802154_INLINE bool is_suported_frame_type(uint8_t frame_type) +{ + // HW supports 4 kinds of frame type: Beacon, Ack, Data, Command. + return (frame_type == IEEE802154_FRAME_TYPE_BEACON || frame_type == IEEE802154_FRAME_TYPE_DATA || + frame_type == IEEE802154_FRAME_TYPE_ACK || frame_type == IEEE802154_FRAME_TYPE_COMMAND); +} + +IEEE802154_STATIC IEEE802154_NOINLINE bool is_dst_panid_present(const uint8_t *frame) +{ + uint8_t dst_mode = dst_addr_mode(frame); + bool dst_panid_present = 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) || + (dst_mode == IEEE802154_FRAME_DST_MODE_EXT && src_mode == IEEE802154_FRAME_SRC_MODE_EXT && panid_compression)) { + dst_panid_present = false; + } else { + dst_panid_present = true; + } + } else { // dest address is not present + if (src_mode == IEEE802154_FRAME_SRC_MODE_NONE && panid_compression) { + dst_panid_present = true; + } else { + dst_panid_present = false; + } + } + } else { // frame version: 0b00, 0b01 + dst_panid_present = (dst_mode != IEEE802154_FRAME_DST_MODE_NONE); + } + + return dst_panid_present; +} + +IEEE802154_STATIC IEEE802154_NOINLINE bool is_src_panid_present(const uint8_t *frame) +{ + uint8_t src_mode = src_addr_mode(frame); + bool panid_compression = is_panid_compression(frame); + bool src_panid_present = 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; + } else { + src_panid_present = !panid_compression; + } + } else { + src_panid_present = false; + } + } else { // frame version: 0b00, 0b01 + if (src_mode != IEEE802154_FRAME_SRC_MODE_NONE) { + src_panid_present = !panid_compression; + } else { + src_panid_present = false; + } + } + + return src_panid_present; +} + +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); +} + +IEEE802154_STATIC IRAM_ATTR uint8_t ieee802154_frame_address_size(const uint8_t *frame) +{ + uint8_t address_size = 0; + + if (is_dst_panid_present(frame)) { + address_size += IEEE802154_FRAME_PANID_SIZE; + } + + switch (dst_addr_mode(frame)) { + case IEEE802154_FRAME_DST_MODE_NONE: + break; + + case IEEE802154_FRAME_DST_MODE_SHORT: + address_size += IEEE802154_FRAME_SHORT_ADDR_SIZE; + break; + + case IEEE802154_FRAME_DST_MODE_EXT: + address_size += IEEE802154_FRAME_EXT_ADDR_SIZE; + break; + + default: + return IEEE802154_FRAME_INVALID_OFFSET; + } + + if (is_src_panid_present(frame)) { + address_size += IEEE802154_FRAME_PANID_SIZE; + } + + switch (src_addr_mode(frame)) { + case IEEE802154_FRAME_SRC_MODE_NONE: + break; + + case IEEE802154_FRAME_SRC_MODE_SHORT: + address_size += IEEE802154_FRAME_SHORT_ADDR_SIZE; + break; + + case IEEE802154_FRAME_SRC_MODE_EXT: + address_size += IEEE802154_FRAME_EXT_ADDR_SIZE; + break; + + default: + return IEEE802154_FRAME_INVALID_OFFSET; + } + + return address_size; +} + +IEEE802154_STATIC IEEE802154_NOINLINE uint8_t ieee802154_frame_security_header_offset(const uint8_t *frame) +{ + ESP_RETURN_ON_FALSE_ISR(is_suported_frame_type(ieee802154_frame_get_type(frame)), IEEE802154_FRAME_INVALID_ADDR_MODE, IEEE802154_TAG, "invalid frame type"); + uint8_t offset = ieee802154_frame_address_offset(frame); + 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"); + + offset += address_size; + + return offset; +} + +IEEE802154_STATIC IEEE802154_NOINLINE uint8_t ieee802154_frame_get_security_field_len(const uint8_t *frame) +{ + ESP_RETURN_ON_FALSE_ISR(is_suported_frame_type(ieee802154_frame_get_type(frame)), IEEE802154_FRAME_INVALID_OFFSET, 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"); + + security_field_len += IEEE802154_FRAME_SE_HEAD_SIZE; + uint8_t security_header = frame[offset]; + + if (security_header & IEEE802154_FRAME_COUNTER_SUPPRESS_BIT) { + security_field_len += 0; + } else { + security_field_len += IEEE802154_FRAME_COUNTER_SIZE; + } + + switch (security_header & IEEE802154_FRAME_KEY_ID_MODE_MASK) { + case IEEE802154_FRAME_KEY_ID_MODE_1: + security_field_len += IEEE802154_FRAME_KEY_ID_MODE_1_SIZE; + break; + case IEEE802154_FRAME_KEY_ID_MODE_2: + security_field_len += IEEE802154_FRAME_KEY_ID_MODE_2_SIZE; + break; + case IEEE802154_FRAME_KEY_ID_MODE_3: + security_field_len += IEEE802154_FRAME_KEY_ID_MODE_3_SIZE; + break; + default: + security_field_len += 0; + break; + } + + return security_field_len; +} + +IEEE802154_STATIC uint8_t ieee802154_frame_ie_header_offset(const uint8_t *frame) +{ + uint8_t offset = ieee802154_frame_security_header_offset(frame); + uint8_t security_field_len = ieee802154_frame_get_security_field_len(frame); + + offset += security_field_len; + + return offset; +} + +IEEE802154_STATIC uint8_t ieee802154_frame_get_mic_len(const uint8_t *frame) +{ + uint8_t offset = ieee802154_frame_security_header_offset(frame); + uint8_t mic_len = 0; + uint8_t security_header = frame[offset]; + + switch (security_header & IEEE802154_FRAME_SECURITY_MASK) { + case IEEE802154_FRAME_SECURITY_MIC_32: + case IEEE802154_FRAME_SECURITY_ENC_MIC_32: + mic_len = IEEE802154_FRAME_SECURITY_MIC_32_SIZE; + break; + case IEEE802154_FRAME_SECURITY_MIC_64: + case IEEE802154_FRAME_SECURITY_ENC_MIC_64: + mic_len = IEEE802154_FRAME_SECURITY_MIC_64_SIZE; + break; + case IEEE802154_FRAME_SECURITY_MIC_128: + case IEEE802154_FRAME_SECURITY_ENC_MIC_128: + mic_len = IEEE802154_FRAME_SECURITY_MIC_128_SIZE; + break; + default: + mic_len = 0; + break; + } + return mic_len; +} + +IEEE802154_STATIC uint8_t ieee802154_frame_get_ie_field_len(const uint8_t *frame) +{ + uint8_t offset = ieee802154_frame_ie_header_offset(frame); + uint8_t ie_field_len = 0; + uint8_t frame_footer_len = ieee802154_frame_get_mic_len(frame) + IEEE802154_FRAME_FCS_SIZE; + + /* 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 + but no data payload. In this case, 2015-spec does not + require Header IE termination to be included (it is optional) + since the end of frame can be determined from frame length and + footer length. (for details, please reference 2015 - spec table 7 - 6 in page 169) */ + + while (frame[0] > offset + ie_field_len + frame_footer_len) { + 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) { + ie_field_len += IEEE802154_FRAME_IE_HEAD_LEN; + break; + } else { + uint8_t ie_subfield_len = (ie_header & IEEE802154_FRAME_IE_SUBFIELD_LEN_MASK); + ie_field_len += IEEE802154_FRAME_IE_HEAD_LEN + ie_subfield_len; + } + } + return ie_field_len; +} + +IEEE802154_STATIC IRAM_ATTR uint8_t ieee802154_frame_payload_offset(const uint8_t *frame) +{ + uint8_t offset = ieee802154_frame_security_header_offset(frame); + if (is_security_enabled(frame)) { + // skip security field. + offset += ieee802154_frame_get_security_field_len(frame); + } + + 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 (ieee802154_frame_get_version(frame) == IEEE802154_FRAME_VERSION_0 || ieee802154_frame_get_version(frame) == IEEE802154_FRAME_VERSION_1) { + if (ieee802154_frame_get_type(frame) == IEEE802154_FRAME_TYPE_BEACON) { + // TODO: skip beacon payload. + } + if (ieee802154_frame_get_type(frame) == IEEE802154_FRAME_TYPE_COMMAND) { + offset += IEEE802154_FRAME_COMMAND_ID_LEN; + } + } + + return offset - 1; +} + +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; +} + +bool IEEE802154_INLINE ieee802154_frame_is_ack_required(const uint8_t *frame) +{ + return (is_suported_frame_type(ieee802154_frame_get_type(frame))) && (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(is_suported_frame_type(ieee802154_frame_get_type(frame)), IEEE802154_FRAME_INVALID_ADDR_MODE, 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"); + + 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)) { + offset += IEEE802154_FRAME_PANID_SIZE; + } + + memcpy(addr, frame + offset, addr_size); + + return dst_mode; +} + +uint8_t ieee802154_frame_get_src_addr(const uint8_t *frame, uint8_t *addr) +{ + ESP_RETURN_ON_FALSE_ISR(is_suported_frame_type(ieee802154_frame_get_type(frame)), IEEE802154_FRAME_INVALID_ADDR_MODE, 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; + + 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; + + if (is_dst_panid_present(frame)) { + offset += IEEE802154_FRAME_PANID_SIZE; + } + + switch (dst_mode) { + case IEEE802154_FRAME_DST_MODE_SHORT: + offset += IEEE802154_FRAME_SHORT_ADDR_SIZE; + break; + + case IEEE802154_FRAME_DST_MODE_EXT: + offset += IEEE802154_FRAME_EXT_ADDR_SIZE; + break; + + default: + break; + } + + if (is_src_panid_present(frame)) { + offset += IEEE802154_FRAME_PANID_SIZE; + } + + memcpy(addr, frame + offset, addr_size); + + return src_mode; +} + +uint8_t ieee802154_frame_get_security_payload_offset(uint8_t *frame) +{ + return ieee802154_frame_payload_offset(frame); +} + +esp_err_t ieee802154_frame_get_dest_panid(const uint8_t *frame, uint8_t *panid) +{ + uint8_t offset = ieee802154_frame_address_offset(frame); + + if (is_dst_panid_present(frame)) { + memcpy(panid, frame + offset, IEEE802154_FRAME_PANID_SIZE); + return ESP_OK; + } + return ESP_FAIL; +} + +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); + + if (is_src_panid_present(frame)) { + if (is_dst_panid_present(frame)) { + offset += IEEE802154_FRAME_PANID_SIZE; + } + + switch (dst_mode) { + case IEEE802154_FRAME_DST_MODE_SHORT: + offset += IEEE802154_FRAME_SHORT_ADDR_SIZE; + break; + + case IEEE802154_FRAME_DST_MODE_EXT: + offset += IEEE802154_FRAME_EXT_ADDR_SIZE; + break; + + default: + break; + } + memcpy(panid, frame + offset, IEEE802154_FRAME_PANID_SIZE); + return ESP_OK; + } + return ESP_FAIL; +} diff --git a/components/ieee802154/driver/esp_ieee802154_pib.c b/components/ieee802154/driver/esp_ieee802154_pib.c new file mode 100644 index 0000000000..8654d5cef1 --- /dev/null +++ b/components/ieee802154/driver/esp_ieee802154_pib.c @@ -0,0 +1,220 @@ +/* + * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include "hal/ieee802154_ll.h" +#include "esp_ieee802154_pib.h" +#include "esp_ieee802154_util.h" + +static ieee802154_pib_t s_ieee802154_pib; +static bool is_pending = false; + +static inline void set_pending(void) +{ + is_pending = true; +} + +static inline void clr_pending(void) +{ + is_pending = false; +} + +bool inline ieee802154_pib_is_pending(void) +{ + return is_pending; +} + +void ieee802154_pib_init(void) +{ + memset(&s_ieee802154_pib, 0, sizeof(ieee802154_pib_t)); + s_ieee802154_pib.auto_ack_rx = true; + s_ieee802154_pib.auto_ack_tx = true; + s_ieee802154_pib.enhance_ack_tx = true; + s_ieee802154_pib.coordinator = false; + s_ieee802154_pib.promiscuous = true; + s_ieee802154_pib.rx_when_idle = false; + s_ieee802154_pib.channel = 11; + s_ieee802154_pib.cca_threshold = CONFIG_IEEE802154_CCA_THRESHOLD; + s_ieee802154_pib.cca_mode = CONFIG_IEEE802154_CCA_MODE; + s_ieee802154_pib.txpower = 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; + } + return ieee820154_txpower_index; +} + +void ieee802154_pib_update(void) +{ + if (ieee802154_pib_is_pending()) { + ieee802154_ll_set_freq(ieee802154_channel_to_freq(s_ieee802154_pib.channel)); + ieee802154_ll_set_power(ieee802154_txpower_convert(s_ieee802154_pib.txpower)); + + ieee802154_ll_set_cca_mode(s_ieee802154_pib.cca_mode); + ieee802154_ll_set_cca_threshold(s_ieee802154_pib.cca_threshold); + + ieee802154_ll_set_tx_auto_ack(s_ieee802154_pib.auto_ack_tx); + ieee802154_ll_set_rx_auto_ack(s_ieee802154_pib.auto_ack_rx); + ieee802154_ll_set_tx_enhance_ack(s_ieee802154_pib.enhance_ack_tx); + + 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); + + clr_pending(); + } +} + +uint8_t ieee802154_pib_get_channel(void) +{ + return s_ieee802154_pib.channel; +} + +void ieee802154_pib_set_channel(uint8_t channel) +{ + if (s_ieee802154_pib.channel != channel) { + s_ieee802154_pib.channel = channel; + set_pending(); + } +} + +int8_t ieee802154_pib_get_power(void) +{ + return s_ieee802154_pib.txpower; +} + +void ieee802154_pib_set_power(int8_t power) +{ + if (s_ieee802154_pib.txpower != power) { + s_ieee802154_pib.txpower = power; + set_pending(); + } +} + +bool ieee802154_pib_get_promiscuous(void) +{ + return s_ieee802154_pib.promiscuous; +} + +void ieee802154_pib_set_promiscuous(bool enable) +{ + if (s_ieee802154_pib.promiscuous != enable) { + s_ieee802154_pib.promiscuous = enable; + set_pending(); + } +} + +int8_t ieee802154_pib_get_cca_threshold(void) +{ + return s_ieee802154_pib.cca_threshold; +} + +void ieee802154_pib_set_cca_threshold(int8_t cca_threshold) +{ + if (s_ieee802154_pib.cca_threshold != cca_threshold) { + s_ieee802154_pib.cca_threshold = cca_threshold; + set_pending(); + } +} + +ieee802154_ll_cca_mode_t ieee802154_pib_get_cca_mode(void) +{ + return s_ieee802154_pib.cca_mode; +} + +void ieee802154_pib_set_cca_mode(ieee802154_ll_cca_mode_t cca_mode) +{ + if (s_ieee802154_pib.cca_mode != cca_mode) { + s_ieee802154_pib.cca_mode = cca_mode; + set_pending(); + } +} + +bool ieee802154_pib_get_auto_ack_tx(void) +{ + return s_ieee802154_pib.auto_ack_tx; +} + +void ieee802154_pib_set_auto_ack_tx(bool enable) +{ + if (s_ieee802154_pib.auto_ack_tx != enable) { + s_ieee802154_pib.auto_ack_tx = enable; + set_pending(); + } +} + +bool ieee802154_pib_get_auto_ack_rx(void) +{ + return s_ieee802154_pib.auto_ack_rx; +} + +void ieee802154_pib_set_auto_ack_rx(bool enable) +{ + if (s_ieee802154_pib.auto_ack_rx != enable) { + s_ieee802154_pib.auto_ack_rx = enable; + set_pending(); + } +} + +bool ieee802154_pib_get_enhance_ack_tx(void) +{ + return s_ieee802154_pib.enhance_ack_tx; +} + +void ieee802154_pib_set_enhance_ack_tx(bool enable) +{ + if (s_ieee802154_pib.enhance_ack_tx != enable) { + s_ieee802154_pib.enhance_ack_tx = enable; + set_pending(); + } +} + +bool ieee802154_pib_get_coordinator(void) +{ + return s_ieee802154_pib.coordinator; +} + +void ieee802154_pib_set_coordinator(bool enable) +{ + if (s_ieee802154_pib.coordinator != enable) { + s_ieee802154_pib.coordinator = enable; + set_pending(); + } +} + +ieee802154_ll_pending_mode_t ieee802154_pib_get_pending_mode(void) +{ + return s_ieee802154_pib.pending_mode; +} + +void ieee802154_pib_set_pending_mode(ieee802154_ll_pending_mode_t pending_mode) +{ + if (s_ieee802154_pib.pending_mode != pending_mode) { + s_ieee802154_pib.pending_mode = pending_mode; + set_pending(); + } +} + +void ieee802154_pib_set_rx_when_idle(bool enable) +{ + s_ieee802154_pib.rx_when_idle = enable; +} + +bool ieee802154_pib_get_rx_when_idle(void) +{ + return s_ieee802154_pib.rx_when_idle; +} diff --git a/components/ieee802154/driver/esp_ieee802154_sec.c b/components/ieee802154/driver/esp_ieee802154_sec.c new file mode 100644 index 0000000000..2192550ab3 --- /dev/null +++ b/components/ieee802154/driver/esp_ieee802154_sec.c @@ -0,0 +1,28 @@ +/* + * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include "esp_err.h" +#include "hal/ieee802154_ll.h" +#include "esp_ieee802154_frame.h" +#include "esp_ieee802154_sec.h" + +#include "esp_ieee802154.h" +static bool s_is_security = false; + +void ieee802154_transmit_security_config(uint8_t *frame, uint8_t *key, uint8_t *addr) +{ + ieee802154_ll_set_security_addr(addr); + ieee802154_ll_set_security_key(key); + ieee802154_ll_set_security_offset(ieee802154_frame_get_security_payload_offset(frame)); + s_is_security = true; +} + +void ieee802154_sec_update(void) +{ + ieee802154_ll_set_transmit_security(s_is_security); + s_is_security = false; +} diff --git a/components/ieee802154/driver/esp_ieee802154_timer.c b/components/ieee802154/driver/esp_ieee802154_timer.c new file mode 100644 index 0000000000..e2bff1a59b --- /dev/null +++ b/components/ieee802154/driver/esp_ieee802154_timer.c @@ -0,0 +1,59 @@ +/* + * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "soc/soc.h" +#include "hal/ieee802154_ll.h" +#include "esp_check.h" +#include "esp_ieee802154_timer.h" +#include "esp_ieee802154_util.h" + +void ieee802154_timer0_start(void) +{ + ieee802154_ll_set_cmd(IEEE802154_CMD_TIMER0_START); +} + +void ieee802154_timer0_stop(void) +{ + ieee802154_ll_set_cmd(IEEE802154_CMD_TIMER0_STOP); +} + +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; +} + +uint32_t ieee802154_timer0_get_value(void) +{ + return ieee802154_ll_timer0_get_value(); +} + +void ieee802154_timer1_start(void) +{ + ieee802154_ll_set_cmd(IEEE802154_CMD_TIMER1_START); +} + +void ieee802154_timer1_stop(void) +{ + ieee802154_ll_set_cmd(IEEE802154_CMD_TIMER1_STOP); +} + +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; +} + +uint32_t ieee802154_timer1_get_value(void) +{ + return ieee802154_ll_timer1_get_value(); +} diff --git a/components/ieee802154/driver/esp_ieee802154_util.c b/components/ieee802154/driver/esp_ieee802154_util.c new file mode 100644 index 0000000000..c3ffed0a94 --- /dev/null +++ b/components/ieee802154/driver/esp_ieee802154_util.c @@ -0,0 +1,63 @@ +/* + * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "esp_private/esp_modem_clock.h" +#include "soc/soc.h" +#include "soc/periph_defs.h" +#include "hal/ieee802154_ll.h" +#include "esp_coex_i154.h" +#include "esp_ieee802154_util.h" + +uint8_t ieee802154_freq_to_channel(uint8_t freq) +{ + return (freq - 3) / 5 + 11; +} + +uint8_t ieee802154_channel_to_freq(uint8_t channel) +{ + return (channel - 11) * 5 + 3; +} + +#if !CONFIG_IEEE802154_TEST && (CONFIG_ESP_COEX_SW_COEXIST_ENABLE || CONFIG_EXTERNAL_COEX_ENABLE) +void ieee802154_set_txrx_pti(ieee802154_txrx_scene_t txrx_scene) +{ + + switch (txrx_scene) { + case IEEE802154_SCENE_IDLE: + esp_coex_ieee802154_txrx_pti_set(IEEE802154_IDLE); + break; + case IEEE802154_SCENE_TX: + case IEEE802154_SCENE_RX: + esp_coex_ieee802154_txrx_pti_set(IEEE802154_LOW); + break; + case IEEE802154_SCENE_TX_AT: + case IEEE802154_SCENE_RX_AT: + esp_coex_ieee802154_txrx_pti_set(IEEE802154_MIDDLE); + break; + default: + assert(false); + break; + } +} +#endif // !CONFIG_IEEE802154_TEST && CONFIG_ESP_COEX_SW_COEXIST_ENABLE || CONFIG_EXTERNAL_COEX_ENABLE + +// TZ-97: implement these two functions using ETM common interface +void ieee802154_etm_channel_clear(uint32_t channel) +{ + if (!(REG_READ(ETM_CHEN_AD0_REG) & (1 << channel))) { + REG_WRITE(ETM_CHENCLR_AD0_REG, (REG_READ(ETM_CHENCLR_AD0_REG)) | 1 << channel); + } +} + +void ieee802154_etm_set_event_task(uint32_t channel, uint32_t event, uint32_t task) +{ + ieee802154_etm_channel_clear(channel); + + 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)); +} diff --git a/components/ieee802154/esp_ieee802154.c b/components/ieee802154/esp_ieee802154.c new file mode 100644 index 0000000000..db80ef8820 --- /dev/null +++ b/components/ieee802154/esp_ieee802154.c @@ -0,0 +1,418 @@ +/* + * SPDX-FileCopyrightText: 2020-2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include "sdkconfig.h" +#include "esp_ieee802154.h" +#include "esp_err.h" +#include "esp_phy_init.h" +#include "esp_ieee802154_ack.h" +#include "esp_ieee802154_dev.h" +#include "esp_ieee802154_frame.h" +#include "esp_ieee802154_pib.h" +#include "esp_ieee802154_sec.h" +#include "esp_ieee802154_util.h" +#include "esp_log.h" +#include "esp_coex_i154.h" +#include "hal/ieee802154_ll.h" +#include "hal/ieee802154_common_ll.h" + +esp_err_t esp_ieee802154_enable(void) +{ + ieee802154_enable(); + ieee802154_rf_enable(); + esp_btbb_enable(); + return ieee802154_mac_init(); +} + +esp_err_t esp_ieee802154_disable(void) +{ + esp_btbb_disable(); + ieee802154_rf_disable(); + ieee802154_disable(); + return ieee802154_mac_deinit(); +} + +uint8_t esp_ieee802154_get_channel(void) +{ + return ieee802154_pib_get_channel(); +} + +esp_err_t esp_ieee802154_set_channel(uint8_t channel) +{ + ieee802154_pib_set_channel(channel); + return ESP_OK; +} + +int8_t esp_ieee802154_get_txpower(void) +{ + return ieee802154_pib_get_power(); +} + +esp_err_t esp_ieee802154_set_txpower(int8_t power) +{ + ieee802154_pib_set_power(power); + return ESP_OK; +} + +bool esp_ieee802154_get_promiscuous(void) +{ + return ieee802154_pib_get_promiscuous(); +} + +esp_err_t esp_ieee802154_set_promiscuous(bool enable) +{ + ieee802154_pib_set_promiscuous(enable); + ieee802154_pib_set_auto_ack_rx(!enable); + ieee802154_pib_set_auto_ack_tx(!enable); + ieee802154_pib_set_enhance_ack_tx(!enable); + return ESP_OK; +} + +int8_t esp_ieee802154_get_cca_threshold(void) +{ + return ieee802154_pib_get_cca_threshold(); +} + +esp_err_t esp_ieee802154_set_cca_threshold(int8_t cca_threshold) +{ + ieee802154_pib_set_cca_threshold(cca_threshold); + return ESP_OK; +} + +esp_ieee802154_cca_mode_t esp_ieee802154_get_cca_mode(void) +{ + return ieee802154_pib_get_cca_mode(); +} + +esp_err_t esp_ieee802154_set_cca_mode(esp_ieee802154_cca_mode_t cca_mode) +{ + ieee802154_pib_set_cca_mode(cca_mode); + return ESP_OK; +} + +bool esp_ieee802154_get_auto_ack_tx(void) +{ + return ieee802154_pib_get_auto_ack_tx(); +} + +esp_err_t esp_ieee802154_set_auto_ack_tx(bool enable) +{ + ieee802154_pib_set_auto_ack_tx(enable); + return ESP_OK; +} + +bool esp_ieee802154_get_auto_ack_rx(void) +{ + return ieee802154_pib_get_auto_ack_rx(); +} + +esp_err_t esp_ieee802154_set_auto_ack_rx(bool enable) +{ + ieee802154_pib_set_auto_ack_rx(enable); + return ESP_OK; +} + +bool esp_ieee802154_get_coordinator(void) +{ + return ieee802154_pib_get_coordinator(); +} + +esp_err_t esp_ieee802154_set_coordinator(bool enable) +{ + ieee802154_pib_set_coordinator(enable); + return ESP_OK; +} + +#if CONFIG_IEEE802154_MULTI_PAN_ENABLE + +uint16_t esp_ieee802154_get_multipan_panid(esp_ieee802154_multipan_index_t index) +{ + assert(index < ESP_IEEE802154_MULTIPAN_MAX); + 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); + 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); + 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); + 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); + 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); + ieee802154_ll_set_multipan_ext_addr(index, ext_addr); + return ESP_OK; +} + +uint8_t esp_ieee802154_get_multipan_enable(void) +{ + return ieee802154_ll_get_multipan_enable_mask(); +} + +esp_err_t esp_ieee802154_set_multipan_enable(uint8_t mask) +{ + assert(mask < (1 << ESP_IEEE802154_MULTIPAN_MAX)); + ieee802154_ll_set_multipan_enable_mask(mask); + return ESP_OK; +} + +#else + +uint16_t esp_ieee802154_get_panid(void) +{ + return ieee802154_ll_get_multipan_panid(ESP_IEEE802154_MULTIPAN_0); +} + +esp_err_t esp_ieee802154_set_panid(uint16_t panid) +{ + ieee802154_ll_set_multipan_panid(ESP_IEEE802154_MULTIPAN_0, panid); + return ESP_OK; +} + +uint16_t esp_ieee802154_get_short_address(void) +{ + return ieee802154_ll_get_multipan_short_addr(ESP_IEEE802154_MULTIPAN_0); +} + +esp_err_t esp_ieee802154_set_short_address(uint16_t short_address) +{ + ieee802154_ll_set_multipan_short_addr(ESP_IEEE802154_MULTIPAN_0, short_address); + return ESP_OK; +} + +esp_err_t esp_ieee802154_get_extended_address(uint8_t *ext_addr) +{ + 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) +{ + ieee802154_ll_set_multipan_ext_addr(ESP_IEEE802154_MULTIPAN_0, ext_addr); + return ESP_OK; +} + +#endif // CONFIG_IEEE802154_MULTI_PAN_ENABLE + +esp_ieee802154_pending_mode_t esp_ieee802154_get_pending_mode(void) +{ + return ieee802154_pib_get_pending_mode(); +} + +esp_err_t esp_ieee802154_set_pending_mode(esp_ieee802154_pending_mode_t pending_mode) +{ + ieee802154_pib_set_pending_mode(pending_mode); + return ESP_OK; +} + +esp_err_t esp_ieee802154_set_rx_when_idle(bool enable) +{ + ieee802154_pib_set_rx_when_idle(enable); + return ESP_OK; +} + +bool esp_ieee802154_get_rx_when_idle(void) +{ + return ieee802154_pib_get_rx_when_idle(); +} + +esp_err_t esp_ieee802154_transmit(const uint8_t *frame, bool cca) +{ + return ieee802154_transmit(frame, cca); +} + +esp_err_t esp_ieee802154_transmit_at(const uint8_t *frame, bool cca, uint32_t time) +{ + return ieee802154_transmit_at(frame, cca, time); +} + +esp_err_t esp_ieee802154_sleep(void) +{ + return ieee802154_sleep(); +} + +esp_err_t esp_ieee802154_receive(void) +{ + return ieee802154_receive(); +} + +esp_err_t esp_ieee802154_receive_at(uint32_t time) +{ + return ieee802154_receive_at(time); +} + +esp_err_t esp_ieee802154_energy_detect(uint32_t duration) +{ + return ieee802154_energy_detect(duration); +} + +esp_err_t esp_ieee802154_cca(void) +{ + return ieee802154_cca(); +} + +esp_ieee802154_state_t esp_ieee802154_get_state(void) +{ + switch (ieee802154_get_state()) { + case IEEE802154_STATE_DISABLE: + return ESP_IEEE802154_RADIO_DISABLE; + + case IEEE802154_STATE_IDLE: + return ESP_IEEE802154_RADIO_IDLE; + + case IEEE802154_STATE_SLEEP: + return ESP_IEEE802154_RADIO_SLEEP; + + case IEEE802154_STATE_RX: + case IEEE802154_STATE_TX_ACK: + case IEEE802154_STATE_ED: + return ESP_IEEE802154_RADIO_RECEIVE; + + case IEEE802154_STATE_TX_CCA: + case IEEE802154_STATE_CCA: + case IEEE802154_STATE_TX: + case IEEE802154_STATE_RX_ACK: + case IEEE802154_STATE_TX_ENH_ACK: + return ESP_IEEE802154_RADIO_TRANSMIT; + + default: + assert(false); + return ESP_IEEE802154_RADIO_DISABLE; + } +} + +esp_err_t esp_ieee802154_set_transmit_security(uint8_t *frame, uint8_t *key, uint8_t *addr) +{ + 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); +} + +esp_err_t esp_ieee802154_clear_pending_addr(const uint8_t *addr, bool is_short) +{ + return ieee802154_clear_pending_addr(addr, is_short); +} + +esp_err_t esp_ieee802154_reset_pending_table(bool is_short) +{ + ieee802154_reset_pending_table(is_short); + return ESP_OK; +} + +int8_t esp_ieee802154_get_recent_rssi(void) +{ + return ieee802154_get_recent_rssi(); +} + +uint8_t esp_ieee802154_get_recent_lqi(void) +{ + return ieee802154_get_recent_lqi(); +} + +esp_err_t esp_ieee802154_receive_handle_done(const uint8_t *frame) +{ + return ieee802154_receive_handle_done(frame); +} + +__attribute__((weak)) void esp_ieee802154_receive_done(uint8_t *data, esp_ieee802154_frame_info_t *frame_info) +{ + +} + +__attribute__((weak)) void esp_ieee802154_receive_sfd_done(void) +{ + +} + +__attribute__((weak)) void esp_ieee802154_receive_failed(uint16_t error) +{ + +} + +__attribute__((weak)) void esp_ieee802154_transmit_done(const uint8_t *frame, const uint8_t *ack, esp_ieee802154_frame_info_t *ack_frame_info) +{ + +} + +__attribute__((weak)) void esp_ieee802154_transmit_failed(const uint8_t *frame, esp_ieee802154_tx_error_t error) +{ + +} + +__attribute__((weak)) void esp_ieee802154_transmit_sfd_done(uint8_t *frame) +{ + +} + +__attribute__((weak)) void esp_ieee802154_cca_done(bool channel_free) +{ + +} + +__attribute__((weak)) void esp_ieee802154_energy_detect_done(int8_t power) +{ + +} + +__attribute__((weak)) void esp_ieee802154_ed_failed(uint16_t error) +{ + +} + +__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"); + return ESP_FAIL; +} + +__attribute__((weak)) void esp_ieee802154_timer0_done(void) +{ + +} + +__attribute__((weak)) void esp_ieee802154_timer1_done(void) +{ + +} + +#if CONFIG_IEEE802154_TXRX_STATISTIC +void esp_ieee802154_txrx_statistic_clear(void) +{ + ieee802154_txrx_statistic_clear(); +} + +void esp_ieee802154_txrx_statistic_print(void) +{ + ieee802154_txrx_statistic_print(); +} +#endif // CONFIG_IEEE802154_TXRX_STATISTIC diff --git a/components/ieee802154/include/esp_ieee802154.h b/components/ieee802154/include/esp_ieee802154.h new file mode 100644 index 0000000000..51adf6ce00 --- /dev/null +++ b/components/ieee802154/include/esp_ieee802154.h @@ -0,0 +1,628 @@ +/* + * SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include +#include +#include "sdkconfig.h" +#include "esp_err.h" +#include "esp_ieee802154_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Initialize the IEEE 802.15.4 subsystem. + * + * @return + * - ESP_OK on success. + * - ESP_FAIL on failure. + * + */ +esp_err_t esp_ieee802154_enable(void); + +/** + * @brief Deinitialize the IEEE 802.15.4 subsystem. + * + * @return + * - ESP_OK on success. + * - ESP_FAIL on failure. + */ +esp_err_t esp_ieee802154_disable(void); + +/** + * @brief Get the operational channel. + * + * @return The channel number (11~26). + * + */ +uint8_t esp_ieee802154_get_channel(void); + +/** + * @brief Set the operational channel. + * + * @param[in] channel The channel number (11-26). + * + * @return + * - ESP_OK on success. + * - ESP_FAIL on failure. + */ +esp_err_t esp_ieee802154_set_channel(uint8_t channel); + +/** + * @brief Get the transmit power. + * + * @return The transmit power in dBm. + * + */ +int8_t esp_ieee802154_get_txpower(void); + +/** + * @brief Set the transmit power. + * + * @param[in] power The transmit power in dBm. + * + * @return + * - ESP_OK on success. + * - ESP_FAIL on failure. + */ +esp_err_t esp_ieee802154_set_txpower(int8_t power); + +/** + * @brief Get the promiscuous mode. + * + * @return + * - True The promiscuous mode is enabled. + * - False The promiscuous mode is disabled. + * + */ +bool esp_ieee802154_get_promiscuous(void); + +/** + * @brief Set the promiscuous mode. + * + * @param[in] enable The promiscuous mode to be set. + * + * @return + * - ESP_OK on success. + * - ESP_FAIL on failure. + */ +esp_err_t esp_ieee802154_set_promiscuous(bool enable); + +/** + * @brief Get the IEEE 802.15.4 Radio state. + * + * @return The IEEE 802.15.4 Radio state, refer to esp_ieee802154_state_t. + * + */ +esp_ieee802154_state_t esp_ieee802154_get_state(void); + +/** + * @brief Set the IEEE 802.15.4 Radio to sleep state. + * + * @return + * - ESP_OK on success. + * - ESP_FAIL on failure due to invalid state. + * + */ +esp_err_t esp_ieee802154_sleep(void); + +/** + * @brief Set the IEEE 802.15.4 Radio to receive state. + * + * @note Radio will continue receiving until it receives a valid frame. + * Refer to `esp_ieee802154_receive_done()`. + * + * @return + * - ESP_OK on success + * - ESP_FAIL on failure due to invalid state. + * + */ +esp_err_t esp_ieee802154_receive(void); + +/** + * @brief Transmit the given frame. + * The transmit result will be reported via `esp_ieee802154_transmit_done()` + * or `esp_ieee802154_transmit_failed()`. + * + * @param[in] frame The pointer to the frame, the frame format: + * |-----------------------------------------------------------------------| + * | Len | MHR | MAC Payload | FCS | + * |-----------------------------------------------------------------------| + * @param[in] cca Perform CCA before transmission if it's true, otherwise transmit the frame directly. + * + * @note During transmission, the hardware calculates the FCS, and send it over the air right after the MAC payload, + * so you just need to prepare the length, mac header and mac payload content. + * + * @return + * - ESP_OK on success. + * - ESP_ERR_INVALID_ARG on an invalid frame. + * - ESP_FAIL on failure due to invalid state. + * + */ +esp_err_t esp_ieee802154_transmit(const uint8_t *frame, bool cca); + +/** + * @brief Set the time to wait for the ack frame. + * + * @param[in] timeout The time to wait for the ack frame, in symbol unit (16 us). + * Default: 0x006C, Range: 0x0000 - 0xFFFF. + * + * @return + * - ESP_OK on success. + * - ESP_FAIL on failure. + */ +esp_err_t esp_ieee802154_set_ack_timeout(uint32_t timeout); + +/** + * @brief Get the device PAN ID. + * + * @return The device PAN ID. + * + */ +uint16_t esp_ieee802154_get_panid(void); + +/** + * @brief Set the device PAN ID. + * + * @param[in] panid The device PAN ID. + * + * @return + * - ESP_OK on success. + * - ESP_FAIL on failure. + */ +esp_err_t esp_ieee802154_set_panid(uint16_t panid); + +/** + * @brief Get the device short address. + * + * @return The device short address. + * + */ +uint16_t esp_ieee802154_get_short_address(void); + +/** + * @brief Set the device short address. + * + * @param[in] short_address The device short address. + * + * @return + * - ESP_OK on success. + * - ESP_FAIL on failure. + */ +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. + * + * @return + * - ESP_OK on success. + * - ESP_FAIL on failure. + */ +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. + * + * @return + * - ESP_OK on success. + * - ESP_FAIL on failure. + */ +esp_err_t esp_ieee802154_set_extended_address(const uint8_t *ext_addr); + +/** + * @brief Get the device PAN ID for specific interface. + * + * @param[in] index The interface index. + * + * @return The device PAN ID. + * + */ +uint16_t esp_ieee802154_get_multipan_panid(esp_ieee802154_multipan_index_t index); + +/** + * @brief Set the device PAN ID for specific interface. + * + * @param[in] index The interface index. + * @param[in] panid The device PAN ID. + * + * @return + * - ESP_OK on success. + * - ESP_FAIL on failure. + */ +esp_err_t esp_ieee802154_set_multipan_panid(esp_ieee802154_multipan_index_t index, uint16_t panid); + +/** + * @brief Get the device short address for specific interface. + * + * @param[in] index The interface index. + * + * @return The device short address. + * + */ +uint16_t esp_ieee802154_get_multipan_short_address(esp_ieee802154_multipan_index_t index); + +/** + * @brief Set the device short address for specific interface. + * + * @param[in] index The interface index. + * @param[in] short_address The device short address. + * + * @return + * - ESP_OK on success. + * - ESP_FAIL on failure. + */ +esp_err_t esp_ieee802154_set_multipan_short_address(esp_ieee802154_multipan_index_t index, uint16_t short_address); + +/** + * @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. + * + * @return + * - ESP_OK on success. + * - ESP_FAIL on failure. + */ +esp_err_t esp_ieee802154_get_multipan_extended_address(esp_ieee802154_multipan_index_t index, uint8_t *ext_addr); + +/** + * @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. + * + * @return + * - ESP_OK on success. + * - ESP_FAIL on failure. + */ +esp_err_t esp_ieee802154_set_multipan_extended_address(esp_ieee802154_multipan_index_t index, const uint8_t *ext_addr); + +/** + * @brief Get the device current multipan interface enable mask. + * + * @return Current multipan interface enable mask. + * + */ +uint8_t esp_ieee802154_get_multipan_enable(void); + +/** + * @brief Enable specific interface for the device. + * + * As an example, call `esp_ieee802154_set_multipan_enable(BIT(ESP_IEEE802154_MULTIPAN_0) | BIT(ESP_IEEE802154_MULTIPAN_1));` + * to enable multipan interface 0 and 1. + * + * @param[in] mask The multipan interface bit mask. + * + * @return + * - ESP_OK on success. + * - ESP_FAIL on failure. + */ +esp_err_t esp_ieee802154_set_multipan_enable(uint8_t mask); + +/** + * @brief Get the device coordinator. + * + * @return + * - True The coordinator is enabled. + * - False The coordinator is disabled. + * + */ +bool esp_ieee802154_get_coordinator(void); + +/** + * @brief Set the device coordinator role. + * + * @param[in] enable The coordinator role to be set. + * + * @return + * - ESP_OK on success. + * - ESP_FAIL on failure. + */ +esp_err_t esp_ieee802154_set_coordinator(bool enable); + +/** + * @brief Get the auto frame pending mode. + * + * @return The auto frame pending mode, refer to esp_ieee802154_pending_mode_t. + * + */ +esp_ieee802154_pending_mode_t esp_ieee802154_get_pending_mode(void); + +/** + * @brief Set the auto frame pending mode. + * + * @param[in] pending_mode The auto frame pending mode, refer to esp_ieee802154_pending_mode_t. + * + * @return + * - ESP_OK on success. + * - ESP_FAIL on failure. + */ +esp_err_t esp_ieee802154_set_pending_mode(esp_ieee802154_pending_mode_t pending_mode); + +/** + * @brief Add address to the source matching table. + * + * @param[in] addr The pointer to the address. + * @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_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] 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_t esp_ieee802154_clear_pending_addr(const uint8_t *addr, bool is_short); + +/** + * @brief Clear the source matching table to empty. + * + * @param[in] is_short Clear Short address table or Extended address table. + * + * @return + * - ESP_OK on success. + * - ESP_FAIL on failure. + */ +esp_err_t esp_ieee802154_reset_pending_table(bool is_short); + +/** + * @brief Get the CCA threshold. + * + * @return The CCA threshold in dBm. + * + */ +int8_t esp_ieee802154_get_cca_threshold(void); + +/** + * @brief Set the CCA threshold. + * + * @param[in] cca_threshold The CCA threshold in dBm. + * + * @return + * - ESP_OK on success. + * - ESP_FAIL on failure. + */ +esp_err_t esp_ieee802154_set_cca_threshold(int8_t cca_threshold); + +/** + * @brief Get the CCA mode. + * + * @return The CCA mode, refer to esp_ieee802154_cca_mode_t. + * + */ +esp_ieee802154_cca_mode_t esp_ieee802154_get_cca_mode(void); + +/** + * @brief Set the CCA mode. + * + * @param[in] cca_mode The CCA mode, refer to esp_ieee802154_cca_mode_t. + * + * @return + * - ESP_OK on success. + * - ESP_FAIL on failure. + */ +esp_err_t esp_ieee802154_set_cca_mode(esp_ieee802154_cca_mode_t cca_mode); + +/** + * @brief Enable rx_on_when_idle mode, radio will receive during idle. + * + * @param[in] enable Enable/Disable rx_on_when_idle mode. + * + * @return + * - ESP_OK on success. + * - ESP_FAIL on failure. + */ +esp_err_t esp_ieee802154_set_rx_when_idle(bool enable); + +/** + * @brief Get the rx_on_when_idle mode. + * + * @return rx_on_when_idle mode. + * + */ +bool esp_ieee802154_get_rx_when_idle(void); + +/** + * @brief Perform energy detection. + * + * @param[in] duration The duration of energy detection, in symbol unit (16 us). + * The result will be reported via esp_ieee802154_energy_detect_done(). + * + * @return + * - ESP_OK on success. + * - ESP_FAIL on failure due to invalid state. + * + */ +esp_err_t esp_ieee802154_energy_detect(uint32_t duration); + +/** + * @brief Notify the IEEE 802.15.4 Radio that the frame is handled done by upper layer. + * + * @param[in] frame The pointer to the frame which was passed from the function `esp_ieee802154_receive_done()` + * or ack frame from `esp_ieee802154_transmit_done()`. + * + * @return + * - ESP_OK on success + * - ESP_FAIL if frame is invalid. + * + */ +esp_err_t esp_ieee802154_receive_handle_done(const uint8_t *frame); + +/** Below are the events generated by IEEE 802.15.4 subsystem, which are in ISR context **/ +/** + * @brief A Frame was received. + * + * @note User must call the function `esp_ieee802154_receive_handle_done()` to notify 802.15.4 driver after the received frame is handled. + * + * @param[in] frame The point to the received frame, frame format: + * |-----------------------------------------------------------------------| + * | Len | MHR | MAC Payload (no FCS) | + * |-----------------------------------------------------------------------| + * @param[in] frame_info More information of the received frame, refer to esp_ieee802154_frame_info_t. + * + * @note During receiving, the hardware calculates the FCS of the received frame, and may drop it if the FCS doesn't match, only the valid + * frames will be received and notified by esp_ieee802154_receive_done(). Please note that the FCS field is replaced by RSSI and LQI + * value of the received frame. + * + */ +extern void esp_ieee802154_receive_done(uint8_t *frame, esp_ieee802154_frame_info_t *frame_info); + +/** + * @brief The SFD field of the frame was received. + * + */ +extern void esp_ieee802154_receive_sfd_done(void); + +/** + * @brief The Frame Transmission succeeded. + * + * @note If the ack frame is not null, user must call the function `esp_ieee802154_receive_handle_done()` to notify 802.15.4 driver + * after the ack frame is handled. + * + * @param[in] frame The pointer to the transmitted frame. + * @param[in] ack The received ACK frame, it could be NULL if the transmitted frame's AR bit is not set. + * @param[in] ack_frame_info More information of the ACK frame, refer to esp_ieee802154_frame_info_t. + * + */ +extern void esp_ieee802154_transmit_done(const uint8_t *frame, const uint8_t *ack, esp_ieee802154_frame_info_t *ack_frame_info); + +/** + * @brief The Frame Transmission failed. Refer to `esp_ieee802154_transmit()`. + * + * @param[in] frame The pointer to the frame. + * @param[in] error The transmission failure reason, refer to esp_ieee802154_tx_error_t. + * + */ +extern void esp_ieee802154_transmit_failed(const uint8_t *frame, esp_ieee802154_tx_error_t error); + +/** + * @brief The SFD field of the frame was transmitted. + * + */ +extern void esp_ieee802154_transmit_sfd_done(uint8_t *frame); + +/** + * @brief The energy detection done. Refer to `esp_ieee802154_energy_detect()`. + * + * @param[in] power The detected power level, in dBm. + * + */ +extern void esp_ieee802154_energy_detect_done(int8_t power); + +/** + * @brief Set the IEEE 802.15.4 Radio to receive state at a specific time. + * + * @note Radio will start receiving after the timestamp, and continue receiving until it receives a valid frame. + * Refer to `esp_ieee802154_receive_done()`. + * + * @param[in] time A specific timestamp for starting receiving. + * @return + * - ESP_OK on success + * - ESP_FAIL on failure due to invalid state. + * + */ +esp_err_t esp_ieee802154_receive_at(uint32_t time); + +/** + * @brief Transmit the given frame at a specific time. + * The transmit result will be reported via `esp_ieee802154_transmit_done()` + * or `esp_ieee802154_transmit_failed()`. + * + * @param[in] frame The pointer to the frame. Refer to `esp_ieee802154_transmit()`. + * @param[in] cca Perform CCA before transmission if it's true, otherwise transmit the frame directly. + * @param[in] time A specific timestamp for starting transmission. + * + * @return + * - ESP_OK on success. + * - ESP_ERR_INVALID_ARG on an invalid frame. + * - ESP_FAIL on failure due to invalid state. + * + */ +esp_err_t esp_ieee802154_transmit_at(const uint8_t *frame, bool cca, uint32_t time); + +/** + * @brief Get the RSSI of the most recent received frame. + * + * @return The value of RSSI. + * + */ +int8_t esp_ieee802154_get_recent_rssi(void); + +/** + * @brief Get the LQI of the most recent received frame. + * + * @return The value of LQI. + * + */ +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. + * + * @return + * - ESP_OK on success. + * - ESP_FAIL on failure. + */ +esp_err_t esp_ieee802154_set_transmit_security(uint8_t *frame, uint8_t *key, uint8_t *addr); + +/** + * @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_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. + * + * @return + * - ESP_OK if Enh-Ack generates done. + * - ESP_FAIL if Enh-Ack generates failed. + * + */ +esp_err_t esp_ieee802154_enh_ack_generator(uint8_t *frame, esp_ieee802154_frame_info_t *frame_info, uint8_t* enhack_frame); + +/** + * The configurable definitions via Kconfig + */ +#if CONFIG_IEEE802154_TXRX_STATISTIC + +/** + * @brief Clear the current IEEE802.15.4 statistic. + * + */ +void esp_ieee802154_txrx_statistic_clear(void); + +/** + * @brief Print the current IEEE802.15.4 statistic. + * + */ +void esp_ieee802154_txrx_statistic_print(void); +#endif // CONFIG_IEEE802154_TXRX_STATISTIC + +#ifdef __cplusplus +} +#endif diff --git a/components/ieee802154/include/esp_ieee802154_types.h b/components/ieee802154/include/esp_ieee802154_types.h new file mode 100644 index 0000000000..8c551f7552 --- /dev/null +++ b/components/ieee802154/include/esp_ieee802154_types.h @@ -0,0 +1,88 @@ +/* + * SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include +#include + +#define US_PER_SYMBLE 16 + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief The radio state types. + */ +typedef enum { + ESP_IEEE802154_RADIO_DISABLE, /*!< Radio not up */ + ESP_IEEE802154_RADIO_IDLE, /*!< Radio in the idle state */ + ESP_IEEE802154_RADIO_SLEEP, /*!< Radio in the sleep state */ + ESP_IEEE802154_RADIO_RECEIVE, /*!< Radio in the receive state */ + ESP_IEEE802154_RADIO_TRANSMIT, /*!< Radio in the transmit state */ +} esp_ieee802154_state_t; + +/** + * @brief The transmit error types. + */ +typedef enum { + ESP_IEEE802154_TX_ERR_NONE, /*!< No transmit error */ + ESP_IEEE802154_TX_ERR_CCA_BUSY, /*!< Channel is busy */ + ESP_IEEE802154_TX_ERR_ABORT, /*!< Transmit abort */ + ESP_IEEE802154_TX_ERR_NO_ACK, /*!< No Ack frame received until timeout */ + ESP_IEEE802154_TX_ERR_INVALID_ACK, /*!< Invalid Ack frame */ + ESP_IEEE802154_TX_ERR_COEXIST, /*!< Rejected by coexist system */ + ESP_IEEE802154_TX_ERR_SECURITY, /*!< Invalid security configuration */ +} esp_ieee802154_tx_error_t; + +/** + * @brief The CCA mode types. + */ +typedef enum { + ESP_IEEE802154_CCA_MODE_CARRIER, /*!< Carrier only */ + ESP_IEEE802154_CCA_MODE_ED, /*!< Energy Detect only */ + ESP_IEEE802154_CCA_MODE_CARRIER_OR_ED, /*!< Carrier or Energy Detect */ + ESP_IEEE802154_CCA_MODE_CARRIER_AND_ED, /*!< Carrier and Energy Detect */ +} esp_ieee802154_cca_mode_t; + +/** + * @brief The frame pending mode types. + */ +typedef enum { + ESP_IEEE802154_AUTO_PENDING_DISABLE, /*!< Frame pending bit always set to 1 in the ack to Data Request */ + ESP_IEEE802154_AUTO_PENDING_ENABLE, /*!< Frame pending bit set to 1 if src address matches, in the ack to Data Request */ + ESP_IEEE802154_AUTO_PENDING_ENHANCED, /*!< Frame pending bit set to 1 if src address matches, in all ack frames */ + ESP_IEEE802154_AUTO_PENDING_ZIGBEE, /*!< Frame pending bit set to 0 only if src address is short address and matches in table, in the ack to Data Request */ +} esp_ieee802154_pending_mode_t; + +/** +* @brief The four groups of mac filter interface index. +*/ +typedef enum { + ESP_IEEE802154_MULTIPAN_0 = 0, + ESP_IEEE802154_MULTIPAN_1 = 1, + ESP_IEEE802154_MULTIPAN_2 = 2, + ESP_IEEE802154_MULTIPAN_3 = 3, + ESP_IEEE802154_MULTIPAN_MAX +} esp_ieee802154_multipan_index_t; + +/** + * @brief The information of received 15.4 frame. + * + */ +typedef struct { + bool pending; /*!< The frame was acked with frame pending set */ + bool process; /*!< The frame needs to be processed by the upper layer */ + uint8_t channel; /*!< Channel */ + int8_t rssi; /*!< RSSI */ + uint8_t lqi; /*!< LQI */ + uint64_t timestamp; /*!< The timestamp when the frame's SFD field was received */ +} esp_ieee802154_frame_info_t; + +#ifdef __cplusplus +} +#endif diff --git a/components/ieee802154/lib/.gitlab-ci.yml b/components/ieee802154/lib/.gitlab-ci.yml new file mode 100755 index 0000000000..527ddb3a2a --- /dev/null +++ b/components/ieee802154/lib/.gitlab-ci.yml @@ -0,0 +1,31 @@ +stages: + - deploy + +push_master_to_github: + stage: deploy + tags: + - github_sync + only: + - master + - /^release\/v/ +# when: on_success + image: $CI_DOCKER_REGISTRY/esp32-ci-env + variables: + GIT_STRATEGY: clone + GITHUB_PUSH_REFS: refs/remotes/origin/release refs/remotes/origin/master + script: + - mkdir -p ~/.ssh + - chmod 700 ~/.ssh + - echo -n $GH_PUSH_KEY > ~/.ssh/id_rsa_base64 + - base64 --decode --ignore-garbage ~/.ssh/id_rsa_base64 > ~/.ssh/id_rsa + - chmod 600 ~/.ssh/id_rsa + - echo -e "Host github.com\n\tStrictHostKeyChecking no\n" >> ~/.ssh/config + - git remote add github git@github.com:espressif/esp-ieee802154-lib.git + # What the next line of script does: goes through the list of refs for all branches we push to github, + # generates a snippet of shell which is evaluated. The snippet checks CI_BUILD_REF against the SHA + # (aka objectname) at tip of each branch, and if any SHAs match then it checks out the local branch + # and then pushes that ref to a corresponding github branch + # + # NB: In gitlab 9.x, CI_BUILD_REF was deprecated. New name is CI_COMMIT_REF. If below command suddenly + # generates bash syntax errors, this is probably why. + - eval $(git for-each-ref --shell bash --format 'if [ $CI_BUILD_REF == %(objectname) ]; then git checkout -B %(refname:strip=3); git push --follow-tags github %(refname:strip=3); fi;' $GITHUB_PUSH_REFS) diff --git a/components/ieee802154/lib/LICENSE b/components/ieee802154/lib/LICENSE new file mode 100644 index 0000000000..d645695673 --- /dev/null +++ b/components/ieee802154/lib/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/components/ieee802154/lib/README.rst b/components/ieee802154/lib/README.rst new file mode 100644 index 0000000000..a1f1cf824c --- /dev/null +++ b/components/ieee802154/lib/README.rst @@ -0,0 +1,10 @@ +ESP IEEE 802.15.4 Libraries +==================== + +This repository contains binary libraries supporting the IEEE 802.15.4 subsystem. It is used as a submodule within `Espressif IoT Development Framework`_ (ESP-IDF). + +Files in this repository are Copyright (C) 2015-2021 Espressif Systems. + +These binary libraries are provided under the same license as the parent esp-idf project - the Apache License 2.0 as provided in the file LICENSE. (The license text refers to this as "Object" form.) + +.. _Espressif IoT Development Framework: https://github.com/espressif/esp-idf diff --git a/components/ieee802154/lib/esp32c6/lib802154.a b/components/ieee802154/lib/esp32c6/lib802154.a new file mode 100644 index 0000000000..aba5317e12 Binary files /dev/null and b/components/ieee802154/lib/esp32c6/lib802154.a differ diff --git a/components/ieee802154/lib/esp32h2/lib802154.a b/components/ieee802154/lib/esp32h2/lib802154.a new file mode 100644 index 0000000000..e8a72e9a95 Binary files /dev/null and b/components/ieee802154/lib/esp32h2/lib802154.a differ diff --git a/components/ieee802154/lib/esp32h2/rev1/lib802154.a b/components/ieee802154/lib/esp32h2/rev1/lib802154.a new file mode 100644 index 0000000000..1a65abc944 Binary files /dev/null and b/components/ieee802154/lib/esp32h2/rev1/lib802154.a differ diff --git a/components/ieee802154/lib/esp32h2/rev2/lib802154.a b/components/ieee802154/lib/esp32h2/rev2/lib802154.a new file mode 100644 index 0000000000..1387aef8cb Binary files /dev/null and b/components/ieee802154/lib/esp32h2/rev2/lib802154.a differ diff --git a/components/ieee802154/linker.lf b/components/ieee802154/linker.lf new file mode 100644 index 0000000000..8f57bdff95 --- /dev/null +++ b/components/ieee802154/linker.lf @@ -0,0 +1,62 @@ +[mapping:ieee802154] +archive: libieee802154.a +entries: + if IEEE802154_ENABLED = y: + # When adding static functions here, add IEEE802154_NOINLINE attribute to them + esp_ieee802154_ack: ieee802154_ack_config_pending_bit (noflash) + esp_ieee802154_dev: ieee802154_rx_frame_info_update (noflash) + esp_ieee802154_dev: ieee802154_isr (noflash) + esp_ieee802154_frame: is_dst_panid_present (noflash) + esp_ieee802154_frame: is_src_panid_present (noflash) + esp_ieee802154_frame: ieee802154_frame_security_header_offset (noflash) + esp_ieee802154_frame: ieee802154_frame_get_security_field_len (noflash) + esp_ieee802154_frame: ieee802154_frame_get_src_addr (noflash) + esp_ieee802154_frame: ieee802154_frame_get_security_payload_offset (noflash) + esp_ieee802154_pib: ieee802154_pib_get_pending_mode (noflash) + esp_ieee802154_pib: ieee802154_pib_get_rx_when_idle (noflash) + esp_ieee802154_sec: ieee802154_transmit_security_config (noflash) + esp_ieee802154_sec: ieee802154_sec_update (noflash) + esp_ieee802154_timer: ieee802154_timer0_set_threshold (noflash) + esp_ieee802154_timer: ieee802154_timer1_set_threshold (noflash) + esp_ieee802154_timer: ieee802154_timer0_start (noflash) + esp_ieee802154_timer: ieee802154_timer1_start (noflash) + esp_ieee802154_timer: ieee802154_timer0_stop (noflash) + esp_ieee802154_timer: ieee802154_timer1_stop (noflash) + esp_ieee802154_util: ieee802154_etm_channel_clear (noflash) + + if IEEE802154_DEBUG = y: + esp_ieee802154_debug (noflash) + + if IEEE802154_TIMING_OPTIMIZATION = y: + esp_ieee802154_dev: set_next_rx_buffer (noflash) + esp_ieee802154_dev: stop_rx (noflash) + esp_ieee802154_dev: stop_tx_ack (noflash) + esp_ieee802154_dev: stop_tx (noflash) + esp_ieee802154_dev: stop_cca (noflash) + esp_ieee802154_dev: stop_tx_cca (noflash) + esp_ieee802154_dev: stop_rx_ack (noflash) + esp_ieee802154_dev: stop_ed (noflash) + esp_ieee802154_dev: stop_current_operation (noflash) + esp_ieee802154_dev: is_target_time_expired (noflash) + esp_ieee802154_dev: ieee802154_transmit_at (noflash) + esp_ieee802154_dev: ieee802154_receive_at (noflash) + esp_ieee802154_dev: ieee802154_transmit (noflash) + esp_ieee802154_dev: ieee802154_receive (noflash) + esp_ieee802154_pib: ieee802154_pib_update (noflash) + esp_ieee802154_pib: ieee802154_txpower_convert (noflash) + esp_ieee802154_util: ieee802154_channel_to_freq (noflash) + esp_ieee802154: esp_ieee802154_transmit_at (noflash) + esp_ieee802154: esp_ieee802154_receive_at (noflash) + esp_ieee802154: esp_ieee802154_transmit (noflash) + esp_ieee802154: esp_ieee802154_receive (noflash) + + if OPENTHREAD_CSL_ENABLE = y || OPENTHREAD_LINK_METRICS = y: + esp_ieee802154: esp_ieee802154_enh_ack_generator (noflash) + esp_ieee802154: esp_ieee802154_get_extended_address (noflash) + esp_ieee802154: esp_ieee802154_set_transmit_security (noflash) + + if OPENTHREAD_LINK_METRICS = y: + esp_ieee802154: esp_ieee802154_get_recent_lqi (noflash) + esp_ieee802154: esp_ieee802154_get_recent_rssi (noflash) + esp_ieee802154_dev: ieee802154_get_recent_rssi (noflash) + esp_ieee802154_dev: ieee802154_get_recent_lqi (noflash) diff --git a/components/ieee802154/private_include/esp_ieee802154_ack.h b/components/ieee802154/private_include/esp_ieee802154_ack.h new file mode 100644 index 0000000000..2910a561b4 --- /dev/null +++ b/components/ieee802154/private_include/esp_ieee802154_ack.h @@ -0,0 +1,79 @@ +/* + * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include +#include +#include "sdkconfig.h" +#include "esp_err.h" +#include "esp_ieee802154_frame.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief The radio pending table, which is utilized to determine whether the received frame should be responded to with pending bit enabled. + */ + +#define IEEE802154_PENDING_TABLE_MASK_BITS (8) +#define IEEE802154_PENDING_TABLE_MASK_SIZE (((CONFIG_IEEE802154_PENDING_TABLE_SIZE - 1) / IEEE802154_PENDING_TABLE_MASK_BITS) + 1) +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 */ +} 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] 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_t ieee802154_add_pending_addr(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] 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_t ieee802154_clear_pending_addr(const uint8_t *addr, bool is_short); + +/** + * @brief Reset the pending table, only clear the mask bits for finishing the process quickly. + * + * @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); + +/** + * @brief Check whether the pending bit should be set or not in the ack frame. + * + * @param[in] frame The pointer to the received frame. + * + * @return + * - True The pending bit should be set, otherwise False. + * + */ +bool ieee802154_ack_config_pending_bit(const uint8_t *frame); + +#ifdef __cplusplus +} +#endif diff --git a/components/ieee802154/private_include/esp_ieee802154_dev.h b/components/ieee802154/private_include/esp_ieee802154_dev.h new file mode 100644 index 0000000000..04d6dc72ff --- /dev/null +++ b/components/ieee802154/private_include/esp_ieee802154_dev.h @@ -0,0 +1,254 @@ +/* + * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include +#include +#include "sdkconfig.h" +#include "esp_log.h" +#include "esp_err.h" +#include "soc/soc.h" +#include "esp_ieee802154_frame.h" +#include "esp_ieee802154.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// These three macros are in microseconds, used for transmit_at +#define IEEE802154_ED_TRIG_TX_RAMPUP_TIME_US 256 +#define IEEE802154_TX_RAMPUP_TIME_US 98 +#define IEEE802154_RX_RAMPUP_TIME_US 146 + +/** + * @brief The state of IEEE802154 radio process. + */ +typedef enum { + IEEE802154_STATE_DISABLE, /*!< IEEE802154 radio state disable */ + IEEE802154_STATE_IDLE, /*!< IEEE802154 radio state idle */ + IEEE802154_STATE_SLEEP, /*!< IEEE802154 radio state sleep */ + IEEE802154_STATE_RX, /*!< IEEE802154 radio state rx */ + IEEE802154_STATE_TX_ACK, /*!< IEEE802154 radio state tx ack */ + IEEE802154_STATE_TX_ENH_ACK, /*!< IEEE802154 radio state tx enh-ack */ + IEEE802154_STATE_TX_CCA, /*!< IEEE802154 radio state cca trigger tx */ + IEEE802154_STATE_TX, /*!< IEEE802154 radio state tx */ + IEEE802154_STATE_TEST_TX, /*!< IEEE802154 radio state test mode tx */ + IEEE802154_STATE_RX_ACK, /*!< IEEE802154 radio state rx ack */ + IEEE802154_STATE_ED, /*!< IEEE802154 radio state ED */ + IEEE802154_STATE_CCA, /*!< IEEE802154 radio state CCA */ +} ieee802154_state_t; + +/** + * @brief Initialize the clock of IEEE 802.15.4 subsystem. + * + */ +void ieee802154_enable(void); + +/** + * @brief Deinitialize the clock of IEEE 802.15.4 subsystem. + * + */ +void ieee802154_disable(void); + +/** + * @brief Enable the RF. + * + */ +void ieee802154_rf_enable(void); + +/** + * @brief Disable the RF. + * + */ +void ieee802154_rf_disable(void); +/** + * @brief Initialize the IEEE 802.15.4 MAC. + * + * @return + * - ESP_OK on success. + * - ESP_FAIL on failure. + * + */ +esp_err_t ieee802154_mac_init(void); + +/** + * @brief Deinitialize the IEEE 802.15.4 MAC. + * + * @return + * - ESP_OK on success. + * - ESP_FAIL on failure. + * + */ +esp_err_t ieee802154_mac_deinit(void); + +/** + * @brief Transmit the given frame. + * + * @param[in] frame The pointer to the frame + * @param[in] cca Perform CCA before transmission if it's true, otherwise transmit the frame directly. + * + * @return + * - ESP_OK on success. + * - ESP_ERR_INVALID_ARG on an invalid frame. + * - ESP_FAIL on failure due to invalid state. + * + */ +esp_err_t ieee802154_transmit(const uint8_t *frame, bool cca); + +/** + * @brief Set the IEEE 802.15.4 Radio to receive state. + * + * @return + * - ESP_OK on success + * - ESP_FAIL on failure due to invalid state. + * + */ +esp_err_t ieee802154_receive(void); + +/** + * @brief Notify the IEEE 802.15.4 Radio that the frame is handled done by upper layer. + * + * @param[in] frame The pointer to the frame which was passed from the function esp_ieee802154_receive_done. + * or ack frame from esp_ieee802154_transmit_done. + * + * @return + * - ESP_OK on success + * - ESP_FAIL if frame is invalid. + * + */ +esp_err_t ieee802154_receive_handle_done(const uint8_t* frame); + +/** + * @brief Transmit the given frame at a specific time. + * + * @param[in] frame The pointer to the frame. Refer to `esp_ieee802154_transmit()`. + * @param[in] cca Perform CCA before transmission if it's true, otherwise transmit the frame directly. + * @param[in] time A specific timestamp for starting transmission. + * + * @return + * - ESP_OK on success. + * - ESP_ERR_INVALID_ARG on an invalid frame. + * - ESP_FAIL on failure due to invalid state. + * + * Note: The transmit result will be reported via esp_ieee802154_transmit_done() + * or esp_ieee802154_transmit_failed(). + * + */ +esp_err_t ieee802154_transmit_at(const uint8_t *frame, bool cca, uint32_t time); + +/** + * @brief Set the IEEE 802.15.4 Radio to receive state at a specific time. + * + * + * @param[in] time A specific timestamp for starting receiving. + * @return + * - ESP_OK on success + * - ESP_FAIL on failure due to invalid state. + * + * Note: Radio will start receiving after the timestamp, and continue receiving until it receives a valid frame. + * Ref to esp_ieee802154_receive_done(). + * + */ +esp_err_t ieee802154_receive_at(uint32_t time); + +/** + * @brief Set the IEEE 802.15.4 Radio to sleep state. + * + * @return + * - ESP_OK on success. + * - ESP_FAIL on failure due to invalid state. + * + */ +esp_err_t ieee802154_sleep(void); + +/** + * @brief Perform energy detection(ED). + * + * @param[in] duration The duration of energy detection, in symbol unit (16 us). + * The result will be reported via esp_ieee802154_energy_detect_done(). + * + * @return + * - ESP_OK on success. + * - ESP_FAIL on failure due to invalid state. + * + */ +esp_err_t ieee802154_energy_detect(uint32_t duration); + +/** + * @brief Perform clear channel assessment(CCA). + * + * @return + * - ESP_OK on success. + * - ESP_FAIL on failure due to invalid state. + * + */ +esp_err_t ieee802154_cca(void); + +/** + * @brief Get the RSSI of the most recent received frame. + * + * @return The value of RSSI. + * + */ +int8_t ieee802154_get_recent_rssi(void); + +/** + * @brief Get the LQI of the most recent received frame. + * + * @return The value of LQI. + * + */ +uint8_t ieee802154_get_recent_lqi(void); + +/** + * @brief Get the IEEE 802.15.4 Radio state. + * + * @return + * - Current state of IEEE 802.15.4 Radio. + * + */ +ieee802154_state_t ieee802154_get_state(void); + +/** The following three functions are only used for internal test. **/ +/** + * @brief The clear channel assessment done. + * + * @param[in] channel_free True if the channel is clear, otherwise false. + * + */ +extern void esp_ieee802154_cca_done(bool channel_free); + +/** + * @brief Current receiving process is failed due to some reasons. + * + * @param[in] error The specific received failed reason. + * + */ +extern void esp_ieee802154_receive_failed(uint16_t error); + +/** + * @brief Current energy detection(ED) is failed due to some reasons. + * + * @param[in] error The specific ED failed reason. + * + */ +extern void esp_ieee802154_ed_failed(uint16_t error); + +#if CONFIG_IEEE802154_TEST +#define IEEE802154_STATIC +#define IEEE802154_INLINE +extern void esp_ieee802154_timer0_done(void); +extern void esp_ieee802154_timer1_done(void); +#else +#define IEEE802154_STATIC static +#define IEEE802154_INLINE inline +#endif // CONFIG_IEEE802154_TEST +#define IEEE802154_NOINLINE __attribute__((noinline)) + +#ifdef __cplusplus +} +#endif diff --git a/components/ieee802154/private_include/esp_ieee802154_frame.h b/components/ieee802154/private_include/esp_ieee802154_frame.h new file mode 100644 index 0000000000..497c1f7ee7 --- /dev/null +++ b/components/ieee802154/private_include/esp_ieee802154_frame.h @@ -0,0 +1,199 @@ +/* + * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include +#include +#include "esp_err.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define IEEE802154_FRAME_INVALID_OFFSET 0xff +#define IEEE802154_FRAME_INVALID_ADDR_MODE 0xff + +#define IEEE802154_FRAME_TYPE_OFFSET 1 +#define IEEE802154_FRAME_TYPE_MASK 0x07 +#define IEEE802154_FRAME_TYPE_BEACON 0x00 +#define IEEE802154_FRAME_TYPE_DATA 0x01 +#define IEEE802154_FRAME_TYPE_ACK 0x02 +#define IEEE802154_FRAME_TYPE_COMMAND 0x03 +#define IEEE802154_FRAME_TYPE_MULTIPURPOSE 0x05 +#define IEEE802154_FRAME_TYPE_FRAGMENT 0x06 +#define IEEE802154_FRAME_TYPE_EXTENDED 0x07 + +#define IEEE802154_FRAME_SECURITY_OFFSET 1 +#define IEEE802154_FRAME_SECURITY_BIT BIT(3) +#define IEEE802154_FRAME_SECURITY_MASK 0x07 +#define IEEE802154_FRAME_SECURITY_MIC_32 0x01 +#define IEEE802154_FRAME_SECURITY_MIC_64 0x02 +#define IEEE802154_FRAME_SECURITY_MIC_128 0x03 +#define IEEE802154_FRAME_SECURITY_ENC_MIC_32 0x05 +#define IEEE802154_FRAME_SECURITY_ENC_MIC_64 0x06 +#define IEEE802154_FRAME_SECURITY_ENC_MIC_128 0x07 +#define IEEE802154_FRAME_SECURITY_MIC_32_SIZE 4 +#define IEEE802154_FRAME_SECURITY_MIC_64_SIZE 8 +#define IEEE802154_FRAME_SECURITY_MIC_128_SIZE 16 + +#define IEEE802154_FRAME_KEY_ID_MODE_MASK 0x18 +#define IEEE802154_FRAME_KEY_ID_MODE_1 0x08 +#define IEEE802154_FRAME_KEY_ID_MODE_2 0x10 +#define IEEE802154_FRAME_KEY_ID_MODE_3 0x18 +#define IEEE802154_FRAME_KEY_ID_MODE_1_SIZE 1 +#define IEEE802154_FRAME_KEY_ID_MODE_2_SIZE 5 +#define IEEE802154_FRAME_KEY_ID_MODE_3_SIZE 9 + +#define IEEE802154_FRAME_COUNTER_SUPPRESS_BIT 0x20 +#define IEEE802154_FRAME_COUNTER_SIZE 4 + +#define IEEE802154_FRAME_AR_OFFSET 1 +#define IEEE802154_FRAME_AR_BIT BIT(5) + +#define IEEE802154_FRAME_PANID_COMP_OFFSET 1 +#define IEEE802154_FRAME_PANID_COMP_BIT BIT(6) + +#define IEEE802154_FRAME_VERSION_OFFSET 2 +#define IEEE802154_FRAME_VERSION_MASK 0x30 +#define IEEE802154_FRAME_VERSION_0 0x00 // IEEE 802.15.4 - 2003 +#define IEEE802154_FRAME_VERSION_1 0x10 // IEEE 802.15.4 - 2006 & 2011 +#define IEEE802154_FRAME_VERSION_2 0x20 // IEEE 802.15.4 - 2015 +#define IEEE802154_FRAME_VERSION_R 0x30 // Reserved + +#define IEEE802154_FRAME_DSN_OFFSET 2 +#define IEEE802154_FRAME_DSN_BIT BIT(0) +#define IEEE802154_FRAME_IE_OFFSET 2 +#define IEEE802154_FRAME_IE_BIT BIT(1) + +#define IEEE802154_FRAME_IE_HEAD_ID_MASK 0x3f80 +#define IEEE802154_IE_TYPE_HT2 0x3f80 +#define IEEE802154_FRAME_IE_SUBFIELD_LEN_MASK 0x007f +#define IEEE802154_FRAME_IE_HEAD_LEN 2 + +#define IEEE802154_FRAME_DST_MODE_OFFSET 2 +#define IEEE802154_FRAME_DST_MODE_MASK 0x0C +#define IEEE802154_FRAME_DST_MODE_NONE 0x00 +#define IEEE802154_FRAME_DST_MODE_SHORT 0x08 +#define IEEE802154_FRAME_DST_MODE_EXT 0x0C + +#define IEEE802154_FRAME_SRC_MODE_OFFSET 2 +#define IEEE802154_FRAME_SRC_MODE_MASK 0xC0 +#define IEEE802154_FRAME_SRC_MODE_NONE 0x00 +#define IEEE802154_FRAME_SRC_MODE_SHORT 0x80 +#define IEEE802154_FRAME_SRC_MODE_EXT 0xC0 + +#define IEEE802154_CMD_INVALID 0x00 +#define IEEE802154_CMD_DATA_REQ 0x04 + +#define IEEE802154_FRAME_PHR_SIZE 1 +#define IEEE802154_FRAME_FCF_SIZE 2 +#define IEEE802154_FRAME_FCS_SIZE 2 +#define IEEE802154_FRAME_DSN_SIZE 1 +#define IEEE802154_FRAME_PANID_SIZE 2 +#define IEEE802154_FRAME_SHORT_ADDR_SIZE 2 +#define IEEE802154_FRAME_EXT_ADDR_SIZE 8 +#define IEEE802154_FRAME_SE_HEAD_SIZE 1 +#define IEEE802154_FRAME_COMMAND_ID_LEN 1 + +/** + * @brief Get the frame type. + * + * @param[in] frame The pointer to the frame. + * + * @return + * - The type of the frame. + * + */ +uint8_t ieee802154_frame_get_type(const uint8_t *frame); + +/** + * @brief Get the frame version. + * + * @param[in] frame The pointer to the frame. + * + * @return + * - The version of the frame. + * + */ +uint8_t ieee802154_frame_get_version(const uint8_t *frame); + +/** + * @brief Is the frame ack required. + * + * @param[in] frame The pointer to the frame. + * + * @return + * - True if the frame is ack required, otherwise false. + * + */ +bool ieee802154_frame_is_ack_required(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. + * + * @return + * - IEEE802154_FRAME_DST_MODE_NONE if destination adress mode is none. + * - IEEE802154_FRAME_DST_MODE_SHORT if destination adress mode is short. + * - IEEE802154_FRAME_DST_MODE_EXT if destination adress mode is extended. + * + */ +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. + * + * @return + * - IEEE802154_FRAME_SRC_MODE_NONE if source adress mode is none. + * - IEEE802154_FRAME_SRC_MODE_SHORT if source adress mode is short. + * - IEEE802154_FRAME_SRC_MODE_EXT if source adress mode is extended. + * + */ +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. + * + * @return + * - The offset of the private payload + * + */ +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. + * + * @return + * - ESP_OK if destination PAN ID is present, otherwise ESP_FAIL. + * + */ +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. + * + * @return + * - ESP_OK if source PAN ID is present, otherwise ESP_FAIL. + * + */ +esp_err_t ieee802154_frame_get_src_panid(const uint8_t *frame, uint8_t *panid); +#ifdef __cplusplus +} +#endif diff --git a/components/ieee802154/private_include/esp_ieee802154_pib.h b/components/ieee802154/private_include/esp_ieee802154_pib.h new file mode 100644 index 0000000000..d26ea6b7d2 --- /dev/null +++ b/components/ieee802154/private_include/esp_ieee802154_pib.h @@ -0,0 +1,234 @@ +/* + * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include +#include +#include "hal/ieee802154_ll.h" +#include "esp_ieee802154_frame.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief The PAN information base(PIB) of IEEE802154 radio. + */ +typedef struct { + bool auto_ack_tx; /*!< A flag indicates auto-tx ack mode is enabled or not */ + bool auto_ack_rx; /*!< A flag indicates auto-rx ack mode is enabled or not */ + bool enhance_ack_tx; /*!< A flag indicates enh-ack timing mode is enabled or not */ + bool promiscuous; /*!< A flag indicates promiscuous mode is enabled or not */ + bool coordinator; /*!< A flag indicates the device is coordinator or not*/ + bool rx_when_idle; /*!< A flag indicates the device is rx on when idle or not */ + int8_t txpower; /*!< Tx power configuration */ + uint8_t channel; /*!< Channel configuration */ + ieee802154_ll_pending_mode_t pending_mode; /*!< Pending mode configuration */ + int8_t cca_threshold; /*!< CCA threshold */ + ieee802154_ll_cca_mode_t cca_mode; /*!< CCA mode */ +} ieee802154_pib_t; + +/** + * @brief Initialize the PAN information base(PIB) of IEEE802154 radio. + * + */ +void ieee802154_pib_init(void); + +/** + * @brief Update the PAN information base(PIB) of IEEE802154 radio. + * + */ +void ieee802154_pib_update(void); + +/** + * @brief Get the state of PIB, if is pending, the PIB should be updated to hardware. + * + * @return + * - True if the PIB is pending, otherwise false. + */ +bool ieee802154_pib_is_pending(void); + +/** + * @brief Set a specific channel to the PIB. + * + * @param[in] channel The channel. + * + */ +void ieee802154_pib_set_channel(uint8_t channel); + +/** + * @brief Get the channel from the PIB. + * + * @return + * - The channel has been set in the PIB. + */ +uint8_t ieee802154_pib_get_channel(void); + +/** + * @brief Set a specific transmission power to the PIB. + * + * @param[in] power The power. + * + */ +void ieee802154_pib_set_power(int8_t power); + +/** + * @brief Get the transmission power from the PIB. + * + * @return + * - The transmission power has been set in the PIB. + */ +int8_t ieee802154_pib_get_power(void); + +/** + * @brief Set the promiscuous mode to the PIB. + * + * @param[in] enable True for enabling the promiscuous mode, otherwise false. + * + */ +void ieee802154_pib_set_promiscuous(bool enable); + +/** + * @brief Get the promiscuous mode from the PIB. + * + * @return + * - The promiscuous mode has been set in the PIB. + */ +bool ieee802154_pib_get_promiscuous(void); + +/** + * @brief Set a specific CCA threshold to the PIB. + * + * @param[in] cca_threshold The CCA threshold. + * + */ +void ieee802154_pib_set_cca_threshold(int8_t cca_threshold); + +/** + * @brief Get the CCA threshold from the PIB. + * + * @return + * - The CCA threshold has been set in the PIB. + */ + int8_t ieee802154_pib_get_cca_threshold(void); + +/** + * @brief Set the CCA mode to the PIB. + * + * @param[in] cca_mode The CCA mode. + * + */ +void ieee802154_pib_set_cca_mode(ieee802154_ll_cca_mode_t cca_mode); + +/** + * @brief Get the CCA mode from the PIB. + * + * @return + * - The CCA mode has been set in the PIB. + */ +ieee802154_ll_cca_mode_t ieee802154_pib_get_cca_mode(void); + +/** + * @brief Configure the auto-ack transmission mode to the PIB. + * + * @param[in] enable True for enabling the auto-ack transmission mode, otherwise false. + * + */ +void ieee802154_pib_set_auto_ack_tx(bool enable); + +/** + * @brief Get the auto-ack transmission mode from the PIB. + * + * @return + * - The auto-ack transmission mode has been set in the PIB. + */ +bool ieee802154_pib_get_auto_ack_tx(void); + +/** + * @brief Configure the auto-ack receiving mode to the PIB. + * + * @param[in] enable True for enabling the auto-ack receiving mode, otherwise false. + * + */ +void ieee802154_pib_set_auto_ack_rx(bool enable); + +/** + * @brief Get the auto-ack receiving mode from the PIB. + * + * @return + * - The auto-ack receiving mode has been set in the PIB. + */ +bool ieee802154_pib_get_auto_ack_rx(void); + +/** + * @brief Configure the enh-ack timing mode to the PIB. + * + * @param[in] enable True for enabling the enh-ack timing mode, otherwise false. + * + */ +void ieee802154_pib_set_enhance_ack_tx(bool enable); + +/** + * @brief Get the enh-ack timing mode from the PIB. + * + * @return + * - The enh-ack timing mode has been set in the PIB. + */ +bool ieee802154_pib_get_enhance_ack_tx(void); + +/** + * @brief Configure this bit to the PIB to indicate the device is coordinator. + * + * @param[in] enable True for configuring the device coordinator, otherwise false. + * + */ +void ieee802154_pib_set_coordinator(bool enable); + +/** + * @brief Get the coordinator configuration of device from the PIB. + * + * @return + * - The coordinator configuration of device has been set in the PIB. + */ +bool ieee802154_pib_get_coordinator(void); + +/** + * @brief Configure the pending mode to the PIB. + * + * @param[in] pending_mode The pending mode. + * + */ +void ieee802154_pib_set_pending_mode(ieee802154_ll_pending_mode_t pending_mode); + +/** + * @brief Get the pending mode from the PIB. + * + * @return + * - The pending mode has been set in the PIB. + */ +ieee802154_ll_pending_mode_t ieee802154_pib_get_pending_mode(void); + +/** + * @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. + * + */ +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. + * + * @return + * - True for continuing to receive when the radio is going to enter ilde, otherwise false. + * + */ +bool ieee802154_pib_get_rx_when_idle(void); + +#ifdef __cplusplus +} +#endif diff --git a/components/ieee802154/private_include/esp_ieee802154_sec.h b/components/ieee802154/private_include/esp_ieee802154_sec.h new file mode 100644 index 0000000000..7c822a82da --- /dev/null +++ b/components/ieee802154/private_include/esp_ieee802154_sec.h @@ -0,0 +1,36 @@ +/* + * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include + +#define IEEE802154_SECURITY_ADDR_SIZE 8 +#define IEEE802154_SECURITY_KEY_SIZE 16 +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Configure the encryption of transmission. + * + * @param[in] frame The frame needs to be encrypted. + * @param[in] key The key using in the encryption process. + * @param[in] addr The address using in the encryption process. + * + */ +void ieee802154_transmit_security_config(uint8_t *frame, uint8_t *key, uint8_t *addr); + +/** + * @brief Update the encryption enabled configuration of the next transmission. + * + * + */ +void ieee802154_sec_update(void); + +#ifdef __cplusplus +} +#endif diff --git a/components/ieee802154/private_include/esp_ieee802154_timer.h b/components/ieee802154/private_include/esp_ieee802154_timer.h new file mode 100644 index 0000000000..aee1230720 --- /dev/null +++ b/components/ieee802154/private_include/esp_ieee802154_timer.h @@ -0,0 +1,84 @@ +/* + * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +#include "esp_log.h" +#include "esp_err.h" + +/** + * @brief Start the IEEE802154 MAC internal timer0. + * + */ +void ieee802154_timer0_start(void); + +/** + * @brief Stop the IEEE802154 MAC internal timer0. + * + */ +void ieee802154_timer0_stop(void); + +/** + * @brief Set the overflow threshold to the IEEE802154 MAC internal timer0. + * + * @param[in] value The threshold. + * + * @return + * ESP_OK if the threshold is valid. + * ESP_ERR_INVALID_ARG if the threshold is invalid. + * + */ +esp_err_t ieee802154_timer0_set_threshold(uint32_t value); + +/** + * @brief Get the current IEEE802154 MAC internal timer0 count. + * + * @return + * The timer0 count. + * + */ +uint32_t ieee802154_timer0_get_value(void); + +/** + * @brief Start the IEEE802154 MAC internal timer1. + * + */ +void ieee802154_timer1_start(void); + +/** + * @brief Stop the IEEE802154 MAC internal timer1. + * + */ +void ieee802154_timer1_stop(void); + +/** + * @brief Set the overflow threshold to the IEEE802154 MAC internal timer1. + * + * @param[in] value The threshold. + * + * @return + * ESP_OK if the threshold is valid. + * ESP_ERR_INVALID_ARG if the threshold is invalid. + * + */ +esp_err_t ieee802154_timer1_set_threshold(uint32_t value); + +/** + * @brief Get the current IEEE802154 MAC internal timer1 count. + * + * @return + * The timer1 count. + * + */ +uint32_t ieee802154_timer1_get_value(void); + +#ifdef __cplusplus +} +#endif diff --git a/components/ieee802154/private_include/esp_ieee802154_util.h b/components/ieee802154/private_include/esp_ieee802154_util.h new file mode 100644 index 0000000000..c1e843055a --- /dev/null +++ b/components/ieee802154/private_include/esp_ieee802154_util.h @@ -0,0 +1,330 @@ +/* + * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include +#include +#include "sdkconfig.h" +#include "soc/soc_caps.h" +#include "esp_ieee802154_dev.h" +#include "hal/ieee802154_ll.h" +#include "esp_timer.h" +#ifdef __cplusplus +extern "C" { +#endif + +#define IEEE802154_TAG "ieee802154" + +#if SOC_PM_MODEM_RETENTION_BY_REGDMA && CONFIG_FREERTOS_USE_TICKLESS_IDLE +#define IEEE802154_RF_ENABLE() ieee802154_rf_enable() +#define IEEE802154_RF_DISABLE() ieee802154_rf_disable() +#else +#define IEEE802154_RF_ENABLE() +#define IEEE802154_RF_DISABLE() +#endif // SOC_PM_MODEM_RETENTION_BY_REGDMA && CONFIG_FREERTOS_USE_TICKLESS_IDLE +#define IEEE802154_PROBE(a) do { \ + IEEE802154_RECORD_EVENT(a); \ + ieee802154_record_abort(a); \ + IEEE802154_TXRX_STATISTIC(a); \ + } while(0) + +#if CONFIG_IEEE802154_RECORD_EVENT +#define IEEE802154_ASSERT_RECORD_EVENT_SIZE CONFIG_IEEE802154_RECORD_EVENT_SIZE +#define IEEE802154_RECORD_EVENT(a) do { \ + g_ieee802154_probe.event[g_ieee802154_probe.event_index].event = a; \ + g_ieee802154_probe.event[g_ieee802154_probe.event_index].state = ieee802154_get_state(); \ + if (a == IEEE802154_EVENT_RX_ABORT) { \ + g_ieee802154_probe.event[g_ieee802154_probe.event_index].abort_reason.rx \ + = ieee802154_ll_get_rx_abort_reason(); \ + } else if (a == IEEE802154_EVENT_TX_ABORT) { \ + g_ieee802154_probe.event[g_ieee802154_probe.event_index].abort_reason.tx \ + = ieee802154_ll_get_tx_abort_reason(); \ + } \ + g_ieee802154_probe.event[g_ieee802154_probe.event_index++].timestamp = esp_timer_get_time(); \ + g_ieee802154_probe.event_index = (g_ieee802154_probe.event_index == IEEE802154_ASSERT_RECORD_EVENT_SIZE) ? \ + 0 : g_ieee802154_probe.event_index; \ + } while(0) + +/** + * @brief The table of recording IEEE802154 event command. + */ +typedef struct { + ieee802154_ll_events event; /*!< record current radio event */ + ieee802154_state_t state; /*!< record current radio state */ + union { + ieee802154_ll_rx_abort_reason_t rx; + ieee802154_ll_tx_abort_reason_t tx; + } abort_reason; /*!< record current radio abort reason */ + uint64_t timestamp; /*!< record timestamp*/ +} ieee802154_event_info_t; +#else +#define IEEE802154_RECORD_EVENT(a) +#endif // CONFIG_IEEE802154_RECORD_EVENT + +#if CONFIG_IEEE802154_RECORD_STATE +#define IEEE802154_ASSERT_RECORD_STATE_SIZE CONFIG_IEEE802154_RECORD_STATE_SIZE +#define ieee802154_set_state(a) do { s_ieee802154_state = a; \ + sprintf(g_ieee802154_probe.state[g_ieee802154_probe.state_index].line_str, "%d", __LINE__); \ + g_ieee802154_probe.state[g_ieee802154_probe.state_index].timestamp = esp_timer_get_time(); \ + g_ieee802154_probe.state[g_ieee802154_probe.state_index++].state = a; \ + g_ieee802154_probe.state_index = \ + (g_ieee802154_probe.state_index == IEEE802154_ASSERT_RECORD_STATE_SIZE) ? 0 : g_ieee802154_probe.state_index; \ + } while(0) + +/** + * @brief The table of recording IEEE802154 state command. + */ +typedef struct { + char line_str[5]; /*!< record which line in esp_ieee802154_dev.c changes the state */ + ieee802154_state_t state; /*!< record current radio state */ + uint64_t timestamp; /*!< record timestamp */ +} ieee802154_state_info_t; +#else +#define ieee802154_set_state(state) (s_ieee802154_state = state) +#endif // CONFIG_IEEE802154_RECORD_STATE + +#if CONFIG_IEEE802154_RECORD_CMD +#define IEEE802154_ASSERT_RECORD_CMD_SIZE CONFIG_IEEE802154_RECORD_CMD_SIZE +#define ieee802154_set_cmd(a) do { ieee802154_ll_set_cmd(a); \ + sprintf(g_ieee802154_probe.cmd[g_ieee802154_probe.cmd_index].line_str, "%d", __LINE__); \ + g_ieee802154_probe.cmd[g_ieee802154_probe.cmd_index].timestamp = esp_timer_get_time(); \ + g_ieee802154_probe.cmd[g_ieee802154_probe.cmd_index++].cmd = a; \ + g_ieee802154_probe.cmd_index = \ + (g_ieee802154_probe.cmd_index == IEEE802154_ASSERT_RECORD_CMD_SIZE) ? 0 : g_ieee802154_probe.cmd_index; \ + } while(0) + +/** + * @brief The table of recording IEEE802154 radio command. + */ +typedef struct { + char line_str[5]; /*!< record which line in esp_ieee802154_dev.c set the command */ + ieee802154_ll_cmd_t cmd; /*!< record current command */ + uint64_t timestamp; /*!< record timestamp */ +} ieee802154_cmd_info_t; +#else +#define ieee802154_set_cmd(cmd) ieee802154_ll_set_cmd(cmd) +#endif //CONFIG_IEEE802154_RECORD_CMD + +#if CONFIG_IEEE802154_RECORD_ABORT +#define IEEE802154_ASSERT_RECORD_ABORT_SIZE CONFIG_IEEE802154_RECORD_ABORT_SIZE +#define ieee802154_record_abort(a) do { \ + if (a == IEEE802154_EVENT_RX_ABORT) { \ + g_ieee802154_probe.abort[g_ieee802154_probe.abort_index].abort_reason.rx \ + = ieee802154_ll_get_rx_abort_reason(); \ + g_ieee802154_probe.abort[g_ieee802154_probe.abort_index].is_tx_abort = 0; \ + g_ieee802154_probe.abort[g_ieee802154_probe.abort_index++].timestamp = esp_timer_get_time(); \ + g_ieee802154_probe.abort_index = (g_ieee802154_probe.abort_index == IEEE802154_ASSERT_RECORD_ABORT_SIZE) ? \ + 0 : g_ieee802154_probe.abort_index; \ + } else if (a == IEEE802154_EVENT_TX_ABORT) { \ + g_ieee802154_probe.abort[g_ieee802154_probe.abort_index].abort_reason.tx \ + = ieee802154_ll_get_tx_abort_reason();\ + g_ieee802154_probe.abort[g_ieee802154_probe.abort_index].is_tx_abort = 1; \ + g_ieee802154_probe.abort[g_ieee802154_probe.abort_index++].timestamp = esp_timer_get_time(); \ + g_ieee802154_probe.abort_index = (g_ieee802154_probe.abort_index == IEEE802154_ASSERT_RECORD_ABORT_SIZE) ? \ + 0 : g_ieee802154_probe.abort_index; \ + } \ + } while(0) + +/** + * @brief The table of recording IEEE802154 radio abort. + */ +typedef struct { + bool is_tx_abort; /*!< record current abort type */ + union { + ieee802154_ll_rx_abort_reason_t rx; + ieee802154_ll_tx_abort_reason_t tx; + } abort_reason; /*!< record current radio abort reason */ + uint64_t timestamp; /*!< record timestamp*/ +} ieee802154_abort_info_t; +#else +#define ieee802154_record_abort(a) +#endif // CONFIG_IEEE802154_RECORD_ABORT + +/** + * @brief The table of recording IEEE802154 information. + */ +typedef struct { +#if CONFIG_IEEE802154_RECORD_EVENT + ieee802154_event_info_t event[IEEE802154_ASSERT_RECORD_EVENT_SIZE]; /*!< record radio event */ + uint8_t event_index; /*!< the index of event */ +#endif // CONFIG_IEEE802154_RECORD_EVENT +#if CONFIG_IEEE802154_RECORD_STATE + ieee802154_state_info_t state[IEEE802154_ASSERT_RECORD_STATE_SIZE]; /*!< record radio state */ + uint8_t state_index; /*!< the index of state */ +#endif // CONFIG_IEEE802154_RECORD_STATE +#if CONFIG_IEEE802154_RECORD_CMD + ieee802154_cmd_info_t cmd[IEEE802154_ASSERT_RECORD_CMD_SIZE]; /*!< record radio command */ + uint8_t cmd_index; /*!< the index of command */ +#endif // CONFIG_IEEE802154_RECORD_CMD +#if CONFIG_IEEE802154_RECORD_ABORT + ieee802154_abort_info_t abort[IEEE802154_ASSERT_RECORD_ABORT_SIZE]; /*!< record radio abort */ + uint8_t abort_index; /*!< the index of abort */ +#endif // CONFIG_IEEE802154_RECORD_ABORT +} ieee802154_probe_info_t; + +extern ieee802154_probe_info_t g_ieee802154_probe; + +#if CONFIG_IEEE802154_ASSERT +/** + * @brief This function print rich information, which is useful for debug. + * Only can be used when `IEEE802154_ASSERT` is enabled. + * + */ +void ieee802154_assert_print(void); +#define IEEE802154_ASSERT(a) do { \ + if(unlikely(!(a))) { \ + ieee802154_assert_print(); \ + assert(a); \ + } \ + } while (0) +#else // CONFIG_IEEE802154_ASSERT +#define IEEE802154_ASSERT(a) assert(a) +#endif // CONFIG_IEEE802154_ASSERT + +#if CONFIG_IEEE802154_TXRX_STATISTIC +typedef struct ieee802154_txrx_statistic{ + struct { + uint64_t nums; + uint64_t deferred_nums; + uint64_t done_nums; + struct { + uint64_t rx_ack_coex_break_nums; // IEEE802154_RX_ACK_ABORT_COEX_CNT_REG + uint64_t rx_ack_timeout_nums; // IEEE802154_RX_ACK_TIMEOUT_CNT_REG + uint64_t tx_coex_break_nums; // IEEE802154_TX_BREAK_COEX_CNT_REG + uint64_t tx_security_error_nums; // IEEE802154_TX_SECURITY_ERROR_CNT_REG + uint64_t cca_failed_nums; // IEEE802154_CCA_FAIL_CNT_REG + uint64_t cca_busy_nums; // IEEE802154_CCA_BUSY_CNT_REG + } abort; + } tx; + struct { + uint64_t done_nums; + struct { + uint64_t sfd_timeout_nums; // IEEE802154_SFD_TIMEOUT_CNT_REG + uint64_t crc_error_nums; // IEEE802154_CRC_ERROR_CNT_REG + uint64_t filter_fail_nums; // IEEE802154_RX_FILTER_FAIL_CNT_REG + uint64_t no_rss_nums; // IEEE802154_NO_RSS_DETECT_CNT_REG + uint64_t rx_coex_break_nums; // IEEE802154_RX_ABORT_COEX_CNT_REG + uint64_t rx_restart_nums; // IEEE802154_RX_RESTART_CNT_REG + uint64_t tx_ack_coex_break_nums; // IEEE802154_TX_ACK_ABORT_COEX_CNT_REG + uint64_t ed_abort_nums; // IEEE802154_ED_ABORT_CNT_REG + } abort; + } rx; +} ieee802154_txrx_statistic_t; + +#define IEEE802154_TXRX_STATISTIC_CLEAR() do { \ + ieee802154_txrx_statistic_clear();\ + } while(0) + +#define IEEE802154_TXRX_STATISTIC(a) do { \ + ieee802154_txrx_statistic(a);\ + } while(0) + +#define IEEE802154_TX_DEFERRED_NUMS_UPDATE() do { \ + ieee802154_tx_deferred_nums_update();\ + } while(0) + +#define IEEE802154_TX_NUMS_UPDATE() do { \ + ieee802154_tx_nums_update();\ + } while(0) + +#define IEEE802154_TX_BREAK_COEX_NUMS_UPDATE() do { \ + ieee802154_tx_break_coex_nums_update();\ + } while(0) + +void ieee802154_txrx_statistic_clear(void); +void ieee802154_txrx_statistic_print(void); +void ieee802154_txrx_statistic(ieee802154_ll_events events); +void ieee802154_tx_nums_update(void); +void ieee802154_tx_deferred_nums_update(void); +void ieee802154_tx_break_coex_nums_update(void); +#else +#define IEEE802154_TXRX_STATISTIC(a) +#define IEEE802154_TX_NUMS_UPDATE() +#define IEEE802154_TX_DEFERRED_NUMS_UPDATE() +#define IEEE802154_TXRX_STATISTIC_CLEAR() +#define IEEE802154_TX_BREAK_COEX_NUMS_UPDATE() +#endif // CONFIG_IEEE802154_TXRX_STATISTIC + +// TODO: replace etm code using common interface + +#define IEEE802154_ETM_CHANNEL0 0 +#define IEEE802154_ETM_CHANNEL1 1 + +/** + * @brief The scene of IEEE802154 radio coexistence. + */ +typedef enum { + IEEE802154_SCENE_IDLE, /*!< IEEE802154 radio coexistence scene IDLE */ + IEEE802154_SCENE_TX, /*!< IEEE802154 radio coexistence scene TX */ + IEEE802154_SCENE_RX, /*!< IEEE802154 radio coexistence scene RX */ + IEEE802154_SCENE_TX_AT, /*!< IEEE802154 radio coexistence scene TX AT */ + IEEE802154_SCENE_RX_AT, /*!< IEEE802154 radio coexistence scene RX AT */ +} ieee802154_txrx_scene_t; + +#if !CONFIG_IEEE802154_TEST && (CONFIG_ESP_COEX_SW_COEXIST_ENABLE || CONFIG_EXTERNAL_COEX_ENABLE) + +/** + * @brief Set the IEEE802154 radio coexistence scene during transmitting or receiving. + * + * @param[in] txrx_scene The scene of IEEE802154 radio coexistence. + * + */ +void ieee802154_set_txrx_pti(ieee802154_txrx_scene_t txrx_scene); + +#define IEEE802154_SET_TXRX_PTI(txrx_scene) ieee802154_set_txrx_pti(txrx_scene) + +#else + +#define IEEE802154_SET_TXRX_PTI(txrx_scene) + +#endif // !CONFIG_IEEE802154_TEST && CONFIG_ESP_COEX_SW_COEXIST_ENABLE || CONFIG_EXTERNAL_COEX_ENABLE + +/** + * @brief Convert the frequency to the index of channel. + * + * @param[in] freq The frequency where the radio is processing. + * + * @return + * The channel index. + * + */ +uint8_t ieee802154_freq_to_channel(uint8_t freq); + +/** + * @brief Convert the index of channel to the frequency. + * + * @param[in] channel The index of channel where the radio is processing. + * + * @return + * The frequency. + * + */ +uint8_t ieee802154_channel_to_freq(uint8_t channel); + +// TZ-97: implement these two functions using ETM common interface +/** + * @brief Configure the ETM module, using [channel] for monitoring the event, when event appears + * hardware will operate the [task]. + * + * @param[in] channel The ETM channel. + * @param[in] event The ETM event. + * @param[in] task The ETM task. + * + */ +void ieee802154_etm_set_event_task(uint32_t channel, uint32_t event, uint32_t task); + +/** + * @brief Clear the ETM module [channel]. + * + * @param[in] channel The ETM channel. + * + */ +void ieee802154_etm_channel_clear(uint32_t channel); + +#ifdef __cplusplus +} +#endif diff --git a/zephyr/esp32c6/CMakeLists.txt b/zephyr/esp32c6/CMakeLists.txt index 385fb919aa..82a4cfbf08 100644 --- a/zephyr/esp32c6/CMakeLists.txt +++ b/zephyr/esp32c6/CMakeLists.txt @@ -109,6 +109,9 @@ if(CONFIG_SOC_SERIES_ESP32C6) ../../components/wpa_supplicant/src/eap_peer ../../components/mbedtls/port/include + ../../components/ieee802154/include + ../../components/ieee802154/private_include + ../port/include/boot ) @@ -316,8 +319,8 @@ if(CONFIG_SOC_SERIES_ESP32C6) ../../components/hal/ledc_hal.c ) - ## shared WIFI/BT resources - if (CONFIG_BT OR CONFIG_WIFI_ESP32) + ## shared WIFI/BT/IEEE802154 resources + if (CONFIG_BT OR CONFIG_WIFI_ESP32 OR CONFIG_IEEE802154) zephyr_sources( ../../components/esp_phy/src/phy_init.c ../../components/esp_phy/src/lib_printf.c @@ -568,6 +571,30 @@ if(CONFIG_SOC_SERIES_ESP32C6) endif() + ## IEEE 802.15.4 definitions + if (CONFIG_IEEE802154) + zephyr_sources( + ../../components/esp_phy/src/btbb_init.c + ../../components/soc/${CONFIG_SOC_SERIES}/ieee802154_periph.c + ../../components/ieee802154/esp_ieee802154.c + ../../components/ieee802154/driver/esp_ieee802154_ack.c + ../../components/ieee802154/driver/esp_ieee802154_dev.c + ../../components/ieee802154/driver/esp_ieee802154_frame.c + ../../components/ieee802154/driver/esp_ieee802154_pib.c + ../../components/ieee802154/driver/esp_ieee802154_util.c + ../../components/ieee802154/driver/esp_ieee802154_sec.c + ../../components/ieee802154/driver/esp_ieee802154_timer.c + ) + + zephyr_compile_definitions(CONFIG_IEEE802154_ENABLED) + zephyr_compile_definitions(CONFIG_SOC_IEEE802154_SUPPORTED) + + zephyr_link_libraries( + btbb + -L${CMAKE_CURRENT_SOURCE_DIR}/../blobs/lib/${CONFIG_SOC_SERIES} + ) + endif() + zephyr_link_libraries_ifdef(CONFIG_NEWLIB_LIBC c) endif()