diff --git a/src/ble/gatt-service/hids_client.c b/src/ble/gatt-service/hids_client.c index 7ecfeeac2..45fa3c412 100644 --- a/src/ble/gatt-service/hids_client.c +++ b/src/ble/gatt-service/hids_client.c @@ -55,16 +55,120 @@ #include "btstack_run_loop.h" #include "gap.h" -static btstack_linked_list_t clients; -static uint16_t hids_cid_counter = 0; - #define HID_REPORT_MODE_REPORT_ID 3 #define HID_REPORT_MODE_REPORT_MAP_ID 4 #define HID_REPORT_MODE_HID_INFORMATION_ID 5 #define HID_REPORT_MODE_HID_CONTROL_POINT_ID 6 +static btstack_linked_list_t clients; +static uint16_t hids_cid_counter = 0; + +static uint8_t * hids_client_descriptor_storage; +static uint16_t hids_client_descriptor_storage_len; + static void handle_gatt_client_event(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size); +static hids_client_t * hids_get_client_for_con_handle(hci_con_handle_t con_handle){ + btstack_linked_list_iterator_t it; + btstack_linked_list_iterator_init(&it, &clients); + while (btstack_linked_list_iterator_has_next(&it)){ + hids_client_t * client = (hids_client_t *)btstack_linked_list_iterator_next(&it); + if (client->con_handle != con_handle) continue; + return client; + } + return NULL; +} + +static hids_client_t * hids_get_client_for_cid(uint16_t hids_cid){ + btstack_linked_list_iterator_t it; + btstack_linked_list_iterator_init(&it, &clients); + while (btstack_linked_list_iterator_has_next(&it)){ + hids_client_t * client = (hids_client_t *)btstack_linked_list_iterator_next(&it); + if (client->cid != hids_cid) continue; + return client; + } + return NULL; +} + + +// START Descriptor Storage Util + +static uint16_t hids_client_descriptor_storage_get_available_space(void){ + // assumes all descriptors are back to back + uint16_t free_space = hids_client_descriptor_storage_len; + uint8_t i; + + btstack_linked_list_iterator_t it; + btstack_linked_list_iterator_init(&it, &clients); + while (btstack_linked_list_iterator_has_next(&it)){ + hids_client_t * client = (hids_client_t *)btstack_linked_list_iterator_next(&it); + for (i = 0; i < client->num_instances; i++){ + free_space -= client->services[i].hid_descriptor_len; + } + } + return free_space; +} + +static void hids_client_descriptor_storage_init(hids_client_t * client, uint8_t service_index){ + client->services[service_index].hid_descriptor_len = 0; + client->services[service_index].hid_descriptor_max_len = hids_client_descriptor_storage_get_available_space(); + client->services[service_index].hid_descriptor_offset = hids_client_descriptor_storage_len - client->services[service_index].hid_descriptor_max_len; +} + +static bool hids_client_descriptor_storage_store(hids_client_t * client, uint8_t service_index, uint8_t byte){ + if (client->services[service_index].hid_descriptor_len >= client->services[service_index].hid_descriptor_max_len) return false; + + hids_client_descriptor_storage[client->services[service_index].hid_descriptor_offset + client->services[service_index].hid_descriptor_len] = byte; + client->services[service_index].hid_descriptor_len++; + return true; +} + +static void hids_client_descriptor_storage_delete(hids_client_t * client){ + uint8_t service_index = 0; + uint16_t next_offset = 0; + + for (service_index = 0; service_index < client->num_instances; service_index++){ + next_offset += client->services[service_index].hid_descriptor_offset + client->services[service_index].hid_descriptor_len; + client->services[service_index].hid_descriptor_len = 0; + client->services[service_index].hid_descriptor_offset = 0; + } + + memmove(&hids_client_descriptor_storage[client->services[0].hid_descriptor_offset], + &hids_client_descriptor_storage[next_offset], + hids_client_descriptor_storage_len - next_offset); + + uint8_t i; + btstack_linked_list_iterator_t it; + btstack_linked_list_iterator_init(&it, &clients); + while (btstack_linked_list_iterator_has_next(&it)){ + hids_client_t * conn = (hids_client_t *)btstack_linked_list_iterator_next(&it); + for (i = 0; i < client->num_instances; i++){ + if (conn->services[i].hid_descriptor_offset >= next_offset){ + conn->services[i].hid_descriptor_offset = next_offset; + next_offset += conn->services[service_index].hid_descriptor_len; + } + } + } +} + +const uint8_t * hids_client_descriptor_storage_get_descriptor_data(uint16_t hids_cid, uint8_t service_index){ + hids_client_t * client = hids_get_client_for_cid(hids_cid); + if (!client){ + return NULL; + } + return &hids_client_descriptor_storage[client->services[service_index].hid_descriptor_offset]; +} + +uint16_t hids_client_descriptor_storage_get_descriptor_len(uint16_t hids_cid, uint8_t service_index){ + hids_client_t * client = hids_get_client_for_cid(hids_cid); + if (!client){ + return 0; + } + return client->services[service_index].hid_descriptor_len; +} + +// END Descriptor Storage Util + static uint16_t hids_get_next_cid(void){ if (hids_cid_counter == 0xffff) { hids_cid_counter = 1; @@ -271,31 +375,11 @@ static hids_client_t * hids_create_client(hci_con_handle_t con_handle, uint16_t } static void hids_finalize_client(hids_client_t * client){ + hids_client_descriptor_storage_delete(client); btstack_linked_list_remove(&clients, (btstack_linked_item_t *) client); btstack_memory_hids_client_free(client); } -static hids_client_t * hids_get_client_for_con_handle(hci_con_handle_t con_handle){ - btstack_linked_list_iterator_t it; - btstack_linked_list_iterator_init(&it, &clients); - while (btstack_linked_list_iterator_has_next(&it)){ - hids_client_t * client = (hids_client_t *)btstack_linked_list_iterator_next(&it); - if (client->con_handle != con_handle) continue; - return client; - } - return NULL; -} - -static hids_client_t * hids_get_client_for_cid(uint16_t hids_cid){ - btstack_linked_list_iterator_t it; - btstack_linked_list_iterator_init(&it, &clients); - while (btstack_linked_list_iterator_has_next(&it)){ - hids_client_t * client = (hids_client_t *)btstack_linked_list_iterator_next(&it); - if (client->cid != hids_cid) continue; - return client; - } - return NULL; -} static void hids_emit_connection_established(hids_client_t * client, uint8_t status){ uint8_t event[8]; @@ -388,7 +472,7 @@ static void hids_run_for_client(hids_client_t * client){ case HIDS_CLIENT_STATE_W2_READ_REPORT_MAP_HID_DESCRIPTOR: client->state = HIDS_CLIENT_STATE_W4_REPORT_MAP_HID_DESCRIPTOR; - 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); + 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); UNUSED(att_status); break; @@ -499,6 +583,10 @@ static void handle_gatt_client_event(uint8_t packet_type, uint16_t channel, uint const uint8_t * characteristic_descriptor_value; uint8_t i; uint8_t report_index; + uint8_t next_service_index; + + const uint8_t * descriptor; + uint16_t descriptor_len; switch(hci_event_packet_get_type(packet)){ case GATT_EVENT_SERVICE_QUERY_RESULT: @@ -510,13 +598,16 @@ static void handle_gatt_client_event(uint8_t packet_type, uint16_t channel, uint hids_finalize_client(client); break; } - - if (client->num_instances < MAX_NUM_HID_SERVICES){ + + next_service_index = client->num_instances; + if (next_service_index < MAX_NUM_HID_SERVICES){ gatt_event_service_query_result_get_service(packet, &service); - client->services[client->num_instances].start_handle = service.start_group_handle; - client->services[client->num_instances].end_handle = service.end_group_handle; + client->services[next_service_index].start_handle = service.start_group_handle; + client->services[next_service_index].end_handle = service.end_group_handle; + + hids_client_descriptor_storage_init(client, next_service_index); + client->num_instances++; } - client->num_instances++; break; case GATT_EVENT_CHARACTERISTIC_QUERY_RESULT: @@ -585,8 +676,18 @@ static void handle_gatt_client_event(uint8_t packet_type, uint16_t channel, uint // Map Report characteristic value == HID Descriptor client = hids_get_client_for_con_handle(gatt_event_characteristic_value_query_result_get_handle(packet)); btstack_assert(client != NULL); - // TODO get value and store it + // printf("HID descriptor found\n"); + descriptor_len = gatt_event_characteristic_value_query_result_get_value_length(packet); + descriptor = gatt_event_characteristic_value_query_result_get_value(packet); + + for (i = 0; i < descriptor_len; i++){ + bool stored = hids_client_descriptor_storage_store(client, client->service_index, descriptor[i]); + if (!stored){ + client->services[client->service_index].hid_descriptor_status = ERROR_CODE_MEMORY_CAPACITY_EXCEEDED; + break; + } + } break; case GATT_EVENT_ALL_CHARACTERISTIC_DESCRIPTORS_QUERY_RESULT: diff --git a/src/ble/gatt-service/hids_client.h b/src/ble/gatt-service/hids_client.h index 2fa4b78c5..b4ec92b51 100644 --- a/src/ble/gatt-service/hids_client.h +++ b/src/ble/gatt-service/hids_client.h @@ -130,6 +130,14 @@ typedef struct { uint16_t report_map_value_handle; uint16_t report_map_end_handle; + + // descriptor storage + uint16_t hid_descriptor_offset; + uint16_t hid_descriptor_len; + uint16_t hid_descriptor_max_len; + uint8_t hid_descriptor_status; // ERROR_CODE_SUCCESS if descriptor available, + // ERROR_CODE_UNSUPPORTED_FEATURE_OR_PARAMETER_VALUE if not, and + // ERROR_CODE_MEMORY_CAPACITY_EXCEEDED if descriptor is larger then the available space } hid_service_t; typedef struct { @@ -159,6 +167,7 @@ typedef struct { uint16_t descriptor_handle; uint16_t report_len; const uint8_t * report; + } hids_client_t; /* API_START */ @@ -195,6 +204,10 @@ uint8_t hids_client_send_report(uint16_t hids_cid, uint8_t report_id, const uint */ uint8_t hids_client_disconnect(uint16_t hids_cid); +const uint8_t * hids_client_descriptor_storage_get_descriptor_data(uint16_t hids_cid, uint8_t service_index); + +uint16_t hids_client_descriptor_storage_get_descriptor_len(uint16_t hids_cid, uint8_t service_index); + /** * @brief De-initialize Battery Service. */