]> granicus.if.org Git - esp-idf/commitdiff
component/bt: Add SPP profile
authorbaohongde <baohongde@espressif.com>
Fri, 5 Jan 2018 08:48:29 +0000 (16:48 +0800)
committerbaohongde <baohongde@espressif.com>
Fri, 5 Jan 2018 08:48:29 +0000 (16:48 +0800)
45 files changed:
components/bt/Kconfig
components/bt/bluedroid/api/esp_spp_api.c [new file with mode: 0644]
components/bt/bluedroid/api/include/esp_spp_api.h [new file with mode: 0644]
components/bt/bluedroid/bta/include/bta_jv_api.h [new file with mode: 0644]
components/bt/bluedroid/bta/include/bta_jv_co.h [new file with mode: 0644]
components/bt/bluedroid/bta/jv/bta_jv_act.c [new file with mode: 0644]
components/bt/bluedroid/bta/jv/bta_jv_api.c [new file with mode: 0644]
components/bt/bluedroid/bta/jv/bta_jv_cfg.c [new file with mode: 0644]
components/bt/bluedroid/bta/jv/bta_jv_int.h [new file with mode: 0644]
components/bt/bluedroid/bta/jv/bta_jv_main.c [new file with mode: 0644]
components/bt/bluedroid/btc/core/btc_task.c
components/bt/bluedroid/btc/core/btc_util.c
components/bt/bluedroid/btc/include/btc_task.h
components/bt/bluedroid/btc/include/btc_util.h
components/bt/bluedroid/btc/profile/std/include/btc_spp.h [new file with mode: 0644]
components/bt/bluedroid/btc/profile/std/spp/btc_spp.c [new file with mode: 0644]
components/bt/bluedroid/include/bt_target.h
components/bt/bluedroid/stack/btu/btu_task.c
components/bt/bluedroid/stack/include/btu.h
components/bt/bluedroid/stack/include/port_api.h
components/bt/bluedroid/stack/rfcomm/include/port_int.h
components/bt/bluedroid/stack/rfcomm/port_api.c
components/bt/bluedroid/stack/rfcomm/port_rfc.c
components/bt/bluedroid/stack/rfcomm/port_utils.c
components/bt/bluedroid/stack/rfcomm/rfc_l2cap_if.c
components/bt/bluedroid/stack/rfcomm/rfc_mx_fsm.c
components/bt/bluedroid/stack/rfcomm/rfc_port_fsm.c
components/bt/bluedroid/stack/rfcomm/rfc_port_if.c
components/bt/bluedroid/stack/rfcomm/rfc_ts_frames.c
components/bt/bluedroid/stack/rfcomm/rfc_utils.c
components/bt/component.mk
docs/Doxyfile
docs/api-reference/bluetooth/classic_bt.rst
docs/api-reference/bluetooth/esp_spp.rst [new file with mode: 0644]
examples/bluetooth/a2dp_sink/sdkconfig.defaults
examples/bluetooth/bt_spp_acceptor/Makefile [new file with mode: 0644]
examples/bluetooth/bt_spp_acceptor/README.rst [new file with mode: 0644]
examples/bluetooth/bt_spp_acceptor/main/component.mk [new file with mode: 0644]
examples/bluetooth/bt_spp_acceptor/main/example_spp_acceptor_demo.c [new file with mode: 0644]
examples/bluetooth/bt_spp_acceptor/sdkconfig.defaults [new file with mode: 0644]
examples/bluetooth/bt_spp_initiator/Makefile [new file with mode: 0644]
examples/bluetooth/bt_spp_initiator/README.rst [new file with mode: 0644]
examples/bluetooth/bt_spp_initiator/main/component.mk [new file with mode: 0644]
examples/bluetooth/bt_spp_initiator/main/example_spp_initiator_demo.c [new file with mode: 0644]
examples/bluetooth/bt_spp_initiator/sdkconfig.defaults [new file with mode: 0644]

index 8a4f5248f0e0e68e012cc8fdf2680ea4f59220ac..ebc677530425d387df50dec0aeee6be27cef9ccd 100644 (file)
@@ -113,6 +113,20 @@ config CLASSIC_BT_ENABLED
     help
         For now this option needs "SMP_ENABLE" to be set to yes
 
+config A2DP_SNK_ENABLED
+    bool "A2DP(SINK)"
+    depends on CLASSIC_BT_ENABLED
+    default n
+    help
+        This option is used to enable/disable Advanced Audio Distribution Profile(Sink)
+    
+config BT_SPP_ENABLED
+    bool "SPP Profile"
+    depends on CLASSIC_BT_ENABLED
+    default n
+    help
+        This enables the SPP Profile
+
 config GATTS_ENABLE
     bool "Include GATT server module(GATTS)"
     depends on BLUEDROID_ENABLED
diff --git a/components/bt/bluedroid/api/esp_spp_api.c b/components/bt/bluedroid/api/esp_spp_api.c
new file mode 100644 (file)
index 0000000..d893525
--- /dev/null
@@ -0,0 +1,169 @@
+// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <string.h>
+
+#include "esp_bt_main.h"
+#include "btc_manage.h"
+
+#include "btc_spp.h"
+#include "esp_spp_api.h"
+#include "bt_target.h"
+
+#if (defined BTC_SPP_INCLUDED && BTC_SPP_INCLUDED == TRUE)
+
+static const uint8_t  UUID_SPP[16] = {0x00, 0x00, 0x11, 0x01, 0x00, 0x00, 0x10, 0x00,
+                                      0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB
+                                     };
+static tSDP_UUID sdp_uuid;
+esp_err_t esp_spp_register_callback(esp_spp_cb_t *callback)
+{
+    ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED);
+
+    if (callback == NULL) {
+        return ESP_FAIL;
+    }
+
+    btc_profile_cb_set(BTC_PID_SPP, callback);
+    return ESP_OK;
+}
+
+
+esp_err_t esp_spp_init(esp_spp_mode_t mode)
+{
+    btc_msg_t msg;
+    btc_spp_args_t arg;
+    ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED);
+
+    if (mode != ESP_SPP_MODE_CB) {
+        LOG_ERROR("%s Watch this space!", __func__);
+        return ESP_FAIL;
+    }
+    msg.sig = BTC_SIG_API_CALL;
+    msg.pid = BTC_PID_SPP;
+    msg.act = BTC_SPP_ACT_INIT;
+
+    return (btc_transfer_context(&msg, &arg, sizeof(btc_spp_args_t), NULL) == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL);
+}
+
+esp_err_t esp_spp_deinit()
+{
+    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_UNINIT;
+
+    return (btc_transfer_context(&msg, &arg, sizeof(btc_spp_args_t), NULL) == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL);
+}
+
+
+esp_err_t esp_spp_start_discovery(esp_bd_addr_t bd_addr)
+{
+    sdp_uuid.len = 16;
+    memcpy(sdp_uuid.uu.uuid128, UUID_SPP, sizeof(sdp_uuid.uu.uuid128));
+
+    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_START_DISCOVERY;
+
+    memcpy(arg.start_discovery.bd_addr, bd_addr, ESP_BD_ADDR_LEN);
+    arg.start_discovery.num_uuid = 1;
+    arg.start_discovery.p_uuid_list = &sdp_uuid;
+
+    return (btc_transfer_context(&msg, &arg, sizeof(btc_spp_args_t), btc_spp_arg_deep_copy) == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL);
+}
+
+esp_err_t esp_spp_connect(esp_spp_sec_t sec_mask,
+                          esp_spp_role_t role, uint8_t remote_scn, esp_bd_addr_t peer_bd_addr)
+{
+    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_CONNECT;
+
+    arg.connect.sec_mask = sec_mask;
+    arg.connect.role = role;
+    arg.connect.remote_scn = remote_scn;
+    memcpy(arg.connect.peer_bd_addr, peer_bd_addr, ESP_BD_ADDR_LEN);
+
+    return (btc_transfer_context(&msg, &arg, sizeof(btc_spp_args_t), NULL) == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL);
+}
+
+esp_err_t esp_spp_disconnect(uint32_t handle)
+{
+    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_DISCONNECT;
+
+    arg.disconnect.handle = handle;
+
+    return (btc_transfer_context(&msg, &arg, sizeof(btc_spp_args_t), NULL) == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL);
+}
+
+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)
+{
+    btc_msg_t msg;
+    btc_spp_args_t arg;
+    ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED);
+
+    if (strlen(name) > ESP_SPP_SERVER_NAME_MAX) {
+        return ESP_ERR_INVALID_ARG;
+    }
+
+    msg.sig = BTC_SIG_API_CALL;
+    msg.pid = BTC_PID_SPP;
+    msg.act = BTC_SPP_ACT_START_SRV;
+
+    arg.start_srv.sec_mask = sec_mask;
+    arg.start_srv.role = role;
+    arg.start_srv.local_scn = local_scn;
+    arg.start_srv.max_session = ESP_SPP_MAX_SESSION;
+    strcpy(arg.start_srv.name, name);
+
+    return (btc_transfer_context(&msg, &arg, 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)
+{
+    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_WRITE;
+
+    arg.write.handle = handle;
+    arg.write.len = len;
+    arg.write.p_data = p_data;
+
+    return (btc_transfer_context(&msg, &arg, sizeof(btc_spp_args_t), btc_spp_arg_deep_copy) == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL);
+}
+#endif ///defined BTC_SPP_INCLUDED && BTC_SPP_INCLUDED == TRUE
diff --git a/components/bt/bluedroid/api/include/esp_spp_api.h b/components/bt/bluedroid/api/include/esp_spp_api.h
new file mode 100644 (file)
index 0000000..5a6bb7d
--- /dev/null
@@ -0,0 +1,294 @@
+// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef __ESP_SPP_API_H__
+#define __ESP_SPP_API_H__
+
+#include "esp_err.h"
+#include "esp_bt_defs.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+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_RESOURCE             /*!< No more set pm control block */
+} esp_spp_status_t;
+
+/* Security Setting Mask */
+#define ESP_SPP_SEC_NONE            0x0000    /*!< No security. relate to BTA_SEC_NONE in bta_api.h */
+#define ESP_SPP_SEC_AUTHORIZE       0x0001    /*!< Authorization required (only needed for out going connection ) relate to BTA_SEC_AUTHORIZE in bta_api.h*/
+#define ESP_SPP_SEC_AUTHENTICATE    0x0012    /*!< Authentication required.  relate to BTA_SEC_AUTHENTICATE in bta_api.h*/
+#define ESP_SPP_SEC_ENCRYPT         0x0024    /*!< Encryption required.  relate to BTA_SEC_ENCRYPT in bta_api.h*/
+#define ESP_SPP_SEC_MODE4_LEVEL4    0x0040    /*!< Mode 4 level 4 service, i.e. incoming/outgoing MITM and P-256 encryption  relate to BTA_SEC_MODE4_LEVEL4 in bta_api.h*/
+#define ESP_SPP_SEC_MITM            0x3000    /*!< Man-In-The_Middle protection  relate to BTA_SEC_MITM in bta_api.h*/
+#define ESP_SPP_SEC_IN_16_DIGITS    0x4000    /*!< Min 16 digit for pin code  relate to BTA_SEC_IN_16_DIGITS in bta_api.h*/
+typedef uint16_t esp_spp_sec_t;
+
+typedef enum {
+    ESP_SPP_ROLE_MASTER     = 0,          /*!< Role: master */
+    ESP_SPP_ROLE_SLAVE      = 1,          /*!< Role: slave */
+} esp_spp_role_t;
+
+typedef enum {
+    ESP_SPP_MODE_CB         = 0,          /*!< When data is coming, a callback will come with data */
+    ESP_SPP_MODE_VFS        = 1,          /*!< Use VFS to write/read data */
+} esp_spp_mode_t;
+
+#define ESP_SPP_MAX_MTU                 (3*330)     /*!< SPP max MTU */
+#define ESP_SPP_MAX_SCN                 31          /*!< SPP max SCN */
+/**
+ * @brief SPP callback function events
+ */
+typedef enum {
+    ESP_SPP_INIT_EVT                    = 0,                /*!< When SPP is inited, 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 */
+    ESP_SPP_START_EVT                   = 28,               /*!< When SPP server started, the event comes */
+    ESP_SPP_CL_INIT_EVT                 = 29,               /*!< When SPP client initiated a connection, the event comes */
+    ESP_SPP_DATA_IND_EVT                = 30,               /*!< When SPP connection received data, the event comes */
+    ESP_SPP_CONG_EVT                    = 31,               /*!< When SPP connection congestion status changed, the event comes */
+    ESP_SPP_WRITE_EVT                   = 33,               /*!< When SPP write operation completes, the event comes */
+    ESP_SPP_SRV_OPEN_EVT                = 34,               /*!< When SPP Server connection open, the event comes */
+} esp_spp_cb_event_t;
+
+
+/**
+ * @brief SPP callback parameters union
+ */
+typedef union {
+    /**
+     * @brief SPP_INIT_EVT
+     */
+    struct spp_init_evt_param {
+        esp_spp_status_t    status;         /*!< status */
+    } init;                                 /*!< SPP callback param of SPP_INIT_EVT */
+
+    /**
+     * @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 # */
+    } disc_comp;                            /*!< SPP callback param of SPP_DISCOVERY_COMP_EVT */
+
+    /**
+     * @brief ESP_SPP_OPEN_EVT
+     */
+    struct spp_open_evt_param {
+        esp_spp_status_t    status;         /*!< status */
+        uint32_t            handle;         /*!< The connection handle */
+        esp_bd_addr_t       rem_bda;        /*!< The peer address */
+    } open;                                 /*!< SPP callback param of ESP_SPP_OPEN_EVT */
+
+    /**
+     * @brief ESP_SPP_SRV_OPEN_EVT
+     */
+    struct spp_srv_open_evt_param {
+        esp_spp_status_t    status;         /*!< status */
+        uint32_t            handle;         /*!< The connection handle */
+        uint32_t            new_listen_handle;  /*!< The new listen handle */
+        esp_bd_addr_t       rem_bda;        /*!< The peer address */
+    } srv_open;                             /*!< SPP callback param of ESP_SPP_SRV_OPEN_EVT */
+    /**
+     * @brief ESP_SPP_CLOSE_EVT
+     */
+    struct spp_close_evt_param {
+        esp_spp_status_t    status;         /*!< status */
+        uint32_t            port_status;    /*!< PORT status */
+        uint32_t            handle;         /*!< The connection handle */
+        bool                async;          /*!< FALSE, if local initiates disconnect */
+    } close;                                /*!< SPP callback param of ESP_SPP_CLOSE_EVT */
+
+    /**
+     * @brief ESP_SPP_START_EVT
+     */
+    struct spp_start_evt_param {
+        esp_spp_status_t    status;         /*!< status */
+        uint32_t            handle;         /*!< The connection handle */
+        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_CL_INIT_EVT
+     */
+    struct spp_cl_init_evt_param {
+        esp_spp_status_t    status;         /*!< status */
+        uint32_t            handle;         /*!< The connection handle */
+        uint8_t             sec_id;         /*!< security ID used by this server */
+        bool                use_co;         /*!< TRUE to use co_rfc_data */
+    } cl_init;                              /*!< SPP callback param of ESP_SPP_CL_INIT_EVT */
+
+    /**
+     * @brief ESP_SPP_WRITE_EVT
+     */
+    struct spp_write_evt_param {
+        esp_spp_status_t    status;         /*!< status */
+        uint32_t            handle;         /*!< The connection handle */
+        uint32_t            req_id;         /*!< The req_id in the associated BTA_JvRfcommWrite() */
+        int                 len;            /*!< The length of the data written. */
+        bool                cong;           /*!< congestion status */
+    } write;                                /*!< SPP callback param of ESP_SPP_WRITE_EVT */
+
+    /**
+     * @brief ESP_SPP_DATA_IND_EVT
+     */
+    struct spp_data_ind_evt_param {
+        esp_spp_status_t    status;         /*!< status */
+        uint32_t            handle;         /*!< The connection handle */
+        uint16_t            len;            /*!< The length of data */
+        uint8_t             *data;          /*!< The data recived */
+    } data_ind;                             /*!< SPP callback param of ESP_SPP_DATA_IND_EVT */
+
+    /**
+     * @brief ESP_SPP_CONG_EVT
+     */
+    struct spp_cong_evt_param {
+        esp_spp_status_t    status;         /*!< status */
+        uint32_t            handle;         /*!< The connection handle */
+        bool                cong;           /*!< TRUE, congested. FALSE, uncongested */
+    } cong;                                 /*!< SPP callback param of ESP_SPP_CONG_EVT */
+} esp_spp_cb_param_t;                       /*!< SPP callback parameter union type */
+
+/**
+ * @brief       SPP callback function type
+ * @param       event:      Event type
+ * @param       param:      Point to callback parameter, currently is union type
+ */
+typedef void (esp_spp_cb_t)(esp_spp_cb_event_t event, esp_spp_cb_param_t *param);
+
+/**
+ * @brief       This function is called to init callbacks
+ *              with SPP module.
+ *
+ * @param[in]   callback:   pointer to the init callback function.
+ *
+ * @return
+ *              - ESP_OK: success
+ *              - other: failed
+ */
+esp_err_t esp_spp_register_callback(esp_spp_cb_t callback);
+
+/**
+ * @brief       This function is called to init SPP.
+ *
+ * @param[in]   mode: Choose the mode of SPP, ESP_SPP_MODE_CB or ESP_SPP_MODE_CB.
+ *                    Now only supports ESP_SPP_MODE_CB mode, we will continue to update.
+ *
+ * @return
+ *              - ESP_OK: success
+ *              - other: failed
+ */
+esp_err_t esp_spp_init(esp_spp_mode_t mode);
+
+/**
+ * @brief       This function is called to uninit SPP.
+ *
+ * @return
+ *              - ESP_OK: success
+ *              - other: failed
+ */
+esp_err_t esp_spp_deinit();
+
+
+/**
+ * @brief       This function is called to performs service discovery for
+ *              the services provided by the given peer device. When the
+ *              operation is complete the callback function will be called
+ *              with a ESP_SPP_DISCOVERY_COMP_EVT.
+ *
+ * @param[in]   bd_addr:   Remote device bluetooth device address.
+ *
+ * @return
+ *              - ESP_OK: success
+ *              - other: failed
+ */
+esp_err_t esp_spp_start_discovery(esp_bd_addr_t bd_addr);
+
+/**
+ * @brief       This function makes an SPP conection to a remote BD Address.
+ *              When the connection is initiated or failed to initiate,
+ *              the callback is called with ESP_SPP_CL_INIT_EVT.
+ *              When the connection is established or failed,
+ *              the callback is called with ESP_SPP_OPEN_EVT.
+ *
+ * @param[in]   sec_mask:     Security Setting Mask .
+ * @param[in]   role:         Msater or slave.
+ * @param[in]   remote_scn:   Remote device bluetooth device SCN.
+ * @param[in]   peer_bd_addr: Remote device bluetooth device address.
+ *
+ * @return
+ *              - ESP_OK: success
+ *              - other: failed
+ */
+esp_err_t esp_spp_connect(esp_spp_sec_t sec_mask,
+                          esp_spp_role_t role, uint8_t remote_scn, esp_bd_addr_t peer_bd_addr);
+
+/**
+ * @brief       This function closes an SPP connection.
+ *
+ * @param[in]   handle:    The connection handle.
+ *
+ * @return
+ *              - ESP_OK: success
+ *              - other: failed
+ */
+esp_err_t esp_spp_disconnect(uint32_t handle);
+
+/**
+ * @brief       This function create a SPP server and starts listening for an
+ *              SPP connection request from a remote Bluetooth device.
+ *              When the server is started successfully, the callback is called
+ *              with ESP_SPP_START_EVT.
+ *              When the connection is established, the callback is called
+ *              with ESP_SPP_SRV_OPEN_EVT.
+ *
+ * @param[in]   sec_mask:     Security Setting Mask .
+ * @param[in]   role:         Msater or slave.
+ * @param[in]   local_scn:    The specific channel you want to get.
+ *                            If channel is 0, means get any channel.
+ * @param[in]   name:         Server's name.
+ *
+ * @return
+ *              - ESP_OK: success
+ *              - other: failed
+ */
+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 closes an SPP connection.
+ *
+ * @param[in]   handle: The connection handle.
+ * @param[in]   len:    The length of the data written.
+ * @param[in]   p_data: The data written.
+ *
+ * @return
+ *              - ESP_OK: success
+ *              - other: failed
+ */
+esp_err_t esp_spp_write(uint32_t handle, int len, uint8_t *p_data);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif ///__ESP_SPP_API_H__
\ No newline at end of file
diff --git a/components/bt/bluedroid/bta/include/bta_jv_api.h b/components/bt/bluedroid/bta/include/bta_jv_api.h
new file mode 100644 (file)
index 0000000..a9279a8
--- /dev/null
@@ -0,0 +1,884 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2006-2012 Broadcom Corporation
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *  This is the public interface file the BTA Java I/F
+ *
+ ******************************************************************************/
+#ifndef BTA_JV_API_H
+#define BTA_JV_API_H
+
+#include "bt_target.h"
+#include "bt_types.h"
+#include "bta_api.h"
+#include "btm_api.h"
+#include "l2c_api.h"
+#include "rfcdefs.h"
+#include "sdp_api.h"
+
+#if (defined BTA_JV_INCLUDED && BTA_JV_INCLUDED == TRUE)
+/*****************************************************************************
+**  Constants and data types
+*****************************************************************************/
+/* status values */
+#define BTA_JV_SUCCESS             0            /* Successful operation. */
+#define BTA_JV_FAILURE             1            /* Generic failure. */
+#define BTA_JV_BUSY                2            /* Temporarily can not handle this request. */
+#define BTA_JV_NO_DATA             3            /* no data. */
+#define BTA_JV_NO_RESOURCE         4            /* No more set pm control block */
+
+typedef UINT8 tBTA_JV_STATUS;
+#define BTA_JV_INTERNAL_ERR        (-1) /* internal error. */
+
+#define BTA_JV_MAX_UUIDS        SDP_MAX_UUID_FILTERS
+#define BTA_JV_MAX_ATTRS        SDP_MAX_ATTR_FILTERS
+#define BTA_JV_MAX_SDP_REC      SDP_MAX_RECORDS
+#define BTA_JV_MAX_L2C_CONN     GAP_MAX_CONNECTIONS /* GAP handle is used as index, hence do not change this value */
+#define BTA_JV_MAX_SCN          PORT_MAX_RFC_PORTS /* same as BTM_MAX_SCN (in btm_int.h) */
+#define BTA_JV_MAX_RFC_CONN     MAX_RFC_PORTS
+
+#ifndef BTA_JV_DEF_RFC_MTU
+#define BTA_JV_DEF_RFC_MTU      (3*330)
+#endif
+
+#ifndef BTA_JV_MAX_RFC_SR_SESSION
+#define BTA_JV_MAX_RFC_SR_SESSION   MAX_BD_CONNECTIONS
+#endif
+
+/* BTA_JV_MAX_RFC_SR_SESSION can not be bigger than MAX_BD_CONNECTIONS */
+#if (BTA_JV_MAX_RFC_SR_SESSION > MAX_BD_CONNECTIONS)
+#undef BTA_JV_MAX_RFC_SR_SESSION
+#define BTA_JV_MAX_RFC_SR_SESSION   MAX_BD_CONNECTIONS
+#endif
+
+#define BTA_JV_FIRST_SERVICE_ID BTA_FIRST_JV_SERVICE_ID
+#define BTA_JV_LAST_SERVICE_ID  BTA_LAST_JV_SERVICE_ID
+#define BTA_JV_NUM_SERVICE_ID   (BTA_LAST_JV_SERVICE_ID - BTA_FIRST_JV_SERVICE_ID + 1)
+
+/* Discoverable modes */
+enum {
+    BTA_JV_DISC_NONE,
+    BTA_JV_DISC_LIMITED,
+    BTA_JV_DISC_GENERAL
+};
+typedef UINT16 tBTA_JV_DISC;
+
+#define BTA_JV_ROLE_SLAVE       BTM_ROLE_SLAVE
+#define BTA_JV_ROLE_MASTER      BTM_ROLE_MASTER
+typedef UINT32 tBTA_JV_ROLE;
+
+#define BTA_JV_SERVICE_LMTD_DISCOVER    BTM_COD_SERVICE_LMTD_DISCOVER   /* 0x0020 */
+#define BTA_JV_SERVICE_POSITIONING      BTM_COD_SERVICE_POSITIONING     /* 0x0100 */
+#define BTA_JV_SERVICE_NETWORKING       BTM_COD_SERVICE_NETWORKING      /* 0x0200 */
+#define BTA_JV_SERVICE_RENDERING        BTM_COD_SERVICE_RENDERING       /* 0x0400 */
+#define BTA_JV_SERVICE_CAPTURING        BTM_COD_SERVICE_CAPTURING       /* 0x0800 */
+#define BTA_JV_SERVICE_OBJ_TRANSFER     BTM_COD_SERVICE_OBJ_TRANSFER    /* 0x1000 */
+#define BTA_JV_SERVICE_AUDIO            BTM_COD_SERVICE_AUDIO           /* 0x2000 */
+#define BTA_JV_SERVICE_TELEPHONY        BTM_COD_SERVICE_TELEPHONY       /* 0x4000 */
+#define BTA_JV_SERVICE_INFORMATION      BTM_COD_SERVICE_INFORMATION     /* 0x8000 */
+
+/* JV ID type */
+#define BTA_JV_PM_ID_1             1    /* PM example profile 1 */
+#define BTA_JV_PM_ID_2             2    /* PM example profile 2 */
+#define BTA_JV_PM_ID_CLEAR         0    /* Special JV ID used to clear PM profile */
+#define BTA_JV_PM_ALL              0xFF /* Generic match all id, see bta_dm_cfg.c */
+typedef UINT8 tBTA_JV_PM_ID;
+
+#define BTA_JV_PM_HANDLE_CLEAR     0xFF /* Special JV ID used to clear PM profile  */
+
+/* define maximum number of registered PM entities. should be in sync with bta pm! */
+#ifndef BTA_JV_PM_MAX_NUM
+#define BTA_JV_PM_MAX_NUM 5
+#endif
+
+/* JV pm connection states */
+enum {
+    BTA_JV_CONN_OPEN = 0,   /* Connection opened state */
+    BTA_JV_CONN_CLOSE,      /* Connection closed state */
+    BTA_JV_APP_OPEN,        /* JV Application opened state */
+    BTA_JV_APP_CLOSE,       /* JV Application closed state */
+    BTA_JV_SCO_OPEN,        /* SCO connection opened state */
+    BTA_JV_SCO_CLOSE,       /* SCO connection opened state */
+    BTA_JV_CONN_IDLE,       /* Connection idle state */
+    BTA_JV_CONN_BUSY,       /* Connection busy state */
+    BTA_JV_MAX_CONN_STATE   /* Max number of connection state */
+};
+typedef UINT8 tBTA_JV_CONN_STATE;
+
+/* JV Connection types */
+#define BTA_JV_CONN_TYPE_RFCOMM    0
+#define BTA_JV_CONN_TYPE_L2CAP     1
+#define BTA_JV_CONN_TYPE_L2CAP_LE  2
+
+/* Java I/F callback events */
+/* events received by tBTA_JV_DM_CBACK */
+#define BTA_JV_ENABLE_EVT           0  /* JV enabled */
+#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 */
+#define BTA_JV_CREATE_RECORD_EVT    11 /* the result for BTA_JvCreateRecord */
+/* events received by tBTA_JV_L2CAP_CBACK */
+#define BTA_JV_L2CAP_OPEN_EVT       16 /* open status of L2CAP connection */
+#define BTA_JV_L2CAP_CLOSE_EVT      17 /* L2CAP connection closed */
+#define BTA_JV_L2CAP_START_EVT      18 /* L2CAP server started */
+#define BTA_JV_L2CAP_CL_INIT_EVT    19 /* L2CAP client initiated a connection */
+#define BTA_JV_L2CAP_DATA_IND_EVT   20 /* L2CAP connection received data */
+#define BTA_JV_L2CAP_CONG_EVT       21 /* L2CAP connection congestion status changed */
+#define BTA_JV_L2CAP_READ_EVT       22 /* the result for BTA_JvL2capRead */
+#define BTA_JV_L2CAP_RECEIVE_EVT    23 /* the result for BTA_JvL2capReceive*/
+#define BTA_JV_L2CAP_WRITE_EVT      24 /* the result for BTA_JvL2capWrite*/
+#define BTA_JV_L2CAP_WRITE_FIXED_EVT 25 /* the result for BTA_JvL2capWriteFixed */
+
+/* events received by tBTA_JV_RFCOMM_CBACK */
+#define BTA_JV_RFCOMM_OPEN_EVT      26 /* open status of RFCOMM Client connection */
+#define BTA_JV_RFCOMM_CLOSE_EVT     27 /* RFCOMM connection closed */
+#define BTA_JV_RFCOMM_START_EVT     28 /* RFCOMM server started */
+#define BTA_JV_RFCOMM_CL_INIT_EVT   29 /* RFCOMM client initiated a connection */
+#define BTA_JV_RFCOMM_DATA_IND_EVT  30 /* RFCOMM connection received data */
+#define BTA_JV_RFCOMM_CONG_EVT      31 /* RFCOMM connection congestion status changed */
+#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 */
+
+typedef UINT16 tBTA_JV_EVT;
+
+/* data associated with BTA_JV_SET_DISCOVER_EVT */
+typedef struct {
+    tBTA_JV_STATUS  status;     /* Whether the operation succeeded or failed. */
+    tBTA_JV_DISC    disc_mode;  /* The current discoverable mode */
+} tBTA_JV_SET_DISCOVER;
+
+/* 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_DISCOVERY_COMP;
+
+/* data associated with BTA_JV_CREATE_RECORD_EVT */
+typedef struct {
+    tBTA_JV_STATUS  status;     /* Whether the operation succeeded or failed. */
+    UINT32          handle;     /* The SDP handle */
+} tBTA_JV_CREATE_RECORD;
+
+/* data associated with BTA_JV_L2CAP_OPEN_EVT */
+typedef struct {
+    tBTA_JV_STATUS  status;     /* Whether the operation succeeded or failed. */
+    UINT32          handle;     /* The connection handle */
+    BD_ADDR         rem_bda;    /* The peer address */
+    INT32           tx_mtu;     /* The transmit MTU */
+} tBTA_JV_L2CAP_OPEN;
+
+/* data associated with BTA_JV_L2CAP_OPEN_EVT for LE sockets */
+typedef struct {
+    tBTA_JV_STATUS  status;     /* Whether the operation succeeded or failed. */
+    UINT32          handle;     /* The connection handle */
+    BD_ADDR         rem_bda;    /* The peer address */
+    INT32           tx_mtu;     /* The transmit MTU */
+    void          **p_p_cback;  /* set them for new socket */
+    void          **p_user_data;/* set them for new socket */
+
+} tBTA_JV_L2CAP_LE_OPEN;
+
+
+/* data associated with BTA_JV_L2CAP_CLOSE_EVT */
+typedef struct {
+    tBTA_JV_STATUS  status;     /* Whether the operation succeeded or failed. */
+    UINT32          handle;     /* The connection handle */
+    BOOLEAN         async;      /* FALSE, if local initiates disconnect */
+} tBTA_JV_L2CAP_CLOSE;
+
+/* data associated with BTA_JV_L2CAP_START_EVT */
+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 */
+} tBTA_JV_L2CAP_START;
+
+/* data associated with BTA_JV_L2CAP_CL_INIT_EVT */
+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 client */
+} tBTA_JV_L2CAP_CL_INIT;
+
+/* data associated with BTA_JV_L2CAP_CONG_EVT */
+typedef struct {
+    tBTA_JV_STATUS  status;     /* Whether the operation succeeded or failed. */
+    UINT32          handle;     /* The connection handle */
+    BOOLEAN         cong;       /* TRUE, congested. FALSE, uncongested */
+} tBTA_JV_L2CAP_CONG;
+
+/* data associated with BTA_JV_L2CAP_READ_EVT */
+typedef struct {
+    tBTA_JV_STATUS  status;     /* Whether the operation succeeded or failed. */
+    UINT32          handle;     /* The connection handle */
+    UINT32          req_id;     /* The req_id in the associated BTA_JvL2capRead() */
+    UINT8           *p_data;    /* This points the same location as the p_data
+                                 * parameter in BTA_JvL2capRead () */
+    UINT16          len;        /* The length of the data read. */
+} tBTA_JV_L2CAP_READ;
+
+/* data associated with BTA_JV_L2CAP_RECEIVE_EVT */
+typedef struct {
+    tBTA_JV_STATUS  status;     /* Whether the operation succeeded or failed. */
+    UINT32          handle;     /* The connection handle */
+    UINT32          req_id;     /* The req_id in the associated BTA_JvL2capReceive() */
+    UINT8           *p_data;    /* This points the same location as the p_data
+                                 * parameter in BTA_JvL2capReceive () */
+    UINT16          len;        /* The length of the data read. */
+} tBTA_JV_L2CAP_RECEIVE;
+
+/* data associated with BTA_JV_L2CAP_WRITE_EVT */
+typedef struct {
+    tBTA_JV_STATUS  status;     /* Whether the operation succeeded or failed. */
+    UINT32          handle;     /* The connection handle */
+    UINT32          req_id;     /* The req_id in the associated BTA_JvL2capWrite() */
+    UINT16          len;        /* The length of the data written. */
+    BOOLEAN         cong;       /* congestion status */
+} tBTA_JV_L2CAP_WRITE;
+
+
+/* data associated with BTA_JV_L2CAP_WRITE_FIXED_EVT */
+typedef struct {
+    tBTA_JV_STATUS  status;     /* Whether the operation succeeded or failed. */
+    UINT16          channel;    /* The connection channel */
+    BD_ADDR         addr;       /* The peer address */
+    UINT32          req_id;     /* The req_id in the associated BTA_JvL2capWrite() */
+    UINT16          len;        /* The length of the data written. */
+    BOOLEAN         cong;       /* congestion status */
+} tBTA_JV_L2CAP_WRITE_FIXED;
+
+/* data associated with BTA_JV_RFCOMM_OPEN_EVT */
+typedef struct {
+    tBTA_JV_STATUS  status;     /* Whether the operation succeeded or failed. */
+    UINT32          handle;     /* The connection handle */
+    BD_ADDR         rem_bda;    /* The peer address */
+} tBTA_JV_RFCOMM_OPEN;
+/* data associated with BTA_JV_RFCOMM_SRV_OPEN_EVT */
+typedef struct {
+    tBTA_JV_STATUS  status;             /* Whether the operation succeeded or failed. */
+    UINT32          handle;             /* The connection handle */
+    UINT32          new_listen_handle;  /* The new listen handle */
+    BD_ADDR         rem_bda;            /* The peer address */
+} tBTA_JV_RFCOMM_SRV_OPEN;
+
+
+/* data associated with BTA_JV_RFCOMM_CLOSE_EVT */
+typedef struct {
+    tBTA_JV_STATUS  status;      /* Whether the operation succeeded or failed. */
+    UINT32          port_status; /* PORT status */
+    UINT32          handle;      /* The connection handle */
+    BOOLEAN         async;       /* FALSE, if local initiates disconnect */
+} tBTA_JV_RFCOMM_CLOSE;
+
+/* data associated with BTA_JV_RFCOMM_START_EVT */
+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 */
+    BOOLEAN         use_co;     /* TRUE to use co_rfc_data */
+} tBTA_JV_RFCOMM_START;
+
+/* data associated with BTA_JV_RFCOMM_CL_INIT_EVT */
+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 client */
+    BOOLEAN         use_co;     /* TRUE to use co_rfc_data */
+} tBTA_JV_RFCOMM_CL_INIT;
+/*data associated with BTA_JV_L2CAP_DATA_IND_EVT & BTA_JV_RFCOMM_DATA_IND_EVT */
+typedef struct {
+    UINT32          handle;     /* The connection handle */
+    BT_HDR         *p_buf;      /* The incoming data */
+} tBTA_JV_DATA_IND;
+
+/*data associated with BTA_JV_L2CAP_DATA_IND_EVT if used for LE */
+typedef struct {
+    UINT32          handle;     /* The connection handle */
+    BT_HDR         *p_buf;      /* The incoming data */
+} tBTA_JV_LE_DATA_IND;
+
+
+/* data associated with BTA_JV_RFCOMM_CONG_EVT */
+typedef struct {
+    tBTA_JV_STATUS  status;     /* Whether the operation succeeded or failed. */
+    UINT32          handle;     /* The connection handle */
+    BOOLEAN         cong;       /* TRUE, congested. FALSE, uncongested */
+} tBTA_JV_RFCOMM_CONG;
+
+/* data associated with BTA_JV_RFCOMM_READ_EVT */
+typedef struct {
+    tBTA_JV_STATUS  status;     /* Whether the operation succeeded or failed. */
+    UINT32          handle;     /* The connection handle */
+    UINT32          req_id;     /* The req_id in the associated BTA_JvRfcommRead() */
+    UINT8           *p_data;    /* This points the same location as the p_data
+                                 * parameter in BTA_JvRfcommRead () */
+    UINT16          len;        /* The length of the data read. */
+} tBTA_JV_RFCOMM_READ;
+
+/* data associated with BTA_JV_RFCOMM_WRITE_EVT */
+typedef struct {
+    tBTA_JV_STATUS  status;     /* Whether the operation succeeded or failed. */
+    UINT32          handle;     /* The connection handle */
+    UINT32          req_id;     /* The req_id in the associated BTA_JvRfcommWrite() */
+    int             len;        /* The length of the data written. */
+    BOOLEAN         cong;       /* congestion status */
+} tBTA_JV_RFCOMM_WRITE;
+
+/* data associated with BTA_JV_API_SET_PM_PROFILE_EVT */
+typedef struct {
+    tBTA_JV_STATUS  status;     /* Status of the operation */
+    UINT32          handle;     /* Connection handle */
+    tBTA_JV_PM_ID   app_id;      /* JV app ID */
+} tBTA_JV_SET_PM_PROFILE;
+
+/* data associated with BTA_JV_API_NOTIFY_PM_STATE_CHANGE_EVT */
+typedef struct {
+    UINT32          handle;     /* Connection handle */
+    tBTA_JV_CONN_STATE  state;  /* JV connection stata */
+} tBTA_JV_NOTIFY_PM_STATE_CHANGE;
+
+
+/* union of data associated with JV callback */
+typedef union {
+    tBTA_JV_STATUS          status;         /* BTA_JV_ENABLE_EVT */
+    tBTA_JV_DISCOVERY_COMP  disc_comp;      /* BTA_JV_DISCOVERY_COMP_EVT */
+    tBTA_JV_SET_DISCOVER    set_discover;   /* BTA_JV_SET_DISCOVER_EVT */
+    UINT8                   scn;            /* BTA_JV_GET_SCN_EVT */
+    UINT16                  psm;            /* BTA_JV_GET_PSM_EVT */
+    tBTA_JV_CREATE_RECORD   create_rec;     /* BTA_JV_CREATE_RECORD_EVT */
+    tBTA_JV_L2CAP_OPEN      l2c_open;       /* BTA_JV_L2CAP_OPEN_EVT */
+    tBTA_JV_L2CAP_CLOSE     l2c_close;      /* BTA_JV_L2CAP_CLOSE_EVT */
+    tBTA_JV_L2CAP_START     l2c_start;      /* BTA_JV_L2CAP_START_EVT */
+    tBTA_JV_L2CAP_CL_INIT   l2c_cl_init;    /* BTA_JV_L2CAP_CL_INIT_EVT */
+    tBTA_JV_L2CAP_CONG      l2c_cong;       /* BTA_JV_L2CAP_CONG_EVT */
+    tBTA_JV_L2CAP_READ      l2c_read;       /* BTA_JV_L2CAP_READ_EVT */
+    tBTA_JV_L2CAP_WRITE     l2c_write;      /* BTA_JV_L2CAP_WRITE_EVT */
+    tBTA_JV_RFCOMM_OPEN     rfc_open;       /* BTA_JV_RFCOMM_OPEN_EVT */
+    tBTA_JV_RFCOMM_SRV_OPEN rfc_srv_open;   /* BTA_JV_RFCOMM_SRV_OPEN_EVT */
+    tBTA_JV_RFCOMM_CLOSE    rfc_close;      /* BTA_JV_RFCOMM_CLOSE_EVT */
+    tBTA_JV_RFCOMM_START    rfc_start;      /* BTA_JV_RFCOMM_START_EVT */
+    tBTA_JV_RFCOMM_CL_INIT  rfc_cl_init;    /* BTA_JV_RFCOMM_CL_INIT_EVT */
+    tBTA_JV_RFCOMM_CONG     rfc_cong;       /* BTA_JV_RFCOMM_CONG_EVT */
+    tBTA_JV_RFCOMM_READ     rfc_read;       /* BTA_JV_RFCOMM_READ_EVT */
+    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_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 */
+} tBTA_JV;
+
+/* JAVA DM Interface callback */
+typedef void (tBTA_JV_DM_CBACK)(tBTA_JV_EVT event, tBTA_JV *p_data, void *user_data);
+
+/* JAVA RFCOMM interface callback */
+typedef void *(tBTA_JV_RFCOMM_CBACK)(tBTA_JV_EVT event, tBTA_JV *p_data, void *user_data);
+
+/* JAVA L2CAP interface callback */
+typedef void (tBTA_JV_L2CAP_CBACK)(tBTA_JV_EVT event, tBTA_JV *p_data, void *user_Data);
+
+/* JV configuration structure */
+typedef struct {
+    UINT16  sdp_raw_size;           /* The size of p_sdp_raw_data */
+    UINT16  sdp_db_size;            /* The size of p_sdp_db */
+    UINT8   *p_sdp_raw_data;        /* The data buffer to keep raw data */
+    tSDP_DISCOVERY_DB   *p_sdp_db;  /* The data buffer to keep SDP database */
+} tBTA_JV_CFG;
+
+/*******************************************************************************
+**
+** Function         BTA_JvEnable
+**
+** Description      Enable the Java I/F service. When the enable
+**                  operation is complete the callback function will be
+**                  called with a BTA_JV_ENABLE_EVT. This function must
+**                  be called before other functions in the JV API are
+**                  called.
+**
+** Returns          BTA_JV_SUCCESS if successful.
+**                  BTA_JV_FAIL if internal failure.
+**
+*******************************************************************************/
+extern tBTA_JV_STATUS BTA_JvEnable(tBTA_JV_DM_CBACK *p_cback);
+
+/*******************************************************************************
+**
+** Function         BTA_JvDisable
+**
+** Description      Disable the Java I/F
+**
+** Returns          void
+**
+*******************************************************************************/
+extern void BTA_JvDisable(void);
+
+/*******************************************************************************
+**
+** Function         BTA_JvIsEnable
+**
+** Description      Get the JV registration status.
+**
+** Returns          TRUE, if registered
+**
+*******************************************************************************/
+extern BOOLEAN BTA_JvIsEnable(void);
+
+/*******************************************************************************
+**
+** Function         BTA_JvIsEncrypted
+**
+** Description      This function checks if the link to peer device is encrypted
+**
+** Returns          TRUE if encrypted.
+**                  FALSE if not.
+**
+*******************************************************************************/
+extern BOOLEAN BTA_JvIsEncrypted(BD_ADDR bd_addr);
+
+/*******************************************************************************
+**
+** Function         BTA_JvGetChannelId
+**
+** Description      This function reserves a SCN/PSM for applications running
+**                  over RFCOMM or L2CAP. It is primarily called by
+**                  server profiles/applications to register their SCN/PSM into the
+**                  SDP database. The SCN is reported by the tBTA_JV_DM_CBACK
+**                  callback with a BTA_JV_GET_SCN_EVT.
+**                  If the SCN/PSM reported is 0, that means all SCN resources are
+**                  exhausted.
+**                  The channel parameter can be used to request a specific
+**                  channel. If the request on the specific channel fails, the
+**                  SCN/PSM returned in the EVT will be 0 - no attempt to request
+**                  a new channel will be made. set channel to <= 0 to automatically
+**                  assign an channel ID.
+**
+** Returns          BTA_JV_SUCCESS, if the request is being processed.
+**                  BTA_JV_FAILURE, otherwise.
+**
+*******************************************************************************/
+extern tBTA_JV_STATUS BTA_JvGetChannelId(int conn_type, void *user_data,
+        INT32 channel);
+
+/*******************************************************************************
+**
+** Function         BTA_JvFreeChannel
+**
+** Description      This function frees a SCN/PSM that was used
+**                  by an application running over RFCOMM or L2CAP.
+**
+** 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);
+
+/*******************************************************************************
+**
+** Function         BTA_JvStartDiscovery
+**
+** Description      This function performs service discovery for the services
+**                  provided by the given peer device. When the operation is
+**                  complete the tBTA_JV_DM_CBACK callback function will be
+**                  called with a BTA_JV_DISCOVERY_COMP_EVT.
+**
+** Returns          BTA_JV_SUCCESS, if the request is being processed.
+**                  BTA_JV_FAILURE, otherwise.
+**
+*******************************************************************************/
+extern tBTA_JV_STATUS BTA_JvStartDiscovery(BD_ADDR bd_addr, UINT16 num_uuid,
+        tSDP_UUID *p_uuid_list, void *user_data);
+
+/*******************************************************************************
+**
+** Function         BTA_JvCreateRecordByUser
+**
+** Description      Create a service record in the local SDP database by user in
+**                  tBTA_JV_DM_CBACK callback with a BTA_JV_CREATE_RECORD_EVT.
+**
+** Returns          BTA_JV_SUCCESS, if the request is being processed.
+**                  BTA_JV_FAILURE, otherwise.
+**
+*******************************************************************************/
+extern tBTA_JV_STATUS BTA_JvCreateRecordByUser(const char *name, UINT32 channel, void *user_data);
+
+/*******************************************************************************
+**
+** Function         BTA_JvDeleteRecord
+**
+** Description      Delete a service record in the local SDP database.
+**
+** Returns          BTA_JV_SUCCESS, if the request is being processed.
+**                  BTA_JV_FAILURE, otherwise.
+**
+*******************************************************************************/
+extern tBTA_JV_STATUS BTA_JvDeleteRecord(UINT32 handle);
+
+/*******************************************************************************
+**
+** Function         BTA_JvL2capConnectLE
+**
+** Description      Initiate a connection as an LE L2CAP client to the given BD
+**                  Address.
+**                  When the connection is initiated or failed to initiate,
+**                  tBTA_JV_L2CAP_CBACK is called with BTA_JV_L2CAP_CL_INIT_EVT
+**                  When the connection is established or failed,
+**                  tBTA_JV_L2CAP_CBACK is called with BTA_JV_L2CAP_OPEN_EVT
+**
+** Returns          BTA_JV_SUCCESS, if the request is being processed.
+**                  BTA_JV_FAILURE, otherwise.
+**
+*******************************************************************************/
+extern tBTA_JV_STATUS BTA_JvL2capConnectLE(tBTA_SEC sec_mask, tBTA_JV_ROLE role,
+        const tL2CAP_ERTM_INFO *ertm_info, UINT16 remote_chan,
+        UINT16 rx_mtu, tL2CAP_CFG_INFO *cfg,
+        BD_ADDR peer_bd_addr, tBTA_JV_L2CAP_CBACK *p_cback, void *user_data);
+
+/*******************************************************************************
+**
+** Function         BTA_JvL2capConnect
+**
+** Description      Initiate a connection as a L2CAP client to the given BD
+**                  Address.
+**                  When the connection is initiated or failed to initiate,
+**                  tBTA_JV_L2CAP_CBACK is called with BTA_JV_L2CAP_CL_INIT_EVT
+**                  When the connection is established or failed,
+**                  tBTA_JV_L2CAP_CBACK is called with BTA_JV_L2CAP_OPEN_EVT
+**
+** Returns          BTA_JV_SUCCESS, if the request is being processed.
+**                  BTA_JV_FAILURE, otherwise.
+**
+*******************************************************************************/
+extern tBTA_JV_STATUS BTA_JvL2capConnect(tBTA_SEC sec_mask, tBTA_JV_ROLE role,
+        const tL2CAP_ERTM_INFO *ertm_info, UINT16 remote_psm,
+        UINT16 rx_mtu, tL2CAP_CFG_INFO *cfg,
+        BD_ADDR peer_bd_addr, tBTA_JV_L2CAP_CBACK *p_cback, void *user_data);
+
+/*******************************************************************************
+**
+** Function         BTA_JvL2capClose
+**
+** Description      This function closes an L2CAP client connection
+**
+** Returns          BTA_JV_SUCCESS, if the request is being processed.
+**                  BTA_JV_FAILURE, otherwise.
+**
+*******************************************************************************/
+extern tBTA_JV_STATUS BTA_JvL2capClose(UINT32 handle);
+
+/*******************************************************************************
+**
+** Function         BTA_JvL2capCloseLE
+**
+** Description      This function closes an L2CAP client connection for Fixed Channels
+**                  Function is idempotent and no callbacks are called!
+**
+** Returns          BTA_JV_SUCCESS, if the request is being processed.
+**                  BTA_JV_FAILURE, otherwise.
+**
+*******************************************************************************/
+extern tBTA_JV_STATUS BTA_JvL2capCloseLE(UINT32 handle);
+
+/*******************************************************************************
+**
+** Function         BTA_JvL2capStartServer
+**
+** Description      This function starts an L2CAP server and listens for an L2CAP
+**                  connection from a remote Bluetooth device.  When the server
+**                  is started successfully, tBTA_JV_L2CAP_CBACK is called with
+**                  BTA_JV_L2CAP_START_EVT.  When the connection is established,
+**                  tBTA_JV_L2CAP_CBACK is called with BTA_JV_L2CAP_OPEN_EVT.
+**
+** Returns          BTA_JV_SUCCESS, if the request is being processed.
+**                  BTA_JV_FAILURE, otherwise.
+**
+*******************************************************************************/
+extern tBTA_JV_STATUS BTA_JvL2capStartServer(tBTA_SEC sec_mask, tBTA_JV_ROLE role,
+        const tL2CAP_ERTM_INFO *ertm_info,
+        UINT16 local_psm, UINT16 rx_mtu, tL2CAP_CFG_INFO *cfg,
+        tBTA_JV_L2CAP_CBACK *p_cback, void *user_data);
+
+/*******************************************************************************
+**
+** Function         BTA_JvL2capStartServerLE
+**
+** Description      This function starts an LE L2CAP server and listens for an L2CAP
+**                  connection from a remote Bluetooth device on a fixed channel
+**                  over an LE link.  When the server
+**                  is started successfully, tBTA_JV_L2CAP_CBACK is called with
+**                  BTA_JV_L2CAP_START_EVT.  When the connection is established,
+**                  tBTA_JV_L2CAP_CBACK is called with BTA_JV_L2CAP_OPEN_EVT.
+**
+** Returns          BTA_JV_SUCCESS, if the request is being processed.
+**                  BTA_JV_FAILURE, otherwise.
+**
+*******************************************************************************/
+extern tBTA_JV_STATUS BTA_JvL2capStartServerLE(tBTA_SEC sec_mask, tBTA_JV_ROLE role,
+        const tL2CAP_ERTM_INFO *ertm_info,
+        UINT16 local_chan, UINT16 rx_mtu, tL2CAP_CFG_INFO *cfg,
+        tBTA_JV_L2CAP_CBACK *p_cback, void *user_data);
+
+/*******************************************************************************
+**
+** Function         BTA_JvL2capStopServerLE
+**
+** Description      This function stops the LE L2CAP server. If the server has an
+**                  active connection, it would be closed.
+**
+** Returns          BTA_JV_SUCCESS, if the request is being processed.
+**                  BTA_JV_FAILURE, otherwise.
+**
+*******************************************************************************/
+extern tBTA_JV_STATUS BTA_JvL2capStopServerLE(UINT16 local_chan, void *user_data);
+
+/*******************************************************************************
+**
+** Function         BTA_JvL2capStopServerLE
+**
+** Description      This function stops the LE L2CAP server. If the server has an
+**                  active connection, it would be closed.
+**
+** Returns          BTA_JV_SUCCESS, if the request is being processed.
+**                  BTA_JV_FAILURE, otherwise.
+**
+*******************************************************************************/
+extern tBTA_JV_STATUS BTA_JvL2capStopServer(UINT16 local_psm, void *user_data);
+
+/*******************************************************************************
+**
+** Function         BTA_JvL2capRead
+**
+** Description      This function reads data from an L2CAP connection
+**                  When the operation is complete, tBTA_JV_L2CAP_CBACK is
+**                  called with BTA_JV_L2CAP_READ_EVT.
+**
+** Returns          BTA_JV_SUCCESS, if the request is being processed.
+**                  BTA_JV_FAILURE, otherwise.
+**
+*******************************************************************************/
+extern tBTA_JV_STATUS BTA_JvL2capRead(UINT32 handle, UINT32 req_id,
+                                      UINT8 *p_data, UINT16 len);
+
+/*******************************************************************************
+**
+** Function         BTA_JvL2capReceive
+**
+** Description      This function reads data from an L2CAP connection
+**                  When the operation is complete, tBTA_JV_L2CAP_CBACK is
+**                  called with BTA_JV_L2CAP_RECEIVE_EVT.
+**                  If there are more data queued in L2CAP than len, the extra data will be discarded.
+**
+** Returns          BTA_JV_SUCCESS, if the request is being processed.
+**                  BTA_JV_FAILURE, otherwise.
+**
+*******************************************************************************/
+extern tBTA_JV_STATUS BTA_JvL2capReceive(UINT32 handle, UINT32 req_id,
+        UINT8 *p_data, UINT16 len);
+
+/*******************************************************************************
+**
+** Function         BTA_JvL2capReady
+**
+** Description      This function determined if there is data to read from
+**                  an L2CAP connection
+**
+** Returns          BTA_JV_SUCCESS, if data queue size is in *p_data_size.
+**                  BTA_JV_FAILURE, if error.
+**
+*******************************************************************************/
+extern tBTA_JV_STATUS BTA_JvL2capReady(UINT32 handle, UINT32 *p_data_size);
+
+/*******************************************************************************
+**
+** Function         BTA_JvL2capWrite
+**
+** Description      This function writes data to an L2CAP connection
+**                  When the operation is complete, tBTA_JV_L2CAP_CBACK is
+**                  called with BTA_JV_L2CAP_WRITE_EVT. Works for
+**                  PSM-based connections
+**
+** Returns          BTA_JV_SUCCESS, if the request is being processed.
+**                  BTA_JV_FAILURE, otherwise.
+**
+*******************************************************************************/
+extern tBTA_JV_STATUS BTA_JvL2capWrite(UINT32 handle, UINT32 req_id,
+                                       UINT8 *p_data, UINT16 len, void *user_data);
+
+
+/*******************************************************************************
+**
+** Function         BTA_JvL2capWriteFixed
+**
+** Description      This function writes data to an L2CAP connection
+**                  When the operation is complete, tBTA_JV_L2CAP_CBACK is
+**                  called with BTA_JV_L2CAP_WRITE_FIXED_EVT. Works for
+**                  fixed-channel connections
+**
+** Returns          BTA_JV_SUCCESS, if the request is being processed.
+**                  BTA_JV_FAILURE, otherwise.
+**
+*******************************************************************************/
+extern tBTA_JV_STATUS BTA_JvL2capWriteFixed(UINT16 channel, BD_ADDR *addr, UINT32 req_id,
+        tBTA_JV_L2CAP_CBACK *p_cback,
+        UINT8 *p_data, UINT16 len, void *user_data);
+
+/*******************************************************************************
+**
+** Function         BTA_JvRfcommConnect
+**
+** Description      This function makes an RFCOMM conection to a remote BD
+**                  Address.
+**                  When the connection is initiated or failed to initiate,
+**                  tBTA_JV_RFCOMM_CBACK is called with BTA_JV_RFCOMM_CL_INIT_EVT
+**                  When the connection is established or failed,
+**                  tBTA_JV_RFCOMM_CBACK is called with BTA_JV_RFCOMM_OPEN_EVT
+**
+** Returns          BTA_JV_SUCCESS, if the request is being processed.
+**                  BTA_JV_FAILURE, otherwise.
+**
+*******************************************************************************/
+extern tBTA_JV_STATUS BTA_JvRfcommConnect(tBTA_SEC sec_mask,
+        tBTA_JV_ROLE role, UINT8 remote_scn, BD_ADDR peer_bd_addr,
+        tBTA_JV_RFCOMM_CBACK *p_cback, void *user_data);
+
+/*******************************************************************************
+**
+** Function         BTA_JvRfcommClose
+**
+** Description      This function closes an RFCOMM connection
+**
+** Returns          BTA_JV_SUCCESS, if the request is being processed.
+**                  BTA_JV_FAILURE, otherwise.
+**
+*******************************************************************************/
+extern tBTA_JV_STATUS BTA_JvRfcommClose(UINT32 handle, void *user_data);
+
+/*******************************************************************************
+**
+** Function         BTA_JvRfcommStartServer
+**
+** Description      This function starts listening for an RFCOMM connection
+**                  request from a remote Bluetooth device.  When the server is
+**                  started successfully, tBTA_JV_RFCOMM_CBACK is called
+**                  with BTA_JV_RFCOMM_START_EVT.
+**                  When the connection is established, tBTA_JV_RFCOMM_CBACK
+**                  is called with BTA_JV_RFCOMM_OPEN_EVT.
+**
+** Returns          BTA_JV_SUCCESS, if the request is being processed.
+**                  BTA_JV_FAILURE, otherwise.
+**
+*******************************************************************************/
+extern tBTA_JV_STATUS BTA_JvRfcommStartServer(tBTA_SEC sec_mask,
+        tBTA_JV_ROLE role, UINT8 local_scn, UINT8 max_session,
+        tBTA_JV_RFCOMM_CBACK *p_cback, void *user_data);
+
+/*******************************************************************************
+**
+** Function         BTA_JvRfcommStopServer
+**
+** Description      This function stops the RFCOMM server. If the server has an
+**                  active connection, it would be closed.
+**
+** Returns          BTA_JV_SUCCESS, if the request is being processed.
+**                  BTA_JV_FAILURE, otherwise.
+**
+*******************************************************************************/
+extern tBTA_JV_STATUS BTA_JvRfcommStopServer(UINT32 handle, void *user_data);
+
+/*******************************************************************************
+**
+** Function         BTA_JvRfcommRead
+**
+** Description      This function reads data from an RFCOMM connection
+**                  When the operation is complete, tBTA_JV_RFCOMM_CBACK is
+**                  called with BTA_JV_RFCOMM_READ_EVT.
+**
+** Returns          BTA_JV_SUCCESS, if the request is being processed.
+**                  BTA_JV_FAILURE, otherwise.
+**
+*******************************************************************************/
+extern tBTA_JV_STATUS BTA_JvRfcommRead(UINT32 handle, UINT32 req_id,
+                                       UINT8 *p_data, UINT16 len);
+
+/*******************************************************************************
+**
+** Function         BTA_JvRfcommReady
+**
+** Description      This function determined if there is data to read from
+**                  an RFCOMM connection
+**
+** Returns          BTA_JV_SUCCESS, if data queue size is in *p_data_size.
+**                  BTA_JV_FAILURE, if error.
+**
+*******************************************************************************/
+extern tBTA_JV_STATUS BTA_JvRfcommReady(UINT32 handle, UINT32 *p_data_size);
+
+/*******************************************************************************
+**
+** Function         BTA_JvRfcommWrite
+**
+** Description      This function writes data to an RFCOMM connection
+**                  When the operation is complete, tBTA_JV_RFCOMM_CBACK is
+**                  called with BTA_JV_RFCOMM_WRITE_EVT.
+**
+** Returns          BTA_JV_SUCCESS, if the request is being processed.
+**                  BTA_JV_FAILURE, otherwise.
+**
+*******************************************************************************/
+// extern tBTA_JV_STATUS BTA_JvRfcommWrite(UINT32 handle, UINT32 req_id);
+extern tBTA_JV_STATUS BTA_JvRfcommWrite(UINT32 handle, UINT32 req_id, int len, UINT8 *p_data);
+
+/*******************************************************************************
+ **
+ ** Function    BTA_JVSetPmProfile
+ **
+ ** Description This function set or free power mode profile for different JV application
+ **
+ ** Parameters:  handle,  JV handle from RFCOMM or L2CAP
+ **              app_id:  app specific pm ID, can be BTA_JV_PM_ALL, see bta_dm_cfg.c for details
+ **              BTA_JV_PM_ID_CLEAR: removes pm management on the handle. init_st is ignored and
+ **              BTA_JV_CONN_CLOSE is called implicitely
+ **              init_st:  state after calling this API. typically it should be BTA_JV_CONN_OPEN
+ **
+ ** Returns      BTA_JV_SUCCESS, if the request is being processed.
+ **              BTA_JV_FAILURE, otherwise.
+ **
+ ** NOTE:        BTA_JV_PM_ID_CLEAR: In general no need to be called as jv pm calls automatically
+ **              BTA_JV_CONN_CLOSE to remove in case of connection close!
+ **
+ *******************************************************************************/
+extern tBTA_JV_STATUS BTA_JvSetPmProfile(UINT32 handle, tBTA_JV_PM_ID app_id,
+        tBTA_JV_CONN_STATE init_st);
+
+/*******************************************************************************
+**
+** Function         BTA_JvRfcommGetPortHdl
+**
+** Description    This function fetches the rfcomm port handle
+**
+** Returns          BTA_JV_SUCCESS, if the request is being processed.
+**                  BTA_JV_FAILURE, otherwise.
+**
+*******************************************************************************/
+UINT16 BTA_JvRfcommGetPortHdl(UINT32 handle);
+
+#endif  ///defined BTA_JV_INCLUDED && BTA_JV_INCLUDED == TRUE
+#endif /* BTA_JV_API_H */
diff --git a/components/bt/bluedroid/bta/include/bta_jv_co.h b/components/bt/bluedroid/bta/include/bta_jv_co.h
new file mode 100644 (file)
index 0000000..e68096c
--- /dev/null
@@ -0,0 +1,55 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2007-2012 Broadcom Corporation
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *  This is the interface file for java interface call-out functions.
+ *
+ ******************************************************************************/
+#ifndef BTA_JV_CO_H
+#define BTA_JV_CO_H
+
+#include "bta_jv_api.h"
+
+#if (defined BTA_JV_INCLUDED && BTA_JV_INCLUDED == TRUE)
+/*****************************************************************************
+**  Function Declarations
+*****************************************************************************/
+
+
+/*******************************************************************************
+**
+** Function         bta_jv_co_rfc_data
+**
+** Description      This function is called by JV to send data to the java glue
+**                  code when the RX data path is configured to use a call-out
+**
+** Returns          void
+**
+*******************************************************************************/
+
+extern int bta_co_rfc_data_incoming(void *user_data, BT_HDR *p_buf);
+extern int bta_co_rfc_data_outgoing_size(void *user_data, int *size);
+extern int bta_co_rfc_data_outgoing(void *user_data, UINT8 *buf, UINT16 size);
+
+extern int bta_co_l2cap_data_incoming(void *user_data, BT_HDR *p_buf);
+extern int bta_co_l2cap_data_outgoing_size(void *user_data, int *size);
+extern int bta_co_l2cap_data_outgoing(void *user_data, UINT8 *buf, UINT16 size);
+
+#endif  ///defined BTA_JV_INCLUDED && BTA_JV_INCLUDED == TRUE
+#endif /* BTA_DG_CO_H */
diff --git a/components/bt/bluedroid/bta/jv/bta_jv_act.c b/components/bt/bluedroid/bta/jv/bta_jv_act.c
new file mode 100644 (file)
index 0000000..47666e3
--- /dev/null
@@ -0,0 +1,2772 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2006-2012 Broadcom Corporation
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *  This file contains action functions for BTA JV APIs.
+ *
+ ******************************************************************************/
+
+#include <arpa/inet.h>
+#include <pthread.h>
+#include <stdlib.h>
+
+#include "allocator.h"
+#include "bt_types.h"
+#include "utl.h"
+#include "bta_sys.h"
+#include "bta_api.h"
+#include "bta_jv_api.h"
+#include "bta_jv_int.h"
+#include "bta_jv_co.h"
+#include "btm_api.h"
+#include "btm_int.h"
+#include "sdp_api.h"
+#include "l2c_api.h"
+#include "port_api.h"
+#include <string.h>
+#include "rfcdefs.h"
+#include "avct_api.h"
+#include "avdt_api.h"
+#include "gap_api.h"
+#include "l2c_api.h"
+
+
+#if (defined BTA_JV_INCLUDED && BTA_JV_INCLUDED == TRUE)
+/* one of these exists for each client */
+struct fc_client {
+    struct fc_client    *next_all_list;
+    struct fc_client    *next_chan_list;
+    BD_ADDR              remote_addr;
+    uint32_t             id;
+    tBTA_JV_L2CAP_CBACK *p_cback;
+    void                *user_data;
+    uint16_t             handle;
+    uint16_t             chan;
+    uint8_t              sec_id;
+    unsigned             server      : 1;
+    unsigned             init_called : 1;
+};
+
+/* one of these exists for each channel we're dealing with */
+struct fc_channel {
+    struct fc_channel   *next;
+    struct fc_client    *clients;
+    uint8_t              has_server : 1;
+    uint16_t             chan;
+};
+
+
+static struct fc_client *fc_clients;
+static struct fc_channel *fc_channels;
+static uint32_t fc_next_id;
+static pthread_once_t fc_init_once = PTHREAD_ONCE_INIT;
+
+
+static void fc_init_work(void)
+{
+    fc_clients = NULL;
+    fc_channels = NULL;
+    fc_next_id = 0;
+
+    //more init here if needed...
+}
+
+static void __attribute__((unused)) fc_init(void)
+{
+    pthread_once(&fc_init_once,  fc_init_work);
+}
+
+
+static void fcchan_conn_chng_cbk(UINT16 chan, BD_ADDR bd_addr, BOOLEAN connected,
+                                 UINT16 reason, tBT_TRANSPORT );
+static void fcchan_data_cbk(UINT16 chan, BD_ADDR bd_addr, BT_HDR *p_buf);
+
+
+extern void uuid_to_string_legacy(bt_uuid_t *p_uuid, char *str);
+static inline void logu(const char *title, const uint8_t *p_uuid)
+{
+    char uuids[128];
+    uuid_to_string_legacy((bt_uuid_t *)p_uuid, uuids);
+    APPL_TRACE_DEBUG("%s: %s", title, uuids);
+}
+
+
+static tBTA_JV_PCB *bta_jv_add_rfc_port(tBTA_JV_RFC_CB *p_cb, tBTA_JV_PCB *p_pcb_open);
+static tBTA_JV_STATUS bta_jv_free_set_pm_profile_cb(UINT32 jv_handle);
+static void bta_jv_pm_conn_busy(tBTA_JV_PM_CB *p_cb);
+static void bta_jv_pm_conn_idle(tBTA_JV_PM_CB *p_cb);
+static void bta_jv_pm_state_change(tBTA_JV_PM_CB *p_cb, const tBTA_JV_CONN_STATE state);
+tBTA_JV_STATUS bta_jv_set_pm_conn_state(tBTA_JV_PM_CB *p_cb, const tBTA_JV_CONN_STATE
+                                        new_st);
+
+/*******************************************************************************
+**
+** Function     bta_jv_alloc_sec_id
+**
+** Description  allocate a security id
+**
+** Returns
+**
+*******************************************************************************/
+UINT8 bta_jv_alloc_sec_id(void)
+{
+    UINT8 ret = 0;
+    int i;
+    for (i = 0; i < BTA_JV_NUM_SERVICE_ID; i++) {
+        if (0 == bta_jv_cb.sec_id[i]) {
+            bta_jv_cb.sec_id[i] = BTA_JV_FIRST_SERVICE_ID + i;
+            ret = bta_jv_cb.sec_id[i];
+            break;
+        }
+    }
+    return ret;
+
+}
+static int get_sec_id_used(void)
+{
+    int i;
+    int used = 0;
+    for (i = 0; i < BTA_JV_NUM_SERVICE_ID; i++) {
+        if (bta_jv_cb.sec_id[i]) {
+            used++;
+        }
+    }
+    if (used == BTA_JV_NUM_SERVICE_ID)
+        APPL_TRACE_ERROR("get_sec_id_used, sec id exceeds the limit:%d",
+                         BTA_JV_NUM_SERVICE_ID);
+    return used;
+}
+static int get_rfc_cb_used(void)
+{
+    int i;
+    int used = 0;
+    for (i = 0; i < BTA_JV_MAX_RFC_CONN; i++) {
+        if (bta_jv_cb.rfc_cb[i].handle ) {
+            used++;
+        }
+    }
+    if (used == BTA_JV_MAX_RFC_CONN)
+        APPL_TRACE_ERROR("get_sec_id_used, rfc ctrl block exceeds the limit:%d",
+                         BTA_JV_MAX_RFC_CONN);
+    return used;
+}
+
+/*******************************************************************************
+**
+** Function     bta_jv_free_sec_id
+**
+** Description  free the given security id
+**
+** Returns
+**
+*******************************************************************************/
+static void bta_jv_free_sec_id(UINT8 *p_sec_id)
+{
+    UINT8 sec_id = *p_sec_id;
+    *p_sec_id = 0;
+    if (sec_id >= BTA_JV_FIRST_SERVICE_ID && sec_id <= BTA_JV_LAST_SERVICE_ID) {
+        BTM_SecClrService(sec_id);
+        bta_jv_cb.sec_id[sec_id - BTA_JV_FIRST_SERVICE_ID] = 0;
+    }
+}
+
+/*******************************************************************************
+**
+** Function     bta_jv_alloc_rfc_cb
+**
+** Description  allocate a control block for the given port handle
+**
+** Returns
+**
+*******************************************************************************/
+tBTA_JV_RFC_CB *bta_jv_alloc_rfc_cb(UINT16 port_handle, tBTA_JV_PCB **pp_pcb)
+{
+    tBTA_JV_RFC_CB *p_cb = NULL;
+    tBTA_JV_PCB *p_pcb;
+    int i, j;
+    for (i = 0; i < BTA_JV_MAX_RFC_CONN; i++) {
+        if (0 == bta_jv_cb.rfc_cb[i].handle ) {
+            p_cb = &bta_jv_cb.rfc_cb[i];
+            /* mask handle to distinguish it with L2CAP handle */
+            p_cb->handle = (i + 1) | BTA_JV_RFCOMM_MASK;
+
+            p_cb->max_sess          = 1;
+            p_cb->curr_sess         = 1;
+            for (j = 0; j < BTA_JV_MAX_RFC_SR_SESSION; j++) {
+                p_cb->rfc_hdl[j] = 0;
+            }
+            p_cb->rfc_hdl[0]        = port_handle;
+            APPL_TRACE_DEBUG( "bta_jv_alloc_rfc_cb port_handle:%d handle:0x%2x",
+                              port_handle, p_cb->handle);
+
+            p_pcb = &bta_jv_cb.port_cb[port_handle - 1];
+            p_pcb->handle = p_cb->handle;
+            p_pcb->port_handle = port_handle;
+            p_pcb->p_pm_cb = NULL;
+            *pp_pcb = p_pcb;
+            break;
+        }
+    }
+    if (p_cb == NULL) {
+        APPL_TRACE_ERROR( "bta_jv_alloc_rfc_cb: port_handle:%d, ctrl block exceeds "
+                          "limit:%d", port_handle, BTA_JV_MAX_RFC_CONN);
+    }
+    return p_cb;
+}
+
+/*******************************************************************************
+**
+** Function     bta_jv_rfc_port_to_pcb
+**
+** Description  find the port control block associated with the given port handle
+**
+** Returns
+**
+*******************************************************************************/
+tBTA_JV_PCB *bta_jv_rfc_port_to_pcb(UINT16 port_handle)
+{
+    tBTA_JV_PCB *p_pcb = NULL;
+
+    if ((port_handle > 0) && (port_handle <= MAX_RFC_PORTS)
+            && bta_jv_cb.port_cb[port_handle - 1].handle) {
+        p_pcb = &bta_jv_cb.port_cb[port_handle - 1];
+    }
+
+    return p_pcb;
+}
+
+/*******************************************************************************
+**
+** Function     bta_jv_rfc_port_to_cb
+**
+** Description  find the RFCOMM control block associated with the given port handle
+**
+** Returns
+**
+*******************************************************************************/
+tBTA_JV_RFC_CB *bta_jv_rfc_port_to_cb(UINT16 port_handle)
+{
+    tBTA_JV_RFC_CB *p_cb = NULL;
+    UINT32 handle;
+
+    if ((port_handle > 0) && (port_handle <= MAX_RFC_PORTS)
+            && bta_jv_cb.port_cb[port_handle - 1].handle) {
+        handle = bta_jv_cb.port_cb[port_handle - 1].handle;
+        handle &= BTA_JV_RFC_HDL_MASK;
+        handle &= ~BTA_JV_RFCOMM_MASK;
+        if (handle) {
+            p_cb = &bta_jv_cb.rfc_cb[handle - 1];
+        }
+    } else {
+        APPL_TRACE_WARNING("bta_jv_rfc_port_to_cb(port_handle:0x%x):jv handle:0x%x not"
+                           " FOUND", port_handle, bta_jv_cb.port_cb[port_handle - 1].handle);
+    }
+    return p_cb;
+}
+
+static tBTA_JV_STATUS bta_jv_free_rfc_cb(tBTA_JV_RFC_CB *p_cb, tBTA_JV_PCB *p_pcb)
+{
+    tBTA_JV_STATUS status = BTA_JV_SUCCESS;
+    BOOLEAN remove_server = FALSE;
+    int close_pending = 0;
+
+    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;
+    }
+    APPL_TRACE_DEBUG("bta_jv_free_sr_rfc_cb: max_sess:%d, curr_sess:%d, p_pcb:%p, user:"
+                     "%p, state:%d, jv handle: 0x%x" , p_cb->max_sess, p_cb->curr_sess, p_pcb,
+                     p_pcb->user_data, p_pcb->state, p_pcb->handle);
+
+    if (p_cb->curr_sess <= 0) {
+        return BTA_JV_SUCCESS;
+    }
+
+    switch (p_pcb->state) {
+    case BTA_JV_ST_CL_CLOSING:
+    case BTA_JV_ST_SR_CLOSING:
+        APPL_TRACE_WARNING("bta_jv_free_sr_rfc_cb: return on closing, port state:%d, "
+                           "scn:%d, p_pcb:%p, user_data:%p", p_pcb->state, p_cb->scn, p_pcb,
+                           p_pcb->user_data);
+        status = BTA_JV_FAILURE;
+        return status;
+    case BTA_JV_ST_CL_OPEN:
+    case BTA_JV_ST_CL_OPENING:
+        APPL_TRACE_DEBUG("bta_jv_free_sr_rfc_cb: state: %d, scn:%d,"
+                         " user_data:%p", p_pcb->state, p_cb->scn, p_pcb->user_data);
+        p_pcb->state = BTA_JV_ST_CL_CLOSING;
+        break;
+    case BTA_JV_ST_SR_LISTEN:
+        p_pcb->state = BTA_JV_ST_SR_CLOSING;
+        remove_server = TRUE;
+        APPL_TRACE_DEBUG("bta_jv_free_sr_rfc_cb: state: BTA_JV_ST_SR_LISTEN, scn:%d,"
+                         " user_data:%p", p_cb->scn, p_pcb->user_data);
+        break;
+    case BTA_JV_ST_SR_OPEN:
+        p_pcb->state = BTA_JV_ST_SR_CLOSING;
+        APPL_TRACE_DEBUG("bta_jv_free_sr_rfc_cb: state: BTA_JV_ST_SR_OPEN, scn:%d,"
+                         " user_data:%p", p_cb->scn, p_pcb->user_data);
+        break;
+    default:
+        APPL_TRACE_WARNING("bta_jv_free_sr_rfc_cb():failed, ignore port state:%d, scn:"
+                           "%d, p_pcb:%p, jv handle: 0x%x, port_handle: %d, user_data:%p",
+                           p_pcb->state, p_cb->scn, p_pcb, p_pcb->handle, p_pcb->port_handle,
+                           p_pcb->user_data);
+        status = BTA_JV_FAILURE;
+        break;
+    }
+    if (BTA_JV_SUCCESS == status) {
+        int port_status;
+
+        if (!remove_server) {
+            port_status = RFCOMM_RemoveConnection(p_pcb->port_handle);
+        } else {
+            port_status = RFCOMM_RemoveServer(p_pcb->port_handle);
+        }
+        if (port_status != PORT_SUCCESS) {
+            status = BTA_JV_FAILURE;
+            APPL_TRACE_WARNING("bta_jv_free_rfc_cb(jv handle: 0x%x, state %d)::"
+                               "port_status: %d, port_handle: %d, close_pending: %d:Remove",
+                               p_pcb->handle, p_pcb->state, port_status, p_pcb->port_handle,
+                               close_pending);
+        }
+    }
+    if (!close_pending) {
+        p_pcb->port_handle = 0;
+        p_pcb->state = BTA_JV_ST_NONE;
+        bta_jv_free_set_pm_profile_cb(p_pcb->handle);
+
+        //Initialize congestion flags
+        p_pcb->cong = FALSE;
+        p_pcb->user_data = 0;
+        int si = BTA_JV_RFC_HDL_TO_SIDX(p_pcb->handle);
+        if (0 <= si && si < BTA_JV_MAX_RFC_SR_SESSION) {
+            p_cb->rfc_hdl[si] = 0;
+        }
+        p_pcb->handle = 0;
+        p_cb->curr_sess--;
+        if (p_cb->curr_sess == 0) {
+            p_cb->scn = 0;
+            bta_jv_free_sec_id(&p_cb->sec_id);
+            p_cb->p_cback = NULL;
+            p_cb->handle = 0;
+            p_cb->curr_sess = -1;
+        }
+        if (remove_server) {
+            bta_jv_free_sec_id(&p_cb->sec_id);
+        }
+    }
+    return status;
+}
+
+/*******************************************************************************
+**
+** Function     bta_jv_free_l2c_cb
+**
+** Description  free the given L2CAP control block
+**
+** Returns
+**
+*******************************************************************************/
+tBTA_JV_STATUS bta_jv_free_l2c_cb(tBTA_JV_L2C_CB *p_cb)
+{
+    tBTA_JV_STATUS status = BTA_JV_SUCCESS;
+
+    if (BTA_JV_ST_NONE != p_cb->state) {
+        bta_jv_free_set_pm_profile_cb((UINT32)p_cb->handle);
+        if (GAP_ConnClose(p_cb->handle) != BT_PASS) {
+            status = BTA_JV_FAILURE;
+        }
+    }
+    p_cb->psm = 0;
+    p_cb->state = BTA_JV_ST_NONE;
+    bta_jv_free_sec_id(&p_cb->sec_id);
+    p_cb->p_cback = NULL;
+    return status;
+}
+
+/*******************************************************************************
+**
+**
+** Function    bta_jv_clear_pm_cb
+**
+** Description clears jv pm control block and optionally calls bta_sys_conn_close()
+**             In general close_conn should be set to TRUE to remove registering with
+**             dm pm!
+**
+** WARNING:    Make sure to clear pointer form port or l2c to this control block too!
+**
+*******************************************************************************/
+static void bta_jv_clear_pm_cb(tBTA_JV_PM_CB *p_pm_cb, BOOLEAN close_conn)
+{
+    /* needs to be called if registered with bta pm, otherwise we may run out of dm pm slots! */
+    if (close_conn) {
+        bta_sys_conn_close(BTA_ID_JV, p_pm_cb->app_id, p_pm_cb->peer_bd_addr);
+    }
+    p_pm_cb->state = BTA_JV_PM_FREE_ST;
+    p_pm_cb->app_id = BTA_JV_PM_ALL;
+    p_pm_cb->handle = BTA_JV_PM_HANDLE_CLEAR;
+    bdcpy(p_pm_cb->peer_bd_addr, bd_addr_null);
+}
+
+/*******************************************************************************
+ **
+ ** Function     bta_jv_free_set_pm_profile_cb
+ **
+ ** Description  free pm profile control block
+ **
+ ** Returns     BTA_JV_SUCCESS if cb has been freed correctly,
+ **             BTA_JV_FAILURE in case of no profile has been registered or already freed
+ **
+ *******************************************************************************/
+static tBTA_JV_STATUS bta_jv_free_set_pm_profile_cb(UINT32 jv_handle)
+{
+    tBTA_JV_STATUS status = BTA_JV_FAILURE;
+    tBTA_JV_PM_CB  **p_cb;
+    int i, j, bd_counter = 0, appid_counter = 0;
+
+    for (i = 0; i < BTA_JV_PM_MAX_NUM; i++) {
+        p_cb = NULL;
+        if ((bta_jv_cb.pm_cb[i].state != BTA_JV_PM_FREE_ST) &&
+                (jv_handle == bta_jv_cb.pm_cb[i].handle)) {
+            for (j = 0; j < BTA_JV_PM_MAX_NUM; j++) {
+                if (bdcmp(bta_jv_cb.pm_cb[j].peer_bd_addr, bta_jv_cb.pm_cb[i].peer_bd_addr) == 0) {
+                    bd_counter++;
+                }
+                if (bta_jv_cb.pm_cb[j].app_id == bta_jv_cb.pm_cb[i].app_id) {
+                    appid_counter++;
+                }
+            }
+
+            APPL_TRACE_API("%s(jv_handle: 0x%2x), idx: %d, "
+                           "app_id: 0x%x", __func__, jv_handle, i, bta_jv_cb.pm_cb[i].app_id);
+            APPL_TRACE_API("%s, bd_counter = %d, "
+                           "appid_counter = %d", __func__, bd_counter, appid_counter);
+            if (bd_counter > 1) {
+                bta_jv_pm_conn_idle(&bta_jv_cb.pm_cb[i]);
+            }
+
+            if (bd_counter <= 1 || (appid_counter <= 1)) {
+                bta_jv_clear_pm_cb(&bta_jv_cb.pm_cb[i], TRUE);
+            } else {
+                bta_jv_clear_pm_cb(&bta_jv_cb.pm_cb[i], FALSE);
+            }
+
+            if (BTA_JV_RFCOMM_MASK & jv_handle) {
+                UINT32 hi = ((jv_handle & BTA_JV_RFC_HDL_MASK) & ~BTA_JV_RFCOMM_MASK) - 1;
+                UINT32 si = BTA_JV_RFC_HDL_TO_SIDX(jv_handle);
+                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]) {
+                    tBTA_JV_PCB *p_pcb = bta_jv_rfc_port_to_pcb(bta_jv_cb.rfc_cb[hi].rfc_hdl[si]);
+                    if (p_pcb) {
+                        if (NULL == p_pcb->p_pm_cb)
+                            APPL_TRACE_WARNING("%s(jv_handle:"
+                                               " 0x%x):port_handle: 0x%x, p_pm_cb: %d: no link to "
+                                               "pm_cb?", __func__, jv_handle, p_pcb->port_handle, i);
+                        p_cb = &p_pcb->p_pm_cb;
+                    }
+                }
+            } else {
+                if (jv_handle < BTA_JV_MAX_L2C_CONN) {
+                    tBTA_JV_L2C_CB *p_l2c_cb = &bta_jv_cb.l2c_cb[jv_handle];
+                    if (NULL == p_l2c_cb->p_pm_cb)
+                        APPL_TRACE_WARNING("%s(jv_handle: "
+                                           "0x%x): p_pm_cb: %d: no link to pm_cb?", __func__, jv_handle, i);
+                    p_cb = &p_l2c_cb->p_pm_cb;
+                }
+            }
+            if (p_cb) {
+                *p_cb = NULL;
+                status = BTA_JV_SUCCESS;
+            }
+        }
+    }
+    return status;
+}
+
+/*******************************************************************************
+ **
+ ** Function    bta_jv_alloc_set_pm_profile_cb
+ **
+ ** Description set PM profile control block
+ **
+ ** Returns     pointer to allocated cb or NULL in case of failure
+ **
+ *******************************************************************************/
+static tBTA_JV_PM_CB *bta_jv_alloc_set_pm_profile_cb(UINT32 jv_handle, tBTA_JV_PM_ID app_id)
+{
+    BOOLEAN bRfcHandle = (jv_handle & BTA_JV_RFCOMM_MASK) != 0;
+    BD_ADDR peer_bd_addr;
+    int i, j;
+    tBTA_JV_PM_CB **pp_cb;
+
+    for (i = 0; i < BTA_JV_PM_MAX_NUM; i++) {
+        pp_cb = NULL;
+        if (bta_jv_cb.pm_cb[i].state == BTA_JV_PM_FREE_ST) {
+            /* rfc handle bd addr retrieval requires core stack handle */
+            if (bRfcHandle) {
+                // UINT32 hi = ((jv_handle & BTA_JV_RFC_HDL_MASK) & ~BTA_JV_RFCOMM_MASK) - 1;
+                // UINT32 si = BTA_JV_RFC_HDL_TO_SIDX(jv_handle);
+                for (j = 0; j < BTA_JV_MAX_RFC_CONN; j++) {
+                    if (jv_handle == bta_jv_cb.port_cb[j].handle) {
+                        pp_cb = &bta_jv_cb.port_cb[j].p_pm_cb;
+                        if (PORT_SUCCESS != PORT_CheckConnection(
+                                    bta_jv_cb.port_cb[j].port_handle, peer_bd_addr, NULL)) {
+                            i = BTA_JV_PM_MAX_NUM;
+                        }
+                        break;
+                    }
+                }
+            } else {
+                /* use jv handle for l2cap bd address retrieval */
+                for (j = 0; j < BTA_JV_MAX_L2C_CONN; j++) {
+                    if (jv_handle == bta_jv_cb.l2c_cb[j].handle) {
+                        pp_cb = &bta_jv_cb.l2c_cb[j].p_pm_cb;
+                        UINT8 *p_bd_addr = GAP_ConnGetRemoteAddr((UINT16)jv_handle);
+                        if (NULL != p_bd_addr) {
+                            bdcpy(peer_bd_addr, p_bd_addr);
+                        } else {
+                            i = BTA_JV_PM_MAX_NUM;
+                        }
+                        break;
+                    }
+                }
+            }
+            APPL_TRACE_API("bta_jv_alloc_set_pm_profile_cb(handle 0x%2x, app_id %d): "
+                           "idx: %d, (BTA_JV_PM_MAX_NUM: %d), pp_cb: %p", jv_handle, app_id,
+                           i, BTA_JV_PM_MAX_NUM, (void *)pp_cb);
+            break;
+        }
+    }
+
+    if ((i != BTA_JV_PM_MAX_NUM) && (NULL != pp_cb)) {
+        *pp_cb = &bta_jv_cb.pm_cb[i];
+        bta_jv_cb.pm_cb[i].handle = jv_handle;
+        bta_jv_cb.pm_cb[i].app_id = app_id;
+        bdcpy(bta_jv_cb.pm_cb[i].peer_bd_addr, peer_bd_addr);
+        bta_jv_cb.pm_cb[i].state = BTA_JV_PM_IDLE_ST;
+        return &bta_jv_cb.pm_cb[i];
+    }
+    APPL_TRACE_WARNING("bta_jv_alloc_set_pm_profile_cb(jv_handle: 0x%x, app_id: %d) "
+                       "return NULL", jv_handle, app_id);
+    return (tBTA_JV_PM_CB *)NULL;
+}
+
+/*******************************************************************************
+**
+** Function     bta_jv_check_psm
+**
+** Description  for now use only the legal PSM per JSR82 spec
+**
+** Returns      TRUE, if allowed
+**
+*******************************************************************************/
+BOOLEAN bta_jv_check_psm(UINT16 psm)
+{
+    BOOLEAN ret = FALSE;
+
+    if (L2C_IS_VALID_PSM(psm)) {
+        if (psm < 0x1001) {
+            /* see if this is defined by spec */
+            switch (psm) {
+            case SDP_PSM:           /* 1 */
+            case BT_PSM_RFCOMM:     /* 3 */
+                /* do not allow java app to use these 2 PSMs */
+                break;
+
+            case TCS_PSM_INTERCOM:  /* 5 */
+            case TCS_PSM_CORDLESS:  /* 7 */
+                if ( FALSE == bta_sys_is_register(BTA_ID_CT) &&
+                        FALSE == bta_sys_is_register(BTA_ID_CG) ) {
+                    ret = TRUE;
+                }
+                break;
+
+            case BT_PSM_BNEP:       /* F */
+                if (FALSE == bta_sys_is_register(BTA_ID_PAN)) {
+                    ret = TRUE;
+                }
+                break;
+
+            case HID_PSM_CONTROL:   /* 0x11 */
+            case HID_PSM_INTERRUPT: /* 0x13 */
+                //FIX: allow HID Device and HID Host to coexist
+                if ( FALSE == bta_sys_is_register(BTA_ID_HD) ||
+                        FALSE == bta_sys_is_register(BTA_ID_HH) ) {
+                    ret = TRUE;
+                }
+                break;
+
+            case AVCT_PSM:          /* 0x17 */
+            case AVDT_PSM:          /* 0x19 */
+                if ((FALSE == bta_sys_is_register(BTA_ID_AV)) &&
+                        (FALSE == bta_sys_is_register(BTA_ID_AVK))) {
+                    ret = TRUE;
+                }
+                break;
+
+            default:
+                ret = TRUE;
+                break;
+            }
+        } else {
+            ret = TRUE;
+        }
+    }
+    return ret;
+
+}
+
+/*******************************************************************************
+**
+** Function     bta_jv_enable
+**
+** Description  Initialises the JAVA I/F
+**
+** Returns      void
+**
+*******************************************************************************/
+void bta_jv_enable(tBTA_JV_MSG *p_data)
+{
+    tBTA_JV_STATUS status = BTA_JV_SUCCESS;
+    bta_jv_cb.p_dm_cback = p_data->enable.p_cback;
+    bta_jv_cb.p_dm_cback(BTA_JV_ENABLE_EVT, (tBTA_JV *)&status, 0);
+    memset(bta_jv_cb.free_psm_list, 0, sizeof(bta_jv_cb.free_psm_list));
+}
+
+/*******************************************************************************
+**
+** Function     bta_jv_disable
+**
+** Description  Disables the BT device manager
+**              free the resources used by java
+**
+** Returns      void
+**
+*******************************************************************************/
+void bta_jv_disable (tBTA_JV_MSG *p_data)
+{
+    UNUSED(p_data);
+
+    APPL_TRACE_ERROR("%s", __func__);
+}
+
+
+/**
+ * We keep a list of PSM's that have been freed from JAVA, for reuse.
+ * This function will return a free PSM, and delete it from the free
+ * list.
+ * If no free PSMs exist, 0 will be returned.
+ */
+static UINT16 bta_jv_get_free_psm()
+{
+    const int cnt = sizeof(bta_jv_cb.free_psm_list) / sizeof(bta_jv_cb.free_psm_list[0]);
+    for (int i = 0; i < cnt; i++) {
+        UINT16 psm = bta_jv_cb.free_psm_list[i];
+        if (psm != 0) {
+            APPL_TRACE_DEBUG("%s(): Reusing PSM: 0x%04d", __func__, psm)
+            bta_jv_cb.free_psm_list[i] = 0;
+            return psm;
+        }
+    }
+    return 0;
+}
+
+static void bta_jv_set_free_psm(UINT16 psm)
+{
+    int free_index = -1;
+    const int cnt = sizeof(bta_jv_cb.free_psm_list) / sizeof(bta_jv_cb.free_psm_list[0]);
+    for (int i = 0; i < cnt; i++) {
+        if (bta_jv_cb.free_psm_list[i] == 0) {
+            free_index = i;
+        } else if (psm == bta_jv_cb.free_psm_list[i]) {
+            return; // PSM already freed?
+        }
+    }
+    if (free_index != -1) {
+        bta_jv_cb.free_psm_list[free_index] = psm;
+        APPL_TRACE_DEBUG("%s(): Recycling PSM: 0x%04d", __func__, psm)
+    } else {
+        APPL_TRACE_ERROR("%s unable to free psm 0x%x no more free slots", __func__, psm);
+    }
+}
+
+/*******************************************************************************
+**
+** Function     bta_jv_get_channel_id
+**
+** Description  Obtain a free SCN (Server Channel Number)
+**              (RFCOMM channel or L2CAP PSM)
+**
+** Returns      void
+**
+*******************************************************************************/
+void bta_jv_get_channel_id(tBTA_JV_MSG *p_data)
+{
+    UINT16   psm = 0;
+
+    switch (p_data->alloc_channel.type) {
+    case BTA_JV_CONN_TYPE_RFCOMM: {
+        INT32   channel = p_data->alloc_channel.channel;
+        UINT8 scn = 0;
+        if (channel > 0) {
+            if (BTM_TryAllocateSCN(channel) == FALSE) {
+                APPL_TRACE_ERROR("rfc channel:%d already in use or invalid", channel);
+                channel = 0;
+            }
+        } else if ((channel = BTM_AllocateSCN()) == 0) {
+            APPL_TRACE_ERROR("run out of rfc channels");
+            channel = 0;
+        }
+        if (channel != 0) {
+            bta_jv_cb.scn[channel - 1] = TRUE;
+            scn = (UINT8) channel;
+        }
+        if (bta_jv_cb.p_dm_cback)
+            bta_jv_cb.p_dm_cback(BTA_JV_GET_SCN_EVT, (tBTA_JV *)&scn,
+                                 p_data->alloc_channel.user_data);
+        return;
+    }
+    case BTA_JV_CONN_TYPE_L2CAP:
+        psm = bta_jv_get_free_psm();
+        if (psm == 0) {
+            psm = L2CA_AllocatePSM();
+            APPL_TRACE_DEBUG("%s() returned PSM: 0x%04x", __func__, psm);
+        }
+        break;
+    case BTA_JV_CONN_TYPE_L2CAP_LE:
+        break;
+    default:
+        break;
+    }
+
+    if (bta_jv_cb.p_dm_cback) {
+        bta_jv_cb.p_dm_cback(BTA_JV_GET_PSM_EVT, (tBTA_JV *)&psm, p_data->alloc_channel.user_data);
+    }
+}
+
+/*******************************************************************************
+**
+** Function     bta_jv_free_scn
+**
+** Description  free a SCN
+**
+** Returns      void
+**
+*******************************************************************************/
+void bta_jv_free_scn(tBTA_JV_MSG *p_data)
+{
+    UINT16   scn = p_data->free_channel.scn;
+
+    switch (p_data->free_channel.type) {
+    case BTA_JV_CONN_TYPE_RFCOMM: {
+        if (scn > 0 && scn <= BTA_JV_MAX_SCN && bta_jv_cb.scn[scn - 1]) {
+            /* this scn is used by JV */
+            bta_jv_cb.scn[scn - 1] = FALSE;
+            BTM_FreeSCN(scn);
+        }
+        break;
+    }
+    case BTA_JV_CONN_TYPE_L2CAP:
+        bta_jv_set_free_psm(scn);
+        break;
+    case BTA_JV_CONN_TYPE_L2CAP_LE:
+        // TODO: Not yet implemented...
+        break;
+    default:
+        break;
+    }
+}
+static inline tBT_UUID shorten_sdp_uuid(const tBT_UUID *u)
+{
+    static uint8_t bt_base_uuid[] =
+    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB };
+
+    logu("in, uuid:", u->uu.uuid128);
+    APPL_TRACE_DEBUG("uuid len:%d", u->len);
+    if (u->len == 16) {
+        if (memcmp(&u->uu.uuid128[4], &bt_base_uuid[4], 12) == 0) {
+            tBT_UUID su;
+            memset(&su, 0, sizeof(su));
+            if (u->uu.uuid128[0] == 0 && u->uu.uuid128[1] == 0) {
+                su.len = 2;
+                uint16_t u16;
+                memcpy(&u16, &u->uu.uuid128[2], sizeof(u16));
+                su.uu.uuid16 = ntohs(u16);
+                APPL_TRACE_DEBUG("shorten to 16 bits uuid: %x", su.uu.uuid16);
+            } else {
+                su.len = 4;
+                uint32_t u32;
+                memcpy(&u32, &u->uu.uuid128[0], sizeof(u32));
+                su.uu.uuid32 = ntohl(u32);
+                APPL_TRACE_DEBUG("shorten to 32 bits uuid: %x", su.uu.uuid32);
+            }
+            return su;
+        }
+    }
+    APPL_TRACE_DEBUG("cannot shorten none-reserved 128 bits uuid");
+    return *u;
+}
+
+/*******************************************************************************
+**
+** Function     bta_jv_start_discovery_cback
+**
+** Description  Callback for Start Discovery
+**
+** Returns      void
+**
+*******************************************************************************/
+static void bta_jv_start_discovery_cback(UINT16 result, void *user_data)
+{
+    tBTA_JV_STATUS status;
+    // UINT8          old_sdp_act = bta_jv_cb.sdp_active;
+
+    APPL_TRACE_DEBUG("bta_jv_start_discovery_cback res: 0x%x", result);
+
+    bta_jv_cb.sdp_active = BTA_JV_SDP_ACT_NONE;
+    if (bta_jv_cb.p_dm_cback) {
+        tBTA_JV_DISCOVERY_COMP dcomp;
+        dcomp.scn_num = 0;
+        status = BTA_JV_FAILURE;
+        if (result == SDP_SUCCESS || result == SDP_DB_FULL) {
+            tSDP_DISC_REC       *p_sdp_rec = 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);
+            logu("shorten uuid:", su.uu.uuid128);
+            do{
+                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];
+                    status = BTA_JV_SUCCESS;
+                }
+            } while (p_sdp_rec);
+        }
+
+        dcomp.status = status;
+        bta_jv_cb.p_dm_cback(BTA_JV_DISCOVERY_COMP_EVT, (tBTA_JV *)&dcomp, user_data);
+    }
+}
+
+/*******************************************************************************
+**
+** Function     bta_jv_start_discovery
+**
+** Description  Discovers services on a remote device
+**
+** Returns      void
+**
+*******************************************************************************/
+void bta_jv_start_discovery(tBTA_JV_MSG *p_data)
+{
+    tBTA_JV_STATUS status = BTA_JV_FAILURE;
+    APPL_TRACE_DEBUG("bta_jv_start_discovery in, sdp_active:%d", bta_jv_cb.sdp_active);
+    if (bta_jv_cb.sdp_active != BTA_JV_SDP_ACT_NONE) {
+        /* SDP is still in progress */
+        status = BTA_JV_BUSY;
+        if (bta_jv_cb.p_dm_cback) {
+            bta_jv_cb.p_dm_cback(BTA_JV_DISCOVERY_COMP_EVT, (tBTA_JV *)&status, p_data->start_discovery.user_data);
+        }
+        return;
+    }
+
+    /* init the database/set up the filter */
+    APPL_TRACE_DEBUG("call SDP_InitDiscoveryDb, p_data->start_discovery.num_uuid:%d",
+                     p_data->start_discovery.num_uuid);
+    SDP_InitDiscoveryDb (p_bta_jv_cfg->p_sdp_db, p_bta_jv_cfg->sdp_db_size,
+                         p_data->start_discovery.num_uuid, p_data->start_discovery.uuid_list, 0, NULL);
+
+    /* tell SDP to keep the raw data */
+    p_bta_jv_cfg->p_sdp_db->raw_data = p_bta_jv_cfg->p_sdp_raw_data;
+    p_bta_jv_cfg->p_sdp_db->raw_size = p_bta_jv_cfg->sdp_raw_size;
+
+    bta_jv_cb.p_sel_raw_data     = 0;
+    bta_jv_cb.uuid = p_data->start_discovery.uuid_list[0];
+
+    bta_jv_cb.sdp_active = BTA_JV_SDP_ACT_YES;
+    if (!SDP_ServiceSearchAttributeRequest2(p_data->start_discovery.bd_addr,
+                                            p_bta_jv_cfg->p_sdp_db,
+                                            bta_jv_start_discovery_cback, p_data->start_discovery.user_data)) {
+        bta_jv_cb.sdp_active = BTA_JV_SDP_ACT_NONE;
+        /* failed to start SDP. report the failure right away */
+        if (bta_jv_cb.p_dm_cback) {
+            bta_jv_cb.p_dm_cback(BTA_JV_DISCOVERY_COMP_EVT, (tBTA_JV *)&status, p_data->start_discovery.user_data);
+        }
+    }
+    /*
+    else report the result when the cback is called
+    */
+}
+
+/**
+ * @brief       Adds a protocol list and service name (if provided) to an SDP record given by
+ *              sdp_handle, and marks it as browseable. This is a shortcut for defining a
+ *              set of protocols that includes L2CAP, RFCOMM, and optionally OBEX.
+ *
+ * @param[in]   sdp_handle: SDP handle
+ * @param[in]   name:       service name
+ * @param[in]   channel:    channel
+ * @param[in]   with_obex:  if TRUE, then an additional OBEX protocol UUID will be included
+ *                          at the end of the protocol list.
+ * @return
+ *              - TRUE : success
+ *              - other  : failed
+ */
+static bool create_base_record(const uint32_t sdp_handle, const char *name, const uint16_t channel, const bool with_obex){
+    APPL_TRACE_DEBUG("create_base_record: scn: %d, name: %s, with_obex: %d",
+                   channel, name, with_obex);
+
+    // Setup the protocol list and add it.
+    tSDP_PROTOCOL_ELEM proto_list[SDP_MAX_LIST_ELEMS];
+    int num_proto_elements = with_obex ? 3 : 2;
+
+    memset(proto_list, 0, num_proto_elements * sizeof(tSDP_PROTOCOL_ELEM));
+
+    proto_list[0].protocol_uuid = UUID_PROTOCOL_L2CAP;
+    proto_list[0].num_params = 0;
+    proto_list[1].protocol_uuid = UUID_PROTOCOL_RFCOMM;
+    proto_list[1].num_params = 1;
+    proto_list[1].params[0] = channel;
+
+    if (with_obex == TRUE) {
+        proto_list[2].protocol_uuid = UUID_PROTOCOL_OBEX;
+        proto_list[2].num_params = 0;
+    }
+
+    char *stage = "protocol_list";
+    if (!SDP_AddProtocolList(sdp_handle, num_proto_elements, proto_list)){
+        APPL_TRACE_ERROR("create_base_record: failed to create base service "
+                   "record, stage: %s, scn: %d, name: %s, with_obex: %d",
+                   stage, channel, name, with_obex);
+        return FALSE;
+    }
+
+    // Add the name to the SDP record.
+    if (name[0] != '\0') {
+        stage = "service_name";
+        if (!SDP_AddAttribute(sdp_handle, ATTR_ID_SERVICE_NAME,
+                          TEXT_STR_DESC_TYPE, (uint32_t)(strlen(name) + 1),
+                          (uint8_t *)name)){
+            APPL_TRACE_ERROR("create_base_record: failed to create base service "
+                       "record, stage: %s, scn: %d, name: %s, with_obex: %d",
+                       stage, channel, name, with_obex);
+            return FALSE;
+        }
+    }
+
+    // Mark the service as browseable.
+    uint16_t list = UUID_SERVCLASS_PUBLIC_BROWSE_GROUP;
+    stage = "browseable";
+    if (!SDP_AddUuidSequence(sdp_handle, ATTR_ID_BROWSE_GROUP_LIST, 1, &list)){
+        APPL_TRACE_ERROR("create_base_record: failed to create base service "
+                   "record, stage: %s, scn: %d, name: %s, with_obex: %d",
+                   stage, channel, name, with_obex);
+        return FALSE;
+    }
+
+
+    APPL_TRACE_DEBUG("create_base_record: successfully created base service "
+                   "record, handle: 0x%08x, scn: %d, name: %s, with_obex: %d",
+                   sdp_handle, channel, name, with_obex);
+    return TRUE;
+}
+
+static int add_spp_sdp(const char *name, const int channel) {
+    APPL_TRACE_DEBUG("add_spp_sdp: scn %d, service_name %s", channel, name);
+
+    int handle = SDP_CreateRecord();
+    if (handle == 0) {
+        APPL_TRACE_ERROR("add_spp_sdp: failed to create sdp record, "
+                     "service_name: %s", name);
+        return 0;
+    }
+
+    // Create the base SDP record.
+    char *stage = "create_base_record";
+    if (!create_base_record(handle, name, channel, FALSE /* with_obex */)){
+        SDP_DeleteRecord(handle);
+        APPL_TRACE_ERROR("add_spp_sdp: failed to register SPP service, "
+                   "stage: %s, service_name: %s", stage, name);
+        return 0;
+    }
+
+    uint16_t service = UUID_SERVCLASS_SERIAL_PORT;
+    stage = "service_class";
+    if (!SDP_AddServiceClassIdList(handle, 1, &service)){
+        SDP_DeleteRecord(handle);
+        APPL_TRACE_ERROR("add_spp_sdp: failed to register SPP service, "
+                   "stage: %s, service_name: %s", stage, name);
+        return 0;
+    }
+
+    APPL_TRACE_DEBUG("add_spp_sdp: service registered successfully, "
+                   "service_name: %s, handle 0x%08x)", name, handle);
+    return handle;
+}
+
+/*******************************************************************************
+**
+** Function     bta_jv_create_record
+**
+** Description  Create an SDP record with the given attributes
+**
+** Returns      void
+**
+*******************************************************************************/
+void bta_jv_create_record(tBTA_JV_MSG *p_data)
+{
+    tBTA_JV_API_CREATE_RECORD *cr = &(p_data->create_record);
+    tBTA_JV_CREATE_RECORD   evt_data;
+
+    int handle = add_spp_sdp(cr->name, cr->channel);
+    evt_data.handle = handle;
+    if (handle) {
+        evt_data.status = BTA_JV_SUCCESS;
+    } else {
+        evt_data.status = BTA_JV_FAILURE;
+    }
+
+    if(bta_jv_cb.p_dm_cback) {
+        //callback user immediately to create his own sdp record in stack thread context
+        bta_jv_cb.p_dm_cback(BTA_JV_CREATE_RECORD_EVT, (tBTA_JV *)&evt_data, cr->user_data);
+    }
+}
+
+/*******************************************************************************
+**
+** Function     bta_jv_delete_record
+**
+** Description  Delete an SDP record
+**
+**
+** Returns      void
+**
+*******************************************************************************/
+void bta_jv_delete_record(tBTA_JV_MSG *p_data)
+{
+    tBTA_JV_API_ADD_ATTRIBUTE *dr = &(p_data->add_attr);
+    if (dr->handle) {
+        /* this is a record created by btif layer*/
+        SDP_DeleteRecord(dr->handle);
+    }
+}
+
+/*******************************************************************************
+**
+** Function     bta_jv_l2cap_client_cback
+**
+** Description  handles the l2cap client events
+**
+** Returns      void
+**
+*******************************************************************************/
+static void bta_jv_l2cap_client_cback(UINT16 gap_handle, UINT16 event)
+{
+    tBTA_JV_L2C_CB  *p_cb = &bta_jv_cb.l2c_cb[gap_handle];
+    tBTA_JV     evt_data;
+
+    if (gap_handle >= BTA_JV_MAX_L2C_CONN && !p_cb->p_cback) {
+        return;
+    }
+
+    APPL_TRACE_DEBUG( "%s: %d evt:x%x", __func__, gap_handle, event);
+    evt_data.l2c_open.status = BTA_JV_SUCCESS;
+    evt_data.l2c_open.handle = gap_handle;
+
+    switch (event) {
+    case GAP_EVT_CONN_OPENED:
+        bdcpy(evt_data.l2c_open.rem_bda, GAP_ConnGetRemoteAddr(gap_handle));
+        evt_data.l2c_open.tx_mtu = GAP_ConnGetRemMtuSize(gap_handle);
+        p_cb->state = BTA_JV_ST_CL_OPEN;
+        p_cb->p_cback(BTA_JV_L2CAP_OPEN_EVT, &evt_data, p_cb->user_data);
+        break;
+
+    case GAP_EVT_CONN_CLOSED:
+        p_cb->state = BTA_JV_ST_NONE;
+        bta_jv_free_sec_id(&p_cb->sec_id);
+        evt_data.l2c_close.async = TRUE;
+        p_cb->p_cback(BTA_JV_L2CAP_CLOSE_EVT, &evt_data, p_cb->user_data);
+        p_cb->p_cback = NULL;
+        break;
+
+    case GAP_EVT_CONN_DATA_AVAIL:
+        evt_data.data_ind.handle = gap_handle;
+        /* Reset idle timer to avoid requesting sniff mode while receiving data */
+        bta_jv_pm_conn_busy(p_cb->p_pm_cb);
+        p_cb->p_cback(BTA_JV_L2CAP_DATA_IND_EVT, &evt_data, p_cb->user_data);
+        bta_jv_pm_conn_idle(p_cb->p_pm_cb);
+        break;
+
+    case GAP_EVT_CONN_CONGESTED:
+    case GAP_EVT_CONN_UNCONGESTED:
+        p_cb->cong = (event == GAP_EVT_CONN_CONGESTED) ? TRUE : FALSE;
+        evt_data.l2c_cong.cong = p_cb->cong;
+        p_cb->p_cback(BTA_JV_L2CAP_CONG_EVT, &evt_data, p_cb->user_data);
+        break;
+
+    default:
+        break;
+    }
+}
+
+/*******************************************************************************
+**
+** Function     bta_jv_l2cap_connect
+**
+** Description  makes an l2cap client connection
+**
+** Returns      void
+**
+*******************************************************************************/
+void bta_jv_l2cap_connect(tBTA_JV_MSG *p_data)
+{
+    tBTA_JV_L2C_CB      *p_cb;
+    tBTA_JV_L2CAP_CL_INIT  evt_data;
+    UINT16  handle = GAP_INVALID_HANDLE;
+    UINT8   sec_id;
+    tL2CAP_CFG_INFO cfg;
+    tBTA_JV_API_L2CAP_CONNECT *cc = &(p_data->l2cap_connect);
+    UINT8 chan_mode_mask = GAP_FCR_CHAN_OPT_BASIC;
+    tL2CAP_ERTM_INFO    *ertm_info = NULL;
+
+    memset(&cfg, 0, sizeof(tL2CAP_CFG_INFO));
+
+    if (cc->has_cfg == TRUE) {
+        cfg = cc->cfg;
+        if (cfg.fcr_present && cfg.fcr.mode == L2CAP_FCR_ERTM_MODE) {
+            chan_mode_mask = GAP_FCR_CHAN_OPT_ERTM;
+        }
+    }
+
+    if (cc->has_ertm_info == TRUE) {
+        ertm_info = &(cc->ertm_info);
+    }
+
+    /* We need to use this value for MTU to be able to handle cases where cfg is not set in req. */
+    cfg.mtu_present = TRUE;
+    cfg.mtu = cc->rx_mtu;
+
+    /* TODO: DM role manager
+    L2CA_SetDesireRole(cc->role);
+    */
+
+    sec_id = bta_jv_alloc_sec_id();
+    evt_data.sec_id = sec_id;
+    evt_data.status = BTA_JV_FAILURE;
+
+    if (sec_id) {
+        if (bta_jv_check_psm(cc->remote_psm)) { /* allowed */
+            if ((handle = GAP_ConnOpen("", sec_id, 0, cc->peer_bd_addr, cc->remote_psm,
+                                       &cfg, ertm_info, cc->sec_mask, chan_mode_mask,
+                                       bta_jv_l2cap_client_cback)) != GAP_INVALID_HANDLE ) {
+                evt_data.status = BTA_JV_SUCCESS;
+            }
+        }
+    }
+
+    if (evt_data.status == BTA_JV_SUCCESS) {
+        p_cb = &bta_jv_cb.l2c_cb[handle];
+        p_cb->handle = handle;
+        p_cb->p_cback = cc->p_cback;
+        p_cb->user_data = cc->user_data;
+        p_cb->psm = 0;  /* not a server */
+        p_cb->sec_id = sec_id;
+        p_cb->state = BTA_JV_ST_CL_OPENING;
+    } else {
+        bta_jv_free_sec_id(&sec_id);
+    }
+
+    evt_data.handle = handle;
+    cc->p_cback(BTA_JV_L2CAP_CL_INIT_EVT, (tBTA_JV *)&evt_data, cc->user_data);
+}
+
+
+/*******************************************************************************
+**
+** Function     bta_jv_l2cap_close
+**
+** Description  Close an L2CAP client connection
+**
+** Returns      void
+**
+*******************************************************************************/
+void bta_jv_l2cap_close(tBTA_JV_MSG *p_data)
+{
+    tBTA_JV_L2CAP_CLOSE  evt_data;
+    tBTA_JV_API_L2CAP_CLOSE *cc = &(p_data->l2cap_close);
+    tBTA_JV_L2CAP_CBACK *p_cback = cc->p_cb->p_cback;
+    void *user_data = cc->p_cb->user_data;
+
+    evt_data.handle = cc->handle;
+    evt_data.status = bta_jv_free_l2c_cb(cc->p_cb);
+    evt_data.async = FALSE;
+
+    if (p_cback) {
+        p_cback(BTA_JV_L2CAP_CLOSE_EVT, (tBTA_JV *)&evt_data, user_data);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         bta_jv_l2cap_server_cback
+**
+** Description      handles the l2cap server callback
+**
+** Returns          void
+**
+*******************************************************************************/
+static void bta_jv_l2cap_server_cback(UINT16 gap_handle, UINT16 event)
+{
+    tBTA_JV_L2C_CB  *p_cb = &bta_jv_cb.l2c_cb[gap_handle];
+    tBTA_JV evt_data;
+    tBTA_JV_L2CAP_CBACK *p_cback;
+    void *user_data;
+
+    if (gap_handle >= BTA_JV_MAX_L2C_CONN && !p_cb->p_cback) {
+        return;
+    }
+
+    APPL_TRACE_DEBUG( "%s: %d evt:x%x", __func__, gap_handle, event);
+    evt_data.l2c_open.status = BTA_JV_SUCCESS;
+    evt_data.l2c_open.handle = gap_handle;
+
+    switch (event) {
+    case GAP_EVT_CONN_OPENED:
+        bdcpy(evt_data.l2c_open.rem_bda, GAP_ConnGetRemoteAddr(gap_handle));
+        evt_data.l2c_open.tx_mtu = GAP_ConnGetRemMtuSize(gap_handle);
+        p_cb->state = BTA_JV_ST_SR_OPEN;
+        p_cb->p_cback(BTA_JV_L2CAP_OPEN_EVT, &evt_data, p_cb->user_data);
+        break;
+
+    case GAP_EVT_CONN_CLOSED:
+        evt_data.l2c_close.async = TRUE;
+        evt_data.l2c_close.handle = p_cb->handle;
+        p_cback = p_cb->p_cback;
+        user_data = p_cb->user_data;
+        evt_data.l2c_close.status = bta_jv_free_l2c_cb(p_cb);
+        p_cback(BTA_JV_L2CAP_CLOSE_EVT, &evt_data, user_data);
+        break;
+
+    case GAP_EVT_CONN_DATA_AVAIL:
+        evt_data.data_ind.handle = gap_handle;
+        /* Reset idle timer to avoid requesting sniff mode while receiving data */
+        bta_jv_pm_conn_busy(p_cb->p_pm_cb);
+        p_cb->p_cback(BTA_JV_L2CAP_DATA_IND_EVT, &evt_data, p_cb->user_data);
+        bta_jv_pm_conn_idle(p_cb->p_pm_cb);
+        break;
+
+    case GAP_EVT_CONN_CONGESTED:
+    case GAP_EVT_CONN_UNCONGESTED:
+        p_cb->cong = (event == GAP_EVT_CONN_CONGESTED) ? TRUE : FALSE;
+        evt_data.l2c_cong.cong = p_cb->cong;
+        p_cb->p_cback(BTA_JV_L2CAP_CONG_EVT, &evt_data, p_cb->user_data);
+        break;
+
+    default:
+        break;
+    }
+}
+
+/*******************************************************************************
+**
+** Function     bta_jv_l2cap_start_server
+**
+** Description  starts an L2CAP server
+**
+** Returns      void
+**
+*******************************************************************************/
+void bta_jv_l2cap_start_server(tBTA_JV_MSG *p_data)
+{
+    tBTA_JV_L2C_CB      *p_cb;
+    UINT8   sec_id;
+    UINT16  handle;
+    tL2CAP_CFG_INFO cfg;
+    tBTA_JV_L2CAP_START evt_data;
+    tBTA_JV_API_L2CAP_SERVER *ls = &(p_data->l2cap_server);
+    // INT32   use_etm = FALSE;
+    UINT8 chan_mode_mask = GAP_FCR_CHAN_OPT_BASIC;
+    tL2CAP_ERTM_INFO    *ertm_info = NULL;
+
+    memset(&cfg, 0, sizeof(tL2CAP_CFG_INFO));
+
+    if (ls->has_cfg == TRUE) {
+        cfg = ls->cfg;
+        if (cfg.fcr_present && cfg.fcr.mode == L2CAP_FCR_ERTM_MODE) {
+            chan_mode_mask = GAP_FCR_CHAN_OPT_ERTM;
+        }
+    }
+
+    if (ls->has_ertm_info == TRUE) {
+        ertm_info = &(ls->ertm_info);
+    }
+
+    //FIX: MTU=0 means not present
+    if (ls->rx_mtu > 0) {
+        cfg.mtu_present = TRUE;
+        cfg.mtu = ls->rx_mtu;
+    } else {
+        cfg.mtu_present = FALSE;
+        cfg.mtu = 0;
+    }
+
+    /* TODO DM role manager
+    L2CA_SetDesireRole(ls->role);
+    */
+
+    sec_id = bta_jv_alloc_sec_id();
+    if (0 == sec_id || (FALSE == bta_jv_check_psm(ls->local_psm)) ||
+            (handle = GAP_ConnOpen("JV L2CAP", sec_id, 1, 0, ls->local_psm, &cfg, ertm_info,
+                                   ls->sec_mask, chan_mode_mask, bta_jv_l2cap_server_cback)) == GAP_INVALID_HANDLE) {
+        bta_jv_free_sec_id(&sec_id);
+        evt_data.status = BTA_JV_FAILURE;
+    } else {
+        p_cb = &bta_jv_cb.l2c_cb[handle];
+        evt_data.status = BTA_JV_SUCCESS;
+        evt_data.handle = handle;
+        evt_data.sec_id = sec_id;
+        p_cb->p_cback = ls->p_cback;
+        p_cb->user_data = ls->user_data;
+        p_cb->handle = handle;
+        p_cb->sec_id = sec_id;
+        p_cb->state = BTA_JV_ST_SR_LISTEN;
+        p_cb->psm = ls->local_psm;
+    }
+
+    ls->p_cback(BTA_JV_L2CAP_START_EVT, (tBTA_JV *)&evt_data, ls->user_data);
+}
+
+/*******************************************************************************
+**
+** Function     bta_jv_l2cap_stop_server
+**
+** Description  stops an L2CAP server
+**
+** Returns      void
+**
+*******************************************************************************/
+void bta_jv_l2cap_stop_server(tBTA_JV_MSG *p_data)
+{
+    tBTA_JV_L2C_CB      *p_cb;
+    tBTA_JV_L2CAP_CLOSE  evt_data;
+    tBTA_JV_API_L2CAP_SERVER *ls = &(p_data->l2cap_server);
+    tBTA_JV_L2CAP_CBACK *p_cback;
+    void *user_data;
+    for (int i = 0; i < BTA_JV_MAX_L2C_CONN; i++) {
+        if (bta_jv_cb.l2c_cb[i].psm == ls->local_psm) {
+            p_cb = &bta_jv_cb.l2c_cb[i];
+            p_cback = p_cb->p_cback;
+            user_data = p_cb->user_data;
+            evt_data.handle = p_cb->handle;
+            evt_data.status = bta_jv_free_l2c_cb(p_cb);
+            evt_data.async = FALSE;
+            p_cback(BTA_JV_L2CAP_CLOSE_EVT, (tBTA_JV *)&evt_data, user_data);
+            break;
+        }
+    }
+}
+
+
+
+/*******************************************************************************
+**
+** Function     bta_jv_l2cap_read
+**
+** Description  Read data from an L2CAP connection
+**
+** Returns      void
+**
+*******************************************************************************/
+void bta_jv_l2cap_read(tBTA_JV_MSG *p_data)
+{
+    tBTA_JV_L2CAP_READ evt_data;
+    tBTA_JV_API_L2CAP_READ *rc = &(p_data->l2cap_read);
+
+    evt_data.status = BTA_JV_FAILURE;
+    evt_data.handle = rc->handle;
+    evt_data.req_id = rc->req_id;
+    evt_data.p_data = rc->p_data;
+    evt_data.len    = 0;
+
+    if (BT_PASS == GAP_ConnReadData(rc->handle, rc->p_data, rc->len, &evt_data.len)) {
+        evt_data.status = BTA_JV_SUCCESS;
+    }
+
+    rc->p_cback(BTA_JV_L2CAP_READ_EVT, (tBTA_JV *)&evt_data, rc->user_data);
+}
+
+
+/*******************************************************************************
+**
+** Function     bta_jv_l2cap_write
+**
+** Description  Write data to an L2CAP connection
+**
+** Returns      void
+**
+*******************************************************************************/
+void bta_jv_l2cap_write(tBTA_JV_MSG *p_data)
+{
+    tBTA_JV_L2CAP_WRITE evt_data;
+    tBTA_JV_API_L2CAP_WRITE *ls = &(p_data->l2cap_write);
+
+    /* As we check this callback exists before the tBTA_JV_API_L2CAP_WRITE can be send through the
+     * API this check should not be needed.
+     * But the API is not designed to be used (safely at least) in a multi-threaded scheduler, hence
+     * if the peer device disconnects the l2cap link after the API is called, but before this
+     * message is handled, the ->p_cback will be cleared at this point. At first glanch this seems
+     * highly unlikely, but for all obex-profiles with two channels connected - e.g. MAP, this
+     * happens around 1 of 4 disconnects, as a disconnect on the server channel causes a disconnect
+     * to be send on the client (notification) channel, but at the peer typically disconnects both
+     * the OBEX disconnect request crosses the incoming l2cap disconnect.
+     * If p_cback is cleared, we simply discard the data.
+     * RISK: The caller must handle any cleanup based on another signal than BTA_JV_L2CAP_WRITE_EVT,
+     *       which is typically not possible, as the pointer to the allocated buffer is stored
+     *       in this message, and can therefore not be freed, hence we have a mem-leak-by-design.*/
+    if (ls->p_cb->p_cback != NULL) {
+        evt_data.status = BTA_JV_FAILURE;
+        evt_data.handle = ls->handle;
+        evt_data.req_id = ls->req_id;
+        evt_data.cong   = ls->p_cb->cong;
+        evt_data.len    = 0;
+        bta_jv_pm_conn_busy(ls->p_cb->p_pm_cb);
+        if (!evt_data.cong &&
+                BT_PASS == GAP_ConnWriteData(ls->handle, ls->p_data, ls->len, &evt_data.len)) {
+            evt_data.status = BTA_JV_SUCCESS;
+        }
+        ls->p_cb->p_cback(BTA_JV_L2CAP_WRITE_EVT, (tBTA_JV *)&evt_data, ls->user_data);
+        bta_jv_set_pm_conn_state(ls->p_cb->p_pm_cb, BTA_JV_CONN_IDLE);
+    } else {
+        /* As this pointer is checked in the API function, this occurs only when the channel is
+         * disconnected after the API function is called, but before the message is handled. */
+        APPL_TRACE_ERROR("%s() ls->p_cb->p_cback == NULL", __func__);
+    }
+}
+
+/*******************************************************************************
+**
+** Function     bta_jv_l2cap_write_fixed
+**
+** Description  Write data to an L2CAP connection using Fixed channels
+**
+** Returns      void
+**
+*******************************************************************************/
+void bta_jv_l2cap_write_fixed(tBTA_JV_MSG *p_data)
+{
+    tBTA_JV_L2CAP_WRITE_FIXED evt_data;
+    tBTA_JV_API_L2CAP_WRITE_FIXED *ls = &(p_data->l2cap_write_fixed);
+    BT_HDR *msg = (BT_HDR *)osi_malloc(sizeof(BT_HDR) + ls->len + L2CAP_MIN_OFFSET);
+    if (!msg) {
+        APPL_TRACE_ERROR("%s() could not allocate msg buffer", __func__);
+        return;
+    }
+    evt_data.status  = BTA_JV_FAILURE;
+    evt_data.channel = ls->channel;
+    memcpy(evt_data.addr, ls->addr, sizeof(evt_data.addr));
+    evt_data.req_id  = ls->req_id;
+    evt_data.len     = 0;
+
+
+    memcpy(((uint8_t *)(msg + 1)) + L2CAP_MIN_OFFSET, ls->p_data, ls->len);
+    msg->len = ls->len;
+    msg->offset = L2CAP_MIN_OFFSET;
+
+    L2CA_SendFixedChnlData(ls->channel, ls->addr, msg);
+
+    ls->p_cback(BTA_JV_L2CAP_WRITE_FIXED_EVT, (tBTA_JV *)&evt_data, ls->user_data);
+}
+
+/*******************************************************************************
+**
+** Function     bta_jv_port_data_co_cback
+**
+** Description  port data callback function of rfcomm
+**              connections
+**
+** Returns      void
+**
+*******************************************************************************/
+static int bta_jv_port_data_co_cback(UINT16 port_handle, UINT8 *buf, UINT16 len, int type)
+{
+    tBTA_JV_RFC_CB  *p_cb = bta_jv_rfc_port_to_cb(port_handle);
+    tBTA_JV_PCB     *p_pcb = bta_jv_rfc_port_to_pcb(port_handle);
+    int ret = 0;
+    APPL_TRACE_DEBUG("%s, p_cb:%p, p_pcb:%p, len:%d, type:%d", __func__, p_cb, p_pcb, len, type);
+    if (p_pcb != NULL) {
+        switch (type) {
+        case DATA_CO_CALLBACK_TYPE_INCOMING:
+            bta_jv_pm_conn_busy(p_pcb->p_pm_cb);
+            ret = bta_co_rfc_data_incoming(p_pcb->user_data, (BT_HDR *)buf);
+            bta_jv_pm_conn_idle(p_pcb->p_pm_cb);
+            return ret;
+        case DATA_CO_CALLBACK_TYPE_OUTGOING_SIZE:
+            return bta_co_rfc_data_outgoing_size(p_pcb->user_data, (int *)buf);
+        case DATA_CO_CALLBACK_TYPE_OUTGOING:
+            return bta_co_rfc_data_outgoing(p_pcb->user_data, buf, len);
+        default:
+            APPL_TRACE_ERROR("unknown callout type:%d", type);
+            break;
+        }
+    }
+    return 0;
+}
+
+/*******************************************************************************
+**
+** Function     bta_jv_port_mgmt_cl_cback
+**
+** Description  callback for port mamangement function of rfcomm
+**              client connections
+**
+** Returns      void
+**
+*******************************************************************************/
+static void bta_jv_port_mgmt_cl_cback(UINT32 code, UINT16 port_handle)
+{
+    tBTA_JV_RFC_CB  *p_cb = bta_jv_rfc_port_to_cb(port_handle);
+    tBTA_JV_PCB     *p_pcb = bta_jv_rfc_port_to_pcb(port_handle);
+    tBTA_JV evt_data;
+    BD_ADDR rem_bda;
+    UINT16 lcid;
+    tBTA_JV_RFCOMM_CBACK *p_cback;  /* the callback function */
+
+    APPL_TRACE_DEBUG( "bta_jv_port_mgmt_cl_cback:code:%d, port_handle%d", code, port_handle);
+    if (NULL == p_cb || NULL == p_cb->p_cback) {
+        return;
+    }
+
+    APPL_TRACE_DEBUG( "bta_jv_port_mgmt_cl_cback code=%d port_handle:%d handle:%d",
+                      code, port_handle, p_cb->handle);
+
+    PORT_CheckConnection(port_handle, rem_bda, &lcid);
+
+    if (code == PORT_SUCCESS) {
+        evt_data.rfc_open.handle = p_cb->handle;
+        evt_data.rfc_open.status = BTA_JV_SUCCESS;
+        bdcpy(evt_data.rfc_open.rem_bda, rem_bda);
+        p_pcb->state = BTA_JV_ST_CL_OPEN;
+        p_cb->p_cback(BTA_JV_RFCOMM_OPEN_EVT, &evt_data, p_pcb->user_data);
+    } else {
+        evt_data.rfc_close.handle = p_cb->handle;
+        evt_data.rfc_close.status = BTA_JV_FAILURE;
+        evt_data.rfc_close.port_status = code;
+        evt_data.rfc_close.async = TRUE;
+        if (p_pcb->state == BTA_JV_ST_CL_CLOSING) {
+            evt_data.rfc_close.async = FALSE;
+        }
+        //p_pcb->state = BTA_JV_ST_NONE;
+        //p_pcb->cong = FALSE;
+        p_cback = p_cb->p_cback;
+        p_cback(BTA_JV_RFCOMM_CLOSE_EVT, &evt_data, p_pcb->user_data);
+        //bta_jv_free_rfc_cb(p_cb, p_pcb);
+    }
+
+}
+
+/*******************************************************************************
+**
+** Function     bta_jv_port_event_cl_cback
+**
+** Description  Callback for RFCOMM client port events
+**
+** Returns      void
+**
+*******************************************************************************/
+static void bta_jv_port_event_cl_cback(UINT32 code, UINT16 port_handle)
+{
+    tBTA_JV_RFC_CB  *p_cb = bta_jv_rfc_port_to_cb(port_handle);
+    tBTA_JV_PCB     *p_pcb = bta_jv_rfc_port_to_pcb(port_handle);
+    tBTA_JV evt_data;
+
+    APPL_TRACE_DEBUG( "bta_jv_port_event_cl_cback:%d", port_handle);
+    if (NULL == p_cb || NULL == p_cb->p_cback) {
+        return;
+    }
+
+    APPL_TRACE_DEBUG( "bta_jv_port_event_cl_cback code=x%x port_handle:%d handle:%d",
+                      code, port_handle, p_cb->handle);
+    if (code & PORT_EV_RXCHAR) {
+        evt_data.data_ind.handle = p_cb->handle;
+        p_cb->p_cback(BTA_JV_RFCOMM_DATA_IND_EVT, &evt_data, p_pcb->user_data);
+    }
+
+    if (code & PORT_EV_FC) {
+        p_pcb->cong = (code & PORT_EV_FCS) ? FALSE : TRUE;
+        evt_data.rfc_cong.cong = p_pcb->cong;
+        evt_data.rfc_cong.handle = p_cb->handle;
+        evt_data.rfc_cong.status = BTA_JV_SUCCESS;
+        p_cb->p_cback(BTA_JV_RFCOMM_CONG_EVT, &evt_data, p_pcb->user_data);
+    }
+
+    if (code & PORT_EV_TXEMPTY) {
+        bta_jv_pm_conn_idle(p_pcb->p_pm_cb);
+    }
+}
+
+/*******************************************************************************
+**
+** Function     bta_jv_rfcomm_connect
+**
+** Description  Client initiates an RFCOMM connection
+**
+** Returns      void
+**
+*******************************************************************************/
+void bta_jv_rfcomm_connect(tBTA_JV_MSG *p_data)
+{
+    UINT16 handle = 0;
+    UINT32 event_mask = BTA_JV_RFC_EV_MASK;
+    tPORT_STATE port_state;
+    UINT8   sec_id = 0;
+    tBTA_JV_RFC_CB  *p_cb = NULL;
+    tBTA_JV_PCB     *p_pcb;
+    tBTA_JV_API_RFCOMM_CONNECT *cc = &(p_data->rfcomm_connect);
+    tBTA_JV_RFCOMM_CL_INIT      evt_data = {0};
+
+    /* TODO DM role manager
+    L2CA_SetDesireRole(cc->role);
+    */
+
+    sec_id = bta_jv_alloc_sec_id();
+    evt_data.sec_id = sec_id;
+    evt_data.status = BTA_JV_SUCCESS;
+    if (0 == sec_id ||
+            BTM_SetSecurityLevel(TRUE, "", sec_id,  cc->sec_mask, BT_PSM_RFCOMM,
+                                 BTM_SEC_PROTO_RFCOMM, cc->remote_scn) == FALSE) {
+        evt_data.status = BTA_JV_FAILURE;
+        APPL_TRACE_ERROR("sec_id:%d is zero or BTM_SetSecurityLevel failed, remote_scn:%d", sec_id, cc->remote_scn);
+    }
+
+    if (evt_data.status == BTA_JV_SUCCESS &&
+            RFCOMM_CreateConnection(UUID_SERVCLASS_SERIAL_PORT, cc->remote_scn, FALSE,
+                                    BTA_JV_DEF_RFC_MTU, cc->peer_bd_addr, &handle, bta_jv_port_mgmt_cl_cback) != PORT_SUCCESS) {
+        APPL_TRACE_ERROR("bta_jv_rfcomm_connect, RFCOMM_CreateConnection failed");
+        evt_data.status = BTA_JV_FAILURE;
+    }
+    if (evt_data.status == BTA_JV_SUCCESS) {
+        p_cb = bta_jv_alloc_rfc_cb(handle, &p_pcb);
+        if (p_cb) {
+            p_cb->p_cback = cc->p_cback;
+            p_cb->sec_id = sec_id;
+            p_cb->scn = 0;
+            p_pcb->state = BTA_JV_ST_CL_OPENING;
+            p_pcb->user_data = cc->user_data;
+            evt_data.use_co = TRUE;
+
+            PORT_SetEventCallback(handle, bta_jv_port_event_cl_cback);
+            PORT_SetEventMask(handle, event_mask);
+            PORT_SetDataCOCallback (handle, bta_jv_port_data_co_cback);
+
+            PORT_GetState(handle, &port_state);
+
+            port_state.fc_type = (PORT_FC_CTS_ON_INPUT | PORT_FC_CTS_ON_OUTPUT);
+
+            /* coverity[uninit_use_in_call]
+               FALSE-POSITIVE: port_state is initialized at PORT_GetState() */
+            PORT_SetState(handle, &port_state);
+
+            evt_data.handle = p_cb->handle;
+        } else {
+            evt_data.status = BTA_JV_FAILURE;
+            APPL_TRACE_ERROR("run out of rfc control block");
+        }
+    }
+    cc->p_cback(BTA_JV_RFCOMM_CL_INIT_EVT, (tBTA_JV *)&evt_data, cc->user_data);
+    if (evt_data.status == BTA_JV_FAILURE) {
+        if (sec_id) {
+            bta_jv_free_sec_id(&sec_id);
+        }
+        if (handle) {
+            RFCOMM_RemoveConnection(handle);
+        }
+    }
+}
+
+static int find_rfc_pcb(void *user_data, tBTA_JV_RFC_CB **cb, tBTA_JV_PCB **pcb)
+{
+    *cb = NULL;
+    *pcb = NULL;
+    int i;
+    for (i = 0; i < MAX_RFC_PORTS; i++) {
+        UINT32 rfc_handle = bta_jv_cb.port_cb[i].handle & BTA_JV_RFC_HDL_MASK;
+        rfc_handle &= ~BTA_JV_RFCOMM_MASK;
+        if (rfc_handle && bta_jv_cb.port_cb[i].user_data == user_data) {
+            *pcb = &bta_jv_cb.port_cb[i];
+            *cb = &bta_jv_cb.rfc_cb[rfc_handle - 1];
+            APPL_TRACE_DEBUG("find_rfc_pcb(): FOUND rfc_cb_handle 0x%x, port.jv_handle:"
+                             " 0x%x, state: %d, rfc_cb->handle: 0x%x", rfc_handle, (*pcb)->handle,
+                             (*pcb)->state, (*cb)->handle);
+            return 1;
+        }
+    }
+    APPL_TRACE_DEBUG("find_rfc_pcb: cannot find rfc_cb from user data:%d", (UINT32)user_data);
+    return 0;
+}
+
+/*******************************************************************************
+**
+** Function     bta_jv_rfcomm_close
+**
+** Description  Close an RFCOMM connection
+**
+** Returns      void
+**
+*******************************************************************************/
+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);
+    if (!cc->handle) {
+        APPL_TRACE_ERROR("bta_jv_rfcomm_close, rfc handle is null");
+        return;
+    }
+
+    void *user_data = cc->user_data;
+    if (!find_rfc_pcb(user_data, &p_cb, &p_pcb)) {
+        return;
+    }
+    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",
+                     get_sec_id_used(), get_rfc_cb_used());
+}
+
+/*******************************************************************************
+**
+** Function     bta_jv_get_num_rfc_listen
+**
+** Description  when a RFCOMM connection goes down, make sure that there's only
+**              one port stays listening on this scn.
+**
+** Returns
+**
+*******************************************************************************/
+static UINT8 __attribute__((unused)) bta_jv_get_num_rfc_listen(tBTA_JV_RFC_CB *p_cb)
+{
+    UINT8   listen = 1;
+
+    if (p_cb->max_sess > 1) {
+        listen = 0;
+        for (UINT8 i = 0; i < p_cb->max_sess; i++) {
+            if (p_cb->rfc_hdl[i] != 0) {
+                const tBTA_JV_PCB *p_pcb = &bta_jv_cb.port_cb[p_cb->rfc_hdl[i] - 1];
+                if (BTA_JV_ST_SR_LISTEN == p_pcb->state) {
+                    listen++;
+                }
+            }
+        }
+    }
+    return listen;
+}
+
+/*******************************************************************************
+**
+** Function     bta_jv_port_mgmt_sr_cback
+**
+** Description  callback for port mamangement function of rfcomm
+**              server connections
+**
+** Returns      void
+**
+*******************************************************************************/
+static void bta_jv_port_mgmt_sr_cback(UINT32 code, UINT16 port_handle)
+{
+    tBTA_JV_PCB     *p_pcb = bta_jv_rfc_port_to_pcb(port_handle);
+    tBTA_JV_RFC_CB  *p_cb = bta_jv_rfc_port_to_cb(port_handle);
+    tBTA_JV evt_data;
+    BD_ADDR rem_bda;
+    UINT16 lcid;
+    // APPL_TRACE_DEBUG("bta_jv_port_mgmt_sr_cback, code:0x%x, port_handle:%d", code, (uint16_t)port_handle);
+    if (NULL == p_cb || NULL == p_cb->p_cback) {
+        // APPL_TRACE_ERROR("bta_jv_port_mgmt_sr_cback, p_cb:%p, p_cb->p_cback%p",
+        // p_cb, p_cb ? p_cb->p_cback : NULL);
+        return;
+    }
+    void *user_data = p_pcb->user_data;
+    // APPL_TRACE_DEBUG( "bta_jv_port_mgmt_sr_cback code=%p port_handle:0x%x handle:0x%x, p_pcb:%p, user:%p",
+    // code, port_handle, p_cb->handle, p_pcb, p_pcb->user_data);
+
+    PORT_CheckConnection(port_handle, rem_bda, &lcid);
+    int failed = TRUE;
+    if (code == PORT_SUCCESS) {
+        evt_data.rfc_srv_open.handle = p_pcb->handle;
+        evt_data.rfc_srv_open.status = BTA_JV_SUCCESS;
+        bdcpy(evt_data.rfc_srv_open.rem_bda, rem_bda);
+        tBTA_JV_PCB *p_pcb_new_listen  = bta_jv_add_rfc_port(p_cb, p_pcb);
+        if (p_pcb_new_listen) {
+            evt_data.rfc_srv_open.new_listen_handle = p_pcb_new_listen->handle;
+            p_pcb_new_listen->user_data = p_cb->p_cback(BTA_JV_RFCOMM_SRV_OPEN_EVT, &evt_data, user_data);
+            APPL_TRACE_DEBUG("PORT_SUCCESS: curr_sess:%d, max_sess:%d", p_cb->curr_sess, p_cb->max_sess);
+            failed = FALSE;
+        } else {
+            APPL_TRACE_ERROR("bta_jv_add_rfc_port failed to create new listen port");
+        }
+    }
+    if (failed) {
+        evt_data.rfc_close.handle = p_cb->handle;
+        evt_data.rfc_close.status = BTA_JV_FAILURE;
+        evt_data.rfc_close.async = TRUE;
+        evt_data.rfc_close.port_status = code;
+        p_pcb->cong = FALSE;
+
+        tBTA_JV_RFCOMM_CBACK    *p_cback = p_cb->p_cback;
+        APPL_TRACE_DEBUG("PORT_CLOSED before BTA_JV_RFCOMM_CLOSE_EVT: curr_sess:%d, max_sess:%d",
+                         p_cb->curr_sess, p_cb->max_sess);
+        if (BTA_JV_ST_SR_CLOSING == p_pcb->state) {
+            evt_data.rfc_close.async = FALSE;
+            evt_data.rfc_close.status = BTA_JV_SUCCESS;
+        }
+        //p_pcb->state = BTA_JV_ST_NONE;
+        p_cback(BTA_JV_RFCOMM_CLOSE_EVT, &evt_data, user_data);
+        //bta_jv_free_rfc_cb(p_cb, p_pcb);
+
+        APPL_TRACE_DEBUG("PORT_CLOSED after BTA_JV_RFCOMM_CLOSE_EVT: curr_sess:%d, max_sess:%d",
+                         p_cb->curr_sess, p_cb->max_sess);
+    }
+}
+
+/*******************************************************************************
+**
+** Function     bta_jv_port_event_sr_cback
+**
+** Description  Callback for RFCOMM server port events
+**
+** Returns      void
+**
+*******************************************************************************/
+static void bta_jv_port_event_sr_cback(UINT32 code, UINT16 port_handle)
+{
+    tBTA_JV_PCB     *p_pcb = bta_jv_rfc_port_to_pcb(port_handle);
+    tBTA_JV_RFC_CB  *p_cb = bta_jv_rfc_port_to_cb(port_handle);
+    tBTA_JV evt_data;
+
+    if (NULL == p_cb || NULL == p_cb->p_cback) {
+        return;
+    }
+
+    APPL_TRACE_DEBUG( "bta_jv_port_event_sr_cback code=x%x port_handle:%d handle:%d",
+                      code, port_handle, p_cb->handle);
+
+    void *user_data = p_pcb->user_data;
+    if (code & PORT_EV_RXCHAR) {
+        evt_data.data_ind.handle = p_cb->handle;
+        p_cb->p_cback(BTA_JV_RFCOMM_DATA_IND_EVT, &evt_data, user_data);
+    }
+
+    if (code & PORT_EV_FC) {
+        p_pcb->cong = (code & PORT_EV_FCS) ? FALSE : TRUE;
+        evt_data.rfc_cong.cong = p_pcb->cong;
+        evt_data.rfc_cong.handle = p_cb->handle;
+        evt_data.rfc_cong.status = BTA_JV_SUCCESS;
+        p_cb->p_cback(BTA_JV_RFCOMM_CONG_EVT, &evt_data, user_data);
+    }
+
+    if (code & PORT_EV_TXEMPTY) {
+        bta_jv_pm_conn_idle(p_pcb->p_pm_cb);
+    }
+}
+
+/*******************************************************************************
+**
+** Function     bta_jv_add_rfc_port
+**
+** Description  add a port for server when the existing posts is open
+**
+** Returns   return a pointer to tBTA_JV_PCB just added
+**
+*******************************************************************************/
+static tBTA_JV_PCB *bta_jv_add_rfc_port(tBTA_JV_RFC_CB *p_cb, tBTA_JV_PCB *p_pcb_open)
+{
+    UINT8   used = 0, i, listen = 0;
+    UINT32  si = 0;
+    tPORT_STATE port_state;
+    UINT32 event_mask = BTA_JV_RFC_EV_MASK;
+    tBTA_JV_PCB *p_pcb = NULL;
+    if (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++;
+                    if (p_pcb_open == p_pcb) {
+                        APPL_TRACE_DEBUG("bta_jv_add_rfc_port, port_handle:%d, change the listen port to open state",
+                                         p_pcb->port_handle);
+                        p_pcb->state = BTA_JV_ST_SR_OPEN;
+
+                    } else {
+                        APPL_TRACE_ERROR("bta_jv_add_rfc_port, open pcb not matching listen one,"
+                                         "listen count:%d, listen pcb handle:%d, open pcb:%d",
+                                         listen, p_pcb->port_handle, p_pcb_open->handle);
+                        return NULL;
+                    }
+                }
+                used++;
+            } else if (si == 0) {
+                si = i + 1;
+            }
+        }
+
+        APPL_TRACE_DEBUG("bta_jv_add_rfc_port max_sess=%d used:%d curr_sess:%d, listen:%d si:%d",
+                         p_cb->max_sess, used, p_cb->curr_sess, listen, si);
+        if (used < p_cb->max_sess && listen == 1 && si) {
+            si--;
+            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->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("bta_jv_add_rfc_port: p_pcb->handle:0x%x, curr_sess:%d",
+                                 p_pcb->handle, p_cb->curr_sess);
+            }
+        } else {
+            APPL_TRACE_ERROR("bta_jv_add_rfc_port, cannot create new rfc listen port");
+        }
+    }
+    APPL_TRACE_DEBUG("bta_jv_add_rfc_port: sec id in use:%d, rfc_cb in use:%d",
+                     get_sec_id_used(), get_rfc_cb_used());
+    return p_pcb;
+}
+
+/*******************************************************************************
+**
+** Function     bta_jv_rfcomm_start_server
+**
+** Description  waits for an RFCOMM client to connect
+**
+**
+** Returns      void
+**
+*******************************************************************************/
+void bta_jv_rfcomm_start_server(tBTA_JV_MSG *p_data)
+{
+    UINT16 handle = 0;
+    UINT32 event_mask = BTA_JV_RFC_EV_MASK;
+    tPORT_STATE port_state;
+    UINT8   sec_id = 0;
+    tBTA_JV_RFC_CB  *p_cb = NULL;
+    tBTA_JV_PCB     *p_pcb;
+    tBTA_JV_API_RFCOMM_SERVER *rs = &(p_data->rfcomm_server);
+    tBTA_JV_RFCOMM_START        evt_data = {0};
+    /* TODO DM role manager
+    L2CA_SetDesireRole(rs->role);
+    */
+    evt_data.status = BTA_JV_FAILURE;
+    APPL_TRACE_DEBUG("bta_jv_rfcomm_start_server: sec id in use:%d, rfc_cb in use:%d",
+                     get_sec_id_used(), get_rfc_cb_used());
+
+    do {
+        sec_id = bta_jv_alloc_sec_id();
+
+        if (0 == sec_id ||
+                BTM_SetSecurityLevel(FALSE, "JV PORT", sec_id,  rs->sec_mask,
+                                     BT_PSM_RFCOMM, BTM_SEC_PROTO_RFCOMM, rs->local_scn) == FALSE) {
+            APPL_TRACE_ERROR("bta_jv_rfcomm_start_server, run out of sec_id");
+            break;
+        }
+
+        if (RFCOMM_CreateConnection(sec_id, rs->local_scn, TRUE,
+                                    BTA_JV_DEF_RFC_MTU, (UINT8 *) bd_addr_any, &handle, bta_jv_port_mgmt_sr_cback) != PORT_SUCCESS) {
+            APPL_TRACE_ERROR("bta_jv_rfcomm_start_server, RFCOMM_CreateConnection failed");
+            break;
+        }
+
+
+        p_cb = bta_jv_alloc_rfc_cb(handle, &p_pcb);
+        if (!p_cb) {
+            APPL_TRACE_ERROR("bta_jv_rfcomm_start_server, run out of rfc control block");
+            break;
+        }
+
+        p_cb->max_sess = rs->max_session;
+        p_cb->p_cback = rs->p_cback;
+        p_cb->sec_id = sec_id;
+        p_cb->scn = rs->local_scn;
+        p_pcb->state = BTA_JV_ST_SR_LISTEN;
+        p_pcb->user_data = rs->user_data;
+        evt_data.status = BTA_JV_SUCCESS;
+        evt_data.handle = p_cb->handle;
+        evt_data.sec_id = sec_id;
+        evt_data.use_co = TRUE;
+
+        PORT_ClearKeepHandleFlag(handle);
+        PORT_SetEventCallback(handle, bta_jv_port_event_sr_cback);
+        PORT_SetEventMask(handle, event_mask);
+        PORT_GetState(handle, &port_state);
+
+        port_state.fc_type = (PORT_FC_CTS_ON_INPUT | PORT_FC_CTS_ON_OUTPUT);
+
+        PORT_SetState(handle, &port_state);
+    } while (0);
+
+    rs->p_cback(BTA_JV_RFCOMM_START_EVT, (tBTA_JV *)&evt_data, rs->user_data);
+    if (evt_data.status == BTA_JV_SUCCESS) {
+        PORT_SetDataCOCallback (handle, bta_jv_port_data_co_cback);
+    } else {
+        if (sec_id) {
+            bta_jv_free_sec_id(&sec_id);
+        }
+        if (handle) {
+            RFCOMM_RemoveConnection(handle);
+        }
+    }
+}
+
+/*******************************************************************************
+**
+** Function     bta_jv_rfcomm_stop_server
+**
+** Description  stops an RFCOMM server
+**
+** Returns      void
+**
+*******************************************************************************/
+
+void bta_jv_rfcomm_stop_server(tBTA_JV_MSG *p_data)
+{
+    tBTA_JV_API_RFCOMM_SERVER *ls = &(p_data->rfcomm_server);
+    tBTA_JV_RFC_CB           *p_cb = NULL;
+    tBTA_JV_PCB              *p_pcb = NULL;
+    APPL_TRACE_DEBUG("bta_jv_rfcomm_stop_server");
+    if (!ls->handle) {
+        APPL_TRACE_ERROR("bta_jv_rfcomm_stop_server, jv handle is null");
+        return;
+    }
+    void *user_data = ls->user_data;
+    if (!find_rfc_pcb(user_data, &p_cb, &p_pcb)) {
+        return;
+    }
+    APPL_TRACE_DEBUG("bta_jv_rfcomm_stop_server: p_pcb:%p, p_pcb->port_handle:%d",
+                     p_pcb, p_pcb->port_handle);
+    bta_jv_free_rfc_cb(p_cb, p_pcb);
+    APPL_TRACE_DEBUG("bta_jv_rfcomm_stop_server: sec id in use:%d, rfc_cb in use:%d",
+                     get_sec_id_used(), get_rfc_cb_used());
+}
+
+/*******************************************************************************
+**
+** Function     bta_jv_rfcomm_read
+**
+** Description  Read data from an RFCOMM connection
+**
+** Returns      void
+**
+*******************************************************************************/
+void bta_jv_rfcomm_read(tBTA_JV_MSG *p_data)
+{
+    tBTA_JV_API_RFCOMM_READ *rc = &(p_data->rfcomm_read);
+    tBTA_JV_RFC_CB  *p_cb = rc->p_cb;
+    tBTA_JV_PCB     *p_pcb = rc->p_pcb;
+    tBTA_JV_RFCOMM_READ    evt_data;
+
+    evt_data.status = BTA_JV_FAILURE;
+    evt_data.handle = p_cb->handle;
+    evt_data.req_id = rc->req_id;
+    evt_data.p_data = rc->p_data;
+    if (PORT_ReadData(rc->p_pcb->port_handle, (char *)rc->p_data, rc->len, &evt_data.len) ==
+            PORT_SUCCESS) {
+        evt_data.status = BTA_JV_SUCCESS;
+    }
+
+    p_cb->p_cback(BTA_JV_RFCOMM_READ_EVT, (tBTA_JV *)&evt_data, p_pcb->user_data);
+}
+
+/*******************************************************************************
+**
+** Function     bta_jv_rfcomm_write
+**
+** Description  write data to an RFCOMM connection
+**
+** Returns      void
+**
+*******************************************************************************/
+void bta_jv_rfcomm_write(tBTA_JV_MSG *p_data)
+{
+    tBTA_JV_API_RFCOMM_WRITE *wc = &(p_data->rfcomm_write);
+    tBTA_JV_RFC_CB  *p_cb = wc->p_cb;
+    tBTA_JV_PCB     *p_pcb = wc->p_pcb;
+    tBTA_JV_RFCOMM_WRITE    evt_data;
+
+    evt_data.status = BTA_JV_FAILURE;
+    evt_data.handle = p_cb->handle;
+    evt_data.req_id = wc->req_id;
+    evt_data.cong   = p_pcb->cong;
+    bta_jv_pm_conn_busy(p_pcb->p_pm_cb);
+    evt_data.len = wc->len;
+    if (!evt_data.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;
+    if (p_cb->p_cback) {
+        p_cb->p_cback(BTA_JV_RFCOMM_WRITE_EVT, (tBTA_JV *)&evt_data, p_pcb->user_data);
+    } else {
+        APPL_TRACE_ERROR("bta_jv_rfcomm_write :: WARNING ! No JV callback set");
+    }
+
+}
+
+/*******************************************************************************
+ **
+ ** Function     bta_jv_set_pm_profile
+ **
+ ** Description  Set or free power mode profile for a JV application
+ **
+ ** Returns      void
+ **
+ *******************************************************************************/
+void bta_jv_set_pm_profile(tBTA_JV_MSG *p_data)
+{
+    tBTA_JV_STATUS status;
+    tBTA_JV_PM_CB *p_cb;
+
+    APPL_TRACE_API("bta_jv_set_pm_profile(handle: 0x%x, app_id: %d, init_st: %d)",
+                   p_data->set_pm.handle, p_data->set_pm.app_id, p_data->set_pm.init_st);
+
+    /* clear PM control block */
+    if (p_data->set_pm.app_id == BTA_JV_PM_ID_CLEAR) {
+        status = bta_jv_free_set_pm_profile_cb(p_data->set_pm.handle);
+
+        if (status != BTA_JV_SUCCESS) {
+            APPL_TRACE_WARNING("bta_jv_set_pm_profile() free pm cb failed: reason %d",
+                               status);
+        }
+    } else { /* set PM control block */
+        p_cb = bta_jv_alloc_set_pm_profile_cb(p_data->set_pm.handle,
+                                              p_data->set_pm.app_id);
+
+        if (NULL != p_cb) {
+            bta_jv_pm_state_change(p_cb, p_data->set_pm.init_st);
+        } else {
+            APPL_TRACE_WARNING("bta_jv_alloc_set_pm_profile_cb() failed");
+        }
+    }
+}
+
+/*******************************************************************************
+ **
+ ** Function     bta_jv_change_pm_state
+ **
+ ** Description  change jv pm connect state, used internally
+ **
+ ** Returns      void
+ **
+ *******************************************************************************/
+void bta_jv_change_pm_state(tBTA_JV_MSG *p_data)
+{
+    tBTA_JV_API_PM_STATE_CHANGE *p_msg = (tBTA_JV_API_PM_STATE_CHANGE *)p_data;
+
+    if (p_msg->p_cb) {
+        bta_jv_pm_state_change(p_msg->p_cb, p_msg->state);
+    }
+}
+
+
+/*******************************************************************************
+ **
+ ** Function    bta_jv_set_pm_conn_state
+ **
+ ** Description Send pm event state change to jv state machine to serialize jv pm changes
+ **             in relation to other jv messages. internal API use mainly.
+ **
+ ** Params:     p_cb: jv pm control block, NULL pointer returns failure
+ **             new_state: new PM connections state, setting is forced by action function
+ **
+ ** Returns     BTA_JV_SUCCESS, BTA_JV_FAILURE (buffer allocation, or NULL ptr!)
+ **
+ *******************************************************************************/
+tBTA_JV_STATUS bta_jv_set_pm_conn_state(tBTA_JV_PM_CB *p_cb, const tBTA_JV_CONN_STATE
+                                        new_st)
+{
+    tBTA_JV_STATUS status = BTA_JV_FAILURE;
+    tBTA_JV_API_PM_STATE_CHANGE *p_msg;
+
+    if (NULL == p_cb) {
+        return status;
+    }
+
+    APPL_TRACE_API("bta_jv_set_pm_conn_state(handle:0x%x, state: %d)", p_cb->handle,
+                   new_st);
+    if ((p_msg = (tBTA_JV_API_PM_STATE_CHANGE *)osi_malloc(
+                     sizeof(tBTA_JV_API_PM_STATE_CHANGE))) != NULL) {
+        p_msg->hdr.event = BTA_JV_API_PM_STATE_CHANGE_EVT;
+        p_msg->p_cb = p_cb;
+        p_msg->state = new_st;
+        bta_sys_sendmsg(p_msg);
+        status = BTA_JV_SUCCESS;
+    }
+    return (status);
+}
+
+/*******************************************************************************
+ **
+ ** Function    bta_jv_pm_conn_busy
+ **
+ ** Description set pm connection busy state (input param safe)
+ **
+ ** Params      p_cb: pm control block of jv connection
+ **
+ ** Returns     void
+ **
+ *******************************************************************************/
+static void bta_jv_pm_conn_busy(tBTA_JV_PM_CB *p_cb)
+{
+    if ((NULL != p_cb) && (BTA_JV_PM_IDLE_ST == p_cb->state)) {
+        bta_jv_pm_state_change(p_cb, BTA_JV_CONN_BUSY);
+    }
+}
+
+/*******************************************************************************
+ **
+ ** Function    bta_jv_pm_conn_busy
+ **
+ ** Description set pm connection busy state (input param safe)
+ **
+ ** Params      p_cb: pm control block of jv connection
+ **
+ ** Returns     void
+ **
+ *******************************************************************************/
+static void bta_jv_pm_conn_idle(tBTA_JV_PM_CB *p_cb)
+{
+    if ((NULL != p_cb) && (BTA_JV_PM_IDLE_ST != p_cb->state)) {
+        bta_jv_pm_state_change(p_cb, BTA_JV_CONN_IDLE);
+    }
+}
+
+/*******************************************************************************
+ **
+ ** Function     bta_jv_pm_state_change
+ **
+ ** Description  Notify power manager there is state change
+ **
+ ** Params      p_cb: must be NONE NULL
+ **
+ ** Returns      void
+ **
+ *******************************************************************************/
+static void bta_jv_pm_state_change(tBTA_JV_PM_CB *p_cb, const tBTA_JV_CONN_STATE state)
+{
+    APPL_TRACE_API("bta_jv_pm_state_change(p_cb: 0x%x, handle: 0x%x, busy/idle_state: %d"
+                   ", app_id: %d, conn_state: %d)", (uint32_t)p_cb, p_cb->handle, p_cb->state,
+                   p_cb->app_id, state);
+
+    switch (state) {
+    case BTA_JV_CONN_OPEN:
+        bta_sys_conn_open(BTA_ID_JV, p_cb->app_id, p_cb->peer_bd_addr);
+        break;
+
+    case BTA_JV_CONN_CLOSE:
+        bta_sys_conn_close(BTA_ID_JV, p_cb->app_id, p_cb->peer_bd_addr);
+        break;
+
+    case BTA_JV_APP_OPEN:
+        bta_sys_app_open(BTA_ID_JV, p_cb->app_id, p_cb->peer_bd_addr);
+        break;
+
+    case BTA_JV_APP_CLOSE:
+        bta_sys_app_close(BTA_ID_JV, p_cb->app_id, p_cb->peer_bd_addr);
+        break;
+
+    case BTA_JV_SCO_OPEN:
+        bta_sys_sco_open(BTA_ID_JV, p_cb->app_id, p_cb->peer_bd_addr);
+        break;
+
+    case BTA_JV_SCO_CLOSE:
+        bta_sys_sco_close(BTA_ID_JV, p_cb->app_id, p_cb->peer_bd_addr);
+        break;
+
+    case BTA_JV_CONN_IDLE:
+        p_cb->state = BTA_JV_PM_IDLE_ST;
+        bta_sys_idle(BTA_ID_JV, p_cb->app_id, p_cb->peer_bd_addr);
+        break;
+
+    case BTA_JV_CONN_BUSY:
+        p_cb->state = BTA_JV_PM_BUSY_ST;
+        bta_sys_busy(BTA_ID_JV, p_cb->app_id, p_cb->peer_bd_addr);
+        break;
+
+    default:
+        APPL_TRACE_WARNING("bta_jv_pm_state_change(state: %d): Invalid state", state);
+        break;
+    }
+}
+/**********************************************************************************************/
+
+
+static struct fc_channel *fcchan_get(uint16_t chan, char create)
+{
+    struct fc_channel *t = fc_channels;
+    static tL2CAP_FIXED_CHNL_REG fcr = {
+        .pL2CA_FixedConn_Cb = fcchan_conn_chng_cbk,
+        .pL2CA_FixedData_Cb = fcchan_data_cbk,
+        .default_idle_tout  = 0xffff,
+        .fixed_chnl_opts = {
+            .mode         = L2CAP_FCR_BASIC_MODE,
+            .max_transmit = 0xFF,
+            .rtrans_tout  = 2000,
+            .mon_tout     = 12000,
+            .mps          = 670,
+            .tx_win_sz    = 1,
+        },
+    };
+
+    while (t && t->chan != chan) {
+        t = t->next;
+    }
+
+    if (t) {
+        return t;
+    } else if (!create) {
+        return NULL;    /* we cannot alloc a struct if not asked to */
+    }
+
+    t = osi_calloc(sizeof(*t));
+    if (!t) {
+        return NULL;
+    }
+
+    t->chan = chan;
+
+    if (!L2CA_RegisterFixedChannel(chan, &fcr)) {
+        osi_free(t);
+        return NULL;
+    }
+
+    //link it in
+    t->next = fc_channels;
+    fc_channels = t;
+
+    return t;
+}
+
+/* pass NULL to find servers */
+static struct fc_client *fcclient_find_by_addr(struct fc_client *start, BD_ADDR addr)
+{
+    struct fc_client *t = start;
+
+    while (t) {
+
+        /* match client if have addr */
+        if (addr && !memcmp(addr, &t->remote_addr, sizeof(t->remote_addr))) {
+            break;
+        }
+
+        /* match server if do not have addr */
+        if (!addr && t->server) {
+            break;
+        }
+
+        t = t->next_all_list;
+    }
+
+    return t;
+}
+
+static struct fc_client *fcclient_find_by_id(uint32_t id)
+{
+    struct fc_client *t = fc_clients;
+
+    while (t && t->id != id) {
+        t = t->next_all_list;
+    }
+
+    return t;
+}
+
+static struct fc_client *fcclient_alloc(uint16_t chan, char server, const uint8_t *sec_id_to_use)
+{
+    struct fc_channel *fc = fcchan_get(chan, TRUE);
+    struct fc_client *t;
+    uint8_t sec_id;
+
+    if (!fc) {
+        return NULL;
+    }
+
+    if (fc->has_server && server) {
+        return NULL;    /* no way to have multiple servers on same channel */
+    }
+
+    if (sec_id_to_use) {
+        sec_id = *sec_id_to_use;
+    } else {
+        sec_id = bta_jv_alloc_sec_id();
+    }
+
+    t = osi_calloc(sizeof(*t));
+    if (t) {
+        //allocate it a unique ID
+        do {
+            t->id = ++fc_next_id;
+        } while (!t->id || fcclient_find_by_id(t->id));
+
+        //populate some params
+        t->chan = chan;
+        t->server = server;
+
+        //get a security id
+        t->sec_id = sec_id;
+
+        //link it in to global list
+        t->next_all_list = fc_clients;
+        fc_clients = t;
+
+        //link it in to channel list
+        t->next_chan_list = fc->clients;
+        fc->clients = t;
+
+        //update channel if needed
+        if (server) {
+            fc->has_server = TRUE;
+        }
+    } else if (!sec_id_to_use) {
+        bta_jv_free_sec_id(&sec_id);
+    }
+
+    return t;
+}
+
+static void fcclient_free(struct fc_client *fc)
+{
+    struct fc_client *t = fc_clients;
+    struct fc_channel *tc = fcchan_get(fc->chan, FALSE);
+
+    //remove from global list
+    while (t && t->next_all_list != fc) {
+        t = t->next_all_list;
+    }
+
+    if (!t && fc != fc_clients) {
+        return;    /* prevent double-free */
+    }
+
+    if (t) {
+        t->next_all_list = fc->next_all_list;
+    } else {
+        fc_clients = fc->next_all_list;
+    }
+
+    //remove from channel list
+    if (tc) {
+        t = tc->clients;
+
+        while (t && t->next_chan_list != fc) {
+            t = t->next_chan_list;
+        }
+
+        if (t) {
+            t->next_chan_list = fc->next_chan_list;
+        } else {
+            tc->clients = fc->next_chan_list;
+        }
+
+        //if was server then channel no longer has a server
+        if (fc->server) {
+            tc->has_server = FALSE;
+        }
+    }
+
+    //free security id
+    bta_jv_free_sec_id(&fc->sec_id);
+
+    osi_free(fc);
+}
+
+static void fcchan_conn_chng_cbk(UINT16 chan, BD_ADDR bd_addr, BOOLEAN connected, UINT16 reason, tBT_TRANSPORT transport)
+{
+    tBTA_JV init_evt;
+    tBTA_JV open_evt;
+    struct fc_channel *tc;
+    struct fc_client *t = NULL, *new_conn;
+    tBTA_JV_L2CAP_CBACK *p_cback = NULL;
+    char call_init = FALSE;
+    void *user_data = NULL;
+
+
+    tc = fcchan_get(chan, FALSE);
+    if (tc) {
+        t = fcclient_find_by_addr(tc->clients, bd_addr); // try to find an open socked for that addr
+        if (t) {
+            p_cback = t->p_cback;
+            user_data = t->user_data;
+        } else {
+            t = fcclient_find_by_addr(tc->clients, NULL); // try to find a listening socked for that channel
+            if (t) {
+                //found: create a normal connection socket and assign the connection to it
+                new_conn = fcclient_alloc(chan, FALSE, &t->sec_id);
+                if (new_conn) {
+
+                    memcpy(&new_conn->remote_addr, bd_addr, sizeof(new_conn->remote_addr));
+                    new_conn->p_cback = NULL; //for now
+                    new_conn->init_called = TRUE; /*nop need to do it again */
+
+                    p_cback = t->p_cback;
+                    user_data = t->user_data;
+
+                    t = new_conn;
+                }
+            } else {
+                //drop it
+                return;
+            }
+        }
+    }
+
+    if (t) {
+
+        if (!t->init_called) {
+
+            call_init = TRUE;
+            t->init_called = TRUE;
+
+            init_evt.l2c_cl_init.handle = t->id;
+            init_evt.l2c_cl_init.status = BTA_JV_SUCCESS;
+            init_evt.l2c_cl_init.sec_id = t->sec_id;
+        }
+
+        open_evt.l2c_open.handle = t->id;
+        open_evt.l2c_open.tx_mtu = 23; /* 23, why not ?*/
+        memcpy(&open_evt.l2c_le_open.rem_bda, &t->remote_addr, sizeof(open_evt.l2c_le_open.rem_bda));
+        open_evt.l2c_le_open.p_p_cback = (void **)&t->p_cback;
+        open_evt.l2c_le_open.p_user_data = &t->user_data;
+        open_evt.l2c_le_open.status = BTA_JV_SUCCESS;
+
+        if (connected) {
+            open_evt.l2c_open.status = BTA_JV_SUCCESS;
+        } else {
+            fcclient_free(t);
+            open_evt.l2c_open.status = BTA_JV_FAILURE;
+        }
+    }
+
+    if (call_init) {
+        p_cback(BTA_JV_L2CAP_CL_INIT_EVT, &init_evt, user_data);
+    }
+
+    //call this with lock taken so socket does not disappear from under us */
+    if (p_cback) {
+        p_cback(BTA_JV_L2CAP_OPEN_EVT, &open_evt, user_data);
+        if (!t->p_cback) { /* no callback set, means they do not want this one... */
+            fcclient_free(t);
+        }
+    }
+}
+
+static void fcchan_data_cbk(UINT16 chan, BD_ADDR bd_addr, BT_HDR *p_buf)
+{
+    tBTA_JV evt_data;
+    // tBTA_JV evt_open;
+    struct fc_channel *tc;
+    struct fc_client *t = NULL;
+    tBTA_JV_L2CAP_CBACK *sock_cback = NULL;
+    void *sock_user_data;
+
+    tc = fcchan_get(chan, FALSE);
+    if (tc) {
+        t = fcclient_find_by_addr(tc->clients, bd_addr); // try to find an open socked for that addr and channel
+        if (!t) {
+            //no socket -> drop it
+            return;
+        }
+    }
+
+    sock_cback = t->p_cback;
+    sock_user_data = t->user_data;
+    evt_data.le_data_ind.handle = t->id;
+    evt_data.le_data_ind.p_buf = p_buf;
+
+    if (sock_cback) {
+        sock_cback(BTA_JV_L2CAP_DATA_IND_EVT, &evt_data, sock_user_data);
+    }
+}
+
+
+/*******************************************************************************
+**
+** Function     bta_jv_l2cap_connect_le
+**
+** Description  makes an le l2cap client connection
+**
+** Returns      void
+**
+*******************************************************************************/
+void bta_jv_l2cap_connect_le(tBTA_JV_MSG *p_data)
+{
+    tBTA_JV_API_L2CAP_CONNECT *cc = &(p_data->l2cap_connect);
+    tBTA_JV evt;
+    uint32_t id;
+    char call_init_f = TRUE;
+    struct fc_client *t;
+
+    evt.l2c_cl_init.handle = GAP_INVALID_HANDLE;
+    evt.l2c_cl_init.status = BTA_JV_FAILURE;
+
+    t = fcclient_alloc(cc->remote_chan, FALSE, NULL);
+    if (!t) {
+        cc->p_cback(BTA_JV_L2CAP_CL_INIT_EVT, &evt, cc->user_data);
+        return;
+    }
+
+    t->p_cback = cc->p_cback;
+    t->user_data = cc->user_data;
+    memcpy(&t->remote_addr, &cc->peer_bd_addr, sizeof(t->remote_addr));
+    id = t->id;
+    t->init_called = FALSE;
+
+    if (L2CA_ConnectFixedChnl(t->chan, t->remote_addr)) {
+
+        evt.l2c_cl_init.status = BTA_JV_SUCCESS;
+        evt.l2c_cl_init.handle = id;
+    }
+
+    //it could have been deleted/moved from under us, so re-find it */
+    t = fcclient_find_by_id(id);
+    if (t) {
+        if (evt.l2c_cl_init.status == BTA_JV_SUCCESS) {
+            call_init_f = !t->init_called;
+        } else {
+            fcclient_free(t);
+        }
+    }
+    if (call_init_f) {
+        cc->p_cback(BTA_JV_L2CAP_CL_INIT_EVT, &evt, cc->user_data);
+    }
+    t->init_called = TRUE;
+}
+
+
+/*******************************************************************************
+**
+** Function     bta_jv_l2cap_stop_server_le
+**
+** Description  stops an LE L2CAP server
+**
+** Returns      void
+**
+*******************************************************************************/
+void bta_jv_l2cap_stop_server_le(tBTA_JV_MSG *p_data)
+{
+    tBTA_JV  evt;
+    tBTA_JV_API_L2CAP_SERVER *ls = &(p_data->l2cap_server);
+    tBTA_JV_L2CAP_CBACK *p_cback = NULL;
+    struct fc_channel *fcchan;
+    struct fc_client *fcclient;
+    void *user_data;
+
+    evt.l2c_close.status = BTA_JV_FAILURE;
+    evt.l2c_close.async = FALSE;
+    evt.l2c_close.handle = GAP_INVALID_HANDLE;
+
+    fcchan = fcchan_get(ls->local_chan, FALSE);
+    if (fcchan) {
+        while ((fcclient = fcchan->clients)) {
+            p_cback = fcclient->p_cback;
+            user_data = fcclient->user_data;
+
+            evt.l2c_close.handle = fcclient->id;
+            evt.l2c_close.status = BTA_JV_SUCCESS;
+            evt.l2c_close.async = FALSE;
+
+            fcclient_free(fcclient);
+
+            if (p_cback) {
+                p_cback(BTA_JV_L2CAP_CLOSE_EVT, &evt, user_data);
+            }
+        }
+    }
+}
+
+/*******************************************************************************
+**
+** Function     bta_jv_l2cap_start_server_le
+**
+** Description  starts an LE L2CAP server
+**
+** Returns      void
+**
+*******************************************************************************/
+void bta_jv_l2cap_start_server_le(tBTA_JV_MSG *p_data)
+{
+    tBTA_JV_API_L2CAP_SERVER *ss = &(p_data->l2cap_server);
+    tBTA_JV_L2CAP_START evt_data;
+    struct fc_client *t;
+    // uint16_t handle;
+
+    evt_data.handle = GAP_INVALID_HANDLE;
+    evt_data.status = BTA_JV_FAILURE;
+
+
+    t = fcclient_alloc(ss->local_chan, TRUE, NULL);
+    if (!t) {
+        goto out;
+    }
+
+    t->p_cback = ss->p_cback;
+    t->user_data = ss->user_data;
+
+    //if we got here, we're registered...
+    evt_data.status = BTA_JV_SUCCESS;
+    evt_data.handle = t->id;
+    evt_data.sec_id = t->sec_id;
+
+out:
+    ss->p_cback(BTA_JV_L2CAP_START_EVT, (tBTA_JV *)&evt_data, ss->user_data);
+}
+
+/*******************************************************************************
+**
+** Function     bta_jv_l2cap_close_fixed
+**
+** Description  close a fixed channel connection. calls no callbacks. idempotent
+**
+** Returns      void
+**
+*******************************************************************************/
+extern void bta_jv_l2cap_close_fixed (tBTA_JV_MSG *p_data)
+{
+    tBTA_JV_API_L2CAP_CLOSE *cc = &(p_data->l2cap_close);
+    struct fc_client *t;
+
+    t = fcclient_find_by_id(cc->handle);
+    if (t) {
+        fcclient_free(t);
+    }
+}
+
+
+#endif  ///defined BTA_JV_INCLUDED && BTA_JV_INCLUDED == TRUE
\ No newline at end of file
diff --git a/components/bt/bluedroid/bta/jv/bta_jv_api.c b/components/bt/bluedroid/bta/jv/bta_jv_api.c
new file mode 100644 (file)
index 0000000..3af262a
--- /dev/null
@@ -0,0 +1,1139 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2006-2012 Broadcom Corporation
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *  This is the implementation of the JAVA API for Bluetooth Wireless
+ *  Technology (JABWT) as specified by the JSR82 specificiation
+ *
+ ******************************************************************************/
+
+#include "bta_api.h"
+#include "bta_sys.h"
+#include "bta_jv_api.h"
+#include "bta_jv_int.h"
+#include "allocator.h"
+#include <string.h>
+#include "port_api.h"
+#include "sdp_api.h"
+#include "utl.h"
+#include "gap_api.h"
+
+#include "bt_target.h"
+#include "sdp_api.h"
+
+
+#if (defined BTA_JV_INCLUDED && BTA_JV_INCLUDED == TRUE)
+/*****************************************************************************
+**  Constants
+*****************************************************************************/
+
+static const tBTA_SYS_REG bta_jv_reg = {
+    bta_jv_sm_execute,
+    NULL
+};
+
+/*******************************************************************************
+**
+** Function         BTA_JvEnable
+**
+** Description      Enable the Java I/F service. When the enable
+**                  operation is complete the callback function will be
+**                  called with a BTA_JV_ENABLE_EVT. This function must
+**                  be called before other function in the JV API are
+**                  called.
+**
+** Returns          BTA_JV_SUCCESS if successful.
+**                  BTA_JV_FAIL if internal failure.
+**
+*******************************************************************************/
+tBTA_JV_STATUS BTA_JvEnable(tBTA_JV_DM_CBACK *p_cback)
+{
+    tBTA_JV_STATUS status = BTA_JV_FAILURE;
+    tBTA_JV_API_ENABLE  *p_buf;
+    int i;
+
+    APPL_TRACE_API( "BTA_JvEnable");
+    if (p_cback && FALSE == bta_sys_is_register(BTA_ID_JV)) {
+        memset(&bta_jv_cb, 0, sizeof(tBTA_JV_CB));
+        /* set handle to invalid value by default */
+        for (i = 0; i < BTA_JV_PM_MAX_NUM; i++) {
+            bta_jv_cb.pm_cb[i].handle = BTA_JV_PM_HANDLE_CLEAR;
+        }
+
+        /* register with BTA system manager */
+        bta_sys_register(BTA_ID_JV, &bta_jv_reg);
+
+        if (p_cback && (p_buf = (tBTA_JV_API_ENABLE *) osi_malloc(sizeof(tBTA_JV_API_ENABLE))) != NULL) {
+            p_buf->hdr.event = BTA_JV_API_ENABLE_EVT;
+            p_buf->p_cback = p_cback;
+            bta_sys_sendmsg(p_buf);
+            status = BTA_JV_SUCCESS;
+        }
+    } else {
+        APPL_TRACE_ERROR("JVenable fails");
+    }
+    return (status);
+}
+
+/*******************************************************************************
+**
+** Function         BTA_JvDisable
+**
+** Description      Disable the Java I/F
+**
+** Returns          void
+**
+*******************************************************************************/
+void BTA_JvDisable(void)
+{
+    BT_HDR  *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;
+        bta_sys_sendmsg(p_buf);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         BTA_JvIsEnable
+**
+** Description      Get the JV registration status.
+**
+** Returns          TRUE, if registered
+**
+*******************************************************************************/
+BOOLEAN BTA_JvIsEnable(void)
+{
+    return bta_sys_is_register(BTA_ID_JV);
+}
+
+/*******************************************************************************
+**
+** Function         BTA_JvIsEncrypted
+**
+** Description      This function checks if the link to peer device is encrypted
+**
+** Returns          TRUE if encrypted.
+**                  FALSE if not.
+**
+*******************************************************************************/
+BOOLEAN BTA_JvIsEncrypted(BD_ADDR bd_addr)
+{
+    BOOLEAN is_encrypted = FALSE;
+    UINT8 sec_flags, le_flags;
+
+    if (BTM_GetSecurityFlags(bd_addr, &sec_flags) &&
+            BTM_GetSecurityFlagsByTransport(bd_addr, &le_flags, BT_TRANSPORT_LE)) {
+        if (sec_flags & BTM_SEC_FLAG_ENCRYPTED ||
+                le_flags & BTM_SEC_FLAG_ENCRYPTED) {
+            is_encrypted = TRUE;
+        }
+    }
+    return is_encrypted;
+}
+/*******************************************************************************
+**
+** Function         BTA_JvGetChannelId
+**
+** Description      This function reserves a SCN (server channel number) for
+**                  applications running over RFCOMM, L2CAP of L2CAP_LE.
+**                  It is primarily called by server profiles/applications to
+**                  register their SCN into the SDP database. The SCN is reported
+**                  by the tBTA_JV_DM_CBACK callback with a BTA_JV_GET_SCN_EVT
+**                  for RFCOMM channels and BTA_JV_GET_PSM_EVT for L2CAP and LE.
+**                  If the SCN/PSM reported is 0, that means all resources are
+**                  exhausted.
+** Parameters
+**   conn_type      one of BTA_JV_CONN_TYPE_
+**   user_data      Any uservalue - will be returned in the resulting event.
+**   channel        Only used for RFCOMM - to try to allocate a specific RFCOMM
+**                  channel.
+**
+** Returns          BTA_JV_SUCCESS, if the request is being processed.
+**                  BTA_JV_FAILURE, otherwise.
+**
+*******************************************************************************/
+tBTA_JV_STATUS BTA_JvGetChannelId(int conn_type, void *user_data, INT32 channel)
+{
+    tBTA_JV_STATUS status = BTA_JV_FAILURE;
+    tBTA_JV_API_ALLOC_CHANNEL *p_msg;
+
+    APPL_TRACE_API( "%s", __func__);
+    if ((p_msg = (tBTA_JV_API_ALLOC_CHANNEL *)osi_malloc(sizeof(tBTA_JV_API_ALLOC_CHANNEL))) != NULL) {
+        p_msg->hdr.event = BTA_JV_API_GET_CHANNEL_EVT;
+        p_msg->type      = conn_type;
+        p_msg->channel   = channel;
+        p_msg->user_data = user_data;
+        bta_sys_sendmsg(p_msg);
+        status = BTA_JV_SUCCESS;
+    }
+
+    return (status);
+}
+
+/*******************************************************************************
+**
+** Function         BTA_JvFreeChannel
+**
+** Description      This function frees a server channel number that was used
+**                  by an application running over RFCOMM.
+** Parameters
+**   channel        The channel to free
+**   conn_type      one of BTA_JV_CONN_TYPE_
+**
+** 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 status = BTA_JV_FAILURE;
+    tBTA_JV_API_FREE_CHANNEL *p_msg;
+
+    APPL_TRACE_API( "%s", __func__);
+    if ((p_msg = (tBTA_JV_API_FREE_CHANNEL *)osi_malloc(sizeof(tBTA_JV_API_FREE_CHANNEL))) != NULL) {
+        p_msg->hdr.event = BTA_JV_API_FREE_SCN_EVT;
+        p_msg->scn       = channel;
+        p_msg->type      = conn_type;
+        bta_sys_sendmsg(p_msg);
+        status = BTA_JV_SUCCESS;
+    }
+
+    return (status);
+}
+
+/*******************************************************************************
+**
+** Function         BTA_JvStartDiscovery
+**
+** Description      This function performs service discovery for the services
+**                  provided by the given peer device. When the operation is
+**                  complete the tBTA_JV_DM_CBACK callback function will be
+**                  called with a BTA_JV_DISCOVERY_COMP_EVT.
+**
+** Returns          BTA_JV_SUCCESS, if the request is being processed.
+**                  BTA_JV_FAILURE, otherwise.
+**
+*******************************************************************************/
+tBTA_JV_STATUS BTA_JvStartDiscovery(BD_ADDR bd_addr, UINT16 num_uuid,
+                                    tSDP_UUID *p_uuid_list, void *user_data)
+{
+    tBTA_JV_STATUS status = BTA_JV_FAILURE;
+    tBTA_JV_API_START_DISCOVERY *p_msg;
+
+    APPL_TRACE_API( "BTA_JvStartDiscovery");
+    if ((p_msg = (tBTA_JV_API_START_DISCOVERY *)osi_malloc(sizeof(tBTA_JV_API_START_DISCOVERY))) != NULL) {
+        p_msg->hdr.event = BTA_JV_API_START_DISCOVERY_EVT;
+        bdcpy(p_msg->bd_addr, bd_addr);
+        p_msg->num_uuid = num_uuid;
+        memcpy(p_msg->uuid_list, p_uuid_list, num_uuid * sizeof(tSDP_UUID));
+        p_msg->num_attr = 0;
+        p_msg->user_data = user_data;
+        bta_sys_sendmsg(p_msg);
+        status = BTA_JV_SUCCESS;
+    }
+
+    return (status);
+}
+
+/*******************************************************************************
+**
+** Function         BTA_JvCreateRecord
+**
+** Description      Create a service record in the local SDP database.
+**                  When the operation is complete the tBTA_JV_DM_CBACK callback
+**                  function will be called with a BTA_JV_CREATE_RECORD_EVT.
+**
+** Returns          BTA_JV_SUCCESS, if the request is being processed.
+**                  BTA_JV_FAILURE, otherwise.
+**
+*******************************************************************************/
+tBTA_JV_STATUS BTA_JvCreateRecordByUser(const char *name, UINT32 channel, void *user_data)
+{
+    tBTA_JV_STATUS status = BTA_JV_FAILURE;
+    tBTA_JV_API_CREATE_RECORD *p_msg;
+
+    APPL_TRACE_API( "BTA_JvCreateRecordByUser");
+    if ((p_msg = (tBTA_JV_API_CREATE_RECORD *)osi_malloc(sizeof(tBTA_JV_API_CREATE_RECORD))) != NULL) {
+        p_msg->hdr.event = BTA_JV_API_CREATE_RECORD_EVT;
+        p_msg->user_data = user_data;
+        strcpy(p_msg->name, name);
+        p_msg->channel = channel;
+        bta_sys_sendmsg(p_msg);
+        status = BTA_JV_SUCCESS;
+    }
+
+    return (status);
+}
+
+/*******************************************************************************
+**
+** Function         BTA_JvDeleteRecord
+**
+** Description      Delete a service record in the local SDP database.
+**
+** Returns          BTA_JV_SUCCESS, if the request is being processed.
+**                  BTA_JV_FAILURE, otherwise.
+**
+*******************************************************************************/
+tBTA_JV_STATUS BTA_JvDeleteRecord(UINT32 handle)
+{
+    tBTA_JV_STATUS status = BTA_JV_FAILURE;
+    tBTA_JV_API_ADD_ATTRIBUTE *p_msg;
+
+    APPL_TRACE_API( "BTA_JvDeleteRecord");
+    if ((p_msg = (tBTA_JV_API_ADD_ATTRIBUTE *)osi_malloc(sizeof(tBTA_JV_API_ADD_ATTRIBUTE))) != NULL) {
+        p_msg->hdr.event = BTA_JV_API_DELETE_RECORD_EVT;
+        p_msg->handle = handle;
+        bta_sys_sendmsg(p_msg);
+        status = BTA_JV_SUCCESS;
+    }
+    return (status);
+}
+
+/*******************************************************************************
+**
+** Function         BTA_JvL2capConnectLE
+**
+** Description      Initiate an LE connection as a L2CAP client to the given BD
+**                  Address.
+**                  When the connection is initiated or failed to initiate,
+**                  tBTA_JV_L2CAP_CBACK is called with BTA_JV_L2CAP_CL_INIT_EVT
+**                  When the connection is established or failed,
+**                  tBTA_JV_L2CAP_CBACK is called with BTA_JV_L2CAP_OPEN_EVT
+**
+** Returns          BTA_JV_SUCCESS, if the request is being processed.
+**                  BTA_JV_FAILURE, otherwise.
+**
+*******************************************************************************/
+tBTA_JV_STATUS BTA_JvL2capConnectLE(tBTA_SEC sec_mask, tBTA_JV_ROLE role,
+                                    const tL2CAP_ERTM_INFO *ertm_info, UINT16 remote_chan,
+                                    UINT16 rx_mtu, tL2CAP_CFG_INFO *cfg,
+                                    BD_ADDR peer_bd_addr, tBTA_JV_L2CAP_CBACK *p_cback, void *user_data)
+{
+    tBTA_JV_STATUS status = BTA_JV_FAILURE;
+    tBTA_JV_API_L2CAP_CONNECT *p_msg;
+
+    APPL_TRACE_API( "%s", __func__);
+
+    if (p_cback &&
+            (p_msg =
+                 (tBTA_JV_API_L2CAP_CONNECT *)osi_malloc(sizeof(tBTA_JV_API_L2CAP_CONNECT))) != NULL) {
+        p_msg->hdr.event    = BTA_JV_API_L2CAP_CONNECT_LE_EVT;
+        p_msg->sec_mask     = sec_mask;
+        p_msg->role         = role;
+        p_msg->remote_chan  = remote_chan;
+        p_msg->rx_mtu       = rx_mtu;
+        if (cfg != NULL) {
+            p_msg->has_cfg = TRUE;
+            p_msg->cfg = *cfg;
+        } else {
+            p_msg->has_cfg = FALSE;
+        }
+        if (ertm_info != NULL) {
+            p_msg->has_ertm_info = TRUE;
+            p_msg->ertm_info = *ertm_info;
+        } else {
+            p_msg->has_ertm_info = FALSE;
+        }
+        memcpy(p_msg->peer_bd_addr, peer_bd_addr, sizeof(BD_ADDR));
+        p_msg->p_cback      = p_cback;
+        p_msg->user_data    = user_data;
+        bta_sys_sendmsg(p_msg);
+        status = BTA_JV_SUCCESS;
+    }
+
+    return (status);
+}
+
+/*******************************************************************************
+**
+** Function         BTA_JvL2capConnect
+**
+** Description      Initiate a connection as a L2CAP client to the given BD
+**                  Address.
+**                  When the connection is initiated or failed to initiate,
+**                  tBTA_JV_L2CAP_CBACK is called with BTA_JV_L2CAP_CL_INIT_EVT
+**                  When the connection is established or failed,
+**                  tBTA_JV_L2CAP_CBACK is called with BTA_JV_L2CAP_OPEN_EVT
+**
+** Returns          BTA_JV_SUCCESS, if the request is being processed.
+**                  BTA_JV_FAILURE, otherwise.
+**
+*******************************************************************************/
+tBTA_JV_STATUS BTA_JvL2capConnect(tBTA_SEC sec_mask, tBTA_JV_ROLE role,
+                                  const tL2CAP_ERTM_INFO *ertm_info, UINT16 remote_psm,
+                                  UINT16 rx_mtu, tL2CAP_CFG_INFO *cfg,
+                                  BD_ADDR peer_bd_addr, tBTA_JV_L2CAP_CBACK *p_cback, void *user_data)
+{
+    tBTA_JV_STATUS status = BTA_JV_FAILURE;
+    tBTA_JV_API_L2CAP_CONNECT *p_msg;
+
+    APPL_TRACE_API( "%s", __func__);
+
+    if (p_cback &&
+            (p_msg = (tBTA_JV_API_L2CAP_CONNECT *)osi_malloc(sizeof(tBTA_JV_API_L2CAP_CONNECT))) != NULL) {
+        p_msg->hdr.event    = BTA_JV_API_L2CAP_CONNECT_EVT;
+        p_msg->sec_mask     = sec_mask;
+        p_msg->role         = role;
+        p_msg->remote_psm   = remote_psm;
+        p_msg->rx_mtu       = rx_mtu;
+        if (cfg != NULL) {
+            p_msg->has_cfg = TRUE;
+            p_msg->cfg = *cfg;
+        } else {
+            p_msg->has_cfg = FALSE;
+        }
+        if (ertm_info != NULL) {
+            p_msg->has_ertm_info = TRUE;
+            p_msg->ertm_info = *ertm_info;
+        } else {
+            p_msg->has_ertm_info = FALSE;
+        }
+        memcpy(p_msg->peer_bd_addr, peer_bd_addr, sizeof(BD_ADDR));
+        p_msg->p_cback      = p_cback;
+        p_msg->user_data    = user_data;
+        bta_sys_sendmsg(p_msg);
+        status = BTA_JV_SUCCESS;
+    }
+
+    return (status);
+}
+
+/*******************************************************************************
+**
+** Function         BTA_JvL2capClose
+**
+** Description      This function closes an L2CAP client connection
+**
+** Returns          BTA_JV_SUCCESS, if the request is being processed.
+**                  BTA_JV_FAILURE, otherwise.
+**
+*******************************************************************************/
+tBTA_JV_STATUS BTA_JvL2capClose(UINT32 handle)
+{
+    tBTA_JV_STATUS status = BTA_JV_FAILURE;
+    tBTA_JV_API_L2CAP_CLOSE *p_msg;
+
+    APPL_TRACE_API( "%s", __func__);
+
+    if (handle < BTA_JV_MAX_L2C_CONN && bta_jv_cb.l2c_cb[handle].p_cback &&
+            (p_msg = (tBTA_JV_API_L2CAP_CLOSE *)osi_malloc(sizeof(tBTA_JV_API_L2CAP_CLOSE))) != NULL) {
+        p_msg->hdr.event = BTA_JV_API_L2CAP_CLOSE_EVT;
+        p_msg->handle = handle;
+        p_msg->p_cb = &bta_jv_cb.l2c_cb[handle];
+        bta_sys_sendmsg(p_msg);
+        status = BTA_JV_SUCCESS;
+    }
+
+    return (status);
+}
+
+/*******************************************************************************
+**
+** Function         BTA_JvL2capCloseLE
+**
+** Description      This function closes an L2CAP client connection for Fixed Channels
+**                  Function is idempotent and no callbacks are called!
+**
+** Returns          BTA_JV_SUCCESS, if the request is being processed.
+**                  BTA_JV_FAILURE, otherwise.
+**
+*******************************************************************************/
+tBTA_JV_STATUS BTA_JvL2capCloseLE(UINT32 handle)
+{
+    tBTA_JV_STATUS status = BTA_JV_FAILURE;
+    tBTA_JV_API_L2CAP_CLOSE *p_msg;
+
+    APPL_TRACE_API( "%s", __func__);
+
+    if ((p_msg = (tBTA_JV_API_L2CAP_CLOSE *)osi_malloc(sizeof(tBTA_JV_API_L2CAP_CLOSE))) != NULL) {
+        p_msg->hdr.event = BTA_JV_API_L2CAP_CLOSE_FIXED_EVT;
+        p_msg->handle = handle;
+        bta_sys_sendmsg(p_msg);
+        status = BTA_JV_SUCCESS;
+    }
+
+    return (status);
+}
+
+/*******************************************************************************
+**
+** Function         BTA_JvL2capStartServer
+**
+** Description      This function starts an L2CAP server and listens for an L2CAP
+**                  connection from a remote Bluetooth device.  When the server
+**                  is started successfully, tBTA_JV_L2CAP_CBACK is called with
+**                  BTA_JV_L2CAP_START_EVT.  When the connection is established,
+**                  tBTA_JV_L2CAP_CBACK is called with BTA_JV_L2CAP_OPEN_EVT.
+**
+** Returns          BTA_JV_SUCCESS, if the request is being processed.
+**                  BTA_JV_FAILURE, otherwise.
+**
+*******************************************************************************/
+tBTA_JV_STATUS BTA_JvL2capStartServer(tBTA_SEC sec_mask, tBTA_JV_ROLE role,
+                                      const tL2CAP_ERTM_INFO *ertm_info, UINT16 local_psm, UINT16 rx_mtu, tL2CAP_CFG_INFO *cfg,
+                                      tBTA_JV_L2CAP_CBACK *p_cback, void *user_data)
+{
+    tBTA_JV_STATUS status = BTA_JV_FAILURE;
+    tBTA_JV_API_L2CAP_SERVER *p_msg;
+
+    APPL_TRACE_API( "%s", __func__);
+
+    if (p_cback &&
+            (p_msg = (tBTA_JV_API_L2CAP_SERVER *)osi_malloc(sizeof(tBTA_JV_API_L2CAP_SERVER))) != NULL) {
+        p_msg->hdr.event = BTA_JV_API_L2CAP_START_SERVER_EVT;
+        p_msg->sec_mask = sec_mask;
+        p_msg->role = role;
+        p_msg->local_psm = local_psm;
+        p_msg->rx_mtu = rx_mtu;
+        if (cfg != NULL) {
+            p_msg->has_cfg = TRUE;
+            p_msg->cfg = *cfg;
+        } else {
+            p_msg->has_cfg = FALSE;
+        }
+        if (ertm_info != NULL) {
+            p_msg->has_ertm_info = TRUE;
+            p_msg->ertm_info = *ertm_info;
+        } else {
+            p_msg->has_ertm_info = FALSE;
+        }
+        p_msg->p_cback = p_cback;
+        p_msg->user_data = user_data;
+        bta_sys_sendmsg(p_msg);
+        status = BTA_JV_SUCCESS;
+    }
+
+    return (status);
+}
+
+/*******************************************************************************
+**
+** Function         BTA_JvL2capStartServerLE
+**
+** Description      This function starts an LE L2CAP server and listens for an L2CAP
+**                  connection from a remote Bluetooth device.  When the server
+**                  is started successfully, tBTA_JV_L2CAP_CBACK is called with
+**                  BTA_JV_L2CAP_START_EVT.  When the connection is established,
+**                  tBTA_JV_L2CAP_CBACK is called with BTA_JV_L2CAP_OPEN_EVT.
+**
+** Returns          BTA_JV_SUCCESS, if the request is being processed.
+**                  BTA_JV_FAILURE, otherwise.
+**
+*******************************************************************************/
+tBTA_JV_STATUS BTA_JvL2capStartServerLE(tBTA_SEC sec_mask, tBTA_JV_ROLE role,
+                                        const tL2CAP_ERTM_INFO *ertm_info, UINT16 local_chan, UINT16 rx_mtu, tL2CAP_CFG_INFO *cfg,
+                                        tBTA_JV_L2CAP_CBACK *p_cback, void *user_data)
+{
+    tBTA_JV_STATUS status = BTA_JV_FAILURE;
+    tBTA_JV_API_L2CAP_SERVER *p_msg;
+
+    APPL_TRACE_API( "%s", __func__);
+
+    if (p_cback &&
+            (p_msg = (tBTA_JV_API_L2CAP_SERVER *)osi_malloc(sizeof(tBTA_JV_API_L2CAP_SERVER))) != NULL) {
+        p_msg->hdr.event = BTA_JV_API_L2CAP_START_SERVER_LE_EVT;
+        p_msg->sec_mask = sec_mask;
+        p_msg->role = role;
+        p_msg->local_chan = local_chan;
+        p_msg->rx_mtu = rx_mtu;
+        if (cfg != NULL) {
+            p_msg->has_cfg = TRUE;
+            p_msg->cfg = *cfg;
+        } else {
+            p_msg->has_cfg = FALSE;
+        }
+        if (ertm_info != NULL) {
+            p_msg->has_ertm_info = TRUE;
+            p_msg->ertm_info = *ertm_info;
+        } else {
+            p_msg->has_ertm_info = FALSE;
+        }
+        p_msg->p_cback = p_cback;
+        p_msg->user_data = user_data;
+        bta_sys_sendmsg(p_msg);
+        status = BTA_JV_SUCCESS;
+    }
+
+    return (status);
+}
+
+/*******************************************************************************
+**
+** Function         BTA_JvL2capStopServer
+**
+** Description      This function stops the L2CAP server. If the server has an
+**                  active connection, it would be closed.
+**
+** Returns          BTA_JV_SUCCESS, if the request is being processed.
+**                  BTA_JV_FAILURE, otherwise.
+**
+*******************************************************************************/
+tBTA_JV_STATUS BTA_JvL2capStopServer(UINT16 local_psm, void *user_data)
+{
+    tBTA_JV_STATUS status = BTA_JV_FAILURE;
+    tBTA_JV_API_L2CAP_SERVER *p_msg;
+
+    APPL_TRACE_API( "%s", __func__);
+
+    if ((p_msg = (tBTA_JV_API_L2CAP_SERVER *)osi_malloc(sizeof(tBTA_JV_API_L2CAP_SERVER))) != NULL) {
+        p_msg->hdr.event = BTA_JV_API_L2CAP_STOP_SERVER_EVT;
+        p_msg->local_psm = local_psm;
+        p_msg->user_data = user_data;
+        bta_sys_sendmsg(p_msg);
+        status = BTA_JV_SUCCESS;
+    }
+
+    return (status);
+}
+
+/*******************************************************************************
+**
+** Function         BTA_JvL2capStopServerLE
+**
+** Description      This function stops the LE L2CAP server. If the server has an
+**                  active connection, it would be closed.
+**
+** Returns          BTA_JV_SUCCESS, if the request is being processed.
+**                  BTA_JV_FAILURE, otherwise.
+**
+*******************************************************************************/
+tBTA_JV_STATUS BTA_JvL2capStopServerLE(UINT16 local_chan, void *user_data)
+{
+    tBTA_JV_STATUS status = BTA_JV_FAILURE;
+    tBTA_JV_API_L2CAP_SERVER *p_msg;
+
+    APPL_TRACE_API( "%s", __func__);
+
+    if ((p_msg = (tBTA_JV_API_L2CAP_SERVER *)osi_malloc(sizeof(tBTA_JV_API_L2CAP_SERVER))) != NULL) {
+        p_msg->hdr.event = BTA_JV_API_L2CAP_STOP_SERVER_LE_EVT;
+        p_msg->local_chan = local_chan;
+        p_msg->user_data = user_data;
+        bta_sys_sendmsg(p_msg);
+        status = BTA_JV_SUCCESS;
+    }
+
+    return (status);
+}
+
+/*******************************************************************************
+**
+** Function         BTA_JvL2capRead
+**
+** Description      This function reads data from an L2CAP connecti;
+    tBTA_JV_RFC_CB  *p_cb = rc->p_cb;
+on
+**                  When the operation is complete, tBTA_JV_L2CAP_CBACK is
+**                  called with BTA_JV_L2CAP_READ_EVT.
+**
+** Returns          BTA_JV_SUCCESS, if the request is being processed.
+**                  BTA_JV_FAILURE, otherwise.
+**
+*******************************************************************************/
+tBTA_JV_STATUS BTA_JvL2capRead(UINT32 handle, UINT32 req_id, UINT8 *p_data, UINT16 len)
+{
+    tBTA_JV_STATUS status = BTA_JV_FAILURE;
+    tBTA_JV_L2CAP_READ evt_data;
+
+    APPL_TRACE_API( "%s", __func__);
+
+
+    if (handle < BTA_JV_MAX_L2C_CONN && bta_jv_cb.l2c_cb[handle].p_cback) {
+        status = BTA_JV_SUCCESS;
+        evt_data.status = BTA_JV_FAILURE;
+        evt_data.handle = handle;
+        evt_data.req_id = req_id;
+        evt_data.p_data = p_data;
+        evt_data.len    = 0;
+
+        if (BT_PASS == GAP_ConnReadData((UINT16)handle, p_data, len, &evt_data.len)) {
+            evt_data.status = BTA_JV_SUCCESS;
+        }
+        bta_jv_cb.l2c_cb[handle].p_cback(
+            BTA_JV_L2CAP_READ_EVT, (tBTA_JV *)&evt_data, bta_jv_cb.l2c_cb[handle].user_data);
+    }
+
+    return (status);
+}
+
+/*******************************************************************************
+**
+** Function         BTA_JvL2capReceive
+**
+** Description      This function reads data from an L2CAP connection
+**                  When the operation is complete, tBTA_JV_L2CAP_CBACK is
+**                  called with BTA_JV_L2CAP_RECEIVE_EVT.
+**                  If there are more data queued in L2CAP than len, the extra data will be discarded.
+**
+** Returns          BTA_JV_SUCCESS, if the request is being processed.
+**                  BTA_JV_FAILURE, otherwise.
+**
+*******************************************************************************/
+tBTA_JV_STATUS BTA_JvL2capReceive(UINT32 handle, UINT32 req_id, UINT8 *p_data, UINT16 len)
+{
+    tBTA_JV_STATUS status = BTA_JV_FAILURE;
+    tBTA_JV_L2CAP_RECEIVE evt_data;
+    UINT32  left_over = 0;
+    UINT16  max_len, read_len;
+
+    APPL_TRACE_API( "%s", __func__);
+
+
+    if (handle < BTA_JV_MAX_L2C_CONN && bta_jv_cb.l2c_cb[handle].p_cback) {
+        status = BTA_JV_SUCCESS;
+        evt_data.status = BTA_JV_FAILURE;
+        evt_data.handle = handle;
+        evt_data.req_id = req_id;
+        evt_data.p_data = p_data;
+        evt_data.len    = 0;
+
+        if (BT_PASS == GAP_ConnReadData((UINT16)handle, p_data, len, &evt_data.len)) {
+            evt_data.status = BTA_JV_SUCCESS;
+            GAP_GetRxQueueCnt ((UINT16)handle, &left_over);
+            while (left_over) {
+                max_len = (left_over > 0xFFFF) ? 0xFFFF : left_over;
+                GAP_ConnReadData ((UINT16)handle, NULL, max_len, &read_len);
+                left_over -= read_len;
+            }
+        }
+        bta_jv_cb.l2c_cb[handle].p_cback(
+            BTA_JV_L2CAP_RECEIVE_EVT, (tBTA_JV *)&evt_data, bta_jv_cb.l2c_cb[handle].user_data);
+    }
+
+    return (status);
+}
+/*******************************************************************************
+**
+** Function         BTA_JvL2capReady
+**
+** Description      This function determined if there is data to read from
+**                    an L2CAP connection
+**
+** Returns          BTA_JV_SUCCESS, if data queue size is in *p_data_size.
+**                  BTA_JV_FAILURE, if error.
+**
+*******************************************************************************/
+tBTA_JV_STATUS BTA_JvL2capReady(UINT32 handle, UINT32 *p_data_size)
+{
+    tBTA_JV_STATUS status = BTA_JV_FAILURE;
+
+    APPL_TRACE_API( "%s: %d", __func__, handle);
+    if (p_data_size && handle < BTA_JV_MAX_L2C_CONN && bta_jv_cb.l2c_cb[handle].p_cback) {
+        *p_data_size = 0;
+        if (BT_PASS == GAP_GetRxQueueCnt((UINT16)handle, p_data_size) ) {
+            status = BTA_JV_SUCCESS;
+        }
+    }
+
+    return (status);
+}
+
+
+/*******************************************************************************
+**
+** Function         BTA_JvL2capWrite
+**
+** Description      This function writes data to an L2CAP connection
+**                  When the operation is complete, tBTA_JV_L2CAP_CBACK is
+**                  called with BTA_JV_L2CAP_WRITE_EVT. Works for
+**                  PSM-based connections
+**
+** Returns          BTA_JV_SUCCESS, if the request is being processed.
+**                  BTA_JV_FAILURE, otherwise.
+**
+*******************************************************************************/
+tBTA_JV_STATUS BTA_JvL2capWrite(UINT32 handle, UINT32 req_id, UINT8 *p_data,
+                                UINT16 len, void *user_data)
+{
+    tBTA_JV_STATUS status = BTA_JV_FAILURE;
+    tBTA_JV_API_L2CAP_WRITE *p_msg;
+
+    APPL_TRACE_API( "%s", __func__);
+
+    if (handle < BTA_JV_MAX_L2C_CONN && bta_jv_cb.l2c_cb[handle].p_cback &&
+            (p_msg = (tBTA_JV_API_L2CAP_WRITE *)osi_malloc(sizeof(tBTA_JV_API_L2CAP_WRITE))) != NULL) {
+        p_msg->hdr.event = BTA_JV_API_L2CAP_WRITE_EVT;
+        p_msg->handle = handle;
+        p_msg->req_id = req_id;
+        p_msg->p_data = p_data;
+        p_msg->p_cb = &bta_jv_cb.l2c_cb[handle];
+        p_msg->len = len;
+        p_msg->user_data = user_data;
+        bta_sys_sendmsg(p_msg);
+        status = BTA_JV_SUCCESS;
+    }
+
+    return (status);
+}
+
+/*******************************************************************************
+**
+** Function         BTA_JvL2capWriteFixed
+**
+** Description      This function writes data to an L2CAP connection
+**                  When the operation is complete, tBTA_JV_L2CAP_CBACK is
+**                  called with BTA_JV_L2CAP_WRITE_EVT. Works for
+**                  fixed-channel connections
+**
+** Returns          BTA_JV_SUCCESS, if the request is being processed.
+**                  BTA_JV_FAILURE, otherwise.
+**
+*******************************************************************************/
+tBTA_JV_STATUS BTA_JvL2capWriteFixed(UINT16 channel, BD_ADDR *addr, UINT32 req_id,
+                                     tBTA_JV_L2CAP_CBACK *p_cback, UINT8 *p_data, UINT16 len, void *user_data)
+{
+    tBTA_JV_STATUS status = BTA_JV_FAILURE;
+    tBTA_JV_API_L2CAP_WRITE_FIXED *p_msg;
+
+    APPL_TRACE_API( "%s", __func__);
+
+    if ((p_msg =
+                (tBTA_JV_API_L2CAP_WRITE_FIXED *)osi_malloc(sizeof(tBTA_JV_API_L2CAP_WRITE_FIXED))) != NULL) {
+        p_msg->hdr.event = BTA_JV_API_L2CAP_WRITE_FIXED_EVT;
+        p_msg->channel = channel;
+        memcpy(p_msg->addr, addr, sizeof(p_msg->addr));
+        p_msg->req_id = req_id;
+        p_msg->p_data = p_data;
+        p_msg->p_cback = p_cback;
+        p_msg->len = len;
+        p_msg->user_data = user_data;
+        bta_sys_sendmsg(p_msg);
+        status = BTA_JV_SUCCESS;
+    }
+
+    return (status);
+}
+
+/*******************************************************************************
+**
+** Function         BTA_JvRfcommConnect
+**
+** Description      This function makes an RFCOMM conection to a remote BD
+**                  Address.
+**                  When the connection is initiated or failed to initiate,
+**                  tBTA_JV_RFCOMM_CBACK is called with BTA_JV_RFCOMM_CL_INIT_EVT
+**                  When the connection is established or failed,
+**                  tBTA_JV_RFCOMM_CBACK is called with BTA_JV_RFCOMM_OPEN_EVT
+**
+** Returns          BTA_JV_SUCCESS, if the request is being processed.
+**                  BTA_JV_FAILURE, otherwise.
+**
+*******************************************************************************/
+tBTA_JV_STATUS BTA_JvRfcommConnect(tBTA_SEC sec_mask,
+                                   tBTA_JV_ROLE role, UINT8 remote_scn, BD_ADDR peer_bd_addr,
+                                   tBTA_JV_RFCOMM_CBACK *p_cback, void *user_data)
+{
+    tBTA_JV_STATUS status = BTA_JV_FAILURE;
+    tBTA_JV_API_RFCOMM_CONNECT *p_msg;
+
+    APPL_TRACE_API( "BTA_JvRfcommConnect");
+    if (p_cback &&
+            (p_msg = (tBTA_JV_API_RFCOMM_CONNECT *)osi_malloc(sizeof(tBTA_JV_API_RFCOMM_CONNECT))) != NULL) {
+        p_msg->hdr.event    = BTA_JV_API_RFCOMM_CONNECT_EVT;
+        p_msg->sec_mask     = sec_mask;
+        p_msg->role         = role;
+        p_msg->remote_scn   = remote_scn;
+        memcpy(p_msg->peer_bd_addr, peer_bd_addr, sizeof(BD_ADDR));
+        p_msg->p_cback      = p_cback;
+        p_msg->user_data    = user_data;
+        bta_sys_sendmsg(p_msg);
+        status = BTA_JV_SUCCESS;
+    }
+
+    return (status);
+}
+
+/*******************************************************************************
+**
+** Function         BTA_JvRfcommClose
+**
+** Description      This function closes an RFCOMM connection
+**
+** 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 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");
+    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) {
+        p_msg->hdr.event = BTA_JV_API_RFCOMM_CLOSE_EVT;
+        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->user_data = user_data;
+        bta_sys_sendmsg(p_msg);
+        status = BTA_JV_SUCCESS;
+    }
+
+    return (status);
+}
+
+/*******************************************************************************
+**
+** Function         BTA_JvRfcommStartServer
+**
+** Description      This function starts listening for an RFCOMM connection
+**                  request from a remote Bluetooth device.  When the server is
+**                  started successfully, tBTA_JV_RFCOMM_CBACK is called
+**                  with BTA_JV_RFCOMM_START_EVT.
+**                  When the connection is established, tBTA_JV_RFCOMM_CBACK
+**                  is called with BTA_JV_RFCOMM_OPEN_EVT.
+**
+** Returns          BTA_JV_SUCCESS, if the request is being processed.
+**                  BTA_JV_FAILURE, otherwise.
+**
+*******************************************************************************/
+tBTA_JV_STATUS BTA_JvRfcommStartServer(tBTA_SEC sec_mask,
+                                       tBTA_JV_ROLE role, UINT8 local_scn, UINT8 max_session,
+                                       tBTA_JV_RFCOMM_CBACK *p_cback, void *user_data)
+{
+    tBTA_JV_STATUS status = BTA_JV_FAILURE;
+    tBTA_JV_API_RFCOMM_SERVER *p_msg;
+
+    APPL_TRACE_API( "BTA_JvRfcommStartServer");
+    if (p_cback &&
+            (p_msg = (tBTA_JV_API_RFCOMM_SERVER *)osi_malloc(sizeof(tBTA_JV_API_RFCOMM_SERVER))) != NULL) {
+        if (max_session == 0) {
+            max_session = 1;
+        }
+        if (max_session > BTA_JV_MAX_RFC_SR_SESSION) {
+            APPL_TRACE_DEBUG( "max_session (%d) is too big. use max (%d)", max_session, BTA_JV_MAX_RFC_SR_SESSION);
+            max_session = BTA_JV_MAX_RFC_SR_SESSION;
+        }
+        p_msg->hdr.event = BTA_JV_API_RFCOMM_START_SERVER_EVT;
+        p_msg->sec_mask = sec_mask;
+        p_msg->role = role;
+        p_msg->local_scn = local_scn;
+        p_msg->max_session = max_session;
+        p_msg->p_cback = p_cback;
+        p_msg->user_data = user_data; //caller's private data
+        bta_sys_sendmsg(p_msg);
+        status = BTA_JV_SUCCESS;
+    }
+
+    return (status);
+}
+
+/*******************************************************************************
+**
+** Function         BTA_JvRfcommStopServer
+**
+** Description      This function stops the RFCOMM server. If the server has an
+**                  active connection, it would be closed.
+**
+** Returns          BTA_JV_SUCCESS, if the request is being processed.
+**                  BTA_JV_FAILURE, otherwise.
+**
+*******************************************************************************/
+tBTA_JV_STATUS BTA_JvRfcommStopServer(UINT32 handle, void *user_data)
+{
+    tBTA_JV_STATUS status = BTA_JV_FAILURE;
+    tBTA_JV_API_RFCOMM_SERVER *p_msg;
+    APPL_TRACE_API( "BTA_JvRfcommStopServer");
+    if ((p_msg = (tBTA_JV_API_RFCOMM_SERVER *)osi_malloc(sizeof(tBTA_JV_API_RFCOMM_SERVER))) != NULL) {
+        p_msg->hdr.event = BTA_JV_API_RFCOMM_STOP_SERVER_EVT;
+        p_msg->handle = handle;
+        p_msg->user_data = user_data; //caller's private data
+        bta_sys_sendmsg(p_msg);
+        status = BTA_JV_SUCCESS;
+    }
+
+    return (status);
+}
+
+/*******************************************************************************
+**
+** Function         BTA_JvRfcommRead
+**
+** Description      This function reads data from an RFCOMM connection
+**                  The actual size of data read is returned in p_len.
+**
+** Returns          BTA_JV_SUCCESS, if the request is being processed.
+**                  BTA_JV_FAILURE, otherwise.
+**
+*******************************************************************************/
+tBTA_JV_STATUS BTA_JvRfcommRead(UINT32 handle, UINT32 req_id, UINT8 *p_data, UINT16 len)
+{
+    tBTA_JV_STATUS status = BTA_JV_FAILURE;
+    tBTA_JV_API_RFCOMM_READ *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_JvRfcommRead");
+    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_READ *)osi_malloc(sizeof(tBTA_JV_API_RFCOMM_READ))) != NULL) {
+        p_msg->hdr.event = BTA_JV_API_RFCOMM_READ_EVT;
+        p_msg->handle = handle;
+        p_msg->req_id = req_id;
+        p_msg->p_data = p_data;
+        p_msg->len = len;
+        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];
+        bta_sys_sendmsg(p_msg);
+        status = BTA_JV_SUCCESS;
+    }
+
+    return (status);
+}
+
+/*******************************************************************************
+**
+** Function         BTA_JvRfcommGetPortHdl
+**
+** Description    This function fetches the rfcomm port handle
+**
+** Returns          BTA_JV_SUCCESS, if the request is being processed.
+**                  BTA_JV_FAILURE, otherwise.
+**
+*******************************************************************************/
+UINT16 BTA_JvRfcommGetPortHdl(UINT32 handle)
+{
+    UINT32  hi = ((handle & BTA_JV_RFC_HDL_MASK) & ~BTA_JV_RFCOMM_MASK) - 1;
+    UINT32  si = BTA_JV_RFC_HDL_TO_SIDX(handle);
+
+    if (hi < BTA_JV_MAX_RFC_CONN &&
+            si < BTA_JV_MAX_RFC_SR_SESSION && bta_jv_cb.rfc_cb[hi].rfc_hdl[si]) {
+        return bta_jv_cb.port_cb[bta_jv_cb.rfc_cb[hi].rfc_hdl[si] - 1].port_handle;
+    } else {
+        return 0xffff;
+    }
+}
+
+
+/*******************************************************************************
+**
+** Function         BTA_JvRfcommReady
+**
+** Description      This function determined if there is data to read from
+**                  an RFCOMM connection
+**
+** Returns          BTA_JV_SUCCESS, if data queue size is in *p_data_size.
+**                  BTA_JV_FAILURE, if error.
+**
+*******************************************************************************/
+tBTA_JV_STATUS BTA_JvRfcommReady(UINT32 handle, UINT32 *p_data_size)
+{
+    tBTA_JV_STATUS status = BTA_JV_FAILURE;
+    UINT16          size = 0;
+    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_JvRfcommReady");
+    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]) {
+        if (PORT_GetRxQueueCnt(bta_jv_cb.rfc_cb[hi].rfc_hdl[si], &size) == PORT_SUCCESS) {
+            status = BTA_JV_SUCCESS;
+        }
+    }
+    *p_data_size = size;
+    return (status);
+}
+
+/*******************************************************************************
+**
+** Function         BTA_JvRfcommWrite
+**
+** Description      This function writes data to an RFCOMM connection
+**
+** Returns          BTA_JV_SUCCESS, if the request is being processed.
+**                  BTA_JV_FAILURE, otherwise.
+**
+*******************************************************************************/
+// UINT8 spp_data[10] = {1,2,3,4,5,6,7,8,9,0};
+
+tBTA_JV_STATUS BTA_JvRfcommWrite(UINT32 handle, UINT32 req_id, int len, UINT8 *p_data)
+{
+    tBTA_JV_STATUS status = BTA_JV_FAILURE;
+    tBTA_JV_API_RFCOMM_WRITE *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_JvRfcommWrite");
+    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_WRITE *)osi_malloc(sizeof(tBTA_JV_API_RFCOMM_WRITE))) != NULL) {
+        p_msg->hdr.event = BTA_JV_API_RFCOMM_WRITE_EVT;
+        p_msg->handle = handle;
+        p_msg->req_id = req_id;
+        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_data = p_data;
+        p_msg->len = len;
+        APPL_TRACE_API( "write ok");
+        bta_sys_sendmsg(p_msg);
+        status = BTA_JV_SUCCESS;
+    }
+
+    return (status);
+}
+
+
+/*******************************************************************************
+ **
+ ** Function    BTA_JVSetPmProfile
+ **
+ ** Description This function set or free power mode profile for different JV application
+ **
+ ** Parameters:  handle,  JV handle from RFCOMM or L2CAP
+ **              app_id:  app specific pm ID, can be BTA_JV_PM_ALL, see bta_dm_cfg.c for details
+ **              BTA_JV_PM_ID_CLEAR: removes pm management on the handle. init_st is ignored and
+ **              BTA_JV_CONN_CLOSE is called implicitely
+ **              init_st:  state after calling this API. typically it should be BTA_JV_CONN_OPEN
+ **
+ ** Returns      BTA_JV_SUCCESS, if the request is being processed.
+ **              BTA_JV_FAILURE, otherwise.
+ **
+ ** NOTE:        BTA_JV_PM_ID_CLEAR: In general no need to be called as jv pm calls automatically
+ **              BTA_JV_CONN_CLOSE to remove in case of connection close!
+ **
+ *******************************************************************************/
+tBTA_JV_STATUS BTA_JvSetPmProfile(UINT32 handle, tBTA_JV_PM_ID app_id, tBTA_JV_CONN_STATE init_st)
+{
+    tBTA_JV_STATUS status = BTA_JV_FAILURE;
+    tBTA_JV_API_SET_PM_PROFILE *p_msg;
+
+    APPL_TRACE_API("BTA_JVSetPmProfile handle:0x%x, app_id:%d", handle, app_id);
+    if ((p_msg = (tBTA_JV_API_SET_PM_PROFILE *)osi_malloc(sizeof(tBTA_JV_API_SET_PM_PROFILE)))
+            != NULL) {
+        p_msg->hdr.event = BTA_JV_API_SET_PM_PROFILE_EVT;
+        p_msg->handle = handle;
+        p_msg->app_id = app_id;
+        p_msg->init_st = init_st;
+        bta_sys_sendmsg(p_msg);
+        status = BTA_JV_SUCCESS;
+    }
+
+    return (status);
+}
+
+#endif  ///defined BTA_JV_INCLUDED && BTA_JV_INCLUDED == TRUE
diff --git a/components/bt/bluedroid/bta/jv/bta_jv_cfg.c b/components/bt/bluedroid/bta/jv/bta_jv_cfg.c
new file mode 100644 (file)
index 0000000..e88aa8c
--- /dev/null
@@ -0,0 +1,60 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2014 The Android Open Source Project
+ *  Copyright (C) 2004-2012 Broadcom Corporation
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *  This file contains compile-time configurable constants for advanced
+ *  audio
+ *
+ ******************************************************************************/
+
+#include "allocator.h"
+#include "bta_api.h"
+#include "bta_jv_api.h"
+#include "bt_target.h"
+
+#if (defined BTA_JV_INCLUDED && BTA_JV_INCLUDED == TRUE)
+#ifndef BTA_JV_SDP_DB_SIZE
+#define BTA_JV_SDP_DB_SIZE          4500
+#endif
+
+#ifndef BTA_JV_SDP_RAW_DATA_SIZE
+#define BTA_JV_SDP_RAW_DATA_SIZE    1800
+#endif
+
+/* The platform may choose to use dynamic memory for these data buffers.
+ * p_bta_jv_cfg->p_sdp_db must be allocated/stay allocated
+ * between BTA_JvEnable and BTA_JvDisable
+ * p_bta_jv_cfg->p_sdp_raw_data can be allocated before calling BTA_JvStartDiscovery
+ * it can be de-allocated after the last call to access the database */
+static UINT8 bta_jv_sdp_raw_data[BTA_JV_SDP_RAW_DATA_SIZE];
+static UINT8 __attribute__ ((aligned(4))) bta_jv_sdp_db_data[BTA_JV_SDP_DB_SIZE];
+
+/* JV configuration structure */
+const tBTA_JV_CFG bta_jv_cfg = {
+    BTA_JV_SDP_RAW_DATA_SIZE,   /* The size of p_sdp_raw_data */
+    BTA_JV_SDP_DB_SIZE,         /* The size of p_sdp_db_data */
+    bta_jv_sdp_raw_data,        /* The data buffer to keep raw data */
+    (tSDP_DISCOVERY_DB *)bta_jv_sdp_db_data /* The data buffer to keep SDP database */
+};
+
+tBTA_JV_CFG *p_bta_jv_cfg = (tBTA_JV_CFG *) &bta_jv_cfg;
+
+
+#endif  ///defined BTA_JV_INCLUDED && BTA_JV_INCLUDED == TRUE
\ No newline at end of file
diff --git a/components/bt/bluedroid/bta/jv/bta_jv_int.h b/components/bt/bluedroid/bta/jv/bta_jv_int.h
new file mode 100644 (file)
index 0000000..2ef9ace
--- /dev/null
@@ -0,0 +1,429 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2006-2012 Broadcom Corporation
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *  This is the private interface file for the BTA Java I/F
+ *
+ ******************************************************************************/
+#ifndef BTA_JV_INT_H
+#define BTA_JV_INT_H
+
+#include "bta_sys.h"
+#include "bta_api.h"
+#include "bta_jv_api.h"
+#include "rfcdefs.h"
+#include "port_api.h"
+#include "sdp_api.h"
+
+#include "bt_target.h"
+#if (defined BTA_JV_INCLUDED && BTA_JV_INCLUDED == TRUE)
+/*****************************************************************************
+**  Constants
+*****************************************************************************/
+
+enum {
+    /* these events are handled by the state machine */
+    BTA_JV_API_ENABLE_EVT = BTA_SYS_EVT_START(BTA_ID_JV),
+    BTA_JV_API_DISABLE_EVT,
+    BTA_JV_API_GET_CHANNEL_EVT,
+    BTA_JV_API_FREE_SCN_EVT,
+    BTA_JV_API_START_DISCOVERY_EVT,
+    BTA_JV_API_CREATE_RECORD_EVT,
+    BTA_JV_API_DELETE_RECORD_EVT,
+    BTA_JV_API_L2CAP_CONNECT_EVT,
+    BTA_JV_API_L2CAP_CLOSE_EVT,
+    BTA_JV_API_L2CAP_START_SERVER_EVT,
+    BTA_JV_API_L2CAP_STOP_SERVER_EVT,
+    BTA_JV_API_L2CAP_READ_EVT,
+    BTA_JV_API_L2CAP_WRITE_EVT,
+    BTA_JV_API_RFCOMM_CONNECT_EVT,
+    BTA_JV_API_RFCOMM_CLOSE_EVT,
+    BTA_JV_API_RFCOMM_START_SERVER_EVT,
+    BTA_JV_API_RFCOMM_STOP_SERVER_EVT,
+    BTA_JV_API_RFCOMM_READ_EVT,
+    BTA_JV_API_RFCOMM_WRITE_EVT,
+    BTA_JV_API_SET_PM_PROFILE_EVT,
+    BTA_JV_API_PM_STATE_CHANGE_EVT,
+    BTA_JV_API_L2CAP_CONNECT_LE_EVT,
+    BTA_JV_API_L2CAP_START_SERVER_LE_EVT,
+    BTA_JV_API_L2CAP_STOP_SERVER_LE_EVT,
+    BTA_JV_API_L2CAP_WRITE_FIXED_EVT,
+    BTA_JV_API_L2CAP_CLOSE_FIXED_EVT,
+    BTA_JV_MAX_INT_EVT
+};
+
+#ifndef BTA_JV_RFC_EV_MASK
+#define BTA_JV_RFC_EV_MASK (PORT_EV_RXCHAR | PORT_EV_TXEMPTY | PORT_EV_FC | PORT_EV_FCS)
+#endif
+
+/* data type for BTA_JV_API_ENABLE_EVT */
+typedef struct {
+    BT_HDR          hdr;
+    tBTA_JV_DM_CBACK   *p_cback;
+} tBTA_JV_API_ENABLE;
+
+/* data type for BTA_JV_API_START_DISCOVERY_EVT */
+typedef struct {
+    BT_HDR      hdr;
+    BD_ADDR bd_addr;
+    UINT16 num_uuid;
+    tSDP_UUID uuid_list[BTA_JV_MAX_UUIDS];
+    UINT16 num_attr;
+    UINT16 attr_list[BTA_JV_MAX_ATTRS];
+    void            *user_data;      /* piggyback caller's private data*/
+} tBTA_JV_API_START_DISCOVERY;
+
+enum {
+    BTA_JV_PM_FREE_ST = 0, /* empty PM slot */
+    BTA_JV_PM_IDLE_ST,
+    BTA_JV_PM_BUSY_ST
+};
+
+/* BTA JV PM control block */
+typedef struct {
+    UINT32          handle;     /* The connection handle */
+    UINT8           state;      /* state: see above enum */
+    tBTA_JV_PM_ID   app_id;     /* JV app specific id indicating power table to use */
+    BD_ADDR         peer_bd_addr;    /* Peer BD address */
+} tBTA_JV_PM_CB;
+
+enum {
+    BTA_JV_ST_NONE = 0,
+    BTA_JV_ST_CL_OPENING,
+    BTA_JV_ST_CL_OPEN,
+    BTA_JV_ST_CL_CLOSING,
+    BTA_JV_ST_SR_LISTEN,
+    BTA_JV_ST_SR_OPEN,
+    BTA_JV_ST_SR_CLOSING
+} ;
+typedef UINT8  tBTA_JV_STATE;
+#define BTA_JV_ST_CL_MAX    BTA_JV_ST_CL_CLOSING
+/* JV L2CAP control block */
+typedef struct {
+    tBTA_JV_L2CAP_CBACK *p_cback;   /* the callback function */
+    UINT16              psm;        /* the psm used for this server connection */
+    tBTA_JV_STATE       state;      /* the state of this control block */
+    tBTA_SERVICE_ID     sec_id;     /* service id */
+    UINT32              handle;     /* the handle reported to java app (same as gap handle) */
+    BOOLEAN             cong;       /* TRUE, if congested */
+    tBTA_JV_PM_CB      *p_pm_cb;    /* ptr to pm control block, NULL: unused */
+    void                *user_data; /* user data for callback from higher layers */
+} tBTA_JV_L2C_CB;
+
+#define BTA_JV_RFC_HDL_MASK         0xFF
+#define BTA_JV_RFCOMM_MASK          0x80
+#define BTA_JV_ALL_APP_ID           0xFF
+#define BTA_JV_RFC_HDL_TO_SIDX(r)   (((r)&0xFF00) >> 8)
+#define BTA_JV_RFC_H_S_TO_HDL(h, s) ((h)|(s<<8))
+
+/* port control block */
+typedef struct {
+    UINT32              handle;     /* the rfcomm session handle at jv */
+    UINT16              port_handle;/* port handle */
+    tBTA_JV_STATE       state;      /* the state of this control block */
+    UINT8               max_sess;   /* max sessions */
+    void                *user_data; /* piggyback caller's private data*/
+    BOOLEAN             cong;       /* TRUE, if congested */
+    tBTA_JV_PM_CB       *p_pm_cb;   /* ptr to pm control block, NULL: unused */
+} tBTA_JV_PCB;
+
+/* JV RFCOMM control block */
+typedef struct {
+    tBTA_JV_RFCOMM_CBACK *p_cback;  /* the callback function */
+    UINT16              rfc_hdl[BTA_JV_MAX_RFC_SR_SESSION];
+    tBTA_SERVICE_ID     sec_id;     /* service id */
+    UINT8               handle;     /* index: the handle reported to java app */
+    UINT8               scn;        /* the scn of the server */
+    UINT8               max_sess;   /* max sessions */
+    int                 curr_sess;   /* current sessions count*/
+} tBTA_JV_RFC_CB;
+
+/* data type for BTA_JV_API_L2CAP_CONNECT_EVT & BTA_JV_API_L2CAP_CONNECT_LE_EVT */
+typedef struct {
+    BT_HDR              hdr;
+    tBTA_SEC            sec_mask;
+    tBTA_JV_ROLE        role;
+    union {
+        UINT16          remote_psm;
+        UINT16          remote_chan;
+    };
+    UINT16              rx_mtu;
+    BD_ADDR             peer_bd_addr;
+    INT32               has_cfg;
+    tL2CAP_CFG_INFO     cfg;
+    INT32               has_ertm_info;
+    tL2CAP_ERTM_INFO    ertm_info;
+    tBTA_JV_L2CAP_CBACK *p_cback;
+    void                *user_data;
+} tBTA_JV_API_L2CAP_CONNECT;
+
+/* data type for BTA_JV_API_L2CAP_SERVER_EVT */
+typedef struct {
+    BT_HDR              hdr;
+    tBTA_SEC            sec_mask;
+    tBTA_JV_ROLE        role;
+    union {
+        UINT16          local_psm;
+        UINT16          local_chan;
+    };
+    UINT16              rx_mtu;
+    INT32               has_cfg;
+    tL2CAP_CFG_INFO     cfg;
+    INT32               has_ertm_info;
+    tL2CAP_ERTM_INFO    ertm_info;
+    tBTA_JV_L2CAP_CBACK *p_cback;
+    void                *user_data;
+} tBTA_JV_API_L2CAP_SERVER;
+
+/* data type for BTA_JV_API_L2CAP_CLOSE_EVT */
+typedef struct {
+    BT_HDR          hdr;
+    UINT32          handle;
+    tBTA_JV_L2C_CB  *p_cb;
+} tBTA_JV_API_L2CAP_CLOSE;
+
+/* data type for BTA_JV_API_L2CAP_READ_EVT */
+typedef struct {
+    BT_HDR              hdr;
+    UINT32              handle;
+    UINT32              req_id;
+    tBTA_JV_L2CAP_CBACK *p_cback;
+    UINT8              *p_data;
+    UINT16              len;
+    void                *user_data;
+} tBTA_JV_API_L2CAP_READ;
+
+/* data type for BTA_JV_API_L2CAP_WRITE_EVT */
+typedef struct {
+    BT_HDR              hdr;
+    UINT32              handle;
+    UINT32              req_id;
+    tBTA_JV_L2C_CB      *p_cb;
+    UINT8               *p_data;
+    UINT16              len;
+    void                *user_data;
+} tBTA_JV_API_L2CAP_WRITE;
+
+/* data type for BTA_JV_API_L2CAP_WRITE_FIXED_EVT */
+typedef struct {
+    BT_HDR              hdr;
+    UINT16              channel;
+    BD_ADDR             addr;
+    UINT32              req_id;
+    tBTA_JV_L2CAP_CBACK *p_cback;
+    UINT8               *p_data;
+    UINT16              len;
+    void                *user_data;
+} tBTA_JV_API_L2CAP_WRITE_FIXED;
+
+/* data type for BTA_JV_API_RFCOMM_CONNECT_EVT */
+typedef struct {
+    BT_HDR          hdr;
+    tBTA_SEC        sec_mask;
+    tBTA_JV_ROLE    role;
+    UINT8           remote_scn;
+    BD_ADDR         peer_bd_addr;
+    tBTA_JV_RFCOMM_CBACK *p_cback;
+    void            *user_data;
+} tBTA_JV_API_RFCOMM_CONNECT;
+
+/* data type for BTA_JV_API_RFCOMM_SERVER_EVT */
+typedef struct {
+    BT_HDR          hdr;
+    tBTA_SEC        sec_mask;
+    tBTA_JV_ROLE    role;
+    UINT8           local_scn;
+    UINT8           max_session;
+    UINT32          handle;
+    tBTA_JV_RFCOMM_CBACK *p_cback;
+    void            *user_data;
+} tBTA_JV_API_RFCOMM_SERVER;
+
+/* data type for BTA_JV_API_RFCOMM_READ_EVT */
+typedef struct {
+    BT_HDR          hdr;
+    UINT32          handle;
+    UINT32          req_id;
+    UINT8           *p_data;
+    UINT16          len;
+    tBTA_JV_RFC_CB  *p_cb;
+    tBTA_JV_PCB     *p_pcb;
+} tBTA_JV_API_RFCOMM_READ;
+
+/* data type for BTA_JV_API_SET_PM_PROFILE_EVT */
+typedef struct {
+    BT_HDR              hdr;
+    UINT32              handle;
+    tBTA_JV_PM_ID       app_id;
+    tBTA_JV_CONN_STATE  init_st;
+} tBTA_JV_API_SET_PM_PROFILE;
+
+/* data type for BTA_JV_API_PM_STATE_CHANGE_EVT */
+typedef struct {
+    BT_HDR              hdr;
+    tBTA_JV_PM_CB       *p_cb;
+    tBTA_JV_CONN_STATE  state;
+} tBTA_JV_API_PM_STATE_CHANGE;
+
+/* data type for BTA_JV_API_RFCOMM_WRITE_EVT */
+typedef struct {
+    BT_HDR          hdr;
+    UINT32          handle;
+    UINT32          req_id;
+    UINT8           *p_data;
+    int             len;
+    tBTA_JV_RFC_CB  *p_cb;
+    tBTA_JV_PCB     *p_pcb;
+} tBTA_JV_API_RFCOMM_WRITE;
+
+/* data type for BTA_JV_API_RFCOMM_CLOSE_EVT */
+typedef struct {
+    BT_HDR          hdr;
+    UINT32          handle;
+    tBTA_JV_RFC_CB  *p_cb;
+    tBTA_JV_PCB     *p_pcb;
+    void            *user_data;
+} tBTA_JV_API_RFCOMM_CLOSE;
+
+/* data type for BTA_JV_API_CREATE_RECORD_EVT */
+typedef struct {
+    BT_HDR      hdr;
+#define ESP_SDP_SERVER_NAME_MAX (32)
+    char name[ESP_SDP_SERVER_NAME_MAX + 1];
+    INT32       channel;
+    void        *user_data;
+} tBTA_JV_API_CREATE_RECORD;
+
+/* data type for BTA_JV_API_ADD_ATTRIBUTE_EVT */
+typedef struct {
+    BT_HDR      hdr;
+    UINT32      handle;
+    UINT16      attr_id;
+    UINT8       *p_value;
+    INT32       value_size;
+} tBTA_JV_API_ADD_ATTRIBUTE;
+
+/* data type for BTA_JV_API_FREE_SCN_EVT */
+typedef struct {
+    BT_HDR      hdr;
+    INT32       type;       /* One of BTA_JV_CONN_TYPE_ */
+    UINT16      scn;
+} tBTA_JV_API_FREE_CHANNEL;
+
+/* data type for BTA_JV_API_ALLOC_CHANNEL_EVT */
+typedef struct {
+    BT_HDR      hdr;
+    INT32       type;       /* One of BTA_JV_CONN_TYPE_ */
+    INT32       channel;    /* optionally request a specific channel */
+    void        *user_data;
+} tBTA_JV_API_ALLOC_CHANNEL;
+/* union of all data types */
+typedef union {
+    /* GKI event buffer header */
+    BT_HDR                          hdr;
+    tBTA_JV_API_ENABLE              enable;
+    tBTA_JV_API_START_DISCOVERY     start_discovery;
+    tBTA_JV_API_ALLOC_CHANNEL       alloc_channel;
+    tBTA_JV_API_FREE_CHANNEL        free_channel;
+    tBTA_JV_API_CREATE_RECORD       create_record;
+    tBTA_JV_API_ADD_ATTRIBUTE       add_attr;
+    tBTA_JV_API_L2CAP_CONNECT       l2cap_connect;
+    tBTA_JV_API_L2CAP_READ          l2cap_read;
+    tBTA_JV_API_L2CAP_WRITE         l2cap_write;
+    tBTA_JV_API_L2CAP_CLOSE         l2cap_close;
+    tBTA_JV_API_L2CAP_SERVER        l2cap_server;
+    tBTA_JV_API_RFCOMM_CONNECT      rfcomm_connect;
+    tBTA_JV_API_RFCOMM_READ         rfcomm_read;
+    tBTA_JV_API_RFCOMM_WRITE        rfcomm_write;
+    tBTA_JV_API_SET_PM_PROFILE      set_pm;
+    tBTA_JV_API_PM_STATE_CHANGE     change_pm_state;
+    tBTA_JV_API_RFCOMM_CLOSE        rfcomm_close;
+    tBTA_JV_API_RFCOMM_SERVER       rfcomm_server;
+    tBTA_JV_API_L2CAP_WRITE_FIXED   l2cap_write_fixed;
+} tBTA_JV_MSG;
+
+/* JV control block */
+typedef struct {
+    /* the SDP handle reported to JV user is the (index + 1) to sdp_handle[].
+     * if sdp_handle[i]==0, it's not used.
+     * otherwise sdp_handle[i] is the stack SDP handle. */
+    UINT32                  sdp_handle[BTA_JV_MAX_SDP_REC]; /* SDP records created */
+    UINT8                   *p_sel_raw_data;/* the raw data of last service select */
+    tBTA_JV_DM_CBACK        *p_dm_cback;
+    tBTA_JV_L2C_CB          l2c_cb[BTA_JV_MAX_L2C_CONN];    /* index is GAP handle (index) */
+    tBTA_JV_RFC_CB          rfc_cb[BTA_JV_MAX_RFC_CONN];
+    tBTA_JV_PCB             port_cb[MAX_RFC_PORTS];         /* index of this array is
+                                                               the port_handle, */
+    UINT8                   sec_id[BTA_JV_NUM_SERVICE_ID];  /* service ID */
+    BOOLEAN                 scn[BTA_JV_MAX_SCN];            /* SCN allocated by java */
+    UINT16                  free_psm_list[BTA_JV_MAX_L2C_CONN];  /* PSMs freed by java
+                                                                    (can be reused) */
+    UINT8                   sdp_active;                     /* see BTA_JV_SDP_ACT_* */
+    tSDP_UUID               uuid;                           /* current uuid of sdp discovery*/
+    tBTA_JV_PM_CB           pm_cb[BTA_JV_PM_MAX_NUM];       /* PM on a per JV handle bases */
+} tBTA_JV_CB;
+
+enum {
+    BTA_JV_SDP_ACT_NONE = 0,
+    BTA_JV_SDP_ACT_YES,     /* waiting for SDP result */
+    BTA_JV_SDP_ACT_CANCEL   /* waiting for cancel complete */
+};
+
+/* JV control block */
+#if BTA_DYNAMIC_MEMORY == FALSE
+extern tBTA_JV_CB bta_jv_cb;
+#else
+extern tBTA_JV_CB *bta_jv_cb_ptr;
+#define bta_jv_cb (*bta_jv_cb_ptr)
+#endif
+
+/* config struct */
+extern tBTA_JV_CFG *p_bta_jv_cfg;
+
+extern BOOLEAN bta_jv_sm_execute(BT_HDR *p_msg);
+
+extern void bta_jv_enable (tBTA_JV_MSG *p_data);
+extern void bta_jv_disable (tBTA_JV_MSG *p_data);
+extern void bta_jv_get_channel_id (tBTA_JV_MSG *p_data);
+extern void bta_jv_free_scn (tBTA_JV_MSG *p_data);
+extern void bta_jv_start_discovery (tBTA_JV_MSG *p_data);
+extern void bta_jv_create_record (tBTA_JV_MSG *p_data);
+extern void bta_jv_delete_record (tBTA_JV_MSG *p_data);
+extern void bta_jv_l2cap_connect (tBTA_JV_MSG *p_data);
+extern void bta_jv_l2cap_close (tBTA_JV_MSG *p_data);
+extern void bta_jv_l2cap_start_server (tBTA_JV_MSG *p_data);
+extern void bta_jv_l2cap_stop_server (tBTA_JV_MSG *p_data);
+extern void bta_jv_l2cap_read (tBTA_JV_MSG *p_data);
+extern void bta_jv_l2cap_write (tBTA_JV_MSG *p_data);
+extern void bta_jv_rfcomm_connect (tBTA_JV_MSG *p_data);
+extern void bta_jv_rfcomm_close (tBTA_JV_MSG *p_data);
+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_set_pm_profile (tBTA_JV_MSG *p_data);
+extern void bta_jv_change_pm_state(tBTA_JV_MSG *p_data);
+extern void bta_jv_l2cap_connect_le (tBTA_JV_MSG *p_data);
+extern void bta_jv_l2cap_start_server_le (tBTA_JV_MSG *p_data);
+extern void bta_jv_l2cap_stop_server_le (tBTA_JV_MSG *p_data);
+extern void bta_jv_l2cap_write_fixed (tBTA_JV_MSG *p_data);
+extern void bta_jv_l2cap_close_fixed (tBTA_JV_MSG *p_data);
+
+#endif  ///defined BTA_JV_INCLUDED && BTA_JV_INCLUDED == TRUE
+#endif /* BTA_JV_INT_H */
diff --git a/components/bt/bluedroid/bta/jv/bta_jv_main.c b/components/bt/bluedroid/bta/jv/bta_jv_main.c
new file mode 100644 (file)
index 0000000..9cce6e0
--- /dev/null
@@ -0,0 +1,100 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2012 Broadcom Corporation
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *  This is the main implementation file for the BTA Java I/F
+ *
+ ******************************************************************************/
+
+#include "bta_api.h"
+#include "bta_sys.h"
+#include "bta_jv_api.h"
+#include "bta_jv_int.h"
+#include "bt_target.h"
+
+#if (defined BTA_JV_INCLUDED && BTA_JV_INCLUDED == TRUE)
+/*****************************************************************************
+** Constants and types
+*****************************************************************************/
+
+#if BTA_DYNAMIC_MEMORY == FALSE
+tBTA_JV_CB bta_jv_cb;
+#endif
+
+/* state machine action enumeration list */
+#define BTA_JV_NUM_ACTIONS  (BTA_JV_MAX_INT_EVT & 0x00ff)
+
+/* type for action functions */
+typedef void (*tBTA_JV_ACTION)(tBTA_JV_MSG *p_data);
+
+/* action function list */
+const tBTA_JV_ACTION bta_jv_action[] = {
+    bta_jv_enable,                  /* BTA_JV_API_ENABLE_EVT */
+    bta_jv_disable,                 /* BTA_JV_API_DISABLE_EVT */
+    bta_jv_get_channel_id,          /* BTA_JV_API_GET_CHANNEL_EVT */
+    bta_jv_free_scn,                /* BTA_JV_API_FREE_SCN_EVT */
+    bta_jv_start_discovery,         /* BTA_JV_API_START_DISCOVERY_EVT */
+    bta_jv_create_record,           /* BTA_JV_API_CREATE_RECORD_EVT */
+    bta_jv_delete_record,           /* BTA_JV_API_DELETE_RECORD_EVT */
+    bta_jv_l2cap_connect,           /* BTA_JV_API_L2CAP_CONNECT_EVT */
+    bta_jv_l2cap_close,             /* BTA_JV_API_L2CAP_CLOSE_EVT */
+    bta_jv_l2cap_start_server,      /* BTA_JV_API_L2CAP_START_SERVER_EVT */
+    bta_jv_l2cap_stop_server,       /* BTA_JV_API_L2CAP_STOP_SERVER_EVT */
+    bta_jv_l2cap_read,              /* BTA_JV_API_L2CAP_READ_EVT */
+    bta_jv_l2cap_write,             /* BTA_JV_API_L2CAP_WRITE_EVT */
+    bta_jv_rfcomm_connect,          /* BTA_JV_API_RFCOMM_CONNECT_EVT */
+    bta_jv_rfcomm_close,            /* BTA_JV_API_RFCOMM_CLOSE_EVT */
+    bta_jv_rfcomm_start_server,     /* BTA_JV_API_RFCOMM_START_SERVER_EVT */
+    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_set_pm_profile,          /* BTA_JV_API_SET_PM_PROFILE_EVT */
+    bta_jv_change_pm_state,         /* BTA_JV_API_PM_STATE_CHANGE_EVT */
+    bta_jv_l2cap_connect_le,        /* BTA_JV_API_L2CAP_CONNECT_LE_EVT */
+    bta_jv_l2cap_start_server_le,   /* BTA_JV_API_L2CAP_START_SERVER_LE_EVT */
+    bta_jv_l2cap_stop_server_le,    /* BTA_JV_API_L2CAP_STOP_SERVER_LE_EVT */
+    bta_jv_l2cap_write_fixed,       /* BTA_JV_API_L2CAP_WRITE_FIXED_EVT */
+    bta_jv_l2cap_close_fixed,       /*  BTA_JV_API_L2CAP_CLOSE_FIXED_EVT */
+};
+
+/*******************************************************************************
+**
+** Function         bta_jv_sm_execute
+**
+** Description      State machine event handling function for JV
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+BOOLEAN bta_jv_sm_execute(BT_HDR *p_msg)
+{
+    BOOLEAN ret = FALSE;
+    UINT16 action = (p_msg->event & 0x00ff);
+    /* execute action functions */
+
+    if (action < BTA_JV_NUM_ACTIONS) {
+        (*bta_jv_action[action])((tBTA_JV_MSG *)p_msg);
+        ret = TRUE;
+    }
+
+    return (ret);
+}
+
+#endif  ///defined BTA_JV_INCLUDED && BTA_JV_INCLUDED == TRUE
\ No newline at end of file
index bcc313ca21804501a2bbf1c37a10b8256fa624cc..0d039c63001afa84fc32f72135d177fc6f8a2806 100644 (file)
 #include "btc_gap_bt.h"
 #endif /* BTC_GAP_BT_INCLUDED == TRUE */
 #include "btc_profile_queue.h"
+#if BTC_AV_INCLUDED
 #include "btc_av.h"
 #include "btc_avrc.h"
+#endif  /* #if BTC_AV_INCLUDED */
+#if CONFIG_BT_SPP_ENABLED
+#include "btc_spp.h"
+#endif /* #if CONFIG_BT_SPP_ENABLED */
 #endif /* #if CONFIG_CLASSIC_BT_ENABLED */
 
 
@@ -64,8 +69,13 @@ static btc_func_t profile_tab[BTC_PID_NUM] = {
     [BTC_PID_GAP_BT]    = {btc_gap_bt_call_handler,     NULL                    },
 #endif /* (BTC_GAP_BT_INCLUDED == TRUE) */
     [BTC_PID_PRF_QUE]   = {btc_profile_queue_handler,   NULL                    },
+#if BTC_AV_INCLUDED
     [BTC_PID_A2DP]      = {btc_a2dp_call_handler,       btc_a2dp_cb_handler     },
     [BTC_PID_AVRC]      = {btc_avrc_call_handler,       NULL                    },
+#endif /* #if BTC_AV_INCLUDED */
+#if CONFIG_BT_SPP_ENABLED
+    [BTC_PID_SPP]       = {btc_spp_call_handler,        btc_spp_cb_handler      },
+#endif /* #if CONFIG_BT_SPP_ENABLED */
 #endif /* #if CONFIG_CLASSIC_BT_ENABLED */
 };
 
index 5dd56c57a3ab43f3ec0c3de9df53369af083025d..3668e4e9f4e8b491d8cc0bd3503c1a57d9ab8892 100644 (file)
@@ -160,3 +160,22 @@ void uuid128_be_to_esp_uuid(esp_bt_uuid_t *u, uint8_t* uuid128)
 
     return;
 }
+
+void uuid_to_string_legacy(bt_uuid_t *p_uuid, char *str)
+{
+    uint32_t uuid0, uuid4;
+    uint16_t uuid1, uuid2, uuid3, uuid5;
+
+    memcpy(&uuid0, &(p_uuid->uu[0]), 4);
+    memcpy(&uuid1, &(p_uuid->uu[4]), 2);
+    memcpy(&uuid2, &(p_uuid->uu[6]), 2);
+    memcpy(&uuid3, &(p_uuid->uu[8]), 2);
+    memcpy(&uuid4, &(p_uuid->uu[10]), 4);
+    memcpy(&uuid5, &(p_uuid->uu[14]), 2);
+
+    sprintf((char *)str, "%.8x-%.4x-%.4x-%.4x-%.8x%.4x",
+            ntohl(uuid0), ntohs(uuid1),
+            ntohs(uuid2), ntohs(uuid3),
+            ntohl(uuid4), ntohs(uuid5));
+    return;
+}
index c91aaad547f61e88a2018f7df8f12ae3abb07ba3..f19c266991a7932a5dc59dc8c1b13f51a6b442c0 100644 (file)
@@ -52,6 +52,7 @@ typedef enum {
     BTC_PID_PRF_QUE,
     BTC_PID_A2DP,
     BTC_PID_AVRC,
+    BTC_PID_SPP,
 #endif  /* CONFIG_CLASSIC_BT_ENABLED */
     BTC_PID_NUM,
 } btc_pid_t; //btc profile id
index ddc27b67736dbfddaf26f3f78d972877b40b8b9c..d2bfdcca8771b19ef0a60d4f3da37673e5de799d 100644 (file)
@@ -42,4 +42,6 @@ UINT32 devclass2uint(DEV_CLASS dev_class);
 void uint2devclass(UINT32 dev, DEV_CLASS dev_class);
 void uuid128_be_to_esp_uuid(esp_bt_uuid_t *u, uint8_t* uuid128);
 
+void uuid_to_string_legacy(bt_uuid_t *p_uuid, char *str);
+
 #endif /*  __BTC_UTIL_H__ */
diff --git a/components/bt/bluedroid/btc/profile/std/include/btc_spp.h b/components/bt/bluedroid/btc/profile/std/include/btc_spp.h
new file mode 100644 (file)
index 0000000..631c696
--- /dev/null
@@ -0,0 +1,89 @@
+// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef __BTC_SPP_H__
+#define __BTC_SPP_H__
+
+#include "btc_task.h"
+#include "esp_bt_defs.h"
+#include "esp_spp_api.h"
+#include "bt_target.h"
+#include "bta_jv_api.h"
+
+#if (defined BTC_SPP_INCLUDED && BTC_SPP_INCLUDED == TRUE)
+
+#define ESP_SPP_MAX_SESSION     BTA_JV_MAX_RFC_SR_SESSION
+#define ESP_SPP_SERVER_NAME_MAX 32
+
+typedef enum {
+    BTC_SPP_ACT_INIT = 0,
+    BTC_SPP_ACT_UNINIT,
+    BTC_SPP_ACT_START_DISCOVERY,
+    BTC_SPP_ACT_CONNECT,
+    BTC_SPP_ACT_DISCONNECT,
+    BTC_SPP_ACT_START_SRV,
+    BTC_SPP_ACT_WRITE,
+} btc_spp_act_t;
+
+/* btc_spp_args_t */
+typedef union {
+    //BTC_SPP_ACT_INIT
+    struct init_arg {
+    } init;
+    //BTC_SPP_ACT_UNINIT
+    struct uninit_arg {
+    } uninit;
+
+    //BTC_SPP_ACT_START_DISCOVERY
+    struct start_discovery_arg {
+        BD_ADDR bd_addr;
+        UINT16 num_uuid;
+        tSDP_UUID *p_uuid_list;
+    } start_discovery;
+    //BTC_SPP_ACT_CONNECT
+    struct connect_arg {
+        esp_spp_sec_t sec_mask;
+        esp_spp_role_t role;
+        UINT8 remote_scn;
+        esp_bd_addr_t peer_bd_addr;
+    } connect;
+    //BTC_SPP_ACT_DISCONNECT
+    struct disconnect_arg {
+        UINT32 handle;
+    } disconnect;
+    //BTC_SPP_ACT_START_SRV
+    struct start_srv_arg {
+        esp_spp_sec_t sec_mask;
+        esp_spp_role_t role;
+        UINT8 local_scn;
+        UINT8 max_session;
+        char name[ESP_SPP_SERVER_NAME_MAX + 1];
+    } start_srv;
+    //BTC_SPP_ACT_WRITE
+    struct write_arg {
+        UINT32 handle;
+        int len;
+        UINT8 *p_data;
+    } write;
+
+} btc_spp_args_t;
+
+
+void btc_spp_call_handler(btc_msg_t *msg);
+void btc_spp_cb_handler(btc_msg_t *msg);
+void btc_spp_arg_deep_copy(btc_msg_t *msg, void *p_dest, void *p_src);
+
+
+#endif ///defined BTC_SPP_INCLUDED && BTC_SPP_INCLUDED == TRUE
+#endif ///__BTC_SPP_H__
\ No newline at end of file
diff --git a/components/bt/bluedroid/btc/profile/std/spp/btc_spp.c b/components/bt/bluedroid/btc/profile/std/spp/btc_spp.c
new file mode 100644 (file)
index 0000000..f3b0246
--- /dev/null
@@ -0,0 +1,544 @@
+// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <string.h>
+
+#include "btc_spp.h"
+#include "btc_manage.h"
+#include "btc_task.h"
+#include "bta_jv_api.h"
+#include "bt_trace.h"
+#include "allocator.h"
+#include "esp_spp_api.h"
+#include "list.h"
+
+#if (defined BTC_SPP_INCLUDED && BTC_SPP_INCLUDED == TRUE)
+
+typedef struct {
+    uint8_t serial;
+    bool connected;
+    uint8_t scn;
+    uint8_t max_session;
+    uint32_t id;
+    uint32_t mtu;//unused
+    uint32_t sdp_handle;
+    uint32_t rfc_handle;
+    uint32_t rfc_port_handle;
+    esp_spp_role_t role;
+    esp_spp_sec_t security;
+    esp_bd_addr_t addr;
+    list_t *list;
+    uint8_t service_uuid[16];
+    char service_name[ESP_SPP_SERVER_NAME_MAX];
+} spp_slot_t;
+static spp_slot_t *spp_slots[BTA_JV_MAX_RFC_SR_SESSION + 1];
+static uint32_t spp_slot_id = 0;
+
+static void spp_osi_free(void *p)
+{
+    osi_free(p);
+}
+static spp_slot_t *malloc_spp_slot(void)
+{
+    if (++spp_slot_id == 0) {
+        spp_slot_id = 1;
+    }
+    for (size_t i = 1; i <= BTA_JV_MAX_RFC_SR_SESSION; i++) {
+        if (spp_slots[i] == NULL) {
+            spp_slots[i] = (spp_slot_t *)osi_malloc(sizeof(spp_slot_t));
+            if (!spp_slots[i]) {
+                return NULL;
+            }
+            spp_slots[i]->id = spp_slot_id;
+            spp_slots[i]->serial = i;
+            spp_slots[i]->connected = FALSE;
+            spp_slots[i]->list = list_new(spp_osi_free);
+            return spp_slots[i];
+        }
+    }
+    return NULL;
+}
+static spp_slot_t *find_slot_by_id(uint32_t id)
+{
+    for (size_t i = 1; i <= BTA_JV_MAX_RFC_SR_SESSION; i++) {
+        if (spp_slots[i] != NULL && spp_slots[i]->id == id) {
+            return spp_slots[i];
+        }
+    }
+    return NULL;
+}
+static spp_slot_t *find_slot_by_handle(uint32_t handle)
+{
+    for (size_t i = 1; i <= BTA_JV_MAX_RFC_SR_SESSION; i++) {
+        if (spp_slots[i] != NULL && spp_slots[i]->rfc_handle == handle) {
+            return spp_slots[i];
+        }
+    }
+    return NULL;
+}
+static void free_spp_slot(spp_slot_t *slot)
+{
+    if (!slot) {
+        return;
+    }
+    spp_slots[slot->serial] = NULL;
+    list_free(slot->list);
+    osi_free(slot);
+}
+
+static inline void btc_spp_cb_to_app(esp_spp_cb_event_t event, esp_spp_cb_param_t *param)
+{
+    esp_spp_cb_t *btc_spp_cb = (esp_spp_cb_t *)btc_profile_cb_get(BTC_PID_SPP);
+    if (btc_spp_cb) {
+        btc_spp_cb(event, param);
+    }
+}
+
+static void btc_create_server_fail_cb(void)
+{
+    esp_spp_cb_param_t param;
+    param.start.status = ESP_SPP_FAILURE;
+    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;
+    btc_msg_t msg;
+    void *new_user_data = NULL;
+
+    uint32_t id = (uintptr_t)user_data;
+    spp_slot_t *slot, *slot_new;
+    switch (event) {
+    case BTA_JV_RFCOMM_SRV_OPEN_EVT:
+        slot = find_slot_by_id(id);
+        if (!slot) {
+            LOG_ERROR("%s unable to find RFCOMM slot!", __func__);
+            break;
+        }
+        slot_new = malloc_spp_slot();
+        if (!slot_new) {
+            LOG_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);
+
+        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);
+        break;
+    case BTA_JV_RFCOMM_OPEN_EVT:
+        slot = find_slot_by_id(id);
+        if (!slot) {
+            LOG_ERROR("%s unable to find RFCOMM slot!", __func__);
+            break;
+        }
+        slot->connected = TRUE;
+        slot->rfc_handle = p_data->rfc_open.handle;
+        slot->rfc_port_handle = BTA_JvRfcommGetPortHdl(p_data->rfc_open.handle);
+        break;
+    case BTA_JV_RFCOMM_CLOSE_EVT:
+        slot = find_slot_by_id(id);
+        if (!slot) {
+            LOG_ERROR("%s unable to find RFCOMM slot!", __func__);
+            break;
+        }
+        if (slot->connected) {
+            BTA_JvRfcommClose(slot->rfc_handle, (void *)slot->id);
+        }
+        free_spp_slot(slot);
+        break;
+    case BTA_JV_RFCOMM_DATA_IND_EVT:
+        break;
+    default:
+        break;
+    }
+    msg.sig = BTC_SIG_API_CB;
+    msg.pid = BTC_PID_SPP;
+    msg.act = event;
+
+
+    status = btc_transfer_context(&msg, p_data,
+                                  sizeof(tBTA_JV), NULL);
+
+    if (status != BT_STATUS_SUCCESS) {
+        LOG_ERROR("%s btc_transfer_context failed", __func__);
+    }
+    return new_user_data;
+}
+
+static void btc_spp_dm_inter_cb(tBTA_JV_EVT event, tBTA_JV *p_data, void *user_data)
+{
+    bt_status_t status;
+    btc_msg_t msg;
+
+    uint32_t id = (uintptr_t)user_data;
+    spp_slot_t *slot;
+    switch (event) {
+    case BTA_JV_GET_SCN_EVT:
+        slot = find_slot_by_id(id);
+        if (!slot) {
+            LOG_ERROR("%s unable to find RFCOMM slot!", __func__);
+            break;
+        }
+        if (p_data->scn == 0) {
+            LOG_ERROR("%s unable to get scn, start server fail!", __func__);
+            btc_create_server_fail_cb();
+            free_spp_slot(slot);
+            break;
+        }
+
+        slot->scn = p_data->scn;
+        BTA_JvCreateRecordByUser(slot->service_name, slot->scn, (void *)slot->id);
+        break;
+    case BTA_JV_CREATE_RECORD_EVT:
+        slot = find_slot_by_id(id);
+        if (!slot) {
+            LOG_ERROR("%s unable to find RFCOMM slot!", __func__);
+            break;
+        }
+        if (p_data->create_rec.status == BTA_JV_SUCCESS) {
+            slot->sdp_handle = p_data->create_rec.handle;
+            BTA_JvRfcommStartServer(slot->security, slot->role, slot->scn,
+                                    slot->max_session, (tBTA_JV_RFCOMM_CBACK *)btc_spp_rfcomm_inter_cb, (void *)slot->id);
+        } else {
+            LOG_ERROR("%s unable to create record, start server fail!", __func__);
+            btc_create_server_fail_cb();
+            BTA_JvFreeChannel(slot->scn, BTA_JV_CONN_TYPE_RFCOMM);
+            free_spp_slot(slot);
+        }
+        break;
+    default:
+        msg.sig = BTC_SIG_API_CB;
+        msg.pid = BTC_PID_SPP;
+        msg.act = event;
+
+        status = btc_transfer_context(&msg, p_data, sizeof(tBTA_JV), NULL);
+
+        if (status != BT_STATUS_SUCCESS) {
+            LOG_ERROR("%s btc_transfer_context failed\n", __func__);
+        }
+        break;
+    }
+
+}
+
+static void btc_spp_init(void)
+{
+    BTA_JvEnable((tBTA_JV_DM_CBACK *)btc_spp_dm_inter_cb);
+}
+static void btc_spp_uninit(void)
+{
+    for (size_t i = 1; i <= BTA_JV_MAX_RFC_SR_SESSION; i++) {
+        if (spp_slots[i] != NULL && spp_slots[i]->connected) {
+            BTA_JvRfcommClose(spp_slots[i]->rfc_handle, (void *)spp_slots[i]->id);
+            free_spp_slot(spp_slots[i]);
+            spp_slots[i] = NULL;
+        }
+    }
+    for (size_t i = 1; i <= BTA_JV_MAX_RFC_SR_SESSION; i++) {
+        if (spp_slots[i] != NULL && !(spp_slots[i]->connected)) {
+            BTA_JvDeleteRecord(spp_slots[i]->sdp_handle);
+            BTA_JvFreeChannel(spp_slots[i]->scn, BTA_JV_CONN_TYPE_RFCOMM);
+            free_spp_slot(spp_slots[i]);
+            spp_slots[i] = NULL;
+        }
+    }
+
+    BTA_JvDisable();
+}
+
+static void btc_spp_start_discovery(btc_spp_args_t *arg)
+{
+    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)
+{
+    spp_slot_t *slot = malloc_spp_slot();
+    if (!slot) {
+        LOG_ERROR("%s unable to malloc RFCOMM slot!", __func__);
+        return;
+    }
+    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);
+}
+static void btc_spp_disconnect(btc_spp_args_t *arg)
+{
+    spp_slot_t *slot = find_slot_by_handle(arg->disconnect.handle);
+    if (!slot) {
+        LOG_ERROR("%s unable to find RFCOMM slot! disconnect fail!", __func__);
+        return;
+    }
+    BTA_JvRfcommClose(arg->disconnect.handle, (void *)slot->id);
+    btc_disconnect_cb(slot->rfc_handle);
+    free_spp_slot(slot);
+
+}
+static void btc_spp_start_srv(btc_spp_args_t *arg)
+{
+    spp_slot_t *slot = malloc_spp_slot();
+    if (!slot) {
+        LOG_ERROR("%s unable to malloc RFCOMM slot!", __func__);
+        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);
+
+    BTA_JvGetChannelId(BTA_JV_CONN_TYPE_RFCOMM, (void *)slot->id, arg->start_srv.local_scn);
+}
+
+static void btc_spp_write(btc_spp_args_t *arg)
+{
+    spp_slot_t *slot = find_slot_by_handle(arg->write.handle);
+    if (!slot) {
+        LOG_ERROR("%s unable to find RFCOMM slot! disconnect fail!", __func__);
+        return;
+    }
+    list_append(slot->list, arg->write.p_data);
+    BTA_JvRfcommWrite(arg->write.handle, slot->id, arg->write.len, arg->write.p_data);
+}
+
+
+void btc_spp_arg_deep_copy(btc_msg_t *msg, void *p_dest, void *p_src)
+{
+    btc_spp_args_t *dst = (btc_spp_args_t *) p_dest;
+    btc_spp_args_t *src = (btc_spp_args_t *) p_src;
+
+    switch (msg->act) {
+    case BTC_SPP_ACT_START_DISCOVERY:
+        dst->start_discovery.p_uuid_list = (tSDP_UUID *)osi_malloc(src->start_discovery.num_uuid * sizeof(tSDP_UUID));
+        if (dst->start_discovery.p_uuid_list) {
+            memcpy(dst->start_discovery.p_uuid_list, src->start_discovery.p_uuid_list, src->start_discovery.num_uuid * sizeof(tSDP_UUID));
+        } else if (src->start_discovery.num_uuid == 0) {
+            LOG_ERROR("%s %d no mem\n", __func__, msg->act);
+        } else {
+            LOG_ERROR("%s %d osi_malloc failed\n", __func__, msg->act);
+        }
+        break;
+    case BTC_SPP_ACT_WRITE:
+        dst->write.p_data = (uint8_t *)osi_malloc(src->write.len);
+        if (dst->write.p_data) {
+            memcpy(dst->write.p_data, src->write.p_data, src->write.len);
+        } else if (src->write.len == 0) {
+            LOG_DEBUG("%s %d no mem\n", __func__, msg->act);
+        } else {
+            LOG_ERROR("%s %d osi_malloc failed\n", __func__, msg->act);
+        }
+        break;
+    default:
+        break;
+    }
+}
+
+void btc_spp_arg_deep_free(btc_msg_t *msg)
+{
+    btc_spp_args_t *arg = (btc_spp_args_t *)msg->arg;
+
+    switch (msg->act) {
+    case BTC_SPP_ACT_START_DISCOVERY:
+        if (arg->start_discovery.p_uuid_list) {
+            osi_free(arg->start_discovery.p_uuid_list);
+        }
+        break;
+    default:
+        break;
+    }
+}
+
+void btc_spp_call_handler(btc_msg_t *msg)
+{
+    btc_spp_args_t *arg = (btc_spp_args_t *)(msg->arg);
+    switch (msg->act) {
+    case BTC_SPP_ACT_INIT:
+        btc_spp_init();
+        break;
+    case BTC_SPP_ACT_UNINIT:
+        btc_spp_uninit();
+        break;
+    case BTC_SPP_ACT_START_DISCOVERY:
+        btc_spp_start_discovery(arg);
+        break;
+    case BTC_SPP_ACT_CONNECT:
+        btc_spp_connect(arg);
+        break;
+    case BTC_SPP_ACT_DISCONNECT:
+        btc_spp_disconnect(arg);
+        break;
+    case BTC_SPP_ACT_START_SRV:
+        btc_spp_start_srv(arg);
+        break;
+    case BTC_SPP_ACT_WRITE:
+        btc_spp_write(arg);
+        break;
+    default:
+        LOG_ERROR("%s: Unhandled event (%d)!\n", __FUNCTION__, msg->act);
+        break;
+    }
+    btc_spp_arg_deep_free(msg);
+}
+
+void btc_spp_cb_handler(btc_msg_t *msg)
+{
+    esp_spp_cb_param_t param;
+    tBTA_JV *p_data = (tBTA_JV *)msg->arg;
+    switch (msg->act) {
+    case BTA_JV_ENABLE_EVT:
+        param.init.status = p_data->status;
+        btc_spp_cb_to_app(ESP_SPP_INIT_EVT, &param);
+        break;
+    case BTA_JV_DISCOVERY_COMP_EVT:
+        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);
+        btc_spp_cb_to_app(ESP_SPP_DISCOVERY_COMP_EVT, &param);
+        break;
+    case BTA_JV_RFCOMM_CL_INIT_EVT:
+        param.cl_init.status = p_data->rfc_cl_init.status;
+        param.cl_init.handle = p_data->rfc_cl_init.handle;
+        param.cl_init.sec_id = p_data->rfc_cl_init.sec_id;
+        param.cl_init.use_co = p_data->rfc_cl_init.use_co;
+        btc_spp_cb_to_app(ESP_SPP_CL_INIT_EVT, &param);
+        break;
+    case BTA_JV_RFCOMM_OPEN_EVT:
+        param.open.status = p_data->rfc_open.status;
+        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, &param);
+        break;
+    case BTA_JV_RFCOMM_START_EVT:
+        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.use_co = p_data->rfc_start.use_co;
+        btc_spp_cb_to_app(ESP_SPP_START_EVT, &param);
+        break;
+    case BTA_JV_RFCOMM_SRV_OPEN_EVT:
+        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:
+        param.write.status = p_data->rfc_write.status;
+        param.write.handle = p_data->rfc_write.handle;
+        param.write.req_id = p_data->rfc_write.req_id;
+        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, &param);
+        spp_slot_t *slot = find_slot_by_handle(p_data->rfc_write.handle);
+        if (!slot) {
+            LOG_ERROR("%s unable to find RFCOMM slot! disconnect fail!", __func__);
+            break;
+        }
+        list_remove(slot->list, list_front(slot->list));
+        break;
+    case BTA_JV_RFCOMM_CLOSE_EVT:
+        param.close.status = p_data->rfc_close.status;
+        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, &param);
+        break;
+    case BTA_JV_RFCOMM_CONG_EVT:
+        param.cong.status = p_data->rfc_cong.status;
+        param.cong.handle = p_data->rfc_cong.handle;
+        param.cong.cong = p_data->rfc_cong.cong;
+        btc_spp_cb_to_app(ESP_SPP_CONG_EVT, &param);
+        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;
+        }
+
+        btc_spp_cb_to_app(ESP_SPP_DATA_IND_EVT, &param);
+        osi_free (p_data->data_ind.p_buf);
+        break;
+    default:
+        LOG_DEBUG("%s: Unhandled event (%d)!", __FUNCTION__, msg->act);
+        break;
+    }
+
+}
+
+
+
+
+
+int bta_co_rfc_data_incoming(void *user_data, BT_HDR *p_buf)
+{
+    bt_status_t status;
+    tBTA_JV p_data;
+    btc_msg_t msg;
+    msg.sig = BTC_SIG_API_CB;
+    msg.pid = BTC_PID_SPP;
+    msg.act = BTA_JV_RFCOMM_DATA_IND_EVT;
+
+    uint32_t id = (uintptr_t)user_data;
+    spp_slot_t *slot = find_slot_by_id(id);
+    if (!slot) {
+        LOG_ERROR("%s unable to find RFCOMM slot!", __func__);
+        return 0;
+    }
+    p_data.data_ind.handle = slot->rfc_handle;
+    p_data.data_ind.p_buf = p_buf;
+    status = btc_transfer_context(&msg, &p_data,
+                                  sizeof(tBTA_JV), NULL);
+
+    if (status != BT_STATUS_SUCCESS) {
+        LOG_ERROR("%s btc_transfer_context failed\n", __func__);
+    }
+    // osi_free (p_buf);
+    return 1;
+}
+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;
+}
+
+#endif ///defined BTC_SPP_INCLUDED && BTC_SPP_INCLUDED == TRUE
\ No newline at end of file
index fe39f8b9bd687785b96f5c0c975bfed851552e16..d7844b7a2bf2f314e1bef677ae2efba608fcab28 100644 (file)
 #define BTA_SDP_INCLUDED            TRUE
 #define BTA_PAN_INCLUDED            FALSE
 #define BTA_HH_INCLUDED             FALSE
+#define SDP_INCLUDED                TRUE
+
+#if CONFIG_A2DP_SNK_ENABLED
 #define BTA_AR_INCLUDED             TRUE
 #define BTA_AV_INCLUDED             TRUE
 #define BTA_AV_SINK_INCLUDED        TRUE
-#define SDP_INCLUDED                TRUE
-#define RFCOMM_INCLUDED             FALSE
-#define PAN_INCLUDED                FALSE
-#define HID_HOST_INCLUDED           FALSE
 #define AVDT_INCLUDED               TRUE
 #define A2D_INCLUDED                TRUE
 #define AVCT_INCLUDED               TRUE
 #define AVRC_INCLUDED               TRUE
+#define BTC_AV_INCLUDED             TRUE
 #define SBC_DEC_INCLUDED            TRUE
+#else
+#define BTA_AR_INCLUDED             FALSE
+#define BTA_AV_INCLUDED             FALSE
+#define BTA_AV_SINK_INCLUDED        FALSE
+#define AVDT_INCLUDED               FALSE
+#define A2D_INCLUDED                FALSE
+#define AVCT_INCLUDED               FALSE
+#define AVRC_INCLUDED               FALSE
+#define BTC_AV_INCLUDED             FALSE
+#define SBC_DEC_INCLUDED            FALSE
+#endif /* CONFIG_A2DP_SNK_ENABLED */
+
+#if CONFIG_BT_SPP_ENABLED
+#define RFCOMM_INCLUDED             TRUE
+#define BTA_JV_INCLUDED             TRUE
+#define BTC_SPP_INCLUDED            TRUE
+#else /* #if CONFIG_BT_SPP_ENABLED */
+#define RFCOMM_INCLUDED             FALSE
+#define BTA_JV_INCLUDED             FALSE
+#define BTC_SPP_INCLUDED            FALSE
+#endif /* #if CONFIG_BT_SPP_ENABLED */
+
+#define PAN_INCLUDED                FALSE
+#define HID_HOST_INCLUDED           FALSE
 #define SBC_ENC_INCLUDED            FALSE
 #define MCA_INCLUDED                FALSE
 #define BTC_SM_INCLUDED             TRUE
 #define BTC_PRF_QUEUE_INCLUDED      TRUE
 #define BTC_GAP_BT_INCLUDED         TRUE
-#define BTC_AV_INCLUDED             TRUE
 
 #else /* #if CONFIG_CLASSIC_BT_ENABLED */
 #define CLASSIC_BT_INCLUDED         FALSE
@@ -73,6 +96,8 @@
 #define BTA_AV_SINK_INCLUDED        FALSE
 #define SDP_INCLUDED                FALSE
 #define RFCOMM_INCLUDED             FALSE
+#define BTA_JV_INCLUDED             FALSE
+#define BTC_SPP_INCLUDED            FALSE
 #define PAN_INCLUDED                FALSE
 #define HID_HOST_INCLUDED           FALSE
 #define AVDT_INCLUDED               FALSE
index 1e52e5f3daf7d8a3561677efbc473c9e2e52f8a4..fc908ba588f315db20b64f39e5f71876ff39ec05 100644 (file)
@@ -498,6 +498,34 @@ void btu_stop_timer(TIMER_LIST_ENT *p_tle)
     osi_alarm_cancel(alarm);
 }
 
+/*******************************************************************************
+**
+** Function         btu_free_timer
+**
+** Description      Stop and free a timer.
+**
+** Returns          void
+**
+*******************************************************************************/
+void btu_free_timer(TIMER_LIST_ENT *p_tle)
+{
+    assert(p_tle != NULL);
+
+    if (p_tle->in_use == FALSE) {
+        return;
+    }
+    p_tle->in_use = FALSE;
+
+    // Get the alarm for the timer list entry.
+    osi_alarm_t *alarm = hash_map_get(btu_general_alarm_hash_map, p_tle);
+    if (alarm == NULL) {
+        LOG_WARN("%s Unable to find expected alarm in hashmap", __func__);
+        return;
+    }
+    osi_alarm_cancel(alarm);
+    hash_map_erase(btu_general_alarm_hash_map, p_tle);
+}
+
 #if defined(QUICK_TIMER_TICKS_PER_SEC) && (QUICK_TIMER_TICKS_PER_SEC > 0)
 /*******************************************************************************
 **
index 862ccec135b5488a4442b2470da47019c3c51040..0401e471c681d2373126931b1cb16ee9e2c96cb9 100644 (file)
@@ -234,6 +234,7 @@ extern const BD_ADDR        BT_BD_ANY;
 */
 void btu_start_timer (TIMER_LIST_ENT *p_tle, UINT16 type, UINT32 timeout);
 void btu_stop_timer (TIMER_LIST_ENT *p_tle);
+void btu_free_timer (TIMER_LIST_ENT *p_tle);
 void btu_start_timer_oneshot(TIMER_LIST_ENT *p_tle, UINT16 type, UINT32 timeout);
 void btu_stop_timer_oneshot(TIMER_LIST_ENT *p_tle);
 
index d5420f56b958760cfa1408bd3c697a077b4b4e72..f37a56c9abaf3b6801d167671bb851a633985ffb 100644 (file)
@@ -598,7 +598,7 @@ extern int PORT_WriteData (UINT16 handle, char *p_data, UINT16 max_len,
 ** Parameters:      handle     - Handle returned in the RFCOMM_CreateConnection
 **
 *******************************************************************************/
-extern int PORT_WriteDataCO (UINT16 handle, int *p_len);
+extern int PORT_WriteDataCO (UINT16 handle, int *p_len, int len, UINT8 *p_data);
 
 /*******************************************************************************
 **
index aa6d48e7fcd8ae868684331bcf5c27d541f1c520..7b1065c6c05f8b1b057db0862b0ec9d136316dd7 100644 (file)
@@ -28,6 +28,8 @@
 #include "bt_target.h"
 #include "rfcdefs.h"
 #include "port_api.h"
+#include "fixed_queue.h"
+#include "bt_defs.h"
 
 /* Local events passed when application event is sent from the api to PORT */
 /* ???*/
index 30eeaff4ebf9b0551d4bc7ada6c1e40c8593c691..0cf9e0951034f875a6f18b4aa977ece956c053e0 100644 (file)
 #include "rfc_int.h"
 #include "l2c_api.h"
 #include "sdp_api.h"
+#include "allocator.h"
+#include "mutex.h"
 
+#if (defined RFCOMM_INCLUDED && RFCOMM_INCLUDED == TRUE)
 /* duration of break in 200ms units */
 #define PORT_BREAK_DURATION     1
 
@@ -366,7 +369,7 @@ int PORT_SetDataCallback (UINT16 port_handle, tPORT_DATA_CALLBACK *p_port_cb)
 {
     tPORT  *p_port;
 
-    RFCOMM_TRACE_API ("PORT_SetDataCallback() handle:%d cb 0x%x", port_handle, p_port_cb);
+    // RFCOMM_TRACE_API ("PORT_SetDataCallback() handle:%d cb 0x%x", port_handle, p_port_cb);
 
     /* Check if handle is valid to avoid crashing */
     if ((port_handle == 0) || (port_handle > MAX_RFC_PORTS)) {
@@ -400,7 +403,7 @@ int PORT_SetDataCOCallback (UINT16 port_handle, tPORT_DATA_CO_CALLBACK *p_port_c
 {
     tPORT  *p_port;
 
-    RFCOMM_TRACE_API ("PORT_SetDataCOCallback() handle:%d cb 0x%x", port_handle, p_port_cb);
+    // RFCOMM_TRACE_API ("PORT_SetDataCOCallback() handle:%d cb 0x%x", port_handle, p_port_cb);
 
     /* Check if handle is valid to avoid crashing */
     if ((port_handle == 0) || (port_handle > MAX_RFC_PORTS)) {
@@ -1173,8 +1176,7 @@ int PORT_ReadData (UINT16 handle, char *p_data, UINT16 max_len, UINT16 *p_len)
         return (PORT_LINE_ERR);
     }
 
-    if (fixed_queue_is_empty(p_port->rx.queue))
-    if (!p_buf) {
+    if (fixed_queue_is_empty(p_port->rx.queue)){
         return (PORT_SUCCESS);
     }
 
@@ -1317,7 +1319,7 @@ static int port_write (tPORT *p_port, BT_HDR *p_buf)
             || ((p_port->port_ctrl & (PORT_CTRL_REQ_SENT | PORT_CTRL_IND_RECEIVED)) !=
                 (PORT_CTRL_REQ_SENT | PORT_CTRL_IND_RECEIVED))) {
         if ((p_port->tx.queue_size  > PORT_TX_CRITICAL_WM)
-         || (fixed_queue_length(p_port->tx.queue) > PORT_TX_BUF_CRITICAL_WM))
+         || (fixed_queue_length(p_port->tx.queue) > PORT_TX_BUF_CRITICAL_WM)){
             RFCOMM_TRACE_WARNING ("PORT_Write: Queue size: %d",
                                   p_port->tx.queue_size);
 
@@ -1421,7 +1423,7 @@ int PORT_Write (UINT16 handle, BT_HDR *p_buf)
 **                  p_len      - Byte count returned
 **
 *******************************************************************************/
-int PORT_WriteDataCO (UINT16 handle, int *p_len)
+int PORT_WriteDataCO (UINT16 handle, int *p_len, int len, UINT8 *p_data)
 {
 
     tPORT      *p_port;
@@ -1449,12 +1451,7 @@ int PORT_WriteDataCO (UINT16 handle, int *p_len)
         return (PORT_UNKNOWN_ERROR);
     }
     int available = 0;
-    //if(ioctl(fd, FIONREAD, &available) < 0)
-    if (p_port->p_data_co_callback(handle, (UINT8 *)&available, sizeof(available),
-                                   DATA_CO_CALLBACK_TYPE_OUTGOING_SIZE) == FALSE) {
-        RFCOMM_TRACE_ERROR("p_data_co_callback DATA_CO_CALLBACK_TYPE_INCOMING_SIZE failed, available:%d", available);
-        return (PORT_UNKNOWN_ERROR);
-    }
+    available = len;
     if (available == 0) {
         return PORT_SUCCESS;
     }
@@ -1469,16 +1466,7 @@ int PORT_WriteDataCO (UINT16 handle, int *p_len)
     if (((p_buf = (BT_HDR *)fixed_queue_try_peek_last(p_port->tx.queue)) != NULL)
             && (((int)p_buf->len + available) <= (int)p_port->peer_mtu)
             && (((int)p_buf->len + available) <= (int)length)) {
-        //if(recv(fd, (UINT8 *)(p_buf + 1) + p_buf->offset + p_buf->len, available, 0) != available)
-        if (p_port->p_data_co_callback(handle, (UINT8 *)(p_buf + 1) + p_buf->offset + p_buf->len,
-                                       available, DATA_CO_CALLBACK_TYPE_OUTGOING) == FALSE)
-
-        {
-            RFCOMM_TRACE_ERROR("p_data_co_callback DATA_CO_CALLBACK_TYPE_OUTGOING failed, available:%d", available);
-            osi_mutex_global_unlock();
-            return (PORT_UNKNOWN_ERROR);
-        }
-        //memcpy ((UINT8 *)(p_buf + 1) + p_buf->offset + p_buf->len, p_data, max_len);
+        memcpy ((UINT8 *)(p_buf + 1) + p_buf->offset + p_buf->len, p_data, available);
         p_port->tx.queue_size += (UINT16)available;
 
         *p_len = available;
@@ -1524,14 +1512,7 @@ int PORT_WriteDataCO (UINT16 handle, int *p_len)
         p_buf->len = length;
         p_buf->event          = BT_EVT_TO_BTU_SP_DATA;
 
-        //memcpy ((UINT8 *)(p_buf + 1) + p_buf->offset, p_data, length);
-        //if(recv(fd, (UINT8 *)(p_buf + 1) + p_buf->offset, (int)length, 0) != (int)length)
-        if (p_port->p_data_co_callback(handle, (UINT8 *)(p_buf + 1) + p_buf->offset, length,
-                                       DATA_CO_CALLBACK_TYPE_OUTGOING) == FALSE) {
-            RFCOMM_TRACE_ERROR("p_data_co_callback DATA_CO_CALLBACK_TYPE_OUTGOING failed, length:%d", length);
-            return (PORT_UNKNOWN_ERROR);
-        }
-
+        memcpy ((UINT8 *)(p_buf + 1) + p_buf->offset, p_data, length);
 
         RFCOMM_TRACE_EVENT ("PORT_WriteData %d bytes", length);
 
@@ -1610,14 +1591,14 @@ int PORT_WriteData (UINT16 handle, char *p_data, UINT16 max_len, UINT16 *p_len)
     }
 
     /* Length for each buffer is the smaller of GKI buffer, peer MTU, or max_len */
-    length = RFCOMM_DATA_POOL_BUF_SIZE -
+    length = RFCOMM_DATA_BUF_SIZE -
              (UINT16)(sizeof(BT_HDR) + L2CAP_MIN_OFFSET + RFCOMM_DATA_OVERHEAD);
 
     /* If there are buffers scheduled for transmission check if requested */
     /* data fits into the end of the queue */
     osi_mutex_global_lock();
 
-    if (((p_buf = (BT_HDR *)fixed_queue_try_peek_last(p_port->tx.queue)) != NULL) {
+    if (((p_buf = (BT_HDR *)fixed_queue_try_peek_last(p_port->tx.queue)) != NULL)
             && ((p_buf->len + max_len) <= p_port->peer_mtu)
             && ((p_buf->len + max_len) <= length)) {
         memcpy ((UINT8 *)(p_buf + 1) + p_buf->offset + p_buf->len, p_data, max_len);
@@ -1800,3 +1781,5 @@ const char *PORT_GetResultString (const uint8_t result_code)
 
     return result_code_strings[result_code];
 }
+
+#endif ///(defined RFCOMM_INCLUDED && RFCOMM_INCLUDED == TRUE)
\ No newline at end of file
index e3076f7121c3cf735bf310e1c3ff3fdbbb7c7df5..6e77e529dc21fbc55d81b8a15a726e2686473103 100644 (file)
@@ -32,7 +32,9 @@
 #include "port_int.h"
 #include "rfc_int.h"
 #include "bt_defs.h"
-
+#include "mutex.h"
+#include "allocator.h"
+#if (defined RFCOMM_INCLUDED && RFCOMM_INCLUDED == TRUE)
 /*
 ** Local function definitions
 */
@@ -1090,3 +1092,6 @@ void port_get_credits (tPORT *p_port, UINT8 k)
         p_port->tx.peer_fc = TRUE;
     }
 }
+
+
+#endif ///(defined RFCOMM_INCLUDED && RFCOMM_INCLUDED == TRUE)
\ No newline at end of file
index 92485075be79759c25d90c3456257d2f05c00b0e..19e208839b0de8f98a5e0516eb0658f311b813a8 100644 (file)
@@ -31,6 +31,9 @@
 #include "l2cdefs.h"
 #include "btm_int.h"
 #include "btu.h"
+#include "mutex.h"
+#include "allocator.h"
+#if (defined RFCOMM_INCLUDED && RFCOMM_INCLUDED == TRUE)
 
 static const tPORT_STATE default_port_pars = {
     PORT_BAUD_RATE_9600,
@@ -564,3 +567,5 @@ void port_flow_control_peer(tPORT *p_port, BOOLEAN enable, UINT16 count)
     }
 }
 
+
+#endif ///(defined RFCOMM_INCLUDED && RFCOMM_INCLUDED == TRUE)
\ No newline at end of file
index 1458166ed351fe844d50da6b5ab93a039024b8f6..0a8cf4be05d75af26133540168ee7b18924793d6 100644 (file)
 #include "l2cdefs.h"
 #include "rfc_int.h"
 #include "bt_defs.h"
-
-
+#include "allocator.h"
+#include "mutex.h"
+#include "alarm.h"
+#if (defined RFCOMM_INCLUDED && RFCOMM_INCLUDED == TRUE)
 /*
 ** Define Callback functions to be called by L2CAP
 */
@@ -413,3 +415,5 @@ void rfc_save_lcid_mcb (tRFC_MCB *p_mcb, UINT16 lcid)
 {
     rfc_cb.rfc.p_rfc_lcid_mcb[lcid - L2CAP_BASE_APPL_CID] = p_mcb;
 }
+
+#endif ///(defined RFCOMM_INCLUDED && RFCOMM_INCLUDED == TRUE)
\ No newline at end of file
index f7a063d8008113ec8812cde0440d414a0689a51c..2ade69e53f362d29ea3265fa7d15cdb5064be047 100644 (file)
 #include "l2c_api.h"
 #include "rfc_int.h"
 #include "bt_defs.h"
+#include "allocator.h"
+#include "mutex.h"
+#include "bt_target.h"
+#if (defined RFCOMM_INCLUDED && RFCOMM_INCLUDED == TRUE)
 
 #define L2CAP_SUCCESS   0
 #define L2CAP_ERROR     1
@@ -572,7 +576,7 @@ static void rfc_mx_send_config_req (tRFC_MCB *p_mcb)
 *******************************************************************************/
 static void rfc_mx_conf_cnf (tRFC_MCB *p_mcb, tL2CAP_CFG_INFO *p_cfg)
 {
-    RFCOMM_TRACE_EVENT ("rfc_mx_conf_cnf p_cfg:%08x res:%d ", p_cfg, (p_cfg) ? p_cfg->result : 0);
+    // RFCOMM_TRACE_EVENT ("rfc_mx_conf_cnf p_cfg:%08x res:%d ", p_cfg, (p_cfg) ? p_cfg->result : 0);
 
     if (p_cfg->result != L2CAP_CFG_OK) {
         if (p_mcb->is_initiator) {
@@ -639,3 +643,5 @@ static void rfc_mx_conf_ind (tRFC_MCB *p_mcb, tL2CAP_CFG_INFO *p_cfg)
         }
     }
 }
+
+#endif ///(defined RFCOMM_INCLUDED && RFCOMM_INCLUDED == TRUE)
\ No newline at end of file
index 710c893a15b99401adf788edcba79906493b030f..b02574c44f3cc368a4f4bbde3d9db441f86195cc 100644 (file)
@@ -31,6 +31,9 @@
 #include "port_int.h"
 #include "rfc_int.h"
 #include "bt_defs.h"
+#include "allocator.h"
+#include "mutex.h"
+#if (defined RFCOMM_INCLUDED && RFCOMM_INCLUDED == TRUE)
 
 /********************************************************************************/
 /*              L O C A L    F U N C T I O N     P R O T O T Y P E S            */
@@ -895,3 +898,4 @@ void rfc_set_port_state(tPORT_STATE *port_pars, MX_FRAME *p_frame)
     }
 }
 
+#endif ///(defined RFCOMM_INCLUDED && RFCOMM_INCLUDED == TRUE)
\ No newline at end of file
index c09d263402724086176753a58cfcf6840050a925..632f82bb2e44a8d9739cf11024c3bf292c46fed6 100644 (file)
@@ -32,6 +32,8 @@
 #include "rfc_int.h"
 #include "bt_defs.h"
 
+#if (defined RFCOMM_INCLUDED && RFCOMM_INCLUDED == TRUE)
+
 #if RFC_DYNAMIC_MEMORY == FALSE
 tRFC_CB rfc_cb;
 #endif
@@ -372,3 +374,4 @@ void RFCOMM_DataReq (tRFC_MCB *p_mcb, UINT8 dlci, BT_HDR *p_buf)
 }
 
 
+#endif ///(defined RFCOMM_INCLUDED && RFCOMM_INCLUDED == TRUE)
\ No newline at end of file
index ac29ccec63ad6f762a74f3181645e05877c3a303..1c5f5d2044db9a722de8d6b99e4f346f593ff4bd 100644 (file)
@@ -29,6 +29,9 @@
 #include "l2c_api.h"
 #include "port_int.h"
 #include "rfc_int.h"
+#include "mutex.h"
+#include "allocator.h"
+#if (defined RFCOMM_INCLUDED && RFCOMM_INCLUDED == TRUE)
 
 /*******************************************************************************
 **
@@ -895,3 +898,4 @@ void rfc_process_mx_message (tRFC_MCB *p_mcb, BT_HDR *p_buf)
     }
 }
 
+#endif ///(defined RFCOMM_INCLUDED && RFCOMM_INCLUDED == TRUE)
\ No newline at end of file
index dc55f8028fe6ee12785112482a59857b3a5bdc2a..6521fb4847de2786490f1af0b9776c4c837c4d7e 100644 (file)
 #include "btu.h"
 #include "bt_defs.h"
 
+#include "allocator.h"
+#include "mutex.h"
+
 #include <string.h>
 
+#if (defined RFCOMM_INCLUDED && RFCOMM_INCLUDED == TRUE)
 /*******************************************************************************
 **
 ** Function         rfc_calc_fcs
@@ -183,7 +187,9 @@ tRFC_MCB *rfc_alloc_multiplexer_channel (BD_ADDR bd_addr, BOOLEAN is_initiator)
     return (NULL);
 }
 
-
+void osi_free_fun(void *p){
+    osi_free(p);
+}
 /*******************************************************************************
 **
 ** Function         rfc_release_multiplexer_channel
@@ -197,8 +203,7 @@ void rfc_release_multiplexer_channel (tRFC_MCB *p_mcb)
 
     rfc_timer_stop (p_mcb);
 
-
-    fixed_queue_free(p_mcb->cmd_q, osi_free);
+    fixed_queue_free(p_mcb->cmd_q, osi_free_fun);
 
     memset (p_mcb, 0, sizeof (tRFC_MCB));
     p_mcb->state = RFC_MX_STATE_IDLE;
@@ -269,7 +274,7 @@ void rfc_port_timer_stop (tPORT *p_port)
 {
     RFCOMM_TRACE_EVENT ("rfc_port_timer_stop");
 
-    btu_stop_timer (&p_port->rfc.tle);
+    btu_free_timer (&p_port->rfc.tle);
 }
 
 
@@ -475,3 +480,4 @@ void rfc_check_send_cmd(tRFC_MCB *p_mcb, BT_HDR *p_buf)
 }
 
 
+#endif ///(defined RFCOMM_INCLUDED && RFCOMM_INCLUDED == TRUE)
\ No newline at end of file
index 8f6ce29d518b6a460d5afaff5bbc661362828475..4fa144ba0253a0d96d4ee4aa7f849f90b87a2aaa 100644 (file)
@@ -52,6 +52,7 @@ COMPONENT_ADD_INCLUDEDIRS +=  bluedroid/bta/include                   \
                                bluedroid/stack/avrc/include            \
                                bluedroid/stack/avdt/include            \
                                bluedroid/stack/a2dp/include            \
+                               bluedroid/stack/rfcomm/include          \
                                bluedroid/stack/include                 \
                                bluedroid/utils/include                 \
                                bluedroid/api/include                   \
@@ -64,6 +65,7 @@ COMPONENT_SRCDIRS +=  bluedroid/bta/dm                        \
                        bluedroid/bta/av                        \
                        bluedroid/bta/ar                        \
                        bluedroid/bta/sys                       \
+                       bluedroid/bta/jv                        \
                        bluedroid/bta                           \
                        bluedroid/btcore                        \
                        bluedroid/btif                          \
@@ -79,6 +81,7 @@ COMPONENT_SRCDIRS +=  bluedroid/bta/dm                        \
                        bluedroid/btc/profile/std/gatt          \
                        bluedroid/btc/profile/std/a2dp          \
                        bluedroid/btc/profile/std/avrc          \
+                       bluedroid/btc/profile/std/spp           \
                        bluedroid/btc/profile                   \
                        bluedroid/stack/btm                     \
                        bluedroid/stack/btu                     \
@@ -93,6 +96,7 @@ COMPONENT_SRCDIRS +=  bluedroid/bta/dm                        \
                        bluedroid/stack/avrc                    \
                        bluedroid/stack/avdt                    \
                        bluedroid/stack/a2dp                    \
+                       bluedroid/stack/rfcomm                  \
                        bluedroid/stack                         \
                        bluedroid/utils                         \
                        bluedroid/api                   \
index 713b6a49dd9a542e4aeaa2a91992f36659df2a50..dbc405d23ed3e594043464b9085a975223b7fa3c 100644 (file)
@@ -48,6 +48,7 @@ INPUT = \
     ## Issue with __attribute__
     ../components/bt/bluedroid/api/include/esp_a2dp_api.h \
     ../components/bt/bluedroid/api/include/esp_avrc_api.h \
+    ../components/bt/bluedroid/api/include/esp_spp_api.h \
     ##
     ## Ethernet - API Reference
     ##
index 59dac87f1b188b6d7026acf1427599bff97f7964..2fd161e711cab14a5a083d745aecb9de0209551a 100644 (file)
@@ -7,3 +7,4 @@ CLASSIC BT
    BT GAP <esp_gap_bt>
    BT A2DP <esp_a2dp>
    BT AVRC <esp_avrc>
+   BT SPP <esp_spp>
diff --git a/docs/api-reference/bluetooth/esp_spp.rst b/docs/api-reference/bluetooth/esp_spp.rst
new file mode 100644 (file)
index 0000000..f686810
--- /dev/null
@@ -0,0 +1,22 @@
+SPP API
+===============
+
+Overview
+--------
+
+`Instructions`_
+
+.. _Instructions: ../template.html
+
+Application Example
+-------------------
+
+Check :example:`bluetooth` folder in ESP-IDF examples, which contains the following application:
+
+* This is a SPP demo. This demo can discover the service, connect, send and recive SPP data :example:`bluetooth/bt_spp_acceptor`, :example:`bluetooth/bt_spp_initiator`
+
+API Reference
+-------------
+
+.. include:: /_build/inc/esp_spp_api.inc
+
index fe6bb31d11ae3c4732c07cf3654100be142da4bc..371169bd4eaad49c0165e7eb8c6f1773fd86b800 100644 (file)
@@ -2,3 +2,5 @@
 # Classic BT is enabled and BT_DRAM_RELEASE is disabled
 CONFIG_BT_ENABLED=y
 CONFIG_CLASSIC_BT_ENABLED=y
+CONFIG_A2DP_SNK_ENABLED=y
+
diff --git a/examples/bluetooth/bt_spp_acceptor/Makefile b/examples/bluetooth/bt_spp_acceptor/Makefile
new file mode 100644 (file)
index 0000000..3d61bab
--- /dev/null
@@ -0,0 +1,10 @@
+#
+# This is a project Makefile. It is assumed the directory this Makefile resides in is a
+# project subdirectory.
+#
+
+PROJECT_NAME := bt_spp_acceptor_demo
+
+#COMPONENT_ADD_INCLUDEDIRS := components/include
+
+include $(IDF_PATH)/make/project.mk
diff --git a/examples/bluetooth/bt_spp_acceptor/README.rst b/examples/bluetooth/bt_spp_acceptor/README.rst
new file mode 100644 (file)
index 0000000..b0a865e
--- /dev/null
@@ -0,0 +1,16 @@
+ESP-IDF BT-SPP-ACCEPTOR demo
+======================
+
+Demo of SPP acceptor role
+
+This is the demo for user to use ESP_APIs to create a SPP acceptor.
+
+Options choose step:
+    1. make menuconfig.
+    2. enter menuconfig "Component config", choose "Bluetooth"
+    3. enter menu Bluetooth, choose "Classic Bluetooth" and "SPP Profile"
+    4. choose your options.
+
+Then set SPP_SHOW_MODE as SPP_SHOW_DATA or SPP_SHOW_SPEED in code(should be same with bt_spp_initator).
+
+After the program started, bt_spp_initator will connect it and send data.
\ No newline at end of file
diff --git a/examples/bluetooth/bt_spp_acceptor/main/component.mk b/examples/bluetooth/bt_spp_acceptor/main/component.mk
new file mode 100644 (file)
index 0000000..a98f634
--- /dev/null
@@ -0,0 +1,4 @@
+#
+# "main" pseudo-component makefile.
+#
+# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)
diff --git a/examples/bluetooth/bt_spp_acceptor/main/example_spp_acceptor_demo.c b/examples/bluetooth/bt_spp_acceptor/main/example_spp_acceptor_demo.c
new file mode 100644 (file)
index 0000000..e46f018
--- /dev/null
@@ -0,0 +1,155 @@
+// Copyright 2015-2017 Espressif Systems (Shanghai) PTE LTD
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <stdint.h>
+#include <string.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include "nvs.h"
+#include "nvs_flash.h"
+#include "freertos/FreeRTOS.h"
+#include "freertos/task.h"
+#include "esp_log.h"
+#include "esp_bt.h"
+#include "esp_bt_main.h"
+#include "esp_gap_bt_api.h"
+#include "esp_bt_device.h"
+#include "esp_spp_api.h"
+
+#include "time.h"
+#include "sys/time.h"
+
+#define SPP_TAG "SPP_ACCEPTOR_DEMO"
+#define SPP_SERVER_NAME "SPP_SERVER"
+#define EXCAMPLE_DEVICE_NAME "ESP_SPP_ACCEPTOR"
+#define SPP_SHOW_DATA 0
+#define SPP_SHOW_SPEED 1
+#define SPP_SHOW_MODE SPP_SHOW_SPEED    /*Choose show mode: show data or speed*/
+
+static const esp_spp_mode_t esp_spp_mode = ESP_SPP_MODE_CB;
+
+static struct timeval time_new, time_old;
+static long data_num = 0;
+
+static const esp_spp_sec_t sec_mask = ESP_SPP_SEC_NONE;
+static const esp_spp_role_t role_slave = ESP_SPP_ROLE_SLAVE;
+
+static void print_speed(void)
+{
+    float time_old_s = time_old.tv_sec + time_old.tv_usec / 1000000.0;
+    float time_new_s = time_new.tv_sec + time_new.tv_usec / 1000000.0;
+    float time_interval = time_new_s - time_old_s;
+    float speed = data_num * 8 / time_interval / 1000.0;
+    ESP_LOGI(SPP_TAG, "speed(%fs ~ %fs): %f kbit/s" , time_old_s, time_new_s, speed);
+    data_num = 0;
+    time_old.tv_sec = time_new.tv_sec;
+    time_old.tv_usec = time_new.tv_usec;
+}
+
+static void esp_spp_cb(esp_spp_cb_event_t event, esp_spp_cb_param_t *param)
+{
+    switch (event) {
+    case ESP_SPP_INIT_EVT:
+        ESP_LOGI(SPP_TAG, "ESP_SPP_INIT_EVT");
+        esp_bt_dev_set_device_name(EXCAMPLE_DEVICE_NAME);
+        esp_bt_gap_set_scan_mode(ESP_BT_SCAN_MODE_CONNECTABLE_DISCOVERABLE);
+        esp_spp_start_srv(sec_mask,role_slave, 0, SPP_SERVER_NAME);
+        break;
+    case ESP_SPP_DISCOVERY_COMP_EVT:
+        ESP_LOGI(SPP_TAG, "ESP_SPP_DISCOVERY_COMP_EVT");
+        break;
+    case ESP_SPP_OPEN_EVT:
+        ESP_LOGI(SPP_TAG, "ESP_SPP_OPEN_EVT");
+        break;
+    case ESP_SPP_CLOSE_EVT:
+        ESP_LOGI(SPP_TAG, "ESP_SPP_CLOSE_EVT");
+        break;
+    case ESP_SPP_START_EVT:
+        ESP_LOGI(SPP_TAG, "ESP_SPP_START_EVT");
+        break;
+    case ESP_SPP_CL_INIT_EVT:
+        ESP_LOGI(SPP_TAG, "ESP_SPP_CL_INIT_EVT");
+        break;
+    case ESP_SPP_DATA_IND_EVT:
+#if (SPP_SHOW_MODE == SPP_SHOW_DATA)
+        ESP_LOGI(SPP_TAG, "ESP_SPP_DATA_IND_EVT len=%d handle=%d",
+                 param->data_ind.len, param->data_ind.handle);
+        esp_log_buffer_hex("",param->data_ind.data,param->data_ind.len);
+#else
+        gettimeofday(&time_new, NULL);
+        data_num += param->data_ind.len;
+        if (time_new.tv_sec - time_old.tv_sec >= 3) {
+            print_speed();
+        }
+#endif
+        break;
+    case ESP_SPP_CONG_EVT:
+        ESP_LOGI(SPP_TAG, "ESP_SPP_CONG_EVT");
+        break;
+    case ESP_SPP_WRITE_EVT:
+        ESP_LOGI(SPP_TAG, "ESP_SPP_WRITE_EVT");
+        break;
+    case ESP_SPP_SRV_OPEN_EVT:
+        ESP_LOGI(SPP_TAG, "ESP_SPP_SRV_OPEN_EVT");
+        gettimeofday(&time_old, NULL);
+        break;
+    default:
+        break;
+    }
+}
+
+
+
+void app_main()
+{
+    esp_err_t ret = nvs_flash_init();
+    if (ret == ESP_ERR_NVS_NO_FREE_PAGES) {
+        ESP_ERROR_CHECK(nvs_flash_erase());
+        ret = nvs_flash_init();
+    }
+    ESP_ERROR_CHECK( ret );
+
+
+    esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT();
+    if (esp_bt_controller_init(&bt_cfg) != ESP_OK) {
+        ESP_LOGE(SPP_TAG, "%s initialize controller failed\n", __func__);
+        return;
+    }
+
+    if (esp_bt_controller_enable(ESP_BT_MODE_CLASSIC_BT) != ESP_OK) {
+        ESP_LOGE(SPP_TAG, "%s enable controller failed\n", __func__);
+        return;
+    }
+
+    if (esp_bluedroid_init() != ESP_OK) {
+        ESP_LOGE(SPP_TAG, "%s initialize bluedroid failed\n", __func__);
+        return;
+    }
+
+    if (esp_bluedroid_enable() != ESP_OK) {
+        ESP_LOGE(SPP_TAG, "%s enable bluedroid failed\n", __func__);
+        return;
+    }
+
+    if (esp_spp_register_callback(esp_spp_cb) != ESP_OK) {
+        ESP_LOGE(SPP_TAG, "%s spp register failed\n", __func__);
+        return;
+    }
+
+    if (esp_spp_init(esp_spp_mode) != ESP_OK) {
+        ESP_LOGE(SPP_TAG, "%s spp init failed\n", __func__);
+        return;
+    }
+}
+
diff --git a/examples/bluetooth/bt_spp_acceptor/sdkconfig.defaults b/examples/bluetooth/bt_spp_acceptor/sdkconfig.defaults
new file mode 100644 (file)
index 0000000..a8ace21
--- /dev/null
@@ -0,0 +1,6 @@
+# Override some defaults so BT stack is enabled
+# and WiFi disabled by default in this example
+CONFIG_BT_ENABLED=y
+CONFIG_CLASSIC_BT_ENABLED=y
+CONFIG_WIFI_ENABLED=n
+CONFIG_BT_SPP_ENABLED=y
\ No newline at end of file
diff --git a/examples/bluetooth/bt_spp_initiator/Makefile b/examples/bluetooth/bt_spp_initiator/Makefile
new file mode 100644 (file)
index 0000000..38567f8
--- /dev/null
@@ -0,0 +1,10 @@
+#
+# This is a project Makefile. It is assumed the directory this Makefile resides in is a
+# project subdirectory.
+#
+
+PROJECT_NAME := bt_spp_initiator_demo
+
+#COMPONENT_ADD_INCLUDEDIRS := components/include
+
+include $(IDF_PATH)/make/project.mk
diff --git a/examples/bluetooth/bt_spp_initiator/README.rst b/examples/bluetooth/bt_spp_initiator/README.rst
new file mode 100644 (file)
index 0000000..4d298e1
--- /dev/null
@@ -0,0 +1,16 @@
+ESP-IDF BT-SPP-INITATOR demo
+======================
+
+Demo of SPP initator role
+
+This is the demo for user to use ESP_APIs to create a SPP initator.
+
+Options choose step:
+    1. make menuconfig.
+    2. enter menuconfig "Component config", choose "Bluetooth"
+    3. enter menu Bluetooth, choose "Classic Bluetooth" and "SPP Profile"
+    4. choose your options.
+
+Then set SPP_SHOW_MODE as SPP_SHOW_DATA or SPP_SHOW_SPEED in code(should be same with bt_spp_acceptor).
+
+After the program started, It will connect to bt_spp_acceptor and send data.
\ No newline at end of file
diff --git a/examples/bluetooth/bt_spp_initiator/main/component.mk b/examples/bluetooth/bt_spp_initiator/main/component.mk
new file mode 100644 (file)
index 0000000..a98f634
--- /dev/null
@@ -0,0 +1,4 @@
+#
+# "main" pseudo-component makefile.
+#
+# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)
diff --git a/examples/bluetooth/bt_spp_initiator/main/example_spp_initiator_demo.c b/examples/bluetooth/bt_spp_initiator/main/example_spp_initiator_demo.c
new file mode 100644 (file)
index 0000000..11d1efd
--- /dev/null
@@ -0,0 +1,254 @@
+// Copyright 2015-2017 Espressif Systems (Shanghai) PTE LTD
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <stdint.h>
+#include <string.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include "nvs.h"
+#include "nvs_flash.h"
+#include "freertos/FreeRTOS.h"
+#include "freertos/task.h"
+#include "esp_log.h"
+#include "esp_bt.h"
+#include "esp_bt_main.h"
+#include "esp_gap_bt_api.h"
+#include "esp_bt_device.h"
+#include "esp_spp_api.h"
+
+#include "time.h"
+#include "sys/time.h"
+
+#define SPP_TAG "SPP_INITIATOR_DEMO"
+#define EXCAMPLE_DEVICE_NAME "ESP_SPP_INITIATOR"
+
+#define SPP_SHOW_DATA 0
+#define SPP_SHOW_SPEED 1
+#define SPP_SHOW_MODE SPP_SHOW_SPEED    /*Choose show mode: show data or speed*/
+
+static const esp_spp_mode_t esp_spp_mode = ESP_SPP_MODE_CB;
+
+static struct timeval time_new, time_old;
+static long data_num = 0;
+
+static const esp_spp_sec_t sec_mask = ESP_SPP_SEC_NONE;
+static const esp_spp_role_t role_master = ESP_SPP_ROLE_MASTER;
+
+static esp_bd_addr_t peer_bd_addr;
+static uint8_t peer_bdname_len;
+static char peer_bdname[ESP_BT_GAP_MAX_BDNAME_LEN + 1];
+static const char remote_device_name[] = "ESP_SPP_ACCEPTOR";
+static const esp_bt_inq_mode_t inq_mode = ESP_BT_INQ_MODE_GENERAL_INQUIRY;
+static const uint8_t inq_len = 30;
+static const uint8_t inq_num_rsps = 0;
+
+#if (SPP_SHOW_MODE == SPP_SHOW_DATA)
+#define SPP_DATA_LEN 20
+#else
+#define SPP_DATA_LEN ESP_SPP_MAX_MTU
+#endif
+static uint8_t spp_data[SPP_DATA_LEN];
+
+static void print_speed(void)
+{
+    float time_old_s = time_old.tv_sec + time_old.tv_usec / 1000000.0;
+    float time_new_s = time_new.tv_sec + time_new.tv_usec / 1000000.0;
+    float time_interval = time_new_s - time_old_s;
+    float speed = data_num * 8 / time_interval / 1000.0;
+    ESP_LOGI(SPP_TAG, "speed(%fs ~ %fs): %f kbit/s" , time_old_s, time_new_s, speed);
+    data_num = 0;
+    time_old.tv_sec = time_new.tv_sec;
+    time_old.tv_usec = time_new.tv_usec;
+}
+
+static bool get_name_from_eir(uint8_t *eir, char *bdname, uint8_t *bdname_len)
+{
+    uint8_t *rmt_bdname = NULL;
+    uint8_t rmt_bdname_len = 0;
+
+    if (!eir) {
+        return false;
+    }
+
+    rmt_bdname = esp_bt_gap_resolve_eir_data(eir, ESP_BT_EIR_TYPE_CMPL_LOCAL_NAME, &rmt_bdname_len);
+    if (!rmt_bdname) {
+        rmt_bdname = esp_bt_gap_resolve_eir_data(eir, ESP_BT_EIR_TYPE_SHORT_LOCAL_NAME, &rmt_bdname_len);
+    }
+
+    if (rmt_bdname) {
+        if (rmt_bdname_len > ESP_BT_GAP_MAX_BDNAME_LEN) {
+            rmt_bdname_len = ESP_BT_GAP_MAX_BDNAME_LEN;
+        }
+
+        if (bdname) {
+            memcpy(bdname, rmt_bdname, rmt_bdname_len);
+            bdname[rmt_bdname_len] = '\0';
+        }
+        if (bdname_len) {
+            *bdname_len = rmt_bdname_len;
+        }
+        return true;
+    }
+
+    return false;
+}
+
+static void esp_spp_cb(esp_spp_cb_event_t event, esp_spp_cb_param_t *param)
+{
+    switch (event) {
+    case ESP_SPP_INIT_EVT:
+        ESP_LOGI(SPP_TAG, "ESP_SPP_INIT_EVT");
+        esp_bt_dev_set_device_name(EXCAMPLE_DEVICE_NAME);
+        esp_bt_gap_set_scan_mode(ESP_BT_SCAN_MODE_CONNECTABLE_DISCOVERABLE);
+        esp_bt_gap_start_discovery(inq_mode, inq_len, inq_num_rsps);
+
+        break;
+    case ESP_SPP_DISCOVERY_COMP_EVT:
+        ESP_LOGI(SPP_TAG, "ESP_SPP_DISCOVERY_COMP_EVT status=%d scn_num=%d",param->disc_comp.status, param->disc_comp.scn_num);
+        if (param->disc_comp.status == ESP_SPP_SUCCESS) {
+            esp_spp_connect(sec_mask, role_master, param->disc_comp.scn[0], peer_bd_addr);
+        }
+        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);
+        gettimeofday(&time_old, NULL);
+        break;
+    case ESP_SPP_CLOSE_EVT:
+        ESP_LOGI(SPP_TAG, "ESP_SPP_CLOSE_EVT");
+        break;
+    case ESP_SPP_START_EVT:
+        ESP_LOGI(SPP_TAG, "ESP_SPP_START_EVT");
+        break;
+    case ESP_SPP_CL_INIT_EVT:
+        ESP_LOGI(SPP_TAG, "ESP_SPP_CL_INIT_EVT");
+        break;
+    case ESP_SPP_DATA_IND_EVT:
+        ESP_LOGI(SPP_TAG, "ESP_SPP_DATA_IND_EVT");
+        break;
+    case ESP_SPP_CONG_EVT:
+#if (SPP_SHOW_MODE == SPP_SHOW_DATA)
+        ESP_LOGI(SPP_TAG, "ESP_SPP_CONG_EVT cong=%d", param->cong.cong);
+#endif
+        if (param->cong.cong == 0) {
+            esp_spp_write(param->cong.handle, SPP_DATA_LEN, spp_data);
+        }
+        break;
+    case ESP_SPP_WRITE_EVT:
+#if (SPP_SHOW_MODE == SPP_SHOW_DATA)
+        ESP_LOGI(SPP_TAG, "ESP_SPP_WRITE_EVT len=%d cong=%d", param->write.len , param->write.cong);
+        esp_log_buffer_hex("",spp_data,SPP_DATA_LEN);
+#else
+        gettimeofday(&time_new, NULL);
+        data_num += param->write.len;
+        if (time_new.tv_sec - time_old.tv_sec >= 3) {
+            print_speed();
+        }
+#endif
+        if (param->write.cong == 0) {
+            esp_spp_write(param->write.handle, SPP_DATA_LEN, spp_data);
+        }
+        break;
+    case ESP_SPP_SRV_OPEN_EVT:
+        ESP_LOGI(SPP_TAG, "ESP_SPP_SRV_OPEN_EVT");
+        break;
+    default:
+        break;
+    }
+}
+
+static void esp_bt_gap_cb(esp_bt_gap_cb_event_t event, esp_bt_gap_cb_param_t *param)
+{
+    switch(event){
+        case ESP_BT_GAP_DISC_RES_EVT:
+            ESP_LOGI(SPP_TAG, "ESP_BT_GAP_DISC_RES_EVT");
+            esp_log_buffer_hex(SPP_TAG, param->disc_res.bda, ESP_BD_ADDR_LEN);
+            for (int i = 0; i < param->disc_res.num_prop; i++){
+                if (param->disc_res.prop[i].type == ESP_BT_GAP_DEV_PROP_EIR
+                    && get_name_from_eir(param->disc_res.prop[i].val, peer_bdname, &peer_bdname_len)){
+                    esp_log_buffer_char(SPP_TAG, peer_bdname, peer_bdname_len);
+                    if (strlen(remote_device_name) == peer_bdname_len
+                        && strncmp(peer_bdname, remote_device_name, peer_bdname_len) == 0) {
+                        memcpy(peer_bd_addr, param->disc_res.bda, ESP_BD_ADDR_LEN);
+                        esp_spp_start_discovery(peer_bd_addr);
+                        esp_bt_gap_cancel_discovery();
+                    }
+                }
+            }
+            break;
+        case ESP_BT_GAP_DISC_STATE_CHANGED_EVT:
+            ESP_LOGI(SPP_TAG, "ESP_BT_GAP_DISC_STATE_CHANGED_EVT");
+            break;
+        case ESP_BT_GAP_RMT_SRVCS_EVT:
+            ESP_LOGI(SPP_TAG, "ESP_BT_GAP_RMT_SRVCS_EVT");
+            break;
+        case ESP_BT_GAP_RMT_SRVC_REC_EVT:
+            ESP_LOGI(SPP_TAG, "ESP_BT_GAP_RMT_SRVC_REC_EVT");
+            break;
+        default:
+            break;
+    }
+}
+
+void app_main()
+{
+    for (int i = 0; i < SPP_DATA_LEN; ++i) {
+        spp_data[i] = i;
+    }
+
+    esp_err_t ret = nvs_flash_init();
+    if (ret == ESP_ERR_NVS_NO_FREE_PAGES) {
+        ESP_ERROR_CHECK(nvs_flash_erase());
+        ret = nvs_flash_init();
+    }
+    ESP_ERROR_CHECK( ret );
+
+
+    esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT();
+    if (esp_bt_controller_init(&bt_cfg) != ESP_OK) {
+        ESP_LOGE(SPP_TAG, "%s initialize controller failed\n", __func__);
+        return;
+    }
+
+    if (esp_bt_controller_enable(ESP_BT_MODE_CLASSIC_BT) != ESP_OK) {
+        ESP_LOGE(SPP_TAG, "%s enable controller failed\n", __func__);
+        return;
+    }
+
+    if (esp_bluedroid_init() != ESP_OK) {
+        ESP_LOGE(SPP_TAG, "%s initialize bluedroid failed\n", __func__);
+        return;
+    }
+
+    if (esp_bluedroid_enable() != ESP_OK) {
+        ESP_LOGE(SPP_TAG, "%s enable bluedroid failed\n", __func__);
+        return;
+    }
+
+    if (esp_bt_gap_register_callback(esp_bt_gap_cb) != ESP_OK) {
+        ESP_LOGE(SPP_TAG, "%s gap register failed\n", __func__);
+        return;
+    }
+
+    if (esp_spp_register_callback(esp_spp_cb) != ESP_OK) {
+        ESP_LOGE(SPP_TAG, "%s spp register failed\n", __func__);
+        return;
+    }
+
+    if (esp_spp_init(esp_spp_mode) != ESP_OK) {
+        ESP_LOGE(SPP_TAG, "%s spp init failed\n", __func__);
+        return;
+    }
+}
+
diff --git a/examples/bluetooth/bt_spp_initiator/sdkconfig.defaults b/examples/bluetooth/bt_spp_initiator/sdkconfig.defaults
new file mode 100644 (file)
index 0000000..a8ace21
--- /dev/null
@@ -0,0 +1,6 @@
+# Override some defaults so BT stack is enabled
+# and WiFi disabled by default in this example
+CONFIG_BT_ENABLED=y
+CONFIG_CLASSIC_BT_ENABLED=y
+CONFIG_WIFI_ENABLED=n
+CONFIG_BT_SPP_ENABLED=y
\ No newline at end of file