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