mirror of
https://github.com/bluekitchen/btstack.git
synced 2025-02-14 00:40:57 +00:00
hid_device: fix create device on incoming connection, add suspend
This commit is contained in:
parent
1ea99aaf8a
commit
6510739ba0
@ -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
|
||||
|
||||
/**
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user