xref: /btstack/src/ble/gatt-service/hids_client.c (revision 708c69d2b8293fc7f7bf4f3c4a79858f76b61a69)
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 static hids_client_t * hids_get_client_for_con_handle(hci_con_handle_t con_handle){
76     btstack_linked_list_iterator_t it;
77     btstack_linked_list_iterator_init(&it, &clients);
78     while (btstack_linked_list_iterator_has_next(&it)){
79         hids_client_t * client = (hids_client_t *)btstack_linked_list_iterator_next(&it);
80         if (client->con_handle != con_handle) continue;
81         return client;
82     }
83     return NULL;
84 }
85 
86 static hids_client_t * hids_get_client_for_cid(uint16_t hids_cid){
87     btstack_linked_list_iterator_t it;
88     btstack_linked_list_iterator_init(&it, &clients);
89     while (btstack_linked_list_iterator_has_next(&it)){
90         hids_client_t * client = (hids_client_t *)btstack_linked_list_iterator_next(&it);
91         if (client->cid != hids_cid) continue;
92         return client;
93     }
94     return NULL;
95 }
96 
97 
98 // START Descriptor Storage Util
99 
100 static uint16_t hids_client_descriptor_storage_get_available_space(void){
101     // assumes all descriptors are back to back
102     uint16_t free_space = hids_client_descriptor_storage_len;
103     uint8_t i;
104 
105     btstack_linked_list_iterator_t it;
106     btstack_linked_list_iterator_init(&it, &clients);
107     while (btstack_linked_list_iterator_has_next(&it)){
108         hids_client_t * client = (hids_client_t *)btstack_linked_list_iterator_next(&it);
109         for (i = 0; i < client->num_instances; i++){
110             free_space -= client->services[i].hid_descriptor_len;
111         }
112     }
113     return free_space;
114 }
115 
116 static void hids_client_descriptor_storage_init(hids_client_t * client, uint8_t service_index){
117     client->services[service_index].hid_descriptor_len = 0;
118     client->services[service_index].hid_descriptor_max_len = hids_client_descriptor_storage_get_available_space();
119     client->services[service_index].hid_descriptor_offset = hids_client_descriptor_storage_len - client->services[service_index].hid_descriptor_max_len;
120 }
121 
122 static bool hids_client_descriptor_storage_store(hids_client_t * client, uint8_t service_index, uint8_t byte){
123     if (client->services[service_index].hid_descriptor_len >= client->services[service_index].hid_descriptor_max_len) return false;
124 
125     hids_client_descriptor_storage[client->services[service_index].hid_descriptor_offset + client->services[service_index].hid_descriptor_len] = byte;
126     client->services[service_index].hid_descriptor_len++;
127     return true;
128 }
129 
130 static void hids_client_descriptor_storage_delete(hids_client_t * client){
131     uint8_t service_index = 0;
132     uint16_t next_offset = 0;
133 
134     for (service_index = 0; service_index < client->num_instances; service_index++){
135         next_offset += client->services[service_index].hid_descriptor_offset + client->services[service_index].hid_descriptor_len;
136         client->services[service_index].hid_descriptor_len = 0;
137         client->services[service_index].hid_descriptor_offset = 0;
138     }
139 
140     memmove(&hids_client_descriptor_storage[client->services[0].hid_descriptor_offset],
141             &hids_client_descriptor_storage[next_offset],
142             hids_client_descriptor_storage_len - next_offset);
143 
144     uint8_t i;
145     btstack_linked_list_iterator_t it;
146     btstack_linked_list_iterator_init(&it, &clients);
147     while (btstack_linked_list_iterator_has_next(&it)){
148         hids_client_t * conn = (hids_client_t *)btstack_linked_list_iterator_next(&it);
149         for (i = 0; i < client->num_instances; i++){
150             if (conn->services[i].hid_descriptor_offset >= next_offset){
151                 conn->services[i].hid_descriptor_offset = next_offset;
152                 next_offset += conn->services[service_index].hid_descriptor_len;
153             }
154         }
155     }
156 }
157 
158 const uint8_t * hids_client_descriptor_storage_get_descriptor_data(uint16_t hids_cid, uint8_t service_index){
159     hids_client_t * client = hids_get_client_for_cid(hids_cid);
160     if (client == NULL){
161         return NULL;
162     }
163     if (service_index >= client->num_instances){
164         return NULL;
165     }
166     return &hids_client_descriptor_storage[client->services[service_index].hid_descriptor_offset];
167 }
168 
169 uint16_t hids_client_descriptor_storage_get_descriptor_len(uint16_t hids_cid, uint8_t service_index){
170     hids_client_t * client = hids_get_client_for_cid(hids_cid);
171     if (client == NULL){
172         return 0;
173     }
174     if (service_index >= client->num_instances){
175         return 0;
176     }
177     return client->services[service_index].hid_descriptor_len;
178 }
179 
180 // END Descriptor Storage Util
181 
182 static uint16_t hids_get_next_cid(void){
183     if (hids_cid_counter == 0xffff) {
184         hids_cid_counter = 1;
185     } else {
186         hids_cid_counter++;
187     }
188     return hids_cid_counter;
189 }
190 
191 static uint8_t find_report_index_for_value_handle(hids_client_t * client, uint16_t value_handle){
192     uint8_t i;
193     for (i = 0; i < client->num_reports; i++){
194         if (client->reports[i].value_handle == value_handle){
195             return i;
196         }
197     }
198     return HIDS_CLIENT_INVALID_REPORT_INDEX;
199 }
200 
201 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){
202     uint8_t i;
203     for (i = 0; i < client->num_reports; i++){
204         if ( (client->reports[i].report_id == report_id) && (client->reports[i].report_type == report_type)){
205             return i;
206         }
207     }
208     return HIDS_CLIENT_INVALID_REPORT_INDEX;
209 }
210 
211 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){
212 
213     uint8_t report_index = find_report_index_for_value_handle(client, characteristic->value_handle);
214     if (report_index != HIDS_CLIENT_INVALID_REPORT_INDEX){
215         return report_index;
216     }
217     report_index = client->num_reports;
218 
219     if (report_index < HIDS_CLIENT_NUM_REPORTS) {
220         client->reports[report_index].value_handle = characteristic->value_handle;
221         client->reports[report_index].end_handle = characteristic->end_handle;
222         client->reports[report_index].properties = characteristic->properties;
223 
224         client->reports[report_index].service_index = client->service_index;
225         client->reports[report_index].report_id = report_id;
226         client->reports[report_index].report_type = report_type;
227         client->reports[report_index].boot_report = boot_report;
228 
229         // log_info("add index %d, id %d, type %d, value handle 0x%02x", report_index, report_id, report_type, characteristic->value_handle);
230         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);
231         client->num_reports++;
232         return report_index;
233     } else {
234         log_info("not enough storage, increase HIDS_CLIENT_NUM_REPORTS");
235         return HIDS_CLIENT_INVALID_REPORT_INDEX;
236     }
237 }
238 
239 static void hids_client_get_characteristic_for_report_index(hids_client_t * client, uint8_t report_index, gatt_client_characteristic_t * characteristic){
240     characteristic->value_handle = client->reports[report_index].value_handle;
241     characteristic->end_handle = client->reports[report_index].end_handle;
242     characteristic->properties = client->reports[report_index].properties;
243 }
244 
245 static bool hid_clients_has_reports_in_report_mode(hids_client_t * client){
246     uint8_t i;
247     for (i = 0; i < client->num_reports; i++){
248         if (!client->reports[i].boot_report){
249             return true;
250         }
251     }
252     return false;
253 }
254 
255 static bool hid_clients_has_reports_in_boot_mode(hids_client_t * client){
256     uint8_t i;
257     for (i = 0; i < client->num_reports; i++){
258         if (client->reports[i].boot_report){
259             return true;
260         }
261     }
262     return false;
263 }
264 
265 static uint8_t hids_client_get_next_active_report_map_index(hids_client_t * client){
266     uint8_t i;
267     uint8_t index = HIDS_CLIENT_INVALID_REPORT_INDEX;
268 
269     for (i = client->service_index; i < client->num_instances; i++){
270         if (client->services[i].report_map_value_handle != 0){
271             index = i;
272             break;
273         }
274     }
275     client->service_index = index;
276     return index;
277 }
278 
279 static bool hids_client_report_query_next_report_map(hids_client_t * client){
280     client->service_index++;
281     if (hids_client_get_next_active_report_map_index(client) != HIDS_CLIENT_INVALID_REPORT_INDEX){
282         client->state = HIDS_CLIENT_STATE_W2_REPORT_MAP_DISCOVER_CHARACTERISTIC_DESCRIPTORS;
283         return true;
284     }
285     return false;
286 }
287 
288 static bool hids_client_report_map_query_init(hids_client_t * client){
289     client->service_index = 0;
290 
291     if (hids_client_get_next_active_report_map_index(client) != HIDS_CLIENT_INVALID_REPORT_INDEX){
292         client->state = HIDS_CLIENT_STATE_W2_READ_REPORT_MAP_HID_DESCRIPTOR;
293         return true;
294     }
295     return false;
296 }
297 
298 
299 static uint8_t hids_client_get_next_active_report_map_uuid_index(hids_client_t * client){
300     uint8_t i;
301     uint8_t index = HIDS_CLIENT_INVALID_REPORT_INDEX;
302 
303     for (i = client->report_index; i < client->num_reports; i++){
304         hids_client_report_t report = client->reports[i];
305         if (report.report_type == HID_REPORT_TYPE_RESERVED && report.report_id == HID_REPORT_MODE_REPORT_MAP_ID){
306             index = i;
307             break;
308         }
309     }
310     client->report_index = index;
311     return index;
312 }
313 
314 static bool hids_client_report_query_next_report_map_uuid(hids_client_t * client){
315     client->report_index++;
316     if (hids_client_get_next_active_report_map_uuid_index(client) != HIDS_CLIENT_INVALID_REPORT_INDEX){
317         client->state = HIDS_CLIENT_STATE_W2_REPORT_MAP_READ_EXTERNAL_REPORT_REFERENCE_UUID;
318         return true;
319     }
320     return false;
321 }
322 
323 
324 
325 static bool hids_client_report_map_uuid_query_init(hids_client_t * client){
326     client->report_index = 0;
327 
328     if (hids_client_get_next_active_report_map_uuid_index(client) != HIDS_CLIENT_INVALID_REPORT_INDEX){
329         client->state = HIDS_CLIENT_STATE_W2_REPORT_MAP_READ_EXTERNAL_REPORT_REFERENCE_UUID;
330         return true;
331     }
332     return false;
333 }
334 
335 static uint8_t hids_client_get_next_report_index(hids_client_t * client){
336     uint8_t i;
337     uint8_t index = HIDS_CLIENT_INVALID_REPORT_INDEX;
338     switch (client->protocol_mode){
339         case HID_PROTOCOL_MODE_REPORT:
340             for (i = client->report_index; i < client->num_reports && (index == HIDS_CLIENT_INVALID_REPORT_INDEX); i++){
341                 hids_client_report_t report = client->reports[i];
342                 if (report.report_type == HID_REPORT_TYPE_RESERVED && report.report_id == HID_REPORT_MODE_REPORT_ID){
343                     index = i;
344                     client->service_index = report.service_index;
345                 }
346             }
347             break;
348         case HID_PROTOCOL_MODE_BOOT:
349             for (i = client->report_index; i < client->num_reports && (index == HIDS_CLIENT_INVALID_REPORT_INDEX); i++){
350                 hids_client_report_t report = client->reports[i];
351                 if (report.boot_report){
352                     index = i;
353                     client->service_index = report.service_index;
354                 }
355             }
356             break;
357         default:
358             break;
359     }
360 
361     client->report_index = index;
362     return index;
363 }
364 
365 static bool hids_client_report_query_next_report(hids_client_t * client){
366     client->report_index++;
367     if (hids_client_get_next_report_index(client) != HIDS_CLIENT_INVALID_REPORT_INDEX){
368         client->state = HIDS_CLIENT_STATE_W2_FIND_REPORT;
369         return true;
370     }
371     return false;
372 }
373 
374 static bool hids_client_report_query_init(hids_client_t * client){
375     client->report_index = 0;
376 
377     if (hids_client_get_next_report_index(client) != HIDS_CLIENT_INVALID_REPORT_INDEX){
378         client->state = HIDS_CLIENT_STATE_W2_FIND_REPORT;
379         return true;
380     }
381     return false;
382 }
383 
384 static uint8_t hids_client_get_next_notification_report_index(hids_client_t * client){
385     uint8_t i;
386     uint8_t index = HIDS_CLIENT_INVALID_REPORT_INDEX;
387 
388     switch (client->protocol_mode){
389         case HID_PROTOCOL_MODE_REPORT:
390             for (i = client->report_index; i < client->num_reports && (index == HIDS_CLIENT_INVALID_REPORT_INDEX); i++){
391                 hids_client_report_t report = client->reports[i];
392                 if (report.report_type != HID_REPORT_TYPE_INPUT){
393                     continue;
394                 }
395                 if (!report.boot_report){
396                     index = i;
397                 }
398             }
399             break;
400 
401         case HID_PROTOCOL_MODE_BOOT:
402             for (i = client->report_index; i < client->num_reports && (index == HIDS_CLIENT_INVALID_REPORT_INDEX); i++){
403                 hids_client_report_t report = client->reports[i];
404                 if (report.report_type != HID_REPORT_TYPE_INPUT){
405                     continue;
406                 }
407                 if (report.boot_report){
408                     index = i;
409                 }
410             }
411             break;
412 
413         default:
414             break;
415     }
416 
417     client->report_index = index;
418     return index;
419 }
420 
421 static bool hids_client_report_next_notification_report_index(hids_client_t * client){
422     client->report_index++;
423     if (hids_client_get_next_notification_report_index(client) != HIDS_CLIENT_INVALID_REPORT_INDEX){
424         client->state = HIDS_CLIENT_STATE_W2_ENABLE_INPUT_REPORTS;
425         return true;
426     }
427     return false;
428 }
429 
430 static bool hids_client_report_notifications_init(hids_client_t * client){
431     client->report_index = 0;
432 
433     if (hids_client_get_next_notification_report_index(client) != HIDS_CLIENT_INVALID_REPORT_INDEX){
434         client->state = HIDS_CLIENT_STATE_W2_ENABLE_INPUT_REPORTS;
435         return true;
436     }
437     return false;
438 }
439 
440 static hids_client_t * hids_create_client(hci_con_handle_t con_handle, uint16_t cid){
441     hids_client_t * client = btstack_memory_hids_client_get();
442     if (!client){
443         log_error("Not enough memory to create client");
444         return NULL;
445     }
446     client->state = HIDS_CLIENT_STATE_IDLE;
447     client->cid = cid;
448     client->con_handle = con_handle;
449 
450     btstack_linked_list_add(&clients, (btstack_linked_item_t *) client);
451     return client;
452 }
453 
454 static void hids_finalize_client(hids_client_t * client){
455     // stop listening
456     uint8_t i;
457     for (i = 0; i < client->num_reports; i++){
458         gatt_client_stop_listening_for_characteristic_value_updates(&client->reports[i].notification_listener);
459     }
460 
461     hids_client_descriptor_storage_delete(client);
462     btstack_linked_list_remove(&clients, (btstack_linked_item_t *) client);
463     btstack_memory_hids_client_free(client);
464 }
465 
466 
467 static void hids_emit_connection_established(hids_client_t * client, uint8_t status){
468     uint8_t event[8];
469     int pos = 0;
470     event[pos++] = HCI_EVENT_GATTSERVICE_META;
471     event[pos++] = sizeof(event) - 2;
472     event[pos++] = GATTSERVICE_SUBEVENT_HID_SERVICE_CONNECTED;
473     little_endian_store_16(event, pos, client->cid);
474     pos += 2;
475     event[pos++] = status;
476     event[pos++] = client->protocol_mode;
477     event[pos++] = client->num_instances;
478     (*client->client_handler)(HCI_EVENT_PACKET, 0, event, sizeof(event));
479 }
480 
481 static void hids_client_setup_report_event(hids_client_t * client, uint8_t report_index, uint8_t *buffer, uint16_t report_len){
482     uint16_t pos = 0;
483     buffer[pos++] = HCI_EVENT_GATTSERVICE_META;
484     pos++;  // skip len
485     buffer[pos++] = GATTSERVICE_SUBEVENT_HID_REPORT;
486     little_endian_store_16(buffer, pos, client->cid);
487     pos += 2;
488     buffer[pos++] = client->reports[report_index].service_index;
489     buffer[pos++] = client->reports[report_index].report_id;
490     little_endian_store_16(buffer, pos, report_len + 1);
491     pos += 2;
492     buffer[pos++] = client->reports[report_index].report_id;
493     buffer[1] = pos + report_len + 1 - 2;
494 }
495 
496 static void handle_report_hid_event(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size) {
497     UNUSED(packet_type);
498     UNUSED(channel);
499     UNUSED(size);
500     if (hci_event_packet_get_type(packet) != GATT_EVENT_NOTIFICATION) return;
501 
502     hids_client_t * client = hids_get_client_for_con_handle(gatt_event_notification_get_handle(packet));
503     btstack_assert(client != NULL);
504 
505     uint8_t report_index = find_report_index_for_value_handle(client, gatt_event_notification_get_value_handle(packet));
506     if (report_index == HIDS_CLIENT_INVALID_REPORT_INDEX){
507         return;
508     }
509 
510     uint8_t * in_place_event = &packet[-1];
511     hids_client_setup_report_event(client, report_index, in_place_event, gatt_event_notification_get_value_length(packet));
512 
513     (*client->client_handler)(HCI_EVENT_GATTSERVICE_META, client->cid, in_place_event, size);
514 }
515 
516 
517 static void hids_run_for_client(hids_client_t * client){
518     uint8_t att_status;
519     gatt_client_service_t service;
520     gatt_client_characteristic_t characteristic;
521 
522     switch (client->state){
523         case HIDS_CLIENT_STATE_W2_QUERY_SERVICE:
524             client->state = HIDS_CLIENT_STATE_W4_SERVICE_RESULT;
525             att_status = gatt_client_discover_primary_services_by_uuid16(handle_gatt_client_event, client->con_handle, ORG_BLUETOOTH_SERVICE_HUMAN_INTERFACE_DEVICE);
526             // TODO handle status
527             UNUSED(att_status);
528             break;
529 
530         case HIDS_CLIENT_STATE_W2_QUERY_CHARACTERISTIC:
531             client->state = HIDS_CLIENT_STATE_W4_CHARACTERISTIC_RESULT;
532 
533             service.start_group_handle = client->services[client->service_index].start_handle;
534             service.end_group_handle = client->services[client->service_index].end_handle;
535             att_status = gatt_client_discover_characteristics_for_service(&handle_gatt_client_event, client->con_handle, &service);
536 
537             UNUSED(att_status);
538             break;
539 
540         case HIDS_CLIENT_STATE_W2_SET_BOOT_PROTOCOL_MODE:
541             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);
542             UNUSED(att_status);
543 
544             client->protocol_mode = client->required_protocol_mode;
545             if (hids_client_report_query_init(client)){
546                 break;
547             }
548 
549             hids_emit_connection_established(client, ERROR_CODE_UNSUPPORTED_FEATURE_OR_PARAMETER_VALUE);
550             hids_finalize_client(client);
551             break;
552 
553         case HIDS_CLIENT_W2_SEND_REPORT:{
554             client->state = HIDS_CLIENT_STATE_CONNECTED;
555 
556             att_status = gatt_client_write_value_of_characteristic_without_response(client->con_handle,
557                 client->reports[client->report_index].value_handle,
558                 client->report_len, (uint8_t *)client->report);
559             UNUSED(att_status);
560             break;
561         }
562 
563         case HIDS_CLIENT_STATE_W2_READ_REPORT_MAP_HID_DESCRIPTOR:
564             client->state = HIDS_CLIENT_STATE_W4_REPORT_MAP_HID_DESCRIPTOR;
565             att_status = gatt_client_read_value_of_characteristic_using_value_handle(&handle_gatt_client_event, client->con_handle, client->services[client->service_index].report_map_value_handle);
566             UNUSED(att_status);
567             break;
568 
569         case HIDS_CLIENT_STATE_W2_REPORT_MAP_DISCOVER_CHARACTERISTIC_DESCRIPTORS:
570             client->state = HIDS_CLIENT_STATE_W4_REPORT_MAP_CHARACTERISTIC_DESCRIPTORS_RESULT;
571 
572             characteristic.value_handle = client->services[client->service_index].report_map_value_handle;
573             characteristic.end_handle = client->services[client->service_index].report_map_end_handle;
574 
575             att_status = gatt_client_discover_characteristic_descriptors(&handle_gatt_client_event, client->con_handle, &characteristic);
576             UNUSED(att_status);
577             break;
578 
579         case HIDS_CLIENT_STATE_W2_REPORT_MAP_READ_EXTERNAL_REPORT_REFERENCE_UUID:
580             client->state = HIDS_CLIENT_STATE_W4_REPORT_MAP_EXTERNAL_REPORT_REFERENCE_UUID;
581 
582             att_status = gatt_client_read_characteristic_descriptor_using_descriptor_handle(&handle_gatt_client_event, client->con_handle, client->reports[client->report_index].value_handle);
583             UNUSED(att_status);
584             break;
585 
586         case HIDS_CLIENT_STATE_W2_DISCOVER_EXTERNAL_REPORT_CHARACTERISTIC:
587             client->state = HIDS_CLIENT_STATE_W4_EXTERNAL_REPORT_CHARACTERISTIC_RESULT;
588 
589             service.start_group_handle = 0x0001;
590             service.end_group_handle = 0xffff;
591             att_status = gatt_client_discover_characteristics_for_service(&handle_gatt_client_event, client->con_handle, &service);
592             UNUSED(att_status);
593             break;
594 
595         case HIDS_CLIENT_STATE_W2_FIND_REPORT:
596             client->state = HIDS_CLIENT_STATE_W4_REPORT_FOUND;
597             client->descriptor_handle = 0;
598             hids_client_get_characteristic_for_report_index(client, client->report_index, &characteristic);
599             att_status = gatt_client_discover_characteristic_descriptors(&handle_gatt_client_event, client->con_handle, &characteristic);
600             UNUSED(att_status);
601             break;
602 
603         case HIDS_CLIENT_STATE_W2_READ_REPORT_ID_AND_TYPE:
604             client->state = HIDS_CLIENT_STATE_W4_REPORT_ID_AND_TYPE;
605 
606             att_status = gatt_client_read_characteristic_descriptor_using_descriptor_handle(&handle_gatt_client_event, client->con_handle, client->descriptor_handle);
607             client->descriptor_handle = 0;
608             UNUSED(att_status);
609             break;
610 
611         case HIDS_CLIENT_STATE_W2_ENABLE_INPUT_REPORTS:
612             client->state = HIDS_CLIENT_STATE_W4_INPUT_REPORTS_ENABLED;
613 
614             characteristic.value_handle = client->reports[client->report_index].value_handle;
615             characteristic.end_handle = client->reports[client->report_index].end_handle;
616             characteristic.properties = client->reports[client->report_index].properties;
617 
618             att_status = gatt_client_write_client_characteristic_configuration(&handle_gatt_client_event, client->con_handle, &characteristic, GATT_CLIENT_CHARACTERISTICS_CONFIGURATION_NOTIFICATION);
619 
620             if (att_status != ERROR_CODE_SUCCESS){
621                 if (hids_client_report_next_notification_report_index(client)){
622                     hids_run_for_client(client);
623                     break;
624                 }
625                 client->state = HIDS_CLIENT_STATE_CONNECTED;
626                 hids_emit_connection_established(client, ERROR_CODE_SUCCESS);
627             } else {
628                 gatt_client_listen_for_characteristic_value_updates(
629                     &client->reports[client->report_index].notification_listener,
630                     &handle_report_hid_event, client->con_handle, &characteristic);
631 
632                 client->state = HIDS_CLIENT_STATE_CONNECTED;
633                 hids_emit_connection_established(client, ERROR_CODE_SUCCESS);
634             }
635             UNUSED(att_status);
636             break;
637 
638         default:
639             break;
640     }
641 }
642 
643 
644 static void handle_gatt_client_event(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
645     UNUSED(packet_type);
646     UNUSED(channel);
647     UNUSED(size);
648 
649     hids_client_t * client = NULL;
650     uint8_t att_status;
651     gatt_client_service_t service;
652     gatt_client_characteristic_t characteristic;
653     gatt_client_characteristic_descriptor_t characteristic_descriptor;
654 
655     // hids_client_report_t * boot_keyboard_report;
656     // hids_client_report_t * boot_mouse_report;
657     const uint8_t * characteristic_descriptor_value;
658     uint8_t i;
659     uint8_t report_index;
660 
661     const uint8_t * descriptor;
662     uint16_t descriptor_len;
663 
664     switch(hci_event_packet_get_type(packet)){
665         case GATT_EVENT_SERVICE_QUERY_RESULT:
666             client = hids_get_client_for_con_handle(gatt_event_service_query_result_get_handle(packet));
667             btstack_assert(client != NULL);
668 
669             if (client->state != HIDS_CLIENT_STATE_W4_SERVICE_RESULT) {
670                 hids_emit_connection_established(client, GATT_CLIENT_IN_WRONG_STATE);
671                 hids_finalize_client(client);
672                 break;
673             }
674 
675             if (client->num_instances < MAX_NUM_HID_SERVICES){
676                 uint8_t index = client->num_instances;
677                 gatt_event_service_query_result_get_service(packet, &service);
678                 client->services[index].start_handle = service.start_group_handle;
679                 client->services[index].end_handle = service.end_group_handle;
680                 client->num_instances++;
681 
682 #ifdef ENABLE_TESTING_SUPPORT
683                 printf("HID Service: start handle 0x%04X, end handle 0x%04X\n", client->services[index].start_handle, client->services[index].end_handle);
684 #endif
685                 hids_client_descriptor_storage_init(client, index);
686             }  else {
687                 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);
688             }
689             break;
690 
691         case GATT_EVENT_CHARACTERISTIC_QUERY_RESULT:
692             client = hids_get_client_for_con_handle(gatt_event_characteristic_query_result_get_handle(packet));
693             btstack_assert(client != NULL);
694             gatt_event_characteristic_query_result_get_characteristic(packet, &characteristic);
695 
696             switch (client->state){
697                 case HIDS_CLIENT_STATE_W4_EXTERNAL_REPORT_CHARACTERISTIC_RESULT:
698                     // update value handle od external reports, set type to reserved so that will be inlcuded in ID,TYPE update in hte next step
699                     for (i = 0; i < client->num_reports; i++){
700                         if (client->reports[i].external_report_reference_uuid == characteristic.uuid16){
701                             client->reports[i].report_id = HID_REPORT_MODE_REPORT_ID;
702                             client->reports[i].report_type = HID_REPORT_TYPE_RESERVED;
703                             client->reports[i].properties = characteristic.properties;
704                             client->reports[i].value_handle = characteristic.value_handle;
705                             client->reports[i].end_handle = characteristic.end_handle;
706                         }
707                     }
708                     break;
709 
710                 default:
711                     switch (characteristic.uuid16){
712                         case ORG_BLUETOOTH_CHARACTERISTIC_PROTOCOL_MODE:
713                             client->protocol_mode_value_handle = characteristic.value_handle;
714                             break;
715 
716                         case ORG_BLUETOOTH_CHARACTERISTIC_BOOT_KEYBOARD_INPUT_REPORT:
717                             hids_client_add_characteristic(client, &characteristic, HID_BOOT_MODE_KEYBOARD_ID, HID_REPORT_TYPE_INPUT, true);
718                             break;
719 
720                         case ORG_BLUETOOTH_CHARACTERISTIC_BOOT_MOUSE_INPUT_REPORT:
721                             hids_client_add_characteristic(client, &characteristic, HID_BOOT_MODE_MOUSE_ID, HID_REPORT_TYPE_INPUT, true);
722                             break;
723 
724                         case ORG_BLUETOOTH_CHARACTERISTIC_BOOT_KEYBOARD_OUTPUT_REPORT:
725                             hids_client_add_characteristic(client, &characteristic, HID_BOOT_MODE_KEYBOARD_ID, HID_REPORT_TYPE_OUTPUT, false);
726                             break;
727 
728                         case ORG_BLUETOOTH_CHARACTERISTIC_REPORT:
729                             hids_client_add_characteristic(client, &characteristic, HID_REPORT_MODE_REPORT_ID, HID_REPORT_TYPE_RESERVED, false);
730                             break;
731 
732                         case ORG_BLUETOOTH_CHARACTERISTIC_REPORT_MAP:
733                             client->services[client->service_index].report_map_value_handle = characteristic.value_handle;
734                             client->services[client->service_index].report_map_end_handle = characteristic.end_handle;
735                             break;
736 
737                         case ORG_BLUETOOTH_CHARACTERISTIC_HID_INFORMATION:
738                             // printf("ORG_BLUETOOTH_CHARACTERISTIC_HID_INFORMATION\n");
739                             break;
740 
741                         case ORG_BLUETOOTH_CHARACTERISTIC_HID_CONTROL_POINT:
742                             // printf("ORG_BLUETOOTH_CHARACTERISTIC_HID_CONTROL_POINT\n");
743                             break;
744                         default:
745                             break;
746                 }
747             }
748 
749             break;
750 
751         case GATT_EVENT_CHARACTERISTIC_VALUE_QUERY_RESULT:
752             // Map Report characteristic value == HID Descriptor
753             client = hids_get_client_for_con_handle(gatt_event_characteristic_value_query_result_get_handle(packet));
754             btstack_assert(client != NULL);
755 
756             descriptor_len = gatt_event_characteristic_value_query_result_get_value_length(packet);
757             descriptor = gatt_event_characteristic_value_query_result_get_value(packet);
758 
759             for (i = 0; i < descriptor_len; i++){
760                 bool stored = hids_client_descriptor_storage_store(client, client->service_index, descriptor[i]);
761                 if (!stored){
762                     client->services[client->service_index].hid_descriptor_status = ERROR_CODE_MEMORY_CAPACITY_EXCEEDED;
763                     break;
764                 }
765             }
766             break;
767 
768         case GATT_EVENT_ALL_CHARACTERISTIC_DESCRIPTORS_QUERY_RESULT:
769             client = hids_get_client_for_con_handle(gatt_event_all_characteristic_descriptors_query_result_get_handle(packet));
770             btstack_assert(client != NULL);
771             gatt_event_all_characteristic_descriptors_query_result_get_characteristic_descriptor(packet, &characteristic_descriptor);
772 
773             switch (client->state) {
774                 case HIDS_CLIENT_STATE_W4_REPORT_MAP_CHARACTERISTIC_DESCRIPTORS_RESULT:
775                     // setup for descriptor value query
776                     if (characteristic_descriptor.uuid16 == ORG_BLUETOOTH_DESCRIPTOR_EXTERNAL_REPORT_REFERENCE){
777                         report_index = hids_client_add_characteristic(client, &characteristic, HID_REPORT_MODE_REPORT_MAP_ID, HID_REPORT_TYPE_RESERVED, false);
778 
779                         if (report_index != HIDS_CLIENT_INVALID_REPORT_INDEX){
780                             client->reports[report_index].value_handle = characteristic_descriptor.handle;
781                             client->reports[report_index].service_index = client->service_index;
782                         }
783 
784                     }
785                     break;
786                 case HIDS_CLIENT_STATE_W4_REPORT_FOUND:
787                     // setup for descriptor value query
788                     if (characteristic_descriptor.uuid16 == ORG_BLUETOOTH_DESCRIPTOR_REPORT_REFERENCE){
789                         client->descriptor_handle = characteristic_descriptor.handle;
790                     }
791                     break;
792                 default:
793                     break;
794             }
795             break;
796 
797         case GATT_EVENT_CHARACTERISTIC_DESCRIPTOR_QUERY_RESULT:
798             client = hids_get_client_for_con_handle(gatt_event_characteristic_descriptor_query_result_get_handle(packet));
799             btstack_assert(client != NULL);
800 
801             if (gatt_event_characteristic_descriptor_query_result_get_descriptor_length(packet) != 2){
802                 break;
803             }
804 
805             characteristic_descriptor_value = gatt_event_characteristic_descriptor_query_result_get_descriptor(packet);
806             switch (client->state) {
807                 case HIDS_CLIENT_STATE_W4_REPORT_MAP_EXTERNAL_REPORT_REFERENCE_UUID:
808                     // get external report characteristic uuid
809                     report_index = find_report_index_for_value_handle(client, gatt_event_characteristic_descriptor_query_result_get_descriptor_handle(packet));
810                     if (report_index != HIDS_CLIENT_INVALID_REPORT_INDEX){
811                         client->reports[report_index].external_report_reference_uuid = little_endian_read_16(characteristic_descriptor_value, 0);
812                     }
813                     break;
814 
815                 case HIDS_CLIENT_STATE_W4_REPORT_ID_AND_TYPE:
816                     client->reports[client->report_index].report_id = characteristic_descriptor_value[0];
817                     client->reports[client->report_index].report_type = (hid_report_type_t)characteristic_descriptor_value[1];
818                     log_info("update index %d, id %d, type %d, value handle 0x%02x",
819                         client->report_index,
820                         client->reports[client->report_index].report_id,
821                         client->reports[client->report_index].report_type,
822                         client->reports[client->report_index].value_handle);
823 
824                     break;
825 
826                 default:
827                     break;
828             }
829             break;
830 
831         case GATT_EVENT_QUERY_COMPLETE:
832             client = hids_get_client_for_con_handle(gatt_event_query_complete_get_handle(packet));
833             btstack_assert(client != NULL);
834 
835             att_status = gatt_event_query_complete_get_att_status(packet);
836 
837             switch (client->state){
838                 case HIDS_CLIENT_STATE_W4_SERVICE_RESULT:
839                     if (att_status != ATT_ERROR_SUCCESS){
840                         hids_emit_connection_established(client, att_status);
841                         hids_finalize_client(client);
842                         break;
843                     }
844 
845                     if (client->num_instances == 0){
846                         hids_emit_connection_established(client, ERROR_CODE_UNSUPPORTED_FEATURE_OR_PARAMETER_VALUE);
847                         hids_finalize_client(client);
848                         break;
849                     }
850 
851                     client->state = HIDS_CLIENT_STATE_W2_QUERY_CHARACTERISTIC;
852                     client->service_index = 0;
853                     break;
854 
855                 case HIDS_CLIENT_STATE_W4_CHARACTERISTIC_RESULT:
856                     if (att_status != ATT_ERROR_SUCCESS){
857                         hids_emit_connection_established(client, att_status);
858                         hids_finalize_client(client);
859                         break;
860                     }
861 
862                     if ((client->service_index + 1) < client->num_instances){
863                         // discover characteristics of next service
864                         client->service_index++;
865                         client->state = HIDS_CLIENT_STATE_W2_QUERY_CHARACTERISTIC;
866                         break;
867                     }
868 
869                     switch (client->required_protocol_mode){
870                         case HID_PROTOCOL_MODE_REPORT:
871                             client->protocol_mode = HID_PROTOCOL_MODE_REPORT;
872                             if (hid_clients_has_reports_in_report_mode(client)){
873                                 client->protocol_mode = HID_PROTOCOL_MODE_REPORT;
874                                 break;
875                             }
876                             hids_emit_connection_established(client, att_status);
877                             hids_finalize_client(client);
878                             return;
879 
880                         case HID_PROTOCOL_MODE_REPORT_WITH_FALLBACK_TO_BOOT:
881                             if (hid_clients_has_reports_in_report_mode(client)){
882                                 client->protocol_mode = HID_PROTOCOL_MODE_REPORT;
883                                 break;
884                             }
885                             if (hid_clients_has_reports_in_boot_mode(client)){
886                                 if (client->protocol_mode_value_handle != 0){
887                                     client->state = HIDS_CLIENT_STATE_W2_SET_BOOT_PROTOCOL_MODE;
888                                     break;
889                                 }
890                                 hids_emit_connection_established(client, att_status);
891                                 hids_finalize_client(client);
892                                 return;
893                             }
894                             break;
895                         default:
896                             if (hid_clients_has_reports_in_boot_mode(client)){
897                                 if (client->protocol_mode_value_handle != 0){
898                                     client->state = HIDS_CLIENT_STATE_W2_SET_BOOT_PROTOCOL_MODE;
899                                     break;
900                                 }
901                                 hids_emit_connection_established(client, att_status);
902                                 hids_finalize_client(client);
903                                 return;
904                             }
905                             break;
906                     }
907 
908                     if (client->state == HIDS_CLIENT_STATE_W2_SET_BOOT_PROTOCOL_MODE){
909                         break;
910                     }
911 
912                     // 1. we need to get HID Descriptor and
913                     // 2. get external Report characteristics if referenced from Report Map
914                     if (hids_client_report_map_query_init(client)){
915                         break;
916                     }
917                     hids_emit_connection_established(client, ERROR_CODE_UNSUPPORTED_FEATURE_OR_PARAMETER_VALUE);
918                     hids_finalize_client(client);
919                     break;
920 
921 
922                 // HID descriptor found
923                 case HIDS_CLIENT_STATE_W4_REPORT_MAP_HID_DESCRIPTOR:
924                     if (att_status != ATT_ERROR_SUCCESS){
925                         hids_emit_connection_established(client, att_status);
926                         hids_finalize_client(client);
927                         break;
928                     }
929                     client->state = HIDS_CLIENT_STATE_W2_REPORT_MAP_DISCOVER_CHARACTERISTIC_DESCRIPTORS;
930                     break;
931 
932                 // found all descriptors, check if there is one with EXTERNAL_REPORT_REFERENCE
933                 case HIDS_CLIENT_STATE_W4_REPORT_MAP_CHARACTERISTIC_DESCRIPTORS_RESULT:
934                     // go for next report map
935                     if (hids_client_report_query_next_report_map(client)){
936                         break;
937                     }
938 
939                     // read UUIDS for external characteristics
940                     if (hids_client_report_map_uuid_query_init(client)){
941                         break;
942                     }
943 
944                     // discover characteristic descriptor for all Report characteristics,
945                     // then read value of characteristic descriptor to get Report ID
946                     if (hids_client_report_query_init(client)){
947                         break;
948                     }
949 
950                     hids_emit_connection_established(client, ERROR_CODE_UNSUPPORTED_FEATURE_OR_PARAMETER_VALUE);
951                     hids_finalize_client(client);
952                     break;
953 
954                 case HIDS_CLIENT_STATE_W4_REPORT_MAP_EXTERNAL_REPORT_REFERENCE_UUID:
955                     // go for next map report
956                     if (hids_client_report_query_next_report_map_uuid(client)){
957                         break;
958                     }
959 
960                     // update external characteristics with correct value handle and end handle
961                     client->state = HIDS_CLIENT_STATE_W2_DISCOVER_EXTERNAL_REPORT_CHARACTERISTIC;
962                     break;
963 
964                 case HIDS_CLIENT_STATE_W4_EXTERNAL_REPORT_CHARACTERISTIC_RESULT:
965                     // discover characteristic descriptor for all Report characteristics,
966                     // then read value of characteristic descriptor to get Report ID
967                     if (hids_client_report_query_init(client)){
968                         break;
969                     }
970 
971                     hids_emit_connection_established(client, ERROR_CODE_UNSUPPORTED_FEATURE_OR_PARAMETER_VALUE);
972                     hids_finalize_client(client);
973                     break;
974 
975                 case HIDS_CLIENT_STATE_W4_REPORT_FOUND:
976                     if (client->descriptor_handle != 0){
977                         // descriptor found
978                         client->state = HIDS_CLIENT_STATE_W2_READ_REPORT_ID_AND_TYPE;
979                         break;
980                     }
981 
982                     // go for next report
983                     if (hids_client_report_query_next_report(client)){
984                         break;
985                     }
986 
987                     // TODO continue with report mode
988                     hids_emit_connection_established(client, ERROR_CODE_SUCCESS);
989                     break;
990 
991                 case HIDS_CLIENT_STATE_W4_REPORT_ID_AND_TYPE:
992                     // go for next report
993                     if (hids_client_report_query_next_report(client)){
994                         break;
995                     }
996 
997                     if (hids_client_report_notifications_init(client)){
998                         break;
999                     }
1000                     hids_emit_connection_established(client, ERROR_CODE_SUCCESS);
1001                     break;
1002 
1003                 case HIDS_CLIENT_STATE_W4_INPUT_REPORTS_ENABLED:
1004                     if (hids_client_report_next_notification_report_index(client)){
1005                         break;
1006                     }
1007                     hids_emit_connection_established(client, ERROR_CODE_SUCCESS);
1008                     break;
1009 
1010                 default:
1011                     break;
1012             }
1013             break;
1014 
1015         default:
1016             break;
1017     }
1018 
1019     if (client != NULL){
1020         hids_run_for_client(client);
1021     }
1022 }
1023 
1024 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){
1025     btstack_assert(packet_handler != NULL);
1026 
1027     hids_client_t * client = hids_get_client_for_con_handle(con_handle);
1028     if (client != NULL){
1029         return ERROR_CODE_COMMAND_DISALLOWED;
1030     }
1031 
1032     uint16_t cid = hids_get_next_cid();
1033     if (hids_cid != NULL) {
1034         *hids_cid = cid;
1035     }
1036 
1037     client = hids_create_client(con_handle, cid);
1038     if (client == NULL) {
1039         return BTSTACK_MEMORY_ALLOC_FAILED;
1040     }
1041 
1042     client->required_protocol_mode = protocol_mode;
1043     client->client_handler = packet_handler;
1044     client->state = HIDS_CLIENT_STATE_W2_QUERY_SERVICE;
1045 
1046     hids_run_for_client(client);
1047     return ERROR_CODE_SUCCESS;
1048 }
1049 
1050 uint8_t hids_client_disconnect(uint16_t hids_cid){
1051     hids_client_t * client = hids_get_client_for_cid(hids_cid);
1052     if (client == NULL){
1053         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
1054     }
1055     // finalize connection
1056     hids_finalize_client(client);
1057     return ERROR_CODE_SUCCESS;
1058 }
1059 
1060 uint8_t hids_client_send_report(uint16_t hids_cid, uint8_t report_id, const uint8_t * report, uint8_t report_len){
1061     hids_client_t * client = hids_get_client_for_cid(hids_cid);
1062     if (client == NULL){
1063         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
1064     }
1065 
1066     if (client->state != HIDS_CLIENT_STATE_CONNECTED) {
1067         return ERROR_CODE_COMMAND_DISALLOWED;
1068     }
1069 
1070     uint8_t report_index = find_report_index_for_report_id_and_type(client, report_id, HID_REPORT_TYPE_OUTPUT);
1071     if (report_index == HIDS_CLIENT_INVALID_REPORT_INDEX){
1072         return ERROR_CODE_UNSUPPORTED_FEATURE_OR_PARAMETER_VALUE;
1073     }
1074 
1075     uint16_t mtu;
1076     uint8_t status = gatt_client_get_mtu(client->con_handle, &mtu);
1077 
1078     if (status != ERROR_CODE_SUCCESS){
1079         return status;
1080     }
1081 
1082     if (mtu - 2 < report_len){
1083         return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE;
1084     }
1085 
1086     client->state = HIDS_CLIENT_W2_SEND_REPORT;
1087     client->report_index = report_index;
1088     client->report = report;
1089     client->report_len = report_len;
1090 
1091     hids_run_for_client(client);
1092     return ERROR_CODE_SUCCESS;
1093 }
1094 
1095 void hids_client_init(uint8_t * hid_descriptor_storage, uint16_t hid_descriptor_storage_len){
1096     hids_client_descriptor_storage = hid_descriptor_storage;
1097     hids_client_descriptor_storage_len = hid_descriptor_storage_len;
1098 }
1099 
1100 void hids_client_deinit(void){}
1101