From fe493a7c9a16d8827e6e693ffc2d2a1c30271986 Mon Sep 17 00:00:00 2001 From: Milanka Ringwald Date: Tue, 19 Jan 2021 11:22:44 +0100 Subject: [PATCH] hid_host: handle boot mode --- src/classic/hid_host.c | 128 ++++++++++++++------------------------- src/classic/hid_host.h | 30 +++------ test/pts/hid_host.md | 10 +-- test/pts/hid_host_test.c | 96 +++++++++++++---------------- 4 files changed, 102 insertions(+), 162 deletions(-) diff --git a/src/classic/hid_host.c b/src/classic/hid_host.c index 005b1b8e4..f96cd8049 100644 --- a/src/classic/hid_host.c +++ b/src/classic/hid_host.c @@ -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; -} diff --git a/src/classic/hid_host.h b/src/classic/hid_host.h index 382594364..72782965e 100644 --- a/src/classic/hid_host.h +++ b/src/classic/hid_host.h @@ -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); diff --git a/test/pts/hid_host.md b/test/pts/hid_host.md index fad66fa9b..7c912fc2f 100644 --- a/test/pts/hid_host.md +++ b/test/pts/hid_host.md @@ -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 diff --git a/test/pts/hid_host_test.c b/test/pts/hid_host_test.c index 566842bb2..e91c6b0ec 100644 --- a/test/pts/hid_host_test.c +++ b/test/pts/hid_host_test.c @@ -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':