Merge branch 'feat/added_nonblocking_mode_for_hci_alloc' into 'master'

feat(bt): block the hci task if no available hci cmd buffer for ESP32-S31, ESP32-H4

See merge request espressif/esp-idf!52765
This commit is contained in:
Wang Meng Yang
2026-09-16 08:13:40 +08:00
9 changed files with 235 additions and 72 deletions

View File

@@ -113,7 +113,7 @@
#include "../../common/btdm_le.h"
#endif /* SOC_BLE_SUPPORTED */
#define BTDM_CONFIG_VERSION 0x20260127
#define BTDM_CONFIG_VERSION 0x20260911
#define BTDM_CONFIG_MAGIC_VALUE 0x5a5aa5a5
/* Types definition
@@ -124,15 +124,16 @@
* @brief BTDM controller common configuration options
*/
typedef struct {
uint32_t version; /*!< Version number of the defined structure */
uint16_t task_stack_size; /*!< Size of Bluetooth controller task stack */
uint8_t task_prio; /*!< Priority of the Bluetooth controller task */
uint8_t task_run_cpu; /*!< CPU number on which the Bluetooth controller task runs */
uint8_t hci_cmd_num; /*!< HCI command buffer number */
uint8_t sleep_en; /*!< Enable sleep functionality */
uint8_t version_num; /*!< Hardware version number of this chip */
uint8_t bluetooth_mode; /*!< Controller mode: BR/EDR, BLE or Dual Mode */
uint32_t magic; /*!< Magic number for configuration validation */
uint32_t version; /*!< Version number of the defined structure */
uint16_t task_stack_size; /*!< Size of Bluetooth controller task stack */
uint8_t task_prio; /*!< Priority of the Bluetooth controller task */
uint8_t task_run_cpu; /*!< CPU number on which the Bluetooth controller task runs */
uint8_t hci_cmd_num; /*!< HCI command buffer number */
uint8_t nonblocking_cmd_buf; /*!< Non-blocking mode for command buffer allocation */
uint8_t sleep_en; /*!< Enable sleep functionality */
uint8_t version_num; /*!< Hardware version number of this chip */
uint8_t bluetooth_mode; /*!< Controller mode: BR/EDR, BLE or Dual Mode */
uint32_t magic; /*!< Magic number for configuration validation */
} esp_bt_ctrl_btdm_config_t;
/**
@@ -157,38 +158,40 @@
#endif // defined(CONFIG_BTDM_CTRL_MODE_BLE_ONLY)
#if SOC_BT_CLASSIC_SUPPORTED
#define BT_CONTROLLER_INIT_CONFIG_DEFAULT() \
{ \
.ble = _BT_CTRL_LE_INIT_CONFIG_DEFAULT(), \
.bredr = _BT_CTRL_BREDR_INIT_CONFIG_DEFAULT(), \
.btdm = \
{ \
.version = BTDM_CONFIG_VERSION, \
.task_stack_size = UC_BT_CTRL_TASK_STACK_SIZE, \
.task_prio = ESP_TASK_BT_CONTROLLER_PRIO, \
.task_run_cpu = CONFIG_BT_CTRL_PINNED_TO_CORE, \
.hci_cmd_num = CONFIG_BT_CTRL_HCI_CMD_NUM, \
.sleep_en = UC_BT_CTRL_SLEEP_ENABLE, \
.version_num = 0, \
.bluetooth_mode = BTDM_CONTROLLER_MODE_EFF, \
.magic = BTDM_CONFIG_MAGIC_VALUE, \
}, \
#define BT_CONTROLLER_INIT_CONFIG_DEFAULT() \
{ \
.ble = _BT_CTRL_LE_INIT_CONFIG_DEFAULT(), \
.bredr = _BT_CTRL_BREDR_INIT_CONFIG_DEFAULT(), \
.btdm = \
{ \
.version = BTDM_CONFIG_VERSION, \
.task_stack_size = UC_BT_CTRL_TASK_STACK_SIZE, \
.task_prio = ESP_TASK_BT_CONTROLLER_PRIO, \
.task_run_cpu = CONFIG_BT_CTRL_PINNED_TO_CORE, \
.hci_cmd_num = CONFIG_BT_CTRL_HCI_CMD_NUM, \
.nonblocking_cmd_buf = UC_BT_CTRL_NONBLOCK_CMD_BUF, \
.sleep_en = UC_BT_CTRL_SLEEP_ENABLE, \
.version_num = 0, \
.bluetooth_mode = BTDM_CONTROLLER_MODE_EFF, \
.magic = BTDM_CONFIG_MAGIC_VALUE, \
}, \
}
#else
#else
#define BT_CONTROLLER_INIT_CONFIG_DEFAULT() \
{ \
.ble = _BT_CTRL_LE_INIT_CONFIG_DEFAULT(), \
.btdm = \
{ \
.version = BTDM_CONFIG_VERSION, \
.task_stack_size = UC_BT_CTRL_TASK_STACK_SIZE, \
.task_prio = ESP_TASK_BT_CONTROLLER_PRIO, \
.task_run_cpu = CONFIG_BT_CTRL_PINNED_TO_CORE, \
.hci_cmd_num = CONFIG_BT_CTRL_HCI_CMD_NUM, \
.sleep_en = UC_BT_CTRL_SLEEP_ENABLE, \
.version_num = 0, \
.bluetooth_mode = BTDM_CONTROLLER_MODE_EFF, \
.magic = BTDM_CONFIG_MAGIC_VALUE, \
.version = BTDM_CONFIG_VERSION, \
.task_stack_size = UC_BT_CTRL_TASK_STACK_SIZE, \
.task_prio = ESP_TASK_BT_CONTROLLER_PRIO, \
.task_run_cpu = CONFIG_BT_CTRL_PINNED_TO_CORE, \
.hci_cmd_num = CONFIG_BT_CTRL_HCI_CMD_NUM, \
.nonblocking_cmd_buf = UC_BT_CTRL_NONBLOCK_CMD_BUF, \
.sleep_en = UC_BT_CTRL_SLEEP_ENABLE, \
.version_num = 0, \
.bluetooth_mode = BTDM_CONTROLLER_MODE_EFF, \
.magic = BTDM_CONFIG_MAGIC_VALUE, \
}, \
}
#endif // SOC_BT_CLASSIC_SUPPORTED

View File

@@ -112,7 +112,7 @@ typedef struct {
#include "../../common/btdm_le.h"
#endif /* SOC_BLE_SUPPORTED */
#define BTDM_CONFIG_VERSION 0x20260127
#define BTDM_CONFIG_VERSION 0x20260911
#define BTDM_CONFIG_MAGIC_VALUE 0x5a5aa5a5
/* Types definition
@@ -128,6 +128,7 @@ typedef struct {
uint8_t task_prio; /*!< Priority of the Bluetooth controller task */
uint8_t task_run_cpu; /*!< CPU number on which the Bluetooth controller task runs */
uint8_t hci_cmd_num; /*!< HCI command buffer number */
uint8_t nonblocking_cmd_buf; /*!< Non-blocking mode for command buffer allocation */
uint8_t sleep_en; /*!< Enable sleep functionality */
uint8_t version_num; /*!< Hardware version number of this chip */
uint8_t bluetooth_mode; /*!< Controller mode: BR/EDR, BLE or Dual Mode */
@@ -167,6 +168,7 @@ typedef struct {
.task_prio = ESP_TASK_BT_CONTROLLER_PRIO, \
.task_run_cpu = CONFIG_BT_CTRL_PINNED_TO_CORE, \
.hci_cmd_num = CONFIG_BT_CTRL_HCI_CMD_NUM, \
.nonblocking_cmd_buf = UC_BT_CTRL_NONBLOCK_CMD_BUF, \
.sleep_en = UC_BT_CTRL_SLEEP_ENABLE, \
.version_num = 0, \
.bluetooth_mode = BTDM_CONTROLLER_MODE_EFF, \
@@ -184,6 +186,7 @@ typedef struct {
.task_prio = ESP_TASK_BT_CONTROLLER_PRIO, \
.task_run_cpu = CONFIG_BT_CTRL_PINNED_TO_CORE, \
.hci_cmd_num = CONFIG_BT_CTRL_HCI_CMD_NUM, \
.nonblocking_cmd_buf = UC_BT_CTRL_NONBLOCK_CMD_BUF, \
.sleep_en = UC_BT_CTRL_SLEEP_ENABLE, \
.version_num = 0, \
.bluetooth_mode = BTDM_CONTROLLER_MODE_EFF, \

View File

@@ -24,6 +24,12 @@ extern "C" {
#define UC_BT_CTRL_TASK_STACK_SIZE CONFIG_BT_CTRL_TASK_STACK_SIZE
#ifdef CONFIG_BT_CTRL_NONBLOCK_CMD_BUF
#define UC_BT_CTRL_NONBLOCK_CMD_BUF CONFIG_BT_CTRL_NONBLOCK_CMD_BUF
#else
#define UC_BT_CTRL_NONBLOCK_CMD_BUF (0)
#endif
#ifdef CONFIG_BT_CTRL_HCI_INTERFACE_USE_UART
#define UC_HCI_UART_EN CONFIG_BT_CTRL_HCI_INTERFACE_USE_UART
#else

View File

@@ -133,4 +133,12 @@ menu "Bluetooth controller HCI"
Deprecated: this option is no longer used after HCI UART DMA
switched to UHCI driver APIs, and will be removed in a future release.
config BT_CTRL_NONBLOCK_CMD_BUF
bool "Return NULL when no HCI command buffer is available instead of blocking"
default y if BT_CTRL_UART_HCI_DMA_MODE || BT_NIMBLE_ENABLED
default n
help
By default, the API will block if no HCI command buffer is available.
It is recommended to enable this option when HCI Tx and Rx processing run within the same task.
Otherwise, the task may deadlock.
endmenu

View File

@@ -45,6 +45,14 @@
#define HCI_H4_SM_W4_HEADER 1
#define HCI_H4_SM_W4_PAYLOAD 2
#define HCI_H4_SM_COMPLETED 3
#define HCI_H4_SM_WAIT_RESET 4
/* Buffer allocation failed. The stream is still in sync, so the state machine
* is kept as is and the allocation is retried on the next pass.
*/
#define HCI_H4_ERR_MEM (-1)
/* The stream cannot be parsed anymore, the current packet has to be dropped. */
#define HCI_H4_ERR_SYNC_LOSS (-2)
#define TAG "HCI_H4"
@@ -78,7 +86,7 @@ hci_h4_frame_start(struct hci_h4_sm *rxs, uint8_t pkt_type)
#endif // (!CONFIG_BT_CONTROLLER_ENABLED)
default:
/* !TODO: Sync loss. Need to wait for reset. */
return -1;
return HCI_H4_ERR_SYNC_LOSS;
}
return 0;
@@ -129,7 +137,7 @@ hci_h4_sm_w4_header(struct hci_h4_sm *h4sm, struct hci_h4_input_buffer *ib)
HCI_TRANS_ASSERT(h4sm->allocs && h4sm->allocs->cmd, 0, 0);
h4sm->pkt = h4sm->allocs->cmd();
if (!h4sm->pkt) {
return -1;
return HCI_H4_ERR_MEM;
}
memcpy(h4sm->pkt->data, h4sm->hdr, h4sm->len);
@@ -143,7 +151,7 @@ hci_h4_sm_w4_header(struct hci_h4_sm *h4sm, struct hci_h4_input_buffer *ib)
h4sm->exp_len = btdm_get_le16(&h4sm->hdr[2]) + 4;
h4sm->pkt = h4sm->allocs->bredr_acl(conn_handle);
if (!h4sm->pkt) {
return -1;
return HCI_H4_ERR_MEM;
}
memcpy(h4sm->pkt->data, h4sm->hdr, h4sm->len);
break;
@@ -153,17 +161,20 @@ hci_h4_sm_w4_header(struct hci_h4_sm *h4sm, struct hci_h4_input_buffer *ib)
if (HCI_INTERNAL_CONN_IS_BLE(conn_handle)) {
h4sm->om = h4sm->allocs->acl();
if (!h4sm->om) {
return -1;
return HCI_H4_ERR_MEM;
}
if (ble_mbuf_append(h4sm->om, h4sm->hdr, h4sm->len)) {
return -1;
/* Release the mbuf so that the retry starts from a clean state. */
h4sm->frees->acl(h4sm->om);
h4sm->om = NULL;
return HCI_H4_ERR_MEM;
}
h4sm->exp_len = btdm_get_le16(&h4sm->hdr[2]) + 4;
break;
}
#endif // UC_BT_CTRL_BLE_IS_ENABLE
return -1;
return HCI_H4_ERR_SYNC_LOSS;
#if UC_BT_CTRL_BR_EDR_IS_ENABLE
case HCI_H4_SYNC:
conn_handle = btdm_get_le16(&h4sm->hdr[0]) & HCI_INTERNAL_CONN_MASK;
@@ -214,7 +225,7 @@ hci_h4_sm_w4_header(struct hci_h4_sm *h4sm, struct hci_h4_input_buffer *ib)
} else {
h4sm->buf = h4sm->allocs->evt(0);
if (!h4sm->buf) {
return -1;
return HCI_H4_ERR_MEM;
}
}
@@ -230,14 +241,14 @@ hci_h4_sm_w4_header(struct hci_h4_sm *h4sm, struct hci_h4_input_buffer *ib)
h4sm->exp_len = (btdm_get_le16(&h4sm->hdr[2]) & 0x3fff) + 4;
h4sm->buf = h4sm->allocs->iso(h4sm->exp_len);
if (!h4sm->buf) {
return -1;
return HCI_H4_ERR_MEM;
}
memcpy(h4sm->buf, h4sm->hdr, h4sm->len);
break;
#endif // CONFIG_BT_LE_ISO_SUPPORT
default:
return -2;
return HCI_H4_ERR_SYNC_LOSS;
}
return 0;
@@ -288,13 +299,13 @@ hci_h4_sm_w4_payload(struct hci_h4_sm *h4sm,
len = BLE_MBUF_PKTLEN(h4sm->om) - mbuf_len;
h4sm->len += len;
hci_h4_ib_consume(ib, len);
return -1;
return HCI_H4_ERR_MEM;
}
}
#endif // UC_BT_CTRL_BLE_IS_ENABLE
break;
default:
return -2;
return HCI_H4_ERR_SYNC_LOSS;
}
h4sm->len += len;
@@ -389,6 +400,67 @@ hci_h4_sm_completed(struct hci_h4_sm *h4sm)
}
}
/* H4 type + HCI Reset (opcode 0x0C03, plen 0). */
static const uint8_t s_hci_h4_reset_pattern[] = {HCI_H4_CMD, 0x03, 0x0C, 0x00};
static int
hci_h4_sm_dispatch_reset_cmd(struct hci_h4_sm *h4sm)
{
HCI_TRANS_ASSERT(h4sm->allocs && h4sm->allocs->cmd, 0, 0);
h4sm->pkt_type = HCI_H4_CMD;
h4sm->pkt = h4sm->allocs->cmd();
if (!h4sm->pkt) {
return HCI_H4_ERR_MEM;
}
memcpy(h4sm->pkt->data, &s_hci_h4_reset_pattern[1], 3);
h4sm->len = 3;
hci_h4_sm_completed(h4sm);
h4sm->reset_match_idx = 0;
h4sm->state = HCI_H4_SM_W4_PKT_TYPE;
return 0;
}
static int
hci_h4_sm_wait_for_reset(struct hci_h4_sm *h4sm, struct hci_h4_input_buffer *ib)
{
int rc;
/* Pattern already fully matched; retry delivery after a previous OOM. */
if (h4sm->reset_match_idx == sizeof(s_hci_h4_reset_pattern)) {
return hci_h4_sm_dispatch_reset_cmd(h4sm);
}
for (uint16_t i = 0; i < ib->len; i++) {
if (ib->buf[i] == s_hci_h4_reset_pattern[h4sm->reset_match_idx]) {
h4sm->reset_match_idx++;
} else {
if (ib->buf[i] == s_hci_h4_reset_pattern[0]) {
h4sm->reset_match_idx = 1;
} else {
h4sm->reset_match_idx = 0;
}
}
if (h4sm->reset_match_idx == sizeof(s_hci_h4_reset_pattern)) {
hci_h4_ib_consume(ib, i + 1);
rc = hci_h4_sm_dispatch_reset_cmd(h4sm);
if (rc == HCI_H4_ERR_MEM) {
/* Reset bytes are already consumed; keep idx at 4 and retry alloc. */
h4sm->state = HCI_H4_SM_WAIT_RESET;
}
return rc;
}
}
if (h4sm->reset_match_idx) {
/* Need more data */
hci_h4_ib_consume(ib, ib->len);
return 1;
}
return HCI_H4_ERR_SYNC_LOSS;
}
static int
hci_h4_sm_free_buf(struct hci_h4_sm *h4sm)
{
@@ -466,7 +538,8 @@ hci_h4_sm_rx(struct hci_h4_sm *h4sm, const uint8_t *buf, uint16_t len)
switch (h4sm->state) {
case HCI_H4_SM_W4_PKT_TYPE:
if (hci_h4_frame_start(h4sm, ib.buf[0]) < 0) {
return -1;
rc = HCI_H4_ERR_SYNC_LOSS;
break;
}
hci_h4_ib_consume(&ib, 1);
@@ -492,27 +565,32 @@ hci_h4_sm_rx(struct hci_h4_sm *h4sm, const uint8_t *buf, uint16_t len)
hci_h4_sm_completed(h4sm);
h4sm->state = HCI_H4_SM_W4_PKT_TYPE;
break;
case HCI_H4_SM_WAIT_RESET:
rc = hci_h4_sm_wait_for_reset(h4sm, &ib);
break;
default:
return -1;
rc = HCI_H4_ERR_SYNC_LOSS;
break;
}
}
if (rc < 0) {
if ((rc < 0) && (rc != HCI_H4_ERR_MEM)) {
hci_h4_sm_free_buf(h4sm);
h4sm->state = HCI_H4_SM_W4_PKT_TYPE;
return -1;
h4sm->reset_match_idx = 0;
h4sm->state = HCI_H4_SM_WAIT_RESET;
return rc;
}
/* 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.
* On oom the state machine is left untouched so that the allocation is
* retried on the next pass, and the number of bytes actually taken from
* `buf` is reported to let the caller resubmit the remaining data.
*/
len = len - ib.len;
if (len == 0) {
HCI_TRANS_ASSERT((rc < 0), rc, ib.len);
return -1;
HCI_TRANS_ASSERT((rc == HCI_H4_ERR_MEM), rc, ib.len);
}
return len;

View File

@@ -53,6 +53,9 @@ typedef struct {
uhci_transmit_buffer_info_t *tx_segments; /*!< Scratch array of UHCI TX segments for one multi-buffer transaction. */
volatile hci_trans_tx_state_t hci_tx_state; /*!< Only one HCI packet is in flight (tx-list entries cannot be mixed). */
volatile bool rx_copy_overflow; /*!< Set in ISR when rx_copy_ringbuf cannot accept a DMA slice. */
uint8_t *rx_pending_item; /*!< Original xRingbufferReceive() pointer; held until H4 consumes the slice. */
uint8_t *rx_pending_data; /*!< Unparsed remainder of rx_pending_item (item + already consumed). */
size_t rx_pending_len; /*!< Bytes still to feed to hci_h4_sm_rx() from rx_pending_data. */
} hci_driver_uart_dma_env_t;
/* Max UHCI TX segments in one uhci_multi_buffer_transmit(); maps to max_transmit_buffer_count. */
@@ -77,7 +80,6 @@ typedef struct {
*/
#define HCI_UHCI_RX_DESC_MEM (UC_BT_CTRL_HCI_TRANS_RX_MEM_NUM * HCI_RX_DMA_RING_SIZE)
#define HCI_RX_COPY_RINGBUF_SIZE HCI_RX_DMA_RING_SIZE
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;
@@ -85,6 +87,18 @@ static portMUX_TYPE s_hci_tx_state_mux = portMUX_INITIALIZER_UNLOCKED;
static int hci_driver_uart_dma_tx_submit(void);
static void
hci_driver_uart_dma_rx_pending_clear(void)
{
if (s_hci_driver_uart_dma_env.rx_pending_item && s_hci_driver_uart_dma_env.rx_copy_ringbuf) {
vRingbufferReturnItem(s_hci_driver_uart_dma_env.rx_copy_ringbuf,
s_hci_driver_uart_dma_env.rx_pending_item);
}
s_hci_driver_uart_dma_env.rx_pending_item = NULL;
s_hci_driver_uart_dma_env.rx_pending_data = NULL;
s_hci_driver_uart_dma_env.rx_pending_len = 0;
}
/**
* @brief Free the DMA ring, software RX ringbuf and TX segment scratch array.
*
@@ -94,6 +108,8 @@ static int hci_driver_uart_dma_tx_submit(void);
static void
hci_driver_uart_dma_memory_deinit(void)
{
hci_driver_uart_dma_rx_pending_clear();
if (s_hci_driver_uart_dma_env.rx_copy_ringbuf) {
vRingbufferDelete(s_hci_driver_uart_dma_env.rx_copy_ringbuf);
s_hci_driver_uart_dma_env.rx_copy_ringbuf = NULL;
@@ -423,18 +439,55 @@ hci_driver_uart_dma_h4_frame_cb(uint8_t pkt_type, void *data, int pkt_len, uint8
return forward_cb(pkt_type, data, pkt_len, HCI_DRIVER_DIR_H2C, data_source);
}
/**
* @brief Feed one H4 slice and either return the ringbuf item or hold the remainder.
*
* @return true if the caller may continue with the next ringbuf item.
* false if H4 consumed fewer bytes than offered (typically OOM); the
* unparsed tail is stored in rx_pending_* and must be retried
* on the next process_rx() entry.
*/
static bool
hci_driver_uart_dma_h4_feed(uint8_t *item, uint8_t *data, size_t item_size)
{
int ret;
ESP_LOGD(TAG, "uart rx");
ESP_LOG_BUFFER_HEXDUMP(TAG, data, item_size, ESP_LOG_DEBUG);
ret = hci_h4_sm_rx(s_hci_driver_uart_dma_env.h4_sm, data, (uint16_t)item_size);
if (ret < 0) {
ESP_LOGW(TAG, "parse rx data error!\n");
#if UC_BT_CTRL_BLE_IS_ENABLE
r_ble_ll_hci_ev_hw_err(ESP_HCI_SYNC_LOSS_ERR);
#endif // #if UC_BT_CTRL_BLE_IS_ENABLE
} else if ((size_t)ret < item_size) {
/* Keep the ringbuf item checked out so the unparsed bytes stay valid. */
s_hci_driver_uart_dma_env.rx_pending_item = item;
s_hci_driver_uart_dma_env.rx_pending_data = data + ret;
s_hci_driver_uart_dma_env.rx_pending_len = item_size - (size_t)ret;
return false;
}
vRingbufferReturnItem(s_hci_driver_uart_dma_env.rx_copy_ringbuf, item);
s_hci_driver_uart_dma_env.rx_pending_item = NULL;
s_hci_driver_uart_dma_env.rx_pending_data = NULL;
s_hci_driver_uart_dma_env.rx_pending_len = 0;
return true;
}
/**
* @brief Drain the software RX ringbuf into the H4 state machine.
*
* Timeout is 0: the process task is already woken by process_sem. Chunks may be
* one DMA node or a short EOF tail; H4 concatenates them into HCI packets.
* If H4 returns a partial consume, the remainder is retried first on the next call.
*/
static void
hci_driver_uart_dma_process_rx(void)
{
size_t item_size;
uint8_t *rx_data;
int ret;
if (s_hci_driver_uart_dma_env.rx_copy_overflow) {
ESP_LOGE(TAG, "RX software ring buffer overflow, HCI stream may lose sync");
@@ -444,17 +497,17 @@ hci_driver_uart_dma_process_rx(void)
#endif // #if UC_BT_CTRL_BLE_IS_ENABLE
}
if (s_hci_driver_uart_dma_env.rx_pending_item) {
if (!hci_driver_uart_dma_h4_feed(s_hci_driver_uart_dma_env.rx_pending_item,
s_hci_driver_uart_dma_env.rx_pending_data,
s_hci_driver_uart_dma_env.rx_pending_len)) {
return;
}
}
while ((rx_data = xRingbufferReceive(s_hci_driver_uart_dma_env.rx_copy_ringbuf, &item_size, 0)) != NULL) {
ESP_LOGD(TAG, "uart rx");
ESP_LOG_BUFFER_HEXDUMP(TAG, rx_data, item_size, ESP_LOG_DEBUG);
ret = hci_h4_sm_rx(s_hci_driver_uart_dma_env.h4_sm, rx_data, (uint16_t)item_size);
/* Return the item before parsing the next slice so the ringbuf can accept more ISR copies. */
vRingbufferReturnItem(s_hci_driver_uart_dma_env.rx_copy_ringbuf, rx_data);
if (ret < 0) {
ESP_LOGW(TAG, "parse rx data error!\n");
#if UC_BT_CTRL_BLE_IS_ENABLE
r_ble_ll_hci_ev_hw_err(ESP_HCI_SYNC_LOSS_ERR);
#endif // #if UC_BT_CTRL_BLE_IS_ENABLE
if (!hci_driver_uart_dma_h4_feed(rx_data, rx_data, item_size)) {
return;
}
}
}

View File

@@ -96,6 +96,7 @@ struct hci_h4_sm {
uint8_t state;
uint8_t pkt_type;
uint8_t min_len;
uint8_t reset_match_idx;
uint16_t len;
uint16_t exp_len;
uint8_t hdr[4];
@@ -115,6 +116,17 @@ void hci_h4_sm_init(struct hci_h4_sm *h4sm,
const struct hci_h4_frees *frees,
hci_h4_frame_cb *frame_cb);
/**
* @brief Feed received H4 data into the parser state machine.
*
* @return Number of bytes of `buf` that have been parsed, which may be less
* than `len` (0 included) when a buffer allocation failed. The
* unparsed data has to be submitted again, the allocation is retried
* on the next call.
* A negative value means the stream cannot be parsed anymore and the
* current packet has been dropped, the caller should report a sync
* loss.
*/
int hci_h4_sm_rx(struct hci_h4_sm *h4sm, const uint8_t *buf, uint16_t len);
#endif /* _HCI_H4_H_ */