xref: /btstack/src/ble/gatt-service/hids_client.c (revision be78df3b6c7394390fa6d2bc04f991dd7ac2de2c)
1 /*
2  * Copyright (C) 2021 BlueKitchen GmbH
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  *
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. Neither the name of the copyright holders nor the names of
14  *    contributors may be used to endorse or promote products derived
15  *    from this software without specific prior written permission.
16  * 4. Any redistribution, use, or modification is done solely for
17  *    personal benefit and not for any commercial purpose or for
18  *    monetary gain.
19  *
20  * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS
21  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BLUEKITCHEN
24  * GMBH OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
27  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
28  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
30  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  *
33  * Please inquire about commercial licensing options at
34  * [email protected]
35  *
36  */
37 
38 #define BTSTACK_FILE__ "hids_client.c"
39 
40 #include "btstack_config.h"
41 
42 #ifdef ENABLE_TESTING_SUPPORT
43 #include <stdio.h>
44 #endif
45 
46 #include <stdint.h>
47 #include <string.h>
48 
49 #include "ble/gatt-service/hids_client.h"
50 
51 #include "btstack_memory.h"
52 #include "ble/core.h"
53 #include "ble/gatt_client.h"
54 #include "bluetooth_gatt.h"
55 #include "btstack_debug.h"
56 #include "btstack_event.h"
57 #include "btstack_run_loop.h"
58 #include "gap.h"
59 
60 #define HID_REPORT_MODE_REPORT_ID               3
61 #define HID_REPORT_MODE_REPORT_MAP_ID           4
62 #define HID_REPORT_MODE_HID_INFORMATION_ID      5
63 #define HID_REPORT_MODE_HID_CONTROL_POINT_ID    6
64 
65 static btstack_linked_list_t clients;
66 static uint16_t hids_cid_counter = 0;
67 
68 static uint8_t * hids_client_descriptor_storage;
69 static uint16_t  hids_client_descriptor_storage_len;
70 
71 static void handle_gatt_client_event(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size);
72 static void hids_client_handle_can_write_without_reponse(void * context);
73 
74 #ifdef ENABLE_TESTING_SUPPORT
75 static char * hid_characteristic_name(uint16_t uuid){
76     switch (uuid){
77         case ORG_BLUETOOTH_CHARACTERISTIC_PROTOCOL_MODE:
78             return "PROTOCOL_MODE";
79 
80         case ORG_BLUETOOTH_CHARACTERISTIC_BOOT_KEYBOARD_INPUT_REPORT:
81             return "BOOT_KEYBOARD_INPUT_REPORT";
82 
83         case ORG_BLUETOOTH_CHARACTERISTIC_BOOT_MOUSE_INPUT_REPORT:
84             return "BOOT_MOUSE_INPUT_REPORT";
85 
86         case ORG_BLUETOOTH_CHARACTERISTIC_BOOT_KEYBOARD_OUTPUT_REPORT:
87             return "BOOT_KEYBOARD_OUTPUT_REPORT";
88 
89         case ORG_BLUETOOTH_CHARACTERISTIC_REPORT:
90             return "REPORT";
91 
92         case ORG_BLUETOOTH_CHARACTERISTIC_REPORT_MAP:
93             return "REPORT_MAP";
94 
95         case ORG_BLUETOOTH_CHARACTERISTIC_HID_INFORMATION:
96             return "HID_INFORMATION";
97 
98         case ORG_BLUETOOTH_CHARACTERISTIC_HID_CONTROL_POINT:
99             return "HID_CONTROL_POINT";
100         default:
101             return "UKNOWN";
102     }
103 }
104 #endif
105 
106 static hids_client_t * hids_get_client_for_con_handle(hci_con_handle_t con_handle){
107     btstack_linked_list_iterator_t it;
108     btstack_linked_list_iterator_init(&it, &clients);
109     while (btstack_linked_list_iterator_has_next(&it)){
110         hids_client_t * client = (hids_client_t *)btstack_linked_list_iterator_next(&it);
111         if (client->con_handle != con_handle) continue;
112         return client;
113     }
114     return NULL;
115 }
116 
117 static hids_client_t * hids_get_client_for_cid(uint16_t hids_cid){
118     btstack_linked_list_iterator_t it;
119     btstack_linked_list_iterator_init(&it, &clients);
120     while (btstack_linked_list_iterator_has_next(&it)){
121         hids_client_t * client = (hids_client_t *)btstack_linked_list_iterator_next(&it);
122         if (client->cid != hids_cid) continue;
123         return client;
124     }
125     return NULL;
126 }
127 
128 
129 // START Descriptor Storage Util
130 
131 static uint16_t hids_client_descriptors_len(hids_client_t * client){
132     uint16_t descriptors_len = 0;
133     uint8_t service_index;
134     for (service_index = 0; service_index < client->num_instances; service_index++){
135         descriptors_len += client->services[service_index].hid_descriptor_len;
136     }
137     return descriptors_len;
138 }
139 
140 static uint16_t hids_client_descriptor_storage_get_available_space(void){
141     // assumes all descriptors are back to back
142     uint16_t free_space = hids_client_descriptor_storage_len;
143     btstack_linked_list_iterator_t it;
144     btstack_linked_list_iterator_init(&it, &clients);
145     while (btstack_linked_list_iterator_has_next(&it)){
146         hids_client_t * client = (hids_client_t *)btstack_linked_list_iterator_next(&it);
147         free_space -= hids_client_descriptors_len(client);
148     }
149     return free_space;
150 }
151 
152 static void hids_client_descriptor_storage_init(hids_client_t * client, uint8_t service_index){
153     // reserve remaining space for this connection
154     uint16_t available_space = hids_client_descriptor_storage_get_available_space();
155     client->services[service_index].hid_descriptor_len = 0;
156     client->services[service_index].hid_descriptor_max_len = available_space;
157     client->services[service_index].hid_descriptor_offset = hids_client_descriptor_storage_len - available_space;
158 }
159 
160 static bool hids_client_descriptor_storage_store(hids_client_t * client, uint8_t service_index, uint8_t byte){
161     // store single hid descriptor byte
162     if (client->services[service_index].hid_descriptor_len >= client->services[service_index].hid_descriptor_max_len) return false;
163 
164     hids_client_descriptor_storage[client->services[service_index].hid_descriptor_offset + client->services[service_index].hid_descriptor_len] = byte;
165     client->services[service_index].hid_descriptor_len++;
166     return true;
167 }
168 
169 static void hids_client_descriptor_storage_delete(hids_client_t * client){
170     uint8_t service_index;
171 
172     // calculate descriptors len
173     uint16_t descriptors_len = hids_client_descriptors_len(client);
174 
175     if (descriptors_len > 0){
176         // move higher descriptors down
177         uint16_t next_offset = client->services[0].hid_descriptor_offset + descriptors_len;
178         memmove(&hids_client_descriptor_storage[client->services[0].hid_descriptor_offset],
179                 &hids_client_descriptor_storage[next_offset],
180                 hids_client_descriptor_storage_len - next_offset);
181 
182         // fix descriptor offset of higher descriptors
183         btstack_linked_list_iterator_t it;
184         btstack_linked_list_iterator_init(&it, &clients);
185         while (btstack_linked_list_iterator_has_next(&it)){
186             hids_client_t * conn = (hids_client_t *)btstack_linked_list_iterator_next(&it);
187             if (conn == client) continue;
188             for (service_index = 0; service_index < client->num_instances; service_index++){
189                 if (conn->services[service_index].hid_descriptor_offset >= next_offset){
190                     conn->services[service_index].hid_descriptor_offset -= descriptors_len;
191                 }
192             }
193         }
194     }
195 
196     // clear descriptors
197     for (service_index = 0; service_index < client->num_instances; service_index++){
198         client->services[service_index].hid_descriptor_len = 0;
199         client->services[service_index].hid_descriptor_offset = 0;
200     }
201 }
202 
203 const uint8_t * hids_client_descriptor_storage_get_descriptor_data(uint16_t hids_cid, uint8_t service_index){
204     hids_client_t * client = hids_get_client_for_cid(hids_cid);
205     if (client == NULL){
206         return NULL;
207     }
208     if (service_index >= client->num_instances){
209         return NULL;
210     }
211     return &hids_client_descriptor_storage[client->services[service_index].hid_descriptor_offset];
212 }
213 
214 uint16_t hids_client_descriptor_storage_get_descriptor_len(uint16_t hids_cid, uint8_t service_index){
215     hids_client_t * client = hids_get_client_for_cid(hids_cid);
216     if (client == NULL){
217         return 0;
218     }
219     if (service_index >= client->num_instances){
220         return 0;
221     }
222     return client->services[service_index].hid_descriptor_len;
223 }
224 
225 // END Descriptor Storage Util
226 
227 static uint16_t hids_get_next_cid(void){
228     if (hids_cid_counter == 0xffff) {
229         hids_cid_counter = 1;
230     } else {
231         hids_cid_counter++;
232     }
233     return hids_cid_counter;
234 }
235 
236 static uint8_t find_report_index_for_value_handle(hids_client_t * client, uint16_t value_handle){
237     uint8_t i;
238     for (i = 0; i < client->num_reports; i++){
239         if (client->reports[i].value_handle == value_handle){
240             return i;
241         }
242     }
243     return HIDS_CLIENT_INVALID_REPORT_INDEX;
244 }
245 
246 static uint8_t find_external_report_index_for_value_handle(hids_client_t * client, uint16_t value_handle){
247     uint8_t i;
248     for (i = 0; i < client->num_external_reports; i++){
249         if (client->external_reports[i].value_handle == value_handle){
250             return i;
251         }
252     }
253     return HIDS_CLIENT_INVALID_REPORT_INDEX;
254 }
255 
256 static bool external_report_index_for_uuid_exists(hids_client_t * client, uint16_t uuid16){
257     uint8_t i;
258     for (i = 0; i < client->num_external_reports; i++){
259         if (client->external_reports[i].external_report_reference_uuid == uuid16){
260             return true;
261         }
262     }
263     return false;
264 }
265 
266 static uint8_t find_report_index_for_report_id_and_report_type(hids_client_t * client, uint8_t report_id, hid_report_type_t report_type){
267     uint8_t i;
268 
269     for (i = 0; i < client->num_reports; i++){
270         hids_client_report_t report = client->reports[i];
271         hid_protocol_mode_t  protocol_mode = client->services[report.service_index].protocol_mode;
272 
273         if (protocol_mode == HID_PROTOCOL_MODE_BOOT){
274             if (!client->reports[i].boot_report){
275                 continue;
276             }
277         } else if (protocol_mode == HID_PROTOCOL_MODE_REPORT){
278             if (client->reports[i].boot_report){
279                 continue;
280             }
281         }
282 
283         if (report.report_id == report_id && report.report_type == report_type){
284             return i;
285         }
286     }
287     return HIDS_CLIENT_INVALID_REPORT_INDEX;
288 }
289 
290 static uint8_t hids_client_add_characteristic(hids_client_t * client, gatt_client_characteristic_t * characteristic, uint8_t report_id, hid_report_type_t report_type, bool boot_report){
291 
292     uint8_t report_index = find_external_report_index_for_value_handle(client, characteristic->value_handle);
293     if (report_index != HIDS_CLIENT_INVALID_REPORT_INDEX){
294         return report_index;
295     }
296     report_index = client->num_reports;
297 
298     if (report_index < HIDS_CLIENT_NUM_REPORTS) {
299         client->reports[report_index].value_handle = characteristic->value_handle;
300         client->reports[report_index].end_handle = characteristic->end_handle;
301         client->reports[report_index].properties = characteristic->properties;
302 
303         client->reports[report_index].service_index = client->service_index;
304         client->reports[report_index].report_id = report_id;
305         client->reports[report_index].report_type = report_type;
306         client->reports[report_index].boot_report = boot_report;
307 
308         log_info("add index %d, id %d, type %d, value handle 0x%02x, properties 0x%02x", report_index, report_id, report_type, characteristic->value_handle, characteristic->properties);
309         client->num_reports++;
310         return report_index;
311     } else {
312         log_info("not enough storage, increase HIDS_CLIENT_NUM_REPORTS");
313         return HIDS_CLIENT_INVALID_REPORT_INDEX;
314     }
315 }
316 
317 static uint8_t hids_client_add_external_report(hids_client_t * client, gatt_client_characteristic_descriptor_t * characteristic_descriptor){
318     uint8_t report_index = client->num_external_reports;
319 
320     if (report_index < HIDS_CLIENT_NUM_REPORTS) {
321         client->external_reports[report_index].value_handle = characteristic_descriptor->handle;
322         client->external_reports[report_index].service_index = client->service_index;
323 
324         client->num_external_reports++;
325         log_info("add external index %d [%d], value handle 0x%02x", report_index, client->num_external_reports, characteristic_descriptor->handle);
326         return report_index;
327     } else {
328         log_info("not enough storage, increase HIDS_CLIENT_NUM_REPORTS");
329         return HIDS_CLIENT_INVALID_REPORT_INDEX;
330     }
331 }
332 
333 static uint8_t hids_client_get_next_active_report_map_index(hids_client_t * client){
334     uint8_t i;
335     for (i = client->service_index; i < client->num_instances; i++){
336         if (client->services[i].report_map_value_handle != 0){
337             return i;
338         }
339     }
340     client->service_index = HIDS_CLIENT_INVALID_REPORT_INDEX;
341     return HIDS_CLIENT_INVALID_REPORT_INDEX;
342 }
343 
344 static bool hids_client_report_query_next_report_map(hids_client_t * client){
345     client->service_index++;
346     if (hids_client_get_next_active_report_map_index(client) != HIDS_CLIENT_INVALID_REPORT_INDEX){
347         client->state = HIDS_CLIENT_STATE_W2_READ_REPORT_MAP_HID_DESCRIPTOR;
348         return true;
349     }
350     return false;
351 }
352 
353 static bool hids_client_report_map_query_init(hids_client_t * client){
354     client->service_index = 0;
355 
356     if (hids_client_get_next_active_report_map_index(client) != HIDS_CLIENT_INVALID_REPORT_INDEX){
357         client->state = HIDS_CLIENT_STATE_W2_READ_REPORT_MAP_HID_DESCRIPTOR;
358         return true;
359     }
360     return false;
361 }
362 
363 static bool hids_client_report_query_next_report_map_uuid(hids_client_t * client){
364     client->report_index++;
365     if (client->report_index < client->num_external_reports){
366         client->state = HIDS_CLIENT_STATE_W2_REPORT_MAP_READ_EXTERNAL_REPORT_REFERENCE_UUID;
367         return true;
368     }
369     return false;
370 }
371 
372 static bool hids_client_report_map_uuid_query_init(hids_client_t * client){
373     client->report_index = 0;
374     if (client->num_external_reports > 0){
375         client->state = HIDS_CLIENT_STATE_W2_REPORT_MAP_READ_EXTERNAL_REPORT_REFERENCE_UUID;
376         return true;
377     }
378     return false;
379 }
380 
381 static uint8_t hids_client_get_next_report_index(hids_client_t * client){
382     uint8_t i;
383     uint8_t index = HIDS_CLIENT_INVALID_REPORT_INDEX;
384 
385     for (i = client->report_index; i < client->num_reports && (index == HIDS_CLIENT_INVALID_REPORT_INDEX); i++){
386         hids_client_report_t report = client->reports[i];
387         if (!report.boot_report){
388             if (report.report_type == HID_REPORT_TYPE_RESERVED && report.report_id == HID_REPORT_MODE_REPORT_ID){
389                 index = i;
390                 client->service_index = report.service_index;
391                 break;
392             }
393         }
394     }
395     client->report_index = index;
396     return index;
397 }
398 
399 static bool hids_client_report_query_next_report(hids_client_t * client){
400     client->report_index++;
401     if (hids_client_get_next_report_index(client) != HIDS_CLIENT_INVALID_REPORT_INDEX){
402         client->state = HIDS_CLIENT_STATE_W2_FIND_REPORT;
403         return true;
404     }
405     return false;
406 }
407 
408 static bool hids_client_report_query_init(hids_client_t * client){
409     client->report_index = 0;
410 
411     if (hids_client_get_next_report_index(client) != HIDS_CLIENT_INVALID_REPORT_INDEX){
412         client->state = HIDS_CLIENT_STATE_W2_FIND_REPORT;
413         return true;
414     }
415     return false;
416 }
417 
418 static uint8_t hids_client_get_next_notification_report_index(hids_client_t * client){
419     uint8_t i;
420     uint8_t index = HIDS_CLIENT_INVALID_REPORT_INDEX;
421 
422     for (i = client->report_index; i < client->num_reports && (index == HIDS_CLIENT_INVALID_REPORT_INDEX); i++){
423         hids_client_report_t report = client->reports[i];
424         hid_protocol_mode_t  protocol_mode = client->services[report.service_index].protocol_mode;
425 
426         if (protocol_mode == HID_PROTOCOL_MODE_BOOT){
427             if (!client->reports[i].boot_report){
428                 continue;
429             }
430         } else if (protocol_mode == HID_PROTOCOL_MODE_REPORT){
431             if (client->reports[i].boot_report){
432                 continue;
433             }
434         }
435         if (report.report_type == HID_REPORT_TYPE_INPUT){
436             index = i;
437         }
438     }
439     client->report_index = index;
440     return index;
441 }
442 
443 static bool hids_client_report_next_notification_report_index(hids_client_t * client){
444     client->report_index++;
445     if (hids_client_get_next_notification_report_index(client) != HIDS_CLIENT_INVALID_REPORT_INDEX){
446         client->state = HIDS_CLIENT_STATE_W2_ENABLE_INPUT_REPORTS;
447         return true;
448     }
449     return false;
450 }
451 
452 static bool hids_client_report_notifications_init(hids_client_t * client){
453 #ifdef ENABLE_TESTING_SUPPORT
454     printf("\nRegister for Notifications: \n");
455 #endif
456     client->report_index = 0;
457 
458     if (hids_client_get_next_notification_report_index(client) != HIDS_CLIENT_INVALID_REPORT_INDEX){
459         client->state = HIDS_CLIENT_STATE_W2_ENABLE_INPUT_REPORTS;
460         return true;
461     }
462     return false;
463 }
464 
465 static bool hids_client_report_next_notifications_configuration_report_index(hids_client_t * client){
466     client->report_index++;
467     if (hids_client_get_next_notification_report_index(client) != HIDS_CLIENT_INVALID_REPORT_INDEX){
468         client->state = HIDS_CLIENT_STATE_W2_CONFIGURE_NOTIFICATIONS;
469         return true;
470     }
471     return false;
472 }
473 
474 static bool hids_client_notifications_configuration_init(hids_client_t * client){
475 #ifdef ENABLE_TESTING_SUPPORT
476     printf("\nConfigure for Notifications: \n");
477 #endif
478     client->report_index = 0;
479 
480     if (hids_client_get_next_notification_report_index(client) != HIDS_CLIENT_INVALID_REPORT_INDEX){
481         client->state = HIDS_CLIENT_STATE_W2_CONFIGURE_NOTIFICATIONS;
482         return true;
483     }
484     return false;
485 }
486 
487 static hids_client_t * hids_create_client(hci_con_handle_t con_handle, uint16_t cid){
488     hids_client_t * client = btstack_memory_hids_client_get();
489     if (!client){
490         log_error("Not enough memory to create client");
491         return NULL;
492     }
493     client->state = HIDS_CLIENT_STATE_IDLE;
494     client->cid = cid;
495     client->con_handle = con_handle;
496 
497     btstack_linked_list_add(&clients, (btstack_linked_item_t *) client);
498     return client;
499 }
500 
501 static void hids_finalize_client(hids_client_t * client){
502     // stop listening
503     uint8_t i;
504     for (i = 0; i < client->num_reports; i++){
505         gatt_client_stop_listening_for_characteristic_value_updates(&client->reports[i].notification_listener);
506     }
507 
508     hids_client_descriptor_storage_delete(client);
509     btstack_linked_list_remove(&clients, (btstack_linked_item_t *) client);
510     btstack_memory_hids_client_free(client);
511 }
512 
513 
514 static void hids_emit_connection_established(hids_client_t * client, uint8_t status){
515     uint8_t event[8];
516     int pos = 0;
517     event[pos++] = HCI_EVENT_GATTSERVICE_META;
518     event[pos++] = sizeof(event) - 2;
519     event[pos++] = GATTSERVICE_SUBEVENT_HID_SERVICE_CONNECTED;
520     little_endian_store_16(event, pos, client->cid);
521     pos += 2;
522     event[pos++] = status;
523     event[pos++] = client->services[0].protocol_mode;
524     event[pos++] = client->num_instances;
525     (*client->client_handler)(HCI_EVENT_PACKET, 0, event, sizeof(event));
526 }
527 
528 static void hids_emit_notifications_configuration(hids_client_t * client){
529     uint8_t event[6];
530     int pos = 0;
531     event[pos++] = HCI_EVENT_GATTSERVICE_META;
532     event[pos++] = sizeof(event) - 2;
533     event[pos++] = GATTSERVICE_SUBEVENT_HID_SERVICE_REPORTS_NOTIFICATION;
534     little_endian_store_16(event, pos, client->cid);
535     pos += 2;
536     event[pos++] = client->value;
537     (*client->client_handler)(HCI_EVENT_PACKET, 0, event, sizeof(event));
538 }
539 
540 static uint16_t hids_client_setup_report_event(hids_client_t * client, uint8_t report_index, uint8_t *buffer, uint16_t report_len){
541     uint16_t pos = 0;
542     buffer[pos++] = HCI_EVENT_GATTSERVICE_META;
543     pos++;  // skip len
544     buffer[pos++] = GATTSERVICE_SUBEVENT_HID_REPORT;
545     little_endian_store_16(buffer, pos, client->cid);
546     pos += 2;
547     buffer[pos++] = client->reports[report_index].service_index;
548     buffer[pos++] = client->reports[report_index].report_id;
549     little_endian_store_16(buffer, pos, report_len);
550     pos += 2;
551     buffer[1] = pos + report_len - 2;
552     return pos;
553 }
554 
555 static void hids_client_setup_report_event_with_report_id(hids_client_t * client, uint8_t report_index, uint8_t *buffer, uint16_t report_len){
556     uint16_t pos = hids_client_setup_report_event(client, report_index, buffer, report_len + 1);
557     buffer[pos] = client->reports[report_index].report_id;
558 }
559 
560 static void hids_client_emit_hid_information_event(hids_client_t * client, const uint8_t *value, uint16_t value_len){
561     if (value_len != 4) return;
562 
563     uint8_t event[11];
564     int pos = 0;
565     event[pos++] = HCI_EVENT_GATTSERVICE_META;
566     event[pos++] = sizeof(event) - 2;
567     event[pos++] = GATTSERVICE_SUBEVENT_HID_INFORMATION;
568     little_endian_store_16(event, pos, client->cid);
569     pos += 2;
570     event[pos++] = client->service_index;
571 
572     memcpy(event+pos, value, 3);
573     pos += 3;
574     event[pos++] = (value[3] & 0x02) >> 1;
575     event[pos++] = value[3] & 0x01;
576 
577     (*client->client_handler)(HCI_EVENT_PACKET, 0, event, sizeof(event));
578 }
579 
580 static void hids_client_emit_protocol_mode_event(hids_client_t * client, const uint8_t *value, uint16_t value_len){
581     if (value_len != 1) return;
582 
583     uint8_t event[11];
584     int pos = 0;
585     event[pos++] = HCI_EVENT_GATTSERVICE_META;
586     event[pos++] = sizeof(event) - 2;
587     event[pos++] = GATTSERVICE_SUBEVENT_HID_PROTOCOL_MODE;
588     little_endian_store_16(event, pos, client->cid);
589     pos += 2;
590     event[pos++] = client->service_index;
591     event[pos++] = value[0];
592     (*client->client_handler)(HCI_EVENT_PACKET, 0, event, sizeof(event));
593 }
594 
595 static void handle_notification_event(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size) {
596     UNUSED(packet_type);
597     UNUSED(channel);
598 
599     if (hci_event_packet_get_type(packet) != GATT_EVENT_NOTIFICATION) return;
600 
601     hids_client_t * client = hids_get_client_for_con_handle(gatt_event_notification_get_handle(packet));
602     if (client == NULL) return;
603 
604     uint8_t report_index = find_report_index_for_value_handle(client, gatt_event_notification_get_value_handle(packet));
605     if (report_index == HIDS_CLIENT_INVALID_REPORT_INDEX){
606         return;
607     }
608 
609     uint8_t * in_place_event = &packet[-2];
610     hids_client_setup_report_event_with_report_id(client, report_index, in_place_event,
611                                                   gatt_event_notification_get_value_length(packet));
612     (*client->client_handler)(HCI_EVENT_GATTSERVICE_META, client->cid, in_place_event, size + 2);
613 }
614 
615 static void handle_report_event(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size) {
616     UNUSED(packet_type);
617     UNUSED(channel);
618 
619     if (hci_event_packet_get_type(packet) != GATT_EVENT_CHARACTERISTIC_VALUE_QUERY_RESULT) return;
620 
621     hids_client_t * client = hids_get_client_for_con_handle(gatt_event_characteristic_value_query_result_get_handle(packet));
622     if (client == NULL) return;
623 
624     if (client->state != HIDS_CLIENT_W4_GET_REPORT_RESULT){
625         return;
626     }
627     client->state = HIDS_CLIENT_STATE_CONNECTED;
628 
629     uint8_t report_index = find_report_index_for_value_handle(client, gatt_event_characteristic_value_query_result_get_value_handle(packet));
630     if (report_index == HIDS_CLIENT_INVALID_REPORT_INDEX){
631         return;
632     }
633 
634     uint8_t * in_place_event = &packet[-2];
635     hids_client_setup_report_event_with_report_id(client, report_index, in_place_event,
636                                                   gatt_event_characteristic_value_query_result_get_value_length(packet));
637     (*client->client_handler)(HCI_EVENT_GATTSERVICE_META, client->cid, in_place_event, size + 2);
638 }
639 
640 static void hids_run_for_client(hids_client_t * client){
641     uint8_t att_status;
642     gatt_client_service_t service;
643     gatt_client_characteristic_t characteristic;
644 
645     switch (client->state){
646         case HIDS_CLIENT_STATE_W2_QUERY_SERVICE:
647 #ifdef ENABLE_TESTING_SUPPORT
648             printf("\n\nQuery Services:\n");
649 #endif
650             client->state = HIDS_CLIENT_STATE_W4_SERVICE_RESULT;
651 
652             // result in GATT_EVENT_SERVICE_QUERY_RESULT
653             att_status = gatt_client_discover_primary_services_by_uuid16(handle_gatt_client_event, client->con_handle, ORG_BLUETOOTH_SERVICE_HUMAN_INTERFACE_DEVICE);
654             UNUSED(att_status);
655             break;
656 
657         case HIDS_CLIENT_STATE_W2_QUERY_CHARACTERISTIC:
658 #ifdef ENABLE_TESTING_SUPPORT
659             printf("\n\nQuery Characteristics of service %d:\n", client->service_index);
660 #endif
661             client->state = HIDS_CLIENT_STATE_W4_CHARACTERISTIC_RESULT;
662 
663             service.start_group_handle = client->services[client->service_index].start_handle;
664             service.end_group_handle = client->services[client->service_index].end_handle;
665 
666             // result in GATT_EVENT_CHARACTERISTIC_QUERY_RESULT
667             att_status = gatt_client_discover_characteristics_for_service(&handle_gatt_client_event, client->con_handle, &service);
668 
669             UNUSED(att_status);
670             break;
671 
672         case HIDS_CLIENT_STATE_W2_READ_REPORT_MAP_HID_DESCRIPTOR:
673 #ifdef ENABLE_TESTING_SUPPORT
674             printf("\n\nRead REPORT_MAP (Handle 0x%04X) HID Descriptor of service %d:\n", client->services[client->service_index].report_map_value_handle, client->service_index);
675 #endif
676             client->state = HIDS_CLIENT_STATE_W4_REPORT_MAP_HID_DESCRIPTOR;
677 
678             // result in GATT_EVENT_LONG_CHARACTERISTIC_VALUE_QUERY_RESULT
679             att_status = gatt_client_read_long_value_of_characteristic_using_value_handle(&handle_gatt_client_event, client->con_handle, client->services[client->service_index].report_map_value_handle);
680             UNUSED(att_status);
681             break;
682 
683         case HIDS_CLIENT_STATE_W2_REPORT_MAP_DISCOVER_CHARACTERISTIC_DESCRIPTORS:
684 #ifdef ENABLE_TESTING_SUPPORT
685             printf("\nDiscover REPORT_MAP (Handle 0x%04X) Characteristic Descriptors of service %d:\n", client->services[client->service_index].report_map_value_handle, client->service_index);
686 #endif
687             client->state = HIDS_CLIENT_STATE_W4_REPORT_MAP_CHARACTERISTIC_DESCRIPTORS_RESULT;
688 
689             characteristic.value_handle = client->services[client->service_index].report_map_value_handle;
690             characteristic.end_handle = client->services[client->service_index].report_map_end_handle;
691 
692             // result in GATT_EVENT_ALL_CHARACTERISTIC_DESCRIPTORS_QUERY_RESULT
693             att_status = gatt_client_discover_characteristic_descriptors(&handle_gatt_client_event, client->con_handle, &characteristic);
694             UNUSED(att_status);
695             break;
696 
697         case HIDS_CLIENT_STATE_W2_REPORT_MAP_READ_EXTERNAL_REPORT_REFERENCE_UUID:
698 #ifdef ENABLE_TESTING_SUPPORT
699             printf("\nRead external chr UUID (Handle 0x%04X) Characteristic Descriptors, service index %d:\n", client->external_reports[client->report_index].value_handle, client->service_index);
700 #endif
701             client->state = HIDS_CLIENT_STATE_W4_REPORT_MAP_EXTERNAL_REPORT_REFERENCE_UUID;
702 
703             // result in GATT_EVENT_CHARACTERISTIC_DESCRIPTOR_QUERY_RESULT
704             att_status = gatt_client_read_characteristic_descriptor_using_descriptor_handle(&handle_gatt_client_event, client->con_handle, client->external_reports[client->report_index].value_handle);
705             UNUSED(att_status);
706             break;
707 
708         case HIDS_CLIENT_STATE_W2_DISCOVER_EXTERNAL_REPORT_CHARACTERISTIC:
709  #ifdef ENABLE_TESTING_SUPPORT
710             printf("\nDiscover External Report Characteristic:\n");
711 #endif
712             client->state = HIDS_CLIENT_STATE_W4_EXTERNAL_REPORT_CHARACTERISTIC_RESULT;
713 
714             service.start_group_handle = 0x0001;
715             service.end_group_handle = 0xffff;
716 
717             // Result in GATT_EVENT_CHARACTERISTIC_QUERY_RESULT
718             att_status = gatt_client_discover_characteristics_for_service(&handle_gatt_client_event, client->con_handle, &service);
719             UNUSED(att_status);
720             break;
721 
722         case HIDS_CLIENT_STATE_W2_FIND_REPORT:
723 #ifdef ENABLE_TESTING_SUPPORT
724             printf("\nQuery Report Characteristic Descriptors [%d, %d, 0x%04X]:\n",
725                 client->report_index,
726                 client->reports[client->report_index].service_index,
727                 client->reports[client->report_index].value_handle);
728 #endif
729             client->state = HIDS_CLIENT_STATE_W4_REPORT_FOUND;
730             client->handle = 0;
731 
732             characteristic.value_handle = client->reports[client->report_index].value_handle;
733             characteristic.end_handle = client->reports[client->report_index].end_handle;
734             characteristic.properties = client->reports[client->report_index].properties;
735 
736             // result in GATT_EVENT_ALL_CHARACTERISTIC_DESCRIPTORS_QUERY_RESULT
737             att_status = gatt_client_discover_characteristic_descriptors(&handle_gatt_client_event, client->con_handle, &characteristic);
738             UNUSED(att_status);
739             break;
740 
741         case HIDS_CLIENT_STATE_W2_READ_REPORT_ID_AND_TYPE:
742             client->state = HIDS_CLIENT_STATE_W4_REPORT_ID_AND_TYPE;
743 
744             // result in GATT_EVENT_CHARACTERISTIC_DESCRIPTOR_QUERY_RESULT
745             att_status = gatt_client_read_characteristic_descriptor_using_descriptor_handle(&handle_gatt_client_event, client->con_handle, client->handle);
746             client->handle = 0;
747             UNUSED(att_status);
748             break;
749 
750         case HIDS_CLIENT_STATE_W2_CONFIGURE_NOTIFICATIONS:
751 #ifdef ENABLE_TESTING_SUPPORT
752             if (client->value > 0){
753                 printf("    Notification configuration enable ");
754             } else {
755                 printf("    Notification configuration disable ");
756             }
757             printf("[%d, %d, 0x%04X]:\n",
758                 client->report_index,
759                 client->reports[client->report_index].service_index, client->reports[client->report_index].value_handle);
760 #endif
761 
762             client->state = HIDS_CLIENT_STATE_W4_NOTIFICATIONS_CONFIGURED;
763 
764             characteristic.value_handle = client->reports[client->report_index].value_handle;
765             characteristic.end_handle = client->reports[client->report_index].end_handle;
766             characteristic.properties = client->reports[client->report_index].properties;
767 
768             // end of write marked in GATT_EVENT_QUERY_COMPLETE
769 
770             att_status = gatt_client_write_client_characteristic_configuration(&handle_gatt_client_event, client->con_handle, &characteristic, client->value);
771 
772             if (att_status == ERROR_CODE_SUCCESS){
773                 switch(client->value){
774                     case GATT_CLIENT_CHARACTERISTICS_CONFIGURATION_NOTIFICATION:
775                         gatt_client_listen_for_characteristic_value_updates(
776                             &client->reports[client->report_index].notification_listener,
777                             &handle_notification_event, client->con_handle, &characteristic);
778                         break;
779                     default:
780                         gatt_client_stop_listening_for_characteristic_value_updates(&client->reports[client->report_index].notification_listener);
781                         break;
782                 }
783             } else {
784                 if (hids_client_report_next_notifications_configuration_report_index(client)){
785                     hids_run_for_client(client);
786                     break;
787                 }
788                 client->state = HIDS_CLIENT_STATE_CONNECTED;
789             }
790             break;
791 
792         case HIDS_CLIENT_STATE_W2_ENABLE_INPUT_REPORTS:
793 #ifdef ENABLE_TESTING_SUPPORT
794             printf("    Notification enable [%d, %d, 0x%04X]:\n",
795                 client->report_index,
796                 client->reports[client->report_index].service_index, client->reports[client->report_index].value_handle);
797 #endif
798             client->state = HIDS_CLIENT_STATE_W4_INPUT_REPORTS_ENABLED;
799 
800             characteristic.value_handle = client->reports[client->report_index].value_handle;
801             characteristic.end_handle = client->reports[client->report_index].end_handle;
802             characteristic.properties = client->reports[client->report_index].properties;
803 
804             // end of write marked in GATT_EVENT_QUERY_COMPLETE
805             att_status = gatt_client_write_client_characteristic_configuration(&handle_gatt_client_event, client->con_handle, &characteristic, GATT_CLIENT_CHARACTERISTICS_CONFIGURATION_NOTIFICATION);
806 
807             if (att_status == ERROR_CODE_SUCCESS){
808                 gatt_client_listen_for_characteristic_value_updates(
809                     &client->reports[client->report_index].notification_listener,
810                     &handle_notification_event, client->con_handle, &characteristic);
811             } else {
812                 if (hids_client_report_next_notification_report_index(client)){
813                     hids_run_for_client(client);
814                     break;
815                 }
816                 client->state = HIDS_CLIENT_STATE_CONNECTED;
817                 hids_emit_connection_established(client, ERROR_CODE_SUCCESS);
818             }
819             break;
820 
821 
822         case HIDS_CLIENT_W2_SEND_WRITE_REPORT:
823 #ifdef ENABLE_TESTING_SUPPORT
824             printf("    Write report [%d, %d, 0x%04X]:\n",
825                 client->report_index,
826                 client->reports[client->report_index].service_index, client->reports[client->report_index].value_handle);
827 #endif
828 
829             client->state = HIDS_CLIENT_W4_WRITE_REPORT_DONE;
830 
831             // see GATT_EVENT_QUERY_COMPLETE for end of write
832             att_status = gatt_client_write_value_of_characteristic(
833                 &handle_gatt_client_event, client->con_handle,
834                 client->reports[client->report_index].value_handle,
835                 client->report_len, (uint8_t *)client->report);
836             UNUSED(att_status);
837             break;
838 
839         case HIDS_CLIENT_W2_SEND_GET_REPORT:
840 #ifdef ENABLE_TESTING_SUPPORT
841             printf("    Get report [index %d, ID %d, Service %d, handle 0x%04X]:\n",
842                 client->report_index,
843                 client->reports[client->report_index].report_id,
844                 client->reports[client->report_index].service_index, client->reports[client->report_index].value_handle);
845 #endif
846 
847             client->state = HIDS_CLIENT_W4_GET_REPORT_RESULT;
848             // result in GATT_EVENT_CHARACTERISTIC_VALUE_QUERY_RESULT
849             att_status = gatt_client_read_value_of_characteristic_using_value_handle(
850                 &handle_report_event,
851                 client->con_handle,
852                 client->reports[client->report_index].value_handle);
853             UNUSED(att_status);
854             break;
855 
856 #ifdef ENABLE_TESTING_SUPPORT
857         case HIDS_CLIENT_W2_READ_CHARACTERISTIC_CONFIGURATION:
858             client->state = HIDS_CLIENT_W4_CHARACTERISTIC_CONFIGURATION_RESULT;
859 
860             // result in GATT_EVENT_CHARACTERISTIC_VALUE_QUERY_RESULT
861             att_status = gatt_client_read_value_of_characteristic_using_value_handle(
862                 &handle_gatt_client_event,
863                 client->con_handle,
864                 client->reports[client->report_index].ccc_handle);
865 
866             break;
867 #endif
868         case HIDS_CLIENT_W2_READ_VALUE_OF_CHARACTERISTIC:
869             client->state = HIDS_CLIENT_W4_VALUE_OF_CHARACTERISTIC_RESULT;
870 
871             // result in GATT_EVENT_CHARACTERISTIC_VALUE_QUERY_RESULT
872             att_status = gatt_client_read_value_of_characteristic_using_value_handle(
873                 &handle_gatt_client_event,
874                 client->con_handle,
875                 client->handle);
876             break;
877 
878         case HIDS_CLIENT_STATE_W2_SET_PROTOCOL_MODE_WITHOUT_RESPONSE:
879         case HIDS_CLIENT_W2_WRITE_VALUE_OF_CHARACTERISTIC_WITHOUT_RESPONSE:
880             client->write_without_response_request.callback = &hids_client_handle_can_write_without_reponse;
881             client->write_without_response_request.context = client;
882             (void) gatt_client_request_to_write_without_response(&client->write_without_response_request, client->con_handle);
883             break;
884 
885         default:
886             break;
887     }
888 }
889 
890 static void hids_client_handle_can_write_without_reponse(void * context) {
891     hids_client_t *client = (hids_client_t *) context;
892     uint8_t att_status;
893     switch (client->state){
894         case HIDS_CLIENT_STATE_W2_SET_PROTOCOL_MODE_WITHOUT_RESPONSE:
895             att_status = gatt_client_write_value_of_characteristic_without_response(
896                 client->con_handle,
897                 client->services[client->service_index].protocol_mode_value_handle, 1, (uint8_t *)&client->required_protocol_mode);
898 
899 #ifdef ENABLE_TESTING_SUPPORT
900             printf("\n\nSet report mode %d of service %d, status 0x%02x", client->required_protocol_mode, client->service_index, att_status);
901 #endif
902 
903             if (att_status == ATT_ERROR_SUCCESS){
904                 client->services[client->service_index].protocol_mode = client->required_protocol_mode;
905                 if ((client->service_index + 1) < client->num_instances){
906                     client->service_index++;
907                     hids_run_for_client(client);
908                     break;
909                 }
910             }
911 
912             // read UUIDS for external characteristics
913             if (hids_client_report_map_uuid_query_init(client)){
914                 hids_run_for_client(client);
915                 break;
916             }
917 
918             // discover characteristic descriptor for all Report characteristics,
919             // then read value of characteristic descriptor to get Report ID
920             if (hids_client_report_query_init(client)){
921                 hids_run_for_client(client);
922                 break;
923             }
924 
925             client->state = HIDS_CLIENT_STATE_CONNECTED;
926             hids_emit_connection_established(client, ERROR_CODE_SUCCESS);
927             break;
928 
929         case HIDS_CLIENT_W2_WRITE_VALUE_OF_CHARACTERISTIC_WITHOUT_RESPONSE:
930 #ifdef ENABLE_TESTING_SUPPORT
931             printf("    Write characteristic [service %d, handle 0x%04X]:\n", client->service_index, client->handle);
932 #endif
933             client->state = HIDS_CLIENT_STATE_CONNECTED;
934             (void) gatt_client_write_value_of_characteristic_without_response(client->con_handle, client->handle, 1, (uint8_t *) &client->value);
935             break;
936 
937         default:
938             break;
939     }
940 }
941 
942 static void handle_gatt_client_event(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
943     UNUSED(packet_type);
944     UNUSED(channel);
945     UNUSED(size);
946 
947     hids_client_t * client = NULL;
948     uint8_t att_status;
949     gatt_client_service_t service;
950     gatt_client_characteristic_t characteristic;
951     gatt_client_characteristic_descriptor_t characteristic_descriptor;
952 
953     // hids_client_report_t * boot_keyboard_report;
954     // hids_client_report_t * boot_mouse_report;
955     const uint8_t * characteristic_descriptor_value;
956     uint8_t i;
957     uint8_t report_index;
958 
959     const uint8_t * value;
960     uint16_t value_len;
961 
962     switch(hci_event_packet_get_type(packet)){
963         case GATT_EVENT_SERVICE_QUERY_RESULT:
964             client = hids_get_client_for_con_handle(gatt_event_service_query_result_get_handle(packet));
965             if (client == NULL) break;
966 
967             if (client->num_instances < MAX_NUM_HID_SERVICES){
968                 uint8_t index = client->num_instances;
969                 gatt_event_service_query_result_get_service(packet, &service);
970                 client->services[index].start_handle = service.start_group_handle;
971                 client->services[index].end_handle = service.end_group_handle;
972                 client->num_instances++;
973 
974 #ifdef ENABLE_TESTING_SUPPORT
975                 printf("HID Service: start handle 0x%04X, end handle 0x%04X\n", client->services[index].start_handle, client->services[index].end_handle);
976 #endif
977                 hids_client_descriptor_storage_init(client, index);
978             }  else {
979                 log_info("%d hid services found, only first %d can be stored, increase MAX_NUM_HID_SERVICES", client->num_instances + 1, MAX_NUM_HID_SERVICES);
980             }
981             break;
982 
983         case GATT_EVENT_CHARACTERISTIC_QUERY_RESULT:
984             client = hids_get_client_for_con_handle(gatt_event_characteristic_query_result_get_handle(packet));
985             if (client == NULL) break;
986 
987             gatt_event_characteristic_query_result_get_characteristic(packet, &characteristic);
988 
989             report_index = HIDS_CLIENT_INVALID_REPORT_INDEX;
990             if (client->state == HIDS_CLIENT_STATE_W4_EXTERNAL_REPORT_CHARACTERISTIC_RESULT){
991                 if (!external_report_index_for_uuid_exists(client, characteristic.uuid16)){
992                     break;
993                 }
994             }
995 
996             switch (characteristic.uuid16){
997                 case ORG_BLUETOOTH_CHARACTERISTIC_PROTOCOL_MODE:
998                     client->services[client->service_index].protocol_mode_value_handle = characteristic.value_handle;
999                     break;
1000 
1001                 case ORG_BLUETOOTH_CHARACTERISTIC_BOOT_KEYBOARD_INPUT_REPORT:
1002                     report_index = hids_client_add_characteristic(client, &characteristic, HID_BOOT_MODE_KEYBOARD_ID, HID_REPORT_TYPE_INPUT, true);
1003                     break;
1004 
1005                 case ORG_BLUETOOTH_CHARACTERISTIC_BOOT_MOUSE_INPUT_REPORT:
1006                     report_index = hids_client_add_characteristic(client, &characteristic, HID_BOOT_MODE_MOUSE_ID, HID_REPORT_TYPE_INPUT, true);
1007                     break;
1008 
1009                 case ORG_BLUETOOTH_CHARACTERISTIC_BOOT_KEYBOARD_OUTPUT_REPORT:
1010                     report_index = hids_client_add_characteristic(client, &characteristic, HID_BOOT_MODE_KEYBOARD_ID, HID_REPORT_TYPE_OUTPUT, true);
1011                     break;
1012 
1013                 case ORG_BLUETOOTH_CHARACTERISTIC_REPORT:
1014                     report_index = hids_client_add_characteristic(client, &characteristic, HID_REPORT_MODE_REPORT_ID, HID_REPORT_TYPE_RESERVED, false);
1015                     break;
1016 
1017                 case ORG_BLUETOOTH_CHARACTERISTIC_REPORT_MAP:
1018                     client->services[client->service_index].report_map_value_handle = characteristic.value_handle;
1019                     client->services[client->service_index].report_map_end_handle = characteristic.end_handle;
1020                     break;
1021 
1022                 case ORG_BLUETOOTH_CHARACTERISTIC_HID_INFORMATION:
1023                     client->services[client->service_index].hid_information_value_handle = characteristic.value_handle;
1024                     break;
1025 
1026                 case ORG_BLUETOOTH_CHARACTERISTIC_HID_CONTROL_POINT:
1027                     client->services[client->service_index].control_point_value_handle = characteristic.value_handle;
1028                     break;
1029 
1030                 default:
1031 #ifdef ENABLE_TESTING_SUPPORT
1032                     printf("    TODO: Found external characteristic 0x%04X\n", characteristic.uuid16);
1033 #endif
1034                     return;
1035             }
1036 
1037 #ifdef ENABLE_TESTING_SUPPORT
1038             printf("HID Characteristic %s:  \n    Attribute Handle 0x%04X, Properties 0x%02X, Handle 0x%04X, UUID 0x%04X, service %d",
1039                 hid_characteristic_name(characteristic.uuid16),
1040                 characteristic.start_handle,
1041                 characteristic.properties,
1042                 characteristic.value_handle, characteristic.uuid16,
1043                 client->service_index);
1044 
1045             if (report_index != HIDS_CLIENT_INVALID_REPORT_INDEX){
1046                 printf(", report index 0x%02X", report_index);
1047             }
1048             printf("\n");
1049 #endif
1050             break;
1051 
1052         case GATT_EVENT_LONG_CHARACTERISTIC_VALUE_QUERY_RESULT:
1053             // Map Report characteristic value == HID Descriptor
1054             client = hids_get_client_for_con_handle(gatt_event_long_characteristic_value_query_result_get_handle(packet));
1055             if (client == NULL) break;
1056 
1057             value = gatt_event_long_characteristic_value_query_result_get_value(packet);
1058             value_len = gatt_event_long_characteristic_value_query_result_get_value_length(packet);
1059 
1060 #ifdef ENABLE_TESTING_SUPPORT
1061             // printf("Report Map HID Desc [%d] for service %d\n", descriptor_len, client->service_index);
1062             printf_hexdump(value, value_len);
1063 #endif
1064             for (i = 0; i < value_len; i++){
1065                 bool stored = hids_client_descriptor_storage_store(client, client->service_index, value[i]);
1066                 if (!stored){
1067                     client->services[client->service_index].hid_descriptor_status = ERROR_CODE_MEMORY_CAPACITY_EXCEEDED;
1068                     break;
1069                 }
1070             }
1071             break;
1072 
1073         case GATT_EVENT_ALL_CHARACTERISTIC_DESCRIPTORS_QUERY_RESULT:
1074             client = hids_get_client_for_con_handle(gatt_event_all_characteristic_descriptors_query_result_get_handle(packet));
1075             if (client == NULL) break;
1076 
1077             gatt_event_all_characteristic_descriptors_query_result_get_characteristic_descriptor(packet, &characteristic_descriptor);
1078 
1079             switch (client->state) {
1080                 case HIDS_CLIENT_STATE_W4_REPORT_MAP_CHARACTERISTIC_DESCRIPTORS_RESULT:
1081                     // setup for descriptor value query
1082                     if (characteristic_descriptor.uuid16 == ORG_BLUETOOTH_DESCRIPTOR_EXTERNAL_REPORT_REFERENCE){
1083                         report_index = hids_client_add_external_report(client, &characteristic_descriptor);
1084 
1085 #ifdef ENABLE_TESTING_SUPPORT
1086                         if (report_index != HIDS_CLIENT_INVALID_REPORT_INDEX){
1087                             printf("    External Report Reference Characteristic Descriptor: Handle 0x%04X, UUID 0x%04X, service %d, report index 0x%02X\n",
1088                                 characteristic_descriptor.handle,
1089                                 characteristic_descriptor.uuid16,
1090                                 client->service_index, report_index);
1091                         }
1092 #endif
1093                     }
1094                     break;
1095                 case HIDS_CLIENT_STATE_W4_REPORT_FOUND:
1096                     // setup for descriptor value query
1097                     if (characteristic_descriptor.uuid16 == ORG_BLUETOOTH_DESCRIPTOR_REPORT_REFERENCE){
1098                         client->handle = characteristic_descriptor.handle;
1099 #ifdef ENABLE_TESTING_SUPPORT
1100                         printf("    Report Characteristic Report Reference Characteristic Descriptor:  Handle 0x%04X, UUID 0x%04X\n",
1101                             characteristic_descriptor.handle,
1102                             characteristic_descriptor.uuid16);
1103 #endif
1104                     }
1105 
1106 #ifdef ENABLE_TESTING_SUPPORT
1107                     if (characteristic_descriptor.uuid16 == ORG_BLUETOOTH_DESCRIPTOR_GATT_CLIENT_CHARACTERISTIC_CONFIGURATION){
1108                         client->reports[client->report_index].ccc_handle = characteristic_descriptor.handle;
1109                         printf("    Report Client Characteristic Configuration Descriptor: Handle 0x%04X, UUID 0x%04X\n",
1110                             characteristic_descriptor.handle,
1111                             characteristic_descriptor.uuid16);
1112                     }
1113 #endif
1114                     break;
1115 
1116                 default:
1117                     break;
1118             }
1119             break;
1120 
1121         case GATT_EVENT_CHARACTERISTIC_VALUE_QUERY_RESULT:
1122             client = hids_get_client_for_con_handle(gatt_event_characteristic_value_query_result_get_handle(packet));
1123             if (client == NULL) break;
1124 
1125             value = gatt_event_characteristic_value_query_result_get_value(packet);
1126             value_len = gatt_event_characteristic_value_query_result_get_value_length(packet);
1127 
1128 
1129             switch (client->state){
1130 #ifdef ENABLE_TESTING_SUPPORT
1131                 case HIDS_CLIENT_W4_CHARACTERISTIC_CONFIGURATION_RESULT:
1132                     printf("    Received CCC value: ");
1133                     printf_hexdump(value,  value_len);
1134                     break;
1135 #endif
1136                 case HIDS_CLIENT_W4_VALUE_OF_CHARACTERISTIC_RESULT:{
1137                     uint16_t value_handle = gatt_event_characteristic_value_query_result_get_value_handle(packet);
1138                     if (value_handle == client->services[client->service_index].hid_information_value_handle){
1139                         hids_client_emit_hid_information_event(client, value, value_len);
1140                         break;
1141                     }
1142                     if (value_handle == client->services[client->service_index].protocol_mode_value_handle){
1143                         hids_client_emit_protocol_mode_event(client, value, value_len);
1144                         break;
1145                     }
1146                     break;
1147                 }
1148                 default:
1149                     break;
1150             }
1151 
1152             break;
1153 
1154         case GATT_EVENT_CHARACTERISTIC_DESCRIPTOR_QUERY_RESULT:
1155             client = hids_get_client_for_con_handle(gatt_event_characteristic_descriptor_query_result_get_handle(packet));
1156             if (client == NULL) break;
1157 
1158             if (gatt_event_characteristic_descriptor_query_result_get_descriptor_length(packet) != 2){
1159                 break;
1160             }
1161 
1162             characteristic_descriptor_value = gatt_event_characteristic_descriptor_query_result_get_descriptor(packet);
1163             switch (client->state) {
1164                 case HIDS_CLIENT_STATE_W4_REPORT_MAP_EXTERNAL_REPORT_REFERENCE_UUID:
1165                     // get external report characteristic uuid
1166                     report_index = find_external_report_index_for_value_handle(client, gatt_event_characteristic_descriptor_query_result_get_descriptor_handle(packet));
1167                     if (report_index != HIDS_CLIENT_INVALID_REPORT_INDEX){
1168                         client->external_reports[report_index].external_report_reference_uuid = little_endian_read_16(characteristic_descriptor_value, 0);
1169 #ifdef ENABLE_TESTING_SUPPORT
1170                         printf("    Update external_report_reference_uuid of report index 0x%02X, service index 0x%02X, UUID 0x%02X\n",
1171                             report_index, client->service_index, client->external_reports[report_index].external_report_reference_uuid);
1172 #endif
1173                     }
1174                     break;
1175 
1176                 case HIDS_CLIENT_STATE_W4_REPORT_ID_AND_TYPE:
1177 
1178                     if (client->report_index != HIDS_CLIENT_INVALID_REPORT_INDEX){
1179                         client->reports[client->report_index].report_id = characteristic_descriptor_value[0];
1180                         client->reports[client->report_index].report_type = (hid_report_type_t)characteristic_descriptor_value[1];
1181     #ifdef ENABLE_TESTING_SUPPORT
1182                         printf("    Update report ID and type [%d, %d] of report index 0x%02X, service index 0x%02X\n",
1183                             client->reports[client->report_index].report_id,
1184                             client->reports[client->report_index].report_type,
1185                             client->report_index, client->service_index);
1186     #endif
1187                     }
1188                     break;
1189 
1190                 default:
1191                     break;
1192             }
1193             break;
1194 
1195         case GATT_EVENT_QUERY_COMPLETE:
1196             client = hids_get_client_for_con_handle(gatt_event_query_complete_get_handle(packet));
1197             if (client == NULL) break;
1198 
1199             att_status = gatt_event_query_complete_get_att_status(packet);
1200 
1201             switch (client->state){
1202                 case HIDS_CLIENT_STATE_W4_SERVICE_RESULT:
1203                     if (att_status != ATT_ERROR_SUCCESS){
1204                         hids_emit_connection_established(client, att_status);
1205                         hids_finalize_client(client);
1206                         return;
1207                     }
1208 
1209                     if (client->num_instances == 0){
1210                         hids_emit_connection_established(client, ERROR_CODE_UNSUPPORTED_FEATURE_OR_PARAMETER_VALUE);
1211                         hids_finalize_client(client);
1212                         return;
1213                     }
1214 
1215                     client->service_index = 0;
1216                     client->state = HIDS_CLIENT_STATE_W2_QUERY_CHARACTERISTIC;
1217                     break;
1218 
1219                 case HIDS_CLIENT_STATE_W4_CHARACTERISTIC_RESULT:
1220                     if (att_status != ATT_ERROR_SUCCESS){
1221                         hids_emit_connection_established(client, att_status);
1222                         hids_finalize_client(client);
1223                         return;
1224                     }
1225 
1226                     if ((client->service_index + 1) < client->num_instances){
1227                         // discover characteristics of next service
1228                         client->service_index++;
1229                         client->state = HIDS_CLIENT_STATE_W2_QUERY_CHARACTERISTIC;
1230                         break;
1231                     }
1232 
1233                     btstack_assert(client->required_protocol_mode != HID_PROTOCOL_MODE_REPORT_WITH_FALLBACK_TO_BOOT);
1234 
1235                     switch (client->required_protocol_mode){
1236                         case HID_PROTOCOL_MODE_REPORT:
1237                             for (i = 0; i < client->num_instances; i++){
1238                                 client->services[i].protocol_mode = HID_PROTOCOL_MODE_REPORT;
1239                             }
1240                             // 1. we need to get HID Descriptor and
1241                             // 2. get external Report characteristics if referenced from Report Map
1242                             if (hids_client_report_map_query_init(client)){
1243                                 break;
1244                             }
1245                             hids_emit_connection_established(client, ERROR_CODE_UNSUPPORTED_FEATURE_OR_PARAMETER_VALUE);
1246                             hids_finalize_client(client);
1247                             return;
1248 
1249                         default:
1250                             // set boot mode
1251                             client->service_index = 0;
1252                             client->state = HIDS_CLIENT_STATE_W2_SET_PROTOCOL_MODE_WITHOUT_RESPONSE;
1253                             break;
1254                     }
1255                     break;
1256 
1257 
1258                 // HID descriptor found
1259                 case HIDS_CLIENT_STATE_W4_REPORT_MAP_HID_DESCRIPTOR:
1260                     if (att_status != ATT_ERROR_SUCCESS){
1261                         hids_emit_connection_established(client, att_status);
1262                         hids_finalize_client(client);
1263                         return;
1264                     }
1265                     client->state = HIDS_CLIENT_STATE_W2_REPORT_MAP_DISCOVER_CHARACTERISTIC_DESCRIPTORS;
1266                     break;
1267 
1268                 // found all descriptors, check if there is one with EXTERNAL_REPORT_REFERENCE
1269                 case HIDS_CLIENT_STATE_W4_REPORT_MAP_CHARACTERISTIC_DESCRIPTORS_RESULT:
1270                     // go for next report map
1271                     if (hids_client_report_query_next_report_map(client)){
1272                         break;
1273                     }
1274 
1275                     // read UUIDS for external characteristics
1276                     if (hids_client_report_map_uuid_query_init(client)){
1277                         break;
1278                     }
1279 
1280                     // discover characteristic descriptor for all Report characteristics,
1281                     // then read value of characteristic descriptor to get Report ID
1282                     if (hids_client_report_query_init(client)){
1283                         break;
1284                     }
1285 
1286                     hids_emit_connection_established(client, ERROR_CODE_UNSUPPORTED_FEATURE_OR_PARAMETER_VALUE);
1287                     hids_finalize_client(client);
1288                     return;
1289 
1290                 case HIDS_CLIENT_STATE_W4_REPORT_MAP_EXTERNAL_REPORT_REFERENCE_UUID:
1291                     // go for next map report
1292                     if (hids_client_report_query_next_report_map_uuid(client)){
1293                         break;
1294                     }
1295 
1296                     // update external characteristics with correct value handle and end handle
1297                     client->state = HIDS_CLIENT_STATE_W2_DISCOVER_EXTERNAL_REPORT_CHARACTERISTIC;
1298                     break;
1299 
1300                 case HIDS_CLIENT_STATE_W4_EXTERNAL_REPORT_CHARACTERISTIC_RESULT:
1301                     // discover characteristic descriptor for all Report characteristics,
1302                     // then read value of characteristic descriptor to get Report ID
1303                     if (hids_client_report_query_init(client)){
1304                         break;
1305                     }
1306 
1307                     hids_emit_connection_established(client, ERROR_CODE_UNSUPPORTED_FEATURE_OR_PARAMETER_VALUE);
1308                     hids_finalize_client(client);
1309                     return;
1310 
1311                 case HIDS_CLIENT_STATE_W4_REPORT_FOUND:
1312                     if (client->handle != 0){
1313                         client->state = HIDS_CLIENT_STATE_W2_READ_REPORT_ID_AND_TYPE;
1314                         break;
1315                     }
1316                     // go for next report
1317                     if (hids_client_report_query_next_report(client)){
1318                         break;
1319                     }
1320                     client->state = HIDS_CLIENT_STATE_CONNECTED;
1321                     hids_emit_connection_established(client, ERROR_CODE_SUCCESS);
1322                     break;
1323 
1324                 case HIDS_CLIENT_STATE_W4_REPORT_ID_AND_TYPE:
1325                     // go for next report
1326                     if (hids_client_report_query_next_report(client)){
1327                         break;
1328                     }
1329                     if (hids_client_report_notifications_init(client)){
1330                         break;
1331                     }
1332                     client->state = HIDS_CLIENT_STATE_CONNECTED;
1333                     hids_emit_connection_established(client, ERROR_CODE_SUCCESS);
1334                     break;
1335 
1336                 case HIDS_CLIENT_STATE_W4_INPUT_REPORTS_ENABLED:
1337                     if (hids_client_report_next_notification_report_index(client)){
1338                         break;
1339                     }
1340                     client->state = HIDS_CLIENT_STATE_CONNECTED;
1341                     hids_emit_connection_established(client, ERROR_CODE_SUCCESS);
1342                     break;
1343 
1344                 case HIDS_CLIENT_STATE_W4_NOTIFICATIONS_CONFIGURED:
1345                     if (hids_client_report_next_notifications_configuration_report_index(client)){
1346                         break;
1347                     }
1348                     hids_emit_notifications_configuration(client);
1349                     client->state = HIDS_CLIENT_STATE_CONNECTED;
1350                     break;
1351 
1352 #ifdef ENABLE_TESTING_SUPPORT
1353                 case HIDS_CLIENT_W4_CHARACTERISTIC_CONFIGURATION_RESULT:
1354                     client->state = HIDS_CLIENT_W2_SEND_GET_REPORT;
1355                     break;
1356 #endif
1357 
1358                 case HIDS_CLIENT_W4_VALUE_OF_CHARACTERISTIC_RESULT:
1359                     client->state = HIDS_CLIENT_STATE_CONNECTED;
1360                     break;
1361 
1362                 case HIDS_CLIENT_W4_WRITE_REPORT_DONE:
1363                     {
1364                         client->state = HIDS_CLIENT_STATE_CONNECTED;
1365 
1366                         // emit empty report to signal done
1367                         uint8_t event[9];
1368                         hids_client_setup_report_event(client, client->report_index, event, 0);
1369                         (*client->client_handler)(HCI_EVENT_PACKET, 0, event, sizeof(event));
1370                     }
1371                     break;
1372 
1373                 default:
1374                     break;
1375             }
1376             break;
1377 
1378         default:
1379             break;
1380     }
1381 
1382     if (client != NULL){
1383         hids_run_for_client(client);
1384     }
1385 }
1386 
1387 uint8_t hids_client_connect(hci_con_handle_t con_handle, btstack_packet_handler_t packet_handler, hid_protocol_mode_t protocol_mode, uint16_t * hids_cid){
1388     btstack_assert(packet_handler != NULL);
1389 
1390     hids_client_t * client = hids_get_client_for_con_handle(con_handle);
1391     if (client != NULL){
1392         return ERROR_CODE_COMMAND_DISALLOWED;
1393     }
1394 
1395     uint16_t cid = hids_get_next_cid();
1396     if (hids_cid != NULL) {
1397         *hids_cid = cid;
1398     }
1399 
1400     client = hids_create_client(con_handle, cid);
1401     if (client == NULL) {
1402         return BTSTACK_MEMORY_ALLOC_FAILED;
1403     }
1404 
1405     client->required_protocol_mode = protocol_mode;
1406     client->client_handler = packet_handler;
1407     client->state = HIDS_CLIENT_STATE_W2_QUERY_SERVICE;
1408 
1409     hids_run_for_client(client);
1410     return ERROR_CODE_SUCCESS;
1411 }
1412 
1413 uint8_t hids_client_disconnect(uint16_t hids_cid){
1414     hids_client_t * client = hids_get_client_for_cid(hids_cid);
1415     if (client == NULL){
1416         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
1417     }
1418     // finalize connection
1419     hids_finalize_client(client);
1420     return ERROR_CODE_SUCCESS;
1421 }
1422 
1423 uint8_t hids_client_send_write_report(uint16_t hids_cid, uint8_t report_id, hid_report_type_t report_type, const uint8_t * report, uint8_t report_len){
1424     hids_client_t * client = hids_get_client_for_cid(hids_cid);
1425     if (client == NULL){
1426         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
1427     }
1428 
1429     if (client->state != HIDS_CLIENT_STATE_CONNECTED) {
1430         return ERROR_CODE_COMMAND_DISALLOWED;
1431     }
1432 
1433     uint8_t report_index = find_report_index_for_report_id_and_report_type(client, report_id, report_type);
1434 
1435     if (report_index == HIDS_CLIENT_INVALID_REPORT_INDEX){
1436         return ERROR_CODE_UNSUPPORTED_FEATURE_OR_PARAMETER_VALUE;
1437     }
1438 
1439     uint16_t mtu;
1440     uint8_t status = gatt_client_get_mtu(client->con_handle, &mtu);
1441 
1442     if (status != ERROR_CODE_SUCCESS){
1443         return status;
1444     }
1445 
1446     if (mtu - 2 < report_len){
1447         return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE;
1448     }
1449 
1450     client->state = HIDS_CLIENT_W2_SEND_WRITE_REPORT;
1451     client->report_index = report_index;
1452     client->report = report;
1453     client->report_len = report_len;
1454 
1455     hids_run_for_client(client);
1456     return ERROR_CODE_SUCCESS;
1457 }
1458 
1459 uint8_t hids_client_send_get_report(uint16_t hids_cid, uint8_t report_id, hid_report_type_t report_type){
1460     hids_client_t * client = hids_get_client_for_cid(hids_cid);
1461     if (client == NULL){
1462         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
1463     }
1464 
1465     if (client->state != HIDS_CLIENT_STATE_CONNECTED) {
1466         return ERROR_CODE_COMMAND_DISALLOWED;
1467     }
1468 
1469     uint8_t report_index = find_report_index_for_report_id_and_report_type(client, report_id, report_type);
1470     if (report_index == HIDS_CLIENT_INVALID_REPORT_INDEX){
1471         return ERROR_CODE_UNSUPPORTED_FEATURE_OR_PARAMETER_VALUE;
1472     }
1473 
1474     client->report_index = report_index;
1475 
1476 #ifdef ENABLE_TESTING_SUPPORT
1477     client->state = HIDS_CLIENT_W2_READ_CHARACTERISTIC_CONFIGURATION;
1478 #else
1479     client->state = HIDS_CLIENT_W2_SEND_GET_REPORT;
1480 #endif
1481     hids_run_for_client(client);
1482     return ERROR_CODE_SUCCESS;
1483 }
1484 
1485 
1486 uint8_t hids_client_get_hid_information(uint16_t hids_cid, uint8_t service_index){
1487     hids_client_t * client = hids_get_client_for_cid(hids_cid);
1488     if (client == NULL){
1489         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
1490     }
1491 
1492     if (client->state != HIDS_CLIENT_STATE_CONNECTED) {
1493         return ERROR_CODE_COMMAND_DISALLOWED;
1494     }
1495 
1496     if (service_index >= client->num_instances){
1497         return ERROR_CODE_UNSUPPORTED_FEATURE_OR_PARAMETER_VALUE;
1498     }
1499 
1500     client->service_index = service_index;
1501     client->handle = client->services[client->service_index].hid_information_value_handle;
1502 
1503     client->state = HIDS_CLIENT_W2_READ_VALUE_OF_CHARACTERISTIC;
1504     hids_run_for_client(client);
1505     return ERROR_CODE_SUCCESS;
1506 }
1507 
1508 uint8_t hids_client_get_protocol_mode(uint16_t hids_cid, uint8_t service_index){
1509     hids_client_t * client = hids_get_client_for_cid(hids_cid);
1510     if (client == NULL){
1511         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
1512     }
1513 
1514     if (client->state != HIDS_CLIENT_STATE_CONNECTED) {
1515         return ERROR_CODE_COMMAND_DISALLOWED;
1516     }
1517 
1518     if (service_index >= client->num_instances){
1519         return ERROR_CODE_UNSUPPORTED_FEATURE_OR_PARAMETER_VALUE;
1520     }
1521 
1522     client->service_index = service_index;
1523     client->handle = client->services[client->service_index].protocol_mode_value_handle;
1524 
1525     client->state = HIDS_CLIENT_W2_READ_VALUE_OF_CHARACTERISTIC;
1526     hids_run_for_client(client);
1527     return ERROR_CODE_SUCCESS;
1528 }
1529 
1530 uint8_t hids_client_send_set_protocol_mode(uint16_t hids_cid, uint8_t service_index, hid_protocol_mode_t protocol_mode){
1531     hids_client_t * client = hids_get_client_for_cid(hids_cid);
1532     if (client == NULL){
1533         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
1534     }
1535 
1536     if (client->state != HIDS_CLIENT_STATE_CONNECTED) {
1537         return ERROR_CODE_COMMAND_DISALLOWED;
1538     }
1539 
1540     if (service_index >= client->num_instances){
1541         return ERROR_CODE_UNSUPPORTED_FEATURE_OR_PARAMETER_VALUE;
1542     }
1543 
1544     client->service_index = service_index;
1545     client->handle = client->services[client->service_index].protocol_mode_value_handle;
1546     client->value = (uint8_t)protocol_mode;
1547 
1548     client->state = HIDS_CLIENT_W2_WRITE_VALUE_OF_CHARACTERISTIC_WITHOUT_RESPONSE;
1549     hids_run_for_client(client);
1550     return ERROR_CODE_SUCCESS;
1551 }
1552 
1553 
1554 static uint8_t hids_client_send_control_point_cmd(uint16_t hids_cid, uint8_t service_index, uint8_t value){
1555     hids_client_t * client = hids_get_client_for_cid(hids_cid);
1556     if (client == NULL){
1557         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
1558     }
1559 
1560     if (client->state != HIDS_CLIENT_STATE_CONNECTED) {
1561         return ERROR_CODE_COMMAND_DISALLOWED;
1562     }
1563 
1564     if (service_index >= client->num_instances){
1565         return ERROR_CODE_UNSUPPORTED_FEATURE_OR_PARAMETER_VALUE;
1566     }
1567 
1568     client->service_index = service_index;
1569     client->handle = client->services[client->service_index].control_point_value_handle;
1570     client->value = value;
1571 
1572     client->state = HIDS_CLIENT_W2_WRITE_VALUE_OF_CHARACTERISTIC_WITHOUT_RESPONSE;
1573     hids_run_for_client(client);
1574     return ERROR_CODE_SUCCESS;
1575 }
1576 
1577 uint8_t hids_client_send_suspend(uint16_t hids_cid, uint8_t service_index){
1578     return hids_client_send_control_point_cmd(hids_cid, service_index, 0);
1579 }
1580 
1581 uint8_t hids_client_send_exit_suspend(uint16_t hids_cid, uint8_t service_index){
1582     return hids_client_send_control_point_cmd(hids_cid, service_index, 1);
1583 }
1584 
1585 uint8_t hids_client_enable_notifications(uint16_t hids_cid){
1586      hids_client_t * client = hids_get_client_for_cid(hids_cid);
1587     if (client == NULL){
1588         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
1589     }
1590 
1591     if (client->state != HIDS_CLIENT_STATE_CONNECTED) {
1592         return ERROR_CODE_COMMAND_DISALLOWED;
1593     }
1594     client->value = GATT_CLIENT_CHARACTERISTICS_CONFIGURATION_NOTIFICATION;
1595     if (hids_client_notifications_configuration_init(client)){
1596         hids_run_for_client(client);
1597         return ERROR_CODE_SUCCESS;
1598     }
1599     hids_emit_notifications_configuration(client);
1600     return ERROR_CODE_SUCCESS;
1601 }
1602 
1603 uint8_t hids_client_disable_notifications(uint16_t hids_cid){
1604          hids_client_t * client = hids_get_client_for_cid(hids_cid);
1605     if (client == NULL){
1606         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
1607     }
1608 
1609     if (client->state != HIDS_CLIENT_STATE_CONNECTED) {
1610         return ERROR_CODE_COMMAND_DISALLOWED;
1611     }
1612 
1613     client->value = GATT_CLIENT_CHARACTERISTICS_CONFIGURATION_NONE;
1614     if (hids_client_notifications_configuration_init(client)){
1615         hids_run_for_client(client);
1616         return ERROR_CODE_SUCCESS;
1617     }
1618     hids_emit_notifications_configuration(client);
1619     return ERROR_CODE_SUCCESS;
1620 }
1621 
1622 void hids_client_init(uint8_t * hid_descriptor_storage, uint16_t hid_descriptor_storage_len){
1623     hids_client_descriptor_storage = hid_descriptor_storage;
1624     hids_client_descriptor_storage_len = hid_descriptor_storage_len;
1625 }
1626 
1627 void hids_client_deinit(void){}
1628