bt_hidh.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450
  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. // http://www.apache.org/licenses/LICENSE-2.0
  7. //
  8. // Unless required by applicable law or agreed to in writing, software
  9. // distributed under the License is distributed on an "AS IS" BASIS,
  10. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  11. // See the License for the specific language governing permissions and
  12. // limitations under the License.
  13. #include "bt_hidh.h"
  14. #if CONFIG_BT_HID_HOST_ENABLED
  15. #include "esp_hidh_private.h"
  16. #include <string.h>
  17. #include <stdbool.h>
  18. #include "freertos/FreeRTOS.h"
  19. #include "freertos/task.h"
  20. #include "freertos/semphr.h"
  21. #include "esp_bt_hh_api.h"
  22. static const char *TAG = "BT_HIDH";
  23. static esp_event_loop_handle_t event_loop_handle;
  24. static const char *s_bta_hh_evt_names[] = {"ENABLE", "DISABLE", "OPEN", "CLOSE", "GET_RPT", "SET_RPT", "GET_PROTO", "SET_PROTO", "GET_IDLE", "SET_IDLE", "GET_DSCP", "ADD_DEV", "RMV_DEV", "VC_UNPLUG", "DATA", "API_ERR", "UPDATE_SCPP"};
  25. static const char *s_bta_hh_status_names[] = {"OK", "HS_HID_NOT_READY", "HS_INVALID_RPT_ID", "HS_TRANS_NOT_SPT", "HS_INVALID_PARAM", "HS_ERROR", "ERR", "ERR_SDP", "ERR_PROTO", "ERR_DB_FULL", "ERR_TOD_UNSPT", "ERR_NO_RES", "ERR_AUTH_FAILED", "ERR_HDL", "ERR_SEC"};
  26. static inline void WAIT_DEV(esp_hidh_dev_t *dev)
  27. {
  28. xSemaphoreTake(dev->semaphore, portMAX_DELAY);
  29. }
  30. static inline void SEND_DEV(esp_hidh_dev_t *dev)
  31. {
  32. xSemaphoreGive(dev->semaphore);
  33. }
  34. static void bta_hh_cb(tBTA_HH_EVT event, tBTA_HH *p_data)
  35. {
  36. static esp_hidh_dev_t *descr_dev = NULL;
  37. esp_hidh_dev_t *dev = NULL;
  38. switch (event) {
  39. case BTA_HH_ENABLE_EVT: {
  40. if (p_data->status) {
  41. ESP_LOGE(TAG, "ENABLE ERROR: %s", s_bta_hh_status_names[p_data->status]);
  42. }
  43. } break;
  44. case BTA_HH_OPEN_EVT: {
  45. dev = esp_hidh_dev_get_by_handle(p_data->conn.handle);
  46. if (dev == NULL) {
  47. ESP_LOGE(TAG, "OPEN ERROR: Device Not Found");
  48. return;
  49. }
  50. dev->status = p_data->conn.status;
  51. memcpy(dev->bda, p_data->conn.bda, sizeof(esp_bd_addr_t));
  52. if (dev->status == BTA_HH_OK) {
  53. descr_dev = dev;
  54. BTA_HhGetDscpInfo(dev->bt.handle);
  55. } else {
  56. ESP_LOGE(TAG, "OPEN ERROR: %s", s_bta_hh_status_names[dev->status]);
  57. if (dev->opened) {
  58. SEND_DEV(dev);
  59. } else {
  60. esp_hidh_dev_free(dev);
  61. }
  62. }
  63. } break;
  64. case BTA_HH_GET_DSCP_EVT: {
  65. ESP_LOGV(TAG, "DESCRIPTOR: PID: 0x%04x, VID: 0x%04x, VERSION: 0x%04x, REPORT_LEN: %u", p_data->dscp_info.product_id, p_data->dscp_info.vendor_id, p_data->dscp_info.version, p_data->dscp_info.descriptor.dl_len);
  66. if (descr_dev == NULL) {
  67. ESP_LOGE(TAG, "Device Not Found");
  68. return;
  69. }
  70. dev = descr_dev;
  71. dev->config.product_id = p_data->dscp_info.product_id;
  72. dev->config.vendor_id = p_data->dscp_info.vendor_id;
  73. dev->config.version = p_data->dscp_info.version;
  74. dev->config.report_maps_len = 1;
  75. dev->config.report_maps = (esp_hid_raw_report_map_t *)malloc(dev->config.report_maps_len * sizeof(esp_hid_raw_report_map_t));
  76. if (dev->config.report_maps == NULL) {
  77. ESP_LOGE(TAG, "malloc report maps failed");
  78. return;
  79. }
  80. dev->config.report_maps[0].data = (uint8_t *)malloc(p_data->dscp_info.descriptor.dl_len);
  81. if (dev->config.report_maps[0].data == NULL) {
  82. ESP_LOGE(TAG, "Malloc Report Map Failed");
  83. dev->status = BTA_HH_ERR_NO_RES;
  84. } else {
  85. dev->config.report_maps[0].len = p_data->dscp_info.descriptor.dl_len;
  86. memcpy((uint8_t *)dev->config.report_maps[0].data, p_data->dscp_info.descriptor.dsc_list, dev->config.report_maps[0].len);
  87. //generate reports
  88. if (dev->config.report_maps[0].len && dev->config.report_maps[0].data) {
  89. esp_hid_report_map_t *map;
  90. esp_hidh_dev_report_t *report;
  91. esp_hid_report_item_t *r;
  92. map = esp_hid_parse_report_map(dev->config.report_maps[0].data, dev->config.report_maps[0].len);
  93. if (map) {
  94. if (dev->usage == 0) {
  95. dev->usage = map->usage;
  96. }
  97. dev->connected = true;
  98. dev->reports = NULL;
  99. for (uint8_t i = 0; i < map->reports_len; i++) {
  100. r = &map->reports[i];
  101. report = (esp_hidh_dev_report_t *)malloc(sizeof(esp_hidh_dev_report_t));
  102. if (report == NULL) {
  103. ESP_LOGE(TAG, "Malloc Report Failed");
  104. dev->status = BTA_HH_ERR_NO_RES;
  105. dev->connected = false;
  106. break;
  107. }
  108. report->map_index = 0;
  109. report->protocol_mode = r->protocol_mode;
  110. report->report_type = r->report_type;
  111. report->report_id = r->report_id;
  112. report->value_len = r->value_len;
  113. report->usage = r->usage;
  114. report->next = dev->reports;
  115. dev->reports = report;
  116. }
  117. dev->reports_len = map->reports_len;
  118. free(map->reports);
  119. free(map);
  120. map = NULL;
  121. } else {
  122. ESP_LOGE(TAG, "Parse Report Map Failed");
  123. dev->status = BTA_HH_ERR;
  124. }
  125. }
  126. }
  127. descr_dev = NULL;
  128. if (dev->status == BTA_HH_OK) {
  129. BTA_HhAddDev(dev->bda, dev->bt.attr_mask, dev->bt.sub_class, dev->bt.app_id, p_data->dscp_info);
  130. } else {
  131. ESP_LOGE(TAG, "Read Report Map Failed, status: %s", s_bta_hh_status_names[dev->status]);
  132. if (dev->opened) {
  133. SEND_DEV(dev);
  134. } else {
  135. esp_hidh_dev_free(dev);
  136. }
  137. }
  138. } break;
  139. case BTA_HH_ADD_DEV_EVT: {
  140. ESP_LOGV(TAG, "ADD_DEV: BDA: " ESP_BD_ADDR_STR ", handle: %d, status: %s", ESP_BD_ADDR_HEX(p_data->dev_info.bda), p_data->dev_info.handle, s_bta_hh_status_names[p_data->dev_info.status]);
  141. dev = esp_hidh_dev_get_by_handle(p_data->conn.handle);
  142. if (dev == NULL) {
  143. ESP_LOGE(TAG, "Device Not Found");
  144. return;
  145. }
  146. dev->status = p_data->conn.status;
  147. if (dev->status == BTA_HH_OK) {
  148. esp_hidh_event_data_t p;
  149. p.open.dev = dev;
  150. esp_event_post_to(event_loop_handle, ESP_HIDH_EVENTS, ESP_HIDH_OPEN_EVENT, &p, sizeof(esp_hidh_event_data_t), portMAX_DELAY);
  151. } else {
  152. ESP_LOGE(TAG, "Device Add Failed, status: %s", s_bta_hh_status_names[dev->status]);
  153. }
  154. if (dev->opened) {
  155. SEND_DEV(dev);
  156. } else if (dev->status != BTA_HH_OK) {
  157. esp_hidh_dev_free(dev);
  158. }
  159. } break;
  160. case BTA_HH_CLOSE_EVT: {
  161. ESP_LOGV(TAG, "CLOSE: handle: %d, status: %s", p_data->dev_status.handle, s_bta_hh_status_names[p_data->dev_status.status]);
  162. dev = esp_hidh_dev_get_by_handle(p_data->dev_status.handle);
  163. if (dev == NULL) {
  164. ESP_LOGE(TAG, "Device Not Found");
  165. return;
  166. }
  167. dev->status = p_data->dev_status.status;
  168. esp_hidh_event_data_t p;
  169. p.close.dev = dev;
  170. p.close.reason = 0;
  171. esp_event_post_to(event_loop_handle, ESP_HIDH_EVENTS, ESP_HIDH_CLOSE_EVENT, &p, sizeof(esp_hidh_event_data_t), portMAX_DELAY);
  172. } break;
  173. case BTA_HH_SET_RPT_EVT: {
  174. dev = esp_hidh_dev_get_by_handle(p_data->dev_status.handle);
  175. if (dev == NULL) {
  176. ESP_LOGE(TAG, "SET_RPT ERROR: hDevice Not Found");
  177. return;
  178. }
  179. if (p_data->dev_status.status) {
  180. ESP_LOGE(TAG, "SET_RPT ERROR: handle: %d, status: %s", p_data->dev_status.handle, s_bta_hh_status_names[p_data->dev_status.status]);
  181. }
  182. dev->status = p_data->dev_status.status;
  183. SEND_DEV(dev);
  184. } break;
  185. case BTA_HH_GET_RPT_EVT: {
  186. dev = esp_hidh_dev_get_by_handle(p_data->hs_data.handle);
  187. if (dev == NULL) {
  188. ESP_LOGE(TAG, "Device Not Found");
  189. return;
  190. }
  191. if (p_data->hs_data.status) {
  192. ESP_LOGE(TAG, "GET_RPT ERROR: handle: %d, status: %s", p_data->hs_data.handle, s_bta_hh_status_names[p_data->hs_data.status]);
  193. }
  194. dev->status = p_data->hs_data.status;
  195. BT_HDR *rpt = p_data->hs_data.rsp_data.p_rpt_data;
  196. dev->tmp = rpt->data + rpt->offset;
  197. dev->tmp_len = rpt->len;
  198. SEND_DEV(dev);
  199. } break;
  200. default:
  201. ESP_LOGV(TAG, "BTA_HH EVENT: %s", s_bta_hh_evt_names[event]);
  202. break;
  203. }
  204. }
  205. /*
  206. * Public Functions
  207. * */
  208. static esp_err_t esp_bt_hidh_dev_close(esp_hidh_dev_t *dev)
  209. {
  210. BTA_HhClose(dev->bt.handle);
  211. return ESP_OK;
  212. }
  213. static esp_err_t 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)
  214. {
  215. esp_hidh_dev_report_t *report = esp_hidh_dev_get_report_by_id_and_type(dev, map_index, report_id, report_type);
  216. if (!report) {
  217. ESP_LOGE(TAG, "%s report %d not found", esp_hid_report_type_str(report_type), report_id);
  218. return ESP_FAIL;
  219. }
  220. if (len > report->value_len) {
  221. 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, len);
  222. return ESP_FAIL;
  223. }
  224. #define BT_HDR_HID_DATA_OFFSET 14 //this equals to L2CAP_MIN_OFFSET + 1 (1 byte to hold the HID transaction header)
  225. uint8_t *pbuf_data;
  226. BT_HDR *p_buf = (BT_HDR *)malloc((uint16_t) (len + 1 + BT_HDR_HID_DATA_OFFSET + sizeof(BT_HDR)));
  227. if (p_buf == NULL) {
  228. ESP_LOGE(TAG, "Could not allocate BT_HDR buffer");
  229. return ESP_ERR_NO_MEM;
  230. }
  231. p_buf->len = len + 1;
  232. p_buf->offset = BT_HDR_HID_DATA_OFFSET;
  233. pbuf_data = (uint8_t *) (p_buf + 1) + p_buf->offset;
  234. pbuf_data[0] = report_id;
  235. memcpy(pbuf_data + 1, data, len);
  236. if (report_type == ESP_HID_REPORT_TYPE_OUTPUT) {
  237. p_buf->layer_specific = BTA_HH_RPTT_OUTPUT;
  238. BTA_HhSendData(dev->bt.handle, dev->bda, p_buf);
  239. } else {
  240. BTA_HhSetReport(dev->bt.handle, report_type, p_buf);
  241. WAIT_DEV(dev);
  242. }
  243. if (dev->status) {
  244. ESP_LOGE(TAG, "Write %s: %s", esp_hid_report_type_str(report_type), s_bta_hh_status_names[dev->status]);
  245. return ESP_FAIL;
  246. }
  247. return ESP_OK;
  248. }
  249. 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, size_t max_length, uint8_t *value, size_t *value_len)
  250. {
  251. esp_hidh_dev_report_t *report = esp_hidh_dev_get_report_by_id_and_type(dev, map_index, report_id, report_type);
  252. if (!report) {
  253. ESP_LOGE(TAG, "%s report %d not found", esp_hid_report_type_str(report_type), report_id);
  254. return ESP_FAIL;
  255. }
  256. BTA_HhGetReport(dev->bt.handle, report_type, report_id, max_length);
  257. if (xSemaphoreTake(dev->semaphore, 500 / portTICK_PERIOD_MS) != pdTRUE) {
  258. ESP_LOGE(TAG, "Read Timeout %s", esp_hid_report_type_str(report_type));
  259. return ESP_FAIL;
  260. }
  261. if (dev->status) {
  262. ESP_LOGE(TAG, "Read %s: %s", esp_hid_report_type_str(report_type), s_bta_hh_status_names[dev->status]);
  263. return ESP_FAIL;
  264. }
  265. if (report_id) {
  266. dev->tmp++;
  267. dev->tmp_len--;
  268. }
  269. if (dev->tmp_len > max_length) {
  270. dev->tmp_len = max_length;
  271. }
  272. *value_len = dev->tmp_len;
  273. memcpy(value, dev->tmp, dev->tmp_len);
  274. return ESP_OK;
  275. }
  276. static void esp_bt_hidh_dev_dump(esp_hidh_dev_t *dev, FILE *fp)
  277. {
  278. fprintf(fp, "BDA:" ESP_BD_ADDR_STR ", Status: %s, Connected: %s, Handle: %d, Usage: %s\n", ESP_BD_ADDR_HEX(dev->bda), s_bta_hh_status_names[dev->status], dev->connected ? "YES" : "NO", dev->bt.handle, esp_hid_usage_str(dev->usage));
  279. 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 : "");
  280. fprintf(fp, "PID: 0x%04x, VID: 0x%04x, VERSION: 0x%04x\n", dev->config.product_id, dev->config.vendor_id, dev->config.version);
  281. fprintf(fp, "Report Map Length: %d\n", dev->config.report_maps[0].len);
  282. esp_hidh_dev_report_t *report = dev->reports;
  283. while (report) {
  284. fprintf(fp, " %8s %7s %6s, ID: %3u, Length: %3u\n",
  285. esp_hid_usage_str(report->usage), esp_hid_report_type_str(report->report_type), esp_hid_protocol_mode_str(report->protocol_mode),
  286. report->report_id, report->value_len);
  287. report = report->next;
  288. }
  289. }
  290. esp_err_t esp_bt_hidh_init(const esp_hidh_config_t *config)
  291. {
  292. if (config == NULL) {
  293. ESP_LOGE(TAG, "Config is NULL");
  294. return ESP_FAIL;
  295. }
  296. esp_event_loop_args_t event_task_args = {
  297. .queue_size = 5,
  298. .task_name = "esp_bt_hidh_events",
  299. .task_priority = uxTaskPriorityGet(NULL),
  300. .task_stack_size = 2048,
  301. .task_core_id = tskNO_AFFINITY
  302. };
  303. esp_err_t ret = esp_event_loop_create(&event_task_args, &event_loop_handle);
  304. if (ret != ESP_OK) {
  305. ESP_LOGE(TAG, "esp_event_loop_create failed!");
  306. return ret;
  307. }
  308. esp_event_handler_register_with(event_loop_handle, ESP_HIDH_EVENTS, ESP_EVENT_ANY_ID, config->callback, NULL);
  309. BTA_HhEnable(0, bta_hh_cb);
  310. return ESP_OK;
  311. }
  312. esp_err_t esp_bt_hidh_deinit(void)
  313. {
  314. if (event_loop_handle) {
  315. esp_event_loop_delete(event_loop_handle);
  316. }
  317. BTA_HhDisable();
  318. return ESP_OK;
  319. }
  320. esp_hidh_dev_t *esp_bt_hidh_dev_open(esp_bd_addr_t bda)
  321. {
  322. esp_hidh_dev_t *dev = esp_hidh_dev_malloc();
  323. if (dev == NULL) {
  324. ESP_LOGE(TAG, "malloc esp_hidh_dev_t failed");
  325. return NULL;
  326. }
  327. dev->transport = ESP_HID_TRANSPORT_BT;
  328. memcpy(dev->bda, bda, sizeof(esp_bd_addr_t));
  329. dev->bt.handle = -1;
  330. dev->opened = true;
  331. BTA_HhOpen(dev->bda, 0, BTA_HH_PROTO_RPT_MODE, (BTA_SEC_AUTHENTICATE | BTA_SEC_ENCRYPT));
  332. WAIT_DEV(dev);
  333. if (dev->status != BTA_HH_OK) {
  334. esp_hidh_dev_free(dev);
  335. return NULL;
  336. }
  337. dev->close = esp_bt_hidh_dev_close;
  338. dev->report_write = esp_bt_hidh_dev_report_write;
  339. dev->report_read = esp_bt_hidh_dev_report_read;
  340. dev->dump = esp_bt_hidh_dev_dump;
  341. return dev;
  342. }
  343. /*
  344. * BlueDroid BT HIDH Stack Callbacks
  345. * */
  346. /* This callback function is executed by BTA_HH when data is received on an interrupt channel. */
  347. void bta_hh_co_data(uint8_t handle, uint8_t *p_rpt, uint16_t len, tBTA_HH_PROTO_MODE mode, uint8_t sub_class, uint8_t country_code, esp_bd_addr_t bda, uint8_t app_id)
  348. {
  349. if (len < 2) {
  350. ESP_LOGE(TAG, "Not Enough Data");
  351. return;
  352. }
  353. esp_hidh_dev_t *dev = NULL;
  354. esp_hidh_dev_report_t *report = NULL;
  355. dev = esp_hidh_dev_get_by_handle(handle);
  356. if (dev == NULL) {
  357. ESP_LOGE(TAG, "Device Not Found: handle %u", handle);
  358. return;
  359. }
  360. report = esp_hidh_dev_get_input_report_by_id_and_proto(dev, p_rpt[0], mode ? ESP_HID_PROTOCOL_MODE_BOOT : ESP_HID_PROTOCOL_MODE_REPORT);
  361. if (report == NULL) {
  362. ESP_LOGE(TAG, "Report Not Found: %d mode: %s", p_rpt[0], mode ? "BOOT" : "REPORT");
  363. return;
  364. }
  365. if (len != (report->value_len + 1)) {
  366. ESP_LOGW(TAG, "Wrong Data Len: %u != %u", len, (report->value_len + 1));
  367. }
  368. if (event_loop_handle) {
  369. esp_hidh_event_data_t p = {0};
  370. if (report->report_type == ESP_HID_REPORT_TYPE_FEATURE) {
  371. p.feature.dev = dev;
  372. p.feature.report_id = report->report_id;
  373. p.feature.usage = report->usage;
  374. p.feature.data = p_rpt + 1;
  375. p.feature.length = len - 1;
  376. esp_event_post_to(event_loop_handle, ESP_HIDH_EVENTS, ESP_HIDH_FEATURE_EVENT, &p, sizeof(esp_hidh_event_data_t), portMAX_DELAY);
  377. } else {
  378. p.input.dev = dev;
  379. p.input.report_id = report->report_id;
  380. p.input.usage = report->usage;
  381. p.input.data = p_rpt + 1;
  382. p.input.length = len - 1;
  383. esp_event_post_to(event_loop_handle, ESP_HIDH_EVENTS, ESP_HIDH_INPUT_EVENT, &p, sizeof(esp_hidh_event_data_t), portMAX_DELAY);
  384. }
  385. }
  386. }
  387. /* This callback function is executed by BTA_HH when connection is opened, and application may do some device specific initialization. */
  388. void bta_hh_co_open(uint8_t handle, uint8_t sub_class, uint16_t attr_mask, uint8_t app_id)
  389. {
  390. esp_hidh_dev_t *dev = NULL;
  391. dev = esp_hidh_dev_get_by_handle(-1);
  392. if (dev == NULL) {
  393. ESP_LOGI(TAG, "Device Not Found? It's probably a reconnect.");
  394. dev = esp_hidh_dev_malloc();
  395. if (dev == NULL) {
  396. ESP_LOGE(TAG, "DEV Malloc Failed");
  397. return;
  398. }
  399. dev->transport = ESP_HID_TRANSPORT_BT;
  400. dev->close = esp_bt_hidh_dev_close;
  401. dev->report_write = esp_bt_hidh_dev_report_write;
  402. dev->report_read = esp_bt_hidh_dev_report_read;
  403. dev->dump = esp_bt_hidh_dev_dump;
  404. }
  405. dev->bt.attr_mask = attr_mask;
  406. dev->bt.app_id = app_id;
  407. dev->bt.sub_class = sub_class;
  408. dev->bt.handle = handle;
  409. }
  410. /* This callback function is executed by BTA_HH when connection is closed, and device specific finalization may be needed. */
  411. void bta_hh_co_close(uint8_t dev_handle, uint8_t app_id) {}
  412. #endif /* CONFIG_BT_HID_HOST_ENABLED */