From a0ec1c8291f3127320195a62c1f906301db145e3 Mon Sep 17 00:00:00 2001 From: xiongweichao Date: Wed, 17 Aug 2022 15:30:20 +0800 Subject: [PATCH 1/4] bt: Enter the congestion state when the queue length waiting for the peer to ack is greater than or equal to the L2CAP ERTM tx window size --- .../bluedroid/common/include/common/bt_target.h | 2 +- .../bt/host/bluedroid/stack/l2cap/l2c_fcr.c | 3 +++ .../bt/host/bluedroid/stack/l2cap/l2c_utils.c | 15 +++++++++++++-- 3 files changed, 17 insertions(+), 3 deletions(-) diff --git a/components/bt/host/bluedroid/common/include/common/bt_target.h b/components/bt/host/bluedroid/common/include/common/bt_target.h index 83abc9ba8c..22de4d6c7b 100644 --- a/components/bt/host/bluedroid/common/include/common/bt_target.h +++ b/components/bt/host/bluedroid/common/include/common/bt_target.h @@ -1578,7 +1578,7 @@ /* ERTM Tx window size */ #ifndef RFC_FCR_OPT_TX_WINDOW_SIZE -#define RFC_FCR_OPT_TX_WINDOW_SIZE 20 +#define RFC_FCR_OPT_TX_WINDOW_SIZE 10 #endif /* ERTM Maximum transmissions before disconnecting */ diff --git a/components/bt/host/bluedroid/stack/l2cap/l2c_fcr.c b/components/bt/host/bluedroid/stack/l2cap/l2c_fcr.c index ecf0bd6c68..aafb4b380d 100644 --- a/components/bt/host/bluedroid/stack/l2cap/l2c_fcr.c +++ b/components/bt/host/bluedroid/stack/l2cap/l2c_fcr.c @@ -928,6 +928,9 @@ static BOOLEAN process_reqseq (tL2C_CCB *p_ccb, UINT16 ctrl_word) full_sdus_xmitted++; } osi_free(p_tmp); + if (p_ccb->cong_sent) { + l2cu_check_channel_congestion(p_ccb); + } } /* If we are still in a wait_ack state, do not mess with the timer */ diff --git a/components/bt/host/bluedroid/stack/l2cap/l2c_utils.c b/components/bt/host/bluedroid/stack/l2cap/l2c_utils.c index ea887b036e..06eebe80b2 100644 --- a/components/bt/host/bluedroid/stack/l2cap/l2c_utils.c +++ b/components/bt/host/bluedroid/stack/l2cap/l2c_utils.c @@ -3613,6 +3613,9 @@ void l2cu_set_acl_hci_header (BT_HDR *p_buf, tL2C_CCB *p_ccb) void l2cu_check_channel_congestion (tL2C_CCB *p_ccb) { size_t q_count = fixed_queue_length(p_ccb->xmit_hold_q); +#if (CLASSIC_BT_INCLUDED == TRUE) + size_t q_waiting_ack_count = fixed_queue_length(p_ccb->fcrb.waiting_for_ack_q); +#endif #if (L2CAP_UCD_INCLUDED == TRUE) if ( p_ccb->local_cid == L2CAP_CONNECTIONLESS_CID ) { @@ -3625,7 +3628,11 @@ void l2cu_check_channel_congestion (tL2C_CCB *p_ccb) /* If this channel was congested */ if ( p_ccb->cong_sent ) { /* If the channel is not congested now, tell the app */ - if (q_count <= (p_ccb->buff_quota / 2)) { + if (q_count <= (p_ccb->buff_quota / 2) +#if (CLASSIC_BT_INCLUDED == TRUE) + && (p_ccb->peer_cfg.fcr.mode == L2CAP_FCR_BASIC_MODE || q_waiting_ack_count < p_ccb->our_cfg.fcr.tx_win_sz) +#endif + ) { p_ccb->cong_sent = FALSE; if (p_ccb->p_rcb && p_ccb->p_rcb->api.pL2CA_CongestionStatus_Cb) { L2CAP_TRACE_DEBUG ("L2CAP - Calling CongestionStatus_Cb (FALSE), CID: 0x%04x xmit_hold_q.count: %u buff_quota: %u", @@ -3664,7 +3671,11 @@ void l2cu_check_channel_congestion (tL2C_CCB *p_ccb) } else { tL2C_LCB *p_lcb = p_ccb->p_lcb; /* If this channel was not congested but it is congested now, tell the app */ - if (q_count > p_ccb->buff_quota || (p_lcb && (p_lcb->link_xmit_data_q) && (list_length(p_lcb->link_xmit_data_q) + q_count) > p_ccb->buff_quota)) { + if (q_count > p_ccb->buff_quota || (p_lcb && (p_lcb->link_xmit_data_q) && (list_length(p_lcb->link_xmit_data_q) + q_count) > p_ccb->buff_quota) +#if (CLASSIC_BT_INCLUDED == TRUE) + || (p_ccb->peer_cfg.fcr.mode != L2CAP_FCR_BASIC_MODE && q_waiting_ack_count >= p_ccb->our_cfg.fcr.tx_win_sz) +#endif + ) { p_ccb->cong_sent = TRUE; if (p_ccb->p_rcb && p_ccb->p_rcb->api.pL2CA_CongestionStatus_Cb) { L2CAP_TRACE_DEBUG ("L2CAP - Calling CongestionStatus_Cb (TRUE),CID:0x%04x,XmitQ:%u,Quota:%u", From ea41a21b0ed65b01a21fe785c28b8bec8df87de7 Mon Sep 17 00:00:00 2001 From: xiongweichao Date: Mon, 19 Sep 2022 20:20:22 +0800 Subject: [PATCH 2/4] bt: Split SPP application layer data packets according to the MTU of the peer --- .../bluedroid/bta/include/bta/bta_jv_api.h | 2 + .../bt/host/bluedroid/bta/jv/bta_jv_act.c | 5 ++ .../bluedroid/btc/profile/std/spp/btc_spp.c | 7 ++- .../bluedroid/stack/include/stack/port_api.h | 8 +++ .../bt/host/bluedroid/stack/rfcomm/port_rfc.c | 49 +++++++++++++------ 5 files changed, 53 insertions(+), 18 deletions(-) diff --git a/components/bt/host/bluedroid/bta/include/bta/bta_jv_api.h b/components/bt/host/bluedroid/bta/include/bta/bta_jv_api.h index 8564b07399..f7293f88e6 100644 --- a/components/bt/host/bluedroid/bta/include/bta/bta_jv_api.h +++ b/components/bt/host/bluedroid/bta/include/bta/bta_jv_api.h @@ -286,6 +286,7 @@ typedef struct { /* data associated with BTA_JV_RFCOMM_OPEN_EVT */ typedef struct { tBTA_JV_STATUS status; /* Whether the operation succeeded or failed. */ + UINT16 peer_mtu; /* Max MTU that port can send */ UINT32 handle; /* The connection handle */ BD_ADDR rem_bda; /* The peer address */ } tBTA_JV_RFCOMM_OPEN; @@ -293,6 +294,7 @@ typedef struct { /* data associated with BTA_JV_RFCOMM_SRV_OPEN_EVT */ typedef struct { tBTA_JV_STATUS status; /* Whether the operation succeeded or failed. */ + UINT16 peer_mtu; /* Max MTU that port can send */ UINT32 handle; /* The connection handle */ UINT32 new_listen_handle; /* The new listen handle */ BD_ADDR rem_bda; /* The peer address */ diff --git a/components/bt/host/bluedroid/bta/jv/bta_jv_act.c b/components/bt/host/bluedroid/bta/jv/bta_jv_act.c index f3106600a1..da3a1225f5 100644 --- a/components/bt/host/bluedroid/bta/jv/bta_jv_act.c +++ b/components/bt/host/bluedroid/bta/jv/bta_jv_act.c @@ -1685,6 +1685,7 @@ static void bta_jv_port_mgmt_cl_cback(UINT32 code, UINT16 port_handle, void* dat BD_ADDR rem_bda = {0}; UINT16 lcid; tBTA_JV_RFCOMM_CBACK *p_cback; /* the callback function */ + tPORT_MGMT_CL_CALLBACK_ARG *p_mgmt_cb_arg = (tPORT_MGMT_CL_CALLBACK_ARG *)data; APPL_TRACE_DEBUG( "bta_jv_port_mgmt_cl_cback:code:%d, port_handle%d", code, port_handle); if (NULL == p_cb || NULL == p_cb->p_cback) { @@ -1701,6 +1702,9 @@ static void bta_jv_port_mgmt_cl_cback(UINT32 code, UINT16 port_handle, void* dat evt_data.rfc_open.status = BTA_JV_SUCCESS; bdcpy(evt_data.rfc_open.rem_bda, rem_bda); p_pcb->state = BTA_JV_ST_CL_OPEN; + if (p_mgmt_cb_arg) { + evt_data.rfc_open.peer_mtu = p_mgmt_cb_arg->peer_mtu; + } p_cb->p_cback(BTA_JV_RFCOMM_OPEN_EVT, &evt_data, p_pcb->user_data); } else { evt_data.rfc_close.handle = p_pcb->handle; @@ -1981,6 +1985,7 @@ static void bta_jv_port_mgmt_sr_cback(UINT32 code, UINT16 port_handle, void *dat } evt_data.rfc_srv_open.handle = p_pcb->handle; evt_data.rfc_srv_open.status = BTA_JV_SUCCESS; + evt_data.rfc_srv_open.peer_mtu = p_mgmt_cb_arg->peer_mtu; bdcpy(evt_data.rfc_srv_open.rem_bda, rem_bda); tBTA_JV_PCB *p_pcb_new_listen = bta_jv_add_rfc_port(p_cb, p_pcb); if (p_pcb_new_listen) { diff --git a/components/bt/host/bluedroid/btc/profile/std/spp/btc_spp.c b/components/bt/host/bluedroid/btc/profile/std/spp/btc_spp.c index db1607ff38..5651213a08 100644 --- a/components/bt/host/bluedroid/btc/profile/std/spp/btc_spp.c +++ b/components/bt/host/bluedroid/btc/profile/std/spp/btc_spp.c @@ -52,8 +52,8 @@ typedef struct { uint8_t serial; uint8_t scn; uint8_t max_session; + uint16_t mtu; uint32_t id; - uint32_t mtu;//unused uint32_t sdp_handle; uint32_t rfc_handle; uint32_t rfc_port_handle; @@ -133,6 +133,7 @@ static spp_slot_t *spp_malloc_slot(void) (*slot)->fd = -1; (*slot)->connected = false; (*slot)->is_server = false; + (*slot)->mtu = 0; (*slot)->write_data = NULL; (*slot)->close_alarm = NULL; /* clear the old event bits */ @@ -333,6 +334,7 @@ static void *btc_spp_rfcomm_inter_cb(tBTA_JV_EVT event, tBTA_JV *p_data, void *u slot_new->max_session = slot->max_session; strcpy(slot_new->service_name, slot->service_name); slot_new->sdp_handle = slot->sdp_handle; + slot_new->mtu = p_data->rfc_srv_open.peer_mtu; slot_new->rfc_handle = p_data->rfc_srv_open.handle; slot_new->rfc_port_handle = BTA_JvRfcommGetPortHdl(slot_new->rfc_handle); BTA_JvSetPmProfile(p_data->rfc_srv_open.handle, BTA_JV_PM_ALL, BTA_JV_CONN_OPEN); @@ -375,6 +377,7 @@ static void *btc_spp_rfcomm_inter_cb(tBTA_JV_EVT event, tBTA_JV *p_data, void *u } slot->connected = true; slot->rfc_handle = p_data->rfc_open.handle; + slot->mtu = p_data->rfc_open.peer_mtu; slot->rfc_port_handle = BTA_JvRfcommGetPortHdl(p_data->rfc_open.handle); BTA_JvSetPmProfile(p_data->rfc_open.handle, BTA_JV_PM_ID_1, BTA_JV_CONN_OPEN); break; @@ -1384,7 +1387,7 @@ static ssize_t spp_vfs_write(int fd, const void * data, size_t size) 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; + write_size = size < slot->mtu ? size : slot->mtu; if ((p_buf = osi_malloc(sizeof(BT_HDR) + write_size)) == NULL) { BTC_TRACE_ERROR("%s malloc failed!", __func__); errno = ENOMEM; diff --git a/components/bt/host/bluedroid/stack/include/stack/port_api.h b/components/bt/host/bluedroid/stack/include/stack/port_api.h index fb9e7574ba..928f8eb962 100644 --- a/components/bt/host/bluedroid/stack/include/stack/port_api.h +++ b/components/bt/host/bluedroid/stack/include/stack/port_api.h @@ -113,8 +113,16 @@ typedef void (tPORT_MGMT_CALLBACK) (UINT32 code, UINT16 port_handle, void* data) typedef struct { BOOLEAN accept; /* If upper layer accepts the incoming connection */ BOOLEAN ignore_rfc_state; /* If need to ignore rfc state for PORT_CheckConnection */ + UINT16 peer_mtu; /* Max MTU that port can send */ } tPORT_MGMT_SR_CALLBACK_ARG; +/** + * Define the client port manage callback function argument + */ +typedef struct { + UINT16 peer_mtu; /* Max MTU that port can send */ +} tPORT_MGMT_CL_CALLBACK_ARG; + /* ** Define events that registered application can receive in the callback */ diff --git a/components/bt/host/bluedroid/stack/rfcomm/port_rfc.c b/components/bt/host/bluedroid/stack/rfcomm/port_rfc.c index ddcef1bb7c..c925ed9cb5 100644 --- a/components/bt/host/bluedroid/stack/rfcomm/port_rfc.c +++ b/components/bt/host/bluedroid/stack/rfcomm/port_rfc.c @@ -427,9 +427,11 @@ void PORT_ParNegCnf (tRFC_MCB *p_mcb, UINT8 dlci, UINT16 mtu, UINT8 cl, UINT8 k) void PORT_DlcEstablishInd (tRFC_MCB *p_mcb, UINT8 dlci, UINT16 mtu) { tPORT *p_port = port_find_mcb_dlci_port (p_mcb, dlci); - tPORT_MGMT_SR_CALLBACK_ARG mgmt_cb_arg = { + tPORT_MGMT_CL_CALLBACK_ARG cl_mgmt_cb_arg = {0}; + tPORT_MGMT_SR_CALLBACK_ARG sr_mgmt_cb_arg = { .accept = TRUE, .ignore_rfc_state = FALSE, + .peer_mtu = 0, }; RFCOMM_TRACE_DEBUG ("PORT_DlcEstablishInd p_mcb:%p, dlci:%d mtu:%di, p_port:%p", p_mcb, dlci, mtu, p_port); @@ -464,22 +466,29 @@ void PORT_DlcEstablishInd (tRFC_MCB *p_mcb, UINT8 dlci, UINT16 mtu) } if (p_port->p_mgmt_callback) { - /** - * @note - * 1. The manage callback function may change the value of accept in mgmt_cb_arg. - * 2. Use mgmt_cb_arg.ignore_rfc_state to work around the issue caused by sending - * RFCOMM establish response after the manage callback function. - */ - mgmt_cb_arg.ignore_rfc_state = TRUE; - p_port->p_mgmt_callback (PORT_SUCCESS, p_port->inx, &mgmt_cb_arg); + if (p_port->is_server) { + sr_mgmt_cb_arg.peer_mtu = p_port->peer_mtu; + /** + * @note + * 1. The manage callback function may change the value of accept in mgmt_cb_arg. + * 2. Use mgmt_cb_arg.ignore_rfc_state to work around the issue caused by sending + * RFCOMM establish response after the manage callback function. + */ + sr_mgmt_cb_arg.ignore_rfc_state = TRUE; + p_port->p_mgmt_callback (PORT_SUCCESS, p_port->inx, &sr_mgmt_cb_arg); + + if (!sr_mgmt_cb_arg.accept) { + RFCOMM_DlcEstablishRsp(p_mcb, dlci, 0, RFCOMM_LOW_RESOURCES); + return; + } + } else { + cl_mgmt_cb_arg.peer_mtu = p_port->peer_mtu; + p_port->p_mgmt_callback (PORT_SUCCESS, p_port->inx, &cl_mgmt_cb_arg); + } } - if (mgmt_cb_arg.accept) { - RFCOMM_DlcEstablishRsp(p_mcb, dlci, p_port->mtu, RFCOMM_SUCCESS); - p_port->state = PORT_STATE_OPENED; - } else { - RFCOMM_DlcEstablishRsp(p_mcb, dlci, 0, RFCOMM_LOW_RESOURCES); - } + RFCOMM_DlcEstablishRsp(p_mcb, dlci, p_port->mtu, RFCOMM_SUCCESS); + p_port->state = PORT_STATE_OPENED; } @@ -496,6 +505,8 @@ void PORT_DlcEstablishInd (tRFC_MCB *p_mcb, UINT8 dlci, UINT16 mtu) void PORT_DlcEstablishCnf (tRFC_MCB *p_mcb, UINT8 dlci, UINT16 mtu, UINT16 result) { tPORT *p_port = port_find_mcb_dlci_port (p_mcb, dlci); + tPORT_MGMT_SR_CALLBACK_ARG sr_mgmt_cb_arg = {0}; + tPORT_MGMT_CL_CALLBACK_ARG cl_mgmt_cb_arg = {0}; RFCOMM_TRACE_EVENT ("PORT_DlcEstablishCnf dlci:%d mtu:%d result:%d", dlci, mtu, result); @@ -522,7 +533,13 @@ void PORT_DlcEstablishCnf (tRFC_MCB *p_mcb, UINT8 dlci, UINT16 mtu, UINT16 resul } if (p_port->p_mgmt_callback) { - p_port->p_mgmt_callback (PORT_SUCCESS, p_port->inx, NULL); + if (p_port->is_server) { + sr_mgmt_cb_arg.peer_mtu = p_port->peer_mtu; + p_port->p_mgmt_callback (PORT_SUCCESS, p_port->inx, &sr_mgmt_cb_arg); + } else { + cl_mgmt_cb_arg.peer_mtu = p_port->peer_mtu; + p_port->p_mgmt_callback (PORT_SUCCESS, p_port->inx, &cl_mgmt_cb_arg); + } } p_port->state = PORT_STATE_OPENED; From 7885f805979265024298afcfd807b59bfa39ba49 Mon Sep 17 00:00:00 2001 From: xiongweichao Date: Tue, 27 Sep 2022 15:12:35 +0800 Subject: [PATCH 3/4] bt: Replaced the tx queue in SPP VFS mode with ringbuffer --- components/bt/host/bluedroid/Kconfig.in | 9 + .../btc/profile/std/include/btc_spp.h | 2 - .../bluedroid/btc/profile/std/spp/btc_spp.c | 229 ++++++++++-------- .../include/common/bluedroid_user_config.h | 6 + .../common/include/common/bt_target.h | 4 + 5 files changed, 147 insertions(+), 103 deletions(-) diff --git a/components/bt/host/bluedroid/Kconfig.in b/components/bt/host/bluedroid/Kconfig.in index 46e619041f..cf6f015f70 100644 --- a/components/bt/host/bluedroid/Kconfig.in +++ b/components/bt/host/bluedroid/Kconfig.in @@ -61,6 +61,15 @@ config BT_SPP_ENABLED help This enables the Serial Port Profile +config BT_SPP_SEND_BUF_DEFAULT + int "SPP default send buffer size" + depends on BT_SPP_ENABLED + range 100 10000 + default 4000 + help + Sets the default send buffer size for new SPP channels. Setting a smaller + default SNDBUF size can save some memory, but may decrease performance. + config BT_L2CAP_ENABLED bool "BT L2CAP" depends on BT_CLASSIC_ENABLED diff --git a/components/bt/host/bluedroid/btc/profile/std/include/btc_spp.h b/components/bt/host/bluedroid/btc/profile/std/include/btc_spp.h index 0615b456c4..7f0f9e81b4 100644 --- a/components/bt/host/bluedroid/btc/profile/std/include/btc_spp.h +++ b/components/bt/host/bluedroid/btc/profile/std/include/btc_spp.h @@ -18,8 +18,6 @@ #define ESP_SPP_MAX_SESSION BTA_JV_MAX_RFC_SR_SESSION #define ESP_SPP_SERVER_NAME_MAX 32 -#define ESP_SPP_RINGBUF_SIZE 1000 - #define BTC_SPP_INVALID_SCN 0x00 typedef enum { diff --git a/components/bt/host/bluedroid/btc/profile/std/spp/btc_spp.c b/components/bt/host/bluedroid/btc/profile/std/spp/btc_spp.c index 5651213a08..fdc57f3db7 100644 --- a/components/bt/host/bluedroid/btc/profile/std/spp/btc_spp.c +++ b/components/bt/host/bluedroid/btc/profile/std/spp/btc_spp.c @@ -49,10 +49,12 @@ typedef struct { typedef struct { bool connected; bool is_server; + bool is_writing; uint8_t serial; uint8_t scn; uint8_t max_session; uint16_t mtu; + uint16_t write_data_len; uint32_t id; uint32_t sdp_handle; uint32_t rfc_handle; @@ -64,7 +66,10 @@ typedef struct { esp_spp_sec_t security; esp_bd_addr_t addr; slot_data_t rx; - slot_data_t tx; + union { + slot_data_t tx; + RingbufHandle_t ringbuf_write; + }; uint8_t service_uuid[16]; char service_name[ESP_SPP_SERVER_NAME_MAX + 1]; } spp_slot_t; @@ -135,6 +140,8 @@ static spp_slot_t *spp_malloc_slot(void) (*slot)->is_server = false; (*slot)->mtu = 0; (*slot)->write_data = NULL; + (*slot)->write_data_len = 0; + (*slot)->is_writing = false; (*slot)->close_alarm = NULL; /* clear the old event bits */ if (spp_local_param.tx_event_group) { @@ -146,12 +153,18 @@ static spp_slot_t *spp_malloc_slot(void) err_no = 1; goto err; } - if (init_slot_data(&(*slot)->tx, SLOT_TX_QUEUE_SIZE)) { - BTC_TRACE_ERROR("%s unable to malloc tx queue!", __func__); - err_no = 2; - goto err; - } - if (spp_local_param.spp_mode == ESP_SPP_MODE_VFS) { + if (spp_local_param.spp_mode == ESP_SPP_MODE_CB) { + if (init_slot_data(&(*slot)->tx, SLOT_TX_QUEUE_SIZE)) { + BTC_TRACE_ERROR("%s unable to malloc tx queue!", __func__); + err_no = 2; + goto err; + } + } else { + if (((*slot)->ringbuf_write = xRingbufferCreate(BTC_SPP_SEND_BUF_DEFAULT, RINGBUF_TYPE_BYTEBUF)) == NULL) { + BTC_TRACE_ERROR("%s write ringbuffer create error!", __func__); + err_no = 2; + goto err; + } 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; @@ -166,7 +179,9 @@ static spp_slot_t *spp_malloc_slot(void) err: switch (err_no) { case 3: - free_slot_data(&(*slot)->tx); + if (spp_local_param.spp_mode == ESP_SPP_MODE_VFS) { + vRingbufferDelete((*slot)->ringbuf_write); + } case 2: free_slot_data(&(*slot)->rx); case 1: @@ -239,7 +254,7 @@ static void close_timeout_handler(void *arg) status = btc_transfer_context(&msg, arg, sizeof(tBTA_JV), NULL); if (arg) { - free(arg); + osi_free(arg); } if (status != BT_STATUS_SUCCESS) { @@ -256,8 +271,10 @@ static void spp_free_slot(spp_slot_t *slot) if (spp_local_param.spp_mode == ESP_SPP_MODE_VFS) { (void) esp_vfs_unregister_fd(spp_local_param.spp_vfs_id, slot->fd); xEventGroupSetBits(spp_local_param.tx_event_group, SLOT_CLOSE_BIT(slot->serial)); + vRingbufferDelete(slot->ringbuf_write); + } else { + free_slot_data(&slot->tx); } - free_slot_data(&slot->tx); free_slot_data(&slot->rx); if (slot->close_alarm) { osi_alarm_free(slot->close_alarm); @@ -734,7 +751,7 @@ static void btc_spp_stop_srv(btc_spp_args_t *arg) esp_spp_status_t ret = ESP_SPP_SUCCESS; bool is_remove_all = false; uint8_t i, j, srv_cnt = 0; - uint8_t *srv_scn_arr = osi_malloc(MAX_RFC_PORTS); + uint8_t *srv_scn_arr = NULL; if (arg->stop_srv.scn == BTC_SPP_INVALID_SCN) { is_remove_all = true; } @@ -745,6 +762,7 @@ static void btc_spp_stop_srv(btc_spp_args_t *arg) ret = ESP_SPP_NEED_INIT; break; } + srv_scn_arr = osi_malloc(MAX_RFC_PORTS); if (srv_scn_arr == NULL) { BTC_TRACE_ERROR("%s malloc srv_scn_arr failed\n", __func__); ret = ESP_SPP_NO_RESOURCE; @@ -837,6 +855,7 @@ static void btc_spp_stop_srv(btc_spp_args_t *arg) static void btc_spp_write(btc_spp_args_t *arg) { esp_spp_status_t ret = ESP_SPP_SUCCESS; + do { if (!is_spp_init()) { BTC_TRACE_ERROR("%s SPP have not been init\n", __func__); @@ -857,18 +876,23 @@ static void btc_spp_write(btc_spp_args_t *arg) break; } if (spp_local_param.spp_mode == ESP_SPP_MODE_VFS) { - 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); + if (slot->is_writing) { + osi_mutex_unlock(&spp_local_param.spp_slot_mutex); + return; + } + size_t item_size = 0; + uint8_t *data = xRingbufferReceiveUpTo(slot->ringbuf_write, &item_size, 0, slot->mtu); + if (item_size > 0) { + slot->write_data = data; + slot->write_data_len = item_size; + slot->is_writing = true; + BTA_JvRfcommWrite(arg->write.handle, slot->id, item_size, data); } } else { 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); @@ -1066,37 +1090,44 @@ void btc_spp_cb_handler(btc_msg_t *msg) } } else { if (slot) { - BT_HDR *p_buf; + size_t item_size = 0; + size_t items_waiting = 0; serial = slot->serial; - if ((p_buf = fixed_queue_try_peek_first(slot->tx.queue)) == NULL) { - osi_mutex_unlock(&spp_local_param.spp_slot_mutex); - break; - } 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)); - } + vRingbufferReturnItem(slot->ringbuf_write,slot->write_data); + slot->write_data = NULL; + slot->is_writing = false; + slot->write_data_len = 0; + vRingbufferGetInfo(slot->ringbuf_write, NULL, NULL, NULL, NULL, &items_waiting); + if (BTC_SPP_SEND_BUF_DEFAULT > items_waiting) { + xEventGroupSetBits(spp_local_param.tx_event_group, SLOT_WRITE_BIT(serial)); } - - 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); + if (items_waiting == 0) { + osi_mutex_unlock(&spp_local_param.spp_slot_mutex); + break; + } + if (!p_data->rfc_write.cong) { + uint8_t *data = xRingbufferReceiveUpTo(slot->ringbuf_write, &item_size, 0, slot->mtu); + if (item_size > 0) { + slot->write_data = data; + slot->write_data_len = item_size; + slot->is_writing = true; + BTA_JvRfcommWrite(p_data->rfc_write.handle, slot->id, item_size, data); + } } } 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, + BTC_TRACE_ERROR("PORT_WriteDataCO failed p_buf:%p, handle:%d\n", slot->write_data, p_data->rfc_write.handle); } else { // need rewrite - p_buf->layer_specific = 0; + if (!p_data->rfc_write.cong && slot->connected) { + slot->is_writing = true; + BTA_JvRfcommWrite(p_data->rfc_write.handle, slot->id, slot->write_data_len, slot->write_data); + } else { + slot->is_writing = false; + } } } } @@ -1188,12 +1219,19 @@ void btc_spp_cb_handler(btc_msg_t *msg) BTC_TRACE_ERROR("%s unable to find RFCOMM slot, event:%d!", __func__, event); break; } - 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); + if (!p_data->rfc_cong.cong && !slot->is_writing) { + if (slot->write_data == NULL && slot->write_data_len == 0) { + size_t item_size = 0; + uint8_t *data = xRingbufferReceiveUpTo(slot->ringbuf_write, &item_size, 0, slot->mtu); + if (item_size > 0) { + slot->write_data = data; + slot->write_data_len = item_size; + slot->is_writing = true; + BTA_JvRfcommWrite(p_data->rfc_cong.handle, slot->id, item_size, data); + } + } else { + slot->is_writing = true; + BTA_JvRfcommWrite(p_data->rfc_cong.handle, slot->id, slot->write_data_len, slot->write_data); } } osi_mutex_unlock(&spp_local_param.spp_slot_mutex); @@ -1351,7 +1389,6 @@ esp_err_t spp_send_data_to_btc(uint32_t handle, int len, uint8_t *p_data, esp_sp == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); } - static ssize_t spp_vfs_write(int fd, const void * data, size_t size) { assert(data != NULL); @@ -1378,77 +1415,67 @@ static ssize_t spp_vfs_write(int fd, const void * data, size_t size) serial = slot->serial; osi_mutex_unlock(&spp_local_param.spp_slot_mutex); - ssize_t sent = 0, write_size = 0; - size_t tx_len; - BT_HDR *p_buf = NULL; - bool enqueue_status= false; + ssize_t sent = 0; + size_t items_waiting = 0; + size_t item_size = 0; EventBits_t tx_event_group_val = 0; - while (1) { + BaseType_t done = false; + while (size) { tx_event_group_val = 0; - if (size) { - if (p_buf == NULL) { - write_size = size < slot->mtu ? size : slot->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)) { + slot = spp_local_param.spp_slots[serial]; + if (slot && slot->connected) { + items_waiting = 0; + item_size = 0; + vRingbufferGetInfo(slot->ringbuf_write, NULL, NULL, NULL, NULL, &items_waiting); + if (items_waiting < BTC_SPP_SEND_BUF_DEFAULT) { + if ((BTC_SPP_SEND_BUF_DEFAULT - items_waiting) > size) { + item_size = size; + done = xRingbufferSend(slot->ringbuf_write, (void *)data + sent, item_size, 0); + } else { + item_size = BTC_SPP_SEND_BUF_DEFAULT - items_waiting; + done = xRingbufferSend(slot->ringbuf_write, (void *)data + sent, item_size, 0); + } + + if (done) { + sent += item_size; + size -= item_size; + if (slot->write_data == NULL) { + spp_send_data_to_btc(slot->rfc_handle, 0, NULL, ESP_SPP_MODE_VFS); + } + osi_mutex_unlock(&spp_local_param.spp_slot_mutex); 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) { - spp_send_data_to_btc(slot->rfc_handle, 0, NULL, ESP_SPP_MODE_VFS); + + BTC_TRACE_DEBUG("%s items_waiting:%d, fd:%d\n", __func__, items_waiting, 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; } - 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); } - //errors occur, need to cleanup - if (p_buf) { - osi_free(p_buf); - p_buf = NULL; - } return sent; } diff --git a/components/bt/host/bluedroid/common/include/common/bluedroid_user_config.h b/components/bt/host/bluedroid/common/include/common/bluedroid_user_config.h index 4362cd10fd..7a017f8cc8 100644 --- a/components/bt/host/bluedroid/common/include/common/bluedroid_user_config.h +++ b/components/bt/host/bluedroid/common/include/common/bluedroid_user_config.h @@ -296,6 +296,12 @@ #define UC_BT_HFP_WBS_ENABLE FALSE #endif +#ifdef CONFIG_BT_SPP_SEND_BUF_DEFAULT +#define UC_BT_SPP_SEND_BUF_DEFAULT CONFIG_BT_SPP_SEND_BUF_DEFAULT +#else +#define UC_BT_SPP_SEND_BUF_DEFAULT 0 +#endif + /********************************************************** * Memory reference **********************************************************/ diff --git a/components/bt/host/bluedroid/common/include/common/bt_target.h b/components/bt/host/bluedroid/common/include/common/bt_target.h index 22de4d6c7b..66a0e08181 100644 --- a/components/bt/host/bluedroid/common/include/common/bt_target.h +++ b/components/bt/host/bluedroid/common/include/common/bt_target.h @@ -351,6 +351,10 @@ #define SBC_ENC_INCLUDED FALSE #endif +#ifndef BTC_SPP_SEND_BUF_DEFAULT +#define BTC_SPP_SEND_BUF_DEFAULT UC_BT_SPP_SEND_BUF_DEFAULT +#endif + /****************************************************************************** ** ** BTA-layer components From 01a67d001e771bec382452391a77c1834168fe8b Mon Sep 17 00:00:00 2001 From: xiongweichao Date: Tue, 27 Sep 2022 16:25:50 +0800 Subject: [PATCH 4/4] bt: Keep the maximum number of credits unchanged --- .../bluedroid/bta/include/bta/bta_jv_api.h | 1 + .../bluedroid/btc/profile/std/spp/btc_spp.c | 21 ++++++++++++------- 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/components/bt/host/bluedroid/bta/include/bta/bta_jv_api.h b/components/bt/host/bluedroid/bta/include/bta/bta_jv_api.h index f7293f88e6..42c4f35e44 100644 --- a/components/bt/host/bluedroid/bta/include/bta/bta_jv_api.h +++ b/components/bt/host/bluedroid/bta/include/bta/bta_jv_api.h @@ -53,6 +53,7 @@ typedef UINT8 tBTA_JV_STATUS; #define BTA_JV_MAX_L2C_CONN GAP_MAX_CONNECTIONS /* GAP handle is used as index, hence do not change this value */ #define BTA_JV_MAX_SCN PORT_MAX_RFC_PORTS /* same as BTM_MAX_SCN (in btm_int.h) */ #define BTA_JV_MAX_RFC_CONN MAX_RFC_PORTS +#define BTA_JV_MAX_CREDIT_NUM PORT_RX_BUF_HIGH_WM #ifndef BTA_JV_DEF_RFC_MTU #define BTA_JV_DEF_RFC_MTU (3*330) diff --git a/components/bt/host/bluedroid/btc/profile/std/spp/btc_spp.c b/components/bt/host/bluedroid/btc/profile/std/spp/btc_spp.c index fdc57f3db7..2cc05382fb 100644 --- a/components/bt/host/bluedroid/btc/profile/std/spp/btc_spp.c +++ b/components/bt/host/bluedroid/btc/profile/std/spp/btc_spp.c @@ -54,6 +54,7 @@ typedef struct { uint8_t scn; uint8_t max_session; uint16_t mtu; + uint16_t credit_rx; uint16_t write_data_len; uint32_t id; uint32_t sdp_handle; @@ -139,6 +140,7 @@ static spp_slot_t *spp_malloc_slot(void) (*slot)->connected = false; (*slot)->is_server = false; (*slot)->mtu = 0; + (*slot)->credit_rx = BTA_JV_MAX_CREDIT_NUM; (*slot)->write_data = NULL; (*slot)->write_data_len = 0; (*slot)->is_writing = false; @@ -1277,6 +1279,9 @@ void btc_spp_cb_handler(btc_msg_t *msg) } } if (count != 0) { + osi_mutex_lock(&spp_local_param.spp_slot_mutex, OSI_MUTEX_MAX_TIMEOUT); + slot->credit_rx += count; + osi_mutex_unlock(&spp_local_param.spp_slot_mutex); BTA_JvRfcommFlowControl(p_data->data_ind.handle, count); BTC_TRACE_DEBUG("%s give credits:%d\n", __func__, count); } @@ -1342,16 +1347,17 @@ int bta_co_rfc_data_incoming(void *user_data, BT_HDR *p_buf) 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 (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 { 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 - } + } + if (--slot->credit_rx == 0) { + 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 + } + if (slot->credit_rx > BTA_JV_MAX_CREDIT_NUM) { + BTC_TRACE_WARNING("%s credit %d", __func__, slot->credit_rx); + assert(0); } osi_mutex_unlock(&spp_local_param.spp_slot_mutex); return ret; @@ -1579,6 +1585,7 @@ static ssize_t spp_vfs_read(int fd, void * dst, size_t size) } if (count > 0) { osi_mutex_lock(&spp_local_param.spp_slot_mutex, OSI_MUTEX_MAX_TIMEOUT); + slot->credit_rx += count; 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);