Просмотр исходного кода

add API esp_spp_stop_srv(), fix the error parameter in esp-idf/examples/bluetooth/bluedroid/classic_bt/bt_spp_initiator/main/example_spp_initiator_demo.c and fix collection of SPP

Closes https://github.com/espressif/esp-idf/issues/5409
Closes https://github.com/espressif/esp-idf/pull/5408

See merge request espressif/esp-idf!9114
liqigan 5 лет назад
Родитель
Сommit
45c4fef890

+ 12 - 0
components/bt/host/bluedroid/api/esp_spp_api.c

@@ -154,6 +154,18 @@ esp_err_t esp_spp_start_srv(esp_spp_sec_t sec_mask,
     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(void)
+{
+    btc_msg_t msg;
+    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;
+
+    return (btc_transfer_context(&msg, NULL, sizeof(btc_spp_args_t), NULL) == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL);
+}
+
 
 esp_err_t esp_spp_write(uint32_t handle, int len, uint8_t *p_data)
 {

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

@@ -57,6 +57,7 @@ typedef enum {
  */
 typedef enum {
     ESP_SPP_INIT_EVT                    = 0,                /*!< When SPP is inited, the event comes */
+    ESP_SPP_UNINIT_EVT                  = 1,                /*!< When SPP is uninited, the event comes */
     ESP_SPP_DISCOVERY_COMP_EVT          = 8,                /*!< When SDP discovery complete, the event comes */
     ESP_SPP_OPEN_EVT                    = 26,               /*!< When SPP Client connection open, the event comes */
     ESP_SPP_CLOSE_EVT                   = 27,               /*!< When SPP connection closed, the event comes */
@@ -66,6 +67,7 @@ typedef enum {
     ESP_SPP_CONG_EVT                    = 31,               /*!< When SPP connection congestion status changed, the event comes, only for ESP_SPP_MODE_CB */
     ESP_SPP_WRITE_EVT                   = 33,               /*!< When SPP write operation completes, the event comes, only for ESP_SPP_MODE_CB */
     ESP_SPP_SRV_OPEN_EVT                = 34,               /*!< When SPP Server connection open, the event comes */
+    ESP_SPP_SRV_STOP_EVT                = 35,               /*!< When SPP server stopped, the event comes */
 } esp_spp_cb_event_t;
 
 
@@ -80,6 +82,13 @@ typedef union {
         esp_spp_status_t    status;         /*!< status */
     } init;                                 /*!< SPP callback param of SPP_INIT_EVT */
 
+    /**
+     * @brief SPP_UNINIT_EVT
+     */
+    struct spp_uninit_evt_param {
+        esp_spp_status_t    status;         /*!< status */
+    } uninit;                                 /*!< SPP callback param of SPP_UNINIT_EVT */
+
     /**
      * @brief SPP_DISCOVERY_COMP_EVT
      */
@@ -128,6 +137,14 @@ typedef union {
         uint8_t             sec_id;         /*!< security ID used by this server */
         bool                use_co;         /*!< TRUE to use co_rfc_data */
     } start;                                /*!< SPP callback param of ESP_SPP_START_EVT */
+
+    /**
+     * @brief ESP_SPP_SRV_STOP_EVT
+     */
+    struct spp_srv_stop_evt_param {
+        esp_spp_status_t    status;         /*!< status */
+    } srv_stop;                                 /*!< SPP callback param of ESP_SPP_SRV_STOP_EVT */
+
     /**
      * @brief ESP_SPP_CL_INIT_EVT
      */
@@ -273,6 +290,16 @@ 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
+ *              When the server is stopped successfully, the callback is called
+ *              with ESP_SPP_SRV_STOP_EVT.
+ *
+ * @return
+ *              - ESP_OK: success
+ *              - other: failed
+ */
+esp_err_t esp_spp_stop_srv(void);
 
 /**
  * @brief       This function is used to write data, only for ESP_SPP_MODE_CB.

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

@@ -129,6 +129,7 @@ typedef UINT8 tBTA_JV_CONN_STATE;
 /* Java I/F callback events */
 /* events received by tBTA_JV_DM_CBACK */
 #define BTA_JV_ENABLE_EVT           0  /* JV enabled */
+#define BTA_JV_DISABLE_EVT          1  /* JV disabled */
 #define BTA_JV_GET_SCN_EVT          6  /* Reserved an SCN */
 #define BTA_JV_GET_PSM_EVT          7  /* Reserved a PSM */
 #define BTA_JV_DISCOVERY_COMP_EVT   8  /* SDP discovery complete */
@@ -155,7 +156,8 @@ typedef UINT8 tBTA_JV_CONN_STATE;
 #define BTA_JV_RFCOMM_READ_EVT      32 /* the result for BTA_JvRfcommRead */
 #define BTA_JV_RFCOMM_WRITE_EVT     33 /* the result for BTA_JvRfcommWrite*/
 #define BTA_JV_RFCOMM_SRV_OPEN_EVT  34 /* open status of Server RFCOMM connection */
-#define BTA_JV_MAX_EVT              35 /* max number of JV events */
+#define BTA_JV_FREE_SCN_EVT         35 /* FREE an SCN */
+#define BTA_JV_MAX_EVT              36 /* max number of JV events */
 
 typedef UINT16 tBTA_JV_EVT;
 
@@ -356,6 +358,24 @@ typedef struct {
     tBTA_JV_CONN_STATE  state;  /* JV connection stata */
 } tBTA_JV_NOTIFY_PM_STATE_CHANGE;
 
+/* indicate server at which status */
+typedef enum {
+    BTA_JV_SERVER_START_FAILED,
+    BTA_JV_SERVER_RUNNING,
+    BTA_JV_SERVER_STATUS_MAX,
+} tBTA_JV_SERVER_STATUS;
+
+typedef struct {
+    tBTA_JV_SERVER_STATUS   server_status;
+    UINT32                  slot_id;
+}tBTA_JV_FREE_SCN_USER_DATA;
+
+/* 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_FREE_SCN;
+
 
 /* union of data associated with JV callback */
 typedef union {
@@ -382,6 +402,7 @@ typedef union {
     tBTA_JV_RFCOMM_WRITE    rfc_write;      /* BTA_JV_RFCOMM_WRITE_EVT */
     tBTA_JV_DATA_IND        data_ind;       /* BTA_JV_L2CAP_DATA_IND_EVT
                                                BTA_JV_RFCOMM_DATA_IND_EVT */
+    tBTA_JV_FREE_SCN        free_scn;       /* BTA_JV_FREE_SCN_EVT */
     tBTA_JV_LE_DATA_IND      le_data_ind;   /* BTA_JV_L2CAP_LE_DATA_IND_EVT */
     tBTA_JV_L2CAP_LE_OPEN      l2c_le_open;       /* BTA_JV_L2CAP_OPEN_EVT */
     tBTA_JV_L2CAP_WRITE_FIXED  l2c_write_fixed;      /* BTA_JV_L2CAP_WRITE_FIXED_EVT */
@@ -424,12 +445,25 @@ extern tBTA_JV_STATUS BTA_JvEnable(tBTA_JV_DM_CBACK *p_cback);
 **
 ** Function         BTA_JvDisable
 **
-** Description      Disable the Java I/F
+** Description      Disable the Java I/F. When the enable
+**                  operation is complete the callback function will be
+**                  called with a BTA_JV_DISABLE_EVT.
+**
+** Returns          void
+**
+*******************************************************************************/
+extern void BTA_JvDisable(tBTA_JV_RFCOMM_CBACK *p_cback);
+
+/*******************************************************************************
+**
+** Function         BTA_JvFree
+**
+** Description      Free JV configuration
 **
 ** Returns          void
 **
 *******************************************************************************/
-extern void BTA_JvDisable(void);
+extern void BTA_JvFree(void);
 
 /*******************************************************************************
 **
@@ -484,12 +518,17 @@ extern tBTA_JV_STATUS BTA_JvGetChannelId(int conn_type, void *user_data,
 **
 ** Description      This function frees a SCN/PSM that was used
 **                  by an application running over RFCOMM or L2CAP.
+** Parameters
+**   channel        The channel to free
+**   conn_type      one of BTA_JV_CONN_TYPE_
+**   p_cback        tBTA_JV_RFCOMM_CBACK is called with BTA_JV_FREE_SCN_EVT when server frees a SCN/PSM
+**   user_data      indicate the RFCOMM server status
 **
 ** Returns          BTA_JV_SUCCESS, if the request is being processed.
 **                  BTA_JV_FAILURE, otherwise.
 **
 *******************************************************************************/
-extern tBTA_JV_STATUS BTA_JvFreeChannel(UINT16 channel, int conn_type);
+extern tBTA_JV_STATUS BTA_JvFreeChannel(UINT16 channel, int conn_type, tBTA_JV_RFCOMM_CBACK *p_cback, void *user_data);
 
 /*******************************************************************************
 **
@@ -769,7 +808,7 @@ extern tBTA_JV_STATUS BTA_JvRfcommConnect(tBTA_SEC sec_mask,
 **                  BTA_JV_FAILURE, otherwise.
 **
 *******************************************************************************/
-extern tBTA_JV_STATUS BTA_JvRfcommClose(UINT32 handle, void *user_data);
+extern tBTA_JV_STATUS BTA_JvRfcommClose(UINT32 handle, tBTA_JV_RFCOMM_CBACK *p_cback, void *user_data);
 
 /*******************************************************************************
 **

+ 111 - 5
components/bt/host/bluedroid/bta/jv/bta_jv_act.c

@@ -115,6 +115,10 @@ static void bta_jv_pm_state_change(tBTA_JV_PM_CB *p_cb, const tBTA_JV_CONN_STATE
 tBTA_JV_STATUS bta_jv_set_pm_conn_state(tBTA_JV_PM_CB *p_cb, const tBTA_JV_CONN_STATE
                                         new_st);
 
+static int find_rfc_pcb(void *user_data, tBTA_JV_RFC_CB **cb, tBTA_JV_PCB **pcb);
+static void bta_jv_port_mgmt_sr_cback(UINT32 code, UINT16 port_handle);
+static void bta_jv_port_event_sr_cback(UINT32 code, UINT16 port_handle);
+static int bta_jv_port_data_co_cback(UINT16 port_handle, UINT8 *buf, UINT16 len, int type);
 /*******************************************************************************
 **
 ** Function     bta_jv_alloc_sec_id
@@ -288,6 +292,12 @@ static tBTA_JV_STATUS bta_jv_free_rfc_cb(tBTA_JV_RFC_CB *p_cb, tBTA_JV_PCB *p_pc
     BOOLEAN remove_server = FALSE;
     int close_pending = 0;
 
+    UINT8 used = 0, i, listen = 0;
+    tPORT_STATE port_state;
+    UINT32 event_mask = BTA_JV_RFC_EV_MASK;
+    UINT32 scn_num = (UINT32)p_cb->scn;
+    tBTA_JV evt_data;
+
     if (!p_cb || !p_pcb) {
         APPL_TRACE_ERROR("bta_jv_free_sr_rfc_cb, p_cb or p_pcb cannot be null");
         return BTA_JV_FAILURE;
@@ -363,6 +373,57 @@ static tBTA_JV_STATUS bta_jv_free_rfc_cb(tBTA_JV_RFC_CB *p_cb, tBTA_JV_PCB *p_pc
         }
         p_pcb->handle = 0;
         p_cb->curr_sess--;
+
+        if ((p_cb->max_sess > 1) &&
+            (p_cb->scn != 0) &&
+            (p_cb->curr_sess == p_cb->max_sess - 1)) {
+
+            for (i = 0; i < p_cb->max_sess; i++) {
+                if (p_cb->rfc_hdl[i] != 0) {
+                    p_pcb = &bta_jv_cb.port_cb[p_cb->rfc_hdl[i] - 1];
+                    if (p_pcb->state == BTA_JV_ST_SR_LISTEN) {
+                        listen++;
+                    }
+                    used++;
+                }
+            }
+            APPL_TRACE_DEBUG("%s max_sess=%d used:%d curr_sess:%d, listen:%d si:%d",
+                             __func__, p_cb->max_sess, used, p_cb->curr_sess, listen, si);
+            if (used < p_cb->max_sess &&
+                listen == 0 &&
+                0 <= si &&
+                si < BTA_JV_MAX_RFC_SR_SESSION) {
+                /* make sure the server has a listen port */
+                if ((RFCOMM_CreateConnection(p_cb->sec_id, p_cb->scn, TRUE,
+                                             BTA_JV_DEF_RFC_MTU, (UINT8 *)bd_addr_any, &(p_cb->rfc_hdl[si]), bta_jv_port_mgmt_sr_cback) == PORT_SUCCESS) &&
+                    (p_cb->rfc_hdl[si] != 0)) {
+                    p_cb->curr_sess++;
+                    p_pcb = &bta_jv_cb.port_cb[p_cb->rfc_hdl[si] - 1];
+                    p_pcb->state = BTA_JV_ST_SR_LISTEN;
+                    p_pcb->port_handle = p_cb->rfc_hdl[si];
+                    // p_pcb->user_data = p_pcb_open->user_data;
+
+                    PORT_ClearKeepHandleFlag(p_pcb->port_handle);
+                    PORT_SetEventCallback(p_pcb->port_handle, bta_jv_port_event_sr_cback);
+                    PORT_SetDataCOCallback(p_pcb->port_handle, bta_jv_port_data_co_cback);
+                    PORT_SetEventMask(p_pcb->port_handle, event_mask);
+                    PORT_GetState(p_pcb->port_handle, &port_state);
+
+                    port_state.fc_type = (PORT_FC_CTS_ON_INPUT | PORT_FC_CTS_ON_OUTPUT);
+
+                    PORT_SetState(p_pcb->port_handle, &port_state);
+                    p_pcb->handle = BTA_JV_RFC_H_S_TO_HDL(p_cb->handle, si);
+                    APPL_TRACE_DEBUG("%s: p_pcb->handle:0x%x, curr_sess:%d", __func__,
+                                     p_pcb->handle, p_cb->curr_sess);
+
+                    evt_data.rfc_srv_open.handle = 0;
+                    evt_data.rfc_srv_open.new_listen_handle = p_pcb->handle;
+                    evt_data.rfc_srv_open.status = BTA_JV_SUCCESS;
+                    p_pcb->user_data = p_cb->p_cback(BTA_JV_RFCOMM_SRV_OPEN_EVT, &evt_data, (void *)scn_num);
+                }
+            }
+        }
+
         if (p_cb->curr_sess == 0) {
             p_cb->scn = 0;
             bta_jv_free_sec_id(&p_cb->sec_id);
@@ -673,7 +734,12 @@ void bta_jv_enable(tBTA_JV_MSG *p_data)
 *******************************************************************************/
 void bta_jv_disable (tBTA_JV_MSG *p_data)
 {
-    UNUSED(p_data);
+    tBTA_JV_STATUS evt_data;
+    evt_data = BTA_JV_SUCCESS;
+    // UNUSED(p_data);
+    if (p_data->disable.p_cback) {
+        p_data->disable.p_cback(BTA_JV_DISABLE_EVT, (tBTA_JV *)&evt_data, NULL);
+    }
 }
 
 
@@ -782,7 +848,16 @@ void bta_jv_get_channel_id(tBTA_JV_MSG *p_data)
 *******************************************************************************/
 void bta_jv_free_scn(tBTA_JV_MSG *p_data)
 {
-    UINT16   scn = p_data->free_channel.scn;
+    tBTA_JV_API_FREE_CHANNEL *fc = &(p_data->free_channel);
+    UINT16   scn = fc->scn;
+    tBTA_JV_FREE_SCN evt_data = {
+        .status = BTA_JV_SUCCESS,
+        .server_status = BTA_JV_SERVER_STATUS_MAX,
+    };
+
+    tBTA_JV_FREE_SCN_USER_DATA *user_data = NULL;
+    tBTA_JV_RFC_CB *p_cb = NULL;
+    tBTA_JV_PCB *p_pcb = NULL;
 
     switch (p_data->free_channel.type) {
     case BTA_JV_CONN_TYPE_RFCOMM: {
@@ -802,6 +877,20 @@ void bta_jv_free_scn(tBTA_JV_MSG *p_data)
     default:
         break;
     }
+
+    if (fc->user_data)
+    {
+        user_data = (tBTA_JV_FREE_SCN_USER_DATA *)fc->user_data;
+        evt_data.server_status = user_data->server_status;
+        if (user_data->server_status == BTA_JV_SERVER_RUNNING && find_rfc_pcb((void *)user_data->slot_id, &p_cb, &p_pcb)) {
+            /* if call bta_jv_rfcomm_stop_server successfully, find_rfc_pcb shall return false */
+            evt_data.status = BTA_JV_FAILURE;
+        }
+
+        if (fc->p_cback) {
+            fc->p_cback(BTA_JV_FREE_SCN_EVT, (tBTA_JV *)&evt_data, (void *)user_data);
+        }
+    }
 }
 static inline tBT_UUID shorten_sdp_uuid(const tBT_UUID *u)
 {
@@ -1596,6 +1685,7 @@ static void bta_jv_port_mgmt_cl_cback(UINT32 code, UINT16 port_handle)
         evt_data.rfc_close.async = TRUE;
         if (p_pcb->state == BTA_JV_ST_CL_CLOSING) {
             evt_data.rfc_close.async = FALSE;
+            evt_data.rfc_close.status = BTA_JV_SUCCESS;
         }
         //p_pcb->state = BTA_JV_ST_NONE;
         //p_pcb->cong = FALSE;
@@ -1760,9 +1850,10 @@ void bta_jv_rfcomm_close(tBTA_JV_MSG *p_data)
     tBTA_JV_API_RFCOMM_CLOSE *cc = &(p_data->rfcomm_close);
     tBTA_JV_RFC_CB           *p_cb = NULL;
     tBTA_JV_PCB              *p_pcb = NULL;
-    APPL_TRACE_DEBUG("bta_jv_rfcomm_close, rfc handle:%d", cc->handle);
+    tBTA_JV                   evt_data;
+    APPL_TRACE_DEBUG("%s, rfc handle:%d",__func__, cc->handle);
     if (!cc->handle) {
-        APPL_TRACE_ERROR("bta_jv_rfcomm_close, rfc handle is null");
+        APPL_TRACE_ERROR("%s, rfc handle is null", __func__);
         return;
     }
 
@@ -1770,8 +1861,21 @@ void bta_jv_rfcomm_close(tBTA_JV_MSG *p_data)
     if (!find_rfc_pcb(user_data, &p_cb, &p_pcb)) {
         return;
     }
+    if(cc->p_cback) {
+        evt_data.rfc_close.status = BTA_JV_SUCCESS;
+        evt_data.rfc_close.port_status = PORT_LOCAL_CLOSED;
+        evt_data.rfc_close.handle = cc->handle;
+        evt_data.rfc_close.async = TRUE;
+        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 ||
+                      p_pcb->state == BTA_JV_ST_CL_OPENING)) {
+            evt_data.rfc_close.async = FALSE;
+        }
+        cc->p_cback(BTA_JV_RFCOMM_CLOSE_EVT, (tBTA_JV *)&evt_data, user_data);
+    }
     bta_jv_free_rfc_cb(p_cb, p_pcb);
-    APPL_TRACE_DEBUG("bta_jv_rfcomm_close: sec id in use:%d, rfc_cb in use:%d",
+    APPL_TRACE_DEBUG("%s: sec id in use:%d, rfc_cb in use:%d",__func__, 
                      get_sec_id_used(), get_rfc_cb_used());
 }
 
@@ -1976,6 +2080,8 @@ static tBTA_JV_PCB *bta_jv_add_rfc_port(tBTA_JV_RFC_CB *p_cb, tBTA_JV_PCB *p_pcb
                                  p_pcb->handle, p_cb->curr_sess);
             }
         } else {
+            /* avoid p_pcb always points to the last element of rfc_hdl */
+            p_pcb = p_pcb_open;
             APPL_TRACE_ERROR("bta_jv_add_rfc_port, cannot create new rfc listen port");
         }
     }

+ 27 - 8
components/bt/host/bluedroid/bta/jv/bta_jv_api.c

@@ -109,17 +109,30 @@ tBTA_JV_STATUS BTA_JvEnable(tBTA_JV_DM_CBACK *p_cback)
 ** Returns          void
 **
 *******************************************************************************/
-void BTA_JvDisable(void)
+void BTA_JvDisable(tBTA_JV_RFCOMM_CBACK *p_cback)
 {
-    BT_HDR  *p_buf;
+    tBTA_JV_API_DISABLE *p_buf;
 
     APPL_TRACE_API( "BTA_JvDisable");
     bta_sys_deregister(BTA_ID_JV);
-    if ((p_buf = (BT_HDR *) osi_malloc(sizeof(BT_HDR))) != NULL) {
-        p_buf->event = BTA_JV_API_DISABLE_EVT;
+    if ((p_buf = (tBTA_JV_API_DISABLE *) osi_malloc(sizeof(tBTA_JV_API_DISABLE))) != NULL) {
+        p_buf->hdr.event = BTA_JV_API_DISABLE_EVT;
+        p_buf->p_cback = p_cback;
         bta_sys_sendmsg(p_buf);
     }
+}
 
+/*******************************************************************************
+**
+** Function         BTA_JvFree
+**
+** Description      Free JV configuration
+**
+** Returns          void
+**
+*******************************************************************************/
+void BTA_JvFree(void)
+{
 #if BTA_DYNAMIC_MEMORY == TRUE
     /* Free buffer for JV configuration structure */
     osi_free(p_bta_jv_cfg->p_sdp_raw_data);
@@ -216,12 +229,14 @@ tBTA_JV_STATUS BTA_JvGetChannelId(int conn_type, void *user_data, INT32 channel)
 ** Parameters
 **   channel        The channel to free
 **   conn_type      one of BTA_JV_CONN_TYPE_
+**   p_cback        tBTA_JV_RFCOMM_CBACK is called with when server
+**   user_data      indicate the RFCOMM server status
 **
 ** Returns          BTA_JV_SUCCESS, if the request is being processed.
 **                  BTA_JV_FAILURE, otherwise.
 **
 *******************************************************************************/
-tBTA_JV_STATUS BTA_JvFreeChannel(UINT16 channel, int conn_type)
+tBTA_JV_STATUS BTA_JvFreeChannel(UINT16 channel, int conn_type, tBTA_JV_RFCOMM_CBACK *p_cback, void *user_data)
 {
     tBTA_JV_STATUS status = BTA_JV_FAILURE;
     tBTA_JV_API_FREE_CHANNEL *p_msg;
@@ -231,6 +246,8 @@ tBTA_JV_STATUS BTA_JvFreeChannel(UINT16 channel, int conn_type)
         p_msg->hdr.event = BTA_JV_API_FREE_SCN_EVT;
         p_msg->scn       = channel;
         p_msg->type      = conn_type;
+        p_msg->p_cback   = p_cback;
+        p_msg->user_data = user_data;
         bta_sys_sendmsg(p_msg);
         status = BTA_JV_SUCCESS;
     }
@@ -885,19 +902,20 @@ tBTA_JV_STATUS BTA_JvRfcommConnect(tBTA_SEC sec_mask,
 ** Function         BTA_JvRfcommClose
 **
 ** Description      This function closes an RFCOMM connection
-**
+**                  When the connection is established or failed,
+**                  tBTA_JV_RFCOMM_CBACK is called with BTA_JV_RFCOMM_CLOSE_EVT
 ** Returns          BTA_JV_SUCCESS, if the request is being processed.
 **                  BTA_JV_FAILURE, otherwise.
 **
 *******************************************************************************/
-tBTA_JV_STATUS BTA_JvRfcommClose(UINT32 handle, void *user_data)
+tBTA_JV_STATUS BTA_JvRfcommClose(UINT32 handle, tBTA_JV_RFCOMM_CBACK *p_cback, void *user_data)
 {
     tBTA_JV_STATUS status = BTA_JV_FAILURE;
     tBTA_JV_API_RFCOMM_CLOSE *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_JvRfcommClose");
+    APPL_TRACE_API( "%s", __func__);
     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_CLOSE *)osi_malloc(sizeof(tBTA_JV_API_RFCOMM_CLOSE))) != NULL) {
@@ -905,6 +923,7 @@ tBTA_JV_STATUS BTA_JvRfcommClose(UINT32 handle, void *user_data)
         p_msg->handle = handle;
         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->p_cback = p_cback;
         p_msg->user_data = user_data;
         bta_sys_sendmsg(p_msg);
         status = BTA_JV_SUCCESS;

+ 10 - 0
components/bt/host/bluedroid/bta/jv/include/bta_jv_int.h

@@ -80,6 +80,12 @@ typedef struct {
     tBTA_JV_DM_CBACK   *p_cback;
 } tBTA_JV_API_ENABLE;
 
+/* data type for BTA_JV_API_DISABLE_EVT */
+typedef struct {
+    BT_HDR          hdr;
+    tBTA_JV_RFCOMM_CBACK   *p_cback;
+} tBTA_JV_API_DISABLE;
+
 /* data type for BTA_JV_API_START_DISCOVERY_EVT */
 typedef struct {
     BT_HDR      hdr;
@@ -300,6 +306,7 @@ typedef struct {
     UINT32          handle;
     tBTA_JV_RFC_CB  *p_cb;
     tBTA_JV_PCB     *p_pcb;
+    tBTA_JV_RFCOMM_CBACK *p_cback;
     void            *user_data;
 } tBTA_JV_API_RFCOMM_CLOSE;
 
@@ -326,6 +333,8 @@ typedef struct {
     BT_HDR      hdr;
     INT32       type;       /* One of BTA_JV_CONN_TYPE_ */
     UINT16      scn;
+    tBTA_JV_RFCOMM_CBACK *p_cback;
+    void        *user_data;
 } tBTA_JV_API_FREE_CHANNEL;
 
 /* data type for BTA_JV_API_ALLOC_CHANNEL_EVT */
@@ -340,6 +349,7 @@ typedef union {
     /* GKI event buffer header */
     BT_HDR                          hdr;
     tBTA_JV_API_ENABLE              enable;
+    tBTA_JV_API_DISABLE             disable;
     tBTA_JV_API_START_DISCOVERY     start_discovery;
     tBTA_JV_API_ALLOC_CHANNEL       alloc_channel;
     tBTA_JV_API_FREE_CHANNEL        free_channel;

+ 1 - 0
components/bt/host/bluedroid/btc/profile/std/include/btc_spp.h

@@ -35,6 +35,7 @@ typedef enum {
     BTC_SPP_ACT_CONNECT,
     BTC_SPP_ACT_DISCONNECT,
     BTC_SPP_ACT_START_SRV,
+    BTC_SPP_ACT_STOP_SRV,
     BTC_SPP_ACT_WRITE,
 } btc_spp_act_t;
 

+ 236 - 77
components/bt/host/bluedroid/btc/profile/std/spp/btc_spp.c

@@ -29,6 +29,7 @@
 #include <sys/fcntl.h>
 #include "esp_vfs.h"
 #include "esp_vfs_dev.h"
+#include "stack/port_api.h"
 
 #if (defined BTC_SPP_INCLUDED && BTC_SPP_INCLUDED == TRUE)
 
@@ -56,7 +57,7 @@ typedef struct {
 } spp_slot_t;
 
 typedef struct {
-    spp_slot_t *spp_slots[BTA_JV_MAX_RFC_SR_SESSION + 1];
+    spp_slot_t *spp_slots[MAX_RFC_PORTS + 1];
     uint32_t spp_slot_id;
     esp_spp_mode_t spp_mode;
     osi_mutex_t spp_slot_mutex;
@@ -80,7 +81,7 @@ static spp_slot_t *spp_malloc_slot(void)
     if (++spp_local_param.spp_slot_id == 0) {
         spp_local_param.spp_slot_id = 1;
     }
-    for (size_t i = 1; i <= BTA_JV_MAX_RFC_SR_SESSION; i++) {
+    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]) {
@@ -88,6 +89,9 @@ static spp_slot_t *spp_malloc_slot(void)
             }
             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);
@@ -108,7 +112,7 @@ static spp_slot_t *spp_malloc_slot(void)
 
 static spp_slot_t *spp_find_slot_by_id(uint32_t id)
 {
-    for (size_t i = 1; i <= BTA_JV_MAX_RFC_SR_SESSION; i++) {
+    for (size_t i = 1; i <= MAX_RFC_PORTS; i++) {
         if (spp_local_param.spp_slots[i] != NULL && spp_local_param.spp_slots[i]->id == id) {
             return spp_local_param.spp_slots[i];
         }
@@ -118,7 +122,7 @@ static spp_slot_t *spp_find_slot_by_id(uint32_t id)
 
 static spp_slot_t *spp_find_slot_by_handle(uint32_t handle)
 {
-    for (size_t i = 1; i <= BTA_JV_MAX_RFC_SR_SESSION; i++) {
+    for (size_t i = 1; i <= MAX_RFC_PORTS; i++) {
         if (spp_local_param.spp_slots[i] != NULL && spp_local_param.spp_slots[i]->rfc_handle == handle) {
             return spp_local_param.spp_slots[i];
         }
@@ -128,7 +132,7 @@ static spp_slot_t *spp_find_slot_by_handle(uint32_t handle)
 
 static spp_slot_t *spp_find_slot_by_fd(int fd)
 {
-    for (size_t i = 1; i <= BTA_JV_MAX_RFC_SR_SESSION; i++) {
+    for (size_t i = 1; i <= MAX_RFC_PORTS; i++) {
         if (spp_local_param.spp_slots[i] != NULL && spp_local_param.spp_slots[i]->fd == fd) {
             return spp_local_param.spp_slots[i];
         }
@@ -136,6 +140,16 @@ static spp_slot_t *spp_find_slot_by_fd(int fd)
     return NULL;
 }
 
+static spp_slot_t *spp_find_slot_by_scn(uint32_t scn)
+{
+    for (size_t i = 1; i <= MAX_RFC_PORTS; i++) {
+        if (spp_local_param.spp_slots[i] != NULL && spp_local_param.spp_slots[i]->scn == (uint8_t)scn) {
+            return spp_local_param.spp_slots[i];
+        }
+    }
+    return NULL;
+}
+
 static void spp_free_slot(spp_slot_t *slot)
 {
     if (!slot) {
@@ -167,15 +181,6 @@ static void btc_create_server_fail_cb(void)
     btc_spp_cb_to_app(ESP_SPP_START_EVT, &param);
 }
 
-static void btc_disconnect_cb(uint32_t handle)
-{
-    esp_spp_cb_param_t param;
-    param.close.status = ESP_SPP_SUCCESS;
-    param.close.handle = handle;
-    param.close.async = FALSE;
-    btc_spp_cb_to_app(ESP_SPP_CLOSE_EVT, &param);
-}
-
 static void *btc_spp_rfcomm_inter_cb(tBTA_JV_EVT event, tBTA_JV *p_data, void *user_data)
 {
     bt_status_t status;
@@ -184,34 +189,53 @@ static void *btc_spp_rfcomm_inter_cb(tBTA_JV_EVT event, tBTA_JV *p_data, void *u
 
     uint32_t id = (uintptr_t)user_data;
     spp_slot_t *slot, *slot_new;
+    if (!spp_local_param.spp_slot_mutex) {
+        BTC_TRACE_WARNING("%s SPP have been deinit, incoming events ignore!\n", __func__);
+        return new_user_data;
+    }
     osi_mutex_lock(&spp_local_param.spp_slot_mutex, OSI_MUTEX_MAX_TIMEOUT);
     switch (event) {
-    case BTA_JV_RFCOMM_SRV_OPEN_EVT:
+    case BTA_JV_RFCOMM_START_EVT:
         slot = spp_find_slot_by_id(id);
         if (!slot) {
             BTC_TRACE_ERROR("%s unable to find RFCOMM slot!", __func__);
             break;
         }
-        slot_new = spp_malloc_slot();
-        if (!slot_new) {
-            BTC_TRACE_ERROR("%s unable to malloc RFCOMM slot!", __func__);
+        slot->rfc_handle = p_data->rfc_start.handle;
+        slot->rfc_port_handle = BTA_JvRfcommGetPortHdl(p_data->rfc_start.handle);
+        break;
+    case BTA_JV_RFCOMM_SRV_OPEN_EVT:
+        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__);
             break;
         }
-        new_user_data = (void *)(uintptr_t)slot_new->id;
-        slot_new->security = slot->security;
-        slot_new->role = slot->role;
-        slot_new->scn = slot->scn;;
-        slot_new->max_session = slot->max_session;
-        strcpy(slot_new->service_name, slot->service_name);
-        slot_new->sdp_handle = slot->sdp_handle;
-        slot_new->rfc_handle = p_data->rfc_srv_open.new_listen_handle;
-        slot_new->rfc_port_handle = BTA_JvRfcommGetPortHdl(p_data->rfc_srv_open.new_listen_handle);
-
-        memcpy(slot->addr, p_data->rfc_srv_open.rem_bda, ESP_BD_ADDR_LEN);
-        slot->connected = TRUE;
-        slot->rfc_handle = p_data->rfc_srv_open.handle;
-        slot->rfc_port_handle = BTA_JvRfcommGetPortHdl(p_data->rfc_srv_open.handle);
-        BTA_JvSetPmProfile(p_data->rfc_srv_open.handle, BTA_JV_PM_ALL, BTA_JV_CONN_OPEN);
+
+        if (p_data->rfc_srv_open.handle) {
+            new_user_data = (void *)(uintptr_t)slot->id;
+            memcpy(slot->addr, p_data->rfc_srv_open.rem_bda, ESP_BD_ADDR_LEN);
+            slot->connected = TRUE;
+            slot->rfc_handle = p_data->rfc_srv_open.handle;
+            slot->rfc_port_handle = BTA_JvRfcommGetPortHdl(p_data->rfc_srv_open.handle);
+            BTA_JvSetPmProfile(p_data->rfc_srv_open.handle, BTA_JV_PM_ALL, BTA_JV_CONN_OPEN);
+        }
+
+        if (p_data->rfc_srv_open.handle != p_data->rfc_srv_open.new_listen_handle) {
+            slot_new = spp_malloc_slot();
+            if (!slot_new) {
+                BTC_TRACE_ERROR("%s unable to malloc RFCOMM slot!", __func__);
+                break;
+            }
+            new_user_data = (void *)(uintptr_t)slot_new->id;
+            slot_new->security = slot->security;
+            slot_new->role = slot->role;
+            slot_new->scn = slot->scn;
+            slot_new->max_session = slot->max_session;
+            strcpy(slot_new->service_name, slot->service_name);
+            slot_new->sdp_handle = slot->sdp_handle;
+            slot_new->rfc_handle = p_data->rfc_srv_open.new_listen_handle;
+            slot_new->rfc_port_handle = BTA_JvRfcommGetPortHdl(p_data->rfc_srv_open.new_listen_handle);
+        }
         break;
     case BTA_JV_RFCOMM_OPEN_EVT:
         slot = spp_find_slot_by_id(id);
@@ -230,14 +254,26 @@ static void *btc_spp_rfcomm_inter_cb(tBTA_JV_EVT event, tBTA_JV *p_data, void *u
             BTC_TRACE_ERROR("%s unable to find RFCOMM slot!", __func__);
             break;
         }
-        if (slot->connected) {
-            BTA_JvRfcommClose(slot->rfc_handle, (void *)slot->id);
+        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.status = BTA_JV_SUCCESS;
         break;
     case BTA_JV_RFCOMM_DATA_IND_EVT:
         break;
+    case BTA_JV_FREE_SCN_EVT:
+        if (user_data) {
+            id = ((tBTA_JV_FREE_SCN_USER_DATA *)user_data)->slot_id;
+            slot = spp_find_slot_by_id(id);
+            if (slot) {
+                spp_free_slot(slot);
+            } else {
+                BTC_TRACE_ERROR("%s unable to find RFCOMM slot!", __func__);
+            }
+            osi_free(user_data);
+        }
+        break;
     default:
         break;
     }
@@ -299,8 +335,15 @@ static void btc_spp_dm_inter_cb(tBTA_JV_EVT event, tBTA_JV *p_data, void *user_d
         } else {
             BTC_TRACE_ERROR("%s unable to create record, start server fail!", __func__);
             btc_create_server_fail_cb();
-            BTA_JvFreeChannel(slot->scn, BTA_JV_CONN_TYPE_RFCOMM);
-            spp_free_slot(slot);
+            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_START_FAILED;
+                user_data->slot_id = slot->id;
+            } else {
+                BTC_TRACE_ERROR("%s unable to malloc user data!", __func__);
+            }
+            BTA_JvFreeChannel(slot->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);
         break;
@@ -320,6 +363,13 @@ 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 (spp_local_param.spp_slot_mutex) {
+        esp_spp_cb_param_t param;
+        param.init.status = ESP_SPP_FAILURE;
+        btc_spp_cb_to_app(ESP_SPP_INIT_EVT, &param);
+        BTC_TRACE_ERROR("%s SPP has been initiated, shall uninit first!", __func__);
+        return;
+    }
 
 #if SPP_DYNAMIC_MEMORY == TRUE
     if ((spp_local_param_ptr = (spp_local_param_t *)osi_malloc(sizeof(spp_local_param_t))) == NULL) {
@@ -340,45 +390,65 @@ static void btc_spp_init(btc_spp_args_t *arg)
 
 static void btc_spp_uninit(void)
 {
+    esp_spp_cb_param_t param;
     if (!spp_local_param.spp_slot_mutex) {
-        BTC_TRACE_ERROR("%s SPP have not been init\n", __func__);
+        param.uninit.status = ESP_SPP_FAILURE;
+        btc_spp_cb_to_app(ESP_SPP_UNINIT_EVT, &param);
+        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);
-    for (size_t i = 1; i <= BTA_JV_MAX_RFC_SR_SESSION; i++) {
+    // 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, (void *)spp_local_param.spp_slots[i]->id);
-            spp_free_slot(spp_local_param.spp_slots[i]);
-            spp_local_param.spp_slots[i] = NULL;
+            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);
         }
     }
-    for (size_t i = 1; i <= BTA_JV_MAX_RFC_SR_SESSION; i++) {
-        if (spp_local_param.spp_slots[i] != NULL && !(spp_local_param.spp_slots[i]->connected)) {
-            BTA_JvRfcommStopServer(spp_local_param.spp_slots[i]->sdp_handle, (void *)spp_local_param.spp_slots[i]->id);
-            BTA_JvDeleteRecord(spp_local_param.spp_slots[i]->sdp_handle);
-            BTA_JvFreeChannel(spp_local_param.spp_slots[i]->scn, BTA_JV_CONN_TYPE_RFCOMM);
-            spp_free_slot(spp_local_param.spp_slots[i]);
-            spp_local_param.spp_slots[i] = NULL;
+    // 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, &param);
+            }
+            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();
+    BTA_JvDisable((tBTA_JV_RFCOMM_CBACK *)btc_spp_rfcomm_inter_cb);
     osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
-    osi_mutex_free(&spp_local_param.spp_slot_mutex);
-
-#if SPP_DYNAMIC_MEMORY == TRUE
-    osi_free(spp_local_param_ptr);
-    spp_local_param_ptr = NULL;
-#endif
 }
 
 static void btc_spp_start_discovery(btc_spp_args_t *arg)
 {
+    if (!spp_local_param.spp_slot_mutex) {
+        BTC_TRACE_ERROR("%s SPP have not been init\n", __func__);
+        return;
+    }
     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 (!spp_local_param.spp_slot_mutex) {
+        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) {
@@ -397,6 +467,10 @@ static void btc_spp_connect(btc_spp_args_t *arg)
 
 static void btc_spp_disconnect(btc_spp_args_t *arg)
 {
+    if (!spp_local_param.spp_slot_mutex) {
+        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) {
@@ -404,14 +478,16 @@ static void btc_spp_disconnect(btc_spp_args_t *arg)
         osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
         return;
     }
-    BTA_JvRfcommClose(arg->disconnect.handle, (void *)slot->id);
-    btc_disconnect_cb(slot->rfc_handle);
-    spp_free_slot(slot);
+    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 (!spp_local_param.spp_slot_mutex) {
+        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) {
@@ -429,8 +505,54 @@ static void btc_spp_start_srv(btc_spp_args_t *arg)
     osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
 }
 
+static void btc_spp_stop_srv(void) {
+    if (!spp_local_param.spp_slot_mutex) {
+        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);
+        }
+    }
+    // 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, &param);
+            }
+            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);
+}
+
 static void btc_spp_write(btc_spp_args_t *arg)
 {
+    if (!spp_local_param.spp_slot_mutex) {
+        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) {
@@ -444,7 +566,7 @@ static void btc_spp_write(btc_spp_args_t *arg)
             osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
             return;
         }
-        uint8_t *data = xRingbufferReceiveUpTo(slot->ringbuf_write, &item_size, 0,990);
+        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);
@@ -525,6 +647,9 @@ void btc_spp_call_handler(btc_msg_t *msg)
     case BTC_SPP_ACT_START_SRV:
         btc_spp_start_srv(arg);
         break;
+    case BTC_SPP_ACT_STOP_SRV:
+        btc_spp_stop_srv();
+        break;
     case BTC_SPP_ACT_WRITE:
         btc_spp_write(arg);
         break;
@@ -583,22 +708,24 @@ void btc_spp_cb_handler(btc_msg_t *msg)
         btc_spp_cb_to_app(ESP_SPP_START_EVT, &param);
         break;
     case BTA_JV_RFCOMM_SRV_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_srv_open.handle);
-            if (!slot) {
-                BTC_TRACE_ERROR("%s unable to find RFCOMM slot!", __func__);
+        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__);
+                    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);
-                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.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);
+            btc_spp_cb_to_app(ESP_SPP_SRV_OPEN_EVT, &param);
         }
-        param.srv_open.status = p_data->rfc_srv_open.status;
-        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);
-        btc_spp_cb_to_app(ESP_SPP_SRV_OPEN_EVT, &param);
         break;
     case BTA_JV_RFCOMM_WRITE_EVT:
         osi_mutex_lock(&spp_local_param.spp_slot_mutex, OSI_MUTEX_MAX_TIMEOUT);
@@ -630,7 +757,7 @@ void btc_spp_cb_handler(btc_msg_t *msg)
                     slot->write_data = NULL;
                 }
                 size_t item_size = 0;
-                uint8_t *data = xRingbufferReceiveUpTo(slot->ringbuf_write, &item_size, 0,990);
+                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);
@@ -666,7 +793,7 @@ void btc_spp_cb_handler(btc_msg_t *msg)
                     slot->write_data = NULL;
                 }
                 size_t item_size = 0;
-                uint8_t *data = xRingbufferReceiveUpTo(slot->ringbuf_write, &item_size, 0,990);
+                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);
@@ -689,6 +816,22 @@ void btc_spp_cb_handler(btc_msg_t *msg)
         btc_spp_cb_to_app(ESP_SPP_DATA_IND_EVT, &param);
         osi_free (p_data->data_ind.p_buf);
         break;
+    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;
+            btc_spp_cb_to_app(ESP_SPP_SRV_STOP_EVT, &param);
+        }
+        break;
+    case BTA_JV_DISABLE_EVT:
+        param.uninit.status = ESP_SPP_SUCCESS;
+        BTA_JvFree();
+        osi_mutex_free(&spp_local_param.spp_slot_mutex);
+#if SPP_DYNAMIC_MEMORY == TRUE
+        osi_free(spp_local_param_ptr);
+        spp_local_param_ptr = NULL;
+#endif
+        btc_spp_cb_to_app(ESP_SPP_UNINIT_EVT, &param);
+        break;
     default:
         BTC_TRACE_DEBUG("%s: Unhandled event (%d)!", __FUNCTION__, msg->act);
         break;
@@ -726,12 +869,16 @@ int bta_co_rfc_data_incoming(void *user_data, BT_HDR *p_buf)
     msg.act = BTA_JV_RFCOMM_DATA_IND_EVT;
 
     uint32_t id = (uintptr_t)user_data;
+    if (!spp_local_param.spp_slot_mutex) {
+        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_id(id);
     if (!slot) {
         BTC_TRACE_ERROR("%s unable to find RFCOMM slot!", __func__);
         osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
-        return 0;
+        return -1;
     }
     p_data.data_ind.handle = slot->rfc_handle;
 
@@ -772,6 +919,10 @@ 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 (!spp_local_param.spp_slot_mutex) {
+        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) {
@@ -791,6 +942,10 @@ static ssize_t spp_vfs_write(int fd, const void * data, size_t size)
 }
 static int spp_vfs_close(int fd)
 {
+    if (!spp_local_param.spp_slot_mutex) {
+        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) {
@@ -819,6 +974,10 @@ static bool incoming_list_2_ringbuf_read(spp_slot_t *slot)
 
 static ssize_t spp_vfs_read(int fd, void * dst, size_t size)
 {
+    if (!spp_local_param.spp_slot_mutex) {
+        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) {

+ 1 - 1
components/bt/host/bluedroid/common/include/common/bt_target.h

@@ -1350,7 +1350,7 @@
 
 /* The maximum number of ports supported. */
 #ifndef MAX_RFC_PORTS
-#define MAX_RFC_PORTS               16 /*max is 30*/
+#define MAX_RFC_PORTS               8 /*max is 30*/
 #endif
 
 /* The maximum simultaneous links to different devices. */

+ 1 - 1
components/bt/host/bluedroid/stack/btm/btm_acl.c

@@ -794,7 +794,7 @@ void btm_acl_encrypt_change (UINT16 handle, UINT8 status, UINT8 encr_enable)
                 BTM_TRACE_WARNING("btm_acl_encrypt_change -> Issuing delayed HCI_Disconnect!!!\n");
                 btsnd_hcic_disconnect(p_dev_rec->hci_handle, HCI_ERR_PEER_USER);
             }
-            BTM_TRACE_ERROR("btm_acl_encrypt_change: tBTM_SEC_DEV:0x%x rs_disc_pending=%d\n",
+            BTM_TRACE_WARNING("btm_acl_encrypt_change: tBTM_SEC_DEV:0x%x rs_disc_pending=%d\n",
                             (UINT32)p_dev_rec, p_dev_rec->rs_disc_pending);
             p_dev_rec->rs_disc_pending = BTM_SEC_RS_NOT_PENDING;     /* reset flag */
         }

+ 1 - 1
components/bt/host/bluedroid/stack/btm/btm_sec.c

@@ -2272,7 +2272,7 @@ tBTM_STATUS btm_sec_l2cap_access_req (BD_ADDR bd_addr, UINT16 psm, UINT16 handle
             }
         } else if (!(BTM_SM4_KNOWN & p_dev_rec->sm4)) {
             /* the remote features are not known yet */
-            BTM_TRACE_DEBUG("%s: (%s) remote features unknown!!sec_flags:0x%02x\n", __FUNCTION__,
+            BTM_TRACE_ERROR("%s: (%s) remote features unknown!!sec_flags:0x%02x\n", __FUNCTION__,
                             (is_originator) ? "initiator" : "acceptor", p_dev_rec->sec_flags);
 
             p_dev_rec->sm4 |= BTM_SM4_REQ_PEND;

+ 6 - 0
examples/bluetooth/bluedroid/classic_bt/bt_spp_acceptor/main/example_spp_acceptor_demo.c

@@ -98,6 +98,12 @@ static void esp_spp_cb(esp_spp_cb_event_t event, esp_spp_cb_param_t *param)
         ESP_LOGI(SPP_TAG, "ESP_SPP_SRV_OPEN_EVT");
         gettimeofday(&time_old, NULL);
         break;
+    case ESP_SPP_SRV_STOP_EVT:
+        ESP_LOGI(SPP_TAG, "ESP_SPP_SRV_STOP_EVT");
+        break;
+    case ESP_SPP_UNINIT_EVT:
+        ESP_LOGI(SPP_TAG, "ESP_SPP_UNINIT_EVT");
+        break;
     default:
         break;
     }

+ 4 - 1
examples/bluetooth/bluedroid/classic_bt/bt_spp_initiator/main/example_spp_initiator_demo.c

@@ -116,7 +116,7 @@ static void esp_spp_cb(esp_spp_cb_event_t event, esp_spp_cb_param_t *param)
         break;
     case ESP_SPP_OPEN_EVT:
         ESP_LOGI(SPP_TAG, "ESP_SPP_OPEN_EVT");
-        esp_spp_write(param->srv_open.handle, SPP_DATA_LEN, spp_data);
+        esp_spp_write(param->open.handle, SPP_DATA_LEN, spp_data);
         gettimeofday(&time_old, NULL);
         break;
     case ESP_SPP_CLOSE_EVT:
@@ -157,6 +157,9 @@ static void esp_spp_cb(esp_spp_cb_event_t event, esp_spp_cb_param_t *param)
     case ESP_SPP_SRV_OPEN_EVT:
         ESP_LOGI(SPP_TAG, "ESP_SPP_SRV_OPEN_EVT");
         break;
+    case ESP_SPP_UNINIT_EVT:
+        ESP_LOGI(SPP_TAG, "ESP_SPP_UNINIT_EVT");
+        break;
     default:
         break;
     }