mirror of
https://github.com/bluekitchen/btstack.git
synced 2025-02-24 12:40:47 +00:00
hid_host: move code from test code to lib
This commit is contained in:
parent
fd7ba7a6d2
commit
ab30106e8f
@ -139,6 +139,18 @@ static inline void hid_emit_connected_event(hid_host_connection_t * context, uin
|
||||
hid_callback(HCI_EVENT_PACKET, context->hid_cid, &event[0], pos);
|
||||
}
|
||||
|
||||
static inline void hid_emit_event(hid_host_connection_t * context, uint8_t subevent_type){
|
||||
uint8_t event[5];
|
||||
int pos = 0;
|
||||
event[pos++] = HCI_EVENT_HID_META;
|
||||
pos++; // skip len
|
||||
event[pos++] = subevent_type;
|
||||
little_endian_store_16(event,pos,context->hid_cid);
|
||||
pos+=2;
|
||||
event[1] = pos - 2;
|
||||
hid_callback(HCI_EVENT_PACKET, context->hid_cid, &event[0], pos);
|
||||
}
|
||||
|
||||
// HID Host
|
||||
|
||||
static uint16_t hid_host_get_next_cid(void){
|
||||
@ -159,7 +171,7 @@ static hid_host_connection_t * hid_host_create_connection(bd_addr_t remote_addr)
|
||||
connection->state = HID_HOST_IDLE;
|
||||
connection->hid_cid = hid_host_get_next_cid();
|
||||
(void)memcpy(connection->remote_addr, remote_addr, 6);
|
||||
printf("hid_host_create_connection, cid 0x%02x, %s \n", connection->hid_cid, bd_addr_to_str(connection->remote_addr));
|
||||
printf("hid_host_create_connectionhid_host_connect, cid 0x%02x, %s \n", connection->hid_cid, bd_addr_to_str(connection->remote_addr));
|
||||
|
||||
btstack_linked_list_add(&connections, (btstack_linked_item_t *) connection);
|
||||
return connection;
|
||||
@ -176,7 +188,7 @@ static hid_host_connection_t * hid_host_get_connection_for_bd_addr(bd_addr_t add
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static hid_host_connection_t * hid_host_connection_for_hid_cid(uint16_t hid_cid){
|
||||
static hid_host_connection_t * hid_host_get_connection_for_hid_cid(uint16_t hid_cid){
|
||||
btstack_linked_list_iterator_t it;
|
||||
btstack_linked_list_iterator_init(&it, &connections);
|
||||
while (btstack_linked_list_iterator_has_next(&it)){
|
||||
@ -187,6 +199,17 @@ static hid_host_connection_t * hid_host_connection_for_hid_cid(uint16_t hid_cid)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static hid_host_connection_t * hid_host_get_connection_for_l2cap_cid(uint16_t l2cap_cid){
|
||||
btstack_linked_list_iterator_t it;
|
||||
btstack_linked_list_iterator_init(&it, &connections);
|
||||
while (btstack_linked_list_iterator_has_next(&it)){
|
||||
hid_host_connection_t * connection = (hid_host_connection_t *)btstack_linked_list_iterator_next(&it);
|
||||
if (connection->interrupt_cid != l2cap_cid || connection->control_cid != l2cap_cid) continue;
|
||||
return connection;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void hid_host_finalize_connection(hid_host_connection_t * connection){
|
||||
btstack_linked_list_remove(&connections, (btstack_linked_item_t*) connection);
|
||||
btstack_memory_hid_host_connection_free(connection);
|
||||
@ -205,11 +228,13 @@ static void hid_host_handle_sdp_client_query_result(uint8_t packet_type, uint16_
|
||||
uint32_t uuid;
|
||||
uint8_t status = ERROR_CODE_SUCCESS;
|
||||
|
||||
hid_host_connection_t * connection = hid_host_connection_for_hid_cid(sdp_query_context_hid_host_control_cid);
|
||||
hid_host_connection_t * connection = hid_host_get_connection_for_hid_cid(sdp_query_context_hid_host_control_cid);
|
||||
if (!connection) {
|
||||
log_error("SDP query, connection with 0x%02x cid not found", sdp_query_context_hid_host_control_cid);
|
||||
return;
|
||||
}
|
||||
|
||||
if (connection->state != HID_HOST_W4_SDP_QUERY_RESULT) return;
|
||||
|
||||
switch (hci_event_packet_get_type(packet)){
|
||||
case SDP_EVENT_QUERY_ATTRIBUTE_VALUE:
|
||||
@ -307,10 +332,11 @@ static void hid_host_handle_sdp_client_query_result(uint8_t packet_type, uint16_
|
||||
break;
|
||||
}
|
||||
|
||||
printf("Setup HID\n");
|
||||
connection->state = HID_HOST_W4_CONTROL_CONNECTION_ESTABLISHED;
|
||||
status = l2cap_create_channel(hid_host_packet_handler, connection->remote_addr, connection->control_psm, 48, &connection->control_cid);
|
||||
printf("l2cap_create_channel HID 0x%02x\n", connection->control_cid);
|
||||
if (status){
|
||||
printf("Connecting to HID Control failed: 0x%02x\n", status);
|
||||
printf("Connecting to HID Control failed: 0x%02x\n", connection->control_cid);
|
||||
}
|
||||
break;
|
||||
|
||||
@ -329,6 +355,196 @@ static void hid_host_handle_sdp_client_query_result(uint8_t packet_type, uint16_
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
// Simplified US Keyboard with Shift modifier
|
||||
|
||||
#define CHAR_ILLEGAL 0xff
|
||||
#define CHAR_RETURN '\n'
|
||||
#define CHAR_ESCAPE 27
|
||||
#define CHAR_TAB '\t'
|
||||
#define CHAR_BACKSPACE 0x7f
|
||||
|
||||
//
|
||||
// English (US)
|
||||
//
|
||||
static const uint8_t keytable_us_none [] = {
|
||||
CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, // 0-3
|
||||
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', // 4-13
|
||||
'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', // 14-23
|
||||
'u', 'v', 'w', 'x', 'y', 'z', // 24-29
|
||||
'1', '2', '3', '4', '5', '6', '7', '8', '9', '0', // 30-39
|
||||
CHAR_RETURN, CHAR_ESCAPE, CHAR_BACKSPACE, CHAR_TAB, ' ', // 40-44
|
||||
'-', '=', '[', ']', '\\', CHAR_ILLEGAL, ';', '\'', 0x60, ',', // 45-54
|
||||
'.', '/', CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, // 55-60
|
||||
CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, // 61-64
|
||||
CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, // 65-68
|
||||
CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, // 69-72
|
||||
CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, // 73-76
|
||||
CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, // 77-80
|
||||
CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, // 81-84
|
||||
'*', '-', '+', '\n', '1', '2', '3', '4', '5', // 85-97
|
||||
'6', '7', '8', '9', '0', '.', 0xa7, // 97-100
|
||||
};
|
||||
|
||||
static const uint8_t keytable_us_shift[] = {
|
||||
CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, // 0-3
|
||||
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', // 4-13
|
||||
'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', // 14-23
|
||||
'U', 'V', 'W', 'X', 'Y', 'Z', // 24-29
|
||||
'!', '@', '#', '$', '%', '^', '&', '*', '(', ')', // 30-39
|
||||
CHAR_RETURN, CHAR_ESCAPE, CHAR_BACKSPACE, CHAR_TAB, ' ', // 40-44
|
||||
'_', '+', '{', '}', '|', CHAR_ILLEGAL, ':', '"', 0x7E, '<', // 45-54
|
||||
'>', '?', CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, // 55-60
|
||||
CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, // 61-64
|
||||
CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, // 65-68
|
||||
CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, // 69-72
|
||||
CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, // 73-76
|
||||
CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, // 77-80
|
||||
CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, // 81-84
|
||||
'*', '-', '+', '\n', '1', '2', '3', '4', '5', // 85-97
|
||||
'6', '7', '8', '9', '0', '.', 0xb1, // 97-100
|
||||
};
|
||||
|
||||
|
||||
#define NUM_KEYS 6
|
||||
static uint8_t last_keys[NUM_KEYS];
|
||||
static void hid_host_handle_interrupt_report(const uint8_t * report, uint16_t report_len){
|
||||
// check if HID Input Report
|
||||
if (report_len < 1) return;
|
||||
if (*report != 0xa1) return;
|
||||
report++;
|
||||
report_len--;
|
||||
btstack_hid_parser_t parser;
|
||||
btstack_hid_parser_init(&parser, hid_descriptor, hid_descriptor_len, HID_REPORT_TYPE_INPUT, report, report_len);
|
||||
int shift = 0;
|
||||
uint8_t new_keys[NUM_KEYS];
|
||||
memset(new_keys, 0, sizeof(new_keys));
|
||||
int new_keys_count = 0;
|
||||
while (btstack_hid_parser_has_more(&parser)){
|
||||
uint16_t usage_page;
|
||||
uint16_t usage;
|
||||
int32_t value;
|
||||
btstack_hid_parser_get_field(&parser, &usage_page, &usage, &value);
|
||||
if (usage_page != 0x07) continue;
|
||||
switch (usage){
|
||||
case 0xe1:
|
||||
case 0xe6:
|
||||
if (value){
|
||||
shift = 1;
|
||||
}
|
||||
continue;
|
||||
case 0x00:
|
||||
continue;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (usage >= sizeof(keytable_us_none)) continue;
|
||||
|
||||
// store new keys
|
||||
new_keys[new_keys_count++] = usage;
|
||||
|
||||
// check if usage was used last time (and ignore in that case)
|
||||
int i;
|
||||
for (i=0;i<NUM_KEYS;i++){
|
||||
if (usage == last_keys[i]){
|
||||
usage = 0;
|
||||
}
|
||||
}
|
||||
if (usage == 0) continue;
|
||||
|
||||
uint8_t key;
|
||||
if (shift){
|
||||
key = keytable_us_shift[usage];
|
||||
} else {
|
||||
key = keytable_us_none[usage];
|
||||
}
|
||||
if (key == CHAR_ILLEGAL) continue;
|
||||
if (key == CHAR_BACKSPACE){
|
||||
printf("\b \b"); // go back one char, print space, go back one char again
|
||||
continue;
|
||||
}
|
||||
printf("%c", key);
|
||||
}
|
||||
memcpy(last_keys, new_keys, NUM_KEYS);
|
||||
}
|
||||
*/
|
||||
|
||||
static void hid_host_handle_control_packet(hid_host_connection_t * connection, uint8_t *packet, uint16_t size){
|
||||
UNUSED(size);
|
||||
uint8_t param;
|
||||
hid_message_type_t message_type;
|
||||
hid_handshake_param_type_t message_status;
|
||||
uint8_t status;
|
||||
|
||||
message_type = (hid_message_type_t)(packet[0] >> 4);
|
||||
message_status = (hid_handshake_param_type_t)(packet[0] & 0x0F);
|
||||
printf("HID Control data, message_type 0x%02x, status 0x%02x: \n", message_type, message_status);
|
||||
|
||||
// TODO handle handshake message_status
|
||||
switch (message_type){
|
||||
case HID_MESSAGE_TYPE_DATA:
|
||||
switch (connection->state){
|
||||
case HID_HOST_W4_GET_REPORT_RESPONSE:
|
||||
printf("HID_HOST_W4_GET_REPORT_RESPONSE \n");
|
||||
break;
|
||||
case HID_HOST_W4_SET_REPORT_RESPONSE:
|
||||
printf("HID_HOST_W4_SET_REPORT_RESPONSE \n");
|
||||
break;
|
||||
case HID_HOST_W4_GET_PROTOCOL_RESPONSE:
|
||||
printf("HID_HOST_W4_GET_PROTOCOL_RESPONSE \n");
|
||||
break;
|
||||
case HID_HOST_W4_SEND_REPORT_RESPONSE:
|
||||
printf("HID_HOST_W4_SEND_REPORT_RESPONSE\n");
|
||||
break;
|
||||
case HID_HOST_W4_SET_PROTOCOL_RESPONSE:
|
||||
printf("HID_HOST_W4_SET_PROTOCOL_RESPONSE \n");
|
||||
switch (message_status){
|
||||
case HID_HANDSHAKE_PARAM_TYPE_SUCCESSFUL:
|
||||
switch(connection->protocol_mode){
|
||||
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;
|
||||
break;
|
||||
}
|
||||
connection->state = HID_HOST_W4_INTERRUPT_CONNECTION_ESTABLISHED;
|
||||
break;
|
||||
}
|
||||
case HID_PROTOCOL_MODE_REPORT:
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
printf("HID_MESSAGE_TYPE_DATA ???\n");
|
||||
break;
|
||||
}
|
||||
connection->state = HID_HOST_CONNECTION_ESTABLISHED;
|
||||
break;
|
||||
|
||||
case HID_MESSAGE_TYPE_HID_CONTROL:
|
||||
param = packet[0] & 0x0F;
|
||||
|
||||
switch ((hid_control_param_t)param){
|
||||
case HID_CONTROL_PARAM_VIRTUAL_CABLE_UNPLUG:
|
||||
// hid_host_emit_event(device, HID_SUBEVENT_VIRTUAL_CABLE_UNPLUG);
|
||||
connection->unplugged = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void hid_host_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
|
||||
UNUSED(channel);
|
||||
UNUSED(size);
|
||||
@ -336,14 +552,24 @@ static void hid_host_packet_handler(uint8_t packet_type, uint16_t channel, uint8
|
||||
uint8_t event;
|
||||
bd_addr_t address;
|
||||
uint8_t status;
|
||||
uint16_t cid;
|
||||
uint16_t l2cap_cid;
|
||||
hid_host_connection_t * connection;
|
||||
|
||||
// uint8_t param;
|
||||
// hid_message_type_t message_type;
|
||||
// hid_handshake_param_type_t message_status;
|
||||
|
||||
switch (packet_type) {
|
||||
|
||||
case L2CAP_DATA_PACKET:
|
||||
connection = hid_host_get_connection_for_l2cap_cid(channel);
|
||||
if (!connection) break;
|
||||
if (channel == connection->interrupt_cid){
|
||||
// hid_host_handle_interrupt_report(packet, size);
|
||||
break;
|
||||
}
|
||||
if (channel == connection->control_cid){
|
||||
hid_host_handle_control_packet(connection, packet, size);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case HCI_EVENT_PACKET:
|
||||
event = hci_event_packet_get_type(packet);
|
||||
switch (event) {
|
||||
@ -415,8 +641,8 @@ static void hid_host_packet_handler(uint8_t packet_type, uint16_t channel, uint8
|
||||
break;
|
||||
}
|
||||
|
||||
cid = l2cap_event_channel_opened_get_local_cid(packet);
|
||||
|
||||
// l2cap_cid = l2cap_event_channel_opened_get_local_cid(packet);
|
||||
|
||||
switch (l2cap_event_channel_opened_get_psm(packet)){
|
||||
case PSM_HID_CONTROL:
|
||||
if (connection->state != HID_HOST_W4_CONTROL_CONNECTION_ESTABLISHED) break;
|
||||
@ -440,11 +666,8 @@ static void hid_host_packet_handler(uint8_t packet_type, uint16_t channel, uint8
|
||||
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;
|
||||
hid_emit_connected_event(connection, ERROR_CODE_SUCCESS);
|
||||
|
||||
log_info("Connection on interrupt channel established, interrupt_cid 0x%02x", connection->interrupt_cid);
|
||||
break;
|
||||
|
||||
default:
|
||||
@ -453,6 +676,92 @@ static void hid_host_packet_handler(uint8_t packet_type, uint16_t channel, uint8
|
||||
// disconnect?
|
||||
break;
|
||||
|
||||
case L2CAP_EVENT_CHANNEL_CLOSED:
|
||||
l2cap_cid = l2cap_event_channel_closed_get_local_cid(packet);
|
||||
connection = hid_host_get_connection_for_l2cap_cid(l2cap_cid);
|
||||
if (!connection) return;
|
||||
|
||||
if (l2cap_cid == connection->interrupt_cid){
|
||||
connection->interrupt_cid = 0;
|
||||
if (connection->state == HID_HOST_W4_INTERRUPT_CONNECTION_DISCONNECTED){
|
||||
connection->state = HID_HOST_W4_CONTROL_CONNECTION_DISCONNECTED;
|
||||
l2cap_disconnect(connection->control_cid, 0);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (l2cap_cid == connection->control_cid){
|
||||
connection->control_cid = 0;
|
||||
hid_emit_event(connection, HID_SUBEVENT_CONNECTION_CLOSED);
|
||||
hid_descriptor_storage_delete(connection);
|
||||
hid_host_finalize_connection(connection);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case L2CAP_EVENT_CAN_SEND_NOW:
|
||||
l2cap_cid = l2cap_event_can_send_now_get_local_cid(packet);
|
||||
connection = hid_host_get_connection_for_l2cap_cid(l2cap_cid);
|
||||
if (!connection) return;
|
||||
|
||||
printf("L2CAP_EVENT_CAN_SEND_NOW, hid_host.state = %d\n", connection->state);
|
||||
switch(connection->state){
|
||||
case HID_HOST_W2_SEND_GET_REPORT:{
|
||||
uint8_t header = (HID_MESSAGE_TYPE_GET_REPORT << 4) | connection->report_type;
|
||||
uint8_t report[] = {header, connection->report_id};
|
||||
// TODO: optional Report ID (1)
|
||||
// TODO: optional Maximum number of bytes to transfer during data phase, little end. (2)
|
||||
|
||||
connection->state = HID_HOST_W4_GET_REPORT_RESPONSE;
|
||||
l2cap_send(connection->control_cid, (uint8_t*) report, sizeof(report));
|
||||
break;
|
||||
}
|
||||
case HID_HOST_W2_SEND_SET_REPORT:{
|
||||
uint8_t header = (HID_MESSAGE_TYPE_SET_REPORT << 4) | connection->report_type;
|
||||
connection->state = HID_HOST_W4_SET_REPORT_RESPONSE;
|
||||
|
||||
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);
|
||||
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);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case HID_HOST_W2_SEND_GET_PROTOCOL:{
|
||||
uint8_t header = (HID_MESSAGE_TYPE_GET_PROTOCOL << 4);
|
||||
uint8_t report[] = {header};
|
||||
connection->state = HID_HOST_W4_GET_PROTOCOL_RESPONSE;
|
||||
l2cap_send(connection->control_cid, (uint8_t*) report, sizeof(report));
|
||||
break;
|
||||
}
|
||||
case HID_HOST_W2_SEND_SET_PROTOCOL:{
|
||||
uint8_t header = (HID_MESSAGE_TYPE_SET_PROTOCOL << 4) | connection->protocol_mode;
|
||||
uint8_t report[] = {header};
|
||||
|
||||
connection->state = HID_HOST_W4_SET_PROTOCOL_RESPONSE;
|
||||
l2cap_send(connection->control_cid, (uint8_t*) report, sizeof(report));
|
||||
break;
|
||||
}
|
||||
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;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@ -523,6 +832,7 @@ uint8_t hid_host_connect(bd_addr_t remote_addr, hid_protocol_mode_t protocol_mod
|
||||
connection->control_psm = 0;
|
||||
connection->interrupt_cid = 0;
|
||||
connection->interrupt_psm = 0;
|
||||
|
||||
printf("hid_host_connect, cid 0x%02x, %s \n", connection->hid_cid, bd_addr_to_str(connection->remote_addr));
|
||||
|
||||
hid_host_handle_sdp_client_query_request.callback = &hid_host_handle_start_sdp_client_query;
|
||||
@ -534,7 +844,29 @@ uint8_t hid_host_connect(bd_addr_t remote_addr, hid_protocol_mode_t protocol_mod
|
||||
|
||||
|
||||
void hid_host_disconnect(uint16_t hid_cid){
|
||||
UNUSED(hid_cid);
|
||||
hid_host_connection_t * connection = hid_host_get_connection_for_hid_cid(hid_cid);
|
||||
if (!connection) return;
|
||||
|
||||
switch (connection->state){
|
||||
case HID_HOST_IDLE:
|
||||
case HID_HOST_W4_CONTROL_CONNECTION_DISCONNECTED:
|
||||
case HID_HOST_W4_INTERRUPT_CONNECTION_DISCONNECTED:
|
||||
return;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (connection->interrupt_cid){
|
||||
connection->state = HID_HOST_W4_INTERRUPT_CONNECTION_DISCONNECTED;
|
||||
l2cap_disconnect(connection->interrupt_cid, 0); // reason isn't used
|
||||
return;
|
||||
}
|
||||
|
||||
if (connection->control_cid){
|
||||
connection->state = HID_HOST_W4_CONTROL_CONNECTION_DISCONNECTED;
|
||||
l2cap_disconnect(connection->control_cid, 0); // reason isn't used
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void hid_host_request_can_send_now_event(uint16_t hid_cid){
|
||||
@ -547,8 +879,139 @@ void hid_host_send_interrupt_message(uint16_t hid_cid, const uint8_t * message,
|
||||
UNUSED(message_len);
|
||||
}
|
||||
|
||||
static 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){
|
||||
return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
|
||||
}
|
||||
if (connection->state != HID_HOST_CONNECTION_ESTABLISHED){
|
||||
return ERROR_CODE_COMMAND_DISALLOWED;
|
||||
}
|
||||
|
||||
connection->state = HID_HOST_W2_SEND_GET_REPORT;
|
||||
connection->report_type = report_type;
|
||||
connection->report_id = report_id;
|
||||
|
||||
l2cap_request_can_send_now_event(connection->control_cid);
|
||||
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);
|
||||
}
|
||||
|
||||
static uint8_t hid_host_send_set_report(uint16_t hid_cid, hid_report_type_t report_type, 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){
|
||||
printf("hid_host_send_set_report: unexpected state 0%02x\n", HID_HOST_CONNECTION_ESTABLISHED);
|
||||
return ERROR_CODE_COMMAND_DISALLOWED;
|
||||
}
|
||||
|
||||
connection->state = HID_HOST_W2_SEND_SET_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;
|
||||
}
|
||||
|
||||
uint8_t hid_host_send_set_output_report(uint16_t hid_cid, uint8_t report_id, uint8_t * report, uint8_t report_len){
|
||||
return hid_host_send_set_report(hid_cid, HID_REPORT_TYPE_OUTPUT, report_id, report, 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){
|
||||
return hid_host_send_set_report(hid_cid, HID_REPORT_TYPE_FEATURE, report_id, report, 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){
|
||||
return hid_host_send_set_report(hid_cid, HID_REPORT_TYPE_INPUT, report_id, report, report_len);
|
||||
}
|
||||
|
||||
uint8_t hid_host_send_get_protocol(uint16_t hid_cid){
|
||||
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_GET_PROTOCOL;
|
||||
|
||||
l2cap_request_can_send_now_event(connection->control_cid);
|
||||
return ERROR_CODE_SUCCESS;
|
||||
}
|
||||
|
||||
uint8_t hid_host_send_set_protocol_mode(uint16_t hid_cid, hid_protocol_mode_t protocol_mode){
|
||||
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_CONTROL_CONNECTION_ESTABLISHED){
|
||||
return ERROR_CODE_COMMAND_DISALLOWED;
|
||||
}
|
||||
|
||||
connection->state = HID_HOST_W2_SEND_SET_PROTOCOL;
|
||||
connection->protocol_mode = protocol_mode;
|
||||
|
||||
l2cap_request_can_send_now_event(connection->control_cid);
|
||||
return ERROR_CODE_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
static uint8_t hid_host_send_report(uint16_t hid_cid, hid_report_type_t report_type, 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;
|
||||
}
|
||||
|
||||
uint8_t hid_host_send_output_report(uint16_t hid_cid, uint8_t report_id, uint8_t * report, uint8_t report_len){
|
||||
return hid_host_send_report(hid_cid, HID_REPORT_TYPE_OUTPUT, report_id, report, report_len);
|
||||
}
|
||||
|
||||
void hid_host_send_control_message(uint16_t hid_cid, const uint8_t * message, uint16_t message_len){
|
||||
UNUSED(hid_cid);
|
||||
UNUSED(message);
|
||||
UNUSED(message_len);
|
||||
hid_host_connection_t * connection = hid_host_get_connection_for_hid_cid(hid_cid);
|
||||
if (!connection || !connection->control_cid) return;
|
||||
l2cap_send(connection->control_cid, (uint8_t*) message, message_len);
|
||||
}
|
||||
|
||||
uint8_t hid_host_send_suspend(uint16_t hid_cid){
|
||||
uint8_t report[] = { (HID_MESSAGE_TYPE_HID_CONTROL << 4) | HID_CONTROL_PARAM_SUSPEND };
|
||||
hid_host_send_control_message(hid_cid, &report[0], sizeof(report));
|
||||
return ERROR_CODE_SUCCESS;
|
||||
}
|
||||
|
||||
uint8_t hid_host_send_exit_suspend(uint16_t hid_cid){
|
||||
uint8_t report[] = { (HID_MESSAGE_TYPE_HID_CONTROL << 4) | HID_CONTROL_PARAM_EXIT_SUSPEND };
|
||||
hid_host_send_control_message(hid_cid, &report[0], sizeof(report));
|
||||
return ERROR_CODE_SUCCESS;
|
||||
}
|
||||
|
||||
uint8_t hid_host_send_virtual_cable_unplug(uint16_t hid_cid){
|
||||
uint8_t report[] = { (HID_MESSAGE_TYPE_HID_CONTROL << 4) | HID_CONTROL_PARAM_VIRTUAL_CABLE_UNPLUG };
|
||||
hid_host_send_control_message(hid_cid, &report[0], sizeof(report));
|
||||
return ERROR_CODE_SUCCESS;
|
||||
}
|
@ -69,10 +69,15 @@ typedef enum {
|
||||
HID_HOST_W2_SEND_SET_PROTOCOL,
|
||||
HID_HOST_W4_SET_PROTOCOL_RESPONSE,
|
||||
HID_HOST_W2_SEND_REPORT,
|
||||
HID_HOST_W4_SEND_REPORT_RESPONSE
|
||||
HID_HOST_W4_SEND_REPORT_RESPONSE,
|
||||
|
||||
HID_HOST_W4_INTERRUPT_CONNECTION_DISCONNECTED,
|
||||
HID_HOST_W4_CONTROL_CONNECTION_DISCONNECTED
|
||||
} hid_host_state_t;
|
||||
|
||||
typedef struct {
|
||||
btstack_linked_item_t item;
|
||||
|
||||
uint16_t hid_cid;
|
||||
hci_con_handle_t con_handle;
|
||||
|
||||
@ -153,6 +158,24 @@ void hid_host_send_interrupt_message(uint16_t hid_cid, const uint8_t * message,
|
||||
void hid_host_send_control_message(uint16_t hid_cid, const uint8_t * message, uint16_t message_len);
|
||||
|
||||
|
||||
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_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_output_report(uint16_t hid_cid, uint8_t report_id, 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);
|
||||
|
||||
|
||||
/* API_END */
|
||||
|
||||
|
@ -35,17 +35,13 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#define __BTSTACK_FILE__ "hid_host_tast.c"
|
||||
#define __BTSTACK_FILE__ "hid_host_test.c"
|
||||
|
||||
/*
|
||||
* hid_host_tast.c
|
||||
* hid_host_test.c
|
||||
*/
|
||||
|
||||
/* EXAMPLE_START(hid_host_tast): HID Host Demo
|
||||
*
|
||||
* @text This example implements an HID Host. For now, it connnects to a fixed device, queries the HID SDP
|
||||
* record and opens the HID Control + Interrupt channels
|
||||
*/
|
||||
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <stdio.h>
|
||||
@ -61,296 +57,19 @@ static enum {
|
||||
} app_state = APP_IDLE;
|
||||
|
||||
static uint16_t hid_host_cid = 0;
|
||||
static bool unplugged;
|
||||
static bool boot_mode = false;
|
||||
static bool send_through_interrupt_channel = false;
|
||||
|
||||
// SDP
|
||||
static uint8_t hid_descriptor[MAX_ATTRIBUTE_VALUE_SIZE];
|
||||
static uint16_t hid_descriptor_len;
|
||||
|
||||
static uint16_t hid_interrupt_psm;
|
||||
|
||||
// PTS
|
||||
static const char * remote_addr_string = "00:1B:DC:08:E2:5C";
|
||||
|
||||
static bd_addr_t remote_addr;
|
||||
|
||||
static btstack_packet_callback_registration_t hci_event_callback_registration;
|
||||
|
||||
|
||||
// Simplified US Keyboard with Shift modifier
|
||||
|
||||
#define CHAR_ILLEGAL 0xff
|
||||
#define CHAR_RETURN '\n'
|
||||
#define CHAR_ESCAPE 27
|
||||
#define CHAR_TAB '\t'
|
||||
#define CHAR_BACKSPACE 0x7f
|
||||
|
||||
/**
|
||||
* English (US)
|
||||
*/
|
||||
static const uint8_t keytable_us_none [] = {
|
||||
CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, /* 0-3 */
|
||||
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', /* 4-13 */
|
||||
'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', /* 14-23 */
|
||||
'u', 'v', 'w', 'x', 'y', 'z', /* 24-29 */
|
||||
'1', '2', '3', '4', '5', '6', '7', '8', '9', '0', /* 30-39 */
|
||||
CHAR_RETURN, CHAR_ESCAPE, CHAR_BACKSPACE, CHAR_TAB, ' ', /* 40-44 */
|
||||
'-', '=', '[', ']', '\\', CHAR_ILLEGAL, ';', '\'', 0x60, ',', /* 45-54 */
|
||||
'.', '/', CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, /* 55-60 */
|
||||
CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, /* 61-64 */
|
||||
CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, /* 65-68 */
|
||||
CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, /* 69-72 */
|
||||
CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, /* 73-76 */
|
||||
CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, /* 77-80 */
|
||||
CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, /* 81-84 */
|
||||
'*', '-', '+', '\n', '1', '2', '3', '4', '5', /* 85-97 */
|
||||
'6', '7', '8', '9', '0', '.', 0xa7, /* 97-100 */
|
||||
};
|
||||
|
||||
static const uint8_t keytable_us_shift[] = {
|
||||
CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, /* 0-3 */
|
||||
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', /* 4-13 */
|
||||
'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', /* 14-23 */
|
||||
'U', 'V', 'W', 'X', 'Y', 'Z', /* 24-29 */
|
||||
'!', '@', '#', '$', '%', '^', '&', '*', '(', ')', /* 30-39 */
|
||||
CHAR_RETURN, CHAR_ESCAPE, CHAR_BACKSPACE, CHAR_TAB, ' ', /* 40-44 */
|
||||
'_', '+', '{', '}', '|', CHAR_ILLEGAL, ':', '"', 0x7E, '<', /* 45-54 */
|
||||
'>', '?', CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, /* 55-60 */
|
||||
CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, /* 61-64 */
|
||||
CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, /* 65-68 */
|
||||
CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, /* 69-72 */
|
||||
CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, /* 73-76 */
|
||||
CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, /* 77-80 */
|
||||
CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, /* 81-84 */
|
||||
'*', '-', '+', '\n', '1', '2', '3', '4', '5', /* 85-97 */
|
||||
'6', '7', '8', '9', '0', '.', 0xb1, /* 97-100 */
|
||||
};
|
||||
|
||||
|
||||
// hid device state
|
||||
typedef struct hid_host {
|
||||
uint16_t cid;
|
||||
bd_addr_t bd_addr;
|
||||
hci_con_handle_t con_handle;
|
||||
uint16_t control_cid;
|
||||
uint16_t interrupt_cid;
|
||||
|
||||
bool unplugged;
|
||||
|
||||
// get report
|
||||
hid_report_type_t report_type;
|
||||
uint8_t report_id;
|
||||
|
||||
// set report
|
||||
uint8_t * report;
|
||||
uint16_t report_len;
|
||||
|
||||
// set protocol
|
||||
hid_protocol_mode_t protocol_mode;
|
||||
|
||||
hid_host_state_t state;
|
||||
uint8_t user_request_can_send_now;
|
||||
} hid_host_t;
|
||||
|
||||
|
||||
static hid_host_t _hid_host;
|
||||
static bool boot_mode = false;
|
||||
static bool send_through_interrupt_channel = false;
|
||||
|
||||
static hid_host_t * hid_host_get_instance_for_hid_cid(uint16_t hid_cid){
|
||||
if (_hid_host.cid == hid_cid){
|
||||
return &_hid_host;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static uint8_t hid_host_send_get_report(uint16_t hid_cid, hid_report_type_t report_type, uint8_t report_id){
|
||||
hid_host_t * hid_host = hid_host_get_instance_for_hid_cid(hid_cid);
|
||||
if (!hid_host || !hid_host->control_cid){
|
||||
return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
|
||||
}
|
||||
if (hid_host->state != HID_HOST_CONNECTION_ESTABLISHED){
|
||||
return ERROR_CODE_COMMAND_DISALLOWED;
|
||||
}
|
||||
|
||||
hid_host->state = HID_HOST_W2_SEND_GET_REPORT;
|
||||
hid_host->report_type = report_type;
|
||||
hid_host->report_id = report_id;
|
||||
|
||||
l2cap_request_can_send_now_event(hid_host->control_cid);
|
||||
return ERROR_CODE_SUCCESS;
|
||||
}
|
||||
|
||||
static 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);
|
||||
}
|
||||
|
||||
static 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);
|
||||
}
|
||||
|
||||
static 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);
|
||||
}
|
||||
|
||||
static uint8_t hid_host_send_set_report(uint16_t hid_cid, hid_report_type_t report_type, uint8_t report_id, uint8_t * report, uint8_t report_len){
|
||||
hid_host_t * hid_host = hid_host_get_instance_for_hid_cid(hid_cid);
|
||||
if (!hid_host || !hid_host->control_cid){
|
||||
return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
|
||||
}
|
||||
|
||||
if (hid_host->state != HID_HOST_CONNECTION_ESTABLISHED){
|
||||
printf("hid_host_send_set_report: unexpected state 0%02x\n", HID_HOST_CONNECTION_ESTABLISHED);
|
||||
return ERROR_CODE_COMMAND_DISALLOWED;
|
||||
}
|
||||
|
||||
hid_host->state = HID_HOST_W2_SEND_SET_REPORT;
|
||||
hid_host->report_type = report_type;
|
||||
hid_host->report_id = report_id;
|
||||
hid_host->report = report;
|
||||
hid_host->report_len = report_len;
|
||||
|
||||
l2cap_request_can_send_now_event(hid_host->control_cid);
|
||||
return ERROR_CODE_SUCCESS;
|
||||
}
|
||||
|
||||
static uint8_t hid_host_send_set_output_report(uint16_t hid_cid, uint8_t report_id, uint8_t * report, uint8_t report_len){
|
||||
return hid_host_send_set_report(hid_cid, HID_REPORT_TYPE_OUTPUT, report_id, report, report_len);
|
||||
}
|
||||
|
||||
static uint8_t hid_host_send_set_feature_report(uint16_t hid_cid, uint8_t report_id, uint8_t * report, uint8_t report_len){
|
||||
return hid_host_send_set_report(hid_cid, HID_REPORT_TYPE_FEATURE, report_id, report, report_len);
|
||||
}
|
||||
|
||||
static uint8_t hid_host_send_set_input_report(uint16_t hid_cid, uint8_t report_id, uint8_t * report, uint8_t report_len){
|
||||
return hid_host_send_set_report(hid_cid, HID_REPORT_TYPE_INPUT, report_id, report, report_len);
|
||||
}
|
||||
|
||||
static uint8_t hid_host_send_get_protocol(uint16_t hid_cid){
|
||||
hid_host_t * hid_host = hid_host_get_instance_for_hid_cid(hid_cid);
|
||||
if (!hid_host || !hid_host->control_cid) return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
|
||||
if (hid_host->state != HID_HOST_CONNECTION_ESTABLISHED) return ERROR_CODE_COMMAND_DISALLOWED;
|
||||
|
||||
hid_host->state = HID_HOST_W2_SEND_GET_PROTOCOL;
|
||||
|
||||
l2cap_request_can_send_now_event(hid_host->control_cid);
|
||||
return ERROR_CODE_SUCCESS;
|
||||
}
|
||||
|
||||
static uint8_t hid_host_send_set_protocol_mode(uint16_t hid_cid, hid_protocol_mode_t protocol_mode){
|
||||
hid_host_t * hid_host = hid_host_get_instance_for_hid_cid(hid_cid);
|
||||
if (!hid_host || !hid_host->control_cid) return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
|
||||
if (hid_host->state != HID_HOST_CONTROL_CONNECTION_ESTABLISHED){
|
||||
return ERROR_CODE_COMMAND_DISALLOWED;
|
||||
}
|
||||
|
||||
|
||||
hid_host->state = HID_HOST_W2_SEND_SET_PROTOCOL;
|
||||
hid_host->protocol_mode = protocol_mode;
|
||||
|
||||
l2cap_request_can_send_now_event(hid_host->control_cid);
|
||||
return ERROR_CODE_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
static uint8_t hid_host_send_report(uint16_t hid_cid, hid_report_type_t report_type, uint8_t report_id, uint8_t * report, uint8_t report_len){
|
||||
hid_host_t * hid_host = hid_host_get_instance_for_hid_cid(hid_cid);
|
||||
if (!hid_host || !hid_host->control_cid){
|
||||
return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
|
||||
}
|
||||
if (hid_host->state != HID_HOST_CONNECTION_ESTABLISHED){
|
||||
return ERROR_CODE_COMMAND_DISALLOWED;
|
||||
}
|
||||
|
||||
hid_host->state = HID_HOST_W2_SEND_REPORT;
|
||||
hid_host->report_type = report_type;
|
||||
hid_host->report_id = report_id;
|
||||
hid_host->report = report;
|
||||
hid_host->report_len = report_len;
|
||||
|
||||
l2cap_request_can_send_now_event(hid_host->control_cid);
|
||||
return ERROR_CODE_SUCCESS;
|
||||
}
|
||||
|
||||
static uint8_t hid_host_send_output_report(uint16_t hid_cid, uint8_t report_id, uint8_t * report, uint8_t report_len){
|
||||
return hid_host_send_report(hid_cid, HID_REPORT_TYPE_OUTPUT, report_id, report, report_len);
|
||||
}
|
||||
|
||||
|
||||
static hid_host_t * hid_host_get_instance_for_l2cap_cid(uint16_t cid){
|
||||
if ((_hid_host.control_cid == cid) || (_hid_host.interrupt_cid == cid)){
|
||||
return &_hid_host;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void _hid_host_send_control_message(uint16_t hid_cid, const uint8_t * message, uint16_t message_len){
|
||||
hid_host_t * hid_host = hid_host_get_instance_for_hid_cid(hid_cid);
|
||||
if (!hid_host || !hid_host->control_cid) return;
|
||||
l2cap_send(hid_host->control_cid, (uint8_t*) message, message_len);
|
||||
}
|
||||
|
||||
static uint8_t hid_host_send_suspend(uint16_t hcid){
|
||||
uint8_t report[] = { (HID_MESSAGE_TYPE_HID_CONTROL << 4) | HID_CONTROL_PARAM_SUSPEND };
|
||||
_hid_host_send_control_message(hcid, &report[0], sizeof(report));
|
||||
return ERROR_CODE_SUCCESS;
|
||||
}
|
||||
|
||||
static uint8_t hid_host_send_exit_suspend(uint16_t hcid){
|
||||
uint8_t report[] = { (HID_MESSAGE_TYPE_HID_CONTROL << 4) | HID_CONTROL_PARAM_EXIT_SUSPEND };
|
||||
_hid_host_send_control_message(hcid, &report[0], sizeof(report));
|
||||
return ERROR_CODE_SUCCESS;
|
||||
}
|
||||
|
||||
static uint8_t hid_host_send_virtual_cable_unplug(uint16_t hcid){
|
||||
uint8_t report[] = { (HID_MESSAGE_TYPE_HID_CONTROL << 4) | HID_CONTROL_PARAM_VIRTUAL_CABLE_UNPLUG };
|
||||
_hid_host_send_control_message(hcid, &report[0], sizeof(report));
|
||||
return ERROR_CODE_SUCCESS;
|
||||
}
|
||||
|
||||
static void hid_host_disconnect_interrupt_channel(uint16_t hid_cid){
|
||||
hid_host_t * hid_host = hid_host_get_instance_for_hid_cid(hid_cid);
|
||||
if (!hid_host){
|
||||
log_error("hid_host_disconnect_interrupt_channel: could not find hid device instace");
|
||||
return;
|
||||
}
|
||||
log_info("Disconnect from interrupt channel HID Host");
|
||||
if (hid_host->interrupt_cid){
|
||||
l2cap_disconnect(hid_host->interrupt_cid, 0); // reason isn't used
|
||||
}
|
||||
}
|
||||
|
||||
static void hid_host_disconnect_control_channel(uint16_t hid_cid){
|
||||
hid_host_t * hid_host = hid_host_get_instance_for_hid_cid(hid_cid);
|
||||
if (!hid_host){
|
||||
log_error("hid_host_disconnect_control_channel: could not find hid device instace");
|
||||
return;
|
||||
}
|
||||
log_info("Disconnect from control channel HID Host");
|
||||
if (hid_host->control_cid){
|
||||
l2cap_disconnect(hid_host->control_cid, 0); // reason isn't used
|
||||
}
|
||||
}
|
||||
|
||||
static void _hid_host_disconnect(uint16_t hid_cid){
|
||||
hid_host_t * hid_host = hid_host_get_instance_for_hid_cid(hid_cid);
|
||||
if (!hid_host){
|
||||
log_error("hid_host_disconnect: could not find hid device instace");
|
||||
return;
|
||||
}
|
||||
log_info("Disconnect from HID Host");
|
||||
if (hid_host->interrupt_cid){
|
||||
l2cap_disconnect(hid_host->interrupt_cid, 0); // reason isn't used
|
||||
}
|
||||
if (hid_host->control_cid){
|
||||
l2cap_disconnect(hid_host->control_cid, 0); // reason isn't used
|
||||
}
|
||||
}
|
||||
/* @section Main application configuration
|
||||
*
|
||||
* @text In the application configuration, L2CAP is initialized
|
||||
*/
|
||||
|
||||
/* LISTING_START(PanuSetup): Panu setup */
|
||||
static void packet_handler (uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size);
|
||||
|
||||
static void hid_host_setup(void){
|
||||
@ -360,6 +79,7 @@ static void hid_host_setup(void){
|
||||
|
||||
// Initialize HID Host
|
||||
hid_host_init(hid_descriptor, hid_descriptor_len);
|
||||
hid_host_register_packet_handler(packet_handler);
|
||||
|
||||
// Allow sniff mode requests by HID device and support role switch
|
||||
gap_set_default_link_policy_settings(LM_LINK_POLICY_ENABLE_SNIFF_MODE | LM_LINK_POLICY_ENABLE_ROLE_SWITCH);
|
||||
@ -376,110 +96,25 @@ static void hid_host_setup(void){
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* @section HID Report Handler
|
||||
*
|
||||
* @text Use BTstack's compact HID Parser to process incoming HID Report
|
||||
* Iterate over all fields and process fields with usage page = 0x07 / Keyboard
|
||||
* Check if SHIFT is down and process first character (don't handle multiple key presses)
|
||||
*
|
||||
*/
|
||||
#define NUM_KEYS 6
|
||||
static uint8_t last_keys[NUM_KEYS];
|
||||
static void hid_host_handle_interrupt_report(const uint8_t * report, uint16_t report_len){
|
||||
// check if HID Input Report
|
||||
if (report_len < 1) return;
|
||||
if (*report != 0xa1) return;
|
||||
report++;
|
||||
report_len--;
|
||||
btstack_hid_parser_t parser;
|
||||
btstack_hid_parser_init(&parser, hid_descriptor, hid_descriptor_len, HID_REPORT_TYPE_INPUT, report, report_len);
|
||||
int shift = 0;
|
||||
uint8_t new_keys[NUM_KEYS];
|
||||
memset(new_keys, 0, sizeof(new_keys));
|
||||
int new_keys_count = 0;
|
||||
while (btstack_hid_parser_has_more(&parser)){
|
||||
uint16_t usage_page;
|
||||
uint16_t usage;
|
||||
int32_t value;
|
||||
btstack_hid_parser_get_field(&parser, &usage_page, &usage, &value);
|
||||
if (usage_page != 0x07) continue;
|
||||
switch (usage){
|
||||
case 0xe1:
|
||||
case 0xe6:
|
||||
if (value){
|
||||
shift = 1;
|
||||
}
|
||||
continue;
|
||||
case 0x00:
|
||||
continue;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (usage >= sizeof(keytable_us_none)) continue;
|
||||
static void packet_handler (uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
|
||||
UNUSED(channel);
|
||||
UNUSED(size);
|
||||
|
||||
// store new keys
|
||||
new_keys[new_keys_count++] = usage;
|
||||
|
||||
// check if usage was used last time (and ignore in that case)
|
||||
int i;
|
||||
for (i=0;i<NUM_KEYS;i++){
|
||||
if (usage == last_keys[i]){
|
||||
usage = 0;
|
||||
}
|
||||
}
|
||||
if (usage == 0) continue;
|
||||
|
||||
uint8_t key;
|
||||
if (shift){
|
||||
key = keytable_us_shift[usage];
|
||||
} else {
|
||||
key = keytable_us_none[usage];
|
||||
}
|
||||
if (key == CHAR_ILLEGAL) continue;
|
||||
if (key == CHAR_BACKSPACE){
|
||||
printf("\b \b"); // go back one char, print space, go back one char again
|
||||
continue;
|
||||
}
|
||||
printf("%c", key);
|
||||
}
|
||||
memcpy(last_keys, new_keys, NUM_KEYS);
|
||||
}
|
||||
|
||||
/*
|
||||
* @section Packet Handler
|
||||
*
|
||||
* @text The packet handler responds to various HCI Events.
|
||||
*/
|
||||
|
||||
/* LISTING_START(packetHandler): Packet Handler */
|
||||
static void packet_handler (uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size)
|
||||
{
|
||||
/* LISTING_PAUSE */
|
||||
uint8_t event;
|
||||
bd_addr_t address;
|
||||
uint8_t status;
|
||||
uint16_t l2cap_cid;
|
||||
hid_host_t * hid_host;
|
||||
uint8_t param;
|
||||
hid_message_type_t message_type;
|
||||
hid_handshake_param_type_t message_status;
|
||||
|
||||
/* LISTING_RESUME */
|
||||
switch (packet_type) {
|
||||
case HCI_EVENT_PACKET:
|
||||
event = hci_event_packet_get_type(packet);
|
||||
switch (event) {
|
||||
/* @text When BTSTACK_EVENT_STATE with state HCI_STATE_WORKING
|
||||
* is received and the example is started in client mode, the remote SDP HID query is started.
|
||||
*/
|
||||
|
||||
case BTSTACK_EVENT_STATE:
|
||||
if (btstack_event_state_get_state(packet) == HCI_STATE_WORKING){
|
||||
printf("BTstack up and running. \n");
|
||||
}
|
||||
break;
|
||||
|
||||
/* LISTING_PAUSE */
|
||||
case HCI_EVENT_PIN_CODE_REQUEST:
|
||||
// inform about pin code request
|
||||
printf("Pin code request - using '0000'\n");
|
||||
@ -495,6 +130,7 @@ static void packet_handler (uint8_t packet_type, uint16_t channel, uint8_t *pack
|
||||
|
||||
case HCI_EVENT_HID_META:
|
||||
switch (hci_event_hid_meta_get_subevent_code(packet)){
|
||||
|
||||
case HID_SUBEVENT_CONNECTION_OPENED:
|
||||
status = hid_subevent_connection_opened_get_status(packet);
|
||||
if (status) {
|
||||
@ -506,181 +142,26 @@ static void packet_handler (uint8_t packet_type, uint16_t channel, uint8_t *pack
|
||||
}
|
||||
app_state = APP_CONNECTED;
|
||||
hid_host_cid = hid_subevent_connection_opened_get_hid_cid(packet);
|
||||
printf("HID Host Connected..\n");
|
||||
printf("HID Host connected..\n");
|
||||
break;
|
||||
|
||||
case HID_SUBEVENT_CONNECTION_CLOSED:
|
||||
printf("HID Host disconnected..\n");
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case L2CAP_EVENT_CHANNEL_CLOSED:
|
||||
l2cap_cid = l2cap_event_channel_closed_get_local_cid(packet);
|
||||
hid_host = hid_host_get_instance_for_l2cap_cid(l2cap_cid);
|
||||
if (!hid_host) return;
|
||||
|
||||
if (l2cap_cid == hid_host->interrupt_cid){
|
||||
hid_host->interrupt_cid = 0;
|
||||
}
|
||||
if (l2cap_cid == hid_host->control_cid){
|
||||
hid_host->control_cid = 0;
|
||||
}
|
||||
if (!hid_host->interrupt_cid && !hid_host->control_cid){
|
||||
// hid_host->connected = 0;
|
||||
hid_host->con_handle = HCI_CON_HANDLE_INVALID;
|
||||
hid_host->cid = 0;
|
||||
// hid_host_emit_event(device, HID_SUBEVENT_CONNECTION_CLOSED);
|
||||
}
|
||||
break;
|
||||
|
||||
case L2CAP_EVENT_CAN_SEND_NOW:
|
||||
l2cap_cid = l2cap_event_can_send_now_get_local_cid(packet);
|
||||
hid_host = hid_host_get_instance_for_l2cap_cid(l2cap_cid);
|
||||
if (!hid_host) return;
|
||||
|
||||
printf("L2CAP_EVENT_CAN_SEND_NOW, hid_host.state = %d\n", hid_host->state);
|
||||
switch(hid_host->state){
|
||||
case HID_HOST_W2_SEND_GET_REPORT:{
|
||||
uint8_t header = (HID_MESSAGE_TYPE_GET_REPORT << 4) | hid_host->report_type;
|
||||
uint8_t report[] = {header, hid_host->report_id};
|
||||
// TODO: optional Report ID (1)
|
||||
// TODO: optional Maximum number of bytes to transfer during data phase, little end. (2)
|
||||
|
||||
hid_host->state = HID_HOST_W4_GET_REPORT_RESPONSE;
|
||||
l2cap_send(hid_host->control_cid, (uint8_t*) report, sizeof(report));
|
||||
break;
|
||||
}
|
||||
case HID_HOST_W2_SEND_SET_REPORT:{
|
||||
uint8_t header = (HID_MESSAGE_TYPE_SET_REPORT << 4) | hid_host->report_type;
|
||||
hid_host->state = HID_HOST_W4_SET_REPORT_RESPONSE;
|
||||
|
||||
l2cap_reserve_packet_buffer();
|
||||
uint8_t * out_buffer = l2cap_get_outgoing_buffer();
|
||||
out_buffer[0] = header;
|
||||
out_buffer[1] = hid_host->report_id;
|
||||
(void)memcpy(out_buffer + 2, hid_host->report, hid_host->report_len);
|
||||
if (boot_mode){
|
||||
l2cap_send_prepared(hid_host->interrupt_cid, hid_host->report_len + 2);
|
||||
} else {
|
||||
l2cap_send_prepared(hid_host->control_cid, hid_host->report_len + 2);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case HID_HOST_W2_SEND_GET_PROTOCOL:{
|
||||
uint8_t header = (HID_MESSAGE_TYPE_GET_PROTOCOL << 4);
|
||||
uint8_t report[] = {header};
|
||||
hid_host->state = HID_HOST_W4_GET_PROTOCOL_RESPONSE;
|
||||
l2cap_send(hid_host->control_cid, (uint8_t*) report, sizeof(report));
|
||||
break;
|
||||
}
|
||||
case HID_HOST_W2_SEND_SET_PROTOCOL:{
|
||||
uint8_t header = (HID_MESSAGE_TYPE_SET_PROTOCOL << 4) | hid_host->protocol_mode;
|
||||
uint8_t report[] = {header};
|
||||
|
||||
hid_host->state = HID_HOST_W4_SET_PROTOCOL_RESPONSE;
|
||||
l2cap_send(hid_host->control_cid, (uint8_t*) report, sizeof(report));
|
||||
break;
|
||||
}
|
||||
case HID_HOST_W2_SEND_REPORT:{
|
||||
hid_host->state = HID_HOST_W4_SEND_REPORT_RESPONSE;
|
||||
uint8_t header = (HID_MESSAGE_TYPE_DATA << 4) | hid_host->report_type;
|
||||
|
||||
l2cap_reserve_packet_buffer();
|
||||
uint8_t * out_buffer = l2cap_get_outgoing_buffer();
|
||||
out_buffer[0] = header;
|
||||
out_buffer[1] = hid_host->report_id;
|
||||
(void)memcpy(out_buffer + 2, hid_host->report, hid_host->report_len);
|
||||
l2cap_send_prepared(hid_host->interrupt_cid, hid_host->report_len + 2);
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case L2CAP_DATA_PACKET:
|
||||
if (channel == _hid_host.interrupt_cid){
|
||||
printf("HID Interrupt data: \n");
|
||||
printf_hexdump(packet, size);
|
||||
hid_host_handle_interrupt_report(packet, size);
|
||||
break;
|
||||
}
|
||||
if (channel != _hid_host.control_cid) break;
|
||||
hid_host = hid_host_get_instance_for_l2cap_cid(channel);
|
||||
if (!hid_host) {
|
||||
log_error("no host with cid 0x%02x", channel);
|
||||
return;
|
||||
}
|
||||
message_type = (hid_message_type_t)(packet[0] >> 4);
|
||||
message_status = (hid_handshake_param_type_t)(packet[0] & 0x0F);
|
||||
printf("HID Control data, message_type 0x%02x, status 0x%02x: \n", message_type, message_status);
|
||||
printf_hexdump(packet, size);
|
||||
|
||||
// TODO handle handshake message_status
|
||||
switch (message_type){
|
||||
case HID_MESSAGE_TYPE_DATA:
|
||||
switch (hid_host->state){
|
||||
case HID_HOST_W4_GET_REPORT_RESPONSE:
|
||||
printf("HID_HOST_W4_GET_REPORT_RESPONSE \n");
|
||||
break;
|
||||
case HID_HOST_W4_SET_REPORT_RESPONSE:
|
||||
printf("HID_HOST_W4_SET_REPORT_RESPONSE \n");
|
||||
break;
|
||||
case HID_HOST_W4_GET_PROTOCOL_RESPONSE:
|
||||
printf("HID_HOST_W4_GET_PROTOCOL_RESPONSE \n");
|
||||
break;
|
||||
case HID_HOST_W4_SEND_REPORT_RESPONSE:
|
||||
printf("HID_HOST_W4_SEND_REPORT_RESPONSE\n");
|
||||
break;
|
||||
case HID_HOST_W4_SET_PROTOCOL_RESPONSE:
|
||||
printf("HID_HOST_W4_SET_PROTOCOL_RESPONSE \n");
|
||||
switch (message_status){
|
||||
case HID_HANDSHAKE_PARAM_TYPE_SUCCESSFUL:
|
||||
switch(hid_host->protocol_mode){
|
||||
case HID_PROTOCOL_MODE_BOOT:{
|
||||
status = l2cap_create_channel(packet_handler, remote_addr, hid_interrupt_psm, 48, &hid_host->interrupt_cid);
|
||||
if (status){
|
||||
printf("Connecting to HID Control failed: 0x%02x\n", status);
|
||||
hid_host->state = HID_HOST_CONTROL_CONNECTION_ESTABLISHED;
|
||||
break;
|
||||
}
|
||||
hid_host->state = HID_HOST_W4_INTERRUPT_CONNECTION_ESTABLISHED;
|
||||
break;
|
||||
}
|
||||
case HID_PROTOCOL_MODE_REPORT:
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
printf("HID_MESSAGE_TYPE_DATA ???\n");
|
||||
break;
|
||||
}
|
||||
hid_host->state = HID_HOST_CONNECTION_ESTABLISHED;
|
||||
break;
|
||||
|
||||
case HID_MESSAGE_TYPE_HID_CONTROL:
|
||||
param = packet[0] & 0x0F;
|
||||
|
||||
switch ((hid_control_param_t)param){
|
||||
case HID_CONTROL_PARAM_VIRTUAL_CABLE_UNPLUG:
|
||||
// hid_host_emit_event(device, HID_SUBEVENT_VIRTUAL_CABLE_UNPLUG);
|
||||
hid_host->unplugged = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
/* LISTING_END */
|
||||
|
||||
@ -702,12 +183,12 @@ static void stdin_process(char cmd){
|
||||
case 'R':
|
||||
printf("Set Protocol mode\n");
|
||||
boot_mode = false;
|
||||
status = hid_host_send_set_protocol_mode(_hid_host.cid, HID_PROTOCOL_MODE_REPORT);
|
||||
status = hid_host_send_set_protocol_mode(hid_host_cid, HID_PROTOCOL_MODE_REPORT);
|
||||
break;
|
||||
case 'b':
|
||||
printf("Set Boot mode\n");
|
||||
boot_mode = false;
|
||||
status = hid_host_send_set_protocol_mode(_hid_host.cid, HID_PROTOCOL_MODE_BOOT);
|
||||
status = hid_host_send_set_protocol_mode(hid_host_cid, HID_PROTOCOL_MODE_BOOT);
|
||||
break;
|
||||
case 'B':
|
||||
printf("Set Boot mode\n");
|
||||
@ -715,7 +196,7 @@ static void stdin_process(char cmd){
|
||||
break;
|
||||
|
||||
case 'c':
|
||||
if (_hid_host.unplugged){
|
||||
if (unplugged){
|
||||
printf("Cannot connect, host is unplugged.\n");
|
||||
break;
|
||||
}
|
||||
@ -728,81 +209,66 @@ static void stdin_process(char cmd){
|
||||
}
|
||||
break;
|
||||
|
||||
case 'i':
|
||||
if (_hid_host.unplugged){
|
||||
printf("Cannot reconnect, host is unplugged.\n");
|
||||
break;
|
||||
}
|
||||
printf("Reconnect, interrupt PSM.\n");
|
||||
status = l2cap_create_channel(packet_handler, remote_addr, BLUETOOTH_PSM_HID_INTERRUPT, 48, &_hid_host.interrupt_cid);
|
||||
if (status){
|
||||
printf("Connecting to HID Control failed: 0x%02x\n", status);
|
||||
}
|
||||
break;
|
||||
case 'I':
|
||||
printf("Disconnect from interrupt channel %s...\n", bd_addr_to_str(remote_addr));
|
||||
hid_host_disconnect_interrupt_channel(_hid_host.cid);
|
||||
break;
|
||||
case 'C':
|
||||
printf("Disconnect from control channel %s...\n", bd_addr_to_str(remote_addr));
|
||||
hid_host_disconnect_control_channel(_hid_host.cid);
|
||||
printf("Disconnect from %s...\n", bd_addr_to_str(remote_addr));
|
||||
hid_host_disconnect(hid_host_cid);
|
||||
break;
|
||||
|
||||
case 's':
|
||||
printf("Send \'Suspend\'\n");
|
||||
hid_host_send_suspend(_hid_host.cid);
|
||||
hid_host_send_suspend(hid_host_cid);
|
||||
break;
|
||||
case 'S':
|
||||
printf("Send \'Exit suspend\'\n");
|
||||
hid_host_send_exit_suspend(_hid_host.cid);
|
||||
hid_host_send_exit_suspend(hid_host_cid);
|
||||
break;
|
||||
case 'u':
|
||||
printf("Send \'Unplug\'\n");
|
||||
_hid_host.unplugged = true;
|
||||
hid_host_send_virtual_cable_unplug(_hid_host.cid);
|
||||
unplugged = true;
|
||||
hid_host_send_virtual_cable_unplug(hid_host_cid);
|
||||
break;
|
||||
|
||||
case '1':
|
||||
printf("Get feature report with id 0x03 from %s\n", remote_addr_string);
|
||||
status = hid_host_send_get_feature_report(_hid_host.cid, 0x03);
|
||||
status = hid_host_send_get_feature_report(hid_host_cid, 0x03);
|
||||
break;
|
||||
case '2':
|
||||
printf("Get output report with id 0x05 from %s\n", remote_addr_string);
|
||||
status = hid_host_send_get_output_report(_hid_host.cid, 0x05);
|
||||
status = hid_host_send_get_output_report(hid_host_cid, 0x05);
|
||||
break;
|
||||
case '3':
|
||||
printf("Get input report from with id 0x02 %s\n", remote_addr_string);
|
||||
status = hid_host_send_get_input_report(_hid_host.cid, 0x02);
|
||||
status = hid_host_send_get_input_report(hid_host_cid, 0x02);
|
||||
break;
|
||||
|
||||
case '4':{
|
||||
uint8_t report[] = {0, 0};
|
||||
printf("Set output report with id 0x03\n");
|
||||
status = hid_host_send_set_output_report(_hid_host.cid, 0x03, report, sizeof(report));
|
||||
status = hid_host_send_set_output_report(hid_host_cid, 0x03, report, sizeof(report));
|
||||
break;
|
||||
}
|
||||
case '5':{
|
||||
uint8_t report[] = {0, 0, 0};
|
||||
printf("Set feature report with id 0x05\n");
|
||||
status = hid_host_send_set_feature_report(_hid_host.cid, 0x05, report, sizeof(report));
|
||||
status = hid_host_send_set_feature_report(hid_host_cid, 0x05, report, sizeof(report));
|
||||
break;
|
||||
}
|
||||
|
||||
case '6':{
|
||||
uint8_t report[] = {0, 0, 0, 0};
|
||||
printf("Set input report with id 0x02\n");
|
||||
status = hid_host_send_set_input_report(_hid_host.cid, 0x02, report, sizeof(report));
|
||||
status = hid_host_send_set_input_report(hid_host_cid, 0x02, report, sizeof(report));
|
||||
break;
|
||||
}
|
||||
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_output_report(_hid_host.cid, 0x01, report, sizeof(report));
|
||||
status = hid_host_send_set_output_report(hid_host_cid, 0x01, report, sizeof(report));
|
||||
break;
|
||||
}
|
||||
case 'p':
|
||||
printf("Get Protocol\n");
|
||||
status = hid_host_send_get_protocol(_hid_host.cid);
|
||||
status = hid_host_send_get_protocol(hid_host_cid);
|
||||
break;
|
||||
|
||||
case 'X':
|
||||
@ -817,19 +283,19 @@ static void stdin_process(char cmd){
|
||||
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));
|
||||
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));
|
||||
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));
|
||||
status = hid_host_send_output_report(hid_host_cid, 0x01, report, sizeof(report));
|
||||
break;
|
||||
}
|
||||
|
||||
@ -861,4 +327,3 @@ int btstack_main(int argc, const char * argv[]){
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* EXAMPLE_END */
|
||||
|
Loading…
x
Reference in New Issue
Block a user