hid_device: fix create device on incoming connection, add suspend

This commit is contained in:
Milanka Ringwald 2018-09-25 10:17:10 +02:00
parent 1ea99aaf8a
commit 6510739ba0
5 changed files with 151 additions and 26 deletions

View File

@ -2093,6 +2093,21 @@ typedef uint8_t sm_key_t[16];
*/
#define HID_SUBEVENT_CAN_SEND_NOW 0x03
/**
* @format 12
* @param subevent_code
* @param con_handle
*/
#define HID_SUBEVENT_SUSPEND 0x04
/**
* @format 12
* @param subevent_code
* @param con_handle
*/
#define HID_SUBEVENT_EXIT_SUSPEND 0x05
// HIDS Meta Event Group
/**

View File

@ -6628,6 +6628,26 @@ static inline uint16_t hid_subevent_can_send_now_get_hid_cid(const uint8_t * eve
return little_endian_read_16(event, 3);
}
/**
* @brief Get field con_handle from event HID_SUBEVENT_SUSPEND
* @param event packet
* @return con_handle
* @note: btstack_type 2
*/
static inline uint16_t hid_subevent_suspend_get_con_handle(const uint8_t * event){
return little_endian_read_16(event, 3);
}
/**
* @brief Get field con_handle from event HID_SUBEVENT_EXIT_SUSPEND
* @param event packet
* @return con_handle
* @note: btstack_type 2
*/
static inline uint16_t hid_subevent_exit_suspend_get_con_handle(const uint8_t * event){
return little_endian_read_16(event, 3);
}
/**
* @brief Get field con_handle from event HIDS_SUBEVENT_CAN_SEND_NOW
* @param event packet

View File

@ -103,8 +103,11 @@ static hid_device_t * hid_device_get_instance_for_cid(uint16_t cid){
return NULL;
}
static hid_device_t * hid_device_create_instance_for_con_handle(uint16_t con_handle){
UNUSED(con_handle);
static hid_device_t * hid_device_create_instance_for_bt_addr(bd_addr_t bd_addr){
memcpy(_hid_device.bd_addr, bd_addr, 6);
if (!_hid_device.cid){
_hid_device.cid = hid_device_get_next_cid();
}
return &_hid_device;
}
@ -251,6 +254,10 @@ void hid_create_sdp_record(
}
de_pop_sequence(service, attribute);
uint8_t hid_remote_wake = 1;
de_add_number(service, DE_UINT, DE_SIZE_16, BLUETOOTH_ATTRIBUTE_HID_REMOTE_WAKE);
de_add_number(service, DE_BOOL, DE_SIZE_8, hid_remote_wake);
de_add_number(service, DE_UINT, DE_SIZE_16, BLUETOOTH_ATTRIBUTE_HID_BOOT_DEVICE);
de_add_number(service, DE_BOOL, DE_SIZE_8, hid_boot_device);
}
@ -264,7 +271,7 @@ static inline void hid_device_emit_connected_event(hid_device_t * context, uint8
little_endian_store_16(event,pos,context->cid);
pos+=2;
event[pos++] = status;
memcpy(&event[pos], context->bd_addr, 6);
reverse_bd_addr(context->bd_addr, &event[pos]);
pos += 6;
little_endian_store_16(event,pos,context->con_handle);
pos += 2;
@ -300,6 +307,19 @@ static inline void hid_device_emit_can_send_now_event(hid_device_t * context){
hid_callback(HCI_EVENT_PACKET, context->cid, &event[0], pos);
}
static inline void hid_device_emit_event(hid_device_t * context, uint8_t subevent_type){
uint8_t event[4];
int pos = 0;
event[pos++] = HCI_EVENT_HID_META;
pos++; // skip len
event[pos++] = subevent_type;
little_endian_store_16(event,pos,context->cid);
pos+=2;
event[1] = pos - 2;
if (pos != sizeof(event)) log_error("hid_device_emit_event size %u", pos);
hid_callback(HCI_EVENT_PACKET, context->cid, &event[0], pos);
}
static void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t * packet, uint16_t packet_size){
UNUSED(channel);
UNUSED(packet_size);
@ -309,6 +329,8 @@ static void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t * pack
hid_device_t * device = NULL;
uint8_t report[20];
int report_size;
uint8_t param;
bd_addr_t address;
switch (packet_type){
case L2CAP_DATA_PACKET:
@ -326,9 +348,24 @@ static void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t * pack
device->report_id = packet[1];
}
device->state = HID_DEVICE_W2_SEND_REPORT;
printf(" answer get report type %d report_type\n", device->report_type);
// printf(" answer get report type %d report_type\n", device->report_type);
l2cap_request_can_send_now_event(device->control_cid);
break;
case HID_MESSAGE_TYPE_HID_CONTROL:
param = packet[0] & 0x0F;
switch (param){
case HID_CONTROL_PARAM_SUSPEND:
hid_device_emit_event(device, HID_SUBEVENT_SUSPEND);
break;
case HID_CONTROL_PARAM_EXIT_SUSPEND:
hid_device_emit_event(device, HID_SUBEVENT_EXIT_SUSPEND);
break;
default:
device->state = HID_DEVICE_W2_SEND_UNSUPPORTED_REQUEST;
l2cap_request_can_send_now_event(device->control_cid);
break;
}
break;
default:
printf("L2CAP_DATA_PACKET %d \n", message_type);
device->state = HID_DEVICE_W2_SEND_UNSUPPORTED_REQUEST;
@ -342,7 +379,8 @@ static void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t * pack
switch (l2cap_event_incoming_connection_get_psm(packet)){
case PSM_HID_CONTROL:
case PSM_HID_INTERRUPT:
device = hid_device_create_instance_for_con_handle(l2cap_event_incoming_connection_get_handle(packet));
l2cap_event_incoming_connection_get_address(packet, address);
device = hid_device_create_instance_for_bt_addr(address);
if (!device) {
log_error("L2CAP_EVENT_INCOMING_CONNECTION, no hid device for con handle 0x%02x", l2cap_event_incoming_connection_get_handle(packet));
l2cap_decline_connection(channel);
@ -351,6 +389,7 @@ static void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t * pack
if (device->con_handle == 0 || l2cap_event_incoming_connection_get_handle(packet) == device->con_handle){
device->con_handle = l2cap_event_incoming_connection_get_handle(packet);
device->incoming = 1;
l2cap_event_incoming_connection_get_address(packet, device->bd_addr);
l2cap_accept_connection(channel);
} else {
l2cap_decline_connection(channel);
@ -390,6 +429,7 @@ static void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t * pack
default:
break;
}
// connect HID Interrupt for outgoing
if (device->incoming == 0 && psm == PSM_HID_CONTROL){
log_info("Create outgoing HID Interrupt");
@ -406,9 +446,8 @@ static void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t * pack
device = hid_device_get_instance_for_cid(l2cap_event_channel_closed_get_local_cid(packet));
if (!device) return;
// connected_before = device->connected;
device->incoming = 0;
device->connected = 0;
connected_before = device->connected;
if (l2cap_event_channel_closed_get_local_cid(packet) == device->control_cid){
log_info("HID Control closed");
device->control_cid = 0;
@ -417,8 +456,10 @@ static void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t * pack
log_info("HID Interrupt closed");
device->interrupt_cid = 0;
}
if (connected_before && !device->connected){
if (!device->interrupt_cid && !device->control_cid){
device->connected = 0;
device->con_handle = 0;
device->cid = 0;
log_info("HID Disconnected");
hid_device_emit_connection_closed_event(device);
}
@ -434,7 +475,7 @@ static void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t * pack
break;
case HID_DEVICE_W2_SEND_UNSUPPORTED_REQUEST:
report[0] = (HID_MESSAGE_TYPE_HANDSHAKE << 4) | HID_HANDSHAKE_PARAM_TYPE_ERR_INVALID_PARAMETER;
hid_device_send_control_message(device->cid, &report[0], report_size);
hid_device_send_control_message(device->cid, &report[0], 1);
break;
default:
log_info("HID Can send now, emit event");
@ -522,19 +563,38 @@ uint8_t hid_device_connect(bd_addr_t addr, uint16_t * hid_cid){
}
// assign hic_cid
*hid_cid = hid_device_get_next_cid();
// store address
memcpy(hid_device->bd_addr, addr, 6);
// reset state
hid_device->cid = *hid_cid;
hid_device->incoming = 0;
hid_device->connected = 0;
hid_device->control_cid = 0;
hid_device->interrupt_cid = 0;
// create l2cap control using fixed HID L2CAP PSM
log_info("Create outgoing HID Control");
uint8_t status = l2cap_create_channel(packet_handler, hid_device->bd_addr, PSM_HID_CONTROL, 48, &hid_device->control_cid);
return status;
}
/*
* @brief Disconnect from HID Host
* @param hid_cid
* @result status
*/
void hid_device_disconnect(uint16_t hid_cid){
hid_device_t * hid_device = hid_device_get_instance_for_cid(hid_cid);
if (!hid_device){
log_error("hid_device_disconnect: could not find hid device instace");
return;
}
log_info("Disconnect from HID Host");
if (hid_device->control_cid){
l2cap_disconnect(hid_device->control_cid, 0); // reason isn't used
}
if (hid_device->interrupt_cid){
l2cap_disconnect(hid_device->interrupt_cid, 0); // reason isn't used
}
}

View File

@ -73,12 +73,12 @@ typedef enum {
} hid_handshake_param_type_t;
typedef enum {
HID_CONTROL_NOP_DEPRECATED = 0, // Deprecated: No Operation.
HID_CONTROL_HARD_RESET_DEPRECATED, // Deprecated: Device performs Power On System Test (POST) then initializes all internal variables and initiates normal operations.
HID_CONTROL_SOFT_RESET_DEPRECATED, // Deprecated: Device initializes all internal variables and initiates normal operations.
HID_CONTROL_SUSPEND = 0x03, // Go to reduced power mode.
HID_CONTROL_EXIT_SUSPEND, // Exit reduced power mode.
HID_CONTROL_VIRTUAL_CABLE_UNPLUG
HID_CONTROL_PARAM_NOP_DEPRECATED = 0, // Deprecated: No Operation.
HID_CONTROL_PARAM_HARD_RESET_DEPRECATED, // Deprecated: Device performs Power On System Test (POST) then initializes all internal variables and initiates normal operations.
HID_CONTROL_PARAM_SOFT_RESET_DEPRECATED, // Deprecated: Device initializes all internal variables and initiates normal operations.
HID_CONTROL_PARAM_SUSPEND = 0x03, // Go to reduced power mode.
HID_CONTROL_PARAM_EXIT_SUSPEND, // Exit reduced power mode.
HID_CONTROL_PARAM_VIRTUAL_CABLE_UNPLUG
} hid_control_param_t;
typedef enum {
@ -142,6 +142,12 @@ void hid_device_register_report_request_callback(void (*callback) (uint16_t hid_
*/
uint8_t hid_device_connect(bd_addr_t addr, uint16_t * hid_cid);
/*
* @brief Disconnect from HID Host
* @param hid_cid
*/
void hid_device_disconnect(uint16_t hid_cid);
/**
* @brief Request can send now event to send HID Report
* Generates an HID_SUBEVENT_CAN_SEND_NOW subevent

View File

@ -237,8 +237,8 @@ static void hid_report_callback(uint16_t cid, hid_report_type_t report_type, uin
UNUSED(report_id);
UNUSED(report_max_size);
printf("hid_report_callback \n");
int modifier = 0x90; int keycode = 0;
uint8_t leds = 0x64;
// int modifier = 0x90; int keycode = 0;
// uint8_t leds = 0x64;
uint8_t header = (HID_MESSAGE_TYPE_DATA << 4) | report_type;
// uint8_t report[] = { header, 0x01, modifier, 0, keycode, 0, 0, 0, 0, 0};
@ -265,37 +265,47 @@ static void hid_report_callback(uint16_t cid, hid_report_type_t report_type, uin
#ifdef HAVE_BTSTACK_STDIN
// On systems with STDIN, we can directly type on the console
#if 0
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 - connect \n");
printf("l - set limited discoverable mode\n");
printf("L - restset limited discoverable mode\n");
printf("Ctrl-c - exit\n");
printf("---\n");
}
#endif
static void stdin_process(char character){
uint8_t modifier;
uint8_t keycode;
int found;
switch (character){
case 'C':
printf("Disconnect from %s...\n", bd_addr_to_str(device_addr));
hid_device_disconnect(hid_cid);
break;
case 'c':
printf("Connecting to %s...\n", bd_addr_to_str(device_addr));
hid_device_connect(device_addr, &hid_cid);
return;
case 'l':
printf("set limited discoverable mode\n");
gap_discoverable_control(1);
gap_set_class_of_device(0x2540);
// TODO move into HCI init
hci_send_cmd(&hci_write_current_iac_lap_two_iacs, 2, GAP_IAC_GENERAL_INQUIRY, GAP_IAC_LIMITED_INQUIRY);
return;
case 'L':
gap_discoverable_control(0);
gap_set_class_of_device(0x0540);
printf("reset limited discoverable mode\n");
return;
case '\n':
case '\r':
break;
default:
show_usage();
// show_usage();
break;
}
@ -393,9 +403,10 @@ static void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t * pack
return;
}
app_state = APP_CONNECTED;
hid_subevent_connection_opened_get_bd_addr(packet, device_addr);
hid_cid = hid_subevent_connection_opened_get_hid_cid(packet);
#ifdef HAVE_BTSTACK_STDIN
printf("HID Connected, please start typing...\n");
printf("HID Connected, please start typing... %s\n", bd_addr_to_str(device_addr));
#else
printf("HID Connected, sending demo text...\n");
hid_embedded_start_typing();
@ -406,7 +417,14 @@ static void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t * pack
app_state = APP_NOT_CONNECTED;
hid_cid = 0;
break;
case HID_SUBEVENT_SUSPEND:
printf("HID Suspend\n");
break;
case HID_SUBEVENT_EXIT_SUSPEND:
printf("HID Exit Suspend\n");
break;
case HID_SUBEVENT_CAN_SEND_NOW:
if (send_keycode){
send_report(send_modifier, send_keycode);
@ -456,8 +474,14 @@ int btstack_main(int argc, const char * argv[]){
// SDP Server
sdp_init();
memset(hid_service_buffer, 0, sizeof(hid_service_buffer));
uint8_t hid_reconnect_initiate = 1;
uint8_t hid_virtual_cable = 1;
// hid sevice subclass 2540 Keyboard, hid counntry code 33 US, hid virtual cable off, hid reconnect initiate off, hid boot device off
hid_create_sdp_record(hid_service_buffer, 0x10001, 0x2540, 33, 0, 0, 0, hid_descriptor_keyboard_boot_mode, sizeof(hid_descriptor_keyboard_boot_mode), hid_device_name);
hid_create_sdp_record(hid_service_buffer, 0x10001, 0x2540, 33,
hid_virtual_cable, hid_reconnect_initiate, 0,
hid_descriptor_keyboard_boot_mode, sizeof(hid_descriptor_keyboard_boot_mode), hid_device_name);
printf("HID service record size: %u\n", de_get_len( hid_service_buffer));
sdp_register_service(hid_service_buffer);