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