From 81717022930cc7946822de6c6b238abb8e95a5f9 Mon Sep 17 00:00:00 2001 From: liqigan Date: Tue, 18 Aug 2020 22:25:11 +0800 Subject: [PATCH 1/3] add event when calling spp API failed --- .../bluedroid/api/include/api/esp_spp_api.h | 5 +- .../bluedroid/btc/profile/std/spp/btc_spp.c | 526 +++++++++++------- 2 files changed, 323 insertions(+), 208 deletions(-) diff --git a/components/bt/host/bluedroid/api/include/api/esp_spp_api.h b/components/bt/host/bluedroid/api/include/api/esp_spp_api.h index 8f1c060896..e1fe47c912 100644 --- a/components/bt/host/bluedroid/api/include/api/esp_spp_api.h +++ b/components/bt/host/bluedroid/api/include/api/esp_spp_api.h @@ -27,7 +27,10 @@ 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 set pm control block */ + ESP_SPP_NEED_INIT, /*!< SPP module shall init first */ + ESP_SPP_NEED_UNINIT, /*!< SPP module shall uninit first */ + ESP_SPP_NO_CONNECTION, /*!< connection may have been closed */ } esp_spp_status_t; /* Security Setting Mask, Suggest to use ESP_SPP_SEC_NONE, ESP_SPP_SEC_AUTHORIZE or ESP_SPP_SEC_AUTHENTICATE only.*/ 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 1b775a727d..f51f961b17 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 @@ -205,6 +205,7 @@ static void *btc_spp_rfcomm_inter_cb(tBTA_JV_EVT event, tBTA_JV *p_data, void *u slot = spp_find_slot_by_id(id); if (!slot) { BTC_TRACE_ERROR("%s unable to find RFCOMM slot!", __func__); + p_data->rfc_start.status = ESP_SPP_NO_CONNECTION; break; } slot->rfc_handle = p_data->rfc_start.handle; @@ -214,6 +215,7 @@ static void *btc_spp_rfcomm_inter_cb(tBTA_JV_EVT event, tBTA_JV *p_data, void *u slot = p_data->rfc_srv_open.handle ? spp_find_slot_by_id(id) : spp_find_slot_by_scn((uint32_t)user_data); if (!slot) { BTC_TRACE_ERROR("%s unable to find RFCOMM slot!", __func__); + p_data->rfc_srv_open.status = ESP_SPP_NO_CONNECTION; break; } @@ -230,6 +232,7 @@ static void *btc_spp_rfcomm_inter_cb(tBTA_JV_EVT event, tBTA_JV *p_data, void *u slot_new = spp_malloc_slot(); if (!slot_new) { BTC_TRACE_ERROR("%s unable to malloc RFCOMM slot!", __func__); + p_data->rfc_srv_open.status = ESP_SPP_NO_RESOURCE; break; } new_user_data = (void *)(uintptr_t)slot_new->id; @@ -247,6 +250,7 @@ static void *btc_spp_rfcomm_inter_cb(tBTA_JV_EVT event, tBTA_JV *p_data, void *u slot = spp_find_slot_by_id(id); if (!slot) { BTC_TRACE_ERROR("%s unable to find RFCOMM slot!", __func__); + p_data->rfc_open.status = ESP_SPP_NO_CONNECTION; break; } slot->connected = TRUE; @@ -258,6 +262,7 @@ static void *btc_spp_rfcomm_inter_cb(tBTA_JV_EVT event, tBTA_JV *p_data, void *u slot = spp_find_slot_by_id(id); if (!slot) { BTC_TRACE_ERROR("%s unable to find RFCOMM slot!", __func__); + p_data->rfc_close.status = ESP_SPP_NO_CONNECTION; break; } if (slot->connected && p_data->rfc_close.port_status != PORT_LOCAL_CLOSED) { @@ -276,6 +281,7 @@ static void *btc_spp_rfcomm_inter_cb(tBTA_JV_EVT event, tBTA_JV *p_data, void *u spp_free_slot(slot); } else { BTC_TRACE_ERROR("%s unable to find RFCOMM slot!", __func__); + p_data->free_scn.status = ESP_SPP_NO_CONNECTION; } osi_free(user_data); } @@ -369,219 +375,317 @@ static void btc_spp_dm_inter_cb(tBTA_JV_EVT event, tBTA_JV *p_data, void *user_d static void btc_spp_init(btc_spp_args_t *arg) { - if (is_spp_init()) { - esp_spp_cb_param_t param; - param.init.status = ESP_SPP_FAILURE; - btc_spp_cb_to_app(ESP_SPP_INIT_EVT, ¶m); - BTC_TRACE_ERROR("%s SPP has been initiated, shall uninit first!", __func__); - return; - } + esp_spp_status_t ret = ESP_SPP_SUCCESS; + do { + if (is_spp_init()) { + BTC_TRACE_ERROR("%s SPP has been initiated, shall uninit first!", __func__); + ret = ESP_SPP_NEED_UNINIT; + break; + } #if SPP_DYNAMIC_MEMORY == TRUE - if ((spp_local_param_ptr = (spp_local_param_t *)osi_malloc(sizeof(spp_local_param_t))) == NULL) { - BTC_TRACE_ERROR("%s malloc failed\n", __func__); - return; - } - memset((void *)spp_local_param_ptr, 0, sizeof(spp_local_param_t)); + if ((spp_local_param_ptr = (spp_local_param_t *)osi_malloc(sizeof(spp_local_param_t))) == NULL) { + BTC_TRACE_ERROR("%s malloc failed\n", __func__); + ret = ESP_SPP_NO_RESOURCE; + break; + } + memset((void *)spp_local_param_ptr, 0, sizeof(spp_local_param_t)); #endif - if (osi_mutex_new(&spp_local_param.spp_slot_mutex) != 0) { - BTC_TRACE_ERROR("%s osi_mutex_new failed\n", __func__); - return; + if (osi_mutex_new(&spp_local_param.spp_slot_mutex) != 0) { + BTC_TRACE_ERROR("%s osi_mutex_new 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); + } while (0); + + if (ret != ESP_SPP_SUCCESS) { + esp_spp_cb_param_t param; + param.init.status = ret; + btc_spp_cb_to_app(ESP_SPP_INIT_EVT, ¶m); } - 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); } static void btc_spp_uninit(void) { - esp_spp_cb_param_t param; - if (!is_spp_init()) { - param.uninit.status = ESP_SPP_FAILURE; + esp_spp_status_t ret = ESP_SPP_SUCCESS; + do { + if (!is_spp_init()) { + BTC_TRACE_ERROR("%s SPP has not been initiated, shall init first!", __func__); + ret = ESP_SPP_NEED_INIT; + break; + } + osi_mutex_lock(&spp_local_param.spp_slot_mutex, OSI_MUTEX_MAX_TIMEOUT); + // first, remove all connection + for (size_t i = 1; i <= MAX_RFC_PORTS; i++) { + if (spp_local_param.spp_slots[i] != NULL && spp_local_param.spp_slots[i]->connected) { + BTA_JvRfcommClose(spp_local_param.spp_slots[i]->rfc_handle, (tBTA_JV_RFCOMM_CBACK *)btc_spp_rfcomm_inter_cb, + (void *)spp_local_param.spp_slots[i]->id); + } + } + // second, remove all server + for (size_t i = 1; i <= MAX_RFC_PORTS; i++) { + if (spp_local_param.spp_slots[i] != NULL && !spp_local_param.spp_slots[i]->connected) { + if (spp_local_param.spp_slots[i]->sdp_handle > 0) { + BTA_JvDeleteRecord(spp_local_param.spp_slots[i]->sdp_handle); + } + + if (spp_local_param.spp_slots[i]->rfc_handle > 0) { + BTA_JvRfcommStopServer(spp_local_param.spp_slots[i]->rfc_handle, + (void *)spp_local_param.spp_slots[i]->id); + } + + tBTA_JV_FREE_SCN_USER_DATA *user_data = osi_malloc(sizeof(tBTA_JV_FREE_SCN_USER_DATA)); + if (user_data) { + user_data->server_status = BTA_JV_SERVER_RUNNING; + user_data->slot_id = spp_local_param.spp_slots[i]->id; + } else { + esp_spp_cb_param_t param; + BTC_TRACE_ERROR("%s unable to malloc user data!", __func__); + param.srv_stop.status = ESP_SPP_NO_RESOURCE; + btc_spp_cb_to_app(ESP_SPP_SRV_STOP_EVT, ¶m); + } + BTA_JvFreeChannel(spp_local_param.spp_slots[i]->scn, BTA_JV_CONN_TYPE_RFCOMM, + (tBTA_JV_RFCOMM_CBACK *)btc_spp_rfcomm_inter_cb, (void *)user_data); + } + } + BTA_JvDisable((tBTA_JV_RFCOMM_CBACK *)btc_spp_rfcomm_inter_cb); + osi_mutex_unlock(&spp_local_param.spp_slot_mutex); + } while(0); + + if (ret != ESP_SPP_SUCCESS) { + esp_spp_cb_param_t param; + param.uninit.status = ret; btc_spp_cb_to_app(ESP_SPP_UNINIT_EVT, ¶m); - BTC_TRACE_ERROR("%s SPP has not been initiated, shall init first!", __func__); - return; } - osi_mutex_lock(&spp_local_param.spp_slot_mutex, OSI_MUTEX_MAX_TIMEOUT); - // first, remove all connection - for (size_t i = 1; i <= MAX_RFC_PORTS; i++) { - if (spp_local_param.spp_slots[i] != NULL && spp_local_param.spp_slots[i]->connected) { - BTA_JvRfcommClose(spp_local_param.spp_slots[i]->rfc_handle,(tBTA_JV_RFCOMM_CBACK *)btc_spp_rfcomm_inter_cb, - (void *)spp_local_param.spp_slots[i]->id); - } - } - // second, remove all server - for (size_t i = 1; i <= MAX_RFC_PORTS; i++) { - if (spp_local_param.spp_slots[i] != NULL && !spp_local_param.spp_slots[i]->connected) { - if (spp_local_param.spp_slots[i]->sdp_handle > 0) { - BTA_JvDeleteRecord(spp_local_param.spp_slots[i]->sdp_handle); - } - - if (spp_local_param.spp_slots[i]->rfc_handle > 0) { - BTA_JvRfcommStopServer(spp_local_param.spp_slots[i]->rfc_handle, - (void *)spp_local_param.spp_slots[i]->id); - } - - tBTA_JV_FREE_SCN_USER_DATA *user_data = osi_malloc(sizeof(tBTA_JV_FREE_SCN_USER_DATA)); - if (user_data) { - user_data->server_status = BTA_JV_SERVER_RUNNING; - user_data->slot_id = spp_local_param.spp_slots[i]->id; - } else { - BTC_TRACE_ERROR("%s unable to malloc user data!", __func__); - param.srv_stop.status = ESP_SPP_NO_RESOURCE; - btc_spp_cb_to_app(ESP_SPP_SRV_STOP_EVT, ¶m); - } - BTA_JvFreeChannel(spp_local_param.spp_slots[i]->scn, BTA_JV_CONN_TYPE_RFCOMM, - (tBTA_JV_RFCOMM_CBACK *)btc_spp_rfcomm_inter_cb, (void *)user_data); - } - } - BTA_JvDisable((tBTA_JV_RFCOMM_CBACK *)btc_spp_rfcomm_inter_cb); - osi_mutex_unlock(&spp_local_param.spp_slot_mutex); } static void btc_spp_start_discovery(btc_spp_args_t *arg) { - if (!is_spp_init()) { - BTC_TRACE_ERROR("%s SPP have not been init\n", __func__); - return; + esp_spp_status_t ret = ESP_SPP_SUCCESS; + do { + if (!is_spp_init()) { + BTC_TRACE_ERROR("%s SPP have not been init\n", __func__); + ret = ESP_SPP_NEED_INIT; + break; + } + BTA_JvStartDiscovery(arg->start_discovery.bd_addr, arg->start_discovery.num_uuid, arg->start_discovery.p_uuid_list, NULL); + } while (0); + + if (ret != ESP_SPP_SUCCESS) { + esp_spp_cb_param_t param; + param.disc_comp.status = ret; + param.disc_comp.scn_num = 0xff; + memset(param.disc_comp.scn, 0xff, ESP_SPP_MAX_SCN); + btc_spp_cb_to_app(ESP_SPP_DISCOVERY_COMP_EVT, ¶m); } - BTA_JvStartDiscovery(arg->start_discovery.bd_addr, arg->start_discovery.num_uuid, arg->start_discovery.p_uuid_list, NULL); } static void btc_spp_connect(btc_spp_args_t *arg) { - if (!is_spp_init()) { - BTC_TRACE_ERROR("%s SPP have not been init\n", __func__); - return; - } - osi_mutex_lock(&spp_local_param.spp_slot_mutex, OSI_MUTEX_MAX_TIMEOUT); - spp_slot_t *slot = spp_malloc_slot(); - if (!slot) { - BTC_TRACE_ERROR("%s unable to malloc RFCOMM slot!", __func__); + esp_spp_status_t ret = ESP_SPP_SUCCESS; + do { + if (!is_spp_init()) { + BTC_TRACE_ERROR("%s SPP have not been init\n", __func__); + ret = ESP_SPP_NEED_INIT; + break; + } + osi_mutex_lock(&spp_local_param.spp_slot_mutex, OSI_MUTEX_MAX_TIMEOUT); + spp_slot_t *slot = spp_malloc_slot(); + if (!slot) { + BTC_TRACE_ERROR("%s unable to malloc RFCOMM slot!", __func__); + osi_mutex_unlock(&spp_local_param.spp_slot_mutex); + ret = ESP_SPP_NO_RESOURCE; + break; + } + slot->security = arg->connect.sec_mask; + slot->role = arg->connect.role; + slot->scn = arg->connect.remote_scn; + + memcpy(slot->addr, arg->connect.peer_bd_addr, ESP_BD_ADDR_LEN); + BTA_JvRfcommConnect(arg->connect.sec_mask, arg->connect.role, arg->connect.remote_scn, + arg->connect.peer_bd_addr, (tBTA_JV_RFCOMM_CBACK *)btc_spp_rfcomm_inter_cb, (void *)slot->id); osi_mutex_unlock(&spp_local_param.spp_slot_mutex); - return; + } while (0); + + if (ret != ESP_SPP_SUCCESS) { + esp_spp_cb_param_t param; + param.open.status = ret; + param.open.handle = 0; + param.open.fd = -1; + memset(param.open.rem_bda, 0, ESP_BD_ADDR_LEN); + btc_spp_cb_to_app(ESP_SPP_OPEN_EVT, ¶m); } - slot->security = arg->connect.sec_mask; - slot->role = arg->connect.role; - slot->scn = arg->connect.remote_scn;; - memcpy(slot->addr, arg->connect.peer_bd_addr, ESP_BD_ADDR_LEN); - BTA_JvRfcommConnect(arg->connect.sec_mask, arg->connect.role, arg->connect.remote_scn, - arg->connect.peer_bd_addr, (tBTA_JV_RFCOMM_CBACK *)btc_spp_rfcomm_inter_cb, (void *)slot->id); - osi_mutex_unlock(&spp_local_param.spp_slot_mutex); } static void btc_spp_disconnect(btc_spp_args_t *arg) { - if (!is_spp_init()) { - BTC_TRACE_ERROR("%s SPP have not been init\n", __func__); - return; - } - 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__); + esp_spp_status_t ret = ESP_SPP_SUCCESS; + do { + if (!is_spp_init()) { + BTC_TRACE_ERROR("%s SPP have not been init\n", __func__); + ret = ESP_SPP_NEED_INIT; + break; + } + 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__); + osi_mutex_unlock(&spp_local_param.spp_slot_mutex); + ret = ESP_SPP_NO_CONNECTION; + break; + } + BTA_JvRfcommClose(arg->disconnect.handle, (tBTA_JV_RFCOMM_CBACK *)btc_spp_rfcomm_inter_cb, (void *)slot->id); osi_mutex_unlock(&spp_local_param.spp_slot_mutex); - return; + } while(0); + + if (ret != ESP_SPP_SUCCESS) { + esp_spp_cb_param_t param; + param.close.status = ret; + param.close.port_status = PORT_ERR_MAX; + param.close.handle = 0; + param.close.async = FALSE; + btc_spp_cb_to_app(ESP_SPP_CLOSE_EVT, ¶m); } - BTA_JvRfcommClose(arg->disconnect.handle, (tBTA_JV_RFCOMM_CBACK *)btc_spp_rfcomm_inter_cb, (void *)slot->id); - osi_mutex_unlock(&spp_local_param.spp_slot_mutex); } static void btc_spp_start_srv(btc_spp_args_t *arg) { - if (!is_spp_init()) { - BTC_TRACE_ERROR("%s SPP have not been init\n", __func__); - return; - } - osi_mutex_lock(&spp_local_param.spp_slot_mutex, OSI_MUTEX_MAX_TIMEOUT); - spp_slot_t *slot = spp_malloc_slot(); - if (!slot) { - BTC_TRACE_ERROR("%s unable to malloc RFCOMM slot!", __func__); - osi_mutex_unlock(&spp_local_param.spp_slot_mutex); - return; - } - slot->security = arg->start_srv.sec_mask; - slot->role = arg->start_srv.role; - slot->scn = arg->start_srv.local_scn;; - slot->max_session = arg->start_srv.max_session; - strcpy(slot->service_name, arg->start_srv.name); + esp_spp_status_t ret = ESP_SPP_SUCCESS; + do { + if (!is_spp_init()) { + BTC_TRACE_ERROR("%s SPP have not been init\n", __func__); + ret = ESP_SPP_NEED_INIT; + break; + } + osi_mutex_lock(&spp_local_param.spp_slot_mutex, OSI_MUTEX_MAX_TIMEOUT); + spp_slot_t *slot = spp_malloc_slot(); + if (!slot) { + BTC_TRACE_ERROR("%s unable to malloc RFCOMM slot!", __func__); + osi_mutex_unlock(&spp_local_param.spp_slot_mutex); + ret = ESP_SPP_NO_RESOURCE; + break; + } + slot->security = arg->start_srv.sec_mask; + slot->role = arg->start_srv.role; + slot->scn = arg->start_srv.local_scn; + slot->max_session = arg->start_srv.max_session; + strcpy(slot->service_name, arg->start_srv.name); - BTA_JvGetChannelId(BTA_JV_CONN_TYPE_RFCOMM, (void *)slot->id, arg->start_srv.local_scn); - osi_mutex_unlock(&spp_local_param.spp_slot_mutex); + BTA_JvGetChannelId(BTA_JV_CONN_TYPE_RFCOMM, (void *)slot->id, arg->start_srv.local_scn); + osi_mutex_unlock(&spp_local_param.spp_slot_mutex); + } while(0); + + if (ret != ESP_SPP_SUCCESS) { + esp_spp_cb_param_t param; + param.srv_open.status = ret; + param.srv_open.handle = 0; + param.srv_open.new_listen_handle = 0; + param.srv_open.fd = -1; + memset(param.srv_open.rem_bda, 0, ESP_BD_ADDR_LEN); + btc_spp_cb_to_app(ESP_SPP_SRV_OPEN_EVT, ¶m); + } } -static void btc_spp_stop_srv(void) { - if (!is_spp_init()) { - BTC_TRACE_ERROR("%s SPP have not been init\n", __func__); - return; - } - esp_spp_cb_param_t param; - osi_mutex_lock(&spp_local_param.spp_slot_mutex, OSI_MUTEX_MAX_TIMEOUT); - // first, remove all connection - for (size_t i = 1; i <= MAX_RFC_PORTS; i++) { - if (spp_local_param.spp_slots[i] != NULL && spp_local_param.spp_slots[i]->connected) { - BTA_JvRfcommClose(spp_local_param.spp_slots[i]->rfc_handle,(tBTA_JV_RFCOMM_CBACK *)btc_spp_rfcomm_inter_cb, - (void *)spp_local_param.spp_slots[i]->id); +static void btc_spp_stop_srv(void) +{ + esp_spp_status_t ret = ESP_SPP_SUCCESS; + do { + if (!is_spp_init()) { + BTC_TRACE_ERROR("%s SPP have not been init\n", __func__); + ret = ESP_SPP_NEED_INIT; + break; } - } - // second, remove all server - for (size_t i = 1; i <= MAX_RFC_PORTS; i++) { - if (spp_local_param.spp_slots[i] != NULL && !spp_local_param.spp_slots[i]->connected) { - if (spp_local_param.spp_slots[i]->sdp_handle > 0) { - BTA_JvDeleteRecord(spp_local_param.spp_slots[i]->sdp_handle); + osi_mutex_lock(&spp_local_param.spp_slot_mutex, OSI_MUTEX_MAX_TIMEOUT); + // first, remove all connection + for (size_t i = 1; i <= MAX_RFC_PORTS; i++) { + if (spp_local_param.spp_slots[i] != NULL && spp_local_param.spp_slots[i]->connected) { + BTA_JvRfcommClose(spp_local_param.spp_slots[i]->rfc_handle, (tBTA_JV_RFCOMM_CBACK *)btc_spp_rfcomm_inter_cb, + (void *)spp_local_param.spp_slots[i]->id); } - - if (spp_local_param.spp_slots[i]->rfc_handle > 0) { - BTA_JvRfcommStopServer(spp_local_param.spp_slots[i]->rfc_handle, - (void *)spp_local_param.spp_slots[i]->id); - } - - tBTA_JV_FREE_SCN_USER_DATA *user_data = osi_malloc(sizeof(tBTA_JV_FREE_SCN_USER_DATA)); - if (user_data) { - user_data->server_status = BTA_JV_SERVER_RUNNING; - user_data->slot_id = spp_local_param.spp_slots[i]->id; - } else { - BTC_TRACE_ERROR("%s unable to malloc user data!", __func__); - param.srv_stop.status = ESP_SPP_NO_RESOURCE; - btc_spp_cb_to_app(ESP_SPP_SRV_STOP_EVT, ¶m); - } - BTA_JvFreeChannel(spp_local_param.spp_slots[i]->scn, BTA_JV_CONN_TYPE_RFCOMM, - (tBTA_JV_RFCOMM_CBACK *)btc_spp_rfcomm_inter_cb, (void *)user_data); } + // second, remove all server + for (size_t i = 1; i <= MAX_RFC_PORTS; i++) { + if (spp_local_param.spp_slots[i] != NULL && !spp_local_param.spp_slots[i]->connected) { + if (spp_local_param.spp_slots[i]->sdp_handle > 0) { + BTA_JvDeleteRecord(spp_local_param.spp_slots[i]->sdp_handle); + } + + if (spp_local_param.spp_slots[i]->rfc_handle > 0) { + BTA_JvRfcommStopServer(spp_local_param.spp_slots[i]->rfc_handle, + (void *)spp_local_param.spp_slots[i]->id); + } + + tBTA_JV_FREE_SCN_USER_DATA *user_data = osi_malloc(sizeof(tBTA_JV_FREE_SCN_USER_DATA)); + if (user_data) { + user_data->server_status = BTA_JV_SERVER_RUNNING; + user_data->slot_id = spp_local_param.spp_slots[i]->id; + } else { + esp_spp_cb_param_t param; + BTC_TRACE_ERROR("%s unable to malloc user data!", __func__); + param.srv_stop.status = ESP_SPP_NO_RESOURCE; + btc_spp_cb_to_app(ESP_SPP_SRV_STOP_EVT, ¶m); + } + BTA_JvFreeChannel(spp_local_param.spp_slots[i]->scn, BTA_JV_CONN_TYPE_RFCOMM, + (tBTA_JV_RFCOMM_CBACK *)btc_spp_rfcomm_inter_cb, (void *)user_data); + } + } + osi_mutex_unlock(&spp_local_param.spp_slot_mutex); + } while(0); + + if (ret != ESP_SPP_SUCCESS) { + esp_spp_cb_param_t param; + param.srv_stop.status = ret; + btc_spp_cb_to_app(ESP_SPP_SRV_STOP_EVT, ¶m); } - osi_mutex_unlock(&spp_local_param.spp_slot_mutex); } static void btc_spp_write(btc_spp_args_t *arg) { - if (!is_spp_init()) { - BTC_TRACE_ERROR("%s SPP have not been init\n", __func__); - return; - } - 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__); - osi_mutex_unlock(&spp_local_param.spp_slot_mutex); - return; - } - if (spp_local_param.spp_mode == ESP_SPP_MODE_VFS) { - size_t item_size = 0; - if (slot->write_data != NULL) { + esp_spp_status_t ret = ESP_SPP_SUCCESS; + do { + if (!is_spp_init()) { + BTC_TRACE_ERROR("%s SPP have not been init\n", __func__); + ret = ESP_SPP_NEED_INIT; + break; + } + 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__); osi_mutex_unlock(&spp_local_param.spp_slot_mutex); - return; + ret = ESP_SPP_NO_CONNECTION; + break; } - 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); + 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); + } + } else { + list_append(slot->list, arg->write.p_data); + BTA_JvRfcommWrite(arg->write.handle, slot->id, arg->write.len, arg->write.p_data); } - } else { - list_append(slot->list, arg->write.p_data); - BTA_JvRfcommWrite(arg->write.handle, slot->id, arg->write.len, arg->write.p_data); + osi_mutex_unlock(&spp_local_param.spp_slot_mutex); + } while (0); + + if (ret != ESP_SPP_SUCCESS && spp_local_param.spp_mode == ESP_SPP_MODE_CB) { + esp_spp_cb_param_t param; + param.write.status = ret; + param.write.handle = 0; + param.write.len = -1; + param.write.cong = false; + btc_spp_cb_to_app(ESP_SPP_WRITE_EVT, ¶m); } - osi_mutex_unlock(&spp_local_param.spp_slot_mutex); } @@ -690,18 +794,21 @@ void btc_spp_cb_handler(btc_msg_t *msg) btc_spp_cb_to_app(ESP_SPP_CL_INIT_EVT, ¶m); break; case BTA_JV_RFCOMM_OPEN_EVT: - if (spp_local_param.spp_mode == ESP_SPP_MODE_VFS) { - 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__); + do { + if (spp_local_param.spp_mode == ESP_SPP_MODE_VFS) { + 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); + param.open.status = ESP_SPP_NO_CONNECTION; + break; + } + param.open.fd = slot->fd; osi_mutex_unlock(&spp_local_param.spp_slot_mutex); - break; } - param.open.fd = slot->fd; - osi_mutex_unlock(&spp_local_param.spp_slot_mutex); - } - param.open.status = p_data->rfc_open.status; + param.open.status = p_data->rfc_open.status; + } while (0); param.open.handle = p_data->rfc_open.handle; memcpy(param.open.rem_bda, p_data->rfc_open.rem_bda, ESP_BD_ADDR_LEN); btc_spp_cb_to_app(ESP_SPP_OPEN_EVT, ¶m); @@ -715,18 +822,21 @@ void btc_spp_cb_handler(btc_msg_t *msg) break; case BTA_JV_RFCOMM_SRV_OPEN_EVT: if (p_data->rfc_srv_open.handle) { - if (spp_local_param.spp_mode == ESP_SPP_MODE_VFS) { - 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__); + do { + if (spp_local_param.spp_mode == ESP_SPP_MODE_VFS) { + 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); + param.srv_open.status = ESP_SPP_NO_CONNECTION; + break; + } + param.srv_open.fd = slot->fd; osi_mutex_unlock(&spp_local_param.spp_slot_mutex); - break; } - param.srv_open.fd = slot->fd; - osi_mutex_unlock(&spp_local_param.spp_slot_mutex); - } - param.srv_open.status = p_data->rfc_srv_open.status; + param.srv_open.status = p_data->rfc_srv_open.status; + } while (0); param.srv_open.handle = p_data->rfc_srv_open.handle; param.srv_open.new_listen_handle = p_data->rfc_srv_open.new_listen_handle; memcpy(param.srv_open.rem_bda, p_data->rfc_srv_open.rem_bda, ESP_BD_ADDR_LEN); @@ -738,35 +848,37 @@ void btc_spp_cb_handler(btc_msg_t *msg) slot = spp_find_slot_by_handle(p_data->rfc_write.handle); if (!slot) { BTC_TRACE_ERROR("%s unable to find RFCOMM slot!", __func__); - osi_mutex_unlock(&spp_local_param.spp_slot_mutex); - break; } if (spp_local_param.spp_mode == ESP_SPP_MODE_CB){ - param.write.status = p_data->rfc_write.status; + param.write.status = slot ? p_data->rfc_write.status : ESP_SPP_NO_CONNECTION; param.write.handle = p_data->rfc_write.handle; param.write.len = p_data->rfc_write.len; param.write.cong = p_data->rfc_write.cong; btc_spp_cb_to_app(ESP_SPP_WRITE_EVT, ¶m); - list_remove(slot->list, list_front(slot->list)); - } else { - 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); - break; + if (slot) { + list_remove(slot->list, list_front(slot->list)); } - if (p_data->rfc_write.cong == 0) { - if (slot->write_data != NULL){ - vRingbufferReturnItem(slot->ringbuf_write,slot->write_data); - slot->write_data = NULL; + } 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); + break; } - 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_write.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); + } } } } From c3171252ecc3436cb7b6f4295bf4585bbaf0edb5 Mon Sep 17 00:00:00 2001 From: liqigan Date: Thu, 20 Aug 2020 13:19:22 +0800 Subject: [PATCH 2/3] move flow control to btc layer defer free slot in btc layer when receive BTA_JV_RFCOMM_CLOSE_EVT --- components/bt/common/osi/include/osi/list.h | 7 + components/bt/common/osi/list.c | 44 +++++ .../bluedroid/bta/include/bta/bta_jv_api.h | 13 ++ .../bt/host/bluedroid/bta/jv/bta_jv_act.c | 20 +++ .../bt/host/bluedroid/bta/jv/bta_jv_api.c | 32 ++++ .../bt/host/bluedroid/bta/jv/bta_jv_main.c | 1 + .../bluedroid/bta/jv/include/bta_jv_int.h | 11 ++ .../bluedroid/btc/profile/std/spp/btc_spp.c | 161 ++++++++++-------- .../bluedroid/stack/include/stack/port_api.h | 13 +- .../bt/host/bluedroid/stack/rfcomm/port_api.c | 71 ++++++++ .../bt/host/bluedroid/stack/rfcomm/port_rfc.c | 3 +- .../host/bluedroid/stack/rfcomm/port_utils.c | 14 +- 12 files changed, 310 insertions(+), 80 deletions(-) diff --git a/components/bt/common/osi/include/osi/list.h b/components/bt/common/osi/include/osi/list.h index c0abd106e5..6b82f6f587 100644 --- a/components/bt/common/osi/include/osi/list.h +++ b/components/bt/common/osi/include/osi/list.h @@ -22,6 +22,10 @@ list_t *list_new(list_free_cb callback); list_node_t *list_free_node(list_t *list, list_node_t *node); + +// similar with list_free_node, this function doesn't free the node data +list_node_t *list_delete_node(list_t *list, list_node_t *node); + // Frees the list. This function accepts NULL as an argument, in which case it // behaves like a no-op. void list_free(list_t *list); @@ -75,6 +79,9 @@ bool list_append(list_t *list, void *data); bool list_remove(list_t *list, void *data); +// similar with list_remove, but do not free the node data +bool list_delete(list_t *list, void *data); + // Removes all elements in the list. Calling this function will return the list to the // same state it was in after |list_new|. |list| may not be NULL. void list_clear(list_t *list); diff --git a/components/bt/common/osi/list.c b/components/bt/common/osi/list.c index 93db17fb38..23a402856e 100644 --- a/components/bt/common/osi/list.c +++ b/components/bt/common/osi/list.c @@ -186,6 +186,36 @@ bool list_remove(list_t *list, void *data) return false; } +bool list_delete(list_t *list, void *data) +{ + assert(list != NULL); + assert(data != NULL); + + if (list_is_empty(list)) { + return false; + } + + if (list->head->data == data) { + list_node_t *next = list_delete_node(list, list->head); + if (list->tail == list->head) { + list->tail = next; + } + list->head = next; + return true; + } + + for (list_node_t *prev = list->head, *node = list->head->next; node; prev = node, node = node->next) + if (node->data == data) { + prev->next = list_delete_node(list, node); + if (list->tail == node) { + list->tail = prev; + } + return true; + } + + return false; +} + void list_clear(list_t *list) { assert(list != NULL); @@ -251,3 +281,17 @@ list_node_t *list_free_node(list_t *list, list_node_t *node) return next; } + +// remove the element from list but do not free the node data +list_node_t *list_delete_node(list_t *list, list_node_t *node) +{ + assert(list != NULL); + assert(node != NULL); + + list_node_t *next = node->next; + + osi_free(node); + --list->length; + + return next; +} \ No newline at end of file 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 d15f5d82f7..fafe694cc9 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 @@ -297,6 +297,7 @@ 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; @@ -894,6 +895,18 @@ extern tBTA_JV_STATUS BTA_JvRfcommReady(UINT32 handle, UINT32 *p_data_size); *******************************************************************************/ extern tBTA_JV_STATUS BTA_JvRfcommWrite(UINT32 handle, UINT32 req_id, int len, UINT8 *p_data); +/******************************************************************************* +** +** Function BTA_JvRfcommFlowControl +** +** Description This function gives the credit to the peer +** +** Returns BTA_JV_SUCCESS, if the request is being processed. +** BTA_JV_FAILURE, otherwise. +** +*******************************************************************************/ +extern tBTA_JV_STATUS BTA_JvRfcommFlowControl(UINT32 handle, UINT16 credits_given); + /******************************************************************************* ** ** Function BTA_JVSetPmProfile 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 1a82c05332..986bb20738 100644 --- a/components/bt/host/bluedroid/bta/jv/bta_jv_act.c +++ b/components/bt/host/bluedroid/bta/jv/bta_jv_act.c @@ -1688,6 +1688,7 @@ 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; @@ -1871,6 +1872,7 @@ 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 || @@ -1960,6 +1962,7 @@ 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; @@ -2275,6 +2278,23 @@ void bta_jv_rfcomm_write(tBTA_JV_MSG *p_data) } +/******************************************************************************* +** +** Function bta_jv_rfcomm_flow_control +** +** Description give credits to the peer +** +** Returns void +** +*******************************************************************************/ +void bta_jv_rfcomm_flow_control(tBTA_JV_MSG *p_data) +{ + tBTA_JV_API_RFCOMM_FLOW_CONTROL *fc = &(p_data->rfcomm_fc); + + tBTA_JV_PCB *p_pcb = fc->p_pcb; + PORT_FlowControl_GiveCredit(p_pcb->port_handle, TRUE, fc->credits_given); +} + /******************************************************************************* ** ** Function bta_jv_set_pm_profile diff --git a/components/bt/host/bluedroid/bta/jv/bta_jv_api.c b/components/bt/host/bluedroid/bta/jv/bta_jv_api.c index b0995c0b1b..06a5ef740b 100644 --- a/components/bt/host/bluedroid/bta/jv/bta_jv_api.c +++ b/components/bt/host/bluedroid/bta/jv/bta_jv_api.c @@ -1136,6 +1136,38 @@ tBTA_JV_STATUS BTA_JvRfcommWrite(UINT32 handle, UINT32 req_id, int len, UINT8 *p return (status); } +/******************************************************************************* +** +** Function BTA_JvRfcommFlowControl +** +** Description This function gives credits to the peer +** +** Returns BTA_JV_SUCCESS, if the request is being processed. +** BTA_JV_FAILURE, otherwise. +** +*******************************************************************************/ +tBTA_JV_STATUS BTA_JvRfcommFlowControl(UINT32 handle, UINT16 credits_given) +{ + tBTA_JV_STATUS status = BTA_JV_FAILURE; + tBTA_JV_API_RFCOMM_FLOW_CONTROL *p_msg; + UINT32 hi = ((handle & BTA_JV_RFC_HDL_MASK) & ~BTA_JV_RFCOMM_MASK) - 1; + UINT32 si = BTA_JV_RFC_HDL_TO_SIDX(handle); + + APPL_TRACE_API( "BTA_JvRfcommFlowControl"); + APPL_TRACE_DEBUG( "handle:0x%x, hi:%d, si:%d", handle, hi, si); + if (hi < BTA_JV_MAX_RFC_CONN && bta_jv_cb.rfc_cb[hi].p_cback && + si < BTA_JV_MAX_RFC_SR_SESSION && bta_jv_cb.rfc_cb[hi].rfc_hdl[si] && + (p_msg = (tBTA_JV_API_RFCOMM_FLOW_CONTROL *)osi_malloc(sizeof(tBTA_JV_API_RFCOMM_FLOW_CONTROL))) != NULL) { + p_msg->hdr.event = BTA_JV_API_RFCOMM_FLOW_CONTROL_EVT; + p_msg->p_cb = &bta_jv_cb.rfc_cb[hi]; + p_msg->p_pcb = &bta_jv_cb.port_cb[p_msg->p_cb->rfc_hdl[si] - 1]; + p_msg->credits_given = credits_given; + APPL_TRACE_API( "credits given %d", credits_given); + bta_sys_sendmsg(p_msg); + status = BTA_JV_SUCCESS; + } + return (status); +} /******************************************************************************* ** diff --git a/components/bt/host/bluedroid/bta/jv/bta_jv_main.c b/components/bt/host/bluedroid/bta/jv/bta_jv_main.c index 9a583d74a5..4d7643eb64 100644 --- a/components/bt/host/bluedroid/bta/jv/bta_jv_main.c +++ b/components/bt/host/bluedroid/bta/jv/bta_jv_main.c @@ -68,6 +68,7 @@ const tBTA_JV_ACTION bta_jv_action[] = { bta_jv_rfcomm_stop_server, /* BTA_JV_API_RFCOMM_STOP_SERVER_EVT */ bta_jv_rfcomm_read, /* BTA_JV_API_RFCOMM_READ_EVT */ bta_jv_rfcomm_write, /* BTA_JV_API_RFCOMM_WRITE_EVT */ + bta_jv_rfcomm_flow_control, /* BTA_JV_API_RFCOMM_FLOW_CONTROL_EVT */ bta_jv_set_pm_profile, /* BTA_JV_API_SET_PM_PROFILE_EVT */ bta_jv_change_pm_state, /* BTA_JV_API_PM_STATE_CHANGE_EVT */ #if BTA_JV_L2CAP_INCLUDED diff --git a/components/bt/host/bluedroid/bta/jv/include/bta_jv_int.h b/components/bt/host/bluedroid/bta/jv/include/bta_jv_int.h index 6bfa59b451..5a0bf66faf 100644 --- a/components/bt/host/bluedroid/bta/jv/include/bta_jv_int.h +++ b/components/bt/host/bluedroid/bta/jv/include/bta_jv_int.h @@ -62,6 +62,7 @@ enum { BTA_JV_API_RFCOMM_STOP_SERVER_EVT, BTA_JV_API_RFCOMM_READ_EVT, BTA_JV_API_RFCOMM_WRITE_EVT, + BTA_JV_API_RFCOMM_FLOW_CONTROL_EVT, BTA_JV_API_SET_PM_PROFILE_EVT, BTA_JV_API_PM_STATE_CHANGE_EVT, #if BTA_JV_L2CAP_INCLUDED @@ -309,6 +310,14 @@ typedef struct { tBTA_JV_PCB *p_pcb; } tBTA_JV_API_RFCOMM_WRITE; +/* data type for BTA_JV_API_RFCOMM_FLOW_CONTROL_EVT */ +typedef struct { + BT_HDR hdr; + tBTA_JV_RFC_CB *p_cb; + tBTA_JV_PCB *p_pcb; + UINT16 credits_given; +} tBTA_JV_API_RFCOMM_FLOW_CONTROL; + /* data type for BTA_JV_API_RFCOMM_CLOSE_EVT */ typedef struct { BT_HDR hdr; @@ -375,6 +384,7 @@ typedef union { tBTA_JV_API_RFCOMM_CONNECT rfcomm_connect; tBTA_JV_API_RFCOMM_READ rfcomm_read; tBTA_JV_API_RFCOMM_WRITE rfcomm_write; + tBTA_JV_API_RFCOMM_FLOW_CONTROL rfcomm_fc; tBTA_JV_API_SET_PM_PROFILE set_pm; tBTA_JV_API_PM_STATE_CHANGE change_pm_state; tBTA_JV_API_RFCOMM_CLOSE rfcomm_close; @@ -444,6 +454,7 @@ extern void bta_jv_rfcomm_start_server (tBTA_JV_MSG *p_data); extern void bta_jv_rfcomm_stop_server (tBTA_JV_MSG *p_data); extern void bta_jv_rfcomm_read (tBTA_JV_MSG *p_data); extern void bta_jv_rfcomm_write (tBTA_JV_MSG *p_data); +extern void bta_jv_rfcomm_flow_control(tBTA_JV_MSG *p_data); extern void bta_jv_set_pm_profile (tBTA_JV_MSG *p_data); extern void bta_jv_change_pm_state(tBTA_JV_MSG *p_data); #if BTA_JV_L2CAP_INCLUDED 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 f51f961b17..d3e8c7a7a6 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 @@ -101,8 +101,8 @@ static spp_slot_t *spp_malloc_slot(void) 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); if (spp_local_param.spp_mode == ESP_SPP_MODE_VFS) { - spp_local_param.spp_slots[i]->incoming_list = list_new(spp_osi_free); 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; @@ -165,10 +165,10 @@ static void spp_free_slot(spp_slot_t *slot) 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); - list_free(slot->incoming_list); vRingbufferDelete(slot->ringbuf_read); vRingbufferDelete(slot->ringbuf_write); } + list_free(slot->incoming_list); osi_free(slot); } @@ -268,7 +268,7 @@ 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); } - spp_free_slot(slot); + p_data->rfc_close.slot = slot; p_data->rfc_close.status = BTA_JV_SUCCESS; break; case BTA_JV_RFCOMM_DATA_IND_EVT: @@ -890,6 +890,7 @@ void btc_spp_cb_handler(btc_msg_t *msg) 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, ¶m); + spp_free_slot((spp_slot_t *)p_data->rfc_close.slot); break; case BTA_JV_RFCOMM_CONG_EVT: if (spp_local_param.spp_mode == ESP_SPP_MODE_CB) { @@ -921,18 +922,52 @@ void btc_spp_cb_handler(btc_msg_t *msg) } break; case BTA_JV_RFCOMM_DATA_IND_EVT: - param.data_ind.status = ESP_SPP_SUCCESS; - param.data_ind.handle = p_data->data_ind.handle; - if (p_data->data_ind.p_buf) { - param.data_ind.len = p_data->data_ind.p_buf->len; - param.data_ind.data = p_data->data_ind.p_buf->data + p_data->data_ind.p_buf->offset; - } else { - param.data_ind.len = 0; - param.data_ind.data = NULL; - } + do { + uint8_t serial; + BT_HDR *p_buf; + UINT16 count = 0; - btc_spp_cb_to_app(ESP_SPP_DATA_IND_EVT, ¶m); - osi_free (p_data->data_ind.p_buf); + 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) { + BTC_TRACE_ERROR("%s unable to find RFCOMM slot!", __func__); + break; + } + + 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); + } else { + osi_mutex_unlock(&spp_local_param.spp_slot_mutex); + break; + } + osi_mutex_unlock(&spp_local_param.spp_slot_mutex); + + // invoke callback + if (p_buf) { + count += 1; + param.data_ind.status = ESP_SPP_SUCCESS; + param.data_ind.handle = p_data->data_ind.handle; + param.data_ind.len = p_buf->len; + param.data_ind.data = p_buf->data + p_buf->offset; + btc_spp_cb_to_app(ESP_SPP_DATA_IND_EVT, ¶m); + BTC_TRACE_DEBUG("data cb to app: len %d\n", p_buf->len); + osi_free(p_buf); + } + } + if (count != 0) { + BTA_JvRfcommFlowControl(p_data->data_ind.handle, count); + BTC_TRACE_DEBUG("%s give credits:%d\n", __func__, count); + } + } while (0); break; case BTA_JV_FREE_SCN_EVT: if (p_data->free_scn.server_status == BTA_JV_SERVER_RUNNING) { @@ -957,28 +992,9 @@ void btc_spp_cb_handler(btc_msg_t *msg) } -/** - * If there is too much data not accepted, wait until accepted,or discard it when timeout! - * @param list list - * @param p_buf incoming data - */ -static void spp_delay_append(list_t *list, BT_HDR *p_buf){ - uint8_t count = 0; - while (count++ < 100) { - if (list_length(list) < 200){ - osi_mutex_lock(&spp_local_param.spp_slot_mutex, OSI_MUTEX_MAX_TIMEOUT); - list_append(list, p_buf); - osi_mutex_unlock(&spp_local_param.spp_slot_mutex); - return; - } - vTaskDelay(100 / portTICK_PERIOD_MS); - } - osi_free(p_buf); - BTC_TRACE_WARNING("%s There is too much data not accepted, discard it!", __func__); -} - int bta_co_rfc_data_incoming(void *user_data, BT_HDR *p_buf) { + int ret = 1; bt_status_t status; tBTA_JV p_data; btc_msg_t msg; @@ -999,36 +1015,35 @@ int bta_co_rfc_data_incoming(void *user_data, BT_HDR *p_buf) 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) { - p_data.data_ind.p_buf = p_buf; - status = btc_transfer_context(&msg, &p_data, - sizeof(tBTA_JV), NULL); - if (status != BT_STATUS_SUCCESS) { - BTC_TRACE_ERROR("%s btc_transfer_context failed\n", __func__); + 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)); + 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 (list_is_empty(slot->incoming_list)) { - BaseType_t done = xRingbufferSend(slot->ringbuf_read, p_buf->data + p_buf->offset, p_buf->len, 0); - if (done) { - osi_free (p_buf); - } else { - list_append(slot->incoming_list, p_buf); - } - } else { - list_t *list = slot->incoming_list; - osi_mutex_unlock(&spp_local_param.spp_slot_mutex); - spp_delay_append(list,p_buf); - return 1; + 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; } } osi_mutex_unlock(&spp_local_param.spp_slot_mutex); - return 1; + return ret; } + int bta_co_rfc_data_outgoing_size(void *user_data, int *size) { return 1; } + int bta_co_rfc_data_outgoing(void *user_data, uint8_t *buf, uint16_t size) { return 1; @@ -1076,20 +1091,6 @@ static int spp_vfs_close(int fd) return 0; } -static bool incoming_list_2_ringbuf_read(spp_slot_t *slot) -{ - while (!list_is_empty(slot->incoming_list)) { - BT_HDR *p_buf = list_front(slot->incoming_list); - BaseType_t done = xRingbufferSend(slot->ringbuf_read, p_buf->data + p_buf->offset, p_buf->len, 0); - if (done) { - list_remove(slot->incoming_list, p_buf); - } else { - return false; - } - } - return true; -} - static ssize_t spp_vfs_read(int fd, void * dst, size_t size) { if (!is_spp_init()) { @@ -1103,12 +1104,28 @@ static ssize_t spp_vfs_read(int fd, void * dst, size_t size) osi_mutex_unlock(&spp_local_param.spp_slot_mutex); return -1; } - incoming_list_2_ringbuf_read(slot); - size_t item_size = 0; - uint8_t *data = xRingbufferReceiveUpTo(slot->ringbuf_read, &item_size, 0, size); - if (item_size > 0){ - memcpy(dst, data, item_size); - vRingbufferReturnItem(slot->ringbuf_read, data); + 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); + 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++; + } else { + memcpy(dst, p_buf->data + p_buf->offset, size); + item_size += size; + p_buf->offset += size; + p_buf->len -= size; + size = 0; + } + } + if (count > 0) { + 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); return item_size; 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 145ef22889..9bab34c3cc 100644 --- a/components/bt/host/bluedroid/stack/include/stack/port_api.h +++ b/components/bt/host/bluedroid/stack/include/stack/port_api.h @@ -409,7 +409,18 @@ extern int PORT_Control (UINT16 handle, UINT8 signal); *******************************************************************************/ extern int PORT_FlowControl (UINT16 handle, BOOLEAN enable); - +/******************************************************************************* +** +** Function PORT_FlowControl_GiveCredit +** +** Description This function gives specified credits to the peer +** +** Parameters: handle - Handle returned in the RFCOMM_CreateConnection +** enable - enables data flow +** credits_given - credits to give +** +*******************************************************************************/ +extern int PORT_FlowControl_GiveCredit (UINT16 handle, BOOLEAN enable, UINT16 credits_given); /******************************************************************************* ** ** Function PORT_GetModemStatus diff --git a/components/bt/host/bluedroid/stack/rfcomm/port_api.c b/components/bt/host/bluedroid/stack/rfcomm/port_api.c index dacf544b9b..d42bbabdf2 100644 --- a/components/bt/host/bluedroid/stack/rfcomm/port_api.c +++ b/components/bt/host/bluedroid/stack/rfcomm/port_api.c @@ -899,6 +899,77 @@ int PORT_FlowControl_MaxCredit (UINT16 handle, BOOLEAN enable) } #endif +/******************************************************************************* +** +** Function PORT_FlowControl_GiveCredit +** +** Description This function gives specified credits to the peer +** +** Parameters: handle - Handle returned in the RFCOMM_CreateConnection +** enable - enables data flow +** credits_given - credits to give +** +*******************************************************************************/ +int PORT_FlowControl_GiveCredit (UINT16 handle, BOOLEAN enable, UINT16 credits_given) +{ + tPORT *p_port; + BOOLEAN old_fc; + UINT32 events; + + RFCOMM_TRACE_DEBUG("%s handle:%d enable: %d, cred %d", __func__, handle, enable, credits_given); + + /* Check if handle is valid to avoid crashing */ + if ((handle == 0) || (handle > MAX_RFC_PORTS)) { + return (PORT_BAD_HANDLE); + } + + p_port = &rfc_cb.port.port[handle - 1]; + + if (!p_port->in_use || (p_port->state == PORT_STATE_CLOSED)) { + return (PORT_NOT_OPENED); + } + + if (!p_port->rfc.p_mcb) { + return (PORT_NOT_OPENED); + } + + p_port->rx.user_fc = !enable; + + if (p_port->rfc.p_mcb->flow == PORT_FC_CREDIT) { + if (!p_port->rx.user_fc) { + port_flow_control_peer(p_port, TRUE, credits_given); + } + } else { + assert(0); // karl: temporarily not allowed + old_fc = p_port->local_ctrl.fc; + + /* FC is set if user is set or peer is set */ + p_port->local_ctrl.fc = (p_port->rx.user_fc | p_port->rx.peer_fc); + + if (p_port->local_ctrl.fc != old_fc) { + port_start_control (p_port); + } + } + + /* Need to take care of the case when we could not deliver events */ + /* to the application because we were flow controlled */ + if (enable && (p_port->rx.queue_size != 0)) { + assert(0); // karl: temporarily not allowed + events = PORT_EV_RXCHAR; + if (p_port->rx_flag_ev_pending) { + p_port->rx_flag_ev_pending = FALSE; + events |= PORT_EV_RXFLAG; + } + + events &= p_port->ev_mask; + if (p_port->p_callback && events) { + p_port->p_callback (events, p_port->inx); + } + } + return (PORT_SUCCESS); +} + + /******************************************************************************* ** ** Function PORT_GetModemStatus diff --git a/components/bt/host/bluedroid/stack/rfcomm/port_rfc.c b/components/bt/host/bluedroid/stack/rfcomm/port_rfc.c index 4a47fb46ca..5dfd1b7e54 100644 --- a/components/bt/host/bluedroid/stack/rfcomm/port_rfc.c +++ b/components/bt/host/bluedroid/stack/rfcomm/port_rfc.c @@ -826,7 +826,8 @@ void PORT_DataInd (tRFC_MCB *p_mcb, UINT8 dlci, BT_HDR *p_buf) /* Another packet is delivered to user. Send credits to peer if required */ if (p_port->p_data_co_callback(p_port->inx, (UINT8 *)p_buf, -1, DATA_CO_CALLBACK_TYPE_INCOMING)) { - port_flow_control_peer(p_port, TRUE, 1); + // do nothing, flow control credits will be given upon upper-layer request; + // port_flow_control_peer(p_port, TRUE, 1); } else { port_flow_control_peer(p_port, FALSE, 0); } diff --git a/components/bt/host/bluedroid/stack/rfcomm/port_utils.c b/components/bt/host/bluedroid/stack/rfcomm/port_utils.c index fc3f281c9f..aaa9c8c1d5 100644 --- a/components/bt/host/bluedroid/stack/rfcomm/port_utils.c +++ b/components/bt/host/bluedroid/stack/rfcomm/port_utils.c @@ -210,17 +210,17 @@ void port_release_port (tPORT *p_port) osi_mutex_global_lock(); RFCOMM_TRACE_DEBUG("port_release_port, p_port:%p", p_port); - if (p_port->rx.queue) { + if (p_port->rx.queue != NULL) { while ((p_buf = (BT_HDR *)fixed_queue_dequeue(p_port->rx.queue, 0)) != NULL) { - osi_free (p_buf); + osi_free(p_buf); } } p_port->rx.queue_size = 0; - if (p_port->tx.queue) { + if (p_port->tx.queue != NULL) { while ((p_buf = (BT_HDR *)fixed_queue_dequeue(p_port->tx.queue, 0)) != NULL) { - osi_free (p_buf); - } + osi_free(p_buf); + } } p_port->tx.queue_size = 0; @@ -514,10 +514,12 @@ void port_flow_control_peer(tPORT *p_port, BOOLEAN enable, UINT16 count) && (p_port->credit_rx_max > p_port->credit_rx)) { rfc_send_credit(p_port->rfc.p_mcb, p_port->dlci, (UINT8) (p_port->credit_rx_max - p_port->credit_rx)); - + RFCOMM_TRACE_DEBUG("send credit: max %d, rx %d, count %d", p_port->credit_rx_max, p_port->credit_rx, count); p_port->credit_rx = p_port->credit_rx_max; p_port->rx.peer_fc = FALSE; + } else { + RFCOMM_TRACE_DEBUG("credit: max %d, rx %d, low %d", p_port->credit_rx_max, p_port->credit_rx, p_port->credit_rx_low); } } /* else want to disable flow from peer */ From caee4c24a9e11e325049e3c1a2b1b41b4a262053 Mon Sep 17 00:00:00 2001 From: liqigan Date: Mon, 24 Aug 2020 09:52:36 +0800 Subject: [PATCH 3/3] 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 --- components/bt/common/btc/core/btc_task.c | 5 + .../bt/common/btc/include/btc/btc_task.h | 1 + .../bluedroid/api/include/api/esp_spp_api.h | 4 +- .../bt/host/bluedroid/bta/dm/bta_dm_act.c | 4 +- .../bluedroid/bta/dm/include/bta_dm_int.h | 2 +- .../bluedroid/bta/include/bta/bta_jv_api.h | 2 +- .../bt/host/bluedroid/bta/jv/bta_jv_act.c | 11 +- .../bluedroid/btc/profile/std/spp/btc_spp.c | 549 +++++++++++++----- .../bt/host/bluedroid/stack/btu/btu_init.c | 5 + .../host/bluedroid/stack/include/stack/btu.h | 2 + 10 files changed, 434 insertions(+), 151 deletions(-) diff --git a/components/bt/common/btc/core/btc_task.c b/components/bt/common/btc/core/btc_task.c index 4564beea1c..aee251ad1f 100644 --- a/components/bt/common/btc/core/btc_task.c +++ b/components/bt/common/btc/core/btc_task.c @@ -415,3 +415,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); +} + diff --git a/components/bt/common/btc/include/btc/btc_task.h b/components/bt/common/btc/include/btc/btc_task.h index a746caef6e..5fa51c207b 100644 --- a/components/bt/common/btc/include/btc/btc_task.h +++ b/components/bt/common/btc/include/btc/btc_task.h @@ -119,5 +119,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__ */ diff --git a/components/bt/host/bluedroid/api/include/api/esp_spp_api.h b/components/bt/host/bluedroid/api/include/api/esp_spp_api.h index e1fe47c912..c5362f3fc9 100644 --- a/components/bt/host/bluedroid/api/include/api/esp_spp_api.h +++ b/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; diff --git a/components/bt/host/bluedroid/bta/dm/bta_dm_act.c b/components/bt/host/bluedroid/bta/dm/bta_dm_act.c index f0cc85a503..802fa2e350 100644 --- a/components/bt/host/bluedroid/bta/dm/bta_dm_act.c +++ b/components/bt/host/bluedroid/bta/dm/bta_dm_act.c @@ -3820,9 +3820,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); } } diff --git a/components/bt/host/bluedroid/bta/dm/include/bta_dm_int.h b/components/bt/host/bluedroid/bta/dm/include/bta_dm_int.h index b6de9fd973..db7aeb730e 100644 --- a/components/bt/host/bluedroid/bta/dm/include/bta_dm_int.h +++ b/components/bt/host/bluedroid/bta/dm/include/bta_dm_int.h @@ -1101,7 +1101,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; 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 fafe694cc9..61042144ab 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 @@ -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 */ 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 986bb20738..685f0c7a7e 100644 --- a/components/bt/host/bluedroid/bta/jv/bta_jv_act.c +++ b/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 { 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 d3e8c7a7a6..c55633a89c 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 @@ -24,22 +24,41 @@ #include "osi/list.h" #include "freertos/ringbuf.h" #include "osi/mutex.h" +#include "osi/alarm.h" #include #include #include #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); - 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; - } - 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); + (*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; } - return spp_local_param.spp_slots[i]; + 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, &(*slot)->fd) != ESP_OK) { + BTC_TRACE_ERROR("%s unable to register fd!", __func__); + err_no = 3; + break; + } + } + 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, ¶m); 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, ¶m); - 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, ¶m); + 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, ¶m); + 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) { - if (!is_spp_init()) { - BTC_TRACE_ERROR("%s SPP have not been init\n", __func__); - return -1; - } - osi_mutex_lock(&spp_local_param.spp_slot_mutex, OSI_MUTEX_MAX_TIMEOUT); - spp_slot_t *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); - return -1; - } - BaseType_t done = xRingbufferSend(slot->ringbuf_write, (void *)data, size, 0); - esp_spp_write(slot->rfc_handle, 0, NULL); - osi_mutex_unlock(&spp_local_param.spp_slot_mutex); - if (done){ - return size; - } else { + 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); + slot = spp_find_slot_by_fd(fd); + if (!slot) { + osi_mutex_unlock(&spp_local_param.spp_slot_mutex); + BTC_TRACE_ERROR("%s unable to find RFCOMM slot!", __func__); + errno = ENOENT; + return -1; + } + 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; + 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; } diff --git a/components/bt/host/bluedroid/stack/btu/btu_init.c b/components/bt/host/bluedroid/stack/btu/btu_init.c index daf5fdadb9..15b7fdbbc0 100644 --- a/components/bt/host/bluedroid/stack/btu/btu_init.c +++ b/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); +} diff --git a/components/bt/host/bluedroid/stack/include/stack/btu.h b/components/bt/host/bluedroid/stack/include/stack/btu.h index fd5d1c989d..9f926b36c0 100644 --- a/components/bt/host/bluedroid/stack/include/stack/btu.h +++ b/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 }