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