diff --git a/components/bt/CMakeLists.txt b/components/bt/CMakeLists.txt index 806c0dbdf2..34ac21bd42 100644 --- a/components/bt/CMakeLists.txt +++ b/components/bt/CMakeLists.txt @@ -137,6 +137,7 @@ if(CONFIG_BT_ENABLED) "common/osi/semaphore.c" "porting/mem/bt_osi_mem.c" "common/ble_log/ble_log_spi_out.c" + "common/ble_log/ble_log_uhci_out.c" ) # Host Bluedroid @@ -946,6 +947,11 @@ if(CONFIG_BT_ENABLED) if(CONFIG_BT_LE_CONTROLLER_LOG_WRAP_PANIC_HANDLER_ENABLE) target_link_libraries(${COMPONENT_LIB} INTERFACE "-Wl,--wrap=esp_panic_handler") endif() + if(CONFIG_BT_BLE_LOG_UHCI_OUT_ENABLED) + target_link_libraries(${COMPONENT_LIB} INTERFACE "-Wl,--wrap=uart_tx_chars") + target_link_libraries(${COMPONENT_LIB} INTERFACE "-Wl,--wrap=uart_write_bytes") + target_link_libraries(${COMPONENT_LIB} INTERFACE "-Wl,--wrap=uart_write_bytes_with_break") + endif() if(CONFIG_IDF_TARGET_ESP32C6) add_prebuilt_library(libble_app "${CMAKE_CURRENT_LIST_DIR}/controller/lib_esp32c6/esp32c6-bt-lib/esp32c6/libble_app.a" diff --git a/components/bt/common/Kconfig.in b/components/bt/common/Kconfig.in index 5202f53e9e..5b1de7fdda 100644 --- a/components/bt/common/Kconfig.in +++ b/components/bt/common/Kconfig.in @@ -197,3 +197,64 @@ config BT_BLE_LOG_SPI_OUT_MESH_TASK_CNT default 3 help Mesh task count + +config BT_BLE_LOG_UHCI_OUT_ENABLED + bool "Output ble logs via UHCI (UART DMA) driver (Experimental)" + default n + help + Output ble logs via UHCI (UART DMA) driver + On enable, BT_BLE_LOG_UHCI_OUT_UART_PORT would be reinited with + BT_BLE_LOG_UHCI_OUT_UART_BAUD_RATE as new baud rate and + BT_BLE_LOG_UHCI_OUT_UART_IO_NUM_TX as new UART Tx IO + +config BT_BLE_LOG_UHCI_OUT_UART_PORT + int "UART port connected to UHCI controller" + depends on BT_BLE_LOG_UHCI_OUT_ENABLED + default 0 + help + UART port connected to UHCI controller + If UART port 0 is selected, UART VFS Driver, UART ROM Driver + and UART Driver output would be redirected to BLE Log UHCI Out + to solve UART Tx FIFO multi-task access issue + +config BT_BLE_LOG_UHCI_OUT_LL_TASK_BUF_SIZE + int "UHCI transaction buffer size for lower layer task logs" + depends on BT_BLE_LOG_UHCI_OUT_ENABLED + default 1024 + help + UHCI transaction buffer size for lower layer task logs + +config BT_BLE_LOG_UHCI_OUT_LL_ISR_BUF_SIZE + int "UHCI transaction buffer size for lower layer ISR logs" + depends on BT_BLE_LOG_UHCI_OUT_ENABLED + default 1024 + help + UHCI transaction buffer size for lower layer ISR logs + +config BT_BLE_LOG_UHCI_OUT_LL_HCI_BUF_SIZE + int "UHCI transaction buffer size for lower layer HCI logs" + depends on BT_BLE_LOG_UHCI_OUT_ENABLED + default 1024 + help + UHCI transaction buffer size for lower layer HCI logs + +config BT_BLE_LOG_UHCI_OUT_UART_NEED_INIT + bool "Enable to init UART port" + depends on BT_BLE_LOG_UHCI_OUT_ENABLED + default y + help + Enable to init UART port + +config BT_BLE_LOG_UHCI_OUT_UART_BAUD_RATE + int "Baud rate for BT_BLE_LOG_UHCI_OUT_UART_PORT" + depends on BT_BLE_LOG_UHCI_OUT_UART_NEED_INIT + default 3000000 + help + Baud rate for BT_BLE_LOG_UHCI_OUT_UART_PORT + +config BT_BLE_LOG_UHCI_OUT_UART_IO_NUM_TX + int "IO number for UART TX port" + depends on BT_BLE_LOG_UHCI_OUT_UART_NEED_INIT + default 0 + help + IO number for UART TX port diff --git a/components/bt/common/ble_log/ble_log_uhci_out.c b/components/bt/common/ble_log/ble_log_uhci_out.c new file mode 100644 index 0000000000..1ab447eee3 --- /dev/null +++ b/components/bt/common/ble_log/ble_log_uhci_out.c @@ -0,0 +1,780 @@ +/* + * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include "ble_log/ble_log_uhci_out.h" + + +#if CONFIG_BT_BLE_LOG_UHCI_OUT_ENABLED + +// Private includes +#include "esp_bt.h" + +// sdkconfig defines +#define UHCI_OUT_LL_TASK_BUF_SIZE CONFIG_BT_BLE_LOG_UHCI_OUT_LL_TASK_BUF_SIZE +#define UHCI_OUT_LL_ISR_BUF_SIZE CONFIG_BT_BLE_LOG_UHCI_OUT_LL_ISR_BUF_SIZE +#define UHCI_OUT_LL_HCI_BUF_SIZE CONFIG_BT_BLE_LOG_UHCI_OUT_LL_HCI_BUF_SIZE +#define UHCI_OUT_UART_PORT CONFIG_BT_BLE_LOG_UHCI_OUT_UART_PORT +#define UHCI_OUT_UART_NEED_INIT CONFIG_BT_BLE_LOG_UHCI_OUT_UART_NEED_INIT + +#if UHCI_OUT_UART_NEED_INIT +#define UHCI_OUT_UART_BAUD_RATE CONFIG_BT_BLE_LOG_UHCI_OUT_UART_BAUD_RATE +#define UHCI_OUT_UART_IO_NUM_TX CONFIG_BT_BLE_LOG_UHCI_OUT_UART_IO_NUM_TX +#endif // UHCI_OUT_UART_NEED_INIT + +// Private defines +#define UHCI_OUT_MAX_TRANSFER_SIZE (10240) +#define UHCI_OUT_MALLOC(size) heap_caps_malloc(size, MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT) +#define UHCI_OUT_FLUSH_TIMEOUT_MS (100) +#define UHCI_OUT_FLUSH_TIMEOUT_US (UHCI_OUT_FLUSH_TIMEOUT_MS * 1000) +#define UHCI_OUT_USER_BUF_SIZE (512) +#define UHCI_OUT_UART_PORT0 (0) +#define UHCI_OUT_UART_PORT1 (1) +#define UHCI_OUT_UART_DRIVER_RX_BUF_SIZE (32) + +// Queue size defines +#define UHCI_OUT_PING_PONG_BUF_CNT (2) +#define UHCI_OUT_USER_QUEUE_SIZE (UHCI_OUT_PING_PONG_BUF_CNT) +#define UHCI_OUT_LL_QUEUE_SIZE (3 * UHCI_OUT_PING_PONG_BUF_CNT) +#define UHCI_OUT_QUEUE_SIZE (UHCI_OUT_USER_QUEUE_SIZE + UHCI_OUT_LL_QUEUE_SIZE) + +// Private typedefs +typedef struct { + // This flag is for multithreading, must be a word, do not modify + volatile uint32_t flag; + uint16_t buf_size; + uint16_t length; + uint8_t buffer[0]; +} uhci_out_trans_cb_t; + +typedef struct { + uhci_out_trans_cb_t *trans_cb[2]; + uint8_t trans_cb_idx; + uint8_t type; + uint16_t lost_frame_cnt; + uint32_t lost_bytes_cnt; + uint32_t frame_sn; +} uhci_out_log_cb_t; + +typedef struct { + uint16_t length; + uint8_t source; + uint8_t type; + uint16_t frame_sn; +} __attribute__((packed)) frame_head_t; + +typedef struct { + uint8_t type; + uint16_t lost_frame_cnt; + uint32_t lost_bytes_cnt; +} __attribute__((packed)) loss_payload_t; + +// Private enums +enum { + TRANS_CB_FLAG_AVAILABLE = 0, + TRANS_CB_FLAG_NEED_QUEUE, + TRANS_CB_FLAG_IN_QUEUE, +}; + +enum { + LOG_CB_TYPE_USER = 0, + LOG_CB_TYPE_LL, +}; + +enum { + LOG_CB_LL_SUBTYPE_TASK = 0, + LOG_CB_LL_SUBTYPE_ISR, + LOG_CB_LL_SUBTYPE_HCI +}; + +enum { + LL_LOG_FLAG_CONTINUE = 0, + LL_LOG_FLAG_END, + LL_LOG_FLAG_TASK, + LL_LOG_FLAG_ISR, + LL_LOG_FLAG_HCI, + LL_LOG_FLAG_RAW, + LL_LOG_FLAG_SYNC +}; + +enum { + LL_EV_FLAG_ISR_APPEND = 0, + LL_EV_FLAG_FLUSH_LOG, +}; + +// Private variables +static bool uhci_out_inited = false; +static uhci_controller_handle_t uhci_handle = NULL; + +static bool user_log_inited = false; +static SemaphoreHandle_t user_log_mutex = NULL; +static uhci_out_log_cb_t *user_log_cb = NULL; +static uint32_t user_last_write_ts = 0; + +static bool ll_log_inited = false; +static uhci_out_log_cb_t *ll_task_log_cb = NULL; +static uhci_out_log_cb_t *ll_isr_log_cb = NULL; +static uhci_out_log_cb_t *ll_hci_log_cb = NULL; +static uint32_t ll_ev_flags = 0; +static uint32_t ll_last_write_ts = 0; + +static esp_timer_handle_t flush_timer = NULL; + +// Private function declarations +extern void esp_panic_handler_feed_wdts(void); + +static int uhci_out_init_trans(uhci_out_trans_cb_t **trans_cb, uint16_t buf_size); +static void uhci_out_deinit_trans(uhci_out_trans_cb_t **trans_cb); +static bool uhci_out_tx_done_cb(uhci_controller_handle_t uhci_ctrl, + const uhci_tx_done_event_data_t *edata, void *user_ctx); +static inline void uhci_out_append_trans(uhci_out_trans_cb_t *trans_cb); + +static int uhci_out_log_cb_init(uhci_out_log_cb_t **log_cb, uint16_t buf_size, uint8_t type, uint8_t idx); +static void uhci_out_log_cb_deinit(uhci_out_log_cb_t **log_cb); +static inline bool uhci_out_log_cb_check_trans(uhci_out_log_cb_t *log_cb, uint16_t len, bool *need_append); +static inline void uhci_out_log_cb_append_trans(uhci_out_log_cb_t *log_cb); +static inline void uhci_out_log_cb_flush_trans(uhci_out_log_cb_t *log_cb); +static bool uhci_out_log_cb_write(uhci_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 void uhci_out_log_cb_write_loss(uhci_out_log_cb_t *log_cb); +static void uhci_out_log_cb_dump(uhci_out_log_cb_t *log_cb); + +static void esp_timer_cb_log_flush(void); +static void uhci_out_user_write_str(const uint8_t *src, uint16_t len); + +#if UHCI_OUT_UART_PORT == UHCI_OUT_UART_PORT0 +static void uhci_out_user_write_char(char c); +#endif // UHCI_OUT_UART_PORT == UHCI_OUT_UART_PORT0 + +static int uhci_out_user_log_init(void); +static void uhci_out_user_log_deinit(void); + +static int uhci_out_ll_log_init(void); +static void uhci_out_ll_log_deinit(void); +static void uhci_out_ll_log_flush(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 UHCI_OUT_LL_PUT_EV r_ble_log_simple_put_ev() +#elif defined(CONFIG_IDF_TARGET_ESP32C2) +extern void ble_log_simple_put_ev(void); +#define UHCI_OUT_LL_PUT_EV ble_log_simple_put_ev() +#else +#define UHCI_OUT_LL_PUT_EV +#endif + +// Private macros +#define UHCI_OUT_FRAME_HEAD_LEN (sizeof(frame_head_t)) +#define UHCI_OUT_FRAME_TAIL_LEN (sizeof(uint32_t)) +#define UHCI_OUT_FRAME_OVERHEAD (UHCI_OUT_FRAME_HEAD_LEN + UHCI_OUT_FRAME_TAIL_LEN) +#define UHCI_OUT_GET_FRAME_SN(VAR) __atomic_fetch_add(VAR, 1, __ATOMIC_RELAXED) + +// Private functions +static int uhci_out_init_trans(uhci_out_trans_cb_t **trans_cb, uint16_t buf_size) +{ + // Memory allocations + size_t cb_size = sizeof(uhci_out_trans_cb_t) + buf_size; + *trans_cb = (uhci_out_trans_cb_t *)UHCI_OUT_MALLOC(cb_size); + if (!(*trans_cb)) { + return -1; + } + memset(*trans_cb, 0, sizeof(uhci_out_trans_cb_t)); + + // Initialization + (*trans_cb)->buf_size = buf_size; + return 0; +} + +static void uhci_out_deinit_trans(uhci_out_trans_cb_t **trans_cb) +{ + if (!(*trans_cb)) { + return; + } + + free(*trans_cb); + *trans_cb = NULL; + return; +} + +IRAM_ATTR static bool uhci_out_tx_done_cb(uhci_controller_handle_t uhci_ctrl, + const uhci_tx_done_event_data_t *edata, void *user_ctx) +{ + uhci_out_trans_cb_t *trans_cb = (uhci_out_trans_cb_t *)((uint8_t *)edata->buffer - sizeof(uhci_out_trans_cb_t)); + trans_cb->length = 0; + trans_cb->flag = TRANS_CB_FLAG_AVAILABLE; + return true; +} + +IRAM_ATTR static inline void uhci_out_append_trans(uhci_out_trans_cb_t *trans_cb) +{ + if ((trans_cb->flag != TRANS_CB_FLAG_NEED_QUEUE) || !trans_cb->length) { + return; + } + + // Note: If task yield after transmission but before flag set + // flag might be reset in tx done ISR before flag set, leading to buffer access failure + trans_cb->flag = TRANS_CB_FLAG_IN_QUEUE; + if (uhci_transmit(uhci_handle, trans_cb->buffer, trans_cb->length) != ESP_OK) { + goto recycle; + } + return; + +recycle: + trans_cb->length = 0; + trans_cb->flag = TRANS_CB_FLAG_AVAILABLE; + return; +} + +static int uhci_out_log_cb_init(uhci_out_log_cb_t **log_cb, uint16_t buf_size, uint8_t type, uint8_t idx) +{ + // Initialize log control block + *log_cb = (uhci_out_log_cb_t *)UHCI_OUT_MALLOC(sizeof(uhci_out_log_cb_t)); + if (!(*log_cb)) { + return -1; + } + memset(*log_cb, 0, sizeof(uhci_out_log_cb_t)); + + // Initialize transactions + int ret = 0; + for (uint8_t i = 0; i < 2; i++) { + ret |= uhci_out_init_trans(&((*log_cb)->trans_cb[i]), buf_size); + } + if (ret != 0) { + uhci_out_log_cb_deinit(log_cb); + return -1; + } + + (*log_cb)->type = (type << 4) | (idx); + return 0; +} + +static void uhci_out_log_cb_deinit(uhci_out_log_cb_t **log_cb) +{ + if (!(*log_cb)) { + return; + } + + for (uint8_t i = 0; i < 2; i++) { + if ((*log_cb)->trans_cb[i]) { + uhci_out_deinit_trans(&((*log_cb)->trans_cb[i])); + } + } + free(*log_cb); + *log_cb = NULL; + return; +} + +IRAM_ATTR static inline bool uhci_out_log_cb_check_trans(uhci_out_log_cb_t *log_cb, uint16_t len, bool *need_append) +{ + uhci_out_trans_cb_t *trans_cb; + *need_append = false; + for (uint8_t i = 0; i < 2; i++) { + trans_cb = log_cb->trans_cb[log_cb->trans_cb_idx]; + if (len > trans_cb->buf_size) { + goto failed; + } + if (trans_cb->flag == TRANS_CB_FLAG_AVAILABLE) { + if ((trans_cb->buf_size - trans_cb->length) >= len) { + return true; + } else { + trans_cb->flag = TRANS_CB_FLAG_NEED_QUEUE; + *need_append = true; + } + } + log_cb->trans_cb_idx = !(log_cb->trans_cb_idx); + } +failed: + log_cb->lost_bytes_cnt += len; + log_cb->lost_frame_cnt++; + return false; +} + +// CRITICAL: Shall not be called from ISR! +IRAM_ATTR static inline void uhci_out_log_cb_append_trans(uhci_out_log_cb_t *log_cb) +{ + uhci_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 == TRANS_CB_FLAG_NEED_QUEUE) { + uhci_out_append_trans(trans_cb); + } + idx = !idx; + } +} + +IRAM_ATTR static inline void uhci_out_log_cb_flush_trans(uhci_out_log_cb_t *log_cb) +{ + uhci_out_trans_cb_t *trans_cb; + for (uint8_t i = 0; i < 2; i++) { + trans_cb = log_cb->trans_cb[i]; + if (trans_cb->length && (trans_cb->flag == TRANS_CB_FLAG_AVAILABLE)) { + trans_cb->flag = TRANS_CB_FLAG_NEED_QUEUE; + } + } +} + +// Return value: Need append +IRAM_ATTR static bool uhci_out_log_cb_write(uhci_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) +{ + uhci_out_trans_cb_t *trans_cb = log_cb->trans_cb[log_cb->trans_cb_idx]; + + uint8_t *buf = trans_cb->buffer + trans_cb->length; + uint16_t total_length = len + len_append; + frame_head_t head = { + .length = total_length, + .source = source, + .type = log_cb->type, + .frame_sn = UHCI_OUT_GET_FRAME_SN(&(log_cb->frame_sn)) & 0xFFFF, + }; + + memcpy(buf, (const uint8_t *)&head, UHCI_OUT_FRAME_HEAD_LEN); + memcpy(buf + UHCI_OUT_FRAME_HEAD_LEN, addr, len); + if (len_append && addr_append) { + memcpy(buf + UHCI_OUT_FRAME_HEAD_LEN + len, addr_append, len_append); + } + + uint32_t checksum = 0; + for (int i = 0; i < UHCI_OUT_FRAME_HEAD_LEN + total_length; i++) { + checksum += buf[i]; + } + memcpy(buf + UHCI_OUT_FRAME_HEAD_LEN + total_length, &checksum, UHCI_OUT_FRAME_TAIL_LEN); + + trans_cb->length += total_length + UHCI_OUT_FRAME_OVERHEAD; + if ((trans_cb->buf_size - trans_cb->length) <= UHCI_OUT_FRAME_OVERHEAD) { + trans_cb->flag = TRANS_CB_FLAG_NEED_QUEUE; + return true; + } + return false; +} + +IRAM_ATTR static void uhci_out_log_cb_write_loss(uhci_out_log_cb_t *log_cb) +{ + if (!log_cb->lost_bytes_cnt || !log_cb->lost_frame_cnt) { + return; + } + bool need_append; + uint16_t frame_len = sizeof(loss_payload_t) + UHCI_OUT_FRAME_OVERHEAD; + if (uhci_out_log_cb_check_trans(log_cb, frame_len, &need_append)) { + loss_payload_t payload = { + .type = log_cb->type, + .lost_frame_cnt = log_cb->lost_frame_cnt, + .lost_bytes_cnt = log_cb->lost_bytes_cnt, + }; + uhci_out_log_cb_write(log_cb, (const uint8_t *)&payload, sizeof(loss_payload_t), + NULL, 0, BLE_LOG_UHCI_OUT_SOURCE_LOSS); + + log_cb->lost_frame_cnt = 0; + log_cb->lost_bytes_cnt = 0; + } +} + +static void uhci_out_log_cb_dump(uhci_out_log_cb_t *log_cb) +{ + uhci_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->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 void esp_timer_cb_log_flush(void) +{ + uint32_t os_ts = pdTICKS_TO_MS(xTaskGetTickCount()); + + if ((os_ts - user_last_write_ts) > UHCI_OUT_FLUSH_TIMEOUT_MS) { + xSemaphoreTake(user_log_mutex, portMAX_DELAY); + uhci_out_log_cb_flush_trans(user_log_cb); + uhci_out_log_cb_append_trans(user_log_cb); + xSemaphoreGive(user_log_mutex); + } + + if ((esp_bt_controller_get_status() >= ESP_BT_CONTROLLER_STATUS_INITED) && + ((os_ts - ll_last_write_ts) > UHCI_OUT_FLUSH_TIMEOUT_MS)) { + ll_ev_flags |= BIT(LL_EV_FLAG_FLUSH_LOG); + UHCI_OUT_LL_PUT_EV; + } + + esp_timer_start_once(flush_timer, UHCI_OUT_FLUSH_TIMEOUT_US); +} + +static void uhci_out_user_write_str(const uint8_t *src, uint16_t len) +{ + if (!user_log_inited || !src || !len) { + return; + } + + xSemaphoreTake(user_log_mutex, portMAX_DELAY); + + bool need_append; + if (uhci_out_log_cb_check_trans(user_log_cb, len, &need_append)) { + uhci_out_trans_cb_t *trans_cb = user_log_cb->trans_cb[user_log_cb->trans_cb_idx]; + uint8_t *buf = trans_cb->buffer + trans_cb->length; + + memcpy(buf, (const uint8_t *)src, len); + trans_cb->length += len; + } + + if (need_append) { + uhci_out_log_cb_append_trans(user_log_cb); + } + + user_last_write_ts = pdTICKS_TO_MS(xTaskGetTickCount()); + + xSemaphoreGive(user_log_mutex); +} + +#if UHCI_OUT_UART_PORT == UHCI_OUT_UART_PORT0 +static void uhci_out_user_write_char(char c) +{ + uhci_out_user_write_str((const uint8_t *)&c, 1); +} +#endif // UHCI_OUT_UART_PORT == UHCI_OUT_UART_PORT0 + +static int uhci_out_user_log_init(void) +{ + if (user_log_inited) { + return 0; + } + + // Initialize mutex + user_log_mutex = xSemaphoreCreateMutex(); + if (!user_log_mutex) { + goto failed; + } + + // Initialize log control block + if (uhci_out_log_cb_init(&user_log_cb, UHCI_OUT_USER_BUF_SIZE, LOG_CB_TYPE_USER, 0) != 0) { + goto failed; + } + + // Initialization done + user_log_inited = true; + return 0; + +failed: + uhci_out_user_log_deinit(); + return -1; +} + +static void uhci_out_user_log_deinit(void) +{ + user_log_inited = false; + + if (!user_log_mutex) { + return; + } + xSemaphoreTake(user_log_mutex, portMAX_DELAY); + + uhci_out_log_cb_deinit(&user_log_cb); + + xSemaphoreGive(user_log_mutex); + vSemaphoreDelete(user_log_mutex); + user_log_mutex = NULL; +} + +static int uhci_out_ll_log_init(void) +{ + if (ll_log_inited) { + return 0; + } + + if (uhci_out_log_cb_init(&ll_task_log_cb, UHCI_OUT_LL_TASK_BUF_SIZE, + LOG_CB_TYPE_LL, LOG_CB_LL_SUBTYPE_TASK) != 0) { + goto failed; + } + if (uhci_out_log_cb_init(&ll_isr_log_cb, UHCI_OUT_LL_ISR_BUF_SIZE, + LOG_CB_TYPE_LL, LOG_CB_LL_SUBTYPE_ISR) != 0) { + goto failed; + } + if (uhci_out_log_cb_init(&ll_hci_log_cb, UHCI_OUT_LL_HCI_BUF_SIZE, + LOG_CB_TYPE_LL, LOG_CB_LL_SUBTYPE_HCI) != 0) { + goto failed; + } + + ll_log_inited = true; + return 0; + +failed: + uhci_out_ll_log_deinit(); + return -1; +} + +static void uhci_out_ll_log_deinit(void) +{ + ll_log_inited = false; + + uhci_out_log_cb_deinit(&ll_hci_log_cb); + uhci_out_log_cb_deinit(&ll_isr_log_cb); + uhci_out_log_cb_deinit(&ll_task_log_cb); +} + +static void uhci_out_ll_log_flush(void) +{ + if (!ll_log_inited) { + return; + } + + uhci_out_log_cb_write_loss(ll_task_log_cb); + uhci_out_log_cb_write_loss(ll_hci_log_cb); + + uhci_out_log_cb_flush_trans(ll_task_log_cb); + uhci_out_log_cb_flush_trans(ll_hci_log_cb); + + portMUX_TYPE spinlock = portMUX_INITIALIZER_UNLOCKED; + portENTER_CRITICAL_SAFE(&spinlock); + uhci_out_log_cb_write_loss(ll_isr_log_cb); + uhci_out_log_cb_flush_trans(ll_isr_log_cb); + portEXIT_CRITICAL_SAFE(&spinlock); + + uhci_out_log_cb_append_trans(ll_task_log_cb); + uhci_out_log_cb_append_trans(ll_hci_log_cb); + uhci_out_log_cb_append_trans(ll_isr_log_cb); +} + +// Public functions +int ble_log_uhci_out_init(void) +{ + // Avoid double init + if (uhci_out_inited) { + return 0; + } + +#if UHCI_OUT_UART_NEED_INIT + uart_config_t uart_config = { + .baud_rate = UHCI_OUT_UART_BAUD_RATE, + .data_bits = UART_DATA_8_BITS, + .parity = UART_PARITY_DISABLE, + .stop_bits = UART_STOP_BITS_1, + .flow_ctrl = UART_HW_FLOWCTRL_CTS_RTS, + .rx_flow_ctrl_thresh = 122, + }; + // Configure UART parameters + uart_param_config(UHCI_OUT_UART_PORT, &uart_config); + uart_set_pin(UHCI_OUT_UART_PORT, UHCI_OUT_UART_IO_NUM_TX, -1, -1, -1); +#endif // UHCI_OUT_UART_NEED_INIT + + uhci_controller_config_t uhci_config = { + .uart_port = UHCI_OUT_UART_PORT, + .tx_trans_queue_depth = UHCI_OUT_QUEUE_SIZE, + .max_receive_internal_mem = 1024, + .max_transmit_size = UHCI_OUT_MAX_TRANSFER_SIZE, + .dma_burst_size = 32, + .rx_eof_flags.idle_eof = 1, + }; + if (uhci_new_controller(&uhci_config, &uhci_handle) != ESP_OK) { + goto failed; + } + + uhci_event_callbacks_t uhci_cbs = { + .on_tx_trans_done = uhci_out_tx_done_cb, + }; + uhci_register_event_callbacks(uhci_handle, &uhci_cbs, NULL); + + if (uhci_out_user_log_init() != 0) { + goto failed; + } + + if (uhci_out_ll_log_init() != 0) { + goto failed; + } + + esp_timer_create_args_t timer_args = { + .callback = (esp_timer_cb_t)esp_timer_cb_log_flush, + .dispatch_method = ESP_TIMER_TASK + }; + if (esp_timer_create(&timer_args, &flush_timer) != ESP_OK) { + goto failed; + } + +#if UHCI_OUT_UART_PORT == UHCI_OUT_UART_PORT0 + // Install UART Driver if not installed + if (!uart_is_driver_installed(UHCI_OUT_UART_PORT0)) { + uart_driver_install(UHCI_OUT_UART_PORT0, UHCI_OUT_UART_DRIVER_RX_BUF_SIZE, 0, 0, NULL, 0); + } + + // Redirect UART VFS Driver to UART Driver + uart_vfs_dev_use_driver(UHCI_OUT_UART_PORT0); + + // Redirect esp_rom_printf to BLE Log UHCI Out + esp_rom_install_channel_putc(1, uhci_out_user_write_char); + esp_rom_install_channel_putc(2, NULL); +#endif // UHCI_OUT_UART_PORT == UHCI_OUT_UART_PORT0 + + uhci_out_inited = true; + esp_timer_start_once(flush_timer, UHCI_OUT_FLUSH_TIMEOUT_US); + return 0; + +failed: + ble_log_uhci_out_deinit(); + return -1; +} + +void ble_log_uhci_out_deinit(void) +{ + uhci_out_inited = false; + + if (flush_timer) { + esp_timer_stop(flush_timer); + esp_timer_delete(flush_timer); + flush_timer = NULL; + } + + if (uhci_handle) { + uhci_wait_all_tx_transaction_done(uhci_handle, portMAX_DELAY); + uhci_del_controller(uhci_handle); + uhci_handle = NULL; + } + + uhci_out_ll_log_deinit(); + uhci_out_user_log_deinit(); +} + +IRAM_ATTR void ble_log_uhci_out_ll_write(uint32_t len, const uint8_t *addr, uint32_t len_append, + const uint8_t *addr_append, uint32_t flag) +{ + // Raw logs will come in case of assert, shall be printed to console directly + if (flag & BIT(LL_LOG_FLAG_RAW)) { + if (len && addr) { + for (uint32_t i = 0; i < len; i++) { esp_rom_printf("%02x ", addr[i]); } + } + if (len_append && addr_append) { + for (uint32_t i = 0; i < len_append; i++) { esp_rom_printf("%02x ", addr_append[i]); } + } + if (flag & BIT(LL_LOG_FLAG_END)) { esp_rom_printf("\n"); } + } + + if (!ll_log_inited) { + return; + } + + bool in_isr = false; + uint8_t source; + uhci_out_log_cb_t *log_cb; + if (flag & BIT(LL_LOG_FLAG_ISR)) { + log_cb = ll_isr_log_cb; + source = BLE_LOG_UHCI_OUT_SOURCE_ESP_ISR; + in_isr = true; + } else if (flag & BIT(LL_LOG_FLAG_HCI)) { + log_cb = ll_hci_log_cb; + source = BLE_LOG_UHCI_OUT_SOURCE_LL_HCI; + } else { + log_cb = ll_task_log_cb; + source = BLE_LOG_UHCI_OUT_SOURCE_ESP; + } + + bool need_append; + uint16_t frame_len = len + len_append + UHCI_OUT_FRAME_OVERHEAD; + if (uhci_out_log_cb_check_trans(log_cb, frame_len, &need_append)) { + need_append |= uhci_out_log_cb_write(log_cb, addr, len, addr_append, + len_append, source); + } + + ll_last_write_ts = in_isr?\ + pdTICKS_TO_MS(xTaskGetTickCountFromISR()):\ + pdTICKS_TO_MS(xTaskGetTickCount()); + + if (need_append) { + if (in_isr) { + ll_ev_flags |= BIT(LL_EV_FLAG_ISR_APPEND); + UHCI_OUT_LL_PUT_EV; + } else { + uhci_out_log_cb_append_trans(log_cb); + } + } +} + +IRAM_ATTR void ble_log_uhci_out_ll_log_ev_proc(void) +{ + if (!ll_log_inited) { + return; + } + + if (ll_ev_flags & BIT(LL_EV_FLAG_ISR_APPEND)) { + uhci_out_log_cb_append_trans(ll_isr_log_cb); + ll_ev_flags &= ~BIT(LL_EV_FLAG_ISR_APPEND); + } + + if (ll_ev_flags & BIT(LL_EV_FLAG_FLUSH_LOG)) { + uhci_out_ll_log_flush(); + ll_ev_flags &= ~BIT(LL_EV_FLAG_FLUSH_LOG); + } + + ll_ev_flags = 0; +} + +// Redirect UART Driver to BLE Log UHCI Out +int __real_uart_tx_chars(uart_port_t uart_num, const char *buffer, uint32_t len); +int __wrap_uart_tx_chars(uart_port_t uart_num, const char *buffer, uint32_t len) +{ +#if UHCI_OUT_UART_PORT == UHCI_OUT_UART_PORT0 + uhci_out_user_write_str((const uint8_t *)buffer, len); + return 0; +#else + return __real_uart_tx_chars(uart_num, buffer, len); +#endif // UHCI_OUT_UART_PORT == UHCI_OUT_UART_PORT0 +} + +int __real_uart_write_bytes(uart_port_t uart_num, const void *src, size_t size); +int __wrap_uart_write_bytes(uart_port_t uart_num, const void *src, size_t size) +{ +#if UHCI_OUT_UART_PORT == UHCI_OUT_UART_PORT0 + uhci_out_user_write_str((const uint8_t *)src, size); + return 0; +#else + return __real_uart_write_bytes(uart_num, src, size); +#endif // UHCI_OUT_UART_PORT == UHCI_OUT_UART_PORT0 +} + +int __real_uart_write_bytes_with_break(uart_port_t uart_num, const void *src, size_t size, int brk_len); +int __wrap_uart_write_bytes_with_break(uart_port_t uart_num, const void *src, size_t size, int brk_len) +{ +#if UHCI_OUT_UART_PORT == UHCI_OUT_UART_PORT0 + return __wrap_uart_write_bytes(uart_num, src, size); +#else + return __real_uart_write_bytes_with_break(uart_num, src, size, brk_len); +#endif // UHCI_OUT_UART_PORT == UHCI_OUT_UART_PORT0 +} + +void ble_log_uhci_out_dump_all(void) +{ + if (!uhci_out_inited) { + return; + } + +#if UHCI_OUT_UART_PORT == UHCI_OUT_UART_PORT0 + esp_rom_output_tx_wait_idle(UHCI_OUT_UART_PORT0); + esp_rom_install_uart_printf(); +#endif // UHCI_OUT_UART_PORT == UHCI_OUT_UART_PORT0 + + portMUX_TYPE spinlock = portMUX_INITIALIZER_UNLOCKED; + portENTER_CRITICAL_SAFE(&spinlock); + + if (ll_log_inited) { + esp_rom_printf("[DUMP_START:\n"); + uhci_out_log_cb_dump(ll_isr_log_cb); + uhci_out_log_cb_dump(ll_task_log_cb); + uhci_out_log_cb_dump(ll_hci_log_cb); + esp_rom_printf("\n:DUMP_END]\n\n"); + } + portEXIT_CRITICAL_SAFE(&spinlock); + +#if UHCI_OUT_UART_PORT == UHCI_OUT_UART_PORT0 + esp_rom_install_channel_putc(1, uhci_out_user_write_char); +#endif // UHCI_OUT_UART_PORT == UHCI_OUT_UART_PORT0 +} +#endif // CONFIG_BT_BLE_LOG_UHCI_OUT_ENABLED diff --git a/components/bt/common/ble_log/include/ble_log/ble_log_uhci_out.h b/components/bt/common/ble_log/include/ble_log/ble_log_uhci_out.h new file mode 100644 index 0000000000..b3e5f1e541 --- /dev/null +++ b/components/bt/common/ble_log/include/ble_log/ble_log_uhci_out.h @@ -0,0 +1,35 @@ +/* + * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef __BT_SPI_OUT_H__ +#define __BT_SPI_OUT_H__ + +#include +#include +#include "driver/uhci.h" +#include "driver/uart.h" +#include "driver/uart_vfs.h" +#include "esp_rom_serial_output.h" +#include "esp_timer.h" +#include "freertos/semphr.h" + +// Public enums +enum { + BLE_LOG_UHCI_OUT_SOURCE_ESP = 0, + BLE_LOG_UHCI_OUT_SOURCE_ESP_ISR = 6, + BLE_LOG_UHCI_OUT_SOURCE_LL_HCI = 8, + BLE_LOG_UHCI_OUT_SOURCE_USER = 0x10, + BLE_LOG_UHCI_OUT_SOURCE_LOSS = 0xFF, +}; + +// Public functions +int ble_log_uhci_out_init(void); +void ble_log_uhci_out_deinit(void); +void ble_log_uhci_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_uhci_out_ll_log_ev_proc(void); +void ble_log_uhci_out_dump_all(void); + +#endif // __BT_SPI_OUT_H__ diff --git a/components/bt/controller/esp32c5/Kconfig.in b/components/bt/controller/esp32c5/Kconfig.in index a95e6ef679..e027a57155 100644 --- a/components/bt/controller/esp32c5/Kconfig.in +++ b/components/bt/controller/esp32c5/Kconfig.in @@ -320,6 +320,16 @@ menu "Controller debug features" help Output ble controller logs to SPI bus + config BT_LE_CONTROLLER_LOG_UHCI_OUT_ENABLED + bool "Output ble controller logs via UART DMA (Experimental)" + depends on BT_LE_CONTROLLER_LOG_ENABLED + depends on !BT_LE_CONTROLLER_LOG_DUMP_ONLY + depends on !BT_LE_CONTROLLER_LOG_SPI_OUT_ENABLED + select BT_BLE_LOG_UHCI_OUT_ENABLED + default y + help + Output ble controller logs via UART DMA + config BT_LE_CONTROLLER_LOG_STORAGE_ENABLE bool "Store ble controller logs to flash(Experimental)" depends on !BT_LE_CONTROLLER_LOG_DUMP_ONLY diff --git a/components/bt/controller/esp32c5/bt.c b/components/bt/controller/esp32c5/bt.c index 3d035ac307..e928a3656b 100644 --- a/components/bt/controller/esp32c5/bt.c +++ b/components/bt/controller/esp32c5/bt.c @@ -60,6 +60,10 @@ #include "ble_log/ble_log_spi_out.h" #endif // CONFIG_BT_BLE_LOG_SPI_OUT_ENABLED +#if CONFIG_BT_BLE_LOG_UHCI_OUT_ENABLED +#include "ble_log/ble_log_uhci_out.h" +#endif // CONFIG_BT_BLE_LOG_UHCI_OUT_ENABLED + /* Macro definition ************************************************************************ */ @@ -189,9 +193,9 @@ 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 -#if !CONFIG_BT_LE_CONTROLLER_LOG_SPI_OUT_ENABLED +#if !CONFIG_BT_LE_CONTROLLER_LOG_SPI_OUT_ENABLED && !CONFIG_BT_LE_CONTROLLER_LOG_UHCI_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 +#endif // !CONFIG_BT_LE_CONTROLLER_LOG_SPI_OUT_ENABLED && !CONFIG_BT_LE_CONTROLLER_LOG_UHCI_OUT_ENABLED #if CONFIG_BT_LE_CONTROLLER_LOG_STORAGE_ENABLE static void esp_bt_ctrl_log_partition_get_and_erase_first_block(void); #endif // CONFIG_BT_LE_CONTROLLER_LOG_STORAGE_ENABLE @@ -218,25 +222,35 @@ esp_err_t esp_bt_controller_log_init(void) } #endif // CONFIG_BT_BLE_LOG_SPI_OUT_ENABLED +#if CONFIG_BT_BLE_LOG_UHCI_OUT_ENABLED + if (ble_log_uhci_out_init() != 0) { + goto uhci_out_init_failed; + } +#endif // CONFIG_BT_BLE_LOG_UHCI_OUT_ENABLED + #if CONFIG_BT_LE_CONTROLLER_LOG_SPI_OUT_ENABLED if (r_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 +#elif CONFIG_BT_LE_CONTROLLER_LOG_UHCI_OUT_ENABLED + if (r_ble_log_init_simple(ble_log_uhci_out_ll_write, ble_log_uhci_out_ll_log_ev_proc) != 0) { + goto log_init_failed; + } +#else 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 #if CONFIG_BT_LE_CONTROLLER_LOG_HCI_ENABLED buffers |= ESP_BLE_LOG_BUF_HCI; -#endif // CONFIG_BT_LE_CONTROLLER_LOG_HCI_ENABLED +#endif 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 +#endif if (r_ble_log_init_async(esp_bt_controller_log_interface, task_create, buffers, (uint32_t *)log_bufs_size) != 0) { goto log_init_failed; @@ -252,14 +266,20 @@ esp_err_t esp_bt_controller_log_init(void) ctrl_level_init_failed: #if CONFIG_BT_LE_CONTROLLER_LOG_SPI_OUT_ENABLED r_ble_log_deinit_simple(); -#else // !CONFIG_BT_LE_CONTROLLER_LOG_SPI_OUT_ENABLED +#elif CONFIG_BT_LE_CONTROLLER_LOG_UHCI_OUT_ENABLED + r_ble_log_deinit_simple(); +#else r_ble_log_deinit_async(); -#endif // CONFIG_BT_LE_CONTROLLER_LOG_SPI_OUT_ENABLED +#endif 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 +#if CONFIG_BT_BLE_LOG_UHCI_OUT_ENABLED + ble_log_uhci_out_deinit(); +uhci_out_init_failed: +#endif // CONFIG_BT_BLE_LOG_UHCI_OUT_ENABLED return ESP_FAIL; } @@ -269,11 +289,17 @@ void esp_bt_controller_log_deinit(void) ble_log_spi_out_deinit(); #endif // CONFIG_BT_BLE_LOG_SPI_OUT_ENABLED +#if CONFIG_BT_BLE_LOG_UHCI_OUT_ENABLED + ble_log_uhci_out_deinit(); +#endif // CONFIG_BT_BLE_LOG_UHCI_OUT_ENABLED + #if CONFIG_BT_LE_CONTROLLER_LOG_SPI_OUT_ENABLED r_ble_log_deinit_simple(); -#else // !CONFIG_BT_LE_CONTROLLER_LOG_SPI_OUT_ENABLED +#elif CONFIG_BT_LE_CONTROLLER_LOG_UHCI_OUT_ENABLED + r_ble_log_deinit_simple(); +#else r_ble_log_deinit_async(); -#endif // CONFIG_BT_LE_CONTROLLER_LOG_SPI_OUT_ENABLED +#endif log_is_inited = false; } @@ -1412,7 +1438,7 @@ esp_power_level_t esp_ble_tx_power_get_enhanced(esp_ble_enhanced_power_type_t po } #if CONFIG_BT_LE_CONTROLLER_LOG_ENABLED -#if !CONFIG_BT_LE_CONTROLLER_LOG_SPI_OUT_ENABLED +#if !CONFIG_BT_LE_CONTROLLER_LOG_SPI_OUT_ENABLED && !CONFIG_BT_LE_CONTROLLER_LOG_UHCI_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 & BIT(BLE_LOG_INTERFACE_FLAG_END)); @@ -1434,7 +1460,7 @@ static void esp_bt_controller_log_interface(uint32_t len, const uint8_t *addr, u portEXIT_CRITICAL_SAFE(&spinlock); #endif // CONFIG_BT_LE_CONTROLLER_LOG_STORAGE_ENABLE } -#endif // !CONFIG_BT_LE_CONTROLLER_LOG_SPI_OUT_ENABLED +#endif // !CONFIG_BT_LE_CONTROLLER_LOG_SPI_OUT_ENABLED && !CONFIG_BT_LE_CONTROLLER_LOG_UHCI_OUT_ENABLED void esp_ble_controller_log_dump_all(bool output) { @@ -1442,9 +1468,13 @@ void esp_ble_controller_log_dump_all(bool output) ble_log_spi_out_dump_all(); #endif // CONFIG_BT_BLE_LOG_SPI_OUT_ENABLED +#if CONFIG_BT_BLE_LOG_UHCI_OUT_ENABLED + ble_log_uhci_out_dump_all(); +#endif // CONFIG_BT_BLE_LOG_UHCI_OUT_ENABLED + #if CONFIG_BT_LE_CONTROLLER_LOG_STORAGE_ENABLE esp_bt_read_ctrl_log_from_flash(output); -#elif !CONFIG_BT_LE_CONTROLLER_LOG_SPI_OUT_ENABLED +#elif !CONFIG_BT_LE_CONTROLLER_LOG_SPI_OUT_ENABLED && !CONFIG_BT_LE_CONTROLLER_LOG_UHCI_OUT_ENABLED portMUX_TYPE spinlock = portMUX_INITIALIZER_UNLOCKED; portENTER_CRITICAL_SAFE(&spinlock); esp_panic_handler_feed_wdts(); diff --git a/components/bt/controller/esp32c6/Kconfig.in b/components/bt/controller/esp32c6/Kconfig.in index f7b2a7db92..22a21ea7b1 100644 --- a/components/bt/controller/esp32c6/Kconfig.in +++ b/components/bt/controller/esp32c6/Kconfig.in @@ -361,6 +361,16 @@ menu "Controller debug features" help Output ble controller logs to SPI bus + config BT_LE_CONTROLLER_LOG_UHCI_OUT_ENABLED + bool "Output ble controller logs via UART DMA (Experimental)" + depends on BT_LE_CONTROLLER_LOG_ENABLED + depends on !BT_LE_CONTROLLER_LOG_DUMP_ONLY + depends on !BT_LE_CONTROLLER_LOG_SPI_OUT_ENABLED + select BT_BLE_LOG_UHCI_OUT_ENABLED + default y + help + Output ble controller logs via UART DMA + config BT_LE_CONTROLLER_LOG_STORAGE_ENABLE bool "Store ble controller logs to flash(Experimental)" depends on !BT_LE_CONTROLLER_LOG_DUMP_ONLY diff --git a/components/bt/controller/esp32c6/bt.c b/components/bt/controller/esp32c6/bt.c index 123acde38c..40adeeef0d 100644 --- a/components/bt/controller/esp32c6/bt.c +++ b/components/bt/controller/esp32c6/bt.c @@ -64,6 +64,10 @@ #include "ble_log/ble_log_spi_out.h" #endif // CONFIG_BT_BLE_LOG_SPI_OUT_ENABLED +#if CONFIG_BT_BLE_LOG_UHCI_OUT_ENABLED +#include "ble_log/ble_log_uhci_out.h" +#endif // CONFIG_BT_BLE_LOG_UHCI_OUT_ENABLED + /* Macro definition ************************************************************************ */ @@ -205,9 +209,9 @@ 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 -#if !CONFIG_BT_LE_CONTROLLER_LOG_SPI_OUT_ENABLED +#if !CONFIG_BT_LE_CONTROLLER_LOG_SPI_OUT_ENABLED && !CONFIG_BT_LE_CONTROLLER_LOG_UHCI_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 +#endif // !CONFIG_BT_LE_CONTROLLER_LOG_SPI_OUT_ENABLED && !CONFIG_BT_LE_CONTROLLER_LOG_UHCI_OUT_ENABLED #if CONFIG_BT_LE_CONTROLLER_LOG_STORAGE_ENABLE static void esp_bt_ctrl_log_partition_get_and_erase_first_block(void); #endif // CONFIG_BT_LE_CONTROLLER_LOG_STORAGE_ENABLE @@ -234,11 +238,21 @@ esp_err_t esp_bt_controller_log_init(void) } #endif // CONFIG_BT_BLE_LOG_SPI_OUT_ENABLED +#if CONFIG_BT_BLE_LOG_UHCI_OUT_ENABLED + if (ble_log_uhci_out_init() != 0) { + goto uhci_out_init_failed; + } +#endif // CONFIG_BT_BLE_LOG_UHCI_OUT_ENABLED + #if CONFIG_BT_LE_CONTROLLER_LOG_SPI_OUT_ENABLED if (r_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 +#elif CONFIG_BT_LE_CONTROLLER_LOG_UHCI_OUT_ENABLED + if (r_ble_log_init_simple(ble_log_uhci_out_ll_write, ble_log_uhci_out_ll_log_ev_proc) != 0) { + goto log_init_failed; + } +#else uint8_t buffers = 0; #if CONFIG_BT_LE_CONTROLLER_LOG_CTRL_ENABLED buffers |= ESP_BLE_LOG_BUF_CONTROLLER; @@ -252,12 +266,12 @@ esp_err_t esp_bt_controller_log_init(void) 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 +#endif if (r_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 +#endif if (r_ble_log_ctrl_level_and_mod(CONFIG_BT_LE_CONTROLLER_LOG_OUTPUT_LEVEL, CONFIG_BT_LE_CONTROLLER_LOG_MOD_OUTPUT_SWITCH) != ESP_OK) { goto ctrl_level_init_failed; @@ -268,14 +282,20 @@ esp_err_t esp_bt_controller_log_init(void) ctrl_level_init_failed: #if CONFIG_BT_LE_CONTROLLER_LOG_SPI_OUT_ENABLED r_ble_log_deinit_simple(); -#else // !CONFIG_BT_LE_CONTROLLER_LOG_SPI_OUT_ENABLED +#elif CONFIG_BT_LE_CONTROLLER_LOG_UHCI_OUT_ENABLED + r_ble_log_deinit_simple(); +#else r_ble_log_deinit_async(); -#endif // CONFIG_BT_LE_CONTROLLER_LOG_SPI_OUT_ENABLED +#endif 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 +#if CONFIG_BT_BLE_LOG_UHCI_OUT_ENABLED + ble_log_uhci_out_deinit(); +uhci_out_init_failed: +#endif // CONFIG_BT_BLE_LOG_UHCI_OUT_ENABLED return ESP_FAIL; } @@ -285,11 +305,17 @@ void esp_bt_controller_log_deinit(void) ble_log_spi_out_deinit(); #endif // CONFIG_BT_BLE_LOG_SPI_OUT_ENABLED +#if CONFIG_BT_BLE_LOG_UHCI_OUT_ENABLED + ble_log_uhci_out_deinit(); +#endif // CONFIG_BT_BLE_LOG_UHCI_OUT_ENABLED + #if CONFIG_BT_LE_CONTROLLER_LOG_SPI_OUT_ENABLED r_ble_log_deinit_simple(); -#else // !CONFIG_BT_LE_CONTROLLER_LOG_SPI_OUT_ENABLED +#elif CONFIG_BT_LE_CONTROLLER_LOG_UHCI_OUT_ENABLED + r_ble_log_deinit_simple(); +#else r_ble_log_deinit_async(); -#endif // CONFIG_BT_LE_CONTROLLER_LOG_SPI_OUT_ENABLED +#endif log_is_inited = false; } @@ -1483,7 +1509,7 @@ esp_power_level_t esp_ble_tx_power_get_enhanced(esp_ble_enhanced_power_type_t po } #if CONFIG_BT_LE_CONTROLLER_LOG_ENABLED -#if !CONFIG_BT_LE_CONTROLLER_LOG_SPI_OUT_ENABLED +#if !CONFIG_BT_LE_CONTROLLER_LOG_SPI_OUT_ENABLED && !CONFIG_BT_LE_CONTROLLER_LOG_UHCI_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 & BIT(BLE_LOG_INTERFACE_FLAG_END)); @@ -1505,7 +1531,7 @@ static void esp_bt_controller_log_interface(uint32_t len, const uint8_t *addr, u portEXIT_CRITICAL_SAFE(&spinlock); #endif // CONFIG_BT_LE_CONTROLLER_LOG_STORAGE_ENABLE } -#endif // !CONFIG_BT_LE_CONTROLLER_LOG_SPI_OUT_ENABLED +#endif // !CONFIG_BT_LE_CONTROLLER_LOG_SPI_OUT_ENABLED && !CONFIG_BT_LE_CONTROLLER_LOG_UHCI_OUT_ENABLED void esp_ble_controller_log_dump_all(bool output) { @@ -1513,9 +1539,13 @@ void esp_ble_controller_log_dump_all(bool output) ble_log_spi_out_dump_all(); #endif // CONFIG_BT_BLE_LOG_SPI_OUT_ENABLED +#if CONFIG_BT_BLE_LOG_UHCI_OUT_ENABLED + ble_log_uhci_out_dump_all(); +#endif // CONFIG_BT_BLE_LOG_UHCI_OUT_ENABLED + #if CONFIG_BT_LE_CONTROLLER_LOG_STORAGE_ENABLE esp_bt_read_ctrl_log_from_flash(output); -#elif !CONFIG_BT_LE_CONTROLLER_LOG_SPI_OUT_ENABLED +#elif !CONFIG_BT_LE_CONTROLLER_LOG_SPI_OUT_ENABLED && !CONFIG_BT_LE_CONTROLLER_LOG_UHCI_OUT_ENABLED portMUX_TYPE spinlock = portMUX_INITIALIZER_UNLOCKED; portENTER_CRITICAL_SAFE(&spinlock); esp_panic_handler_feed_wdts(); diff --git a/components/bt/controller/esp32h2/Kconfig.in b/components/bt/controller/esp32h2/Kconfig.in index 5ff989a8b4..87de9de997 100644 --- a/components/bt/controller/esp32h2/Kconfig.in +++ b/components/bt/controller/esp32h2/Kconfig.in @@ -355,6 +355,16 @@ menu "Controller debug features" help Output ble controller logs to SPI bus + config BT_LE_CONTROLLER_LOG_UHCI_OUT_ENABLED + bool "Output ble controller logs via UART DMA (Experimental)" + depends on BT_LE_CONTROLLER_LOG_ENABLED + depends on !BT_LE_CONTROLLER_LOG_DUMP_ONLY + depends on !BT_LE_CONTROLLER_LOG_SPI_OUT_ENABLED + select BT_BLE_LOG_UHCI_OUT_ENABLED + default y + help + Output ble controller logs via UART DMA + config BT_LE_CONTROLLER_LOG_STORAGE_ENABLE bool "Store ble controller logs to flash(Experimental)" depends on !BT_LE_CONTROLLER_LOG_DUMP_ONLY diff --git a/components/bt/controller/esp32h2/bt.c b/components/bt/controller/esp32h2/bt.c index 28672c244a..e4f34c5935 100644 --- a/components/bt/controller/esp32h2/bt.c +++ b/components/bt/controller/esp32h2/bt.c @@ -59,6 +59,10 @@ #include "ble_log/ble_log_spi_out.h" #endif // CONFIG_BT_BLE_LOG_SPI_OUT_ENABLED +#if CONFIG_BT_BLE_LOG_UHCI_OUT_ENABLED +#include "ble_log/ble_log_uhci_out.h" +#endif // CONFIG_BT_BLE_LOG_UHCI_OUT_ENABLED + /* Macro definition ************************************************************************ */ @@ -191,9 +195,9 @@ 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 -#if !CONFIG_BT_LE_CONTROLLER_LOG_SPI_OUT_ENABLED +#if !CONFIG_BT_LE_CONTROLLER_LOG_SPI_OUT_ENABLED && !CONFIG_BT_LE_CONTROLLER_LOG_UHCI_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 +#endif // !CONFIG_BT_LE_CONTROLLER_LOG_SPI_OUT_ENABLED && !CONFIG_BT_LE_CONTROLLER_LOG_UHCI_OUT_ENABLED #if CONFIG_BT_LE_CONTROLLER_LOG_STORAGE_ENABLE static void esp_bt_ctrl_log_partition_get_and_erase_first_block(void); #endif // CONFIG_BT_LE_CONTROLLER_LOG_STORAGE_ENABLE @@ -220,11 +224,21 @@ esp_err_t esp_bt_controller_log_init(void) } #endif // CONFIG_BT_BLE_LOG_SPI_OUT_ENABLED +#if CONFIG_BT_BLE_LOG_UHCI_OUT_ENABLED + if (ble_log_uhci_out_init() != 0) { + goto uhci_out_init_failed; + } +#endif // CONFIG_BT_BLE_LOG_UHCI_OUT_ENABLED + #if CONFIG_BT_LE_CONTROLLER_LOG_SPI_OUT_ENABLED if (r_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 +#elif CONFIG_BT_LE_CONTROLLER_LOG_UHCI_OUT_ENABLED + if (r_ble_log_init_simple(ble_log_uhci_out_ll_write, ble_log_uhci_out_ll_log_ev_proc) != 0) { + goto log_init_failed; + } +#else uint8_t buffers = 0; #if CONFIG_BT_LE_CONTROLLER_LOG_CTRL_ENABLED buffers |= ESP_BLE_LOG_BUF_CONTROLLER; @@ -238,12 +252,12 @@ esp_err_t esp_bt_controller_log_init(void) 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 +#endif if (r_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 +#endif if (r_ble_log_ctrl_level_and_mod(CONFIG_BT_LE_CONTROLLER_LOG_OUTPUT_LEVEL, CONFIG_BT_LE_CONTROLLER_LOG_MOD_OUTPUT_SWITCH) != ESP_OK) { goto ctrl_level_init_failed; @@ -254,14 +268,20 @@ esp_err_t esp_bt_controller_log_init(void) ctrl_level_init_failed: #if CONFIG_BT_LE_CONTROLLER_LOG_SPI_OUT_ENABLED r_ble_log_deinit_simple(); -#else // !CONFIG_BT_LE_CONTROLLER_LOG_SPI_OUT_ENABLED +#elif CONFIG_BT_LE_CONTROLLER_LOG_UHCI_OUT_ENABLED + r_ble_log_deinit_simple(); +#else r_ble_log_deinit_async(); -#endif // CONFIG_BT_LE_CONTROLLER_LOG_SPI_OUT_ENABLED +#endif 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 +#if CONFIG_BT_BLE_LOG_UHCI_OUT_ENABLED + ble_log_uhci_out_deinit(); +uhci_out_init_failed: +#endif // CONFIG_BT_BLE_LOG_UHCI_OUT_ENABLED return ESP_FAIL; } @@ -271,11 +291,17 @@ void esp_bt_controller_log_deinit(void) ble_log_spi_out_deinit(); #endif // CONFIG_BT_BLE_LOG_SPI_OUT_ENABLED +#if CONFIG_BT_BLE_LOG_UHCI_OUT_ENABLED + ble_log_uhci_out_deinit(); +#endif // CONFIG_BT_BLE_LOG_UHCI_OUT_ENABLED + #if CONFIG_BT_LE_CONTROLLER_LOG_SPI_OUT_ENABLED r_ble_log_deinit_simple(); -#else // !CONFIG_BT_LE_CONTROLLER_LOG_SPI_OUT_ENABLED +#elif CONFIG_BT_LE_CONTROLLER_LOG_UHCI_OUT_ENABLED + r_ble_log_deinit_simple(); +#else r_ble_log_deinit_async(); -#endif // CONFIG_BT_LE_CONTROLLER_LOG_SPI_OUT_ENABLED +#endif log_is_inited = false; } @@ -1406,7 +1432,7 @@ esp_power_level_t esp_ble_tx_power_get_enhanced(esp_ble_enhanced_power_type_t po } #if CONFIG_BT_LE_CONTROLLER_LOG_ENABLED -#if !CONFIG_BT_LE_CONTROLLER_LOG_SPI_OUT_ENABLED +#if !CONFIG_BT_LE_CONTROLLER_LOG_SPI_OUT_ENABLED && !CONFIG_BT_LE_CONTROLLER_LOG_UHCI_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 & BIT(BLE_LOG_INTERFACE_FLAG_END)); @@ -1428,7 +1454,7 @@ static void esp_bt_controller_log_interface(uint32_t len, const uint8_t *addr, u portEXIT_CRITICAL_SAFE(&spinlock); #endif // CONFIG_BT_LE_CONTROLLER_LOG_STORAGE_ENABLE } -#endif // !CONFIG_BT_LE_CONTROLLER_LOG_SPI_OUT_ENABLED +#endif // !CONFIG_BT_LE_CONTROLLER_LOG_SPI_OUT_ENABLED && !CONFIG_BT_LE_CONTROLLER_LOG_UHCI_OUT_ENABLED void esp_ble_controller_log_dump_all(bool output) { @@ -1436,9 +1462,13 @@ void esp_ble_controller_log_dump_all(bool output) ble_log_spi_out_dump_all(); #endif // CONFIG_BT_BLE_LOG_SPI_OUT_ENABLED +#if CONFIG_BT_BLE_LOG_UHCI_OUT_ENABLED + ble_log_uhci_out_dump_all(); +#endif // CONFIG_BT_BLE_LOG_UHCI_OUT_ENABLED + #if CONFIG_BT_LE_CONTROLLER_LOG_STORAGE_ENABLE esp_bt_read_ctrl_log_from_flash(output); -#elif !CONFIG_BT_LE_CONTROLLER_LOG_SPI_OUT_ENABLED +#elif !CONFIG_BT_LE_CONTROLLER_LOG_SPI_OUT_ENABLED && !CONFIG_BT_LE_CONTROLLER_LOG_UHCI_OUT_ENABLED portMUX_TYPE spinlock = portMUX_INITIALIZER_UNLOCKED; portENTER_CRITICAL_SAFE(&spinlock); esp_panic_handler_feed_wdts();