7 Commits

Author SHA1 Message Date
kenji cb7421eab7 add toggle button for USB and improve BLE polling rate 2025-10-18 22:38:23 -04:00
kenji a1a0723e89 update CMake for Pico 2 W build 2025-10-18 10:35:33 -04:00
kenji c430a53755 add schematic 2025-09-11 09:42:11 -04:00
kenji 2e9159cb57 Fix preserve pairing on power cycle 2025-09-09 15:05:45 -04:00
kenji a1e1ff70fc improve memory management & polling 2025-08-20 21:30:22 -04:00
kenji 5b3a5beb32 remove device CDC debug 2025-08-17 17:18:27 -04:00
kenji 8a8ec23d87 add diagram and video to README 2025-08-15 09:07:30 -04:00
19 changed files with 14613 additions and 241 deletions
+1 -1
View File
@@ -1 +1 @@
/build/**/*
/*/**/*
+4
View File
@@ -2,7 +2,9 @@ set(PROJECT ble_hid)
cmake_minimum_required(VERSION 3.13)
set(PICO_SDK_PATH /home/kenji/programming/pico/c/pico-sdk)
set(PICO_PIO_USB_PATH /home/kenji/programming/pico/c/Pico-PIO-USB)
if (NOT DEFINED PICO_BOARD)
set(PICO_BOARD pico_w)
endif()
include (${PICO_SDK_PATH}/external/pico_sdk_import.cmake)
project(${PROJECT} C CXX ASM)
@@ -45,5 +47,7 @@ target_link_libraries(${PROJECT} PRIVATE
pico_btstack_make_gatt_header(ble_hid PRIVATE "${CMAKE_CURRENT_LIST_DIR}/ble_hid.gatt")
set_target_properties(${PROJECT} PROPERTIES OUTPUT_NAME "${PROJECT}-${PICO_BOARD}")
pico_add_extra_outputs(${PROJECT})
+16
View File
@@ -4,13 +4,20 @@ This project uses a Raspberry Pi Pico W as a Bluetooth Low Energy adapter for
a wired USB HID input peripheral, allowing it to connect to a host device
over BLE using HID over GATT Profile.
## Setup
[YouTube Video](https://youtu.be/YuHbTrccshw)
### Hardware
You will need the following hardware to make the device:
- Raspberry Pi Pico W
- USB extension cable
- (Optional) Momentary push button
![Wiring schematic](schematic.svg)
You will need to cut the USB extension in half and connect the wires from the
female end to the Raspberry Pi Pico W. The default configuration is to attach
@@ -27,6 +34,10 @@ respectively. For the data wires, you can solder them to the two test points
TP2 and TP3 on the back of the Raspberry Pi Pico. The white cable goes to TP2
and the green cable to TP3.
![Wiring of USB connectors to Raspberry Pi Pico W](diagram.png)
Optionally, a momentary push button can be wired to GP5 and GND to switch between Bluetooth and USB passthrough mode.
The individual wires on the USB can be fragile, so hot glue or other strain
relief is a good idea.
@@ -56,6 +67,11 @@ with many LEDs, the sudden power draw when plugging in can cause issues, so it
is recommended to turn off the LEDs before connecting to the Raspberry Pi Pico
W.
If you connected a push button to GP5, then pressing the button will switch
between Bluetooth connection mode and USB passthrough mode. In USB passthrough
mode, the inputs will be passed through from the host to the USB connection made
through the test points or the Micro USB port.
In principle, the Pico BLE HID will work with peripherals plugged into
a USB hub, but compatibility will vary with the specific hardware used,
including the peripherals, USB hub, and operating system. This is because the
+8
View File
@@ -0,0 +1,8 @@
#ifndef BLEHID_CONFIG_H_
#define BLEHID_CONFIG_H_
#define BUTTON_PIN 5
#define BUTTON_DEBOUNCE 20000
#define BUTTON_LONG_PRESS 3000000
#endif
+50 -32
View File
@@ -26,7 +26,10 @@ static btstack_packet_callback_registration_t l2cap_event_callback_registration;
static btstack_packet_callback_registration_t sm_event_callback_registration;
static uint8_t battery = 100;
hci_con_handle_t con_handle = HCI_CON_HANDLE_INVALID;
uint16_t conn_interval=1000;
static uint8_t protocol_mode = 1;
bt_state_t bt_state;
bt_device_command_t bt_device_command;
static hids_device_report_t *dev_report_storage;
@@ -45,16 +48,11 @@ const uint8_t adv_data_len = sizeof(adv_data);
static void bt_hid_setup(void);
static void packet_handler (uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size);
//extern uint8_t desc_hid_report[];
//extern uint16_t desc_hid_report_len;
// start BTstack
void btstack_main(void){
bt_hid_setup();
init_report_buf();
hci_power_control(HCI_POWER_ON);
}
static void bt_hid_setup(void) {
@@ -79,7 +77,7 @@ static void bt_hid_setup(void) {
// setup HID Device service
dev_report_storage = (hids_device_report_t *)malloc(sizeof(hids_device_report_t)*NUM_REPORT_IDS);
hids_device_init_with_storage(0, get_desc_hid_report(), get_desc_hid_report_len(), NUM_REPORT_IDS, dev_report_storage);
hids_device_init_with_storage(0, desc_hid_report, desc_hid_report_len, NUM_REPORT_IDS, dev_report_storage);
// setup advertisements
uint16_t adv_int_min = 0x0030;
@@ -112,50 +110,68 @@ static void packet_handler (uint8_t packet_type, uint16_t channel, uint8_t *pack
(void) channel;
(void) size;
uint16_t conn_interval;
if (packet_type != HCI_EVENT_PACKET) return;
if (packet_type != HCI_EVENT_PACKET) {
cdc_count = sprintf(cdc_buf, "Unexpected packet type %02X\n", packet_type);
cdc_print_str(cdc_buf, cdc_count);
return;
}
switch (hci_event_packet_get_type(packet)) {
case HCI_EVENT_DISCONNECTION_COMPLETE:
con_handle = HCI_CON_HANDLE_INVALID;
printf("Disconnected\n");
cdc_print_msg("Disconnected\n");
set_host_state(HOST_STOP_LISTEN);
if ( device_state == DEVICE_INACTIVE) {
host_state = HOST_STOP_LISTEN;
}
cyw43_arch_gpio_put(CYW43_WL_GPIO_LED_PIN, 0);
break;
case SM_EVENT_JUST_WORKS_REQUEST:
printf("Just Works requested\n");
cdc_print_msg("Just Works requested\n");
sm_just_works_confirm(sm_event_just_works_request_get_handle(packet));
cyw43_arch_gpio_put(CYW43_WL_GPIO_LED_PIN, 0);
break;
case SM_EVENT_NUMERIC_COMPARISON_REQUEST:
printf("Confirming numeric comparison: %"PRIu32"\n", sm_event_numeric_comparison_request_get_passkey(packet));
cdc_count = sprintf(cdc_buf, "Confirming numeric comparison: %"PRIu32"\n", sm_event_numeric_comparison_request_get_passkey(packet));
cdc_print_str(cdc_buf, cdc_count);
sm_numeric_comparison_confirm(sm_event_passkey_display_number_get_handle(packet));
break;
case SM_EVENT_PASSKEY_DISPLAY_NUMBER:
printf("Display Passkey: %"PRIu32"\n", sm_event_passkey_display_number_get_passkey(packet));
cdc_count = sprintf(cdc_buf, "Display Passkey: %"PRIu32"\n", sm_event_passkey_display_number_get_passkey(packet));
cdc_print_str(cdc_buf, cdc_count);
break;
case SM_EVENT_IDENTITY_RESOLVING_STARTED:
break;
case L2CAP_EVENT_CONNECTION_PARAMETER_UPDATE_RESPONSE:
printf("L2CAP Connection Parameter Update Complete, response: %x\n", l2cap_event_connection_parameter_update_response_get_result(packet));
cdc_count = sprintf(cdc_buf, "L2CAP Connection Parameter Update Complete, response: %x\n", l2cap_event_connection_parameter_update_response_get_result(packet));
cdc_print_str(cdc_buf, cdc_count);
break;
case HCI_EVENT_LE_META:
switch (hci_event_le_meta_get_subevent_code(packet)) {
case HCI_SUBEVENT_LE_CONNECTION_COMPLETE:
// print connection parameters (without using float operations)
conn_interval = hci_subevent_le_connection_complete_get_conn_interval(packet);
printf("LE Connection Complete:\n");
printf("- Connection Interval: %u.%02u ms\n", conn_interval * 125 / 100, 25 * (conn_interval & 3));
printf("- Connection Latency: %u\n", hci_subevent_le_connection_complete_get_conn_latency(packet));
set_host_poll_interval(conn_interval);
cdc_print_msg("LE Connection Complete:\n");
cdc_count = sprintf(cdc_buf, "- Connection Interval: %u.%02u ms\n", conn_interval * 125 / 100, 25 * (conn_interval & 3));
cdc_print_str(cdc_buf, cdc_count);
cdc_count = sprintf(cdc_buf, "- Connection Latency: %u\n", hci_subevent_le_connection_complete_get_conn_latency(packet));
cdc_print_str(cdc_buf, cdc_count);
break;
case HCI_SUBEVENT_LE_CONNECTION_UPDATE_COMPLETE:
// print connection parameters (without using float operations)
conn_interval = hci_subevent_le_connection_update_complete_get_conn_interval(packet);
printf("LE Connection Update:\n");
printf("- Connection Interval: %u.%02u ms\n", conn_interval * 125 / 100, 25 * (conn_interval & 3));
printf("- Connection Latency: %u\n", hci_subevent_le_connection_update_complete_get_conn_latency(packet));
set_host_poll_interval(conn_interval);
cdc_print_msg("LE Connection Update:\n");
cdc_count = sprintf(cdc_buf, "- Connection Interval: %u.%02u ms\n", conn_interval * 125 / 100, 25 * (conn_interval & 3));
cdc_print_str(cdc_buf, cdc_count);
cdc_count = sprintf(cdc_buf, "- Connection Latency: %u\n", hci_subevent_le_connection_update_complete_get_conn_latency(packet));
cdc_print_str(cdc_buf, cdc_count);
break;
default:
//cdc_count = sprintf(cdc_buf,"LE packet unknown %02X\n", hci_event_le_meta_get_subevent_code(packet));
//cdc_print_str(cdc_buf, cdc_count);
break;
}
break;
@@ -163,43 +179,45 @@ static void packet_handler (uint8_t packet_type, uint16_t channel, uint8_t *pack
switch (hci_event_hids_meta_get_subevent_code(packet)){
case HIDS_SUBEVENT_INPUT_REPORT_ENABLE:
con_handle = hids_subevent_input_report_enable_get_con_handle(packet);
printf("Report Characteristic Subscribed %u\n", hids_subevent_input_report_enable_get_enable(packet));
cdc_count = sprintf(cdc_buf, "Report Characteristic Subscribed %u\n", hids_subevent_input_report_enable_get_enable(packet));
cdc_print_str(cdc_buf, cdc_count);
set_host_state(HOST_START_LISTEN);
host_state = HOST_START_LISTEN;
cyw43_arch_gpio_put(CYW43_WL_GPIO_LED_PIN, 1);
// request connection param update via L2CAP following Apple Bluetooth Design Guidelines
// gap_request_connection_parameter_update(con_handle, 12, 12, 4, 100); // 15 ms, 4, 1s
// directly update connection params via HCI following Apple Bluetooth Design Guidelines
// gap_update_connection_parameters(con_handle, 12, 12, 4, 100); // 60-75 ms, 4, 1s
// request update to max 125Hz polling
gap_request_connection_parameter_update(con_handle, 6,6,0,100);
break;
case HIDS_SUBEVENT_PROTOCOL_MODE:
protocol_mode = hids_subevent_protocol_mode_get_protocol_mode(packet);
printf("Protocol Mode: %s mode\n", hids_subevent_protocol_mode_get_protocol_mode(packet) ? "Report" : "Boot");
cdc_count = sprintf(cdc_buf, "Protocol Mode: %s mode\n", hids_subevent_protocol_mode_get_protocol_mode(packet) ? "Report" : "Boot");
cdc_print_str(cdc_buf, cdc_count);
break;
case HIDS_SUBEVENT_CAN_SEND_NOW:
printf("HIDS_SUBEVENT_CAN_SEND_NOW\n");
send_report();
cyw43_arch_gpio_put(CYW43_WL_GPIO_LED_PIN, 1-cyw43_arch_gpio_get(CYW43_WL_GPIO_LED_PIN));
break;
default:
//cdc_count = sprintf(cdc_buf, "Unknown HID event %02X\n", hci_event_hids_meta_get_subevent_code(packet));
//cdc_print_str(cdc_buf, cdc_count);
break;
}
break;
default:
//cdc_count = sprintf(cdc_buf, "Unknown HCI event %02X\n", hci_event_packet_get_type(packet));
//cdc_print_str(cdc_buf, cdc_count);
break;
}
}
// called to update the report map aka HID report descriptor on the BT interface
void update_desc_hid_report(void) {
con_handle = HCI_CON_HANDLE_INVALID;
hci_power_control(HCI_POWER_OFF);
uint16_t len = get_desc_hid_report_len();
if (len>0) {
hids_device_init_with_storage(0, get_desc_hid_report(), len, NUM_REPORT_IDS, dev_report_storage);
if (bt_state == BT_STATE_ACTIVE && desc_hid_report_len>0) {
hids_device_init_with_storage(0, desc_hid_report, desc_hid_report_len, NUM_REPORT_IDS, dev_report_storage);
hci_power_control(HCI_POWER_ON);
}
}
+20
View File
@@ -1,6 +1,26 @@
#ifndef BT_DEVICE_H_
#define BT_DEVICE_H_
#define BT_LOOP_POLL_INTERVAL 100
typedef enum {
BT_STATE_INACTIVE=0,
BT_STATE_STOP,
BT_STATE_START,
BT_STATE_ACTIVE
} bt_state_t;
typedef enum {
BT_DEVICE_COMMAND_NONE=0,
BT_DEVICE_COMMAND_SWITCH,
BT_DEVICE_COMMAND_UNPAIR,
BT_DEVICE_COMMAND_UPDATE,
} bt_device_command_t;
extern bt_state_t bt_state;
extern bt_device_command_t bt_device_command;
extern uint16_t conn_interval;
void btstack_main(void);
void update_desc_hid_report(void);
-3
View File
@@ -86,7 +86,4 @@
// To get the audio demos working even with HCI dump at 115200, this truncates long ACL packets
//#define HCI_DUMP_STDOUT_MAX_SIZE_ACL 100
// enable larger HID descriptor
#define MAX_ATTRIBUTE_VALUE_SIZE 512
#endif // _PICO_BTSTACK_BTSTACK_CONFIG_H
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 511 KiB

+97 -47
View File
@@ -11,14 +11,20 @@
#include "usb_device.h"
#include "usb_host.h"
#include "bt_device.h"
#include "hid_report.h"
extern hci_con_handle_t con_handle;
uint8_t desc_hid_report[HID_DESCRIPTOR_SIZE];
uint16_t desc_hid_report_len=0;
uint8_t num_mounted=0;
static uint8_t buffer_storage[REPORT_BUF_SIZE];
static btstack_ring_buffer_t report_buf;
static uint8_t desc_hid_report[HID_DESCRIPTOR_SIZE];
static uint16_t desc_hid_report_len=0;
static struct report_data *report;
static struct report_desc *descriptors;
static struct report_desc* report_desc_alloc(void);
@@ -30,8 +36,6 @@ static void report_dict_init(struct report_dict *mapping);
static void report_dict_free(struct report_dict *mapping, struct report_desc *descriptor);
static struct report_dict* find_mapping(uint8_t dev_addr, uint8_t instance, uint8_t report_id);
extern hci_con_handle_t con_handle;
// start listening to HID input reports on all mounted devices
bool request_hid_reports_all(void) {
// send request to receive reports on all mounted devices
@@ -39,15 +43,18 @@ bool request_hid_reports_all(void) {
for (current=descriptors; current != NULL; current=current->next) {
if (! current->listening) {
if(request_hid_report(current->dev_addr, current->instance)) {
char tempbuf[40];
size_t count = sprintf(tempbuf, "Listening to input reports on [%u:%u]\n", current->dev_addr, current->instance);
cdc_print_str(tempbuf, count);
cdc_count = sprintf(cdc_buf, "Listening to input reports on [%u:%u]\n", current->dev_addr, current->instance);
cdc_print_str(cdc_buf, cdc_count);
current->listening = true;
} else {
cdc_print_msg("Error listening to input report(s)\n");
stop_hid_reports_all();
return false;
}
}
}
host_state = HOST_LISTENING;
return true;
}
@@ -58,15 +65,21 @@ bool stop_hid_reports_all(void) {
for (current=descriptors; current != NULL; current=current->next) {
if (current->listening) {
if(stop_hid_report(current->dev_addr, current->instance)) {
char tempbuf[40];
size_t count = sprintf(tempbuf, "Stopping input reports on [%u:%u]\n", current->dev_addr, current->instance);
cdc_print_str(tempbuf, count);
cdc_count = sprintf(cdc_buf, "Stopping input reports on [%u:%u]\n", current->dev_addr, current->instance);
cdc_print_str(cdc_buf, cdc_count);
current->listening = false;
} else {
cdc_print_msg("Error stopping input report(s)\n");
return false;
}
}
}
if (num_mounted > 0) {
host_state = HOST_MOUNTED;
} else {
host_state = HOST_INACTIVE;
}
return true;
}
@@ -74,58 +87,72 @@ bool stop_hid_reports_all(void) {
void send_report(){
// process queue and send next report
if (btstack_ring_buffer_bytes_available(&report_buf)) {
uint8_t dev_addr;
uint8_t instance;
uint8_t len8[2];
uint16_t len;
uint32_t num_bytes_read;
// retrieve dev_addr from ring_buffer
btstack_ring_buffer_read(&report_buf, &dev_addr, 1, &num_bytes_read);
btstack_ring_buffer_read(&report_buf, &report->dev_addr, 1, &num_bytes_read);
// retrieve instance from ring buffer
btstack_ring_buffer_read(&report_buf, &instance, 1, &num_bytes_read);
btstack_ring_buffer_read(&report_buf, &report->instance, 1, &num_bytes_read);
// retrieve length as two uint8_t and turn into uint16_t
btstack_ring_buffer_read(&report_buf, len8, 2, &num_bytes_read);
memcpy(&len, len8, 2);
memcpy(&report->len, len8, 2);
// retrieve report from ring buffer
uint8_t report[len];
btstack_ring_buffer_read(&report_buf, report, len, &num_bytes_read);
btstack_ring_buffer_read(&report_buf, report->report, report->len, &num_bytes_read);
// send over BLE if connected
if (con_handle != HCI_CON_HANDLE_INVALID) {
// find report id mapping
struct report_dict * mapping = find_mapping(dev_addr, instance, report[0]);
struct report_dict * mapping = find_mapping(report->dev_addr, report->instance, report->report[0]);
char tempbuf[16];
size_t count=sprintf(tempbuf, "[%04x](%u) ", con_handle, mapping->ble_id);
cdc_print_str(tempbuf, count);
cdc_count=sprintf(cdc_buf, "[%04x](%u)> ", con_handle, mapping->ble_id);
cdc_print_str(cdc_buf, cdc_count);
// send hid report to ble interface
if (mapping != NULL) {
if (mapping->report_id==0) {
hids_device_send_input_report_for_id(con_handle, mapping->ble_id, report, len);
cdc_print_hex(report, len);
hids_device_send_input_report_for_id(con_handle, mapping->ble_id, report->report, report->len);
cdc_print_hex(report->report, report->len);
} else {
// replace report ID in original report before sending
hids_device_send_input_report_for_id(con_handle, mapping->ble_id, &report[1], len-1);
cdc_print_hex(&report[1], len-1);
hids_device_send_input_report_for_id(con_handle, mapping->ble_id, &report->report[1], report->len-1);
cdc_print_hex(&report->report[1], report->len-1);
}
}
// request sending of next report
if (btstack_ring_buffer_bytes_available(&report_buf)) {
hids_device_request_can_send_now_event(con_handle);
}
}
// request send of next report
hids_device_request_can_send_now_event(con_handle);
// send over USB if enabled
if ( device_state == DEVICE_ACTIVE ) {
struct report_desc *descriptor = report_desc_find(report->dev_addr, report->instance);
cdc_count=sprintf(cdc_buf, "[%u]> ", descriptor->dev_instance);
cdc_print_str(cdc_buf, cdc_count);
forward_report(descriptor->dev_instance, report->report, report->len);
cdc_print_hex(report->report, report->len);
}
// set host to poll USB
if (host_state == HOST_WAIT_POLL) {
host_state = HOST_POLL;
}
}
}
// add report to the BTstack ring buffer for sending
void queue_report(uint8_t dev_addr, uint8_t instance, uint8_t const* report, uint16_t len) {
if (con_handle != HCI_CON_HANDLE_INVALID) {
if (con_handle != HCI_CON_HANDLE_INVALID || device_state == DEVICE_ACTIVE ) {
// convert len to array of two uint8_t from single uint16_t
uint8_t len8[2];
memcpy(len8, &len, 2);
if (btstack_ring_buffer_bytes_free(&report_buf) >= len+4) {
if (btstack_ring_buffer_bytes_free(&report_buf) >= len+5) {
// put instance, length, and report into ring buffer if space available
btstack_ring_buffer_write(&report_buf, &dev_addr, 1);
btstack_ring_buffer_write(&report_buf, &instance, 1);
@@ -133,14 +160,25 @@ void queue_report(uint8_t dev_addr, uint8_t instance, uint8_t const* report, uin
btstack_ring_buffer_write(&report_buf, report, len);
}
if (con_handle != HCI_CON_HANDLE_INVALID) {
// request send on BLE HID interface
hids_device_request_can_send_now_event(con_handle);
} else {
// BLE is not active, send over USB
send_report();
}
}
// HID report on device has not been requested, flag so it can be polled
struct report_desc * descriptor;
descriptor = report_desc_find(dev_addr, instance);
descriptor->listening = false;
}
// allocate memory for HID report ring buffer
void init_report_buf(void) {
btstack_ring_buffer_init(&report_buf, buffer_storage, sizeof(buffer_storage));
report = REPORT_DATA_ALLOC();
}
// allocate memory for USB interface report descriptor
@@ -200,6 +238,7 @@ bool add_descriptor(uint8_t dev_addr, uint8_t instance, uint8_t const* desc_repo
descriptor->desc_len = desc_len;
descriptor->dev_addr = dev_addr;
descriptor->instance = instance;
descriptor->dev_instance = instance;
descriptor->listening = false;
return true;
@@ -211,7 +250,8 @@ bool generate_report_descriptor(void) {
memset(desc_hid_report, 0, sizeof(desc_hid_report));
desc_hid_report_len=0;
uint8_t num_mounted = 0;
uint8_t id_counter = 0;
uint8_t instance_counter = 0;
struct report_desc * current;
for (current=descriptors; current != NULL; current=current->next) {
@@ -236,11 +276,11 @@ bool generate_report_descriptor(void) {
if (report_map == NULL) {
return false;
}
num_mounted++;
id_counter++;
report_map->report_id = current->descriptor[i];
report_map->ble_id = num_mounted;
report_map->ble_id = id_counter;
desc_hid_report[desc_hid_report_len+i]=num_mounted;
desc_hid_report[desc_hid_report_len+i]=id_counter;
}
}
@@ -255,30 +295,49 @@ bool generate_report_descriptor(void) {
}
}
desc_hid_report[desc_hid_report_len+col_pos+2] = 0x85;
desc_hid_report[desc_hid_report_len+col_pos+3] = num_mounted+1;
desc_hid_report[desc_hid_report_len+col_pos+3] = id_counter+1;
memcpy(&desc_hid_report[desc_hid_report_len+col_pos+4], &current->descriptor[col_pos+2], current->desc_len-col_pos);
desc_hid_report_len += current->desc_len+2;
// store mapping with report ID of 0
struct report_dict * report_map = report_dict_alloc(current);
num_mounted++;
id_counter++;
report_map->report_id = 0;
report_map->ble_id = num_mounted;
report_map->ble_id = id_counter;
} else {
desc_hid_report_len += current->desc_len;
}
// store mapping for host instance to device instance
current->dev_instance = instance_counter;
instance_counter++;
}
if (num_mounted > NUM_REPORT_IDS) {
if (id_counter > NUM_REPORT_IDS) {
cdc_print_msg("Error: too many report IDs\n");
return false;
}
// update number of instances mounted
num_mounted = instance_counter;
btstack_ring_buffer_reset(&report_buf);
return true;
}
// find a return the report descriptor by dvice address and device instance
struct report_desc * get_report_desc(uint8_t dev_instance) {
struct report_desc *descriptor;
for (descriptor = descriptors; descriptor != NULL; descriptor = descriptor->next) {
if (descriptor->dev_instance==dev_instance) {
break;
}
}
return descriptor;
}
// remove report descriptor for HID interface
void remove_instance(uint8_t dev_addr, uint8_t instance) {
struct report_desc *descriptor = report_desc_find(dev_addr, instance);
@@ -358,12 +417,3 @@ static struct report_dict * find_mapping(uint8_t dev_addr, uint8_t instance, uin
return NULL;
}
uint16_t get_desc_hid_report_len(void) {
return desc_hid_report_len;
}
uint8_t const* get_desc_hid_report(void) {
return desc_hid_report;
}
+15 -2
View File
@@ -1,6 +1,7 @@
#ifndef HID_REPORT_H_
#define HID_REPORT_H_
#define REPORT_MAX_SIZE 64
#define NUM_REPORT_IDS 16
#define REPORT_BUF_SIZE 256
#define DESCRIPTOR_BUF_SIZE 256
@@ -11,6 +12,7 @@ struct report_desc {
uint8_t instance;
uint8_t descriptor[DESCRIPTOR_BUF_SIZE];
uint16_t desc_len;
uint8_t dev_instance;
struct report_desc *next;
struct report_dict *mappings;
bool listening;
@@ -22,8 +24,20 @@ struct report_dict {
struct report_dict *next;
};
struct report_data {
uint8_t dev_addr;
uint8_t instance;
uint8_t report[REPORT_MAX_SIZE];
uint16_t len;
};
#define REPORT_DESC_ALLOC() (struct report_desc *)malloc(sizeof(struct report_desc))
#define REPORT_DICT_ALLOC() (struct report_dict *)malloc(sizeof(struct report_dict))
#define REPORT_DATA_ALLOC() (struct report_data *)malloc(sizeof(struct report_data))
extern uint8_t desc_hid_report[HID_DESCRIPTOR_SIZE];
extern uint16_t desc_hid_report_len;
extern uint8_t num_mounted;
bool request_hid_reports_all(void);
bool stop_hid_reports_all(void);
@@ -33,7 +47,6 @@ void init_report_buf(void);
bool add_descriptor(uint8_t dev_addr, uint8_t instance, uint8_t const* desc_report, uint16_t desc_len);
void remove_instance(uint8_t dev_addr, uint8_t instance);
bool generate_report_descriptor(void);
uint16_t get_desc_hid_report_len(void);
uint8_t const* get_desc_hid_report(void);
struct report_desc * get_report_desc(uint8_t dev_instance);
#endif
+111 -28
View File
@@ -2,6 +2,7 @@
#include "pico/multicore.h"
#include "pico/bootrom.h"
#include "hardware/clocks.h"
#include "hardware/gpio.h"
#include "pio_usb.h"
#include "tusb.h"
@@ -12,61 +13,143 @@
#include "usb_device.h"
#include "usb_host.h"
#include "blehid_config.h"
static void usb_main(void);
#ifdef BUTTON_PIN
static absolute_time_t last_button_time;
static uint32_t last_button_event;
static void gpio_callback(uint pin, uint32_t events);
#endif
// main loop
int main(void) {
// for PIO USB, we want clock speed to be multiple of 12MHz
set_sys_clock_khz(144000, true);
set_sys_clock_khz(192000, true);
// need so BTstack can save pairing information to flash
flash_safe_execute_core_init();
sleep_ms(10);
// setup BLE on core 1
// run BLE on core 1
multicore_reset_core1();
multicore_launch_core1(btstack_main);
// run usb on core 0
usb_main();
return 0;
}
static void usb_main(void) {
// setup GPIO button for pair selection
#ifdef BUTTON_PIN
gpio_init(BUTTON_PIN);
gpio_pull_up(BUTTON_PIN);
gpio_set_irq_enabled_with_callback(BUTTON_PIN, GPIO_IRQ_EDGE_RISE | GPIO_IRQ_EDGE_FALL, true, &gpio_callback);
#endif
// init and run usb host
usb_host_init();
// init and run usb device
usb_device_init();
// set initial state
bt_state = BT_STATE_ACTIVE;
device_state = DEVICE_INACTIVE;
while (true) {
switch ( get_host_state() ) {
switch ( host_state ) {
case HOST_NEW_DESCRIPTOR:
if ( host_ready() ) {
if(generate_report_descriptor()) {
if ( get_desc_hid_report_len() > 0 ) {
set_host_state(HOST_MOUNTED);
cyw43_arch_gpio_put(CYW43_WL_GPIO_LED_PIN, 1);
} else {
set_host_state(HOST_INACTIVE);
}
cdc_print_msg("Updating HID report map\n");
update_desc_hid_report();
}
}
host_ready();
break;
case HOST_START_LISTEN:
if (request_hid_reports_all()) {
set_host_state(HOST_LISTENING);
} else {
cdc_print_msg("Error listening to input report(s)\n");
set_host_state(HOST_INACTIVE);
}
request_hid_reports_all();
break;
case HOST_STOP_LISTEN:
if (stop_hid_reports_all()) {
set_host_state(HOST_INACTIVE);
} else {
cdc_print_msg("Error stopping input report(s)\n");
}
stop_hid_reports_all();
break;
case HOST_POLL:
poll_devices();
break;
default:
break;
}
switch ( device_state ) {
case DEVICE_STOP:
case DEVICE_START:
if ( tud_disconnect() ) {
sleep_ms(10);
tud_connect();
}
if ( device_state == DEVICE_STOP ) {
device_state = DEVICE_INACTIVE;
host_state = HOST_STOP_LISTEN;
} else if (device_state == DEVICE_START ) {
device_state = DEVICE_ACTIVE;
if ( num_mounted > 0 ) {
set_host_poll_interval(1);
host_state = HOST_START_LISTEN;
}
}
break;
default:
break;
}
switch ( bt_state ) {
case BT_STATE_STOP:
bt_state = BT_STATE_INACTIVE;
update_desc_hid_report();
break;
case BT_STATE_START:
bt_state = BT_STATE_ACTIVE;
update_desc_hid_report();
break;
default:
break;
}
tuh_task(); // tinyusb host task
tud_task(); // tinyusb device task
tud_cdc_write_flush();
}
return 0;
}
#ifdef BUTTON_PIN
static void gpio_callback(uint pin, uint32_t events) {
uint64_t diff = absolute_time_diff_us(last_button_time, get_absolute_time());
if (pin == BUTTON_PIN && diff >= BUTTON_DEBOUNCE) {
if (events & GPIO_IRQ_EDGE_FALL) {
// button pressed
last_button_time = get_absolute_time();
} else if (events & GPIO_IRQ_EDGE_RISE) {
// button released
if (diff >= BUTTON_LONG_PRESS) {
//bt_device_command = BT_DEVICE_COMMAND_UNPAIR;
} else {
if ( bt_state == BT_STATE_ACTIVE ) {
bt_state = BT_STATE_STOP;
} else if ( bt_state == BT_STATE_INACTIVE ) {
bt_state = BT_STATE_START;
}
if ( device_state == DEVICE_ACTIVE ) {
device_state = DEVICE_STOP;
} else if ( device_state == DEVICE_INACTIVE ) {
device_state = DEVICE_START;
}
//bt_device_command = BT_DEVICE_COMMAND_SWITCH;
}
last_button_time = get_absolute_time();
}
}
}
#endif
+14111
View File
File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 255 KiB

+5 -4
View File
@@ -85,13 +85,14 @@
//------------- Driver configuration -------------//
#define CFG_TUD_CDC 1
#define CFG_TUD_HID 8
// CDC FIFO size of TX and RX
#define CFG_TUD_CDC_RX_BUFSIZE 32
#define CFG_TUD_CDC_TX_BUFSIZE 64
#define CFG_TUD_CDC_TX_BUFSIZE 128
// CDC Endpoint transfer buffer size, more is faster
#define CFG_TUD_CDC_EP_BUFSIZE 64
#define CFG_TUD_CDC_EP_BUFSIZE 128
//--------------------------------------------------------------------
// HOST CONFIGURATION
@@ -121,8 +122,8 @@
#define CFG_TUH_DEVICE_MAX (CFG_TUH_HUB*3+1) // hub typically has 4 ports
#define CFG_TUH_HID (3*CFG_TUH_DEVICE_MAX+1)
#define CFG_TUH_HID_EPIN_BUFSIZE 64
#define CFG_TUH_HID_EPOUT_BUFSIZE 64
#define CFG_TUH_HID_EPIN_BUFSIZE 128
#define CFG_TUH_HID_EPOUT_BUFSIZE 128
#ifdef __cplusplus
}
+62 -58
View File
@@ -1,37 +1,16 @@
/*
* The MIT License (MIT)
*
* Copyright (c) 2019 Ha Thach (tinyusb.org)
* sekigon-gonnoc
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
#include "tusb.h"
#include "bsp/board_api.h"
#include "hid_report.h"
#include "usb_device.h"
#include "usb_descriptors.h"
//--------------------------------------------------------------------+
// Device Descriptors
//--------------------------------------------------------------------+
// reserve space for HID descriptor
static uint8_t desc_configuration[DESC_CFG_MAX];
static uint16_t _desc_str[32+1];
// USB device descriptor
tusb_desc_device_t const desc_device =
{
.bLength = sizeof(tusb_desc_device_t),
@@ -57,6 +36,17 @@ tusb_desc_device_t const desc_device =
.bNumConfigurations = 0x01
};
// string labels for device
char const* string_desc_arr [] =
{
(const char[]) { 0x09, 0x04 }, // 0: is supported language is English (0x0409)
"Raspberry Pi", // 1: Manufacturer
"Pico BLE HID", // 2: Product
NULL, // 3: Serials, should use chip ID
"Pico BLE HID CDC", // 4: CDC
"Pico USB HID", // 5: USB HID Device
};
// Invoked when received GET DEVICE DESCRIPTOR
// Application return pointer to descriptor
uint8_t const * tud_descriptor_device_cb(void)
@@ -64,45 +54,45 @@ uint8_t const * tud_descriptor_device_cb(void)
return (uint8_t const *) &desc_device;
}
//--------------------------------------------------------------------+
// Configuration Descriptor
//--------------------------------------------------------------------+
// full speed configuration
uint8_t const desc_fs_configuration[] =
{
// Config number, interface count, string index, total length, attribute, power in mA
TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, 0x00, 100),
// Interface number, string index, protocol, report descriptor len, EP In address, size & polling interval
TUD_CDC_DESCRIPTOR(ITF_NUM_CDC, 4, EPNUM_CDC_NOTIF, 8, EPNUM_CDC_OUT, EPNUM_CDC_IN, 64),
};
// Invoked when received GET CONFIGURATION DESCRIPTOR
// Application return pointer to descriptor
// Descriptor contents must exist long enough for transfer to complete
uint8_t const * tud_descriptor_configuration_cb(uint8_t index)
{
(void) index; // for multiple configurations
return desc_fs_configuration;
// set configuration descriptor and CDC descriptor
memset(desc_configuration, 0, sizeof(desc_configuration));
if ( device_state == DEVICE_ACTIVE ) {
uint8_t desc_initial[TUD_CONFIG_DESC_LEN+TUD_CDC_DESC_LEN+1] = {
TUD_CONFIG_DESCRIPTOR(1, 4+num_mounted, 0, TUD_CONFIG_DESC_LEN+TUD_CDC_DESC_LEN+num_mounted*TUD_HID_DESC_LEN, 0x00, 100),
TUD_CDC_DESCRIPTOR(ITF_NUM_CDC, 4, EPNUM_CDC_NOTIF, 8, EPNUM_CDC_OUT, EPNUM_CDC_IN, 64),
};
memcpy(desc_configuration, desc_initial, TUD_CONFIG_DESC_LEN+TUD_CDC_DESC_LEN);
} else {
uint8_t desc_initial[TUD_CONFIG_DESC_LEN+TUD_CDC_DESC_LEN+1] = {
TUD_CONFIG_DESCRIPTOR(1, 4, 0, TUD_CONFIG_DESC_LEN+TUD_CDC_DESC_LEN, 0x00, 100),
TUD_CDC_DESCRIPTOR(ITF_NUM_CDC, 4, EPNUM_CDC_NOTIF, 8, EPNUM_CDC_OUT, EPNUM_CDC_IN, 64),
};
memcpy(desc_configuration, desc_initial, TUD_CONFIG_DESC_LEN+TUD_CDC_DESC_LEN);
}
//--------------------------------------------------------------------+
// String Descriptors
//--------------------------------------------------------------------+
// array of pointer to string descriptors
char const* string_desc_arr [] =
{
(const char[]) { 0x09, 0x04 }, // 0: is supported language is English (0x0409)
"Raspberry Pi", // 1: Manufacturer
"Pico BLE HID", // 2: Product
NULL, // 3: Serials, should use chip ID
// add a HID descriptor for each interface mounted on host
if ( device_state == DEVICE_ACTIVE ) {
struct report_desc * descriptor;
for (uint8_t i=0; i<num_mounted;i++) {
descriptor = get_report_desc(i);
if ( descriptor != NULL ) {
uint8_t hid_desc[TUD_HID_DESC_LEN+1] = {
TUD_HID_DESCRIPTOR(ITF_NUM_HID+i, 5, HID_ITF_PROTOCOL_NONE, descriptor->desc_len, EPNUM_HID+i, CFG_TUD_HID_EP_BUFSIZE, 1)
};
memcpy(&desc_configuration[TUD_CONFIG_DESC_LEN+TUD_CDC_DESC_LEN+i*TUD_HID_DESC_LEN], hid_desc, TUD_HID_DESC_LEN);
}
}
}
static uint16_t _desc_str[32+1];
return desc_configuration;
}
// Invoked when received GET STRING DESCRIPTOR request
// Application return pointer to descriptor, whose contents must exist long enough for transfer to complete
@@ -144,3 +134,17 @@ uint16_t const* tud_descriptor_string_cb(uint8_t index, uint16_t langid)
return _desc_str;
}
// Invoked when received GET HID REPORT DESCRIPTOR
// Application return pointer to descriptor
// Descriptor contents must exist long enough for transfer to complete
uint8_t const * tud_hid_descriptor_report_cb(uint8_t itf)
{
// find HID report descriptor for indicated interface on the host and forward to device
struct report_desc * descriptor = get_report_desc(itf);
if ( descriptor != NULL ) {
return descriptor->descriptor;
}
return NULL;
}
+3 -1
View File
@@ -5,6 +5,7 @@ enum
{
ITF_NUM_CDC=0,
ITF_NUM_CDC_DATA,
ITF_NUM_HID,
ITF_NUM_TOTAL
};
@@ -15,7 +16,8 @@ enum
#define EPNUM_CDC_NOTIF 0x81
#define EPNUM_CDC_OUT 0x02
#define EPNUM_CDC_IN 0x82
#define EPNUM_HID 0x83
#define CONFIG_TOTAL_LEN (TUD_CONFIG_DESC_LEN + TUD_CDC_DESC_LEN)
#define DESC_CFG_MAX (TUD_CONFIG_DESC_LEN + TUD_CDC_DESC_LEN + CFG_TUD_HID*TUD_HID_DESC_LEN)
#endif /* USB_DESCRIPTORS_H_ */
+18 -6
View File
@@ -9,6 +9,12 @@
#include "usb_device.h"
char cdc_buf[64];
uint16_t cdc_len;
size_t cdc_count;
device_state_t device_state;
void usb_device_init(void) {
// run TinyUSB device
tusb_rhport_init_t dev_init = {
@@ -42,23 +48,29 @@ uint16_t tud_hid_get_report_cb(uint8_t instance, uint8_t report_id, hid_report_t
return 0;
}
bool forward_report(uint8_t instance, uint8_t const* report, uint16_t len) {
return tud_hid_n_report(instance, 0, report, len);
}
// print message to CDC in raw hex
void cdc_print_hex(uint8_t const* msg, uint16_t msg_len) {
char tempbuf[8];
size_t count;
(void) msg;
(void) msg_len;
for (int i=0; i<msg_len; i++) {
count=sprintf(tempbuf, "%02X ", msg[i]);
tud_cdc_write(tempbuf, count);
cdc_count=sprintf(cdc_buf, "%02X ", msg[i]);
tud_cdc_write(cdc_buf, cdc_count);
}
tud_cdc_write_str("\n");
}
// print text message to CDC
void cdc_print_str(char const* msg, uint16_t msg_len) {
(void) msg;
(void) msg_len;
tud_cdc_write(msg, msg_len);
}
void cdc_print_msg(char const* msg) {
uint16_t msg_len = strlen(msg);
cdc_print_str(msg, msg_len);
cdc_len = strlen(msg);
cdc_print_str(msg, cdc_len);
}
+15 -2
View File
@@ -1,7 +1,20 @@
#ifndef MAIN_DEVICE_H_
#define MAIN_DEVICE_H_
#ifndef USB_DEVICE_H_
#define USB_DEVICE_H_
typedef enum {
DEVICE_INACTIVE=0,
DEVICE_START,
DEVICE_STOP,
DEVICE_ACTIVE
} device_state_t;
extern char cdc_buf[64];
extern uint16_t cdc_len;
extern size_t cdc_count;
extern device_state_t device_state;
void usb_device_init(void);
bool forward_report(uint8_t instance, uint8_t const* report, uint16_t len);
void cdc_print_hex(uint8_t const* msg, uint16_t msg_len);
void cdc_print_str(char const* msg, uint16_t msg_len);
void cdc_print_msg(char const* msg);
+48 -33
View File
@@ -11,11 +11,14 @@
#include "hid_report.h"
#include "usb_device.h"
#include "bt_device.h"
#include "usb_host.h"
static host_state_t host_state;
host_state_t host_state;
static absolute_time_t request_time;
static absolute_time_t last_report;
static uint16_t host_poll_interval=HOST_POLL_INTERVAL;
// initialize usb host
void usb_host_init(void) {
@@ -32,7 +35,7 @@ void usb_host_init(void) {
tuh_hid_set_default_protocol(HID_PROTOCOL_REPORT);
tusb_init(BOARD_TUH_RHPORT, &host_init);
set_host_state(HOST_INACTIVE);
host_state=HOST_INACTIVE;
}
@@ -44,16 +47,12 @@ void tuh_hid_mount_cb(uint8_t dev_addr, uint8_t instance, uint8_t const* desc_re
uint8_t const itf_protocol = tuh_hid_interface_protocol(dev_addr, instance);
/// send device vid:pid information to CDC for debugging
char tempbuf[CFG_TUD_CDC_TX_BUFSIZE];
size_t count = sprintf(tempbuf, "Mount: [%04x:%04x][%u:%u] Protocol = %u\n", vid, pid, dev_addr, instance, itf_protocol);
cdc_print_str(tempbuf, count);
// print descriptor
//cdc_print_hex(desc_report, desc_len);
cdc_count = sprintf(cdc_buf, "Mount: [%04x:%04x][%u:%u] Protocol = %u\n", vid, pid, dev_addr, instance, itf_protocol);
cdc_print_str(cdc_buf, cdc_count);
// add to HID report descriptor
if ( add_descriptor(dev_addr, instance, desc_report, desc_len)) {
set_host_state(HOST_NEW_DESCRIPTOR);
host_state=HOST_NEW_DESCRIPTOR;
request_time=get_absolute_time();
cyw43_arch_gpio_put(CYW43_WL_GPIO_LED_PIN, 0);
}
@@ -63,58 +62,74 @@ void tuh_hid_mount_cb(uint8_t dev_addr, uint8_t instance, uint8_t const* desc_re
void tuh_hid_umount_cb(uint8_t dev_addr, uint8_t instance)
{
// send device address:instance to CDC for debugging
char tempbuf[CFG_TUD_CDC_TX_BUFSIZE];
size_t count = sprintf(tempbuf, "Unmount: [%u:%u]\n", dev_addr, instance);
cdc_print_str(tempbuf, count);
cdc_count = sprintf(cdc_buf, "Unmount: [%u:%u]\n", dev_addr, instance);
cdc_print_str(cdc_buf, cdc_count);
if (stop_hid_report(dev_addr, instance)) {
cdc_print_msg("Successfully stopped receiving reports\n");
}
remove_instance(dev_addr, instance);
set_host_state(HOST_NEW_DESCRIPTOR);
host_state=HOST_NEW_DESCRIPTOR;
request_time=get_absolute_time();
}
// Invoked when received report from device via interrupt endpoint
void tuh_hid_report_received_cb(uint8_t dev_addr, uint8_t instance, uint8_t const* report, uint16_t len)
{
char tempbuf[32];
size_t count = sprintf(tempbuf, "[%04x:%04x](%u) ", dev_addr, instance, len);
cdc_print_str(tempbuf,count);
cdc_count = sprintf(cdc_buf, "[%u:%u](%u)< ", dev_addr, instance, len);
cdc_print_str(cdc_buf,cdc_count);
cdc_print_hex(report, len);
last_report = get_absolute_time();
host_state = HOST_WAIT_POLL;
queue_report(dev_addr, instance, report, len);
}
// continue to request to receive report
if ( !tuh_hid_receive_report(dev_addr, instance) )
{
cdc_print_msg("Error: cannot request report\r\n");
// get host ready by updating descriptors
void host_ready(void) {
if (absolute_time_diff_us(request_time, get_absolute_time()) >= 1000000){
if ( generate_report_descriptor() ) {
if ( num_mounted > 0 ) {
host_state = HOST_MOUNTED;
cyw43_arch_gpio_put(CYW43_WL_GPIO_LED_PIN, 1);
} else {
host_state = HOST_INACTIVE;
}
cdc_print_msg("Updating HID report map\n");
update_desc_hid_report();
if ( device_state == DEVICE_ACTIVE ) {
device_state = DEVICE_START;
}
}
}
}
// set the state of the host
void set_host_state(host_state_t new_host_state) {
host_state = new_host_state;
// set devices to listening once polling interval has passed
void poll_devices(void) {
if (absolute_time_diff_us(last_report, get_absolute_time()) >= host_poll_interval) {
request_hid_reports_all();
host_state = HOST_LISTENING;
}
}
// get the current state of the host
host_state_t get_host_state(void) {
return host_state;
// set the USB host polling interval based on the BT connection interval
void set_host_poll_interval(uint16_t bt_conn_interval) {
if (bt_conn_interval*1250 > HOST_POLL_INTERVAL) {
host_poll_interval = bt_conn_interval*1250;
} else {
host_poll_interval = HOST_POLL_INTERVAL;
}
// indicate whether host is ready for updating descriptors
bool host_ready(void) {
return (absolute_time_diff_us(request_time, get_absolute_time()) > 1000000);
}
// request HID input reports on specified device address and instance
bool request_hid_report(uint8_t dev_addr, uint8_t instance) {
// request to receive reports HID devices
if ( !tuh_hid_receive_report(dev_addr, instance) ) {
char tempbuf[CFG_TUD_CDC_TX_BUFSIZE];
size_t count = sprintf(tempbuf, "Error: cannot request report on [%u:%u]\n", dev_addr, instance);
cdc_print_str(tempbuf, count);
cdc_count = sprintf(cdc_buf, "Error: cannot request report on [%u:%u]\n", dev_addr, instance);
cdc_print_str(cdc_buf, cdc_count);
return false;
}
return true;
+10 -5
View File
@@ -1,5 +1,7 @@
#ifndef MAIN_HOST_H_
#define MAIN_HOST_H_
#ifndef USB_HOST_H_
#define USB_HOST_H_
#define HOST_POLL_INTERVAL 7500
typedef enum {
HOST_INACTIVE=0,
@@ -7,14 +9,17 @@ typedef enum {
HOST_MOUNTED,
HOST_START_LISTEN,
HOST_LISTENING,
HOST_WAIT_POLL,
HOST_POLL,
HOST_STOP_LISTEN,
} host_state_t;
extern host_state_t host_state;
void usb_host_init(void);
void set_host_state(host_state_t new_host_state);
host_state_t get_host_state(void);
bool host_ready(void);
void host_ready(void);
void poll_devices(void);
void set_host_poll_interval(uint16_t bt_conn_interval);
bool request_hid_report(uint8_t dev_addr, uint8_t instance);
bool stop_hid_report(uint8_t dev_addr, uint8_t instance);