1 /*
2  * SPDX-FileCopyrightText: 2017-2021 Espressif Systems (Shanghai) CO LTD
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <string.h>
8 #include <stdbool.h>
9 
10 #include "ble_hidd.h"
11 #if CONFIG_GATTS_ENABLE
12 
13 #include "esp_hidd_private.h"
14 #include "esp_log.h"
15 #include "esp_bt.h"
16 #include "esp_bt_main.h"
17 #include "esp_bt_defs.h"
18 #include "esp_gatts_api.h"
19 #include "esp_gatt_defs.h"
20 #include "esp_gap_ble_api.h"
21 
22 static const char *TAG = "BLE_HIDD";
23 
24 /// Maximal length of Report Char. Value
25 #define HIDD_LE_REPORT_MAX_LEN                (255)
26 
27 /// Maximal length of Report Map Char. Value
28 #define HIDD_LE_REPORT_MAP_MAX_LEN            (512)
29 
30 /// Length of Boot Report Char. Value Maximal Length
31 #define HIDD_LE_BOOT_REPORT_MAX_LEN           (8)
32 
33 typedef hidd_report_item_t hidd_le_report_item_t;
34 
35 /*
36  * UUIDs
37  * */
38 
39 //the uuid definition
40 static const uint16_t s_primary_service_uuid = ESP_GATT_UUID_PRI_SERVICE;
41 static const uint16_t s_include_service_uuid = ESP_GATT_UUID_INCLUDE_SERVICE;
42 static const uint16_t s_character_declaration_uuid = ESP_GATT_UUID_CHAR_DECLARE;
43 static const uint16_t s_character_client_config_uuid = ESP_GATT_UUID_CHAR_CLIENT_CONFIG;
44 
45 //the property definition
46 static const uint8_t s_char_prop_read = ESP_GATT_CHAR_PROP_BIT_READ;
47 //static const uint8_t s_char_prop_write = ESP_GATT_CHAR_PROP_BIT_WRITE;
48 static const uint8_t s_char_prop_write_nr = ESP_GATT_CHAR_PROP_BIT_WRITE_NR;
49 static const uint8_t s_char_prop_read_notify = ESP_GATT_CHAR_PROP_BIT_READ | ESP_GATT_CHAR_PROP_BIT_NOTIFY;
50 static const uint8_t s_char_prop_read_write = ESP_GATT_CHAR_PROP_BIT_WRITE | ESP_GATT_CHAR_PROP_BIT_READ;
51 static const uint8_t s_char_prop_read_write_nr = ESP_GATT_CHAR_PROP_BIT_WRITE_NR | ESP_GATT_CHAR_PROP_BIT_READ;
52 static const uint8_t s_char_prop_read_write_write_nr = ESP_GATT_CHAR_PROP_BIT_WRITE | ESP_GATT_CHAR_PROP_BIT_WRITE_NR | ESP_GATT_CHAR_PROP_BIT_READ;
53 //static const uint8_t s_char_prop_read_write_notify = ESP_GATT_CHAR_PROP_BIT_READ|ESP_GATT_CHAR_PROP_BIT_WRITE|ESP_GATT_CHAR_PROP_BIT_NOTIFY;
54 
55 // Service UUIDs
56 static const uint16_t s_bat_svc = ESP_GATT_UUID_BATTERY_SERVICE_SVC;
57 static const uint16_t s_device_info_svc = ESP_GATT_UUID_DEVICE_INFO_SVC;
58 static const uint16_t s_hid_le_svc = ESP_GATT_UUID_HID_SVC;
59 
60 // Battery UUIDs
61 static const uint16_t s_bat_level_uuid = ESP_GATT_UUID_BATTERY_LEVEL;
62 static const uint16_t s_bat_char_pres_format_uuid = ESP_GATT_UUID_CHAR_PRESENT_FORMAT;
63 
64 // Device Info UUIDs
65 static const uint16_t s_device_info_pnp_id_uuid = ESP_GATT_UUID_PNP_ID;
66 static const uint16_t s_device_info_manufacturer_uuid = ESP_GATT_UUID_MANU_NAME;
67 static const uint16_t s_device_info_serial_num_uuid = ESP_GATT_UUID_SERIAL_NUMBER_STR;
68 
69 // HID General UUIDs
70 static const uint16_t s_hid_report_map_uuid    = ESP_GATT_UUID_HID_REPORT_MAP;
71 static const uint16_t s_hid_report_map_ext_desc_uuid = ESP_GATT_UUID_EXT_RPT_REF_DESCR;
72 static const uint16_t s_hid_info_char_uuid = ESP_GATT_UUID_HID_INFORMATION;
73 static const uint16_t s_hid_control_point_uuid = ESP_GATT_UUID_HID_CONTROL_POINT;
74 static const uint16_t s_hid_proto_mode_uuid = ESP_GATT_UUID_HID_PROTO_MODE;
75 
76 // HID Report UUIDs
77 static const uint16_t s_hid_report_ref_descr_uuid = ESP_GATT_UUID_RPT_REF_DESCR;
78 static const uint16_t s_hid_report_uuid = ESP_GATT_UUID_HID_REPORT;
79 
80 // HID BOOT UUIDs
81 static const uint16_t s_hid_boot_kb_input_uuid = ESP_GATT_UUID_HID_BT_KB_INPUT;
82 static const uint16_t s_hid_boot_kb_output_uuid = ESP_GATT_UUID_HID_BT_KB_OUTPUT;
83 static const uint16_t s_hid_boot_mouse_input_uuid = ESP_GATT_UUID_HID_BT_MOUSE_INPUT;
84 
85 // Battery Service Attributes Indexes
86 enum {
87     BAS_IDX_SVC,
88 
89     BAS_IDX_BATT_LVL_CHAR,
90     BAS_IDX_BATT_LVL_VAL,
91     BAS_IDX_BATT_LVL_CCC,
92     BAS_IDX_BATT_LVL_PRES_FMT,
93 
94     BAS_IDX_NB,
95 };
96 
97 // HID Service Attributes Indexes
98 enum {
99     HIDD_LE_IDX_SVC,
100 
101     // Included Service
102     HIDD_LE_IDX_INCL_SVC,
103 
104     // HID Information
105     HIDD_LE_IDX_HID_INFO_CHAR,
106     HIDD_LE_IDX_HID_INFO_VAL,
107 
108     // HID Control Point
109     HIDD_LE_IDX_HID_CTNL_PT_CHAR,
110     HIDD_LE_IDX_HID_CTNL_PT_VAL,
111 
112     // Protocol Mode
113     HIDD_LE_IDX_PROTO_MODE_CHAR,
114     HIDD_LE_IDX_PROTO_MODE_VAL,
115 
116     // Report Map
117     HIDD_LE_IDX_REPORT_MAP_CHAR,
118     HIDD_LE_IDX_REPORT_MAP_VAL,
119     HIDD_LE_IDX_REPORT_MAP_EXT_REP_REF,
120 
121     HIDD_LE_IDX_NB,
122 };
123 
124 typedef struct {
125     esp_gatt_if_t               gatt_if;
126     uint16_t                    handle;
127 } hidd_le_service_t;
128 
129 typedef struct {
130     esp_hid_raw_report_map_t    reports_map;
131     uint8_t                     reports_len;
132     hidd_le_report_item_t      *reports;
133     hidd_le_service_t           hid_svc;
134     uint16_t                    hid_control_handle;
135     uint16_t                    hid_protocol_handle;
136 } hidd_dev_map_t;
137 
138 struct esp_ble_hidd_dev_s {
139     esp_hidd_dev_t             *dev;
140     xSemaphoreHandle            sem;
141     esp_event_loop_handle_t     event_loop_handle;
142     esp_hid_device_config_t     config;
143     uint16_t                    appearance;
144 
145 
146     bool                        connected;
147     uint16_t                    conn_id;
148     esp_bd_addr_t               remote_bda;
149 
150     hidd_le_ccc_value_t         bat_ccc;
151     uint8_t                     bat_level;  // 0 - 100 - battery percentage
152     uint8_t                     control;    // 0x00 suspend, 0x01 suspend off
153     uint8_t                     protocol;   // 0x00 boot, 0x01 report
154 
155     hidd_le_service_t           bat_svc;
156     hidd_le_service_t           info_svc;
157     esp_gatts_incl_svc_desc_t   hid_incl_svc;
158 
159     uint16_t                    bat_level_handle;
160     uint16_t                    bat_ccc_handle;
161 
162 
163     uint8_t                     pnp[7];
164 
165     hidd_dev_map_t             *devices;
166     uint8_t                     devices_len;
167 };
168 typedef struct esp_ble_hidd_dev_s esp_ble_hidd_dev_t;
169 
170 // HID Information characteristic value
171 static const uint8_t hidInfo[4] = {
172     0x11, 0x01,     // bcdHID (USB HID version)
173     0x00,           // bCountryCode
174     ESP_HID_FLAGS_REMOTE_WAKE | ESP_HID_FLAGS_NORMALLY_CONNECTABLE   // Flags
175 };
176 
177 
178 #define WAIT_CB(d) xSemaphoreTake(d->sem, portMAX_DELAY)
179 #define SEND_CB(d) xSemaphoreGive(d->sem)
180 
181 static const char *gatts_evt_names[25] = { "REG", "READ", "WRITE", "EXEC_WRITE", "MTU", "CONF", "UNREG", "CREATE", "ADD_INCL_SRVC", "ADD_CHAR", "ADD_CHAR_DESCR", "DELETE", "START", "STOP", "CONNECT", "DISCONNECT", "OPEN", "CANCEL_OPEN", "CLOSE", "LISTEN", "CONGEST", "RESPONSE", "CREAT_ATTR_TAB", "SET_ATTR_VAL", "SEND_SERVICE_CHANGE"};
182 
gatts_evt_str(uint8_t event)183 static const char *gatts_evt_str(uint8_t event)
184 {
185     if (event >= (sizeof(gatts_evt_names)/sizeof(*gatts_evt_names))) {
186         return "UNKNOWN";
187     }
188     return gatts_evt_names[event];
189 }
190 
add_db_record(esp_gatts_attr_db_t * db,size_t index,uint8_t * uuid,uint8_t perm,uint16_t max_length,uint16_t length,uint8_t * value)191 static void add_db_record(esp_gatts_attr_db_t *db, size_t index, uint8_t *uuid, uint8_t perm, uint16_t max_length, uint16_t length, uint8_t *value)
192 {
193     db[index].attr_control.auto_rsp = ESP_GATT_AUTO_RSP;
194     db[index].att_desc.uuid_length = ESP_UUID_LEN_16;
195     db[index].att_desc.uuid_p = uuid;
196     db[index].att_desc.perm = perm;
197     db[index].att_desc.max_length = max_length;
198     db[index].att_desc.length = length;
199     db[index].att_desc.value = value;
200 }
201 
202 static esp_gatts_attr_db_t *_last_db = NULL;
203 
create_bat_db(esp_ble_hidd_dev_t * dev)204 static esp_err_t create_bat_db(esp_ble_hidd_dev_t *dev)
205 {
206     _last_db = (esp_gatts_attr_db_t *)malloc(sizeof(esp_gatts_attr_db_t) * BAS_IDX_NB);
207     if (!_last_db) {
208         ESP_LOGE(TAG, "Malloc bat_db failed");
209         return ESP_FAIL;
210     }
211     add_db_record(_last_db, BAS_IDX_SVC, (uint8_t *)&s_primary_service_uuid, ESP_GATT_PERM_READ, 2, 2, (uint8_t *)&s_bat_svc);
212     add_db_record(_last_db, BAS_IDX_BATT_LVL_CHAR, (uint8_t *)&s_character_declaration_uuid, ESP_GATT_PERM_READ, 1, 1, (uint8_t *)&s_char_prop_read_notify);
213     add_db_record(_last_db, BAS_IDX_BATT_LVL_VAL, (uint8_t *)&s_bat_level_uuid, ESP_GATT_PERM_READ, 1, 1, (uint8_t *)&dev->bat_level);
214     add_db_record(_last_db, BAS_IDX_BATT_LVL_CCC, (uint8_t *)&s_character_client_config_uuid, ESP_GATT_PERM_READ | ESP_GATT_PERM_WRITE, 2, 0,  NULL);
215     add_db_record(_last_db, BAS_IDX_BATT_LVL_PRES_FMT, (uint8_t *)&s_bat_char_pres_format_uuid, ESP_GATT_PERM_READ, 7, 0,  NULL);
216     esp_err_t err = esp_ble_gatts_create_attr_tab(_last_db, dev->bat_svc.gatt_if, BAS_IDX_NB, 0);
217     return err;
218 }
219 
create_info_db(esp_ble_hidd_dev_t * dev)220 static esp_err_t create_info_db(esp_ble_hidd_dev_t *dev)
221 {
222     _last_db = (esp_gatts_attr_db_t *)malloc(sizeof(esp_gatts_attr_db_t) * 7);
223     if (!_last_db) {
224         ESP_LOGE(TAG, "Malloc info_db failed");
225         return ESP_FAIL;
226     }
227     size_t index = 0;
228     add_db_record(_last_db, index++, (uint8_t *)&s_primary_service_uuid, ESP_GATT_PERM_READ, 2, 2, (uint8_t *)&s_device_info_svc);
229 
230     if (dev->config.product_id || dev->config.vendor_id || dev->config.version) {
231         uint8_t pnp_val[7] = {
232             0x02, //0x1=BT, 0x2=USB
233             dev->config.vendor_id & 0xFF, (dev->config.vendor_id >> 8) & 0xFF, //VID
234             dev->config.product_id & 0xFF, (dev->config.product_id >> 8) & 0xFF, //PID
235             dev->config.version & 0xFF, (dev->config.version >> 8) & 0xFF  //VERSION
236         };
237         memcpy(dev->pnp, pnp_val, 7);
238         add_db_record(_last_db, index++, (uint8_t *)&s_character_declaration_uuid, ESP_GATT_PERM_READ, 1, 1, (uint8_t *)&s_char_prop_read);
239         add_db_record(_last_db, index++, (uint8_t *)&s_device_info_pnp_id_uuid, ESP_GATT_PERM_READ, 7, 7, (uint8_t *)dev->pnp);
240     }
241 
242     if (dev->config.manufacturer_name && dev->config.manufacturer_name[0]) {
243         size_t name_len = strlen(dev->config.manufacturer_name);
244         add_db_record(_last_db, index++, (uint8_t *)&s_character_declaration_uuid, ESP_GATT_PERM_READ, 1, 1, (uint8_t *)&s_char_prop_read);
245         add_db_record(_last_db, index++, (uint8_t *)&s_device_info_manufacturer_uuid, ESP_GATT_PERM_READ, name_len, name_len, (uint8_t *)dev->config.manufacturer_name);
246     }
247 
248     if (dev->config.serial_number && dev->config.serial_number[0]) {
249         size_t name_len = strlen(dev->config.serial_number);
250         add_db_record(_last_db, index++, (uint8_t *)&s_character_declaration_uuid, ESP_GATT_PERM_READ, 1, 1, (uint8_t *)&s_char_prop_read);
251         add_db_record(_last_db, index++, (uint8_t *)&s_device_info_serial_num_uuid, ESP_GATT_PERM_READ, name_len, name_len, (uint8_t *)dev->config.serial_number);
252     }
253 
254     esp_err_t err = esp_ble_gatts_create_attr_tab(_last_db, dev->info_svc.gatt_if, index, 0);
255     return err;
256 }
257 
create_hid_db(esp_ble_hidd_dev_t * dev,int device_index)258 static esp_err_t create_hid_db(esp_ble_hidd_dev_t *dev, int device_index)
259 {
260     size_t report_attr_len = 0;
261     for (uint8_t i = 0; i < dev->devices[device_index].reports_len; i++) {
262         if (dev->devices[device_index].reports[i].report_type == ESP_HID_REPORT_TYPE_INPUT) {
263             report_attr_len += 3;
264         } else {
265             report_attr_len += 2;
266         }
267         if (dev->devices[device_index].reports[i].protocol_mode == ESP_HID_PROTOCOL_MODE_REPORT) {
268             report_attr_len += 1;
269         }
270     }
271 
272     _last_db = (esp_gatts_attr_db_t *)malloc(sizeof(esp_gatts_attr_db_t) * (HIDD_LE_IDX_NB + report_attr_len + (dev->devices_len * 3)));
273     if (!_last_db) {
274         ESP_LOGE(TAG, "Malloc hid_db failed");
275         return ESP_FAIL;
276     }
277 
278     add_db_record(_last_db, HIDD_LE_IDX_SVC, (uint8_t *)&s_primary_service_uuid, ESP_GATT_PERM_READ_ENCRYPTED, 2, 2, (uint8_t *)&s_hid_le_svc);
279     add_db_record(_last_db, HIDD_LE_IDX_INCL_SVC, (uint8_t *)&s_include_service_uuid, ESP_GATT_PERM_READ, sizeof(esp_gatts_incl_svc_desc_t), sizeof(esp_gatts_incl_svc_desc_t), (uint8_t *)&dev->hid_incl_svc);
280 
281     add_db_record(_last_db, HIDD_LE_IDX_HID_INFO_CHAR, (uint8_t *)&s_character_declaration_uuid, ESP_GATT_PERM_READ, 1, 1, (uint8_t *)&s_char_prop_read);
282     add_db_record(_last_db, HIDD_LE_IDX_HID_INFO_VAL, (uint8_t *)&s_hid_info_char_uuid, ESP_GATT_PERM_READ, 4, 4, (uint8_t *)hidInfo);
283 
284     add_db_record(_last_db, HIDD_LE_IDX_HID_CTNL_PT_CHAR, (uint8_t *)&s_character_declaration_uuid, ESP_GATT_PERM_READ, 1, 1, (uint8_t *)&s_char_prop_write_nr);
285     add_db_record(_last_db, HIDD_LE_IDX_HID_CTNL_PT_VAL, (uint8_t *)&s_hid_control_point_uuid, ESP_GATT_PERM_READ, 1, 0, NULL);
286 
287     add_db_record(_last_db, HIDD_LE_IDX_PROTO_MODE_CHAR, (uint8_t *)&s_character_declaration_uuid, ESP_GATT_PERM_READ, 1, 1, (uint8_t *)&s_char_prop_read_write_nr);
288     add_db_record(_last_db, HIDD_LE_IDX_PROTO_MODE_VAL, (uint8_t *)&s_hid_proto_mode_uuid, ESP_GATT_PERM_READ | ESP_GATT_PERM_WRITE, 1, 1, (uint8_t *)&dev->protocol);
289 
290     add_db_record(_last_db, HIDD_LE_IDX_REPORT_MAP_CHAR, (uint8_t *)&s_character_declaration_uuid, ESP_GATT_PERM_READ, 1, 1, (uint8_t *)&s_char_prop_read);
291     add_db_record(_last_db, HIDD_LE_IDX_REPORT_MAP_VAL, (uint8_t *)&s_hid_report_map_uuid, ESP_GATT_PERM_READ, HIDD_LE_REPORT_MAP_MAX_LEN, dev->devices[device_index].reports_map.len, (uint8_t *)dev->devices[device_index].reports_map.data);
292     add_db_record(_last_db, HIDD_LE_IDX_REPORT_MAP_EXT_REP_REF, (uint8_t *)&s_hid_report_map_ext_desc_uuid, ESP_GATT_PERM_READ, 2, 2, (uint8_t *)&s_bat_level_uuid);
293 
294     size_t index = HIDD_LE_IDX_NB;
295 
296     for (uint8_t i = 0; i < dev->devices[device_index].reports_len; i++) {
297         hidd_le_report_item_t *report = &dev->devices[device_index].reports[i];
298         if (report->protocol_mode == ESP_HID_PROTOCOL_MODE_REPORT) {
299             if (report->report_type == ESP_HID_REPORT_TYPE_INPUT) {
300                 //Input Report
301                 add_db_record(_last_db, index++, (uint8_t *)&s_character_declaration_uuid, ESP_GATT_PERM_READ, 1, 1, (uint8_t *)&s_char_prop_read_notify);
302                 report->index = index;
303                 add_db_record(_last_db, index++, (uint8_t *)&s_hid_report_uuid, ESP_GATT_PERM_READ, report->value_len, 0, NULL);
304                 add_db_record(_last_db, index++, (uint8_t *)&s_character_client_config_uuid, ESP_GATT_PERM_READ | ESP_GATT_PERM_WRITE, 2, 0, NULL);
305             } else if (report->report_type == ESP_HID_REPORT_TYPE_OUTPUT) {
306                 //Output Report
307                 add_db_record(_last_db, index++, (uint8_t *)&s_character_declaration_uuid, ESP_GATT_PERM_READ, 1, 1, (uint8_t *)&s_char_prop_read_write_write_nr);
308                 report->index = index;
309                 add_db_record(_last_db, index++, (uint8_t *)&s_hid_report_uuid, ESP_GATT_PERM_READ | ESP_GATT_PERM_WRITE, report->value_len, 0, NULL);
310             } else {
311                 //Feature Report
312                 add_db_record(_last_db, index++, (uint8_t *)&s_character_declaration_uuid, ESP_GATT_PERM_READ, 1, 1, (uint8_t *)&s_char_prop_read_write);
313                 report->index = index;
314                 add_db_record(_last_db, index++, (uint8_t *)&s_hid_report_uuid, ESP_GATT_PERM_READ | ESP_GATT_PERM_WRITE, report->value_len, 0, NULL);
315             }
316             add_db_record(_last_db, index++, (uint8_t *)&s_hid_report_ref_descr_uuid, ESP_GATT_PERM_READ, 2, 2, (uint8_t *)&report->report_id);
317         } else {
318             if (report->report_type == ESP_HID_REPORT_TYPE_INPUT) {
319                 add_db_record(_last_db, index++, (uint8_t *)&s_character_declaration_uuid, ESP_GATT_PERM_READ, 1, 1, (uint8_t *)&s_char_prop_read_notify);
320                 report->index = index;
321                 if (report->usage == ESP_HID_USAGE_KEYBOARD) { //Boot Keyboard Input
322                     add_db_record(_last_db, index++, (uint8_t *)&s_hid_boot_kb_input_uuid, ESP_GATT_PERM_READ, HIDD_LE_BOOT_REPORT_MAX_LEN, 0, NULL);
323                 } else { //Boot Mouse Input
324                     add_db_record(_last_db, index++, (uint8_t *)&s_hid_boot_mouse_input_uuid, ESP_GATT_PERM_READ, HIDD_LE_BOOT_REPORT_MAX_LEN, 0, NULL);
325                 }
326                 add_db_record(_last_db, index++, (uint8_t *)&s_character_client_config_uuid, ESP_GATT_PERM_READ | ESP_GATT_PERM_WRITE, 2, 0, NULL);
327             } else { //Boot Keyboard Output
328                 add_db_record(_last_db, index++, (uint8_t *)&s_character_declaration_uuid, ESP_GATT_PERM_READ, 1, 1, (uint8_t *)&s_char_prop_read_write_write_nr);
329                 report->index = index;
330                 add_db_record(_last_db, index++, (uint8_t *)&s_hid_boot_kb_output_uuid, ESP_GATT_PERM_READ | ESP_GATT_PERM_WRITE, HIDD_LE_BOOT_REPORT_MAX_LEN, 0, NULL);
331             }
332         }
333 
334     }
335     esp_err_t err = esp_ble_gatts_create_attr_tab(_last_db, dev->devices[device_index].hid_svc.gatt_if, index, device_index);
336     return err;
337 }
338 
339 
link_report_handles(hidd_dev_map_t * dev,uint16_t * handles)340 static void link_report_handles(hidd_dev_map_t *dev, uint16_t *handles)
341 {
342 
343     hidd_le_report_item_t *rpt = NULL;
344     for (uint8_t i = 0; i < dev->reports_len; i++) {
345         rpt = &dev->reports[i];
346         rpt->handle = handles[rpt->index];
347         if (rpt->report_type == ESP_HID_REPORT_TYPE_INPUT) {
348             rpt->ccc_handle = handles[rpt->index + 1];
349         }
350     }
351 }
352 
get_report_by_handle(esp_ble_hidd_dev_t * dev,uint16_t handle)353 static hidd_le_report_item_t *get_report_by_handle(esp_ble_hidd_dev_t *dev, uint16_t handle)
354 {
355     hidd_le_report_item_t *rpt = NULL;
356     for (uint8_t d = 0; d < dev->devices_len; d++) {
357         for (uint8_t i = 0; i < dev->devices[d].reports_len; i++) {
358             rpt = &dev->devices[d].reports[i];
359             if (rpt->handle == handle || rpt->ccc_handle == handle) {
360                 return rpt;
361             }
362         }
363     }
364     return NULL;
365 }
366 
get_report_by_id_and_type(esp_ble_hidd_dev_t * dev,uint8_t id,uint8_t type)367 static hidd_le_report_item_t *get_report_by_id_and_type(esp_ble_hidd_dev_t *dev, uint8_t id, uint8_t type)
368 {
369     hidd_le_report_item_t *rpt = NULL;
370     for (uint8_t d = 0; d < dev->devices_len; d++) {
371         for (uint8_t i = 0; i < dev->devices[d].reports_len; i++) {
372             rpt = &dev->devices[d].reports[i];
373             if (rpt->report_id == id && rpt->report_type == type && rpt->protocol_mode == ESP_HID_PROTOCOL_MODE_REPORT) {
374                 return rpt;
375             }
376         }
377     }
378     return NULL;
379 }
380 
bat_event_handler(esp_ble_hidd_dev_t * dev,esp_gatts_cb_event_t event,esp_gatt_if_t gatts_if,esp_ble_gatts_cb_param_t * param)381 static void bat_event_handler(esp_ble_hidd_dev_t *dev, esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t *param)
382 {
383     switch (event) {
384     case ESP_GATTS_REG_EVT:
385         ESP_LOGV(TAG, "Battery REG App ID: 0x%x", param->reg.app_id);
386         break;
387     case ESP_GATTS_CREAT_ATTR_TAB_EVT:
388         dev->bat_svc.handle = param->add_attr_tab.handles[BAS_IDX_SVC];
389         dev->bat_level_handle = param->add_attr_tab.handles[BAS_IDX_BATT_LVL_VAL];//so we notify of the change
390         dev->bat_ccc_handle = param->add_attr_tab.handles[BAS_IDX_BATT_LVL_CCC];//so we know if we can send notify
391         ESP_LOGV(TAG, "Battery CREAT_ATTR_TAB service handle = %d", dev->bat_svc.handle);
392 
393         dev->hid_incl_svc.start_hdl = dev->bat_svc.handle;
394         dev->hid_incl_svc.end_hdl = dev->bat_svc.handle + BAS_IDX_NB - 1;
395 
396         esp_ble_gatts_start_service(dev->bat_svc.handle);
397 
398         // Add the info service next, because it's shared between all device maps
399         create_info_db(dev);
400         break;
401 
402     case ESP_GATTS_READ_EVT:
403         if (param->read.handle == dev->bat_level_handle) {
404             ESP_LOGD(TAG, "Battery READ %d", dev->bat_level);
405         }
406         break;
407     case ESP_GATTS_WRITE_EVT: {
408         if (param->write.handle == dev->bat_ccc_handle) {
409             dev->bat_ccc.value = param->write.value[0];
410             ESP_LOGV(TAG, "Battery CCC: Notify: %s, Indicate: %s", dev->bat_ccc.notify_enable ? "On" : "Off", dev->bat_ccc.indicate_enable ? "On" : "Off");
411         }
412         break;
413     }
414     case ESP_GATTS_SET_ATTR_VAL_EVT: {
415         if (param->set_attr_val.attr_handle == dev->bat_level_handle) {
416             ESP_LOGD(TAG, "Battery SET %d, status: 0x%02x", dev->bat_level, param->set_attr_val.status);
417         }
418         break;
419     }
420     default:
421         ESP_LOGV(TAG, "Battery %s", gatts_evt_str(event));
422         break;
423     }
424 }
425 
info_event_handler(esp_ble_hidd_dev_t * dev,esp_gatts_cb_event_t event,esp_gatt_if_t gatts_if,esp_ble_gatts_cb_param_t * param)426 static void info_event_handler(esp_ble_hidd_dev_t *dev, esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t *param)
427 {
428     switch (event) {
429     case ESP_GATTS_REG_EVT:
430         ESP_LOGV(TAG, "Dev Info REG App ID: 0x%x", param->reg.app_id);
431         break;
432     case ESP_GATTS_CREAT_ATTR_TAB_EVT:
433         dev->info_svc.handle = param->add_attr_tab.handles[0];
434         ESP_LOGV(TAG, "Dev Info service handle = %d", dev->info_svc.handle);
435         esp_ble_gatts_start_service(dev->info_svc.handle);
436         create_hid_db(dev, 0);
437         break;
438 
439     default:
440         ESP_LOGV(TAG, "Dev Info %s", gatts_evt_str(event));
441         break;
442     }
443 }
444 
hid_event_handler(esp_ble_hidd_dev_t * dev,int device_index,esp_gatts_cb_event_t event,esp_gatt_if_t gatts_if,esp_ble_gatts_cb_param_t * param)445 static void hid_event_handler(esp_ble_hidd_dev_t *dev, int device_index, esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t *param)
446 {
447     switch (event) {
448     case ESP_GATTS_REG_EVT: {
449         ESP_LOGV(TAG, "HID REG[%d] App ID: 0x%x", device_index, param->reg.app_id);
450         // is this the last report map app?
451         if (device_index == (dev->devices_len - 1)) {
452             // we should add the battery service first, because the hid service should include the battery service.
453             create_bat_db(dev);
454         }
455         break;
456     }
457     case ESP_GATTS_CREAT_ATTR_TAB_EVT: {
458         dev->devices[device_index].hid_svc.handle = param->add_attr_tab.handles[HIDD_LE_IDX_SVC];
459         dev->devices[device_index].hid_control_handle = param->add_attr_tab.handles[HIDD_LE_IDX_HID_CTNL_PT_VAL];
460         dev->devices[device_index].hid_protocol_handle = param->add_attr_tab.handles[HIDD_LE_IDX_PROTO_MODE_VAL];
461         ESP_LOGV(TAG, "HID CREAT_ATTR_TAB[%u] service handle = %d", device_index, dev->devices[device_index].hid_svc.handle);
462 
463         link_report_handles(&dev->devices[device_index], param->add_attr_tab.handles);
464         esp_ble_gatts_start_service(dev->devices[device_index].hid_svc.handle);
465         if ((device_index + 1) < dev->devices_len) {
466             create_hid_db(dev, device_index + 1);//add next device
467         }
468         break;
469     }
470     case ESP_GATTS_START_EVT: {
471         ESP_LOGD(TAG, "HID START[%d] status: 0x%02x", device_index, param->start.status);
472         if (device_index == (dev->devices_len - 1)) {
473             esp_event_post_to(dev->event_loop_handle, ESP_HIDD_EVENTS, ESP_HIDD_START_EVENT, NULL, 0, portMAX_DELAY);
474         }
475         break;
476     }
477     case ESP_GATTS_CONNECT_EVT: {
478         ESP_LOGD(TAG, "HID CONNECT[%d] conn_id = %x", device_index, param->connect.conn_id);
479         if (!dev->connected && device_index == (dev->devices_len - 1)) {
480             dev->connected = true;
481             dev->conn_id   = param->connect.conn_id;
482             memcpy(dev->remote_bda, param->connect.remote_bda, ESP_BD_ADDR_LEN);
483 
484             esp_ble_set_encryption(param->connect.remote_bda, ESP_BLE_SEC_ENCRYPT_NO_MITM);
485 
486             esp_hidd_event_data_t cb_param = {
487                 .connect.dev = dev->dev,
488             };
489             esp_event_post_to(dev->event_loop_handle, ESP_HIDD_EVENTS, ESP_HIDD_CONNECT_EVENT, &cb_param, sizeof(esp_hidd_event_data_t), portMAX_DELAY);
490         }
491         break;
492     }
493     case ESP_GATTS_DISCONNECT_EVT: {
494         ESP_LOGD(TAG, "HID DISCONNECT[%d] 0x%x", device_index, param->disconnect.reason);
495         if (dev->connected) {
496             dev->connected = false;
497             esp_hidd_event_data_t cb_param = {0};
498             cb_param.disconnect.dev = dev->dev;
499             cb_param.disconnect.reason = param->disconnect.reason;
500             esp_event_post_to(dev->event_loop_handle, ESP_HIDD_EVENTS, ESP_HIDD_DISCONNECT_EVENT, &cb_param, sizeof(esp_hidd_event_data_t), portMAX_DELAY);
501         }
502         break;
503     }
504     case ESP_GATTS_READ_EVT: {
505         hidd_le_report_item_t *map = get_report_by_handle(dev, param->read.handle);
506         if (map && map->handle == param->read.handle) {
507             ESP_LOGV(TAG, "HID READ[%d] %8s %7s %6s id: %d, need_resp: %d", device_index, esp_hid_usage_str(map->usage), esp_hid_report_type_str(map->report_type), esp_hid_protocol_mode_str(map->protocol_mode), map->report_id, param->read.need_rsp);
508         }
509         break;
510     }
511     case ESP_GATTS_WRITE_EVT: {
512 
513         if (param->write.handle == dev->devices[device_index].hid_control_handle) {
514             dev->control = param->write.value[0];
515 
516             esp_hidd_event_data_t cb_param = {0};
517             cb_param.control.dev = dev->dev;
518             cb_param.control.control = dev->control;
519             cb_param.control.map_index = device_index;
520             esp_event_post_to(dev->event_loop_handle, ESP_HIDD_EVENTS, ESP_HIDD_CONTROL_EVENT, &cb_param, sizeof(esp_hidd_event_data_t), portMAX_DELAY);
521         } else if (param->write.handle == dev->devices[device_index].hid_protocol_handle) {
522             dev->protocol = param->write.value[0];
523 
524             esp_hidd_event_data_t cb_param = {};
525             cb_param.protocol_mode.dev = dev->dev;
526             cb_param.protocol_mode.protocol_mode = dev->protocol;
527             cb_param.protocol_mode.map_index = device_index;
528             esp_event_post_to(dev->event_loop_handle, ESP_HIDD_EVENTS, ESP_HIDD_PROTOCOL_MODE_EVENT, &cb_param, sizeof(esp_hidd_event_data_t), portMAX_DELAY);
529         } else {
530             hidd_le_report_item_t *map = get_report_by_handle(dev, param->write.handle);
531             if (map) {
532                 if (param->write.handle == map->ccc_handle) {
533                     map->ccc.value = param->write.value[0];
534                     ESP_LOGV(TAG, "HID CCC[%d] %8s %7s %6s id: %d, Notify: %s, Indicate: %s", device_index, esp_hid_usage_str(map->usage), esp_hid_report_type_str(map->report_type), esp_hid_protocol_mode_str(map->protocol_mode), map->report_id, map->ccc.notify_enable ? "On" : "Off", map->ccc.indicate_enable ? "On" : "Off");
535                 } else {
536                     ESP_LOGV(TAG, "HID WRITE %8s %7s %6s id: %d, len: %d", esp_hid_usage_str(map->usage), esp_hid_report_type_str(map->report_type), esp_hid_protocol_mode_str(map->protocol_mode), map->report_id, param->write.len);
537 
538                     esp_hidd_event_data_t *p_cb_param = NULL;
539                     size_t event_data_size = sizeof(esp_hidd_event_data_t);
540                     if (param->write.len > 0 && param->write.value) {
541                         event_data_size += param->write.len;
542                     }
543 
544                     if ((p_cb_param = (esp_hidd_event_data_t *)malloc(event_data_size)) == NULL) {
545                         ESP_LOGE(TAG, "%s malloc event data failed!", __func__);
546                         break;
547                     }
548                     memset(p_cb_param, 0, event_data_size);
549                     if (param->write.len > 0 && param->write.value) {
550                         memcpy(((uint8_t *)p_cb_param) + sizeof(esp_hidd_event_data_t), param->write.value,
551                                param->write.len);
552                     }
553 
554                     if (map->report_type == ESP_HID_REPORT_TYPE_OUTPUT) {
555                         p_cb_param->output.dev = dev->dev;
556                         p_cb_param->output.report_id = map->report_id;
557                         p_cb_param->output.usage = map->usage;
558                         p_cb_param->output.length = param->write.len;
559                         p_cb_param->output.data = param->write.value; /* move the data pointer in the wrapper loop handler */
560                         p_cb_param->output.map_index = device_index;
561                         esp_event_post_to(dev->event_loop_handle, ESP_HIDD_EVENTS, ESP_HIDD_OUTPUT_EVENT, p_cb_param, event_data_size, portMAX_DELAY);
562                     } else {
563                         p_cb_param->feature.dev = dev->dev;
564                         p_cb_param->feature.report_id = map->report_id;
565                         p_cb_param->feature.usage = map->usage;
566                         p_cb_param->feature.length = param->write.len;
567                         p_cb_param->feature.data = param->write.value; /* move the data pointer in the wrapper loop handler */
568                         p_cb_param->feature.map_index = device_index;
569                         esp_event_post_to(dev->event_loop_handle, ESP_HIDD_EVENTS, ESP_HIDD_FEATURE_EVENT, p_cb_param, event_data_size, portMAX_DELAY);
570                     }
571 
572                     if (p_cb_param) {
573                         free(p_cb_param);
574                         p_cb_param = NULL;
575                     }
576                 }
577             }
578 
579         }
580         break;
581     }
582     case ESP_GATTS_SET_ATTR_VAL_EVT: {
583         hidd_le_report_item_t *map = get_report_by_handle(dev, param->set_attr_val.attr_handle);
584         if (map && map->handle == param->set_attr_val.attr_handle) {
585             ESP_LOGV(TAG, "HID SET[%d] %8s %7s %6s id: %d, status: 0x%02x", device_index, esp_hid_usage_str(map->usage), esp_hid_report_type_str(map->report_type), esp_hid_protocol_mode_str(map->protocol_mode), map->report_id, param->set_attr_val.status);
586         }
587         SEND_CB(dev);
588         break;
589     }
590     case ESP_GATTS_CONF_EVT: {
591         ESP_LOGV(TAG, "HID CONF[%d] status: 0x%02x, len: %d", device_index, param->conf.status, param->conf.len);
592         SEND_CB(dev);
593         break;
594     }
595     case ESP_GATTS_MTU_EVT:
596         ESP_LOGV(TAG, "HID[%d] MTU = %d", device_index, param->mtu.mtu);
597         break;
598 
599     default:
600         ESP_LOGV(TAG, "HID[%d] %s", device_index, gatts_evt_str(event));
601         break;
602     }
603 }
604 
get_device_map_index_by_gatts_if(esp_ble_hidd_dev_t * dev,esp_gatt_if_t gatts_if)605 static int get_device_map_index_by_gatts_if (esp_ble_hidd_dev_t *dev, esp_gatt_if_t gatts_if)
606 {
607     for (uint8_t d = 0; d < dev->devices_len; d++) {
608         if (dev->devices[d].hid_svc.gatt_if && gatts_if == dev->devices[d].hid_svc.gatt_if) {
609             return d;
610         }
611     }
612     return -1;
613 }
614 
ble_hid_start_gatts(esp_ble_hidd_dev_t * dev)615 static esp_err_t ble_hid_start_gatts(esp_ble_hidd_dev_t *dev)
616 {
617     esp_err_t ret;
618 
619     if ((ret = esp_ble_gatts_app_register(ESP_GATT_UUID_BATTERY_SERVICE_SVC)) != ESP_OK) {
620         ESP_LOGE(TAG, "GATTS register battery service failed: %d", ret);
621         return ret;
622     }
623     if ((ret = esp_ble_gatts_app_register(ESP_GATT_UUID_DEVICE_INFO_SVC)) != ESP_OK) {
624         ESP_LOGE(TAG, "GATTS register device info service failed: %d", ret);
625         return ret;
626     }
627     for (uint8_t i = 0; i < dev->devices_len; i++) {
628         if ((ret = esp_ble_gatts_app_register(ESP_GATT_UUID_HID_SVC + i)) != ESP_OK) {
629             ESP_LOGE(TAG, "GATTS register HID[%u] service failed: %d", i, ret);
630             return ret;
631         }
632     }
633     return ret;
634 }
635 
ble_hid_stop_gatts(esp_ble_hidd_dev_t * dev)636 static esp_err_t ble_hid_stop_gatts(esp_ble_hidd_dev_t *dev)
637 {
638     esp_err_t ret = ESP_OK;
639 
640     for (uint8_t d = 0; d < dev->devices_len; d++) {
641         esp_ble_gatts_stop_service(dev->devices[d].hid_svc.handle);
642         esp_ble_gatts_delete_service(dev->devices[d].hid_svc.handle);
643         esp_ble_gatts_app_unregister(dev->devices[d].hid_svc.gatt_if);
644     }
645 
646     esp_ble_gatts_stop_service(dev->info_svc.handle);
647     esp_ble_gatts_delete_service(dev->info_svc.handle);
648     esp_ble_gatts_app_unregister(dev->info_svc.gatt_if);
649 
650     esp_ble_gatts_stop_service(dev->bat_svc.handle);
651     esp_ble_gatts_delete_service(dev->bat_svc.handle);
652     esp_ble_gatts_app_unregister(dev->bat_svc.gatt_if);
653 
654     return ret;
655 }
656 
ble_hid_init_config(esp_ble_hidd_dev_t * dev,const esp_hid_device_config_t * config)657 static esp_err_t ble_hid_init_config(esp_ble_hidd_dev_t *dev, const esp_hid_device_config_t *config)
658 {
659     memset((uint8_t *)(&dev->config), 0, sizeof(esp_hid_device_config_t));
660     dev->config.vendor_id = config->vendor_id;
661     dev->config.product_id = config->product_id;
662     dev->config.version = config->version;
663     if (config->device_name != NULL) {
664         dev->config.device_name = strdup(config->device_name);
665     }
666     if (config->manufacturer_name != NULL) {
667         dev->config.manufacturer_name = strdup(config->manufacturer_name);
668     }
669     if (config->serial_number != NULL) {
670         dev->config.serial_number = strdup(config->serial_number);
671     }
672     dev->appearance = ESP_HID_APPEARANCE_GENERIC;
673 
674     if (config->report_maps_len) {
675         dev->devices = (hidd_dev_map_t *)malloc(config->report_maps_len * sizeof(hidd_dev_map_t));
676         if (dev->devices == NULL) {
677             ESP_LOGE(TAG, "devices malloc(%d) failed", config->report_maps_len);
678             return ESP_FAIL;
679         }
680         memset(dev->devices, 0, config->report_maps_len * sizeof(hidd_dev_map_t));
681         dev->devices_len = config->report_maps_len;
682         for (uint8_t d = 0; d < dev->devices_len; d++) {
683 
684             //raw report map
685             uint8_t *map = (uint8_t *)malloc(config->report_maps[d].len);
686             if (map == NULL) {
687                 ESP_LOGE(TAG, "report map malloc(%d) failed", config->report_maps[d].len);
688                 return ESP_FAIL;
689             }
690             memcpy(map, config->report_maps[d].data, config->report_maps[d].len);
691 
692             dev->devices[d].reports_map.data = (const uint8_t *)map;
693             dev->devices[d].reports_map.len = config->report_maps[d].len;
694 
695             esp_hid_report_map_t *rmap = esp_hid_parse_report_map(config->report_maps[d].data, config->report_maps[d].len);
696             if (rmap == NULL) {
697                 ESP_LOGE(TAG, "hid_parse_report_map[%d](%d) failed", d, config->report_maps[d].len);
698                 return ESP_FAIL;
699             }
700             dev->appearance = rmap->appearance;
701             dev->devices[d].reports_len = rmap->reports_len;
702             dev->devices[d].reports = (hidd_le_report_item_t *)malloc(rmap->reports_len * sizeof(hidd_le_report_item_t));
703             if (dev->devices[d].reports == NULL) {
704                 ESP_LOGE(TAG, "reports malloc(%d) failed", rmap->reports_len * sizeof(hidd_le_report_item_t));
705                 free(rmap);
706                 return ESP_FAIL;
707             }
708             for (uint8_t r = 0; r < rmap->reports_len; r++) {
709                 dev->devices[d].reports[r].map_index = d;
710                 dev->devices[d].reports[r].report_id = rmap->reports[r].report_id;
711                 dev->devices[d].reports[r].protocol_mode = rmap->reports[r].protocol_mode;
712                 dev->devices[d].reports[r].report_type = rmap->reports[r].report_type;
713                 dev->devices[d].reports[r].usage = rmap->reports[r].usage;
714                 dev->devices[d].reports[r].value_len = rmap->reports[r].value_len;
715             }
716             free(rmap->reports);
717             free(rmap);
718         }
719     }
720 
721     return ESP_OK;
722 }
723 
ble_hid_free_config(esp_ble_hidd_dev_t * dev)724 static esp_err_t ble_hid_free_config(esp_ble_hidd_dev_t *dev)
725 {
726     for (uint8_t d = 0; d < dev->devices_len; d++) {
727         free((void *)dev->devices[d].reports);
728         free((void *)dev->devices[d].reports_map.data);
729     }
730 
731     free((void *)dev->devices);
732     free((void *)dev->config.device_name);
733     free((void *)dev->config.manufacturer_name);
734     free((void *)dev->config.serial_number);
735     if (dev->sem != NULL) {
736         vSemaphoreDelete(dev->sem);
737     }
738     if (dev->event_loop_handle != NULL) {
739         esp_event_loop_delete(dev->event_loop_handle);
740     }
741     return ESP_OK;
742 }
743 
744 /*
745  * PUBLIC FUNCTIONS
746  * */
747 
748 // there can be only one BLE HID device
749 static esp_ble_hidd_dev_t *s_dev = NULL;
750 
esp_hidd_gatts_event_handler(esp_gatts_cb_event_t event,esp_gatt_if_t gatts_if,esp_ble_gatts_cb_param_t * param)751 void esp_hidd_gatts_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t *param)
752 {
753     if (!s_dev) {
754         return;
755     }
756 
757     if (event == ESP_GATTS_REG_EVT) {
758         if (param->reg.status != ESP_GATT_OK) {
759             ESP_LOGE(TAG, "Reg app failed, app_id %04x, status %d", param->reg.app_id, param->reg.status);
760             return;
761         } else {
762             if (param->reg.app_id == ESP_GATT_UUID_DEVICE_INFO_SVC) {
763                 s_dev->info_svc.gatt_if = gatts_if;
764             } else if (param->reg.app_id == ESP_GATT_UUID_BATTERY_SERVICE_SVC) {
765                 s_dev->bat_svc.gatt_if = gatts_if;
766             } else if (param->reg.app_id >= ESP_GATT_UUID_HID_SVC && param->reg.app_id < (ESP_GATT_UUID_HID_SVC + s_dev->devices_len)) {
767                 ESP_LOGV(TAG, "HID SVC[%u] IF: %d", param->reg.app_id - ESP_GATT_UUID_HID_SVC, gatts_if);
768                 s_dev->devices[param->reg.app_id - ESP_GATT_UUID_HID_SVC].hid_svc.gatt_if = gatts_if;
769             } else {
770                 ESP_LOGE(TAG, "Unknown Application, app_id %04x", param->reg.app_id);
771                 return;
772             }
773         }
774     } else if (event == ESP_GATTS_CREAT_ATTR_TAB_EVT) {
775         free(_last_db);
776         _last_db = NULL;
777     }
778 
779     if (s_dev->bat_svc.gatt_if && gatts_if == s_dev->bat_svc.gatt_if) {
780         bat_event_handler(s_dev, event, gatts_if, param);
781     } else if (s_dev->info_svc.gatt_if && gatts_if == s_dev->info_svc.gatt_if) {
782         info_event_handler(s_dev, event, gatts_if, param);
783     } else {
784         int devi = get_device_map_index_by_gatts_if (s_dev, gatts_if);
785         if (devi >= 0) {
786             hid_event_handler(s_dev, devi, event, gatts_if, param);
787         } else {
788             ESP_LOGE(TAG, "Unknown gatts_if %u", gatts_if);
789         }
790         return;
791     }
792 }
793 
esp_ble_hidd_dev_deinit(void * devp)794 static esp_err_t esp_ble_hidd_dev_deinit(void *devp)
795 {
796     esp_ble_hidd_dev_t *dev = (esp_ble_hidd_dev_t *)devp;
797     if (!s_dev) {
798         ESP_LOGE(TAG, "HID device profile already uninitialized");
799         return ESP_OK;
800     }
801 
802     if (s_dev != dev) {
803         ESP_LOGE(TAG, "Wrong HID device provided");
804         return ESP_FAIL;
805     }
806     s_dev = NULL;
807 
808     ble_hid_stop_gatts(dev);
809     esp_event_post_to(dev->event_loop_handle, ESP_HIDD_EVENTS, ESP_HIDD_STOP_EVENT, NULL, 0, portMAX_DELAY);
810     ble_hid_free_config(dev);
811     free(dev);
812     return ESP_OK;
813 }
814 
esp_ble_hidd_dev_connected(void * devp)815 static bool esp_ble_hidd_dev_connected(void *devp)
816 {
817     esp_ble_hidd_dev_t *dev = (esp_ble_hidd_dev_t *)devp;
818     return (dev != NULL && s_dev == dev && dev->connected);
819 }
820 
esp_ble_hidd_dev_battery_set(void * devp,uint8_t level)821 static esp_err_t esp_ble_hidd_dev_battery_set(void *devp, uint8_t level)
822 {
823     esp_err_t ret;
824     esp_ble_hidd_dev_t *dev = (esp_ble_hidd_dev_t *)devp;
825     if (!dev || s_dev != dev) {
826         return ESP_FAIL;
827     }
828     dev->bat_level = level;
829 
830     if (!dev->connected || dev->bat_ccc.value == 0) {
831         //if we are not yet connected, that is not an error
832         return ESP_OK;
833     }
834 
835     ret = esp_ble_gatts_send_indicate(dev->bat_svc.gatt_if, dev->conn_id, dev->bat_level_handle, 1, &dev->bat_level, dev->bat_ccc.indicate_enable);
836     if (ret) {
837         ESP_LOGE(TAG, "esp_ble_gatts_send_indicate failed: %d", ret);
838         return ESP_FAIL;
839     }
840     WAIT_CB(dev);
841     return ESP_OK;
842 }
843 
esp_ble_hidd_dev_input_set(void * devp,size_t index,size_t id,uint8_t * data,size_t length)844 static esp_err_t esp_ble_hidd_dev_input_set(void *devp, size_t index, size_t id, uint8_t *data, size_t length)
845 {
846     hidd_le_report_item_t *p_rpt;
847     esp_ble_hidd_dev_t *dev = (esp_ble_hidd_dev_t *)devp;
848     if (!dev || s_dev != dev) {
849         return ESP_FAIL;
850     }
851 
852     if (!dev->connected) {
853         ESP_LOGE(TAG, "%s Device Not Connected", __func__);
854         return ESP_FAIL;
855     }
856 
857     if (index >= dev->devices_len) {
858         ESP_LOGE(TAG, "%s index out of range[0-%d]", __func__, dev->devices_len - 1);
859         return ESP_FAIL;
860     }
861 
862     if ((p_rpt = get_report_by_id_and_type(dev, id, ESP_HID_REPORT_TYPE_INPUT)) != NULL && p_rpt->ccc.value) {
863         esp_err_t err = esp_ble_gatts_send_indicate(dev->devices[index].hid_svc.gatt_if, dev->conn_id, p_rpt->handle, length, data, p_rpt->ccc.indicate_enable);
864         if (err != ESP_OK) {
865             ESP_LOGE(TAG, "Send Input Indicate Failed: %d", err);
866             return ESP_FAIL;
867         }
868         WAIT_CB(dev);
869     } else {
870         ESP_LOGE(TAG, "Indicate Not Enabled: %d", 0);
871         return ESP_FAIL;
872     }
873     return ESP_OK;
874 }
875 
esp_ble_hidd_dev_feature_set(void * devp,size_t index,size_t id,uint8_t * data,size_t length)876 static esp_err_t esp_ble_hidd_dev_feature_set(void *devp, size_t index, size_t id, uint8_t *data, size_t length)
877 {
878     esp_err_t ret;
879     esp_ble_hidd_dev_t *dev = (esp_ble_hidd_dev_t *)devp;
880     if (!dev || s_dev != dev) {
881         return ESP_FAIL;
882     }
883 
884     if (!dev->connected) {
885         ESP_LOGE(TAG, "%s Device Not Connected", __func__);
886         return ESP_FAIL;
887     }
888 
889     if (index >= dev->devices_len) {
890         ESP_LOGE(TAG, "%s index out of range[0-%d]", __func__, dev->devices_len - 1);
891         return ESP_FAIL;
892     }
893 
894     hidd_le_report_item_t *p_rpt;
895     if ((p_rpt = get_report_by_id_and_type(dev, id, ESP_HID_REPORT_TYPE_FEATURE)) != NULL) {
896         ret = esp_ble_gatts_set_attr_value(p_rpt->handle, length, data);
897         if (ret) {
898             ESP_LOGE(TAG, "esp_ble_gatts_set_attr_value failed: %d", ret);
899             return ESP_FAIL;
900         }
901         WAIT_CB(dev);
902         if (dev->connected && p_rpt->ccc.value) {
903             ret = esp_ble_gatts_send_indicate(dev->devices[index].hid_svc.gatt_if, dev->conn_id, p_rpt->handle, length, data, p_rpt->ccc.indicate_enable);
904             if (ret != ESP_OK) {
905                 ESP_LOGE(TAG, "Send Feature Indicate Failed: %d", ret);
906                 return ESP_FAIL;
907             }
908             WAIT_CB(dev);
909         }
910     } else {
911         ESP_LOGE(TAG, "FEATURE %d not found", id);
912         return ESP_FAIL;
913     }
914     return ESP_OK;
915 }
916 
esp_ble_hidd_dev_event_handler_register(void * devp,esp_event_handler_t callback,esp_hidd_event_t event)917 static esp_err_t esp_ble_hidd_dev_event_handler_register(void *devp, esp_event_handler_t callback, esp_hidd_event_t event)
918 {
919     esp_ble_hidd_dev_t *dev = (esp_ble_hidd_dev_t *)devp;
920     if (!dev || s_dev != dev) {
921         return ESP_FAIL;
922     }
923     return esp_event_handler_register_with(dev->event_loop_handle, ESP_HIDD_EVENTS, event, callback, dev->dev);
924 }
925 
esp_ble_hidd_dev_event_handler_unregister(void * devp,esp_event_handler_t callback,esp_hidd_event_t event)926 static esp_err_t esp_ble_hidd_dev_event_handler_unregister(void *devp, esp_event_handler_t callback, esp_hidd_event_t event)
927 {
928     esp_ble_hidd_dev_t *dev = (esp_ble_hidd_dev_t *)devp;
929     if (!dev || s_dev != dev) {
930         return ESP_FAIL;
931     }
932     return esp_event_handler_unregister_with(dev->event_loop_handle, ESP_HIDD_EVENTS, event, callback);
933 }
934 
ble_hidd_dev_free(void)935 static void ble_hidd_dev_free(void)
936 {
937     if (s_dev) {
938         ble_hid_free_config(s_dev);
939         free(s_dev);
940         s_dev = NULL;
941     }
942 }
943 
esp_ble_hidd_dev_init(esp_hidd_dev_t * dev_p,const esp_hid_device_config_t * config,esp_event_handler_t callback)944 esp_err_t esp_ble_hidd_dev_init(esp_hidd_dev_t *dev_p, const esp_hid_device_config_t *config, esp_event_handler_t callback)
945 {
946     esp_err_t ret;
947 
948     if (s_dev) {
949         ESP_LOGE(TAG, "HID device profile already initialized");
950         return ESP_FAIL;
951     }
952 
953     s_dev = (esp_ble_hidd_dev_t *)calloc(1, sizeof(esp_ble_hidd_dev_t));
954     if (s_dev == NULL) {
955         ESP_LOGE(TAG, "HID device could not be allocated");
956         return ESP_FAIL;
957     }
958 
959     // Reset the hid device target environment
960     s_dev->bat_level = 100;
961     s_dev->bat_ccc.value = 0;
962     s_dev->control = ESP_HID_CONTROL_EXIT_SUSPEND;
963     s_dev->protocol = ESP_HID_PROTOCOL_MODE_REPORT;
964     s_dev->event_loop_handle = NULL;
965     s_dev->dev = dev_p;
966     s_dev->sem = xSemaphoreCreateBinary();
967     if (s_dev->sem == NULL) {
968         ESP_LOGE(TAG, "HID device semaphore could not be allocated");
969         ble_hidd_dev_free();
970         return ESP_FAIL;
971     }
972 
973 
974     esp_event_loop_args_t event_task_args = {
975         .queue_size = 5,
976         .task_name = "ble_hidd_events",
977         .task_priority = uxTaskPriorityGet(NULL),
978         .task_stack_size = 2048,
979         .task_core_id = tskNO_AFFINITY
980     };
981     ret = esp_event_loop_create(&event_task_args, &s_dev->event_loop_handle);
982     if (ret != ESP_OK) {
983         ESP_LOGE(TAG, "HID device event loop could not be created");
984         ble_hidd_dev_free();
985         return ret;
986     }
987 
988     ret = ble_hid_init_config(s_dev, config);
989     if (ret != ESP_OK) {
990         ble_hidd_dev_free();
991         return ret;
992     }
993 
994     dev_p->dev = s_dev;
995     dev_p->connected = esp_ble_hidd_dev_connected;
996     dev_p->deinit = esp_ble_hidd_dev_deinit;
997     dev_p->battery_set = esp_ble_hidd_dev_battery_set;
998     dev_p->input_set = esp_ble_hidd_dev_input_set;
999     dev_p->feature_set = esp_ble_hidd_dev_feature_set;
1000     dev_p->event_handler_register = esp_ble_hidd_dev_event_handler_register;
1001     dev_p->event_handler_unregister = esp_ble_hidd_dev_event_handler_unregister;
1002 
1003     ret = esp_ble_hidd_dev_event_handler_register(s_dev, esp_hidd_process_event_data_handler, ESP_EVENT_ANY_ID);
1004     if (ret != ESP_OK) {
1005         ble_hidd_dev_free();
1006         return ret;
1007     }
1008 
1009     if (callback != NULL) {
1010         ret = esp_ble_hidd_dev_event_handler_register(s_dev, callback, ESP_EVENT_ANY_ID);
1011         if (ret != ESP_OK) {
1012             ble_hidd_dev_free();
1013             return ret;
1014         }
1015     }
1016 
1017     ret = ble_hid_start_gatts(s_dev);
1018     if (ret != ESP_OK) {
1019         ble_hidd_dev_free();
1020         return ret;
1021     }
1022 
1023     return ret;
1024 }
1025 
1026 #endif /* CONFIG_GATTS_ENABLE */
1027