Merge branch 'feature/add_l2cap_ertm_api' into 'master'

Component_bt:Add l2cap and sdp api

Closes IDF-4487

See merge request espressif/esp-idf!18034
This commit is contained in:
Jiang Jiang Jian 2022-05-29 17:34:38 +08:00
commit 4ed2e6130a
48 changed files with 5087 additions and 100 deletions

View File

@ -113,6 +113,8 @@ if(CONFIG_BT_ENABLED)
"host/bluedroid/api/esp_hf_ag_api.c"
"host/bluedroid/api/esp_hf_client_api.c"
"host/bluedroid/api/esp_spp_api.c"
"host/bluedroid/api/esp_sdp_api.c"
"host/bluedroid/api/esp_l2cap_bt_api.c"
"host/bluedroid/bta/ar/bta_ar.c"
"host/bluedroid/bta/av/bta_av_aact.c"
"host/bluedroid/bta/av/bta_av_act.c"
@ -214,6 +216,8 @@ if(CONFIG_BT_ENABLED)
"host/bluedroid/btc/profile/std/gatt/btc_gattc.c"
"host/bluedroid/btc/profile/std/gatt/btc_gatts.c"
"host/bluedroid/btc/profile/std/spp/btc_spp.c"
"host/bluedroid/btc/profile/std/sdp/btc_sdp.c"
"host/bluedroid/btc/profile/std/l2cap/btc_l2cap.c"
"host/bluedroid/device/bdaddr.c"
"host/bluedroid/device/controller.c"
"host/bluedroid/device/interop.c"

View File

@ -39,6 +39,12 @@
#if (BTC_SPP_INCLUDED == TRUE)
#include "btc_spp.h"
#endif /* #if (BTC_SPP_INCLUDED == TRUE) */
#if (BTC_L2CAP_INCLUDED == TRUE)
#include "btc_l2cap.h"
#endif /* #if (BTC_L2CAP_INCLUDED == TRUE) */
#if (BTC_SDP_INCLUDED == TRUE)
#include "btc_sdp.h"
#endif /* #if (BTC_SDP_INCLUDED == TRUE) */
#if BTC_HF_INCLUDED
#include "btc_hf_ag.h"
#endif/* #if BTC_HF_INCLUDED */
@ -112,6 +118,12 @@ static const btc_func_t profile_tab[BTC_PID_NUM] = {
#if (BTC_SPP_INCLUDED == TRUE)
[BTC_PID_SPP] = {btc_spp_call_handler, btc_spp_cb_handler },
#endif /* #if (BTC_SPP_INCLUDED == TRUE) */
#if (BTC_L2CAP_INCLUDED == TRUE)
[BTC_PID_L2CAP] = {btc_l2cap_call_handler, btc_l2cap_cb_handler },
#endif /* #if (BTC_L2CAP_INCLUDED == TRUE) */
#if (BTC_SDP_INCLUDED == TRUE)
[BTC_PID_SDP] = {btc_sdp_call_handler, btc_sdp_cb_handler },
#endif /* #if (BTC_SDP_INCLUDED == TRUE) */
#if BTC_HF_INCLUDED
[BTC_PID_HF] = {btc_hf_call_handler, btc_hf_cb_handler},
#endif /* #if BTC_HF_INCLUDED */

View File

@ -59,6 +59,8 @@ typedef enum {
BTC_PID_SPP,
BTC_PID_HD,
BTC_PID_HH,
BTC_PID_L2CAP,
BTC_PID_SDP,
#if (BTC_HF_INCLUDED == TRUE)
BTC_PID_HF,
#endif /* BTC_HF_INCLUDED */

View File

@ -61,6 +61,14 @@ config BT_SPP_ENABLED
help
This enables the Serial Port Profile
config BT_L2CAP_ENABLED
bool "BT L2CAP"
depends on BT_CLASSIC_ENABLED
default n
help
This enables the Logical Link Control and Adaptation Layer Protocol.
Only supported classic bluetooth.
config BT_HFP_ENABLE
bool "Hands Free/Handset Profile"
depends on BT_CLASSIC_ENABLED

View File

@ -0,0 +1,131 @@
/*
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <string.h>
#include "esp_bt_main.h"
#include "btc/btc_manage.h"
#include "btc_l2cap.h"
#include "esp_l2cap_bt_api.h"
#include "common/bt_target.h"
#if (defined BTC_L2CAP_INCLUDED && BTC_L2CAP_INCLUDED == TRUE)
esp_err_t esp_bt_l2cap_register_callback(esp_bt_l2cap_cb_t callback)
{
ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED);
if (callback == NULL) {
return ESP_FAIL;
}
btc_profile_cb_set(BTC_PID_L2CAP, callback);
return ESP_OK;
}
esp_err_t esp_bt_l2cap_init(void)
{
btc_msg_t msg;
ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED);
msg.sig = BTC_SIG_API_CALL;
msg.pid = BTC_PID_L2CAP;
msg.act = BTC_L2CAP_ACT_INIT;
return (btc_transfer_context(&msg, NULL, 0, NULL) == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL);
}
esp_err_t esp_bt_l2cap_deinit(void)
{
btc_msg_t msg;
ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED);
msg.sig = BTC_SIG_API_CALL;
msg.pid = BTC_PID_L2CAP;
msg.act = BTC_L2CAP_ACT_UNINIT;
return (btc_transfer_context(&msg, NULL, 0, NULL) == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL);
}
esp_err_t esp_bt_l2cap_connect(esp_bt_l2cap_cntl_flags_t cntl_flag, uint16_t remote_psm, esp_bd_addr_t peer_bd_addr)
{
btc_msg_t msg;
btc_l2cap_args_t arg;
ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED);
msg.sig = BTC_SIG_API_CALL;
msg.pid = BTC_PID_L2CAP;
msg.act = BTC_L2CAP_ACT_CONNECT;
arg.connect.sec_mask = (cntl_flag & 0xffff);
arg.connect.remote_psm = remote_psm;
memcpy(arg.connect.peer_bd_addr, peer_bd_addr, ESP_BD_ADDR_LEN);
return (btc_transfer_context(&msg, &arg, sizeof(btc_l2cap_args_t), NULL) == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL);
}
esp_err_t esp_bt_l2cap_start_srv(esp_bt_l2cap_cntl_flags_t cntl_flag, uint16_t local_psm)
{
btc_msg_t msg;
btc_l2cap_args_t arg;
ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED);
msg.sig = BTC_SIG_API_CALL;
msg.pid = BTC_PID_L2CAP;
msg.act = BTC_L2CAP_ACT_START_SRV;
arg.start_srv.sec_mask = (cntl_flag & 0xffff);
arg.start_srv.local_psm = local_psm;
return (btc_transfer_context(&msg, &arg, sizeof(btc_l2cap_args_t), NULL) == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL);
}
esp_err_t esp_bt_l2cap_stop_all_srv(void)
{
btc_msg_t msg;
btc_l2cap_args_t arg;
ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED);
msg.sig = BTC_SIG_API_CALL;
msg.pid = BTC_PID_L2CAP;
msg.act = BTC_L2CAP_ACT_STOP_SRV;
arg.stop_srv.psm = BTC_L2CAP_INVALID_PSM;
return (btc_transfer_context(&msg, &arg, sizeof(btc_l2cap_args_t), NULL) == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL);
}
esp_err_t esp_bt_l2cap_stop_srv(uint16_t local_psm)
{
btc_msg_t msg;
btc_l2cap_args_t arg;
ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED);
msg.sig = BTC_SIG_API_CALL;
msg.pid = BTC_PID_L2CAP;
msg.act = BTC_L2CAP_ACT_STOP_SRV;
arg.stop_srv.psm = local_psm;
return (btc_transfer_context(&msg, &arg, sizeof(btc_l2cap_args_t), NULL) == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL);
}
esp_err_t esp_bt_l2cap_vfs_register(void)
{
ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED);
return btc_l2cap_vfs_register();
}
esp_err_t esp_bt_l2cap_vfs_unregister(void)
{
ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED);
return btc_l2cap_vfs_unregister();
}
#endif ///defined BTC_L2CAP_INCLUDED && BTC_L2CAP_INCLUDED == TRUE

View File

@ -0,0 +1,129 @@
/*
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <string.h>
#include "esp_bt_main.h"
#include "btc/btc_manage.h"
#include "btc_sdp.h"
#include "esp_sdp_api.h"
#include "common/bt_target.h"
#if (defined BTC_SDP_INCLUDED && BTC_SDP_INCLUDED == TRUE)
esp_err_t esp_sdp_register_callback(esp_sdp_cb_t callback)
{
ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED);
if (callback == NULL) {
return ESP_FAIL;
}
btc_profile_cb_set(BTC_PID_SDP, callback);
return ESP_OK;
}
esp_err_t esp_sdp_init(void)
{
ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED);
btc_msg_t msg;
bt_status_t stat;
msg.sig = BTC_SIG_API_CALL;
msg.pid = BTC_PID_SDP;
msg.act = BTC_SDP_ACT_INIT;
/* Switch to BTC context */
stat = btc_transfer_context(&msg, NULL, 0, NULL);
return (stat == BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL;
}
esp_err_t esp_sdp_deinit(void)
{
ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED);
btc_msg_t msg;
bt_status_t stat;
msg.sig = BTC_SIG_API_CALL;
msg.pid = BTC_PID_SDP;
msg.act = BTC_SDP_ACT_DEINIT;
/* Switch to BTC context */
stat = btc_transfer_context(&msg, NULL, 0, NULL);
return (stat == BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL;
}
esp_err_t esp_sdp_search_record(esp_bd_addr_t bd_addr, esp_bt_uuid_t uuid)
{
ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED);
btc_msg_t msg;
bt_status_t stat;
btc_sdp_args_t arg;
msg.sig = BTC_SIG_API_CALL;
msg.pid = BTC_PID_SDP;
msg.act = BTC_SDP_ACT_SEARCH;
memset(&arg, 0, sizeof(btc_sdp_args_t));
memcpy(arg.search.bd_addr, bd_addr, ESP_BD_ADDR_LEN);
arg.search.sdp_uuid.len = uuid.len;
memcpy(&arg.search.sdp_uuid.uu, &uuid.uuid, sizeof(uuid.uuid));
/* Switch to BTC context */
stat = btc_transfer_context(&msg, &arg, sizeof(btc_sdp_args_t), NULL);
return (stat == BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL;
}
esp_err_t esp_sdp_create_record(esp_bluetooth_sdp_record_t *record)
{
ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED);
if (record == NULL || record->hdr.service_name_length > ESP_SDP_SERVER_NAME_MAX
|| strlen(record->hdr.service_name)+1 != record->hdr.service_name_length) {
LOG_ERROR("Invalid server name!\n");
return ESP_ERR_INVALID_ARG;
}
btc_msg_t msg;
bt_status_t stat;
btc_sdp_args_t arg;
msg.sig = BTC_SIG_API_CALL;
msg.pid = BTC_PID_SDP;
msg.act = BTC_SDP_ACT_CREATE_RECORD;
memset(&arg, 0, sizeof(btc_sdp_args_t));
arg.creat_record.record = (bluetooth_sdp_record *)record;
/* Switch to BTC context */
stat = btc_transfer_context(&msg, &arg, sizeof(btc_sdp_args_t), btc_sdp_arg_deep_copy);
return (stat == BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL;
}
esp_err_t esp_sdp_remove_record(int record_handle)
{
ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED);
btc_msg_t msg;
bt_status_t stat;
btc_sdp_args_t arg;
msg.sig = BTC_SIG_API_CALL;
msg.pid = BTC_PID_SDP;
msg.act = BTC_SDP_ACT_REMOVE_RECORD;
arg.remove_record.record_handle = record_handle;
/* Switch to BTC context */
stat = btc_transfer_context(&msg, &arg, sizeof(btc_sdp_args_t), NULL);
return (stat == BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL;
}
#endif ///defined BTC_SDP_INCLUDED && BTC_SDP_INCLUDED == TRUE

View File

@ -0,0 +1,251 @@
/*
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef __ESP_L2CAP_BT_API_H__
#define __ESP_L2CAP_BT_API_H__
#include "esp_err.h"
#include "esp_bt_defs.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief L2CAP operation success and failure codes
*/
typedef enum {
ESP_BT_L2CAP_SUCCESS = 0, /*!< Successful operation. */
ESP_BT_L2CAP_FAILURE, /*!< Generic failure. */
ESP_BT_L2CAP_BUSY, /*!< Temporarily can not handle this request. */
ESP_BT_L2CAP_NO_RESOURCE, /*!< No more resource */
ESP_BT_L2CAP_NEED_INIT, /*!< L2CAP module shall init first */
ESP_BT_L2CAP_NEED_DEINIT, /*!< L2CAP module shall deinit first */
ESP_BT_L2CAP_NO_CONNECTION, /*!< Connection may have been closed */
ESP_BT_L2CAP_NO_SERVER, /*!< No server */
} esp_bt_l2cap_status_t;
/**
* @brief Security Setting Mask. Use these three mask mode:
* 1. ESP_BT_L2CAP_SEC_NONE
* 2. ESP_BT_L2CAP_SEC_AUTHENTICATE
* 3. (ESP_BT_L2CAP_SEC_ENCRYPT|ESP_BT_L2CAP_SEC_AUTHENTICATE)
*/
#define ESP_BT_L2CAP_SEC_NONE 0x0000 /*!< No security */
#define ESP_BT_L2CAP_SEC_AUTHORIZE 0x0001 /*!< Authorization required */
#define ESP_BT_L2CAP_SEC_AUTHENTICATE 0x0012 /*!< Authentication required */
#define ESP_BT_L2CAP_SEC_ENCRYPT 0x0024 /*!< Encryption required */
typedef uint32_t esp_bt_l2cap_cntl_flags_t;
/**
* @brief L2CAP callback function events
*/
typedef enum {
ESP_BT_L2CAP_INIT_EVT = 0, /*!< When L2CAP is inited, the event comes */
ESP_BT_L2CAP_UNINIT_EVT = 1, /*!< When L2CAP is uninited, the event comes */
ESP_BT_L2CAP_OPEN_EVT = 16, /*!< When L2CAP Client connection open, the event comes */
ESP_BT_L2CAP_CLOSE_EVT = 17, /*!< When L2CAP connection closed, the event comes */
ESP_BT_L2CAP_START_EVT = 18, /*!< When L2CAP server started, the event comes */
ESP_BT_L2CAP_CL_INIT_EVT = 19, /*!< When L2CAP client initiated a connection, the event comes */
ESP_BT_L2CAP_SRV_STOP_EVT = 36, /*!< When L2CAP server stopped, the event comes */
} esp_bt_l2cap_cb_event_t;
/**
* @brief L2CAP callback parameters union
*/
typedef union {
/**
* @brief ESP_BT_L2CAP_INIT_EVT
*/
struct l2cap_init_evt_param {
esp_bt_l2cap_status_t status; /*!< status */
} init; /*!< L2CAP callback param of ESP_BT_L2CAP_INIT_EVT */
/**
* @brief ESP_BT_L2CAP_UNINIT_EVT
*/
struct l2cap_uninit_evt_param {
esp_bt_l2cap_status_t status; /*!< status */
} uninit; /*!< L2CAP callback param of ESP_BT_L2CAP_UNINIT_EVT */
/**
* @brief ESP_BT_L2CAP_OPEN_EVT
*/
struct l2cap_open_evt_param {
esp_bt_l2cap_status_t status; /*!< status */
uint32_t handle; /*!< The connection handle */
int fd; /*!< File descriptor */
esp_bd_addr_t rem_bda; /*!< The peer address */
int32_t tx_mtu; /*!< The transmit MTU */
} open; /*!< L2CAP callback param of ESP_BT_L2CAP_OPEN_EVT */
/**
* @brief ESP_BT_L2CAP_CLOSE_EVT
*/
struct l2cap_close_evt_param {
esp_bt_l2cap_status_t status; /*!< status */
uint32_t handle; /*!< The connection handle */
bool async; /*!< FALSE, if local initiates disconnect */
} close; /*!< L2CAP callback param of ESP_BT_L2CAP_CLOSE_EVT */
/**
* @brief ESP_BT_L2CAP_START_EVT
*/
struct l2cap_start_evt_param {
esp_bt_l2cap_status_t status; /*!< status */
uint32_t handle; /*!< The connection handle */
uint8_t sec_id; /*!< security ID used by this server */
} start; /*!< L2CAP callback param of ESP_BT_L2CAP_START_EVT */
/**
* @brief ESP_BT_L2CAP_CL_INIT_EVT
*/
struct l2cap_cl_init_evt_param {
esp_bt_l2cap_status_t status; /*!< status */
uint32_t handle; /*!< The connection handle */
uint8_t sec_id; /*!< security ID used by this server */
} cl_init; /*!< L2CAP callback param of ESP_BT_L2CAP_CL_INIT_EVT */
/**
* @brief ESP_BT_L2CAP_SRV_STOP_EVT
*/
struct l2cap_srv_stop_evt_param {
esp_bt_l2cap_status_t status; /*!< status */
uint8_t psm; /*!< local psm */
} srv_stop; /*!< L2CAP callback param of ESP_BT_L2CAP_SRV_STOP_EVT */
} esp_bt_l2cap_cb_param_t;
/**
* @brief L2CAP callback function type.
*
* @param event: Event type
* @param param: Point to callback parameter, currently is union type
*/
typedef void (* esp_bt_l2cap_cb_t)(esp_bt_l2cap_cb_event_t event, esp_bt_l2cap_cb_param_t *param);
/**
* @brief This function is called to init callbacks with L2CAP module.
*
* @param[in] callback: pointer to the init callback function.
*
* @return
* - ESP_OK: success
* - other: failed
*/
esp_err_t esp_bt_l2cap_register_callback(esp_bt_l2cap_cb_t callback);
/**
* @brief This function is called to init L2CAP module.
* When the operation is completed, the callback function will be called with ESP_BT_L2CAP_INIT_EVT.
* This function should be called after esp_bluedroid_enable() completes successfully.
*
* @return
* - ESP_OK: success
* - other: failed
*/
esp_err_t esp_bt_l2cap_init(void);
/**
* @brief This function is called to uninit l2cap module.
* The operation will close all active L2CAP connection first, then the callback function will be called
* with ESP_BT_L2CAP_CLOSE_EVT, and the number of ESP_BT_L2CAP_CLOSE_EVT is equal to the number of connection.
* When the operation is completed, the callback function will be called with ESP_BT_L2CAP_UNINIT_EVT.
* This function should be called after esp_bt_l2cap_init() completes successfully.
*
* @return
* - ESP_OK: success
* - other: failed
*/
esp_err_t esp_bt_l2cap_deinit(void);
/**
* @brief This function makes an L2CAP connection to a remote BD Address.
* When the connection is initiated or failed to initiate, the callback is called with ESP_BT_L2CAP_CL_INIT_EVT.
* When the connection is established or failed, the callback is called with ESP_BT_L2CAP_OPEN_EVT.
* This funciton must be called after esp_bt_l2cap_init() successful and before esp_bt_l2cap_deinit().
*
* @param[in] cntl_flag: Lower 16-bit security settings mask.
* @param[in] remote_psm: Remote device bluetooth Profile PSM.
* @param[in] peer_bd_addr: Remote device bluetooth device address.
*
* @return
* - ESP_OK: success
* - other: failed
*/
esp_err_t esp_bt_l2cap_connect(esp_bt_l2cap_cntl_flags_t cntl_flag, uint16_t remote_psm, esp_bd_addr_t peer_bd_addr);
/**
* @brief This function create a L2CAP server and starts listening for an
* L2CAP connection request from a remote Bluetooth device.
* When the server is started successfully, the callback is called with ESP_BT_L2CAP_START_EVT.
* When the connection is established, the callback is called with ESP_BT_L2CAP_OPEN_EVT.
* This funciton must be called after esp_bt_l2cap_init() successful and before esp_bt_l2cap_deinit().
*
* @param[in] cntl_flag: Lower 16-bit security settings mask.
* @param[in] local_psm: Dynamic PSM.
*
* @return
* - ESP_OK: success
* - other: failed
*/
esp_err_t esp_bt_l2cap_start_srv(esp_bt_l2cap_cntl_flags_t cntl_flag, uint16_t local_psm);
/**
* @brief This function stops all L2CAP servers.
* The operation will close all active L2CAP connection first, then the callback function will be called
* with ESP_BT_L2CAP_CLOSE_EVT, and the number of ESP_BT_L2CAP_CLOSE_EVT is equal to the number of connection.
* When the operation is completed, the callback is called with ESP_BT_L2CAP_SRV_STOP_EVT.
* This funciton must be called after esp_bt_l2cap_init() successful and before esp_bt_l2cap_deinit().
*
* @return
* - ESP_OK: success
* - other: failed
*/
esp_err_t esp_bt_l2cap_stop_all_srv(void);
/**
* @brief This function stops a specific L2CAP server.
* The operation will close all active L2CAP connection first on the specific L2CAP server, then the callback function will
* be called with ESP_BT_L2CAP_CLOSE_EVT, and the number of ESP_BT_L2CAP_CLOSE_EVT is equal to the number of connection.
* When the operation is completed, the callback is called with ESP_BT_L2CAP_SRV_STOP_EVT.
* This funciton must be called after esp_bt_l2cap_init() successful and before esp_bt_l2cap_deinit().
*
* @param[in] local_psm: Dynamic PSM.
*
* @return
* - ESP_OK: success
* - other: failed
*/
esp_err_t esp_bt_l2cap_stop_srv(uint16_t local_psm);
/**
* @brief This function is used to register VFS.
* Only supports write, read and close.
* This funciton must be called after esp_bt_l2cap_init() successful and before esp_bt_l2cap_deinit().
*
* @return
* - ESP_OK: success
* - other: failed
*/
esp_err_t esp_bt_l2cap_vfs_register(void);
/**
* @brief This function is used to unregister VFS.
* This funciton must be called after esp_bt_l2cap_init() successful and before esp_bt_l2cap_deinit().
*
* @return
* - ESP_OK: success
* - other: failed
*/
esp_err_t esp_bt_l2cap_vfs_unregister(void);
#ifdef __cplusplus
}
#endif
#endif ///__ESP_L2CAP_BT_API_H__

View File

@ -0,0 +1,271 @@
/*
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef __ESP_SDP_API_H__
#define __ESP_SDP_API_H__
#include "esp_err.h"
#include "esp_bt_defs.h"
#ifdef __cplusplus
extern "C" {
#endif
#define ESP_SDP_SERVER_NAME_MAX 32 /*!< Service name max length */
#define SDP_OPP_SUPPORTED_FORMATS_MAX_LENGTH 15 /*!< OPP supported format list maximum length */
typedef enum {
ESP_SDP_SUCCESS = 0, /*!< Successful operation. */
ESP_SDP_FAILURE, /*!< Generic failure. */
ESP_SDP_NO_RESOURCE, /*!< No more resource */
ESP_SDP_NEED_INIT, /*!< SDP module shall init first */
ESP_SDP_NEED_DEINIT, /*!< SDP module shall deinit first */
ESP_SDP_NO_CREATE_RECORD, /*!< No record created */
} esp_sdp_status_t;
/**
* @brief SDP callback function events
*/
typedef enum {
ESP_SDP_INIT_EVT = 0, /*!< When SDP is inited, the event comes */
ESP_SDP_DEINIT_EVT = 1, /*!< When SDP is deinited, the event comes */
ESP_SDP_SEARCH_COMP_EVT = 2, /*!< When SDP search complete, the event comes */
ESP_SDP_CREATE_RECORD_COMP_EVT = 3, /*!< When create SDP records complete, the event comes */
ESP_SDP_REMOVE_RECORD_COMP_EVT = 4, /*!< When remove a SDP record complete, the event comes */
} esp_sdp_cb_event_t;
/**
* @brief SDP record type
*/
typedef enum {
ESP_SDP_TYPE_RAW, /*!< Used to carry raw SDP search data for unknown UUIDs */
ESP_SDP_TYPE_MAP_MAS, /*!< Message Access Profile - Server */
ESP_SDP_TYPE_MAP_MNS, /*!< Message Access Profile - Client (Notification Server) */
ESP_SDP_TYPE_PBAP_PSE, /*!< Phone Book Profile - Server */
ESP_SDP_TYPE_PBAP_PCE, /*!< Phone Book Profile - Client */
ESP_SDP_TYPE_OPP_SERVER, /*!< Object Push Profile */
ESP_SDP_TYPE_SAP_SERVER /*!< SIM Access Profile */
} esp_bluetooth_sdp_types_t;
/**
* @brief Some signals need additional pointers, hence we introduce a
* generic way to handle these pointers.
*/
typedef struct bluetooth_sdp_hdr_overlay {
esp_bluetooth_sdp_types_t type; /*!< SDP type */
esp_bt_uuid_t uuid; /*!< UUID type include uuid and uuid length */
uint32_t service_name_length; /*!< Service name length */
char *service_name; /*!< service name */
int32_t rfcomm_channel_number; /*!< rfcomm channel number, if not used set to -1*/
int32_t l2cap_psm; /*!< l2cap psm, if not used set to -1 */
int32_t profile_version; /*!< profile version */
// User pointers, only used for some signals - see esp_bluetooth_sdp_ops_record_t
int user1_ptr_len; /*!< see esp_bluetooth_sdp_ops_record_t */
uint8_t *user1_ptr; /*!< see esp_bluetooth_sdp_ops_record_t */
int user2_ptr_len; /*!< see esp_bluetooth_sdp_ops_record_t */
uint8_t *user2_ptr; /*!< see esp_bluetooth_sdp_ops_record_t */
} esp_bluetooth_sdp_hdr_overlay_t;
/**
* @brief Message Access Profile - Server parameters
*/
typedef struct bluetooth_sdp_mas_record {
esp_bluetooth_sdp_hdr_overlay_t hdr; /*!< General info */
uint32_t mas_instance_id; /*!< MAS Instance ID */
uint32_t supported_features; /*!< Map supported features */
uint32_t supported_message_types; /*!< Supported message types */
} esp_bluetooth_sdp_mas_record_t;
/**
* @brief Message Access Profile - Client (Notification Server) parameters
*/
typedef struct bluetooth_sdp_mns_record {
esp_bluetooth_sdp_hdr_overlay_t hdr; /*!< General info */
uint32_t supported_features; /*!< Supported features */
} esp_bluetooth_sdp_mns_record_t;
/**
* @brief Phone Book Profile - Server parameters
*/
typedef struct bluetooth_sdp_pse_record {
esp_bluetooth_sdp_hdr_overlay_t hdr; /*!< General info */
uint32_t supported_features; /*!< Pbap Supported Features */
uint32_t supported_repositories; /*!< Supported Repositories */
} esp_bluetooth_sdp_pse_record_t;
/**
* @brief Phone Book Profile - Client parameters
*/
typedef struct bluetooth_sdp_pce_record {
esp_bluetooth_sdp_hdr_overlay_t hdr; /*!< General info */
} esp_bluetooth_sdp_pce_record_t;
/**
* @brief Object Push Profile parameters
*/
typedef struct bluetooth_sdp_ops_record {
esp_bluetooth_sdp_hdr_overlay_t hdr; /*!< General info */
int supported_formats_list_len; /*!< Supported formats list length */
uint8_t supported_formats_list[SDP_OPP_SUPPORTED_FORMATS_MAX_LENGTH]; /*!< Supported formats list */
} esp_bluetooth_sdp_ops_record_t;
/**
* @brief SIM Access Profile parameters
*/
typedef struct bluetooth_sdp_sap_record {
esp_bluetooth_sdp_hdr_overlay_t hdr; /*!< General info */
} esp_bluetooth_sdp_sap_record_t;
/**
* @brief SDP record parameters union
*/
typedef union {
esp_bluetooth_sdp_hdr_overlay_t hdr; /*!< General info */
esp_bluetooth_sdp_mas_record_t mas; /*!< Message Access Profile - Server */
esp_bluetooth_sdp_mns_record_t mns; /*!< Message Access Profile - Client (Notification Server) */
esp_bluetooth_sdp_pse_record_t pse; /*!< Phone Book Profile - Server */
esp_bluetooth_sdp_pce_record_t pce; /*!< Phone Book Profile - Client */
esp_bluetooth_sdp_ops_record_t ops; /*!< Object Push Profile */
esp_bluetooth_sdp_sap_record_t sap; /*!< SIM Access Profile */
} esp_bluetooth_sdp_record_t;
/**
* @brief SDP callback parameters union
*/
typedef union {
/**
* @brief ESP_SDP_INIT_EVT
*/
struct sdp_init_evt_param {
esp_sdp_status_t status; /*!< status */
} init; /*!< SDP callback param of ESP_SDP_INIT_EVT */
/**
* @brief ESP_SDP_DEINIT_EVT
*/
struct sdp_deinit_evt_param {
esp_sdp_status_t status; /*!< status */
} deinit; /*!< SDP callback param of ESP_SDP_DEINIT_EVT */
/**
* @brief ESP_SDP_SEARCH_COMP_EVT
*/
struct sdp_search_evt_param {
esp_sdp_status_t status; /*!< status */
esp_bd_addr_t remote_addr; /*!< remote device address */
esp_bt_uuid_t sdp_uuid; /*!< service uuid */
int record_count; /*!< Number of SDP records */
esp_bluetooth_sdp_record_t *records;/*!< SDP records */
} search; /*!< SDP callback param of ESP_SDP_SEARCH_COMP_EVT */
/**
* @brief ESP_SDP_CREATE_RECORD_COMP_EVT
*/
struct sdp_crate_record_evt_param {
esp_sdp_status_t status; /*!< status */
int record_handle; /*!< SDP record handle */
} create_record; /*!< SDP callback param of ESP_SDP_CREATE_RECORD_COMP_EVT */
/**
* @brief ESP_SDP_REMOVE_RECORD_COMP_EVT
*/
struct sdp_remove_record_evt_param {
esp_sdp_status_t status; /*!< status */
} remove_record; /*!< SDP callback param of ESP_SDP_REMOVE_RECORD_COMP_EVT */
} esp_sdp_cb_param_t; /*!< SDP callback parameter union type */
/**
* @brief SDP callback function type.
*
* @param event: Event type
* @param param: Point to callback parameter, currently is union type
*/
typedef void (* esp_sdp_cb_t)(esp_sdp_cb_event_t event, esp_sdp_cb_param_t *param);
/**
* @brief This function is called to init callbacks with SDP module.
*
* @param[in] callback: pointer to the init callback function.
*
* @return
* - ESP_OK: success
* - other: failed
*/
esp_err_t esp_sdp_register_callback(esp_sdp_cb_t callback);
/**
* @brief This function is called to init SDP module.
* When the operation is completed, the callback function will be called with ESP_SDP_INIT_EVT.
* This function should be called after esp_bluedroid_enable() completes successfully.
*
* @return
* - ESP_OK: success
* - other: failed
*/
esp_err_t esp_sdp_init(void);
/**
* @brief This function is called to de-initialize SDP module.
* The operation will remove all SDP records, then the callback function will be called
* with ESP_SDP_REMOVE_RECORD_COMP_EVT, and the number of ESP_SDP_REMOVE_RECORD_COMP_EVT is
* equal to the number of SDP records.When the operation is completed, the callback function
* will be called with ESP_SDP_DEINIT_EVT. This function should be called after esp_sdp_init()
* completes successfully.
*
* @return
* - ESP_OK: success
* - other: failed
*/
esp_err_t esp_sdp_deinit(void);
/**
* @brief This function is called to performs service discovery for the services provided by the given peer device.
* When the operation is completed, the callback function will be called with ESP_SDP_SEARCH_COMP_EVT.
* This funciton must be called after esp_sdp_init() successful and before esp_sdp_deinit().
*
* @param[in] bd_addr: Remote device bluetooth device address.
* @param[in] uuid: Service UUID of the remote device.
*
* @return
* - ESP_OK: success
* - other: failed
*/
esp_err_t esp_sdp_search_record(esp_bd_addr_t bd_addr, esp_bt_uuid_t uuid);
/**
* @brief This function is called to create SDP records.
* When the operation is completed, the callback function will be called with ESP_SDP_CREATE_RECORD_COMP_EVT.
* This funciton must be called after esp_sdp_init() successful and before esp_sdp_deinit().
*
* @param[in] record: The SDP record to create.
*
* @return
* - ESP_OK: success
* - other: failed
*/
esp_err_t esp_sdp_create_record(esp_bluetooth_sdp_record_t *record);
/**
* @brief This function is called to remove a SDP record.
* When the operation is completed, the callback function will be called with ESP_SDP_REMOVE_RECORD_COMP_EVT.
* This funciton must be called after esp_sdp_init() successful and before esp_sdp_deinit().
*
* @param[in] record_handle: The SDP record handle.
*
* @return
* - ESP_OK: success
* - other: failed
*/
esp_err_t esp_sdp_remove_record(int record_handle);
#ifdef __cplusplus
}
#endif
#endif ///__ESP_SDP_API_H__

View File

@ -42,6 +42,7 @@
#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 */
#define BTA_JV_ALREADY_DONE 5 /* already done, repeat the operation */
typedef UINT8 tBTA_JV_STATUS;
#define BTA_JV_INTERNAL_ERR (-1) /* internal error. */
@ -150,6 +151,7 @@ typedef UINT8 tBTA_JV_CONN_STATE;
#endif /* BTA_JV_L2CAP_INCLUDED */
/* events received by tBTA_JV_RFCOMM_CBACK */
#if BTA_JV_RFCOMM_INCLUDED
#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 */
@ -159,6 +161,7 @@ typedef UINT8 tBTA_JV_CONN_STATE;
#define BTA_JV_RFCOMM_READ_EVT 32 /* the result for BTA_JvRfcommRead */
#define BTA_JV_RFCOMM_WRITE_EVT 33 /* the result for BTA_JvRfcommWrite*/
#define BTA_JV_RFCOMM_SRV_OPEN_EVT 34 /* open status of Server RFCOMM connection */
#endif /* BTA_JV_RFCOMM_INCLUDED */
#define BTA_JV_FREE_SCN_EVT 35 /* FREE an SCN */
#define BTA_JV_MAX_EVT 36 /* max number of JV events */
@ -198,6 +201,7 @@ typedef struct {
tBTA_JV_STATUS status; /* Whether the operation succeeded or failed. */
UINT32 handle; /* The connection handle */
BOOLEAN async; /* FALSE, if local initiates disconnect */
void * user_data; /* piggyback caller's private data */
} tBTA_JV_L2CAP_CLOSE;
/* data associated with BTA_JV_L2CAP_START_EVT */
@ -278,6 +282,7 @@ typedef struct {
} tBTA_JV_L2CAP_WRITE_FIXED;
#endif /* BTA_JV_L2CAP_INCLUDED */
#if BTA_JV_RFCOMM_INCLUDED
/* data associated with BTA_JV_RFCOMM_OPEN_EVT */
typedef struct {
tBTA_JV_STATUS status; /* Whether the operation succeeded or failed. */
@ -319,12 +324,6 @@ typedef struct {
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_RFCOMM_CONG_EVT */
typedef struct {
tBTA_JV_STATUS status; /* Whether the operation succeeded or failed. */
@ -351,6 +350,13 @@ typedef struct {
BOOLEAN cong; /* congestion status */
BOOLEAN old_cong; /* congestion status */
} tBTA_JV_RFCOMM_WRITE;
#endif /* BTA_JV_RFCOMM_INCLUDED */
/*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_API_SET_PM_PROFILE_EVT */
typedef struct {
@ -402,6 +408,7 @@ typedef union {
tBTA_JV_L2CAP_READ l2c_read; /* BTA_JV_L2CAP_READ_EVT */
tBTA_JV_L2CAP_WRITE l2c_write; /* BTA_JV_L2CAP_WRITE_EVT */
#endif /* BTA_JV_L2CAP_INCLUDED */
#if BTA_JV_RFCOMM_INCLUDED
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 */
@ -410,6 +417,7 @@ typedef union {
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 */
#endif /* BTA_JV_RFCOMM_INCLUDED */
tBTA_JV_DATA_IND data_ind; /* BTA_JV_L2CAP_DATA_IND_EVT
BTA_JV_RFCOMM_DATA_IND_EVT */
tBTA_JV_FREE_SCN free_scn; /* BTA_JV_FREE_SCN_EVT */
@ -428,7 +436,7 @@ typedef void *(tBTA_JV_RFCOMM_CBACK)(tBTA_JV_EVT event, tBTA_JV *p_data, void *u
#if BTA_JV_L2CAP_INCLUDED
/* JAVA L2CAP interface callback */
typedef void (tBTA_JV_L2CAP_CBACK)(tBTA_JV_EVT event, tBTA_JV *p_data, void *user_Data);
typedef void *(tBTA_JV_L2CAP_CBACK)(tBTA_JV_EVT event, tBTA_JV *p_data, void *user_Data);
#endif /* BTA_JV_L2CAP_INCLUDED */
/* JV configuration structure */
@ -636,7 +644,7 @@ extern tBTA_JV_STATUS BTA_JvL2capConnect(tBTA_SEC sec_mask, tBTA_JV_ROLE role,
** BTA_JV_FAILURE, otherwise.
**
*******************************************************************************/
extern tBTA_JV_STATUS BTA_JvL2capClose(UINT32 handle);
extern tBTA_JV_STATUS BTA_JvL2capClose(UINT32 handle, tBTA_JV_L2CAP_CBACK *p_cback, void *user_data);
/*******************************************************************************
**
@ -724,12 +732,10 @@ extern tBTA_JV_STATUS BTA_JvL2capStopServer(UINT16 local_psm, void *user_data);
** 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.
** Returns Length of read data.
**
*******************************************************************************/
extern tBTA_JV_STATUS BTA_JvL2capRead(UINT32 handle, UINT32 req_id,
UINT8 *p_data, UINT16 len);
extern int BTA_JvL2capRead(UINT32 handle, UINT32 req_id, UINT8 *p_data, UINT16 len);
/*******************************************************************************
**
@ -795,6 +801,7 @@ extern tBTA_JV_STATUS BTA_JvL2capWriteFixed(UINT16 channel, BD_ADDR *addr, UINT3
UINT8 *p_data, UINT16 len, void *user_data);
#endif /* BTA_JV_L2CAP_INCLUDED */
#if BTA_JV_RFCOMM_INCLUDED
/*******************************************************************************
**
** Function BTA_JvRfcommConnect
@ -911,6 +918,19 @@ extern tBTA_JV_STATUS BTA_JvRfcommWrite(UINT32 handle, UINT32 req_id, int len, U
*******************************************************************************/
extern tBTA_JV_STATUS BTA_JvRfcommFlowControl(UINT32 handle, UINT16 credits_given);
/*******************************************************************************
**
** 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 /* BTA_JV_RFCOMM_INCLUDED */
/*******************************************************************************
**
** Function BTA_JVSetPmProfile
@ -932,17 +952,5 @@ extern tBTA_JV_STATUS BTA_JvRfcommFlowControl(UINT32 handle, UINT16 credits_give
*******************************************************************************/
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 */

View File

@ -40,12 +40,13 @@ typedef UINT8 tBTA_SDP_STATUS;
/* SDP I/F callback events */
/* events received by tBTA_SDP_DM_CBACK */
#define BTA_SDP_ENABLE_EVT 0 /* SDP service i/f enabled*/
#define BTA_SDP_SEARCH_EVT 1 /* SDP Service started */
#define BTA_SDP_SEARCH_COMP_EVT 2 /* SDP search complete */
#define BTA_SDP_CREATE_RECORD_USER_EVT 3 /* SDP search complete */
#define BTA_SDP_REMOVE_RECORD_USER_EVT 4 /* SDP search complete */
#define BTA_SDP_MAX_EVT 5 /* max number of SDP events */
#define BTA_SDP_ENABLE_EVT 0 /* SDP service enabled*/
#define BTA_SDP_DISENABLE_EVT 1 /* SDP service disenabled*/
#define BTA_SDP_SEARCH_EVT 2 /* SDP search started */
#define BTA_SDP_SEARCH_COMP_EVT 3 /* SDP search complete */
#define BTA_SDP_CREATE_RECORD_USER_EVT 4 /* SDP create record complete */
#define BTA_SDP_REMOVE_RECORD_USER_EVT 5 /* SDP remove reocrd complete */
#define BTA_SDP_MAX_EVT 6 /* max number of SDP events */
#define BTA_SDP_MAX_RECORDS 15
@ -63,6 +64,7 @@ typedef struct {
typedef union {
tBTA_SDP_STATUS status; /* BTA_SDP_SEARCH_EVT */
tBTA_SDP_SEARCH_COMP sdp_search_comp; /* BTA_SDP_SEARCH_COMP_EVT */
int handle;
} tBTA_SDP;
/* SDP DM Interface callback */

View File

@ -107,17 +107,19 @@ static inline void logu(const char *title, const uint8_t *p_uuid)
}
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);
#if BTA_JV_RFCOMM_INCLUDED
static tBTA_JV_PCB *bta_jv_add_rfc_port(tBTA_JV_RFC_CB *p_cb, tBTA_JV_PCB *p_pcb_open);
static int find_rfc_pcb(void *user_data, tBTA_JV_RFC_CB **cb, tBTA_JV_PCB **pcb);
static void bta_jv_port_mgmt_sr_cback(UINT32 code, UINT16 port_handle, void* data);
static void bta_jv_port_event_sr_cback(UINT32 code, UINT16 port_handle);
static int bta_jv_port_data_co_cback(UINT16 port_handle, UINT8 *buf, UINT16 len, int type);
#endif /* BTA_JV_RFCOMM_INCLUDED */
/*******************************************************************************
**
** Function bta_jv_alloc_sec_id
@ -156,6 +158,7 @@ UNUSED_ATTR static int get_sec_id_used(void)
}
return used;
}
#if BTA_JV_RFCOMM_INCLUDED
UNUSED_ATTR static int get_rfc_cb_used(void)
{
int i;
@ -171,6 +174,7 @@ UNUSED_ATTR static int get_rfc_cb_used(void)
}
return used;
}
#endif /* BTA_JV_RFCOMM_INCLUDED */
/*******************************************************************************
**
@ -191,6 +195,7 @@ static void bta_jv_free_sec_id(UINT8 *p_sec_id)
}
}
#if BTA_JV_RFCOMM_INCLUDED
/*******************************************************************************
**
** Function bta_jv_alloc_rfc_cb
@ -431,6 +436,8 @@ static tBTA_JV_STATUS bta_jv_free_rfc_cb(tBTA_JV_RFC_CB *p_cb, tBTA_JV_PCB *p_pc
}
return status;
}
#endif /* BTA_JV_RFCOMM_INCLUDED */
#if BTA_JV_L2CAP_INCLUDED
/*******************************************************************************
**
@ -525,6 +532,7 @@ static tBTA_JV_STATUS bta_jv_free_set_pm_profile_cb(UINT32 jv_handle)
}
if (BTA_JV_RFCOMM_MASK & jv_handle) {
#if BTA_JV_RFCOMM_INCLUDED
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
@ -538,6 +546,7 @@ static tBTA_JV_STATUS bta_jv_free_set_pm_profile_cb(UINT32 jv_handle)
p_cb = &p_pcb->p_pm_cb;
}
}
#endif /* BTA_JV_RFCOMM_INCLUDED */
}
#if BTA_JV_L2CAP_INCLUDED
else {
@ -582,6 +591,7 @@ static tBTA_JV_PM_CB *bta_jv_alloc_set_pm_profile_cb(UINT32 jv_handle, tBTA_JV_P
if (bta_jv_cb.pm_cb[i].state == BTA_JV_PM_FREE_ST) {
/* rfc handle bd addr retrieval requires core stack handle */
if (bRfcHandle) {
#if BTA_JV_RFCOMM_INCLUDED
// 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++) {
@ -594,6 +604,7 @@ static tBTA_JV_PM_CB *bta_jv_alloc_set_pm_profile_cb(UINT32 jv_handle, tBTA_JV_P
break;
}
}
#endif /* BTA_JV_RFCOMM_INCLUDED */
}
#if BTA_JV_L2CAP_INCLUDED
else {
@ -855,20 +866,39 @@ void bta_jv_free_scn(tBTA_JV_MSG *p_data)
};
tBTA_JV_FREE_SCN_USER_DATA *user_data = NULL;
#if BTA_JV_RFCOMM_INCLUDED
tBTA_JV_RFC_CB *p_cb = NULL;
tBTA_JV_PCB *p_pcb = NULL;
#endif /* BTA_JV_RFCOMM_INCLUDED */
switch (p_data->free_channel.type) {
case BTA_JV_CONN_TYPE_RFCOMM: {
#if BTA_JV_RFCOMM_INCLUDED
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);
}
if (fc->user_data) {
user_data = (tBTA_JV_FREE_SCN_USER_DATA *)fc->user_data;
evt_data.server_status = user_data->server_status;
if (user_data->server_status == BTA_JV_SERVER_RUNNING && find_rfc_pcb((void *)user_data->slot_id, &p_cb, &p_pcb)) {
/* if call bta_jv_rfcomm_stop_server successfully, find_rfc_pcb shall return false */
evt_data.status = BTA_JV_FAILURE;
}
if (fc->p_cback) {
fc->p_cback(BTA_JV_FREE_SCN_EVT, (tBTA_JV *)&evt_data, (void *)user_data);
}
}
#endif /* BTA_JV_RFCOMM_INCLUDED */
break;
}
case BTA_JV_CONN_TYPE_L2CAP:
bta_jv_set_free_psm(scn);
if (fc->p_cback) {
fc->p_cback(BTA_JV_FREE_SCN_EVT, (tBTA_JV *)&evt_data, (void *)user_data);
}
break;
case BTA_JV_CONN_TYPE_L2CAP_LE:
// TODO: Not yet implemented...
@ -876,20 +906,6 @@ void bta_jv_free_scn(tBTA_JV_MSG *p_data)
default:
break;
}
if (fc->user_data)
{
user_data = (tBTA_JV_FREE_SCN_USER_DATA *)fc->user_data;
evt_data.server_status = user_data->server_status;
if (user_data->server_status == BTA_JV_SERVER_RUNNING && find_rfc_pcb((void *)user_data->slot_id, &p_cb, &p_pcb)) {
/* if call bta_jv_rfcomm_stop_server successfully, find_rfc_pcb shall return false */
evt_data.status = BTA_JV_FAILURE;
}
if (fc->p_cback) {
fc->p_cback(BTA_JV_FREE_SCN_EVT, (tBTA_JV *)&evt_data, (void *)user_data);
}
}
}
static inline tBT_UUID shorten_sdp_uuid(const tBT_UUID *u)
{
@ -1271,7 +1287,7 @@ void bta_jv_l2cap_connect(tBTA_JV_MSG *p_data)
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;
chan_mode_mask |= GAP_FCR_CHAN_OPT_ERTM;
}
}
@ -1331,15 +1347,14 @@ 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;
void *user_data = cc->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);
if (cc->p_cback) {
cc->p_cback(BTA_JV_L2CAP_CLOSE_EVT, (tBTA_JV *)&evt_data, user_data);
}
}
@ -1430,7 +1445,7 @@ void bta_jv_l2cap_start_server(tBTA_JV_MSG *p_data)
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;
chan_mode_mask |= GAP_FCR_CHAN_OPT_ERTM;
}
}
@ -1615,6 +1630,7 @@ void bta_jv_l2cap_write_fixed(tBTA_JV_MSG *p_data)
}
#endif /* BTA_JV_L2CAP_INCLUDED */
#if BTA_JV_RFCOMM_INCLUDED
/*******************************************************************************
**
** Function bta_jv_port_data_co_cback
@ -2345,6 +2361,7 @@ void bta_jv_rfcomm_flow_control(tBTA_JV_MSG *p_data)
tBTA_JV_PCB *p_pcb = fc->p_pcb;
PORT_FlowControl_GiveCredit(p_pcb->port_handle, TRUE, fc->credits_given);
}
#endif /* BTA_JV_RFCOMM_INCLUDED */
/*******************************************************************************
**
@ -2854,7 +2871,7 @@ void bta_jv_l2cap_connect_le(tBTA_JV_MSG *p_data)
id = t->id;
t->init_called = FALSE;
if (L2CA_ConnectFixedChnl(t->chan, t->remote_addr, BLE_ADDR_UNKNOWN_TYPE)) {
if (L2CA_ConnectFixedChnl(t->chan, t->remote_addr, BLE_ADDR_UNKNOWN_TYPE, FALSE)) {
evt.l2c_cl_init.status = BTA_JV_SUCCESS;
evt.l2c_cl_init.handle = id;

View File

@ -98,7 +98,7 @@ tBTA_JV_STATUS BTA_JvEnable(tBTA_JV_DM_CBACK *p_cback)
APPL_TRACE_ERROR("No p_cback.");
} else {
APPL_TRACE_WARNING("No need to Init again.");
// status = BTA_JV_SUCCESS;
status = BTA_JV_ALREADY_DONE;
}
return (status);
}
@ -467,7 +467,7 @@ tBTA_JV_STATUS BTA_JvL2capConnect(tBTA_SEC sec_mask, tBTA_JV_ROLE role,
** BTA_JV_FAILURE, otherwise.
**
*******************************************************************************/
tBTA_JV_STATUS BTA_JvL2capClose(UINT32 handle)
tBTA_JV_STATUS BTA_JvL2capClose(UINT32 handle, tBTA_JV_L2CAP_CBACK *p_cback, void *user_data)
{
tBTA_JV_STATUS status = BTA_JV_FAILURE;
tBTA_JV_API_L2CAP_CLOSE *p_msg;
@ -479,6 +479,8 @@ tBTA_JV_STATUS BTA_JvL2capClose(UINT32 handle)
p_msg->hdr.event = BTA_JV_API_L2CAP_CLOSE_EVT;
p_msg->handle = handle;
p_msg->p_cb = &bta_jv_cb.l2c_cb[handle];
p_msg->p_cback = p_cback;
p_msg->user_data = user_data;
bta_sys_sendmsg(p_msg);
status = BTA_JV_SUCCESS;
}
@ -684,20 +686,16 @@ 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.
** Returns Length of read data.
**
*******************************************************************************/
tBTA_JV_STATUS BTA_JvL2capRead(UINT32 handle, UINT32 req_id, UINT8 *p_data, UINT16 len)
int 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;
@ -711,7 +709,7 @@ tBTA_JV_STATUS BTA_JvL2capRead(UINT32 handle, UINT32 req_id, UINT8 *p_data, UINT
BTA_JV_L2CAP_READ_EVT, (tBTA_JV *)&evt_data, bta_jv_cb.l2c_cb[handle].user_data);
}
return (status);
return (evt_data.len);
}
/*******************************************************************************
@ -863,6 +861,7 @@ tBTA_JV_STATUS BTA_JvL2capWriteFixed(UINT16 channel, BD_ADDR *addr, UINT32 req_i
}
#endif /* BTA_JV_L2CAP_INCLUDED */
#if BTA_JV_RFCOMM_INCLUDED
/*******************************************************************************
**
** Function BTA_JvRfcommConnect
@ -1168,6 +1167,7 @@ tBTA_JV_STATUS BTA_JvRfcommFlowControl(UINT32 handle, UINT16 credits_given)
}
return (status);
}
#endif /* BTA_JV_RFCOMM_INCLUDED */
/*******************************************************************************
**

View File

@ -62,6 +62,7 @@ const tBTA_JV_ACTION bta_jv_action[] = {
bta_jv_l2cap_read, /* BTA_JV_API_L2CAP_READ_EVT */
bta_jv_l2cap_write, /* BTA_JV_API_L2CAP_WRITE_EVT */
#endif /* BTA_JV_L2CAP_INCLUDED */
#if BTA_JV_RFCOMM_INCLUDED
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 */
@ -69,6 +70,7 @@ const tBTA_JV_ACTION bta_jv_action[] = {
bta_jv_rfcomm_read, /* BTA_JV_API_RFCOMM_READ_EVT */
bta_jv_rfcomm_write, /* BTA_JV_API_RFCOMM_WRITE_EVT */
bta_jv_rfcomm_flow_control, /* BTA_JV_API_RFCOMM_FLOW_CONTROL_EVT */
#endif /* BTA_JV_RFCOMM_INCLUDED */
bta_jv_set_pm_profile, /* BTA_JV_API_SET_PM_PROFILE_EVT */
bta_jv_change_pm_state, /* BTA_JV_API_PM_STATE_CHANGE_EVT */
#if BTA_JV_L2CAP_INCLUDED

View File

@ -56,6 +56,7 @@ enum {
BTA_JV_API_L2CAP_READ_EVT,
BTA_JV_API_L2CAP_WRITE_EVT,
#endif /* BTA_JV_L2CAP_INCLUDED */
#if BTA_JV_RFCOMM_INCLUDED
BTA_JV_API_RFCOMM_CONNECT_EVT,
BTA_JV_API_RFCOMM_CLOSE_EVT,
BTA_JV_API_RFCOMM_START_SERVER_EVT,
@ -63,6 +64,7 @@ enum {
BTA_JV_API_RFCOMM_READ_EVT,
BTA_JV_API_RFCOMM_WRITE_EVT,
BTA_JV_API_RFCOMM_FLOW_CONTROL_EVT,
#endif /* BTA_JV_RFCOMM_INCLUDED */
BTA_JV_API_SET_PM_PROFILE_EVT,
BTA_JV_API_PM_STATE_CHANGE_EVT,
#if BTA_JV_L2CAP_INCLUDED
@ -159,6 +161,7 @@ typedef struct {
tBTA_JV_PM_CB *p_pm_cb; /* ptr to pm control block, NULL: unused */
} tBTA_JV_PCB;
#if BTA_JV_RFCOMM_INCLUDED
/* JV RFCOMM control block */
typedef struct {
tBTA_JV_RFCOMM_CBACK *p_cback; /* the callback function */
@ -169,6 +172,7 @@ typedef struct {
UINT8 max_sess; /* max sessions */
int curr_sess; /* current sessions count*/
} tBTA_JV_RFC_CB;
#endif /* BTA_JV_RFCOMM_INCLUDED */
#if BTA_JV_L2CAP_INCLUDED
/* data type for BTA_JV_API_L2CAP_CONNECT_EVT & BTA_JV_API_L2CAP_CONNECT_LE_EVT */
@ -213,6 +217,8 @@ typedef struct {
BT_HDR hdr;
UINT32 handle;
tBTA_JV_L2C_CB *p_cb;
tBTA_JV_L2CAP_CBACK *p_cback;
void *user_data;
} tBTA_JV_API_L2CAP_CLOSE;
/* data type for BTA_JV_API_L2CAP_READ_EVT */
@ -250,6 +256,7 @@ typedef struct {
} tBTA_JV_API_L2CAP_WRITE_FIXED;
#endif /* BTA_JV_L2CAP_INCLUDED */
#if BTA_JV_RFCOMM_INCLUDED
/* data type for BTA_JV_API_RFCOMM_CONNECT_EVT */
typedef struct {
BT_HDR hdr;
@ -283,6 +290,7 @@ typedef struct {
tBTA_JV_RFC_CB *p_cb;
tBTA_JV_PCB *p_pcb;
} tBTA_JV_API_RFCOMM_READ;
#endif /* BTA_JV_RFCOMM_INCLUDED */
/* data type for BTA_JV_API_SET_PM_PROFILE_EVT */
typedef struct {
@ -299,6 +307,7 @@ typedef struct {
tBTA_JV_CONN_STATE state;
} tBTA_JV_API_PM_STATE_CHANGE;
#if BTA_JV_RFCOMM_INCLUDED
/* data type for BTA_JV_API_RFCOMM_WRITE_EVT */
typedef struct {
BT_HDR hdr;
@ -327,6 +336,7 @@ typedef struct {
tBTA_JV_RFCOMM_CBACK *p_cback;
void *user_data;
} tBTA_JV_API_RFCOMM_CLOSE;
#endif /* BTA_JV_RFCOMM_INCLUDED */
/* data type for BTA_JV_API_CREATE_RECORD_EVT */
typedef struct {
@ -381,14 +391,16 @@ typedef union {
tBTA_JV_API_L2CAP_SERVER l2cap_server;
tBTA_JV_API_L2CAP_WRITE_FIXED l2cap_write_fixed;
#endif /* BTA_JV_L2CAP_INCLUDED */
#if BTA_JV_RFCOMM_INCLUDED
tBTA_JV_API_RFCOMM_CONNECT rfcomm_connect;
tBTA_JV_API_RFCOMM_READ rfcomm_read;
tBTA_JV_API_RFCOMM_WRITE rfcomm_write;
tBTA_JV_API_RFCOMM_FLOW_CONTROL rfcomm_fc;
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;
#endif /* BTA_JV_RFCOMM_INCLUDED */
tBTA_JV_API_SET_PM_PROFILE set_pm;
tBTA_JV_API_PM_STATE_CHANGE change_pm_state;
} tBTA_JV_MSG;
/* JV control block */
@ -402,7 +414,9 @@ typedef struct {
#if BTA_JV_L2CAP_INCLUDED
tBTA_JV_L2C_CB l2c_cb[BTA_JV_MAX_L2C_CONN]; /* index is GAP handle (index) */
#endif /* BTA_JV_L2CAP_INCLUDED */
#if BTA_JV_RFCOMM_INCLUDED
tBTA_JV_RFC_CB rfc_cb[BTA_JV_MAX_RFC_CONN];
#endif /* BTA_JV_RFCOMM_INCLUDED */
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 */
@ -448,6 +462,7 @@ 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);
#endif /* BTA_JV_L2CAP_INCLUDED */
#if BTA_JV_RFCOMM_INCLUDED
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);
@ -455,6 +470,7 @@ 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_rfcomm_flow_control(tBTA_JV_MSG *p_data);
#endif /* BTA_JV_RFCOMM_INCLUDED */
extern void bta_jv_set_pm_profile (tBTA_JV_MSG *p_data);
extern void bta_jv_change_pm_state(tBTA_JV_MSG *p_data);
#if BTA_JV_L2CAP_INCLUDED

View File

@ -50,6 +50,9 @@ static const uint8_t UUID_OBEX_OBJECT_PUSH[] = {0x00, 0x00, 0x11, 0x05, 0x00, 0
static const uint8_t UUID_PBAP_PSE[] = {0x00, 0x00, 0x11, 0x2F, 0x00, 0x00, 0x10, 0x00,
0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB
};
static const uint8_t UUID_PBAP_PCE[] = {0x00, 0x00, 0x11, 0x2E, 0x00, 0x00, 0x10, 0x00,
0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB
};
static const uint8_t UUID_MAP_MAS[] = {0x00, 0x00, 0x11, 0x32, 0x00, 0x00, 0x10, 0x00,
0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB
};
@ -223,6 +226,28 @@ static void bta_create_pse_sdp_record(bluetooth_sdp_record *record, tSDP_DISC_RE
}
}
static void bta_create_pce_sdp_record(bluetooth_sdp_record *record, tSDP_DISC_REC *p_rec)
{
tSDP_DISC_ATTR *p_attr;
UINT16 pversion;
record->pce.hdr.type = SDP_TYPE_PBAP_PCE;
record->pce.hdr.service_name_length = 0;
record->pce.hdr.service_name = NULL;
record->pce.hdr.rfcomm_channel_number = 0; // unused
record->pce.hdr.l2cap_psm = -1; // unused
record->pce.hdr.profile_version = 0;
if ((p_attr = SDP_FindAttributeInRec(p_rec, ATTR_ID_SERVICE_NAME)) != NULL) {
record->pce.hdr.service_name_length = SDP_DISC_ATTR_LEN(p_attr->attr_len_type);
record->pce.hdr.service_name = (char *)p_attr->attr_value.v.array;
}
if (SDP_FindProfileVersionInRec(p_rec, UUID_SERVCLASS_PHONE_ACCESS, &pversion)) {
record->pce.hdr.profile_version = pversion;
}
}
static void bta_create_ops_sdp_record(bluetooth_sdp_record *record, tSDP_DISC_REC *p_rec)
{
tSDP_DISC_ATTR *p_attr, *p_sattr;
@ -342,6 +367,10 @@ static void bta_create_raw_sdp_record(bluetooth_sdp_record *record, tSDP_DISC_RE
record->pse.hdr.service_name = (char *)p_attr->attr_value.v.array;
}
if ((p_attr = SDP_FindAttributeInRec(p_rec, ATTR_ID_GOEP_L2CAP_PSM)) != NULL) {
record->hdr.l2cap_psm = p_attr->attr_value.v.u16;
}
/* Try to extract an RFCOMM channel */
if (SDP_FindProtocolListElemInRec(p_rec, UUID_PROTOCOL_RFCOMM, &pe)) {
record->pse.hdr.rfcomm_channel_number = pe.params[0];
@ -395,6 +424,9 @@ static void bta_sdp_search_cback(UINT16 result, void *user_data)
} else if (IS_UUID(UUID_PBAP_PSE, uuid->uu.uuid128)) {
APPL_TRACE_DEBUG("%s() - found PBAP (PSE) uuid\n", __func__);
bta_create_pse_sdp_record(&evt_data.records[count], p_rec);
} else if (IS_UUID(UUID_PBAP_PCE, uuid->uu.uuid128)) {
APPL_TRACE_DEBUG("%s() - found PBAP (PCE) uuid\n", __func__);
bta_create_pce_sdp_record(&evt_data.records[count], p_rec);
} else if (IS_UUID(UUID_OBEX_OBJECT_PUSH, uuid->uu.uuid128)) {
APPL_TRACE_DEBUG("%s() - found Object Push Server (OPS) uuid\n", __func__);
bta_create_ops_sdp_record(&evt_data.records[count], p_rec);
@ -439,9 +471,10 @@ static void bta_sdp_search_cback(UINT16 result, void *user_data)
void bta_sdp_enable(tBTA_SDP_MSG *p_data)
{
APPL_TRACE_DEBUG("%s in, sdp_active:%d\n", __func__, bta_sdp_cb.sdp_active);
tBTA_SDP_STATUS status = BTA_SDP_SUCCESS;
tBTA_SDP bta_sdp;
bta_sdp.status = BTA_SDP_SUCCESS;
bta_sdp_cb.p_dm_cback = p_data->enable.p_cback;
bta_sdp_cb.p_dm_cback(BTA_SDP_ENABLE_EVT, (tBTA_SDP *)&status, NULL);
bta_sdp_cb.p_dm_cback(BTA_SDP_ENABLE_EVT, (tBTA_SDP *)&bta_sdp, NULL);
}
/*******************************************************************************
@ -523,8 +556,11 @@ void bta_sdp_search(tBTA_SDP_MSG *p_data)
void bta_sdp_create_record(tBTA_SDP_MSG *p_data)
{
APPL_TRACE_DEBUG("%s() event: %d\n", __func__, p_data->record.hdr.event);
tBTA_SDP bta_sdp;
bta_sdp.status = BTA_SDP_SUCCESS;
bta_sdp.handle = (int)p_data->record.user_data;
if (bta_sdp_cb.p_dm_cback) {
bta_sdp_cb.p_dm_cback(BTA_SDP_CREATE_RECORD_USER_EVT, NULL, p_data->record.user_data);
bta_sdp_cb.p_dm_cback(BTA_SDP_CREATE_RECORD_USER_EVT, &bta_sdp, p_data->record.user_data);
}
}
@ -540,8 +576,10 @@ void bta_sdp_create_record(tBTA_SDP_MSG *p_data)
void bta_sdp_remove_record(tBTA_SDP_MSG *p_data)
{
APPL_TRACE_DEBUG("%s() event: %d\n", __func__, p_data->record.hdr.event);
tBTA_SDP bta_sdp;
bta_sdp.status = BTA_SDP_SUCCESS;
if (bta_sdp_cb.p_dm_cback) {
bta_sdp_cb.p_dm_cback(BTA_SDP_REMOVE_RECORD_USER_EVT, NULL, p_data->record.user_data);
bta_sdp_cb.p_dm_cback(BTA_SDP_REMOVE_RECORD_USER_EVT, &bta_sdp, p_data->record.user_data);
}
}

View File

@ -102,6 +102,8 @@ tBTA_SDP_STATUS BTA_SdpEnable(tBTA_SDP_DM_CBACK *p_cback)
tBTA_SDP_STATUS BTA_SdpDisable(void)
{
tBTA_SDP_STATUS status = BTA_SDP_SUCCESS;
bta_sys_deregister(BTA_ID_SDP);
#if BTA_DYNAMIC_MEMORY == TRUE
/* Free buffer for SDP configuration structure */
osi_free(p_bta_sdp_cfg->p_sdp_db);

View File

@ -20,6 +20,7 @@
#include <stdint.h>
// #include "bluetooth.h"
#include "common/bt_defs.h"
#include "esp_bt_defs.h"
#define SDP_OPP_SUPPORTED_FORMATS_MAX_LENGTH 15
@ -38,7 +39,7 @@ typedef enum {
typedef struct _bluetooth_sdp_hdr {
bluetooth_sdp_types type;
bt_uuid_t uuid;
esp_bt_uuid_t uuid;
uint32_t service_name_length;
char *service_name;
int32_t rfcomm_channel_number;
@ -52,7 +53,7 @@ typedef struct _bluetooth_sdp_hdr {
*/
typedef struct _bluetooth_sdp_hdr_overlay {
bluetooth_sdp_types type;
bt_uuid_t uuid;
esp_bt_uuid_t bt_uuid;
uint32_t service_name_length;
char *service_name;
int32_t rfcomm_channel_number;

View File

@ -0,0 +1,72 @@
/*
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef __BTC_L2CAP_H__
#define __BTC_L2CAP_H__
#include "btc/btc_task.h"
#include "esp_bt_defs.h"
#include "esp_l2cap_bt_api.h"
#include "common/bt_target.h"
#include "bta/bta_jv_api.h"
#if (defined BTC_L2CAP_INCLUDED && BTC_L2CAP_INCLUDED == TRUE)
#define BTC_L2CAP_INVALID_PSM 0x00
typedef enum {
BTC_L2CAP_ACT_INIT = 0,
BTC_L2CAP_ACT_UNINIT,
BTC_L2CAP_ACT_START_DISCOVERY,
BTC_L2CAP_ACT_CONNECT,
BTC_L2CAP_ACT_START_SRV,
BTC_L2CAP_ACT_STOP_SRV,
} btc_l2cap_act_t;
/* btc_l2cap_args_t */
typedef union {
//BTC_L2CAP_ACT_INIT
struct l2cap_init_arg {
} init;
//BTC_L2CAP_ACT_UNINIT
struct l2cap_uninit_arg {
} uninit;
//BTC_L2CAP_ACT_START_DISCOVERY
struct l2cap_start_discovery_arg {
BD_ADDR bd_addr;
UINT16 num_uuid;
tSDP_UUID *p_uuid_list;
} start_discovery;
//BTC_L2CAP_ACT_CONNECT
struct l2cap_connect_arg {
UINT16 sec_mask;
UINT16 remote_psm;
esp_bd_addr_t peer_bd_addr;
} connect;
//BTC_L2CAP_ACT_START_SRV
struct l2cap_start_srv_arg {
UINT16 sec_mask;
UINT16 local_psm;
} start_srv;
//BTC_L2CAP_ACT_STOP_SRV
struct l2cap_stop_srv_arg {
UINT16 psm;
} stop_srv;
} btc_l2cap_args_t;
void btc_l2cap_call_handler(btc_msg_t *msg);
void btc_l2cap_cb_handler(btc_msg_t *msg);
esp_err_t btc_l2cap_vfs_register(void);
esp_err_t btc_l2cap_vfs_unregister(void);
#endif ///defined BTC_L2CAP_INCLUDED && BTC_L2CAP_INCLUDED == TRUE
#endif ///__BTC_L2CAP_H__

View File

@ -0,0 +1,53 @@
/*
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef __BTC_SDP_H__
#define __BTC_SDP_H__
#include "btc/btc_task.h"
#include "esp_bt_defs.h"
#include "common/bt_target.h"
#include "bta/bta_sdp_api.h"
#include "bt_sdp.h"
#if (defined BTC_SDP_INCLUDED && BTC_SDP_INCLUDED == TRUE)
typedef enum {
BTC_SDP_ACT_INIT = 0,
BTC_SDP_ACT_DEINIT,
BTC_SDP_ACT_SEARCH,
BTC_SDP_ACT_CREATE_RECORD,
BTC_SDP_ACT_REMOVE_RECORD,
} btc_sdp_act_t;
/* btc_sdp_args_t */
typedef union {
//BTC_SDP_ACT_SEARCH
struct search_record_arg {
BD_ADDR bd_addr;
tSDP_UUID sdp_uuid;
} search;
//BTC_SDP_ACT_CREATE_RECORD
struct creat_record_arg {
bluetooth_sdp_record *record;
} creat_record;
//BTC_SDP_ACT_REMOVE_RECORD
struct remove_record_arg {
int record_handle;
} remove_record;
} btc_sdp_args_t;
void btc_sdp_arg_deep_copy(btc_msg_t *msg, void *p_dest, void *p_src);
void btc_sdp_arg_deep_free(btc_msg_t *msg);
void btc_sdp_call_handler(btc_msg_t *msg);
void btc_sdp_cb_handler(btc_msg_t *msg);
#endif ///defined BTC_SDP_INCLUDED && BTC_SDP_INCLUDED == TRUE
#endif ///__BTC_SDP_H__

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -106,7 +106,7 @@ static int init_slot_data(slot_data_t *slot_data, size_t queue_size)
return 0;
}
void free_slot_data(slot_data_t *slot_data)
static void free_slot_data(slot_data_t *slot_data)
{
fixed_queue_free(slot_data->queue, spp_osi_free);
slot_data->queue = NULL;

View File

@ -45,6 +45,13 @@
#define UC_BT_SPP_ENABLED FALSE
#endif
//L2CAP
#ifdef CONFIG_BT_L2CAP_ENABLED
#define UC_BT_L2CAP_ENABLED CONFIG_BT_L2CAP_ENABLED
#else
#define UC_BT_L2CAP_ENABLED FALSE
#endif
//HFP(AG)
#ifdef CONFIG_BT_HFP_AG_ENABLE
#define UC_BT_HFP_AG_ENABLED CONFIG_BT_HFP_AG_ENABLE

View File

@ -80,13 +80,22 @@
#if (UC_BT_SPP_ENABLED == TRUE)
#define RFCOMM_INCLUDED TRUE
#define BTA_JV_INCLUDED TRUE
#define BTA_JV_RFCOMM_INCLUDED TRUE
#define BTC_SPP_INCLUDED TRUE
#endif /* UC_BT_SPP_ENABLED */
#if (UC_BT_L2CAP_ENABLED == TRUE)
#define BTA_JV_INCLUDED TRUE
#define BTC_L2CAP_INCLUDED TRUE
#define BTC_SDP_INCLUDED TRUE
#define VND_BT_JV_BTA_L2CAP TRUE
#endif /* UC_BT_L2CAP_ENABLED */
#if (UC_BT_HFP_AG_ENABLED == TRUE)
#define BTC_HF_INCLUDED TRUE
#define BTA_AG_INCLUDED TRUE
#define PLC_INCLUDED TRUE
#define BTA_JV_RFCOMM_INCLUDED TRUE
#ifndef RFCOMM_INCLUDED
#define RFCOMM_INCLUDED TRUE
#endif
@ -1405,7 +1414,7 @@
/* The maximum number of attributes in each record. */
#ifndef SDP_MAX_REC_ATTR
#if defined(HID_DEV_INCLUDED) && (HID_DEV_INCLUDED==TRUE)
#if (defined(HID_DEV_INCLUDED) && (HID_DEV_INCLUDED==TRUE)) || (defined(BTC_SDP_INCLUDED) && (BTC_SDP_INCLUDED==TRUE))
#define SDP_MAX_REC_ATTR 25
#else
#define SDP_MAX_REC_ATTR 8
@ -1480,6 +1489,10 @@
#define RFCOMM_INCLUDED FALSE
#endif
#ifndef BTA_JV_RFCOMM_INCLUDED
#define BTA_JV_RFCOMM_INCLUDED FALSE
#endif
/* The maximum number of ports supported. */
#ifndef MAX_RFC_PORTS
#define MAX_RFC_PORTS 8 /*max is 30*/
@ -1557,6 +1570,31 @@
#define PORT_CREDIT_RX_LOW 8
#endif
/* ERTM Tx window size */
#ifndef RFC_FCR_OPT_TX_WINDOW_SIZE
#define RFC_FCR_OPT_TX_WINDOW_SIZE 20
#endif
/* ERTM Maximum transmissions before disconnecting */
#ifndef RFC_FCR_OPT_MAX_TX_B4_DISCNT
#define RFC_FCR_OPT_MAX_TX_B4_DISCNT 20
#endif
/* ERTM Retransmission timeout (2 secs) */
#ifndef RFC_FCR_OPT_RETX_TOUT
#define RFC_FCR_OPT_RETX_TOUT 2000
#endif
/* ERTM Monitor timeout (12 secs) */
#ifndef RFC_FCR_OPT_MONITOR_TOUT
#define RFC_FCR_OPT_MONITOR_TOUT 12000
#endif
/* ERTM ERTM MPS segment size */
#ifndef RFC_FCR_OPT_MAX_PDU_SIZE
#define RFC_FCR_OPT_MAX_PDU_SIZE 1010
#endif
/******************************************************************************
**
** OBEX
@ -1594,51 +1632,88 @@
#define OBX_FCR_TX_BUF_SIZE BT_DEFAULT_BUFFER_SIZE
#endif
/* This option is application when OBX_14_INCLUDED=TRUE
Size of the transmission window when using enhanced retransmission mode. Not used
in basic and streaming modes. Range: 1 - 63
*/
/*
* Size of the transmission window when using enhanced retransmission mode. Not used
* in basic and streaming modes. Range: 1 - 63
*/
#ifndef OBX_FCR_OPT_TX_WINDOW_SIZE_BR_EDR
#define OBX_FCR_OPT_TX_WINDOW_SIZE_BR_EDR 20
#endif
/* This option is application when OBX_14_INCLUDED=TRUE
Number of transmission attempts for a single I-Frame before taking
Down the connection. Used In ERTM mode only. Value is Ignored in basic and
Streaming modes.
Range: 0, 1-0xFF
0 - infinite retransmissions
1 - single transmission
*/
/*
* Number of transmission attempts for a single I-Frame before taking
* Down the connection. Used In ERTM mode only. Value is Ignored in basic and
* Streaming modes.
* Range: 0, 1-0xFF
* 0 - infinite retransmissions
* 1 - single transmission
*/
#ifndef OBX_FCR_OPT_MAX_TX_B4_DISCNT
#define OBX_FCR_OPT_MAX_TX_B4_DISCNT 20
#endif
/* This option is application when OBX_14_INCLUDED=TRUE
Retransmission Timeout
Range: Minimum 2000 (2 secs) on BR/EDR when supporting PBF.
/*
* Retransmission Timeout
* Range: Minimum 2000 (2 secs) on BR/EDR when supporting PBF.
*/
#ifndef OBX_FCR_OPT_RETX_TOUT
#define OBX_FCR_OPT_RETX_TOUT 2000
#endif
/* This option is application when OBX_14_INCLUDED=TRUE
Monitor Timeout
Range: Minimum 12000 (12 secs) on BR/EDR when supporting PBF.
*/
/*
* Monitor Timeout
* Range: Minimum 12000 (12 secs) on BR/EDR when supporting PBF.
*/
#ifndef OBX_FCR_OPT_MONITOR_TOUT
#define OBX_FCR_OPT_MONITOR_TOUT 12000
#endif
/* This option is application when OBX_14_INCLUDED=TRUE
Maximum PDU payload size.
Suggestion: The maximum amount of data that will fit into a 3-DH5 packet.
Range: 2 octets
/*
* Maximum PDU payload size.
* Suggestion: The maximum amount of data that will fit into a 3-DH5 packet.
* Range: 2 octets
*/
#ifndef OBX_FCR_OPT_MAX_PDU_SIZE
#define OBX_FCR_OPT_MAX_PDU_SIZE L2CAP_MPS_OVER_BR_EDR
#endif
/*
* Pool ID where to reassemble the SDU.
* This Pool will allow buffers to be used that are larger than
* the L2CAP_MAX_MTU.
*/
#ifndef OBX_USER_RX_POOL_ID
#define OBX_USER_RX_POOL_ID 4
#endif
/*
* Pool ID where to hold the SDU.
* This Pool will allow buffers to be used that are larger than
* the L2CAP_MAX_MTU.
*/
#ifndef OBX_USER_TX_POOL_ID
#define OBX_USER_TX_POOL_ID 4
#endif
/*
* GKI Buffer Pool ID used to hold MPS segments during SDU reassembly
*/
#ifndef OBX_FCR_RX_POOL_ID
#define OBX_FCR_RX_POOL_ID 3
#endif
/*
* Pool ID used to hold MPS segments used in (re)transmissions.
* L2CAP_DEFAULT_ERM_POOL_ID is specified to use the HCI ACL data pool.
* Note: This pool needs to have enough buffers to hold two times the window size negotiated
* in the L2CA_SetFCROptions (2 * tx_win_size) to allow for retransmissions.
* The size of each buffer must be able to hold the maximum MPS segment size passed in
* L2CA_SetFCROptions plus BT_HDR (8) + HCI preamble (4) + L2CAP_MIN_OFFSET (11 - as of BT 2.1 + EDR Spec).
*/
#ifndef OBX_FCR_TX_POOL_ID
#define OBX_FCR_TX_POOL_ID 3
#endif
/******************************************************************************
**

View File

@ -1559,7 +1559,7 @@ tL2C_CCB *l2cu_allocate_ccb (tL2C_LCB *p_lcb, UINT16 cid)
l2c_fcr_free_timer (p_ccb);
#endif ///CLASSIC_BT_INCLUDED == TRUE
p_ccb->ertm_info.preferred_mode = L2CAP_FCR_BASIC_MODE; /* Default mode for channel is basic mode */
p_ccb->ertm_info.allowed_modes = L2CAP_FCR_CHAN_OPT_BASIC; /* Default mode for channel is basic mode */
p_ccb->ertm_info.allowed_modes = L2CAP_FCR_CHAN_OPT_BASIC|L2CAP_FCR_CHAN_OPT_BASIC;
p_ccb->ertm_info.fcr_rx_buf_size = L2CAP_FCR_RX_BUF_SIZE;
p_ccb->ertm_info.fcr_tx_buf_size = L2CAP_FCR_TX_BUF_SIZE;
p_ccb->ertm_info.user_rx_buf_size = L2CAP_USER_RX_BUF_SIZE;

View File

@ -36,6 +36,17 @@
#include "osi/mutex.h"
#include "osi/alarm.h"
#if (defined RFCOMM_INCLUDED && RFCOMM_INCLUDED == TRUE)
static tL2CAP_ERTM_INFO rfc_l2c_etm_opt =
{
L2CAP_FCR_ERTM_MODE,
L2CAP_FCR_CHAN_OPT_ERTM|L2CAP_FCR_CHAN_OPT_BASIC, /* Some devices do not support ERTM */
L2CAP_USER_RX_BUF_SIZE,
L2CAP_USER_TX_BUF_SIZE,
L2CAP_FCR_RX_BUF_SIZE,
L2CAP_FCR_TX_BUF_SIZE
};
/*
** Define Callback functions to be called by L2CAP
*/
@ -117,7 +128,8 @@ void RFCOMM_ConnectInd (BD_ADDR bd_addr, UINT16 lcid, UINT16 psm, UINT8 id)
}
if (p_mcb == NULL) {
L2CA_ConnectRsp (bd_addr, id, lcid, L2CAP_CONN_NO_RESOURCES, 0);
// L2CA_ConnectRsp (bd_addr, id, lcid, L2CAP_CONN_NO_RESOURCES, 0);
L2CA_ErtmConnectRsp (bd_addr, id, lcid, L2CAP_CONN_NO_RESOURCES, 0, &rfc_l2c_etm_opt);
return;
}
p_mcb->lcid = lcid;
@ -178,7 +190,9 @@ void RFCOMM_ConnectCnf (UINT16 lcid, UINT16 result)
RFCOMM_TRACE_DEBUG ("RFCOMM_ConnectCnf peer gave up pending LCID(0x%x)", p_mcb->pending_lcid);
/* Peer gave up his connection request, make sure cleaning up L2CAP channel */
L2CA_ConnectRsp (p_mcb->bd_addr, p_mcb->pending_id, p_mcb->pending_lcid, L2CAP_CONN_NO_RESOURCES, 0);
// L2CA_ConnectRsp (p_mcb->bd_addr, p_mcb->pending_id, p_mcb->pending_lcid, L2CAP_CONN_NO_RESOURCES, 0);
L2CA_ErtmConnectRsp (p_mcb->bd_addr, p_mcb->pending_id, p_mcb->pending_lcid, L2CAP_CONN_NO_RESOURCES, 0,
&rfc_l2c_etm_opt);
p_mcb->pending_lcid = 0;
}

View File

@ -39,6 +39,25 @@
#define L2CAP_SUCCESS 0
#define L2CAP_ERROR 1
static tL2CAP_ERTM_INFO rfc_l2c_etm_opt =
{
L2CAP_FCR_ERTM_MODE,
L2CAP_FCR_CHAN_OPT_ERTM|L2CAP_FCR_CHAN_OPT_BASIC, /* Some devices do not support ERTM */
L2CAP_USER_RX_BUF_SIZE,
L2CAP_USER_TX_BUF_SIZE,
L2CAP_FCR_RX_BUF_SIZE,
L2CAP_FCR_TX_BUF_SIZE
};
static tL2CAP_FCR_OPTS rfc_l2c_fcr_opts_def =
{
L2CAP_FCR_ERTM_MODE,
RFC_FCR_OPT_TX_WINDOW_SIZE, /* Tx window size */
RFC_FCR_OPT_MAX_TX_B4_DISCNT, /* Maximum transmissions before disconnecting */
RFC_FCR_OPT_RETX_TOUT, /* Retransmission timeout (2 secs) */
RFC_FCR_OPT_MONITOR_TOUT, /* Monitor timeout (12 secs) */
RFC_FCR_OPT_MAX_PDU_SIZE /* MPS segment size */
};
/********************************************************************************/
/* L O C A L F U N C T I O N P R O T O T Y P E S */
@ -124,7 +143,8 @@ void rfc_mx_sm_state_idle (tRFC_MCB *p_mcb, UINT16 event, void *p_data)
/* Initialize L2CAP MTU */
p_mcb->peer_l2cap_mtu = L2CAP_DEFAULT_MTU - RFCOMM_MIN_OFFSET - 1;
if ((p_mcb->lcid = L2CA_ConnectReq (BT_PSM_RFCOMM, p_mcb->bd_addr)) == 0) {
// if ((p_mcb->lcid = L2CA_ConnectReq (BT_PSM_RFCOMM, p_mcb->bd_addr)) == 0) {
if ((p_mcb->lcid = L2CA_ErtmConnectReq (BT_PSM_RFCOMM, p_mcb->bd_addr, &rfc_l2c_etm_opt)) == 0) {
PORT_StartCnf (p_mcb, RFCOMM_ERROR);
return;
}
@ -144,7 +164,8 @@ void rfc_mx_sm_state_idle (tRFC_MCB *p_mcb, UINT16 event, void *p_data)
case RFC_MX_EVENT_CONN_IND:
rfc_timer_start (p_mcb, RFCOMM_CONN_TIMEOUT);
L2CA_ConnectRsp (p_mcb->bd_addr, *((UINT8 *)p_data), p_mcb->lcid, L2CAP_CONN_OK, 0);
// L2CA_ConnectRsp (p_mcb->bd_addr, *((UINT8 *)p_data), p_mcb->lcid, L2CAP_CONN_OK, 0);
L2CA_ErtmConnectRsp (p_mcb->bd_addr, *((UINT8 *)p_data), p_mcb->lcid, L2CAP_CONN_OK, 0, &rfc_l2c_etm_opt);
rfc_mx_send_config_req (p_mcb);
@ -482,7 +503,8 @@ void rfc_mx_sm_state_disc_wait_ua (tRFC_MCB *p_mcb, UINT16 event, void *p_data)
if (p_mcb->restart_required) {
/* Start Request was received while disconnecting. Execute it again */
if ((p_mcb->lcid = L2CA_ConnectReq (BT_PSM_RFCOMM, p_mcb->bd_addr)) == 0) {
// if ((p_mcb->lcid = L2CA_ConnectReq (BT_PSM_RFCOMM, p_mcb->bd_addr)) == 0) {
if ((p_mcb->lcid = L2CA_ErtmConnectReq (BT_PSM_RFCOMM, p_mcb->bd_addr, &rfc_l2c_etm_opt)) == 0) {
PORT_StartCnf (p_mcb, RFCOMM_ERROR);
return;
}
@ -554,6 +576,9 @@ static void rfc_mx_send_config_req (tRFC_MCB *p_mcb)
cfg.mtu_present = TRUE;
cfg.mtu = L2CAP_MTU_SIZE;
cfg.fcr_present = TRUE;
cfg.fcr = rfc_l2c_fcr_opts_def;
/* Defaults set by memset
cfg.flush_to_present = FALSE;
cfg.qos_present = FALSE;

View File

@ -40,6 +40,8 @@ CLASSIC_BT_DOCS = ['api-reference/bluetooth/classic_bt.rst',
'api-reference/bluetooth/esp_a2dp.rst',
'api-reference/bluetooth/esp_avrc.rst',
'api-reference/bluetooth/esp_hidd.rst',
'api-reference/bluetooth/esp_l2cap_bt.rst',
'api-reference/bluetooth/esp_sdp.rst',
'api-reference/bluetooth/esp_hf_defs.rst',
'api-reference/bluetooth/esp_hf_client.rst',
'api-reference/bluetooth/esp_hf_ag.rst',

View File

@ -56,6 +56,8 @@ INPUT = \
$(PROJECT_PATH)/components/bt/host/bluedroid/api/include/api/esp_hf_defs.h \
$(PROJECT_PATH)/components/bt/host/bluedroid/api/include/api/esp_spp_api.h \
$(PROJECT_PATH)/components/bt/host/bluedroid/api/include/api/esp_hidd_api.h \
$(PROJECT_PATH)/components/bt/host/bluedroid/api/include/api/esp_l2cap_bt_api.h \
$(PROJECT_PATH)/components/bt/host/bluedroid/api/include/api/esp_sdp_api.h \
$(PROJECT_PATH)/components/bt/host/nimble/esp-hci/include/esp_nimble_hci.h \
$(PROJECT_PATH)/components/bt/include/esp32/include/esp_bt.h \
$(PROJECT_PATH)/components/console/esp_console.h \

View File

@ -12,3 +12,5 @@ CLASSIC BT
BT HFP Client <esp_hf_client>
BT HFP AG <esp_hf_ag>
BT HID DEVICE <esp_hidd>
BT L2CAP <esp_l2cap_bt>
BT SDP <esp_sdp>

View File

@ -0,0 +1,15 @@
Clissic Bluetooth L2CAP API
============================
Application Example
-------------------
Check :example:`bluetooth/bluedroid/classic_bt` folder in ESP-IDF examples, which contains the following application:
* This is a BT_L2CAP demo. This demo can connect, send and recive L2CAP data :example:`bluetooth/bluedroid/classic_bt/bt_l2cap_client`, :example:`bluetooth/bluedroid/classic_bt/bt_l2cap_server`
API Reference
-------------
.. include-build-file:: inc/esp_l2cap_bt_api.inc

View File

@ -0,0 +1,14 @@
BT SDP APIs
=============
Overview
--------
Bluetooth SDP reference APIs.
API Reference
-------------
.. include-build-file:: inc/esp_sdp_api.inc

View File

@ -0,0 +1 @@
.. include:: ../../../en/api-reference/bluetooth/esp_l2cap_bt.rst

View File

@ -0,0 +1 @@
.. include:: ../../../en/api-reference/bluetooth/esp_sdp.rst

View File

@ -0,0 +1,6 @@
# The following lines of boilerplate have to be in your project's
# CMakeLists in this exact order for cmake to work correctly
cmake_minimum_required(VERSION 3.5)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(bt_l2cap_client)

View File

@ -0,0 +1,66 @@
| Supported Targets | ESP32 |
| ----------------- | ----- |
ESP-IDF BT-L2CAP-CLIENT EXAMPLE
===================================
This example is to show how to use the APIs of **Logical Link Control and Adaptation Layer Protocol** (**L2CAP**) to create an L2CAP client. We also provide demo `bt_l2cap_server` to create L2CAP server. In fact, you can create L2CAP clients and L2CAP servers on a single device at the same time.
## How to use example
### Hardware Required
This example is designed to run on commonly available ESP32 development board, e.g. ESP32-DevKitC. To operate the example, it is supposed to connect to [bt_l2cap_server example](../bt_l2cap_server) in ESP-IDF.
### Configure the project
1. Open the project configuration menu:
```
idf.py menuconfig
```
2. Enable the BT-L2CAP functionality by choosing the path as following:
`Component config --> Bluetooth --> Bluedroid Options --> BT-L2CAP`
3. If you want to limit the number of connected devices, please make sure set the `BT/BLE MAX ACL CONNECTIONS` and `BR/EDR ACL Max Connections` with same value you want.
`Component config --> Bluetooth --> Bluedroid Options --> BT/BLE MAX ACL CONNECTIONS(1~7)`
and
`Component config --> Bluetooth --> Bluetooth --> Bluetooth controller --> BR/EDR ACL Max Connections`
### Build and Flash
Build the project and flash it to the board, then run monitor tool to view serial output:
```
idf.py -p PORT flash monitor
```
(Replace PORT with the name of the serial port to use.)
(To exit the serial monitor, type ``Ctrl-]``.)
See the [Getting Started Guide](https://docs.espressif.com/projects/esp-idf/en/latest/get-started/index.html) for full steps to configure and use ESP-IDF to build projects.
## Example Output
For the first step, this example performs device discovery to search for a target device whose device name is "ESP_BT_L2CAP_SERVER". If a candidate target is found, the local device will initiate connection with it.
When you run this example, the explain prints the following at the very begining:
```
I (1383) L2CAP_TAG: ESP_BT_L2CAP_INIT_EVT: status:0
I (1393) SDP_TAG: ESP_SDP_INIT_EVT: status:0
I (1393) SDP_TAG: ESP_SDP_CREATE_RECORD_COMP_EVT: status:0
I (1403) L2CAP_TAG: event: 10
I (1413) L2CAP_TAG: event: 1
I (1403) L2CAP_TAG: Own address:[c4:dd:57:5b:e7:46]
```
## Troubleshooting
* This example just demonstrates how to use the SDP and L2CAP APIs. This example cannot establish an l2cap connection with other devices (smartphones, computers, etc.) because the UUID is unknown and does not conform to the Bluetooth protocol standard.
* You can complete OBEX related profiles through SPP, SDP and L2CAP APIs.

View File

@ -0,0 +1,3 @@
idf_component_register(SRCS "main.c"
"bt_app_core.c"
INCLUDE_DIRS ".")

View File

@ -0,0 +1,144 @@
/*
* SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
#include <stdint.h>
#include <string.h>
#include <stdbool.h>
#include "freertos/xtensa_api.h"
#include "freertos/FreeRTOSConfig.h"
#include "freertos/FreeRTOS.h"
#include "freertos/queue.h"
#include "freertos/task.h"
#include "esp_log.h"
#include "bt_app_core.h"
#include "freertos/ringbuf.h"
/*******************************
* STATIC FUNCTION DECLARATIONS
******************************/
/* handler for application task */
static void bt_app_task_handler(void *arg);
/* message sender */
static bool bt_app_send_msg(bt_app_msg_t *msg);
/* handle dispatched messages */
static void bt_app_work_dispatched(bt_app_msg_t *msg);
/*******************************
* STATIC VARIABLE DEFINITIONS
******************************/
static QueueHandle_t s_bt_app_task_queue = NULL; /* handle of work queue */
static TaskHandle_t s_bt_app_task_handle = NULL; /* handle of application task */
/*******************************
* STATIC FUNCTION DEFINITIONS
******************************/
static bool bt_app_send_msg(bt_app_msg_t *msg)
{
if (msg == NULL) {
return false;
}
/* send the message to work queue */
if (xQueueSend(s_bt_app_task_queue, msg, 10 / portTICK_PERIOD_MS) != pdTRUE) {
ESP_LOGE(BT_APP_CORE_TAG, "%s xQueue send failed", __func__);
return false;
}
return true;
}
static void bt_app_work_dispatched(bt_app_msg_t *msg)
{
if (msg->cb) {
msg->cb(msg->event, msg->param);
}
}
static void bt_app_task_handler(void *arg)
{
bt_app_msg_t msg;
for (;;) {
/* receive message from work queue and handle it */
if (pdTRUE == xQueueReceive(s_bt_app_task_queue, &msg, (TickType_t)portMAX_DELAY)) {
ESP_LOGD(BT_APP_CORE_TAG, "%s, signal: 0x%x, event: 0x%x", __func__, msg.sig, msg.event);
switch (msg.sig) {
case BT_APP_SIG_WORK_DISPATCH:
bt_app_work_dispatched(&msg);
break;
default:
ESP_LOGW(BT_APP_CORE_TAG, "%s, unhandled signal: %d", __func__, msg.sig);
break;
} /* switch (msg.sig) */
if (msg.param) {
free(msg.param);
}
}
}
}
/********************************
* EXTERNAL FUNCTION DEFINITIONS
*******************************/
bool bt_app_work_dispatch(bt_app_cb_t p_cback, uint16_t event, void *p_params, int param_len, bt_app_copy_cb_t p_copy_cback)
{
ESP_LOGD(BT_APP_CORE_TAG, "%s event: 0x%x, param len: %d", __func__, event, param_len);
bt_app_msg_t msg;
memset(&msg, 0, sizeof(bt_app_msg_t));
msg.sig = BT_APP_SIG_WORK_DISPATCH;
msg.event = event;
msg.cb = p_cback;
if (param_len == 0) {
return bt_app_send_msg(&msg);
} else if (p_params && param_len > 0) {
if ((msg.param = malloc(param_len)) != NULL) {
memcpy(msg.param, p_params, param_len);
/* check if caller has provided a copy callback to do the deep copy */
if (p_copy_cback) {
p_copy_cback(msg.param, p_params, param_len);
}
return bt_app_send_msg(&msg);
}
}
return false;
}
void bt_app_task_start_up(void)
{
s_bt_app_task_queue = xQueueCreate(10, sizeof(bt_app_msg_t));
xTaskCreate(bt_app_task_handler, "BtAppTask", 3072, NULL, configMAX_PRIORITIES - 3, &s_bt_app_task_handle);
}
void bt_app_task_shut_down(void)
{
if (s_bt_app_task_handle) {
vTaskDelete(s_bt_app_task_handle);
s_bt_app_task_handle = NULL;
}
if (s_bt_app_task_queue) {
vQueueDelete(s_bt_app_task_queue);
s_bt_app_task_queue = NULL;
}
}
void l2cap_wr_task_start_up(l2cap_wr_task_cb_t p_cback, int fd)
{
xTaskCreate(p_cback, "write_read", 2048, (void *)fd, 5, NULL);
}
void l2cap_wr_task_shut_down(void)
{
vTaskDelete(NULL);
}

View File

@ -0,0 +1,77 @@
/*
* SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
#ifndef __BT_APP_CORE_H__
#define __BT_APP_CORE_H__
#include <stdint.h>
#include <stdbool.h>
#include <stdio.h>
/* log tag */
#define BT_APP_CORE_TAG "BT_APP_CORE"
/* signal for `bt_app_work_dispatch` */
#define BT_APP_SIG_WORK_DISPATCH (0x01)
/**
* @brief handler for the dispatched work
*
* @param [in] event event id
* @param [in] param handler parameter
*/
typedef void (* bt_app_cb_t) (uint16_t event, void *param);
/**
* @brief handler for write and read
*/
typedef void (* l2cap_wr_task_cb_t) (void *fd);
/* message to be sent */
typedef struct {
uint16_t sig; /*!< signal to bt_app_task */
uint16_t event; /*!< message event id */
bt_app_cb_t cb; /*!< context switch callback */
void *param; /*!< parameter area needs to be last */
} bt_app_msg_t;
/**
* @brief parameter deep-copy function to be customized
*
* @param [out] p_dest pointer to destination data
* @param [in] p_src pointer to source data
* @param [in] len data length in byte
*/
typedef void (* bt_app_copy_cb_t) (void *p_dest, void *p_src, int len);
/**
* @brief work dispatcher for the application task
*
* @param [in] p_cback callback function
* @param [in] event event id
* @param [in] p_params callback paramters
* @param [in] param_len parameter length in byte
* @param [in] p_copy_cback parameter deep-copy function
*
* @return true if work dispatch successfully, false otherwise
*/
bool bt_app_work_dispatch(bt_app_cb_t p_cback, uint16_t event, void *p_params, int param_len, bt_app_copy_cb_t p_copy_cback);
/**
* @brief start up the application task
*/
void bt_app_task_start_up(void);
/**
* @brief shut down the application task
*/
void bt_app_task_shut_down(void);
void l2cap_wr_task_start_up(l2cap_wr_task_cb_t p_cback, int fd);
void l2cap_wr_task_shut_down(void);
#endif /* __BT_APP_CORE_H__ */

View File

@ -0,0 +1,457 @@
/*
* SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <stdbool.h>
#include <stdio.h>
#include "nvs.h"
#include "nvs_flash.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_log.h"
#include "esp_bt.h"
#include "esp_bt_main.h"
#include "esp_gap_bt_api.h"
#include "esp_bt_device.h"
#include "esp_l2cap_bt_api.h"
#include "time.h"
#include "sys/time.h"
#include "esp_vfs.h"
#include "esp_sdp_api.h"
#include "bt_app_core.h"
#define L2CAP_TAG "L2CAP_TAG"
#define SDP_TAG "SDP_TAG"
#define EXAMPLE_DEVICE_NAME "ESP_BT_L2CAP_CLIENT"
#define TARGET_DEVICE_NAME "ESP_BT_L2CAP_SERVER"
#define L2CAP_DATA_LEN 100
#define BT_L2CAP_DYNMIC_PSM 0x1001
#define BT_UNUSED_RFCOMM -1
#define BT_UNKONWN_PROFILE_VERSION 0x0102
static esp_bt_l2cap_cntl_flags_t sec_mask = ESP_BT_L2CAP_SEC_AUTHENTICATE;
static char *sdp_service_name = "Unknown_profile";
static const uint8_t UUID_UNKNOWN[] = {0x00, 0x00, 0x10, 0x10, 0x00, 0x00, 0x10, 0x00,
0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB
};
static void esp_bt_l2cap_cb(esp_bt_l2cap_cb_event_t event, esp_bt_l2cap_cb_param_t *param);
static void esp_hdl_bt_l2cap_cb_evt(uint16_t event, void *p_param);
static void esp_hdl_sdp_cb_evt(uint16_t event, void *p_param);
static char *bda2str(esp_bd_addr_t bda, char *str, size_t size)
{
if (bda == NULL || str == NULL || size < 18) {
return NULL;
}
sprintf(str, "%02x:%02x:%02x:%02x:%02x:%02x",
bda[0], bda[1], bda[2], bda[3], bda[4], bda[5]);
return str;
}
static bool get_name_from_eir(uint8_t *eir, uint8_t *bdname, uint8_t *bdname_len)
{
uint8_t *rmt_bdname = NULL;
uint8_t rmt_bdname_len = 0;
if (!eir) {
return false;
}
/* get complete or short local name from eir data */
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 filter_inquiry_scan_result(esp_bt_gap_cb_param_t *param)
{
char bda_str[18];
uint32_t cod = 0; /* class of device */
int32_t rssi = -129; /* invalid value */
uint8_t *eir = NULL;
uint8_t peer_bdname[ESP_BT_GAP_MAX_BDNAME_LEN + 1];
esp_bt_gap_dev_prop_t *p;
esp_bt_uuid_t uuid = {0};
/* handle the discovery results */
ESP_LOGI(L2CAP_TAG, "Scanned device: %s", bda2str(param->disc_res.bda, bda_str, 18));
for (int i = 0; i < param->disc_res.num_prop; i++) {
p = param->disc_res.prop + i;
switch (p->type) {
case ESP_BT_GAP_DEV_PROP_COD:
cod = *(uint32_t *)(p->val);
ESP_LOGI(L2CAP_TAG, "--Class of Device: 0x%x", cod);
break;
case ESP_BT_GAP_DEV_PROP_RSSI:
rssi = *(int8_t *)(p->val);
ESP_LOGI(L2CAP_TAG, "--RSSI: %d", rssi);
break;
case ESP_BT_GAP_DEV_PROP_EIR:
eir = (uint8_t *)(p->val);
break;
case ESP_BT_GAP_DEV_PROP_BDNAME:
default:
break;
}
}
/* search for target device in its Extended Inqury Response */
if (eir) {
get_name_from_eir(eir, peer_bdname, NULL);
if (strcmp((char *)peer_bdname, TARGET_DEVICE_NAME) == 0) {
ESP_LOGI(L2CAP_TAG, "Found a target device, address %s, name %s", bda_str, peer_bdname);
ESP_LOGI(L2CAP_TAG, "Cancel device discovery ...");
esp_bt_gap_cancel_discovery();
uuid.len = sizeof(UUID_UNKNOWN);
memcpy(uuid.uuid.uuid128, UUID_UNKNOWN, sizeof(UUID_UNKNOWN));
esp_sdp_search_record(param->disc_res.bda, uuid);
}
}
}
static void esp_bt_gap_cb(esp_bt_gap_cb_event_t event, esp_bt_gap_cb_param_t *param)
{
char bda_str[18] = {0};
switch (event) {
/* when device discovered a result, this event comes */
case ESP_BT_GAP_DISC_RES_EVT: {
filter_inquiry_scan_result(param);
break;
}
/* when Legacy Pairing pin code requested, this event comes */
case ESP_BT_GAP_AUTH_CMPL_EVT:{
if (param->auth_cmpl.stat == ESP_BT_STATUS_SUCCESS) {
ESP_LOGI(L2CAP_TAG, "authentication success: %s bda:[%s]", param->auth_cmpl.device_name,
bda2str(param->auth_cmpl.bda, bda_str, sizeof(bda_str)));
} else {
ESP_LOGE(L2CAP_TAG, "authentication failed, status:%d", param->auth_cmpl.stat);
}
break;
}
/* when Security Simple Pairing user confirmation requested, this event comes */
case ESP_BT_GAP_PIN_REQ_EVT:{
ESP_LOGI(L2CAP_TAG, "ESP_BT_GAP_PIN_REQ_EVT min_16_digit:%d", param->pin_req.min_16_digit);
if (param->pin_req.min_16_digit) {
ESP_LOGI(L2CAP_TAG, "Input pin code: 0000 0000 0000 0000");
esp_bt_pin_code_t pin_code = {0};
esp_bt_gap_pin_reply(param->pin_req.bda, true, 16, pin_code);
} else {
ESP_LOGI(L2CAP_TAG, "Input pin code: 1234");
esp_bt_pin_code_t pin_code;
pin_code[0] = '1';
pin_code[1] = '2';
pin_code[2] = '3';
pin_code[3] = '4';
esp_bt_gap_pin_reply(param->pin_req.bda, true, 4, pin_code);
}
break;
}
#if (CONFIG_BT_SSP_ENABLED == true)
/* when Security Simple Pairing user confirmation requested, this event comes */
case ESP_BT_GAP_CFM_REQ_EVT:
ESP_LOGI(L2CAP_TAG, "ESP_BT_GAP_CFM_REQ_EVT Please compare the numeric value: %d", param->cfm_req.num_val);
esp_bt_gap_ssp_confirm_reply(param->cfm_req.bda, true);
break;
/* when Security Simple Pairing passkey notified, this event comes */
case ESP_BT_GAP_KEY_NOTIF_EVT:
ESP_LOGI(L2CAP_TAG, "ESP_BT_GAP_KEY_NOTIF_EVT passkey: %d", param->key_notif.passkey);
break;
/* when Security Simple Pairing passkey requested, this event comes */
case ESP_BT_GAP_KEY_REQ_EVT:
ESP_LOGI(L2CAP_TAG, "ESP_BT_GAP_KEY_REQ_EVT Please enter passkey!");
break;
#endif
/* when GAP mode changed, this event comes */
case ESP_BT_GAP_MODE_CHG_EVT:
ESP_LOGI(L2CAP_TAG, "ESP_BT_GAP_MODE_CHG_EVT mode:%d bda:[%s]", param->mode_chg.mode,
bda2str(param->mode_chg.bda, bda_str, sizeof(bda_str)));
break;
/* other */
default: {
ESP_LOGI(L2CAP_TAG, "event: %d", event);
break;
}
}
return;
}
static void l2cap_write_handle(void * param)
{
int size = 0;
int fd = (int)param;
uint8_t *l2cap_data = NULL;
uint16_t i = 0;
l2cap_data = malloc(L2CAP_DATA_LEN);
if (!l2cap_data) {
ESP_LOGE(L2CAP_TAG, "malloc l2cap_data failed, fd:%d", fd);
goto done;
}
for (i = 0; i < L2CAP_DATA_LEN; ++i) {
l2cap_data[i] = i;
}
do {
/*
* The write function is blocked until all the target length of data has been sent to the lower layer
* successfully an error occurs.
*/
size = write(fd, l2cap_data, L2CAP_DATA_LEN);
if (size == -1) {
break;
} else if (size == 0) {
/*write fail due to ringbuf is full, retry after 500 ms*/
vTaskDelay(500 / portTICK_PERIOD_MS);
} else {
ESP_LOGI(L2CAP_TAG, "fd = %d data_len = %d", fd, size);
vTaskDelay(50 / portTICK_PERIOD_MS);
}
} while (1);
done:
if (l2cap_data) {
free(l2cap_data);
}
l2cap_wr_task_shut_down();
}
static void esp_bt_l2cap_cb(esp_bt_l2cap_cb_event_t event, esp_bt_l2cap_cb_param_t *param)
{
switch (event) {
case ESP_BT_L2CAP_INIT_EVT:
case ESP_BT_L2CAP_UNINIT_EVT:
case ESP_BT_L2CAP_OPEN_EVT:
case ESP_BT_L2CAP_CLOSE_EVT:
case ESP_BT_L2CAP_CL_INIT_EVT:
case ESP_BT_L2CAP_START_EVT:
case ESP_BT_L2CAP_SRV_STOP_EVT: {
bt_app_work_dispatch(esp_hdl_bt_l2cap_cb_evt, event, param, sizeof(esp_bt_l2cap_cb_param_t), NULL);
break;
}
default:
ESP_LOGE(L2CAP_TAG, "Invalid L2CAP event: %d", event);
break;
}
}
static void esp_hdl_bt_l2cap_cb_evt(uint16_t event, void *p_param)
{
char bda_str[18] = {0};
esp_bt_l2cap_cb_param_t *l2cap_param = (esp_bt_l2cap_cb_param_t *)p_param;
switch (event) {
case ESP_BT_L2CAP_INIT_EVT:
ESP_LOGI(L2CAP_TAG, "ESP_BT_L2CAP_INIT_EVT: status:%d\n", l2cap_param->init.status);
if (l2cap_param->init.status == ESP_BT_L2CAP_SUCCESS) {
esp_bt_l2cap_vfs_register();
}
break;
case ESP_BT_L2CAP_UNINIT_EVT:
ESP_LOGI(L2CAP_TAG, "ESP_BT_L2CAP_UNINIT_EVT: status:%d\n", l2cap_param->uninit.status);
break;
case ESP_BT_L2CAP_OPEN_EVT:
if (l2cap_param->open.status == ESP_BT_L2CAP_SUCCESS) {
ESP_LOGI(L2CAP_TAG, "ESP_BT_L2CAP_OPEN_EVT: status:%d, fd = %d, tx mtu = %d, remote_address:%s\n", l2cap_param->open.status,
l2cap_param->open.fd, l2cap_param->open.tx_mtu, bda2str(l2cap_param->open.rem_bda, bda_str, sizeof(bda_str)));
l2cap_wr_task_start_up(l2cap_write_handle, l2cap_param->open.fd);
} else {
ESP_LOGI(L2CAP_TAG, "ESP_BT_L2CAP_OPEN_EVT: status:%d\n", l2cap_param->open.status);
}
break;
case ESP_BT_L2CAP_CLOSE_EVT:
ESP_LOGI(L2CAP_TAG, "ESP_BT_L2CAP_CLOSE_EVT: status:%d\n", l2cap_param->close.status);
break;
case ESP_BT_L2CAP_CL_INIT_EVT:
ESP_LOGI(L2CAP_TAG, "ESP_BT_L2CAP_CL_INIT_EVT: status:%d\n", l2cap_param->cl_init.status);
break;
case ESP_BT_L2CAP_START_EVT:
if (l2cap_param->start.status == ESP_BT_L2CAP_SUCCESS) {
ESP_LOGI(L2CAP_TAG, "ESP_BT_L2CAP_START_EVT: status:%d, hdl:0x%x, sec_id:0x%x\n",
l2cap_param->start.status, l2cap_param->start.handle, l2cap_param->start.sec_id);
} else {
ESP_LOGI(L2CAP_TAG, "ESP_BT_L2CAP_START_EVT: status:%d\n", l2cap_param->start.status);
}
break;
case ESP_BT_L2CAP_SRV_STOP_EVT:
ESP_LOGI(L2CAP_TAG, "ESP_BT_L2CAP_CLOSE_EVT: status:%d, psm = 0x%x\n", l2cap_param->srv_stop.status, l2cap_param->srv_stop.psm);
break;
default:
break;
}
return;
}
static void esp_sdp_cb(esp_sdp_cb_event_t event, esp_sdp_cb_param_t *param)
{
switch (event) {
case ESP_SDP_INIT_EVT:
case ESP_SDP_DEINIT_EVT:
case ESP_SDP_SEARCH_COMP_EVT:
case ESP_SDP_CREATE_RECORD_COMP_EVT:
case ESP_SDP_REMOVE_RECORD_COMP_EVT: {
bt_app_work_dispatch(esp_hdl_sdp_cb_evt, event, param, sizeof(esp_sdp_cb_param_t), NULL);
break;
}
default:
ESP_LOGE(SDP_TAG, "Invalid SDP event: %d", event);
break;
}
}
static void esp_hdl_sdp_cb_evt(uint16_t event, void *p_param)
{
esp_bluetooth_sdp_record_t record = {0};
esp_sdp_cb_param_t *sdp_param = (esp_sdp_cb_param_t *)p_param;
char bda_str[18] = {0};
switch (event) {
case ESP_SDP_INIT_EVT:
ESP_LOGI(SDP_TAG, "ESP_SDP_INIT_EVT: status:%d\n", sdp_param->init.status);
if (sdp_param->init.status == ESP_SDP_SUCCESS) {
record.hdr.type = ESP_SDP_TYPE_RAW;
record.hdr.uuid.len = sizeof(UUID_UNKNOWN);
memcpy(record.hdr.uuid.uuid.uuid128, UUID_UNKNOWN, sizeof(UUID_UNKNOWN));
record.hdr.service_name_length = strlen(sdp_service_name) + 1;
record.hdr.service_name = sdp_service_name;
record.hdr.rfcomm_channel_number = BT_UNUSED_RFCOMM;
record.hdr.l2cap_psm = BT_L2CAP_DYNMIC_PSM;
record.hdr.profile_version = BT_UNKONWN_PROFILE_VERSION;
esp_sdp_create_record(&record);
}
break;
case ESP_SDP_DEINIT_EVT:
ESP_LOGI(SDP_TAG, "ESP_SDP_DEINIT_EVT: status:%d\n", sdp_param->deinit.status);
break;
case ESP_SDP_SEARCH_COMP_EVT:
ESP_LOGI(SDP_TAG, "ESP_SDP_SEARCH_COMP_EVT: status:%d\n", sdp_param->search.status);
if (sdp_param->search.status == ESP_SDP_SUCCESS) {
ESP_LOGI(SDP_TAG, "Remote device address: %s\n", bda2str(sdp_param->search.remote_addr, bda_str, sizeof(bda_str)));
ESP_LOGI(SDP_TAG, "Remote device record count: %d\n", sdp_param->search.record_count);
ESP_LOGI(SDP_TAG, "Remote device rfcomm channel number: %d\n", sdp_param->search.records->hdr.rfcomm_channel_number);
ESP_LOGI(SDP_TAG, "Remote device l2cap psm: 0x%04x\n", sdp_param->search.records->hdr.l2cap_psm);
esp_bt_l2cap_connect(sec_mask, sdp_param->search.records->hdr.l2cap_psm, sdp_param->search.remote_addr);
}
break;
case ESP_SDP_CREATE_RECORD_COMP_EVT:
ESP_LOGI(SDP_TAG, "ESP_SDP_CREATE_RECORD_COMP_EVT: status:%d\n", sdp_param->create_record.status);
if (sdp_param->create_record.status == ESP_SDP_SUCCESS) {
esp_bt_dev_set_device_name(EXAMPLE_DEVICE_NAME);
esp_bt_gap_set_scan_mode(ESP_BT_CONNECTABLE, ESP_BT_GENERAL_DISCOVERABLE);
esp_bt_gap_start_discovery(ESP_BT_INQ_MODE_GENERAL_INQUIRY, 10, 0);
}
break;
case ESP_SDP_REMOVE_RECORD_COMP_EVT:
ESP_LOGI(SDP_TAG, "ESP_SDP_REMOVE_RECORD_COMP_EVT: status:%d\n", sdp_param->remove_record.status);
break;
default:
break;
}
}
void app_main(void)
{
char bda_str[18] = {0};
esp_err_t ret = nvs_flash_init();
if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
ESP_ERROR_CHECK(nvs_flash_erase());
ret = nvs_flash_init();
}
ESP_ERROR_CHECK( ret );
ESP_ERROR_CHECK(esp_bt_controller_mem_release(ESP_BT_MODE_BLE));
esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT();
if ((ret = esp_bt_controller_init(&bt_cfg)) != ESP_OK) {
ESP_LOGE(L2CAP_TAG, "%s initialize controller failed: %s\n", __func__, esp_err_to_name(ret));
return;
}
if ((ret = esp_bt_controller_enable(ESP_BT_MODE_CLASSIC_BT)) != ESP_OK) {
ESP_LOGE(L2CAP_TAG, "%s enable controller failed: %s\n", __func__, esp_err_to_name(ret));
return;
}
if ((ret = esp_bluedroid_init()) != ESP_OK) {
ESP_LOGE(L2CAP_TAG, "%s initialize bluedroid failed: %s\n", __func__, esp_err_to_name(ret));
return;
}
if ((ret = esp_bluedroid_enable()) != ESP_OK) {
ESP_LOGE(L2CAP_TAG, "%s enable bluedroid failed: %s\n", __func__, esp_err_to_name(ret));
return;
}
bt_app_task_start_up();
if ((ret = esp_bt_gap_register_callback(esp_bt_gap_cb)) != ESP_OK) {
ESP_LOGE(L2CAP_TAG, "%s gap register failed: %s\n", __func__, esp_err_to_name(ret));
return;
}
if ((ret = esp_bt_l2cap_register_callback(esp_bt_l2cap_cb)) != ESP_OK) {
ESP_LOGE(L2CAP_TAG, "%s l2cap register failed: %s\n", __func__, esp_err_to_name(ret));
return;
}
if ((ret = esp_bt_l2cap_init()) != ESP_OK) {
ESP_LOGE(L2CAP_TAG, "%s l2cap init failed: %s\n", __func__, esp_err_to_name(ret));
return;
}
if ((ret = esp_sdp_register_callback(esp_sdp_cb)) != ESP_OK) {
ESP_LOGE(SDP_TAG, "%s sdp register failed: %s\n", __func__, esp_err_to_name(ret));
return;
}
if ((ret = esp_sdp_init()) != ESP_OK) {
ESP_LOGE(SDP_TAG, "%s sdp init failed: %s\n", __func__, esp_err_to_name(ret));
return;
}
#if (CONFIG_BT_SSP_ENABLED == true)
/* Set default parameters for Secure Simple Pairing */
esp_bt_sp_param_t param_type = ESP_BT_SP_IOCAP_MODE;
esp_bt_io_cap_t iocap = ESP_BT_IO_CAP_IO;
esp_bt_gap_set_security_param(param_type, &iocap, sizeof(uint8_t));
#endif
/*
* Set default parameters for Legacy Pairing
* Use variable pin, input pin code when pairing
*/
esp_bt_pin_type_t pin_type = ESP_BT_PIN_TYPE_VARIABLE;
esp_bt_pin_code_t pin_code;
esp_bt_gap_set_pin(pin_type, 0, pin_code);
ESP_LOGI(L2CAP_TAG, "Own address:[%s]", bda2str((uint8_t *)esp_bt_dev_get_address(), bda_str, sizeof(bda_str)));
}

View File

@ -0,0 +1,9 @@
# Override some defaults so BT stack is enabled and
# Classic BT is enabled
CONFIG_BT_ENABLED=y
CONFIG_BTDM_CTRL_MODE_BLE_ONLY=n
CONFIG_BTDM_CTRL_MODE_BR_EDR_ONLY=y
CONFIG_BTDM_CTRL_MODE_BTDM=n
CONFIG_BT_BLUEDROID_ENABLED=y
CONFIG_BT_CLASSIC_ENABLED=y
CONFIG_BT_L2CAP_ENABLED=y

View File

@ -0,0 +1,6 @@
# The following lines of boilerplate have to be in your project's
# CMakeLists in this exact order for cmake to work correctly
cmake_minimum_required(VERSION 3.5)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(bt_l2cap_server)

View File

@ -0,0 +1,68 @@
| Supported Targets | ESP32 |
| ----------------- | ----- |
ESP-IDF BT-L2CAP-SERVER EXAMPLE
===================================
This example is to show how to use the APIs of **Logical Link Control and Adaptation Layer Protocol** (**L2CAP**) to create an L2CAP server. We also provide demo `bt_l2cap_client` to create L2CAP client. In fact, you can create L2CAP clients and L2CAP servers on a single device at the same time.
## How to use example
### Hardware Required
This example is designed to run on commonly available ESP32 development board, e.g. ESP32-DevKitC. To operate the example, it should be connected to the L2CAP client running on another ESP32 board.
### Configure the project
1. Open the project configuration menu:
```
idf.py menuconfig
```
2. Enable the BT-L2CAP functionality by choosing the path as following:
`Component config --> Bluetooth --> Bluedroid Options --> BT-L2CAP`
3. If you want to limit the number of connected devices, please make sure set the `BT/BLE MAX ACL CONNECTIONS` and `BR/EDR ACL Max Connections` with same value you want.
`Component config --> Bluetooth --> Bluedroid Options --> BT/BLE MAX ACL CONNECTIONS(1~7)`
and
`Component config --> Bluetooth --> Bluetooth --> Bluetooth controller --> BR/EDR ACL Max Connections`
### Build and Flash
Build the project and flash it to the board, then run monitor tool to view serial output:
```
idf.py -p PORT flash monitor
```
(Replace PORT with the name of the serial port to use.)
(To exit the serial monitor, type ``Ctrl-]``.)
See the [Getting Started Guide](https://docs.espressif.com/projects/esp-idf/en/latest/get-started/index.html) for full steps to configure and use ESP-IDF to build projects.
## Example Output
After the program is started, the example starts inquiry scan and page scan, awaiting being discovered and connected. Other bluetooth devices can discover a device named "ESP_BT_L2CAP_SERVER". ESP-IDF examples for other L2CAP client can be used to connect to the local device.
When you run this example, the explain prints the following at the very begining:
```
I (1398) L2CAP_TAG: ESP_BT_L2CAP_INIT_EVT: status:0
I (1398) L2CAP_TAG: ESP_BT_L2CAP_START_EVT: status:0, hdl:0x0, sec_id:0x37
I (1408) SDP_TAG: ESP_SDP_INIT_EVT: status:0
I (1408) SDP_TAG: ESP_SDP_CREATE_RECORD_COMP_EVT: status:0
I (1418) L2CAP_TAG: event: 10
I (1428) L2CAP_TAG: Own address:[c4:dd:57:5b:e7:46]
```
## Troubleshooting
* This example just demonstrates how to use the SDP and L2CAP APIs. This example cannot establish an l2cap connection with other devices (smartphones, computers, etc.) because the UUID is unknown and does not conform to the Bluetooth protocol standard.
* You can complete OBEX related profiles through SPP, SDP and L2CAP APIs.

View File

@ -0,0 +1,3 @@
idf_component_register(SRCS "main.c"
"bt_app_core.c"
INCLUDE_DIRS ".")

View File

@ -0,0 +1,144 @@
/*
* SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
#include <stdint.h>
#include <string.h>
#include <stdbool.h>
#include "freertos/xtensa_api.h"
#include "freertos/FreeRTOSConfig.h"
#include "freertos/FreeRTOS.h"
#include "freertos/queue.h"
#include "freertos/task.h"
#include "esp_log.h"
#include "bt_app_core.h"
#include "freertos/ringbuf.h"
/*******************************
* STATIC FUNCTION DECLARATIONS
******************************/
/* handler for application task */
static void bt_app_task_handler(void *arg);
/* message sender */
static bool bt_app_send_msg(bt_app_msg_t *msg);
/* handle dispatched messages */
static void bt_app_work_dispatched(bt_app_msg_t *msg);
/*******************************
* STATIC VARIABLE DEFINITIONS
******************************/
static QueueHandle_t s_bt_app_task_queue = NULL; /* handle of work queue */
static TaskHandle_t s_bt_app_task_handle = NULL; /* handle of application task */
/*******************************
* STATIC FUNCTION DEFINITIONS
******************************/
static bool bt_app_send_msg(bt_app_msg_t *msg)
{
if (msg == NULL) {
return false;
}
/* send the message to work queue */
if (xQueueSend(s_bt_app_task_queue, msg, 10 / portTICK_PERIOD_MS) != pdTRUE) {
ESP_LOGE(BT_APP_CORE_TAG, "%s xQueue send failed", __func__);
return false;
}
return true;
}
static void bt_app_work_dispatched(bt_app_msg_t *msg)
{
if (msg->cb) {
msg->cb(msg->event, msg->param);
}
}
static void bt_app_task_handler(void *arg)
{
bt_app_msg_t msg;
for (;;) {
/* receive message from work queue and handle it */
if (pdTRUE == xQueueReceive(s_bt_app_task_queue, &msg, (TickType_t)portMAX_DELAY)) {
ESP_LOGD(BT_APP_CORE_TAG, "%s, signal: 0x%x, event: 0x%x", __func__, msg.sig, msg.event);
switch (msg.sig) {
case BT_APP_SIG_WORK_DISPATCH:
bt_app_work_dispatched(&msg);
break;
default:
ESP_LOGW(BT_APP_CORE_TAG, "%s, unhandled signal: %d", __func__, msg.sig);
break;
} /* switch (msg.sig) */
if (msg.param) {
free(msg.param);
}
}
}
}
/********************************
* EXTERNAL FUNCTION DEFINITIONS
*******************************/
bool bt_app_work_dispatch(bt_app_cb_t p_cback, uint16_t event, void *p_params, int param_len, bt_app_copy_cb_t p_copy_cback)
{
ESP_LOGD(BT_APP_CORE_TAG, "%s event: 0x%x, param len: %d", __func__, event, param_len);
bt_app_msg_t msg;
memset(&msg, 0, sizeof(bt_app_msg_t));
msg.sig = BT_APP_SIG_WORK_DISPATCH;
msg.event = event;
msg.cb = p_cback;
if (param_len == 0) {
return bt_app_send_msg(&msg);
} else if (p_params && param_len > 0) {
if ((msg.param = malloc(param_len)) != NULL) {
memcpy(msg.param, p_params, param_len);
/* check if caller has provided a copy callback to do the deep copy */
if (p_copy_cback) {
p_copy_cback(msg.param, p_params, param_len);
}
return bt_app_send_msg(&msg);
}
}
return false;
}
void bt_app_task_start_up(void)
{
s_bt_app_task_queue = xQueueCreate(10, sizeof(bt_app_msg_t));
xTaskCreate(bt_app_task_handler, "BtAppTask", 3072, NULL, configMAX_PRIORITIES - 3, &s_bt_app_task_handle);
}
void bt_app_task_shut_down(void)
{
if (s_bt_app_task_handle) {
vTaskDelete(s_bt_app_task_handle);
s_bt_app_task_handle = NULL;
}
if (s_bt_app_task_queue) {
vQueueDelete(s_bt_app_task_queue);
s_bt_app_task_queue = NULL;
}
}
void l2cap_wr_task_start_up(l2cap_wr_task_cb_t p_cback, int fd)
{
xTaskCreate(p_cback, "write_read", 2048, (void *)fd, 5, NULL);
}
void l2cap_wr_task_shut_down(void)
{
vTaskDelete(NULL);
}

View File

@ -0,0 +1,77 @@
/*
* SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
#ifndef __BT_APP_CORE_H__
#define __BT_APP_CORE_H__
#include <stdint.h>
#include <stdbool.h>
#include <stdio.h>
/* log tag */
#define BT_APP_CORE_TAG "BT_APP_CORE"
/* signal for `bt_app_work_dispatch` */
#define BT_APP_SIG_WORK_DISPATCH (0x01)
/**
* @brief handler for the dispatched work
*
* @param [in] event event id
* @param [in] param handler parameter
*/
typedef void (* bt_app_cb_t) (uint16_t event, void *param);
/**
* @brief handler for write and read
*/
typedef void (* l2cap_wr_task_cb_t) (void *fd);
/* message to be sent */
typedef struct {
uint16_t sig; /*!< signal to bt_app_task */
uint16_t event; /*!< message event id */
bt_app_cb_t cb; /*!< context switch callback */
void *param; /*!< parameter area needs to be last */
} bt_app_msg_t;
/**
* @brief parameter deep-copy function to be customized
*
* @param [out] p_dest pointer to destination data
* @param [in] p_src pointer to source data
* @param [in] len data length in byte
*/
typedef void (* bt_app_copy_cb_t) (void *p_dest, void *p_src, int len);
/**
* @brief work dispatcher for the application task
*
* @param [in] p_cback callback function
* @param [in] event event id
* @param [in] p_params callback paramters
* @param [in] param_len parameter length in byte
* @param [in] p_copy_cback parameter deep-copy function
*
* @return true if work dispatch successfully, false otherwise
*/
bool bt_app_work_dispatch(bt_app_cb_t p_cback, uint16_t event, void *p_params, int param_len, bt_app_copy_cb_t p_copy_cback);
/**
* @brief start up the application task
*/
void bt_app_task_start_up(void);
/**
* @brief shut down the application task
*/
void bt_app_task_shut_down(void);
void l2cap_wr_task_start_up(l2cap_wr_task_cb_t p_cback, int fd);
void l2cap_wr_task_shut_down(void);
#endif /* __BT_APP_CORE_H__ */

View File

@ -0,0 +1,360 @@
/*
* SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <stdbool.h>
#include <stdio.h>
#include "nvs.h"
#include "nvs_flash.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_log.h"
#include "esp_bt.h"
#include "esp_bt_main.h"
#include "esp_gap_bt_api.h"
#include "esp_bt_device.h"
#include "esp_l2cap_bt_api.h"
#include "time.h"
#include "sys/time.h"
#include "esp_vfs.h"
#include "esp_sdp_api.h"
#include "bt_app_core.h"
#define L2CAP_TAG "L2CAP_TAG"
#define SDP_TAG "SDP_TAG"
#define EXAMPLE_DEVICE_NAME "ESP_BT_L2CAP_SERVER"
#define L2CAP_DATA_LEN 100
#define BT_UNUSED_RFCOMM -1
#define BT_L2CAP_DYNMIC_PSM 0x1001
#define BT_UNKONWN_PROFILE_VERSION 0x0102
static esp_bt_l2cap_cntl_flags_t sec_mask = ESP_BT_L2CAP_SEC_AUTHENTICATE;
static char *sdp_service_name = "Unknown_profile";
static const uint8_t UUID_UNKNOWN[] = {0x00, 0x00, 0x10, 0x10, 0x00, 0x00, 0x10, 0x00,
0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB
};
static void esp_bt_l2cap_cb(esp_bt_l2cap_cb_event_t event, esp_bt_l2cap_cb_param_t *param);
static void esp_hdl_bt_l2cap_cb_evt(uint16_t event, void *p_param);
static void esp_hdl_sdp_cb_evt(uint16_t event, void *p_param);
static char *bda2str(esp_bd_addr_t bda, char *str, size_t size)
{
if (bda == NULL || str == NULL || size < 18) {
return NULL;
}
sprintf(str, "%02x:%02x:%02x:%02x:%02x:%02x",
bda[0], bda[1], bda[2], bda[3], bda[4], bda[5]);
return str;
}
static void esp_bt_gap_cb(esp_bt_gap_cb_event_t event, esp_bt_gap_cb_param_t *param)
{
char bda_str[18] = {0};
switch (event) {
/* when Legacy Pairing pin code requested, this event comes */
case ESP_BT_GAP_AUTH_CMPL_EVT:{
if (param->auth_cmpl.stat == ESP_BT_STATUS_SUCCESS) {
ESP_LOGI(L2CAP_TAG, "authentication success: %s bda:[%s]", param->auth_cmpl.device_name,
bda2str(param->auth_cmpl.bda, bda_str, sizeof(bda_str)));
} else {
ESP_LOGE(L2CAP_TAG, "authentication failed, status:%d", param->auth_cmpl.stat);
}
break;
}
/* when Security Simple Pairing user confirmation requested, this event comes */
case ESP_BT_GAP_PIN_REQ_EVT:{
ESP_LOGI(L2CAP_TAG, "ESP_BT_GAP_PIN_REQ_EVT min_16_digit:%d", param->pin_req.min_16_digit);
if (param->pin_req.min_16_digit) {
ESP_LOGI(L2CAP_TAG, "Input pin code: 0000 0000 0000 0000");
esp_bt_pin_code_t pin_code = {0};
esp_bt_gap_pin_reply(param->pin_req.bda, true, 16, pin_code);
} else {
ESP_LOGI(L2CAP_TAG, "Input pin code: 1234");
esp_bt_pin_code_t pin_code;
pin_code[0] = '1';
pin_code[1] = '2';
pin_code[2] = '3';
pin_code[3] = '4';
esp_bt_gap_pin_reply(param->pin_req.bda, true, 4, pin_code);
}
break;
}
#if (CONFIG_BT_SSP_ENABLED == true)
/* when Security Simple Pairing user confirmation requested, this event comes */
case ESP_BT_GAP_CFM_REQ_EVT:
ESP_LOGI(L2CAP_TAG, "ESP_BT_GAP_CFM_REQ_EVT Please compare the numeric value: %d", param->cfm_req.num_val);
esp_bt_gap_ssp_confirm_reply(param->cfm_req.bda, true);
break;
/* when Security Simple Pairing passkey notified, this event comes */
case ESP_BT_GAP_KEY_NOTIF_EVT:
ESP_LOGI(L2CAP_TAG, "ESP_BT_GAP_KEY_NOTIF_EVT passkey:%d", param->key_notif.passkey);
break;
/* when Security Simple Pairing passkey requested, this event comes */
case ESP_BT_GAP_KEY_REQ_EVT:
ESP_LOGI(L2CAP_TAG, "ESP_BT_GAP_KEY_REQ_EVT Please enter passkey!");
break;
#endif
/* when GAP mode changed, this event comes */
case ESP_BT_GAP_MODE_CHG_EVT:
ESP_LOGI(L2CAP_TAG, "ESP_BT_GAP_MODE_CHG_EVT mode:%d bda:[%s]", param->mode_chg.mode,
bda2str(param->mode_chg.bda, bda_str, sizeof(bda_str)));
break;
/* other */
default: {
ESP_LOGI(L2CAP_TAG, "event: %d", event);
break;
}
}
return;
}
static void l2cap_read_handle(void * param)
{
int size = 0;
int fd = (int)param;
uint8_t *l2cap_data = NULL;
l2cap_data = malloc(L2CAP_DATA_LEN);
if (!l2cap_data) {
ESP_LOGE(L2CAP_TAG, "malloc l2cap_data failed, fd:%d", fd);
goto done;
}
do {
/* The frequency of calling this function also limits the speed at which the peer device can send data. */
size = read(fd, l2cap_data, L2CAP_DATA_LEN);
if (size < 0) {
break;
} else if (size == 0) {
/* There is no data, retry after 500 ms */
vTaskDelay(500 / portTICK_PERIOD_MS);
} else {
ESP_LOGI(L2CAP_TAG, "fd = %d data_len = %d", fd, size);
// esp_log_buffer_hex(L2CAP_TAG, l2cap_data, size);
/* To avoid task watchdog */
vTaskDelay(10 / portTICK_PERIOD_MS);
}
} while (1);
done:
if (l2cap_data) {
free(l2cap_data);
}
l2cap_wr_task_shut_down();
}
static void esp_bt_l2cap_cb(esp_bt_l2cap_cb_event_t event, esp_bt_l2cap_cb_param_t *param)
{
switch (event) {
case ESP_BT_L2CAP_INIT_EVT:
case ESP_BT_L2CAP_UNINIT_EVT:
case ESP_BT_L2CAP_OPEN_EVT:
case ESP_BT_L2CAP_CLOSE_EVT:
case ESP_BT_L2CAP_CL_INIT_EVT:
case ESP_BT_L2CAP_START_EVT:
case ESP_BT_L2CAP_SRV_STOP_EVT: {
bt_app_work_dispatch(esp_hdl_bt_l2cap_cb_evt, event, param, sizeof(esp_bt_l2cap_cb_param_t), NULL);
break;
}
default:
ESP_LOGE(L2CAP_TAG, "Invalid L2CAP event: %d", event);
break;
}
}
static void esp_hdl_bt_l2cap_cb_evt(uint16_t event, void *p_param)
{
char bda_str[18] = {0};
esp_bt_l2cap_cb_param_t *l2cap_param = (esp_bt_l2cap_cb_param_t *)p_param;
switch (event) {
case ESP_BT_L2CAP_INIT_EVT:
if (l2cap_param->init.status == ESP_BT_L2CAP_SUCCESS) {
ESP_LOGI(L2CAP_TAG, "ESP_BT_L2CAP_INIT_EVT: status:%d\n", l2cap_param->init.status);
esp_bt_l2cap_vfs_register();
esp_bt_l2cap_start_srv(sec_mask, BT_L2CAP_DYNMIC_PSM);
} else {
ESP_LOGI(L2CAP_TAG, "ESP_BT_L2CAP_INIT_EVT: status:%d\n", l2cap_param->init.status);
}
break;
case ESP_BT_L2CAP_UNINIT_EVT:
ESP_LOGI(L2CAP_TAG, "ESP_BT_L2CAP_UNINIT_EVT: status:%d\n", l2cap_param->uninit.status);
break;
case ESP_BT_L2CAP_OPEN_EVT:
if (l2cap_param->open.status == ESP_BT_L2CAP_SUCCESS) {
ESP_LOGI(L2CAP_TAG, "ESP_BT_L2CAP_OPEN_EVT: status:%d, fd = %d, tx mtu = %d, remote_address:%s\n", l2cap_param->open.status,
l2cap_param->open.fd, l2cap_param->open.tx_mtu, bda2str(l2cap_param->open.rem_bda, bda_str, sizeof(bda_str)));
l2cap_wr_task_start_up(l2cap_read_handle, l2cap_param->open.fd);
} else {
ESP_LOGI(L2CAP_TAG, "ESP_BT_L2CAP_OPEN_EVT: status:%d\n", l2cap_param->open.status);
}
break;
case ESP_BT_L2CAP_CLOSE_EVT:
ESP_LOGI(L2CAP_TAG, "ESP_BT_L2CAP_CLOSE_EVT: status:%d\n", l2cap_param->close.status);
esp_bt_l2cap_start_srv(sec_mask, BT_L2CAP_DYNMIC_PSM); // bug, need to do fix
break;
case ESP_BT_L2CAP_CL_INIT_EVT:
ESP_LOGI(L2CAP_TAG, "ESP_BT_L2CAP_CL_INIT_EVT: status:%d\n", l2cap_param->cl_init.status);
break;
case ESP_BT_L2CAP_START_EVT:
if (l2cap_param->start.status == ESP_BT_L2CAP_SUCCESS) {
ESP_LOGI(L2CAP_TAG, "ESP_BT_L2CAP_START_EVT: status:%d, hdl:0x%x, sec_id:0x%x\n",
l2cap_param->start.status, l2cap_param->start.handle, l2cap_param->start.sec_id);
} else {
ESP_LOGI(L2CAP_TAG, "ESP_BT_L2CAP_START_EVT: status:%d\n", l2cap_param->start.status);
}
break;
case ESP_BT_L2CAP_SRV_STOP_EVT:
ESP_LOGI(L2CAP_TAG, "ESP_BT_L2CAP_SRV_STOP_EVT: status:%d, psm = 0x%x\n", l2cap_param->srv_stop.status, l2cap_param->srv_stop.psm);
break;
default:
break;
}
return;
}
static void esp_sdp_cb(esp_sdp_cb_event_t event, esp_sdp_cb_param_t *param)
{
switch (event) {
case ESP_SDP_INIT_EVT:
case ESP_SDP_DEINIT_EVT:
case ESP_SDP_SEARCH_COMP_EVT:
case ESP_SDP_CREATE_RECORD_COMP_EVT:
case ESP_SDP_REMOVE_RECORD_COMP_EVT: {
bt_app_work_dispatch(esp_hdl_sdp_cb_evt, event, param, sizeof(esp_sdp_cb_param_t), NULL);
break;
}
default:
ESP_LOGE(SDP_TAG, "Invalid SDP event: %d", event);
break;
}
}
static void esp_hdl_sdp_cb_evt(uint16_t event, void *p_param)
{
esp_bluetooth_sdp_record_t record = {0};
esp_sdp_cb_param_t *sdp_param = (esp_sdp_cb_param_t *)p_param;
switch (event) {
case ESP_SDP_INIT_EVT:
ESP_LOGI(SDP_TAG, "ESP_SDP_INIT_EVT: status:%d\n", sdp_param->init.status);
if (sdp_param->init.status == ESP_SDP_SUCCESS) {
record.hdr.type = ESP_SDP_TYPE_RAW;
record.hdr.uuid.len = sizeof(UUID_UNKNOWN);
memcpy(record.hdr.uuid.uuid.uuid128, UUID_UNKNOWN, sizeof(UUID_UNKNOWN));
record.hdr.service_name_length = strlen(sdp_service_name) + 1;
record.hdr.service_name = sdp_service_name;
record.hdr.rfcomm_channel_number = BT_UNUSED_RFCOMM;
record.hdr.l2cap_psm = BT_L2CAP_DYNMIC_PSM;
record.hdr.profile_version = BT_UNKONWN_PROFILE_VERSION;
esp_sdp_create_record(&record);
}
break;
case ESP_SDP_DEINIT_EVT:
ESP_LOGI(SDP_TAG, "ESP_SDP_DEINIT_EVT: status:%d\n", sdp_param->deinit.status);
break;
case ESP_SDP_SEARCH_COMP_EVT:
ESP_LOGI(SDP_TAG, "ESP_SDP_SEARCH_COMP_EVT: status:%d\n", sdp_param->search.status);
break;
case ESP_SDP_CREATE_RECORD_COMP_EVT:
ESP_LOGI(SDP_TAG, "ESP_SDP_CREATE_RECORD_COMP_EVT: status:%d\n", sdp_param->create_record.status);
if (sdp_param->create_record.status == ESP_SDP_SUCCESS) {
esp_bt_dev_set_device_name(EXAMPLE_DEVICE_NAME);
esp_bt_gap_set_scan_mode(ESP_BT_CONNECTABLE, ESP_BT_GENERAL_DISCOVERABLE);
}
break;
case ESP_SDP_REMOVE_RECORD_COMP_EVT:
ESP_LOGI(SDP_TAG, "ESP_SDP_REMOVE_RECORD_COMP_EVT: status:%d\n", sdp_param->remove_record.status);
break;
default:
break;
}
}
void app_main(void)
{
char bda_str[18] = {0};
esp_err_t ret = nvs_flash_init();
if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
ESP_ERROR_CHECK(nvs_flash_erase());
ret = nvs_flash_init();
}
ESP_ERROR_CHECK( ret );
ESP_ERROR_CHECK(esp_bt_controller_mem_release(ESP_BT_MODE_BLE));
esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT();
if ((ret = esp_bt_controller_init(&bt_cfg)) != ESP_OK) {
ESP_LOGE(L2CAP_TAG, "%s initialize controller failed: %s\n", __func__, esp_err_to_name(ret));
return;
}
if ((ret = esp_bt_controller_enable(ESP_BT_MODE_CLASSIC_BT)) != ESP_OK) {
ESP_LOGE(L2CAP_TAG, "%s enable controller failed: %s\n", __func__, esp_err_to_name(ret));
return;
}
if ((ret = esp_bluedroid_init()) != ESP_OK) {
ESP_LOGE(L2CAP_TAG, "%s initialize bluedroid failed: %s\n", __func__, esp_err_to_name(ret));
return;
}
if ((ret = esp_bluedroid_enable()) != ESP_OK) {
ESP_LOGE(L2CAP_TAG, "%s enable bluedroid failed: %s\n", __func__, esp_err_to_name(ret));
return;
}
bt_app_task_start_up();
if ((ret = esp_bt_gap_register_callback(esp_bt_gap_cb)) != ESP_OK) {
ESP_LOGE(L2CAP_TAG, "%s gap register failed: %s\n", __func__, esp_err_to_name(ret));
return;
}
if ((ret = esp_bt_l2cap_register_callback(esp_bt_l2cap_cb)) != ESP_OK) {
ESP_LOGE(L2CAP_TAG, "%s l2cap register failed: %s\n", __func__, esp_err_to_name(ret));
return;
}
if ((ret = esp_bt_l2cap_init()) != ESP_OK) {
ESP_LOGE(L2CAP_TAG, "%s l2cap init failed: %s\n", __func__, esp_err_to_name(ret));
return;
}
if ((ret = esp_sdp_register_callback(esp_sdp_cb)) != ESP_OK) {
ESP_LOGE(SDP_TAG, "%s sdp register failed: %s\n", __func__, esp_err_to_name(ret));
return;
}
if ((ret = esp_sdp_init()) != ESP_OK) {
ESP_LOGE(SDP_TAG, "%s sdp init failed: %s\n", __func__, esp_err_to_name(ret));
return;
}
#if (CONFIG_BT_SSP_ENABLED == true)
/* Set default parameters for Secure Simple Pairing */
esp_bt_sp_param_t param_type = ESP_BT_SP_IOCAP_MODE;
esp_bt_io_cap_t iocap = ESP_BT_IO_CAP_IO;
esp_bt_gap_set_security_param(param_type, &iocap, sizeof(uint8_t));
#endif
/*
* Set default parameters for Legacy Pairing
* Use variable pin, input pin code when pairing
*/
esp_bt_pin_type_t pin_type = ESP_BT_PIN_TYPE_VARIABLE;
esp_bt_pin_code_t pin_code;
esp_bt_gap_set_pin(pin_type, 0, pin_code);
ESP_LOGI(L2CAP_TAG, "Own address:[%s]", bda2str((uint8_t *)esp_bt_dev_get_address(), bda_str, sizeof(bda_str)));
}

View File

@ -0,0 +1,9 @@
# Override some defaults so BT stack is enabled and
# Classic BT is enabled
CONFIG_BT_ENABLED=y
CONFIG_BTDM_CTRL_MODE_BLE_ONLY=n
CONFIG_BTDM_CTRL_MODE_BR_EDR_ONLY=y
CONFIG_BTDM_CTRL_MODE_BTDM=n
CONFIG_BT_BLUEDROID_ENABLED=y
CONFIG_BT_CLASSIC_ENABLED=y
CONFIG_BT_L2CAP_ENABLED=y