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