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_input_report_index_for_report_id(hids_client_t * client, uint8_t report_id){ 254 uint8_t i; 255 switch (client->protocol_mode){ 256 case HID_PROTOCOL_MODE_BOOT: 257 for (i = 0; i < client->num_reports; i++){ 258 if (!client->reports[i].boot_report){ 259 continue; 260 } 261 if ((client->reports[i].report_id == report_id) && (client->reports[i].report_type != HID_REPORT_TYPE_OUTPUT)){ 262 return i; 263 } 264 } 265 break; 266 267 default: 268 for (i = 0; i < client->num_reports; i++){ 269 if (client->reports[i].boot_report){ 270 continue; 271 } 272 if ((client->reports[i].report_id == report_id) && (client->reports[i].report_type != HID_REPORT_TYPE_OUTPUT)){ 273 return i; 274 } 275 } 276 break; 277 } 278 return HIDS_CLIENT_INVALID_REPORT_INDEX; 279 } 280 281 282 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){ 283 uint8_t i; 284 switch (client->protocol_mode){ 285 case HID_PROTOCOL_MODE_BOOT: 286 for (i = 0; i < client->num_reports; i++){ 287 if (!client->reports[i].boot_report){ 288 continue; 289 } 290 if ((client->reports[i].report_id == report_id) && (client->reports[i].report_type == report_type)){ 291 return i; 292 } 293 } 294 break; 295 296 default: 297 for (i = 0; i < client->num_reports; i++){ 298 if (client->reports[i].boot_report){ 299 continue; 300 } 301 if ((client->reports[i].report_id == report_id) && (client->reports[i].report_type == report_type)){ 302 return i; 303 } 304 } 305 break; 306 } 307 return HIDS_CLIENT_INVALID_REPORT_INDEX; 308 } 309 310 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){ 311 312 uint8_t report_index = find_external_report_index_for_value_handle(client, characteristic->value_handle); 313 if (report_index != HIDS_CLIENT_INVALID_REPORT_INDEX){ 314 return report_index; 315 } 316 report_index = client->num_reports; 317 318 if (report_index < HIDS_CLIENT_NUM_REPORTS) { 319 client->reports[report_index].value_handle = characteristic->value_handle; 320 client->reports[report_index].end_handle = characteristic->end_handle; 321 client->reports[report_index].properties = characteristic->properties; 322 323 client->reports[report_index].service_index = client->service_index; 324 client->reports[report_index].report_id = report_id; 325 client->reports[report_index].report_type = report_type; 326 client->reports[report_index].boot_report = boot_report; 327 328 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); 329 client->num_reports++; 330 return report_index; 331 } else { 332 log_info("not enough storage, increase HIDS_CLIENT_NUM_REPORTS"); 333 return HIDS_CLIENT_INVALID_REPORT_INDEX; 334 } 335 } 336 337 static uint8_t hids_client_add_external_report(hids_client_t * client, gatt_client_characteristic_descriptor_t * characteristic_descriptor){ 338 uint8_t report_index = client->num_external_reports; 339 340 if (report_index < HIDS_CLIENT_NUM_REPORTS) { 341 client->external_reports[report_index].value_handle = characteristic_descriptor->handle; 342 client->external_reports[report_index].service_index = client->service_index; 343 344 client->num_external_reports++; 345 log_info("add external index %d [%d], value handle 0x%02x", report_index, client->num_external_reports, characteristic_descriptor->handle); 346 return report_index; 347 } else { 348 log_info("not enough storage, increase HIDS_CLIENT_NUM_REPORTS"); 349 return HIDS_CLIENT_INVALID_REPORT_INDEX; 350 } 351 } 352 353 354 static bool hid_clients_has_reports_in_report_mode(hids_client_t * client){ 355 uint8_t i; 356 for (i = 0; i < client->num_reports; i++){ 357 if (!client->reports[i].boot_report){ 358 return true; 359 } 360 } 361 return false; 362 } 363 364 static bool hid_clients_has_reports_in_boot_mode(hids_client_t * client){ 365 uint8_t i; 366 for (i = 0; i < client->num_reports; i++){ 367 if (client->reports[i].boot_report){ 368 return true; 369 } 370 } 371 return false; 372 } 373 374 static uint8_t hids_client_get_next_active_report_map_index(hids_client_t * client){ 375 uint8_t i; 376 for (i = client->service_index; i < client->num_instances; i++){ 377 if (client->services[i].report_map_value_handle != 0){ 378 return i; 379 } 380 } 381 client->service_index = HIDS_CLIENT_INVALID_REPORT_INDEX; 382 return HIDS_CLIENT_INVALID_REPORT_INDEX; 383 } 384 385 static bool hids_client_report_query_next_report_map(hids_client_t * client){ 386 client->service_index++; 387 if (hids_client_get_next_active_report_map_index(client) != HIDS_CLIENT_INVALID_REPORT_INDEX){ 388 client->state = HIDS_CLIENT_STATE_W2_READ_REPORT_MAP_HID_DESCRIPTOR; 389 return true; 390 } 391 return false; 392 } 393 394 static bool hids_client_report_map_query_init(hids_client_t * client){ 395 client->service_index = 0; 396 397 if (hids_client_get_next_active_report_map_index(client) != HIDS_CLIENT_INVALID_REPORT_INDEX){ 398 client->state = HIDS_CLIENT_STATE_W2_READ_REPORT_MAP_HID_DESCRIPTOR; 399 return true; 400 } 401 return false; 402 } 403 404 static bool hids_client_report_query_next_report_map_uuid(hids_client_t * client){ 405 client->report_index++; 406 if (client->report_index < client->num_external_reports){ 407 client->state = HIDS_CLIENT_STATE_W2_REPORT_MAP_READ_EXTERNAL_REPORT_REFERENCE_UUID; 408 return true; 409 } 410 return false; 411 } 412 413 static bool hids_client_report_map_uuid_query_init(hids_client_t * client){ 414 client->report_index = 0; 415 if (client->num_external_reports > 0){ 416 client->state = HIDS_CLIENT_STATE_W2_REPORT_MAP_READ_EXTERNAL_REPORT_REFERENCE_UUID; 417 return true; 418 } 419 return false; 420 } 421 422 static uint8_t hids_client_get_next_report_index(hids_client_t * client){ 423 uint8_t i; 424 uint8_t index = HIDS_CLIENT_INVALID_REPORT_INDEX; 425 switch (client->protocol_mode){ 426 case HID_PROTOCOL_MODE_REPORT: 427 for (i = client->report_index; i < client->num_reports && (index == HIDS_CLIENT_INVALID_REPORT_INDEX); i++){ 428 hids_client_report_t report = client->reports[i]; 429 if (report.report_type == HID_REPORT_TYPE_RESERVED && report.report_id == HID_REPORT_MODE_REPORT_ID){ 430 index = i; 431 client->service_index = report.service_index; 432 } 433 } 434 break; 435 case HID_PROTOCOL_MODE_BOOT: 436 for (i = client->report_index; i < client->num_reports && (index == HIDS_CLIENT_INVALID_REPORT_INDEX); i++){ 437 hids_client_report_t report = client->reports[i]; 438 if (report.boot_report){ 439 index = i; 440 client->service_index = report.service_index; 441 } 442 } 443 break; 444 default: 445 break; 446 } 447 448 client->report_index = index; 449 return index; 450 } 451 452 static bool hids_client_report_query_next_report(hids_client_t * client){ 453 client->report_index++; 454 if (hids_client_get_next_report_index(client) != HIDS_CLIENT_INVALID_REPORT_INDEX){ 455 client->state = HIDS_CLIENT_STATE_W2_FIND_REPORT; 456 return true; 457 } 458 return false; 459 } 460 461 static bool hids_client_report_query_init(hids_client_t * client){ 462 client->report_index = 0; 463 464 if (hids_client_get_next_report_index(client) != HIDS_CLIENT_INVALID_REPORT_INDEX){ 465 client->state = HIDS_CLIENT_STATE_W2_FIND_REPORT; 466 return true; 467 } 468 return false; 469 } 470 471 static uint8_t hids_client_get_next_notification_report_index(hids_client_t * client){ 472 uint8_t i; 473 uint8_t index = HIDS_CLIENT_INVALID_REPORT_INDEX; 474 475 switch (client->protocol_mode){ 476 case HID_PROTOCOL_MODE_REPORT: 477 for (i = client->report_index; i < client->num_reports && (index == HIDS_CLIENT_INVALID_REPORT_INDEX); i++){ 478 hids_client_report_t report = client->reports[i]; 479 if (report.report_type != HID_REPORT_TYPE_INPUT){ 480 continue; 481 } 482 if (!report.boot_report){ 483 index = i; 484 } 485 } 486 break; 487 488 case HID_PROTOCOL_MODE_BOOT: 489 for (i = client->report_index; i < client->num_reports && (index == HIDS_CLIENT_INVALID_REPORT_INDEX); i++){ 490 hids_client_report_t report = client->reports[i]; 491 if (report.report_type != HID_REPORT_TYPE_INPUT){ 492 continue; 493 } 494 if (report.boot_report){ 495 index = i; 496 } 497 } 498 break; 499 500 default: 501 break; 502 } 503 504 client->report_index = index; 505 return index; 506 } 507 508 static bool hids_client_report_next_notification_report_index(hids_client_t * client){ 509 client->report_index++; 510 if (hids_client_get_next_notification_report_index(client) != HIDS_CLIENT_INVALID_REPORT_INDEX){ 511 client->state = HIDS_CLIENT_STATE_W2_ENABLE_INPUT_REPORTS; 512 return true; 513 } 514 return false; 515 } 516 517 static bool hids_client_report_notifications_init(hids_client_t * client){ 518 client->report_index = 0; 519 520 if (hids_client_get_next_notification_report_index(client) != HIDS_CLIENT_INVALID_REPORT_INDEX){ 521 client->state = HIDS_CLIENT_STATE_W2_ENABLE_INPUT_REPORTS; 522 return true; 523 } 524 return false; 525 } 526 527 static hids_client_t * hids_create_client(hci_con_handle_t con_handle, uint16_t cid){ 528 hids_client_t * client = btstack_memory_hids_client_get(); 529 if (!client){ 530 log_error("Not enough memory to create client"); 531 return NULL; 532 } 533 client->state = HIDS_CLIENT_STATE_IDLE; 534 client->cid = cid; 535 client->con_handle = con_handle; 536 537 btstack_linked_list_add(&clients, (btstack_linked_item_t *) client); 538 return client; 539 } 540 541 static void hids_finalize_client(hids_client_t * client){ 542 // stop listening 543 uint8_t i; 544 for (i = 0; i < client->num_reports; i++){ 545 gatt_client_stop_listening_for_characteristic_value_updates(&client->reports[i].notification_listener); 546 } 547 548 hids_client_descriptor_storage_delete(client); 549 btstack_linked_list_remove(&clients, (btstack_linked_item_t *) client); 550 btstack_memory_hids_client_free(client); 551 } 552 553 554 static void hids_emit_connection_established(hids_client_t * client, uint8_t status){ 555 uint8_t event[8]; 556 int pos = 0; 557 event[pos++] = HCI_EVENT_GATTSERVICE_META; 558 event[pos++] = sizeof(event) - 2; 559 event[pos++] = GATTSERVICE_SUBEVENT_HID_SERVICE_CONNECTED; 560 little_endian_store_16(event, pos, client->cid); 561 pos += 2; 562 event[pos++] = status; 563 event[pos++] = client->protocol_mode; 564 event[pos++] = client->num_instances; 565 (*client->client_handler)(HCI_EVENT_PACKET, 0, event, sizeof(event)); 566 } 567 568 static void hids_client_setup_report_event(hids_client_t * client, uint8_t report_index, uint8_t *buffer, uint16_t report_len){ 569 uint16_t pos = 0; 570 buffer[pos++] = HCI_EVENT_GATTSERVICE_META; 571 pos++; // skip len 572 buffer[pos++] = GATTSERVICE_SUBEVENT_HID_REPORT; 573 little_endian_store_16(buffer, pos, client->cid); 574 pos += 2; 575 buffer[pos++] = client->reports[report_index].service_index; 576 buffer[pos++] = client->reports[report_index].report_id; 577 little_endian_store_16(buffer, pos, report_len + 1); 578 pos += 2; 579 buffer[pos++] = client->reports[report_index].report_id; 580 buffer[1] = pos + (report_len + 1) - 2; 581 582 } 583 584 static void handle_notification_event(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size) { 585 UNUSED(packet_type); 586 UNUSED(channel); 587 588 if (hci_event_packet_get_type(packet) != GATT_EVENT_NOTIFICATION) return; 589 590 hids_client_t * client = hids_get_client_for_con_handle(gatt_event_notification_get_handle(packet)); 591 btstack_assert(client != NULL); 592 593 uint8_t report_index = find_report_index_for_value_handle(client, gatt_event_notification_get_value_handle(packet)); 594 if (report_index == HIDS_CLIENT_INVALID_REPORT_INDEX){ 595 return; 596 } 597 598 uint8_t * in_place_event = &packet[-2]; 599 hids_client_setup_report_event(client, report_index, in_place_event, gatt_event_notification_get_value_length(packet)); 600 (*client->client_handler)(HCI_EVENT_GATTSERVICE_META, client->cid, in_place_event, size + 2); 601 } 602 603 static void handle_report_event(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size) { 604 UNUSED(packet_type); 605 UNUSED(channel); 606 607 if (hci_event_packet_get_type(packet) != GATT_EVENT_CHARACTERISTIC_VALUE_QUERY_RESULT) return; 608 609 hids_client_t * client = hids_get_client_for_con_handle(gatt_event_characteristic_value_query_result_get_handle(packet)); 610 btstack_assert(client != NULL); 611 612 if (client->state != HIDS_CLIENT_W4_GET_REPORT_RESULT){ 613 return; 614 } 615 client->state = HIDS_CLIENT_STATE_CONNECTED; 616 617 uint8_t report_index = find_report_index_for_value_handle(client, gatt_event_characteristic_value_query_result_get_value_handle(packet)); 618 if (report_index == HIDS_CLIENT_INVALID_REPORT_INDEX){ 619 return; 620 } 621 622 uint8_t * in_place_event = &packet[-2]; 623 hids_client_setup_report_event(client, report_index, in_place_event, gatt_event_characteristic_value_query_result_get_value_length(packet)); 624 (*client->client_handler)(HCI_EVENT_GATTSERVICE_META, client->cid, in_place_event, size + 2); 625 } 626 627 static void hids_run_for_client(hids_client_t * client){ 628 uint8_t att_status; 629 gatt_client_service_t service; 630 gatt_client_characteristic_t characteristic; 631 632 switch (client->state){ 633 case HIDS_CLIENT_STATE_W2_QUERY_SERVICE: 634 #ifdef ENABLE_TESTING_SUPPORT 635 printf("\n\nQuery Services:\n"); 636 #endif 637 client->state = HIDS_CLIENT_STATE_W4_SERVICE_RESULT; 638 639 // result in GATT_EVENT_SERVICE_QUERY_RESULT 640 att_status = gatt_client_discover_primary_services_by_uuid16(handle_gatt_client_event, client->con_handle, ORG_BLUETOOTH_SERVICE_HUMAN_INTERFACE_DEVICE); 641 UNUSED(att_status); 642 break; 643 644 case HIDS_CLIENT_STATE_W2_QUERY_CHARACTERISTIC: 645 #ifdef ENABLE_TESTING_SUPPORT 646 printf("\n\nQuery Characteristics of service %d:\n", client->service_index); 647 #endif 648 client->state = HIDS_CLIENT_STATE_W4_CHARACTERISTIC_RESULT; 649 650 service.start_group_handle = client->services[client->service_index].start_handle; 651 service.end_group_handle = client->services[client->service_index].end_handle; 652 653 // result in GATT_EVENT_CHARACTERISTIC_QUERY_RESULT 654 att_status = gatt_client_discover_characteristics_for_service(&handle_gatt_client_event, client->con_handle, &service); 655 656 UNUSED(att_status); 657 break; 658 659 case HIDS_CLIENT_STATE_W2_SET_BOOT_PROTOCOL_MODE: 660 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); 661 UNUSED(att_status); 662 663 client->protocol_mode = client->required_protocol_mode; 664 if (hids_client_report_query_init(client)){ 665 break; 666 } 667 668 hids_emit_connection_established(client, ERROR_CODE_UNSUPPORTED_FEATURE_OR_PARAMETER_VALUE); 669 hids_finalize_client(client); 670 break; 671 672 case HIDS_CLIENT_STATE_W2_READ_REPORT_MAP_HID_DESCRIPTOR: 673 #ifdef ENABLE_TESTING_SUPPORT 674 printf("\n\nRead REPORT_MAP (Handle 0x%04X) HID Descriptor of service %d:\n", client->services[client->service_index].report_map_value_handle, client->service_index); 675 #endif 676 client->state = HIDS_CLIENT_STATE_W4_REPORT_MAP_HID_DESCRIPTOR; 677 678 // result in GATT_EVENT_LONG_CHARACTERISTIC_VALUE_QUERY_RESULT 679 att_status = gatt_client_read_long_value_of_characteristic_using_value_handle(&handle_gatt_client_event, client->con_handle, client->services[client->service_index].report_map_value_handle); 680 UNUSED(att_status); 681 break; 682 683 case HIDS_CLIENT_STATE_W2_REPORT_MAP_DISCOVER_CHARACTERISTIC_DESCRIPTORS: 684 #ifdef ENABLE_TESTING_SUPPORT 685 printf("\nDiscover REPORT_MAP (Handle 0x%04X) Characteristic Descriptors of service %d:\n", client->services[client->service_index].report_map_value_handle, client->service_index); 686 #endif 687 client->state = HIDS_CLIENT_STATE_W4_REPORT_MAP_CHARACTERISTIC_DESCRIPTORS_RESULT; 688 689 characteristic.value_handle = client->services[client->service_index].report_map_value_handle; 690 characteristic.end_handle = client->services[client->service_index].report_map_end_handle; 691 692 // result in GATT_EVENT_ALL_CHARACTERISTIC_DESCRIPTORS_QUERY_RESULT 693 att_status = gatt_client_discover_characteristic_descriptors(&handle_gatt_client_event, client->con_handle, &characteristic); 694 UNUSED(att_status); 695 break; 696 697 case HIDS_CLIENT_STATE_W2_REPORT_MAP_READ_EXTERNAL_REPORT_REFERENCE_UUID: 698 #ifdef ENABLE_TESTING_SUPPORT 699 printf("\nRead external chr UUID (Handle 0x%04X) Characteristic Descriptors, service index %d:\n", client->external_reports[client->report_index].value_handle, client->service_index); 700 #endif 701 client->state = HIDS_CLIENT_STATE_W4_REPORT_MAP_EXTERNAL_REPORT_REFERENCE_UUID; 702 703 // result in GATT_EVENT_CHARACTERISTIC_DESCRIPTOR_QUERY_RESULT 704 att_status = gatt_client_read_characteristic_descriptor_using_descriptor_handle(&handle_gatt_client_event, client->con_handle, client->external_reports[client->report_index].value_handle); 705 UNUSED(att_status); 706 break; 707 708 case HIDS_CLIENT_STATE_W2_DISCOVER_EXTERNAL_REPORT_CHARACTERISTIC: 709 #ifdef ENABLE_TESTING_SUPPORT 710 printf("\nDiscover External Report Characteristic:\n"); 711 #endif 712 client->state = HIDS_CLIENT_STATE_W4_EXTERNAL_REPORT_CHARACTERISTIC_RESULT; 713 714 service.start_group_handle = 0x0001; 715 service.end_group_handle = 0xffff; 716 717 // Result in GATT_EVENT_CHARACTERISTIC_QUERY_RESULT 718 att_status = gatt_client_discover_characteristics_for_service(&handle_gatt_client_event, client->con_handle, &service); 719 UNUSED(att_status); 720 break; 721 722 case HIDS_CLIENT_STATE_W2_FIND_REPORT: 723 #ifdef ENABLE_TESTING_SUPPORT 724 printf("\nQuery Report Characteristic Descriptors [%d, %d, 0x%04X]:\n", 725 client->report_index, 726 client->reports[client->report_index].service_index, 727 client->reports[client->report_index].value_handle); 728 #endif 729 client->state = HIDS_CLIENT_STATE_W4_REPORT_FOUND; 730 client->descriptor_handle = 0; 731 732 characteristic.value_handle = client->reports[client->report_index].value_handle; 733 characteristic.end_handle = client->reports[client->report_index].end_handle; 734 characteristic.properties = client->reports[client->report_index].properties; 735 736 // result in GATT_EVENT_ALL_CHARACTERISTIC_DESCRIPTORS_QUERY_RESULT 737 att_status = gatt_client_discover_characteristic_descriptors(&handle_gatt_client_event, client->con_handle, &characteristic); 738 UNUSED(att_status); 739 break; 740 741 case HIDS_CLIENT_STATE_W2_READ_REPORT_ID_AND_TYPE: 742 client->state = HIDS_CLIENT_STATE_W4_REPORT_ID_AND_TYPE; 743 744 // result in GATT_EVENT_CHARACTERISTIC_DESCRIPTOR_QUERY_RESULT 745 att_status = gatt_client_read_characteristic_descriptor_using_descriptor_handle(&handle_gatt_client_event, client->con_handle, client->descriptor_handle); 746 client->descriptor_handle = 0; 747 UNUSED(att_status); 748 break; 749 750 case HIDS_CLIENT_STATE_W2_ENABLE_INPUT_REPORTS: 751 client->state = HIDS_CLIENT_STATE_W4_INPUT_REPORTS_ENABLED; 752 753 characteristic.value_handle = client->reports[client->report_index].value_handle; 754 characteristic.end_handle = client->reports[client->report_index].end_handle; 755 characteristic.properties = client->reports[client->report_index].properties; 756 757 // end of write marked in GATT_EVENT_QUERY_COMPLETE 758 att_status = gatt_client_write_client_characteristic_configuration(&handle_gatt_client_event, client->con_handle, &characteristic, GATT_CLIENT_CHARACTERISTICS_CONFIGURATION_NOTIFICATION); 759 760 if (att_status != ERROR_CODE_SUCCESS){ 761 if (hids_client_report_next_notification_report_index(client)){ 762 hids_run_for_client(client); 763 break; 764 } 765 client->state = HIDS_CLIENT_STATE_CONNECTED; 766 hids_emit_connection_established(client, ERROR_CODE_SUCCESS); 767 } else { 768 gatt_client_listen_for_characteristic_value_updates( 769 &client->reports[client->report_index].notification_listener, 770 &handle_notification_event, client->con_handle, &characteristic); 771 772 client->state = HIDS_CLIENT_STATE_CONNECTED; 773 hids_emit_connection_established(client, ERROR_CODE_SUCCESS); 774 } 775 UNUSED(att_status); 776 break; 777 778 779 case HIDS_CLIENT_W2_SEND_REPORT: 780 781 #ifdef ENABLE_TESTING_SUPPORT 782 printf(" Send report [%d, %d, 0x%04X]:\n", 783 client->report_index, 784 client->reports[client->report_index].service_index, client->reports[client->report_index].value_handle); 785 #endif 786 787 client->state = HIDS_CLIENT_STATE_CONNECTED; 788 789 att_status = gatt_client_write_value_of_characteristic_without_response(client->con_handle, 790 client->reports[client->report_index].value_handle, 791 client->report_len, (uint8_t *)client->report); 792 UNUSED(att_status); 793 break; 794 795 case HIDS_CLIENT_W2_SEND_GET_REPORT: 796 #ifdef ENABLE_TESTING_SUPPORT 797 printf(" Get report [ID %d, Service %d, handle 0x%04X]:\n", 798 client->reports[client->report_index].report_id, 799 client->reports[client->report_index].service_index, client->reports[client->report_index].value_handle); 800 #endif 801 802 client->state = HIDS_CLIENT_W4_GET_REPORT_RESULT; 803 804 att_status = gatt_client_read_value_of_characteristic_using_value_handle( 805 &handle_report_event, 806 client->con_handle, 807 client->reports[client->report_index].value_handle); 808 UNUSED(att_status); 809 break; 810 811 #ifdef ENABLE_TESTING_SUPPORT 812 case HIDS_CLIENT_W2_READ_CHARACTERISTIC_CONFIGURATION: 813 client->state = HIDS_CLIENT_W4_CHARACTERISTIC_CONFIGURATION_RESULT; 814 815 // end of write marked in GATT_EVENT_QUERY_COMPLETE 816 att_status = gatt_client_read_value_of_characteristic_using_value_handle( 817 &handle_gatt_client_event, 818 client->con_handle, 819 client->reports[client->report_index].ccc_handle); 820 821 break; 822 #endif 823 824 default: 825 break; 826 } 827 } 828 829 static void handle_gatt_client_event(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ 830 UNUSED(packet_type); 831 UNUSED(channel); 832 UNUSED(size); 833 834 hids_client_t * client = NULL; 835 uint8_t att_status; 836 gatt_client_service_t service; 837 gatt_client_characteristic_t characteristic; 838 gatt_client_characteristic_descriptor_t characteristic_descriptor; 839 840 // hids_client_report_t * boot_keyboard_report; 841 // hids_client_report_t * boot_mouse_report; 842 const uint8_t * characteristic_descriptor_value; 843 uint8_t i; 844 uint8_t report_index; 845 846 const uint8_t * descriptor_value; 847 uint16_t descriptor_value_len; 848 849 switch(hci_event_packet_get_type(packet)){ 850 case GATT_EVENT_SERVICE_QUERY_RESULT: 851 client = hids_get_client_for_con_handle(gatt_event_service_query_result_get_handle(packet)); 852 btstack_assert(client != NULL); 853 854 if (client->state != HIDS_CLIENT_STATE_W4_SERVICE_RESULT) { 855 hids_emit_connection_established(client, GATT_CLIENT_IN_WRONG_STATE); 856 hids_finalize_client(client); 857 break; 858 } 859 860 if (client->num_instances < MAX_NUM_HID_SERVICES){ 861 uint8_t index = client->num_instances; 862 gatt_event_service_query_result_get_service(packet, &service); 863 client->services[index].start_handle = service.start_group_handle; 864 client->services[index].end_handle = service.end_group_handle; 865 client->num_instances++; 866 867 #ifdef ENABLE_TESTING_SUPPORT 868 printf("HID Service: start handle 0x%04X, end handle 0x%04X\n", client->services[index].start_handle, client->services[index].end_handle); 869 #endif 870 hids_client_descriptor_storage_init(client, index); 871 } else { 872 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); 873 } 874 break; 875 876 case GATT_EVENT_CHARACTERISTIC_QUERY_RESULT: 877 client = hids_get_client_for_con_handle(gatt_event_characteristic_query_result_get_handle(packet)); 878 btstack_assert(client != NULL); 879 gatt_event_characteristic_query_result_get_characteristic(packet, &characteristic); 880 881 report_index = HIDS_CLIENT_INVALID_REPORT_INDEX; 882 if (client->state == HIDS_CLIENT_STATE_W4_EXTERNAL_REPORT_CHARACTERISTIC_RESULT){ 883 if (!external_report_index_for_uuid_exists(client, characteristic.uuid16)){ 884 break; 885 } 886 } 887 888 switch (characteristic.uuid16){ 889 case ORG_BLUETOOTH_CHARACTERISTIC_PROTOCOL_MODE: 890 client->protocol_mode_value_handle = characteristic.value_handle; 891 break; 892 893 case ORG_BLUETOOTH_CHARACTERISTIC_BOOT_KEYBOARD_INPUT_REPORT: 894 report_index = hids_client_add_characteristic(client, &characteristic, HID_BOOT_MODE_KEYBOARD_ID, HID_REPORT_TYPE_INPUT, true); 895 break; 896 897 case ORG_BLUETOOTH_CHARACTERISTIC_BOOT_MOUSE_INPUT_REPORT: 898 report_index = hids_client_add_characteristic(client, &characteristic, HID_BOOT_MODE_MOUSE_ID, HID_REPORT_TYPE_INPUT, true); 899 break; 900 901 case ORG_BLUETOOTH_CHARACTERISTIC_BOOT_KEYBOARD_OUTPUT_REPORT: 902 report_index = hids_client_add_characteristic(client, &characteristic, HID_BOOT_MODE_KEYBOARD_ID, HID_REPORT_TYPE_OUTPUT, false); 903 break; 904 905 case ORG_BLUETOOTH_CHARACTERISTIC_REPORT: 906 report_index = hids_client_add_characteristic(client, &characteristic, HID_REPORT_MODE_REPORT_ID, HID_REPORT_TYPE_RESERVED, false); 907 break; 908 909 case ORG_BLUETOOTH_CHARACTERISTIC_REPORT_MAP: 910 client->services[client->service_index].report_map_value_handle = characteristic.value_handle; 911 client->services[client->service_index].report_map_end_handle = characteristic.end_handle; 912 break; 913 914 case ORG_BLUETOOTH_CHARACTERISTIC_HID_INFORMATION: 915 break; 916 917 case ORG_BLUETOOTH_CHARACTERISTIC_HID_CONTROL_POINT: 918 break; 919 920 default: 921 #ifdef ENABLE_TESTING_SUPPORT 922 printf(" TODO: Found external characteristic 0x%04X\n", characteristic.uuid16); 923 #endif 924 return; 925 } 926 927 #ifdef ENABLE_TESTING_SUPPORT 928 printf("HID Characteristic %s: \n Attribute Handle 0x%04X, Properties 0x%02X, Handle 0x%04X, UUID 0x%04X, service %d", 929 hid_characteristic_name(characteristic.uuid16), 930 characteristic.start_handle, 931 characteristic.properties, 932 characteristic.value_handle, characteristic.uuid16, 933 client->service_index); 934 935 if (report_index != HIDS_CLIENT_INVALID_REPORT_INDEX){ 936 printf(", report index 0x%02X", report_index); 937 } 938 printf("\n"); 939 #endif 940 break; 941 942 case GATT_EVENT_LONG_CHARACTERISTIC_VALUE_QUERY_RESULT: 943 // Map Report characteristic value == HID Descriptor 944 client = hids_get_client_for_con_handle(gatt_event_long_characteristic_value_query_result_get_handle(packet)); 945 btstack_assert(client != NULL); 946 947 descriptor_value = gatt_event_long_characteristic_value_query_result_get_value(packet); 948 descriptor_value_len = gatt_event_long_characteristic_value_query_result_get_value_length(packet); 949 950 #ifdef ENABLE_TESTING_SUPPORT 951 // printf("Report Map HID Desc [%d] for service %d\n", descriptor_len, client->service_index); 952 printf_hexdump(descriptor_value, descriptor_value_len); 953 #endif 954 for (i = 0; i < descriptor_value_len; i++){ 955 bool stored = hids_client_descriptor_storage_store(client, client->service_index, descriptor_value[i]); 956 if (!stored){ 957 client->services[client->service_index].hid_descriptor_status = ERROR_CODE_MEMORY_CAPACITY_EXCEEDED; 958 break; 959 } 960 } 961 break; 962 963 case GATT_EVENT_ALL_CHARACTERISTIC_DESCRIPTORS_QUERY_RESULT: 964 client = hids_get_client_for_con_handle(gatt_event_all_characteristic_descriptors_query_result_get_handle(packet)); 965 btstack_assert(client != NULL); 966 gatt_event_all_characteristic_descriptors_query_result_get_characteristic_descriptor(packet, &characteristic_descriptor); 967 968 switch (client->state) { 969 case HIDS_CLIENT_STATE_W4_REPORT_MAP_CHARACTERISTIC_DESCRIPTORS_RESULT: 970 // setup for descriptor value query 971 if (characteristic_descriptor.uuid16 == ORG_BLUETOOTH_DESCRIPTOR_EXTERNAL_REPORT_REFERENCE){ 972 report_index = hids_client_add_external_report(client, &characteristic_descriptor); 973 974 #ifdef ENABLE_TESTING_SUPPORT 975 if (report_index != HIDS_CLIENT_INVALID_REPORT_INDEX){ 976 printf(" External Report Reference Characteristic Descriptor: Handle 0x%04X, UUID 0x%04X, service %d, report index 0x%02X\n", 977 characteristic_descriptor.handle, 978 characteristic_descriptor.uuid16, 979 client->service_index, report_index); 980 } 981 #endif 982 } 983 break; 984 case HIDS_CLIENT_STATE_W4_REPORT_FOUND: 985 // setup for descriptor value query 986 if (characteristic_descriptor.uuid16 == ORG_BLUETOOTH_DESCRIPTOR_REPORT_REFERENCE){ 987 client->descriptor_handle = characteristic_descriptor.handle; 988 #ifdef ENABLE_TESTING_SUPPORT 989 printf(" Report Characteristic Report Reference Characteristic Descriptor: Handle 0x%04X, UUID 0x%04X\n", 990 characteristic_descriptor.handle, 991 characteristic_descriptor.uuid16); 992 #endif 993 } 994 995 #ifdef ENABLE_TESTING_SUPPORT 996 if (characteristic_descriptor.uuid16 == ORG_BLUETOOTH_DESCRIPTOR_GATT_CLIENT_CHARACTERISTIC_CONFIGURATION){ 997 client->reports[client->report_index].ccc_handle = characteristic_descriptor.handle; 998 printf(" Report Client Characteristic Configuration Descriptor: Handle 0x%04X, UUID 0x%04X\n", 999 characteristic_descriptor.handle, 1000 characteristic_descriptor.uuid16); 1001 } 1002 #endif 1003 break; 1004 1005 default: 1006 break; 1007 } 1008 break; 1009 1010 #ifdef ENABLE_TESTING_SUPPORT 1011 case GATT_EVENT_CHARACTERISTIC_VALUE_QUERY_RESULT: 1012 client = hids_get_client_for_con_handle(gatt_event_characteristic_value_query_result_get_handle(packet)); 1013 btstack_assert(client != NULL); 1014 1015 printf(" Received CCC value: "); 1016 printf_hexdump(gatt_event_characteristic_value_query_result_get_value(packet), gatt_event_characteristic_value_query_result_get_value_length(packet)); 1017 client->state = HIDS_CLIENT_W2_SEND_GET_REPORT; 1018 break; 1019 #endif 1020 1021 case GATT_EVENT_CHARACTERISTIC_DESCRIPTOR_QUERY_RESULT: 1022 client = hids_get_client_for_con_handle(gatt_event_characteristic_descriptor_query_result_get_handle(packet)); 1023 btstack_assert(client != NULL); 1024 1025 if (gatt_event_characteristic_descriptor_query_result_get_descriptor_length(packet) != 2){ 1026 break; 1027 } 1028 1029 characteristic_descriptor_value = gatt_event_characteristic_descriptor_query_result_get_descriptor(packet); 1030 switch (client->state) { 1031 case HIDS_CLIENT_STATE_W4_REPORT_MAP_EXTERNAL_REPORT_REFERENCE_UUID: 1032 // get external report characteristic uuid 1033 report_index = find_external_report_index_for_value_handle(client, gatt_event_characteristic_descriptor_query_result_get_descriptor_handle(packet)); 1034 if (report_index != HIDS_CLIENT_INVALID_REPORT_INDEX){ 1035 client->external_reports[report_index].external_report_reference_uuid = little_endian_read_16(characteristic_descriptor_value, 0); 1036 #ifdef ENABLE_TESTING_SUPPORT 1037 printf(" Update external_report_reference_uuid of report index 0x%02X, service index 0x%02X, UUID 0x%02X\n", 1038 report_index, client->service_index, client->external_reports[report_index].external_report_reference_uuid); 1039 #endif 1040 } 1041 break; 1042 1043 case HIDS_CLIENT_STATE_W4_REPORT_ID_AND_TYPE: 1044 1045 if (client->report_index != HIDS_CLIENT_INVALID_REPORT_INDEX){ 1046 client->reports[client->report_index].report_id = characteristic_descriptor_value[0]; 1047 client->reports[client->report_index].report_type = (hid_report_type_t)characteristic_descriptor_value[1]; 1048 #ifdef ENABLE_TESTING_SUPPORT 1049 printf(" Update report ID and type [%d, %d] of report index 0x%02X, service index 0x%02X\n", 1050 client->reports[client->report_index].report_id, 1051 client->reports[client->report_index].report_type, 1052 client->report_index, client->service_index); 1053 #endif 1054 } 1055 break; 1056 1057 default: 1058 break; 1059 } 1060 break; 1061 1062 case GATT_EVENT_QUERY_COMPLETE: 1063 client = hids_get_client_for_con_handle(gatt_event_query_complete_get_handle(packet)); 1064 btstack_assert(client != NULL); 1065 1066 att_status = gatt_event_query_complete_get_att_status(packet); 1067 1068 switch (client->state){ 1069 case HIDS_CLIENT_STATE_W4_SERVICE_RESULT: 1070 if (att_status != ATT_ERROR_SUCCESS){ 1071 hids_emit_connection_established(client, att_status); 1072 hids_finalize_client(client); 1073 break; 1074 } 1075 1076 if (client->num_instances == 0){ 1077 hids_emit_connection_established(client, ERROR_CODE_UNSUPPORTED_FEATURE_OR_PARAMETER_VALUE); 1078 hids_finalize_client(client); 1079 break; 1080 } 1081 1082 client->service_index = 0; 1083 client->state = HIDS_CLIENT_STATE_W2_QUERY_CHARACTERISTIC; 1084 break; 1085 1086 case HIDS_CLIENT_STATE_W4_CHARACTERISTIC_RESULT: 1087 if (att_status != ATT_ERROR_SUCCESS){ 1088 hids_emit_connection_established(client, att_status); 1089 hids_finalize_client(client); 1090 break; 1091 } 1092 1093 if ((client->service_index + 1) < client->num_instances){ 1094 // discover characteristics of next service 1095 client->service_index++; 1096 client->state = HIDS_CLIENT_STATE_W2_QUERY_CHARACTERISTIC; 1097 break; 1098 } 1099 1100 switch (client->required_protocol_mode){ 1101 case HID_PROTOCOL_MODE_REPORT: 1102 client->protocol_mode = HID_PROTOCOL_MODE_REPORT; 1103 if (hid_clients_has_reports_in_report_mode(client)){ 1104 client->protocol_mode = HID_PROTOCOL_MODE_REPORT; 1105 break; 1106 } 1107 hids_emit_connection_established(client, att_status); 1108 hids_finalize_client(client); 1109 return; 1110 1111 case HID_PROTOCOL_MODE_REPORT_WITH_FALLBACK_TO_BOOT: 1112 if (hid_clients_has_reports_in_report_mode(client)){ 1113 client->protocol_mode = HID_PROTOCOL_MODE_REPORT; 1114 break; 1115 } 1116 if (hid_clients_has_reports_in_boot_mode(client)){ 1117 if (client->protocol_mode_value_handle != 0){ 1118 client->state = HIDS_CLIENT_STATE_W2_SET_BOOT_PROTOCOL_MODE; 1119 break; 1120 } 1121 hids_emit_connection_established(client, att_status); 1122 hids_finalize_client(client); 1123 return; 1124 } 1125 break; 1126 default: 1127 if (hid_clients_has_reports_in_boot_mode(client)){ 1128 if (client->protocol_mode_value_handle != 0){ 1129 client->state = HIDS_CLIENT_STATE_W2_SET_BOOT_PROTOCOL_MODE; 1130 break; 1131 } 1132 hids_emit_connection_established(client, att_status); 1133 hids_finalize_client(client); 1134 return; 1135 } 1136 break; 1137 } 1138 1139 if (client->state == HIDS_CLIENT_STATE_W2_SET_BOOT_PROTOCOL_MODE){ 1140 break; 1141 } 1142 1143 // 1. we need to get HID Descriptor and 1144 // 2. get external Report characteristics if referenced from Report Map 1145 if (hids_client_report_map_query_init(client)){ 1146 break; 1147 } 1148 hids_emit_connection_established(client, ERROR_CODE_UNSUPPORTED_FEATURE_OR_PARAMETER_VALUE); 1149 hids_finalize_client(client); 1150 break; 1151 1152 1153 // HID descriptor found 1154 case HIDS_CLIENT_STATE_W4_REPORT_MAP_HID_DESCRIPTOR: 1155 if (att_status != ATT_ERROR_SUCCESS){ 1156 hids_emit_connection_established(client, att_status); 1157 hids_finalize_client(client); 1158 break; 1159 } 1160 client->state = HIDS_CLIENT_STATE_W2_REPORT_MAP_DISCOVER_CHARACTERISTIC_DESCRIPTORS; 1161 break; 1162 1163 // found all descriptors, check if there is one with EXTERNAL_REPORT_REFERENCE 1164 case HIDS_CLIENT_STATE_W4_REPORT_MAP_CHARACTERISTIC_DESCRIPTORS_RESULT: 1165 // go for next report map 1166 if (hids_client_report_query_next_report_map(client)){ 1167 break; 1168 } 1169 1170 // read UUIDS for external characteristics 1171 if (hids_client_report_map_uuid_query_init(client)){ 1172 break; 1173 } 1174 1175 // discover characteristic descriptor for all Report characteristics, 1176 // then read value of characteristic descriptor to get Report ID 1177 if (hids_client_report_query_init(client)){ 1178 break; 1179 } 1180 1181 hids_emit_connection_established(client, ERROR_CODE_UNSUPPORTED_FEATURE_OR_PARAMETER_VALUE); 1182 hids_finalize_client(client); 1183 break; 1184 1185 case HIDS_CLIENT_STATE_W4_REPORT_MAP_EXTERNAL_REPORT_REFERENCE_UUID: 1186 // go for next map report 1187 if (hids_client_report_query_next_report_map_uuid(client)){ 1188 break; 1189 } 1190 1191 // update external characteristics with correct value handle and end handle 1192 client->state = HIDS_CLIENT_STATE_W2_DISCOVER_EXTERNAL_REPORT_CHARACTERISTIC; 1193 break; 1194 1195 case HIDS_CLIENT_STATE_W4_EXTERNAL_REPORT_CHARACTERISTIC_RESULT: 1196 // discover characteristic descriptor for all Report characteristics, 1197 // then read value of characteristic descriptor to get Report ID 1198 if (hids_client_report_query_init(client)){ 1199 break; 1200 } 1201 1202 hids_emit_connection_established(client, ERROR_CODE_UNSUPPORTED_FEATURE_OR_PARAMETER_VALUE); 1203 hids_finalize_client(client); 1204 break; 1205 1206 case HIDS_CLIENT_STATE_W4_REPORT_FOUND: 1207 if (client->descriptor_handle != 0){ 1208 client->state = HIDS_CLIENT_STATE_W2_READ_REPORT_ID_AND_TYPE; 1209 break; 1210 } 1211 1212 // go for next report 1213 if (hids_client_report_query_next_report(client)){ 1214 break; 1215 } 1216 1217 hids_emit_connection_established(client, ERROR_CODE_SUCCESS); 1218 break; 1219 1220 case HIDS_CLIENT_STATE_W4_REPORT_ID_AND_TYPE: 1221 // go for next report 1222 if (hids_client_report_query_next_report(client)){ 1223 break; 1224 } 1225 1226 if (hids_client_report_notifications_init(client)){ 1227 break; 1228 } 1229 hids_emit_connection_established(client, ERROR_CODE_SUCCESS); 1230 break; 1231 1232 case HIDS_CLIENT_STATE_W4_INPUT_REPORTS_ENABLED: 1233 if (hids_client_report_next_notification_report_index(client)){ 1234 break; 1235 } 1236 hids_emit_connection_established(client, ERROR_CODE_SUCCESS); 1237 break; 1238 1239 default: 1240 break; 1241 } 1242 break; 1243 1244 default: 1245 break; 1246 } 1247 1248 if (client != NULL){ 1249 hids_run_for_client(client); 1250 } 1251 } 1252 1253 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){ 1254 btstack_assert(packet_handler != NULL); 1255 1256 hids_client_t * client = hids_get_client_for_con_handle(con_handle); 1257 if (client != NULL){ 1258 return ERROR_CODE_COMMAND_DISALLOWED; 1259 } 1260 1261 uint16_t cid = hids_get_next_cid(); 1262 if (hids_cid != NULL) { 1263 *hids_cid = cid; 1264 } 1265 1266 client = hids_create_client(con_handle, cid); 1267 if (client == NULL) { 1268 return BTSTACK_MEMORY_ALLOC_FAILED; 1269 } 1270 1271 client->required_protocol_mode = protocol_mode; 1272 client->client_handler = packet_handler; 1273 client->state = HIDS_CLIENT_STATE_W2_QUERY_SERVICE; 1274 1275 hids_run_for_client(client); 1276 return ERROR_CODE_SUCCESS; 1277 } 1278 1279 uint8_t hids_client_disconnect(uint16_t hids_cid){ 1280 hids_client_t * client = hids_get_client_for_cid(hids_cid); 1281 if (client == NULL){ 1282 return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 1283 } 1284 // finalize connection 1285 hids_finalize_client(client); 1286 return ERROR_CODE_SUCCESS; 1287 } 1288 1289 uint8_t hids_client_send_report(uint16_t hids_cid, uint8_t report_id, const uint8_t * report, uint8_t report_len){ 1290 hids_client_t * client = hids_get_client_for_cid(hids_cid); 1291 if (client == NULL){ 1292 return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 1293 } 1294 1295 if (client->state != HIDS_CLIENT_STATE_CONNECTED) { 1296 return ERROR_CODE_COMMAND_DISALLOWED; 1297 } 1298 1299 uint8_t report_index = find_report_index_for_report_id_and_type(client, report_id, HID_REPORT_TYPE_OUTPUT); 1300 1301 if (report_index == HIDS_CLIENT_INVALID_REPORT_INDEX){ 1302 return ERROR_CODE_UNSUPPORTED_FEATURE_OR_PARAMETER_VALUE; 1303 } 1304 1305 uint16_t mtu; 1306 uint8_t status = gatt_client_get_mtu(client->con_handle, &mtu); 1307 1308 if (status != ERROR_CODE_SUCCESS){ 1309 return status; 1310 } 1311 1312 if (mtu - 2 < report_len){ 1313 return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE; 1314 } 1315 1316 client->state = HIDS_CLIENT_W2_SEND_REPORT; 1317 client->report_index = report_index; 1318 client->report = report; 1319 client->report_len = report_len; 1320 1321 hids_run_for_client(client); 1322 return ERROR_CODE_SUCCESS; 1323 } 1324 1325 uint8_t hids_client_send_get_report(uint16_t hids_cid, uint8_t report_id){ 1326 hids_client_t * client = hids_get_client_for_cid(hids_cid); 1327 if (client == NULL){ 1328 return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 1329 } 1330 1331 if (client->state != HIDS_CLIENT_STATE_CONNECTED) { 1332 return ERROR_CODE_COMMAND_DISALLOWED; 1333 } 1334 1335 uint8_t report_index = find_input_report_index_for_report_id(client, report_id); 1336 if (report_index == HIDS_CLIENT_INVALID_REPORT_INDEX){ 1337 return ERROR_CODE_UNSUPPORTED_FEATURE_OR_PARAMETER_VALUE; 1338 } 1339 1340 client->report_index = report_index; 1341 1342 #ifdef ENABLE_TESTING_SUPPORT 1343 client->state = HIDS_CLIENT_W2_READ_CHARACTERISTIC_CONFIGURATION; 1344 #else 1345 client->state = HIDS_CLIENT_W2_SEND_GET_REPORT; 1346 #endif 1347 hids_run_for_client(client); 1348 return ERROR_CODE_SUCCESS; 1349 } 1350 1351 1352 void hids_client_init(uint8_t * hid_descriptor_storage, uint16_t hid_descriptor_storage_len){ 1353 hids_client_descriptor_storage = hid_descriptor_storage; 1354 hids_client_descriptor_storage_len = hid_descriptor_storage_len; 1355 } 1356 1357 void hids_client_deinit(void){} 1358