1 /* This example code is in the Public Domain (or CC0 licensed, at your option.)
2 Unless required by applicable law or agreed to in writing, this software is
3 distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
4 CONDITIONS OF ANY KIND, either express or implied.
5 */
6
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <string.h>
10
11 #include "freertos/FreeRTOS.h"
12 #include "freertos/task.h"
13 #include "freertos/event_groups.h"
14 #include "esp_system.h"
15 #include "esp_wifi.h"
16 #include "esp_event.h"
17 #include "esp_log.h"
18 #include "nvs_flash.h"
19 #include "esp_bt.h"
20 #include "esp_bt_defs.h"
21 #if CONFIG_BT_BLE_ENABLED
22 #include "esp_gap_ble_api.h"
23 #include "esp_gatts_api.h"
24 #include "esp_gatt_defs.h"
25 #endif
26 #include "esp_bt_main.h"
27 #include "esp_bt_device.h"
28
29 #include "esp_hidd.h"
30 #include "esp_hid_gap.h"
31
32 static const char *TAG = "HID_DEV_DEMO";
33
34 typedef struct
35 {
36 xTaskHandle task_hdl;
37 esp_hidd_dev_t *hid_dev;
38 uint8_t protocol_mode;
39 uint8_t *buffer;
40 } local_param_t;
41
42 #if CONFIG_BT_BLE_ENABLED
43 static local_param_t s_ble_hid_param = {0};
44 const unsigned char hidapiReportMap[] = { //8 bytes input, 8 bytes feature
45 0x06, 0x00, 0xFF, // Usage Page (Vendor Defined 0xFF00)
46 0x0A, 0x00, 0x01, // Usage (0x0100)
47 0xA1, 0x01, // Collection (Application)
48 0x85, 0x01, // Report ID (1)
49 0x15, 0x00, // Logical Minimum (0)
50 0x26, 0xFF, 0x00, // Logical Maximum (255)
51 0x75, 0x08, // Report Size (8)
52 0x95, 0x08, // Report Count (8)
53 0x09, 0x01, // Usage (0x01)
54 0x82, 0x02, 0x01, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Buffered Bytes)
55 0x95, 0x08, // Report Count (8)
56 0x09, 0x02, // Usage (0x02)
57 0xB2, 0x02, 0x01, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile,Buffered Bytes)
58 0x95, 0x08, // Report Count (8)
59 0x09, 0x03, // Usage (0x03)
60 0x91, 0x02, // Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
61 0xC0, // End Collection
62
63 // 38 bytes
64 };
65
66 const unsigned char mediaReportMap[] = {
67 0x05, 0x0C, // Usage Page (Consumer)
68 0x09, 0x01, // Usage (Consumer Control)
69 0xA1, 0x01, // Collection (Application)
70 0x85, 0x03, // Report ID (3)
71 0x09, 0x02, // Usage (Numeric Key Pad)
72 0xA1, 0x02, // Collection (Logical)
73 0x05, 0x09, // Usage Page (Button)
74 0x19, 0x01, // Usage Minimum (0x01)
75 0x29, 0x0A, // Usage Maximum (0x0A)
76 0x15, 0x01, // Logical Minimum (1)
77 0x25, 0x0A, // Logical Maximum (10)
78 0x75, 0x04, // Report Size (4)
79 0x95, 0x01, // Report Count (1)
80 0x81, 0x00, // Input (Data,Array,Abs,No Wrap,Linear,Preferred State,No Null Position)
81 0xC0, // End Collection
82 0x05, 0x0C, // Usage Page (Consumer)
83 0x09, 0x86, // Usage (Channel)
84 0x15, 0xFF, // Logical Minimum (-1)
85 0x25, 0x01, // Logical Maximum (1)
86 0x75, 0x02, // Report Size (2)
87 0x95, 0x01, // Report Count (1)
88 0x81, 0x46, // Input (Data,Var,Rel,No Wrap,Linear,Preferred State,Null State)
89 0x09, 0xE9, // Usage (Volume Increment)
90 0x09, 0xEA, // Usage (Volume Decrement)
91 0x15, 0x00, // Logical Minimum (0)
92 0x75, 0x01, // Report Size (1)
93 0x95, 0x02, // Report Count (2)
94 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
95 0x09, 0xE2, // Usage (Mute)
96 0x09, 0x30, // Usage (Power)
97 0x09, 0x83, // Usage (Recall Last)
98 0x09, 0x81, // Usage (Assign Selection)
99 0x09, 0xB0, // Usage (Play)
100 0x09, 0xB1, // Usage (Pause)
101 0x09, 0xB2, // Usage (Record)
102 0x09, 0xB3, // Usage (Fast Forward)
103 0x09, 0xB4, // Usage (Rewind)
104 0x09, 0xB5, // Usage (Scan Next Track)
105 0x09, 0xB6, // Usage (Scan Previous Track)
106 0x09, 0xB7, // Usage (Stop)
107 0x15, 0x01, // Logical Minimum (1)
108 0x25, 0x0C, // Logical Maximum (12)
109 0x75, 0x04, // Report Size (4)
110 0x95, 0x01, // Report Count (1)
111 0x81, 0x00, // Input (Data,Array,Abs,No Wrap,Linear,Preferred State,No Null Position)
112 0x09, 0x80, // Usage (Selection)
113 0xA1, 0x02, // Collection (Logical)
114 0x05, 0x09, // Usage Page (Button)
115 0x19, 0x01, // Usage Minimum (0x01)
116 0x29, 0x03, // Usage Maximum (0x03)
117 0x15, 0x01, // Logical Minimum (1)
118 0x25, 0x03, // Logical Maximum (3)
119 0x75, 0x02, // Report Size (2)
120 0x81, 0x00, // Input (Data,Array,Abs,No Wrap,Linear,Preferred State,No Null Position)
121 0xC0, // End Collection
122 0x81, 0x03, // Input (Const,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
123 0xC0, // End Collection
124 };
125
126 static esp_hid_raw_report_map_t ble_report_maps[] = {
127 {
128 .data = hidapiReportMap,
129 .len = sizeof(hidapiReportMap)
130 },
131 {
132 .data = mediaReportMap,
133 .len = sizeof(mediaReportMap)
134 }
135 };
136
137 static esp_hid_device_config_t ble_hid_config = {
138 .vendor_id = 0x16C0,
139 .product_id = 0x05DF,
140 .version = 0x0100,
141 .device_name = "ESP BLE HID2",
142 .manufacturer_name = "Espressif",
143 .serial_number = "1234567890",
144 .report_maps = ble_report_maps,
145 .report_maps_len = 2
146 };
147
148 #define HID_CC_RPT_MUTE 1
149 #define HID_CC_RPT_POWER 2
150 #define HID_CC_RPT_LAST 3
151 #define HID_CC_RPT_ASSIGN_SEL 4
152 #define HID_CC_RPT_PLAY 5
153 #define HID_CC_RPT_PAUSE 6
154 #define HID_CC_RPT_RECORD 7
155 #define HID_CC_RPT_FAST_FWD 8
156 #define HID_CC_RPT_REWIND 9
157 #define HID_CC_RPT_SCAN_NEXT_TRK 10
158 #define HID_CC_RPT_SCAN_PREV_TRK 11
159 #define HID_CC_RPT_STOP 12
160
161 #define HID_CC_RPT_CHANNEL_UP 0x10
162 #define HID_CC_RPT_CHANNEL_DOWN 0x30
163 #define HID_CC_RPT_VOLUME_UP 0x40
164 #define HID_CC_RPT_VOLUME_DOWN 0x80
165
166 // HID Consumer Control report bitmasks
167 #define HID_CC_RPT_NUMERIC_BITS 0xF0
168 #define HID_CC_RPT_CHANNEL_BITS 0xCF
169 #define HID_CC_RPT_VOLUME_BITS 0x3F
170 #define HID_CC_RPT_BUTTON_BITS 0xF0
171 #define HID_CC_RPT_SELECTION_BITS 0xCF
172
173 // Macros for the HID Consumer Control 2-byte report
174 #define HID_CC_RPT_SET_NUMERIC(s, x) (s)[0] &= HID_CC_RPT_NUMERIC_BITS; (s)[0] = (x)
175 #define HID_CC_RPT_SET_CHANNEL(s, x) (s)[0] &= HID_CC_RPT_CHANNEL_BITS; (s)[0] |= ((x) & 0x03) << 4
176 #define HID_CC_RPT_SET_VOLUME_UP(s) (s)[0] &= HID_CC_RPT_VOLUME_BITS; (s)[0] |= 0x40
177 #define HID_CC_RPT_SET_VOLUME_DOWN(s) (s)[0] &= HID_CC_RPT_VOLUME_BITS; (s)[0] |= 0x80
178 #define HID_CC_RPT_SET_BUTTON(s, x) (s)[1] &= HID_CC_RPT_BUTTON_BITS; (s)[1] |= (x)
179 #define HID_CC_RPT_SET_SELECTION(s, x) (s)[1] &= HID_CC_RPT_SELECTION_BITS; (s)[1] |= ((x) & 0x03) << 4
180
181 // HID Consumer Usage IDs (subset of the codes available in the USB HID Usage Tables spec)
182 #define HID_CONSUMER_POWER 48 // Power
183 #define HID_CONSUMER_RESET 49 // Reset
184 #define HID_CONSUMER_SLEEP 50 // Sleep
185
186 #define HID_CONSUMER_MENU 64 // Menu
187 #define HID_CONSUMER_SELECTION 128 // Selection
188 #define HID_CONSUMER_ASSIGN_SEL 129 // Assign Selection
189 #define HID_CONSUMER_MODE_STEP 130 // Mode Step
190 #define HID_CONSUMER_RECALL_LAST 131 // Recall Last
191 #define HID_CONSUMER_QUIT 148 // Quit
192 #define HID_CONSUMER_HELP 149 // Help
193 #define HID_CONSUMER_CHANNEL_UP 156 // Channel Increment
194 #define HID_CONSUMER_CHANNEL_DOWN 157 // Channel Decrement
195
196 #define HID_CONSUMER_PLAY 176 // Play
197 #define HID_CONSUMER_PAUSE 177 // Pause
198 #define HID_CONSUMER_RECORD 178 // Record
199 #define HID_CONSUMER_FAST_FORWARD 179 // Fast Forward
200 #define HID_CONSUMER_REWIND 180 // Rewind
201 #define HID_CONSUMER_SCAN_NEXT_TRK 181 // Scan Next Track
202 #define HID_CONSUMER_SCAN_PREV_TRK 182 // Scan Previous Track
203 #define HID_CONSUMER_STOP 183 // Stop
204 #define HID_CONSUMER_EJECT 184 // Eject
205 #define HID_CONSUMER_RANDOM_PLAY 185 // Random Play
206 #define HID_CONSUMER_SELECT_DISC 186 // Select Disk
207 #define HID_CONSUMER_ENTER_DISC 187 // Enter Disc
208 #define HID_CONSUMER_REPEAT 188 // Repeat
209 #define HID_CONSUMER_STOP_EJECT 204 // Stop/Eject
210 #define HID_CONSUMER_PLAY_PAUSE 205 // Play/Pause
211 #define HID_CONSUMER_PLAY_SKIP 206 // Play/Skip
212
213 #define HID_CONSUMER_VOLUME 224 // Volume
214 #define HID_CONSUMER_BALANCE 225 // Balance
215 #define HID_CONSUMER_MUTE 226 // Mute
216 #define HID_CONSUMER_BASS 227 // Bass
217 #define HID_CONSUMER_VOLUME_UP 233 // Volume Increment
218 #define HID_CONSUMER_VOLUME_DOWN 234 // Volume Decrement
219
220 #define HID_RPT_ID_CC_IN 3 // Consumer Control input report ID
221 #define HID_CC_IN_RPT_LEN 2 // Consumer Control input report Len
esp_hidd_send_consumer_value(uint8_t key_cmd,bool key_pressed)222 void esp_hidd_send_consumer_value(uint8_t key_cmd, bool key_pressed)
223 {
224 uint8_t buffer[HID_CC_IN_RPT_LEN] = {0, 0};
225 if (key_pressed) {
226 switch (key_cmd) {
227 case HID_CONSUMER_CHANNEL_UP:
228 HID_CC_RPT_SET_CHANNEL(buffer, HID_CC_RPT_CHANNEL_UP);
229 break;
230
231 case HID_CONSUMER_CHANNEL_DOWN:
232 HID_CC_RPT_SET_CHANNEL(buffer, HID_CC_RPT_CHANNEL_DOWN);
233 break;
234
235 case HID_CONSUMER_VOLUME_UP:
236 HID_CC_RPT_SET_VOLUME_UP(buffer);
237 break;
238
239 case HID_CONSUMER_VOLUME_DOWN:
240 HID_CC_RPT_SET_VOLUME_DOWN(buffer);
241 break;
242
243 case HID_CONSUMER_MUTE:
244 HID_CC_RPT_SET_BUTTON(buffer, HID_CC_RPT_MUTE);
245 break;
246
247 case HID_CONSUMER_POWER:
248 HID_CC_RPT_SET_BUTTON(buffer, HID_CC_RPT_POWER);
249 break;
250
251 case HID_CONSUMER_RECALL_LAST:
252 HID_CC_RPT_SET_BUTTON(buffer, HID_CC_RPT_LAST);
253 break;
254
255 case HID_CONSUMER_ASSIGN_SEL:
256 HID_CC_RPT_SET_BUTTON(buffer, HID_CC_RPT_ASSIGN_SEL);
257 break;
258
259 case HID_CONSUMER_PLAY:
260 HID_CC_RPT_SET_BUTTON(buffer, HID_CC_RPT_PLAY);
261 break;
262
263 case HID_CONSUMER_PAUSE:
264 HID_CC_RPT_SET_BUTTON(buffer, HID_CC_RPT_PAUSE);
265 break;
266
267 case HID_CONSUMER_RECORD:
268 HID_CC_RPT_SET_BUTTON(buffer, HID_CC_RPT_RECORD);
269 break;
270
271 case HID_CONSUMER_FAST_FORWARD:
272 HID_CC_RPT_SET_BUTTON(buffer, HID_CC_RPT_FAST_FWD);
273 break;
274
275 case HID_CONSUMER_REWIND:
276 HID_CC_RPT_SET_BUTTON(buffer, HID_CC_RPT_REWIND);
277 break;
278
279 case HID_CONSUMER_SCAN_NEXT_TRK:
280 HID_CC_RPT_SET_BUTTON(buffer, HID_CC_RPT_SCAN_NEXT_TRK);
281 break;
282
283 case HID_CONSUMER_SCAN_PREV_TRK:
284 HID_CC_RPT_SET_BUTTON(buffer, HID_CC_RPT_SCAN_PREV_TRK);
285 break;
286
287 case HID_CONSUMER_STOP:
288 HID_CC_RPT_SET_BUTTON(buffer, HID_CC_RPT_STOP);
289 break;
290
291 default:
292 break;
293 }
294 }
295 esp_hidd_dev_input_set(s_ble_hid_param.hid_dev, 1, HID_RPT_ID_CC_IN, buffer, HID_CC_IN_RPT_LEN);
296 return;
297 }
298
ble_hid_demo_task(void * pvParameters)299 void ble_hid_demo_task(void *pvParameters)
300 {
301 static bool send_volum_up = false;
302 while (1) {
303 ESP_LOGI(TAG, "Send the volume");
304 if (send_volum_up) {
305 esp_hidd_send_consumer_value(HID_CONSUMER_VOLUME_UP, true);
306 vTaskDelay(100 / portTICK_PERIOD_MS);
307 esp_hidd_send_consumer_value(HID_CONSUMER_VOLUME_UP, false);
308 } else {
309 esp_hidd_send_consumer_value(HID_CONSUMER_VOLUME_DOWN, true);
310 vTaskDelay(100 / portTICK_PERIOD_MS);
311 esp_hidd_send_consumer_value(HID_CONSUMER_VOLUME_DOWN, false);
312 }
313 send_volum_up = !send_volum_up;
314 vTaskDelay(2000 / portTICK_PERIOD_MS);
315 }
316 }
317
ble_hid_task_start_up(void)318 void ble_hid_task_start_up(void)
319 {
320 xTaskCreate(ble_hid_demo_task, "ble_hid_demo_task", 2 * 1024, NULL, configMAX_PRIORITIES - 3,
321 &s_ble_hid_param.task_hdl);
322 }
323
ble_hid_task_shut_down(void)324 void ble_hid_task_shut_down(void)
325 {
326 if (s_ble_hid_param.task_hdl) {
327 vTaskDelete(s_ble_hid_param.task_hdl);
328 s_ble_hid_param.task_hdl = NULL;
329 }
330 }
331
ble_hidd_event_callback(void * handler_args,esp_event_base_t base,int32_t id,void * event_data)332 static void ble_hidd_event_callback(void *handler_args, esp_event_base_t base, int32_t id, void *event_data)
333 {
334 esp_hidd_event_t event = (esp_hidd_event_t)id;
335 esp_hidd_event_data_t *param = (esp_hidd_event_data_t *)event_data;
336 static const char *TAG = "HID_DEV_BLE";
337
338 switch (event) {
339 case ESP_HIDD_START_EVENT: {
340 ESP_LOGI(TAG, "START");
341 esp_hid_ble_gap_adv_start();
342 break;
343 }
344 case ESP_HIDD_CONNECT_EVENT: {
345 ESP_LOGI(TAG, "CONNECT");
346 ble_hid_task_start_up();//todo: this should be on auth_complete (in GAP)
347 break;
348 }
349 case ESP_HIDD_PROTOCOL_MODE_EVENT: {
350 ESP_LOGI(TAG, "PROTOCOL MODE[%u]: %s", param->protocol_mode.map_index, param->protocol_mode.protocol_mode ? "REPORT" : "BOOT");
351 break;
352 }
353 case ESP_HIDD_CONTROL_EVENT: {
354 ESP_LOGI(TAG, "CONTROL[%u]: %sSUSPEND", param->control.map_index, param->control.control ? "EXIT_" : "");
355 break;
356 }
357 case ESP_HIDD_OUTPUT_EVENT: {
358 ESP_LOGI(TAG, "OUTPUT[%u]: %8s ID: %2u, Len: %d, Data:", param->output.map_index, esp_hid_usage_str(param->output.usage), param->output.report_id, param->output.length);
359 ESP_LOG_BUFFER_HEX(TAG, param->output.data, param->output.length);
360 break;
361 }
362 case ESP_HIDD_FEATURE_EVENT: {
363 ESP_LOGI(TAG, "FEATURE[%u]: %8s ID: %2u, Len: %d, Data:", param->feature.map_index, esp_hid_usage_str(param->feature.usage), param->feature.report_id, param->feature.length);
364 ESP_LOG_BUFFER_HEX(TAG, param->feature.data, param->feature.length);
365 break;
366 }
367 case ESP_HIDD_DISCONNECT_EVENT: {
368 ESP_LOGI(TAG, "DISCONNECT: %s", esp_hid_disconnect_reason_str(esp_hidd_dev_transport_get(param->disconnect.dev), param->disconnect.reason));
369 ble_hid_task_shut_down();
370 esp_hid_ble_gap_adv_start();
371 break;
372 }
373 case ESP_HIDD_STOP_EVENT: {
374 ESP_LOGI(TAG, "STOP");
375 break;
376 }
377 default:
378 break;
379 }
380 return;
381 }
382 #endif
383
384 #if CONFIG_BT_HID_DEVICE_ENABLED
385 static local_param_t s_bt_hid_param = {0};
386 const unsigned char mouseReportMap[] = {
387 0x05, 0x01, // USAGE_PAGE (Generic Desktop)
388 0x09, 0x02, // USAGE (Mouse)
389 0xa1, 0x01, // COLLECTION (Application)
390
391 0x09, 0x01, // USAGE (Pointer)
392 0xa1, 0x00, // COLLECTION (Physical)
393
394 0x05, 0x09, // USAGE_PAGE (Button)
395 0x19, 0x01, // USAGE_MINIMUM (Button 1)
396 0x29, 0x03, // USAGE_MAXIMUM (Button 3)
397 0x15, 0x00, // LOGICAL_MINIMUM (0)
398 0x25, 0x01, // LOGICAL_MAXIMUM (1)
399 0x95, 0x03, // REPORT_COUNT (3)
400 0x75, 0x01, // REPORT_SIZE (1)
401 0x81, 0x02, // INPUT (Data,Var,Abs)
402 0x95, 0x01, // REPORT_COUNT (1)
403 0x75, 0x05, // REPORT_SIZE (5)
404 0x81, 0x03, // INPUT (Cnst,Var,Abs)
405
406 0x05, 0x01, // USAGE_PAGE (Generic Desktop)
407 0x09, 0x30, // USAGE (X)
408 0x09, 0x31, // USAGE (Y)
409 0x09, 0x38, // USAGE (Wheel)
410 0x15, 0x81, // LOGICAL_MINIMUM (-127)
411 0x25, 0x7f, // LOGICAL_MAXIMUM (127)
412 0x75, 0x08, // REPORT_SIZE (8)
413 0x95, 0x03, // REPORT_COUNT (3)
414 0x81, 0x06, // INPUT (Data,Var,Rel)
415
416 0xc0, // END_COLLECTION
417 0xc0 // END_COLLECTION
418 };
419
420 static esp_hid_raw_report_map_t bt_report_maps[] = {
421 {
422 .data = mouseReportMap,
423 .len = sizeof(mouseReportMap)
424 },
425 };
426
427 static esp_hid_device_config_t bt_hid_config = {
428 .vendor_id = 0x16C0,
429 .product_id = 0x05DF,
430 .version = 0x0100,
431 .device_name = "ESP BT HID1",
432 .manufacturer_name = "Espressif",
433 .serial_number = "1234567890",
434 .report_maps = bt_report_maps,
435 .report_maps_len = 1
436 };
437
438 // send the buttons, change in x, and change in y
send_mouse(uint8_t buttons,char dx,char dy,char wheel)439 void send_mouse(uint8_t buttons, char dx, char dy, char wheel)
440 {
441 static uint8_t buffer[4] = {0};
442 buffer[0] = buttons;
443 buffer[1] = dx;
444 buffer[2] = dy;
445 buffer[3] = wheel;
446 esp_hidd_dev_input_set(s_bt_hid_param.hid_dev, 0, 0, buffer, 4);
447 }
448
bt_hid_demo_task(void * pvParameters)449 void bt_hid_demo_task(void *pvParameters)
450 {
451 static const char* help_string = "########################################################################\n"\
452 "BT hid mouse demo usage:\n"\
453 "You can input these value to simulate mouse: 'q', 'w', 'e', 'a', 's', 'd', 'h'\n"\
454 "q -- click the left key\n"\
455 "w -- move up\n"\
456 "e -- click the right key\n"\
457 "a -- move left\n"\
458 "s -- move down\n"\
459 "d -- move right\n"\
460 "h -- show the help\n"\
461 "########################################################################\n";
462 printf("%s\n", help_string);
463 char c;
464 while (1) {
465 c = fgetc(stdin);
466 switch (c) {
467 case 'q':
468 send_mouse(1, 0, 0, 0);
469 break;
470 case 'w':
471 send_mouse(0, 0, -10, 0);
472 break;
473 case 'e':
474 send_mouse(2, 0, 0, 0);
475 break;
476 case 'a':
477 send_mouse(0, -10, 0, 0);
478 break;
479 case 's':
480 send_mouse(0, 0, 10, 0);
481 break;
482 case 'd':
483 send_mouse(0, 10, 0, 0);
484 break;
485 case 'h':
486 printf("%s\n", help_string);
487 break;
488 default:
489 break;
490 }
491 vTaskDelay(10 / portTICK_PERIOD_MS);
492 }
493 }
494
bt_hid_task_start_up(void)495 void bt_hid_task_start_up(void)
496 {
497 xTaskCreate(bt_hid_demo_task, "bt_hid_demo_task", 2 * 1024, NULL, configMAX_PRIORITIES - 3, &s_bt_hid_param.task_hdl);
498 return;
499 }
500
bt_hid_task_shut_down(void)501 void bt_hid_task_shut_down(void)
502 {
503 if (s_bt_hid_param.task_hdl) {
504 vTaskDelete(s_bt_hid_param.task_hdl);
505 s_bt_hid_param.task_hdl = NULL;
506 }
507 }
508
bt_hidd_event_callback(void * handler_args,esp_event_base_t base,int32_t id,void * event_data)509 static void bt_hidd_event_callback(void *handler_args, esp_event_base_t base, int32_t id, void *event_data)
510 {
511 esp_hidd_event_t event = (esp_hidd_event_t)id;
512 esp_hidd_event_data_t *param = (esp_hidd_event_data_t *)event_data;
513 static const char *TAG = "HID_DEV_BT";
514
515 switch (event) {
516 case ESP_HIDD_START_EVENT: {
517 if (param->start.status == ESP_OK) {
518 ESP_LOGI(TAG, "START OK");
519 ESP_LOGI(TAG, "Setting to connectable, discoverable");
520 esp_bt_gap_set_scan_mode(ESP_BT_CONNECTABLE, ESP_BT_GENERAL_DISCOVERABLE);
521 } else {
522 ESP_LOGE(TAG, "START failed!");
523 }
524 break;
525 }
526 case ESP_HIDD_CONNECT_EVENT: {
527 if (param->connect.status == ESP_OK) {
528 ESP_LOGI(TAG, "CONNECT OK");
529 ESP_LOGI(TAG, "Setting to non-connectable, non-discoverable");
530 esp_bt_gap_set_scan_mode(ESP_BT_NON_CONNECTABLE, ESP_BT_NON_DISCOVERABLE);
531 bt_hid_task_start_up();
532 } else {
533 ESP_LOGE(TAG, "CONNECT failed!");
534 }
535 break;
536 }
537 case ESP_HIDD_PROTOCOL_MODE_EVENT: {
538 ESP_LOGI(TAG, "PROTOCOL MODE[%u]: %s", param->protocol_mode.map_index, param->protocol_mode.protocol_mode ? "REPORT" : "BOOT");
539 break;
540 }
541 case ESP_HIDD_OUTPUT_EVENT: {
542 ESP_LOGI(TAG, "OUTPUT[%u]: %8s ID: %2u, Len: %d, Data:", param->output.map_index, esp_hid_usage_str(param->output.usage), param->output.report_id, param->output.length);
543 ESP_LOG_BUFFER_HEX(TAG, param->output.data, param->output.length);
544 break;
545 }
546 case ESP_HIDD_FEATURE_EVENT: {
547 ESP_LOGI(TAG, "FEATURE[%u]: %8s ID: %2u, Len: %d, Data:", param->feature.map_index, esp_hid_usage_str(param->feature.usage), param->feature.report_id, param->feature.length);
548 ESP_LOG_BUFFER_HEX(TAG, param->feature.data, param->feature.length);
549 break;
550 }
551 case ESP_HIDD_DISCONNECT_EVENT: {
552 if (param->disconnect.status == ESP_OK) {
553 ESP_LOGI(TAG, "DISCONNECT OK");
554 bt_hid_task_shut_down();
555 ESP_LOGI(TAG, "Setting to connectable, discoverable again");
556 esp_bt_gap_set_scan_mode(ESP_BT_CONNECTABLE, ESP_BT_GENERAL_DISCOVERABLE);
557 } else {
558 ESP_LOGE(TAG, "DISCONNECT failed!");
559 }
560 break;
561 }
562 case ESP_HIDD_STOP_EVENT: {
563 ESP_LOGI(TAG, "STOP");
564 break;
565 }
566 default:
567 break;
568 }
569 return;
570 }
571 #endif
572
app_main(void)573 void app_main(void)
574 {
575 esp_err_t ret;
576 #if HID_DEV_MODE == HIDD_IDLE_MODE
577 ESP_LOGE(TAG, "Please turn on BT HID device or BLE!");
578 return;
579 #endif
580 ret = nvs_flash_init();
581 if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
582 ESP_ERROR_CHECK(nvs_flash_erase());
583 ret = nvs_flash_init();
584 }
585 ESP_ERROR_CHECK( ret );
586
587 ESP_LOGI(TAG, "setting hid gap, mode:%d", HID_DEV_MODE);
588 ret = esp_hid_gap_init(HID_DEV_MODE);
589 ESP_ERROR_CHECK( ret );
590
591 #if CONFIG_BT_BLE_ENABLED
592 ret = esp_hid_ble_gap_adv_init(ESP_HID_APPEARANCE_GENERIC, ble_hid_config.device_name);
593 ESP_ERROR_CHECK( ret );
594
595 if ((ret = esp_ble_gatts_register_callback(esp_hidd_gatts_event_handler)) != ESP_OK) {
596 ESP_LOGE(TAG, "GATTS register callback failed: %d", ret);
597 return;
598 }
599 ESP_LOGI(TAG, "setting ble device");
600 ESP_ERROR_CHECK(
601 esp_hidd_dev_init(&ble_hid_config, ESP_HID_TRANSPORT_BLE, ble_hidd_event_callback, &s_ble_hid_param.hid_dev));
602 #endif
603
604 #if CONFIG_BT_HID_DEVICE_ENABLED
605 ESP_LOGI(TAG, "setting device name");
606 esp_bt_dev_set_device_name(bt_hid_config.device_name);
607 ESP_LOGI(TAG, "setting cod major, peripheral");
608 esp_bt_cod_t cod;
609 cod.major = ESP_BT_COD_MAJOR_DEV_PERIPHERAL;
610 esp_bt_gap_set_cod(cod, ESP_BT_SET_COD_MAJOR_MINOR);
611 vTaskDelay(1000 / portTICK_PERIOD_MS);
612 ESP_LOGI(TAG, "setting bt device");
613 ESP_ERROR_CHECK(
614 esp_hidd_dev_init(&bt_hid_config, ESP_HID_TRANSPORT_BT, bt_hidd_event_callback, &s_bt_hid_param.hid_dev));
615 #endif
616 }
617