diff --git a/components/bt/host/bluedroid/api/esp_spp_api.c b/components/bt/host/bluedroid/api/esp_spp_api.c index fb7f9b6019..040fe4a469 100644 --- a/components/bt/host/bluedroid/api/esp_spp_api.c +++ b/components/bt/host/bluedroid/api/esp_spp_api.c @@ -133,7 +133,8 @@ esp_err_t esp_spp_start_srv(esp_spp_sec_t sec_mask, btc_spp_args_t arg; ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED); - if (strlen(name) > ESP_SPP_SERVER_NAME_MAX) { + if (name == NULL || strlen(name) > ESP_SPP_SERVER_NAME_MAX) { + LOG_ERROR("Invalid server name!\n"); return ESP_ERR_INVALID_ARG; } @@ -157,13 +158,34 @@ esp_err_t esp_spp_start_srv(esp_spp_sec_t sec_mask, esp_err_t esp_spp_stop_srv(void) { btc_msg_t msg; + btc_spp_args_t arg; ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED); msg.sig = BTC_SIG_API_CALL; msg.pid = BTC_PID_SPP; msg.act = BTC_SPP_ACT_STOP_SRV; + arg.stop_srv.scn = BTC_SPP_INVALID_SCN; - return (btc_transfer_context(&msg, NULL, sizeof(btc_spp_args_t), NULL) == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); + return (btc_transfer_context(&msg, &arg, sizeof(btc_spp_args_t), NULL) == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); +} + +esp_err_t esp_spp_stop_srv_scn(uint8_t scn) +{ + btc_msg_t msg; + btc_spp_args_t arg; + ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED); + + if ((scn == 0) || (scn >= PORT_MAX_RFC_PORTS)) { + LOG_ERROR("Invalid SCN!\n"); + return ESP_ERR_INVALID_ARG; + } + + msg.sig = BTC_SIG_API_CALL; + msg.pid = BTC_PID_SPP; + msg.act = BTC_SPP_ACT_STOP_SRV; + arg.stop_srv.scn = scn; + + return (btc_transfer_context(&msg, &arg, sizeof(btc_spp_args_t), NULL) == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); } 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 afbdde20e0..9df1e58a71 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 @@ -26,11 +26,12 @@ typedef enum { ESP_SPP_SUCCESS = 0, /*!< Successful operation. */ ESP_SPP_FAILURE, /*!< Generic failure. */ ESP_SPP_BUSY, /*!< Temporarily can not handle this request. */ - ESP_SPP_NO_DATA, /*!< no data. */ + ESP_SPP_NO_DATA, /*!< No data */ ESP_SPP_NO_RESOURCE, /*!< No more resource */ ESP_SPP_NEED_INIT, /*!< SPP module shall init first */ ESP_SPP_NEED_DEINIT, /*!< SPP module shall deinit first */ - ESP_SPP_NO_CONNECTION, /*!< connection may have been closed */ + ESP_SPP_NO_CONNECTION, /*!< Connection may have been closed */ + ESP_SPP_NO_SERVER, /*!< No SPP server */ } esp_spp_status_t; /* Security Setting Mask @@ -101,9 +102,10 @@ typedef union { * @brief SPP_DISCOVERY_COMP_EVT */ struct spp_discovery_comp_evt_param { - esp_spp_status_t status; /*!< status */ - uint8_t scn_num; /*!< The num of scn_num */ - uint8_t scn[ESP_SPP_MAX_SCN]; /*!< channel # */ + esp_spp_status_t status; /*!< status */ + uint8_t scn_num; /*!< The num of scn_num */ + uint8_t scn[ESP_SPP_MAX_SCN]; /*!< channel # */ + const char *service_name[ESP_SPP_MAX_SCN]; /*!< service_name */ } disc_comp; /*!< SPP callback param of SPP_DISCOVERY_COMP_EVT */ /** @@ -143,6 +145,7 @@ typedef union { esp_spp_status_t status; /*!< status */ uint32_t handle; /*!< The connection handle */ uint8_t sec_id; /*!< security ID used by this server */ + uint8_t scn; /*!< Server channel number */ bool use_co; /*!< TRUE to use co_rfc_data */ } start; /*!< SPP callback param of ESP_SPP_START_EVT */ @@ -151,6 +154,7 @@ typedef union { */ struct spp_srv_stop_evt_param { esp_spp_status_t status; /*!< status */ + uint8_t scn; /*!< Server channel number */ } srv_stop; /*!< SPP callback param of ESP_SPP_SRV_STOP_EVT */ /** @@ -304,7 +308,7 @@ esp_err_t esp_spp_disconnect(uint32_t handle); esp_err_t esp_spp_start_srv(esp_spp_sec_t sec_mask, esp_spp_role_t role, uint8_t local_scn, const char *name); /** - * @brief This function stops a SPP server. + * @brief This function stops all SPP servers. * The operation will close all active SPP connection first, then the callback function will be called * with ESP_SPP_CLOSE_EVT, and the number of ESP_SPP_CLOSE_EVT is equal to the number of connection. * When the operation is completed, the callback is called with ESP_SPP_SRV_STOP_EVT. @@ -314,8 +318,24 @@ esp_err_t esp_spp_start_srv(esp_spp_sec_t sec_mask, esp_spp_role_t role, uint8_t * - ESP_OK: success * - other: failed */ + esp_err_t esp_spp_stop_srv(void); +/** + * @brief This function stops a specific SPP server. + * The operation will close all active SPP connection first on the specific SPP server, then the callback function will be called + * with ESP_SPP_CLOSE_EVT, and the number of ESP_SPP_CLOSE_EVT is equal to the number of connection. + * When the operation is completed, the callback is called with ESP_SPP_SRV_STOP_EVT. + * This funciton must be called after esp_spp_init() successful and before esp_spp_deinit(). + * + * @param[in] scn: Server channel number. + * + * @return + * - ESP_OK: success + * - other: failed + */ +esp_err_t esp_spp_stop_srv_scn(uint8_t scn); + /** * @brief This function is used to write data, only for ESP_SPP_MODE_CB. * When this function need to be called repeatedly, it is strongly recommended to call this function again after 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 61042144ab..b83a9df5c5 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 @@ -172,9 +172,10 @@ typedef struct { /* data associated with BTA_JV_DISCOVERY_COMP_EVT_ */ typedef struct { - tBTA_JV_STATUS status; /* Whether the operation succeeded or failed. */ - UINT8 scn_num; /* num of channel */ - UINT8 scn[BTA_JV_MAX_SCN]; /* channel # */ + tBTA_JV_STATUS status; /* Whether the operation succeeded or failed. */ + UINT8 scn_num; /* num of channel */ + UINT8 scn[BTA_JV_MAX_SCN]; /* channel # */ + const char *service_name[BTA_JV_MAX_SCN]; /* service_name */ } tBTA_JV_DISCOVERY_COMP; /* data associated with BTA_JV_CREATE_RECORD_EVT */ @@ -305,6 +306,7 @@ typedef struct { tBTA_JV_STATUS status; /* Whether the operation succeeded or failed. */ UINT32 handle; /* The connection handle */ UINT8 sec_id; /* security ID used by this server */ + UINT8 scn; /* Server channe number */ BOOLEAN use_co; /* TRUE to use co_rfc_data */ } tBTA_JV_RFCOMM_START; @@ -376,8 +378,9 @@ typedef struct { /* data associated with BTA_JV_FREE_SCN_EVT */ typedef struct { - tBTA_JV_STATUS status; /* Status of the operation */ - tBTA_JV_SERVER_STATUS server_status; + tBTA_JV_STATUS status; /* Status of the operation */ + tBTA_JV_SERVER_STATUS server_status; /* Server status */ + UINT8 scn; /* Server channe number */ } tBTA_JV_FREE_SCN; 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 4060d0795f..f4106bbecd 100644 --- a/components/bt/host/bluedroid/bta/jv/bta_jv_act.c +++ b/components/bt/host/bluedroid/bta/jv/bta_jv_act.c @@ -856,6 +856,7 @@ void bta_jv_free_scn(tBTA_JV_MSG *p_data) tBTA_JV_FREE_SCN evt_data = { .status = BTA_JV_SUCCESS, .server_status = BTA_JV_SERVER_STATUS_MAX, + .scn = scn }; tBTA_JV_FREE_SCN_USER_DATA *user_data = NULL; @@ -949,6 +950,7 @@ static void bta_jv_start_discovery_cback(UINT16 result, void *user_data) status = BTA_JV_FAILURE; if (result == SDP_SUCCESS || result == SDP_DB_FULL) { tSDP_DISC_REC *p_sdp_rec = NULL; + tSDP_DISC_ATTR *p_attr = NULL; tSDP_PROTOCOL_ELEM pe; logu("bta_jv_cb.uuid", bta_jv_cb.uuid.uu.uuid128); tBT_UUID su = shorten_sdp_uuid(&bta_jv_cb.uuid); @@ -957,7 +959,13 @@ static void bta_jv_start_discovery_cback(UINT16 result, void *user_data) p_sdp_rec = SDP_FindServiceUUIDInDb(p_bta_jv_cfg->p_sdp_db, &su, p_sdp_rec); APPL_TRACE_DEBUG("p_sdp_rec:%p", p_sdp_rec); if (p_sdp_rec && SDP_FindProtocolListElemInRec(p_sdp_rec, UUID_PROTOCOL_RFCOMM, &pe)){ - dcomp.scn[dcomp.scn_num++] = (UINT8) pe.params[0]; + dcomp.scn[dcomp.scn_num] = (UINT8) pe.params[0]; + if ((p_attr = SDP_FindAttributeInRec(p_sdp_rec, ATTR_ID_SERVICE_NAME)) != NULL) { + dcomp.service_name[dcomp.scn_num] = (char *)p_attr->attr_value.v.array; + } else { + dcomp.service_name[dcomp.scn_num] = NULL; + } + dcomp.scn_num++; status = BTA_JV_SUCCESS; } } while (p_sdp_rec); @@ -2154,6 +2162,7 @@ void bta_jv_rfcomm_start_server(tBTA_JV_MSG *p_data) evt_data.status = BTA_JV_SUCCESS; evt_data.handle = p_pcb->handle; evt_data.sec_id = sec_id; + evt_data.scn = rs->local_scn; evt_data.use_co = TRUE; PORT_ClearKeepHandleFlag(handle); 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 d3c8a49382..a344305225 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 @@ -28,6 +28,8 @@ #define ESP_SPP_RINGBUF_SIZE 1000 +#define BTC_SPP_INVALID_SCN 0x00 + typedef enum { BTC_SPP_ACT_INIT = 0, BTC_SPP_ACT_UNINIT, @@ -74,6 +76,10 @@ typedef union { UINT8 max_session; char name[ESP_SPP_SERVER_NAME_MAX + 1]; } start_srv; + //BTC_SPP_ACT_STOP_SRV + struct stop_srv_arg { + UINT8 scn; + } stop_srv; //BTC_SPP_ACT_WRITE struct write_arg { UINT32 handle; 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 31aca9f1af..a8fe25e352 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 @@ -265,6 +265,10 @@ static void btc_create_server_fail_cb(void) { esp_spp_cb_param_t param; param.start.status = ESP_SPP_FAILURE; + param.start.handle = 0; + param.start.sec_id = 0; + param.start.scn = BTC_SPP_INVALID_SCN; + param.start.use_co = FALSE; btc_spp_cb_to_app(ESP_SPP_START_EVT, ¶m); } @@ -531,6 +535,7 @@ static void btc_spp_uninit(void) esp_spp_cb_param_t param; BTC_TRACE_ERROR("%s unable to malloc user data!", __func__); param.srv_stop.status = ESP_SPP_NO_RESOURCE; + param.srv_stop.scn = spp_local_param.spp_slots[i]->scn; 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, @@ -672,61 +677,117 @@ static void btc_spp_start_srv(btc_spp_args_t *arg) if (ret != ESP_SPP_SUCCESS) { esp_spp_cb_param_t param; param.start.status = ret; + param.start.handle = 0; + param.start.sec_id = 0; + param.start.scn = BTC_SPP_INVALID_SCN; + param.start.use_co = FALSE; btc_spp_cb_to_app(ESP_SPP_START_EVT, ¶m); } } -static void btc_spp_stop_srv(void) +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); + if (arg->stop_srv.scn == BTC_SPP_INVALID_SCN) { + is_remove_all = true; + } + do { if (!is_spp_init()) { BTC_TRACE_ERROR("%s SPP have not been init\n", __func__); ret = ESP_SPP_NEED_INIT; break; } + if (srv_scn_arr == NULL) { + BTC_TRACE_ERROR("%s malloc srv_scn_arr failed\n", __func__); + ret = ESP_SPP_NO_RESOURCE; + 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); + // [1] find all server + for (i = 1; i <= MAX_RFC_PORTS; i++) { + if (spp_local_param.spp_slots[i] != NULL && !spp_local_param.spp_slots[i]->connected && + spp_local_param.spp_slots[i]->sdp_handle > 0) { + if (is_remove_all) { + srv_scn_arr[srv_cnt++] = spp_local_param.spp_slots[i]->scn; + } else if (spp_local_param.spp_slots[i]->scn == arg->stop_srv.scn) { + srv_scn_arr[srv_cnt++] = spp_local_param.spp_slots[i]->scn; + 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); - } + if (srv_cnt == 0) { + if (is_remove_all) { + BTC_TRACE_ERROR("%s can not find any server!\n", __func__); + } else { + BTC_TRACE_ERROR("%s can not find server:%d!\n", __func__, arg->stop_srv.scn); + } + ret = ESP_SPP_NO_SERVER; + break; + } - 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); + // [2] remove all local related connection + for (j = 0; j < srv_cnt; j++) { + for (i = 1; i <= MAX_RFC_PORTS; i++) { + if (spp_local_param.spp_slots[i] != NULL && spp_local_param.spp_slots[i]->connected && + spp_local_param.spp_slots[i]->sdp_handle > 0 && + spp_local_param.spp_slots[i]->scn == srv_scn_arr[j]) { + 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); } + } + } - 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); + // [3] remove all server + for (j = 0; j < srv_cnt; j++) { + for (i = 1; i <= MAX_RFC_PORTS; i++) { + if (spp_local_param.spp_slots[i] != NULL && !spp_local_param.spp_slots[i]->connected && + spp_local_param.spp_slots[i]->sdp_handle > 0 && + spp_local_param.spp_slots[i]->scn == srv_scn_arr[j]) { + 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; + param.srv_stop.scn = spp_local_param.spp_slots[i]->scn; + 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_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); + } while (0); if (ret != ESP_SPP_SUCCESS) { esp_spp_cb_param_t param; param.srv_stop.status = ret; + param.srv_stop.scn = BTC_SPP_INVALID_SCN; btc_spp_cb_to_app(ESP_SPP_SRV_STOP_EVT, ¶m); } + + if (srv_scn_arr) { + osi_free(srv_scn_arr); + srv_scn_arr = NULL; + } } static void btc_spp_write(btc_spp_args_t *arg) @@ -849,7 +910,7 @@ void btc_spp_call_handler(btc_msg_t *msg) btc_spp_start_srv(arg); break; case BTC_SPP_ACT_STOP_SRV: - btc_spp_stop_srv(); + btc_spp_stop_srv(arg); break; case BTC_SPP_ACT_WRITE: btc_spp_write(arg); @@ -876,6 +937,8 @@ void btc_spp_cb_handler(btc_msg_t *msg) param.disc_comp.status = p_data->disc_comp.status; param.disc_comp.scn_num = p_data->disc_comp.scn_num; memcpy(param.disc_comp.scn, p_data->disc_comp.scn, p_data->disc_comp.scn_num); + memcpy(param.disc_comp.service_name, p_data->disc_comp.service_name, + p_data->disc_comp.scn_num * sizeof(const char *)); btc_spp_cb_to_app(ESP_SPP_DISCOVERY_COMP_EVT, ¶m); break; case BTA_JV_RFCOMM_CL_INIT_EVT: @@ -909,6 +972,7 @@ void btc_spp_cb_handler(btc_msg_t *msg) param.start.status = p_data->rfc_start.status; param.start.handle = p_data->rfc_start.handle; param.start.sec_id = p_data->rfc_start.sec_id; + param.start.scn = p_data->rfc_start.scn; param.start.use_co = p_data->rfc_start.use_co; btc_spp_cb_to_app(ESP_SPP_START_EVT, ¶m); break; @@ -1130,6 +1194,7 @@ void btc_spp_cb_handler(btc_msg_t *msg) case BTA_JV_FREE_SCN_EVT: if (p_data->free_scn.server_status == BTA_JV_SERVER_RUNNING) { param.srv_stop.status = p_data->free_scn.status; + param.srv_stop.scn = p_data->free_scn.scn; btc_spp_cb_to_app(ESP_SPP_SRV_STOP_EVT, ¶m); } break;