Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
101 commits
Select commit Hold shift + click to select a range
a387b46
HID micro parser
Feb 1, 2022
ed80b26
HID micro parser
Feb 1, 2022
b65f257
HID micro parser
Feb 1, 2022
b458eda
HID micro parser
Feb 1, 2022
5f87607
HID micro parser
Feb 1, 2022
77c1ff8
HID micro parser
Feb 2, 2022
448c4e2
HID micro parser
Feb 2, 2022
3a65c8b
Merge branch 'hathach:master' into hid_micro_parser
fruit-bat Feb 3, 2022
911e872
HID micro parser
Feb 3, 2022
ab0a5d8
HID micro parser
Feb 3, 2022
3a87bca
HID micro parser
Feb 3, 2022
31acb25
HID micro parser
Feb 4, 2022
e14e988
HID micro parser
Feb 4, 2022
692708f
HID micro parser
Feb 4, 2022
388dc9b
HID micro parser
Feb 4, 2022
a95a410
HID micro parser
Feb 4, 2022
27013e9
HID micro parser
Feb 5, 2022
2ec43d7
HID micro parser
Feb 5, 2022
2a1ae02
HID micro parser
Feb 5, 2022
daecfb3
HID micro parser
Feb 5, 2022
e561f94
HID micro parser
Feb 5, 2022
92ca20b
HID micro parser
Feb 5, 2022
63aecd2
HID micro parser
Feb 5, 2022
8f5792f
HID micro parser
Feb 5, 2022
fd44668
HID micro parser
Feb 5, 2022
f7ad24c
HID micro parser
Feb 5, 2022
af7d3ca
HID micro parser
Feb 5, 2022
d31a61e
HID micro parser
Feb 6, 2022
9229f02
HID micro parser
Feb 6, 2022
af0e05f
HID micro parser
Feb 6, 2022
d4beada
HID micro parser
Feb 6, 2022
13e5937
HID micro parser
Feb 6, 2022
94e2409
HID micro parser
Feb 6, 2022
9c9a163
HID micro parser
Feb 6, 2022
5838a63
HID micro parser
Feb 6, 2022
ab9a626
HID micro parser
Feb 6, 2022
c4aecdc
HID micro parser
Feb 6, 2022
9b42234
HID micro parser
Feb 7, 2022
6456411
HID micro parser
Feb 7, 2022
a05d644
HID micro parser
Feb 7, 2022
9047195
Update hid_rip.h
fruit-bat Feb 8, 2022
9ad4ed8
HID micro parser
Feb 10, 2022
229f11d
Merge branch 'hid_micro_parser' of github.com:fruit-bat/tinyusb into …
Feb 10, 2022
54d845a
HID micro parser
Feb 11, 2022
3d87d36
HID micro parser
Feb 11, 2022
daa23aa
Merge branch 'hathach:master' into hid_micro_parser
fruit-bat Feb 12, 2022
954b3bc
HID micro parser
Feb 12, 2022
34e0cd5
HID micro parser
Feb 12, 2022
aea8893
HID micro parser
Feb 12, 2022
86d3c0d
HID micro parser
Feb 13, 2022
43fca5b
HID micro parser
Feb 13, 2022
79cabf6
HID micro parser
Feb 13, 2022
dc08e4e
HID micro parser
Feb 13, 2022
f056cfe
HID micro parser
Feb 13, 2022
9beba25
HID micro parser
Feb 13, 2022
2942026
HID micro parser
Feb 13, 2022
42bd477
HID micro parser
Feb 14, 2022
721474a
HID micro parser
Feb 14, 2022
6ea3805
HID micro parser
Feb 14, 2022
52dd993
HID micro parser
Feb 14, 2022
e89cf32
Merge branch 'hathach:master' into hid_micro_parser
fruit-bat Feb 15, 2022
94060ec
HID micro parser
Feb 15, 2022
62fbea6
HID micro parser
Feb 16, 2022
9891f6b
HID micro parser
Feb 17, 2022
0be1bac
HID micro parser
Feb 17, 2022
1ff9bd0
Merge branch 'hathach:master' into hid_micro_parser
fruit-bat Feb 17, 2022
7a22ce3
HID micro parser
Feb 18, 2022
2982523
Merge branch 'hathach:master' into hid_micro_parser
fruit-bat Feb 18, 2022
74619ea
HID micro parser
Feb 18, 2022
a9a6618
HID micro parser
Feb 19, 2022
dd359ec
Fix for 64bit test environment
Feb 23, 2022
d503ea4
fix build on 64bit compiler
fruit-bat Feb 26, 2022
a70d64c
Merge branch 'hathach:master' into hid_micro_parser
fruit-bat Feb 27, 2022
193fd0d
Use strict C function prototypes
fruit-bat Mar 6, 2022
d0f3650
Fix for Wall Werror
fruit-bat Mar 9, 2022
2362115
Merge branch 'hathach:master' into hid_micro_parser
fruit-bat Mar 11, 2022
2706708
Fix ceedling test build
fruit-bat Mar 11, 2022
3cde913
Merge branch 'hathach:master' into hid_micro_parser
fruit-bat Mar 27, 2022
f5163f2
Merge branch 'hathach:master' into hid_micro_parser
fruit-bat Apr 2, 2022
465ca82
Merge branch 'master' into hid_micro_parser
fruit-bat Apr 23, 2022
ba3b11b
Merge branch 'master' into hid_micro_parser
fruit-bat May 21, 2022
08e089b
Merge branch 'master' into hid_micro_parser
fruit-bat Jul 17, 2022
7276ef0
change CFG_TUH_ENDPOINT_MAX to TUP_DCD_ENDPOINT_MAX in example
fruit-bat Jul 17, 2022
7ba041a
change CFG_TUH_ENDPOINT_MAX to TUP_DCD_ENDPOINT_MAX in example
fruit-bat Jul 17, 2022
f99cf0c
Merge branch 'hathach:master' into hid_micro_parser
fruit-bat Jul 18, 2022
046f569
Fix for simple joystick with single axis
fruit-bat Aug 27, 2022
9aec491
Merge branch 'hathach:master' into hid_micro_parser
fruit-bat Sep 1, 2022
31512ca
Merge pull request #9 from fruit-bat/bugfix/oneaxisjoy
fruit-bat Sep 1, 2022
23c1f49
Merge with TinyUSB master
fruit-bat Jan 14, 2023
8e83dd0
Fix typo
fruit-bat Jan 18, 2023
b12521d
Fix typo
fruit-bat Jan 18, 2023
ae5ec40
Add hid code to Makefile
fruit-bat Jan 18, 2023
6012511
Merge branch 'hathach:master' into hid_micro_parser
fruit-bat Jan 31, 2023
f648491
Merge branch 'master' into hid_micro_parser
fruit-bat Mar 27, 2023
ca28ec7
Merge branch 'hid_micro_parser' of github.com:fruit-bat/tinyusb into …
fruit-bat Mar 27, 2023
040a9d7
HACK to default hosted devices to REPORT rather than BOOT
fruit-bat Jun 29, 2024
330e73d
BOOT vs REPORT
fruit-bat Jul 7, 2024
4c14a90
Add mouse example
fruit-bat Jul 21, 2024
47c406f
Merge branch 'master' into merge/hid_micro_parser_21_08_24
fruit-bat Aug 21, 2024
d278d9f
Merge pull request #13 from fruit-bat/master
fruit-bat Aug 31, 2024
d220125
Merge pull request #14 from fruit-bat/merge/hid_micro_parser_21_08_24
fruit-bat Sep 2, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions examples/host/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
build
9 changes: 9 additions & 0 deletions examples/host/cdc_msc_hid/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,19 @@ endif()

add_executable(${PROJECT})

target_compile_definitions(${PROJECT} PRIVATE
HID_PROTOCOL_DEFAULT=HID_PROTOCOL_REPORT
)

# Example source
target_sources(${PROJECT} PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/src/cdc_app.c
${CMAKE_CURRENT_SOURCE_DIR}/src/hid_app.c
${CMAKE_CURRENT_SOURCE_DIR}/src/hid_host_utils.c
${CMAKE_CURRENT_SOURCE_DIR}/src/hid_host_info.c
${CMAKE_CURRENT_SOURCE_DIR}/src/hid_host_common.c
${CMAKE_CURRENT_SOURCE_DIR}/src/hid_host_mouse.c
${CMAKE_CURRENT_SOURCE_DIR}/src/hid_host_joy.c
${CMAKE_CURRENT_SOURCE_DIR}/src/main.c
${CMAKE_CURRENT_SOURCE_DIR}/src/msc_app.c
)
Expand Down
15 changes: 15 additions & 0 deletions examples/host/cdc_msc_hid/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,24 @@ INC += \
EXAMPLE_SOURCE = \
src/cdc_app.c \
src/hid_app.c \
src/hid_host_utils.c \
src/hid_host_info.c \
src/hid_host_joy.c \
src/main.c \
src/msc_app.c \

SRC_C += $(addprefix $(CURRENT_PATH)/, $(EXAMPLE_SOURCE))

# TinyUSB Host Stack source
# SRC_C += \
# src/class/cdc/cdc_host.c \
# src/class/hid/hid_host.c \
# src/class/hid/hid_rip.c \
# src/class/hid/hid_ri.c \
# src/class/msc/msc_host.c \
# src/host/hub.c \
# src/host/usbh.c \
# src/portable/ohci/ohci.c \
# src/portable/nxp/lpc17_40/hcd_lpc17_40.c

include ../../build_system/make/rules.mk
188 changes: 122 additions & 66 deletions examples/host/cdc_msc_hid/src/hid_app.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@

#include "bsp/board_api.h"
#include "tusb.h"
#include "hid_host_joy.h"
#include "hid_host_info.h"

//--------------------------------------------------------------------+
// MACRO TYPEDEF CONSTANT ENUM DECLARATION
Expand All @@ -38,13 +40,6 @@

static uint8_t const keycode2ascii[128][2] = { HID_KEYCODE_TO_ASCII };

// Each HID instance can has multiple reports
static struct
{
uint8_t report_count;
tuh_hid_report_info_t report_info[MAX_REPORT];
}hid_info[CFG_TUH_HID];

static void process_kbd_report(hid_keyboard_report_t const *report);
static void process_mouse_report(hid_mouse_report_t const * report);
static void process_generic_report(uint8_t dev_addr, uint8_t instance, uint8_t const* report, uint16_t len);
Expand All @@ -54,6 +49,61 @@ void hid_app_task(void)
// nothing to do
}

void handle_kbd_report(tusb_hid_host_info_t* info, const uint8_t* report, uint8_t report_length, uint8_t report_id)
{
// Stop unused parameter errors
(void) info;
(void) report_length;
(void) report_id;

TU_LOG1("HID receive keyboard report\r\n");
process_kbd_report((hid_keyboard_report_t const *)report);
}

void handle_mouse_report(tusb_hid_host_info_t* info, const uint8_t* report, uint8_t report_length, uint8_t report_id)
{
// Stop unused parameter errors
(void) info;
(void) report_length;
(void) report_id;

TU_LOG1("HID receive mouse report\r\n");
process_mouse_report((hid_mouse_report_t const *)report);
}

void handle_joystick_report(tusb_hid_host_info_t* info, const uint8_t* report, uint8_t report_length, uint8_t report_id)
{
TU_LOG1("HID receive joystick report\r\n");
tusb_hid_simple_joystick_t* simple_joystick = tuh_hid_get_simple_joystick(
info->key.elements.dev_addr,
info->key.elements.instance,
report_id);

if (simple_joystick != NULL) {
tusb_hid_simple_joystick_process_report(simple_joystick, report, report_length);
tusb_hid_print_simple_joystick_report(simple_joystick);
}
}

void handle_joystick_unmount(tusb_hid_host_info_t* info) {
TU_LOG1("HID joystick unmount\n");
// Free up joystick definitions
tuh_hid_free_simple_joysticks_for_instance(info->key.elements.dev_addr, info->key.elements.instance);
}

void handle_gamepad_report(tusb_hid_host_info_t* info, const uint8_t* report, uint8_t report_length, uint8_t report_id)
{
// Stop unused parameter errors
(void) info;
(void) report_id;

TU_LOG1("HID receive gamepad report ");
for(int i = 0; i < report_length; ++i) {
printf("%02x", report[i]);
}
printf("\r\n");
}

//--------------------------------------------------------------------+
// TinyUSB Callbacks
//--------------------------------------------------------------------+
Expand All @@ -67,6 +117,10 @@ void tuh_hid_mount_cb(uint8_t dev_addr, uint8_t instance, uint8_t const* desc_re
{
printf("HID device address = %d, instance = %d is mounted\r\n", dev_addr, instance);

printf("HID Report Description \r\n");
for(int i = 0; i < desc_len; ++i) printf("%02X ", desc_report[i]);
printf("\r\n");

// Interface protocol (hid_interface_protocol_enum_t)
const char* protocol_str[] = { "None", "Keyboard", "Mouse" };
uint8_t const itf_protocol = tuh_hid_interface_protocol(dev_addr, instance);
Expand All @@ -77,8 +131,50 @@ void tuh_hid_mount_cb(uint8_t dev_addr, uint8_t instance, uint8_t const* desc_re
// Therefore for this simple example, we only need to parse generic report descriptor (with built-in parser)
if ( itf_protocol == HID_ITF_PROTOCOL_NONE )
{
hid_info[instance].report_count = tuh_hid_parse_report_descriptor(hid_info[instance].report_info, MAX_REPORT, desc_report, desc_len);
printf("HID has %u reports \r\n", hid_info[instance].report_count);
tuh_hid_report_info_t reports[MAX_REPORT];
uint8_t report_count = tuh_hid_parse_report_descriptor(reports, MAX_REPORT, desc_report, desc_len);
printf("HID has %u reports \r\n", report_count);

for (uint8_t i = 0; i < report_count; ++i) {
tuh_hid_report_info_t *report = &reports[i];
bool has_report_id = report_count > 1 || (report[0].report_id > 0);

printf("HID report usage_page=%d, usage=%d, has_report_id=%d dev=%d instance=%d\n", report->usage_page, report->usage, has_report_id, dev_addr, instance);

if (report->usage_page == HID_USAGE_PAGE_DESKTOP)
{
switch (report->usage)
{
case HID_USAGE_DESKTOP_KEYBOARD: {
printf("HID receive keyboard report description\r\n");
tuh_hid_allocate_info(dev_addr, instance, has_report_id, &handle_kbd_report, NULL);
break;
}
case HID_USAGE_DESKTOP_JOYSTICK: {
printf("HID receive joystick report description\r\n");
if(tuh_hid_allocate_info(dev_addr, instance, has_report_id, &handle_joystick_report, handle_joystick_unmount)) {
tuh_hid_joystick_parse_report_descriptor(desc_report, desc_len, dev_addr, instance);
}
break;
}
case HID_USAGE_DESKTOP_MOUSE: {
printf("HID receive mouse report description\r\n");
tuh_hid_allocate_info(dev_addr, instance, has_report_id, &handle_mouse_report, NULL);
break;
}
case HID_USAGE_DESKTOP_GAMEPAD: {
printf("HID receive gamepad report description\r\n");
tuh_hid_allocate_info(dev_addr, instance, has_report_id, &handle_gamepad_report, NULL);
// May be able to handle this in the same was as a the joystick. Needs a little investigation
break;
}
default: {
TU_LOG1("HID usage unknown usage:%d\r\n", report->usage);
break;
}
}
}
}
}

// request to receive report
Expand All @@ -93,6 +189,9 @@ 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)
{
printf("HID device address = %d, instance = %d is unmounted\r\n", dev_addr, instance);

// Invoke unmount functions and free up host info structure
tuh_hid_free_info(dev_addr, instance);
}

// Invoked when received report from device via interrupt endpoint
Expand All @@ -113,6 +212,7 @@ void tuh_hid_report_received_cb(uint8_t dev_addr, uint8_t instance, uint8_t cons
break;

default:
TU_LOG2("HID receive boot generic report\r\n");
// Generic report requires matching ReportID and contents with previous parsed report info
process_generic_report(dev_addr, instance, report, len);
break;
Expand Down Expand Up @@ -234,66 +334,22 @@ static void process_mouse_report(hid_mouse_report_t const * report)
//--------------------------------------------------------------------+
static void process_generic_report(uint8_t dev_addr, uint8_t instance, uint8_t const* report, uint16_t len)
{
(void) dev_addr;
(void) len;

uint8_t const rpt_count = hid_info[instance].report_count;
tuh_hid_report_info_t* rpt_info_arr = hid_info[instance].report_info;
tuh_hid_report_info_t* rpt_info = NULL;

if ( rpt_count == 1 && rpt_info_arr[0].report_id == 0)
{
// Simple report without report ID as 1st byte
rpt_info = &rpt_info_arr[0];
}else
tusb_hid_host_info_t* info = tuh_hid_get_info(dev_addr, instance);

if (info == NULL)
{
// Composite report, 1st byte is report ID, data starts from 2nd byte
uint8_t const rpt_id = report[0];

// Find report id in the array
for(uint8_t i=0; i<rpt_count; i++)
{
if (rpt_id == rpt_info_arr[i].report_id )
{
rpt_info = &rpt_info_arr[i];
break;
}
}

report++;
len--;
}

if (!rpt_info)
{
printf("Couldn't find report info !\r\n");
printf("Couldn't find the host report info for dev_addr=%d instance=%d\r\n", dev_addr, instance);
return;
}

uint8_t rpt_id = 0;

// For complete list of Usage Page & Usage checkout src/class/hid/hid.h. For examples:
// - Keyboard : Desktop, Keyboard
// - Mouse : Desktop, Mouse
// - Gamepad : Desktop, Gamepad
// - Consumer Control (Media Key) : Consumer, Consumer Control
// - System Control (Power key) : Desktop, System Control
// - Generic (vendor) : 0xFFxx, xx
if ( rpt_info->usage_page == HID_USAGE_PAGE_DESKTOP )
{
switch (rpt_info->usage)
{
case HID_USAGE_DESKTOP_KEYBOARD:
TU_LOG1("HID receive keyboard report\r\n");
// Assume keyboard follow boot report layout
process_kbd_report( (hid_keyboard_report_t const*) report );
break;

case HID_USAGE_DESKTOP_MOUSE:
TU_LOG1("HID receive mouse report\r\n");
// Assume mouse follow boot report layout
process_mouse_report( (hid_mouse_report_t const*) report );
break;

default: break;
}
if (info->has_report_id) {
rpt_id = report[0];
report++;
len--;
}

// TODO check if the length should be 16 bits
info->handler(info, report, (uint8_t)len, rpt_id);
}
59 changes: 59 additions & 0 deletions examples/host/cdc_msc_hid/src/hid_host_common.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
#include "hid_host_common.h"

void tuh_hid_simple_init_axis(
tusb_hid_simple_axis_t* simple_axis)
{
simple_axis->start = 0;
simple_axis->length = 0;
simple_axis->flags.is_signed = true;
simple_axis->logical_min = -1;
simple_axis->logical_max = 1;
}

// Fetch some data from the HID parser
//
// The data fetched here may be relevant to multiple usage items
//
// returns false if obviously not of interest
bool tuh_hid_get_simple_input_data(
tuh_hid_rip_state_t *pstate, // The current HID report parser state
const uint8_t* ri_input, // Pointer to the input item we have arrived at
tuh_hid_simple_input_data_t* data) // Data structure to complete
{
const uint8_t* ri_report_size = tuh_hid_rip_global(pstate, RI_GLOBAL_REPORT_SIZE);
const uint8_t* ri_report_count = tuh_hid_rip_global(pstate, RI_GLOBAL_REPORT_COUNT);
const uint8_t* ri_report_id = tuh_hid_rip_global(pstate, RI_GLOBAL_REPORT_ID);
const uint8_t* ri_logical_min = tuh_hid_rip_global(pstate, RI_GLOBAL_LOGICAL_MIN);
const uint8_t* ri_logical_max = tuh_hid_rip_global(pstate, RI_GLOBAL_LOGICAL_MAX);
const uint8_t* ri_usage_page = tuh_hid_rip_global(pstate, RI_GLOBAL_USAGE_PAGE);
const uint8_t* ri_usage_min = tuh_hid_rip_local(pstate, RI_LOCAL_USAGE_MIN);
const uint8_t* ri_usage_max = tuh_hid_rip_local(pstate, RI_LOCAL_USAGE_MAX);

// We need to know how the size of the data
if (ri_report_size == NULL || ri_report_count == NULL || ri_usage_page == NULL) return false;

data->report_size = tuh_hid_ri_short_udata32(ri_report_size);
data->report_count = tuh_hid_ri_short_udata32(ri_report_count);
data->report_id = ri_report_id ? tuh_hid_ri_short_udata8(ri_report_id) : 0;
data->logical_min = ri_logical_min ? tuh_hid_ri_short_data32(ri_logical_min) : 0;
data->logical_max = ri_logical_max ? tuh_hid_ri_short_data32(ri_logical_max) : 0;
data->input_flags.byte = tuh_hid_ri_short_udata8(ri_input);
data->usage_page = (uint16_t)tuh_hid_ri_short_udata32(ri_usage_page);
data->usage_min = ri_usage_min ? (uint16_t)tuh_hid_ri_short_udata32(ri_usage_min) : 0;
data->usage_max = ri_usage_max ? (uint16_t)tuh_hid_ri_short_udata32(ri_usage_max) : 0;
data->usage_is_range = (ri_usage_min != NULL) && (ri_usage_max != NULL);

return true;
}

void tuh_hid_process_simple_axis(
tuh_hid_simple_input_data_t* jdata,
uint32_t bitpos,
tusb_hid_simple_axis_t* simple_axis)
{
simple_axis->start = (uint16_t)bitpos;
simple_axis->length = (uint16_t)jdata->report_size;
simple_axis->flags.is_signed = jdata->logical_min < 0;
simple_axis->logical_min = jdata->logical_min;
simple_axis->logical_max = jdata->logical_max;
}
Loading