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 "bt_hidh.h"
16 #if CONFIG_BT_HID_HOST_ENABLED
17 #include "esp_hidh_private.h"
18 #include <string.h>
19 #include <stdbool.h>
20
21 #include "freertos/FreeRTOS.h"
22 #include "freertos/task.h"
23 #include "freertos/semphr.h"
24 #include "osi/fixed_queue.h"
25 #include "string.h"
26 #include "esp_hidh_api.h"
27
28 static const char *TAG = "BT_HIDH";
29
30 // element of connection queue
31 typedef struct {
32 esp_hidh_dev_t* dev;
33 } conn_item_t;
34
35 typedef struct {
36 fixed_queue_t *connection_queue; /* Queue of connection */
37 esp_event_loop_handle_t event_loop_handle;
38 } hidh_local_param_t;
39
40 static hidh_local_param_t hidh_local_param;
41 #define TRANS_TO 1000000 // us
42 #define is_init() (hidh_local_param.event_loop_handle != NULL)
43
44 #define get_protocol_mode(mode) (mode) ? "REPORT" : "BOOT"
45 static const char *s_esp_hh_evt_names[] = {"INIT", "DEINIT", "OPEN", "CLOSE", "GET_RPT", "SET_RPT", "GET_PROTO", "SET_PROTO", "GET_IDLE", "SET_IDLE", "GET_DSCP", "ADD_DEV", "RMV_DEV", "VC_UNPLUG", "DATA", "DATA_IND", "SET_INFO"};
46 static const char *s_esp_hh_status_names[] = {"OK",
47 "HS_HID_NOT_READY",
48 "HS_INVALID_RPT_ID",
49 "HS_TRANS_NOT_SPT",
50 "HS_INVALID_PARAM",
51 "HS_ERROR",
52 "ERR",
53 "ERR_SDP",
54 "ERR_PROTO",
55 "ERR_DB_FULL",
56 "ERR_TOD_UNSPT",
57 "ERR_NO_RES",
58 "ERR_AUTH_FAILED",
59 "ERR_HDL",
60 "ERR_SEC",
61 "BUSY",
62 "NO_DATA",
63 "NEED_INIT",
64 "NEED_DEINIT",
65 "NO_CONNECTION"};
66
67 static esp_hidh_dev_t *hidh_dev_ctor(esp_bd_addr_t bda);
68
get_trans_type_str(esp_hid_trans_type_t trans_type)69 static char *get_trans_type_str(esp_hid_trans_type_t trans_type)
70 {
71 switch (trans_type) {
72 case ESP_HID_TRANS_HANDSHAKE:
73 return "TRANS_HANDSHAKE";
74 case ESP_HID_TRANS_CONTROL:
75 return "TRANS_CONTROL";
76 case ESP_HID_TRANS_GET_REPORT:
77 return "TRANS_GET_REPORT";
78 case ESP_HID_TRANS_SET_REPORT:
79 return "TRANS_SET_REPORT";
80 case ESP_HID_TRANS_GET_PROTOCOL:
81 return "TRANS_GET_PROTOCOL";
82 case ESP_HID_TRANS_SET_PROTOCOL:
83 return "TRANS_SET_PROTOCOL";
84 case ESP_HID_TRANS_GET_IDLE:
85 return "TRANS_GET_IDLE";
86 case ESP_HID_TRANS_SET_IDLE:
87 return "TRANS_SET_IDLE";
88 case ESP_HID_TRANS_DATA:
89 return "TRANS_DATA";
90 case ESP_HID_TRANS_DATAC:
91 return "TRANS_DATAC";
92 case ESP_HID_TRANS_MAX:
93 return "TRANS_MAX";
94 default:
95 return "UNKOWN";
96 }
97 }
98
bt_hidh_get_status(esp_hidh_status_t status)99 static esp_err_t bt_hidh_get_status(esp_hidh_status_t status)
100 {
101 esp_err_t ret = ESP_OK;
102 switch (status) {
103 case ESP_HIDH_OK:
104 ret = ESP_OK;
105 break;
106 case ESP_HIDH_ERR_NO_RES:
107 ret = ESP_ERR_NO_MEM;
108 break;
109 default:
110 ret = ESP_FAIL;
111 break;
112 }
113 return ret;
114 }
115
utl_freebuf(void ** p)116 static void utl_freebuf(void **p)
117 {
118 if (*p != NULL) {
119 free(*p);
120 *p = NULL;
121 }
122 }
123
transaction_timeout_handler(void * arg)124 static void transaction_timeout_handler(void *arg)
125 {
126 esp_hidh_dev_t *dev = (esp_hidh_dev_t *)arg;
127 if (dev != NULL && esp_hidh_dev_exists(dev)) {
128 ESP_LOGW(TAG, "transaction timeout!");
129 esp_hidh_dev_lock(dev);
130 dev->trans_type = ESP_HID_TRANS_MAX;
131 dev->report_id = 0;
132 dev->report_type = 0;
133 esp_hidh_dev_unlock(dev);
134 }
135 }
136
set_trans(esp_hidh_dev_t * dev,esp_hid_trans_type_t trans_type)137 static inline void set_trans(esp_hidh_dev_t *dev, esp_hid_trans_type_t trans_type)
138 {
139 dev->trans_type = trans_type;
140 if (dev->trans_timer == NULL) {
141 esp_timer_create_args_t config = {
142 .callback = &transaction_timeout_handler,
143 .arg = (void *)dev,
144 .name = "hid_trans"
145 };
146 if (esp_timer_create(&config, &dev->trans_timer) != ESP_OK) {
147 ESP_LOGE(TAG, "create trans timer failed! trans:%s", get_trans_type_str(trans_type));
148 return;
149 }
150 }
151 if (!esp_timer_is_active(dev->trans_timer) && esp_timer_start_once(dev->trans_timer, TRANS_TO) != ESP_OK) {
152 ESP_LOGE(TAG, "set trans timer failed! trans:%s", get_trans_type_str(trans_type));
153 }
154 }
155
reset_trans(esp_hidh_dev_t * dev)156 static inline void reset_trans(esp_hidh_dev_t *dev)
157 {
158 esp_hidh_dev_lock(dev);
159 dev->trans_type = ESP_HID_TRANS_MAX;
160 dev->report_id = 0;
161 dev->report_type = 0;
162 if (dev->trans_timer) {
163 esp_timer_stop(dev->trans_timer);
164 }
165 esp_hidh_dev_unlock(dev);
166 }
167
is_trans_done(esp_hidh_dev_t * dev)168 static inline bool is_trans_done(esp_hidh_dev_t *dev)
169 {
170 bool ret = (dev->trans_type == ESP_HID_TRANS_MAX);
171 return ret;
172 }
173
free_local_param(void)174 static void free_local_param(void)
175 {
176 if (hidh_local_param.event_loop_handle) {
177 esp_event_loop_delete(hidh_local_param.event_loop_handle);
178 }
179
180 if (hidh_local_param.connection_queue) {
181 fixed_queue_free(hidh_local_param.connection_queue, free);
182 }
183 }
184
open_failed_cb(esp_hidh_dev_t * dev,esp_hidh_status_t status,esp_hidh_event_data_t * p,size_t event_data_size)185 static void open_failed_cb(esp_hidh_dev_t *dev, esp_hidh_status_t status, esp_hidh_event_data_t *p,
186 size_t event_data_size)
187 {
188 p->open.status = bt_hidh_get_status(status);
189 p->open.dev = dev;
190 if (dev != NULL) {
191 esp_hidh_dev_lock(dev);
192 if (dev->connected) {
193 esp_bt_hid_host_disconnect(dev->bda);
194 } else {
195 dev->in_use = false;
196 }
197 esp_hidh_dev_unlock(dev);
198 }
199 esp_event_post_to(hidh_local_param.event_loop_handle, ESP_HIDH_EVENTS, ESP_HIDH_OPEN_EVENT, p, event_data_size,
200 portMAX_DELAY);
201 }
202
esp_hh_cb(esp_hidh_cb_event_t event,esp_hidh_cb_param_t * param)203 static void esp_hh_cb(esp_hidh_cb_event_t event, esp_hidh_cb_param_t *param)
204 {
205 conn_item_t *conn_item = NULL;
206 esp_hidh_dev_t *dev = NULL;
207 esp_hidh_dev_report_t *report = NULL;
208 bool has_report_id = false;
209 size_t data_len = 0;
210 uint8_t *p_data = NULL;
211 esp_hidh_event_data_t p = {0};
212 esp_hidh_event_data_t *p_param = NULL;
213 size_t event_data_size = sizeof(esp_hidh_event_data_t);
214
215 switch (event) {
216 case ESP_HIDH_INIT_EVT: {
217 p.start.status = bt_hidh_get_status(param->init.status);
218 esp_event_post_to(hidh_local_param.event_loop_handle, ESP_HIDH_EVENTS, ESP_HIDH_START_EVENT, &p,
219 event_data_size, portMAX_DELAY);
220 if (param->init.status != ESP_HIDH_OK) {
221 ESP_LOGE(TAG, "ENABLE ERROR: %s", s_esp_hh_status_names[param->init.status]);
222 free_local_param();
223 }
224 break;
225 }
226 case ESP_HIDH_DEINIT_EVT: {
227 p.stop.status = bt_hidh_get_status(param->deinit.status);
228 esp_event_post_to(hidh_local_param.event_loop_handle, ESP_HIDH_EVENTS, ESP_HIDH_STOP_EVENT, &p,
229 event_data_size, portMAX_DELAY);
230 if (param->deinit.status != ESP_HIDH_OK) {
231 ESP_LOGE(TAG, "DISABLE ERROR: %s", s_esp_hh_status_names[param->deinit.status]);
232 } else {
233 free_local_param();
234 }
235 break;
236 }
237 case ESP_HIDH_OPEN_EVT: {
238 if (param->open.conn_status == ESP_HIDH_CONN_STATE_CONNECTING) {
239 // ignore this conn_status
240 break;
241 }
242
243 do {
244 dev = esp_hidh_dev_get_by_bda(param->open.bd_addr);
245 if (dev == NULL) {
246 if (param->open.is_orig) {
247 ESP_LOGE(TAG, "OPEN ERROR: Device Not Found");
248 param->open.status = ESP_HIDH_NO_CONNECTION;
249 break;
250 } else {
251 ESP_LOGD(TAG, "incoming device connect");
252 if (param->open.status == ESP_HIDH_OK) {
253 if ((dev = hidh_dev_ctor(param->open.bd_addr)) == NULL) {
254 ESP_LOGE(TAG, "%s create device failed!", __func__);
255 param->open.status = ESP_HIDH_ERR_NO_RES;
256 break;
257 }
258 esp_hidh_dev_lock(dev);
259 dev->opened = false; // not opened by ourself
260 dev->is_orig = false;
261 esp_hidh_dev_unlock(dev);
262 }
263 }
264 }
265
266 if (param->open.status != ESP_HIDH_OK) {
267 break;
268 }
269 esp_hidh_dev_lock(dev);
270 dev->connected = true;
271 dev->bt.handle = param->open.handle;
272 esp_hidh_dev_unlock(dev);
273 conn_item = malloc(sizeof(conn_item_t));
274 if (conn_item == NULL) {
275 ESP_LOGE(TAG, "conn_item malloc failed!");
276 param->open.status = ESP_HIDH_ERR_NO_RES;
277 break;
278 }
279 conn_item->dev = dev;
280 bool ret = fixed_queue_enqueue(hidh_local_param.connection_queue, conn_item, FIXED_QUEUE_MAX_TIMEOUT);
281 assert(ret == true);
282 } while (0);
283
284 if (param->open.status != ESP_HIDH_OK) {
285 ESP_LOGE(TAG, "OPEN ERROR: %s", s_esp_hh_status_names[param->open.status]);
286 open_failed_cb(dev, param->open.status, &p, event_data_size);
287 }
288
289 if (dev != NULL) {
290 esp_hidh_dev_lock(dev);
291 dev->status = param->open.status;
292 esp_hidh_dev_unlock(dev);
293 }
294 break;
295 }
296 case ESP_HIDH_GET_DSCP_EVT: {
297 do {
298 ESP_LOGV(TAG, "DESCRIPTOR: PID: 0x%04x, VID: 0x%04x, VERSION: 0x%04x, REPORT_LEN: %u",
299 param->dscp.product_id, param->dscp.vendor_id, param->dscp.version, param->dscp.dl_len);
300 if ((conn_item = (conn_item_t *)fixed_queue_dequeue(hidh_local_param.connection_queue,
301 FIXED_QUEUE_MAX_TIMEOUT)) == NULL) {
302 ESP_LOGE(TAG, "No pending connect device!");
303 param->dscp.status = ESP_HIDH_NO_CONNECTION;
304 break;
305 }
306 dev = conn_item->dev;
307 utl_freebuf((void **)&conn_item);
308 // in case the dev has been freed
309 if (!esp_hidh_dev_exists(dev)) {
310 ESP_LOGE(TAG, "Device Not Found");
311 dev = NULL;
312 param->dscp.status = ESP_HIDH_NO_CONNECTION;
313 break;
314 }
315 // check if connected
316 esp_hidh_dev_lock(dev);
317 if (!dev->connected) {
318 esp_hidh_dev_unlock(dev);
319 ESP_LOGE(TAG, "Connection has been released!");
320 param->dscp.status = ESP_HIDH_NO_CONNECTION;
321 break;
322 }
323 // check if get descriptor failed
324 if (param->dscp.status != ESP_HIDH_OK) {
325 esp_hidh_dev_unlock(dev);
326 ESP_LOGE(TAG, "GET_DSCP ERROR: %s", s_esp_hh_status_names[param->dscp.status]);
327 break;
328 }
329 dev->added = param->dscp.added;
330 dev->config.product_id = param->dscp.product_id;
331 dev->config.vendor_id = param->dscp.vendor_id;
332 dev->config.version = param->dscp.version;
333
334 dev->config.report_maps_len = 1;
335 dev->config.report_maps =
336 (esp_hid_raw_report_map_t *)malloc(dev->config.report_maps_len * sizeof(esp_hid_raw_report_map_t));
337 if (dev->config.report_maps == NULL) {
338 esp_hidh_dev_unlock(dev);
339 ESP_LOGE(TAG, "malloc report maps failed");
340 param->dscp.status = ESP_HIDH_ERR_NO_RES;
341 break;
342 }
343
344 dev->config.report_maps[0].data = (uint8_t *)malloc(param->dscp.dl_len);
345 if (dev->config.report_maps[0].data == NULL) {
346 ESP_LOGE(TAG, "Malloc Report Map Failed");
347 param->dscp.status = ESP_HIDH_ERR_NO_RES;
348 } else {
349 dev->config.report_maps[0].len = param->dscp.dl_len;
350 memcpy((uint8_t *)dev->config.report_maps[0].data, param->dscp.dsc_list,
351 dev->config.report_maps[0].len);
352 // generate reports
353
354 if (dev->config.report_maps[0].len && dev->config.report_maps[0].data) {
355 esp_hid_report_map_t *map;
356 esp_hidh_dev_report_t *report;
357 esp_hid_report_item_t *r;
358 map = esp_hid_parse_report_map(dev->config.report_maps[0].data, dev->config.report_maps[0].len);
359 if (map) {
360 if (dev->usage == 0) {
361 dev->usage = map->usage;
362 }
363 dev->reports = NULL;
364 for (uint8_t i = 0; i < map->reports_len; i++) {
365 r = &map->reports[i];
366 report = (esp_hidh_dev_report_t *)malloc(sizeof(esp_hidh_dev_report_t));
367 if (report == NULL) {
368 ESP_LOGE(TAG, "Malloc Report Failed");
369 param->dscp.status = ESP_HIDH_ERR_NO_RES;
370 break;
371 }
372 report->map_index = 0;
373 report->protocol_mode = r->protocol_mode;
374 report->report_type = r->report_type;
375 report->report_id = r->report_id;
376 report->value_len = r->value_len;
377 report->usage = r->usage;
378 report->next = dev->reports;
379 dev->reports = report;
380 }
381 dev->reports_len = map->reports_len;
382 free(map->reports);
383 free(map);
384 map = NULL;
385 } else {
386 ESP_LOGE(TAG, "Parse Report Map Failed");
387 param->dscp.status = ESP_HIDH_ERR;
388 }
389 }
390 }
391 esp_hidh_dev_unlock(dev);
392 } while (0);
393
394 if (param->dscp.status != ESP_HIDH_OK) {
395 open_failed_cb(dev, param->dscp.status, &p, event_data_size);
396 }
397
398 if (dev != NULL) {
399 esp_hidh_dev_lock(dev);
400 dev->status = param->dscp.status;
401 // if has been added by lower layer, tell up layer
402 if (dev->status == ESP_HIDH_OK && dev->connected && dev->added) {
403 p.open.status = bt_hidh_get_status(ESP_HIDH_OK);
404 p.open.dev = dev;
405 esp_hidh_dev_unlock(dev);
406 esp_event_post_to(hidh_local_param.event_loop_handle, ESP_HIDH_EVENTS, ESP_HIDH_OPEN_EVENT, &p,
407 event_data_size, portMAX_DELAY);
408 } else {
409 esp_hidh_dev_unlock(dev);
410 }
411 }
412 break;
413 }
414 case ESP_HIDH_ADD_DEV_EVT: {
415 ESP_LOGV(TAG, "ADD_DEV: BDA: " ESP_BD_ADDR_STR ", handle: %d, status: %s",
416 ESP_BD_ADDR_HEX(param->add_dev.bd_addr), param->add_dev.handle,
417 s_esp_hh_status_names[param->add_dev.status]);
418 do {
419 dev = esp_hidh_dev_get_by_handle(param->add_dev.handle);
420 if (dev == NULL) {
421 ESP_LOGE(TAG, "Device Not Found");
422 param->add_dev.status = ESP_HIDH_NO_CONNECTION;
423 break;
424 }
425 esp_hidh_dev_lock(dev);
426 dev->added = param->add_dev.status == ESP_HIDH_OK ? true : false;
427 esp_hidh_dev_unlock(dev);
428 } while(0);
429
430 if (param->add_dev.status != ESP_HIDH_OK) {
431 ESP_LOGE(TAG, "ADD_DEV ERROR: %s", s_esp_hh_status_names[param->add_dev.status]);
432 open_failed_cb(dev, param->add_dev.status, &p, event_data_size);
433 }
434 if (dev != NULL) {
435 esp_hidh_dev_lock(dev);
436 dev->status = param->add_dev.status;
437 if (dev->status == ESP_HIDH_OK && dev->connected && dev->added) {
438 p.open.status = bt_hidh_get_status(ESP_HIDH_OK);
439 p.open.dev = dev;
440 esp_hidh_dev_unlock(dev);
441 esp_event_post_to(hidh_local_param.event_loop_handle, ESP_HIDH_EVENTS, ESP_HIDH_OPEN_EVENT, &p,
442 event_data_size, portMAX_DELAY);
443 } else {
444 esp_hidh_dev_unlock(dev);
445 }
446 }
447 break;
448 }
449 case ESP_HIDH_CLOSE_EVT: {
450 if (param->close.conn_status == ESP_HIDH_CONN_STATE_DISCONNECTING) {
451 // ignore this conn_status
452 break;
453 }
454 ESP_LOGV(TAG, "CLOSE: handle: %d, status: %s", param->close.handle, s_esp_hh_status_names[param->close.status]);
455 do {
456 dev = esp_hidh_dev_get_by_handle(param->close.handle);
457 if (dev == NULL) {
458 ESP_LOGE(TAG, "Device Not Found");
459 param->close.status = ESP_HIDH_NO_CONNECTION;
460 break;
461 }
462 esp_hidh_dev_lock(dev);
463 dev->status = param->close.status;
464 if (dev->connected) {
465 dev->connected = false;
466 }
467 // free the device in the wrapper event handler
468 dev->in_use = false;
469 esp_hidh_dev_unlock(dev);
470 } while(0);
471
472 if (param->close.status != ESP_HIDH_OK) {
473 ESP_LOGE(TAG, "CLOSE ERROR: %s", s_esp_hh_status_names[param->close.status]);
474 }
475 p.close.dev = dev;
476 p.close.status = bt_hidh_get_status(param->close.status);
477 esp_event_post_to(hidh_local_param.event_loop_handle, ESP_HIDH_EVENTS, ESP_HIDH_CLOSE_EVENT, &p,
478 event_data_size, portMAX_DELAY);
479
480 break;
481 }
482 case ESP_HIDH_SET_RPT_EVT: {
483 if (param->set_rpt.status != ESP_HIDH_OK) {
484 ESP_LOGE(TAG, "SET_RPT ERROR: handle: %d, status: %s", param->set_rpt.handle,
485 s_esp_hh_status_names[param->set_rpt.status]);
486 }
487 dev = esp_hidh_dev_get_by_handle(param->set_rpt.handle);
488 if (dev == NULL) {
489 ESP_LOGE(TAG, "SET_RPT ERROR: Device Not Found");
490 break;
491 }
492 esp_hidh_dev_lock(dev);
493 dev->status = param->set_rpt.status;
494 p.feature.dev = dev;
495 esp_hidh_dev_unlock(dev);
496 p.feature.status = bt_hidh_get_status(param->set_rpt.status);
497 p.feature.trans_type = ESP_HID_TRANS_SET_REPORT;
498 esp_event_post_to(hidh_local_param.event_loop_handle, ESP_HIDH_EVENTS, ESP_HIDH_FEATURE_EVENT, &p,
499 event_data_size, portMAX_DELAY);
500 reset_trans(dev);
501 break;
502 }
503 case ESP_HIDH_GET_RPT_EVT: {
504 if (param->get_rpt.status != ESP_HIDH_OK) {
505 ESP_LOGE(TAG, "GET_RPT ERROR: handle: %d, status: %s", param->get_rpt.handle,
506 s_esp_hh_status_names[param->get_rpt.status]);
507 } else if (param->get_rpt.len > 0 && param->get_rpt.data) {
508 event_data_size += param->get_rpt.len;
509 }
510 dev = esp_hidh_dev_get_by_handle(param->get_rpt.handle);
511 if (dev == NULL) {
512 ESP_LOGE(TAG, "GET_RPT ERROR: Device Not Found");
513 break;
514 }
515 esp_hidh_dev_lock(dev);
516 dev->status = param->get_rpt.status;
517 if ((p_param = (esp_hidh_event_data_t *)malloc(event_data_size)) != NULL) {
518 memset(p_param, 0, event_data_size);
519 p_param->feature.dev = dev;
520 p_param->feature.status = bt_hidh_get_status(param->get_rpt.status);
521 p_param->feature.trans_type = ESP_HID_TRANS_GET_REPORT;
522 if (param->get_rpt.status == ESP_HIDH_OK && param->get_rpt.len > 0 && param->get_rpt.data) {
523 if (dev->report_id) {
524 data_len = param->get_rpt.len - 1;
525 p_data = (uint8_t *)param->get_rpt.data + 1;
526 } else {
527 data_len = param->get_rpt.len;
528 p_data = (uint8_t *)param->get_rpt.data;
529 }
530 memcpy(((uint8_t *)p_param) + sizeof(esp_hidh_event_data_t), p_data, data_len);
531 p_param->feature.length = data_len;
532 p_param->feature.data = p_data;
533 p_param->feature.report_id = dev->report_id;
534 esp_hidh_dev_unlock(dev);
535 }
536 esp_event_post_to(hidh_local_param.event_loop_handle, ESP_HIDH_EVENTS, ESP_HIDH_FEATURE_EVENT, p_param,
537 event_data_size, portMAX_DELAY);
538 } else {
539 esp_hidh_dev_unlock(dev);
540 ESP_LOGE(TAG, "GET_RPT ERROR: malloc event data failed!");
541 }
542 reset_trans(dev);
543 break;
544 }
545 case ESP_HIDH_GET_IDLE_EVT:{
546 if (param->get_idle.status != ESP_HIDH_OK) {
547 ESP_LOGE(TAG, "GET_IDLE ERROR: handle: %d, status: %s", param->get_idle.handle,
548 s_esp_hh_status_names[param->get_idle.status]);
549 } else {
550 event_data_size += 1;
551 }
552 dev = esp_hidh_dev_get_by_handle(param->get_idle.handle);
553 if (dev == NULL) {
554 ESP_LOGE(TAG, "GET_IDLE ERROR: Device Not Found");
555 break;
556 }
557 esp_hidh_dev_lock(dev);
558 dev->status = param->get_idle.status;
559 if ((p_param = (esp_hidh_event_data_t *)malloc(event_data_size)) != NULL) {
560 memset(p_param, 0, event_data_size);
561 p_param->feature.dev = dev;
562 p_param->feature.status = bt_hidh_get_status(param->get_idle.status);
563 p_param->feature.trans_type = ESP_HID_TRANS_GET_IDLE;
564 if (param->get_idle.status == ESP_HIDH_OK) {
565 *(((uint8_t *)p_param) + sizeof(esp_hidh_event_data_t)) = param->get_idle.idle_rate;
566 p_param->feature.length = 1;
567 p_param->feature.data = ((uint8_t *)p_param) + sizeof(esp_hidh_event_data_t);
568 }
569 esp_hidh_dev_unlock(dev);
570 esp_event_post_to(hidh_local_param.event_loop_handle, ESP_HIDH_EVENTS, ESP_HIDH_FEATURE_EVENT, p_param,
571 event_data_size, portMAX_DELAY);
572 } else {
573 esp_hidh_dev_unlock(dev);
574 ESP_LOGE(TAG, "GET_IDLE ERROR: malloc event data failed!");
575 }
576 reset_trans(dev);
577 break;
578 }
579 case ESP_HIDH_SET_IDLE_EVT: {
580 if (param->set_idle.status != ESP_HIDH_OK) {
581 ESP_LOGE(TAG, "SET_IDLE ERROR: handle: %d, status: %s", param->set_idle.handle,
582 s_esp_hh_status_names[param->set_idle.status]);
583 }
584 dev = esp_hidh_dev_get_by_handle(param->set_idle.handle);
585 if (dev == NULL) {
586 ESP_LOGE(TAG, "SET_IDLE ERROR: Device Not Found");
587 break;
588 }
589 esp_hidh_dev_lock(dev);
590 dev->status = param->set_idle.status;
591 p.feature.dev = dev;
592 esp_hidh_dev_unlock(dev);
593 p.feature.status = bt_hidh_get_status(param->set_idle.status);
594 p.feature.trans_type = ESP_HID_TRANS_SET_IDLE;
595 esp_event_post_to(hidh_local_param.event_loop_handle, ESP_HIDH_EVENTS, ESP_HIDH_FEATURE_EVENT, &p,
596 event_data_size, portMAX_DELAY);
597 reset_trans(dev);
598 break;
599 }
600 case ESP_HIDH_GET_PROTO_EVT: {
601 if (param->get_proto.status != ESP_HIDH_OK) {
602 ESP_LOGE(TAG, "GET_PROTO ERROR: handle: %d, status: %s", param->get_proto.handle,
603 s_esp_hh_status_names[param->get_proto.status]);
604 } else {
605 event_data_size += 1;
606 }
607 dev = esp_hidh_dev_get_by_handle(param->get_proto.handle);
608 if (dev == NULL) {
609 ESP_LOGE(TAG, "GET_PROTO ERROR: Device Not Found");
610 break;
611 }
612 esp_hidh_dev_lock(dev);
613 dev->status = param->get_proto.status;
614 if ((p_param = (esp_hidh_event_data_t *)malloc(event_data_size)) != NULL) {
615 memset(p_param, 0, event_data_size);
616 p_param->feature.dev = dev;
617 p_param->feature.status = bt_hidh_get_status(param->get_proto.status);
618 p_param->feature.trans_type = ESP_HID_TRANS_GET_PROTOCOL;
619 if (param->get_proto.status == ESP_HIDH_OK) {
620 dev->protocol_mode = param->get_proto.proto_mode; // update the device protocol mode
621 *(((uint8_t *)p_param) + sizeof(esp_hidh_event_data_t)) = param->get_proto.proto_mode;
622 p_param->feature.length = 1;
623 p_param->feature.data = ((uint8_t *)p_param) + sizeof(esp_hidh_event_data_t);
624 }
625 esp_hidh_dev_unlock(dev);
626 esp_event_post_to(hidh_local_param.event_loop_handle, ESP_HIDH_EVENTS, ESP_HIDH_FEATURE_EVENT, p_param,
627 event_data_size, portMAX_DELAY);
628 } else {
629 esp_hidh_dev_unlock(dev);
630 ESP_LOGE(TAG, "GET_PROTO ERROR: malloc event data failed!");
631 }
632 reset_trans(dev);
633 break;
634 }
635 case ESP_HIDH_SET_PROTO_EVT: {
636 if (param->set_proto.status != ESP_HIDH_OK) {
637 ESP_LOGE(TAG, "SET_PROTO ERROR: handle: %d, status: %s", param->set_proto.handle,
638 s_esp_hh_status_names[param->set_proto.status]);
639 }
640 dev = esp_hidh_dev_get_by_handle(param->set_proto.handle);
641 if (dev == NULL) {
642 ESP_LOGE(TAG, "Device Not Found");
643 break;
644 }
645 esp_hidh_dev_lock(dev);
646 dev->status = param->set_proto.status;
647 p.feature.dev = dev;
648 esp_hidh_dev_unlock(dev);
649 p.feature.status = bt_hidh_get_status(param->set_proto.status);
650 p.feature.trans_type = ESP_HID_TRANS_SET_PROTOCOL;
651 esp_event_post_to(hidh_local_param.event_loop_handle, ESP_HIDH_EVENTS, ESP_HIDH_FEATURE_EVENT, &p,
652 event_data_size, portMAX_DELAY);
653 reset_trans(dev);
654 break;
655 }
656 case ESP_HIDH_DATA_IND_EVT: {
657 esp_hid_usage_t _usage;
658 if (param->data_ind.status != ESP_HIDH_OK) {
659 ESP_LOGE(TAG, "DATA_IND ERROR: handle: %d, status: %s", param->data_ind.handle,
660 s_esp_hh_status_names[param->data_ind.status]);
661 }
662 dev = esp_hidh_dev_get_by_handle(param->data_ind.handle);
663 if (dev == NULL) {
664 ESP_LOGE(TAG, "Device Not Found: handle %u", param->data_ind.handle);
665 break;
666 }
667
668 if (param->data_ind.len > 0 && param->data_ind.data != NULL) {
669 esp_hidh_dev_lock(dev);
670 event_data_size += param->data_ind.len;
671 if (param->data_ind.proto_mode == ESP_HID_PROTOCOL_MODE_BOOT) {
672 /**
673 * first data shall have report_id, according to HID_SPEC_V10
674 * | Device | Report ID | Report Size |
675 * --------------------------------------
676 * | Keyboard | 1 | 9 Bytes |
677 * | Mouse | 2 | 4 Bytes |
678 * | Reserved | 0, 3-255 | N/A |
679 */
680 if (param->data_ind.len == 9 && *(param->data_ind.data) == 1) {
681 has_report_id = true;
682 _usage = ESP_HID_USAGE_KEYBOARD;
683 } else if (param->data_ind.len == 4 && *(param->data_ind.data) == 2) {
684 has_report_id = true;
685 _usage = ESP_HID_USAGE_MOUSE;
686 } else {
687 esp_hidh_dev_unlock(dev);
688 ESP_LOGE(TAG, "Invalid Boot Report format, rpt_len:%d, rpt_id:%d!", param->data_ind.len,
689 *(param->data_ind.data));
690 break;
691 }
692 } else {
693 report = esp_hidh_dev_get_input_report_by_proto_and_data(
694 dev, ESP_HID_PROTOCOL_MODE_REPORT, param->data_ind.len, param->data_ind.data, &has_report_id);
695 if (report == NULL) {
696 esp_hidh_dev_unlock(dev);
697 ESP_LOGE(TAG, "Not find report handle: %d mode: %s", param->data_ind.handle,
698 param->data_ind.proto_mode == ESP_HID_PROTOCOL_MODE_REPORT ? "REPORT" : "BOOT");
699 break;
700 }
701 _usage = report->usage;
702 }
703
704 if ((p_param = (esp_hidh_event_data_t *)malloc(event_data_size)) == NULL) {
705 esp_hidh_dev_unlock(dev);
706 ESP_LOGE(TAG, "DATA_IND ERROR: malloc event data failed!");
707 break;
708 }
709 memset(p_param, 0, event_data_size);
710 p_param->input.dev = dev;
711 p_param->input.usage = _usage;
712 if (has_report_id) {
713 data_len = param->data_ind.len - 1;
714 p_data = (uint8_t *)param->data_ind.data + 1;
715 p_param->input.report_id = *(uint8_t *)param->data_ind.data;
716 } else {
717 data_len = param->data_ind.len;
718 p_data = (uint8_t *)param->data_ind.data;
719 p_param->input.report_id = report->report_id;
720 }
721 memcpy(((uint8_t *)p_param) + sizeof(esp_hidh_event_data_t), p_data, data_len);
722 p_param->input.length = data_len;
723 p_param->input.data = p_data;
724 esp_hidh_dev_unlock(dev);
725 esp_event_post_to(hidh_local_param.event_loop_handle, ESP_HIDH_EVENTS, ESP_HIDH_INPUT_EVENT, p_param,
726 event_data_size, portMAX_DELAY);
727 }
728 break;
729 }
730 case ESP_HIDH_DATA_EVT:
731 break;
732 default:
733 ESP_LOGV(TAG, "BTA_HH EVENT: %s", s_esp_hh_evt_names[event]);
734 break;
735 }
736
737 if (p_param) {
738 free(p_param);
739 p_param = NULL;
740 }
741 }
742
743 /*
744 * Public Functions
745 * */
746
esp_bt_hidh_dev_close(esp_hidh_dev_t * dev)747 static esp_err_t esp_bt_hidh_dev_close(esp_hidh_dev_t *dev)
748 {
749 esp_err_t ret = ESP_OK;
750 do {
751 if (dev == NULL) {
752 ret = ESP_ERR_INVALID_ARG;
753 break;
754 }
755 if (!dev->connected) {
756 ESP_LOGW(TAG, "%s hdl:0x%02x not connected", __func__, dev->bt.handle);
757 ret = ESP_ERR_INVALID_STATE;
758 break;
759 }
760 ret = esp_bt_hid_host_disconnect(dev->bda);
761 } while (0);
762 return ret;
763 }
764
esp_bt_hidh_dev_report_write(esp_hidh_dev_t * dev,size_t map_index,size_t report_id,int report_type,uint8_t * data,size_t len)765 static esp_err_t esp_bt_hidh_dev_report_write(esp_hidh_dev_t *dev, size_t map_index, size_t report_id,
766 int report_type, uint8_t *data, size_t len)
767 {
768 esp_err_t ret = ESP_OK;
769 uint8_t *p_data = NULL;
770 do {
771 esp_hidh_dev_report_t *report =
772 esp_hidh_dev_get_report_by_id_type_proto(dev, map_index, report_id, report_type, dev->protocol_mode);
773 if (!report) {
774 ESP_LOGE(TAG, "mode:%s report:%s id:%d not found", get_protocol_mode(dev->protocol_mode),
775 esp_hid_report_type_str(report_type), report_id);
776 ret = ESP_FAIL;
777 break;
778 }
779 if (len > report->value_len) {
780 ESP_LOGE(TAG, "%s report %d takes maximum %d bytes. you have provided %d",
781 esp_hid_report_type_str(report_type), report_id, report->value_len, len);
782 ret = ESP_FAIL;
783 break;
784 }
785
786 if (report_type != ESP_HID_REPORT_TYPE_OUTPUT) {
787 ESP_LOGE(TAG,
788 "Only OUTPUT type data can be send on interrupt channel.\n" \
789 "You have provided %s, try Set_Report!",
790 esp_hid_report_type_str(report_type));
791 ret = ESP_FAIL;
792 break;
793 }
794
795 if (report_id) {
796 if ((p_data = malloc(len + 1)) == NULL) {
797 ESP_LOGE(TAG, "%s malloc failed!", __func__);
798 ret = ESP_FAIL;
799 break;
800 }
801 *p_data = report_id;
802 memcpy(p_data + 1, data, len);
803 data = p_data;
804 len = len + 1;
805 }
806 ret = esp_bt_hid_host_send_data(dev->bda, data, len);
807 } while (0);
808 return ret;
809 }
810
esp_bt_hidh_dev_set_report(esp_hidh_dev_t * dev,size_t map_index,size_t report_id,int report_type,uint8_t * data,size_t len)811 static esp_err_t esp_bt_hidh_dev_set_report(esp_hidh_dev_t *dev, size_t map_index, size_t report_id,
812 int report_type, uint8_t *data, size_t len)
813 {
814 esp_err_t ret = ESP_OK;
815 uint8_t *p_data = NULL;
816 esp_hidh_dev_report_t *report = NULL;
817 do {
818 if (!is_trans_done(dev)) {
819 ESP_LOGE(TAG, "Pending previous tansaction %s done, try later!", get_trans_type_str(dev->trans_type));
820 ret = ESP_FAIL;
821 break;
822 }
823 report = esp_hidh_dev_get_report_by_id_type_proto(dev, map_index, report_id, report_type, dev->protocol_mode);
824 if (!report) {
825 ESP_LOGE(TAG, "mode:%s report:%s id:%d not found", get_protocol_mode(dev->protocol_mode),
826 esp_hid_report_type_str(report_type), report_id);
827 ret = ESP_FAIL;
828 break;
829 }
830 if (len > report->value_len) {
831 ESP_LOGE(TAG, "%s report %d takes maximum %d bytes. you have provided %d",
832 esp_hid_report_type_str(report_type), report_id, report->value_len, len);
833 ret = ESP_FAIL;
834 break;
835 }
836
837 if (report_id) {
838 if ((p_data = malloc(len + 1)) == NULL) {
839 ESP_LOGE(TAG, "%s malloc failed!", __func__);
840 ret = ESP_FAIL;
841 break;
842 }
843 *p_data = report_id;
844 memcpy(p_data + 1, data, len);
845 data = p_data;
846 len = len + 1;
847 }
848 ret = esp_bt_hid_host_set_report(dev->bda, report_type, data, len);
849 if (ret == ESP_OK) {
850 set_trans(dev, ESP_HID_TRANS_SET_REPORT);
851 }
852 } while (0);
853 return ret;
854 }
855
esp_bt_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)856 static esp_err_t esp_bt_hidh_dev_report_read(esp_hidh_dev_t *dev, size_t map_index, size_t report_id, int report_type,
857 size_t max_length, uint8_t *value, size_t *value_len)
858 {
859 esp_err_t ret = ESP_OK;
860 esp_hidh_dev_report_t *report = NULL;
861 do {
862 if (!is_trans_done(dev)) {
863 ESP_LOGE(TAG, "Pending previous tansaction %s done, try later!", get_trans_type_str(dev->trans_type));
864 ret = ESP_FAIL;
865 break;
866 }
867 report = esp_hidh_dev_get_report_by_id_type_proto(dev, map_index, report_id, report_type, dev->protocol_mode);
868 if (!report) {
869 ESP_LOGE(TAG, "mode:%s report:%s id:%d not found", get_protocol_mode(dev->protocol_mode),
870 esp_hid_report_type_str(report_type), report_id);
871 ret = ESP_FAIL;
872 break;
873 }
874 ret = esp_bt_hid_host_get_report(dev->bda, report_type, report_id, max_length);
875 if (ret == ESP_OK) {
876 dev->trans_type = ESP_HID_TRANS_GET_REPORT;
877 dev->report_id = report_id;
878 dev->report_type = report_type;
879 }
880 } while (0);
881 return ret;
882 }
883
esp_bt_hidh_dev_get_idle(esp_hidh_dev_t * dev)884 static esp_err_t esp_bt_hidh_dev_get_idle(esp_hidh_dev_t *dev)
885 {
886 esp_err_t ret = ESP_OK;
887 do {
888 if (!is_trans_done(dev)) {
889 ESP_LOGE(TAG, "Pending previous tansaction %s done, try later!", get_trans_type_str(dev->trans_type));
890 ret = ESP_FAIL;
891 break;
892 }
893 if (!dev->connected) {
894 ESP_LOGW(TAG, "%s hdl:0x%02x not connected", __func__, dev->bt.handle);
895 ret = ESP_ERR_INVALID_STATE;
896 break;
897 }
898 ret = esp_bt_hid_host_get_idle(dev->bda);
899 if (ret == ESP_OK) {
900 set_trans(dev, ESP_HID_TRANS_GET_IDLE);
901 }
902 } while(0);
903
904 return ret;
905 }
906
esp_bt_hidh_dev_set_idle(esp_hidh_dev_t * dev,uint8_t idle_time)907 static esp_err_t esp_bt_hidh_dev_set_idle(esp_hidh_dev_t *dev, uint8_t idle_time)
908 {
909 esp_err_t ret = ESP_OK;
910 do {
911 if (!is_trans_done(dev)) {
912 ESP_LOGE(TAG, "Pending previous tansaction %s done, try later!", get_trans_type_str(dev->trans_type));
913 ret = ESP_FAIL;
914 break;
915 }
916 if (!dev->connected) {
917 ESP_LOGW(TAG, "%s hdl:0x%02x not connected", __func__, dev->bt.handle);
918 ret = ESP_ERR_INVALID_STATE;
919 break;
920 }
921 ret = esp_bt_hid_host_set_idle(dev->bda, idle_time);
922 if (ret == ESP_OK) {
923 set_trans(dev, ESP_HID_TRANS_SET_IDLE);
924 }
925 } while(0);
926
927 return ret;
928 }
929
esp_bt_hidh_dev_get_protocol(esp_hidh_dev_t * dev)930 static esp_err_t esp_bt_hidh_dev_get_protocol(esp_hidh_dev_t *dev)
931 {
932 esp_err_t ret = ESP_OK;
933 do {
934 if (!is_trans_done(dev)) {
935 ESP_LOGE(TAG, "Pending previous tansaction %s done, try later!", get_trans_type_str(dev->trans_type));
936 ret = ESP_FAIL;
937 break;
938 }
939 if (!dev->connected) {
940 ESP_LOGW(TAG, "%s hdl:0x%02x not connected", __func__, dev->bt.handle);
941 ret = ESP_ERR_INVALID_STATE;
942 break;
943 }
944 ret = esp_bt_hid_host_get_protocol(dev->bda);
945 if (ret == ESP_OK) {
946 set_trans(dev, ESP_HID_TRANS_GET_PROTOCOL);
947 }
948 } while(0);
949
950 return ret;
951 }
952
esp_bt_hidh_dev_set_protocol(esp_hidh_dev_t * dev,uint8_t protocol_mode)953 static esp_err_t esp_bt_hidh_dev_set_protocol(esp_hidh_dev_t *dev, uint8_t protocol_mode)
954 {
955 esp_err_t ret = ESP_OK;
956
957 do {
958 if (!is_trans_done(dev)) {
959 ESP_LOGE(TAG, "Pending previous tansaction %s done, try later!", get_trans_type_str(dev->trans_type));
960 ret = ESP_FAIL;
961 break;
962 }
963 if (!dev->connected) {
964 ESP_LOGW(TAG, "%s hdl:0x%02x not connected", __func__, dev->bt.handle);
965 ret = ESP_ERR_INVALID_STATE;
966 break;
967 }
968 ret = esp_bt_hid_host_set_protocol(dev->bda, protocol_mode);
969 if (ret == ESP_OK) {
970 set_trans(dev, ESP_HID_TRANS_SET_PROTOCOL);
971 }
972 } while(0);
973
974 return ret;
975 }
976
esp_bt_hidh_dev_dump(esp_hidh_dev_t * dev,FILE * fp)977 static void esp_bt_hidh_dev_dump(esp_hidh_dev_t *dev, FILE *fp)
978 {
979 fprintf(fp, "BDA:" ESP_BD_ADDR_STR ", Status: %s, Connected: %s, Handle: %d, Usage: %s\n", ESP_BD_ADDR_HEX(dev->bda), s_esp_hh_status_names[dev->status], dev->connected ? "YES" : "NO", dev->bt.handle, esp_hid_usage_str(dev->usage));
980 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 : "");
981 fprintf(fp, "PID: 0x%04x, VID: 0x%04x, VERSION: 0x%04x\n", dev->config.product_id, dev->config.vendor_id, dev->config.version);
982 fprintf(fp, "Report Map Length: %d\n", dev->config.report_maps[0].len);
983 esp_hidh_dev_report_t *report = dev->reports;
984 while (report) {
985 fprintf(fp, " %8s %7s %6s, ID: %3u, Length: %3u\n",
986 esp_hid_usage_str(report->usage), esp_hid_report_type_str(report->report_type), get_protocol_mode(report->protocol_mode),
987 report->report_id, report->value_len);
988 report = report->next;
989 }
990 }
991
esp_bt_hidh_init(const esp_hidh_config_t * config)992 esp_err_t esp_bt_hidh_init(const esp_hidh_config_t *config)
993 {
994 esp_err_t ret = ESP_OK;
995 if (config == NULL) {
996 ESP_LOGE(TAG, "Config is NULL");
997 return ESP_ERR_INVALID_ARG;
998 }
999 esp_event_loop_args_t event_task_args = {
1000 .queue_size = 5,
1001 .task_name = "esp_bt_hidh_events",
1002 .task_priority = uxTaskPriorityGet(NULL),
1003 .task_stack_size = config->event_stack_size > 0 ? config->event_stack_size : 4096,
1004 .task_core_id = tskNO_AFFINITY
1005 };
1006
1007 do {
1008 if ((hidh_local_param.connection_queue = fixed_queue_new(QUEUE_SIZE_MAX)) == NULL) {
1009 ESP_LOGE(TAG, "connection_queue create failed!");
1010 ret = ESP_FAIL;
1011 break;
1012 }
1013 ret = esp_event_loop_create(&event_task_args, &hidh_local_param.event_loop_handle);
1014 if (ret != ESP_OK) {
1015 ESP_LOGE(TAG, "esp_event_loop_create failed!");
1016 ret = ESP_FAIL;
1017 break;
1018 }
1019 ret = esp_event_handler_register_with(hidh_local_param.event_loop_handle, ESP_HIDH_EVENTS, ESP_EVENT_ANY_ID,
1020 esp_hidh_process_event_data_handler, NULL);
1021 ret |= esp_event_handler_register_with(hidh_local_param.event_loop_handle, ESP_HIDH_EVENTS, ESP_EVENT_ANY_ID,
1022 config->callback, config->callback_arg);
1023 if (ret != ESP_OK) {
1024 ESP_LOGE(TAG, "event_loop register failed!");
1025 ret = ESP_FAIL;
1026 break;
1027 }
1028 ret = esp_bt_hid_host_register_callback(esp_hh_cb);
1029 ret |= esp_bt_hid_host_init();
1030 } while (0);
1031
1032 if (ret != ESP_OK) {
1033 free_local_param();
1034 }
1035 return ret;
1036 }
1037
esp_bt_hidh_deinit(void)1038 esp_err_t esp_bt_hidh_deinit(void)
1039 {
1040 esp_err_t ret = esp_bt_hid_host_deinit();
1041 return ret;
1042 }
1043
hidh_dev_ctor(esp_bd_addr_t bda)1044 static esp_hidh_dev_t *hidh_dev_ctor(esp_bd_addr_t bda)
1045 {
1046 esp_hidh_dev_t *dev = NULL;
1047 dev = esp_hidh_dev_malloc();
1048 if (dev == NULL) {
1049 return NULL;
1050 }
1051 dev->in_use = true;
1052 dev->transport = ESP_HID_TRANSPORT_BT;
1053 dev->trans_type = ESP_HID_TRANS_MAX;
1054 dev->trans_timer = NULL;
1055 dev->protocol_mode = ESP_HID_PROTOCOL_MODE_REPORT; // device default protocol mode
1056 dev->connected = false;
1057 dev->opened = true;
1058 dev->added = false;
1059 dev->is_orig = true;
1060 dev->reports = NULL;
1061 dev->reports_len = 0;
1062 dev->tmp = NULL;
1063 dev->tmp_len = 0;
1064 memcpy(dev->bda, bda, sizeof(esp_bd_addr_t));
1065 dev->bt.handle = 0xff;
1066
1067 dev->close = esp_bt_hidh_dev_close;
1068 dev->report_write = esp_bt_hidh_dev_report_write;
1069 dev->report_read = esp_bt_hidh_dev_report_read;
1070 dev->set_report = esp_bt_hidh_dev_set_report;
1071 dev->get_idle = esp_bt_hidh_dev_get_idle;
1072 dev->set_idle = esp_bt_hidh_dev_set_idle;
1073 dev->get_protocol = esp_bt_hidh_dev_get_protocol;
1074 dev->set_protocol = esp_bt_hidh_dev_set_protocol;
1075 dev->dump = esp_bt_hidh_dev_dump;
1076
1077 return dev;
1078 }
1079
esp_bt_hidh_dev_open(esp_bd_addr_t bda)1080 esp_hidh_dev_t *esp_bt_hidh_dev_open(esp_bd_addr_t bda)
1081 {
1082 esp_hidh_dev_t *dev = esp_hidh_dev_get_by_bda(bda);
1083 if (dev == NULL) {
1084 if ((dev = hidh_dev_ctor(bda)) == NULL) {
1085 ESP_LOGE(TAG, "%s create device failed!", __func__);
1086 return NULL;
1087 }
1088 } else {
1089 ESP_LOGW(TAG, "device has opened, connected: %d", dev->connected);
1090 }
1091
1092 if (!dev->connected) {
1093 esp_bt_hid_host_connect(dev->bda);
1094 }
1095 return dev;
1096 }
1097
1098 #endif /* CONFIG_BT_HID_HOST_ENABLED */
1099