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