Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
90 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
a617645
Merge pull request #2 from fruit-bat/hid_micro_parser
fruit-bat Feb 23, 2022
d503ea4
fix build on 64bit compiler
fruit-bat Feb 26, 2022
535bba4
Merge pull request #3 from fruit-bat/hid_micro_parser
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
ec3279e
Merge pull request #5 from fruit-bat/hid_micro_parser
fruit-bat Mar 6, 2022
d0f3650
Fix for Wall Werror
fruit-bat Mar 9, 2022
09f0dac
Merge pull request #6 from fruit-bat/hid_micro_parser
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
d16feee
Merge pull request #7 from fruit-bat/hid_micro_parser
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
48d8629
Merge pull request #8 from fruit-bat/hid_micro_parser
fruit-bat Jul 17, 2022
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
3 changes: 3 additions & 0 deletions examples/host/cdc_msc_hid/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ add_executable(${PROJECT})
# Example source
target_sources(${PROJECT} PUBLIC
${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_joy.c
${CMAKE_CURRENT_SOURCE_DIR}/src/main.c
${CMAKE_CURRENT_SOURCE_DIR}/src/msc_app.c
)
Expand Down
2 changes: 2 additions & 0 deletions examples/host/cdc_msc_hid/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ CFLAGS += -Wno-error=cast-align -Wno-error=null-dereference
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 \
Expand Down
186 changes: 121 additions & 65 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.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_joysick_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_joysick_process_report(simple_joystick, report, report_length);
tusb_hid_print_simple_joysick_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 adn 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 @@ -232,65 +332,21 @@ 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;

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 arrray
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 the report info for this report !\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--;
}

info->handler(info, report, len, rpt_id);
}
95 changes: 95 additions & 0 deletions examples/host/cdc_msc_hid/src/hid_host_info.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
/*
* The MIT License (MIT)
*
* 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 "hid_host_info.h"

static tusb_hid_host_info_t hid_info[TUP_DCD_ENDPOINT_MAX];

tusb_hid_host_info_t* tuh_hid_get_info(uint8_t dev_addr, uint8_t instance)
{
tusb_hid_host_info_key_t key;
key.elements.dev_addr = dev_addr;
key.elements.instance = instance;
key.elements.in_use = 1;
uint32_t combined = key.combined;

// Linear search for endpoint, which is fine while TUP_DCD_ENDPOINT_MAX
// is small. Perhaps a 'bsearch' version should be used if TUP_DCD_ENDPOINT_MAX
// is large.
for(uint8_t i = 0; i < TUP_DCD_ENDPOINT_MAX; ++i) {
tusb_hid_host_info_t* info = &hid_info[i];
if (info->key.combined == combined) return info;
}
return NULL;
}

void tuh_hid_free_sinlge_info(tusb_hid_host_info_t* info)
{
if (info->key.elements.in_use && info->unmount != NULL) {
info->unmount(info);
}
info->key.elements.in_use = 0;
}

void tuh_hid_free_all_info(void)
{
for(uint8_t i = 0; i < TUP_DCD_ENDPOINT_MAX; ++i) {
tuh_hid_free_sinlge_info(&hid_info[i]);
}
}

void tuh_hid_free_info(uint8_t dev_addr, uint8_t instance)
{
for(uint8_t i = 0; i < TUP_DCD_ENDPOINT_MAX; ++i) {
tusb_hid_host_info_t* info = &hid_info[i];
if (info->key.elements.instance == instance && info->key.elements.dev_addr == dev_addr && info->key.elements.in_use) {
tuh_hid_free_sinlge_info(info);
}
}
}

tusb_hid_host_info_t* tuh_hid_allocate_info(
uint8_t dev_addr,
uint8_t instance,
bool has_report_id,
void (*handler)(struct tusb_hid_host_info* info, const uint8_t* report, uint8_t report_length, uint8_t report_id),
void (*unmount)(struct tusb_hid_host_info* info))
{
for(uint8_t i = 0; i < TUP_DCD_ENDPOINT_MAX; ++i) {
tusb_hid_host_info_t* info = &hid_info[i];
if (!info->key.elements.in_use) {
tu_memclr(info, sizeof(tusb_hid_host_info_t));
info->key.elements.in_use = true;
info->key.elements.dev_addr = dev_addr;
info->key.elements.instance = instance;
info->has_report_id = has_report_id;
info->handler = handler;
info->unmount = unmount;
return info;
}
}
TU_LOG1("FAILED TO ALLOCATE INFO for dev_addr=%d, instance=%d\r\n", dev_addr, instance);
return NULL;
}


Loading