component/bt: implement Classic Bluetooth GAP APIs for device and service discovery

This commit is contained in:
wangmengyang 2017-11-24 17:28:43 +08:00
parent f32fa0c1e9
commit c23af0b5bb
14 changed files with 1367 additions and 95 deletions

View file

@ -20,7 +20,21 @@
#include "btc_manage.h"
#include "btc_gap_bt.h"
#if BTC_GAP_BT_INCLUDED
#if (BTC_GAP_BT_INCLUDED == TRUE)
esp_err_t esp_bt_gap_register_callback(esp_bt_gap_cb_t callback)
{
if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) {
return ESP_ERR_INVALID_STATE;
}
if (callback == NULL) {
return ESP_FAIL;
}
btc_profile_cb_set(BTC_PID_GAP_BT, callback);
return ESP_OK;
}
esp_err_t esp_bt_gap_set_scan_mode(esp_bt_scan_mode_t mode)
{
@ -30,7 +44,7 @@ esp_err_t esp_bt_gap_set_scan_mode(esp_bt_scan_mode_t mode)
if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) {
return ESP_ERR_INVALID_STATE;
}
msg.sig = BTC_SIG_API_CALL;
msg.pid = BTC_PID_GAP_BT;
msg.act = BTC_GAP_BT_ACT_SET_SCAN_MODE;
@ -39,4 +53,92 @@ esp_err_t esp_bt_gap_set_scan_mode(esp_bt_scan_mode_t mode)
return (btc_transfer_context(&msg, &arg, sizeof(btc_gap_bt_args_t), NULL) == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL);
}
#endif /* #if BTC_GAP_BT_INCLUDED */
esp_err_t esp_bt_gap_start_discovery(esp_bt_inq_mode_t mode, uint8_t inq_len, uint8_t num_rsps)
{
btc_msg_t msg;
btc_gap_bt_args_t arg;
if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) {
return ESP_ERR_INVALID_STATE;
}
if (mode != ESP_BT_INQ_MODE_GENERAL_INQUIRY &&
mode != ESP_BT_INQ_MODE_LIMITED_INQIURY) {
return ESP_ERR_INVALID_ARG;
}
if (inq_len < ESP_BT_GAP_MIN_INQ_LEN ||
inq_len > ESP_BT_GAP_MAX_INQ_LEN) {
return ESP_ERR_INVALID_ARG;
}
msg.sig = BTC_SIG_API_CALL;
msg.pid = BTC_PID_GAP_BT;
msg.act = BTC_GAP_BT_ACT_START_DISCOVERY;
arg.start_disc.mode = mode;
arg.start_disc.inq_len = inq_len;
arg.start_disc.num_rsps = num_rsps;
return (btc_transfer_context(&msg, &arg, sizeof(btc_gap_bt_args_t), NULL) == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL);
}
esp_err_t esp_bt_gap_cancel_discovery(void)
{
btc_msg_t msg;
if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) {
return ESP_ERR_INVALID_STATE;
}
msg.sig = BTC_SIG_API_CALL;
msg.pid = BTC_PID_GAP_BT;
msg.act = BTC_GAP_BT_ACT_CANCEL_DISCOVERY;
return (btc_transfer_context(&msg, NULL, 0, NULL) == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL);
}
esp_err_t esp_bt_gap_get_remote_services(esp_bd_addr_t remote_bda)
{
btc_msg_t msg;
btc_gap_bt_args_t arg;
if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) {
return ESP_ERR_INVALID_STATE;
}
msg.sig = BTC_SIG_API_CALL;
msg.pid = BTC_PID_GAP_BT;
msg.act = BTC_GAP_BT_ACT_GET_REMOTE_SERVICES;
memcpy(&arg.bda, remote_bda, sizeof(bt_bdaddr_t));
return (btc_transfer_context(&msg, &arg, sizeof(btc_gap_bt_args_t), NULL) == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL);
}
esp_err_t esp_bt_gap_get_remote_service_record(esp_bd_addr_t remote_bda, esp_bt_uuid_t *uuid)
{
btc_msg_t msg;
btc_gap_bt_args_t arg;
if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) {
return ESP_ERR_INVALID_STATE;
}
msg.sig = BTC_SIG_API_CALL;
msg.pid = BTC_PID_GAP_BT;
msg.act = BTC_GAP_BT_ACT_GET_REMOTE_SERVICE_RECORD;
memcpy(&arg.get_rmt_srv_rcd.bda, remote_bda, sizeof(bt_bdaddr_t));
memcpy(&arg.get_rmt_srv_rcd.uuid, uuid, sizeof(esp_bt_uuid_t));
return (btc_transfer_context(&msg, &arg, sizeof(btc_gap_bt_args_t), NULL) == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL);
}
uint8_t *esp_bt_gap_resolve_eir_data(uint8_t *eir, esp_bt_eir_type_t type, uint8_t *length)
{
if (!eir) {
return NULL;
}
return BTM_CheckEirData(eir, type, length);
}
#endif /* #if BTC_GAP_BT_INCLUDED == TRUE */

View file

@ -28,9 +28,227 @@ extern "C" {
typedef enum {
ESP_BT_SCAN_MODE_NONE = 0, /*!< Neither discoverable nor connectable */
ESP_BT_SCAN_MODE_CONNECTABLE, /*!< Connectable but not discoverable */
ESP_BT_SCAN_MODE_CONNECTABLE_DISCOVERABLE /*!< both discoverable and connectaable */
ESP_BT_SCAN_MODE_CONNECTABLE_DISCOVERABLE /*!< both discoverable and connectable */
} esp_bt_scan_mode_t;
/// Bluetooth Device Property type
typedef enum {
ESP_BT_GAP_DEV_PROP_BDNAME = 1, /*!< Bluetooth device name, value type is int8_t [] */
ESP_BT_GAP_DEV_PROP_COD, /*!< Class of Device, value type is uint32_t */
ESP_BT_GAP_DEV_PROP_RSSI, /*!< Received Signal strength Indication, value type is int8_t, ranging from -128 to 127 */
ESP_BT_GAP_DEV_PROP_EIR, /*!< Extended Inquiry Response, value type is uint8_t [] */
} esp_bt_gap_dev_prop_type_t;
/// Maximum bytes of Bluetooth device name
#define ESP_BT_GAP_MAX_BDNAME_LEN (248)
/// Maximum size of EIR Significant part
#define ESP_BT_GAP_EIR_DATA_LEN (240)
/// Bluetooth Device Property Descriptor
typedef struct {
esp_bt_gap_dev_prop_type_t type; /*!< device property type */
int len; /*!< device property value length */
void *val; /*!< devlice prpoerty value */
} esp_bt_gap_dev_prop_t;
/// Extended Inquiry Response data type
typedef enum {
ESP_BT_EIR_TYPE_FLAGS = 0x01, /*!< Flag with information such as BR/EDR and LE support */
ESP_BT_EIR_TYPE_INCMPL_16BITS_UUID = 0x02, /*!< Incomplete list of 16-bit service UUIDs */
ESP_BT_EIR_TYPE_CMPL_16BITS_UUID = 0x03, /*!< Complete list of 16-bit service UUIDs */
ESP_BT_EIR_TYPE_INCMPL_32BITS_UUID = 0x04, /*!< Incomplete list of 32-bit service UUIDs */
ESP_BT_EIR_TYPE_CMPL_32BITS_UUID = 0x05, /*!< Complete list of 32-bit service UUIDs */
ESP_BT_EIR_TYPE_INCMPL_128BITS_UUID = 0x06, /*!< Incomplete list of 128-bit service UUIDs */
ESP_BT_EIR_TYPE_CMPL_128BITS_UUID = 0x07, /*!< Complete list of 128-bit service UUIDs */
ESP_BT_EIR_TYPE_SHORT_LOCAL_NAME = 0x08, /*!< Shortened Local Name */
ESP_BT_EIR_TYPE_CMPL_LOCAL_NAME = 0x09, /*!< Complete Local Name */
ESP_BT_EIR_TYPE_TX_POWER_LEVEL = 0x0a, /*!< Tx power level, value is 1 octet ranging from -127 to 127, unit is dBm*/
ESP_BT_EIR_TYPE_MANU_SPECIFIC = 0xff, /*!< Manufacturer specific data */
} esp_bt_eir_type_t;
/// Major service class field of Class of Device, mutiple bits can be set
typedef enum {
ESP_BT_COD_SRVC_NONE = 0, /*!< None indicates an invalid value */
ESP_BT_COD_SRVC_LMTD_DISCOVER = 0x1, /*!< Limited Discoverable Mode */
ESP_BT_COD_SRVC_POSITIONING = 0x8, /*!< Positioning (Location identification) */
ESP_BT_COD_SRVC_NETWORKING = 0x10, /*!< Networking, e.g. LAN, Ad hoc */
ESP_BT_COD_SRVC_RENDERING = 0x20, /*!< Rendering, e.g. Printing, Speakers */
ESP_BT_COD_SRVC_CAPTURING = 0x40, /*!< Capturing, e.g. Scanner, Microphone */
ESP_BT_COD_SRVC_OBJ_TRANSFER = 0x80, /*!< Object Transfer, e.g. v-Inbox, v-Folder */
ESP_BT_COD_SRVC_AUDIO = 0x100, /*!< Audio, e.g. Speaker, Microphone, Headerset service */
ESP_BT_COD_SRVC_TELEPHONY = 0x200, /*!< Telephony, e.g. Cordless telephony, Modem, Headset service */
ESP_BT_COD_SRVC_INFORMATION = 0x400, /*!< Information, e.g., WEB-server, WAP-server */
} esp_bt_cod_srvc_t;
/// Bits of major service class field
#define ESP_BT_COD_SRVC_BIT_MASK (0xffe000) /*!< Major service bit mask */
#define ESP_BT_COD_SRVC_BIT_OFFSET (13) /*!< Major service bit offset */
/// Major device class field of Class of Device
typedef enum {
ESP_BT_COD_MAJOR_DEV_MISC = 0, /*!< Miscellaneous */
ESP_BT_COD_MAJOR_DEV_COMPUTER = 1, /*!< Computer */
ESP_BT_COD_MAJOR_DEV_PHONE = 2, /*!< Phone(cellular, cordless, pay phone, modem */
ESP_BT_COD_MAJOR_DEV_LAN_NAP = 3, /*!< LAN, Network Access Point */
ESP_BT_COD_MAJOR_DEV_AV = 4, /*!< Audio/Video(headset, speaker, stereo, video display, VCR */
ESP_BT_COD_MAJOR_DEV_PERIPHERAL = 5, /*!< Peripheral(mouse, joystick, keyboard) */
ESP_BT_COD_MAJOR_DEV_IMAGING = 6, /*!< Imaging(printer, scanner, camera, display */
ESP_BT_COD_MAJOR_DEV_WEARABLE = 7, /*!< Wearable */
ESP_BT_COD_MAJOR_DEV_TOY = 8, /*!< Toy */
ESP_BT_COD_MAJOR_DEV_HEALTH = 9, /*!< Health */
ESP_BT_COD_MAJOR_DEV_UNCATEGORIZED = 31, /*!< Uncategorized: device not specified */
} esp_bt_cod_major_dev_t;
/// Bits of major device class field
#define ESP_BT_COD_MAJOR_DEV_BIT_MASK (0x1f00) /*!< Major device bit mask */
#define ESP_BT_COD_MAJOR_DEV_BIT_OFFSET (8) /*!< Major device bit offset */
/// Bits of minor device class field
#define ESP_BT_COD_MINOR_DEV_BIT_MASK (0xfc) /*!< Minor device bit mask */
#define ESP_BT_COD_MINOR_DEV_BIT_OFFSET (2) /*!< Minor device bit offset */
/// Bits of format type
#define ESP_BT_COD_FORMAT_TYPE_BIT_MASK (0x03) /*!< Format type bit mask */
#define ESP_BT_COD_FORMAT_TYPE_BIT_OFFSET (0) /*!< Format type bit offset */
/// Class of device format type 1
#define ESP_BT_COD_FORMAT_TYPE_1 (0x00)
/** Bluetooth Device Discovery state */
typedef enum {
ESP_BT_GAP_DISCOVERY_STOPPED, /*!< device discovery stopped */
ESP_BT_GAP_DISCOVERY_STARTED, /*!< device discovery started */
} esp_bt_gap_discovery_state_t;
/// BT GAP callback events
typedef enum {
ESP_BT_GAP_DISC_RES_EVT = 0, /*!< device discovery result event */
ESP_BT_GAP_DISC_STATE_CHANGED_EVT, /*!< discovery state changed event */
ESP_BT_GAP_RMT_SRVCS_EVT, /*!< get remote services event */
ESP_BT_GAP_RMT_SRVC_REC_EVT, /*!< get remote service record event */
} esp_bt_gap_cb_event_t;
/** Inquiry Mode */
typedef enum {
ESP_BT_INQ_MODE_GENERAL_INQUIRY, /*!< General inquiry mode */
ESP_BT_INQ_MODE_LIMITED_INQIURY, /*!< Limited inquiry mode */
} esp_bt_inq_mode_t;
/** Minimum and Maximum inquiry length*/
#define ESP_BT_GAP_MIN_INQ_LEN (0x01) /*!< Minimum inquiry duration, unit is 1.28s */
#define ESP_BT_GAP_MAX_INQ_LEN (0x30) /*!< Maximum inquiry duration, unit is 1.28s */
/// A2DP state callback parameters
typedef union {
/**
* @brief ESP_BT_GAP_DISC_RES_EVT
*/
struct disc_res_param {
esp_bd_addr_t bda; /*!< remote bluetooth device address*/
int num_prop; /*!< number of properties got */
esp_bt_gap_dev_prop_t *prop; /*!< properties discovered from the new device */
} disc_res; /*!< discovery result paramter struct */
/**
* @brief ESP_BT_GAP_DISC_STATE_CHANGED_EVT
*/
struct disc_state_changed_param {
esp_bt_gap_discovery_state_t state; /*!< discovery state */
} disc_st_chg; /*!< discovery state changed parameter struct */
/**
* @brief ESP_BT_GAP_RMT_SRVCS_EVT
*/
struct rmt_srvcs_param {
esp_bd_addr_t bda; /*!< remote bluetooth device address*/
esp_bt_status_t stat; /*!< service search status */
int num_uuids; /*!< number of UUID in uuid_list */
esp_bt_uuid_t *uuid_list; /*!< list of service UUIDs of remote device */
} rmt_srvcs; /*!< services of remote device parameter struct */
/**
* @brief ESP_BT_GAP_RMT_SRVC_REC_EVT
*/
struct rmt_srvc_rec_param {
esp_bd_addr_t bda; /*!< remote bluetooth device address*/
esp_bt_status_t stat; /*!< service search status */
} rmt_srvc_rec; /*!< specific service record from remote device parameter struct */
} esp_bt_gap_cb_param_t;
/**
* @brief bluetooth GAP callback function type
* @param event : Event type
* @param param : Pointer to callback parameter
*/
typedef void (* esp_bt_gap_cb_t)(esp_bt_gap_cb_event_t event, esp_bt_gap_cb_param_t *param);
/**
* @brief get major service field of COD
* @param[in] cod: Class of Device
* @return major service bits
*/
inline uint32_t esp_bt_gap_get_cod_srvc(uint32_t cod)
{
return (cod & ESP_BT_COD_SRVC_BIT_MASK) >> ESP_BT_COD_SRVC_BIT_OFFSET;
}
/**
* @brief get major device field of COD
* @param[in] cod: Class of Device
* @return major device bits
*/
inline uint32_t esp_bt_gap_get_cod_major_dev(uint32_t cod)
{
return (cod & ESP_BT_COD_MAJOR_DEV_BIT_MASK) >> ESP_BT_COD_MAJOR_DEV_BIT_OFFSET;
}
/**
* @brief get minor service field of COD
* @param[in] cod: Class of Device
* @return minor service bits
*/
inline uint32_t esp_bt_gap_get_cod_minor_dev(uint32_t cod)
{
return (cod & ESP_BT_COD_MINOR_DEV_BIT_MASK) >> ESP_BT_COD_MINOR_DEV_BIT_OFFSET;
}
/**
* @brief get format type of COD
* @param[in] cod: Class of Device
* @return format type
*/
inline uint32_t esp_bt_gap_get_cod_format_type(uint32_t cod)
{
return (cod & ESP_BT_COD_FORMAT_TYPE_BIT_MASK);
}
/**
* @brief decide the integrity of COD
* @param[in] cod: Class of Device
* @return
* - true if cod is valid
* - false otherise
*/
inline bool esp_bt_gap_is_valid_cod(uint32_t cod)
{
if (esp_bt_gap_get_cod_format_type(cod) == ESP_BT_COD_FORMAT_TYPE_1 &&
esp_bt_gap_get_cod_srvc(cod) != ESP_BT_COD_SRVC_NONE) {
return true;
}
return false;
}
/**
* @brief register callback function. This function should be called after esp_bluedroid_enable() completes successfully
*
* @return
* - ESP_OK : Succeed
* - ESP_FAIL: others
*/
esp_err_t esp_bt_gap_register_callback(esp_bt_gap_cb_t callback);
/**
* @brief Set discoverability and connectability mode for legacy bluetooth. This function should
* be called after esp_bluedroid_enable() completes successfully
@ -45,6 +263,69 @@ typedef enum {
*/
esp_err_t esp_bt_gap_set_scan_mode(esp_bt_scan_mode_t mode);
/**
* @brief Start device discovery. This function should be called after esp_bluedroid_enable() completes successfully.
* esp_bt_gap_cb_t will is called with ESP_BT_GAP_DISC_STATE_CHANGED_EVT if discovery is started or halted.
* esp_bt_gap_cb_t will is called with ESP_BT_GAP_DISC_RES_EVT if discovery result is got.
*
* @param[in] mode - inquiry mode
* @param[in] inq_len - inquiry duration in 1.28 sec units, ranging from 0x01 to 0x30
* @param[in] num_rsps - number of inquiry responses that can be received, value 0 indicates an unlimited number of responses
*
* @return
* - ESP_OK : Succeed
* - ESP_INVALID_STATE: if bluetooth stack is not yet enabled
* - ESP_ERR_INVALID_ARG: if invalid parameters are provided
* - ESP_FAIL: others
*/
esp_err_t esp_bt_gap_start_discovery(esp_bt_inq_mode_t mode, uint8_t inq_len, uint8_t num_rsps);
/**
* @brief Cancel device discovery. This function should be called after esp_bluedroid_enable() completes successfully
* esp_bt_gap_cb_t will is called with ESP_BT_GAP_DISC_STATE_CHANGED_EVT if discovery is stopped.
*
* @return
* - ESP_OK : Succeed
* - ESP_INVALID_STATE: if bluetooth stack is not yet enabled
* - ESP_FAIL: others
*/
esp_err_t esp_bt_gap_cancel_discovery(void);
/**
* @brief Start SDP to get remote services. This function should be called after esp_bluedroid_enable() completes successfully.
* esp_bt_gap_cb_t will is called with ESP_BT_GAP_RMT_SRVCS_EVT after service discovery ends
*
* @return
* - ESP_OK : Succeed
* - ESP_INVALID_STATE: if bluetooth stack is not yet enabled
* - ESP_FAIL: others
*/
esp_err_t esp_bt_gap_get_remote_services(esp_bd_addr_t remote_bda);
/**
* @brief Start SDP to look up the service matching uuid on the remote device. This function should be called after
* esp_bluedroid_enable() completes successfully
*
* esp_bt_gap_cb_t will is called with ESP_BT_GAP_RMT_SRVC_REC_EVT after service discovery ends
* @return
* - ESP_OK : Succeed
* - ESP_INVALID_STATE: if bluetooth stack is not yet enabled
* - ESP_FAIL: others
*/
esp_err_t esp_bt_gap_get_remote_service_record(esp_bd_addr_t remote_bda, esp_bt_uuid_t *uuid);
/**
* @brief This function is called to get EIR data for a specific type.
*
* @param[in] eir - pointer of raw eir data to be resolved
* @param[in] type - specific EIR data type
* @param[out] length - return the length of EIR data excluding fields of length and data type
*
* @return pointer of starting position of eir data excluding eir data type, NULL if not found
*
*/
uint8_t *esp_bt_gap_resolve_eir_data(uint8_t *eir, esp_bt_eir_type_t type, uint8_t *length);
#ifdef __cplusplus
}
#endif

View file

@ -1560,11 +1560,9 @@ void bta_dm_sdp_result (tBTA_DM_MSG *p_data)
|| (p_data->sdp_event.sdp_result == SDP_DB_FULL)) {
APPL_TRACE_DEBUG("sdp_result::0x%x", p_data->sdp_event.sdp_result);
do {
p_sdp_rec = NULL;
if ( bta_dm_search_cb.service_index == (BTA_USER_SERVICE_ID + 1) ) {
p_sdp_rec = SDP_FindServiceUUIDInDb(bta_dm_search_cb.p_sdp_db, &bta_dm_search_cb.uuid, p_sdp_rec);
if (p_sdp_rec && SDP_FindProtocolListElemInRec(p_sdp_rec, UUID_PROTOCOL_RFCOMM, &pe)) {
bta_dm_search_cb.peer_scn = (UINT8) pe.params[0];
scn_found = TRUE;
@ -1580,7 +1578,6 @@ void bta_dm_sdp_result (tBTA_DM_MSG *p_data)
p_uuid += (bta_dm_search_cb.num_uuid - bta_dm_search_cb.uuid_to_search);
/* only support 16 bits UUID for now */
service = p_uuid->uu.uuid16;
}
/* all GATT based services */
do {
@ -1613,7 +1610,7 @@ void bta_dm_sdp_result (tBTA_DM_MSG *p_data)
if (((p_data->sdp_event.sdp_result == SDP_DB_FULL) &&
bta_dm_search_cb.services != BTA_ALL_SERVICE_MASK) ||
(p_sdp_rec != NULL)) {
if (service != UUID_SERVCLASS_PNP_INFORMATION) {
if (service != UUID_SERVCLASS_PNP_INFORMATION && service != 0) {
UINT16 tmp_svc = 0xFFFF;
bta_dm_search_cb.services_found |=
(tBTA_SERVICE_MASK)(BTA_SERVICE_ID_TO_SERVICE_MASK(bta_dm_search_cb.service_index - 1));
@ -1640,11 +1637,8 @@ void bta_dm_sdp_result (tBTA_DM_MSG *p_data)
} else { /* regular one service per search or PNP search */
break;
}
} while (bta_dm_search_cb.service_index <= BTA_MAX_SERVICE_ID);
// osi_free(bta_dm_search_cb.p_sdp_db);
// bta_dm_search_cb.p_sdp_db = NULL;
APPL_TRACE_DEBUG("%s services_found = %04x", __FUNCTION__,
bta_dm_search_cb.services_found);
@ -2054,13 +2048,13 @@ static void bta_dm_find_services ( BD_ADDR bd_addr)
memset (&uuid, 0, sizeof(tSDP_UUID));
while (bta_dm_search_cb.service_index < BTA_MAX_SERVICE_ID) {
if ( bta_dm_search_cb.services_to_search
& (tBTA_SERVICE_MASK)(BTA_SERVICE_ID_TO_SERVICE_MASK(bta_dm_search_cb.service_index))) {
tBTA_SERVICE_MASK this_service_mask = (tBTA_SERVICE_MASK)(BTA_SERVICE_ID_TO_SERVICE_MASK(bta_dm_search_cb.service_index));
if ( bta_dm_search_cb.services_to_search & this_service_mask) {
if ((bta_dm_search_cb.p_sdp_db = (tSDP_DISCOVERY_DB *)osi_malloc(BTA_DM_SDP_DB_SIZE)) != NULL) {
APPL_TRACE_DEBUG("bta_dm_search_cb.services = %04x***********", bta_dm_search_cb.services);
/* try to search all services by search based on L2CAP UUID */
if (bta_dm_search_cb.services == BTA_ALL_SERVICE_MASK ) {
LOG_INFO("%s services_to_search=%08x", __func__, bta_dm_search_cb.services_to_search);
APPL_TRACE_DEBUG("%s services_to_search=%08x", __func__, bta_dm_search_cb.services_to_search);
if (bta_dm_search_cb.services_to_search & BTA_RES_SERVICE_MASK) {
uuid.uu.uuid16 = bta_service_id_to_uuid_lkup_tbl[0];
bta_dm_search_cb.services_to_search &= ~BTA_RES_SERVICE_MASK;
@ -2071,7 +2065,7 @@ static void bta_dm_find_services ( BD_ADDR bd_addr)
} else {
#if BLE_INCLUDED == TRUE && BTA_GATT_INCLUDED == TRUE
/* for LE only profile */
if (bta_dm_search_cb.service_index == BTA_BLE_SERVICE_ID) {
if (this_service_mask == BTA_BLE_SERVICE_MASK) {
if (bta_dm_search_cb.uuid_to_search > 0 && bta_dm_search_cb.p_srvc_uuid) {
memcpy(&uuid,
(const void *)(bta_dm_search_cb.p_srvc_uuid + \
@ -2102,11 +2096,11 @@ static void bta_dm_find_services ( BD_ADDR bd_addr)
uuid.len = LEN_UUID_16;
}
if (bta_dm_search_cb.service_index == BTA_USER_SERVICE_ID) {
if (this_service_mask == BTA_USER_SERVICE_MASK) {
memcpy(&uuid, &bta_dm_search_cb.uuid, sizeof(tSDP_UUID));
}
LOG_INFO("%s search UUID = %04x", __func__, uuid.uu.uuid16);
APPL_TRACE_DEBUG("%s search UUID = %04x", __func__, uuid.uu.uuid16);
SDP_InitDiscoveryDb (bta_dm_search_cb.p_sdp_db, BTA_DM_SDP_DB_SIZE, 1, &uuid, 0, NULL);
memset(g_disc_raw_data_buf, 0, sizeof(g_disc_raw_data_buf));
@ -2123,9 +2117,9 @@ static void bta_dm_find_services ( BD_ADDR bd_addr)
} else {
#if BLE_INCLUDED == TRUE && BTA_GATT_INCLUDED == TRUE
if ((bta_dm_search_cb.service_index == BTA_BLE_SERVICE_ID &&
if ((this_service_mask == BTA_BLE_SERVICE_MASK &&
bta_dm_search_cb.uuid_to_search == 0) ||
bta_dm_search_cb.service_index != BTA_BLE_SERVICE_ID)
this_service_mask != BTA_BLE_SERVICE_MASK)
#endif
bta_dm_search_cb.service_index++;
return;

View file

@ -28,6 +28,9 @@
#include "bta_gatt_api.h"
#include "allocator.h"
#if (BTC_GAP_BT_INCLUDED == TRUE)
#include "btc_gap_bt.h"
#endif /* BTC_GAP_BT_INCLUDED == TRUE */
/******************************************************************************
** Constants & Macros
@ -481,6 +484,14 @@ void btc_dm_sec_cb_handler(btc_msg_t *msg)
break;
}
case BTA_DM_BUSY_LEVEL_EVT:
#if (BTC_GAP_BT_INCLUDED == TRUE)
{
if (p_data->busy_level.level_flags & BTM_BL_INQUIRY_PAGING_MASK) {
btc_gap_bt_busy_level_updated(p_data->busy_level.level_flags);
}
break;
}
#endif /* BTC_GAP_BT_INCLUDED == TRUE */
case BTA_DM_LINK_UP_EVT:
case BTA_DM_LINK_DOWN_EVT:
case BTA_DM_HW_ERROR_EVT:

View file

@ -14,6 +14,7 @@
#include <stdlib.h>
#include <string.h>
#include "bt_target.h"
#include "btc_task.h"
#include "bt_trace.h"
#include "thread.h"
@ -29,7 +30,9 @@
#include "btc_alarm.h"
#include "bta_gatt_api.h"
#if CONFIG_CLASSIC_BT_ENABLED
#if (BTC_GAP_BT_INCLUDED == TRUE)
#include "btc_gap_bt.h"
#endif /* BTC_GAP_BT_INCLUDED == TRUE */
#include "btc_profile_queue.h"
#include "btc_av.h"
#include "btc_avrc.h"
@ -57,7 +60,9 @@ static btc_func_t profile_tab[BTC_PID_NUM] = {
[BTC_PID_DM_SEC] = {NULL, btc_dm_sec_cb_handler },
[BTC_PID_ALARM] = {btc_alarm_handler, NULL },
#if CONFIG_CLASSIC_BT_ENABLED
#if (BTC_GAP_BT_INCLUDED == TRUE)
[BTC_PID_GAP_BT] = {btc_gap_bt_call_handler, NULL },
#endif /* (BTC_GAP_BT_INCLUDED == TRUE) */
[BTC_PID_PRF_QUE] = {btc_profile_queue_handler, NULL },
[BTC_PID_A2DP] = {btc_a2dp_call_handler, btc_a2dp_cb_handler },
[BTC_PID_AVRC] = {btc_avrc_call_handler, NULL },

View file

@ -129,6 +129,7 @@ UINT32 devclass2uint(DEV_CLASS dev_class)
}
return cod;
}
void uint2devclass(UINT32 cod, DEV_CLASS dev_class)
{
dev_class[2] = (UINT8)cod;
@ -136,61 +137,26 @@ void uint2devclass(UINT32 cod, DEV_CLASS dev_class)
dev_class[0] = (UINT8)(cod >> 16);
}
static const UINT8 sdp_base_uuid[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00,
0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB
};
static const UINT8 base_uuid_be[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00,
0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB};
void uuid16_to_uuid128(uint16_t uuid16, bt_uuid_t *uuid128)
void uuid128_be_to_esp_uuid(esp_bt_uuid_t *u, uint8_t* uuid128)
{
uint16_t uuid16_bo;
memset(uuid128, 0, sizeof(bt_uuid_t));
memcpy(uuid128->uu, sdp_base_uuid, MAX_UUID_SIZE);
uuid16_bo = ntohs(uuid16);
memcpy(uuid128->uu + 2, &uuid16_bo, sizeof(uint16_t));
}
void string_to_uuid(char *str, bt_uuid_t *p_uuid)
{
uint32_t uuid0, uuid4;
uint16_t uuid1, uuid2, uuid3, uuid5;
sscanf(str, "%08x-%04hx-%04hx-%04hx-%08x%04hx",
&uuid0, &uuid1, &uuid2, &uuid3, &uuid4, &uuid5);
uuid0 = htonl(uuid0);
uuid1 = htons(uuid1);
uuid2 = htons(uuid2);
uuid3 = htons(uuid3);
uuid4 = htonl(uuid4);
uuid5 = htons(uuid5);
memcpy(&(p_uuid->uu[0]), &uuid0, 4);
memcpy(&(p_uuid->uu[4]), &uuid1, 2);
memcpy(&(p_uuid->uu[6]), &uuid2, 2);
memcpy(&(p_uuid->uu[8]), &uuid3, 2);
memcpy(&(p_uuid->uu[10]), &uuid4, 4);
memcpy(&(p_uuid->uu[14]), &uuid5, 2);
if (memcmp(base_uuid_be+4, uuid128 + 4, 12) != 0) {
u->len = ESP_UUID_LEN_128;
uint8_t *p_i = uuid128 + ESP_UUID_LEN_128 - 1;
uint8_t *p_o = u->uuid.uuid128;
uint8_t *p_end = p_o + ESP_UUID_LEN_128;
for (; p_o != p_end; *p_o++ = *p_i--)
;
} else if (uuid128[0] == 0 && uuid128[1] == 0) {
u->len = 2;
u->uuid.uuid16 = (uuid128[2] << 8) + uuid128[3];
} else {
u->len = 4;
u->uuid.uuid32 = (uuid128[2] << 8) + uuid128[3];
u->uuid.uuid32 += (uuid128[0] << 24) + (uuid128[1] << 16);
}
return;
}
void uuid_to_string_legacy(bt_uuid_t *p_uuid, char *str)
{
uint32_t uuid0, uuid4;
uint16_t uuid1, uuid2, uuid3, uuid5;
memcpy(&uuid0, &(p_uuid->uu[0]), 4);
memcpy(&uuid1, &(p_uuid->uu[4]), 2);
memcpy(&uuid2, &(p_uuid->uu[6]), 2);
memcpy(&uuid3, &(p_uuid->uu[8]), 2);
memcpy(&uuid4, &(p_uuid->uu[10]), 4);
memcpy(&uuid5, &(p_uuid->uu[14]), 2);
sprintf((char *)str, "%.8x-%.4x-%.4x-%.4x-%.8x%.4x",
ntohl(uuid0), ntohs(uuid1),
ntohs(uuid2), ntohs(uuid3),
ntohl(uuid4), ntohs(uuid5));
return;
}

View file

@ -18,6 +18,7 @@
#include <stdbool.h>
#include "bt_types.h"
#include "bt_defs.h"
#include "esp_bt_defs.h"
/*******************************************************************************
** Constants & Macros
@ -39,9 +40,6 @@ const char *dump_rc_pdu(UINT8 pdu);
UINT32 devclass2uint(DEV_CLASS dev_class);
void uint2devclass(UINT32 dev, DEV_CLASS dev_class);
void uuid16_to_uuid128(uint16_t uuid16, bt_uuid_t *uuid128);
void uuid_to_string_legacy(bt_uuid_t *p_uuid, char *str);
void string_to_uuid(char *str, bt_uuid_t *p_uuid);
void uuid128_be_to_esp_uuid(esp_bt_uuid_t *u, uint8_t* uuid128);
#endif /* __BTC_UTIL_H__ */

View file

@ -12,30 +12,37 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#include <string.h>
#include "esp_bt_defs.h"
#include "esp_gap_bt_api.h"
#include "btc_gap_bt.h"
#include "bta_api.h"
#include "bt_trace.h"
#include <string.h>
#include "bt_target.h"
#include "btc_manage.h"
#include "btc_util.h"
#include "allocator.h"
#if BTC_GAP_BT_INCLUDED
void btc_gap_bt_arg_deep_copy(btc_msg_t *msg, void *p_dest, void *p_src)
{
switch (msg->act) {
default:
// LOG_ERROR("Unhandled deep copy %d\n", msg->act);
break;
}
}
#if (BTC_GAP_BT_INCLUDED == TRUE)
static void btc_gap_bt_arg_deep_free(btc_msg_t *msg)
#define COD_UNCLASSIFIED ((0x1F) << 8)
#define BTC_STORAGE_FILL_PROPERTY(p_prop, t, l, p_v) \
(p_prop)->type = t;(p_prop)->len = l; (p_prop)->val = (p_v);
static void bte_search_devices_evt(tBTA_DM_SEARCH_EVT event, tBTA_DM_SEARCH *p_data);
static void bte_dm_search_services_evt(tBTA_DM_SEARCH_EVT event, tBTA_DM_SEARCH *p_data);
static void bte_dm_remote_service_record_evt(tBTA_DM_SEARCH_EVT event, tBTA_DM_SEARCH *p_data);
static void search_services_copy_cb(btc_msg_t *msg, void *p_dest, void *p_src);
static void search_service_record_copy_cb(btc_msg_t *msg, void *p_dest, void *p_src);
static bool btc_gap_bt_inquiry_in_progress = false;
static inline void btc_gap_bt_cb_to_app(esp_bt_gap_cb_event_t event, esp_bt_gap_cb_param_t *param)
{
LOG_DEBUG("%s \n", __func__);
switch (msg->act) {
default:
// LOG_DEBUG("Unhandled deep free %d\n", msg->act);
break;
esp_bt_gap_cb_t cb = (esp_bt_gap_cb_t)btc_profile_cb_get(BTC_PID_GAP_BT);
if (cb) {
cb(event, param);
}
}
@ -69,6 +76,497 @@ static void btc_bt_set_scan_mode(esp_bt_scan_mode_t mode)
return;
}
static void btc_gap_bt_start_discovery(btc_gap_bt_args_t *arg)
{
tBTA_DM_INQ inq_params;
tBTA_SERVICE_MASK services = 0;
BTIF_TRACE_EVENT("%s", __FUNCTION__);
inq_params.mode = (arg->start_disc.mode == ESP_BT_INQ_MODE_GENERAL_INQUIRY) ?
BTA_DM_GENERAL_INQUIRY : BTA_DM_LIMITED_INQUIRY;
inq_params.duration = arg->start_disc.inq_len;
inq_params.max_resps = arg->start_disc.num_rsps;
inq_params.report_dup = TRUE;
inq_params.filter_type = BTA_DM_INQ_CLR;
/* TODO: Filter device by BDA needs to be implemented here */
/* Will be enabled to TRUE once inquiry busy level has been received */
btc_gap_bt_inquiry_in_progress = FALSE;
/* find nearby devices */
BTA_DmSearch(&inq_params, services, bte_search_devices_evt);
return;
}
static void btc_gap_bt_cancel_discovery(void)
{
BTA_DmSearchCancel();
}
static void btc_gap_bt_get_remote_services(bt_bdaddr_t *remote_bda)
{
BTA_DmDiscover(remote_bda->address, BTA_ALL_SERVICE_MASK,
bte_dm_search_services_evt, TRUE);
}
static void btc_gap_bt_get_remote_service_record(btc_gap_bt_args_t *arg)
{
esp_bt_uuid_t *uuid = &arg->get_rmt_srv_rcd.uuid;
bt_bdaddr_t *remote_bda = &arg->get_rmt_srv_rcd.bda;
tSDP_UUID sdp_uuid;
sdp_uuid.len = uuid->len;
memcpy(&sdp_uuid.uu, &uuid->uuid, uuid->len);
BTA_DmDiscoverUUID(remote_bda->address, &sdp_uuid,
bte_dm_remote_service_record_evt, TRUE);
}
/*******************************************************************************
**
** Function search_devices_copy_cb
**
** Description Deep copy callback for search devices event
**
** Returns void
**
*******************************************************************************/
static void search_devices_copy_cb(btc_msg_t *msg, void *p_dest, void *p_src)
{
tBTA_DM_SEARCH *p_dest_data = (tBTA_DM_SEARCH *) p_dest;
tBTA_DM_SEARCH *p_src_data = (tBTA_DM_SEARCH *) p_src;
if (!p_src) {
return;
}
switch (msg->aid) {
case BTA_DM_INQ_RES_EVT: {
if (p_src_data->inq_res.p_eir) {
p_dest_data->inq_res.p_eir = (UINT8 *)(p_dest + sizeof(tBTA_DM_SEARCH));
memcpy(p_dest_data->inq_res.p_eir, p_src_data->inq_res.p_eir, HCI_EXT_INQ_RESPONSE_LEN);
}
}
break;
case BTA_DM_DISC_RES_EVT: {
if (p_src_data->disc_res.raw_data_size && p_src_data->disc_res.p_raw_data) {
p_dest_data->disc_res.p_raw_data = (UINT8 *)(p_dest + sizeof(tBTA_DM_SEARCH));
memcpy(p_dest_data->disc_res.p_raw_data,
p_src_data->disc_res.p_raw_data,
p_src_data->disc_res.raw_data_size);
}
}
break;
}
}
/*******************************************************************************
**
** Function search_service_record_copy_cb
**
** Description Deep copy callback for search service record event
**
** Returns void
**
*******************************************************************************/
static void search_service_record_copy_cb(btc_msg_t *msg, void *p_dest, void *p_src)
{
tBTA_DM_SEARCH *p_dest_data = (tBTA_DM_SEARCH *) p_dest;
tBTA_DM_SEARCH *p_src_data = (tBTA_DM_SEARCH *) p_src;
if (!p_src) {
return;
}
switch (msg->aid) {
case BTA_DM_DISC_RES_EVT: {
if (p_src_data->disc_res.p_raw_data && p_src_data->disc_res.raw_data_size > 0) {
p_dest_data->disc_res.p_raw_data = (UINT8 *)(p_dest + sizeof(tBTA_DM_SEARCH));
memcpy(p_dest_data->disc_res.p_raw_data,
p_src_data->disc_res.p_raw_data,
p_src_data->disc_res.raw_data_size);
}
}
break;
default:
break;
}
}
/*******************************************************************************
**
** Function check_eir_remote_name
**
** Description Check if remote name is in the EIR data
**
** Returns TRUE if remote name found
** Populate p_remote_name, if provided and remote name found
**
*******************************************************************************/
static BOOLEAN check_eir_remote_name(tBTA_DM_SEARCH *p_search_data,
UINT8 *p_remote_name, UINT8 *p_remote_name_len)
{
UINT8 *p_eir_remote_name = NULL;
UINT8 remote_name_len = 0;
/* Check EIR for remote name and services */
if (p_search_data->inq_res.p_eir) {
p_eir_remote_name = BTM_CheckEirData(p_search_data->inq_res.p_eir,
BTM_EIR_COMPLETE_LOCAL_NAME_TYPE, &remote_name_len);
if (!p_eir_remote_name) {
p_eir_remote_name = BTM_CheckEirData(p_search_data->inq_res.p_eir,
BTM_EIR_SHORTENED_LOCAL_NAME_TYPE, &remote_name_len);
}
if (p_eir_remote_name) {
if (remote_name_len > BD_NAME_LEN) {
remote_name_len = BD_NAME_LEN;
}
if (p_remote_name && p_remote_name_len) {
memcpy(p_remote_name, p_eir_remote_name, remote_name_len);
*(p_remote_name + remote_name_len) = 0;
*p_remote_name_len = remote_name_len;
}
return TRUE;
}
}
return FALSE;
}
/*******************************************************************************
**
** Function bte_search_devices_evt
**
** Description Switches context from BTE to BTIF for DM search events
**
** Returns void
**
*******************************************************************************/
static void bte_search_devices_evt(tBTA_DM_SEARCH_EVT event, tBTA_DM_SEARCH *p_data)
{
UINT16 param_len = 0;
if (p_data) {
param_len += sizeof(tBTA_DM_SEARCH);
}
/* Allocate buffer to hold the pointers (deep copy). The pointers will point to the end of the tBTA_DM_SEARCH */
switch (event) {
case BTA_DM_INQ_RES_EVT: {
if (p_data->inq_res.p_eir) {
param_len += HCI_EXT_INQ_RESPONSE_LEN;
}
}
break;
case BTA_DM_DISC_RES_EVT: {
if (p_data->disc_res.raw_data_size && p_data->disc_res.p_raw_data) {
param_len += p_data->disc_res.raw_data_size;
}
}
break;
}
/* if remote name is available in EIR, set the flag so that stack doesn't trigger RNR */
if (event == BTA_DM_INQ_RES_EVT) {
p_data->inq_res.remt_name_not_required = check_eir_remote_name(p_data, NULL, NULL);
}
do {
btc_msg_t msg;
msg.sig = BTC_SIG_API_CALL;
msg.pid = BTC_PID_GAP_BT;
msg.act = BTC_GAP_BT_ACT_SEARCH_DEVICES;
msg.aid = event;
btc_transfer_context(&msg, p_data, param_len,
(param_len > sizeof(tBTA_DM_SEARCH)) ? search_devices_copy_cb : NULL);
} while (0);
}
static void btc_gap_bt_search_devices_evt(tBTA_DM_SEARCH_EVT event, tBTA_DM_SEARCH *p_data)
{
switch (event) {
case BTA_DM_DISC_RES_EVT: {
/* remote name update */
uint32_t bdname_len = strlen((const char *)p_data->disc_res.bd_name);
if (bdname_len) {
esp_bt_gap_dev_prop_t prop[1];
BTC_STORAGE_FILL_PROPERTY(&prop[0], ESP_BT_GAP_DEV_PROP_BDNAME, bdname_len + 1, p_data->disc_res.bd_name);
esp_bt_gap_cb_param_t param;
bdcpy(param.disc_res.bda, p_data->disc_res.bd_addr);
param.disc_res.num_prop = 1;
param.disc_res.prop = prop;
btc_gap_bt_cb_to_app(ESP_BT_GAP_DISC_RES_EVT, &param);
}
break;
}
case BTA_DM_INQ_RES_EVT: {
/* inquiry result */
uint32_t cod = devclass2uint (p_data->inq_res.dev_class);
if (cod == 0) {
LOG_DEBUG("%s cod is 0, set as unclassified", __func__);
cod = COD_UNCLASSIFIED;
}
do {
esp_bt_gap_dev_prop_t prop[3];
int num_prop = 0;
memset(prop, 0, sizeof(prop));
BTC_STORAGE_FILL_PROPERTY(&prop[0], ESP_BT_GAP_DEV_PROP_COD, sizeof(cod), &cod);
num_prop++;
BTC_STORAGE_FILL_PROPERTY(&prop[1], ESP_BT_GAP_DEV_PROP_RSSI, 1, &(p_data->inq_res.rssi));
num_prop++;
if (p_data->inq_res.p_eir) {
BTC_STORAGE_FILL_PROPERTY(&prop[2], ESP_BT_GAP_DEV_PROP_EIR, HCI_EXT_INQ_RESPONSE_LEN, p_data->inq_res.p_eir);
num_prop++;
}
/* Callback to notify upper layer of device */
esp_bt_gap_cb_param_t param;
bdcpy(param.disc_res.bda, p_data->inq_res.bd_addr);
param.disc_res.num_prop = num_prop;
param.disc_res.prop = prop;
btc_gap_bt_cb_to_app(ESP_BT_GAP_DISC_RES_EVT, &param);
} while (0);
}
break;
case BTA_DM_INQ_CMPL_EVT:
break;
case BTA_DM_DISC_CMPL_EVT: {
esp_bt_gap_cb_param_t param;
param.disc_st_chg.state = ESP_BT_GAP_DISCOVERY_STOPPED;
btc_gap_bt_cb_to_app(ESP_BT_GAP_DISC_STATE_CHANGED_EVT, &param);
break;
}
case BTA_DM_SEARCH_CANCEL_CMPL_EVT: {
/* if inquiry is not in progress and we get a cancel event, then
* it means we are done with inquiry, but remote_name fetches are in
* progress
*
* if inquiry is in progress, then we don't want to act on this cancel_cmpl_evt
* but instead wait for the cancel_cmpl_evt_via the busy level
*/
if (btc_gap_bt_inquiry_in_progress == false) {
esp_bt_gap_cb_param_t param;
param.disc_st_chg.state = ESP_BT_GAP_DISCOVERY_STOPPED;
btc_gap_bt_cb_to_app(ESP_BT_GAP_DISC_STATE_CHANGED_EVT, &param);
}
break;
}
}
}
/*******************************************************************************
**
** Function btc_gap_bt_search_service_record
**
** Description Executes search service record event in btif context
**
** Returns void
**
*******************************************************************************/
static void btc_gap_bt_search_service_record(UINT16 event, char *p_param)
{
tBTA_DM_SEARCH *p_data = (tBTA_DM_SEARCH *)p_param;
switch (event) {
case BTA_DM_DISC_RES_EVT: {
esp_bt_gap_cb_param_t param;
memcpy(param.rmt_srvcs.bda, p_data->disc_res.bd_addr, BD_ADDR_LEN);
if (p_data->disc_res.p_raw_data && p_data->disc_res.raw_data_size > 0) {
param.rmt_srvc_rec.stat = ESP_BT_STATUS_SUCCESS;
// param.rmt_srvc_rec.raw_data_size = p_data->disc_res.raw_data_size;
// param.rmt_srvc_rec.raw_data = p_data->disc_res.p_raw_data;
} else {
param.rmt_srvc_rec.stat = ESP_BT_STATUS_FAIL;
// param.rmt_srvc_rec.raw_data_size = 0;
// param.rmt_srvc_rec.raw_data = NULL;
}
btc_gap_bt_cb_to_app(ESP_BT_GAP_RMT_SRVC_REC_EVT, &param);
}
break;
case BTA_DM_DISC_CMPL_EVT:
default:
break;
}
}
/*******************************************************************************
**
** Function bte_dm_remote_service_record_evt
**
** Description Switches context from BTE to BTC for DM search service
** record event
**
** Returns void
**
*******************************************************************************/
static void bte_dm_remote_service_record_evt(tBTA_DM_SEARCH_EVT event, tBTA_DM_SEARCH *p_data)
{
UINT16 param_len = 0;
if (p_data) {
param_len += sizeof(tBTA_DM_SEARCH);
}
/* Allocate buffer to hold the pointers (deep copy). The pointers will point to the end of the tBTA_DM_SEARCH */
if (event == BTA_DM_DISC_RES_EVT) {
if (p_data->disc_res.raw_data_size && p_data->disc_res.p_raw_data) {
param_len += p_data->disc_res.raw_data_size;
}
}
do {
btc_msg_t msg;
msg.sig = BTC_SIG_API_CALL;
msg.pid = BTC_PID_GAP_BT;
msg.act = BTC_GAP_BT_ACT_SEARCH_SERVICE_RECORD;
msg.aid = event;
btc_transfer_context(&msg, p_data, param_len,
(param_len > sizeof(tBTA_DM_SEARCH)) ? search_service_record_copy_cb : NULL);
} while (0);
}
/*******************************************************************************
**
** Function btc_gap_bt_search_services
**
** Description Executes search services event in btc context
**
** Returns void
**
*******************************************************************************/
static void btc_gap_bt_search_services(UINT16 event, char *p_param)
{
tBTA_DM_SEARCH *p_data = (tBTA_DM_SEARCH *)p_param;
switch (event) {
case BTA_DM_DISC_RES_EVT: {
esp_bt_gap_cb_param_t param;
esp_bt_uuid_t *uuid_list = NULL;
memcpy(param.rmt_srvcs.bda, p_data->disc_res.bd_addr, BD_ADDR_LEN);
param.rmt_srvcs.stat = ESP_BT_STATUS_FAIL;
if (p_data->disc_res.result == BTA_SUCCESS) {
uuid_list = malloc(sizeof(esp_bt_uuid_t) * p_data->disc_res.num_uuids);
if (uuid_list) {
param.rmt_srvcs.stat = ESP_BT_STATUS_SUCCESS;
param.rmt_srvcs.num_uuids = p_data->disc_res.num_uuids;
param.rmt_srvcs.uuid_list = uuid_list;
// copy UUID list
uint8_t *i_uu = (uint8_t *)p_data->disc_res.p_uuid_list;
esp_bt_uuid_t *o_uu = uuid_list;
for (int i = 0; i < p_data->disc_res.num_uuids; i++, i_uu += ESP_UUID_LEN_128, o_uu++) {
uuid128_be_to_esp_uuid(o_uu, i_uu);
}
}
}
if (param.rmt_srvcs.stat == ESP_BT_STATUS_FAIL) {
param.rmt_srvcs.num_uuids = 0;
param.rmt_srvcs.uuid_list = NULL;
}
btc_gap_bt_cb_to_app(ESP_BT_GAP_RMT_SRVCS_EVT, &param);
if (uuid_list) {
osi_free(uuid_list);
}
}
break;
case BTA_DM_DISC_BLE_RES_EVT:
case BTA_DM_DISC_CMPL_EVT:
default:
break;
}
}
/*******************************************************************************
**
** Function bte_dm_search_services_evt
**
** Description Switches context from BTE to BTIF for DM search services
** event
**
** Returns void
**
*******************************************************************************/
static void bte_dm_search_services_evt(tBTA_DM_SEARCH_EVT event, tBTA_DM_SEARCH *p_data)
{
UINT16 param_len = 0;
if (p_data) {
param_len += sizeof(tBTA_DM_SEARCH);
}
switch (event) {
case BTA_DM_DISC_RES_EVT: {
if ((p_data->disc_res.result == BTA_SUCCESS) && (p_data->disc_res.num_uuids > 0)) {
param_len += (p_data->disc_res.num_uuids * MAX_UUID_SIZE);
}
} break;
}
/* TODO: The only other member that needs a deep copy is the p_raw_data. But not sure
* if raw_data is needed. */
do {
btc_msg_t msg;
msg.sig = BTC_SIG_API_CALL;
msg.pid = BTC_PID_GAP_BT;
msg.act = BTC_GAP_BT_ACT_SEARCH_SERVICES;
msg.aid = event;
btc_transfer_context(&msg, p_data, param_len,
(param_len > sizeof(tBTA_DM_SEARCH)) ? search_services_copy_cb : NULL);
} while (0);
}
static void search_services_copy_cb(btc_msg_t *msg, void *p_dest, void *p_src)
{
tBTA_DM_SEARCH *p_dest_data = (tBTA_DM_SEARCH *) p_dest;
tBTA_DM_SEARCH *p_src_data = (tBTA_DM_SEARCH *) p_src;
if (!p_src) {
return;
}
switch (msg->aid) {
case BTA_DM_DISC_RES_EVT: {
if (p_src_data->disc_res.result == BTA_SUCCESS) {
if (p_src_data->disc_res.num_uuids > 0) {
p_dest_data->disc_res.p_uuid_list = (UINT8 *)(p_dest + sizeof(tBTA_DM_SEARCH));
memcpy(p_dest_data->disc_res.p_uuid_list, p_src_data->disc_res.p_uuid_list,
p_src_data->disc_res.num_uuids * MAX_UUID_SIZE);
osi_free(p_src_data->disc_res.p_uuid_list);
p_src_data->disc_res.p_uuid_list = NULL;
}
if (p_src_data->disc_res.p_raw_data != NULL) {
osi_free(p_src_data->disc_res.p_raw_data);
p_src_data->disc_res.p_raw_data = NULL;
}
}
} break;
}
}
void btc_gap_bt_call_handler(btc_msg_t *msg)
{
btc_gap_bt_args_t *arg = (btc_gap_bt_args_t *)msg->arg;
@ -78,10 +576,55 @@ void btc_gap_bt_call_handler(btc_msg_t *msg)
btc_bt_set_scan_mode(arg->set_scan_mode.mode);
break;
}
case BTC_GAP_BT_ACT_START_DISCOVERY: {
btc_gap_bt_start_discovery(msg->arg);
break;
}
case BTC_GAP_BT_ACT_SEARCH_DEVICES: {
btc_gap_bt_search_devices_evt(msg->aid, msg->arg);
break;
}
case BTC_GAP_BT_ACT_CANCEL_DISCOVERY: {
btc_gap_bt_cancel_discovery();
break;
}
case BTC_GAP_BT_ACT_GET_REMOTE_SERVICES: {
btc_gap_bt_get_remote_services(msg->arg);
break;
}
case BTC_GAP_BT_ACT_SEARCH_SERVICES: {
btc_gap_bt_search_services(msg->aid, msg->arg);
break;
}
case BTC_GAP_BT_ACT_GET_REMOTE_SERVICE_RECORD: {
btc_gap_bt_get_remote_service_record(msg->arg);
break;
}
case BTC_GAP_BT_ACT_SEARCH_SERVICE_RECORD: {
btc_gap_bt_search_service_record(msg->aid, msg->arg);
break;
}
default:
break;
}
btc_gap_bt_arg_deep_free(msg);
return;
}
#endif /* #if BTC_GAP_BT_INCLUDED */
void btc_gap_bt_busy_level_updated(uint8_t bl_flags)
{
esp_bt_gap_cb_param_t param;
if (bl_flags == BTM_BL_INQUIRY_STARTED) {
param.disc_st_chg.state = ESP_BT_GAP_DISCOVERY_STARTED;
btc_gap_bt_cb_to_app(ESP_BT_GAP_DISC_STATE_CHANGED_EVT, &param);
btc_gap_bt_inquiry_in_progress = true;
} else if (bl_flags == BTM_BL_INQUIRY_CANCELLED ||
bl_flags == BTM_BL_INQUIRY_COMPLETE) {
param.disc_st_chg.state = ESP_BT_GAP_DISCOVERY_STOPPED;
btc_gap_bt_cb_to_app(ESP_BT_GAP_DISC_STATE_CHANGED_EVT, &param);
btc_gap_bt_inquiry_in_progress = false;
}
}
#endif /* (BTC_GAP_BT_INCLUDED == TRUE) */

View file

@ -15,12 +15,23 @@
#ifndef __BTC_GAP_BT_H__
#define __BTC_GAP_BT_H__
#include "bt_target.h"
#include "esp_bt_defs.h"
#include "esp_gap_bt_api.h"
#include "btc_task.h"
#if (BTC_GAP_BT_INCLUDED == TRUE)
typedef enum {
BTC_GAP_BT_ACT_SET_SCAN_MODE = 0,
BTC_GAP_BT_ACT_REG_CB,
BTC_GAP_BT_ACT_START_DISCOVERY,
BTC_GAP_BT_ACT_SEARCH_DEVICES,
BTC_GAP_BT_ACT_CANCEL_DISCOVERY,
BTC_GAP_BT_ACT_GET_REMOTE_SERVICES,
BTC_GAP_BT_ACT_SEARCH_SERVICES,
BTC_GAP_BT_ACT_GET_REMOTE_SERVICE_RECORD,
BTC_GAP_BT_ACT_SEARCH_SERVICE_RECORD,
} btc_gap_bt_act_t;
/* btc_bt_gap_args_t */
@ -29,10 +40,28 @@ typedef union {
struct set_bt_scan_mode_args {
esp_bt_scan_mode_t mode;
} set_scan_mode;
// BTC_GAP_BT_ACT_START_DISCOVERY
struct start_disc_args {
esp_bt_inq_mode_t mode;
uint8_t inq_len;
uint8_t num_rsps;
} start_disc;
// BTC_BT_GAP_ACT_GET_REMOTE_SERVICES
bt_bdaddr_t bda;
// BTC_BT_GAP_ACT_GET_REMTOE_SERVICE_RECORD
struct get_rmt_srv_rcd_args {
bt_bdaddr_t bda;
esp_bt_uuid_t uuid;
} get_rmt_srv_rcd;
} btc_gap_bt_args_t;
void btc_gap_bt_call_handler(btc_msg_t *msg);
void btc_gap_bt_arg_deep_copy(btc_msg_t *msg, void *p_dest, void *p_src);
void btc_gap_bt_busy_level_updated(uint8_t bl_flags);
#endif /* #if BTC_GAP_BT_INCLUDED */
#endif /* __BTC_GAP_BT_H__ */

View file

@ -0,0 +1,9 @@
#
# This is a project Makefile. It is assumed the directory this Makefile resides in is a
# project subdirectory.
#
PROJECT_NAME := bt_discovery
include $(IDF_PATH)/make/project.mk

View file

@ -0,0 +1,14 @@
ESP-IDF BT-INQUIRY demo
======================
Demo of Classic Bluetooth Device and Service Discovery
This is the demo for user to use ESP_APIs to perform inquiry to search for a target device and then performs service search via SDP.
Options choose step:
1. make menuconfig.
2. enter menuconfig "Component config", choose "Bluetooth"
3. enter menu Bluetooth, choose "Classic Bluetooth" and do not choose "Release DRAM from Classic BT controller"
4. choose your options.
After the program started, the device will start inquiry to search for a device with Major device type "PHONE" in the Class of Device Field. Then it will cancel the inquiry and started to perform service discovering on this remote device.

View file

@ -0,0 +1,310 @@
// Copyright 2015-2017 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/****************************************************************************
*
* This file is for Classic Bluetooth device and service discovery Demo.
*
****************************************************************************/
#include <stdint.h>
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "nvs.h"
#include "nvs_flash.h"
#include "esp_system.h"
#include "esp_log.h"
#include "bt.h"
#include "esp_bt_main.h"
#include "esp_bt_device.h"
#include "esp_gap_bt_api.h"
#define GAP_TAG "GAP"
typedef enum {
APP_GAP_STATE_IDLE = 0,
APP_GAP_STATE_DEVICE_DISCOVERING,
APP_GAP_STATE_DEVICE_DISCOVER_COMPLETE,
APP_GAP_STATE_SERVICE_DISCOVERING,
APP_GAP_STATE_SERVICE_DISCOVER_COMPLETE,
} app_gap_state_t;
typedef struct {
bool dev_found;
uint8_t bdname_len;
uint8_t eir_len;
uint8_t rssi;
uint32_t cod;
uint8_t eir[ESP_BT_GAP_EIR_DATA_LEN];
uint8_t bdname[ESP_BT_GAP_MAX_BDNAME_LEN + 1];
esp_bd_addr_t bda;
app_gap_state_t state;
} app_gap_cb_t;
static app_gap_cb_t m_dev_info;
static char *bda2str(esp_bd_addr_t bda, char *str, size_t size)
{
if (bda == NULL || str == NULL || size < 18) {
return NULL;
}
uint8_t *p = bda;
sprintf(str, "%02x:%02x:%02x:%02x:%02x:%02x",
p[0], p[1], p[2], p[3], p[4], p[5]);
return str;
}
static char *uuid2str(esp_bt_uuid_t *uuid, char *str, size_t size)
{
if (uuid == NULL || str == NULL) {
return NULL;
}
if (uuid->len == 2 && size >= 5) {
sprintf(str, "%04x", uuid->uuid.uuid16);
} else if (uuid->len == 4 && size >= 9) {
sprintf(str, "%08x", uuid->uuid.uuid32);
} else if (uuid->len == 16 && size >= 37) {
uint8_t *p = uuid->uuid.uuid128;
sprintf(str, "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
p[15], p[14], p[13], p[12], p[11], p[10], p[9], p[8],
p[7], p[6], p[5], p[4], p[3], p[2], p[1], p[0]);
} else {
return NULL;
}
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;
}
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 update_device_info(esp_bt_gap_cb_param_t *param)
{
char bda_str[18];
uint32_t cod = 0;
int32_t rssi = -129; /* invalid value */
esp_bt_gap_dev_prop_t *p;
ESP_LOGI(GAP_TAG, "Device found: %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(GAP_TAG, "--Class of Device: 0x%x", cod);
break;
case ESP_BT_GAP_DEV_PROP_RSSI:
rssi = *(int8_t *)(p->val);
ESP_LOGI(GAP_TAG, "--RSSI: %d", rssi);
break;
case ESP_BT_GAP_DEV_PROP_BDNAME:
default:
break;
}
}
/* search for device with MAJOR service class as "rendering" in COD */
app_gap_cb_t *p_dev = &m_dev_info;
if (p_dev->dev_found && 0 != memcmp(param->disc_res.bda, p_dev->bda, ESP_BD_ADDR_LEN)) {
return;
}
if (!esp_bt_gap_is_valid_cod(cod) ||
!(esp_bt_gap_get_cod_major_dev(cod) == ESP_BT_COD_MAJOR_DEV_PHONE)) {
return;
}
memcpy(p_dev->bda, param->disc_res.bda, ESP_BD_ADDR_LEN);
p_dev->dev_found = true;
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:
p_dev->cod = *(uint32_t *)(p->val);
break;
case ESP_BT_GAP_DEV_PROP_RSSI:
p_dev->rssi = *(int8_t *)(p->val);
break;
case ESP_BT_GAP_DEV_PROP_BDNAME: {
uint8_t len = (p->len > ESP_BT_GAP_MAX_BDNAME_LEN) ? ESP_BT_GAP_MAX_BDNAME_LEN :
(uint8_t)p->len;
memcpy(p_dev->bdname, (uint8_t *)(p->val), len);
p_dev->bdname[len] = '\0';
p_dev->bdname_len = len;
break;
}
case ESP_BT_GAP_DEV_PROP_EIR: {
memcpy(p_dev->eir, (uint8_t *)(p->val), p->len);
p_dev->eir_len = p->len;
break;
}
default:
break;
}
}
if (p_dev->eir && p_dev->bdname_len == 0) {
get_name_from_eir(p_dev->eir, p_dev->bdname, &p_dev->bdname_len);
ESP_LOGI(GAP_TAG, "Found a target device, address %s, name %s", bda_str, p_dev->bdname);
p_dev->state = APP_GAP_STATE_DEVICE_DISCOVER_COMPLETE;
ESP_LOGI(GAP_TAG, "Cancel device discovery ...");
esp_bt_gap_cancel_discovery();
}
}
void bt_app_gap_init(void)
{
app_gap_cb_t *p_dev = &m_dev_info;
memset(p_dev, 0, sizeof(app_gap_cb_t));
}
void bt_app_gap_cb(esp_bt_gap_cb_event_t event, esp_bt_gap_cb_param_t *param)
{
app_gap_cb_t *p_dev = &m_dev_info;
char bda_str[18];
char uuid_str[37];
switch (event) {
case ESP_BT_GAP_DISC_RES_EVT: {
update_device_info(param);
break;
}
case ESP_BT_GAP_DISC_STATE_CHANGED_EVT: {
if (param->disc_st_chg.state == ESP_BT_GAP_DISCOVERY_STOPPED) {
ESP_LOGI(GAP_TAG, "Device discovery stopped.");
if ( (p_dev->state == APP_GAP_STATE_DEVICE_DISCOVER_COMPLETE ||
p_dev->state == APP_GAP_STATE_DEVICE_DISCOVERING)
&& p_dev->dev_found) {
p_dev->state = APP_GAP_STATE_SERVICE_DISCOVERING;
ESP_LOGI(GAP_TAG, "Discover services ...");
esp_bt_gap_get_remote_services(p_dev->bda);
}
} else if (param->disc_st_chg.state == ESP_BT_GAP_DISCOVERY_STARTED) {
ESP_LOGI(GAP_TAG, "Discovery started.");
}
break;
}
case ESP_BT_GAP_RMT_SRVCS_EVT: {
if (memcmp(param->rmt_srvcs.bda, p_dev->bda, ESP_BD_ADDR_LEN) == 0 &&
p_dev->state == APP_GAP_STATE_SERVICE_DISCOVERING) {
p_dev->state = APP_GAP_STATE_SERVICE_DISCOVER_COMPLETE;
if (param->rmt_srvcs.stat == ESP_BT_STATUS_SUCCESS) {
ESP_LOGI(GAP_TAG, "Services for device %s found", bda2str(p_dev->bda, bda_str, 18));
for (int i = 0; i < param->rmt_srvcs.num_uuids; i++) {
esp_bt_uuid_t *u = param->rmt_srvcs.uuid_list + i;
ESP_LOGI(GAP_TAG, "--%s", uuid2str(u, uuid_str, 37));
// ESP_LOGI(GAP_TAG, "--%d", u->len);
}
} else {
ESP_LOGI(GAP_TAG, "Services for device %s not found", bda2str(p_dev->bda, bda_str, 18));
}
}
break;
}
case ESP_BT_GAP_RMT_SRVC_REC_EVT:
default: {
ESP_LOGI(GAP_TAG, "event: %d", event);
break;
}
}
return;
}
void bt_app_gap_start_up(void)
{
char *dev_name = "ESP_GAP_INQRUIY";
esp_bt_dev_set_device_name(dev_name);
/* set discoverable and connectable mode, wait to be connected */
esp_bt_gap_set_scan_mode(ESP_BT_SCAN_MODE_CONNECTABLE_DISCOVERABLE);
/* register GAP callback function */
esp_bt_gap_register_callback(bt_app_gap_cb);
/* inititialize device information and status */
app_gap_cb_t *p_dev = &m_dev_info;
memset(p_dev, 0, sizeof(app_gap_cb_t));
/* start to discover nearby Bluetooth devices */
p_dev->state = APP_GAP_STATE_DEVICE_DISCOVERING;
esp_bt_gap_start_discovery(ESP_BT_INQ_MODE_GENERAL_INQUIRY, 10, 0);
}
void app_main()
{
/* Initialize NVS — it is used to store PHY calibration data */
esp_err_t ret = nvs_flash_init();
if (ret == ESP_ERR_NVS_NO_FREE_PAGES) {
ESP_ERROR_CHECK(nvs_flash_erase());
ret = nvs_flash_init();
}
ESP_ERROR_CHECK( ret );
esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT();
if (esp_bt_controller_init(&bt_cfg) != ESP_OK) {
ESP_LOGE(GAP_TAG, "%s initialize controller failed\n", __func__);
return;
}
if (esp_bt_controller_enable(ESP_BT_MODE_BTDM) != ESP_OK) {
ESP_LOGE(GAP_TAG, "%s enable controller failed\n", __func__);
return;
}
if (esp_bluedroid_init() != ESP_OK) {
ESP_LOGE(GAP_TAG, "%s initialize bluedroid failed\n", __func__);
return;
}
if (esp_bluedroid_enable() != ESP_OK) {
ESP_LOGE(GAP_TAG, "%s enable bluedroid failed\n", __func__);
return;
}
bt_app_gap_start_up();
}

View file

@ -0,0 +1,5 @@
#
# "main" pseudo-component makefile.
#
# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)

View file

@ -0,0 +1,5 @@
# Override some defaults so BT stack is enabled and
# Classic BT is enabled and BT_DRAM_RELEASE is disabled
CONFIG_BT_ENABLED=y
CONFIG_CLASSIC_BT_ENABLED=y