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