hids_client: get report ID from external report reference

This commit is contained in:
Milanka Ringwald 2021-03-16 10:34:17 +01:00
parent a381a464ca
commit 70093cf595
3 changed files with 177 additions and 12 deletions

View File

@ -442,7 +442,7 @@ static void packet_handler (uint8_t packet_type, uint16_t channel, uint8_t *pack
printf("Search for HID service.\n");
app_state = W4_HID_CLIENT_CONNECTED;
status = hids_client_connect(connection_handle, handle_gatt_client_event, HID_PROTOCOL_MODE_BOOT, &hids_cid);
status = hids_client_connect(connection_handle, handle_gatt_client_event, HID_PROTOCOL_MODE_REPORT, &hids_cid);
if (status != ERROR_CODE_SUCCESS){
printf("HID client connection failed, status 0x%02x\n", status);
}

View File

@ -58,6 +58,11 @@
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 void handle_gatt_client_event(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size);
static uint16_t hids_get_next_cid(void){
@ -113,31 +118,48 @@ static void hids_client_add_characteristic(hids_client_t * client, gatt_client_c
}
if (client->active_report_index < HIDS_CLIENT_NUM_REPORTS) {
client->active_report_index++;
client->reports[client->active_report_index].value_handle = characteristic->value_handle;
client->reports[client->active_report_index].end_handle = characteristic->end_handle;
client->reports[client->active_report_index].properties = characteristic->properties;
client->reports[client->active_report_index].service_index = client->service_index;
client->reports[client->active_report_index].report_id = report_id;
client->reports[client->active_report_index].report_type = report_type;
client->active_report_index++;
client->num_reports++;
} else {
log_info("not enough storage, increase HIDS_CLIENT_NUM_REPORTS");
}
}
static void hids_client_get_characteristic_for_report_index(hids_client_t * client, uint8_t report_index, gatt_client_characteristic_t * characteristic){
characteristic->value_handle = client->reports[report_index].value_handle;
characteristic->end_handle = client->reports[report_index].end_handle;
characteristic->properties = client->reports[report_index].properties;
}
static uint8_t hids_client_get_characteristic(hids_client_t * client, uint8_t report_id, hid_report_type_t report_type, gatt_client_characteristic_t * characteristic){
uint8_t report_index = find_report_index_for_report_id_and_type(client, report_id, report_type);
if (report_index == HIDS_CLIENT_INVALID_REPORT_INDEX){
return report_index;
}
characteristic->value_handle = client->reports[report_index].value_handle;
characteristic->end_handle = client->reports[report_index].end_handle;
characteristic->properties = client->reports[report_index].properties;
hids_client_get_characteristic_for_report_index(client, report_index, characteristic);
return report_index;
}
static void hids_client_get_next_active_report_index(hids_client_t * client){
uint8_t i;
for (i = client->active_report_index; i < client->num_reports; i++){
hids_client_report_t report = client->reports[i];
if (report.report_type == HID_REPORT_TYPE_RESERVED && report.report_id == HID_REPORT_MODE_REPORT_ID){
client->active_report_index = i;
}
return;
}
client->active_report_index = HIDS_CLIENT_INVALID_REPORT_INDEX;
}
static hids_client_t * hids_create_client(hci_con_handle_t con_handle, uint16_t cid){
hids_client_t * client = btstack_memory_hids_client_get();
@ -268,6 +290,23 @@ static void hids_run_for_client(hids_client_t * client){
UNUSED(att_status);
break;
}
case HIDS_CLIENT_STATE_W2_REPORT_QUERY_CHARACTERISTIC_DESCRIPTORS:
client->state = HIDS_CLIENT_STATE_W4_REPORT_CHARACTERISTIC_DESCRIPTORS_RESULT;
client->descriptor_handle = 0;
hids_client_get_characteristic_for_report_index(client, client->active_report_index, &characteristic);
att_status = gatt_client_discover_characteristic_descriptors(&handle_gatt_client_event, client->con_handle, &characteristic);
UNUSED(att_status);
break;
case HIDS_CLIENT_STATE_W2_REPORT_READ_CHARACTERISTIC_DESCRIPTOR_VALUE:
client->state = HIDS_CLIENT_STATE_W4_REPORT_CHARACTERISTIC_DESCRIPTOR_VALUE_RESULT;
att_status = gatt_client_read_characteristic_descriptor_using_descriptor_handle(&handle_gatt_client_event, client->con_handle, client->descriptor_handle);
client->descriptor_handle = 0;
UNUSED(att_status);
break;
default:
break;
}
@ -326,6 +365,7 @@ static void handle_gatt_client_event(uint8_t packet_type, uint16_t channel, uint
uint8_t att_status;
gatt_client_service_t service;
gatt_client_characteristic_t characteristic;
gatt_client_characteristic_descriptor_t characteristic_descriptor;
hids_client_report_t * boot_keyboard_report;
hids_client_report_t * boot_mouse_report;
@ -355,6 +395,10 @@ static void handle_gatt_client_event(uint8_t packet_type, uint16_t channel, uint
gatt_event_characteristic_query_result_get_characteristic(packet, &characteristic);
switch (characteristic.uuid16){
case ORG_BLUETOOTH_CHARACTERISTIC_PROTOCOL_MODE:
client->protocol_mode_value_handle = characteristic.value_handle;
break;
case ORG_BLUETOOTH_CHARACTERISTIC_BOOT_KEYBOARD_INPUT_REPORT:
hids_client_add_characteristic(client, &characteristic, HID_BOOT_MODE_KEYBOARD_ID, HID_REPORT_TYPE_INPUT);
break;
@ -363,19 +407,55 @@ static void handle_gatt_client_event(uint8_t packet_type, uint16_t channel, uint
hids_client_add_characteristic(client, &characteristic, HID_BOOT_MODE_MOUSE_ID, HID_REPORT_TYPE_INPUT);
break;
case ORG_BLUETOOTH_CHARACTERISTIC_PROTOCOL_MODE:
client->protocol_mode_value_handle = characteristic.value_handle;
break;
case ORG_BLUETOOTH_CHARACTERISTIC_BOOT_KEYBOARD_OUTPUT_REPORT:
hids_client_add_characteristic(client, &characteristic, HID_BOOT_MODE_KEYBOARD_ID, HID_REPORT_TYPE_OUTPUT);
break;
case ORG_BLUETOOTH_CHARACTERISTIC_REPORT:
hids_client_add_characteristic(client, &characteristic, HID_REPORT_MODE_REPORT_ID, HID_REPORT_TYPE_RESERVED);
break;
case ORG_BLUETOOTH_CHARACTERISTIC_REPORT_MAP:
// printf("ORG_BLUETOOTH_CHARACTERISTIC_REPORT_MAP\n");
hids_client_add_characteristic(client, &characteristic, HID_REPORT_MODE_REPORT_MAP_ID, HID_REPORT_TYPE_INPUT);
break;
case ORG_BLUETOOTH_CHARACTERISTIC_HID_INFORMATION:
// printf("ORG_BLUETOOTH_CHARACTERISTIC_HID_INFORMATION\n");
hids_client_add_characteristic(client, &characteristic, HID_REPORT_MODE_HID_INFORMATION_ID, HID_REPORT_TYPE_INPUT);
break;
case ORG_BLUETOOTH_CHARACTERISTIC_HID_CONTROL_POINT:
// printf("ORG_BLUETOOTH_CHARACTERISTIC_HID_CONTROL_POINT\n");
hids_client_add_characteristic(client, &characteristic, HID_REPORT_MODE_HID_CONTROL_POINT_ID, HID_REPORT_TYPE_INPUT);
break;
default:
break;
}
break;
case GATT_EVENT_ALL_CHARACTERISTIC_DESCRIPTORS_QUERY_RESULT:
client = hids_get_client_for_con_handle(gatt_event_all_characteristic_descriptors_query_result_get_handle(packet));
btstack_assert(client != NULL);
gatt_event_all_characteristic_descriptors_query_result_get_characteristic_descriptor(packet, &characteristic_descriptor);
// setup for descriptor value query
if (characteristic_descriptor.uuid16 == ORG_BLUETOOTH_DESCRIPTOR_REPORT_REFERENCE){
client->descriptor_handle = characteristic_descriptor.handle;
}
break;
case GATT_EVENT_CHARACTERISTIC_DESCRIPTOR_QUERY_RESULT:
// get report ID
client = hids_get_client_for_con_handle(gatt_event_characteristic_descriptor_query_result_get_handle(packet));
btstack_assert(client != NULL);
if (gatt_event_characteristic_descriptor_query_result_get_descriptor_length(packet) == 2){
const uint8_t * value = gatt_event_characteristic_descriptor_query_result_get_descriptor(packet);
client->reports[client->active_report_index].report_id = value[0];
client->reports[client->active_report_index].report_type = (hid_report_type_t)value[1];
}
break;
case GATT_EVENT_QUERY_COMPLETE:
client = hids_get_client_for_con_handle(gatt_event_query_complete_get_handle(packet));
btstack_assert(client != NULL);
@ -411,7 +491,7 @@ static void handle_gatt_client_event(uint8_t packet_type, uint16_t channel, uint
hids_finalize_client(client);
break;
}
switch (client->required_protocol_mode){
case HID_PROTOCOL_MODE_BOOT:
if (get_boot_keyboard_input_report(client) != NULL){
@ -425,11 +505,65 @@ static void handle_gatt_client_event(uint8_t packet_type, uint16_t channel, uint
hids_emit_connection_established(client, ERROR_CODE_UNSUPPORTED_FEATURE_OR_PARAMETER_VALUE);
hids_finalize_client(client);
break;
case HID_PROTOCOL_MODE_REPORT:
if ((client->service_index + 1) < client->num_instances){
// discover characteristics of next service
client->service_index++;
client->state = HIDS_CLIENT_STATE_W2_QUERY_CHARACTERISTIC;
} else {
// discover characteristic descriptor for all Report characteristics,
// then read value of characteristic descriptor to get Report ID
client->active_report_index = 0;
client->service_index = 0;
hids_client_get_next_active_report_index(client);
if (client->active_report_index != HIDS_CLIENT_INVALID_REPORT_INDEX){
client->state = HIDS_CLIENT_STATE_W2_REPORT_QUERY_CHARACTERISTIC_DESCRIPTORS;
break;
}
hids_emit_connection_established(client, ERROR_CODE_UNSUPPORTED_FEATURE_OR_PARAMETER_VALUE);
hids_finalize_client(client);
}
break;
default:
break;
}
break;
case HIDS_CLIENT_STATE_W4_REPORT_CHARACTERISTIC_DESCRIPTORS_RESULT:
if (client->descriptor_handle != 0){
// descriptor found
client->state = HIDS_CLIENT_STATE_W2_REPORT_READ_CHARACTERISTIC_DESCRIPTOR_VALUE;
break;
}
// go for next report
client->active_report_index++;
hids_client_get_next_active_report_index(client);
if (client->active_report_index != HIDS_CLIENT_INVALID_REPORT_INDEX){
client->state = HIDS_CLIENT_STATE_W2_REPORT_QUERY_CHARACTERISTIC_DESCRIPTORS;
break;
}
// TODO continue with report mode
hids_emit_connection_established(client, ERROR_CODE_SUCCESS);
break;
case HIDS_CLIENT_STATE_W4_REPORT_CHARACTERISTIC_DESCRIPTOR_VALUE_RESULT:
// go for next report
client->active_report_index++;
hids_client_get_next_active_report_index(client);
if (client->active_report_index != HIDS_CLIENT_INVALID_REPORT_INDEX){
client->state = HIDS_CLIENT_STATE_W2_REPORT_QUERY_CHARACTERISTIC_DESCRIPTORS;
break;
}
// TODO continue with report mode
hids_emit_connection_established(client, ERROR_CODE_SUCCESS);
break;
case HIDS_CLIENT_STATE_W4_KEYBOARD_ENABLED:
boot_keyboard_report = get_boot_keyboard_input_report(client);
if (boot_keyboard_report != NULL){

View File

@ -58,16 +58,44 @@ extern "C" {
typedef enum {
HIDS_CLIENT_STATE_IDLE,
// get all HID services
HIDS_CLIENT_STATE_W2_QUERY_SERVICE,
HIDS_CLIENT_STATE_W4_SERVICE_RESULT,
// for each service, discover all characteristics
HIDS_CLIENT_STATE_W2_QUERY_CHARACTERISTIC,
HIDS_CLIENT_STATE_W4_CHARACTERISTIC_RESULT,
// for each REPORT_MAP characteristic, read HID Descriptor (Report Map Characteristic Value)
HIDS_CLIENT_STATE_W2_READ_REPORT_MAP_CHARACTERISTIC_VALUE,
HIDS_CLIENT_STATE_W4_REPORT_MAP_CHARACTERISTIC_VALUE_RESULT,
// for REPORT_MAP characteristic, read External Report Reference Characteristic Descriptor
HIDS_CLIENT_STATE_W2_REPORT_MAP_READ_CHARACTERISTIC_DESCRIPTOR_VALUE,
HIDS_CLIENT_STATE_W4_REPORT_MAP_CHARACTERISTIC_DESCRIPTOR_VALUE_RESULT,
// for every external report reference uuid, discover external Report characteristic
HIDS_CLIENT_STATE_W2_REPORT_MAP_QUERY_EXTERNAL_REPORT_CHARACTERISTIC,
HIDS_CLIENT_STATE_W4_REPORT_MAP_EXTERNAL_REPORT_CHARACTERISTIC_RESULT,
// for each Report characteristics, discover characteristic descriptor
HIDS_CLIENT_STATE_W2_REPORT_QUERY_CHARACTERISTIC_DESCRIPTORS,
HIDS_CLIENT_STATE_W4_REPORT_CHARACTERISTIC_DESCRIPTORS_RESULT,
// then read value of characteristic descriptor to get report ID and type
HIDS_CLIENT_STATE_W2_REPORT_READ_CHARACTERISTIC_DESCRIPTOR_VALUE,
HIDS_CLIENT_STATE_W4_REPORT_CHARACTERISTIC_DESCRIPTOR_VALUE_RESULT,
// Boot Mode
HIDS_CLIENT_STATE_W2_ENABLE_KEYBOARD,
HIDS_CLIENT_STATE_W4_KEYBOARD_ENABLED,
HIDS_CLIENT_STATE_W2_ENABLE_MOUSE,
HIDS_CLIENT_STATE_W4_MOUSE_ENABLED,
HIDS_CLIENT_STATE_W2_SET_PROTOCOL_MODE,
HIDS_CLIENT_STATE_W4_SET_PROTOCOL_MODE,
HIDS_CLIENT_STATE_CONNECTED,
HIDS_CLIENT_W2_SEND_REPORT
} hid_service_client_state_t;
@ -78,9 +106,11 @@ typedef struct {
uint16_t value_handle;
uint16_t end_handle;
uint16_t properties;
uint16_t external_report_reference_uuid;
// service mapping
uint8_t report_id;
uint8_t service_index;
uint8_t report_id;
hid_report_type_t report_type;
gatt_client_notification_t notifications;
} hids_client_report_t;
@ -113,6 +143,7 @@ typedef struct {
uint8_t num_reports;
uint8_t active_report_index;
uint16_t descriptor_handle;
uint16_t report_len;
const uint8_t * report;
} hids_client_t;