From 32c92aed88ba0b5d5b638ec72225974fdf481ee0 Mon Sep 17 00:00:00 2001 From: Zhou Xiao Date: Tue, 18 Mar 2025 12:53:34 +0800 Subject: [PATCH 1/7] change(ble): [AUTO_MR] Update lib_esp32c2 to 5d9a6661 (cherry picked from commit f1983020674fa86352a4eed92e8afdff76b8fc6b) Co-authored-by: Zhou Xiao --- components/bt/controller/lib_esp32c2/esp32c2-bt-lib | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/bt/controller/lib_esp32c2/esp32c2-bt-lib b/components/bt/controller/lib_esp32c2/esp32c2-bt-lib index 5518d3409b..3ce1675e0e 160000 --- a/components/bt/controller/lib_esp32c2/esp32c2-bt-lib +++ b/components/bt/controller/lib_esp32c2/esp32c2-bt-lib @@ -1 +1 @@ -Subproject commit 5518d3409be1c4cd2f06e22cf99353d4fe5cfc79 +Subproject commit 3ce1675e0e0154345819eb79793d53bea522b29a From b424d7bcb63b91ca11755a0653a894db653d2079 Mon Sep 17 00:00:00 2001 From: Zhou Xiao Date: Tue, 18 Mar 2025 12:53:37 +0800 Subject: [PATCH 2/7] feat(ble): support ble log simple output via SPI interface for ESP32-C2 (cherry picked from commit df829ac9195e3ad91ef6026f55eaf41a4846360f) Co-authored-by: Zhou Xiao --- components/bt/controller/esp32c2/bt.c | 201 ++++++++++++-------------- 1 file changed, 92 insertions(+), 109 deletions(-) diff --git a/components/bt/controller/esp32c2/bt.c b/components/bt/controller/esp32c2/bt.c index 18d8544644..392195f2df 100644 --- a/components/bt/controller/esp32c2/bt.c +++ b/components/bt/controller/esp32c2/bt.c @@ -61,11 +61,9 @@ #include "hal/efuse_ll.h" #include "soc/rtc.h" -#if CONFIG_BT_LE_CONTROLLER_LOG_ENABLED -#if CONFIG_BT_LE_CONTROLLER_LOG_SPI_OUT_ENABLED +#if CONFIG_BT_BLE_LOG_SPI_OUT_ENABLED #include "ble_log/ble_log_spi_out.h" -#endif // CONFIG_BT_LE_CONTROLLER_LOG_SPI_OUT_ENABLED -#endif // CONFIG_BT_LE_CONTROLLER_LOG_ENABLED +#endif // CONFIG_BT_BLE_LOG_SPI_OUT_ENABLED /* Macro definition ************************************************************************ @@ -115,7 +113,7 @@ struct ext_funcs_t { }; #if CONFIG_BT_LE_CONTROLLER_LOG_ENABLED -typedef void (*interface_func_t) (uint32_t len, const uint8_t*addr, bool end); +typedef void (*interface_func_t) (uint32_t len, const uint8_t *addr, uint32_t len_append, const uint8_t *addr_append, uint32_t flag); #endif // CONFIG_BT_LE_CONTROLLER_LOG_ENABLED /* External functions or variables @@ -125,8 +123,10 @@ extern int ble_osi_coex_funcs_register(struct osi_coex_funcs_t *coex_funcs); extern int coex_core_ble_conn_dyn_prio_get(bool *low, bool *high); extern int ble_controller_init(esp_bt_controller_config_t *cfg); #if CONFIG_BT_LE_CONTROLLER_LOG_ENABLED -extern int ble_log_init_async(interface_func_t bt_controller_log_interface, bool task_create, uint8_t buffers, uint32_t *bufs_size); +extern int ble_log_init_async(interface_func_t interface, bool task_create, uint8_t buffers, uint32_t *bufs_size); extern int ble_log_deinit_async(void); +extern int ble_log_init_simple(interface_func_t interface, void *handler); +extern void ble_log_deinit_simple(void); extern void ble_log_async_output_dump_all(bool output); extern void esp_panic_handler_feed_wdts(void); #endif // CONFIG_BT_LE_CONTROLLER_LOG_ENABLED @@ -195,10 +195,12 @@ static int esp_ecc_gen_key_pair(uint8_t *pub, uint8_t *priv); static int esp_ecc_gen_dh_key(const uint8_t *peer_pub_key_x, const uint8_t *peer_pub_key_y, const uint8_t *our_priv_key, uint8_t *out_dhkey); #if CONFIG_BT_LE_CONTROLLER_LOG_ENABLED -static void esp_bt_controller_log_interface(uint32_t len, const uint8_t *addr, bool end); +#if !CONFIG_BT_LE_CONTROLLER_LOG_SPI_OUT_ENABLED +static void esp_bt_controller_log_interface(uint32_t len, const uint8_t *addr, uint32_t len_append, const uint8_t *addr_append, uint32_t flag); +#endif // !CONFIG_BT_LE_CONTROLLER_LOG_SPI_OUT_ENABLED #if CONFIG_BT_LE_CONTROLLER_LOG_STORAGE_ENABLE static void esp_bt_ctrl_log_partition_get_and_erase_first_block(void); -#endif // #if CONFIG_BT_LE_CONTROLLER_LOG_STORAGE_ENABLE +#endif // CONFIG_BT_LE_CONTROLLER_LOG_STORAGE_ENABLE #endif // CONFIG_BT_LE_CONTROLLER_LOG_ENABLED /* Local variable definition *************************************************************************** @@ -208,50 +210,29 @@ void *g_ble_lll_rfmgmt_env_p; #endif /* Static variable declare */ static DRAM_ATTR esp_bt_controller_status_t ble_controller_status = ESP_BT_CONTROLLER_STATUS_IDLE; + #if CONFIG_BT_LE_CONTROLLER_LOG_ENABLED const static uint32_t log_bufs_size[] = {CONFIG_BT_LE_LOG_CTRL_BUF1_SIZE, CONFIG_BT_LE_LOG_HCI_BUF_SIZE, CONFIG_BT_LE_LOG_CTRL_BUF2_SIZE}; -enum log_out_mode { - LOG_DUMP_MEMORY, - LOG_ASYNC_OUT, - LOG_STORAGE_TO_FLASH, - LOG_SPI_OUT, -}; +static bool log_is_inited = false; -bool log_is_inited = false; -#if CONFIG_BT_LE_CONTROLLER_LOG_DUMP_ONLY -uint8_t log_output_mode = LOG_DUMP_MEMORY; -#else -#if CONFIG_BT_LE_CONTROLLER_LOG_STORAGE_ENABLE -uint8_t log_output_mode = LOG_STORAGE_TO_FLASH; -#elif CONFIG_BT_LE_CONTROLLER_LOG_SPI_OUT_ENABLED -uint8_t log_output_mode = LOG_SPI_OUT; -#else -uint8_t log_output_mode = LOG_ASYNC_OUT; -#endif // CONFIG_BT_LE_CONTROLLER_LOG_STORAGE_ENABLE -#endif // CONFIG_BT_LE_CONTROLLER_LOG_DUMP_ONLY - -void esp_bt_log_output_mode_set(uint8_t output_mode) +esp_err_t esp_bt_controller_log_init(void) { - log_output_mode = output_mode; -} - -uint8_t esp_bt_log_output_mode_get(void) -{ - return log_output_mode; -} - -esp_err_t esp_bt_controller_log_init(uint8_t log_output_mode) -{ - esp_err_t ret = ESP_OK; - interface_func_t bt_controller_log_interface; - bt_controller_log_interface = esp_bt_controller_log_interface; - bool task_create; - uint8_t buffers = 0; - if (log_is_inited) { - return ret; + return ESP_OK; } +#if CONFIG_BT_BLE_LOG_SPI_OUT_ENABLED + if (ble_log_spi_out_init() != 0) { + goto spi_out_init_failed; + } +#endif // CONFIG_BT_BLE_LOG_SPI_OUT_ENABLED + +#if CONFIG_BT_LE_CONTROLLER_LOG_SPI_OUT_ENABLED + if (ble_log_init_simple(ble_log_spi_out_ll_write, ble_log_spi_out_ll_log_ev_proc) != 0) { + goto log_init_failed; + } +#else // !CONFIG_BT_LE_CONTROLLER_LOG_SPI_OUT_ENABLED + uint8_t buffers = 0; #if CONFIG_BT_LE_CONTROLLER_LOG_CTRL_ENABLED buffers |= ESP_BLE_LOG_BUF_CONTROLLER; #endif // CONFIG_BT_LE_CONTROLLER_LOG_CTRL_ENABLED @@ -259,44 +240,41 @@ esp_err_t esp_bt_controller_log_init(uint8_t log_output_mode) buffers |= ESP_BLE_LOG_BUF_HCI; #endif // CONFIG_BT_LE_CONTROLLER_LOG_HCI_ENABLED - switch (log_output_mode) { - case LOG_DUMP_MEMORY: - task_create = false; - break; - case LOG_ASYNC_OUT: - case LOG_STORAGE_TO_FLASH: - task_create = true; -#if CONFIG_BT_LE_CONTROLLER_LOG_STORAGE_ENABLE - if (log_output_mode == LOG_STORAGE_TO_FLASH) { - esp_bt_ctrl_log_partition_get_and_erase_first_block(); - } -#endif // CONFIG_BT_LE_CONTROLLER_LOG_STORAGE_ENABLE - break; - case LOG_SPI_OUT: - task_create = true; -#if CONFIG_BT_LE_CONTROLLER_LOG_SPI_OUT_ENABLED - ble_log_spi_out_init(); - bt_controller_log_interface = ble_log_spi_out_write_esp; + bool task_create = true; +#if CONFIG_BT_LE_CONTROLLER_LOG_DUMP_ONLY + task_create = false; +#elif CONFIG_BT_LE_CONTROLLER_LOG_STORAGE_ENABLE + esp_bt_ctrl_log_partition_get_and_erase_first_block(); #endif // CONFIG_BT_LE_CONTROLLER_LOG_SPI_OUT_ENABLED - break; - default: - assert(0); - } - ret = ble_log_init_async(bt_controller_log_interface, task_create, buffers, (uint32_t *)log_bufs_size); - if (ret == ESP_OK) { - log_is_inited = true; + if (ble_log_init_async(esp_bt_controller_log_interface, task_create, buffers, (uint32_t *)log_bufs_size) != 0) { + goto log_init_failed; } +#endif // CONFIG_BT_LE_CONTROLLER_LOG_SPI_OUT_ENABLED - return ret; + log_is_inited = true; + return ESP_OK; + +log_init_failed: +#if CONFIG_BT_BLE_LOG_SPI_OUT_ENABLED + ble_log_spi_out_deinit(); +spi_out_init_failed: +#endif // CONFIG_BT_BLE_LOG_SPI_OUT_ENABLED + return ESP_FAIL; } -void esp_bt_ontroller_log_deinit(void) +void esp_bt_controller_log_deinit(void) { - ble_log_deinit_async(); -#if CONFIG_BT_LE_CONTROLLER_LOG_SPI_OUT_ENABLED +#if CONFIG_BT_BLE_LOG_SPI_OUT_ENABLED ble_log_spi_out_deinit(); -#endif +#endif // CONFIG_BT_BLE_LOG_SPI_OUT_ENABLED + +#if CONFIG_BT_LE_CONTROLLER_LOG_SPI_OUT_ENABLED + ble_log_deinit_simple(); +#else // !CONFIG_BT_LE_CONTROLLER_LOG_SPI_OUT_ENABLED + ble_log_deinit_async(); +#endif // CONFIG_BT_LE_CONTROLLER_LOG_SPI_OUT_ENABLED + log_is_inited = false; } @@ -391,7 +369,7 @@ void esp_bt_read_ctrl_log_from_flash(bool output) portENTER_CRITICAL_SAFE(&spinlock); esp_panic_handler_feed_wdts(); ble_log_async_output_dump_all(true); - esp_bt_ontroller_log_deinit(); + esp_bt_controller_log_deinit(); stop_write = true; buffer = (const uint8_t *)mapped_ptr; @@ -417,48 +395,53 @@ void esp_bt_read_ctrl_log_from_flash(bool output) esp_rom_printf(":DUMP_END]\r\n"); portEXIT_CRITICAL_SAFE(&spinlock); esp_partition_munmap(mmap_handle); - err = esp_bt_controller_log_init(log_output_mode); + err = esp_bt_controller_log_init(); assert(err == ESP_OK); } #endif // CONFIG_BT_LE_CONTROLLER_LOG_STORAGE_ENABLE -static void esp_bt_controller_log_interface(uint32_t len, const uint8_t *addr, bool end) -{ - if (log_output_mode == LOG_STORAGE_TO_FLASH) { -#if CONFIG_BT_LE_CONTROLLER_LOG_STORAGE_ENABLE - esp_bt_controller_log_storage(len, addr, end); -#endif //CONFIG_BT_LE_CONTROLLER_LOG_STORAGE_ENABLE - } else { - portMUX_TYPE spinlock = portMUX_INITIALIZER_UNLOCKED; - portENTER_CRITICAL_SAFE(&spinlock); - esp_panic_handler_feed_wdts(); - for (int i = 0; i < len; i++) { - esp_rom_printf("%02x ", addr[i]); - } - if (end) { - esp_rom_printf("\n"); - } - portEXIT_CRITICAL_SAFE(&spinlock); +#if !CONFIG_BT_LE_CONTROLLER_LOG_SPI_OUT_ENABLED +static void esp_bt_controller_log_interface(uint32_t len, const uint8_t *addr, uint32_t len_append, const uint8_t *addr_append, uint32_t flag) +{ + bool end = flag ? true : false; +#if CONFIG_BT_LE_CONTROLLER_LOG_STORAGE_ENABLE + esp_bt_controller_log_storage(len, addr, end); +#else // !CONFIG_BT_LE_CONTROLLER_LOG_STORAGE_ENABLE + portMUX_TYPE spinlock = portMUX_INITIALIZER_UNLOCKED; + portENTER_CRITICAL_SAFE(&spinlock); + esp_panic_handler_feed_wdts(); + for (int i = 0; i < len; i++) { + esp_rom_printf("%02x ", addr[i]); } + + if (end) { + esp_rom_printf("\n"); + } + portEXIT_CRITICAL_SAFE(&spinlock); +#endif // CONFIG_BT_LE_CONTROLLER_LOG_STORAGE_ENABLE } +#endif // !CONFIG_BT_LE_CONTROLLER_LOG_SPI_OUT_ENABLED void esp_ble_controller_log_dump_all(bool output) { - if (log_output_mode == LOG_STORAGE_TO_FLASH) { +#if CONFIG_BT_BLE_LOG_SPI_OUT_ENABLED + ble_log_spi_out_dump_all(); +#endif // CONFIG_BT_BLE_LOG_SPI_OUT_ENABLED + #if CONFIG_BT_LE_CONTROLLER_LOG_STORAGE_ENABLE - esp_bt_read_ctrl_log_from_flash(output); -#endif // CONFIG_BT_LE_CONTROLLER_LOG_STORAGE_ENABLE - } else { - portMUX_TYPE spinlock = portMUX_INITIALIZER_UNLOCKED; - portENTER_CRITICAL_SAFE(&spinlock); - esp_panic_handler_feed_wdts(); - BT_ASSERT_PRINT("\r\n[DUMP_START:"); - ble_log_async_output_dump_all(output); - BT_ASSERT_PRINT(":DUMP_END]\r\n"); - portEXIT_CRITICAL_SAFE(&spinlock); - } + esp_bt_read_ctrl_log_from_flash(output); +#elif !CONFIG_BT_LE_CONTROLLER_LOG_SPI_OUT_ENABLED + portMUX_TYPE spinlock = portMUX_INITIALIZER_UNLOCKED; + portENTER_CRITICAL_SAFE(&spinlock); + esp_panic_handler_feed_wdts(); + BT_ASSERT_PRINT("\r\n[DUMP_START:"); + ble_log_async_output_dump_all(output); + BT_ASSERT_PRINT(":DUMP_END]\r\n"); + portEXIT_CRITICAL_SAFE(&spinlock); +#endif } + #if CONFIG_BT_LE_CONTROLLER_LOG_TASK_WDT_USER_HANDLER_ENABLE void esp_task_wdt_isr_user_handler(void) { @@ -899,7 +882,7 @@ esp_err_t esp_bt_controller_init(esp_bt_controller_config_t *cfg) ESP_LOGI(NIMBLE_PORT_LOG_TAG, "ble rom commit:[%s]", r_ble_controller_get_rom_compile_version()); #if CONFIG_BT_LE_CONTROLLER_LOG_ENABLED - ret = esp_bt_controller_log_init(log_output_mode); + ret = esp_bt_controller_log_init(); if (ret != ESP_OK) { ESP_LOGW(NIMBLE_PORT_LOG_TAG, "ble_controller_log_init failed %d", ret); goto controller_init_err; @@ -948,7 +931,7 @@ free_controller: controller_sleep_deinit(); #if CONFIG_BT_LE_CONTROLLER_LOG_ENABLED controller_init_err: - esp_bt_ontroller_log_deinit(); + esp_bt_controller_log_deinit(); #endif // CONFIG_BT_LE_CONTROLLER_LOG_ENABLED ble_controller_deinit(); modem_deint: @@ -978,7 +961,7 @@ esp_err_t esp_bt_controller_deinit(void) controller_sleep_deinit(); #if CONFIG_BT_LE_CONTROLLER_LOG_ENABLED - esp_bt_ontroller_log_deinit(); + esp_bt_controller_log_deinit(); #endif // CONFIG_BT_LE_CONTROLLER_LOG_ENABLED ble_controller_deinit(); From d21703765be20ea616ce08ba642992686350fba5 Mon Sep 17 00:00:00 2001 From: Zhou Xiao Date: Tue, 18 Mar 2025 12:53:39 +0800 Subject: [PATCH 3/7] feat(ble): add enhanced connect function on ESP32-C2 (cherry picked from commit 71cea016948a2aa5779d07d475850eb373a9609c) Co-authored-by: zwl --- components/bt/controller/esp32c2/Kconfig.in | 30 +++++++++++++++++++ components/bt/controller/esp32c2/esp_bt_cfg.h | 26 ++++++++++++++++ .../bt/include/esp32c2/include/esp_bt.h | 5 ++++ .../esp32c2/ld/esp32c2.rom.ble-eco4.ld | 14 ++++----- .../esp_rom/esp32c2/ld/esp32c2.rom.ble.ld | 10 +++---- 5 files changed, 73 insertions(+), 12 deletions(-) diff --git a/components/bt/controller/esp32c2/Kconfig.in b/components/bt/controller/esp32c2/Kconfig.in index 7f456f2f88..53b18f7103 100644 --- a/components/bt/controller/esp32c2/Kconfig.in +++ b/components/bt/controller/esp32c2/Kconfig.in @@ -688,3 +688,33 @@ config BT_LE_CTRL_CHECK_CONNECT_IND_ACCESS_ADDRESS Enabling this option will add stricter verification of the Access Address in the CONNECT_IND PDU. This improves security by ensuring that only connection requests with valid Access Addresses are accepted. If disabled, only basic checks are applied, improving compatibility. + +menu "BLE disconnects when Instant Passed (0x28) occurs" + config BT_LE_CTRL_LLCP_CONN_UPDATE + bool "BLE ACL connection update procedure" + default n + help + If this option is enabled, Controller will terminate the connection + when Instant Passed (0x28) error occurs during connection update procedure. + + config BT_LE_CTRL_LLCP_CHAN_MAP_UPDATE + bool "BLE ACL channel map update procedure" + default n + help + If this option is enabled, Controller will terminate the connection + when Instant Passed (0x28) error occurs in channel map update procedure. + + config BT_LE_CTRL_LLCP_PHY_UPDATE + bool "BLE ACL PHY update procedure" + default n + help + If this option is enabled, Controller will terminate the connection + when Instant Passed (0x28) error occurs in PHY update procedure. +endmenu + +config BT_CTRL_SCAN_BACKOFF_UPPERLIMITMAX + int "The value of upperlimitmax during scan backoff procedure" + range 1 256 + default 32 + help + The value of upperlimitmax needs to be a power of 2. diff --git a/components/bt/controller/esp32c2/esp_bt_cfg.h b/components/bt/controller/esp32c2/esp_bt_cfg.h index a4e76ac863..c0e64563ba 100644 --- a/components/bt/controller/esp32c2/esp_bt_cfg.h +++ b/components/bt/controller/esp32c2/esp_bt_cfg.h @@ -226,6 +226,32 @@ extern "C" { #define DEFAULT_BT_LE_CTRL_CHECK_CONNECT_IND_ACCESS_ADDRESS (0) #endif +#ifdef CONFIG_BT_LE_CTRL_LLCP_CONN_UPDATE +#define BT_CTRL_BLE_LLCP_CONN_UPDATE (1<<0) +#else +#define BT_CTRL_BLE_LLCP_CONN_UPDATE (0<<0) +#endif + +#ifdef CONFIG_BT_LE_CTRL_LLCP_CHAN_MAP_UPDATE +#define BT_CTRL_BLE_LLCP_CHAN_MAP_UPDATE (1<<1) +#else +#define BT_CTRL_BLE_LLCP_CHAN_MAP_UPDATE (0<<1) +#endif + +#ifdef CONFIG_BT_LE_CTRL_LLCP_PHY_UPDATE +#define BT_CTRL_BLE_LLCP_PHY_UPDATE (1<<2) +#else +#define BT_CTRL_BLE_LLCP_PHY_UPDATE (0<<2) +#endif + +#define BT_LE_CTRL_LLCP_DISC_FLAG (BT_CTRL_BLE_LLCP_CONN_UPDATE | BT_CTRL_BLE_LLCP_CHAN_MAP_UPDATE | BT_CTRL_BLE_LLCP_PHY_UPDATE) + +#ifdef CONFIG_BT_CTRL_SCAN_BACKOFF_UPPERLIMITMAX +#define BT_CTRL_SCAN_BACKOFF_UPPERLIMITMAX (CONFIG_BT_CTRL_SCAN_BACKOFF_UPPERLIMITMAX) +#else +#define BT_CTRL_SCAN_BACKOFF_UPPERLIMITMAX (256) +#endif + #ifdef CONFIG_BT_LE_HCI_INTERFACE_USE_UART #define HCI_UART_EN CONFIG_BT_LE_HCI_INTERFACE_USE_UART #else diff --git a/components/bt/include/esp32c2/include/esp_bt.h b/components/bt/include/esp32c2/include/esp_bt.h index 1c752223e6..ff9713ffe4 100644 --- a/components/bt/include/esp32c2/include/esp_bt.h +++ b/components/bt/include/esp32c2/include/esp_bt.h @@ -234,6 +234,9 @@ typedef struct { uint8_t ignore_wl_for_direct_adv; /*!< Ignore the white list for directed advertising */ uint8_t csa2_select; /*!< Select CSA#2 */ uint8_t ble_aa_check; /*!< True if adds a verification step for the Access Address within the CONNECT_IND PDU; false otherwise. Configurable in menuconfig */ + uint8_t ble_llcp_disc_flag; /*!< Flag indicating whether the Controller disconnects after Instant Passed (0x28) error occurs. Configurable in menuconfig. + - The Controller does not disconnect after Instant Passed (0x28) by default. */ + uint16_t scan_backoff_upperlimitmax; /*!< The value of upperlimitmax is 2^n, The maximum value is 256 */ uint8_t vhci_enabled; /*!< VHCI mode is enabled */ uint32_t config_magic; /*!< Configuration magic value */ } esp_bt_controller_config_t; @@ -282,6 +285,8 @@ typedef struct { .ignore_wl_for_direct_adv = 0, \ .csa2_select = DEFAULT_BT_LE_50_FEATURE_SUPPORT, \ .ble_aa_check = DEFAULT_BT_LE_CTRL_CHECK_CONNECT_IND_ACCESS_ADDRESS, \ + .ble_llcp_disc_flag = BT_LE_CTRL_LLCP_DISC_FLAG, \ + .scan_backoff_upperlimitmax = BT_CTRL_SCAN_BACKOFF_UPPERLIMITMAX, \ .vhci_enabled = DEFAULT_BT_LE_VHCI_ENABLED, \ .config_magic = CONFIG_MAGIC, \ } diff --git a/components/esp_rom/esp32c2/ld/esp32c2.rom.ble-eco4.ld b/components/esp_rom/esp32c2/ld/esp32c2.rom.ble-eco4.ld index aa4fedcc1f..d4c81556cc 100644 --- a/components/esp_rom/esp32c2/ld/esp32c2.rom.ble-eco4.ld +++ b/components/esp_rom/esp32c2/ld/esp32c2.rom.ble-eco4.ld @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2021-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -257,7 +257,7 @@ r_ble_ll_conn_tx_pkt_in = 0x40000e4c; r_ble_ll_conn_update_eff_data_len = 0x40000e50; r_ble_ll_ctrl_chanmap_req_make = 0x40000e54; r_ble_ll_ctrl_chk_proc_start = 0x40000e58; -r_ble_ll_ctrl_conn_param_pdu_make = 0x40000e5c; +//r_ble_ll_ctrl_conn_param_pdu_make = 0x40000e5c; r_ble_ll_ctrl_conn_param_pdu_proc = 0x40000e60; r_ble_ll_ctrl_conn_param_reply = 0x40000e64; r_ble_ll_ctrl_conn_upd_make = 0x40000e68; @@ -284,7 +284,7 @@ r_ble_ll_ctrl_proc_unk_rsp = 0x40000eb8; r_ble_ll_ctrl_proc_with_instant_initiated = 0x40000ebc; r_ble_ll_ctrl_rej_ext_ind_make = 0x40000ec0; r_ble_ll_ctrl_reject_ind_send = 0x40000ec4; -r_ble_ll_ctrl_rx_chanmap_req = 0x40000ec8; +//r_ble_ll_ctrl_rx_chanmap_req = 0x40000ec8; r_ble_ll_ctrl_rx_conn_param_req = 0x40000ecc; //r_ble_ll_ctrl_rx_conn_param_rsp = 0x40000ed0; //r_ble_ll_ctrl_rx_conn_update = 0x40000ed4; @@ -298,7 +298,7 @@ r_ble_ll_ctrl_rx_pdu = 0x40000ef0; r_ble_ll_ctrl_rx_periodic_sync_ind = 0x40000ef4; r_ble_ll_ctrl_rx_phy_req = 0x40000ef8; r_ble_ll_ctrl_rx_phy_rsp = 0x40000efc; -r_ble_ll_ctrl_rx_phy_update_ind = 0x40000f00; +//r_ble_ll_ctrl_rx_phy_update_ind = 0x40000f00; r_ble_ll_ctrl_rx_ping_rsp = 0x40000f04; r_ble_ll_ctrl_rx_reject_ind = 0x40000f08; r_ble_ll_ctrl_rx_sca_req = 0x40000f0c; @@ -346,7 +346,7 @@ r_ble_ll_hci_cmd_rx = 0x40000fb0; r_ble_ll_hci_ctlr_bb_cmd_proc = 0x40000fb4; r_ble_ll_hci_deinit = 0x40000fb8; r_ble_ll_hci_disconnect = 0x40000fbc; -r_ble_ll_hci_env_init = 0x40000fc0; +//r_ble_ll_hci_env_init = 0x40000fc0; r_ble_ll_hci_ev_conn_update = 0x40000fc4; r_ble_ll_hci_ev_databuf_overflow = 0x40000fc8; r_ble_ll_hci_ev_datalen_chg = 0x40000fcc; @@ -805,7 +805,7 @@ r_ble_lll_scan_npl_store = 0x400016dc; r_ble_lll_scan_period_timer_cb = 0x400016e0; r_ble_lll_scan_process_adv_in_isr = 0x400016e4; r_ble_lll_scan_process_rsp_in_isr = 0x400016e8; -r_ble_lll_scan_req_backoff = 0x400016ec; +//r_ble_lll_scan_req_backoff = 0x400016ec; r_ble_lll_scan_restart = 0x400016f0; r_ble_lll_scan_rx_isr_on_aux = 0x400016f4; r_ble_lll_scan_rx_isr_on_legacy = 0x400016f8; @@ -1216,7 +1216,7 @@ r_ble_lll_scan_filter_out_useless_adv = 0x40002ff4; r_ble_hw_whitelist_check_in_wl = 0x40002ff8; r_ble_phy_stats_reset = 0x40002ffc; r_ble_phy_ramup_time_set = 0x40003000; -r_ble_lll_rfmgmt_should_skip_light_sleep_check = 0x40003004; +//r_ble_lll_rfmgmt_should_skip_light_sleep_check = 0x40003004; r_ble_phy_rx_err_record = 0x40003008; r_ble_lll_rfmgmt_wake_up_overhead_set = 0x4000300c; //r_ble_lll_conn_event_delete_and_reschedule = 0x40003010; diff --git a/components/esp_rom/esp32c2/ld/esp32c2.rom.ble.ld b/components/esp_rom/esp32c2/ld/esp32c2.rom.ble.ld index c4e201cc07..36ee9535be 100644 --- a/components/esp_rom/esp32c2/ld/esp32c2.rom.ble.ld +++ b/components/esp_rom/esp32c2/ld/esp32c2.rom.ble.ld @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2021-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -202,7 +202,7 @@ r_ble_ll_conn_sm_get = 0x40000e3c; r_ble_ll_conn_tx_pkt_in = 0x40000e4c; r_ble_ll_conn_update_eff_data_len = 0x40000e50; r_ble_ll_ctrl_chanmap_req_make = 0x40000e54; -r_ble_ll_ctrl_conn_param_pdu_make = 0x40000e5c; +//r_ble_ll_ctrl_conn_param_pdu_make = 0x40000e5c; r_ble_ll_ctrl_conn_param_pdu_proc = 0x40000e60; r_ble_ll_ctrl_conn_param_reply = 0x40000e64; r_ble_ll_ctrl_datalen_upd_make = 0x40000e6c; @@ -224,7 +224,7 @@ r_ble_ll_ctrl_proc_stop = 0x40000eb4; r_ble_ll_ctrl_proc_with_instant_initiated = 0x40000ebc; r_ble_ll_ctrl_rej_ext_ind_make = 0x40000ec0; r_ble_ll_ctrl_reject_ind_send = 0x40000ec4; -r_ble_ll_ctrl_rx_chanmap_req = 0x40000ec8; +//r_ble_ll_ctrl_rx_chanmap_req = 0x40000ec8; r_ble_ll_ctrl_rx_conn_param_req = 0x40000ecc; r_ble_ll_ctrl_rx_enc_req = 0x40000ed8; r_ble_ll_ctrl_rx_enc_rsp = 0x40000edc; @@ -234,7 +234,7 @@ r_ble_ll_ctrl_rx_pause_enc_rsp = 0x40000eec; r_ble_ll_ctrl_rx_periodic_sync_ind = 0x40000ef4; r_ble_ll_ctrl_rx_phy_req = 0x40000ef8; r_ble_ll_ctrl_rx_phy_rsp = 0x40000efc; -r_ble_ll_ctrl_rx_phy_update_ind = 0x40000f00; +//r_ble_ll_ctrl_rx_phy_update_ind = 0x40000f00; r_ble_ll_ctrl_rx_ping_rsp = 0x40000f04; r_ble_ll_ctrl_rx_reject_ind = 0x40000f08; r_ble_ll_ctrl_rx_sca_req = 0x40000f0c; @@ -636,7 +636,7 @@ r_ble_lll_scan_npl_restore = 0x400016d8; r_ble_lll_scan_npl_store = 0x400016dc; r_ble_lll_scan_period_timer_cb = 0x400016e0; r_ble_lll_scan_process_adv_in_isr = 0x400016e4; -r_ble_lll_scan_req_backoff = 0x400016ec; +//r_ble_lll_scan_req_backoff = 0x400016ec; r_ble_lll_scan_sched_next_aux = 0x40001700; r_ble_lll_scan_sched_remove = 0x40001704; r_ble_lll_scan_start = 0x40001708; From f3b25c4b34b1b9465d4c9dd97e712cda5e0e85e8 Mon Sep 17 00:00:00 2001 From: Zhou Xiao Date: Tue, 18 Mar 2025 12:53:41 +0800 Subject: [PATCH 4/7] fix(ble): fix ble log init failure mem leak for ESP32-C3 (cherry picked from commit 9ff9fb0661832393fccd30d411c5c8f1597204ae) Co-authored-by: Zhou Xiao --- components/bt/controller/esp32c3/bt.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/components/bt/controller/esp32c3/bt.c b/components/bt/controller/esp32c3/bt.c index 0722af7c78..5e7c4d3bf4 100644 --- a/components/bt/controller/esp32c3/bt.c +++ b/components/bt/controller/esp32c3/bt.c @@ -533,7 +533,7 @@ static void esp_bt_controller_log_interface(uint32_t len, const uint8_t *addr, b #if CONFIG_BT_CTRL_LE_LOG_SPI_OUT_EN static IRAM_ATTR void esp_bt_controller_spi_log_interface(uint32_t len, const uint8_t *addr, bool end) { - return ble_log_spi_out_write(BLE_LOG_SPI_OUT_SOURCE_ESP_LEGACY, addr, len); + ble_log_spi_out_write(BLE_LOG_SPI_OUT_SOURCE_ESP_LEGACY, addr, len); } #endif // CONFIG_BT_CTRL_LE_LOG_SPI_OUT_EN @@ -1776,7 +1776,10 @@ esp_err_t esp_bt_controller_init(esp_bt_controller_config_t *cfg) #endif #if CONFIG_BT_BLE_LOG_SPI_OUT_ENABLED - ble_log_spi_out_init(); + if (ble_log_spi_out_init() != 0) { + ESP_LOGE(BT_LOG_TAG, "BLE Log SPI output init failed"); + goto error; + } #endif // CONFIG_BT_BLE_LOG_SPI_OUT_ENABLED periph_module_enable(PERIPH_BT_MODULE); @@ -1804,6 +1807,10 @@ esp_err_t esp_bt_controller_init(esp_bt_controller_config_t *cfg) error: +#if CONFIG_BT_BLE_LOG_SPI_OUT_ENABLED + ble_log_spi_out_deinit(); +#endif // CONFIG_BT_BLE_LOG_SPI_OUT_ENABLED + bt_controller_deinit_internal(); return err; From a72a99dae594c923a58a221ce79412191f7650cb Mon Sep 17 00:00:00 2001 From: Zhou Xiao Date: Tue, 18 Mar 2025 12:53:43 +0800 Subject: [PATCH 5/7] fix(ble): fix ble log init failure mem leak for ESP32 (cherry picked from commit bb9dc5a92722c90000a48fb7922873ff0fafd0cf) Co-authored-by: Zhou Xiao --- components/bt/controller/esp32/bt.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/components/bt/controller/esp32/bt.c b/components/bt/controller/esp32/bt.c index b6a919cfb8..92ac149992 100644 --- a/components/bt/controller/esp32/bt.c +++ b/components/bt/controller/esp32/bt.c @@ -1743,7 +1743,10 @@ esp_err_t esp_bt_controller_init(esp_bt_controller_config_t *cfg) #endif #if CONFIG_BT_BLE_LOG_SPI_OUT_ENABLED - ble_log_spi_out_init(); + if (ble_log_spi_out_init() != 0) { + ESP_LOGE(BTDM_LOG_TAG, "BLE Log SPI output init failed"); + goto error; + } #endif // CONFIG_BT_BLE_LOG_SPI_OUT_ENABLED btdm_cfg_mask = btdm_config_mask_load(); @@ -1762,6 +1765,10 @@ esp_err_t esp_bt_controller_init(esp_bt_controller_config_t *cfg) error: +#if CONFIG_BT_BLE_LOG_SPI_OUT_ENABLED + ble_log_spi_out_deinit(); +#endif // CONFIG_BT_BLE_LOG_SPI_OUT_ENABLED + bt_controller_deinit_internal(); return err; From 9ac3dcf07d0614f686135e6f781b7cded930ff8e Mon Sep 17 00:00:00 2001 From: Zhou Xiao Date: Thu, 20 Mar 2025 09:48:35 +0800 Subject: [PATCH 6/7] feat(ble): support ble log simple output via SPI interface --- components/bt/common/Kconfig.in | 47 +- .../bt/common/ble_log/ble_log_spi_out.c | 993 +++++++++++++----- .../ble_log/include/ble_log/ble_log_spi_out.h | 15 +- 3 files changed, 776 insertions(+), 279 deletions(-) diff --git a/components/bt/common/Kconfig.in b/components/bt/common/Kconfig.in index 13e745219c..c4ce35ef90 100644 --- a/components/bt/common/Kconfig.in +++ b/components/bt/common/Kconfig.in @@ -8,9 +8,18 @@ config BT_ALARM_MAX_NUM config BT_BLE_LOG_SPI_OUT_ENABLED bool "Output ble logs to SPI bus (Experimental)" default n + select SPI_MASTER_IN_IRAM help Output ble logs to SPI bus +config BT_BLE_LOG_SPI_OUT_UL_TASK_BUF_SIZE + int "SPI transaction buffer size for upper layer task logs" + depends on BT_BLE_LOG_SPI_OUT_ENABLED + default 512 + help + SPI transaction buffer size for upper layer task logs. + There will be 2 SPI DMA buffers with the same size. + config BT_BLE_LOG_SPI_OUT_HCI_ENABLED bool "Enable HCI log output to SPI" depends on BT_BLE_LOG_SPI_OUT_ENABLED @@ -26,51 +35,61 @@ config BT_BLE_LOG_SPI_OUT_HOST_ENABLED This configuration applies to the logs of both Bluedroid Host and NimBLE Host. When BLE SPI log output is enabled, this option allows host logs to be transmitted via SPI. -config BT_BLE_LOG_SPI_OUT_QUEUE_SIZE - int "Number of ble log async SPI output queues" +config BT_BLE_LOG_SPI_OUT_LL_ENABLED + bool "Enable Controller log output to SPI" depends on BT_BLE_LOG_SPI_OUT_ENABLED - default 4 + depends on BT_LE_CONTROLLER_LOG_SPI_OUT_ENABLED + default n help - The number of ble log async SPI output queues + Enable controller log output to SPI bus. -config BT_BLE_LOG_SPI_OUT_TRANS_BUF_SIZE - int "Size of ble log async SPI output transaction buffer size" - depends on BT_BLE_LOG_SPI_OUT_ENABLED - default 2048 +config BT_BLE_LOG_SPI_OUT_LL_TASK_BUF_SIZE + int "SPI transaction buffer size for lower layer task logs" + depends on BT_BLE_LOG_SPI_OUT_LL_ENABLED + default 1024 help - The size of ble log async SPI output transaction buffer size + SPI transaction buffer size for upper layer task logs. + There will be 2 SPI DMA buffers with the same size. + +config BT_BLE_LOG_SPI_OUT_LL_ISR_BUF_SIZE + int "SPI transaction buffer size for lower layer ISR logs" + depends on BT_BLE_LOG_SPI_OUT_LL_ENABLED + default 512 + help + SPI transaction buffer size for upper layer ISR logs. + There will be 2 SPI DMA buffers with the same size. config BT_BLE_LOG_SPI_OUT_MOSI_IO_NUM int "GPIO number of SPI MOSI" depends on BT_BLE_LOG_SPI_OUT_ENABLED default 0 help - GPIO number of SPI MOSI + GPIO number of SPI MOSI config BT_BLE_LOG_SPI_OUT_SCLK_IO_NUM int "GPIO number of SPI SCLK" depends on BT_BLE_LOG_SPI_OUT_ENABLED default 1 help - GPIO number of SPI SCLK + GPIO number of SPI SCLK config BT_BLE_LOG_SPI_OUT_CS_IO_NUM int "GPIO number of SPI CS" depends on BT_BLE_LOG_SPI_OUT_ENABLED default 2 help - GPIO number of SPI CS + GPIO number of SPI CS config BT_BLE_LOG_SPI_OUT_TS_SYNC_ENABLED bool "Enable ble log & logic analyzer log time sync" depends on BT_BLE_LOG_SPI_OUT_ENABLED default y help - Enable ble log & logic analyzer log time sync + Enable ble log & logic analyzer log time sync config BT_BLE_LOG_SPI_OUT_SYNC_IO_NUM int "GPIO number of SYNC IO" depends on BT_BLE_LOG_SPI_OUT_TS_SYNC_ENABLED default 3 help - GPIO number of SYNC IO + GPIO number of SYNC IO diff --git a/components/bt/common/ble_log/ble_log_spi_out.c b/components/bt/common/ble_log/ble_log_spi_out.c index 4524f355f0..cdf498dc9e 100644 --- a/components/bt/common/ble_log/ble_log_spi_out.c +++ b/components/bt/common/ble_log/ble_log_spi_out.c @@ -8,186 +8,575 @@ #if CONFIG_BT_BLE_LOG_SPI_OUT_ENABLED // Private defines +#define BLE_LOG_TAG "BLE_LOG" #define SPI_OUT_BUS SPI2_HOST -#define SPI_OUT_TAIL 0xAA +#define SPI_OUT_MAX_TRANSFER_SIZE 10240 +#define SPI_OUT_FRAME_HEAD_LEN 4 +#define SPI_OUT_FRAME_TAIL 0xAA +#define SPI_OUT_FRAME_TAIL_LEN 1 +#define SPI_OUT_FRAME_OVERHEAD (SPI_OUT_FRAME_HEAD_LEN + SPI_OUT_FRAME_TAIL_LEN) +#define SPI_OUT_RECYCLE_TIMEOUT 1000 +#define SPI_OUT_TRANS_CB_FLAG_AVAILABLE 0 +#define SPI_OUT_TRANS_CB_FLAG_NEED_QUEUE 1 +#define SPI_OUT_TRANS_CB_FLAG_IN_QUEUE 2 #define SPI_OUT_FLUSHOUT_TIMEOUT (1000 * 1000) -#define SPI_OUT_TS_SYNC_TIMEOUT (1000 * 1000) - -// Private typedefs -typedef struct spi_out_trans { - spi_transaction_t trans; - struct spi_out_trans *next; -} spi_out_trans_t; - -// Private variables -static spi_device_handle_t spi_handle = NULL; -static spi_out_trans_t *trans_head = NULL; -static SemaphoreHandle_t mutex_handle = NULL; -static bool spi_out_inited = false; -static esp_timer_handle_t flushout_timer_handle = NULL; -static uint32_t loss_frame_cnt = 0; +#define SPI_OUT_PACKET_LOSS_UL 0 +#define SPI_OUT_PACKET_LOSS_LL_TASK 1 +#define SPI_OUT_PACKET_LOSS_LL_ISR 2 +#define SPI_OUT_PACKET_LOSS_FRAME_SIZE 6 +#define BLE_LOG_INTERFACE_FLAG_IN_ISR (1 << 3) #if CONFIG_BT_BLE_LOG_SPI_OUT_TS_SYNC_ENABLED -static bool sync_io_level = false; -static esp_timer_handle_t ts_sync_timer_handle = NULL; +#define SPI_OUT_TS_SYNC_TIMEOUT (1000 * 1000) #endif // CONFIG_BT_BLE_LOG_SPI_OUT_TS_SYNC_ENABLED -// Private function declarations -static void spi_out_init_trans(void); -static void spi_out_deinit_trans(void); -static void spi_out_recycle_trans(uint32_t ms_to_wait); -static void spi_out_append_trans(void); -static int spi_out_write(const uint8_t *addr, uint16_t len); -static void esp_timer_cb_flushout(void); -static void esp_timer_cb_ts_sync(void); +// Private typedefs +typedef struct { + // CRITICAL: 0 for available, 1 for need queue (ISR), 2 for in queue + // This flag is for multithreading, must be a word, do not modify + volatile uint32_t flag; + uint16_t buf_size; + uint16_t length; + spi_transaction_t trans; +} spi_out_trans_cb_t; + +typedef struct { + spi_out_trans_cb_t *trans_cb[2]; + uint8_t trans_cb_idx; + uint8_t frame_cnt; + uint32_t bytes_loss_cnt; + uint8_t trans_loss_cnt; +} spi_out_log_cb_t; + +// Private variables +static bool spi_out_inited = false; +static spi_device_handle_t spi_handle = NULL; +static bool timer_enabled = true; + +static bool ul_log_inited = false; +static SemaphoreHandle_t ul_log_mutex = NULL; +static spi_out_log_cb_t *ul_log_cb = NULL; +static esp_timer_handle_t ul_log_flushout_timer = NULL; + +#if CONFIG_BT_BLE_LOG_SPI_OUT_LL_ENABLED +static bool ll_log_inited = false; +static bool ll_log_need_flushout = false; +static spi_out_log_cb_t *ll_task_log_cb = NULL; +static spi_out_log_cb_t *ll_isr_log_cb = NULL; +static esp_timer_handle_t ll_log_flushout_timer = NULL; +#endif // BT_BLE_LOG_SPI_OUT_LL_ENABLED #if CONFIG_BT_BLE_LOG_SPI_OUT_TS_SYNC_ENABLED -#if defined(CONFIG_IDF_TARGET_ESP32H2) || defined(CONFIG_IDF_TARGET_ESP32C6) +static bool ts_sync_inited = false; +static bool sync_io_level = false; +static esp_timer_handle_t ts_sync_timer = NULL; +#endif // CONFIG_BT_BLE_LOG_SPI_OUT_TS_SYNC_ENABLED + +// Extern function declarations +extern void esp_panic_handler_feed_wdts(void); + +// Private function declarations +static int spi_out_init_trans(spi_out_trans_cb_t **trans_cb, uint16_t buf_size); +static void spi_out_deinit_trans(spi_out_trans_cb_t **trans_cb); +static void spi_out_tx_done_cb(spi_transaction_t *ret_trans); +static inline int spi_out_append_trans(spi_out_trans_cb_t *trans_cb); + +static int spi_out_log_cb_init(spi_out_log_cb_t **log_cb, uint16_t buf_size); +static void spi_out_log_cb_deinit(spi_out_log_cb_t **log_cb); +static inline int spi_out_log_cb_check_trans(spi_out_log_cb_t *log_cb, uint16_t len); +static inline void spi_out_log_cb_append_trans(spi_out_log_cb_t *log_cb, bool in_isr); +static inline void spi_out_log_cb_flush_trans(spi_out_log_cb_t *log_cb); +static void spi_out_log_cb_write(spi_out_log_cb_t *log_cb, const uint8_t *addr, uint16_t len, \ + const uint8_t *addr_append, uint16_t len_append, uint8_t source); +static inline void spi_out_log_cb_write_packet_loss(spi_out_log_cb_t *log_cb, uint8_t flag); +static void spi_out_log_cb_dump(spi_out_log_cb_t *log_cb); + +static int spi_out_ul_log_init(void); +static void spi_out_ul_log_deinit(void); +static void esp_timer_cb_ul_log_flushout(void); + +#if CONFIG_BT_BLE_LOG_SPI_OUT_LL_ENABLED +static int spi_out_ll_log_init(void); +static void spi_out_ll_log_deinit(void); +static void spi_out_ll_log_ev_proc(void); +static void esp_timer_cb_ll_log_flushout(void); + +#if defined(CONFIG_IDF_TARGET_ESP32H2) || defined(CONFIG_IDF_TARGET_ESP32C6) || defined(CONFIG_IDF_TARGET_ESP32C5) ||\ + defined(CONFIG_IDF_TARGET_ESP32C61) || defined(CONFIG_IDF_TARGET_ESP32H21) +extern void r_ble_log_simple_put_ev(void); +#define BLE_LOG_LL_PUT_EV r_ble_log_simple_put_ev() +#elif defined(CONFIG_IDF_TARGET_ESP32C2) +extern void ble_log_simple_put_ev(void); +#define BLE_LOG_LL_PUT_EV ble_log_simple_put_ev() +#else +#define BLE_LOG_LL_PUT_EV +#endif + +#endif // CONFIG_BT_BLE_LOG_SPI_OUT_LL_ENABLED + +#if CONFIG_BT_BLE_LOG_SPI_OUT_TS_SYNC_ENABLED +static int spi_out_ts_sync_init(void); +static void spi_out_ts_sync_deinit(void); +static void esp_timer_cb_ts_sync(void); + +#if defined(CONFIG_IDF_TARGET_ESP32H2) || defined(CONFIG_IDF_TARGET_ESP32C6) || defined(CONFIG_IDF_TARGET_ESP32C5) ||\ + defined(CONFIG_IDF_TARGET_ESP32C61) || defined(CONFIG_IDF_TARGET_ESP32H21) extern uint32_t r_ble_lll_timer_current_tick_get(void); -#endif // CONFIG_IDF_TARGET_ESP32H2 || CONFIG_IDF_TARGET_ESP32C6 -#if defined(CONFIG_IDF_TARGET_ESP32C2) +#define SPI_OUT_GET_LC_TIME r_ble_lll_timer_current_tick_get() +#elif defined(CONFIG_IDF_TARGET_ESP32C2) extern uint32_t r_os_cputime_get32(void); -#endif // CONFIG_IDF_TARGET_ESP32C2 +#define SPI_OUT_GET_LC_TIME r_os_cputime_get32() +#else +#define SPI_OUT_GET_LC_TIME 0 +#endif + #endif // CONFIG_BT_BLE_LOG_SPI_OUT_TS_SYNC_ENABLED // Private functions -static void spi_out_init_trans(void) +static int spi_out_init_trans(spi_out_trans_cb_t **trans_cb, uint16_t buf_size) { - for (int i = 0; i < CONFIG_BT_BLE_LOG_SPI_OUT_QUEUE_SIZE; i++) { - // Allocate memory for SPI transaction - uint8_t *buf = (uint8_t *)heap_caps_malloc(CONFIG_BT_BLE_LOG_SPI_OUT_TRANS_BUF_SIZE, MALLOC_CAP_DMA); - assert(buf); - - // Initialize new trans - spi_out_trans_t *new_trans = (spi_out_trans_t *)malloc(sizeof(spi_out_trans_t)); - assert(new_trans); - memset(new_trans, 0, sizeof(spi_out_trans_t)); - new_trans->trans.tx_buffer = buf; - new_trans->trans.length = 0; - - // Append new trans to free trans list - new_trans->next = trans_head; - trans_head = new_trans; + // Memory allocations + *trans_cb = (spi_out_trans_cb_t *)malloc(sizeof(spi_out_trans_cb_t)); + if (!(*trans_cb)) { + return -1; } + uint8_t *buf = (uint8_t *)heap_caps_malloc(buf_size, MALLOC_CAP_DMA); + if (!buf) { + free(*trans_cb); + return -1; + } + + // Initialization + memset(*trans_cb, 0, sizeof(spi_out_trans_cb_t)); + (*trans_cb)->buf_size = buf_size; + (*trans_cb)->trans.tx_buffer = buf; + return 0; +} + +static void spi_out_deinit_trans(spi_out_trans_cb_t **trans_cb) +{ + if (!(*trans_cb)) { + return; + } + + free((uint8_t *)(*trans_cb)->trans.tx_buffer); + free(*trans_cb); + *trans_cb = NULL; return; } -static void spi_out_deinit_trans(void) +IRAM_ATTR static void spi_out_tx_done_cb(spi_transaction_t *ret_trans) { - // Wait up to QUEUE_SIZE * 100 ms for all transactions to complete and be recycled - spi_out_recycle_trans(100); - - // Release memory - spi_out_trans_t *next; - while (trans_head != NULL) { - next = trans_head->next; - free((uint8_t *)trans_head->trans.tx_buffer); - free(trans_head); - trans_head = next; - } - trans_head = NULL; - return; + spi_out_trans_cb_t *trans_cb = __containerof(ret_trans, spi_out_trans_cb_t, trans); + trans_cb->length = 0; + trans_cb->flag = SPI_OUT_TRANS_CB_FLAG_AVAILABLE; } -// CRITICAL: Do not recycle trans when trans_head is not empty! -IRAM_ATTR static void spi_out_recycle_trans(uint32_t ms_to_wait) +IRAM_ATTR static inline int spi_out_append_trans(spi_out_trans_cb_t *trans_cb) { - // Try to recycle transaction - spi_transaction_t *ret_trans; - spi_out_trans_t *recycled_trans; - while (ESP_OK == spi_device_get_trans_result(spi_handle, &ret_trans, pdMS_TO_TICKS(ms_to_wait))) { - recycled_trans = __containerof(ret_trans, spi_out_trans_t, trans); - recycled_trans->next = trans_head; - trans_head = recycled_trans; - trans_head->trans.length = 0; - trans_head->trans.rxlength = 0; + if (trans_cb->flag != SPI_OUT_TRANS_CB_FLAG_NEED_QUEUE) { + return -1; + } + + // CRITICAL: Length unit conversion from bytes to bits + trans_cb->trans.length = trans_cb->length * 8; + trans_cb->trans.rxlength = 0; + if (spi_device_queue_trans(spi_handle, &(trans_cb->trans), 0) == ESP_OK) { + trans_cb->flag = SPI_OUT_TRANS_CB_FLAG_IN_QUEUE; + return 0; + } else { + return -1; } } -IRAM_ATTR static void spi_out_append_trans(void) +static int spi_out_log_cb_init(spi_out_log_cb_t **log_cb, uint16_t buf_size) { - // Stop flushout timer - esp_timer_stop(flushout_timer_handle); - - // Transaction head shall not be NULL for appending - if (trans_head) { - // Detach transaction head - spi_out_trans_t *trans_to_append = trans_head; - trans_head = trans_head->next; - trans_to_append->next = NULL; - - // CRITICAL: Length unit conversion from bytes to bits - trans_to_append->trans.length *= 8; - ESP_ERROR_CHECK(spi_device_queue_trans(spi_handle, &trans_to_append->trans, 0)); + // Initialize log control block + *log_cb = (spi_out_log_cb_t *)malloc(sizeof(spi_out_log_cb_t)); + if (!(*log_cb)) { + ESP_LOGE(BLE_LOG_TAG, "Failed to initialize log control block!"); + return -1; } + memset(*log_cb, 0, sizeof(spi_out_log_cb_t)); - // Try to recycle trans - spi_out_recycle_trans(0); - - // Restart flushout timer - esp_timer_start_once(flushout_timer_handle, SPI_OUT_FLUSHOUT_TIMEOUT); -} - -IRAM_ATTR static int spi_out_write(const uint8_t *addr, uint16_t len) -{ - // Recycle trans if free buffer list is empty - if (!trans_head) { - spi_out_recycle_trans(0); + // Initialize transactions + int ret = 0; + for (uint8_t i = 0; i < 2; i++) { + ret |= spi_out_init_trans(&((*log_cb)->trans_cb[i]), buf_size); } - - // Copy user data to buffer - uint16_t copy_buf_len; - uint16_t data_left_len = len; - uint16_t empty_buf_len = CONFIG_BT_BLE_LOG_SPI_OUT_TRANS_BUF_SIZE - trans_head->trans.length; - while (data_left_len) { - // There shall always be available buffer in free buffer list during write operation - if (!trans_head) { - return -1; - } - - // Copy data to buffer and update length - copy_buf_len = (data_left_len > empty_buf_len) ? empty_buf_len : data_left_len; - memcpy((uint8_t *)trans_head->trans.tx_buffer + trans_head->trans.length, addr + (len - data_left_len), copy_buf_len); - trans_head->trans.length += copy_buf_len; - data_left_len -= copy_buf_len; - - // If buffer is full, append transaction and reset buffer length - if (trans_head->trans.length == CONFIG_BT_BLE_LOG_SPI_OUT_TRANS_BUF_SIZE) { - spi_out_append_trans(); - empty_buf_len = CONFIG_BT_BLE_LOG_SPI_OUT_TRANS_BUF_SIZE; - } + if (ret != 0) { + ESP_LOGE(BLE_LOG_TAG, "Failed to initialize SPI transactions!"); + spi_out_log_cb_deinit(log_cb); + return -1; } return 0; } -// CRITICAL: This function is called in ESP Timer task -IRAM_ATTR static void esp_timer_cb_flushout(void) +static void spi_out_log_cb_deinit(spi_out_log_cb_t **log_cb) { - // Take semaphore - assert(xSemaphoreTakeRecursive(mutex_handle, portMAX_DELAY) == pdTRUE); - - // Flushout - if (trans_head) { - // Make sure there's enough space for loss frame counter - if (trans_head->next && loss_frame_cnt) { - ble_log_spi_out_write(BLE_LOG_SPI_OUT_SOURCE_LOSS, (uint8_t *)&loss_frame_cnt, sizeof(loss_frame_cnt)); - loss_frame_cnt = 0; - } - if (trans_head->trans.length) { - spi_out_append_trans(); - } + if (!(*log_cb)) { + return; } - // Restart flushout timer if not active - if (!esp_timer_is_active(flushout_timer_handle)) { - esp_timer_start_once(flushout_timer_handle, SPI_OUT_FLUSHOUT_TIMEOUT); + for (uint8_t i = 0; i < 2; i++) { + if ((*log_cb)->trans_cb[i]) { + spi_out_deinit_trans(&((*log_cb)->trans_cb[i])); + } } - - // Release semaphore - xSemaphoreGiveRecursive(mutex_handle); + free(*log_cb); + return; } +IRAM_ATTR static inline int spi_out_log_cb_check_trans(spi_out_log_cb_t *log_cb, uint16_t len) +{ + spi_out_trans_cb_t *trans_cb; + uint16_t frame_len = len + SPI_OUT_FRAME_OVERHEAD; + for (uint8_t i = 0; i < 2; i++) { + trans_cb = log_cb->trans_cb[log_cb->trans_cb_idx]; + if (frame_len > trans_cb->buf_size) { + goto failed; + } + if (trans_cb->flag == SPI_OUT_TRANS_CB_FLAG_AVAILABLE) { + if ((trans_cb->buf_size - trans_cb->length) >= (len + SPI_OUT_FRAME_OVERHEAD)) { + return 0; + } else { + trans_cb->flag = SPI_OUT_TRANS_CB_FLAG_NEED_QUEUE; + } + } + log_cb->trans_cb_idx = !(log_cb->trans_cb_idx); + } +failed: + log_cb->bytes_loss_cnt += len + SPI_OUT_FRAME_OVERHEAD; + log_cb->frame_cnt++; + return -1; +} + +IRAM_ATTR static inline void spi_out_log_cb_append_trans(spi_out_log_cb_t *log_cb, bool in_isr) +{ + spi_out_trans_cb_t *trans_cb; + uint8_t idx = !log_cb->trans_cb_idx; + for (uint8_t i = 0; i < 2; i++) { + trans_cb = log_cb->trans_cb[idx]; + if (trans_cb->flag == SPI_OUT_TRANS_CB_FLAG_NEED_QUEUE) { + if (!in_isr) { + if (spi_out_append_trans(trans_cb) != 0) { + log_cb->trans_loss_cnt++; + } + } +#if CONFIG_BT_BLE_LOG_SPI_OUT_LL_ENABLED + else { + BLE_LOG_LL_PUT_EV; + return; + } +#endif // CONFIG_BT_BLE_LOG_SPI_OUT_LL_ENABLED + } + idx = !idx; + } +} + +IRAM_ATTR static inline void spi_out_log_cb_flush_trans(spi_out_log_cb_t *log_cb) +{ + spi_out_trans_cb_t *trans_cb = log_cb->trans_cb[log_cb->trans_cb_idx]; + if (trans_cb->length && (trans_cb->flag == SPI_OUT_TRANS_CB_FLAG_AVAILABLE)) { + trans_cb->flag = SPI_OUT_TRANS_CB_FLAG_NEED_QUEUE; + } +} + +IRAM_ATTR static void spi_out_log_cb_write(spi_out_log_cb_t *log_cb, const uint8_t *addr, uint16_t len, \ + const uint8_t *addr_append, uint16_t len_append, uint8_t source) +{ + spi_out_trans_cb_t *trans_cb = log_cb->trans_cb[log_cb->trans_cb_idx]; + + uint8_t *buf = (uint8_t *)trans_cb->trans.tx_buffer + trans_cb->length; + uint16_t total_length = len + len_append; + const uint8_t head[4] = {total_length & 0xFF, (total_length >> 8) & 0xFF, source, log_cb->frame_cnt}; + + memcpy(buf, head, SPI_OUT_FRAME_HEAD_LEN); + memcpy(buf + SPI_OUT_FRAME_HEAD_LEN, addr, len); + if (len_append) { + memcpy(buf + SPI_OUT_FRAME_HEAD_LEN + len, addr_append, len_append); + } + buf[SPI_OUT_FRAME_HEAD_LEN + total_length] = SPI_OUT_FRAME_TAIL; + + trans_cb->length += total_length + SPI_OUT_FRAME_OVERHEAD; + log_cb->frame_cnt++; + if ((trans_cb->buf_size - trans_cb->length) <= SPI_OUT_FRAME_OVERHEAD) { + trans_cb->flag = SPI_OUT_TRANS_CB_FLAG_NEED_QUEUE; + } + return; +} + +IRAM_ATTR static inline void spi_out_log_cb_write_packet_loss(spi_out_log_cb_t *log_cb, uint8_t flag) +{ + if (log_cb->bytes_loss_cnt || log_cb->trans_loss_cnt) { + uint8_t packet_loss_frame[SPI_OUT_PACKET_LOSS_FRAME_SIZE]; + packet_loss_frame[0] = flag; + memcpy(packet_loss_frame + 1, (uint8_t *)&log_cb->bytes_loss_cnt, 4); + packet_loss_frame[5] = log_cb->trans_loss_cnt; + spi_out_log_cb_write(log_cb, packet_loss_frame, SPI_OUT_PACKET_LOSS_FRAME_SIZE, NULL, 0, BLE_LOG_SPI_OUT_SOURCE_LOSS); + log_cb->bytes_loss_cnt = 0; + log_cb->trans_loss_cnt = 0; + } +} + +static void spi_out_log_cb_dump(spi_out_log_cb_t *log_cb) +{ + spi_out_trans_cb_t *trans_cb; + uint8_t *buf; + for (uint8_t i = 0; i < 2; i++) { + // Dump the last transaction before dumping the current transaction + log_cb->trans_cb_idx = !(log_cb->trans_cb_idx); + trans_cb = log_cb->trans_cb[log_cb->trans_cb_idx]; + buf = (uint8_t *)trans_cb->trans.tx_buffer; + for (uint16_t j = 0; j < trans_cb->buf_size; j++) { + esp_rom_printf("%02x ", buf[j]); + + // Feed watchdogs periodically to avoid wdts timeout + if ((j % 100) == 0) { + esp_panic_handler_feed_wdts(); + } + } + } +} + +static int spi_out_ul_log_init(void) +{ + if (ul_log_inited) { + return 0; + } + + // Initialize mutex + ul_log_mutex = xSemaphoreCreateMutex(); + if (!ul_log_mutex) { + ESP_LOGE(BLE_LOG_TAG, "Failed to create mutex for upper layer task log!"); + goto mutex_init_failed; + } + + // Initialize flushout timer + esp_timer_create_args_t timer_args = { + .callback = (esp_timer_cb_t)esp_timer_cb_ul_log_flushout, + .dispatch_method = ESP_TIMER_TASK + }; + if (esp_timer_create(&timer_args, &ul_log_flushout_timer) != ESP_OK) { + ESP_LOGE(BLE_LOG_TAG, "Failed to initialize flushout timer upper layer task log!"); + goto timer_init_failed; + } + + // Initialize log control block + if (spi_out_log_cb_init(&ul_log_cb, CONFIG_BT_BLE_LOG_SPI_OUT_UL_TASK_BUF_SIZE) != 0) { + ESP_LOGE(BLE_LOG_TAG, "Failed to initialize log control blocks for upper layer task log!"); + goto log_cb_init_failed; + } + + // Initialization done + ESP_LOGI(BLE_LOG_TAG, "Succeeded to initialize upper layer task log!"); + ul_log_inited = true; + return 0; + +log_cb_init_failed: + esp_timer_delete(ul_log_flushout_timer); +timer_init_failed: + vSemaphoreDelete(ul_log_mutex); +mutex_init_failed: + return -1; +} + +static void spi_out_ul_log_deinit(void) +{ + if (!ul_log_inited) { + return; + } + + esp_timer_stop(ul_log_flushout_timer); + esp_timer_delete(ul_log_flushout_timer); + + xSemaphoreTake(ul_log_mutex, portMAX_DELAY); + spi_out_log_cb_deinit(&ul_log_cb); + xSemaphoreGive(ul_log_mutex); + + vSemaphoreDelete(ul_log_mutex); + ul_log_mutex = NULL; + + ESP_LOGI(BLE_LOG_TAG, "Succeeded to deinitialize upper layer log!"); + ul_log_inited = false; + return; +} + +IRAM_ATTR static void esp_timer_cb_ul_log_flushout(void) +{ + xSemaphoreTake(ul_log_mutex, portMAX_DELAY); + if (spi_out_log_cb_check_trans(ul_log_cb, SPI_OUT_PACKET_LOSS_FRAME_SIZE) == 0) { + spi_out_log_cb_write_packet_loss(ul_log_cb, SPI_OUT_PACKET_LOSS_UL); + } + spi_out_log_cb_flush_trans(ul_log_cb); + spi_out_log_cb_append_trans(ul_log_cb, false); + xSemaphoreGive(ul_log_mutex); + + if (timer_enabled) { + esp_timer_start_once(ul_log_flushout_timer, SPI_OUT_FLUSHOUT_TIMEOUT); + } +} + +#if CONFIG_BT_BLE_LOG_SPI_OUT_LL_ENABLED +static int spi_out_ll_log_init(void) +{ + if (ll_log_inited) { + return 0; + } + + // Initialize flushout timer + esp_timer_create_args_t timer_args = { + .callback = (esp_timer_cb_t)esp_timer_cb_ll_log_flushout, + .dispatch_method = ESP_TIMER_TASK + }; + if (esp_timer_create(&timer_args, &ll_log_flushout_timer) != ESP_OK) { + ESP_LOGE(BLE_LOG_TAG, "Failed to initialize flushout timer for controller log!"); + goto timer_init_failed; + } + + // Initialize log control blocks for controller task & ISR logs + if (spi_out_log_cb_init(&ll_task_log_cb, CONFIG_BT_BLE_LOG_SPI_OUT_LL_TASK_BUF_SIZE) != 0) { + ESP_LOGE(BLE_LOG_TAG, "Failed to initialize log control blocks for controller task!"); + goto task_log_cb_init_failed; + } + if (spi_out_log_cb_init(&ll_isr_log_cb, CONFIG_BT_BLE_LOG_SPI_OUT_LL_ISR_BUF_SIZE) != 0) { + ESP_LOGE(BLE_LOG_TAG, "Failed to initialize log control blocks for controller ISR!"); + goto isr_log_cb_init_failed; + } + + // Initialization done + ESP_LOGI(BLE_LOG_TAG, "Succeeded to initialize log control blocks for controller task & ISR!"); + ll_log_inited = true; + return 0; + +isr_log_cb_init_failed: + spi_out_log_cb_deinit(&ll_task_log_cb); +task_log_cb_init_failed: + esp_timer_delete(ll_log_flushout_timer); +timer_init_failed: + return -1; +} + +static void spi_out_ll_log_deinit(void) +{ + if (!ll_log_inited) { + return; + } + + esp_timer_stop(ll_log_flushout_timer); + esp_timer_delete(ll_log_flushout_timer); + + spi_out_log_cb_deinit(&ll_isr_log_cb); + spi_out_log_cb_deinit(&ll_task_log_cb); + + // Deinitialization done + ESP_LOGI(BLE_LOG_TAG, "Succeeded to deinitialize controller log!"); + ll_log_inited = false; + return; +} + +IRAM_ATTR static void spi_out_ll_log_ev_proc(void) +{ + // Request from LL ISR + if (!ll_log_need_flushout) { + esp_timer_stop(ll_log_flushout_timer); + spi_out_log_cb_append_trans(ll_isr_log_cb, false); + if (timer_enabled) { + esp_timer_start_once(ll_log_flushout_timer, SPI_OUT_FLUSHOUT_TIMEOUT); + } + return; + } + + // Request from flushout timer + ll_log_need_flushout = false; + if (spi_out_log_cb_check_trans(ll_isr_log_cb, SPI_OUT_PACKET_LOSS_FRAME_SIZE) == 0) { + spi_out_log_cb_write_packet_loss(ll_isr_log_cb, SPI_OUT_PACKET_LOSS_LL_ISR); + } + spi_out_log_cb_flush_trans(ll_isr_log_cb); + spi_out_log_cb_append_trans(ll_isr_log_cb, false); + + if (spi_out_log_cb_check_trans(ll_task_log_cb, SPI_OUT_PACKET_LOSS_FRAME_SIZE) == 0) { + spi_out_log_cb_write_packet_loss(ll_task_log_cb, SPI_OUT_PACKET_LOSS_LL_TASK); + } + spi_out_log_cb_flush_trans(ll_task_log_cb); + spi_out_log_cb_append_trans(ll_task_log_cb, false); + if (timer_enabled) { + esp_timer_start_once(ll_log_flushout_timer, SPI_OUT_FLUSHOUT_TIMEOUT); + } + return; +} + +IRAM_ATTR static void esp_timer_cb_ll_log_flushout(void) +{ + ll_log_need_flushout = true; + BLE_LOG_LL_PUT_EV; +} +#endif // CONFIG_BT_BLE_LOG_SPI_OUT_LL_ENABLED + #if CONFIG_BT_BLE_LOG_SPI_OUT_TS_SYNC_ENABLED +static int spi_out_ts_sync_init(void) +{ + if (ts_sync_inited) { + return 0; + } + + // Initialize sync timer + esp_timer_create_args_t timer_args = { + .callback = (esp_timer_cb_t)esp_timer_cb_ts_sync, + .dispatch_method = ESP_TIMER_TASK + }; + if (esp_timer_create(&timer_args, &ts_sync_timer) != ESP_OK) { + ESP_LOGE(BLE_LOG_TAG, "Failed to initialize timestamp synchronizer timer!"); + goto timer_init_failed; + } + + // Initialize sync IO + gpio_config_t io_conf = { + .intr_type = GPIO_INTR_DISABLE, + .mode = GPIO_MODE_OUTPUT, + .pin_bit_mask = (1UL << CONFIG_BT_BLE_LOG_SPI_OUT_SYNC_IO_NUM), + .pull_down_en = 0, + .pull_up_en = 0 + }; + if (gpio_config(&io_conf) != ESP_OK) { + ESP_LOGE(BLE_LOG_TAG, "Failed to initialize timestamp synchronizer IO!"); + goto gpio_init_failed; + } + + // Initialization done + ESP_LOGI(BLE_LOG_TAG, "Succeeded to initialize timestamp synchronizer!"); + sync_io_level = false; + gpio_set_level(CONFIG_BT_BLE_LOG_SPI_OUT_SYNC_IO_NUM, sync_io_level); + ts_sync_inited = true; + return 0; + +gpio_init_failed: + esp_timer_delete(ts_sync_timer); +timer_init_failed: + return -1; +} + +static void spi_out_ts_sync_deinit(void) +{ + if (!ts_sync_inited) { + return; + } + + // Deinitialize timestamp synchronizer + esp_timer_stop(ts_sync_timer); + esp_timer_delete(ts_sync_timer); + + // Deinitialize sync IO + sync_io_level = false; + gpio_set_level(CONFIG_BT_BLE_LOG_SPI_OUT_SYNC_IO_NUM, sync_io_level); + gpio_reset_pin(CONFIG_BT_BLE_LOG_SPI_OUT_SYNC_IO_NUM); + + // Deinitialization done + ESP_LOGI(BLE_LOG_TAG, "Succeeded to deinitialize timestamp synchronizer!"); + ts_sync_inited = false; + return; +} + // CRITICAL: This function is called in ESP Timer task IRAM_ATTR static void esp_timer_cb_ts_sync(void) { @@ -200,22 +589,17 @@ IRAM_ATTR static void esp_timer_cb_ts_sync(void) // Enter critical portMUX_TYPE spinlock = portMUX_INITIALIZER_UNLOCKED; - portENTER_CRITICAL_SAFE(&spinlock); + portENTER_CRITICAL(&spinlock); // Get LC timestamp -#if defined(CONFIG_IDF_TARGET_ESP32H2) || defined(CONFIG_IDF_TARGET_ESP32C6) - lc_ts = r_ble_lll_timer_current_tick_get(); -#endif // CONFIG_IDF_TARGET_ESP32H2 || CONFIG_IDF_TARGET_ESP32C6 -#if defined(CONFIG_IDF_TARGET_ESP32C2) - lc_ts = r_os_cputime_get32(); -#endif // CONFIG_IDF_TARGET_ESP32C2 + lc_ts = SPI_OUT_GET_LC_TIME; // Set sync IO level gpio_set_level(CONFIG_BT_BLE_LOG_SPI_OUT_SYNC_IO_NUM, (uint32_t)sync_io_level); // Get ESP timestamp esp_ts = esp_timer_get_time(); - portEXIT_CRITICAL_SAFE(&spinlock); + portEXIT_CRITICAL(&spinlock); // Exit critical // Write timestamp sync log @@ -228,16 +612,13 @@ IRAM_ATTR static void esp_timer_cb_ts_sync(void) #endif // CONFIG_BT_BLE_LOG_SPI_OUT_TS_SYNC_ENABLED // Public functions -void ble_log_spi_out_init(void) +int ble_log_spi_out_init(void) { // Avoid double init if (spi_out_inited) { - return; + return 0; } - // Initialize mutex - mutex_handle = xSemaphoreCreateRecursiveMutex(); - // Initialize SPI spi_bus_config_t bus_config = { .miso_io_num = -1, @@ -245,50 +626,68 @@ void ble_log_spi_out_init(void) .sclk_io_num = CONFIG_BT_BLE_LOG_SPI_OUT_SCLK_IO_NUM, .quadwp_io_num = -1, .quadhd_io_num = -1, - .max_transfer_sz = 10240 + .max_transfer_sz = SPI_OUT_MAX_TRANSFER_SIZE, + .intr_flags = ESP_INTR_FLAG_IRAM }; spi_device_interface_config_t dev_config = { .clock_speed_hz = SPI_MASTER_FREQ_20M, .mode = 0, .spics_io_num = CONFIG_BT_BLE_LOG_SPI_OUT_CS_IO_NUM, - .queue_size = CONFIG_BT_BLE_LOG_SPI_OUT_QUEUE_SIZE + .queue_size = 4 + 2, + .post_cb = (transaction_cb_t)spi_out_tx_done_cb }; - ESP_ERROR_CHECK(spi_bus_initialize(SPI_OUT_BUS, &bus_config, SPI_DMA_CH_AUTO)); - ESP_ERROR_CHECK(spi_bus_add_device(SPI_OUT_BUS, &dev_config, &spi_handle)); + if (spi_bus_initialize(SPI_OUT_BUS, &bus_config, SPI_DMA_CH_AUTO) != ESP_OK) { + ESP_LOGE(BLE_LOG_TAG, "Failed to initialize SPI bus!"); + goto spi_bus_init_failed; + } + if (spi_bus_add_device(SPI_OUT_BUS, &dev_config, &spi_handle) != ESP_OK) { + ESP_LOGE(BLE_LOG_TAG, "Failed to add device to SPI bus!"); + goto spi_device_add_failed; + } - // Initialize transaction link nodes - spi_out_init_trans(); + if (spi_out_ul_log_init() != 0) { + goto ul_log_init_failed; + } - // Initialize flushout timer - esp_timer_create_args_t timer_args = { - .callback = (esp_timer_cb_t)esp_timer_cb_flushout, - .dispatch_method = ESP_TIMER_TASK - }; - ESP_ERROR_CHECK(esp_timer_create(&timer_args, &flushout_timer_handle)); - esp_timer_start_once(flushout_timer_handle, SPI_OUT_FLUSHOUT_TIMEOUT); - loss_frame_cnt = 0; +#if CONFIG_BT_BLE_LOG_SPI_OUT_LL_ENABLED + if (spi_out_ll_log_init() != 0) { + goto ll_log_init_failed; + } +#endif // CONFIG_BT_BLE_LOG_SPI_OUT_LL_ENABLED #if CONFIG_BT_BLE_LOG_SPI_OUT_TS_SYNC_ENABLED - // Initialize timestamp synchronizer - gpio_config_t io_conf = { - .intr_type = GPIO_INTR_DISABLE, - .mode = GPIO_MODE_OUTPUT, - .pin_bit_mask = (1UL << CONFIG_BT_BLE_LOG_SPI_OUT_SYNC_IO_NUM), - .pull_down_en = 0, - .pull_up_en = 0 - }; - ESP_ERROR_CHECK(gpio_config(&io_conf)); - sync_io_level = false; - gpio_set_level(CONFIG_BT_BLE_LOG_SPI_OUT_SYNC_IO_NUM, sync_io_level); - esp_timer_create_args_t ts_sync_timer_args = { - .callback = (esp_timer_cb_t)esp_timer_cb_ts_sync, - .dispatch_method = ESP_TIMER_TASK - }; - ESP_ERROR_CHECK(esp_timer_create(&ts_sync_timer_args, &ts_sync_timer_handle)); + if (spi_out_ts_sync_init() != 0) { + goto ts_sync_init_failed; + } #endif // CONFIG_BT_BLE_LOG_SPI_OUT_TS_SYNC_ENABLED - // Set init flag + // Initialization done + ESP_LOGI(BLE_LOG_TAG, "Succeeded to initialize BLE log SPI output interface!"); spi_out_inited = true; + + // Start flushout timer + esp_timer_start_once(ul_log_flushout_timer, SPI_OUT_FLUSHOUT_TIMEOUT); + +#if CONFIG_BT_BLE_LOG_SPI_OUT_LL_ENABLED + esp_timer_start_once(ll_log_flushout_timer, SPI_OUT_FLUSHOUT_TIMEOUT); +#endif // CONFIG_BT_BLE_LOG_SPI_OUT_LL_ENABLED + return 0; + +#if CONFIG_BT_BLE_LOG_SPI_OUT_TS_SYNC_ENABLED +ts_sync_init_failed: +#endif // CONFIG_BT_BLE_LOG_SPI_OUT_TS_SYNC_ENABLED +#if CONFIG_BT_BLE_LOG_SPI_OUT_LL_ENABLED + spi_out_ll_log_deinit(); +ll_log_init_failed: +#endif // CONFIG_BT_BLE_LOG_SPI_OUT_LL_ENABLED + spi_out_ul_log_deinit(); +ul_log_init_failed: + spi_bus_remove_device(spi_handle); + spi_handle = NULL; +spi_device_add_failed: + spi_bus_free(SPI_OUT_BUS); +spi_bus_init_failed: + return -1; } void ble_log_spi_out_deinit(void) @@ -299,27 +698,19 @@ void ble_log_spi_out_deinit(void) } #if CONFIG_BT_BLE_LOG_SPI_OUT_TS_SYNC_ENABLED - // Deinitialize timestamp synchronizer - esp_timer_stop(ts_sync_timer_handle); - esp_timer_delete(ts_sync_timer_handle); - gpio_reset_pin(CONFIG_BT_BLE_LOG_SPI_OUT_SYNC_IO_NUM); + spi_out_ts_sync_deinit(); #endif // CONFIG_BT_BLE_LOG_SPI_OUT_TS_SYNC_ENABLED - // Deinitialize flushout timer - esp_timer_stop(flushout_timer_handle); - esp_timer_delete(flushout_timer_handle); +#if CONFIG_BT_BLE_LOG_SPI_OUT_LL_ENABLED + spi_out_ll_log_deinit(); +#endif // CONFIG_BT_BLE_LOG_SPI_OUT_LL_ENABLED - // Deinitialize transaction link nodes - spi_out_deinit_trans(); + spi_out_ul_log_deinit(); // Deinitialize SPI - ESP_ERROR_CHECK(spi_bus_remove_device(spi_handle)); - ESP_ERROR_CHECK(spi_bus_free(SPI_OUT_BUS)); + spi_bus_remove_device(spi_handle); spi_handle = NULL; - - // Deinitialize mutex - vSemaphoreDelete(mutex_handle); - mutex_handle = NULL; + spi_bus_free(SPI_OUT_BUS); // Reset init flag spi_out_inited = false; @@ -334,9 +725,9 @@ void ble_log_spi_out_ts_sync_start(void) } // Start timestamp sync timer - if (ts_sync_timer_handle) { - if (!esp_timer_is_active(ts_sync_timer_handle)) { - esp_timer_start_periodic(ts_sync_timer_handle, SPI_OUT_TS_SYNC_TIMEOUT); + if (ts_sync_timer) { + if (!esp_timer_is_active(ts_sync_timer)) { + esp_timer_start_periodic(ts_sync_timer, SPI_OUT_TS_SYNC_TIMEOUT); } } } @@ -349,9 +740,9 @@ void ble_log_spi_out_ts_sync_stop(void) } // Stop timestamp sync timer - if (ts_sync_timer_handle) { - if (esp_timer_is_active(ts_sync_timer_handle)) { - esp_timer_stop(ts_sync_timer_handle); + if (ts_sync_timer) { + if (esp_timer_is_active(ts_sync_timer)) { + esp_timer_stop(ts_sync_timer); } // Set sync IO to low level @@ -361,51 +752,56 @@ void ble_log_spi_out_ts_sync_stop(void) } #endif // CONFIG_BT_BLE_LOG_SPI_OUT_TS_SYNC_ENABLED -IRAM_ATTR void ble_log_spi_out_write_esp(uint32_t len, const uint8_t *addr, bool end) +#if CONFIG_BT_BLE_LOG_SPI_OUT_LL_ENABLED +// Only LL task has access to this API +IRAM_ATTR void ble_log_spi_out_ll_write(uint32_t len, const uint8_t *addr, uint32_t len_append,\ + const uint8_t *addr_append, uint32_t flag) { - return ble_log_spi_out_write(BLE_LOG_SPI_OUT_SOURCE_ESP, addr, len); + if (!ll_log_inited) { + return; + } + + bool in_isr = (bool)(flag & BLE_LOG_INTERFACE_FLAG_IN_ISR); + uint8_t source = in_isr ? BLE_LOG_SPI_OUT_SOURCE_ESP_ISR : BLE_LOG_SPI_OUT_SOURCE_ESP; + spi_out_log_cb_t *log_cb = in_isr ? ll_isr_log_cb : ll_task_log_cb; + uint16_t total_length = (uint16_t)(len + len_append); + if (spi_out_log_cb_check_trans(log_cb, total_length) == 0) { + spi_out_log_cb_write(log_cb, addr, (uint16_t)len, addr_append, (uint16_t)len_append, source); + } + spi_out_log_cb_append_trans(log_cb, in_isr); + return; } -IRAM_ATTR void ble_log_spi_out_write(uint8_t source, const uint8_t *addr, uint16_t len) +IRAM_ATTR void ble_log_spi_out_ll_log_ev_proc(void) { - // Initialize frame sequence number - static uint8_t frame_sn = 0; + if (!ll_log_inited) { + return; + } + return spi_out_ll_log_ev_proc(); +} +#endif // CONFIG_BT_BLE_LOG_SPI_OUT_LL_ENABLED - // Take semaphore - assert(xSemaphoreTakeRecursive(mutex_handle, portMAX_DELAY) == pdTRUE); +IRAM_ATTR int ble_log_spi_out_write(uint8_t source, const uint8_t *addr, uint16_t len) +{ + if (!ul_log_inited) { + return -1; + } - // Prepare frame head and frame tail - const uint8_t head[4] = {len & 0xFF, (len >> 8) & 0xFF, (uint8_t)source, frame_sn}; - const uint8_t tail = SPI_OUT_TAIL; - - // Write frame head first, then payload, finally frame tail - do { - if (spi_out_write(head, 4) != 0) { - loss_frame_cnt++; - break; - } - if (spi_out_write(addr, len) != 0) { - loss_frame_cnt++; - break; - } - if (spi_out_write(&tail, 1) != 0) { - loss_frame_cnt++; - break; - } - } while (0); - - // Update frame sequence number - frame_sn++; - - // Release semaphore - xSemaphoreGiveRecursive(mutex_handle); - return; + xSemaphoreTake(ul_log_mutex, portMAX_DELAY); + int ret = spi_out_log_cb_check_trans(ul_log_cb, len); + if (ret == 0) { + spi_out_log_cb_write(ul_log_cb, addr, len, NULL, 0, source); + } + spi_out_log_cb_append_trans(ul_log_cb, false); + xSemaphoreGive(ul_log_mutex); + return ret; } IRAM_ATTR int ble_log_spi_out_printf(uint8_t source, const char *format, ...) { - // Get esp timestamp - uint32_t esp_ts = esp_timer_get_time(); + if (!ul_log_inited) { + return -1; + } // Get arguments va_list args; @@ -434,19 +830,25 @@ IRAM_ATTR int ble_log_spi_out_printf(uint8_t source, const char *format, ...) vsnprintf((char *)buffer, len + 1, format, args); va_end(args); - // Write to SPI - ble_log_spi_out_write(source, (const uint8_t *)&esp_ts, 4); - ble_log_spi_out_write(source, (const uint8_t *)buffer, len); + uint32_t esp_ts = esp_timer_get_time(); + xSemaphoreTake(ul_log_mutex, portMAX_DELAY); + int ret = spi_out_log_cb_check_trans(ul_log_cb, 4 + len); + if (ret == 0) { + spi_out_log_cb_write(ul_log_cb, (const uint8_t *)&esp_ts, 4, (const uint8_t *)buffer, len, source); + } + spi_out_log_cb_append_trans(ul_log_cb, false); + xSemaphoreGive(ul_log_mutex); // Release free(buffer); - return 0; + return ret; } IRAM_ATTR int ble_log_spi_out_printf_enh(uint8_t source, uint8_t level, const char *tag, const char *format, ...) { - // Get ESP timestamp - uint32_t esp_ts = esp_timer_get_time(); + if (!ul_log_inited) { + return -1; + } // Create log prefix in the format: "[level][tag] " char prefix[32]; @@ -481,22 +883,91 @@ IRAM_ATTR int ble_log_spi_out_printf_enh(uint8_t source, uint8_t level, const ch vsnprintf((char *)(buffer + prefix_len), log_len + 1, format, args); va_end(args); - // Transmit log data via SPI - ble_log_spi_out_write(source, (const uint8_t *)&esp_ts, 4); - ble_log_spi_out_write(source, buffer, total_len); - - // Free allocated memory - free(buffer); - return 0; -} - -IRAM_ATTR void ble_log_spi_out_write_with_ts(uint8_t source, const uint8_t *addr, uint16_t len) -{ - // Get esp timestamp uint32_t esp_ts = esp_timer_get_time(); + xSemaphoreTake(ul_log_mutex, portMAX_DELAY); + int ret = spi_out_log_cb_check_trans(ul_log_cb, 4 + total_len); + if (ret == 0) { + spi_out_log_cb_write(ul_log_cb, (const uint8_t *)&esp_ts, 4, (const uint8_t *)buffer, total_len, source); + } + spi_out_log_cb_append_trans(ul_log_cb, false); + xSemaphoreGive(ul_log_mutex); - // Write to SPI - ble_log_spi_out_write(source, (const uint8_t *)&esp_ts, 4); - ble_log_spi_out_write(source, addr, len); + free(buffer); + return ret; } + +IRAM_ATTR int ble_log_spi_out_write_with_ts(uint8_t source, const uint8_t *addr, uint16_t len) +{ + if (!ul_log_inited) { + return -1; + } + + uint32_t esp_ts = esp_timer_get_time(); + xSemaphoreTake(ul_log_mutex, portMAX_DELAY); + int ret = spi_out_log_cb_check_trans(ul_log_cb, 4 + len); + if (ret == 0) { + spi_out_log_cb_write(ul_log_cb, (const uint8_t *)&esp_ts, 4, addr, len, source); + } + spi_out_log_cb_append_trans(ul_log_cb, false); + xSemaphoreGive(ul_log_mutex); + return ret; +} + +void ble_log_spi_out_dump_all(void) +{ + portMUX_TYPE spinlock = portMUX_INITIALIZER_UNLOCKED; + portENTER_CRITICAL_SAFE(&spinlock); + +#if CONFIG_BT_BLE_LOG_SPI_OUT_LL_ENABLED + if (ll_log_inited) { + // Dump lower layer log buffer + esp_rom_printf("[LL_ISR_LOG_DUMP_START:\n"); + spi_out_log_cb_dump(ll_isr_log_cb); + esp_rom_printf("\n:LL_ISR_LOG_DUMP_END]\n\n"); + + esp_rom_printf("[LL_TASK_LOG_DUMP_START:\n"); + spi_out_log_cb_dump(ll_task_log_cb); + esp_rom_printf("\n:LL_TASK_LOG_DUMP_END]\n\n"); + } +#endif // CONFIG_BT_BLE_LOG_SPI_OUT_LL_ENABLED + + if (ul_log_inited) { + // Dump upper layer log buffer + esp_rom_printf("[UL_LOG_DUMP_START:\n"); + spi_out_log_cb_dump(ul_log_cb); + esp_rom_printf("\n:UL_LOG_DUMP_END]\n\n"); + } + portEXIT_CRITICAL_SAFE(&spinlock); +} + +void ble_log_spi_out_timer_control(bool enable) +{ + timer_enabled = enable; + if (enable) { + if (!esp_timer_is_active(ul_log_flushout_timer)) { + esp_timer_start_once(ul_log_flushout_timer, SPI_OUT_FLUSHOUT_TIMEOUT); + } + +#if CONFIG_BT_BLE_LOG_SPI_OUT_LL_ENABLED + if (!esp_timer_is_active(ll_log_flushout_timer)) { + esp_timer_start_once(ll_log_flushout_timer, SPI_OUT_FLUSHOUT_TIMEOUT); + } +#endif // CONFIG_BT_BLE_LOG_SPI_OUT_LL_ENABLED + +#if CONFIG_BT_BLE_LOG_SPI_OUT_TS_SYNC_ENABLED + ble_log_spi_out_ts_sync_start(); +#endif // CONFIG_BT_BLE_LOG_SPI_OUT_TS_SYNC_ENABLED + } else { + esp_timer_stop(ul_log_flushout_timer); + +#if CONFIG_BT_BLE_LOG_SPI_OUT_LL_ENABLED + esp_timer_stop(ll_log_flushout_timer); +#endif // CONFIG_BT_BLE_LOG_SPI_OUT_LL_ENABLED + +#if CONFIG_BT_BLE_LOG_SPI_OUT_TS_SYNC_ENABLED + ble_log_spi_out_ts_sync_stop(); +#endif // CONFIG_BT_BLE_LOG_SPI_OUT_TS_SYNC_ENABLED + } +} + #endif // CONFIG_BT_BLE_LOG_SPI_OUT_ENABLED diff --git a/components/bt/common/ble_log/include/ble_log/ble_log_spi_out.h b/components/bt/common/ble_log/include/ble_log/ble_log_spi_out.h index c1a4506637..1b22ad5f42 100644 --- a/components/bt/common/ble_log/include/ble_log/ble_log_spi_out.h +++ b/components/bt/common/ble_log/include/ble_log/ble_log_spi_out.h @@ -11,6 +11,7 @@ #include "driver/spi_master.h" #include "driver/gpio.h" #include "esp_timer.h" +#include "esp_log.h" #include "freertos/semphr.h" // Public typedefs @@ -20,6 +21,8 @@ #define BLE_LOG_SPI_OUT_SOURCE_NIMBLE 3 #define BLE_LOG_SPI_OUT_SOURCE_HCI_UPSTREAM 4 #define BLE_LOG_SPI_OUT_SOURCE_HCI_DOWNSTREAM 5 +#define BLE_LOG_SPI_OUT_SOURCE_ESP_ISR 6 +#define BLE_LOG_SPI_OUT_SOURCE_ESP_LEGACY_ISR 7 #define BLE_LOG_SPI_OUT_SOURCE_USER 0x10 #define BLE_LOG_SPI_OUT_SOURCE_SYNC 0xFE #define BLE_LOG_SPI_OUT_SOURCE_LOSS 0xFF @@ -34,14 +37,18 @@ #define BLE_LOG_SPI_OUT_LEVEL_MAX 6 /*!< Number of SPI log levels supported */ // Public functions -void ble_log_spi_out_init(void); +int ble_log_spi_out_init(void); void ble_log_spi_out_deinit(void); -void ble_log_spi_out_write(uint8_t source, const uint8_t *addr, uint16_t len); -void ble_log_spi_out_write_esp(uint32_t len, const uint8_t *addr, bool end); +void ble_log_spi_out_timer_control(bool enable); +int ble_log_spi_out_write(uint8_t source, const uint8_t *addr, uint16_t len); +void ble_log_spi_out_ll_write(uint32_t len, const uint8_t *addr, uint32_t len_append,\ + const uint8_t *addr_append, uint32_t flag); +void ble_log_spi_out_ll_log_ev_proc(void); void ble_log_spi_out_ts_sync_start(void); void ble_log_spi_out_ts_sync_stop(void); int ble_log_spi_out_printf(uint8_t source, const char *format, ...); int ble_log_spi_out_printf_enh(uint8_t source, uint8_t level, const char *tag, const char *format, ...); -void ble_log_spi_out_write_with_ts(uint8_t source, const uint8_t *addr, uint16_t len); +int ble_log_spi_out_write_with_ts(uint8_t source, const uint8_t *addr, uint16_t len); +void ble_log_spi_out_dump_all(void); #endif // __BT_SPI_OUT_H__ From 32e72c42e837347a7077b8925150f5db0e397892 Mon Sep 17 00:00:00 2001 From: Geng Yuchao Date: Fri, 14 Mar 2025 16:40:49 +0800 Subject: [PATCH 7/7] fix(ble): Add link requires esp_phy for ble. --- components/bt/CMakeLists.txt | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/components/bt/CMakeLists.txt b/components/bt/CMakeLists.txt index 380f9bb2cb..ec2d763c33 100644 --- a/components/bt/CMakeLists.txt +++ b/components/bt/CMakeLists.txt @@ -745,16 +745,20 @@ if(CONFIG_BT_ENABLED) endif() elseif(CONFIG_IDF_TARGET_ESP32H2 AND CONFIG_BT_CONTROLLER_ENABLED) if(CONFIG_IDF_TARGET_ESP32H2_BETA_VERSION_1) - add_prebuilt_library(nimblelib "controller/lib_esp32h2/esp32h2-bt-lib/beta1/libble_app.a") + add_prebuilt_library(nimblelib "controller/lib_esp32h2/esp32h2-bt-lib/beta1/libble_app.a" + REQUIRES esp_phy) elseif(CONFIG_IDF_TARGET_ESP32H2_BETA_VERSION_2) - add_prebuilt_library(nimblelib "controller/lib_esp32h2/esp32h2-bt-lib/beta2/libble_app.a") + add_prebuilt_library(nimblelib "controller/lib_esp32h2/esp32h2-bt-lib/beta2/libble_app.a" + REQUIRES esp_phy) endif() target_link_libraries(${COMPONENT_LIB} PRIVATE nimblelib) elseif(CONFIG_IDF_TARGET_ESP32C2 AND CONFIG_BT_CONTROLLER_ENABLED) if(CONFIG_BT_CTRL_RUN_IN_FLASH_ONLY) - add_prebuilt_library(nimblelib "controller/lib_esp32c2/esp32c2-bt-lib/libble_app_flash.a") + add_prebuilt_library(nimblelib "controller/lib_esp32c2/esp32c2-bt-lib/libble_app_flash.a" + REQUIRES esp_phy) else() - add_prebuilt_library(nimblelib "controller/lib_esp32c2/esp32c2-bt-lib/libble_app.a") + add_prebuilt_library(nimblelib "controller/lib_esp32c2/esp32c2-bt-lib/libble_app.a" + REQUIRES esp_phy) endif() target_link_libraries(${COMPONENT_LIB} PRIVATE nimblelib) endif()