Ver Fonte

replace list and ringbuffer with fixed queue

use eventgroup to sync spp_vfs_write

each connection has a switch_delay_timer not sharing a one

revert functions like spp_find_slot_by_xxx

fix vfs read bug when peer close
liqigan há 5 anos atrás
pai
commit
023f44e348

+ 5 - 0
components/bt/common/btc/core/btc_task.c

@@ -409,3 +409,8 @@ bool btc_check_queue_is_congest(void)
     return false;
 }
 
+int get_btc_work_queue_size(void)
+{
+    return osi_thread_queue_wait_size(btc_thread, 0);
+}
+

+ 1 - 0
components/bt/common/btc/include/btc/btc_task.h

@@ -116,5 +116,6 @@ bt_status_t btc_inter_profile_call(btc_msg_t *msg, void *arg);
 bt_status_t btc_init(void);
 void btc_deinit(void);
 bool btc_check_queue_is_congest(void);
+int get_btc_work_queue_size(void);
 
 #endif /* __BTC_TASK_H__ */

+ 2 - 2
components/bt/host/bluedroid/api/include/api/esp_spp_api.h

@@ -27,9 +27,9 @@ typedef enum {
     ESP_SPP_FAILURE,                /*!< Generic failure. */
     ESP_SPP_BUSY,                   /*!< Temporarily can not handle this request. */
     ESP_SPP_NO_DATA,                /*!< no data. */
-    ESP_SPP_NO_RESOURCE,            /*!< No more set pm control block */
+    ESP_SPP_NO_RESOURCE,            /*!< No more resource */
     ESP_SPP_NEED_INIT,              /*!< SPP module shall init first */
-    ESP_SPP_NEED_UNINIT,            /*!< SPP module shall uninit first */
+    ESP_SPP_NEED_DEINIT,            /*!< SPP module shall deinit first */
     ESP_SPP_NO_CONNECTION,          /*!< connection may have been closed */
 } esp_spp_status_t;
 

+ 2 - 2
components/bt/host/bluedroid/bta/dm/bta_dm_act.c

@@ -3759,9 +3759,9 @@ static void bta_dm_adjust_roles(BOOLEAN delay_role_switch)
                         BTM_SwitchRole (bta_dm_cb.device_list.peer_device[i].peer_bdaddr,
                                         HCI_ROLE_MASTER, NULL);
                     } else {
-                        bta_dm_cb.switch_delay_timer.p_cback =
+                        bta_dm_cb.switch_delay_timer[i].p_cback =
                             (TIMER_CBACK *)&bta_dm_delay_role_switch_cback;
-                        bta_sys_start_timer(&bta_dm_cb.switch_delay_timer, 0, 500);
+                        bta_sys_start_timer(&bta_dm_cb.switch_delay_timer[i], 0, 500);
                     }
                 }
 

+ 1 - 1
components/bt/host/bluedroid/bta/dm/include/bta_dm_int.h

@@ -1067,7 +1067,7 @@ typedef struct {
 
 
     tBTA_DM_ENCRYPT_CBACK      *p_encrypt_cback;
-    TIMER_LIST_ENT              switch_delay_timer;
+    TIMER_LIST_ENT              switch_delay_timer[BTA_DM_NUM_PEER_DEVICE];
 
 } tBTA_DM_CB;
 

+ 1 - 1
components/bt/host/bluedroid/bta/include/bta/bta_jv_api.h

@@ -297,7 +297,6 @@ typedef struct {
     tBTA_JV_STATUS  status;      /* Whether the operation succeeded or failed. */
     UINT32          port_status; /* PORT status */
     UINT32          handle;      /* The connection handle */
-    void            *slot;       /* slot pointer */
     BOOLEAN         async;       /* FALSE, if local initiates disconnect */
 } tBTA_JV_RFCOMM_CLOSE;
 
@@ -347,6 +346,7 @@ typedef struct {
     UINT32          req_id;     /* The req_id in the associated BTA_JvRfcommWrite() */
     int             len;        /* The length of the data written. */
     BOOLEAN         cong;       /* congestion status */
+    BOOLEAN         old_cong;   /* congestion status */
 } tBTA_JV_RFCOMM_WRITE;
 
 /* data associated with BTA_JV_API_SET_PM_PROFILE_EVT */

+ 4 - 7
components/bt/host/bluedroid/bta/jv/bta_jv_act.c

@@ -1688,7 +1688,6 @@ static void bta_jv_port_mgmt_cl_cback(UINT32 code, UINT16 port_handle)
         evt_data.rfc_close.status = BTA_JV_FAILURE;
         evt_data.rfc_close.port_status = code;
         evt_data.rfc_close.async = TRUE;
-        evt_data.rfc_close.slot = NULL;
         if (p_pcb->state == BTA_JV_ST_CL_CLOSING) {
             evt_data.rfc_close.async = FALSE;
             evt_data.rfc_close.status = BTA_JV_SUCCESS;
@@ -1872,7 +1871,6 @@ void bta_jv_rfcomm_close(tBTA_JV_MSG *p_data)
         evt_data.rfc_close.port_status = PORT_LOCAL_CLOSED;
         evt_data.rfc_close.handle = cc->handle;
         evt_data.rfc_close.async = TRUE;
-        evt_data.rfc_close.slot = NULL;
         if (p_pcb && (p_pcb->state == BTA_JV_ST_SR_LISTEN ||
                       p_pcb->state == BTA_JV_ST_SR_OPEN ||
                       p_pcb->state == BTA_JV_ST_CL_OPEN ||
@@ -1962,7 +1960,6 @@ static void bta_jv_port_mgmt_sr_cback(UINT32 code, UINT16 port_handle)
         evt_data.rfc_close.status = BTA_JV_FAILURE;
         evt_data.rfc_close.async = TRUE;
         evt_data.rfc_close.port_status = code;
-        evt_data.rfc_close.slot = NULL;
         p_pcb->cong = FALSE;
 
         tBTA_JV_RFCOMM_CBACK    *p_cback = p_cb->p_cback;
@@ -2260,16 +2257,16 @@ void bta_jv_rfcomm_write(tBTA_JV_MSG *p_data)
     evt_data.status = BTA_JV_FAILURE;
     evt_data.handle = p_pcb->handle;
     evt_data.req_id = wc->req_id;
-    evt_data.cong   = p_pcb->cong;
+    evt_data.old_cong = p_pcb->cong;
     bta_jv_pm_conn_busy(p_pcb->p_pm_cb);
-    evt_data.len = wc->len;
-    if (!evt_data.cong &&
+    evt_data.len = -1;
+    if (!evt_data.old_cong &&
             PORT_WriteDataCO(p_pcb->port_handle, &evt_data.len, wc->len, wc->p_data) ==
             PORT_SUCCESS) {
         evt_data.status = BTA_JV_SUCCESS;
     }
     // update congestion flag
-    evt_data.cong   = p_pcb->cong;
+    evt_data.cong = p_pcb->cong;
     if (p_cb->p_cback) {
         p_cb->p_cback(BTA_JV_RFCOMM_WRITE_EVT, (tBTA_JV *)&evt_data, p_pcb->user_data);
     } else {

+ 401 - 128
components/bt/host/bluedroid/btc/profile/std/spp/btc_spp.c

@@ -24,22 +24,41 @@
 #include "osi/list.h"
 #include "freertos/ringbuf.h"
 #include "osi/mutex.h"
+#include "osi/alarm.h"
 #include <sys/errno.h>
 #include <sys/lock.h>
 #include <sys/fcntl.h>
 #include "esp_vfs.h"
 #include "esp_vfs_dev.h"
 #include "stack/port_api.h"
+#include "freertos/FreeRTOS.h"
+#include "freertos/event_groups.h"
+
+#include "btc/btc_task.h"
+#include "stack/btu.h"
 
 #if (defined BTC_SPP_INCLUDED && BTC_SPP_INCLUDED == TRUE)
 
+#define SLOT_WRITE_BIT(i) (1UL << (i - 1))
+#define SLOT_CLOSE_BIT(i) (1UL << (i + MAX_RFC_PORTS - 1))
+#define VFS_WRITE_TIMEOUT (40 * 1000)
+#define SLOT_TX_QUEUE_SIZE 10
+#define SLOT_TX_QUEUE_LOW_WM 4
+#define SLOT_TX_DATA_HIGH_WM (SLOT_TX_QUEUE_SIZE * BTA_JV_DEF_RFC_MTU)
+#define VFS_CLOSE_TIMEOUT (20 * 1000)
+
+typedef struct {
+    bool peer_fc;         /* true if flow control is set based on peer's request */
+    bool user_fc;         /* true if flow control is set based on user's request  */
+    fixed_queue_t *queue; /* Queue of buffers waiting to be sent */
+    uint32_t data_size;   /* Number of data bytes in the queue */
+} slot_data_t;
+
 typedef struct {
     uint8_t serial;
     bool connected;
     uint8_t scn;
     uint8_t max_session;
-    RingbufHandle_t ringbuf_read;
-    RingbufHandle_t ringbuf_write;
     uint32_t id;
     uint32_t mtu;//unused
     uint32_t sdp_handle;
@@ -47,11 +66,12 @@ typedef struct {
     uint32_t rfc_port_handle;
     int fd;
     uint8_t *write_data;
+    osi_alarm_t *close_alarm;
     esp_spp_role_t role;
     esp_spp_sec_t security;
     esp_bd_addr_t addr;
-    list_t *list;
-    list_t *incoming_list;
+    slot_data_t rx;
+    slot_data_t tx;
     uint8_t service_uuid[16];
     char service_name[ESP_SPP_SERVER_NAME_MAX + 1];
 } spp_slot_t;
@@ -61,6 +81,7 @@ typedef struct {
     uint32_t spp_slot_id;
     esp_spp_mode_t spp_mode;
     osi_mutex_t spp_slot_mutex;
+    EventGroupHandle_t tx_event_group;
     esp_vfs_id_t spp_vfs_id;
 } spp_local_param_t;
 
@@ -82,38 +103,76 @@ static void spp_osi_free(void *p)
 #define is_spp_init() (&spp_local_param != NULL && spp_local_param.spp_slot_mutex != NULL)
 #endif
 
+static int init_slot_data(slot_data_t *slot_data, size_t queue_size)
+{
+    memset(slot_data, 0, sizeof(slot_data_t));
+    if ((slot_data->queue = fixed_queue_new(queue_size)) == NULL) {
+        return -1;
+    }
+    slot_data->data_size = 0;
+    return 0;
+}
+
+void free_slot_data(slot_data_t *slot_data)
+{
+    fixed_queue_free(slot_data->queue, spp_osi_free);
+    slot_data->queue = NULL;
+}
+
 static spp_slot_t *spp_malloc_slot(void)
 {
+    uint8_t err_no = 0;
+    spp_slot_t **slot = NULL;
     if (++spp_local_param.spp_slot_id == 0) {
         spp_local_param.spp_slot_id = 1;
     }
     for (size_t i = 1; i <= MAX_RFC_PORTS; i++) {
-        if (spp_local_param.spp_slots[i] == NULL) {
-            spp_local_param.spp_slots[i] = (spp_slot_t *)osi_malloc(sizeof(spp_slot_t));
-            if (!spp_local_param.spp_slots[i]) {
+        slot = &spp_local_param.spp_slots[i];
+        if ((*slot) == NULL) {
+            if (((*slot) = (spp_slot_t *)osi_malloc(sizeof(spp_slot_t))) == NULL) {
                 return NULL;
             }
-            spp_local_param.spp_slots[i]->id = spp_local_param.spp_slot_id;
-            spp_local_param.spp_slots[i]->serial = i;
-            spp_local_param.spp_slots[i]->sdp_handle = 0;
-            spp_local_param.spp_slots[i]->rfc_handle = 0;
-            spp_local_param.spp_slots[i]->rfc_port_handle = 0;
-            spp_local_param.spp_slots[i]->connected = FALSE;
-            spp_local_param.spp_slots[i]->write_data = NULL;
-            spp_local_param.spp_slots[i]->list = list_new(spp_osi_free);
-            spp_local_param.spp_slots[i]->incoming_list = list_new(spp_osi_free);
+            (*slot)->id = spp_local_param.spp_slot_id;
+            (*slot)->serial = i;
+            (*slot)->sdp_handle = 0;
+            (*slot)->rfc_handle = 0;
+            (*slot)->rfc_port_handle = 0;
+            (*slot)->connected = FALSE;
+            (*slot)->write_data = NULL;
+            (*slot)->close_alarm = NULL;
+            if (init_slot_data(&(*slot)->rx, QUEUE_SIZE_MAX)) {
+                BTC_TRACE_ERROR("%s unable to malloc rx queue!", __func__);
+                err_no = 1;
+                break;
+            }
+            if (init_slot_data(&(*slot)->tx, SLOT_TX_QUEUE_SIZE)) {
+                BTC_TRACE_ERROR("%s unable to malloc tx queue!", __func__);
+                err_no = 2;
+                break;
+            }
             if (spp_local_param.spp_mode == ESP_SPP_MODE_VFS) {
-                if (esp_vfs_register_fd(spp_local_param.spp_vfs_id, &spp_local_param.spp_slots[i]->fd) != ESP_OK) {
-                    osi_free(spp_local_param.spp_slots[i]);
-                    return NULL;
+                if (esp_vfs_register_fd(spp_local_param.spp_vfs_id, &(*slot)->fd) != ESP_OK) {
+                    BTC_TRACE_ERROR("%s unable to register fd!", __func__);
+                    err_no = 3;
+                    break;
                 }
-                spp_local_param.spp_slots[i]->ringbuf_read = xRingbufferCreate(ESP_SPP_RINGBUF_SIZE, RINGBUF_TYPE_BYTEBUF);
-                spp_local_param.spp_slots[i]->ringbuf_write = xRingbufferCreate(ESP_SPP_RINGBUF_SIZE, RINGBUF_TYPE_BYTEBUF);
             }
-            return spp_local_param.spp_slots[i];
+            return (*slot);
         }
     }
-    return NULL;
+    switch (err_no) {
+        case 3:
+            free_slot_data(&(*slot)->tx);
+        case 2:
+            free_slot_data(&(*slot)->rx);
+        case 1:
+            osi_free((*slot));
+            (*slot) = NULL;
+            break;
+        default:
+            break;
+    }
+    return (*slot);
 }
 
 static spp_slot_t *spp_find_slot_by_id(uint32_t id)
@@ -156,19 +215,41 @@ static spp_slot_t *spp_find_slot_by_scn(uint32_t scn)
     return NULL;
 }
 
+static void close_timeout_handler(void *arg)
+{
+    btc_msg_t msg;
+    bt_status_t status;
+
+    msg.sig = BTC_SIG_API_CB;
+    msg.pid = BTC_PID_SPP;
+    msg.act = BTA_JV_RFCOMM_CLOSE_EVT;
+
+    status = btc_transfer_context(&msg, arg, sizeof(tBTA_JV), NULL);
+
+    if (arg) {
+        free(arg);
+    }
+
+    if (status != BT_STATUS_SUCCESS) {
+        BTC_TRACE_ERROR("%s btc_transfer_context failed", __func__);
+    }
+}
+
 static void spp_free_slot(spp_slot_t *slot)
 {
     if (!slot) {
         return;
     }
     spp_local_param.spp_slots[slot->serial] = NULL;
-    list_free(slot->list);
     if (spp_local_param.spp_mode == ESP_SPP_MODE_VFS) {
         (void) esp_vfs_unregister_fd(spp_local_param.spp_vfs_id, slot->fd);
-        vRingbufferDelete(slot->ringbuf_read);
-        vRingbufferDelete(slot->ringbuf_write);
+        xEventGroupSetBits(spp_local_param.tx_event_group, SLOT_CLOSE_BIT(slot->serial));
+    }
+    free_slot_data(&slot->tx);
+    free_slot_data(&slot->rx);
+    if (slot->close_alarm) {
+        osi_alarm_free(slot->close_alarm);
     }
-    list_free(slot->incoming_list);
     osi_free(slot);
 }
 
@@ -194,8 +275,8 @@ static void *btc_spp_rfcomm_inter_cb(tBTA_JV_EVT event, tBTA_JV *p_data, void *u
     void *new_user_data = NULL;
 
     uint32_t id = (uintptr_t)user_data;
-    spp_slot_t *slot, *slot_new;
-    if (!spp_local_param.spp_slot_mutex) {
+    spp_slot_t *slot = NULL, *slot_new = NULL;
+    if (!is_spp_init()) {
         BTC_TRACE_WARNING("%s SPP have been deinit, incoming events ignore!\n", __func__);
         return new_user_data;
     }
@@ -268,7 +349,6 @@ static void *btc_spp_rfcomm_inter_cb(tBTA_JV_EVT event, tBTA_JV *p_data, void *u
         if (slot->connected && p_data->rfc_close.port_status != PORT_LOCAL_CLOSED) {
             BTA_JvRfcommClose(slot->rfc_handle, NULL, (void *)slot->id);
         }
-        p_data->rfc_close.slot = slot;
         p_data->rfc_close.status = BTA_JV_SUCCESS;
         break;
     case BTA_JV_RFCOMM_DATA_IND_EVT:
@@ -310,21 +390,21 @@ static void btc_spp_dm_inter_cb(tBTA_JV_EVT event, tBTA_JV *p_data, void *user_d
     btc_msg_t msg;
 
     uint32_t id = (uintptr_t)user_data;
-    spp_slot_t *slot;
+    spp_slot_t *slot = NULL;
     switch (event) {
     case BTA_JV_GET_SCN_EVT:
         osi_mutex_lock(&spp_local_param.spp_slot_mutex, OSI_MUTEX_MAX_TIMEOUT);
         slot = spp_find_slot_by_id(id);
         if (!slot) {
-            BTC_TRACE_ERROR("%s unable to find RFCOMM slot!", __func__);
             osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
+            BTC_TRACE_ERROR("%s unable to find RFCOMM slot!", __func__);
             break;
         }
         if (p_data->scn == 0) {
-            BTC_TRACE_ERROR("%s unable to get scn, start server fail!", __func__);
             btc_create_server_fail_cb();
             spp_free_slot(slot);
             osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
+            BTC_TRACE_ERROR("%s unable to get scn, start server fail!", __func__);
             break;
         }
 
@@ -336,8 +416,8 @@ static void btc_spp_dm_inter_cb(tBTA_JV_EVT event, tBTA_JV *p_data, void *user_d
         osi_mutex_lock(&spp_local_param.spp_slot_mutex, OSI_MUTEX_MAX_TIMEOUT);
         slot = spp_find_slot_by_id(id);
         if (!slot) {
-            BTC_TRACE_ERROR("%s unable to find RFCOMM slot!", __func__);
             osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
+            BTC_TRACE_ERROR("%s unable to find RFCOMM slot!", __func__);
             break;
         }
         if (p_data->create_rec.status == BTA_JV_SUCCESS) {
@@ -379,7 +459,7 @@ static void btc_spp_init(btc_spp_args_t *arg)
     do {
         if (is_spp_init()) {
             BTC_TRACE_ERROR("%s SPP has been initiated, shall uninit first!", __func__);
-            ret = ESP_SPP_NEED_UNINIT;
+            ret = ESP_SPP_NEED_DEINIT;
             break;
         }
 
@@ -397,6 +477,11 @@ static void btc_spp_init(btc_spp_args_t *arg)
             ret = ESP_SPP_NO_RESOURCE;
             break;
         }
+        if ((spp_local_param.tx_event_group = xEventGroupCreate()) == NULL) {
+            BTC_TRACE_ERROR("%s create tx_event_group failed\n", __func__);
+            ret = ESP_SPP_NO_RESOURCE;
+            break;
+        }
         spp_local_param.spp_mode = arg->init.mode;
         spp_local_param.spp_slot_id = 0;
         BTA_JvEnable((tBTA_JV_DM_CBACK *)btc_spp_dm_inter_cb);
@@ -530,11 +615,16 @@ static void btc_spp_disconnect(btc_spp_args_t *arg)
             ret = ESP_SPP_NEED_INIT;
             break;
         }
+        spp_slot_t *slot = NULL;
         osi_mutex_lock(&spp_local_param.spp_slot_mutex, OSI_MUTEX_MAX_TIMEOUT);
-        spp_slot_t *slot = spp_find_slot_by_handle(arg->disconnect.handle);
-        if (!slot) {
-            BTC_TRACE_ERROR("%s unable to find RFCOMM slot! disconnect fail!", __func__);
+        slot = spp_find_slot_by_handle(arg->disconnect.handle);
+        if (!slot || (slot && !slot->connected)) {
             osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
+            if (!slot) {
+                BTC_TRACE_ERROR("%s unable to find RFCOMM slot! disconnect fail!", __func__);
+            } else {
+                BTC_TRACE_ERROR("%s RFCOMM has been disconnected already!", __func__);
+            }
             ret = ESP_SPP_NO_CONNECTION;
             break;
         }
@@ -652,28 +742,33 @@ static void btc_spp_write(btc_spp_args_t *arg)
             ret = ESP_SPP_NEED_INIT;
             break;
         }
+        spp_slot_t *slot = NULL;
         osi_mutex_lock(&spp_local_param.spp_slot_mutex, OSI_MUTEX_MAX_TIMEOUT);
-        spp_slot_t *slot = spp_find_slot_by_handle(arg->write.handle);
-        if (!slot) {
-            BTC_TRACE_ERROR("%s unable to find RFCOMM slot!", __func__);
+        slot = spp_find_slot_by_handle(arg->write.handle);
+        if (!slot || (slot && !slot->connected)) {
             osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
+            if (!slot) {
+                BTC_TRACE_ERROR("%s unable to find RFCOMM slot!", __func__);
+            } else {
+                BTC_TRACE_ERROR("%s RFCOMM has been disconnected already!", __func__);
+            }
             ret = ESP_SPP_NO_CONNECTION;
             break;
         }
         if (spp_local_param.spp_mode == ESP_SPP_MODE_VFS) {
-            size_t item_size = 0;
-            if (slot->write_data != NULL) {
-                osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
-                return;
-            }
-            uint8_t *data = xRingbufferReceiveUpTo(slot->ringbuf_write, &item_size, 0, BTA_JV_DEF_RFC_MTU);
-            if (item_size != 0) {
-                slot->write_data = data;
-                BTA_JvRfcommWrite(arg->write.handle, slot->id, item_size, data);
+            BT_HDR *p_buf;
+            if ((p_buf = fixed_queue_try_peek_first(slot->tx.queue)) != NULL && p_buf->layer_specific == 0) {
+                p_buf->event++;
+                p_buf->layer_specific = 1;
+                BTA_JvRfcommWrite(arg->write.handle, slot->id, p_buf->len, p_buf->data + p_buf->offset);
             }
         } else {
-            list_append(slot->list, arg->write.p_data);
-            BTA_JvRfcommWrite(arg->write.handle, slot->id, arg->write.len, arg->write.p_data);
+            if (fixed_queue_enqueue(slot->tx.queue, arg->write.p_data, 0)) {
+                BTA_JvRfcommWrite(arg->write.handle, slot->id, arg->write.len, arg->write.p_data);
+            } else {
+                ret = ESP_SPP_NO_RESOURCE;
+                break;
+            }
         }
         osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
     } while (0);
@@ -774,7 +869,8 @@ void btc_spp_cb_handler(btc_msg_t *msg)
 {
     esp_spp_cb_param_t param;
     tBTA_JV *p_data = (tBTA_JV *)msg->arg;
-    spp_slot_t *slot;
+    spp_slot_t *slot = NULL;
+    uint8_t serial = 0;
     switch (msg->act) {
     case BTA_JV_ENABLE_EVT:
         param.init.status = p_data->status;
@@ -799,8 +895,8 @@ void btc_spp_cb_handler(btc_msg_t *msg)
                 osi_mutex_lock(&spp_local_param.spp_slot_mutex, OSI_MUTEX_MAX_TIMEOUT);
                 slot = spp_find_slot_by_handle(p_data->rfc_open.handle);
                 if (!slot) {
-                    BTC_TRACE_ERROR("%s unable to find RFCOMM slot!", __func__);
                     osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
+                    BTC_TRACE_ERROR("%s unable to find RFCOMM slot!", __func__);
                     param.open.status = ESP_SPP_NO_CONNECTION;
                     break;
                 }
@@ -827,8 +923,8 @@ void btc_spp_cb_handler(btc_msg_t *msg)
                     osi_mutex_lock(&spp_local_param.spp_slot_mutex, OSI_MUTEX_MAX_TIMEOUT);
                     slot = spp_find_slot_by_handle(p_data->rfc_srv_open.handle);
                     if (!slot) {
-                        BTC_TRACE_ERROR("%s unable to find RFCOMM slot!", __func__);
                         osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
+                        BTC_TRACE_ERROR("%s unable to find RFCOMM slot!", __func__);
                         param.srv_open.status = ESP_SPP_NO_CONNECTION;
                         break;
                     }
@@ -844,10 +940,10 @@ void btc_spp_cb_handler(btc_msg_t *msg)
         }
         break;
     case BTA_JV_RFCOMM_WRITE_EVT:
-        osi_mutex_lock(&spp_local_param.spp_slot_mutex, OSI_MUTEX_MAX_TIMEOUT);
+        osi_mutex_lock(&spp_local_param.spp_slot_mutex, OSI_MUTEX_MAX_TIMEOUT); 
         slot = spp_find_slot_by_handle(p_data->rfc_write.handle);
         if (!slot) {
-            BTC_TRACE_ERROR("%s unable to find RFCOMM slot!", __func__);
+            BTC_TRACE_ERROR("%s unable to find RFCOMM slot!, handle:%d", __func__, p_data->rfc_write.handle);
         }
         if (spp_local_param.spp_mode == ESP_SPP_MODE_CB){
             param.write.status = slot ? p_data->rfc_write.status : ESP_SPP_NO_CONNECTION;
@@ -856,28 +952,40 @@ void btc_spp_cb_handler(btc_msg_t *msg)
             param.write.cong = p_data->rfc_write.cong;
             btc_spp_cb_to_app(ESP_SPP_WRITE_EVT, &param);
             if (slot) {
-                list_remove(slot->list, list_front(slot->list));
+                osi_free(fixed_queue_dequeue(slot->tx.queue, FIXED_QUEUE_MAX_TIMEOUT));
             }
         } else {
             if (slot) {
-                if (p_data->rfc_write.status != BTA_JV_SUCCESS) {
-                    if (slot->write_data != NULL) {
-                        vRingbufferReturnItem(slot->ringbuf_write, slot->write_data);
-                        slot->write_data = NULL;
-                    }
-                    osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
+                BT_HDR *p_buf;
+                serial = slot->serial;
+                if ((p_buf = fixed_queue_try_peek_first(slot->tx.queue)) == NULL) {
                     break;
                 }
-                if (p_data->rfc_write.cong == 0) {
-                    if (slot->write_data != NULL) {
-                        vRingbufferReturnItem(slot->ringbuf_write, slot->write_data);
-                        slot->write_data = NULL;
+                if (p_data->rfc_write.status == BTA_JV_SUCCESS) {
+                    p_buf->len -= p_data->rfc_write.len;
+                    p_buf->offset += p_data->rfc_write.len;
+                    p_buf->layer_specific = 0;
+                    if (p_buf->len == 0) {
+                        osi_free(fixed_queue_dequeue(slot->tx.queue, FIXED_QUEUE_MAX_TIMEOUT));
+                        if (fixed_queue_length(slot->tx.queue) <= SLOT_TX_QUEUE_LOW_WM) {
+                            xEventGroupSetBits(spp_local_param.tx_event_group, SLOT_WRITE_BIT(serial));
+                        }
                     }
-                    size_t item_size = 0;
-                    uint8_t *data = xRingbufferReceiveUpTo(slot->ringbuf_write, &item_size, 0, BTA_JV_DEF_RFC_MTU);
-                    if (item_size != 0) {
-                        slot->write_data = data;
-                        BTA_JvRfcommWrite(slot->rfc_handle, slot->id, item_size, data);
+
+                    if ((p_buf = fixed_queue_try_peek_first(slot->tx.queue)) != NULL && p_buf->layer_specific == 0 &&
+                        !p_data->rfc_write.cong) {
+                        p_buf->layer_specific = 1;
+                        p_buf->event++;
+                        BTA_JvRfcommWrite(p_data->rfc_write.handle, slot->id, p_buf->len, p_buf->data + p_buf->offset);
+                    }
+                } else {
+                    if (!p_data->rfc_write.old_cong) {
+                        // PORT_WriteDataCO failed
+                        BTC_TRACE_ERROR("PORT_WriteDataCO failed p_buf:%p, handle:%d\n", p_buf,
+                                        p_data->rfc_write.handle);
+                    } else {
+                        // need rewrite
+                        p_buf->layer_specific = 0;
                     }
                 }
             }
@@ -889,8 +997,69 @@ void btc_spp_cb_handler(btc_msg_t *msg)
         param.close.port_status = p_data->rfc_close.port_status;
         param.close.handle = p_data->rfc_close.handle;
         param.close.async = p_data->rfc_close.async;
-        btc_spp_cb_to_app(ESP_SPP_CLOSE_EVT, &param);
-        spp_free_slot((spp_slot_t *)p_data->rfc_close.slot);
+        if (spp_local_param.spp_mode == ESP_SPP_MODE_CB) {
+            btc_spp_cb_to_app(ESP_SPP_CLOSE_EVT, &param);
+            osi_mutex_lock(&spp_local_param.spp_slot_mutex, OSI_MUTEX_MAX_TIMEOUT);
+            slot = spp_find_slot_by_handle(p_data->rfc_close.handle);
+            if (!slot) {
+                osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
+                BTC_TRACE_ERROR("%s unable to find RFCOMM slot!", __func__);
+                break;
+            }
+            spp_free_slot(slot);
+            osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
+        } else {
+            bool need_call = true;
+            do {
+                osi_mutex_lock(&spp_local_param.spp_slot_mutex, OSI_MUTEX_MAX_TIMEOUT);
+                slot = spp_find_slot_by_handle(p_data->rfc_close.handle);
+                if (!slot) {
+                    param.close.status = ESP_SPP_NO_CONNECTION;
+                    osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
+                    BTC_TRACE_ERROR("%s unable to find RFCOMM slot!", __func__);
+                    break;
+                }
+                // if rx still has data, delay free slot
+                if (slot->close_alarm == NULL && slot->rx.queue && fixed_queue_length(slot->rx.queue) > 0) {
+                    tBTA_JV *p_arg = NULL;
+                    if ((p_arg = malloc(sizeof(tBTA_JV))) == NULL) {
+                        param.close.status = ESP_SPP_NO_RESOURCE;
+                        osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
+                        BTC_TRACE_ERROR("%s unable to malloc slot close_alarm arg!", __func__);
+                        break;
+                    }
+                    memcpy(p_arg, p_data, sizeof(tBTA_JV));
+                    if ((slot->close_alarm =
+                             osi_alarm_new("slot", close_timeout_handler, (void *)p_arg, VFS_CLOSE_TIMEOUT)) == NULL) {
+                        free(p_arg);
+                        param.close.status = ESP_SPP_NO_RESOURCE;
+                        osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
+                        BTC_TRACE_ERROR("%s unable to malloc slot close_alarm!", __func__);
+                        break;
+                    }
+                    if (osi_alarm_set(slot->close_alarm, VFS_CLOSE_TIMEOUT) != OSI_ALARM_ERR_PASS) {
+                        free(p_arg);
+                        osi_alarm_free(slot->close_alarm);
+                        param.close.status = ESP_SPP_BUSY;
+                        osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
+                        BTC_TRACE_ERROR("%s set slot close_alarm failed!", __func__);
+                        break;
+                    }
+                    BTC_TRACE_WARNING("%s slot rx data will be discard in %d seconds!", __func__,
+                                      VFS_CLOSE_TIMEOUT / 1000);
+                    slot->connected = false;
+                    need_call = false;
+                }
+                osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
+            } while (0);
+
+            if (need_call) {
+                btc_spp_cb_to_app(ESP_SPP_CLOSE_EVT, &param);
+                osi_mutex_lock(&spp_local_param.spp_slot_mutex, OSI_MUTEX_MAX_TIMEOUT);
+                spp_free_slot(slot);
+                osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
+            }
+        }
         break;
     case BTA_JV_RFCOMM_CONG_EVT:
         if (spp_local_param.spp_mode == ESP_SPP_MODE_CB) {
@@ -902,20 +1071,16 @@ void btc_spp_cb_handler(btc_msg_t *msg)
             osi_mutex_lock(&spp_local_param.spp_slot_mutex, OSI_MUTEX_MAX_TIMEOUT);
             slot = spp_find_slot_by_handle(p_data->rfc_cong.handle);
             if (!slot) {
-                BTC_TRACE_ERROR("%s unable to find RFCOMM slot!", __func__);
                 osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
+                BTC_TRACE_ERROR("%s unable to find RFCOMM slot!", __func__);
                 break;
             }
-            if (p_data->rfc_cong.cong == 0) {
-                if (slot->write_data != NULL){
-                    vRingbufferReturnItem(slot->ringbuf_write,slot->write_data);
-                    slot->write_data = NULL;
-                }
-                size_t item_size = 0;
-                uint8_t *data = xRingbufferReceiveUpTo(slot->ringbuf_write, &item_size, 0, BTA_JV_DEF_RFC_MTU);
-                if (item_size != 0){
-                    slot->write_data = data;
-                    BTA_JvRfcommWrite(slot->rfc_handle, slot->id, item_size, data);
+            if (!p_data->rfc_cong.cong) {
+                BT_HDR *p_buf;
+                if ((p_buf = fixed_queue_try_peek_first(slot->tx.queue)) != NULL && p_buf->layer_specific == 0) {
+                    p_buf->event++;
+                    p_buf->layer_specific = 1;
+                    BTA_JvRfcommWrite(p_data->rfc_cong.handle, slot->id, p_buf->len, p_buf->data + p_buf->offset);
                 }
             }
             osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
@@ -923,28 +1088,25 @@ void btc_spp_cb_handler(btc_msg_t *msg)
         break;
     case BTA_JV_RFCOMM_DATA_IND_EVT:
         do {
-            uint8_t serial;
             BT_HDR *p_buf;
             UINT16 count = 0;
-
             osi_mutex_lock(&spp_local_param.spp_slot_mutex, OSI_MUTEX_MAX_TIMEOUT);
             slot = spp_find_slot_by_handle(p_data->data_ind.handle);
-            if (slot) {
-                serial = slot->serial;
-            }
-            osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
-
             if (!slot) {
+                osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
                 BTC_TRACE_ERROR("%s unable to find RFCOMM slot!", __func__);
                 break;
             }
+            serial = slot->serial;
+            osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
 
             while (1) {
                 // get incoming_data from slot incoming list
                 osi_mutex_lock(&spp_local_param.spp_slot_mutex, OSI_MUTEX_MAX_TIMEOUT);
-                if ((slot = spp_local_param.spp_slots[serial]) != NULL && slot->rfc_handle == p_data->data_ind.handle && !list_is_empty(slot->incoming_list)) {
-                    p_buf = list_front(slot->incoming_list);
-                    list_delete(slot->incoming_list, p_buf);
+                if ((slot = spp_local_param.spp_slots[serial]) != NULL &&
+                    slot->rfc_handle == p_data->data_ind.handle &&
+                    fixed_queue_length(slot->rx.queue) > 0) {
+                    p_buf = (BT_HDR *)fixed_queue_dequeue(slot->rx.queue, FIXED_QUEUE_MAX_TIMEOUT);
                 } else {
                     osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
                     break;
@@ -1010,29 +1172,29 @@ int bta_co_rfc_data_incoming(void *user_data, BT_HDR *p_buf)
     osi_mutex_lock(&spp_local_param.spp_slot_mutex, OSI_MUTEX_MAX_TIMEOUT);
     spp_slot_t *slot = spp_find_slot_by_id(id);
     if (!slot) {
-        BTC_TRACE_ERROR("%s unable to find RFCOMM slot!", __func__);
         osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
+        BTC_TRACE_ERROR("%s unable to find RFCOMM slot!", __func__);
         return -1;
     }
     p_data.data_ind.handle = slot->rfc_handle;
     p_data.data_ind.p_buf = NULL;
 
     if (spp_local_param.spp_mode == ESP_SPP_MODE_CB) {
-        bool incoming_list_empty = list_is_empty(slot->incoming_list);
-        list_append(slot->incoming_list, p_buf);
-        if (incoming_list_empty) {
-            BTC_TRACE_DEBUG("%s data post! %d, %d", __func__, slot->rfc_handle, list_length(slot->incoming_list));
+        size_t rx_len = fixed_queue_length(slot->rx.queue);
+        fixed_queue_enqueue(slot->rx.queue, p_buf, FIXED_QUEUE_MAX_TIMEOUT);
+        if (rx_len == 0) {
+            BTC_TRACE_DEBUG("%s data post! %d, %d", __func__, slot->rfc_handle, rx_len);
             status = btc_transfer_context(&msg, &p_data, sizeof(tBTA_JV), NULL);
             assert(status == BT_STATUS_SUCCESS);
-        } else if (list_length(slot->incoming_list) > 2) {
-            BTC_TRACE_ERROR("%s data post stop! %d %d", __func__, slot->rfc_handle, list_length(slot->incoming_list));
-            ret = 0;
+        } else if (fixed_queue_length(slot->rx.queue) > 2) {
+            BTC_TRACE_DEBUG("%s data post stop! %d %d", __func__, slot->rfc_handle, fixed_queue_length(slot->rx.queue));
+            ret = 0; // reserved for other flow control
         }
     } else {
-        list_append(slot->incoming_list, p_buf);
-        if (list_length(slot->incoming_list) > 2) {
-            BTC_TRACE_ERROR("%s data post stop! %d %d", __func__, slot->rfc_handle, list_length(slot->incoming_list));
-            ret = 0;
+        fixed_queue_enqueue(slot->rx.queue, p_buf, FIXED_QUEUE_MAX_TIMEOUT);
+        if (fixed_queue_length(slot->rx.queue) > 2) {
+            BTC_TRACE_DEBUG("%s data post stop! %d %d", __func__, slot->rfc_handle, fixed_queue_length(slot->rx.queue));
+            ret = 0; // reserved for other flow control
         }
     }
     osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
@@ -1052,38 +1214,111 @@ int bta_co_rfc_data_outgoing(void *user_data, uint8_t *buf, uint16_t size)
 
 static ssize_t spp_vfs_write(int fd, const void * data, size_t size)
 {
+    assert(data != NULL);
+    if (size == 0) {
+        return 0;
+    }
     if (!is_spp_init()) {
         BTC_TRACE_ERROR("%s SPP have not been init\n", __func__);
+        errno = ESRCH;
         return -1;
     }
+
+    spp_slot_t *slot = NULL;
+    uint8_t serial = 0;
     osi_mutex_lock(&spp_local_param.spp_slot_mutex, OSI_MUTEX_MAX_TIMEOUT);
-    spp_slot_t *slot = spp_find_slot_by_fd(fd);
+    slot = spp_find_slot_by_fd(fd);
     if (!slot) {
-        BTC_TRACE_ERROR("%s unable to find RFCOMM slot!", __func__);
         osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
+        BTC_TRACE_ERROR("%s unable to find RFCOMM slot!", __func__);
+        errno = ENOENT;
         return -1;
     }
-    BaseType_t done = xRingbufferSend(slot->ringbuf_write, (void *)data, size, 0);
-    esp_spp_write(slot->rfc_handle, 0, NULL);
+    serial = slot->serial;
     osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
-    if (done){
-        return size;
-    } else {
-        return 0;
-    }
 
+    ssize_t sent = 0, write_size = 0;
+    size_t tx_len;
+    BT_HDR *p_buf = NULL;
+    bool enqueue_status= false;
+    EventBits_t tx_event_group_val = 0;
+    while (1) {
+        tx_event_group_val = 0;
+        if (size) {
+            if (p_buf == NULL) {
+                write_size = size < BTA_JV_DEF_RFC_MTU ? size : BTA_JV_DEF_RFC_MTU;
+                if ((p_buf = osi_malloc(sizeof(BT_HDR) + write_size)) == NULL) {
+                    BTC_TRACE_ERROR("%s malloc failed!", __func__);
+                    errno = ENOMEM;
+                    sent = -1;
+                    break;
+                }
+                p_buf->offset = 0;
+                p_buf->len = write_size;
+                p_buf->event = 0; // indicate the p_buf be sent count
+                p_buf->layer_specific = 0; // indicate the p_buf whether to be sent, 0 - ready to send; 1 - have sent
+                memcpy((UINT8 *)(p_buf + 1), data + sent, write_size);
+            }
+        } else {
+            break;
+        }
+
+        osi_mutex_lock(&spp_local_param.spp_slot_mutex, OSI_MUTEX_MAX_TIMEOUT);
+        if ((slot = spp_local_param.spp_slots[serial]) != NULL) {
+            tx_len = fixed_queue_length(slot->tx.queue);
+            enqueue_status = fixed_queue_enqueue(slot->tx.queue, p_buf, 0);
+            if (!enqueue_status) {
+                BTC_TRACE_DEBUG("%s tx_len:%d, fd:%d\n", __func__, fixed_queue_length(slot->tx.queue), fd);
+                osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
+                //block untill under water level, be closed or time out
+                tx_event_group_val =
+                    xEventGroupWaitBits(spp_local_param.tx_event_group, SLOT_WRITE_BIT(serial) | SLOT_CLOSE_BIT(serial), pdTRUE,
+                                        pdFALSE, VFS_WRITE_TIMEOUT / portTICK_PERIOD_MS);
+                if (tx_event_group_val & SLOT_CLOSE_BIT(serial)) {
+                    BTC_TRACE_ERROR("%s exit for RFCOMM close, fd:%d!", __func__, fd);
+                    errno = EPIPE;
+                    sent = -1;
+                    break;
+                } else if (tx_event_group_val & SLOT_WRITE_BIT(serial)) {
+                    continue;
+                } else if (tx_event_group_val == 0) {
+                    BTC_TRACE_ERROR("%s exit for time out, fd:%d!", __func__, fd);
+                    errno = EBUSY;
+                    sent = -1;
+                    break;
+                }
+            }
+            if (tx_len == 0) {
+                esp_spp_write(slot->rfc_handle, 0, NULL);
+            }
+            sent += write_size;
+            size -= write_size;
+            p_buf = NULL;
+        } else {
+            osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
+            errno = EPIPE;
+            sent = -1;
+            break;
+        }
+        osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
+    }
+    return sent;
 }
+
 static int spp_vfs_close(int fd)
 {
     if (!is_spp_init()) {
         BTC_TRACE_ERROR("%s SPP have not been init\n", __func__);
+        errno = ESRCH;
         return -1;
     }
+    spp_slot_t *slot = NULL;
     osi_mutex_lock(&spp_local_param.spp_slot_mutex, OSI_MUTEX_MAX_TIMEOUT);
-    spp_slot_t *slot = spp_find_slot_by_fd(fd);
+    slot = spp_find_slot_by_fd(fd);
     if (!slot) {
-        BTC_TRACE_ERROR("%s unable to find RFCOMM slot!", __func__);
         osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
+        BTC_TRACE_ERROR("%s unable to find RFCOMM slot!", __func__);
+        errno = ENOENT;
         return -1;
     }
     esp_spp_disconnect(slot->rfc_handle);
@@ -1093,28 +1328,63 @@ static int spp_vfs_close(int fd)
 
 static ssize_t spp_vfs_read(int fd, void * dst, size_t size)
 {
+    assert(dst != NULL);
     if (!is_spp_init()) {
         BTC_TRACE_ERROR("%s SPP have not been init\n", __func__);
+        errno = ESRCH;
         return -1;
     }
+
+    spp_slot_t *slot = NULL;
+    uint8_t serial = 0;
     osi_mutex_lock(&spp_local_param.spp_slot_mutex, OSI_MUTEX_MAX_TIMEOUT);
-    spp_slot_t *slot = spp_find_slot_by_fd(fd);
+    slot = spp_find_slot_by_fd(fd);
     if (!slot) {
-        BTC_TRACE_ERROR("%s unable to find RFCOMM slot!", __func__);
         osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
+        BTC_TRACE_ERROR("%s unable to find RFCOMM slot!\n", __func__);
+        errno = ENOENT;
         return -1;
     }
+    serial = slot->serial;
+    osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
+
     ssize_t item_size = 0;
     uint16_t count = 0;
-    while (!list_is_empty(slot->incoming_list) && size > 0) {
-        BT_HDR *p_buf = list_front(slot->incoming_list);
+    BT_HDR *p_buf;
+    while (1) {
+        osi_mutex_lock(&spp_local_param.spp_slot_mutex, OSI_MUTEX_MAX_TIMEOUT);
+        if ((slot = spp_local_param.spp_slots[serial]) != NULL) {
+            if (fixed_queue_length(slot->rx.queue) > 0) {
+                // free unused p_buf
+                if ((p_buf = (BT_HDR *)fixed_queue_try_peek_first(slot->rx.queue)) != NULL && p_buf->len == 0) {
+                    osi_free(fixed_queue_dequeue(slot->rx.queue, FIXED_QUEUE_MAX_TIMEOUT));
+                    p_buf = NULL;
+                    count++;
+                }
+                if (size == 0 || (p_buf = (BT_HDR *)fixed_queue_try_peek_first(slot->rx.queue)) == NULL) {
+                    osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
+                    break;
+                }
+            } else {
+                osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
+                break;
+            }
+        } else {
+            osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
+            BTC_TRACE_ERROR("%s peer close, data will be discarded!\n", __func__);
+            errno = EPIPE;
+            item_size = -1;
+            break;
+        }
+        osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
+
         if (p_buf->len <= size) {
             memcpy(dst, p_buf->data + p_buf->offset, p_buf->len);
             size -= p_buf->len;
             item_size += p_buf->len;
             dst += p_buf->len;
-            list_remove(slot->incoming_list, p_buf);
-            count++;
+            p_buf->offset += p_buf->len;
+            p_buf->len = 0; // indicate the p_buf is unused
         } else {
             memcpy(dst, p_buf->data + p_buf->offset, size);
             item_size += size;
@@ -1124,10 +1394,13 @@ static ssize_t spp_vfs_read(int fd, void * dst, size_t size)
         }
     }
     if (count > 0) {
-        BTA_JvRfcommFlowControl(slot->rfc_handle, count);
-        BTC_TRACE_DEBUG("%s give credits:%d\n", __func__, count);
+        osi_mutex_lock(&spp_local_param.spp_slot_mutex, OSI_MUTEX_MAX_TIMEOUT);
+        if ((slot = spp_local_param.spp_slots[serial]) != NULL) {
+            BTA_JvRfcommFlowControl(slot->rfc_handle, count);
+            BTC_TRACE_DEBUG("%s give credits:%d\n", __func__, count);
+        }
+        osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
     }
-    osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
     return item_size;
 }
 

+ 5 - 0
components/bt/host/bluedroid/stack/btu/btu_init.c

@@ -260,3 +260,8 @@ bool BTU_check_queue_is_congest(void)
     return false;
 }
 #endif
+
+int get_btu_work_queue_size(void)
+{
+    return osi_thread_queue_wait_size(btu_thread, 0);
+}

+ 2 - 0
components/bt/host/bluedroid/stack/include/stack/btu.h

@@ -290,6 +290,8 @@ UINT16 BTU_BleAclPktSize(void);
 
 bool btu_task_post(uint32_t sig, void *param, uint32_t timeout);
 
+int get_btu_work_queue_size(void);
+
 /*
 #ifdef __cplusplus
 }