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