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