hid_host: handle boot mode

This commit is contained in:
Milanka Ringwald 2021-01-19 11:22:44 +01:00 committed by Matthias Ringwald
parent a93a968fd2
commit fe493a7c9a
4 changed files with 102 additions and 162 deletions

View File

@ -415,6 +415,12 @@ static void hid_host_handle_sdp_client_query_result(uint8_t packet_type, uint16_
break;
case SDP_EVENT_QUERY_COMPLETE:
status = sdp_event_query_complete_get_status(packet);
if (status != ERROR_CODE_SUCCESS){
break;
}
if (!connection->control_psm) {
status = ERROR_CODE_UNSUPPORTED_FEATURE_OR_PARAMETER_VALUE;
break;
@ -516,7 +522,6 @@ static void hid_host_handle_control_packet(hid_host_connection_t * connection, u
break;
case HID_HOST_W4_SET_PROTOCOL_RESPONSE:
printf("HID_HOST_W4_SET_PROTOCOL_RESPONSE \n");
hid_emit_event_with_status(connection, HID_SUBEVENT_SET_PROTOCOL_RESPONSE, message_status);
switch (message_status){
@ -525,15 +530,12 @@ static void hid_host_handle_control_packet(hid_host_connection_t * connection, u
case HID_PROTOCOL_MODE_BOOT:{
status = l2cap_create_channel(hid_host_packet_handler, connection->remote_addr, connection->interrupt_psm, 48, &connection->interrupt_cid);
if (status){
printf("Connecting to HID Control failed: 0x%02x\n", status);
connection->state = HID_HOST_CONTROL_CONNECTION_ESTABLISHED;
log_info("HID Inrerrupt Connection failed: 0x%02x\n", status);
break;
}
connection->state = HID_HOST_W4_INTERRUPT_CONNECTION_ESTABLISHED;
break;
return;
}
case HID_PROTOCOL_MODE_REPORT:
break;
default:
break;
}
@ -542,10 +544,6 @@ static void hid_host_handle_control_packet(hid_host_connection_t * connection, u
}
break;
case HID_HOST_W4_SEND_REPORT_RESPONSE:
printf("HID_HOST_W4_SEND_REPORT_RESPONSE\n");
break;
default:
log_info("ignore invalid HID Control message");
break;
@ -571,9 +569,9 @@ static void hid_host_packet_handler(uint8_t packet_type, uint16_t channel, uint8
if (!connection) break;
if (channel == connection->interrupt_cid){
uint8_t * in_place_event = packet - 6;
uint8_t * in_place_event = packet - 7;
hid_setup_report_event(connection, in_place_event, size-1);
hid_callback(HCI_EVENT_PACKET, connection->hid_cid, in_place_event, size + 6);
hid_callback(HCI_EVENT_PACKET, connection->hid_cid, in_place_event, size + 7);
break;
}
@ -634,7 +632,7 @@ static void hid_host_packet_handler(uint8_t packet_type, uint16_t channel, uint8
case L2CAP_EVENT_CHANNEL_OPENED:
l2cap_event_channel_opened_get_address(packet, address);
status = l2cap_event_channel_opened_get_status(packet);
if (status){
log_info("L2CAP connection %s failed: 0x%02xn", bd_addr_to_str(address), status);
@ -646,30 +644,34 @@ static void hid_host_packet_handler(uint8_t packet_type, uint16_t channel, uint8
log_error("Connection does not exist %s", bd_addr_to_str(address));
break;
}
switch (l2cap_event_channel_opened_get_psm(packet)){
case PSM_HID_CONTROL:
if (connection->state != HID_HOST_W4_CONTROL_CONNECTION_ESTABLISHED) break;
connection->state = HID_HOST_CONTROL_CONNECTION_ESTABLISHED;
if (connection->boot_mode){
break;
}
if (!connection->incoming){
status = l2cap_create_channel(hid_host_packet_handler, address, connection->interrupt_psm, 48, &connection->interrupt_cid);
if (status){
log_info("Connecting to HID Interrupt failed: 0x%02x", status);
connection->con_handle = l2cap_event_channel_opened_get_handle(packet);
switch (connection->protocol_mode){
case HID_PROTOCOL_MODE_BOOT:
connection->state = HID_HOST_W2_SEND_SET_PROTOCOL;
l2cap_request_can_send_now_event(connection->control_cid);
break;
default:
if (connection->incoming) break;
status = l2cap_create_channel(hid_host_packet_handler, address, connection->interrupt_psm, 48, &connection->interrupt_cid);
if (status){
log_info("Connecting to HID Interrupt failed: 0x%02x", status);
break;
}
connection->state = HID_HOST_W4_INTERRUPT_CONNECTION_ESTABLISHED;
break;
}
connection->con_handle = l2cap_event_channel_opened_get_handle(packet);
connection->state = HID_HOST_W4_INTERRUPT_CONNECTION_ESTABLISHED;
}
break;
case PSM_HID_INTERRUPT:
if (connection->state != HID_HOST_W4_INTERRUPT_CONNECTION_ESTABLISHED) break;
if (connection->con_handle != l2cap_event_channel_opened_get_handle(packet)) break;
connection->state = HID_HOST_CONNECTION_ESTABLISHED;
log_info("HID host connection established, cids: control 0x%02x, interrupt 0x%02x interrupt, hid 0x%02x",
connection->control_cid, connection->interrupt_cid, connection->hid_cid);
@ -742,7 +744,6 @@ static void hid_host_packet_handler(uint8_t packet_type, uint16_t channel, uint8
}
case HID_HOST_W2_SEND_SET_REPORT:{
printf(" HID_HOST_W2_SEND_SET_REPORT control\n");
uint8_t header = (HID_MESSAGE_TYPE_SET_REPORT << 4) | connection->report_type;
connection->state = HID_HOST_W4_SET_REPORT_RESPONSE;
@ -751,11 +752,7 @@ static void hid_host_packet_handler(uint8_t packet_type, uint16_t channel, uint8
out_buffer[0] = header;
out_buffer[1] = connection->report_id;
(void)memcpy(out_buffer + 2, connection->report, connection->report_len);
if (connection->boot_mode){
l2cap_send_prepared(connection->interrupt_cid, connection->report_len + 2);
} else {
l2cap_send_prepared(connection->control_cid, connection->report_len + 2);
}
l2cap_send_prepared(connection->control_cid, connection->report_len + 2);
break;
}
@ -779,24 +776,20 @@ static void hid_host_packet_handler(uint8_t packet_type, uint16_t channel, uint8
default:
break;
}
return;
}
switch(connection->state){
case HID_HOST_W2_SEND_REPORT:{
connection->state = HID_HOST_W4_SEND_REPORT_RESPONSE;
uint8_t header = (HID_MESSAGE_TYPE_DATA << 4) | connection->report_type;
if (connection->interrupt_cid == l2cap_cid && connection->state == HID_HOST_W2_SEND_REPORT){
connection->state = HID_HOST_CONNECTION_ESTABLISHED;
// there is no response for this type of message
uint8_t header = (HID_MESSAGE_TYPE_DATA << 4) | connection->report_type;
l2cap_reserve_packet_buffer();
uint8_t * out_buffer = l2cap_get_outgoing_buffer();
out_buffer[0] = header;
out_buffer[1] = connection->report_id;
(void)memcpy(out_buffer + 2, connection->report, connection->report_len);
l2cap_send_prepared(connection->interrupt_cid, connection->report_len + 2);
}
default:
break;
l2cap_reserve_packet_buffer();
uint8_t * out_buffer = l2cap_get_outgoing_buffer();
out_buffer[0] = header;
out_buffer[1] = connection->report_id;
(void)memcpy(out_buffer + 2, connection->report, connection->report_len);
l2cap_send_prepared(connection->interrupt_cid, connection->report_len + 2);
break;
}
if (connection->control_tasks != 0){
@ -944,7 +937,7 @@ uint8_t hid_host_send_virtual_cable_unplug(uint16_t hid_cid){
return hid_host_send_control_message(hid_cid, CONTROL_MESSAGE_BITMASK_VIRTUAL_CABLE_UNPLUG);
}
static uint8_t hid_host_send_get_report(uint16_t hid_cid, hid_report_type_t report_type, uint8_t report_id){
uint8_t hid_host_send_get_report(uint16_t hid_cid, hid_report_type_t report_type, uint8_t report_id){
hid_host_connection_t * connection = hid_host_get_connection_for_hid_cid(hid_cid);
if (!connection || !connection->control_cid){
@ -954,6 +947,8 @@ static uint8_t hid_host_send_get_report(uint16_t hid_cid, hid_report_type_t rep
return ERROR_CODE_COMMAND_DISALLOWED;
}
printf("protocol mode %d\n", connection->protocol_mode);
connection->state = HID_HOST_W2_SEND_GET_REPORT;
connection->report_type = report_type;
connection->report_id = report_id;
@ -962,19 +957,7 @@ static uint8_t hid_host_send_get_report(uint16_t hid_cid, hid_report_type_t rep
return ERROR_CODE_SUCCESS;
}
uint8_t hid_host_send_get_output_report(uint16_t hid_cid, uint8_t report_id){
return hid_host_send_get_report(hid_cid, HID_REPORT_TYPE_OUTPUT, report_id);
}
uint8_t hid_host_send_get_feature_report(uint16_t hid_cid, uint8_t report_id){
return hid_host_send_get_report(hid_cid, HID_REPORT_TYPE_FEATURE, report_id);
}
uint8_t hid_host_send_get_input_report(uint16_t hid_cid, uint8_t report_id){
return hid_host_send_get_report(hid_cid, HID_REPORT_TYPE_INPUT, report_id);
}
uint8_t hid_host_send_set_report_on_control_channel(uint16_t hid_cid, hid_report_type_t report_type, uint8_t report_id, const uint8_t * report, uint8_t report_len){
uint8_t hid_host_send_set_report(uint16_t hid_cid, hid_report_type_t report_type, uint8_t report_id, const uint8_t * report, uint8_t report_len){
hid_host_connection_t * connection = hid_host_get_connection_for_hid_cid(hid_cid);
if (!connection || !connection->control_cid){
@ -1030,7 +1013,7 @@ uint8_t hid_host_send_set_protocol_mode(uint16_t hid_cid, hid_protocol_mode_t pr
}
uint8_t hid_host_send_report_on_interrupt_channel(uint16_t hid_cid, hid_report_type_t report_type, uint8_t report_id, const uint8_t * report, uint8_t report_len){
uint8_t hid_host_send_report(uint16_t hid_cid, uint8_t report_id, const uint8_t * report, uint8_t report_len){
hid_host_connection_t * connection = hid_host_get_connection_for_hid_cid(hid_cid);
if (!connection || !connection->control_cid || !connection->interrupt_cid) {
return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
@ -1048,7 +1031,7 @@ uint8_t hid_host_send_report_on_interrupt_channel(uint16_t hid_cid, hid_report_t
}
connection->state = HID_HOST_W2_SEND_REPORT;
connection->report_type = report_type;
connection->report_type = HID_REPORT_TYPE_OUTPUT;
connection->report_id = report_id;
connection->report = report;
connection->report_len = report_len;
@ -1056,22 +1039,3 @@ uint8_t hid_host_send_report_on_interrupt_channel(uint16_t hid_cid, hid_report_t
l2cap_request_can_send_now_event(connection->interrupt_cid);
return ERROR_CODE_SUCCESS;
}
uint8_t hid_host_send_report_on_control_channel(uint16_t hid_cid, hid_report_type_t report_type, const uint8_t report_id, uint8_t * report, uint8_t report_len){
hid_host_connection_t * connection = hid_host_get_connection_for_hid_cid(hid_cid);
if (!connection || !connection->control_cid){
return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
}
if (connection->state != HID_HOST_CONNECTION_ESTABLISHED){
return ERROR_CODE_COMMAND_DISALLOWED;
}
connection->state = HID_HOST_W2_SEND_REPORT;
connection->report_type = report_type;
connection->report_id = report_id;
connection->report = report;
connection->report_len = report_len;
l2cap_request_can_send_now_event(connection->control_cid);
return ERROR_CODE_SUCCESS;
}

View File

@ -83,8 +83,7 @@ typedef struct {
bd_addr_t remote_addr;
bool incoming;
bool boot_mode;
uint16_t control_cid;
uint16_t control_psm;
uint16_t interrupt_cid;
@ -149,31 +148,20 @@ void hid_host_disconnect(uint16_t hid_cid);
// Control messages:
uint8_t hid_host_send_suspend(uint16_t hid_cid);
uint8_t hid_host_send_exit_suspend(uint16_t hid_cid);
uint8_t hid_host_send_virtual_cable_unplug(uint16_t hid_cid);
uint8_t hid_host_send_set_protocol_mode(uint16_t hid_cid, hid_protocol_mode_t protocol_mode);
uint8_t hid_host_send_get_protocol(uint16_t hid_cid);
uint8_t hid_host_send_set_report(uint16_t hid_cid, hid_report_type_t report_type, uint8_t report_id, const uint8_t * report, uint8_t report_len);
uint8_t hid_host_send_get_report(uint16_t hid_cid, hid_report_type_t report_type, uint8_t report_id);
/**
* @brief Send HID message on interrupt channel
* @param hid_cid
*/
uint8_t hid_host_send_set_protocol_mode(uint16_t hid_cid, hid_protocol_mode_t protocol_mode);
uint8_t hid_host_send_get_protocol(uint16_t hid_cid);
uint8_t hid_host_send_report_on_interrupt_channel(uint16_t hid_cid, hid_report_type_t report_type, uint8_t report_id, const uint8_t * report, uint8_t report_len);
uint8_t hid_host_send_report_on_control_channel(uint16_t hid_cid, hid_report_type_t report_type, const uint8_t report_id, uint8_t * report, uint8_t report_len);
uint8_t hid_host_send_set_report_on_control_channel(uint16_t hid_cid, hid_report_type_t report_type, uint8_t report_id, const uint8_t * report, uint8_t report_len);
uint8_t hid_host_send_set_output_report(uint16_t hid_cid, uint8_t report_id, uint8_t * report, uint8_t report_len);
uint8_t hid_host_send_set_feature_report(uint16_t hid_cid, uint8_t report_id, uint8_t * report, uint8_t report_len);
uint8_t hid_host_send_set_input_report(uint16_t hid_cid, uint8_t report_id, uint8_t * report, uint8_t report_len);
uint8_t hid_host_send_get_output_report(uint16_t hid_cid, uint8_t report_id);
uint8_t hid_host_send_get_feature_report(uint16_t hid_cid, uint8_t report_id);
uint8_t hid_host_send_get_input_report(uint16_t hid_cid, uint8_t report_id);
// on interrupt channel, allways output
uint8_t hid_host_send_report(uint16_t hid_cid, uint8_t report_id, const uint8_t * report, uint8_t report_len);
const uint8_t * hid_descriptor_storage_get_descriptor_data(uint16_t hid_cid);
const uint16_t hid_descriptor_storage_get_descriptor_len(uint16_t hid_cid);

View File

@ -20,13 +20,13 @@ HID11/HOS/HCT/BV-08-C: c, s, S
HID11/HOS/HCT/BI-01-C: c, (wait)
HID11/HOS/HCT/BI-02-C: c, 1, (Confirmation), 3, (Confirmation), 3, (Confirmation)
HID11/HOS/BHCT/BV-03-C:
HID11/HOS/BHCT/BI-01-C:
HID11/HOS/BHCT/BV-03-C: a, 9???
HID11/HOS/BHCT/BI-01-C: a, 3, (Confirmation) , 3, (Confirmation), 3, (Confirmation)
HID11/HOS/HIT/BV-01-C: c
HID11/HOS/HIT/BV-02-C: c, 7
HID11/HOS/HIT/BI-01-C: c, (Confirmation), (Confirmation), (Confirmation)
HID11/HOS/BHIT/BV-01-C:
HID11/HOS/BHIT/BV-02-C:
HID11/HOS/BHIT/BI-01-C:
HID11/HOS/BHIT/BV-01-C: a
HID11/HOS/BHIT/BV-02-C: a, 0 (ID 1, size 9)
HID11/HOS/BHIT/BI-01-C: a

View File

@ -109,11 +109,8 @@ static enum {
APP_CONNECTED
} app_state = APP_IDLE;
static bool unplugged;
static bool unplugged = false;
static uint16_t hid_host_cid = 0;
static bool boot_mode = false;
static bool send_through_interrupt_channel = false;
// SDP
static uint8_t hid_descriptor[MAX_ATTRIBUTE_VALUE_SIZE];
@ -287,8 +284,6 @@ static void packet_handler (uint8_t packet_type, uint16_t channel, uint8_t *pack
case HID_SUBEVENT_CONNECTION_CLOSED:
hid_host_cid = 0;
boot_mode = false;
send_through_interrupt_channel = false;
printf("HID Host disconnected..\n");
break;
@ -366,7 +361,8 @@ static void show_usage(void){
bd_addr_t iut_address;
gap_local_bd_addr(iut_address);
printf("\n--- Bluetooth HID Host Test Console %s ---\n", bd_addr_to_str(iut_address));
printf("c - start SDP scan and connect to %s\n", remote_addr_string);
printf("a - start SDP scan and connect to %s in BOOT mode\n", remote_addr_string);
printf("c - start SDP scan and connect to %s in REPORT mode\n", remote_addr_string);
printf("C - disconnect from %s\n", remote_addr_string);
printf("\n");
printf("s - suspend\n");
@ -383,10 +379,12 @@ static void show_usage(void){
printf("4 - Set report with id 0x03\n");
printf("5 - Set report with id 0x05\n");
printf("6 - Set report with id 0x02\n");
printf("\n");
printf("7 - Send output report with id 0x03 on interrupt channel\n");
printf("7 - Set report with id 0x01\n");
printf("\n");
printf("t - Send report with id 0x03\n");
printf("o - Send report with id 0x01\n");
printf("\n");
printf("p - Get protocol\n");
printf("r - Set protocol in REPORT mode\n");
@ -399,18 +397,22 @@ static void show_usage(void){
static void stdin_process(char cmd){
uint8_t status = ERROR_CODE_SUCCESS;
switch (cmd){
case 'a':
if (unplugged){
printf("Cannot connect, host is unplugged.\n");
break;
}
printf("Start SDP scan and connect to %s in boot mode.\n", remote_addr_string);
status = hid_host_connect(remote_addr, HID_PROTOCOL_MODE_BOOT, &hid_host_cid);
break;
case 'c':
if (unplugged){
printf("Cannot connect, host is unplugged.\n");
break;
}
printf("Start SDP scan and connect to %s.\n", remote_addr_string);
if (boot_mode){
status = hid_host_connect(remote_addr, HID_PROTOCOL_MODE_BOOT, &hid_host_cid);
} else {
status = hid_host_connect(remote_addr, HID_PROTOCOL_MODE_REPORT, &hid_host_cid);
}
printf("Start SDP scan and connect to %s in report mode.\n", remote_addr_string);
status = hid_host_connect(remote_addr, HID_PROTOCOL_MODE_REPORT, &hid_host_cid);
break;
case 'C':
@ -425,12 +427,10 @@ static void stdin_process(char cmd){
break;
case 'r':
printf("Set protocol in REPORT mode\n");
boot_mode = false;
status = hid_host_send_set_protocol_mode(hid_host_cid, HID_PROTOCOL_MODE_REPORT);
break;
case 'b':
printf("Set protocol in BOOT mode\n");
boot_mode = true;
status = hid_host_send_set_protocol_mode(hid_host_cid, HID_PROTOCOL_MODE_BOOT);
break;
@ -451,71 +451,59 @@ static void stdin_process(char cmd){
case '1':
printf("Get report with id 0x05\n");
status = hid_host_send_get_feature_report(hid_host_cid, 0x05);
status = hid_host_send_get_report(hid_host_cid, HID_REPORT_TYPE_FEATURE, 0x05);
break;
case '2':
printf("Get report with id 0x03\n");
status = hid_host_send_get_output_report(hid_host_cid, 0x03);
status = hid_host_send_get_report(hid_host_cid, HID_REPORT_TYPE_OUTPUT, 0x03);
break;
case '3':
printf("Get report from with id 0x02\n");
status = hid_host_send_get_input_report(hid_host_cid, 0x02);
break;
case 'x':
printf("Set send through interrupt channel\n");
send_through_interrupt_channel = true;
status = hid_host_send_get_report(hid_host_cid, HID_REPORT_TYPE_INPUT, 0x02);
break;
case '4':{
printf("Set output report with id 0x03\n");
uint8_t report[] = {0, 0};
status = hid_host_send_set_report_on_control_channel(hid_host_cid, HID_REPORT_TYPE_OUTPUT, 0x03, report, sizeof(report));
status = hid_host_send_set_report(hid_host_cid, HID_REPORT_TYPE_OUTPUT, 0x03, report, sizeof(report));
break;
}
case '5':{
printf("Set feature report with id 0x05\n");
uint8_t report[] = {0, 0, 0};
status = hid_host_send_set_report_on_control_channel(hid_host_cid, HID_REPORT_TYPE_FEATURE, 0x05, report, sizeof(report));
status = hid_host_send_set_report(hid_host_cid, HID_REPORT_TYPE_FEATURE, 0x05, report, sizeof(report));
break;
}
case '6':{
printf("Set input report with id 0x02\n");
uint8_t report[] = {0, 0, 0, 0};
status = hid_host_send_set_report_on_control_channel(hid_host_cid, HID_REPORT_TYPE_INPUT, 0x02, report, sizeof(report));
status = hid_host_send_set_report(hid_host_cid, HID_REPORT_TYPE_INPUT, 0x02, report, sizeof(report));
break;
}
case '7':
printf("Send output report with id 0x03 on interrupt channel\n");
uint8_t report[] = {0, 0};
status = hid_host_send_report_on_interrupt_channel(hid_host_cid, HID_REPORT_TYPE_OUTPUT, 0x03, report, sizeof(report));
case '7':{
uint8_t report[] = {0, 0, 0, 0, 0, 0, 0, 0};
printf("Set output report with id 0x01\n");
status = hid_host_send_set_report(hid_host_cid, HID_REPORT_TYPE_OUTPUT, 0x01, report, sizeof(report));
break;
}
case 't':{
printf("Send report with id 0x03\n");
uint8_t report[] = {0, 0};
status = hid_host_send_report(hid_host_cid, 0x03, report, sizeof(report));
break;
}
// case '8':{
// uint8_t report[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
// printf("Send output report with id 0x03\n");
// status = hid_host_send_output_report(hid_host_cid, 0x03, report, sizeof(report));
// break;
// }
// case '9':{
// uint8_t report[] = {0, 0, 0, 0, 0, 0, 0, 0};
// printf("Set output report with id 0x01\n");
// status = hid_host_send_set_output_report(hid_host_cid, 0x01, report, sizeof(report));
// break;
// }
// case '0':{
// uint8_t report[] = {0, 0, 0, 0, 0, 0, 0, 0};
// printf("Send output report with id 0x01\n");
// status = hid_host_send_output_report(hid_host_cid, 0x01, report, sizeof(report));
// break;
// }
case 'o':{
uint8_t report[] = {0, 0, 0, 0, 0, 0, 0, 0};
printf("Set output report with id 0x01\n");
status = hid_host_send_report(hid_host_cid, 0x01, report, sizeof(report));
break;
}
case '\n':
case '\r':