1 // Copyright 2017-2019 Espressif Systems (Shanghai) PTE LTD
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include <string.h>
16 #include "ble_hidh.h"
17 #if CONFIG_GATTC_ENABLE
18 #include "esp_hidh_private.h"
19 #include "esp_err.h"
20 #include "esp_log.h"
21 
22 #include "esp_bt.h"
23 #include "esp_bt_defs.h"
24 #include "esp_bt_main.h"
25 #include "esp_gattc_api.h"
26 #include "esp_gatt_defs.h"
27 #include "esp_gap_ble_api.h"
28 #include "esp_hid_common.h"
29 
30 #include "freertos/FreeRTOS.h"
31 #include "freertos/task.h"
32 #include "freertos/semphr.h"
33 
34 static const char *TAG = "BLE_HIDH";
35 
36 static const char *s_gattc_evt_names[] = {"REG", "UNREG", "OPEN", "READ_CHAR", "WRITE_CHAR", "CLOSE", "SEARCH_CMPL", "SEARCH_RES", "READ_DESCR", "WRITE_DESCR", "NOTIFY", "PREP_WRITE", "EXEC", "ACL", "CANCEL_OPEN", "SRVC_CHG", "", "ENC_CMPL_CB", "CFG_MTU", "ADV_DATA", "MULT_ADV_ENB", "MULT_ADV_UPD", "MULT_ADV_DATA", "MULT_ADV_DIS", "CONGEST", "BTH_SCAN_ENB", "BTH_SCAN_CFG", "BTH_SCAN_RD", "BTH_SCAN_THR", "BTH_SCAN_PARAM", "BTH_SCAN_DIS", "SCAN_FLT_CFG", "SCAN_FLT_PARAM", "SCAN_FLT_STATUS", "ADV_VSC", "", "", "", "REG_FOR_NOTIFY", "UNREG_FOR_NOTIFY", "CONNECT", "DISCONNECT", "READ_MULTIPLE", "QUEUE_FULL", "SET_ASSOC", "GET_ADDR_LIST", "DIS_SRVC_CMPL"};
37 
gattc_evt_str(uint8_t event)38 const char *gattc_evt_str(uint8_t event)
39 {
40     if (event >= (sizeof(s_gattc_evt_names)/sizeof(*s_gattc_evt_names))) {
41         return "UNKNOWN";
42     }
43     return s_gattc_evt_names[event];
44 }
45 
46 static xSemaphoreHandle s_ble_hidh_cb_semaphore = NULL;
47 
WAIT_CB(void)48 static inline void WAIT_CB(void)
49 {
50     xSemaphoreTake(s_ble_hidh_cb_semaphore, portMAX_DELAY);
51 }
52 
SEND_CB(void)53 static inline void SEND_CB(void)
54 {
55     xSemaphoreGive(s_ble_hidh_cb_semaphore);
56 }
57 
58 static esp_event_loop_handle_t event_loop_handle;
59 static uint8_t *s_read_data_val = NULL;
60 static uint16_t s_read_data_len = 0;
61 static esp_gatt_status_t s_read_status = ESP_GATT_OK;
62 
read_char(esp_gatt_if_t gattc_if,uint16_t conn_id,uint16_t handle,esp_gatt_auth_req_t auth_req,uint8_t ** out,uint16_t * out_len)63 static esp_gatt_status_t read_char(esp_gatt_if_t gattc_if, uint16_t conn_id, uint16_t handle, esp_gatt_auth_req_t auth_req, uint8_t **out, uint16_t *out_len)
64 {
65     s_read_data_val = NULL;
66     s_read_data_len = 0;
67     if (esp_ble_gattc_read_char(gattc_if, conn_id, handle, auth_req) != ESP_OK) {
68         ESP_LOGE(TAG, "read_char failed");
69         return ESP_GATT_ERROR;
70     }
71     WAIT_CB();
72     if (s_read_status == ESP_GATT_OK) {
73         *out = s_read_data_val;
74         *out_len = s_read_data_len;
75     }
76     return s_read_status;
77 }
78 
read_descr(esp_gatt_if_t gattc_if,uint16_t conn_id,uint16_t handle,esp_gatt_auth_req_t auth_req,uint8_t ** out,uint16_t * out_len)79 static esp_gatt_status_t read_descr(esp_gatt_if_t gattc_if, uint16_t conn_id, uint16_t handle, esp_gatt_auth_req_t auth_req, uint8_t **out, uint16_t *out_len)
80 {
81     s_read_data_val = NULL;
82     s_read_data_len = 0;
83     if (esp_ble_gattc_read_char_descr(gattc_if, conn_id, handle, auth_req) != ESP_OK) {
84         ESP_LOGE(TAG, "esp_ble_gattc_read_char failed");
85         return ESP_GATT_ERROR;
86     }
87     WAIT_CB();
88     if (s_read_status == ESP_GATT_OK) {
89         *out = s_read_data_val;
90         *out_len = s_read_data_len;
91     }
92     return s_read_status;
93 }
94 
read_device_services(esp_gatt_if_t gattc_if,esp_hidh_dev_t * dev)95 static void read_device_services(esp_gatt_if_t gattc_if, esp_hidh_dev_t *dev)
96 {
97     uint16_t suuid, cuuid, duuid;
98     uint16_t chandle, dhandle;
99     esp_hidh_dev_report_t *report = NULL;
100     uint8_t *rdata = 0;
101     uint16_t rlen = 0;
102     esp_hid_report_item_t *r;
103     esp_hid_report_map_t *map;
104 
105     esp_gattc_service_elem_t service_result[10];
106     uint16_t dcount = 10;
107     uint8_t hidindex = 0;
108     if (esp_ble_gattc_get_service(gattc_if, dev->ble.conn_id, NULL, service_result, &dcount, 0) == ESP_OK) {
109         ESP_LOGD(TAG, "Found %u HID Services", dev->config.report_maps_len);
110         dev->config.report_maps = (esp_hid_raw_report_map_t *)malloc(dev->config.report_maps_len * sizeof(esp_hid_raw_report_map_t));
111         if (dev->config.report_maps == NULL) {
112             ESP_LOGE(TAG, "malloc report maps failed");
113             return;
114         }
115 
116         for (uint16_t s = 0; s < dcount; s++) {
117             suuid = service_result[s].uuid.uuid.uuid16;
118             ESP_LOGV(TAG, "SRV(%d) %s start_handle %d, end_handle %d, uuid: 0x%04x", s, service_result[s].is_primary ? " PRIMARY" : "", service_result[s].start_handle, service_result[s].end_handle, suuid);
119 
120             if (suuid != ESP_GATT_UUID_BATTERY_SERVICE_SVC
121                     && suuid != ESP_GATT_UUID_DEVICE_INFO_SVC
122                     && suuid != ESP_GATT_UUID_HID_SVC
123                     && suuid != 0x1800) {//device name?
124                 continue;
125             }
126 
127             esp_gattc_char_elem_t char_result[20];
128             uint16_t ccount = 20;
129             if (esp_ble_gattc_get_all_char(gattc_if, dev->ble.conn_id, service_result[s].start_handle, service_result[s].end_handle, char_result, &ccount, 0) == ESP_OK) {
130                 for (uint16_t c = 0; c < ccount; c++) {
131                     cuuid = char_result[c].uuid.uuid.uuid16;
132                     chandle = char_result[c].char_handle;
133                     ESP_LOGV(TAG, "  CHAR:(%d), handle: %d, perm: 0x%02x, uuid: 0x%04x", c + 1, chandle, char_result[c].properties, cuuid);
134 
135                     if (suuid == 0x1800) {
136                         if (dev->config.device_name == NULL && cuuid == 0x2a00 && (char_result[c].properties & ESP_GATT_CHAR_PROP_BIT_READ) != 0) {
137                             if (read_char(gattc_if, dev->ble.conn_id, chandle, ESP_GATT_AUTH_REQ_NO_MITM, &rdata, &rlen) == ESP_GATT_OK && rlen) {
138                                 dev->config.device_name = (const char *)rdata;
139                             }
140                         } else {
141                             continue;
142                         }
143                     } else if (suuid == ESP_GATT_UUID_BATTERY_SERVICE_SVC) {
144                         if (cuuid == ESP_GATT_UUID_BATTERY_LEVEL && (char_result[c].properties & ESP_GATT_CHAR_PROP_BIT_READ) != 0) {
145                             dev->ble.battery_handle = chandle;
146                         } else {
147                             continue;
148                         }
149                     } else if (suuid == ESP_GATT_UUID_DEVICE_INFO_SVC) {
150                         if (char_result[c].properties & ESP_GATT_CHAR_PROP_BIT_READ) {
151                             if (cuuid == ESP_GATT_UUID_PNP_ID) {
152                                 if (read_char(gattc_if, dev->ble.conn_id, chandle, ESP_GATT_AUTH_REQ_NO_MITM, &rdata, &rlen) == ESP_GATT_OK && rlen == 7) {
153                                     dev->config.vendor_id = *((uint16_t *)&rdata[1]);
154                                     dev->config.product_id = *((uint16_t *)&rdata[3]);
155                                     dev->config.version = *((uint16_t *)&rdata[5]);
156                                 }
157                                 free(rdata);
158                             } else if (cuuid == ESP_GATT_UUID_MANU_NAME) {
159                                 if (read_char(gattc_if, dev->ble.conn_id, chandle, ESP_GATT_AUTH_REQ_NO_MITM, &rdata, &rlen) == ESP_GATT_OK && rlen) {
160                                     dev->config.manufacturer_name = (const char *)rdata;
161                                 }
162                             } else if (cuuid == ESP_GATT_UUID_SERIAL_NUMBER_STR) {
163                                 if (read_char(gattc_if, dev->ble.conn_id, chandle, ESP_GATT_AUTH_REQ_NO_MITM, &rdata, &rlen) == ESP_GATT_OK && rlen) {
164                                     dev->config.serial_number = (const char *)rdata;
165                                 }
166                             }
167                         }
168                         continue;
169                     } else {
170                         if (cuuid == ESP_GATT_UUID_HID_REPORT_MAP) {
171                             if (char_result[c].properties & ESP_GATT_CHAR_PROP_BIT_READ) {
172                                 if (read_char(gattc_if, dev->ble.conn_id, chandle, ESP_GATT_AUTH_REQ_NO_MITM, &rdata, &rlen) == ESP_GATT_OK && rlen) {
173                                     dev->config.report_maps[hidindex].data = (const uint8_t *)rdata;
174                                     dev->config.report_maps[hidindex].len = rlen;
175                                 }
176                             }
177                             continue;
178                         } else if (cuuid == ESP_GATT_UUID_HID_BT_KB_INPUT || cuuid == ESP_GATT_UUID_HID_BT_KB_OUTPUT || cuuid == ESP_GATT_UUID_HID_BT_MOUSE_INPUT || cuuid == ESP_GATT_UUID_HID_REPORT) {
179                             report = (esp_hidh_dev_report_t *)malloc(sizeof(esp_hidh_dev_report_t));
180                             if (report == NULL) {
181                                 ESP_LOGE(TAG, "malloc esp_hidh_dev_report_t failed");
182                                 return;
183                             }
184                             report->next = NULL;
185                             report->permissions = char_result[c].properties;
186                             report->handle = chandle;
187                             report->ccc_handle = 0;
188                             report->report_id = 0;
189                             report->map_index = hidindex;
190                             if (cuuid == ESP_GATT_UUID_HID_BT_KB_INPUT) {
191                                 report->protocol_mode = ESP_HID_PROTOCOL_MODE_BOOT;
192                                 report->report_type = ESP_HID_REPORT_TYPE_INPUT;
193                                 report->usage = ESP_HID_USAGE_KEYBOARD;
194                                 report->value_len = 8;
195                             } else if (cuuid == ESP_GATT_UUID_HID_BT_KB_OUTPUT) {
196                                 report->protocol_mode = ESP_HID_PROTOCOL_MODE_BOOT;
197                                 report->report_type = ESP_HID_REPORT_TYPE_OUTPUT;
198                                 report->usage = ESP_HID_USAGE_KEYBOARD;
199                                 report->value_len = 8;
200                             } else if (cuuid == ESP_GATT_UUID_HID_BT_MOUSE_INPUT) {
201                                 report->protocol_mode = ESP_HID_PROTOCOL_MODE_BOOT;
202                                 report->report_type = ESP_HID_REPORT_TYPE_INPUT;
203                                 report->usage = ESP_HID_USAGE_MOUSE;
204                                 report->value_len = 8;
205                             } else {
206                                 report->protocol_mode = ESP_HID_PROTOCOL_MODE_REPORT;
207                                 report->report_type = 0;
208                                 report->usage = ESP_HID_USAGE_GENERIC;
209                                 report->value_len = 0;
210                             }
211                         } else {
212                             continue;
213                         }
214                     }
215                     esp_gattc_descr_elem_t descr_result[20];
216                     uint16_t dcount = 20;
217                     if (esp_ble_gattc_get_all_descr(gattc_if, dev->ble.conn_id, char_result[c].char_handle, descr_result, &dcount, 0) == ESP_OK) {
218                         for (uint16_t d = 0; d < dcount; d++) {
219                             duuid = descr_result[d].uuid.uuid.uuid16;
220                             dhandle = descr_result[d].handle;
221                             ESP_LOGV(TAG, "    DESCR:(%d), handle: %d, uuid: 0x%04x", d + 1, dhandle, duuid);
222 
223                             if (suuid == ESP_GATT_UUID_BATTERY_SERVICE_SVC) {
224                                 if (duuid == ESP_GATT_UUID_CHAR_CLIENT_CONFIG && (char_result[c].properties & ESP_GATT_CHAR_PROP_BIT_NOTIFY) != 0) {
225                                     dev->ble.battery_ccc_handle = dhandle;
226                                 }
227                             } else if (suuid == ESP_GATT_UUID_HID_SVC && report != NULL) {
228                                 if (duuid == ESP_GATT_UUID_CHAR_CLIENT_CONFIG && (report->permissions & ESP_GATT_CHAR_PROP_BIT_NOTIFY) != 0) {
229                                     report->ccc_handle = dhandle;
230                                 } else if (duuid == ESP_GATT_UUID_RPT_REF_DESCR) {
231                                     if (read_descr(gattc_if, dev->ble.conn_id, dhandle, ESP_GATT_AUTH_REQ_NO_MITM, &rdata, &rlen) == ESP_GATT_OK && rlen) {
232                                         report->report_id = rdata[0];
233                                         report->report_type = rdata[1];
234                                         free(rdata);
235                                     }
236                                 }
237                             }
238                         }
239                     }
240                     if (suuid == ESP_GATT_UUID_HID_SVC && report != NULL) {
241                         report->next = dev->reports;
242                         dev->reports = report;
243                         dev->reports_len++;
244                     }
245                 }
246                 if (suuid == ESP_GATT_UUID_HID_SVC) {
247                     hidindex++;
248                 }
249             }
250         }
251 
252         for (uint8_t d = 0; d < dev->config.report_maps_len; d++) {
253             if (dev->reports_len && dev->config.report_maps[d].len) {
254                 map = esp_hid_parse_report_map(dev->config.report_maps[d].data, dev->config.report_maps[d].len);
255                 if (map) {
256                     if (dev->ble.appearance == 0) {
257                         dev->ble.appearance = map->appearance;
258                     }
259                     report = dev->reports;
260                     while (report) {
261                         if (report->map_index == d) {
262                             for (uint8_t i = 0; i < map->reports_len; i++) {
263                                 r = &map->reports[i];
264                                 if (report->protocol_mode == ESP_HID_PROTOCOL_MODE_BOOT
265                                         && report->protocol_mode == r->protocol_mode
266                                         && report->report_type == r->report_type
267                                         && report->usage == r->usage) {
268                                     report->report_id = r->report_id;
269                                     report->value_len = r->value_len;
270                                 } else if (report->protocol_mode == r->protocol_mode
271                                            && report->report_type == r->report_type
272                                            && report->report_id == r->report_id) {
273                                     report->usage = r->usage;
274                                     report->value_len = r->value_len;
275                                 }
276                             }
277                         }
278                         report = report->next;
279                     }
280                     free(map->reports);
281                     free(map);
282                     map = NULL;
283                 }
284             }
285         }
286     }
287 }
288 
register_for_notify(esp_gatt_if_t gattc_if,esp_bd_addr_t bda,uint16_t handle)289 static void register_for_notify(esp_gatt_if_t gattc_if, esp_bd_addr_t bda, uint16_t handle)
290 {
291     esp_ble_gattc_register_for_notify(gattc_if, bda, handle);
292     WAIT_CB();
293 }
294 
write_char_descr(esp_gatt_if_t gattc_if,uint16_t conn_id,uint16_t handle,uint16_t value_len,uint8_t * value,esp_gatt_write_type_t write_type,esp_gatt_auth_req_t auth_req)295 static void write_char_descr(esp_gatt_if_t gattc_if, uint16_t conn_id, uint16_t handle, uint16_t value_len, uint8_t *value, esp_gatt_write_type_t write_type, esp_gatt_auth_req_t auth_req)
296 {
297     esp_ble_gattc_write_char_descr(gattc_if, conn_id, handle, value_len, value, write_type, auth_req);
298     WAIT_CB();
299 }
300 
attach_report_listeners(esp_gatt_if_t gattc_if,esp_hidh_dev_t * dev)301 static void attach_report_listeners(esp_gatt_if_t gattc_if, esp_hidh_dev_t *dev)
302 {
303     if (dev == NULL) {
304         return;
305     }
306     uint16_t ccc_data = 1;
307     esp_hidh_dev_report_t *report = dev->reports;
308 
309     //subscribe to battery notifications
310     if (dev->ble.battery_handle) {
311         register_for_notify(gattc_if, dev->bda, dev->ble.battery_handle);
312         if (dev->ble.battery_ccc_handle) {
313             //Write CCC descr to enable notifications
314             write_char_descr(gattc_if, dev->ble.conn_id, dev->ble.battery_ccc_handle, 2, (uint8_t *)&ccc_data, ESP_GATT_WRITE_TYPE_NO_RSP, ESP_GATT_AUTH_REQ_NO_MITM);
315         }
316     }
317 
318     while (report) {
319         //subscribe to notifications
320         if ((report->permissions & ESP_GATT_CHAR_PROP_BIT_NOTIFY) != 0 && report->protocol_mode == ESP_HID_PROTOCOL_MODE_REPORT) {
321             register_for_notify(gattc_if, dev->bda, report->handle);
322             if (report->ccc_handle) {
323                 //Write CCC descr to enable notifications
324                 write_char_descr(gattc_if, dev->ble.conn_id, report->ccc_handle, 2, (uint8_t *)&ccc_data, ESP_GATT_WRITE_TYPE_NO_RSP, ESP_GATT_AUTH_REQ_NO_MITM);
325             }
326         }
327         report = report->next;
328     }
329 }
330 
331 static esp_gatt_if_t hid_gattc_if = 0;
332 
esp_hidh_gattc_event_handler(esp_gattc_cb_event_t event,esp_gatt_if_t gattc_if,esp_ble_gattc_cb_param_t * param)333 void esp_hidh_gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if, esp_ble_gattc_cb_param_t *param)
334 {
335     esp_ble_gattc_cb_param_t *p_data = param;
336     esp_hidh_dev_t *dev = NULL;
337     esp_hidh_dev_report_t *report = NULL;
338 
339     switch (event) {
340     case ESP_GATTC_REG_EVT:
341         if (param->reg.status == ESP_GATT_OK) {
342             hid_gattc_if = gattc_if;
343         } else {
344             ESP_LOGE(TAG, "Reg app failed, app_id %04x, status 0x%x", param->reg.app_id,  param->reg.status);
345             return;
346         }
347         SEND_CB();
348         break;
349 
350     case ESP_GATTC_OPEN_EVT:
351         ESP_LOGV(TAG, "OPEN bda " ESP_BD_ADDR_STR ", conn_id %d, status 0x%x, mtu %d", ESP_BD_ADDR_HEX(p_data->open.remote_bda), p_data->open.conn_id, p_data->open.status, p_data->open.mtu);
352         dev = esp_hidh_dev_get_by_bda(p_data->open.remote_bda);
353         if (!dev) {
354             ESP_LOGE(TAG, "OPEN received for unknown device");
355             break;
356         }
357         if (p_data->open.status != 0) {
358             //error
359             ESP_LOGE(TAG, "OPEN failed: 0x%x", p_data->open.status);
360             dev->status = p_data->open.status;//ESP_GATT_CONN_FAIL_ESTABLISH;
361             dev->ble.conn_id = -1;
362             SEND_CB();//return from open
363         } else {
364             dev->status = ESP_GATT_NOT_FOUND;//set to not found and clear if HID service is found
365             dev->ble.conn_id = p_data->open.conn_id;
366             esp_ble_gattc_search_service(gattc_if, dev->ble.conn_id, NULL);
367         }
368         break;
369 
370     case ESP_GATTC_SEARCH_RES_EVT:
371         dev = esp_hidh_dev_get_by_conn_id(p_data->search_res.conn_id);
372         if (!dev) {
373             ESP_LOGE(TAG, "SEARCH_RES received for unknown device");
374             break;
375         }
376         if (p_data->search_res.srvc_id.uuid.uuid.uuid16 == ESP_GATT_UUID_HID_SVC) {
377             dev->status = ESP_GATT_OK;
378             dev->config.report_maps_len++;
379             ESP_LOGV(TAG, "SEARCH_RES HID Service was found");
380         }
381         break;
382 
383     case ESP_GATTC_SEARCH_CMPL_EVT:
384         dev = esp_hidh_dev_get_by_conn_id(p_data->search_cmpl.conn_id);
385         if (!dev) {
386             ESP_LOGE(TAG, "SEARCH_CMPL received for unknown device");
387             break;
388         }
389         if (dev->status == ESP_GATT_NOT_FOUND) {
390             //service not found
391             ESP_LOGE(TAG, "SEARCH_CMPL HID Service was not found on the device");
392             dev->status = ESP_GATT_CONN_NONE;
393         } else if (p_data->search_cmpl.status) {
394             //error
395             dev->status = p_data->search_cmpl.status;
396         }
397         if (dev->status) {
398             esp_ble_gattc_close(gattc_if, dev->ble.conn_id);
399             dev->ble.conn_id = -1;
400         }
401         dev->connected = true;
402         SEND_CB();//return from open
403         break;
404 
405 
406     case ESP_GATTC_READ_CHAR_EVT:
407     case ESP_GATTC_READ_DESCR_EVT: {
408         dev = esp_hidh_dev_get_by_conn_id(p_data->read.conn_id);
409         if (!dev) {
410             ESP_LOGE(TAG, "READ received for unknown device");
411             break;
412         }
413         dev->status = p_data->read.status;
414         s_read_status = p_data->read.status;
415         s_read_data_len = 0;
416         s_read_data_val = NULL;
417         if (s_read_status == 0 && p_data->read.value_len > 0) {
418             s_read_data_len = p_data->read.value_len;
419             s_read_data_val = (uint8_t *)malloc(s_read_data_len + 1);
420             if (s_read_data_val) {
421                 memcpy(s_read_data_val, p_data->read.value, s_read_data_len);
422                 s_read_data_val[s_read_data_len] = 0;
423             }
424         }
425         SEND_CB();
426         break;
427     }
428 
429     case ESP_GATTC_WRITE_DESCR_EVT: {
430         dev = esp_hidh_dev_get_by_conn_id(p_data->write.conn_id);
431         if (!dev) {
432             ESP_LOGE(TAG, "WRITE_DESCR received for unknown device");
433             break;
434         }
435         dev->status = p_data->write.status;
436         SEND_CB();
437         break;
438     }
439 
440     case ESP_GATTC_WRITE_CHAR_EVT: {
441         dev = esp_hidh_dev_get_by_conn_id(p_data->write.conn_id);
442         if (!dev) {
443             ESP_LOGE(TAG, "WRITE_CHAR received for unknown device");
444             break;
445         }
446         dev->status = p_data->write.status;
447         if (p_data->write.status) {
448             ESP_LOGE(TAG, "WRITE_CHAR: conn_id %d, handle %d, status 0x%x", p_data->write.conn_id, p_data->write.handle, p_data->write.status);
449         }
450         break;
451     }
452 
453     case ESP_GATTC_REG_FOR_NOTIFY_EVT: {
454         SEND_CB();
455         break;
456     }
457 
458     case ESP_GATTC_DISCONNECT_EVT: {
459         ESP_LOGV(TAG, "DISCONNECT: bda " ESP_BD_ADDR_STR ", conn_id %u, reason 0x%x", ESP_BD_ADDR_HEX(p_data->disconnect.remote_bda), p_data->disconnect.conn_id, p_data->disconnect.reason);
460         break;
461     }
462 
463     case ESP_GATTC_NOTIFY_EVT: {
464         dev = esp_hidh_dev_get_by_conn_id(p_data->notify.conn_id);
465         if (!dev) {
466             ESP_LOGE(TAG, "NOTIFY received for unknown device");
467             break;
468         }
469         if (event_loop_handle) {
470             esp_hidh_event_data_t p = {0};
471             if (p_data->notify.handle == dev->ble.battery_handle) {
472                 p.battery.dev = dev;
473                 p.battery.level = p_data->notify.value[0];
474                 esp_event_post_to(event_loop_handle, ESP_HIDH_EVENTS, ESP_HIDH_BATTERY_EVENT, &p, sizeof(esp_hidh_event_data_t), portMAX_DELAY);
475             } else {
476                 report = esp_hidh_dev_get_report_by_handle(dev, p_data->notify.handle);
477                 if (report) {
478                     esp_hidh_event_data_t *p_param = NULL;
479                     size_t event_data_size = sizeof(esp_hidh_event_data_t);
480 
481                     if (p_data->notify.value_len && p_data->notify.value) {
482                         event_data_size += p_data->notify.value_len;
483                     }
484 
485                     if ((p_param = (esp_hidh_event_data_t *)malloc(event_data_size)) == NULL) {
486                         ESP_LOGE(TAG, "%s malloc event data failed!", __func__);
487                         break;
488                     }
489                     memset(p_param, 0, event_data_size);
490                     if (p_data->notify.value_len && p_data->notify.value) {
491                         memcpy(((uint8_t *)p_param) + sizeof(esp_hidh_event_data_t), p_data->notify.value,
492                                p_data->notify.value_len);
493                     }
494 
495                     if (report->report_type == ESP_HID_REPORT_TYPE_FEATURE) {
496                         p_param->feature.dev = dev;
497                         p_param->feature.map_index = report->map_index;
498                         p_param->feature.report_id = report->report_id;
499                         p_param->feature.usage = report->usage;
500                         p_param->feature.length = p_data->notify.value_len;
501                         p_param->feature.data = p_data->notify.value;
502                         esp_event_post_to(event_loop_handle, ESP_HIDH_EVENTS, ESP_HIDH_FEATURE_EVENT, p_param, event_data_size, portMAX_DELAY);
503                     } else {
504                         p_param->input.dev = dev;
505                         p_param->input.map_index = report->map_index;
506                         p_param->input.report_id = report->report_id;
507                         p_param->input.usage = report->usage;
508                         p_param->input.length = p_data->notify.value_len;
509                         p_param->input.data = p_data->notify.value;
510                         esp_event_post_to(event_loop_handle, ESP_HIDH_EVENTS, ESP_HIDH_INPUT_EVENT, p_param, event_data_size, portMAX_DELAY);
511                     }
512 
513                     if (p_param) {
514                         free(p_param);
515                         p_param = NULL;
516                     }
517                 }
518             }
519         }
520         break;
521     }
522 
523     case ESP_GATTC_CLOSE_EVT: {
524         ESP_LOGV(TAG, "CLOSE bda " ESP_BD_ADDR_STR ", conn_id %d, status 0x%x, reason 0x%x", ESP_BD_ADDR_HEX(p_data->close.remote_bda), p_data->close.conn_id, p_data->close.status, p_data->close.reason);
525         dev = esp_hidh_dev_get_by_bda(p_data->open.remote_bda);
526         if (!dev) {
527             ESP_LOGE(TAG, "CLOSE received for unknown device");
528             break;
529         }
530         if (!dev->connected) {
531             dev->status = p_data->close.reason;
532             dev->ble.conn_id = -1;
533             SEND_CB();//return from open
534         } else {
535             dev->connected = false;
536             dev->status = p_data->close.status;
537             // free the device in the wrapper event handler
538             dev->in_use = false;
539             if (event_loop_handle) {
540                 esp_hidh_event_data_t p = {0};
541                 p.close.dev = dev;
542                 p.close.reason = p_data->close.reason;
543                 p.close.status = ESP_OK;
544                 esp_event_post_to(event_loop_handle, ESP_HIDH_EVENTS, ESP_HIDH_CLOSE_EVENT, &p, sizeof(esp_hidh_event_data_t), portMAX_DELAY);
545             } else {
546                 esp_hidh_dev_free_inner(dev);
547             }
548         }
549         break;
550     }
551 
552     default:
553         ESP_LOGV(TAG, "GATTC EVENT %s", gattc_evt_str(event));
554         break;
555     }
556 }
557 
558 /*
559  * Public Functions
560  * */
561 
esp_ble_hidh_dev_close(esp_hidh_dev_t * dev)562 static esp_err_t esp_ble_hidh_dev_close(esp_hidh_dev_t *dev)
563 {
564     return esp_ble_gattc_close(hid_gattc_if, dev->ble.conn_id);
565 }
566 
esp_ble_hidh_dev_report_write(esp_hidh_dev_t * dev,size_t map_index,size_t report_id,int report_type,uint8_t * value,size_t value_len)567 static esp_err_t esp_ble_hidh_dev_report_write(esp_hidh_dev_t *dev, size_t map_index, size_t report_id, int report_type, uint8_t *value, size_t value_len)
568 {
569     esp_hidh_dev_report_t *report = esp_hidh_dev_get_report_by_id_and_type(dev, map_index, report_id, report_type);
570     if (!report) {
571         ESP_LOGE(TAG, "%s report %d not found", esp_hid_report_type_str(report_type), report_id);
572         return ESP_FAIL;
573     }
574     if (value_len > report->value_len) {
575         ESP_LOGE(TAG, "%s report %d takes maximum %d bytes. you have provided %d", esp_hid_report_type_str(report_type), report_id, report->value_len, value_len);
576         return ESP_FAIL;
577     }
578     return esp_ble_gattc_write_char(hid_gattc_if, dev->ble.conn_id, report->handle, value_len, value, ESP_GATT_WRITE_TYPE_RSP, ESP_GATT_AUTH_REQ_NO_MITM);
579 }
580 
esp_ble_hidh_dev_report_read(esp_hidh_dev_t * dev,size_t map_index,size_t report_id,int report_type,size_t max_length,uint8_t * value,size_t * value_len)581 static esp_err_t esp_ble_hidh_dev_report_read(esp_hidh_dev_t *dev, size_t map_index, size_t report_id, int report_type, size_t max_length, uint8_t *value, size_t *value_len)
582 {
583     esp_hidh_dev_report_t *report = esp_hidh_dev_get_report_by_id_and_type(dev, map_index, report_id, report_type);
584     if (!report) {
585         ESP_LOGE(TAG, "%s report %d not found", esp_hid_report_type_str(report_type), report_id);
586         return ESP_FAIL;
587     }
588     uint16_t len = max_length;
589     uint8_t *v = NULL;
590     esp_gatt_status_t s = read_char(hid_gattc_if, dev->ble.conn_id, report->handle, ESP_GATT_AUTH_REQ_NO_MITM, &v, &len);
591     if (s == ESP_GATT_OK) {
592         if (len > max_length) {
593             len = max_length;
594         }
595         *value_len = len;
596         memcpy(value, v, len);
597         return ESP_OK;
598     }
599     ESP_LOGE(TAG, "%s report %d read failed: 0x%x", esp_hid_report_type_str(report_type), report_id, s);
600     return ESP_FAIL;
601 }
602 
esp_ble_hidh_dev_dump(esp_hidh_dev_t * dev,FILE * fp)603 static void esp_ble_hidh_dev_dump(esp_hidh_dev_t *dev, FILE *fp)
604 {
605     fprintf(fp, "BDA:" ESP_BD_ADDR_STR ", Appearance: 0x%04x, Connection ID: %d\n", ESP_BD_ADDR_HEX(dev->bda), dev->ble.appearance, dev->ble.conn_id);
606     fprintf(fp, "Name: %s, Manufacturer: %s, Serial Number: %s\n", dev->config.device_name ? dev->config.device_name : "", dev->config.manufacturer_name ? dev->config.manufacturer_name : "", dev->config.serial_number ? dev->config.serial_number : "");
607     fprintf(fp, "PID: 0x%04x, VID: 0x%04x, VERSION: 0x%04x\n", dev->config.product_id, dev->config.vendor_id, dev->config.version);
608     fprintf(fp, "Battery: Handle: %u, CCC Handle: %u\n", dev->ble.battery_handle, dev->ble.battery_ccc_handle);
609     fprintf(fp, "Report Maps: %d\n", dev->config.report_maps_len);
610     for (uint8_t d = 0; d < dev->config.report_maps_len; d++) {
611         fprintf(fp, "  Report Map Length: %d\n", dev->config.report_maps[d].len);
612         esp_hidh_dev_report_t *report = dev->reports;
613         while (report) {
614             if (report->map_index == d) {
615                 fprintf(fp, "    %8s %7s %6s, ID: %2u, Length: %3u, Permissions: 0x%02x, Handle: %3u, CCC Handle: %3u\n",
616                        esp_hid_usage_str(report->usage), esp_hid_report_type_str(report->report_type), esp_hid_protocol_mode_str(report->protocol_mode),
617                        report->report_id, report->value_len, report->permissions, report->handle, report->ccc_handle);
618             }
619             report = report->next;
620         }
621     }
622 
623 }
624 
esp_ble_hidh_init(const esp_hidh_config_t * config)625 esp_err_t esp_ble_hidh_init(const esp_hidh_config_t *config)
626 {
627     esp_err_t ret;
628     if (config == NULL) {
629         ESP_LOGE(TAG, "Config is NULL");
630         return ESP_FAIL;
631     }
632     if (s_ble_hidh_cb_semaphore != NULL) {
633         ESP_LOGE(TAG, "Already initialised");
634         return ESP_FAIL;
635     }
636     s_ble_hidh_cb_semaphore = xSemaphoreCreateBinary();
637     if (s_ble_hidh_cb_semaphore == NULL) {
638         ESP_LOGE(TAG, "xSemaphoreCreateMutex failed!");
639         return ESP_FAIL;
640     }
641     esp_event_loop_args_t event_task_args = {
642         .queue_size = 5,
643         .task_name = "esp_ble_hidh_events",
644         .task_priority = uxTaskPriorityGet(NULL),
645         .task_stack_size = config->event_stack_size > 0 ? config->event_stack_size : 2048,
646         .task_core_id = tskNO_AFFINITY
647     };
648 
649     do {
650         ret = esp_event_loop_create(&event_task_args, &event_loop_handle);
651         if (ret != ESP_OK) {
652             ESP_LOGE(TAG, "%s esp_event_loop_create failed!", __func__);
653             break;
654         }
655 
656         ret = esp_ble_gattc_app_register(0);
657         if (ret != ESP_OK) {
658             ESP_LOGE(TAG, "esp_ble_gattc_app_register failed!");
659             break;
660         }
661         WAIT_CB();
662         ret = esp_event_handler_register_with(event_loop_handle, ESP_HIDH_EVENTS, ESP_EVENT_ANY_ID,
663                                               esp_hidh_process_event_data_handler, NULL);
664         ret |= esp_event_handler_register_with(event_loop_handle, ESP_HIDH_EVENTS, ESP_EVENT_ANY_ID, config->callback,
665                                               config->callback_arg);
666     } while (0);
667 
668     if (ret != ESP_OK) {
669         if (event_loop_handle) {
670             esp_event_loop_delete(event_loop_handle);
671         }
672 
673         if (s_ble_hidh_cb_semaphore) {
674             vSemaphoreDelete(s_ble_hidh_cb_semaphore);
675             s_ble_hidh_cb_semaphore = NULL;
676         }
677     }
678     return ret;
679 }
680 
esp_ble_hidh_deinit(void)681 esp_err_t esp_ble_hidh_deinit(void)
682 {
683     if (s_ble_hidh_cb_semaphore == NULL) {
684         ESP_LOGE(TAG, "Already deinitialised");
685         return ESP_FAIL;
686     }
687 
688     esp_err_t err = esp_ble_gattc_app_unregister(hid_gattc_if);
689     if (err != ESP_OK) {
690         ESP_LOGE(TAG, "App Unregister Failed");
691         return err;
692     }
693 
694     if (event_loop_handle) {
695         esp_event_loop_delete(event_loop_handle);
696     }
697     vSemaphoreDelete(s_ble_hidh_cb_semaphore);
698     s_ble_hidh_cb_semaphore = NULL;
699     return err;
700 }
701 
esp_ble_hidh_dev_open(esp_bd_addr_t bda,esp_ble_addr_type_t address_type)702 esp_hidh_dev_t *esp_ble_hidh_dev_open(esp_bd_addr_t bda, esp_ble_addr_type_t address_type)
703 {
704     esp_err_t ret;
705 
706     esp_hidh_dev_t *dev = esp_hidh_dev_malloc();
707     if (dev == NULL) {
708         ESP_LOGE(TAG, "malloc esp_hidh_dev_t failed");
709         return NULL;
710     }
711 
712     dev->in_use = true;
713     dev->transport = ESP_HID_TRANSPORT_BLE;
714     memcpy(dev->bda, bda, sizeof(esp_bd_addr_t));
715     dev->ble.address_type = address_type;
716     dev->ble.appearance = ESP_HID_APPEARANCE_GENERIC;
717 
718     ret = esp_ble_gattc_open(hid_gattc_if, dev->bda, dev->ble.address_type, true);
719     if (ret) {
720         esp_hidh_dev_free_inner(dev);
721         ESP_LOGE(TAG, "esp_ble_gattc_open failed: %d", ret);
722         return NULL;
723     }
724     WAIT_CB();
725     if (dev->ble.conn_id < 0) {
726         ret = dev->status;
727         ESP_LOGE(TAG, "dev open failed! status: 0x%x", dev->status);
728         esp_hidh_dev_free_inner(dev);
729         return NULL;
730     }
731 
732     dev->close = esp_ble_hidh_dev_close;
733     dev->report_write = esp_ble_hidh_dev_report_write;
734     dev->report_read = esp_ble_hidh_dev_report_read;
735     dev->dump = esp_ble_hidh_dev_dump;
736 
737     read_device_services(hid_gattc_if, dev);
738 
739     if (event_loop_handle) {
740         esp_hidh_event_data_t p = {0};
741         p.open.status = ESP_OK;
742         p.open.dev = dev;
743         esp_event_post_to(event_loop_handle, ESP_HIDH_EVENTS, ESP_HIDH_OPEN_EVENT, &p, sizeof(esp_hidh_event_data_t), portMAX_DELAY);
744     }
745 
746     attach_report_listeners(hid_gattc_if, dev);
747     return dev;
748 }
749 
750 #endif /* CONFIG_GATTC_ENABLE */
751