From c23af0b5bbfba767b785d208495949b38ea0b7ec Mon Sep 17 00:00:00 2001 From: wangmengyang Date: Fri, 24 Nov 2017 17:28:43 +0800 Subject: [PATCH] component/bt: implement Classic Bluetooth GAP APIs for device and service discovery --- components/bt/bluedroid/api/esp_gap_bt_api.c | 108 +++- .../bt/bluedroid/api/include/esp_gap_bt_api.h | 283 ++++++++- components/bt/bluedroid/bta/dm/bta_dm_act.c | 24 +- components/bt/bluedroid/btc/core/btc_dm.c | 11 + components/bt/bluedroid/btc/core/btc_task.c | 5 + components/bt/bluedroid/btc/core/btc_util.c | 72 +-- .../bt/bluedroid/btc/include/btc_util.h | 6 +- .../btc/profile/std/gap/btc_gap_bt.c | 579 +++++++++++++++++- .../btc/profile/std/include/btc_gap_bt.h | 31 +- examples/bluetooth/bt_discovery/Makefile | 9 + examples/bluetooth/bt_discovery/README.rst | 14 + .../bt_discovery/main/bt_discovery.c | 310 ++++++++++ .../bluetooth/bt_discovery/main/component.mk | 5 + .../bluetooth/bt_discovery/sdkconfig.defaults | 5 + 14 files changed, 1367 insertions(+), 95 deletions(-) create mode 100755 examples/bluetooth/bt_discovery/Makefile create mode 100755 examples/bluetooth/bt_discovery/README.rst create mode 100644 examples/bluetooth/bt_discovery/main/bt_discovery.c create mode 100755 examples/bluetooth/bt_discovery/main/component.mk create mode 100644 examples/bluetooth/bt_discovery/sdkconfig.defaults diff --git a/components/bt/bluedroid/api/esp_gap_bt_api.c b/components/bt/bluedroid/api/esp_gap_bt_api.c index 1f68879663..49302d0233 100644 --- a/components/bt/bluedroid/api/esp_gap_bt_api.c +++ b/components/bt/bluedroid/api/esp_gap_bt_api.c @@ -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 */ diff --git a/components/bt/bluedroid/api/include/esp_gap_bt_api.h b/components/bt/bluedroid/api/include/esp_gap_bt_api.h index 5efdd63326..d61e3ce967 100644 --- a/components/bt/bluedroid/api/include/esp_gap_bt_api.h +++ b/components/bt/bluedroid/api/include/esp_gap_bt_api.h @@ -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 diff --git a/components/bt/bluedroid/bta/dm/bta_dm_act.c b/components/bt/bluedroid/bta/dm/bta_dm_act.c index 2d08011f4f..7c09d0daae 100644 --- a/components/bt/bluedroid/bta/dm/bta_dm_act.c +++ b/components/bt/bluedroid/bta/dm/bta_dm_act.c @@ -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; diff --git a/components/bt/bluedroid/btc/core/btc_dm.c b/components/bt/bluedroid/btc/core/btc_dm.c index b81d5bc7b6..2320ea16b4 100644 --- a/components/bt/bluedroid/btc/core/btc_dm.c +++ b/components/bt/bluedroid/btc/core/btc_dm.c @@ -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: diff --git a/components/bt/bluedroid/btc/core/btc_task.c b/components/bt/bluedroid/btc/core/btc_task.c index bed68bbb7b..bcc313ca21 100644 --- a/components/bt/bluedroid/btc/core/btc_task.c +++ b/components/bt/bluedroid/btc/core/btc_task.c @@ -14,6 +14,7 @@ #include #include +#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 }, diff --git a/components/bt/bluedroid/btc/core/btc_util.c b/components/bt/bluedroid/btc/core/btc_util.c index 1ecfbb97f3..5dd56c57a3 100644 --- a/components/bt/bluedroid/btc/core/btc_util.c +++ b/components/bt/bluedroid/btc/core/btc_util.c @@ -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; } diff --git a/components/bt/bluedroid/btc/include/btc_util.h b/components/bt/bluedroid/btc/include/btc_util.h index 23a8fe309d..ddc27b6773 100644 --- a/components/bt/bluedroid/btc/include/btc_util.h +++ b/components/bt/bluedroid/btc/include/btc_util.h @@ -18,6 +18,7 @@ #include #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__ */ diff --git a/components/bt/bluedroid/btc/profile/std/gap/btc_gap_bt.c b/components/bt/bluedroid/btc/profile/std/gap/btc_gap_bt.c index 07737b7d33..2a972089e2 100644 --- a/components/bt/bluedroid/btc/profile/std/gap/btc_gap_bt.c +++ b/components/bt/bluedroid/btc/profile/std/gap/btc_gap_bt.c @@ -12,30 +12,37 @@ // See the License for the specific language governing permissions and // limitations under the License. +#include +#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 #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, ¶m); + } + 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, ¶m); + } 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, ¶m); + 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, ¶m); + } + 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, ¶m); + } + 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, ¶m); + + 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, ¶m); + 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, ¶m); + btc_gap_bt_inquiry_in_progress = false; + } +} + +#endif /* (BTC_GAP_BT_INCLUDED == TRUE) */ diff --git a/components/bt/bluedroid/btc/profile/std/include/btc_gap_bt.h b/components/bt/bluedroid/btc/profile/std/include/btc_gap_bt.h index d77a4b9f65..01b0709652 100644 --- a/components/bt/bluedroid/btc/profile/std/include/btc_gap_bt.h +++ b/components/bt/bluedroid/btc/profile/std/include/btc_gap_bt.h @@ -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__ */ diff --git a/examples/bluetooth/bt_discovery/Makefile b/examples/bluetooth/bt_discovery/Makefile new file mode 100755 index 0000000000..37e3abec5f --- /dev/null +++ b/examples/bluetooth/bt_discovery/Makefile @@ -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 + diff --git a/examples/bluetooth/bt_discovery/README.rst b/examples/bluetooth/bt_discovery/README.rst new file mode 100755 index 0000000000..29db5e73c1 --- /dev/null +++ b/examples/bluetooth/bt_discovery/README.rst @@ -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. diff --git a/examples/bluetooth/bt_discovery/main/bt_discovery.c b/examples/bluetooth/bt_discovery/main/bt_discovery.c new file mode 100644 index 0000000000..789b634cf4 --- /dev/null +++ b/examples/bluetooth/bt_discovery/main/bt_discovery.c @@ -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 +#include +#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(); +} diff --git a/examples/bluetooth/bt_discovery/main/component.mk b/examples/bluetooth/bt_discovery/main/component.mk new file mode 100755 index 0000000000..0b9d7585e7 --- /dev/null +++ b/examples/bluetooth/bt_discovery/main/component.mk @@ -0,0 +1,5 @@ +# +# "main" pseudo-component makefile. +# +# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.) + diff --git a/examples/bluetooth/bt_discovery/sdkconfig.defaults b/examples/bluetooth/bt_discovery/sdkconfig.defaults new file mode 100644 index 0000000000..dd570f866e --- /dev/null +++ b/examples/bluetooth/bt_discovery/sdkconfig.defaults @@ -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 +