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
--- /dev/null
+// 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
--- /dev/null
+// 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
--- /dev/null
+/******************************************************************************
+ *
+ * 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 */
--- /dev/null
+/******************************************************************************
+ *
+ * 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 */
--- /dev/null
+/******************************************************************************
+ *
+ * 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
--- /dev/null
+/******************************************************************************
+ *
+ * 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
--- /dev/null
+/******************************************************************************
+ *
+ * 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
--- /dev/null
+/******************************************************************************
+ *
+ * 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 */
--- /dev/null
+/******************************************************************************
+ *
+ * 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
#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 */
[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 */
};
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;
+}
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
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__ */
--- /dev/null
+// 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
--- /dev/null
+// 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, ¶m);
+}
+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, ¶m);
+}
+
+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, ¶m);
+ 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, ¶m);
+ 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, ¶m);
+ 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, ¶m);
+ 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, ¶m);
+ 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, ¶m);
+ 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, ¶m);
+ 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, ¶m);
+ 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, ¶m);
+ 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, ¶m);
+ 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
#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
#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
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)
/*******************************************************************************
**
*/
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);
** 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);
/*******************************************************************************
**
#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 */
/* ???*/
#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
{
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)) {
{
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)) {
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);
}
|| ((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);
** 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;
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;
}
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;
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);
}
/* 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);
return result_code_strings[result_code];
}
+
+#endif ///(defined RFCOMM_INCLUDED && RFCOMM_INCLUDED == TRUE)
\ No newline at end of file
#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
*/
p_port->tx.peer_fc = TRUE;
}
}
+
+
+#endif ///(defined RFCOMM_INCLUDED && RFCOMM_INCLUDED == TRUE)
\ No newline at end of file
#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,
}
}
+
+#endif ///(defined RFCOMM_INCLUDED && RFCOMM_INCLUDED == TRUE)
\ No newline at end of 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
*/
{
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
#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
*******************************************************************************/
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) {
}
}
}
+
+#endif ///(defined RFCOMM_INCLUDED && RFCOMM_INCLUDED == TRUE)
\ No newline at end of file
#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 */
}
}
+#endif ///(defined RFCOMM_INCLUDED && RFCOMM_INCLUDED == TRUE)
\ No newline at end of file
#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
}
+#endif ///(defined RFCOMM_INCLUDED && RFCOMM_INCLUDED == TRUE)
\ No newline at end of file
#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)
/*******************************************************************************
**
}
}
+#endif ///(defined RFCOMM_INCLUDED && RFCOMM_INCLUDED == TRUE)
\ No newline at end of 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
return (NULL);
}
-
+void osi_free_fun(void *p){
+ osi_free(p);
+}
/*******************************************************************************
**
** Function rfc_release_multiplexer_channel
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;
{
RFCOMM_TRACE_EVENT ("rfc_port_timer_stop");
- btu_stop_timer (&p_port->rfc.tle);
+ btu_free_timer (&p_port->rfc.tle);
}
}
+#endif ///(defined RFCOMM_INCLUDED && RFCOMM_INCLUDED == TRUE)
\ No newline at end of file
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 \
bluedroid/bta/av \
bluedroid/bta/ar \
bluedroid/bta/sys \
+ bluedroid/bta/jv \
bluedroid/bta \
bluedroid/btcore \
bluedroid/btif \
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 \
bluedroid/stack/avrc \
bluedroid/stack/avdt \
bluedroid/stack/a2dp \
+ bluedroid/stack/rfcomm \
bluedroid/stack \
bluedroid/utils \
bluedroid/api \
## 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
##
BT GAP <esp_gap_bt>
BT A2DP <esp_a2dp>
BT AVRC <esp_avrc>
+ BT SPP <esp_spp>
--- /dev/null
+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
+
# Classic BT is enabled and BT_DRAM_RELEASE is disabled
CONFIG_BT_ENABLED=y
CONFIG_CLASSIC_BT_ENABLED=y
+CONFIG_A2DP_SNK_ENABLED=y
+
--- /dev/null
+#
+# 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
--- /dev/null
+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
--- /dev/null
+#
+# "main" pseudo-component makefile.
+#
+# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)
--- /dev/null
+// 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;
+ }
+}
+
--- /dev/null
+# 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
--- /dev/null
+#
+# 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
--- /dev/null
+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
--- /dev/null
+#
+# "main" pseudo-component makefile.
+#
+# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)
--- /dev/null
+// 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;
+ }
+}
+
--- /dev/null
+# 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