]> granicus.if.org Git - esp-idf/blob - examples/bluetooth/bt_discovery/main/bt_discovery.c
Merge branch 'bugfix/spiram_malloc_reserve_internal_fragments' into 'master'
[esp-idf] / examples / bluetooth / bt_discovery / main / bt_discovery.c
1 /*
2    This example code is in the Public Domain (or CC0 licensed, at your option.)
3
4    Unless required by applicable law or agreed to in writing, this
5    software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
6    CONDITIONS OF ANY KIND, either express or implied.
7 */
8
9
10
11 /****************************************************************************
12 *
13 * This file is for Classic Bluetooth device and service discovery Demo.
14 *
15 ****************************************************************************/
16
17 #include <stdint.h>
18 #include <string.h>
19 #include "freertos/FreeRTOS.h"
20 #include "freertos/task.h"
21 #include "nvs.h"
22 #include "nvs_flash.h"
23 #include "esp_system.h"
24 #include "esp_log.h"
25 #include "esp_bt.h"
26 #include "esp_bt_main.h"
27 #include "esp_bt_device.h"
28 #include "esp_gap_bt_api.h"
29
30 #define GAP_TAG          "GAP"
31
32 typedef enum {
33     APP_GAP_STATE_IDLE = 0,
34     APP_GAP_STATE_DEVICE_DISCOVERING,
35     APP_GAP_STATE_DEVICE_DISCOVER_COMPLETE,
36     APP_GAP_STATE_SERVICE_DISCOVERING,
37     APP_GAP_STATE_SERVICE_DISCOVER_COMPLETE,
38 } app_gap_state_t;
39
40 typedef struct {
41     bool dev_found;
42     uint8_t bdname_len;
43     uint8_t eir_len;
44     uint8_t rssi;
45     uint32_t cod;
46     uint8_t eir[ESP_BT_GAP_EIR_DATA_LEN];
47     uint8_t bdname[ESP_BT_GAP_MAX_BDNAME_LEN + 1];
48     esp_bd_addr_t bda;
49     app_gap_state_t state;
50 } app_gap_cb_t;
51
52 static app_gap_cb_t m_dev_info;
53
54 static char *bda2str(esp_bd_addr_t bda, char *str, size_t size)
55 {
56     if (bda == NULL || str == NULL || size < 18) {
57         return NULL;
58     }
59
60     uint8_t *p = bda;
61     sprintf(str, "%02x:%02x:%02x:%02x:%02x:%02x",
62             p[0], p[1], p[2], p[3], p[4], p[5]);
63     return str;
64 }
65
66 static char *uuid2str(esp_bt_uuid_t *uuid, char *str, size_t size)
67 {
68     if (uuid == NULL || str == NULL) {
69         return NULL;
70     }
71
72     if (uuid->len == 2 && size >= 5) {
73         sprintf(str, "%04x", uuid->uuid.uuid16);
74     } else if (uuid->len == 4 && size >= 9) {
75         sprintf(str, "%08x", uuid->uuid.uuid32);
76     } else if (uuid->len == 16 && size >= 37) {
77         uint8_t *p = uuid->uuid.uuid128;
78         sprintf(str, "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
79                 p[15], p[14], p[13], p[12], p[11], p[10], p[9], p[8],
80                 p[7], p[6], p[5], p[4], p[3], p[2], p[1], p[0]);
81     } else {
82         return NULL;
83     }
84
85     return str;
86 }
87
88 static bool get_name_from_eir(uint8_t *eir, uint8_t *bdname, uint8_t *bdname_len)
89 {
90     uint8_t *rmt_bdname = NULL;
91     uint8_t rmt_bdname_len = 0;
92
93     if (!eir) {
94         return false;
95     }
96
97     rmt_bdname = esp_bt_gap_resolve_eir_data(eir, ESP_BT_EIR_TYPE_CMPL_LOCAL_NAME, &rmt_bdname_len);
98     if (!rmt_bdname) {
99         rmt_bdname = esp_bt_gap_resolve_eir_data(eir, ESP_BT_EIR_TYPE_SHORT_LOCAL_NAME, &rmt_bdname_len);
100     }
101
102     if (rmt_bdname) {
103         if (rmt_bdname_len > ESP_BT_GAP_MAX_BDNAME_LEN) {
104             rmt_bdname_len = ESP_BT_GAP_MAX_BDNAME_LEN;
105         }
106
107         if (bdname) {
108             memcpy(bdname, rmt_bdname, rmt_bdname_len);
109             bdname[rmt_bdname_len] = '\0';
110         }
111         if (bdname_len) {
112             *bdname_len = rmt_bdname_len;
113         }
114         return true;
115     }
116
117     return false;
118 }
119
120 static void update_device_info(esp_bt_gap_cb_param_t *param)
121 {
122     char bda_str[18];
123     uint32_t cod = 0;
124     int32_t rssi = -129; /* invalid value */
125     esp_bt_gap_dev_prop_t *p;
126
127     ESP_LOGI(GAP_TAG, "Device found: %s", bda2str(param->disc_res.bda, bda_str, 18));
128     for (int i = 0; i < param->disc_res.num_prop; i++) {
129         p = param->disc_res.prop + i;
130         switch (p->type) {
131         case ESP_BT_GAP_DEV_PROP_COD:
132             cod = *(uint32_t *)(p->val);
133             ESP_LOGI(GAP_TAG, "--Class of Device: 0x%x", cod);
134             break;
135         case ESP_BT_GAP_DEV_PROP_RSSI:
136             rssi = *(int8_t *)(p->val);
137             ESP_LOGI(GAP_TAG, "--RSSI: %d", rssi);
138             break;
139         case ESP_BT_GAP_DEV_PROP_BDNAME:
140         default:
141             break;
142         }
143     }
144
145     /* search for device with MAJOR service class as "rendering" in COD */
146     app_gap_cb_t *p_dev = &m_dev_info;
147     if (p_dev->dev_found && 0 != memcmp(param->disc_res.bda, p_dev->bda, ESP_BD_ADDR_LEN)) {
148         return;
149     }
150
151     if (!esp_bt_gap_is_valid_cod(cod) ||
152             !(esp_bt_gap_get_cod_major_dev(cod) == ESP_BT_COD_MAJOR_DEV_PHONE)) {
153         return;
154     }
155
156     memcpy(p_dev->bda, param->disc_res.bda, ESP_BD_ADDR_LEN);
157     p_dev->dev_found = true;
158     for (int i = 0; i < param->disc_res.num_prop; i++) {
159         p = param->disc_res.prop + i;
160         switch (p->type) {
161         case ESP_BT_GAP_DEV_PROP_COD:
162             p_dev->cod = *(uint32_t *)(p->val);
163             break;
164         case ESP_BT_GAP_DEV_PROP_RSSI:
165             p_dev->rssi = *(int8_t *)(p->val);
166             break;
167         case ESP_BT_GAP_DEV_PROP_BDNAME: {
168             uint8_t len = (p->len > ESP_BT_GAP_MAX_BDNAME_LEN) ? ESP_BT_GAP_MAX_BDNAME_LEN :
169                           (uint8_t)p->len;
170             memcpy(p_dev->bdname, (uint8_t *)(p->val), len);
171             p_dev->bdname[len] = '\0';
172             p_dev->bdname_len = len;
173             break;
174         }
175         case ESP_BT_GAP_DEV_PROP_EIR: {
176             memcpy(p_dev->eir, (uint8_t *)(p->val), p->len);
177             p_dev->eir_len = p->len;
178             break;
179         }
180         default:
181             break;
182         }
183     }
184
185     if (p_dev->eir && p_dev->bdname_len == 0) {
186         get_name_from_eir(p_dev->eir, p_dev->bdname, &p_dev->bdname_len);
187         ESP_LOGI(GAP_TAG, "Found a target device, address %s, name %s", bda_str, p_dev->bdname);
188         p_dev->state = APP_GAP_STATE_DEVICE_DISCOVER_COMPLETE;
189         ESP_LOGI(GAP_TAG, "Cancel device discovery ...");
190         esp_bt_gap_cancel_discovery();
191     }
192 }
193
194 void bt_app_gap_init(void)
195 {
196     app_gap_cb_t *p_dev = &m_dev_info;
197     memset(p_dev, 0, sizeof(app_gap_cb_t));
198 }
199
200 void bt_app_gap_cb(esp_bt_gap_cb_event_t event, esp_bt_gap_cb_param_t *param)
201 {
202     app_gap_cb_t *p_dev = &m_dev_info;
203     char bda_str[18];
204     char uuid_str[37];
205
206     switch (event) {
207     case ESP_BT_GAP_DISC_RES_EVT: {
208         update_device_info(param);
209         break;
210     }
211     case ESP_BT_GAP_DISC_STATE_CHANGED_EVT: {
212         if (param->disc_st_chg.state == ESP_BT_GAP_DISCOVERY_STOPPED) {
213             ESP_LOGI(GAP_TAG, "Device discovery stopped.");
214             if ( (p_dev->state == APP_GAP_STATE_DEVICE_DISCOVER_COMPLETE ||
215                     p_dev->state == APP_GAP_STATE_DEVICE_DISCOVERING)
216                     && p_dev->dev_found) {
217                 p_dev->state = APP_GAP_STATE_SERVICE_DISCOVERING;
218                 ESP_LOGI(GAP_TAG, "Discover services ...");
219                 esp_bt_gap_get_remote_services(p_dev->bda);
220             }
221         } else if (param->disc_st_chg.state == ESP_BT_GAP_DISCOVERY_STARTED) {
222             ESP_LOGI(GAP_TAG, "Discovery started.");
223         }
224         break;
225     }
226     case ESP_BT_GAP_RMT_SRVCS_EVT: {
227         if (memcmp(param->rmt_srvcs.bda, p_dev->bda, ESP_BD_ADDR_LEN) == 0 &&
228                 p_dev->state == APP_GAP_STATE_SERVICE_DISCOVERING) {
229             p_dev->state = APP_GAP_STATE_SERVICE_DISCOVER_COMPLETE;
230             if (param->rmt_srvcs.stat == ESP_BT_STATUS_SUCCESS) {
231                 ESP_LOGI(GAP_TAG, "Services for device %s found",  bda2str(p_dev->bda, bda_str, 18));
232                 for (int i = 0; i < param->rmt_srvcs.num_uuids; i++) {
233                     esp_bt_uuid_t *u = param->rmt_srvcs.uuid_list + i;
234                     ESP_LOGI(GAP_TAG, "--%s", uuid2str(u, uuid_str, 37));
235                     // ESP_LOGI(GAP_TAG, "--%d", u->len);
236                 }
237             } else {
238                 ESP_LOGI(GAP_TAG, "Services for device %s not found",  bda2str(p_dev->bda, bda_str, 18));
239             }
240         }
241         break;
242     }
243     case ESP_BT_GAP_RMT_SRVC_REC_EVT:
244     default: {
245         ESP_LOGI(GAP_TAG, "event: %d", event);
246         break;
247     }
248     }
249     return;
250 }
251
252 void bt_app_gap_start_up(void)
253 {
254     char *dev_name = "ESP_GAP_INQRUIY";
255     esp_bt_dev_set_device_name(dev_name);
256
257     /* set discoverable and connectable mode, wait to be connected */
258     esp_bt_gap_set_scan_mode(ESP_BT_SCAN_MODE_CONNECTABLE_DISCOVERABLE);
259
260     /* register GAP callback function */
261     esp_bt_gap_register_callback(bt_app_gap_cb);
262
263     /* inititialize device information and status */
264     app_gap_cb_t *p_dev = &m_dev_info;
265     memset(p_dev, 0, sizeof(app_gap_cb_t));
266
267     /* start to discover nearby Bluetooth devices */
268     p_dev->state = APP_GAP_STATE_DEVICE_DISCOVERING;
269     esp_bt_gap_start_discovery(ESP_BT_INQ_MODE_GENERAL_INQUIRY, 10, 0);
270 }
271
272 void app_main()
273 {
274     /* Initialize NVS — it is used to store PHY calibration data */
275     esp_err_t ret = nvs_flash_init();
276     if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
277         ESP_ERROR_CHECK(nvs_flash_erase());
278         ret = nvs_flash_init();
279     }
280     ESP_ERROR_CHECK( ret );
281
282     esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT();
283     if ((ret = esp_bt_controller_init(&bt_cfg)) != ESP_OK) {
284         ESP_LOGE(GAP_TAG, "%s initialize controller failed: %s\n", __func__, esp_err_to_name(ret));
285         return;
286     }
287
288     if ((ret = esp_bt_controller_enable(ESP_BT_MODE_BTDM)) != ESP_OK) {
289         ESP_LOGE(GAP_TAG, "%s enable controller failed: %s\n", __func__, esp_err_to_name(ret));
290         return;
291     }
292
293     if ((ret = esp_bluedroid_init()) != ESP_OK) {
294         ESP_LOGE(GAP_TAG, "%s initialize bluedroid failed: %s\n", __func__, esp_err_to_name(ret));
295         return;
296     }
297
298     if ((ret = esp_bluedroid_enable()) != ESP_OK) {
299         ESP_LOGE(GAP_TAG, "%s enable bluedroid failed: %s\n", __func__, esp_err_to_name(ret));
300         return;
301     }
302
303     bt_app_gap_start_up();
304 }