diff --git a/components/bt/host/bluedroid/Kconfig.in b/components/bt/host/bluedroid/Kconfig.in index d03f182b11..1666865f4b 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..44dd4ed664 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); @@ -1378,77 +1416,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