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