Merge branch 'feat/optimize_bt_porting_hci_0628_5.2' into 'release/v5.2'

Feat/optimize bt porting hci 0628 5.2

See merge request espressif/esp-idf!32133
This commit is contained in:
Island
2024-07-17 19:29:31 +08:00
42 changed files with 3133 additions and 940 deletions

View File

@ -110,6 +110,7 @@ if(CONFIG_BT_ENABLED)
common/btc/include
common/include
porting/mem/
porting/include
)
list(APPEND include_dirs ${common_include_dirs})
@ -569,26 +570,48 @@ if(CONFIG_BT_ENABLED)
list(APPEND srcs
"porting/npl/freertos/src/npl_os_freertos.c"
"porting/mem/os_msys_init.c"
"porting/transport/src/hci_transport.c"
)
if(CONFIG_BT_CONTROLLER_DISABLED)
list(APPEND srcs
"host/nimble/nimble/porting/nimble/src/hal_uart.c"
)
elseif(CONFIG_BT_LE_HCI_INTERFACE_USE_RAM)
if(CONFIG_BT_NIMBLE_ENABLED)
list(APPEND srcs
"porting/transport/driver/vhci/hci_driver_nimble.c"
"host/nimble/nimble/nimble/transport/esp_ipc/src/hci_esp_ipc.c"
)
else()
list(APPEND srcs
"porting/transport/driver/vhci/hci_driver_standard.c"
)
endif()
elseif(CONFIG_BT_LE_HCI_INTERFACE_USE_UART)
list(APPEND srcs
"porting/transport/driver/common/hci_driver_util.c"
"porting/transport/driver/common/hci_driver_h4.c"
"porting/transport/driver/common/hci_driver_mem.c"
"porting/transport/driver/uart/hci_driver_uart_config.c"
)
if(CONFIG_BT_LE_UART_HCI_DMA_MODE)
list(APPEND srcs
"porting/transport/driver/uart/hci_driver_uart_dma.c"
)
else()
list(APPEND srcs
"porting/transport/driver/uart/hci_driver_uart.c"
)
endif()
endif()
list(APPEND include_dirs
porting/include
porting/npl/freertos/include
porting/transport/include
)
if(CONFIG_BT_LE_HCI_INTERFACE_USE_UART)
list(APPEND srcs
"porting/transport/uart/hci_uart.c"
)
endif()
endif()
if(NOT (CONFIG_BT_LE_CRYPTO_STACK_MBEDTLS OR CONFIG_BT_NIMBLE_CRYPTO_STACK_MBEDTLS))
list(APPEND include_dirs
@ -614,7 +637,6 @@ if(CONFIG_BT_ENABLED)
if(CONFIG_BT_NIMBLE_ENABLED)
list(APPEND include_dirs
host/nimble/nimble/nimble/host/include
host/nimble/nimble/nimble/include
host/nimble/nimble/nimble/host/services/ans/include
@ -718,10 +740,12 @@ if(CONFIG_BT_ENABLED)
"host/nimble/nimble/porting/npl/freertos/src/nimble_port_freertos.c"
"host/nimble/port/src/nvs_port.c"
)
list(APPEND include_dirs
host/nimble/nimble/porting/nimble/include
host/nimble/port/include
host/nimble/nimble/nimble/transport/include
host/nimble/nimble/nimble/include
)
if(CONFIG_BT_CONTROLLER_DISABLED)
@ -755,6 +779,7 @@ if(CONFIG_BT_ENABLED)
if(CONFIG_BT_NIMBLE_LEGACY_VHCI_ENABLE AND CONFIG_BT_CONTROLLER_ENABLED)
list(APPEND srcs
"host/nimble/esp-hci/src/esp_nimble_hci.c"
"host/nimble/nimble/nimble/transport/esp_ipc_legacy/src/hci_esp_ipc_legacy.c"
)
list(APPEND include_dirs ${nimble_hci_include_dirs})
endif()

View File

@ -2,15 +2,15 @@
menu "HCI Config"
choice BT_LE_HCI_INTERFACE
prompt "Select HCI interface"
prompt "HCI mode"
default BT_LE_HCI_INTERFACE_USE_RAM
config BT_LE_HCI_INTERFACE_USE_RAM
bool "ram"
bool "VHCI"
help
Use RAM as HCI interface
config BT_LE_HCI_INTERFACE_USE_UART
bool "uart"
bool "UART(H4)"
help
Use UART as HCI interface
endchoice
@ -73,12 +73,26 @@ menu "HCI Config"
UART_PARITY_ODD
endchoice
config BT_LE_HCI_UART_TASK_STACK_SIZE
int "HCI uart task stack size"
depends on BT_LE_HCI_INTERFACE_USE_UART
default 1000
config BT_LE_HCI_UART_RX_BUFFER_SIZE
int "The size of rx ring buffer memory"
depends on !BT_LE_HCI_INTERFACE_USE_RAM
default 512
help
Set the size of uart task stack
The size of rx ring buffer memory
config BT_LE_HCI_UART_TX_BUFFER_SIZE
int "The size of tx ring buffer memory"
depends on !BT_LE_HCI_INTERFACE_USE_RAM
default 256
help
The size of tx ring buffer memory
config BT_LE_HCI_TRANS_TASK_STACK_SIZE
int "HCI transport task stack size"
depends on !BT_LE_HCI_INTERFACE_USE_RAM
default 1024
help
This configures stack size of hci transport task
endmenu
config BT_LE_CONTROLLER_NPL_OS_PORTING_SUPPORT

View File

@ -31,7 +31,7 @@
#endif
#include "nimble/nimble_npl_os.h"
#include "ble_hci_trans.h"
#include "esp_hci_transport.h"
#include "os/endian.h"
#include "esp_bt.h"
@ -42,13 +42,8 @@
#include "soc/syscon_reg.h"
#include "soc/modem_clkrst_reg.h"
#include "esp_private/periph_ctrl.h"
#include "hci_uart.h"
#include "bt_osi_mem.h"
#ifdef CONFIG_BT_BLUEDROID_ENABLED
#include "hci/hci_hal.h"
#endif
#if CONFIG_FREERTOS_USE_TICKLESS_IDLE
#include "esp_private/sleep_modem.h"
#endif // CONFIG_FREERTOS_USE_TICKLESS_IDLE
@ -65,6 +60,7 @@
#include "hal/efuse_ll.h"
#include "soc/rtc.h"
/* Macro definition
************************************************************************
*/
@ -77,12 +73,6 @@
#define EXT_FUNC_MAGIC_VALUE 0xA5A5A5A5
#define BT_ASSERT_PRINT ets_printf
#ifdef CONFIG_BT_BLUEDROID_ENABLED
/* ACL_DATA_MBUF_LEADINGSPCAE: The leadingspace in user info header for ACL data */
#define ACL_DATA_MBUF_LEADINGSPCAE 4
#endif // CONFIG_BT_BLUEDROID_ENABLED
typedef enum ble_rtc_slow_clk_src {
BT_SLOW_CLK_SRC_MAIN_XTAL,
BT_SLOW_CLK_SRC_32K_XTAL_ON_PIN0,
@ -106,12 +96,12 @@ struct ext_funcs_t {
int (*_esp_intr_free)(void **ret_handle);
void *(* _malloc)(size_t size);
void (*_free)(void *p);
void (*_hal_uart_start_tx)(int);
int (*_hal_uart_init_cbs)(int, hci_uart_tx_char, hci_uart_tx_done, hci_uart_rx_char, void *);
int (*_hal_uart_config)(int, int32_t, uint8_t, uint8_t, uart_parity_t, uart_hw_flowcontrol_t);
int (*_hal_uart_close)(int);
void (*_hal_uart_blocking_tx)(int, uint8_t);
int (*_hal_uart_init)(int, void *);
void (*_rsv1)(int);
int (*_rsv2)(int, int (*)(void *arg), int (*)(void *arg, uint8_t byte), int (*)(void *arg, uint8_t byte), void *);
int (*_rsv3)(int, int32_t, uint8_t, uint8_t, int, int);
int (*_rsv4)(int);
void (*_rsv5)(int, uint8_t);
int (*_rsv6)(int, void *);
int (* _task_create)(void *task_func, const char *name, uint32_t stack_depth, void *param, uint32_t prio, void *task_handle, uint32_t core_id);
void (* _task_delete)(void *task_handle);
void (*_osi_assert)(const uint32_t ln, const char *fn, uint32_t param1, uint32_t param2);
@ -189,16 +179,6 @@ static void coex_schm_status_bit_set_wrapper(uint32_t type, uint32_t status);
static void coex_schm_status_bit_clear_wrapper(uint32_t type, uint32_t status);
static int task_create_wrapper(void *task_func, const char *name, uint32_t stack_depth, void *param, uint32_t prio, void *task_handle, uint32_t core_id);
static void task_delete_wrapper(void *task_handle);
#if CONFIG_BT_LE_HCI_INTERFACE_USE_UART
static void hci_uart_start_tx_wrapper(int uart_no);
static int hci_uart_init_cbs_wrapper(int uart_no, hci_uart_tx_char tx_func,
hci_uart_tx_done tx_done, hci_uart_rx_char rx_func, void *arg);
static int hci_uart_config_wrapper(int uart_no, int32_t speed, uint8_t databits, uint8_t stopbits,
uart_parity_t parity, uart_hw_flowcontrol_t flow_ctl);
static int hci_uart_close_wrapper(int uart_no);
static void hci_uart_blocking_tx_wrapper(int port, uint8_t data);
static int hci_uart_init_wrapper(int uart_no, void *cfg);
#endif // CONFIG_BT_LE_HCI_INTERFACE_USE_UART
static int esp_intr_alloc_wrapper(int source, int flags, intr_handler_t handler,
void *arg, void **ret_handle_in);
static int esp_intr_free_wrapper(void **ret_handle);
@ -216,7 +196,6 @@ static void esp_bt_controller_log_interface(uint32_t len, const uint8_t *addr, b
*/
/* 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};
#endif // CONFIG_BT_LE_CONTROLLER_LOG_ENABLED
@ -230,7 +209,6 @@ static DRAM_ATTR esp_pm_lock_handle_t s_pm_lock = NULL;
#define BLE_RTC_DELAY_US (1800)
static const struct osi_coex_funcs_t s_osi_coex_funcs_ro = {
._magic = OSI_COEX_MAGIC_VALUE,
._version = OSI_COEX_VERSION,
@ -246,14 +224,6 @@ struct ext_funcs_t ext_funcs_ro = {
._esp_intr_free = esp_intr_free_wrapper,
._malloc = bt_osi_mem_malloc_internal,
._free = bt_osi_mem_free,
#if CONFIG_BT_LE_HCI_INTERFACE_USE_UART
._hal_uart_start_tx = hci_uart_start_tx_wrapper,
._hal_uart_init_cbs = hci_uart_init_cbs_wrapper,
._hal_uart_config = hci_uart_config_wrapper,
._hal_uart_close = hci_uart_close_wrapper,
._hal_uart_blocking_tx = hci_uart_blocking_tx_wrapper,
._hal_uart_init = hci_uart_init_wrapper,
#endif //CONFIG_BT_LE_HCI_INTERFACE_USE_UART
._task_create = task_create_wrapper,
._task_delete = task_delete_wrapper,
._osi_assert = osi_assert_wrapper,
@ -300,83 +270,6 @@ static void coex_schm_status_bit_clear_wrapper(uint32_t type, uint32_t status)
#endif // CONFIG_SW_COEXIST_ENABLE
}
#ifdef CONFIG_BT_BLUEDROID_ENABLED
bool esp_vhci_host_check_send_available(void)
{
if (ble_controller_status != ESP_BT_CONTROLLER_STATUS_ENABLED) {
return false;
}
return true;
}
/**
* Allocates an mbuf for use by the nimble host.
*/
static struct os_mbuf *ble_hs_mbuf_gen_pkt(uint16_t leading_space)
{
struct os_mbuf *om;
int rc;
om = os_msys_get_pkthdr(0, 0);
if (om == NULL) {
return NULL;
}
if (om->om_omp->omp_databuf_len < leading_space) {
rc = os_mbuf_free_chain(om);
assert(rc == 0);
return NULL;
}
om->om_data += leading_space;
return om;
}
/**
* Allocates an mbuf suitable for an HCI ACL data packet.
*
* @return An empty mbuf on success; null on memory
* exhaustion.
*/
struct os_mbuf *ble_hs_mbuf_acl_pkt(void)
{
return ble_hs_mbuf_gen_pkt(4 + 1);
}
void esp_vhci_host_send_packet(uint8_t *data, uint16_t len)
{
if (ble_controller_status != ESP_BT_CONTROLLER_STATUS_ENABLED) {
return;
}
if (*(data) == DATA_TYPE_COMMAND) {
struct ble_hci_cmd *cmd = NULL;
cmd = (struct ble_hci_cmd *) ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_CMD);
assert(cmd);
memcpy((uint8_t *)cmd, data + 1, len - 1);
ble_hci_trans_hs_cmd_tx((uint8_t *)cmd);
}
if (*(data) == DATA_TYPE_ACL) {
struct os_mbuf *om = os_msys_get_pkthdr(len, ACL_DATA_MBUF_LEADINGSPCAE);
assert(om);
assert(os_mbuf_append(om, &data[1], len - 1) == 0);
ble_hci_trans_hs_acl_tx(om);
}
}
esp_err_t esp_vhci_host_register_callback(const esp_vhci_host_callback_t *callback)
{
if (ble_controller_status != ESP_BT_CONTROLLER_STATUS_ENABLED) {
return ESP_FAIL;
}
ble_hci_trans_cfg_hs(ble_hs_hci_rx_evt, NULL, ble_hs_rx_data, NULL);
return ESP_OK;
}
#endif // CONFIG_BT_BLUEDROID_ENABLED
static int task_create_wrapper(void *task_func, const char *name, uint32_t stack_depth, void *param, uint32_t prio, void *task_handle, uint32_t core_id)
{
return (uint32_t)xTaskCreatePinnedToCore(task_func, name, stack_depth, param, prio, task_handle, (core_id < portNUM_PROCESSORS ? core_id : tskNO_AFFINITY));
@ -406,56 +299,6 @@ static int esp_ecc_gen_dh_key(const uint8_t *peer_pub_key_x, const uint8_t *peer
return rc;
}
#ifdef CONFIG_BT_LE_HCI_INTERFACE_USE_UART
static void hci_uart_start_tx_wrapper(int uart_no)
{
hci_uart_start_tx(uart_no);
}
static int hci_uart_init_cbs_wrapper(int uart_no, hci_uart_tx_char tx_func,
hci_uart_tx_done tx_done, hci_uart_rx_char rx_func, void *arg)
{
int rc = -1;
rc = hci_uart_init_cbs(uart_no, tx_func, tx_done, rx_func, arg);
return rc;
}
static int hci_uart_config_wrapper(int port_num, int32_t baud_rate, uint8_t data_bits,
uint8_t stop_bits,uart_parity_t parity,
uart_hw_flowcontrol_t flow_ctl)
{
int rc = -1;
rc = hci_uart_config(port_num, baud_rate, data_bits, stop_bits, parity, flow_ctl);
return rc;
}
static int hci_uart_close_wrapper(int uart_no)
{
int rc = -1;
rc = hci_uart_close(uart_no);
return rc;
}
static void hci_uart_blocking_tx_wrapper(int port, uint8_t data)
{
//This function is nowhere to use.
}
static int hci_uart_init_wrapper(int uart_no, void *cfg)
{
//This function is nowhere to use.
return 0;
}
#endif //CONFIG_BT_LE_HCI_INTERFACE_USE_UART
static int ble_hci_unregistered_hook(void*, void*)
{
ESP_LOGD(NIMBLE_PORT_LOG_TAG,"%s ble hci rx_evt is not registered.",__func__);
return 0;
}
static int esp_intr_alloc_wrapper(int source, int flags, intr_handler_t handler, void *arg, void **ret_handle_in)
{
int rc = esp_intr_alloc(source, flags | ESP_INTR_FLAG_IRAM, handler, arg, (intr_handle_t *)ret_handle_in);
@ -633,6 +476,7 @@ esp_err_t esp_bt_controller_init(esp_bt_controller_config_t *cfg)
esp_err_t ret = ESP_OK;
ble_npl_count_info_t npl_info;
ble_rtc_slow_clk_src_t rtc_clk_src;
uint8_t hci_transport_mode;
memset(&npl_info, 0, sizeof(ble_npl_count_info_t));
if (ble_controller_status != ESP_BT_CONTROLLER_STATUS_IDLE) {
@ -755,10 +599,19 @@ esp_err_t esp_bt_controller_init(esp_bt_controller_config_t *cfg)
ble_controller_status = ESP_BT_CONTROLLER_STATUS_INITED;
ble_hci_trans_cfg_hs((ble_hci_trans_rx_cmd_fn *)ble_hci_unregistered_hook,NULL,
(ble_hci_trans_rx_acl_fn *)ble_hci_unregistered_hook,NULL);
#if CONFIG_BT_LE_HCI_INTERFACE_USE_RAM
hci_transport_mode = HCI_TRANSPORT_VHCI;
#elif CONFIG_BT_LE_HCI_INTERFACE_USE_UART
hci_transport_mode = HCI_TRANSPORT_UART_NO_DMA;
#endif // CONFIG_BT_LE_HCI_INTERFACE_USE_RAM
ret = hci_transport_init(hci_transport_mode);
if (ret) {
ESP_LOGW(NIMBLE_PORT_LOG_TAG, "hci transport init failed %d", ret);
goto free_controller;
}
return ESP_OK;
free_controller:
hci_transport_deinit();
controller_sleep_deinit();
#if CONFIG_BT_LE_CONTROLLER_LOG_ENABLED
controller_init_err:
@ -787,6 +640,7 @@ esp_err_t esp_bt_controller_deinit(void)
return ESP_FAIL;
}
hci_transport_deinit();
controller_sleep_deinit();
#if CONFIG_BT_LE_CONTROLLER_LOG_ENABLED

View File

@ -28,7 +28,6 @@ extern "C" {
#else
#define BLE_LL_SCAN_PHY_NUMBER_N (1)
#endif
#define DEFAULT_BT_LE_MAX_PERIODIC_ADVERTISER_LIST MYNEWT_VAL(BLE_MAX_PERIODIC_ADVERTISER_LIST)
#define DEFAULT_BT_LE_MAX_PERIODIC_SYNCS MYNEWT_VAL(BLE_MAX_PERIODIC_SYNCS)
#define DEFAULT_BT_LE_MAX_CONNECTIONS MYNEWT_VAL(BLE_MAX_CONNECTIONS)
@ -152,6 +151,20 @@ extern "C" {
#else
#define DEFAULT_BT_LE_ROLE_OBSERVER (0)
#endif
#if defined (CONFIG_BT_LE_HCI_UART_FLOWCTRL)
#define DEFAULT_BT_LE_HCI_UART_FLOW_CTRL (CONFIG_BT_LE_HCI_UART_FLOWCTRL)
#if DEFAULT_BT_LE_HCI_UART_FLOW_CTRL
#define DEFAULT_BT_LE_HCI_UART_CTS_PIN (CONFIG_BT_LE_HCI_UART_CTS_PIN)
#define DEFAULT_BT_LE_HCI_UART_RTS_PIN (CONFIG_BT_LE_HCI_UART_RTS_PIN)
#else
#define DEFAULT_BT_LE_HCI_UART_CTS_PIN (-1)
#define DEFAULT_BT_LE_HCI_UART_RTS_PIN (-1)
#endif
#else
#define DEFAULT_BT_LE_HCI_UART_FLOW_CTRL (0)
#define DEFAULT_BT_LE_HCI_UART_CTS_PIN (-1)
#define DEFAULT_BT_LE_HCI_UART_RTS_PIN (-1)
#endif
#endif
#define DEFAULT_BT_LE_COEX_PHY_CODED_TX_RX_TLIM_EFF CONFIG_BT_LE_COEX_PHY_CODED_TX_RX_TLIM_EFF
@ -192,8 +205,6 @@ extern "C" {
#define DEFAULT_BT_LE_HCI_UART_DATA_BITS (UART_DATA_8_BITS)
#define DEFAULT_BT_LE_HCI_UART_STOP_BITS (UART_STOP_BITS_1)
#define DEFAULT_BT_LE_HCI_UART_PARITY (0)
#define DEFAULT_BT_LE_HCI_UART_TASK_STACK_SIZE (CONFIG_BT_LE_HCI_UART_TASK_STACK_SIZE)
#define DEFAULT_BT_LE_HCI_UART_FLOW_CTRL (0)
#else
#define DEFAULT_BT_LE_HCI_UART_TX_PIN (0)
#define DEFAULT_BT_LE_HCI_UART_RX_PIN (0)
@ -202,8 +213,6 @@ extern "C" {
#define DEFAULT_BT_LE_HCI_UART_DATA_BITS (0)
#define DEFAULT_BT_LE_HCI_UART_STOP_BITS (0)
#define DEFAULT_BT_LE_HCI_UART_PARITY (0)
#define DEFAULT_BT_LE_HCI_UART_TASK_STACK_SIZE (0)
#define DEFAULT_BT_LE_HCI_UART_FLOW_CTRL (0)
#endif
/* Unchanged configuration */

View File

@ -2,19 +2,37 @@
menu "HCI Config"
choice BT_LE_HCI_INTERFACE
prompt "Select HCI interface"
prompt "HCI mode"
default BT_LE_HCI_INTERFACE_USE_RAM
config BT_LE_HCI_INTERFACE_USE_RAM
bool "ram"
bool "VHCI"
help
Use RAM as HCI interface
config BT_LE_HCI_INTERFACE_USE_UART
bool "uart"
bool "UART(H4)"
help
Use UART as HCI interface
endchoice
choice BT_LE_UART_HCI_MODE_CHOICE
prompt "UART HCI mode"
depends on BT_LE_HCI_INTERFACE_USE_UART
default BT_LE_UART_HCI_NO_DMA_MODE
help
Specify UART HCI mode: DMA or No DMA
config BT_LE_UART_HCI_DMA_MODE
bool "UHCI(UART with DMA)(EXPERIMENTAL)"
help
UART HCI Mode with DMA functionality.
config BT_LE_UART_HCI_NO_DMA_MODE
bool "UART(NO DMA)"
help
UART HCI Mode without DMA functionality.
endchoice
config BT_LE_HCI_UART_PORT
int "HCI UART port"
depends on BT_LE_HCI_INTERFACE_USE_UART
@ -73,12 +91,40 @@ menu "HCI Config"
UART_PARITY_ODD
endchoice
config BT_LE_HCI_UART_TASK_STACK_SIZE
int "HCI uart task stack size"
depends on BT_LE_HCI_INTERFACE_USE_UART
default 1000
config BT_LE_HCI_UART_RX_BUFFER_SIZE
int "The size of rx ring buffer memory"
depends on BT_LE_UART_HCI_NO_DMA_MODE
default 512
help
Set the size of uart task stack
The size of rx ring buffer memory
config BT_LE_HCI_UART_TX_BUFFER_SIZE
int "The size of tx ring buffer memory"
depends on BT_LE_UART_HCI_NO_DMA_MODE
default 256
help
The size of tx ring buffer memory
config BT_LE_HCI_TRANS_TASK_STACK_SIZE
int "HCI transport task stack size"
depends on !BT_LE_HCI_INTERFACE_USE_RAM
default 1024
help
This configures stack size of hci transport task
config BT_LE_HCI_TRANS_RX_MEM_NUM
int "The amount of rx memory received at the same time"
depends on BT_LE_UART_HCI_DMA_MODE
default 3
help
The amount of rx memory received at the same time
config BT_LE_HCI_LLDESCS_POOL_NUM
int "The amount of lldecs memory for driver dma mode"
depends on BT_LE_UART_HCI_DMA_MODE
default 20
help
The amount of lldecs memory for driver dma mode
endmenu
config BT_LE_CONTROLLER_NPL_OS_PORTING_SUPPORT

View File

@ -30,7 +30,7 @@
#endif // CONFIG_SW_COEXIST_ENABLE
#include "nimble/nimble_npl_os.h"
#include "ble_hci_trans.h"
#include "esp_hci_transport.h"
#include "os/endian.h"
#include "esp_bt.h"
@ -39,7 +39,6 @@
#include "esp_pm.h"
#include "esp_phy_init.h"
#include "esp_private/periph_ctrl.h"
#include "hci_uart.h"
#include "bt_osi_mem.h"
#if SOC_PM_RETENTION_HAS_CLOCK_BUG
@ -50,10 +49,6 @@
#include "esp_private/sleep_modem.h"
#endif // CONFIG_FREERTOS_USE_TICKLESS_IDLE
#ifdef CONFIG_BT_BLUEDROID_ENABLED
#include "hci/hci_hal.h"
#endif // CONFIG_BT_BLUEDROID_ENABLED
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
@ -69,16 +64,11 @@
#define OSI_COEX_VERSION 0x00010006
#define OSI_COEX_MAGIC_VALUE 0xFADEBEAD
#define EXT_FUNC_VERSION 0x20221122
#define EXT_FUNC_VERSION 0x20240422
#define EXT_FUNC_MAGIC_VALUE 0xA5A5A5A5
#define BT_ASSERT_PRINT ets_printf
#ifdef CONFIG_BT_BLUEDROID_ENABLED
/* ACL_DATA_MBUF_LEADINGSPCAE: The leadingspace in user info header for ACL data */
#define ACL_DATA_MBUF_LEADINGSPCAE 4
#endif // CONFIG_BT_BLUEDROID_ENABLED
/* Types definition
************************************************************************
*/
@ -97,12 +87,6 @@ struct ext_funcs_t {
int (*_esp_intr_free)(void **ret_handle);
void *(* _malloc)(size_t size);
void (*_free)(void *p);
void (*_hal_uart_start_tx)(int);
int (*_hal_uart_init_cbs)(int, hci_uart_tx_char, hci_uart_tx_done, hci_uart_rx_char, void *);
int (*_hal_uart_config)(int, int32_t, uint8_t, uint8_t, uart_parity_t, uart_hw_flowcontrol_t);
int (*_hal_uart_close)(int);
void (*_hal_uart_blocking_tx)(int, uint8_t);
int (*_hal_uart_init)(int, void *);
int (* _task_create)(void *task_func, const char *name, uint32_t stack_depth, void *param,
uint32_t prio, void *task_handle, uint32_t core_id);
void (* _task_delete)(void *task_handle);
@ -179,16 +163,6 @@ static void coex_schm_status_bit_clear_wrapper(uint32_t type, uint32_t status);
static int task_create_wrapper(void *task_func, const char *name, uint32_t stack_depth,
void *param, uint32_t prio, void *task_handle, uint32_t core_id);
static void task_delete_wrapper(void *task_handle);
#if CONFIG_BT_LE_HCI_INTERFACE_USE_UART
static void hci_uart_start_tx_wrapper(int uart_no);
static int hci_uart_init_cbs_wrapper(int uart_no, hci_uart_tx_char tx_func,
hci_uart_tx_done tx_done, hci_uart_rx_char rx_func, void *arg);
static int hci_uart_config_wrapper(int uart_no, int32_t speed, uint8_t databits, uint8_t stopbits,
uart_parity_t parity, uart_hw_flowcontrol_t flow_ctl);
static int hci_uart_close_wrapper(int uart_no);
static void hci_uart_blocking_tx_wrapper(int port, uint8_t data);
static int hci_uart_init_wrapper(int uart_no, void *cfg);
#endif // CONFIG_BT_LE_HCI_INTERFACE_USE_UART
static int esp_intr_alloc_wrapper(int source, int flags, intr_handler_t handler,
void *arg, void **ret_handle_in);
static int esp_intr_free_wrapper(void **ret_handle);
@ -206,7 +180,6 @@ static void esp_bt_controller_log_interface(uint32_t len, const uint8_t *addr, b
*/
/* 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};
#endif // CONFIG_BT_LE_CONTROLLER_LOG_ENABLED
@ -236,14 +209,6 @@ struct ext_funcs_t ext_funcs_ro = {
._esp_intr_free = esp_intr_free_wrapper,
._malloc = bt_osi_mem_malloc_internal,
._free = bt_osi_mem_free,
#if CONFIG_BT_LE_HCI_INTERFACE_USE_UART
._hal_uart_start_tx = hci_uart_start_tx_wrapper,
._hal_uart_init_cbs = hci_uart_init_cbs_wrapper,
._hal_uart_config = hci_uart_config_wrapper,
._hal_uart_close = hci_uart_close_wrapper,
._hal_uart_blocking_tx = hci_uart_blocking_tx_wrapper,
._hal_uart_init = hci_uart_init_wrapper,
#endif //CONFIG_BT_LE_HCI_INTERFACE_USE_UART
._task_create = task_create_wrapper,
._task_delete = task_delete_wrapper,
._osi_assert = osi_assert_wrapper,
@ -288,75 +253,6 @@ static void coex_schm_status_bit_clear_wrapper(uint32_t type, uint32_t status)
#endif // CONFIG_SW_COEXIST_ENABLE
}
#ifdef CONFIG_BT_BLUEDROID_ENABLED
bool esp_vhci_host_check_send_available(void)
{
if (ble_controller_status != ESP_BT_CONTROLLER_STATUS_ENABLED) {
return false;
}
return true;
}
static struct os_mbuf *ble_hs_mbuf_gen_pkt(uint16_t leading_space)
{
struct os_mbuf *om;
int rc;
om = os_msys_get_pkthdr(0, 0);
if (om == NULL) {
return NULL;
}
if (om->om_omp->omp_databuf_len < leading_space) {
rc = os_mbuf_free_chain(om);
assert(rc == 0);
return NULL;
}
om->om_data += leading_space;
return om;
}
struct os_mbuf *ble_hs_mbuf_acl_pkt(void)
{
return ble_hs_mbuf_gen_pkt(4 + 1);
}
void esp_vhci_host_send_packet(uint8_t *data, uint16_t len)
{
if (ble_controller_status != ESP_BT_CONTROLLER_STATUS_ENABLED) {
return;
}
if (*(data) == DATA_TYPE_COMMAND) {
struct ble_hci_cmd *cmd = NULL;
cmd = (struct ble_hci_cmd *) ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_CMD);
assert(cmd);
memcpy((uint8_t *)cmd, data + 1, len - 1);
ble_hci_trans_hs_cmd_tx((uint8_t *)cmd);
}
if (*(data) == DATA_TYPE_ACL) {
struct os_mbuf *om = os_msys_get_pkthdr(len, ACL_DATA_MBUF_LEADINGSPCAE);
assert(om);
assert(os_mbuf_append(om, &data[1], len - 1) == 0);
ble_hci_trans_hs_acl_tx(om);
}
}
esp_err_t esp_vhci_host_register_callback(const esp_vhci_host_callback_t *callback)
{
if (ble_controller_status != ESP_BT_CONTROLLER_STATUS_ENABLED) {
return ESP_FAIL;
}
ble_hci_trans_cfg_hs(ble_hs_hci_rx_evt, NULL, ble_hs_rx_data, NULL);
return ESP_OK;
}
#endif // CONFIG_BT_BLUEDROID_ENABLED
static int task_create_wrapper(void *task_func, const char *name, uint32_t stack_depth,
void *param, uint32_t prio, void *task_handle, uint32_t core_id)
{
@ -388,56 +284,6 @@ static int esp_ecc_gen_dh_key(const uint8_t *peer_pub_key_x, const uint8_t *peer
return rc;
}
#ifdef CONFIG_BT_LE_HCI_INTERFACE_USE_UART
static void hci_uart_start_tx_wrapper(int uart_no)
{
hci_uart_start_tx(uart_no);
}
static int hci_uart_init_cbs_wrapper(int uart_no, hci_uart_tx_char tx_func,
hci_uart_tx_done tx_done, hci_uart_rx_char rx_func, void *arg)
{
int rc = -1;
rc = hci_uart_init_cbs(uart_no, tx_func, tx_done, rx_func, arg);
return rc;
}
static int hci_uart_config_wrapper(int port_num, int32_t baud_rate, uint8_t data_bits,
uint8_t stop_bits, uart_parity_t parity,
uart_hw_flowcontrol_t flow_ctl)
{
int rc = -1;
rc = hci_uart_config(port_num, baud_rate, data_bits, stop_bits, parity, flow_ctl);
return rc;
}
static int hci_uart_close_wrapper(int uart_no)
{
int rc = -1;
rc = hci_uart_close(uart_no);
return rc;
}
static void hci_uart_blocking_tx_wrapper(int port, uint8_t data)
{
//This function is nowhere to use.
}
static int hci_uart_init_wrapper(int uart_no, void *cfg)
{
//This function is nowhere to use.
return 0;
}
#endif //CONFIG_BT_LE_HCI_INTERFACE_USE_UART
static int ble_hci_unregistered_hook(void*, void*)
{
ESP_LOGD(NIMBLE_PORT_LOG_TAG,"%s ble hci rx_evt is not registered.",__func__);
return 0;
}
static int esp_intr_alloc_wrapper(int source, int flags, intr_handler_t handler,
void *arg, void **ret_handle_in)
{
@ -716,6 +562,7 @@ esp_err_t esp_bt_controller_init(esp_bt_controller_config_t *cfg)
esp_err_t ret = ESP_OK;
ble_npl_count_info_t npl_info;
uint32_t slow_clk_freq = 0;
uint8_t hci_transport_mode;
memset(&npl_info, 0, sizeof(ble_npl_count_info_t));
@ -860,11 +707,23 @@ esp_err_t esp_bt_controller_init(esp_bt_controller_config_t *cfg)
ble_controller_status = ESP_BT_CONTROLLER_STATUS_INITED;
ble_hci_trans_cfg_hs((ble_hci_trans_rx_cmd_fn *)ble_hci_unregistered_hook,NULL,
(ble_hci_trans_rx_acl_fn *)ble_hci_unregistered_hook,NULL);
return ESP_OK;
#if CONFIG_BT_LE_HCI_INTERFACE_USE_RAM
hci_transport_mode = HCI_TRANSPORT_VHCI;
#elif CONFIG_BT_LE_HCI_INTERFACE_USE_UART
hci_transport_mode = HCI_TRANSPORT_UART_NO_DMA;
#if CONFIG_BT_LE_UART_HCI_DMA_MODE
hci_transport_mode = HCI_TRANSPORT_UART_UHCI;
#endif // CONFIG_BT_LE_UART_HCI_DMA_MODE
#endif // CONFIG_BT_LE_HCI_INTERFACE_USE_RAM
ret = hci_transport_init(hci_transport_mode);
if (ret) {
ESP_LOGW(NIMBLE_PORT_LOG_TAG, "hci transport init failed %d", ret);
goto free_controller;
}
return ESP_OK;
free_controller:
hci_transport_deinit();
controller_sleep_deinit();
os_msys_deinit();
r_ble_controller_deinit();
@ -895,6 +754,7 @@ esp_err_t esp_bt_controller_deinit(void)
return ESP_FAIL;
}
hci_transport_deinit();
controller_sleep_deinit();
os_msys_deinit();

View File

@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -129,6 +129,21 @@ extern "C" {
#else
#define DEFAULT_BT_LE_50_FEATURE_SUPPORT (0)
#endif
#if defined (CONFIG_BT_LE_HCI_UART_FLOWCTRL)
#define DEFAULT_BT_LE_HCI_UART_FLOW_CTRL (CONFIG_BT_LE_HCI_UART_FLOWCTRL)
#if DEFAULT_BT_LE_HCI_UART_FLOW_CTRL
#define DEFAULT_BT_LE_HCI_UART_CTS_PIN (CONFIG_BT_LE_HCI_UART_CTS_PIN)
#define DEFAULT_BT_LE_HCI_UART_RTS_PIN (CONFIG_BT_LE_HCI_UART_RTS_PIN)
#else
#define DEFAULT_BT_LE_HCI_UART_CTS_PIN (-1)
#define DEFAULT_BT_LE_HCI_UART_RTS_PIN (-1)
#endif
#else
#define DEFAULT_BT_LE_HCI_UART_FLOW_CTRL (0)
#define DEFAULT_BT_LE_HCI_UART_CTS_PIN (-1)
#define DEFAULT_BT_LE_HCI_UART_RTS_PIN (-1)
#endif
#endif
#define DEFAULT_BT_LE_COEX_PHY_CODED_TX_RX_TLIM_EFF CONFIG_BT_LE_COEX_PHY_CODED_TX_RX_TLIM_EFF
@ -169,8 +184,6 @@ extern "C" {
#define DEFAULT_BT_LE_HCI_UART_DATA_BITS (UART_DATA_8_BITS)
#define DEFAULT_BT_LE_HCI_UART_STOP_BITS (UART_STOP_BITS_1)
#define DEFAULT_BT_LE_HCI_UART_PARITY (0)
#define DEFAULT_BT_LE_HCI_UART_TASK_STACK_SIZE (CONFIG_BT_LE_HCI_UART_TASK_STACK_SIZE)
#define DEFAULT_BT_LE_HCI_UART_FLOW_CTRL (0)
#else
#define DEFAULT_BT_LE_HCI_UART_TX_PIN (0)
#define DEFAULT_BT_LE_HCI_UART_RX_PIN (0)
@ -179,8 +192,6 @@ extern "C" {
#define DEFAULT_BT_LE_HCI_UART_DATA_BITS (0)
#define DEFAULT_BT_LE_HCI_UART_STOP_BITS (0)
#define DEFAULT_BT_LE_HCI_UART_PARITY (0)
#define DEFAULT_BT_LE_HCI_UART_TASK_STACK_SIZE (0)
#define DEFAULT_BT_LE_HCI_UART_FLOW_CTRL (0)
#endif
/* Unchanged configuration */

View File

@ -2,19 +2,37 @@
menu "HCI Config"
choice BT_LE_HCI_INTERFACE
prompt "Select HCI interface"
prompt "HCI mode"
default BT_LE_HCI_INTERFACE_USE_RAM
config BT_LE_HCI_INTERFACE_USE_RAM
bool "ram"
bool "VHCI"
help
Use RAM as HCI interface
config BT_LE_HCI_INTERFACE_USE_UART
bool "uart"
bool "UART(H4)"
help
Use UART as HCI interface
endchoice
choice BT_LE_UART_HCI_MODE_CHOICE
prompt "UART HCI mode"
depends on BT_LE_HCI_INTERFACE_USE_UART
default BT_LE_UART_HCI_NO_DMA_MODE
help
Specify UART HCI mode: DMA or No DMA
config BT_LE_UART_HCI_DMA_MODE
bool "UHCI(UART with DMA)(EXPERIMENTAL)"
help
UART HCI Mode with DMA functionality.
config BT_LE_UART_HCI_NO_DMA_MODE
bool "UART(NO DMA)"
help
UART HCI Mode without DMA functionality.
endchoice
config BT_LE_HCI_UART_PORT
int "HCI UART port"
depends on BT_LE_HCI_INTERFACE_USE_UART
@ -73,12 +91,40 @@ menu "HCI Config"
UART_PARITY_ODD
endchoice
config BT_LE_HCI_UART_TASK_STACK_SIZE
int "HCI uart task stack size"
depends on BT_LE_HCI_INTERFACE_USE_UART
default 1000
config BT_LE_HCI_UART_RX_BUFFER_SIZE
int "The size of rx ring buffer memory"
depends on BT_LE_UART_HCI_NO_DMA_MODE
default 512
help
Set the size of uart task stack
The size of rx ring buffer memory
config BT_LE_HCI_UART_TX_BUFFER_SIZE
int "The size of tx ring buffer memory"
depends on BT_LE_UART_HCI_NO_DMA_MODE
default 256
help
The size of tx ring buffer memory
config BT_LE_HCI_TRANS_TASK_STACK_SIZE
int "HCI transport task stack size"
depends on !BT_LE_HCI_INTERFACE_USE_RAM
default 1024
help
This configures stack size of hci transport task
config BT_LE_HCI_TRANS_RX_MEM_NUM
int "The amount of rx memory received at the same time"
depends on BT_LE_UART_HCI_DMA_MODE
default 3
help
The amount of rx memory received at the same time
config BT_LE_HCI_LLDESCS_POOL_NUM
int "The amount of lldecs memory for driver dma mode"
depends on BT_LE_UART_HCI_DMA_MODE
default 20
help
The amount of lldecs memory for driver dma mode
endmenu
config BT_LE_CONTROLLER_NPL_OS_PORTING_SUPPORT

View File

@ -30,7 +30,7 @@
#endif // CONFIG_SW_COEXIST_ENABLE
#include "nimble/nimble_npl_os.h"
#include "ble_hci_trans.h"
#include "esp_hci_transport.h"
#include "os/endian.h"
#include "esp_bt.h"
@ -39,7 +39,6 @@
#include "esp_pm.h"
#include "esp_phy_init.h"
#include "esp_private/periph_ctrl.h"
#include "hci_uart.h"
#include "bt_osi_mem.h"
#if CONFIG_FREERTOS_USE_TICKLESS_IDLE
@ -47,10 +46,6 @@
#include "esp_private/sleep_retention.h"
#endif // CONFIG_FREERTOS_USE_TICKLESS_IDLE
#ifdef CONFIG_BT_BLUEDROID_ENABLED
#include "hci/hci_hal.h"
#endif // CONFIG_BT_BLUEDROID_ENABLED
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
@ -64,16 +59,11 @@
#define OSI_COEX_VERSION 0x00010006
#define OSI_COEX_MAGIC_VALUE 0xFADEBEAD
#define EXT_FUNC_VERSION 0x20221122
#define EXT_FUNC_VERSION 0x20240422
#define EXT_FUNC_MAGIC_VALUE 0xA5A5A5A5
#define BT_ASSERT_PRINT ets_printf
#ifdef CONFIG_BT_BLUEDROID_ENABLED
/* ACL_DATA_MBUF_LEADINGSPCAE: The leadingspace in user info header for ACL data */
#define ACL_DATA_MBUF_LEADINGSPCAE 4
#endif // CONFIG_BT_BLUEDROID_ENABLED
/* Types definition
************************************************************************
*/
@ -92,12 +82,6 @@ struct ext_funcs_t {
int (*_esp_intr_free)(void **ret_handle);
void *(* _malloc)(size_t size);
void (*_free)(void *p);
void (*_hal_uart_start_tx)(int);
int (*_hal_uart_init_cbs)(int, hci_uart_tx_char, hci_uart_tx_done, hci_uart_rx_char, void *);
int (*_hal_uart_config)(int, int32_t, uint8_t, uint8_t, uart_parity_t, uart_hw_flowcontrol_t);
int (*_hal_uart_close)(int);
void (*_hal_uart_blocking_tx)(int, uint8_t);
int (*_hal_uart_init)(int, void *);
int (* _task_create)(void *task_func, const char *name, uint32_t stack_depth, void *param,
uint32_t prio, void *task_handle, uint32_t core_id);
void (* _task_delete)(void *task_handle);
@ -173,16 +157,6 @@ static void coex_schm_status_bit_clear_wrapper(uint32_t type, uint32_t status);
static int task_create_wrapper(void *task_func, const char *name, uint32_t stack_depth,
void *param, uint32_t prio, void *task_handle, uint32_t core_id);
static void task_delete_wrapper(void *task_handle);
#if CONFIG_BT_LE_HCI_INTERFACE_USE_UART
static void hci_uart_start_tx_wrapper(int uart_no);
static int hci_uart_init_cbs_wrapper(int uart_no, hci_uart_tx_char tx_func,
hci_uart_tx_done tx_done, hci_uart_rx_char rx_func, void *arg);
static int hci_uart_config_wrapper(int uart_no, int32_t speed, uint8_t databits, uint8_t stopbits,
uart_parity_t parity, uart_hw_flowcontrol_t flow_ctl);
static int hci_uart_close_wrapper(int uart_no);
static void hci_uart_blocking_tx_wrapper(int port, uint8_t data);
static int hci_uart_init_wrapper(int uart_no, void *cfg);
#endif // CONFIG_BT_LE_HCI_INTERFACE_USE_UART
static int esp_intr_alloc_wrapper(int source, int flags, intr_handler_t handler,
void *arg, void **ret_handle_in);
static int esp_intr_free_wrapper(void **ret_handle);
@ -200,7 +174,6 @@ static void esp_bt_controller_log_interface(uint32_t len, const uint8_t *addr, b
*/
/* 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};
#endif // CONFIG_BT_LE_CONTROLLER_LOG_ENABLED
@ -230,14 +203,6 @@ struct ext_funcs_t ext_funcs_ro = {
._esp_intr_free = esp_intr_free_wrapper,
._malloc = bt_osi_mem_malloc_internal,
._free = bt_osi_mem_free,
#if CONFIG_BT_LE_HCI_INTERFACE_USE_UART
._hal_uart_start_tx = hci_uart_start_tx_wrapper,
._hal_uart_init_cbs = hci_uart_init_cbs_wrapper,
._hal_uart_config = hci_uart_config_wrapper,
._hal_uart_close = hci_uart_close_wrapper,
._hal_uart_blocking_tx = hci_uart_blocking_tx_wrapper,
._hal_uart_init = hci_uart_init_wrapper,
#endif //CONFIG_BT_LE_HCI_INTERFACE_USE_UART
._task_create = task_create_wrapper,
._task_delete = task_delete_wrapper,
._osi_assert = osi_assert_wrapper,
@ -282,75 +247,6 @@ static void coex_schm_status_bit_clear_wrapper(uint32_t type, uint32_t status)
#endif // CONFIG_SW_COEXIST_ENABLE
}
#ifdef CONFIG_BT_BLUEDROID_ENABLED
bool esp_vhci_host_check_send_available(void)
{
if (ble_controller_status != ESP_BT_CONTROLLER_STATUS_ENABLED) {
return false;
}
return true;
}
static struct os_mbuf *ble_hs_mbuf_gen_pkt(uint16_t leading_space)
{
struct os_mbuf *om;
int rc;
om = os_msys_get_pkthdr(0, 0);
if (om == NULL) {
return NULL;
}
if (om->om_omp->omp_databuf_len < leading_space) {
rc = os_mbuf_free_chain(om);
assert(rc == 0);
return NULL;
}
om->om_data += leading_space;
return om;
}
struct os_mbuf *ble_hs_mbuf_acl_pkt(void)
{
return ble_hs_mbuf_gen_pkt(4 + 1);
}
void esp_vhci_host_send_packet(uint8_t *data, uint16_t len)
{
if (ble_controller_status != ESP_BT_CONTROLLER_STATUS_ENABLED) {
return;
}
if (*(data) == DATA_TYPE_COMMAND) {
struct ble_hci_cmd *cmd = NULL;
cmd = (struct ble_hci_cmd *) ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_CMD);
assert(cmd);
memcpy((uint8_t *)cmd, data + 1, len - 1);
ble_hci_trans_hs_cmd_tx((uint8_t *)cmd);
}
if (*(data) == DATA_TYPE_ACL) {
struct os_mbuf *om = os_msys_get_pkthdr(len, ACL_DATA_MBUF_LEADINGSPCAE);
assert(om);
assert(os_mbuf_append(om, &data[1], len - 1) == 0);
ble_hci_trans_hs_acl_tx(om);
}
}
esp_err_t esp_vhci_host_register_callback(const esp_vhci_host_callback_t *callback)
{
if (ble_controller_status != ESP_BT_CONTROLLER_STATUS_ENABLED) {
return ESP_FAIL;
}
ble_hci_trans_cfg_hs(ble_hs_hci_rx_evt, NULL, ble_hs_rx_data, NULL);
return ESP_OK;
}
#endif // CONFIG_BT_BLUEDROID_ENABLED
static int task_create_wrapper(void *task_func, const char *name, uint32_t stack_depth,
void *param, uint32_t prio, void *task_handle, uint32_t core_id)
{
@ -382,56 +278,6 @@ static int esp_ecc_gen_dh_key(const uint8_t *peer_pub_key_x, const uint8_t *peer
return rc;
}
#ifdef CONFIG_BT_LE_HCI_INTERFACE_USE_UART
static void hci_uart_start_tx_wrapper(int uart_no)
{
hci_uart_start_tx(uart_no);
}
static int hci_uart_init_cbs_wrapper(int uart_no, hci_uart_tx_char tx_func,
hci_uart_tx_done tx_done, hci_uart_rx_char rx_func, void *arg)
{
int rc = -1;
rc = hci_uart_init_cbs(uart_no, tx_func, tx_done, rx_func, arg);
return rc;
}
static int hci_uart_config_wrapper(int port_num, int32_t baud_rate, uint8_t data_bits,
uint8_t stop_bits, uart_parity_t parity,
uart_hw_flowcontrol_t flow_ctl)
{
int rc = -1;
rc = hci_uart_config(port_num, baud_rate, data_bits, stop_bits, parity, flow_ctl);
return rc;
}
static int hci_uart_close_wrapper(int uart_no)
{
int rc = -1;
rc = hci_uart_close(uart_no);
return rc;
}
static void hci_uart_blocking_tx_wrapper(int port, uint8_t data)
{
//This function is nowhere to use.
}
static int hci_uart_init_wrapper(int uart_no, void *cfg)
{
//This function is nowhere to use.
return 0;
}
#endif //CONFIG_BT_LE_HCI_INTERFACE_USE_UART
static int ble_hci_unregistered_hook(void*, void*)
{
ESP_LOGD(NIMBLE_PORT_LOG_TAG,"%s ble hci rx_evt is not registered.",__func__);
return 0;
}
static int esp_intr_alloc_wrapper(int source, int flags, intr_handler_t handler,
void *arg, void **ret_handle_in)
{
@ -689,6 +535,7 @@ esp_err_t esp_bt_controller_init(esp_bt_controller_config_t *cfg)
esp_err_t ret = ESP_OK;
ble_npl_count_info_t npl_info;
uint32_t slow_clk_freq = 0;
uint8_t hci_transport_mode;
memset(&npl_info, 0, sizeof(ble_npl_count_info_t));
if (ble_controller_status != ESP_BT_CONTROLLER_STATUS_IDLE) {
@ -831,11 +678,23 @@ esp_err_t esp_bt_controller_init(esp_bt_controller_config_t *cfg)
ble_controller_status = ESP_BT_CONTROLLER_STATUS_INITED;
ble_hci_trans_cfg_hs((ble_hci_trans_rx_cmd_fn *)ble_hci_unregistered_hook,NULL,
(ble_hci_trans_rx_acl_fn *)ble_hci_unregistered_hook,NULL);
return ESP_OK;
#if CONFIG_BT_LE_HCI_INTERFACE_USE_RAM
hci_transport_mode = HCI_TRANSPORT_VHCI;
#elif CONFIG_BT_LE_HCI_INTERFACE_USE_UART
hci_transport_mode = HCI_TRANSPORT_UART_NO_DMA;
#if CONFIG_BT_LE_UART_HCI_DMA_MODE
hci_transport_mode = HCI_TRANSPORT_UART_UHCI;
#endif // CONFIG_BT_LE_UART_HCI_DMA_MODE
#endif // CONFIG_BT_LE_HCI_INTERFACE_USE_RAM
ret = hci_transport_init(hci_transport_mode);
if (ret) {
ESP_LOGW(NIMBLE_PORT_LOG_TAG, "hci transport init failed %d", ret);
goto free_controller;
}
return ESP_OK;
free_controller:
hci_transport_deinit();
controller_sleep_deinit();
os_msys_deinit();
r_ble_controller_deinit();
@ -865,6 +724,7 @@ esp_err_t esp_bt_controller_deinit(void)
return ESP_FAIL;
}
hci_transport_deinit();
controller_sleep_deinit();
os_msys_deinit();

View File

@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -124,12 +124,26 @@ extern "C" {
#else
#define DEFAULT_BT_LE_POWER_CONTROL_ENABLED (0)
#endif
#if defined(CONFIG_BT_LE_50_FEATURE_SUPPORT)
#define DEFAULT_BT_LE_50_FEATURE_SUPPORT (1)
#else
#define DEFAULT_BT_LE_50_FEATURE_SUPPORT (0)
#endif
#if defined (CONFIG_BT_LE_HCI_UART_FLOWCTRL)
#define DEFAULT_BT_LE_HCI_UART_FLOW_CTRL (CONFIG_BT_LE_HCI_UART_FLOWCTRL)
#if DEFAULT_BT_LE_HCI_UART_FLOW_CTRL
#define DEFAULT_BT_LE_HCI_UART_CTS_PIN (CONFIG_BT_LE_HCI_UART_CTS_PIN)
#define DEFAULT_BT_LE_HCI_UART_RTS_PIN (CONFIG_BT_LE_HCI_UART_RTS_PIN)
#else
#define DEFAULT_BT_LE_HCI_UART_CTS_PIN (-1)
#define DEFAULT_BT_LE_HCI_UART_RTS_PIN (-1)
#endif
#else
#define DEFAULT_BT_LE_HCI_UART_FLOW_CTRL (0)
#define DEFAULT_BT_LE_HCI_UART_CTS_PIN (-1)
#define DEFAULT_BT_LE_HCI_UART_RTS_PIN (-1)
#endif
#endif
#define DEFAULT_BT_LE_COEX_PHY_CODED_TX_RX_TLIM_EFF CONFIG_BT_LE_COEX_PHY_CODED_TX_RX_TLIM_EFF
@ -170,8 +184,6 @@ extern "C" {
#define DEFAULT_BT_LE_HCI_UART_DATA_BITS (UART_DATA_8_BITS)
#define DEFAULT_BT_LE_HCI_UART_STOP_BITS (UART_STOP_BITS_1)
#define DEFAULT_BT_LE_HCI_UART_PARITY (0)
#define DEFAULT_BT_LE_HCI_UART_TASK_STACK_SIZE (CONFIG_BT_LE_HCI_UART_TASK_STACK_SIZE)
#define DEFAULT_BT_LE_HCI_UART_FLOW_CTRL (0)
#else
#define DEFAULT_BT_LE_HCI_UART_TX_PIN (0)
#define DEFAULT_BT_LE_HCI_UART_RX_PIN (0)
@ -180,8 +192,6 @@ extern "C" {
#define DEFAULT_BT_LE_HCI_UART_DATA_BITS (0)
#define DEFAULT_BT_LE_HCI_UART_STOP_BITS (0)
#define DEFAULT_BT_LE_HCI_UART_PARITY (0)
#define DEFAULT_BT_LE_HCI_UART_TASK_STACK_SIZE (0)
#define DEFAULT_BT_LE_HCI_UART_FLOW_CTRL (0)
#endif
/* Unchanged configuration */

View File

@ -35,10 +35,6 @@
#include "esp_bluedroid_hci.h"
#include "stack/hcimsgs.h"
#if ((BT_CONTROLLER_INCLUDED == TRUE) && SOC_ESP_NIMBLE_CONTROLLER)
#include "ble_hci_trans.h"
#endif
#if (C2H_FLOW_CONTROL_INCLUDED == TRUE)
#include "l2c_int.h"
#endif ///C2H_FLOW_CONTROL_INCLUDED == TRUE
@ -622,42 +618,6 @@ static int host_recv_pkt_cb(uint8_t *data, uint16_t len)
return 0;
}
#if ((BT_CONTROLLER_INCLUDED == TRUE) && SOC_ESP_NIMBLE_CONTROLLER)
int
ble_hs_hci_rx_evt(uint8_t *hci_ev, void *arg)
{
if(esp_bluedroid_get_status() == ESP_BLUEDROID_STATUS_UNINITIALIZED) {
ble_hci_trans_buf_free(hci_ev);
return 0;
}
uint16_t len = hci_ev[1] + 3;
uint8_t *data = (uint8_t *)malloc(len);
assert(data != NULL);
data[0] = 0x04;
memcpy(&data[1], hci_ev, len - 1);
ble_hci_trans_buf_free(hci_ev);
host_recv_pkt_cb(data, len);
free(data);
return 0;
}
int
ble_hs_rx_data(struct os_mbuf *om, void *arg)
{
uint16_t len = OS_MBUF_PKTHDR(om)->omp_len + 1;
uint8_t *data = (uint8_t *)malloc(len);
assert(data != NULL);
data[0] = 0x02;
os_mbuf_copydata(om, 0, len - 1, &data[1]);
host_recv_pkt_cb(data, len);
free(data);
os_mbuf_free_chain(om);
return 0;
}
#endif
static const esp_bluedroid_hci_driver_callbacks_t hci_host_cb = {
.notify_host_send_available = host_send_pkt_available_cb,
.notify_host_recv = host_recv_pkt_cb,

View File

@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -262,13 +262,6 @@ typedef struct {
.controller_run_cpu = 0, \
.enable_qa_test = RUN_QA_TEST, \
.enable_bqb_test = RUN_BQB_TEST, \
.enable_uart_hci = HCI_UART_EN, \
.ble_hci_uart_port = DEFAULT_BT_LE_HCI_UART_PORT, \
.ble_hci_uart_baud = DEFAULT_BT_LE_HCI_UART_BAUD, \
.ble_hci_uart_data_bits = DEFAULT_BT_LE_HCI_UART_DATA_BITS, \
.ble_hci_uart_stop_bits = DEFAULT_BT_LE_HCI_UART_STOP_BITS, \
.ble_hci_uart_flow_ctrl = DEFAULT_BT_LE_HCI_UART_FLOW_CTRL, \
.ble_hci_uart_uart_parity = DEFAULT_BT_LE_HCI_UART_PARITY, \
.enable_tx_cca = DEFAULT_BT_LE_TX_CCA_ENABLED, \
.cca_rssi_thresh = 256 - DEFAULT_BT_LE_CCA_RSSI_THRESH, \
.sleep_en = NIMBLE_SLEEP_ENABLE, \

View File

@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -155,7 +155,7 @@ esp_err_t esp_ble_tx_power_set_enhanced(esp_ble_enhanced_power_type_t power_type
*/
esp_power_level_t esp_ble_tx_power_get_enhanced(esp_ble_enhanced_power_type_t power_type, uint16_t handle);
#define CONFIG_VERSION 0x20231124
#define CONFIG_VERSION 0x20240422
#define CONFIG_MAGIC 0x5A5AA5A5
/**
@ -196,13 +196,6 @@ typedef struct {
uint8_t controller_run_cpu; /*!< CPU core on which the controller runs */
uint8_t enable_qa_test; /*!< Enable quality assurance (QA) testing */
uint8_t enable_bqb_test; /*!< Enable Bluetooth Qualification Test (BQB) testing */
uint8_t enable_uart_hci; /*!< Enable UART HCI (Host Controller Interface) */
uint8_t ble_hci_uart_port; /*!< UART port number for Bluetooth HCI */
uint32_t ble_hci_uart_baud; /*!< Baud rate for Bluetooth HCI UART */
uint8_t ble_hci_uart_data_bits; /*!< Number of data bits for Bluetooth HCI UART */
uint8_t ble_hci_uart_stop_bits; /*!< Number of stop bits for Bluetooth HCI UART */
uint8_t ble_hci_uart_flow_ctrl; /*!< Flow control settings for Bluetooth HCI UART */
uint8_t ble_hci_uart_uart_parity; /*!< Parity settings for Bluetooth HCI UART */
uint8_t enable_tx_cca; /*!< Enable Transmit Clear Channel Assessment (TX CCA) */
uint8_t cca_rssi_thresh; /*!< RSSI threshold for Transmit Clear Channel Assessment (CCA) */
uint8_t sleep_en; /*!< Enable sleep mode */
@ -253,13 +246,6 @@ typedef struct {
.controller_run_cpu = 0, \
.enable_qa_test = RUN_QA_TEST, \
.enable_bqb_test = RUN_BQB_TEST, \
.enable_uart_hci = HCI_UART_EN, \
.ble_hci_uart_port = DEFAULT_BT_LE_HCI_UART_PORT, \
.ble_hci_uart_baud = DEFAULT_BT_LE_HCI_UART_BAUD, \
.ble_hci_uart_data_bits = DEFAULT_BT_LE_HCI_UART_DATA_BITS, \
.ble_hci_uart_stop_bits = DEFAULT_BT_LE_HCI_UART_STOP_BITS, \
.ble_hci_uart_flow_ctrl = DEFAULT_BT_LE_HCI_UART_FLOW_CTRL, \
.ble_hci_uart_uart_parity = DEFAULT_BT_LE_HCI_UART_PARITY, \
.enable_tx_cca = DEFAULT_BT_LE_TX_CCA_ENABLED, \
.cca_rssi_thresh = 256 - DEFAULT_BT_LE_CCA_RSSI_THRESH, \
.sleep_en = NIMBLE_SLEEP_ENABLE, \

View File

@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -160,7 +160,7 @@ esp_err_t esp_ble_tx_power_set_enhanced(esp_ble_enhanced_power_type_t power_type
*/
esp_power_level_t esp_ble_tx_power_get_enhanced(esp_ble_enhanced_power_type_t power_type, uint16_t handle);
#define CONFIG_VERSION 0x20231124
#define CONFIG_VERSION 0x20240422
#define CONFIG_MAGIC 0x5A5AA5A5
/**
@ -201,13 +201,6 @@ typedef struct {
uint8_t controller_run_cpu; /*!< CPU number on which the Bluetooth controller task runs */
uint8_t enable_qa_test; /*!< Enable for QA test */
uint8_t enable_bqb_test; /*!< Enable for BQB test */
uint8_t enable_uart_hci; /*!< Enable UART for HCI (Host Controller Interface) */
uint8_t ble_hci_uart_port; /*!< Port of UART for HCI */
uint32_t ble_hci_uart_baud; /*!< Baudrate of UART for HCI */
uint8_t ble_hci_uart_data_bits; /*!< Data bits of UART for HCI */
uint8_t ble_hci_uart_stop_bits; /*!< Stop bits of UART for HCI */
uint8_t ble_hci_uart_flow_ctrl; /*!< Flow control of UART for HCI */
uint8_t ble_hci_uart_uart_parity; /*!< UART parity */
uint8_t enable_tx_cca; /*!< Enable Clear Channel Assessment (CCA) when transmitting */
uint8_t cca_rssi_thresh; /*!< RSSI threshold for CCA */
uint8_t sleep_en; /*!< Enable sleep functionality */
@ -258,13 +251,6 @@ typedef struct {
.controller_run_cpu = 0, \
.enable_qa_test = RUN_QA_TEST, \
.enable_bqb_test = RUN_BQB_TEST, \
.enable_uart_hci = HCI_UART_EN, \
.ble_hci_uart_port = DEFAULT_BT_LE_HCI_UART_PORT, \
.ble_hci_uart_baud = DEFAULT_BT_LE_HCI_UART_BAUD, \
.ble_hci_uart_data_bits = DEFAULT_BT_LE_HCI_UART_DATA_BITS, \
.ble_hci_uart_stop_bits = DEFAULT_BT_LE_HCI_UART_STOP_BITS, \
.ble_hci_uart_flow_ctrl = DEFAULT_BT_LE_HCI_UART_FLOW_CTRL, \
.ble_hci_uart_uart_parity = DEFAULT_BT_LE_HCI_UART_PARITY, \
.enable_tx_cca = DEFAULT_BT_LE_TX_CCA_ENABLED, \
.cca_rssi_thresh = 256 - DEFAULT_BT_LE_CCA_RSSI_THRESH, \
.sleep_en = NIMBLE_SLEEP_ENABLE, \

View File

@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -116,6 +116,20 @@ extern "C" {
#define DEFAULT_BT_LE_HCI_EVT_LO_BUF_COUNT (8)
#endif
#if defined (CONFIG_BT_LE_HCI_UART_FLOWCTRL)
#define DEFAULT_BT_LE_HCI_UART_FLOW_CTRL (CONFIG_BT_LE_HCI_UART_FLOWCTRL)
#if DEFAULT_BT_LE_HCI_UART_FLOW_CTRL
#define DEFAULT_BT_LE_HCI_UART_CTS_PIN (CONFIG_BT_LE_HCI_UART_CTS_PIN)
#define DEFAULT_BT_LE_HCI_UART_RTS_PIN (CONFIG_BT_LE_HCI_UART_RTS_PIN)
#else
#define DEFAULT_BT_LE_HCI_UART_CTS_PIN (-1)
#define DEFAULT_BT_LE_HCI_UART_RTS_PIN (-1)
#endif
#else
#define DEFAULT_BT_LE_HCI_UART_FLOW_CTRL (0)
#define DEFAULT_BT_LE_HCI_UART_CTS_PIN (-1)
#define DEFAULT_BT_LE_HCI_UART_RTS_PIN (-1)
#endif
#endif
#define DEFAULT_BT_LE_COEX_PHY_CODED_TX_RX_TLIM_EFF CONFIG_BT_LE_COEX_PHY_CODED_TX_RX_TLIM_EFF
@ -156,8 +170,6 @@ extern "C" {
#define DEFAULT_BT_LE_HCI_UART_DATA_BITS (UART_DATA_8_BITS)
#define DEFAULT_BT_LE_HCI_UART_STOP_BITS (UART_STOP_BITS_1)
#define DEFAULT_BT_LE_HCI_UART_PARITY (0)
#define DEFAULT_BT_LE_HCI_UART_TASK_STACK_SIZE (CONFIG_BT_LE_HCI_UART_TASK_STACK_SIZE)
#define DEFAULT_BT_LE_HCI_UART_FLOW_CTRL (0)
#else
#define DEFAULT_BT_LE_HCI_UART_TX_PIN (0)
#define DEFAULT_BT_LE_HCI_UART_RX_PIN (0)
@ -166,8 +178,6 @@ extern "C" {
#define DEFAULT_BT_LE_HCI_UART_DATA_BITS (0)
#define DEFAULT_BT_LE_HCI_UART_STOP_BITS (0)
#define DEFAULT_BT_LE_HCI_UART_PARITY (0)
#define DEFAULT_BT_LE_HCI_UART_TASK_STACK_SIZE (0)
#define DEFAULT_BT_LE_HCI_UART_FLOW_CTRL (0)
#endif
/* Unchanged configuration */

View File

@ -0,0 +1,356 @@
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#include <assert.h>
#include <stdint.h>
#include <string.h>
#include <os/os.h>
#include <os/os_mbuf.h>
#include "common/hci_driver_h4.h"
#ifndef min
#define min(a, b) ((a) < (b) ? (a) : (b))
#endif
#ifndef max
#define max(a, b) ((a) > (b) ? (a) : (b))
#endif
#define HCI_H4_SM_W4_PKT_TYPE 0
#define HCI_H4_SM_W4_HEADER 1
#define HCI_H4_SM_W4_PAYLOAD 2
#define HCI_H4_SM_COMPLETED 3
struct hci_h4_input_buffer {
const uint8_t *buf;
uint16_t len;
};
static int
hci_h4_frame_start(struct hci_h4_sm *rxs, uint8_t pkt_type)
{
rxs->pkt_type = pkt_type;
rxs->len = 0;
rxs->exp_len = 0;
switch (rxs->pkt_type) {
case HCI_H4_CMD:
rxs->min_len = 3;
break;
case HCI_H4_ACL:
case HCI_H4_ISO:
rxs->min_len = 4;
break;
case HCI_H4_EVT:
rxs->min_len = 2;
break;
default:
/* !TODO: Sync loss. Need to wait for reset. */
return -1;
}
return 0;
}
static int
hci_h4_ib_consume(struct hci_h4_input_buffer *ib, uint16_t len)
{
assert(ib->len >= len);
ib->buf += len;
ib->len -= len;
return len;
}
static int
hci_h4_ib_pull_min_len(struct hci_h4_sm *rxs,
struct hci_h4_input_buffer *ib)
{
uint16_t len;
len = min(ib->len, rxs->min_len - rxs->len);
memcpy(&rxs->hdr[rxs->len], ib->buf, len);
rxs->len += len;
hci_h4_ib_consume(ib, len);
return rxs->len != rxs->min_len;
}
static int
hci_h4_sm_w4_header(struct hci_h4_sm *h4sm, struct hci_h4_input_buffer *ib)
{
int rc;
rc = hci_h4_ib_pull_min_len(h4sm, ib);
if (rc) {
/* need more data */
return 1;
}
switch (h4sm->pkt_type) {
case HCI_H4_CMD:
assert(h4sm->allocs && h4sm->allocs->cmd);
h4sm->buf = h4sm->allocs->cmd();
if (!h4sm->buf) {
return -1;
}
memcpy(h4sm->buf, h4sm->hdr, h4sm->len);
h4sm->exp_len = h4sm->hdr[2] + 3;
break;
case HCI_H4_ACL:
assert(h4sm->allocs && h4sm->allocs->acl);
h4sm->om = h4sm->allocs->acl();
if (!h4sm->om) {
return -1;
}
os_mbuf_append(h4sm->om, h4sm->hdr, h4sm->len);
h4sm->exp_len = get_le16(&h4sm->hdr[2]) + 4;
break;
#if !CONFIG_BT_CONTROLLER_ENABLED
case HCI_H4_EVT:
if (h4sm->hdr[0] == BLE_HCI_EVCODE_LE_META) {
/* For LE Meta event we need 3 bytes to parse header */
h4sm->min_len = 3;
rc = hci_h4_ib_pull_min_len(h4sm, ib);
if (rc) {
/* need more data */
return 1;
}
}
assert(h4sm->allocs && h4sm->allocs->evt);
/* We can drop legacy advertising events if there's no free buffer in
* discardable pool.
*/
if (h4sm->hdr[2] == BLE_HCI_LE_SUBEV_ADV_RPT) {
h4sm->buf = h4sm->allocs->evt(1);
} else {
h4sm->buf = h4sm->allocs->evt(0);
if (!h4sm->buf) {
return -1;
}
}
if (h4sm->buf) {
memcpy(h4sm->buf, h4sm->hdr, h4sm->len);
}
h4sm->exp_len = h4sm->hdr[1] + 2;
break;
#endif // !CONFIG_BT_CONTROLLER_ENABLED
case HCI_H4_ISO:
assert(h4sm->allocs && h4sm->allocs->iso);
h4sm->om = h4sm->allocs->iso();
if (!h4sm->om) {
return -1;
}
os_mbuf_append(h4sm->om, h4sm->hdr, h4sm->len);
h4sm->exp_len = (get_le16(&h4sm->hdr[2]) & 0x7fff) + 4;
break;
default:
assert(0);
break;
}
return 0;
}
static int
hci_h4_sm_w4_payload(struct hci_h4_sm *h4sm,
struct hci_h4_input_buffer *ib)
{
uint16_t mbuf_len;
uint16_t len;
int rc;
len = min(ib->len, h4sm->exp_len - h4sm->len);
switch (h4sm->pkt_type) {
case HCI_H4_CMD:
case HCI_H4_EVT:
if (h4sm->buf) {
memcpy(&h4sm->buf[h4sm->len], ib->buf, len);
}
break;
case HCI_H4_ACL:
case HCI_H4_ISO:
assert(h4sm->om);
mbuf_len = OS_MBUF_PKTLEN(h4sm->om);
rc = os_mbuf_append(h4sm->om, ib->buf, len);
if (rc) {
/* Some data may already be appended so need to adjust h4sm only by
* the size of appended data.
*/
len = OS_MBUF_PKTLEN(h4sm->om) - mbuf_len;
h4sm->len += len;
hci_h4_ib_consume(ib, len);
return -1;
}
break;
default:
assert(0);
break;
}
h4sm->len += len;
hci_h4_ib_consume(ib, len);
/* return 1 if need more data */
return h4sm->len != h4sm->exp_len;
}
static void
hci_h4_sm_completed(struct hci_h4_sm *h4sm)
{
int rc;
switch (h4sm->pkt_type) {
#if CONFIG_BT_CONTROLLER_ENABLED
case HCI_H4_CMD:
if (h4sm->buf) {
assert(h4sm->frame_cb);
rc = h4sm->frame_cb(h4sm->pkt_type, h4sm->buf);
assert(rc == 0);
h4sm->buf = NULL;
}
break;
case HCI_H4_ACL:
case HCI_H4_ISO:
if (h4sm->om) {
assert(h4sm->frame_cb);
rc = h4sm->frame_cb(h4sm->pkt_type, h4sm->om);
assert(rc == 0);
h4sm->om = NULL;
}
break;
#else
case HCI_H4_CMD:
case HCI_H4_EVT:
if (h4sm->buf) {
assert(h4sm->frame_cb);
rc = h4sm->frame_cb(h4sm->pkt_type, h4sm->buf);
if (rc != 0) {
ble_transport_free(h4sm->buf);
}
h4sm->buf = NULL;
}
break;
case HCI_H4_ACL:
case HCI_H4_ISO:
if (h4sm->om) {
assert(h4sm->frame_cb);
rc = h4sm->frame_cb(h4sm->pkt_type, h4sm->om);
if (rc != 0) {
os_mbuf_free_chain(h4sm->om);
}
h4sm->om = NULL;
}
break;
#endif // CONFIG_BT_CONTROLLER_ENABLED
default:
assert(0);
break;
}
}
int
hci_h4_sm_rx(struct hci_h4_sm *h4sm, const uint8_t *buf, uint16_t len)
{
struct hci_h4_input_buffer ib = {
.buf = buf,
.len = len,
};
int rc = 0;
while (ib.len && (rc >= 0)) {
rc = 0;
switch (h4sm->state) {
case HCI_H4_SM_W4_PKT_TYPE:
if (hci_h4_frame_start(h4sm, ib.buf[0]) < 0) {
return -1;
}
hci_h4_ib_consume(&ib, 1);
h4sm->state = HCI_H4_SM_W4_HEADER;
/* no break */
case HCI_H4_SM_W4_HEADER:
rc = hci_h4_sm_w4_header(h4sm, &ib);
assert(rc >= 0);
if (rc) {
break;
}
h4sm->state = HCI_H4_SM_W4_PAYLOAD;
/* no break */
case HCI_H4_SM_W4_PAYLOAD:
rc = hci_h4_sm_w4_payload(h4sm, &ib);
assert(rc >= 0);
if (rc) {
break;
}
h4sm->state = HCI_H4_SM_COMPLETED;
/* no break */
case HCI_H4_SM_COMPLETED:
hci_h4_sm_completed(h4sm);
h4sm->state = HCI_H4_SM_W4_PKT_TYPE;
break;
default:
return -1;
}
}
/* Calculate consumed bytes
*
* Note: we should always consume some bytes unless there is an oom error.
* It's also possible that we have an oom error but already consumed some
* data, in such case just return success and error will be returned on next
* pass.
*/
len = len - ib.len;
if (len == 0) {
assert(rc < 0);
return -1;
}
return len;
}
void
hci_h4_sm_init(struct hci_h4_sm *h4sm, const struct hci_h4_allocators *allocs,
hci_h4_frame_cb *frame_cb)
{
memset(h4sm, 0, sizeof(*h4sm));
h4sm->allocs = allocs;
h4sm->frame_cb = frame_cb;
}

View File

@ -0,0 +1,55 @@
/*
* SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdio.h>
#include <string.h>
#include "common/hci_driver_mem.h"
#include "common/hci_driver_h4.h"
#include "esp_hci_internal.h"
void *
hci_driver_mem_cmd_alloc(void)
{
return r_ble_hci_trans_buf_alloc(ESP_HCI_INTERNAL_BUF_CMD);
}
void *
hci_driver_mem_evt_alloc(int discardable)
{
/* The controller shouldn't invoke this. */
assert(0);
return NULL;
}
struct os_mbuf *
hci_driver_mem_acl_alloc(void)
{
return os_msys_get_pkthdr(0, ESP_HCI_INTERNAL_ACL_MBUF_LEADINGSPCAE);
}
struct os_mbuf *
hci_driver_mem_acl_len_alloc(uint32_t len)
{
return os_msys_get_pkthdr(len, ESP_HCI_INTERNAL_ACL_MBUF_LEADINGSPCAE);
}
struct os_mbuf *
hci_driver_mem_iso_alloc(void)
{
return os_msys_get_pkthdr(0, ESP_HCI_INTERNAL_ACL_MBUF_LEADINGSPCAE);
}
struct os_mbuf *
hci_driver_mem_iso_len_alloc(uint32_t len)
{
return os_msys_get_pkthdr(len, ESP_HCI_INTERNAL_ACL_MBUF_LEADINGSPCAE);
}
const struct hci_h4_allocators s_hci_driver_mem_alloc = {
.cmd = hci_driver_mem_cmd_alloc,
.evt = hci_driver_mem_evt_alloc,
.acl = hci_driver_mem_acl_alloc,
.iso = hci_driver_mem_iso_alloc,
};

View File

@ -0,0 +1,225 @@
/*
* SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdio.h>
#include <string.h>
#include "esp_log.h"
#include "os/os.h"
#include "os/os_mempool.h"
#include "esp_hci_driver.h"
#include "esp_hci_internal.h"
#include "common/hci_driver_util.h"
#define TAG "HCI_UTIL"
#define HCI_DRIVER_UTIL_TX_POOL_NUM \
(CONFIG_BT_LE_ACL_BUF_COUNT + CONFIG_BT_LE_HCI_EVT_HI_BUF_COUNT + CONFIG_BT_LE_HCI_EVT_LO_BUF_COUNT)
#ifndef min
#define min(a, b) ((a) < (b) ? (a) : (b))
#endif
/**
* @brief Structure representing HCI TX data.
*/
typedef struct hci_driver_util_tx_entry {
hci_driver_data_type_t data_type; ///< Type of the HCI TX data.
uint8_t *data; ///< Pointer to the TX data.
uint32_t length; ///< Length of the TX data.
STAILQ_ENTRY(hci_driver_util_tx_entry) next; ///< Next element in the linked list.
} hci_driver_util_tx_entry_t;
/* The list for hci_driver_util_tx_entry */
STAILQ_HEAD(hci_driver_util_tx_list, hci_driver_util_tx_entry);
typedef struct {
struct hci_driver_util_tx_list tx_head;
struct hci_driver_util_tx_entry *cur_tx_entry;
uint32_t cur_tx_off;
struct os_mempool *tx_entry_pool;
uint8_t *tx_entry_mem;
} hci_driver_util_env_t;
static hci_driver_util_env_t s_hci_driver_util_env;
static void
hci_driver_util_memory_deinit(void)
{
if (s_hci_driver_util_env.tx_entry_pool) {
free(s_hci_driver_util_env.tx_entry_pool);
s_hci_driver_util_env.tx_entry_pool = NULL;
}
if (s_hci_driver_util_env.tx_entry_mem) {
free(s_hci_driver_util_env.tx_entry_mem);
s_hci_driver_util_env.tx_entry_mem = NULL;
}
}
static int
hci_driver_util_memory_init(void)
{
int rc;
s_hci_driver_util_env.tx_entry_pool = (struct os_mempool *)malloc(sizeof(struct os_mempool));
if (!s_hci_driver_util_env.tx_entry_pool) {
ESP_LOGE(TAG, "No memory for tx pool");
goto init_err;
}
s_hci_driver_util_env.tx_entry_mem = malloc(OS_MEMPOOL_SIZE(HCI_DRIVER_UTIL_TX_POOL_NUM,
sizeof(hci_driver_util_tx_entry_t)) * sizeof(os_membuf_t));
if (!s_hci_driver_util_env.tx_entry_mem) {
ESP_LOGE(TAG, "No memory for tx pool buffer");
goto init_err;
}
rc = os_mempool_init(s_hci_driver_util_env.tx_entry_pool, HCI_DRIVER_UTIL_TX_POOL_NUM,
sizeof(hci_driver_util_tx_entry_t), s_hci_driver_util_env.tx_entry_mem,
"hci_tx_entry_pool");
if (rc) {
ESP_LOGE(TAG, "Failed to initialize tx pool");
goto init_err;
}
return 0;
init_err:
hci_driver_util_memory_deinit();
return -1;
}
void
hci_driver_util_tx_list_enqueue(hci_driver_data_type_t type, uint8_t *data, uint32_t len)
{
os_sr_t sr;
hci_driver_util_tx_entry_t *tx_entry;
tx_entry = os_memblock_get(s_hci_driver_util_env.tx_entry_pool);
assert(tx_entry != NULL);
tx_entry->data_type = type;
tx_entry->data = data;
tx_entry->length = len;
/* If the txbuf is command status event or command complete event, we should send firstly.
* The tx list maybe used in the controller task and hci task. Therefore, enter critical area.
*/
if ((type == HCI_DRIVER_TYPE_EVT) && ((data[0] == 0x0E) || (data[0] == 0x0F))) {
OS_ENTER_CRITICAL(sr);
STAILQ_INSERT_HEAD(&s_hci_driver_util_env.tx_head, tx_entry, next);
OS_EXIT_CRITICAL(sr);
} else {
OS_ENTER_CRITICAL(sr);
STAILQ_INSERT_TAIL(&s_hci_driver_util_env.tx_head, tx_entry, next);
OS_EXIT_CRITICAL(sr);
}
}
uint32_t
hci_driver_util_tx_list_dequeue(uint32_t max_tx_len, void **tx_data, bool *last_frame)
{
os_sr_t sr;
uint32_t tx_len;
uint32_t data_len;
uint16_t out_off;
struct os_mbuf *om;
hci_driver_util_tx_entry_t *tx_entry;
/* Check if there is any remaining data that hasn't been sent completely. If it has been completed,
* free the corresponding memory. Therefore, the HCI TX entry needs to be sent one by one; multiple
* entries cannot be sent together.
*/
tx_len = 0;
tx_entry = s_hci_driver_util_env.cur_tx_entry;
if (tx_entry) {
data_len = tx_entry->length;
if (tx_entry->data_type == HCI_DRIVER_TYPE_ACL) {
om = (struct os_mbuf *)tx_entry->data;
if (s_hci_driver_util_env.cur_tx_off >= data_len) {
os_mbuf_free_chain(om);
} else {
om = os_mbuf_off(om, s_hci_driver_util_env.cur_tx_off, &out_off);
tx_len = min(max_tx_len, om->om_len - out_off);
*tx_data = (void *)&om->om_data[out_off];
}
} else if (tx_entry->data_type == HCI_DRIVER_TYPE_EVT) {
if (s_hci_driver_util_env.cur_tx_off >= data_len) {
r_ble_hci_trans_buf_free(tx_entry->data);
} else {
tx_len = min(max_tx_len, data_len - s_hci_driver_util_env.cur_tx_off);
*tx_data = &tx_entry->data[s_hci_driver_util_env.cur_tx_off];
}
} else {
assert(0);
}
/* If this is the last frame, inform the invoker not to call this API until the current data
* has been completely sent.
*/
if (tx_len) {
s_hci_driver_util_env.cur_tx_off += tx_len;
if (s_hci_driver_util_env.cur_tx_off >= data_len) {
*last_frame = true;
} else {
*last_frame = false;
}
} else {
os_memblock_put(s_hci_driver_util_env.tx_entry_pool, (void *)tx_entry);
s_hci_driver_util_env.cur_tx_entry = NULL;
}
}
/* Find a new entry. */
if (!tx_len && !STAILQ_EMPTY(&s_hci_driver_util_env.tx_head)) {
OS_ENTER_CRITICAL(sr);
tx_entry = STAILQ_FIRST(&s_hci_driver_util_env.tx_head);
STAILQ_REMOVE_HEAD(&s_hci_driver_util_env.tx_head, next);
OS_EXIT_CRITICAL(sr);
*tx_data = &tx_entry->data_type;
s_hci_driver_util_env.cur_tx_entry = tx_entry;
s_hci_driver_util_env.cur_tx_off = 0;
tx_len = 1;
*last_frame = false;
}
return tx_len;
}
int
hci_driver_util_init(void)
{
memset(&s_hci_driver_util_env, 0, sizeof(hci_driver_util_env_t));
if (hci_driver_util_memory_init()) {
return -1;
}
STAILQ_INIT(&s_hci_driver_util_env.tx_head);
return 0;
}
void
hci_driver_util_deinit(void)
{
hci_driver_util_tx_entry_t *tx_entry;
hci_driver_util_tx_entry_t *next_entry;
/* Free all of controller buffers which haven't been sent yet. The whole mempool will be freed.
* Therefore, it's unnecessary to put the tx_entry into mempool.
*/
tx_entry = STAILQ_FIRST(&s_hci_driver_util_env.tx_head);
while (tx_entry) {
next_entry = STAILQ_NEXT(tx_entry, next);
if (tx_entry->data_type == HCI_DRIVER_TYPE_ACL) {
os_mbuf_free_chain((struct os_mbuf *)tx_entry->data);
} else if (tx_entry->data_type == HCI_DRIVER_TYPE_EVT) {
r_ble_hci_trans_buf_free(tx_entry->data);
}
tx_entry = next_entry;
}
hci_driver_util_memory_deinit();
memset(&s_hci_driver_util_env, 0, sizeof(hci_driver_util_env_t));
}

View File

@ -0,0 +1,222 @@
/*
* SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdio.h>
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/queue.h"
#include "freertos/task.h"
#include "freertos/semphr.h"
#include "esp_log.h"
#include "driver/uart.h"
#include "esp_hci_transport.h"
#include "esp_hci_internal.h"
#include "common/hci_driver_h4.h"
#include "common/hci_driver_util.h"
#include "common/hci_driver_mem.h"
#include "hci_driver_uart.h"
static const char *TAG = "hci_uart";
#define CONFIG_BT_LE_HCI_RX_PROC_DATA_LEN (256)
typedef struct {
TaskHandle_t tx_task_handler;
TaskHandle_t rx_task_handler;
hci_driver_uart_params_config_t *hci_uart_params;
SemaphoreHandle_t tx_sem;
QueueHandle_t rx_event_queue;
uint8_t *rx_data;
struct hci_h4_sm *h4_sm;
hci_driver_forward_fn *forward_cb;
} hci_driver_uart_env_t;
static hci_driver_uart_env_t s_hci_driver_uart_env;
static struct hci_h4_sm s_hci_driver_uart_h4_sm;
static uint8_t s_hci_driver_uart_rx_data[CONFIG_BT_LE_HCI_RX_PROC_DATA_LEN];
static hci_driver_uart_params_config_t hci_driver_uart_params = BT_HCI_DRIVER_UART_CONFIG_DEFAULT();
static int
hci_driver_uart_tx(hci_driver_data_type_t data_type, uint8_t *data, uint32_t length,
hci_driver_direction_t dir)
{
/* By now, this layer is only used by controller. */
assert(dir == HCI_DRIVER_DIR_C2H);
ESP_LOGD(TAG, "controller tx len:%d\n", length);
hci_driver_util_tx_list_enqueue(data_type, data, length);
xSemaphoreGive(s_hci_driver_uart_env.tx_sem);
return 0;
}
static int
hci_driver_uart_h4_frame_cb(uint8_t pkt_type, void *data)
{
hci_driver_forward_fn *forward_cb;
forward_cb = s_hci_driver_uart_env.forward_cb;
if (!forward_cb) {
return -1;
}
ESP_LOGD(TAG, "h4 frame\n");
return forward_cb(pkt_type, data, 0, HCI_DRIVER_DIR_H2C);
}
static void
hci_driver_uart_tx_task(void *p)
{
void *data;
bool last_frame;
uint32_t tx_len;
uart_port_t port;
port = s_hci_driver_uart_env.hci_uart_params->hci_uart_port;
while (true) {
xSemaphoreTake(s_hci_driver_uart_env.tx_sem, portMAX_DELAY);
while (true) {
tx_len = hci_driver_util_tx_list_dequeue(0xffffff, &data, &last_frame);
if (tx_len == 0) {
break;
}
ESP_LOGD(TAG, "uart tx");
ESP_LOG_BUFFER_HEXDUMP(TAG, data, tx_len, ESP_LOG_DEBUG);
uart_write_bytes(port, data, tx_len);
}
}
}
static void
hci_driver_uart_rx_task(void *p)
{
void *data;
int read_len;
int ret;
uart_port_t port;
uart_event_t uart_event;
port = s_hci_driver_uart_env.hci_uart_params->hci_uart_port;
while (true) {
xQueueReceive(s_hci_driver_uart_env.rx_event_queue, &uart_event, portMAX_DELAY);
data = s_hci_driver_uart_env.rx_data;
while (true) {
read_len = uart_read_bytes(port, data, CONFIG_BT_LE_HCI_RX_PROC_DATA_LEN, 0);
if (read_len == 0) {
break;
}
ESP_LOGD(TAG, "uart rx");
ESP_LOG_BUFFER_HEXDUMP(TAG, data, read_len, ESP_LOG_DEBUG);
ret = hci_h4_sm_rx(s_hci_driver_uart_env.h4_sm, data, read_len);
if (ret < 0) {
r_ble_ll_hci_ev_hw_err(ESP_HCI_SYNC_LOSS_ERR);
}
}
}
}
static int
hci_driver_uart_task_create(void)
{
/* !TODO: Set the core id by menuconfig */
xTaskCreatePinnedToCore(hci_driver_uart_tx_task, "hci_driver_uart_tx_task",
CONFIG_BT_LE_HCI_TRANS_TASK_STACK_SIZE, NULL,
ESP_TASK_BT_CONTROLLER_PRIO, &s_hci_driver_uart_env.tx_task_handler,
0);
assert(s_hci_driver_uart_env.tx_task_handler);
xTaskCreatePinnedToCore(hci_driver_uart_rx_task, "hci_driver_uart_rx_task",
CONFIG_BT_LE_HCI_TRANS_TASK_STACK_SIZE, NULL,
ESP_TASK_BT_CONTROLLER_PRIO, &s_hci_driver_uart_env.rx_task_handler,
0);
assert(s_hci_driver_uart_env.rx_task_handler);
ESP_LOGI(TAG, "hci transport task create successfully, prio:%d, stack size: %ld",
ESP_TASK_BT_CONTROLLER_PRIO, CONFIG_BT_LE_HCI_TRANS_TASK_STACK_SIZE);
return 0;
}
static void
hci_driver_uart_deinit(void)
{
if (s_hci_driver_uart_env.tx_task_handler) {
vTaskDelete(s_hci_driver_uart_env.tx_task_handler);
s_hci_driver_uart_env.tx_task_handler = NULL;
}
if (s_hci_driver_uart_env.rx_task_handler) {
vTaskDelete(s_hci_driver_uart_env.rx_task_handler);
s_hci_driver_uart_env.rx_task_handler = NULL;
}
ESP_ERROR_CHECK(uart_driver_delete(s_hci_driver_uart_env.hci_uart_params->hci_uart_port));
if (!s_hci_driver_uart_env.tx_sem) {
vSemaphoreDelete(s_hci_driver_uart_env.tx_sem);
}
hci_driver_util_deinit();
memset(&s_hci_driver_uart_env, 0, sizeof(hci_driver_uart_env_t));
}
static int
hci_driver_uart_init(hci_driver_forward_fn *cb)
{
int rc;
memset(&s_hci_driver_uart_env, 0, sizeof(hci_driver_uart_env_t));
s_hci_driver_uart_env.h4_sm = &s_hci_driver_uart_h4_sm;
hci_h4_sm_init(s_hci_driver_uart_env.h4_sm, &s_hci_driver_mem_alloc, hci_driver_uart_h4_frame_cb);
rc = hci_driver_util_init();
if (rc) {
goto error;
}
s_hci_driver_uart_env.tx_sem = xSemaphoreCreateBinary();
if (!s_hci_driver_uart_env.tx_sem) {
goto error;
}
s_hci_driver_uart_env.rx_data = s_hci_driver_uart_rx_data;
s_hci_driver_uart_env.forward_cb = cb;
s_hci_driver_uart_env.hci_uart_params = &hci_driver_uart_params;
hci_driver_uart_config(&hci_driver_uart_params);
/* Currently, the queue size is set to 1. It will be considered as semaphore. */
ESP_ERROR_CHECK(uart_driver_install(s_hci_driver_uart_env.hci_uart_params->hci_uart_port,
CONFIG_BT_LE_HCI_UART_RX_BUFFER_SIZE,
CONFIG_BT_LE_HCI_UART_TX_BUFFER_SIZE,
1, &s_hci_driver_uart_env.rx_event_queue,
0));
rc = hci_driver_uart_task_create();
if (rc) {
goto error;
}
return 0;
error:
hci_driver_uart_deinit();
return rc;
}
int
hci_driver_uart_reconfig_pin(int tx_pin, int rx_pin, int cts_pin, int rts_pin)
{
hci_driver_uart_params_config_t *uart_param = s_hci_driver_uart_env.hci_uart_params;
uart_param->hci_uart_tx_pin = tx_pin;
uart_param->hci_uart_rx_pin = rx_pin;
uart_param->hci_uart_rts_pin = rts_pin;
uart_param->hci_uart_cts_pin = cts_pin;
return hci_driver_uart_config(uart_param);
}
hci_driver_ops_t hci_driver_uart_ops = {
.hci_driver_tx = hci_driver_uart_tx,
.hci_driver_init = hci_driver_uart_init,
.hci_driver_deinit = hci_driver_uart_deinit,
};

View File

@ -0,0 +1,97 @@
/*
* SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
#include <inttypes.h>
#include "driver/uart.h"
#include "os/os_mbuf.h"
#include "esp_bt.h"
#include "esp_hci_transport.h"
/**
* @brief UART configuration parameters for the HCI driver
*/
typedef struct hci_driver_uart_params_config
{
uint8_t hci_uart_port; /*!< Port of UART for HCI */
uint8_t hci_uart_data_bits; /*!< Data bits of UART for HCI */
uint8_t hci_uart_stop_bits; /*!< Stop bits of UART for HCI */
uint8_t hci_uart_flow_ctrl; /*!< Flow control of UART for HCI */
uint8_t hci_uart_parity; /*!< UART parity */
uint8_t hci_uart_driver_mode; /*!< UART driver mode */
uint32_t hci_uart_baud; /*!< Baudrate of UART for HCI */
int hci_uart_tx_pin; /*!< Tx Pin number of UART for HCI */
int hci_uart_rx_pin; /*!< Rx Pin number of UART for HCI */
int hci_uart_rts_pin; /*!< RTS Pin number of UART for HCI */
int hci_uart_cts_pin; /*!< CTS Pin number of UART for HCI */
} hci_driver_uart_params_config_t;
#define BT_HCI_DRIVER_UART_CONFIG_DEFAULT() { \
.hci_uart_port = DEFAULT_BT_LE_HCI_UART_PORT, \
.hci_uart_baud = DEFAULT_BT_LE_HCI_UART_BAUD, \
.hci_uart_tx_pin = DEFAULT_BT_LE_HCI_UART_TX_PIN , \
.hci_uart_rx_pin = DEFAULT_BT_LE_HCI_UART_RX_PIN, \
.hci_uart_cts_pin = DEFAULT_BT_LE_HCI_UART_CTS_PIN, \
.hci_uart_rts_pin = DEFAULT_BT_LE_HCI_UART_RTS_PIN, \
.hci_uart_data_bits = DEFAULT_BT_LE_HCI_UART_DATA_BITS, \
.hci_uart_stop_bits = DEFAULT_BT_LE_HCI_UART_STOP_BITS, \
.hci_uart_flow_ctrl = DEFAULT_BT_LE_HCI_UART_FLOW_CTRL, \
.hci_uart_parity = DEFAULT_BT_LE_HCI_UART_PARITY, \
}
/**
* @brief Configures the HCI driver UART parameters.
* This function sets up the UART interface according to the specified configuration parameters.
*
* @param uart_config A pointer to a structure containing the UART configuration parameters.
* The structure should include details such as baud rate, parity, stop bits, and flow control.
* Ensure that the uart_config structure is correctly initialized before calling this function.
*
* @return int Returns 0 on success, or a non-zero error code on failure.
*
* @note This function should be called before any UART communication is initiated.
*/
int hci_driver_uart_config(hci_driver_uart_params_config_t *uart_config);
#if CONFIG_BT_LE_UART_HCI_DMA_MODE
/**
* @brief Reconfigure the UART pins for the HCI driver.
*
* This function changes the UART pin configuration for the HCI driver.
*
* @param tx_pin The pin number for the UART TX (transmit) line.
* @param rx_pin The pin number for the UART RX (receive) line.
* @param cts_pin The pin number for the UART CTS (clear to send) line.
* @param rts_pin The pin number for the UART RTS (request to send) line.
*
* @return int Returns 0 on success, or a negative error code on failure.
*/
int hci_driver_uart_dma_reconfig_pin(int tx_pin, int rx_pin, int cts_pin, int rts_pin);
#define hci_uart_reconfig_pin hci_driver_uart_dma_reconfig_pin
#else
/**
* @brief Reconfigure the UART pins for the HCI driver.
*
* This function changes the UART pin configuration for the HCI driver.
*
* @param tx_pin The pin number for the UART TX (transmit) line.
* @param rx_pin The pin number for the UART RX (receive) line.
* @param cts_pin The pin number for the UART CTS (clear to send) line.
* @param rts_pin The pin number for the UART RTS (request to send) line.
*
* @return int Returns 0 on success, or a negative error code on failure.
*/
int hci_driver_uart_reconfig_pin(int tx_pin, int rx_pin, int cts_pin, int rts_pin);
#define hci_uart_reconfig_pin hci_driver_uart_reconfig_pin
#endif // CONFIG_BT_LE_UART_HCI_DMA_MODE
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,40 @@
/*
* SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdio.h>
#include <string.h>
#include "esp_log.h"
#include "driver/uart.h"
#include "hci_driver_uart.h"
static const char *TAG = "hci_uart_config";
static uart_config_t s_uart_cfg;
int hci_driver_uart_config(hci_driver_uart_params_config_t *uart_config)
{
uart_config_t *uart_cfg;
uart_cfg = &s_uart_cfg;
uart_cfg->baud_rate = uart_config->hci_uart_baud;
uart_cfg->data_bits = uart_config->hci_uart_data_bits;
uart_cfg->stop_bits = uart_config->hci_uart_stop_bits;
uart_cfg->parity = uart_config->hci_uart_parity;
uart_cfg->flow_ctrl = uart_config->hci_uart_flow_ctrl;
uart_cfg->source_clk= UART_SCLK_DEFAULT;
uart_cfg->rx_flow_ctrl_thresh = UART_HW_FIFO_LEN(uart_config->hci_uart_port) - 1;
ESP_LOGI(TAG,"set uart pin tx:%d, rx:%d.\n", uart_config->hci_uart_tx_pin, uart_config->hci_uart_rx_pin);
ESP_LOGI(TAG,"set rts:%d, cts:%d.\n", uart_config->hci_uart_rts_pin, uart_config->hci_uart_cts_pin);
ESP_LOGI(TAG,"set baud_rate:%d.\n", uart_config->hci_uart_baud);
ESP_LOGI(TAG,"set flow_ctrl:%d.\n", uart_config->hci_uart_flow_ctrl);
ESP_ERROR_CHECK(uart_driver_delete(uart_config->hci_uart_port));
ESP_ERROR_CHECK(uart_param_config(uart_config->hci_uart_port, uart_cfg));
ESP_ERROR_CHECK(uart_set_pin(uart_config->hci_uart_port, uart_config->hci_uart_tx_pin, uart_config->hci_uart_rx_pin,
uart_config->hci_uart_rts_pin, uart_config->hci_uart_cts_pin));
return 0;
}

View File

@ -0,0 +1,671 @@
/*
* SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdio.h>
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/queue.h"
#include "freertos/task.h"
#include "freertos/semphr.h"
#include "esp_log.h"
#include "driver/uart.h"
#include "esp_hci_transport.h"
#include "esp_hci_internal.h"
#include "common/hci_driver_h4.h"
#include "common/hci_driver_util.h"
#include "common/hci_driver_mem.h"
#include "hci_driver_uart.h"
#include "ble_hci_trans.h"
#include "esp_private/periph_ctrl.h"
#include "esp_private/gdma.h"
#include "hal/uhci_ll.h"
/*
* UART DMA Desc struct
*
* --------------------------------------------------------------
* | own | EoF | sub_sof | 5'b0 | length [11:0] | size [11:0] |
* --------------------------------------------------------------
* | buf_ptr [31:0] |
* --------------------------------------------------------------
* | next_desc_ptr [31:0] |
* --------------------------------------------------------------
*/
/* this bitfield is start from the LSB!!! */
typedef struct uhci_lldesc_s {
volatile uint32_t size : 12,
length: 12,
offset: 5, /* h/w reserved 5bit, s/w use it as offset in buffer */
sosf : 1, /* start of sub-frame */
eof : 1, /* end of frame */
owner : 1; /* hw or sw */
volatile const uint8_t *buf; /* point to buffer data */
union {
volatile uint32_t empty;
STAILQ_ENTRY(uhci_lldesc_s) qe; /* pointing to the next desc */
};
} uhci_lldesc_t;
/**
* @brief Enumeration of HCI transport transmission states.
*/
typedef enum {
HCI_TRANS_TX_IDLE, ///< HCI Transport TX is in idle state.
HCI_TRANS_TX_START, ///< HCI Transport TX is starting transmission.
HCI_TRANS_TX_END, ///< HCI Transport TX has completed transmission.
} hci_trans_tx_state_t;
typedef struct {
TaskHandle_t task_handler;
hci_driver_uart_params_config_t *hci_uart_params;
SemaphoreHandle_t process_sem;
struct hci_h4_sm *h4_sm;
hci_driver_forward_fn *forward_cb;
struct os_mempool *hci_rx_data_pool; /*!< Init a memory pool for rx_data cache */
uint8_t *hci_rx_data_buffer;
struct os_mempool *hci_rxinfo_pool; /*!< Init a memory pool for rxinfo cache */
os_membuf_t *hci_rxinfo_buffer;
volatile bool rxinfo_mem_exhausted; /*!< Indicate rxinfo memory does not exist */
volatile bool is_continue_rx; /*!< Continue to rx */
volatile hci_trans_tx_state_t hci_tx_state; /*!< HCI Tx State */
struct os_mempool lldesc_mem_pool;/*!< Init a memory pool for uhci_lldesc_t */
uhci_lldesc_t *lldesc_mem;
} hci_driver_uart_dma_env_t;
#define ESP_BT_HCI_TL_STATUS_OK (0) /*!< HCI_TL Tx/Rx operation status OK */
/* The number of lldescs pool */
#define HCI_LLDESCS_POOL_NUM (CONFIG_BT_LE_HCI_LLDESCS_POOL_NUM)
/* Default block size for HCI RX data */
#define HCI_RX_DATA_BLOCK_SIZE (DEFAULT_BT_LE_ACL_BUF_SIZE + BLE_HCI_TRANS_CMD_SZ)
#define HCI_RX_DATA_POOL_NUM (CONFIG_BT_LE_HCI_TRANS_RX_MEM_NUM)
#define HCI_RX_INFO_POOL_NUM (CONFIG_BT_LE_HCI_TRANS_RX_MEM_NUM + 1)
/**
* @brief callback function for HCI Transport Layer send/receive operations
*/
typedef void (* esp_bt_hci_tl_callback_t) (void *arg, uint8_t status);
struct uart_txrxchannel {
esp_bt_hci_tl_callback_t callback;
void *arg;
uhci_lldesc_t *link_head;
};
struct uart_env_tag {
struct uart_txrxchannel tx;
struct uart_txrxchannel rx;
};
typedef struct hci_message {
void *ptr; ///< Pointer to the message data.
uint32_t length; ///< Length of the message data.
STAILQ_ENTRY(hci_message) next; ///< Next element in the linked list.
} hci_message_t;
static void hci_driver_uart_dma_recv_async(uint8_t *buf, uint32_t size, esp_bt_hci_tl_callback_t callback, void *arg);
int hci_driver_uart_dma_rx_start(uint8_t *rx_data, uint32_t length);
int hci_driver_uart_dma_tx_start(esp_bt_hci_tl_callback_t callback, void *arg);
static const char *TAG = "uart_dma";
static hci_driver_uart_dma_env_t s_hci_driver_uart_dma_env;
static struct hci_h4_sm s_hci_driver_uart_h4_sm;
static hci_driver_uart_params_config_t hci_driver_uart_dma_params = BT_HCI_DRIVER_UART_CONFIG_DEFAULT();
/* The list for hci_rx_data */
STAILQ_HEAD(g_hci_rxinfo_list, hci_message);
DRAM_ATTR struct g_hci_rxinfo_list g_hci_rxinfo_head;
static DRAM_ATTR struct uart_env_tag uart_env;
static volatile uhci_dev_t *s_uhci_hw = &UHCI0;
static DRAM_ATTR gdma_channel_handle_t s_rx_channel;
static DRAM_ATTR gdma_channel_handle_t s_tx_channel;
static int hci_driver_uart_dma_memory_deinit(void)
{
if (s_hci_driver_uart_dma_env.hci_rxinfo_buffer) {
free(s_hci_driver_uart_dma_env.hci_rxinfo_buffer);
s_hci_driver_uart_dma_env.hci_rxinfo_buffer = NULL;
}
if (s_hci_driver_uart_dma_env.hci_rxinfo_pool) {
free(s_hci_driver_uart_dma_env.hci_rxinfo_pool);
s_hci_driver_uart_dma_env.hci_rxinfo_pool = NULL;
}
if (s_hci_driver_uart_dma_env.hci_rx_data_buffer) {
free(s_hci_driver_uart_dma_env.hci_rx_data_buffer);
s_hci_driver_uart_dma_env.hci_rx_data_buffer = NULL;
}
if (s_hci_driver_uart_dma_env.hci_rx_data_pool) {
free(s_hci_driver_uart_dma_env.hci_rx_data_pool);
s_hci_driver_uart_dma_env.hci_rx_data_pool = NULL;
}
if (s_hci_driver_uart_dma_env.lldesc_mem) {
free(s_hci_driver_uart_dma_env.lldesc_mem);
s_hci_driver_uart_dma_env.lldesc_mem = NULL;
}
return 0;
}
static int hci_driver_uart_dma_memory_init(void)
{
int rc = 0;
s_hci_driver_uart_dma_env.lldesc_mem = malloc(OS_MEMPOOL_SIZE(HCI_LLDESCS_POOL_NUM,
sizeof (uhci_lldesc_t)) * sizeof(os_membuf_t));
if (!s_hci_driver_uart_dma_env.lldesc_mem) {
return -1;
}
rc = os_mempool_init(&s_hci_driver_uart_dma_env.lldesc_mem_pool, HCI_LLDESCS_POOL_NUM,
sizeof (uhci_lldesc_t), s_hci_driver_uart_dma_env.lldesc_mem, "hci_lldesc_pool");
if (rc) {
goto init_err;
}
s_hci_driver_uart_dma_env.hci_rx_data_pool = (struct os_mempool *)malloc(sizeof(struct os_mempool));
if (!s_hci_driver_uart_dma_env.hci_rx_data_pool) {
goto init_err;
}
memset(s_hci_driver_uart_dma_env.hci_rx_data_pool, 0, sizeof(struct os_mempool));
s_hci_driver_uart_dma_env.hci_rx_data_buffer = malloc(OS_MEMPOOL_SIZE(HCI_RX_DATA_POOL_NUM,
HCI_RX_DATA_BLOCK_SIZE) * sizeof(os_membuf_t));
if (!s_hci_driver_uart_dma_env.hci_rx_data_buffer) {
goto init_err;
}
memset(s_hci_driver_uart_dma_env.hci_rx_data_buffer, 0, OS_MEMPOOL_SIZE(HCI_RX_DATA_POOL_NUM,
HCI_RX_DATA_BLOCK_SIZE) * sizeof(os_membuf_t));
rc = os_mempool_init(s_hci_driver_uart_dma_env.hci_rx_data_pool, HCI_RX_DATA_POOL_NUM,
HCI_RX_DATA_BLOCK_SIZE, s_hci_driver_uart_dma_env.hci_rx_data_buffer,
"hci_rx_data_pool");
if (rc) {
goto init_err;
}
/* Malloc hci rxinfo pool */
s_hci_driver_uart_dma_env.hci_rxinfo_pool = (struct os_mempool *)malloc(sizeof(struct os_mempool));
if (!s_hci_driver_uart_dma_env.hci_rxinfo_pool) {
goto init_err;
}
memset(s_hci_driver_uart_dma_env.hci_rxinfo_pool, 0, sizeof(struct os_mempool));
s_hci_driver_uart_dma_env.hci_rxinfo_buffer = malloc(OS_MEMPOOL_SIZE(HCI_RX_INFO_POOL_NUM,
sizeof(hci_message_t)) * sizeof(os_membuf_t));
if (!s_hci_driver_uart_dma_env.hci_rxinfo_buffer) {
goto init_err;
}
memset(s_hci_driver_uart_dma_env.hci_rxinfo_buffer, 0, OS_MEMPOOL_SIZE(HCI_RX_INFO_POOL_NUM,
sizeof(hci_message_t)) * sizeof(os_membuf_t));
rc = os_mempool_init(s_hci_driver_uart_dma_env.hci_rxinfo_pool, HCI_RX_INFO_POOL_NUM,
sizeof(hci_message_t), s_hci_driver_uart_dma_env.hci_rxinfo_buffer,
"hci_rxinfo_pool");
if (rc) {
goto init_err;
}
return rc;
init_err:
hci_driver_uart_dma_memory_deinit();
return rc;
}
static IRAM_ATTR bool hci_uart_tl_rx_eof_callback(gdma_channel_handle_t dma_chan, gdma_event_data_t *event_data, void *user_data)
{
esp_bt_hci_tl_callback_t callback = uart_env.rx.callback;
void *arg = uart_env.rx.arg;
assert(dma_chan == s_rx_channel);
assert(uart_env.rx.callback != NULL);
// clear callback pointer
uart_env.rx.callback = NULL;
uart_env.rx.arg = NULL;
// call handler
callback(arg, ESP_BT_HCI_TL_STATUS_OK);
return true;
}
static IRAM_ATTR bool hci_uart_tl_tx_eof_callback(gdma_channel_handle_t dma_chan, gdma_event_data_t *event_data, void *user_data)
{
esp_bt_hci_tl_callback_t callback = uart_env.tx.callback;
assert(dma_chan == s_tx_channel);
assert(uart_env.tx.callback != NULL);
// clear callback pointer
uart_env.tx.callback = NULL;
// call handler
callback(uart_env.tx.arg, ESP_BT_HCI_TL_STATUS_OK);
uart_env.tx.arg = NULL;
return true;
}
uint8_t * IRAM_ATTR hci_driver_uart_dma_rxdata_memory_get(void)
{
uint8_t *rx_data;
rx_data = os_memblock_get(s_hci_driver_uart_dma_env.hci_rx_data_pool);
return rx_data;
}
hci_message_t * IRAM_ATTR hci_driver_uart_dma_rxinfo_memory_get(void)
{
hci_message_t *rx_info;
rx_info = os_memblock_get(s_hci_driver_uart_dma_env.hci_rxinfo_pool);
return rx_info;
}
void IRAM_ATTR hci_driver_uart_dma_cache_rxinfo(hci_message_t *hci_rxinfo)
{
os_sr_t sr;
OS_ENTER_CRITICAL(sr);
STAILQ_INSERT_TAIL(&g_hci_rxinfo_head, hci_rxinfo, next);
OS_EXIT_CRITICAL(sr);
}
void IRAM_ATTR hci_driver_uart_dma_continue_rx_enable(bool enable)
{
os_sr_t sr;
OS_ENTER_CRITICAL(sr);
s_hci_driver_uart_dma_env.is_continue_rx = enable;
OS_EXIT_CRITICAL(sr);
}
void IRAM_ATTR hci_driver_uart_dma_rxinfo_mem_exhausted_set(bool is_exhausted)
{
os_sr_t sr;
OS_ENTER_CRITICAL(sr);
s_hci_driver_uart_dma_env.rxinfo_mem_exhausted = is_exhausted;
OS_EXIT_CRITICAL(sr);
}
void IRAM_ATTR hci_driver_uart_dma_recv_callback(void *arg, uint8_t status)
{
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
hci_message_t *hci_rxinfo;
uint8_t *rx_data;
if (s_hci_driver_uart_dma_env.rxinfo_mem_exhausted) {
ESP_LOGE(TAG, "Will lost rx data, need adjust rxinfo memory count\n");
assert(0);
}
hci_rxinfo = hci_driver_uart_dma_rxinfo_memory_get();
if (!hci_rxinfo) {
ESP_LOGW(TAG, "set rxinfo mem exhausted flag\n");
hci_driver_uart_dma_rxinfo_mem_exhausted_set(true);
xSemaphoreGiveFromISR(s_hci_driver_uart_dma_env.process_sem, &xHigherPriorityTaskWoken);
return;
}
hci_rxinfo->ptr = (void *)uart_env.rx.link_head->buf;
hci_rxinfo->length = uart_env.rx.link_head->length;
hci_driver_uart_dma_cache_rxinfo(hci_rxinfo);
xSemaphoreGiveFromISR(s_hci_driver_uart_dma_env.process_sem, &xHigherPriorityTaskWoken);
rx_data = hci_driver_uart_dma_rxdata_memory_get();
if (!rx_data) {
hci_driver_uart_dma_continue_rx_enable(true);
}else {
hci_driver_uart_dma_rx_start(rx_data, HCI_RX_DATA_BLOCK_SIZE);
}
}
void IRAM_ATTR hci_driver_uart_dma_txstate_set(hci_trans_tx_state_t tx_state)
{
os_sr_t sr;
OS_ENTER_CRITICAL(sr);
s_hci_driver_uart_dma_env.hci_tx_state = tx_state;
OS_EXIT_CRITICAL(sr);
}
void IRAM_ATTR hci_driver_uart_dma_send_callback(void *arg, uint8_t status)
{
uhci_lldesc_t *lldesc_head;
uhci_lldesc_t *lldesc_nxt;
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
lldesc_head = uart_env.tx.link_head;
while (lldesc_head) {
lldesc_nxt = lldesc_head->qe.stqe_next;
os_memblock_put(&s_hci_driver_uart_dma_env.lldesc_mem_pool, lldesc_head);
lldesc_head = lldesc_nxt;
}
uart_env.tx.link_head = NULL;
hci_driver_uart_dma_txstate_set(HCI_TRANS_TX_IDLE);
xSemaphoreGiveFromISR(s_hci_driver_uart_dma_env.process_sem, &xHigherPriorityTaskWoken);
}
static IRAM_ATTR void hci_driver_uart_dma_recv_async(uint8_t *buf, uint32_t size, esp_bt_hci_tl_callback_t callback, void *arg)
{
uhci_lldesc_t *lldesc_head;
assert(buf != NULL);
assert(size != 0);
assert(callback != NULL);
uart_env.rx.callback = callback;
uart_env.rx.arg = arg;
lldesc_head = uart_env.rx.link_head;
while (lldesc_head) {
os_memblock_put(&s_hci_driver_uart_dma_env.lldesc_mem_pool, lldesc_head),
lldesc_head = lldesc_head->qe.stqe_next;
}
uart_env.rx.link_head = NULL;
lldesc_head = os_memblock_get(&s_hci_driver_uart_dma_env.lldesc_mem_pool);
assert(lldesc_head);
memset(lldesc_head, 0, sizeof(uhci_lldesc_t));
lldesc_head->buf = buf;
lldesc_head->size = size;
lldesc_head->eof = 0;
s_uhci_hw->pkt_thres.pkt_thrs = size;
uart_env.rx.link_head = lldesc_head;
gdma_start(s_rx_channel, (intptr_t)(uart_env.rx.link_head));
}
int IRAM_ATTR hci_driver_uart_dma_rx_start(uint8_t *rx_data, uint32_t length)
{
hci_driver_uart_dma_recv_async(rx_data, length, hci_driver_uart_dma_recv_callback, NULL);
return 0;
}
int hci_driver_uart_dma_tx_start(esp_bt_hci_tl_callback_t callback, void *arg)
{
void *data;
bool last_frame;
bool head_is_setted;
uint32_t tx_len;
uhci_lldesc_t *lldesc_data;
uhci_lldesc_t *lldesc_head;
uhci_lldesc_t *lldesc_tail;
lldesc_head = NULL;
lldesc_tail = NULL;
head_is_setted = false;
last_frame = false;
while (true) {
tx_len = hci_driver_util_tx_list_dequeue(0xffffff, &data, &last_frame);
if (!tx_len) {
break;
}
lldesc_data = os_memblock_get(&s_hci_driver_uart_dma_env.lldesc_mem_pool);
/* According to the current processing logic It should not be empty */
assert(lldesc_data);
memset(lldesc_data, 0, sizeof(uhci_lldesc_t));
lldesc_data->length = tx_len;
lldesc_data->buf = data;
lldesc_data->eof = 0;
if (!head_is_setted) {
lldesc_head = lldesc_data;
head_is_setted = true;
} else {
lldesc_tail->qe.stqe_next = lldesc_data;
}
lldesc_tail = lldesc_data;
if (last_frame) {
break;
}
}
if (lldesc_head) {
lldesc_tail->eof = 1;
uart_env.tx.link_head = lldesc_head;
uart_env.tx.callback = callback;
uart_env.tx.arg = arg;
/* The DMA interrupt may have been triggered before setting the tx_state,
* So we set it first.
*/
hci_driver_uart_dma_txstate_set(HCI_TRANS_TX_START);
gdma_start(s_tx_channel, (intptr_t)(uart_env.tx.link_head));
return 0;
} else {
return -1;
}
}
static void hci_driver_uart_dma_install(void)
{
periph_module_enable(PERIPH_UHCI0_MODULE);
periph_module_reset(PERIPH_UHCI0_MODULE);
// install DMA driver
gdma_channel_alloc_config_t tx_channel_config = {
.flags.reserve_sibling = 1,
.direction = GDMA_CHANNEL_DIRECTION_TX,
};
ESP_ERROR_CHECK(gdma_new_channel(&tx_channel_config, &s_tx_channel));
gdma_channel_alloc_config_t rx_channel_config = {
.direction = GDMA_CHANNEL_DIRECTION_RX,
.sibling_chan = s_tx_channel,
};
ESP_ERROR_CHECK(gdma_new_channel(&rx_channel_config, &s_rx_channel));
gdma_connect(s_tx_channel, GDMA_MAKE_TRIGGER(GDMA_TRIG_PERIPH_UHCI, 0));
gdma_connect(s_rx_channel, GDMA_MAKE_TRIGGER(GDMA_TRIG_PERIPH_UHCI, 0));
gdma_strategy_config_t strategy_config = {
.auto_update_desc = false,
.owner_check = false
};
gdma_apply_strategy(s_tx_channel, &strategy_config);
gdma_apply_strategy(s_rx_channel, &strategy_config);
gdma_rx_event_callbacks_t rx_cbs = {
.on_recv_eof = hci_uart_tl_rx_eof_callback
};
gdma_register_rx_event_callbacks(s_rx_channel, &rx_cbs, NULL);
gdma_tx_event_callbacks_t tx_cbs = {
.on_trans_eof = hci_uart_tl_tx_eof_callback
};
gdma_register_tx_event_callbacks(s_tx_channel, &tx_cbs, NULL);
// configure UHCI
uhci_ll_init((uhci_dev_t *)s_uhci_hw);
// uhci_ll_set_eof_mode((uhci_dev_t *)s_uhci_hw, UHCI_RX_LEN_EOF);
uhci_ll_set_eof_mode((uhci_dev_t *)s_uhci_hw, UHCI_RX_IDLE_EOF);
// disable software flow control
s_uhci_hw->escape_conf.val = 0;
uhci_ll_attach_uart_port((uhci_dev_t *)s_uhci_hw, s_hci_driver_uart_dma_env.hci_uart_params->hci_uart_port);
}
static int
hci_driver_uart_dma_tx(hci_driver_data_type_t data_type, uint8_t *data, uint32_t length,
hci_driver_direction_t dir)
{
/* By now, this layer is only used by controller. */
assert(dir == HCI_DRIVER_DIR_C2H);
ESP_LOGD(TAG, "dma tx:");
ESP_LOG_BUFFER_HEXDUMP(TAG, data, length, ESP_LOG_DEBUG);
hci_driver_util_tx_list_enqueue(data_type, data, length);
xSemaphoreGive(s_hci_driver_uart_dma_env.process_sem);
return 0;
}
static int
hci_driver_uart_dma_h4_frame_cb(uint8_t pkt_type, void *data)
{
hci_driver_forward_fn *forward_cb;
forward_cb = s_hci_driver_uart_dma_env.forward_cb;
if (!forward_cb) {
return -1;
}
ESP_LOGD(TAG, "h4 frame\n");
return forward_cb(pkt_type, data, 0, HCI_DRIVER_DIR_H2C);
}
static void
hci_driver_uart_dma_process_task(void *p)
{
hci_message_t *rxinfo_container;
os_sr_t sr;
int ret;
uint8_t* rx_data;
uint32_t rx_len;
while (true) {
xSemaphoreTake(s_hci_driver_uart_dma_env.process_sem, portMAX_DELAY);
ESP_LOGD(TAG, "task run:%d\n",s_hci_driver_uart_dma_env.hci_tx_state);
/* Process Tx data */
if (s_hci_driver_uart_dma_env.hci_tx_state == HCI_TRANS_TX_IDLE) {
hci_driver_uart_dma_tx_start(hci_driver_uart_dma_send_callback, (void*)&uart_env);
}
if (s_hci_driver_uart_dma_env.rxinfo_mem_exhausted) {
rx_data = (void *)uart_env.rx.link_head->buf;
rx_len = uart_env.rx.link_head->length;
ESP_LOGD(TAG, "rxinfo exhausted:");
ESP_LOG_BUFFER_HEXDUMP(TAG, rx_data, rx_len, ESP_LOG_DEBUG);
ret = hci_h4_sm_rx(s_hci_driver_uart_dma_env.h4_sm, rx_data, rx_len);
hci_driver_uart_dma_rx_start(rx_data, HCI_RX_DATA_BLOCK_SIZE);
hci_driver_uart_dma_rxinfo_mem_exhausted_set(false);
if (ret < 0) {
ESP_LOGW(TAG, "parse rx data error!\n");
r_ble_ll_hci_ev_hw_err(ESP_HCI_SYNC_LOSS_ERR);
}
}
while (!STAILQ_EMPTY(&g_hci_rxinfo_head)) {
OS_ENTER_CRITICAL(sr);
rxinfo_container = STAILQ_FIRST(&g_hci_rxinfo_head);
STAILQ_REMOVE_HEAD(&g_hci_rxinfo_head, next);
OS_EXIT_CRITICAL(sr);
rx_data = rxinfo_container->ptr;
rx_len = rxinfo_container->length;
ESP_LOGD(TAG, "uart rx");
ESP_LOG_BUFFER_HEXDUMP(TAG, rx_data, rx_len, ESP_LOG_DEBUG);
ret = hci_h4_sm_rx(s_hci_driver_uart_dma_env.h4_sm, rx_data, rx_len);
if (ret < 0) {
ESP_LOGW(TAG, "parse rx data error!\n");
r_ble_ll_hci_ev_hw_err(ESP_HCI_SYNC_LOSS_ERR);
}
os_memblock_put(s_hci_driver_uart_dma_env.hci_rxinfo_pool, rxinfo_container);
/* No need to enter CRITICAL */
if (s_hci_driver_uart_dma_env.is_continue_rx) {
/* We should set continux rx flag first, RX interrupted may happened when rx start soon */
hci_driver_uart_dma_continue_rx_enable(false);
hci_driver_uart_dma_rx_start(rx_data, HCI_RX_DATA_BLOCK_SIZE);
} else {
os_memblock_put(s_hci_driver_uart_dma_env.hci_rx_data_pool, rx_data);
}
}
}
}
static int
hci_driver_uart_dma_task_create(void)
{
/* !TODO: Set the core id by menuconfig */
xTaskCreatePinnedToCore(hci_driver_uart_dma_process_task, "hci_driver_uart_dma_process_task",
CONFIG_BT_LE_HCI_TRANS_TASK_STACK_SIZE, NULL,
ESP_TASK_BT_CONTROLLER_PRIO, &s_hci_driver_uart_dma_env.task_handler,
0);
assert(s_hci_driver_uart_dma_env.task_handler);
ESP_LOGI(TAG, "hci transport task create successfully, prio:%d, stack size: %ld",
ESP_TASK_BT_CONTROLLER_PRIO, CONFIG_BT_LE_HCI_TRANS_TASK_STACK_SIZE);
return 0;
}
static void
hci_driver_uart_dma_deinit(void)
{
if (s_hci_driver_uart_dma_env.task_handler) {
vTaskDelete(s_hci_driver_uart_dma_env.task_handler);
s_hci_driver_uart_dma_env.task_handler = NULL;
}
ESP_ERROR_CHECK(uart_driver_delete(s_hci_driver_uart_dma_env.hci_uart_params->hci_uart_port));
hci_driver_uart_dma_memory_deinit();
if (!s_hci_driver_uart_dma_env.process_sem) {
vSemaphoreDelete(s_hci_driver_uart_dma_env.process_sem);
}
hci_driver_util_deinit();
memset(&s_hci_driver_uart_dma_env, 0, sizeof(hci_driver_uart_dma_env_t));
}
static int
hci_driver_uart_dma_init(hci_driver_forward_fn *cb)
{
int rc;
memset(&s_hci_driver_uart_dma_env, 0, sizeof(hci_driver_uart_dma_env_t));
s_hci_driver_uart_dma_env.h4_sm = &s_hci_driver_uart_h4_sm;
hci_h4_sm_init(s_hci_driver_uart_dma_env.h4_sm, &s_hci_driver_mem_alloc, hci_driver_uart_dma_h4_frame_cb);
rc = hci_driver_util_init();
if (rc) {
goto error;
}
s_hci_driver_uart_dma_env.process_sem = xSemaphoreCreateBinary();
if (!s_hci_driver_uart_dma_env.process_sem) {
goto error;
}
rc = hci_driver_uart_dma_memory_init();
if (rc) {
goto error;
}
s_hci_driver_uart_dma_env.forward_cb = cb;
s_hci_driver_uart_dma_env.hci_uart_params = &hci_driver_uart_dma_params;
hci_driver_uart_config(&hci_driver_uart_dma_params);
ESP_LOGI(TAG, "uart attach uhci!");
hci_driver_uart_dma_install();
STAILQ_INIT(&g_hci_rxinfo_head);
rc = hci_driver_uart_dma_task_create();
if (rc) {
goto error;
}
s_hci_driver_uart_dma_env.hci_tx_state = HCI_TRANS_TX_IDLE;
s_hci_driver_uart_dma_env.rxinfo_mem_exhausted = false;
s_hci_driver_uart_dma_env.is_continue_rx = false;
hci_driver_uart_dma_rx_start(os_memblock_get(s_hci_driver_uart_dma_env.hci_rx_data_pool),
HCI_RX_DATA_BLOCK_SIZE);
return 0;
error:
hci_driver_uart_dma_deinit();
return rc;
}
int
hci_driver_uart_dma_reconfig_pin(int tx_pin, int rx_pin, int cts_pin, int rts_pin)
{
hci_driver_uart_params_config_t *uart_param = s_hci_driver_uart_dma_env.hci_uart_params;
uart_param->hci_uart_tx_pin = tx_pin;
uart_param->hci_uart_rx_pin = rx_pin;
uart_param->hci_uart_rts_pin = rts_pin;
uart_param->hci_uart_cts_pin = cts_pin;
return hci_driver_uart_config(uart_param);
}
hci_driver_ops_t hci_driver_uart_dma_ops = {
.hci_driver_tx = hci_driver_uart_dma_tx,
.hci_driver_init = hci_driver_uart_dma_init,
.hci_driver_deinit = hci_driver_uart_dma_deinit,
};

View File

@ -0,0 +1,61 @@
/*
* SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <string.h>
#include <stdio.h>
#include "esp_hci_internal.h"
#include "esp_hci_driver.h"
typedef struct {
hci_driver_forward_fn *forward_cb;
} hci_driver_vhci_env_t;
static hci_driver_vhci_env_t s_hci_driver_vhci_env;
static int
hci_driver_vhci_controller_tx(hci_driver_data_type_t data_type, uint8_t *data)
{
/* The length is contained in the data. */
return s_hci_driver_vhci_env.forward_cb(data_type, data, 0, HCI_DRIVER_DIR_C2H);
}
static int
hci_driver_vhci_host_tx(hci_driver_data_type_t data_type, uint8_t *data, uint32_t length)
{
return s_hci_driver_vhci_env.forward_cb(data_type, data, length, HCI_DRIVER_DIR_H2C);
}
static int
hci_driver_vhci_tx(hci_driver_data_type_t data_type, uint8_t *data, uint32_t length,
hci_driver_direction_t dir)
{
int rc;
if (dir == HCI_DRIVER_DIR_C2H) {
rc = hci_driver_vhci_controller_tx(data_type, data);
} else {
rc = hci_driver_vhci_host_tx(data_type, data, length);
}
return rc;
}
static int
hci_driver_vhci_init(hci_driver_forward_fn *cb)
{
s_hci_driver_vhci_env.forward_cb = cb;
return 0;
}
static void
hci_driver_vhci_deinit(void)
{
memset(&s_hci_driver_vhci_env, 0, sizeof(hci_driver_vhci_env_t));
}
hci_driver_ops_t hci_driver_vhci_ops = {
.hci_driver_tx = hci_driver_vhci_tx,
.hci_driver_init = hci_driver_vhci_init,
.hci_driver_deinit = hci_driver_vhci_deinit,
};

View File

@ -0,0 +1,149 @@
/*
* SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <string.h>
#include <stdio.h>
#include "os/os_mbuf.h"
#include "esp_hci_transport.h"
#include "esp_hci_internal.h"
#include "esp_hci_driver.h"
#include "esp_bt.h"
typedef struct {
hci_driver_forward_fn *forward_cb;
const esp_vhci_host_callback_t *host_recv_cb;
} hci_driver_vhci_env_t;
static hci_driver_vhci_env_t s_hci_driver_vhci_env;
static int
hci_driver_vhci_controller_tx(hci_driver_data_type_t data_type, uint8_t *data, uint32_t length)
{
int rc;
uint16_t buf_len = 0;
uint8_t *buf = NULL;
struct os_mbuf *om;
if (data_type == HCI_DRIVER_TYPE_ACL) {
om = (struct os_mbuf *)data;
buf_len = length + 1;
buf = malloc(buf_len);
/* TODO: If there is no memory, should handle it in the controller. */
assert(buf);
buf[0] = HCI_DRIVER_TYPE_ACL;
os_mbuf_copydata(om, 0, length, &buf[1]);
os_mbuf_free_chain(om);
} else if (data_type == HCI_DRIVER_TYPE_EVT) {
buf_len = length + 1;
buf = malloc(buf_len);
/* TODO: If there is no memory, should handle it in the controller. */
assert(buf != NULL);
buf[0] = HCI_DRIVER_TYPE_EVT;
memcpy(&buf[1], data, length);
r_ble_hci_trans_buf_free(data);
}
rc = s_hci_driver_vhci_env.forward_cb(data_type, buf, buf_len, HCI_DRIVER_DIR_C2H);
free(buf);
return rc;
}
static int
hci_driver_vhci_host_tx(hci_driver_data_type_t data_type, uint8_t *data, uint32_t length)
{
uint8_t *cmd;
struct os_mbuf *om;
if (data_type == HCI_DRIVER_TYPE_ACL) {
om = os_msys_get_pkthdr(length, ESP_HCI_INTERNAL_ACL_MBUF_LEADINGSPCAE);
assert(om);
assert(os_mbuf_append(om, &data[1], length - 1) == 0);
data = (uint8_t *)om;
} else if (data_type == HCI_DRIVER_TYPE_CMD) {
cmd = r_ble_hci_trans_buf_alloc(ESP_HCI_INTERNAL_BUF_CMD);
assert(cmd);
memcpy(cmd, data + 1, length - 1);
data = cmd;
}
return s_hci_driver_vhci_env.forward_cb(data_type, data, length, HCI_DRIVER_DIR_H2C);
}
static int
hci_driver_vhci_tx(hci_driver_data_type_t data_type, uint8_t *data, uint32_t length,
hci_driver_direction_t dir)
{
int rc;
if (dir == HCI_DRIVER_DIR_C2H) {
rc = hci_driver_vhci_controller_tx(data_type, data, length);
} else {
rc = hci_driver_vhci_host_tx(data_type, data, length);
}
return rc;
}
static int
hci_driver_vhci_init(hci_driver_forward_fn *cb)
{
memset(&s_hci_driver_vhci_env, 0, sizeof(hci_driver_vhci_env_t));
s_hci_driver_vhci_env.forward_cb = cb;
return 0;
}
static void
hci_driver_vhci_deinit(void)
{
memset(&s_hci_driver_vhci_env, 0, sizeof(hci_driver_vhci_env_t));
}
hci_driver_ops_t hci_driver_vhci_ops = {
.hci_driver_tx = hci_driver_vhci_tx,
.hci_driver_init = hci_driver_vhci_init,
.hci_driver_deinit = hci_driver_vhci_deinit,
};
/* Special APIs declared in the `esp_bt.h'. */
static int
hci_driver_vhci_host_recv_cb(hci_trans_pkt_ind_t type, uint8_t *data, uint16_t len)
{
static const esp_vhci_host_callback_t *host_recv_cb;
host_recv_cb = s_hci_driver_vhci_env.host_recv_cb;
if (host_recv_cb) {
return host_recv_cb->notify_host_recv(data, len);
}
return -1;
}
esp_err_t
esp_vhci_host_register_callback(const esp_vhci_host_callback_t *callback)
{
if (esp_bt_controller_get_status() != ESP_BT_CONTROLLER_STATUS_ENABLED) {
return ESP_FAIL;
}
s_hci_driver_vhci_env.host_recv_cb = callback;
if(hci_transport_host_callback_register(hci_driver_vhci_host_recv_cb)) {
s_hci_driver_vhci_env.host_recv_cb = NULL;
return ESP_FAIL;
}
return ESP_OK;
}
void
esp_vhci_host_send_packet(uint8_t *data, uint16_t len)
{
hci_driver_vhci_tx(data[0], data, len, HCI_DRIVER_DIR_H2C);
}
bool
esp_vhci_host_check_send_available(void)
{
return true;
}

View File

@ -0,0 +1,133 @@
/*
* SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <string.h>
#include <stdio.h>
#include "os/os_mbuf.h"
#include "esp_hci_transport.h"
#include "esp_hci_internal.h"
#include "esp_hci_driver.h"
typedef struct {
hci_driver_forward_fn *forward_cb;
} hci_driver_vhci_env_t;
static hci_driver_vhci_env_t s_hci_driver_vhci_env;
static int
hci_driver_vhci_controller_tx(hci_driver_data_type_t data_type, uint8_t *data, uint32_t length)
{
int rc;
uint16_t len = 0;
uint8_t *buf = NULL;
struct os_mbuf *om;
if (data_type == HCI_DRIVER_TYPE_ACL) {
/* The ACL data will be packaged as structure of `os_mbuf`.
* 1. Allocate a buffer suitable for the host. Use the following method to copy the data
* from the os_mbuf to the newly allocated memory.
* ```c
* buf = malloc(length);
* os_mbuf_copydata(om, 0, length, buf);
* ```
* 2. Free the controller's os_mbuf
* ```c
* os_mbuf_free_chain(om);
* ```
*/
} else if (data_type == HCI_DRIVER_TYPE_EVT) {
/* The event data will be packaged as an array.
* 1. Allocate a buffer suitable for the host. Use the following method to copy the data
* from the controller buffer to the newly allocated memory.
* ```c
* buf = malloc(length);
* memcpy(buf, data, length);
* ```
* 2. Free the controller's buffer.
* ```c
* r_ble_hci_trans_buf_free(data);
* ```
*/
} else {
assert(0);
}
rc = s_hci_driver_vhci_env.forward_cb(data_type, buf, len, HCI_DRIVER_DIR_C2H);
free(buf);
return rc;
}
static int
hci_driver_vhci_host_tx(hci_driver_data_type_t data_type, uint8_t *data, uint32_t length)
{
uint8_t *hci_data;
struct os_mbuf *om;
if (data_type == HCI_DRIVER_TYPE_ACL) {
/* The ACL data needs to be packaged as structure of `os_mbuf`.
* 1. Get an os_mbuf in the following way.
* ```c
* om = os_msys_get_pkthdr(length, ESP_HCI_INTERNAL_ACL_MBUF_LEADINGSPCAE);
* ```
* 2. Copy the host's data into this os_mbuf using the following method.
* ```c
* assert(os_mbuf_append(om, data, length) == 0);
* hci_data = (uint8_t *)om;
* ```
* 3. Free the host's buffer if needed.
*/
} else if (data_type == HCI_DRIVER_TYPE_CMD) {
/* The COMMAND data needs to be packaged as an array.
* 1. Get a command buffer from the controller.
* ```c
* hci_data = r_ble_hci_trans_buf_alloc(ESP_HCI_INTERNAL_BUF_CMD);
* ```
* 2. Copy the host's data into this buffer.
* ```c
* memcpy(hci_data, data, length);
* ```
* 3. Free the host's buffer if needed.
*/
} else {
assert(0);
}
return s_hci_driver_vhci_env.forward_cb(data_type, hci_data, length, HCI_DRIVER_DIR_H2C);
}
static int
hci_driver_vhci_tx(hci_driver_data_type_t data_type, uint8_t *data, uint32_t length,
hci_driver_direction_t dir)
{
int rc;
if (dir == HCI_DRIVER_DIR_C2H) {
rc = hci_driver_vhci_controller_tx(data_type, data, length);
} else {
rc = hci_driver_vhci_host_tx(data_type, data, length);
}
return rc;
}
static int
hci_driver_vhci_init(hci_driver_forward_fn *cb)
{
memset(&s_hci_driver_vhci_env, 0, sizeof(hci_driver_vhci_env_t));
s_hci_driver_vhci_env.forward_cb = cb;
return 0;
}
static void
hci_driver_vhci_deinit(void)
{
memset(&s_hci_driver_vhci_env, 0, sizeof(hci_driver_vhci_env_t));
}
hci_driver_ops_t hci_driver_vhci_ops = {
.hci_driver_tx = hci_driver_vhci_tx,
.hci_driver_init = hci_driver_vhci_init,
.hci_driver_deinit = hci_driver_vhci_deinit,
};

View File

@ -0,0 +1,75 @@
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#ifndef _HCI_H4_H_
#define _HCI_H4_H_
#include <stdint.h>
#define HCI_H4_NONE 0x00
#define HCI_H4_CMD 0x01
#define HCI_H4_ACL 0x02
#define HCI_H4_EVT 0x04
#define HCI_H4_ISO 0x05
typedef void *(hci_h4_alloc_cmd)(void);
typedef void *(hci_h4_alloc_evt)(int);
typedef struct os_mbuf *(hci_h4_alloc_acl)(void);
typedef struct os_mbuf *(hci_h4_alloc_iso)(void);
struct hci_h4_allocators {
hci_h4_alloc_cmd *cmd;
hci_h4_alloc_acl *acl;
hci_h4_alloc_evt *evt;
hci_h4_alloc_iso *iso;
};
extern const struct hci_h4_allocators hci_h4_allocs_from_ll;
extern const struct hci_h4_allocators hci_h4_allocs_from_hs;
typedef int (hci_h4_frame_cb)(uint8_t pkt_type, void *data);
struct hci_h4_sm {
uint8_t state;
uint8_t pkt_type;
uint8_t min_len;
uint16_t len;
uint16_t exp_len;
uint8_t hdr[4];
union {
uint8_t *buf;
struct os_mbuf *om;
};
const struct hci_h4_allocators *allocs;
hci_h4_frame_cb *frame_cb;
};
void hci_h4_sm_init(struct hci_h4_sm *h4sm,
const struct hci_h4_allocators *allocs,
hci_h4_frame_cb *frame_cb);
int hci_h4_sm_rx(struct hci_h4_sm *h4sm, const uint8_t *buf, uint16_t len);
#endif /* _HCI_H4_H_ */

View File

@ -0,0 +1,25 @@
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef _H_HCI_DRIVER_MEM_
#define _H_HCI_DRIVER_MEM_
#include <stdint.h>
#include "os/os_mbuf.h"
void *hci_driver_mem_cmd_alloc(void);
void *hci_driver_mem_evt_alloc(int discardable);
struct os_mbuf *hci_driver_mem_acl_alloc(void);
struct os_mbuf *hci_driver_mem_acl_len_alloc(uint32_t len);
struct os_mbuf *hci_driver_mem_iso_alloc(void);
struct os_mbuf *hci_driver_mem_iso_len_alloc(uint32_t len);
extern const struct hci_h4_allocators s_hci_driver_mem_alloc;
#endif // _H_HCI_DRIVER_MEM_

View File

@ -0,0 +1,18 @@
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef _H_HCI_DRIVER_UTIL_
#define _H_HCI_DRIVER_UTIL_
#include <stdint.h>
int hci_driver_util_init(void);
void hci_driver_util_deinit(void);
void hci_driver_util_tx_list_enqueue(hci_driver_data_type_t type, uint8_t *data, uint32_t len);
uint32_t hci_driver_util_tx_list_dequeue(uint32_t max_tx_len, void **tx_data, bool *last_frame);
#endif // _H_HCI_DRIVER_UTIL_

View File

@ -0,0 +1,52 @@
/*
* SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef H_ESP_HCI_DRIVER_
#define H_ESP_HCI_DRIVER_
#include <stdint.h>
/**
* @brief Enumeration of HCI transport direction.
*/
typedef enum {
HCI_DRIVER_DIR_C2H = 0x00, ///< From controller to host.
HCI_DRIVER_DIR_H2C, ///< From host to controller.
} hci_driver_direction_t;
typedef enum {
HCI_DRIVER_TYPE_CMD = 0x01, ///< HCI Command Indicator.
HCI_DRIVER_TYPE_ACL, ///< HCI ACL Data Indicator.
HCI_DRIVER_TYPE_SYNC, ///< HCI Synchronous Data Indicator.
HCI_DRIVER_TYPE_EVT, ///< HCI Event Indicator.
HCI_DRIVER_TYPE_ISO, ///< HCI Isochronous Data Indicator.
HCI_DRIVER_TYPE_VENDOR, ///< HCI Vendor data Indicator.
} hci_driver_data_type_t;
typedef int hci_driver_forward_fn(hci_driver_data_type_t data_type, uint8_t *data, uint32_t length,
hci_driver_direction_t dir);
/**
* @brief Structure of HCI driver operations.
*/
typedef struct hci_driver_ops {
int (*hci_driver_tx)(hci_driver_data_type_t data_type, uint8_t *data, uint32_t length,
hci_driver_direction_t dir);
int (*hci_driver_init)(hci_driver_forward_fn *cb);
void (*hci_driver_deinit)(void);
} hci_driver_ops_t;
#if CONFIG_BT_LE_HCI_INTERFACE_USE_RAM
extern hci_driver_ops_t hci_driver_vhci_ops;
#endif // CONFIG_BT_LE_HCI_INTERFACE_USE_RAM
#if CONFIG_BT_LE_HCI_INTERFACE_USE_UART
extern hci_driver_ops_t hci_driver_uart_ops;
#if CONFIG_BT_LE_UART_HCI_DMA_MODE
extern hci_driver_ops_t hci_driver_uart_dma_ops;
#endif // CONFIG_BT_LE_UART_HCI_DMA_MODE
#endif // CONFIG_BT_LE_HCI_INTERFACE_USE_UART
#endif // H_ESP_HCI_DRIVER_

View File

@ -0,0 +1,121 @@
/*
* SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef H_ESP_HCI_INTERNAL_
#define H_ESP_HCI_INTERNAL_
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
#include "os/os_mbuf.h"
/* The leadingspace in user info header for ACL data */
#define ESP_HCI_INTERNAL_ACL_MBUF_LEADINGSPCAE (4)
#define ESP_HCI_INTERNAL_BUF_CMD (3)
/**
* @brief Define the HCI hardware error code for synchronization loss.
* This error code is used to indicate a loss of synchronization between the controller and the host.
*/
#define ESP_HCI_SYNC_LOSS_ERR (0x1)
/** Callback function types; executed when HCI packets are received. */
typedef int esp_hci_internal_rx_cmd_fn(uint8_t *cmd, void *arg);
typedef int esp_hci_internal_rx_acl_fn(struct os_mbuf *om, void *arg);
/**
* Configures the HCI transport to operate with a host. The transport will
* execute specified callbacks upon receiving HCI packets from the controller.
*
* @param evt_cb The callback to execute upon receiving an HCI
* event.
* @param evt_arg Optional argument to pass to the event
* callback.
* @param acl_cb The callback to execute upon receiving ACL
* data.
* @param acl_arg Optional argument to pass to the ACL
* callback.
*/
void r_ble_hci_trans_cfg_hs(esp_hci_internal_rx_cmd_fn *evt_cb, void *evt_arg,
esp_hci_internal_rx_acl_fn *acl_cb, void *acl_arg);
/**
* Sends ACL data from host to controller.
*
* @param om The ACL data packet to send.
*
* @return 0 on success;
* A BLE_ERR_[...] error code on failure.
*/
int r_ble_hci_trans_hs_acl_tx(struct os_mbuf *om);
/**
* Sends an HCI command from the host to the controller.
*
* @param cmd The HCI command to send. This buffer must be
* allocated via ble_hci_trans_buf_alloc().
*
* @return 0 on success;
* A BLE_ERR_[...] error code on failure.
*/
int r_ble_hci_trans_hs_cmd_tx(uint8_t *cmd);
/**
* Allocates a flat buffer of the specified type.
*
* @param type The type of buffer to allocate; one of the
* BLE_HCI_TRANS_BUF_[...] constants.
*
* @return The allocated buffer on success;
* NULL on buffer exhaustion.
*/
uint8_t * r_ble_hci_trans_buf_alloc(int type);
/**
* Frees the specified flat buffer. The buffer must have been allocated via
* ble_hci_trans_buf_alloc().
*
* @param buf The buffer to free.
*/
void r_ble_hci_trans_buf_free(uint8_t *buf);
/**
* Configures a callback to get executed whenever an ACL data packet is freed.
* The function is called immediately before the free occurs.
*
* @param cb The callback to configure.
* @param arg An optional argument to pass to the callback.
*
* @return 0 on success;
* BLE_ERR_UNSUPPORTED if the transport does not
* support this operation.
*/
int r_ble_hci_trans_set_acl_free_cb(os_mempool_put_fn *cb, void *arg);
/**
* @brief Handle an HCI hardware error event.
* This function processes a hardware error code and generates the appropriate HCI hardware error event.
*
* @param hw_err The hardware error code that needs to be processed. The specific meaning of the error code
* depends on the implementation and the hardware.
*
* @return int Returns 0 on success, or a non-zero error code on failure.
*
* @note This function should be called whenever a hardware error is detected in the HCI Layer.
*/
int r_ble_ll_hci_ev_hw_err(uint8_t hw_err);
//!TODO: Check what this API is used for
int r_ble_hci_trans_reset(void);
//!TODO: Should we initialize the hci layer in IDF ?
void esp_ble_hci_trans_init(uint8_t);
#ifdef __cplusplus
}
#endif
#endif /* H_ESP_HCI_INTERNAL_ */

View File

@ -0,0 +1,83 @@
/*
* SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef H_ESP_HCI_TRANSPORT_
#define H_ESP_HCI_TRANSPORT_
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
#include "os/os_mbuf.h"
#include "esp_hci_driver.h"
/**
* @brief Enumeration of HCI packet indicators
*/
typedef enum {
HCI_CMD_IND = 0x01, /*!< HCI Command Indicator */
HCI_ACL_IND, /*!< HCI ACL Data Indicator */
HCI_SYNC_IND, /*!< HCI Synchronous Data Indicator */
HCI_EVT_IND, /*!< HCI Event Indicator */
HCI_ISO_IND, /*!< HCI Isochronous Data Indicator */
HCI_VENDOR_IND, /*!< HCI Vendor data Indicator */
} hci_trans_pkt_ind_t;
/**
* @brief Enumeration of HCI Transport Mode
*/
typedef enum {
HCI_TRANSPORT_VHCI, /*!< VHCI Transport Mode */
HCI_TRANSPORT_UART_NO_DMA, /*!< UART_NO_DMA Transport Mode */
HCI_TRANSPORT_UART_UHCI, /*!< UART_UHCI Transport Mode */
HCI_TRANSPORT_SDIO, /*!< SDIO Transport Mode */
HCI_TRANSPORT_USB, /*!< USB Transport Mode */
} hci_trans_mode_t;
typedef int hci_transport_host_recv_fn(hci_trans_pkt_ind_t type, uint8_t *data, uint16_t len);
/**
* @brief Initialize the HCI transport layer.
* It should be called before using any other functions in the transport layer.
*
* @param hci_transport_mode The mode in which the HCI transport should operate.
*
* @return int Returns 0 on success, or a non-zero error code on failure.
*/
int hci_transport_init(uint8_t hci_transport_mode);
/**
* @brief Deinitialize the HCI transport layer for releasing any allocated resources.
*/
void hci_transport_deinit(void);
/**
* @brief Set the host's HCI callback which will be invoked when receiving ACL/Events from controller.
* @param callback hci_transport_host_recv_fn type variable
* @return int 0 on success, non-zero error code on failure.
*/
int hci_transport_host_callback_register(hci_transport_host_recv_fn *callback);
/**
* @brief Called to send HCI commands form host to controller.
* @param data Point to the commands data
* @param length Length of data
* @return int 0 on success, non-zero error code on failure.
*/
int hci_transport_host_cmd_tx(uint8_t *data, uint32_t length);
/**
* @brief Called to send HCI ACL form host to controller.
* @param data Point to the ACL data
* @param length Length of data
* @return int 0 on success, non-zero error code on failure.
*/
int hci_transport_host_acl_tx(uint8_t *data, uint32_t length);
#ifdef __cplusplus
}
#endif
#endif /* H_ESP_HCI_TRANSPORT_ */

View File

@ -1,100 +0,0 @@
/*
* SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
#include <inttypes.h>
#include "driver/uart.h"
/**
* Function prototype for UART driver to ask for more data to send.
* Returns -1 if no more data is available for TX.
* Driver must call this with interrupts disabled.
*/
typedef int (*hci_uart_tx_char)(void *arg);
/**
* Function prototype for UART driver to report that transmission is
* complete. This should be called when transmission of last byte is
* finished.
* Driver must call this with interrupts disabled.
*/
typedef void (*hci_uart_tx_done)(void *arg);
/**
* Function prototype for UART driver to report incoming byte of data.
* Returns -1 if data was dropped.
* Driver must call this with interrupts disabled.
*/
typedef int (*hci_uart_rx_char)(void *arg, uint8_t byte);
/**
* Initializes given uart. Mapping of logical UART number to physical
* UART/GPIO pins is in BSP.
*/
int hci_uart_init_cbs(int uart, hci_uart_tx_char tx_func,
hci_uart_tx_done tx_done, hci_uart_rx_char rx_func, void *arg);
/**
* Applies given configuration to UART.
*
* @param port_num The UART number to configure
* @param speed The baudrate in bps to configure
* @param databits The number of databits to send per byte
* @param stopbits The number of stop bits to send
* @param parity The UART parity
* @param flow_ctl Flow control settings on the UART
*
* @return 0 on success, non-zero error code on failure
*/
int hci_uart_config(int port_num, int32_t baud_rate, uint8_t data_bits, uint8_t stop_bits,
uart_parity_t parity, uart_hw_flowcontrol_t flow_ctl);
/**
* Close UART port. Can call hal_uart_config() with different settings after
* calling this.
*
* @param port_num The UART number to close
*/
int hci_uart_close(int port_num);
/**
* More data queued for transmission. UART driver will start asking for that
* data.
*
* @param port_num The UART number to start TX on
*/
void hci_uart_start_tx(int port_num);
/**
* Upper layers have consumed some data, and are now ready to receive more.
* This is meaningful after uart_rx_char callback has returned -1 telling
* that no more data can be accepted.
*
* @param port_num The UART number to begin RX on
*/
void hci_uart_start_rx(int port_num);
/**
* @brief reconfig hci uart pin
*
* @param tx_pin The Tx pin
* @param rx_pin The Rx pin
* @param cts_pin The CTS pin
* @param rts_pin The RTS pin
* @return int 0 on success, non-zero error code on failure
*/
int hci_uart_reconfig_pin(int tx_pin, int rx_pin, int cts_pin, int rts_pin);
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,175 @@
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdio.h>
#include <string.h>
#include "esp_log.h"
#include "esp_hci_transport.h"
#include "esp_hci_internal.h"
#include "esp_bt.h"
typedef struct hci_transport_env
{
hci_transport_host_recv_fn *host_recv_cb;
hci_driver_ops_t *driver_ops;
} hci_transport_env_t;
static hci_transport_env_t s_hci_transport_env;
/* Functions for packets Rx. */
static int
hci_transport_controller_packet_rx(hci_driver_data_type_t data_type, uint8_t *data)
{
if (data_type == HCI_DRIVER_TYPE_CMD) {
r_ble_hci_trans_hs_cmd_tx(data);
}
if (data_type == HCI_DRIVER_TYPE_ACL) {
r_ble_hci_trans_hs_acl_tx((struct os_mbuf *) data);
}
return 0;
}
static int
hci_transport_host_packet_rx(hci_driver_data_type_t data_type, uint8_t *data, uint32_t length)
{
if (!s_hci_transport_env.host_recv_cb) {
return -1;
}
return s_hci_transport_env.host_recv_cb((hci_trans_pkt_ind_t)data_type, data, length);
}
static int
hci_transport_packet_rx(hci_driver_data_type_t data_type, uint8_t *data, uint32_t length,
hci_driver_direction_t dir)
{
int rc;
if (esp_bt_controller_get_status() != ESP_BT_CONTROLLER_STATUS_ENABLED) {
return -1;
}
if (dir == HCI_DRIVER_DIR_C2H) {
rc = hci_transport_host_packet_rx(data_type, data, length);
} else {
rc = hci_transport_controller_packet_rx(data_type, data);
}
return rc;
}
/* Functions for controller Tx. */
static int
hci_transport_controller_tx_dummy(void *data, void *arg)
{
return -1;
}
static int
hci_transport_controller_evt_tx(uint8_t *hci_ev, void *arg)
{
uint32_t len;
if (esp_bt_controller_get_status() != ESP_BT_CONTROLLER_STATUS_ENABLED) {
return -1;
}
len = hci_ev[1] + 2;
return s_hci_transport_env.driver_ops->hci_driver_tx(HCI_DRIVER_TYPE_EVT, hci_ev, len,
HCI_DRIVER_DIR_C2H);
}
static int
hci_transport_controller_acl_tx(struct os_mbuf *om, void *arg)
{
uint16_t len;
if (esp_bt_controller_get_status() != ESP_BT_CONTROLLER_STATUS_ENABLED) {
return -1;
}
len = OS_MBUF_PKTHDR(om)->omp_len;
return s_hci_transport_env.driver_ops->hci_driver_tx(HCI_DRIVER_TYPE_ACL, (uint8_t *)om, len,
HCI_DRIVER_DIR_C2H);
}
/* Functions for host Tx. */
int
hci_transport_host_cmd_tx(uint8_t *data, uint32_t length)
{
return s_hci_transport_env.driver_ops->hci_driver_tx(HCI_DRIVER_TYPE_CMD, data, length,
HCI_DRIVER_DIR_H2C);
}
int
hci_transport_host_acl_tx(uint8_t *data, uint32_t length)
{
return s_hci_transport_env.driver_ops->hci_driver_tx(HCI_DRIVER_TYPE_ACL, data, length,
HCI_DRIVER_DIR_H2C);
}
int
hci_transport_host_callback_register(hci_transport_host_recv_fn *callback)
{
s_hci_transport_env.host_recv_cb = callback;
return 0;
}
int
hci_transport_init(uint8_t hci_transport_mode)
{
int rc;
hci_driver_ops_t *ops;
memset(&s_hci_transport_env, 0, sizeof(hci_transport_env_t));
switch(hci_transport_mode) {
#if CONFIG_BT_LE_HCI_INTERFACE_USE_RAM
case HCI_TRANSPORT_VHCI:
ops = &hci_driver_vhci_ops;
break;
#endif // CONFIG_BT_LE_HCI_INTERFACE_USE_RAM
#if CONFIG_BT_LE_HCI_INTERFACE_USE_UART
#if CONFIG_BT_LE_UART_HCI_DMA_MODE
case HCI_TRANSPORT_UART_UHCI:
ops = &hci_driver_uart_dma_ops;
break;
#else
case HCI_TRANSPORT_UART_NO_DMA:
ops = &hci_driver_uart_ops;
break;
#endif // CONFIG_BT_LE_UART_HCI_DMA_MODE
#endif // CONFIG_BT_LE_HCI_INTERFACE_USE_UART
default:
assert(0);
}
rc = ops->hci_driver_init(hci_transport_packet_rx);
if (rc) {
goto error;
}
s_hci_transport_env.driver_ops = ops;
r_ble_hci_trans_cfg_hs(hci_transport_controller_evt_tx, NULL, hci_transport_controller_acl_tx, NULL);
return 0;
error:
hci_transport_deinit();
return rc;
}
void
hci_transport_deinit(void)
{
hci_driver_ops_t *ops;
r_ble_hci_trans_cfg_hs((esp_hci_internal_rx_cmd_fn *)hci_transport_controller_tx_dummy, NULL,
(esp_hci_internal_rx_acl_fn *)hci_transport_controller_tx_dummy, NULL);
ops = s_hci_transport_env.driver_ops;
if (ops) {
ops->hci_driver_deinit();
}
memset(&s_hci_transport_env, 0, sizeof(hci_transport_env_t));
}

View File

@ -1,207 +0,0 @@
/*
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdio.h>
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/queue.h"
#include "driver/uart.h"
#include "hci_uart.h"
#include "esp_log.h"
#include "esp_attr.h"
#ifdef CONFIG_BT_LE_HCI_INTERFACE_USE_UART
static const char *TAG = "hci_uart";
#define BUF_SIZE (1024)
#define RD_BUF_SIZE (BUF_SIZE)
#define HCI_UART_TX_PIN CONFIG_BT_LE_HCI_UART_TX_PIN
#define HCI_UART_RX_PIN CONFIG_BT_LE_HCI_UART_RX_PIN
#ifdef CONFIG_BT_LE_HCI_UART_FLOWCTRL
#define HCI_UART_FLOWCTRL UART_HW_FLOWCTRL_CTS_RTS
#define HCI_UART_RTS_PIN CONFIG_BT_LE_HCI_UART_RTS_PIN
#define HCI_UART_CTS_PIN CONFIG_BT_LE_HCI_UART_CTS_PIN
#else
#define HCI_UART_FLOWCTRL UART_HW_FLOWCTRL_DISABLE
#define HCI_UART_RTS_PIN (-1)
#define HCI_UART_CTS_PIN (-1)
#endif
typedef struct {
bool uart_opened;
uart_port_t port;
uart_config_t cfg;
QueueHandle_t evt_queue;
TaskHandle_t rx_task_handler;
hci_uart_tx_char tx_char;
hci_uart_tx_done tx_done;
hci_uart_rx_char rx_char;
void *u_func_arg;
} hci_uart_t;
static hci_uart_t hci_uart;
static void IRAM_ATTR hci_uart_rx_task(void *pvParameters)
{
uart_event_t event;
uint8_t *dtmp = (uint8_t *) malloc(RD_BUF_SIZE);
while (hci_uart.uart_opened) {
//Waiting for UART event.
if (xQueueReceive(hci_uart.evt_queue, (void * )&event, (TickType_t)portMAX_DELAY)) {
bzero(dtmp, RD_BUF_SIZE);
ESP_LOGD(TAG, "uart[%d] event:", hci_uart.port);
switch (event.type) {
//Event of UART receving data
/*We'd better handler data event fast, there would be much more data events than
other types of events. If we take too much time on data event, the queue might
be full.*/
case UART_DATA:
// ESP_LOGI(TAG, "[UART DATA]: %d", event.size);
uart_read_bytes(hci_uart.port, dtmp, event.size, portMAX_DELAY);
for (int i = 0 ; i < event.size; i++) {
hci_uart.rx_char(hci_uart.u_func_arg, dtmp[i]);
}
break;
//Event of HW FIFO overflow detected
case UART_FIFO_OVF:
ESP_LOGI(TAG, "hw fifo overflow");
// If fifo overflow happened, you should consider adding flow control for your application.
// The ISR has already reset the rx FIFO,
uart_flush_input(hci_uart.port);
xQueueReset(hci_uart.evt_queue);
break;
//Event of UART ring buffer full
case UART_BUFFER_FULL:
ESP_LOGI(TAG, "ring buffer full");
// If buffer full happened, you should consider encreasing your buffer size
uart_flush_input(hci_uart.port);
xQueueReset(hci_uart.evt_queue);
break;
//Event of UART RX break detected
case UART_BREAK:
ESP_LOGI(TAG, "uart rx break");
break;
//Event of UART parity check error
case UART_PARITY_ERR:
ESP_LOGI(TAG, "uart parity error");
break;
//Event of UART frame error
case UART_FRAME_ERR:
ESP_LOGI(TAG, "uart frame error");
break;
//Others
default:
ESP_LOGI(TAG, "uart event type: %d", event.type);
break;
}
}
}
free(dtmp);
dtmp = NULL;
hci_uart.rx_task_handler = NULL;
vTaskDelete(NULL);
}
int hci_uart_config(int port_num, int32_t baud_rate, uint8_t data_bits, uint8_t stop_bits,
uart_parity_t parity, uart_hw_flowcontrol_t flow_ctl)
{
uart_config_t uart_cfg = {
.baud_rate = baud_rate,
.data_bits = data_bits,
.parity = parity,
.stop_bits = stop_bits,
.flow_ctrl = HCI_UART_FLOWCTRL,
.source_clk = UART_SCLK_DEFAULT,
.rx_flow_ctrl_thresh = UART_HW_FIFO_LEN(port_num) - 1,
};
hci_uart.port = port_num;
hci_uart.cfg = uart_cfg;
int intr_alloc_flags = 0;
intr_alloc_flags = ESP_INTR_FLAG_IRAM;
printf("set uart pin tx:%d, rx:%d.\n", HCI_UART_TX_PIN, HCI_UART_RX_PIN);
printf("set rts:%d, cts:%d.\n", HCI_UART_RTS_PIN, HCI_UART_CTS_PIN);
printf("set baud_rate:%d.\n", baud_rate);
ESP_ERROR_CHECK(uart_driver_delete(port_num));
ESP_ERROR_CHECK(uart_driver_install(port_num, BUF_SIZE * 2, BUF_SIZE * 2, 20, &hci_uart.evt_queue, intr_alloc_flags));
ESP_ERROR_CHECK(uart_param_config(port_num, &hci_uart.cfg));
ESP_ERROR_CHECK(uart_set_pin(port_num, HCI_UART_TX_PIN, HCI_UART_RX_PIN, HCI_UART_RTS_PIN, HCI_UART_CTS_PIN));
hci_uart.uart_opened = true;
//Create a task to handler UART event from ISR
xTaskCreate(hci_uart_rx_task, "hci_uart_rx_task", 2048, NULL, 12, &hci_uart.rx_task_handler);
return 0;
}
void IRAM_ATTR hci_uart_start_tx(int port_num)
{
int data;
uint8_t u8_data = 0;
while (1) {
data = hci_uart.tx_char(hci_uart.u_func_arg);
if (data >= 0) {
u8_data = data;
uart_write_bytes(port_num, (char *)&u8_data, 1);
} else {
break;
}
}
if (hci_uart.tx_done) {
hci_uart.tx_done(hci_uart.u_func_arg);
}
}
int hci_uart_init_cbs(int port_num, hci_uart_tx_char tx_func,
hci_uart_tx_done tx_done, hci_uart_rx_char rx_func, void *arg)
{
hci_uart.tx_char = tx_func;
hci_uart.rx_char = rx_func;
hci_uart.tx_done = tx_done;
hci_uart.u_func_arg = arg;
return 0;
}
int hci_uart_close(int port_num)
{
uart_event_t uart_event;
uart_event.type = UART_BREAK;
hci_uart.uart_opened = false;
// Stop uart rx task
if (hci_uart.rx_task_handler != NULL) {
xQueueSend(hci_uart.evt_queue, (void *)&uart_event, 1000);
ESP_LOGW(TAG, "Waiting for uart task finish...");
}
while (hci_uart.rx_task_handler != NULL);
uart_driver_delete(port_num);
ESP_LOGI(TAG, "hci uart close success.");
return 0;
}
int hci_uart_reconfig_pin(int tx_pin, int rx_pin, int cts_pin, int rts_pin)
{
int port_num = hci_uart.port;
int32_t baud_rate = hci_uart.cfg.baud_rate;
uint8_t data_bits = hci_uart.cfg.data_bits;
uint8_t stop_bits = hci_uart.cfg.stop_bits;
uart_parity_t parity = hci_uart.cfg.parity;
uart_hw_flowcontrol_t flow_ctl = hci_uart.cfg.flow_ctrl;
hci_uart_close(port_num);
hci_uart_config(port_num, baud_rate, data_bits, stop_bits, parity, flow_ctl);
ESP_ERROR_CHECK(uart_set_pin(port_num, tx_pin, rx_pin, rts_pin, cts_pin));
return 0;
}
#endif //CONFIG_BT_LE_HCI_INTERFACE_USE_UART

View File

@ -828,7 +828,6 @@ r_ble_ll_hci_ev_send_adv_set_terminated = 0x40000ff4;
r_ble_ll_hci_ev_send_scan_req_recv = 0x40000ff8;
r_ble_ll_hci_ev_send_scan_timeout = 0x40000ffc;
r_ble_ll_hci_ev_send_vendor_err = 0x40001000;
r_ble_ll_hci_event_send = 0x40001004;
r_ble_ll_hci_ext_scan_set_enable = 0x40001008;
r_ble_ll_hci_get_num_cmd_pkts = 0x4000100c;
r_ble_ll_hci_info_params_cmd_proc = 0x40001010;

View File

@ -0,0 +1,133 @@
/*
* SPDX-FileCopyrightText: 2020-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <stdio.h>
#include "hal/uhci_types.h"
#include "soc/uhci_struct.h"
#ifdef __cplusplus
extern "C" {
#endif
#define UHCI_LL_GET_HW(num) (((num) == 0) ? (&UHCI0) : (NULL))
typedef enum {
UHCI_RX_BREAK_CHR_EOF = 0x1,
UHCI_RX_IDLE_EOF = 0x2,
UHCI_RX_LEN_EOF = 0x4,
UHCI_RX_EOF_MAX = 0x7,
} uhci_rxeof_cfg_t;
static inline void uhci_ll_init(uhci_dev_t *hw)
{
typeof(hw->conf0) conf0_reg;
hw->conf0.clk_en = 1;
conf0_reg.val = 0;
conf0_reg.clk_en = 1;
hw->conf0.val = conf0_reg.val;
hw->conf1.val = 0;
}
static inline void uhci_ll_attach_uart_port(uhci_dev_t *hw, int uart_num)
{
hw->conf0.uart0_ce = (uart_num == 0)? 1: 0;
hw->conf0.uart1_ce = (uart_num == 1)? 1: 0;
}
static inline void uhci_ll_set_seper_chr(uhci_dev_t *hw, uhci_seper_chr_t *seper_char)
{
if (seper_char->sub_chr_en) {
typeof(hw->esc_conf0) esc_conf0_reg;
esc_conf0_reg.val = hw->esc_conf0.val;
esc_conf0_reg.seper_char = seper_char->seper_chr;
esc_conf0_reg.seper_esc_char0 = seper_char->sub_chr1;
esc_conf0_reg.seper_esc_char1 = seper_char->sub_chr2;
hw->esc_conf0.val = esc_conf0_reg.val;
hw->escape_conf.tx_c0_esc_en = 1;
hw->escape_conf.rx_c0_esc_en = 1;
} else {
hw->escape_conf.tx_c0_esc_en = 0;
hw->escape_conf.rx_c0_esc_en = 0;
}
}
static inline void uhci_ll_get_seper_chr(uhci_dev_t *hw, uhci_seper_chr_t *seper_chr)
{
(void)hw;
(void)seper_chr;
}
static inline void uhci_ll_set_swflow_ctrl_sub_chr(uhci_dev_t *hw, uhci_swflow_ctrl_sub_chr_t *sub_ctr)
{
typeof(hw->escape_conf) escape_conf_reg;
escape_conf_reg.val = hw->escape_conf.val;
if (sub_ctr->flow_en == 1) {
typeof(hw->esc_conf2) esc_conf2_reg;
esc_conf2_reg.val = hw->esc_conf2.val;
typeof(hw->esc_conf3) esc_conf3_reg;
esc_conf3_reg.val = hw->esc_conf3.val;
esc_conf2_reg.esc_seq1 = sub_ctr->xon_chr;
esc_conf2_reg.esc_seq1_char0 = sub_ctr->xon_sub1;
esc_conf2_reg.esc_seq1_char1 = sub_ctr->xon_sub2;
esc_conf3_reg.esc_seq2 = sub_ctr->xoff_chr;
esc_conf3_reg.esc_seq2_char0 = sub_ctr->xoff_sub1;
esc_conf3_reg.esc_seq2_char1 = sub_ctr->xoff_sub2;
escape_conf_reg.tx_11_esc_en = 1;
escape_conf_reg.tx_13_esc_en = 1;
escape_conf_reg.rx_11_esc_en = 1;
escape_conf_reg.rx_13_esc_en = 1;
hw->esc_conf2.val = esc_conf2_reg.val;
hw->esc_conf3.val = esc_conf3_reg.val;
} else {
escape_conf_reg.tx_11_esc_en = 0;
escape_conf_reg.tx_13_esc_en = 0;
escape_conf_reg.rx_11_esc_en = 0;
escape_conf_reg.rx_13_esc_en = 0;
}
hw->escape_conf.val = escape_conf_reg.val;
}
static inline void uhci_ll_enable_intr(uhci_dev_t *hw, uint32_t intr_mask)
{
hw->int_ena.val |= intr_mask;
}
static inline void uhci_ll_disable_intr(uhci_dev_t *hw, uint32_t intr_mask)
{
hw->int_ena.val &= (~intr_mask);
}
static inline void uhci_ll_clear_intr(uhci_dev_t *hw, uint32_t intr_mask)
{
hw->int_clr.val = intr_mask;
}
static inline uint32_t uhci_ll_get_intr(uhci_dev_t *hw)
{
return hw->int_st.val;
}
static inline void uhci_ll_set_eof_mode(uhci_dev_t *hw, uint32_t eof_mode)
{
if (eof_mode & UHCI_RX_BREAK_CHR_EOF) {
hw->conf0.uart_rx_brk_eof_en = 1;
}
if (eof_mode & UHCI_RX_IDLE_EOF) {
hw->conf0.uart_idle_eof_en = 1;
}
if (eof_mode & UHCI_RX_LEN_EOF) {
hw->conf0.len_eof_en = 1;
}
}
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,133 @@
/*
* SPDX-FileCopyrightText: 2020-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <stdio.h>
#include "hal/uhci_types.h"
#include "soc/uhci_struct.h"
#ifdef __cplusplus
extern "C" {
#endif
#define UHCI_LL_GET_HW(num) (((num) == 0) ? (&UHCI0) : (NULL))
typedef enum {
UHCI_RX_BREAK_CHR_EOF = 0x1,
UHCI_RX_IDLE_EOF = 0x2,
UHCI_RX_LEN_EOF = 0x4,
UHCI_RX_EOF_MAX = 0x7,
} uhci_rxeof_cfg_t;
static inline void uhci_ll_init(uhci_dev_t *hw)
{
typeof(hw->conf0) conf0_reg;
hw->conf0.clk_en = 1;
conf0_reg.val = 0;
conf0_reg.clk_en = 1;
hw->conf0.val = conf0_reg.val;
hw->conf1.val = 0;
}
static inline void uhci_ll_attach_uart_port(uhci_dev_t *hw, int uart_num)
{
hw->conf0.uart0_ce = (uart_num == 0)? 1: 0;
hw->conf0.uart1_ce = (uart_num == 1)? 1: 0;
}
static inline void uhci_ll_set_seper_chr(uhci_dev_t *hw, uhci_seper_chr_t *seper_char)
{
if (seper_char->sub_chr_en) {
typeof(hw->esc_conf0) esc_conf0_reg;
esc_conf0_reg.val = hw->esc_conf0.val;
esc_conf0_reg.seper_char = seper_char->seper_chr;
esc_conf0_reg.seper_esc_char0 = seper_char->sub_chr1;
esc_conf0_reg.seper_esc_char1 = seper_char->sub_chr2;
hw->esc_conf0.val = esc_conf0_reg.val;
hw->escape_conf.tx_c0_esc_en = 1;
hw->escape_conf.rx_c0_esc_en = 1;
} else {
hw->escape_conf.tx_c0_esc_en = 0;
hw->escape_conf.rx_c0_esc_en = 0;
}
}
static inline void uhci_ll_get_seper_chr(uhci_dev_t *hw, uhci_seper_chr_t *seper_chr)
{
(void)hw;
(void)seper_chr;
}
static inline void uhci_ll_set_swflow_ctrl_sub_chr(uhci_dev_t *hw, uhci_swflow_ctrl_sub_chr_t *sub_ctr)
{
typeof(hw->escape_conf) escape_conf_reg;
escape_conf_reg.val = hw->escape_conf.val;
if (sub_ctr->flow_en == 1) {
typeof(hw->esc_conf2) esc_conf2_reg;
esc_conf2_reg.val = hw->esc_conf2.val;
typeof(hw->esc_conf3) esc_conf3_reg;
esc_conf3_reg.val = hw->esc_conf3.val;
esc_conf2_reg.esc_seq1 = sub_ctr->xon_chr;
esc_conf2_reg.esc_seq1_char0 = sub_ctr->xon_sub1;
esc_conf2_reg.esc_seq1_char1 = sub_ctr->xon_sub2;
esc_conf3_reg.esc_seq2 = sub_ctr->xoff_chr;
esc_conf3_reg.esc_seq2_char0 = sub_ctr->xoff_sub1;
esc_conf3_reg.esc_seq2_char1 = sub_ctr->xoff_sub2;
escape_conf_reg.tx_11_esc_en = 1;
escape_conf_reg.tx_13_esc_en = 1;
escape_conf_reg.rx_11_esc_en = 1;
escape_conf_reg.rx_13_esc_en = 1;
hw->esc_conf2.val = esc_conf2_reg.val;
hw->esc_conf3.val = esc_conf3_reg.val;
} else {
escape_conf_reg.tx_11_esc_en = 0;
escape_conf_reg.tx_13_esc_en = 0;
escape_conf_reg.rx_11_esc_en = 0;
escape_conf_reg.rx_13_esc_en = 0;
}
hw->escape_conf.val = escape_conf_reg.val;
}
static inline void uhci_ll_enable_intr(uhci_dev_t *hw, uint32_t intr_mask)
{
hw->int_ena.val |= intr_mask;
}
static inline void uhci_ll_disable_intr(uhci_dev_t *hw, uint32_t intr_mask)
{
hw->int_ena.val &= (~intr_mask);
}
static inline void uhci_ll_clear_intr(uhci_dev_t *hw, uint32_t intr_mask)
{
hw->int_clr.val = intr_mask;
}
static inline uint32_t uhci_ll_get_intr(uhci_dev_t *hw)
{
return hw->int_st.val;
}
static inline void uhci_ll_set_eof_mode(uhci_dev_t *hw, uint32_t eof_mode)
{
if (eof_mode & UHCI_RX_BREAK_CHR_EOF) {
hw->conf0.uart_rx_brk_eof_en = 1;
}
if (eof_mode & UHCI_RX_IDLE_EOF) {
hw->conf0.uart_idle_eof_en = 1;
}
if (eof_mode & UHCI_RX_LEN_EOF) {
hw->conf0.len_eof_en = 1;
}
}
#ifdef __cplusplus
}
#endif

View File

@ -163,6 +163,13 @@ void hci_uart_send(uint8_t *buf, uint16_t len)
}
}
void
ble_transport_ll_init(void)
{
}
int
ble_transport_to_ll_acl_impl(struct os_mbuf *om)
{