From a387b46d3e9db3074ecad359621a19cafaba1407 Mon Sep 17 00:00:00 2001 From: Phil Date: Tue, 1 Feb 2022 21:08:23 +0000 Subject: [PATCH 01/71] HID micro parser --- hw/bsp/rp2040/family.cmake | 1 + src/class/hid/hid_ri.c | 101 ++++++++++++++++++++++++++++++ src/class/hid/hid_ri.h | 84 +++++++++++++++++++++++++ test/test/class/hid/test_hid_ri.c | 87 +++++++++++++++++++++++++ tools/iar_template.ipcf | 1 + 5 files changed, 274 insertions(+) create mode 100644 src/class/hid/hid_ri.c create mode 100644 src/class/hid/hid_ri.h create mode 100644 test/test/class/hid/test_hid_ri.c diff --git a/hw/bsp/rp2040/family.cmake b/hw/bsp/rp2040/family.cmake index 1aa180ef82..a587b1c441 100644 --- a/hw/bsp/rp2040/family.cmake +++ b/hw/bsp/rp2040/family.cmake @@ -86,6 +86,7 @@ if (NOT TARGET _rp2040_family_inclusion_marker) ${TOP}/src/host/usbh_control.c ${TOP}/src/host/hub.c ${TOP}/src/class/cdc/cdc_host.c + ${TOP}/src/class/hid/hid_ri.c ${TOP}/src/class/hid/hid_host.c ${TOP}/src/class/msc/msc_host.c ${TOP}/src/class/vendor/vendor_host.c diff --git a/src/class/hid/hid_ri.c b/src/class/hid/hid_ri.c new file mode 100644 index 0000000000..aae4af3843 --- /dev/null +++ b/src/class/hid/hid_ri.c @@ -0,0 +1,101 @@ +/* + * 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. + * + * This file is part of the TinyUSB stack. + */ + +#include "hid_ri.h" + +// #if (TUSB_OPT_HOST_ENABLED && CFG_TUH_HID) + +uint8_t hidri_short_data_length(uint8_t *ri) { + // 0 -> 0, 1 -> 1, 2 -> 2, 3 -> 4 + return (1 << (*ri & 3)) >> 1; +} + +uint8_t hidri_short_type(uint8_t *ri) { + return (*ri >> 2) & 3; +} + +uint8_t hidri_short_tag(uint8_t *ri) { + return (*ri >> 4) & 15; +} + +bool hidri_is_long(uint8_t *ri) { + return *ri == 0xfe; +} + +uint32_t hidri_short_udata32(uint8_t *ri) { + uint32_t d = 0; + uint8_t l = hidri_short_data_length(ri++); + for(uint8_t i = 0; i < l; ++i) d |= ((uint32_t)(*ri++)) << (i << 3); + return d; +} + +int32_t hidri_short_data32(uint8_t *ri) { + int32_t d = 0; + uint8_t l = hidri_short_data_length(ri++); + bool negative = false; + for(uint8_t i = 0; i < 4; ++i) { + if (i < l) { + uint32_t b = *ri++; + d |= b << (i << 3); + negative = ((b >> 7) == 1); + } + else if (negative) { + d |= 0xff << (i << 3); + } + } + return d; +} + +uint8_t hidri_long_data_length(uint8_t *ri) { + return ri[1]; +} + +uint8_t hidri_long_tag(uint8_t *ri) { + return ri[2]; +} + +uint8_t* hidri_long_item_data(uint8_t *ri) { + return ri + 2; +} + +int16_t hidri_size(uint8_t *ri, uint16_t l) { + // Make sure there is enough room for the header + if (l < 1) return -1; + // Calculate the short item length + uint16_t sl = 1 + hidri_short_data_length(ri); + // check it fits + if (l < sl) return -2; + // Check if we need to worry about a long item + if (hidri_is_long(ri)) { + uint16_t ll = hidri_long_data_length(ri); + uint16_t tl = sl + tl; + if (l < tl) return -3; + return tl; + } + else { + return sl; + } +} + +// #endif diff --git a/src/class/hid/hid_ri.h b/src/class/hid/hid_ri.h new file mode 100644 index 0000000000..85e8492e1e --- /dev/null +++ b/src/class/hid/hid_ri.h @@ -0,0 +1,84 @@ +/* + * 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. + * + * This file is part of the TinyUSB stack. + */ + +#ifndef _TUSB_HID_RI_H_ +#define _TUSB_HID_RI_H_ + +#include "tusb.h" + +#ifdef __cplusplus + extern "C" { +#endif + +//--------------------------------------------------------------------+ +// HID Report Description Item functions +// +// Implementation intended to minimise memory footprint, +// mildly at the expense of performance. +//--------------------------------------------------------------------+ + +// Get the length of a short item +uint8_t hidri_short_data_length(uint8_t *ri); + +// Get the type of a short item +uint8_t hidri_short_type(uint8_t *ri); + +// Get the tag from a short item +uint8_t hidri_short_tag(uint8_t *ri); + +// Test if the item is a long item +bool hidri_is_long(uint8_t *ri); + +// Get the short item data unsigned +uint32_t hidri_short_udata32(uint8_t *ri); + +// Get the short item data signed (with sign extend to uint32) +int32_t hidri_short_data32(uint8_t *ri); + +// Get the data length of a long item +uint8_t hidri_long_data_length(uint8_t *ri); + +// Get the tag from a long item +uint8_t hidri_long_tag(uint8_t *ri); + +// Get a pointer to the data in a long item +uint8_t* hidri_long_item_data(uint8_t *ri); + +// Get the size of the item in bytes +// +// Important: +// To prevent buffer overflow call this before accessing short/long data +// and check the return code for eof or error. +// +// return values: +// -1 -> eof, +// -2 -> missing short bytes, +// -3 -> missing long bytes +int16_t hidri_size(uint8_t *ri, uint16_t l); + +#ifdef __cplusplus +} +#endif + +#endif /* _TUSB_HID_HOST_H_ */ diff --git a/test/test/class/hid/test_hid_ri.c b/test/test/class/hid/test_hid_ri.c new file mode 100644 index 0000000000..1a559aa85d --- /dev/null +++ b/test/test/class/hid/test_hid_ri.c @@ -0,0 +1,87 @@ +/* + * 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. + * + * This file is part of the TinyUSB stack. + */ + + +#include "unity.h" + +// Files to test +#include "hid_ri.h" +TEST_FILE("hid_ri.c") + +void setUp(void) +{ +} + +void tearDown(void) +{ +} + +//--------------------------------------------------------------------+ +// Tests +//--------------------------------------------------------------------+ +void test_short_item_length(void) { + uint8_t tb[] = { 0x00, 0x01, 0x02, 0x03 }; + TEST_ASSERT_EQUAL(0, hidri_short_data_length(&tb[0])); + TEST_ASSERT_EQUAL(1, hidri_short_data_length(&tb[1])); + TEST_ASSERT_EQUAL(2, hidri_short_data_length(&tb[2])); + TEST_ASSERT_EQUAL(4, hidri_short_data_length(&tb[3])); +} + +void test_physical_max_315(void) +{ + uint8_t tb[] = { 0x46, 0x3B, 0x01 }; /* Physical Maximum (315) */ + + TEST_ASSERT_EQUAL( 2, hidri_short_data_length(tb) ); + TEST_ASSERT_EQUAL( 1, hidri_short_type(tb) ); + TEST_ASSERT_EQUAL( 4, hidri_short_tag(tb) ); + TEST_ASSERT_EQUAL( false, hidri_is_long(tb) ); + TEST_ASSERT_EQUAL( 315, hidri_short_udata32(tb) ); + TEST_ASSERT_EQUAL( 315, hidri_short_data32(tb) ); + TEST_ASSERT_EQUAL( 3, hidri_size(tb, 3) ); +} + +void test_logical_min_neg_127(void) +{ + uint8_t tb[] = { 0x15, 0x81 }; /* LOGICAL_MINIMUM (-127) */ + + TEST_ASSERT_EQUAL( 1, hidri_short_data_length(tb) ); + TEST_ASSERT_EQUAL( 1, hidri_short_type(tb) ); + TEST_ASSERT_EQUAL( 1, hidri_short_tag(tb) ); + TEST_ASSERT_EQUAL( false, hidri_is_long(tb) ); + TEST_ASSERT_EQUAL( 0x81, hidri_short_udata32(tb) ); + TEST_ASSERT_EQUAL( -127, hidri_short_data32(tb) ); + TEST_ASSERT_EQUAL( 2, hidri_size(tb, 2) ); +} + +void test_logical_min_neg_2147483648(void) +{ + uint8_t tb[] = { 0x17, 0x01, 0x00, 0x00, 0x80 }; // Logical Minimum (-2147483647) + + TEST_ASSERT_EQUAL( 4, hidri_short_data_length(tb) ); + TEST_ASSERT_EQUAL( 1, hidri_short_type(tb) ); + TEST_ASSERT_EQUAL( 1, hidri_short_tag(tb) ); + TEST_ASSERT_EQUAL( false, hidri_is_long(tb) ); + TEST_ASSERT_EQUAL( -2147483647, hidri_short_data32(tb) ); + TEST_ASSERT_EQUAL( 5, hidri_size(tb, 5) ); +} diff --git a/tools/iar_template.ipcf b/tools/iar_template.ipcf index ba54fe0578..e90e95c1e9 100644 --- a/tools/iar_template.ipcf +++ b/tools/iar_template.ipcf @@ -31,6 +31,7 @@ $TUSB_DIR$/src/class/hid/hid_device.c + $TUSB_DIR$/src/class/hid/hid_ri.c $TUSB_DIR$/src/class/hid/hid_host.c From ed80b26d6629921f2bae74c45d22ac7efa747fbb Mon Sep 17 00:00:00 2001 From: Phil Date: Tue, 1 Feb 2022 21:52:01 +0000 Subject: [PATCH 02/71] HID micro parser --- src/class/hid/hid_ri.c | 6 +-- test/test/class/hid/test_hid_ri.c | 76 +++++++++++++++++++++++-------- 2 files changed, 59 insertions(+), 23 deletions(-) diff --git a/src/class/hid/hid_ri.c b/src/class/hid/hid_ri.c index aae4af3843..6cb7a22c18 100644 --- a/src/class/hid/hid_ri.c +++ b/src/class/hid/hid_ri.c @@ -76,7 +76,7 @@ uint8_t hidri_long_tag(uint8_t *ri) { } uint8_t* hidri_long_item_data(uint8_t *ri) { - return ri + 2; + return ri + 3; } int16_t hidri_size(uint8_t *ri, uint16_t l) { @@ -88,8 +88,8 @@ int16_t hidri_size(uint8_t *ri, uint16_t l) { if (l < sl) return -2; // Check if we need to worry about a long item if (hidri_is_long(ri)) { - uint16_t ll = hidri_long_data_length(ri); - uint16_t tl = sl + tl; + uint16_t ll = hidri_long_data_length(ri); + uint16_t tl = sl + ll; if (l < tl) return -3; return tl; } diff --git a/test/test/class/hid/test_hid_ri.c b/test/test/class/hid/test_hid_ri.c index 1a559aa85d..eec3df7511 100644 --- a/test/test/class/hid/test_hid_ri.c +++ b/test/test/class/hid/test_hid_ri.c @@ -48,40 +48,76 @@ void test_short_item_length(void) { TEST_ASSERT_EQUAL(4, hidri_short_data_length(&tb[3])); } +void test_short_item_size_check(void) +{ + uint8_t tb[] = { 0x46, 0x3B, 0x01 }; /* Physical Maximum (315) */ + + TEST_ASSERT_EQUAL( 3, hidri_size(tb, 3)); + TEST_ASSERT_EQUAL(-2, hidri_size(tb, 2)); + TEST_ASSERT_EQUAL(-2, hidri_size(tb, 1)); + TEST_ASSERT_EQUAL(-1, hidri_size(tb, 0)); +} + +void test_long_item(void) { + uint8_t tb[] = { 0xfe, 0xff, 0x81, 0x01 }; + TEST_ASSERT_EQUAL(true, hidri_is_long(tb)); + TEST_ASSERT_EQUAL(2, hidri_short_data_length(tb)); + TEST_ASSERT_EQUAL(255, hidri_long_data_length(tb)); + TEST_ASSERT_EQUAL(0x81, hidri_long_tag(tb)); + TEST_ASSERT_EQUAL(1, hidri_long_item_data(tb)[0]); + TEST_ASSERT_EQUAL(3 + 255, hidri_size(tb, 3 + 255)); +} + void test_physical_max_315(void) { uint8_t tb[] = { 0x46, 0x3B, 0x01 }; /* Physical Maximum (315) */ - TEST_ASSERT_EQUAL( 2, hidri_short_data_length(tb) ); - TEST_ASSERT_EQUAL( 1, hidri_short_type(tb) ); - TEST_ASSERT_EQUAL( 4, hidri_short_tag(tb) ); - TEST_ASSERT_EQUAL( false, hidri_is_long(tb) ); - TEST_ASSERT_EQUAL( 315, hidri_short_udata32(tb) ); - TEST_ASSERT_EQUAL( 315, hidri_short_data32(tb) ); - TEST_ASSERT_EQUAL( 3, hidri_size(tb, 3) ); + TEST_ASSERT_EQUAL(2, hidri_short_data_length(tb)); + TEST_ASSERT_EQUAL(1, hidri_short_type(tb)); + TEST_ASSERT_EQUAL(4, hidri_short_tag(tb)); + TEST_ASSERT_EQUAL(false, hidri_is_long(tb)); + TEST_ASSERT_EQUAL(315, hidri_short_udata32(tb)); + TEST_ASSERT_EQUAL(315, hidri_short_data32(tb)); + TEST_ASSERT_EQUAL(3, hidri_size(tb, 3)); } void test_logical_min_neg_127(void) { uint8_t tb[] = { 0x15, 0x81 }; /* LOGICAL_MINIMUM (-127) */ - TEST_ASSERT_EQUAL( 1, hidri_short_data_length(tb) ); - TEST_ASSERT_EQUAL( 1, hidri_short_type(tb) ); - TEST_ASSERT_EQUAL( 1, hidri_short_tag(tb) ); - TEST_ASSERT_EQUAL( false, hidri_is_long(tb) ); - TEST_ASSERT_EQUAL( 0x81, hidri_short_udata32(tb) ); - TEST_ASSERT_EQUAL( -127, hidri_short_data32(tb) ); - TEST_ASSERT_EQUAL( 2, hidri_size(tb, 2) ); + TEST_ASSERT_EQUAL(1, hidri_short_data_length(tb)); + TEST_ASSERT_EQUAL(1, hidri_short_type(tb)); + TEST_ASSERT_EQUAL(1, hidri_short_tag(tb)); + TEST_ASSERT_EQUAL(false, hidri_is_long(tb)); + TEST_ASSERT_EQUAL(0x81, hidri_short_udata32(tb)); + TEST_ASSERT_EQUAL(-127, hidri_short_data32(tb)); + TEST_ASSERT_EQUAL(2, hidri_size(tb, 2)); +} + +void test_logical_min_neg_32768(void) +{ + uint8_t tb[] = { 0x16, 0x00, 0x80 }; // Logical Minimum (-32768) + + TEST_ASSERT_EQUAL(2, hidri_short_data_length(tb)); + TEST_ASSERT_EQUAL(1, hidri_short_type(tb)); + TEST_ASSERT_EQUAL(1, hidri_short_tag(tb)); + TEST_ASSERT_EQUAL(false, hidri_is_long(tb)); + TEST_ASSERT_EQUAL(-32768, hidri_short_data32(tb)); + TEST_ASSERT_EQUAL(3, hidri_size(tb, 3)); } void test_logical_min_neg_2147483648(void) { uint8_t tb[] = { 0x17, 0x01, 0x00, 0x00, 0x80 }; // Logical Minimum (-2147483647) - TEST_ASSERT_EQUAL( 4, hidri_short_data_length(tb) ); - TEST_ASSERT_EQUAL( 1, hidri_short_type(tb) ); - TEST_ASSERT_EQUAL( 1, hidri_short_tag(tb) ); - TEST_ASSERT_EQUAL( false, hidri_is_long(tb) ); - TEST_ASSERT_EQUAL( -2147483647, hidri_short_data32(tb) ); - TEST_ASSERT_EQUAL( 5, hidri_size(tb, 5) ); + TEST_ASSERT_EQUAL(4, hidri_short_data_length(tb)); + TEST_ASSERT_EQUAL(1, hidri_short_type(tb)); + TEST_ASSERT_EQUAL(1, hidri_short_tag(tb)); + TEST_ASSERT_EQUAL(false, hidri_is_long(tb)); + TEST_ASSERT_EQUAL(-2147483647, hidri_short_data32(tb)); + TEST_ASSERT_EQUAL(5, hidri_size(tb, 5)); } + + + + From b65f25785a420cbebefe27fdf722892b122a80a5 Mon Sep 17 00:00:00 2001 From: Phil Date: Tue, 1 Feb 2022 21:58:36 +0000 Subject: [PATCH 03/71] HID micro parser --- test/test/class/hid/test_hid_ri.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/test/test/class/hid/test_hid_ri.c b/test/test/class/hid/test_hid_ri.c index eec3df7511..185c3595b6 100644 --- a/test/test/class/hid/test_hid_ri.c +++ b/test/test/class/hid/test_hid_ri.c @@ -68,6 +68,16 @@ void test_long_item(void) { TEST_ASSERT_EQUAL(3 + 255, hidri_size(tb, 3 + 255)); } +void test_long_item_size_check(void) { + uint8_t tb[] = { 0xfe, 0xff, 0x81, 0x01 }; + TEST_ASSERT_EQUAL(3 + 255, hidri_size(tb, 3 + 255)); + TEST_ASSERT_EQUAL(-3, hidri_size(tb, 3 + 254)); + TEST_ASSERT_EQUAL(-3, hidri_size(tb, 3)); + TEST_ASSERT_EQUAL(-2, hidri_size(tb, 2)); + TEST_ASSERT_EQUAL(-2, hidri_size(tb, 1)); + TEST_ASSERT_EQUAL(-1, hidri_size(tb, 0)); +} + void test_physical_max_315(void) { uint8_t tb[] = { 0x46, 0x3B, 0x01 }; /* Physical Maximum (315) */ From b458edab90a061bead9c51ae46dc5ee6986e1eb5 Mon Sep 17 00:00:00 2001 From: Phil Date: Tue, 1 Feb 2022 22:00:06 +0000 Subject: [PATCH 04/71] HID micro parser --- test/test/class/hid/test_hid_ri.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/test/test/class/hid/test_hid_ri.c b/test/test/class/hid/test_hid_ri.c index 185c3595b6..6d7c592450 100644 --- a/test/test/class/hid/test_hid_ri.c +++ b/test/test/class/hid/test_hid_ri.c @@ -40,8 +40,10 @@ void tearDown(void) //--------------------------------------------------------------------+ // Tests //--------------------------------------------------------------------+ -void test_short_item_length(void) { +void test_short_item_length(void) +{ uint8_t tb[] = { 0x00, 0x01, 0x02, 0x03 }; + TEST_ASSERT_EQUAL(0, hidri_short_data_length(&tb[0])); TEST_ASSERT_EQUAL(1, hidri_short_data_length(&tb[1])); TEST_ASSERT_EQUAL(2, hidri_short_data_length(&tb[2])); @@ -58,8 +60,10 @@ void test_short_item_size_check(void) TEST_ASSERT_EQUAL(-1, hidri_size(tb, 0)); } -void test_long_item(void) { +void test_long_item(void) +{ uint8_t tb[] = { 0xfe, 0xff, 0x81, 0x01 }; + TEST_ASSERT_EQUAL(true, hidri_is_long(tb)); TEST_ASSERT_EQUAL(2, hidri_short_data_length(tb)); TEST_ASSERT_EQUAL(255, hidri_long_data_length(tb)); @@ -68,8 +72,10 @@ void test_long_item(void) { TEST_ASSERT_EQUAL(3 + 255, hidri_size(tb, 3 + 255)); } -void test_long_item_size_check(void) { +void test_long_item_size_check(void) +{ uint8_t tb[] = { 0xfe, 0xff, 0x81, 0x01 }; + TEST_ASSERT_EQUAL(3 + 255, hidri_size(tb, 3 + 255)); TEST_ASSERT_EQUAL(-3, hidri_size(tb, 3 + 254)); TEST_ASSERT_EQUAL(-3, hidri_size(tb, 3)); From 5f87607008ab5add907476b18b96e3cb6e9e070a Mon Sep 17 00:00:00 2001 From: Phil Date: Tue, 1 Feb 2022 22:04:54 +0000 Subject: [PATCH 05/71] HID micro parser --- test/test/class/hid/test_hid_ri.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/test/test/class/hid/test_hid_ri.c b/test/test/class/hid/test_hid_ri.c index 6d7c592450..82a32f5127 100644 --- a/test/test/class/hid/test_hid_ri.c +++ b/test/test/class/hid/test_hid_ri.c @@ -122,7 +122,9 @@ void test_logical_min_neg_32768(void) TEST_ASSERT_EQUAL(3, hidri_size(tb, 3)); } -void test_logical_min_neg_2147483648(void) +// https://eleccelerator.com/usbdescreqparser/ says this should be -2147483648, +// which I am pretty sure is wrong.. but worth noting in case problems arise later. +void test_logical_min_neg_2147483647(void) { uint8_t tb[] = { 0x17, 0x01, 0x00, 0x00, 0x80 }; // Logical Minimum (-2147483647) From 77c1ff8775d7ef56e48e859fa65fbbe2ab6e9c22 Mon Sep 17 00:00:00 2001 From: Phil Date: Wed, 2 Feb 2022 22:39:01 +0000 Subject: [PATCH 06/71] HID micro parser --- src/class/hid/hid_ri.c | 4 ++-- src/class/hid/hid_ri.h | 6 +++++ src/class/hid/hid_rip.c | 25 +++++++++++++++++++ src/class/hid/hid_rip.h | 53 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 86 insertions(+), 2 deletions(-) create mode 100644 src/class/hid/hid_rip.c create mode 100644 src/class/hid/hid_rip.h diff --git a/src/class/hid/hid_ri.c b/src/class/hid/hid_ri.c index 6cb7a22c18..c541fc77c6 100644 --- a/src/class/hid/hid_ri.c +++ b/src/class/hid/hid_ri.c @@ -24,7 +24,7 @@ #include "hid_ri.h" -// #if (TUSB_OPT_HOST_ENABLED && CFG_TUH_HID) +#if ((TUSB_OPT_HOST_ENABLED && CFG_TUH_HID) || _UNITY_TEST_) uint8_t hidri_short_data_length(uint8_t *ri) { // 0 -> 0, 1 -> 1, 2 -> 2, 3 -> 4 @@ -98,4 +98,4 @@ int16_t hidri_size(uint8_t *ri, uint16_t l) { } } -// #endif +#endif diff --git a/src/class/hid/hid_ri.h b/src/class/hid/hid_ri.h index 85e8492e1e..058f0b58f8 100644 --- a/src/class/hid/hid_ri.h +++ b/src/class/hid/hid_ri.h @@ -36,6 +36,12 @@ // // Implementation intended to minimise memory footprint, // mildly at the expense of performance. +// +// See: +// https://www.usb.org/sites/default/files/hid1_11.pdf +// https://eleccelerator.com/usbdescreqparser/ +// https://usb.org/sites/default/files/hut1_2.pdf +// https://eleccelerator.com/tutorial-about-usb-hid-report-descriptors/ //--------------------------------------------------------------------+ // Get the length of a short item diff --git a/src/class/hid/hid_rip.c b/src/class/hid/hid_rip.c new file mode 100644 index 0000000000..e9ba665243 --- /dev/null +++ b/src/class/hid/hid_rip.c @@ -0,0 +1,25 @@ +/* + * 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. + * + * This file is part of the TinyUSB stack. + */ + +#include "hid_rip.h" diff --git a/src/class/hid/hid_rip.h b/src/class/hid/hid_rip.h new file mode 100644 index 0000000000..a2878682d4 --- /dev/null +++ b/src/class/hid/hid_rip.h @@ -0,0 +1,53 @@ +/* + * 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. + * + * This file is part of the TinyUSB stack. + */ + +#ifndef _TUSB_HID_RIP_H_ +#define _TUSB_HID_RIP_H_ + +#include "tusb.h" +#include "hid_ri.h" + +#ifdef __cplusplus + extern "C" { +#endif + +//--------------------------------------------------------------------+ +// HID Report Description Parser functions +// +// Implementation intended to minimise memory footprint, +// mildly at the expense of performance. +// +// See: +// https://www.usb.org/sites/default/files/hid1_11.pdf +// https://eleccelerator.com/usbdescreqparser/ +// https://usb.org/sites/default/files/hut1_2.pdf +// https://eleccelerator.com/tutorial-about-usb-hid-report-descriptors/ +//--------------------------------------------------------------------+ + + + + + +#endif + From 448c4e231c459a22f632d3dc51ab3d19c46d64a3 Mon Sep 17 00:00:00 2001 From: Phil Date: Wed, 2 Feb 2022 22:58:26 +0000 Subject: [PATCH 07/71] HID micro parser --- hw/bsp/rp2040/family.cmake | 1 + src/class/hid/hid_rip.c | 10 ++++++ src/class/hid/hid_rip.h | 15 +++++++-- test/test/class/hid/test_hid_rip.c | 49 ++++++++++++++++++++++++++++++ tools/iar_template.ipcf | 1 + 5 files changed, 73 insertions(+), 3 deletions(-) create mode 100644 test/test/class/hid/test_hid_rip.c diff --git a/hw/bsp/rp2040/family.cmake b/hw/bsp/rp2040/family.cmake index a587b1c441..148143833c 100644 --- a/hw/bsp/rp2040/family.cmake +++ b/hw/bsp/rp2040/family.cmake @@ -87,6 +87,7 @@ if (NOT TARGET _rp2040_family_inclusion_marker) ${TOP}/src/host/hub.c ${TOP}/src/class/cdc/cdc_host.c ${TOP}/src/class/hid/hid_ri.c + ${TOP}/src/class/hid/hid_rip.c ${TOP}/src/class/hid/hid_host.c ${TOP}/src/class/msc/msc_host.c ${TOP}/src/class/vendor/vendor_host.c diff --git a/src/class/hid/hid_rip.c b/src/class/hid/hid_rip.c index e9ba665243..413b0c6bd5 100644 --- a/src/class/hid/hid_rip.c +++ b/src/class/hid/hid_rip.c @@ -23,3 +23,13 @@ */ #include "hid_rip.h" + +void hidrip_init_state(struct tuh_hid_rip_state *state) { + state->stack_index = 0; + state->usage_index = 0; + memset(&state->global_items, 0, sizeof(uint8_t *) * HID_REPORT_STACK_SIZE * 16); + memset(&state->local_items, 0, sizeof(uint8_t *) * 16); + memset(&state->usages, 0, sizeof(uint8_t *) * HID_REPORT_MAX_USAGES); +} + + diff --git a/src/class/hid/hid_rip.h b/src/class/hid/hid_rip.h index a2878682d4..b3f9335956 100644 --- a/src/class/hid/hid_rip.h +++ b/src/class/hid/hid_rip.h @@ -45,9 +45,18 @@ // https://eleccelerator.com/tutorial-about-usb-hid-report-descriptors/ //--------------------------------------------------------------------+ - - - +#define HID_REPORT_STACK_SIZE 10 +#define HID_REPORT_MAX_USAGES 20 + +struct tuh_hid_rip_state { + uint8_t stack_index; + uint8_t usage_index; + uint8_t *global_items[HID_REPORT_STACK_SIZE][16]; + uint8_t *local_items[16]; + uint8_t *usages[HID_REPORT_MAX_USAGES]; +}; + +void hidrip_init_state(struct tuh_hid_rip_state *state); #endif diff --git a/test/test/class/hid/test_hid_rip.c b/test/test/class/hid/test_hid_rip.c new file mode 100644 index 0000000000..1c13713a7b --- /dev/null +++ b/test/test/class/hid/test_hid_rip.c @@ -0,0 +1,49 @@ +/* + * 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. + * + * This file is part of the TinyUSB stack. + */ + + +#include "unity.h" + +// Files to test +#include "hid_rip.h" +TEST_FILE("hid_rip.c") + +void setUp(void) +{ +} + +void tearDown(void) +{ +} + +//--------------------------------------------------------------------+ +// Tests +//--------------------------------------------------------------------+ +void test_nothing(void) +{ + +} + + + diff --git a/tools/iar_template.ipcf b/tools/iar_template.ipcf index e90e95c1e9..fe836cc701 100644 --- a/tools/iar_template.ipcf +++ b/tools/iar_template.ipcf @@ -32,6 +32,7 @@ $TUSB_DIR$/src/class/hid/hid_device.c $TUSB_DIR$/src/class/hid/hid_ri.c + $TUSB_DIR$/src/class/hid/hid_rip.c $TUSB_DIR$/src/class/hid/hid_host.c From 911e872daad65391eeddb04594c62fb711205bb6 Mon Sep 17 00:00:00 2001 From: Phil Date: Thu, 3 Feb 2022 21:30:18 +0000 Subject: [PATCH 08/71] HID micro parser --- src/class/hid/hid_ri.c | 6 +-- src/class/hid/hid_ri.h | 6 +-- src/class/hid/hid_rip.c | 69 +++++++++++++++++++++++++++--- src/class/hid/hid_rip.h | 14 +++--- test/test/class/hid/test_hid_ri.c | 16 +++---- test/test/class/hid/test_hid_rip.c | 1 + 6 files changed, 86 insertions(+), 26 deletions(-) diff --git a/src/class/hid/hid_ri.c b/src/class/hid/hid_ri.c index c541fc77c6..f03e3fb931 100644 --- a/src/class/hid/hid_ri.c +++ b/src/class/hid/hid_ri.c @@ -81,16 +81,16 @@ uint8_t* hidri_long_item_data(uint8_t *ri) { int16_t hidri_size(uint8_t *ri, uint16_t l) { // Make sure there is enough room for the header - if (l < 1) return -1; + if (l < 1) return 0; // Calculate the short item length uint16_t sl = 1 + hidri_short_data_length(ri); // check it fits - if (l < sl) return -2; + if (l < sl) return -1; // Check if we need to worry about a long item if (hidri_is_long(ri)) { uint16_t ll = hidri_long_data_length(ri); uint16_t tl = sl + ll; - if (l < tl) return -3; + if (l < tl) return -2; return tl; } else { diff --git a/src/class/hid/hid_ri.h b/src/class/hid/hid_ri.h index 058f0b58f8..e427ca17b0 100644 --- a/src/class/hid/hid_ri.h +++ b/src/class/hid/hid_ri.h @@ -78,9 +78,9 @@ uint8_t* hidri_long_item_data(uint8_t *ri); // and check the return code for eof or error. // // return values: -// -1 -> eof, -// -2 -> missing short bytes, -// -3 -> missing long bytes +// 0 -> eof, +// -1 -> missing short bytes, +// -2 -> missing long bytes int16_t hidri_size(uint8_t *ri, uint16_t l); #ifdef __cplusplus diff --git a/src/class/hid/hid_rip.c b/src/class/hid/hid_rip.c index 413b0c6bd5..7da2ec38ee 100644 --- a/src/class/hid/hid_rip.c +++ b/src/class/hid/hid_rip.c @@ -23,13 +23,72 @@ */ #include "hid_rip.h" +#include "hid.h" -void hidrip_init_state(struct tuh_hid_rip_state *state) { +void hidrip_init_state(tuh_hid_rip_state_t *state) { state->stack_index = 0; - state->usage_index = 0; - memset(&state->global_items, 0, sizeof(uint8_t *) * HID_REPORT_STACK_SIZE * 16); - memset(&state->local_items, 0, sizeof(uint8_t *) * 16); - memset(&state->usages, 0, sizeof(uint8_t *) * HID_REPORT_MAX_USAGES); + state->usage_count = 0; + memset(&state->global_items, 0, sizeof(uint8_t*) * HID_REPORT_STACK_SIZE * 16); + memset(&state->local_items, 0, sizeof(uint8_t*) * 16); + memset(&state->usages, 0, sizeof(uint32_t) * HID_REPORT_MAX_USAGES); +} + +int16_t hidrip_parse_item(tuh_hid_rip_state_t *state, uint8_t *ri, uint16_t length) { + int16_t il = hidri_size(ri, length); + if (il > 0) { + if (hidri_is_long(ri)) { + // For now just don't do anything with long items. + } + else { + uint8_t short_type = hidri_short_type(ri); + uint8_t short_tag = hidri_short_tag(ri); + switch (short_type) { + case RI_TYPE_GLOBAL: + state->global_items[state->stack_index][short_tag] = ri; + switch (short_tag) { + case RI_GLOBAL_PUSH: + if (++state->stack_index == HID_REPORT_STACK_SIZE) return -1; // TODO enum? Stack overflow + memcpy(&state->global_items[state->stack_index], &state->global_items[state->stack_index - 1], sizeof(uint8_t*) * 16); + break; + case RI_GLOBAL_POP: + if (state->stack_index-- == 0) return -2; // TODO enum? Stack underflow + break; + default: + break; + } + break; + case RI_TYPE_LOCAL: + switch(short_tag) { + case RI_LOCAL_USAGE: { + uint32_t usage = hidri_short_udata32(ri); + if (hidri_short_data_length(ri) <= 2) { + uint8_t* usage_page_item = state->global_items[state->stack_index][RI_GLOBAL_USAGE_PAGE]; + uint32_t usage_page = usage_page_item ? hidri_short_udata32(usage_page_item) : 0; + usage |= usage_page << 16; + } + if (state->usage_count == HID_REPORT_MAX_USAGES) return -3; // TODO enum? Max usages overflow + state->usages[state->usage_count++] = usage; + break; + } + default: + state->local_items[short_tag] = ri; + break; + } + break; + case RI_TYPE_MAIN: + // Hmmm ??!? + // TODO handle the main item + // ...then clear down local state... maybe not here! + memset(&state->local_items, 0, sizeof(uint8_t*) * 16); + state->usage_count = 0; + break; + + default: + break; + } + } + } + return il; } diff --git a/src/class/hid/hid_rip.h b/src/class/hid/hid_rip.h index b3f9335956..96012a82c4 100644 --- a/src/class/hid/hid_rip.h +++ b/src/class/hid/hid_rip.h @@ -48,15 +48,15 @@ #define HID_REPORT_STACK_SIZE 10 #define HID_REPORT_MAX_USAGES 20 -struct tuh_hid_rip_state { +typedef struct tuh_hid_rip_state { uint8_t stack_index; - uint8_t usage_index; - uint8_t *global_items[HID_REPORT_STACK_SIZE][16]; - uint8_t *local_items[16]; - uint8_t *usages[HID_REPORT_MAX_USAGES]; -}; + uint8_t usage_count; + uint8_t* global_items[HID_REPORT_STACK_SIZE][16]; + uint8_t* local_items[16]; + uint32_t usages[HID_REPORT_MAX_USAGES]; +} tuh_hid_rip_state_t; -void hidrip_init_state(struct tuh_hid_rip_state *state); +void hidrip_init_state(tuh_hid_rip_state_t *state); #endif diff --git a/test/test/class/hid/test_hid_ri.c b/test/test/class/hid/test_hid_ri.c index 82a32f5127..c850350c59 100644 --- a/test/test/class/hid/test_hid_ri.c +++ b/test/test/class/hid/test_hid_ri.c @@ -55,9 +55,9 @@ void test_short_item_size_check(void) uint8_t tb[] = { 0x46, 0x3B, 0x01 }; /* Physical Maximum (315) */ TEST_ASSERT_EQUAL( 3, hidri_size(tb, 3)); - TEST_ASSERT_EQUAL(-2, hidri_size(tb, 2)); - TEST_ASSERT_EQUAL(-2, hidri_size(tb, 1)); - TEST_ASSERT_EQUAL(-1, hidri_size(tb, 0)); + TEST_ASSERT_EQUAL(-1, hidri_size(tb, 2)); + TEST_ASSERT_EQUAL(-1, hidri_size(tb, 1)); + TEST_ASSERT_EQUAL( 0, hidri_size(tb, 0)); } void test_long_item(void) @@ -77,11 +77,11 @@ void test_long_item_size_check(void) uint8_t tb[] = { 0xfe, 0xff, 0x81, 0x01 }; TEST_ASSERT_EQUAL(3 + 255, hidri_size(tb, 3 + 255)); - TEST_ASSERT_EQUAL(-3, hidri_size(tb, 3 + 254)); - TEST_ASSERT_EQUAL(-3, hidri_size(tb, 3)); - TEST_ASSERT_EQUAL(-2, hidri_size(tb, 2)); - TEST_ASSERT_EQUAL(-2, hidri_size(tb, 1)); - TEST_ASSERT_EQUAL(-1, hidri_size(tb, 0)); + TEST_ASSERT_EQUAL(-2, hidri_size(tb, 3 + 254)); + TEST_ASSERT_EQUAL(-2, hidri_size(tb, 3)); + TEST_ASSERT_EQUAL(-1, hidri_size(tb, 2)); + TEST_ASSERT_EQUAL(-1, hidri_size(tb, 1)); + TEST_ASSERT_EQUAL( 0, hidri_size(tb, 0)); } void test_physical_max_315(void) diff --git a/test/test/class/hid/test_hid_rip.c b/test/test/class/hid/test_hid_rip.c index 1c13713a7b..3108c80887 100644 --- a/test/test/class/hid/test_hid_rip.c +++ b/test/test/class/hid/test_hid_rip.c @@ -27,6 +27,7 @@ // Files to test #include "hid_rip.h" +TEST_FILE("hid_ri.c") TEST_FILE("hid_rip.c") void setUp(void) From ab0a5d88e43102662b26b9ead0b0b21ffe5ca66c Mon Sep 17 00:00:00 2001 From: Phil Date: Thu, 3 Feb 2022 21:34:10 +0000 Subject: [PATCH 09/71] HID micro parser --- src/class/hid/hid_rip.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/class/hid/hid_rip.c b/src/class/hid/hid_rip.c index 7da2ec38ee..6526c7352e 100644 --- a/src/class/hid/hid_rip.c +++ b/src/class/hid/hid_rip.c @@ -35,11 +35,7 @@ void hidrip_init_state(tuh_hid_rip_state_t *state) { int16_t hidrip_parse_item(tuh_hid_rip_state_t *state, uint8_t *ri, uint16_t length) { int16_t il = hidri_size(ri, length); - if (il > 0) { - if (hidri_is_long(ri)) { - // For now just don't do anything with long items. - } - else { + if (il > 0 && !hidri_is_long(ri)) { // For now ignore long items. uint8_t short_type = hidri_short_type(ri); uint8_t short_tag = hidri_short_tag(ri); switch (short_type) { From 3a87bca2a7abdeef85655d59cc9f6df6557fd49b Mon Sep 17 00:00:00 2001 From: Phil Date: Thu, 3 Feb 2022 21:49:07 +0000 Subject: [PATCH 10/71] HID micro parser --- src/class/hid/hid_rip.c | 103 ++++++++++++++++++++++------------------ src/class/hid/hid_rip.h | 3 ++ 2 files changed, 61 insertions(+), 45 deletions(-) diff --git a/src/class/hid/hid_rip.c b/src/class/hid/hid_rip.c index 6526c7352e..f58210b055 100644 --- a/src/class/hid/hid_rip.c +++ b/src/class/hid/hid_rip.c @@ -28,60 +28,73 @@ void hidrip_init_state(tuh_hid_rip_state_t *state) { state->stack_index = 0; state->usage_count = 0; + state->collections_count = 0; memset(&state->global_items, 0, sizeof(uint8_t*) * HID_REPORT_STACK_SIZE * 16); memset(&state->local_items, 0, sizeof(uint8_t*) * 16); - memset(&state->usages, 0, sizeof(uint32_t) * HID_REPORT_MAX_USAGES); } int16_t hidrip_parse_item(tuh_hid_rip_state_t *state, uint8_t *ri, uint16_t length) { int16_t il = hidri_size(ri, length); if (il > 0 && !hidri_is_long(ri)) { // For now ignore long items. - uint8_t short_type = hidri_short_type(ri); - uint8_t short_tag = hidri_short_tag(ri); - switch (short_type) { - case RI_TYPE_GLOBAL: - state->global_items[state->stack_index][short_tag] = ri; - switch (short_tag) { - case RI_GLOBAL_PUSH: - if (++state->stack_index == HID_REPORT_STACK_SIZE) return -1; // TODO enum? Stack overflow - memcpy(&state->global_items[state->stack_index], &state->global_items[state->stack_index - 1], sizeof(uint8_t*) * 16); - break; - case RI_GLOBAL_POP: - if (state->stack_index-- == 0) return -2; // TODO enum? Stack underflow - break; - default: - break; - } - break; - case RI_TYPE_LOCAL: - switch(short_tag) { - case RI_LOCAL_USAGE: { - uint32_t usage = hidri_short_udata32(ri); - if (hidri_short_data_length(ri) <= 2) { - uint8_t* usage_page_item = state->global_items[state->stack_index][RI_GLOBAL_USAGE_PAGE]; - uint32_t usage_page = usage_page_item ? hidri_short_udata32(usage_page_item) : 0; - usage |= usage_page << 16; - } - if (state->usage_count == HID_REPORT_MAX_USAGES) return -3; // TODO enum? Max usages overflow - state->usages[state->usage_count++] = usage; - break; + uint8_t short_type = hidri_short_type(ri); + uint8_t short_tag = hidri_short_tag(ri); + switch (short_type) { + case RI_TYPE_GLOBAL: + state->global_items[state->stack_index][short_tag] = ri; + switch (short_tag) { + case RI_GLOBAL_PUSH: + if (++state->stack_index == HID_REPORT_STACK_SIZE) return -1; // TODO enum? Stack overflow + memcpy(&state->global_items[state->stack_index], &state->global_items[state->stack_index - 1], sizeof(uint8_t*) * 16); + break; + case RI_GLOBAL_POP: + if (state->stack_index-- == 0) return -2; // TODO enum? Stack underflow + break; + default: + break; + } + break; + case RI_TYPE_LOCAL: + switch(short_tag) { + case RI_LOCAL_USAGE: { + uint32_t usage = hidri_short_udata32(ri); + if (hidri_short_data_length(ri) <= 2) { + uint8_t* usage_page_item = state->global_items[state->stack_index][RI_GLOBAL_USAGE_PAGE]; + uint32_t usage_page = usage_page_item ? hidri_short_udata32(usage_page_item) : 0; + usage |= usage_page << 16; } - default: - state->local_items[short_tag] = ri; - break; + if (state->usage_count == HID_REPORT_MAX_USAGES) return -3; // TODO enum? Max usages overflow + state->usages[state->usage_count++] = usage; + break; + } + default: + state->local_items[short_tag] = ri; + break; + } + break; + case RI_TYPE_MAIN: + // Hmmm ??!? + // TODO handle the main item + // ...then clear down local state... maybe not here! + + switch(short_tag) { + case RI_MAIN_COLLECTION: { + if (state->collections_count == HID_REPORT_MAX_COLLECTION_DEPTH) return -4; // TODO enum? Max collections overflow + state->collections[state->collections_count++] = ri; + break; } - break; - case RI_TYPE_MAIN: - // Hmmm ??!? - // TODO handle the main item - // ...then clear down local state... maybe not here! - memset(&state->local_items, 0, sizeof(uint8_t*) * 16); - state->usage_count = 0; - break; - - default: - break; - } + case RI_MAIN_COLLECTION_END: + if (state->collections_count-- == 0) return -5; // TODO enum? Max collections underflow + break; + default: + break; + } + + memset(&state->local_items, 0, sizeof(uint8_t*) * 16); + state->usage_count = 0; + break; + + default: + break; } } return il; diff --git a/src/class/hid/hid_rip.h b/src/class/hid/hid_rip.h index 96012a82c4..3146b158fd 100644 --- a/src/class/hid/hid_rip.h +++ b/src/class/hid/hid_rip.h @@ -47,12 +47,15 @@ #define HID_REPORT_STACK_SIZE 10 #define HID_REPORT_MAX_USAGES 20 +#define HID_REPORT_MAX_COLLECTION_DEPTH 20 typedef struct tuh_hid_rip_state { uint8_t stack_index; uint8_t usage_count; + uint8_t collections_count; uint8_t* global_items[HID_REPORT_STACK_SIZE][16]; uint8_t* local_items[16]; + uint8_t* collections[HID_REPORT_MAX_COLLECTION_DEPTH]; uint32_t usages[HID_REPORT_MAX_USAGES]; } tuh_hid_rip_state_t; From 31acb25dfdf68aeeca51e87487a517f74930c629 Mon Sep 17 00:00:00 2001 From: Phil Date: Fri, 4 Feb 2022 18:34:36 +0000 Subject: [PATCH 11/71] HID micro parser --- src/class/hid/hid_rip.c | 41 +++++++++++++++++++++++++++++------------ src/class/hid/hid_rip.h | 5 ++++- 2 files changed, 33 insertions(+), 13 deletions(-) diff --git a/src/class/hid/hid_rip.c b/src/class/hid/hid_rip.c index f58210b055..b434ed441f 100644 --- a/src/class/hid/hid_rip.c +++ b/src/class/hid/hid_rip.c @@ -25,7 +25,10 @@ #include "hid_rip.h" #include "hid.h" -void hidrip_init_state(tuh_hid_rip_state_t *state) { +void hidrip_init_state(tuh_hid_rip_state_t *state, uint8_t *report, uint16_t length) { + state->cursor = report; + state->length = length; + state->item_length = 0; state->stack_index = 0; state->usage_count = 0; state->collections_count = 0; @@ -33,8 +36,29 @@ void hidrip_init_state(tuh_hid_rip_state_t *state) { memset(&state->local_items, 0, sizeof(uint8_t*) * 16); } -int16_t hidrip_parse_item(tuh_hid_rip_state_t *state, uint8_t *ri, uint16_t length) { - int16_t il = hidri_size(ri, length); +int16_t hidrip_parse_item(tuh_hid_rip_state_t *state) { + + + uint8_t *ri = state->cursor; + int16_t il = state->item_length; + // Exit early if there has been an error + // TODO Think - error vs eof + if (il < 0) return il; + + if (il > 0 && hidri_short_type(ri) == RI_TYPE_MAIN) { + // Clear down local state after a main item + memset(&state->local_items, 0, sizeof(uint8_t*) * 16); + state->usage_count = 0; + } + + // Advance to the next report item + ri += il; + state->cursor = ri; + state->length -= il; + il = hidri_size(ri, state->length); + state->item_length = il; + + // Check the report item is valid if (il > 0 && !hidri_is_long(ri)) { // For now ignore long items. uint8_t short_type = hidri_short_type(ri); uint8_t short_tag = hidri_short_tag(ri); @@ -71,11 +95,7 @@ int16_t hidrip_parse_item(tuh_hid_rip_state_t *state, uint8_t *ri, uint16_t leng break; } break; - case RI_TYPE_MAIN: - // Hmmm ??!? - // TODO handle the main item - // ...then clear down local state... maybe not here! - + case RI_TYPE_MAIN: { switch(short_tag) { case RI_MAIN_COLLECTION: { if (state->collections_count == HID_REPORT_MAX_COLLECTION_DEPTH) return -4; // TODO enum? Max collections overflow @@ -88,11 +108,8 @@ int16_t hidrip_parse_item(tuh_hid_rip_state_t *state, uint8_t *ri, uint16_t leng default: break; } - - memset(&state->local_items, 0, sizeof(uint8_t*) * 16); - state->usage_count = 0; break; - + } default: break; } diff --git a/src/class/hid/hid_rip.h b/src/class/hid/hid_rip.h index 3146b158fd..eff2e706c2 100644 --- a/src/class/hid/hid_rip.h +++ b/src/class/hid/hid_rip.h @@ -50,6 +50,9 @@ #define HID_REPORT_MAX_COLLECTION_DEPTH 20 typedef struct tuh_hid_rip_state { + uint8_t* cursor; + uint16_t length; + int16_t item_length; uint8_t stack_index; uint8_t usage_count; uint8_t collections_count; @@ -59,7 +62,7 @@ typedef struct tuh_hid_rip_state { uint32_t usages[HID_REPORT_MAX_USAGES]; } tuh_hid_rip_state_t; -void hidrip_init_state(tuh_hid_rip_state_t *state); +void hidrip_init_state(tuh_hid_rip_state_t *state, uint8_t *report, uint16_t length); #endif From e14e98866eeed0cf1016bc3399f836789ae65732 Mon Sep 17 00:00:00 2001 From: Phil Date: Fri, 4 Feb 2022 21:53:13 +0000 Subject: [PATCH 12/71] HID micro parser --- src/class/hid/hid_rip.c | 19 ++++++++++--------- src/class/hid/hid_rip.h | 1 + test/test/class/hid/test_hid_rip.c | 22 ++++++++++++++++++++-- 3 files changed, 31 insertions(+), 11 deletions(-) diff --git a/src/class/hid/hid_rip.c b/src/class/hid/hid_rip.c index b434ed441f..1ee0114e3c 100644 --- a/src/class/hid/hid_rip.c +++ b/src/class/hid/hid_rip.c @@ -25,7 +25,8 @@ #include "hid_rip.h" #include "hid.h" -void hidrip_init_state(tuh_hid_rip_state_t *state, uint8_t *report, uint16_t length) { +void hidrip_init_state(tuh_hid_rip_state_t *state, uint8_t *report, uint16_t length) +{ state->cursor = report; state->length = length; state->item_length = 0; @@ -36,13 +37,13 @@ void hidrip_init_state(tuh_hid_rip_state_t *state, uint8_t *report, uint16_t len memset(&state->local_items, 0, sizeof(uint8_t*) * 16); } -int16_t hidrip_parse_item(tuh_hid_rip_state_t *state) { - - +int16_t hidrip_next_item(tuh_hid_rip_state_t *state) +{ + if (state->length == 0) return 0; + uint8_t *ri = state->cursor; int16_t il = state->item_length; - // Exit early if there has been an error - // TODO Think - error vs eof + if (il < 0) return il; if (il > 0 && hidri_short_type(ri) == RI_TYPE_MAIN) { @@ -55,10 +56,10 @@ int16_t hidrip_parse_item(tuh_hid_rip_state_t *state) { ri += il; state->cursor = ri; state->length -= il; - il = hidri_size(ri, state->length); - state->item_length = il; - + // Check the report item is valid + state->item_length = il = hidri_size(ri, state->length); + if (il > 0 && !hidri_is_long(ri)) { // For now ignore long items. uint8_t short_type = hidri_short_type(ri); uint8_t short_tag = hidri_short_tag(ri); diff --git a/src/class/hid/hid_rip.h b/src/class/hid/hid_rip.h index eff2e706c2..67d8a40fb6 100644 --- a/src/class/hid/hid_rip.h +++ b/src/class/hid/hid_rip.h @@ -63,6 +63,7 @@ typedef struct tuh_hid_rip_state { } tuh_hid_rip_state_t; void hidrip_init_state(tuh_hid_rip_state_t *state, uint8_t *report, uint16_t length); +int16_t hidrip_next_item(tuh_hid_rip_state_t *state); #endif diff --git a/test/test/class/hid/test_hid_rip.c b/test/test/class/hid/test_hid_rip.c index 3108c80887..c1a019b96e 100644 --- a/test/test/class/hid/test_hid_rip.c +++ b/test/test/class/hid/test_hid_rip.c @@ -41,9 +41,27 @@ void tearDown(void) //--------------------------------------------------------------------+ // Tests //--------------------------------------------------------------------+ -void test_nothing(void) +void test_next_simple(void) { - + uint8_t tb[] = { + 0x05, 0x01, // Usage Page (Generic Desktop Ctrls) + 0x09, 0x02, // Usage (Mouse) + 0xA1, 0x01, // Collection (Application) + }; + + tuh_hid_rip_state_t pstate; + hidrip_init_state(&pstate, (uint8_t*)&tb, sizeof(tb)); + TEST_ASSERT_EQUAL(2, hidrip_next_item(&pstate)); + TEST_ASSERT_EQUAL(2, pstate.item_length); + TEST_ASSERT_EQUAL(0x05, *pstate.cursor); + TEST_ASSERT_EQUAL(2, hidrip_next_item(&pstate)); + TEST_ASSERT_EQUAL(2, pstate.item_length); + TEST_ASSERT_EQUAL(0x09, *pstate.cursor); + TEST_ASSERT_EQUAL(2, hidrip_next_item(&pstate)); + TEST_ASSERT_EQUAL(2, pstate.item_length); + TEST_ASSERT_EQUAL(0xA1, *pstate.cursor); + TEST_ASSERT_EQUAL(0, hidrip_next_item(&pstate)); + TEST_ASSERT_EQUAL(0, pstate.item_length); } From 692708f0cc48a6fb5b80bad95d15b3a9f2653ac9 Mon Sep 17 00:00:00 2001 From: Phil Date: Fri, 4 Feb 2022 22:06:12 +0000 Subject: [PATCH 13/71] HID micro parser --- test/test/class/hid/test_hid_rip.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/test/test/class/hid/test_hid_rip.c b/test/test/class/hid/test_hid_rip.c index c1a019b96e..d37c15d927 100644 --- a/test/test/class/hid/test_hid_rip.c +++ b/test/test/class/hid/test_hid_rip.c @@ -64,5 +64,20 @@ void test_next_simple(void) TEST_ASSERT_EQUAL(0, pstate.item_length); } - +void test_usage_with_page(void) +{ + uint8_t tb[] = { + 0x05, 0x01, // Usage Page (Generic Desktop Ctrls) + 0x09, 0x02, // Usage (Mouse) + }; + + tuh_hid_rip_state_t pstate; + hidrip_init_state(&pstate, (uint8_t*)&tb, sizeof(tb)); + TEST_ASSERT_EQUAL(2, hidrip_next_item(&pstate)); + TEST_ASSERT_EQUAL(0x01, hidri_short_udata32(pstate.cursor)); + TEST_ASSERT_EQUAL(2, hidrip_next_item(&pstate)); + TEST_ASSERT_EQUAL(1, pstate.usage_count); + TEST_ASSERT_EQUAL(0x02, hidri_short_udata32(pstate.cursor)); + TEST_ASSERT_EQUAL(0x00010002, pstate.usages[0]); +} From 388dc9b93ead5880b6f6ccf03c71aa058d9fb577 Mon Sep 17 00:00:00 2001 From: Phil Date: Fri, 4 Feb 2022 22:28:10 +0000 Subject: [PATCH 14/71] HID micro parser --- test/test/class/hid/test_hid_rip.c | 38 ++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/test/test/class/hid/test_hid_rip.c b/test/test/class/hid/test_hid_rip.c index d37c15d927..7b3dedc982 100644 --- a/test/test/class/hid/test_hid_rip.c +++ b/test/test/class/hid/test_hid_rip.c @@ -81,3 +81,41 @@ void test_usage_with_page(void) TEST_ASSERT_EQUAL(0x00010002, pstate.usages[0]); } +void test_globals_recorded(void) +{ + uint8_t tb[] = { + 0x05, 0x01, // Usage Page (Generic Desktop Ctrls) + 0x15, 0x55, // Logical Minimum 55 + }; + + tuh_hid_rip_state_t pstate; + hidrip_init_state(&pstate, (uint8_t*)&tb, sizeof(tb)); + TEST_ASSERT_EQUAL(2, hidrip_next_item(&pstate)); + TEST_ASSERT_EQUAL(2, hidrip_next_item(&pstate)); + TEST_ASSERT_EQUAL(0, pstate.stack_index); + TEST_ASSERT_EQUAL(0x01, hidri_short_udata32(pstate.global_items[pstate.stack_index][0])); + TEST_ASSERT_EQUAL(0x55, hidri_short_data32(pstate.global_items[pstate.stack_index][1])); +} + +void test_main_clears_local(void) +{ + uint8_t tb[] = { + 0x05, 0x01, // Usage Page (Generic Desktop Ctrls) + 0x09, 0x02, // Usage (Mouse) + 0x39, 0x04, // Designator Index 4 + 0xA1, 0x01, // Collection (Application) + 0x75, 0x05, // REPORT_SIZE (5) + }; + + tuh_hid_rip_state_t pstate; + hidrip_init_state(&pstate, (uint8_t*)&tb, sizeof(tb)); + TEST_ASSERT_EQUAL(2, hidrip_next_item(&pstate)); + TEST_ASSERT_EQUAL(2, hidrip_next_item(&pstate)); + TEST_ASSERT_EQUAL(2, hidrip_next_item(&pstate)); + TEST_ASSERT_EQUAL(2, hidrip_next_item(&pstate)); + TEST_ASSERT_EQUAL(1, pstate.usage_count); + TEST_ASSERT_EQUAL(4, hidri_short_data32(pstate.global_items[pstate.stack_index][3])); + TEST_ASSERT_EQUAL(2, hidrip_next_item(&pstate)); + TEST_ASSERT_EQUAL(0, pstate.global_items[pstate.stack_index][3]); + TEST_ASSERT_EQUAL(0, pstate.usage_count); +} From a95a41076655f73283f037013b59c8b04a632e9d Mon Sep 17 00:00:00 2001 From: Phil Date: Fri, 4 Feb 2022 22:41:25 +0000 Subject: [PATCH 15/71] HID micro parser --- test/test/class/hid/test_hid_rip.c | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/test/test/class/hid/test_hid_rip.c b/test/test/class/hid/test_hid_rip.c index 7b3dedc982..a644ba2744 100644 --- a/test/test/class/hid/test_hid_rip.c +++ b/test/test/class/hid/test_hid_rip.c @@ -114,8 +114,33 @@ void test_main_clears_local(void) TEST_ASSERT_EQUAL(2, hidrip_next_item(&pstate)); TEST_ASSERT_EQUAL(2, hidrip_next_item(&pstate)); TEST_ASSERT_EQUAL(1, pstate.usage_count); - TEST_ASSERT_EQUAL(4, hidri_short_data32(pstate.global_items[pstate.stack_index][3])); + TEST_ASSERT_EQUAL(&tb[4], pstate.local_items[3]); + TEST_ASSERT_EQUAL(4, hidri_short_data32(pstate.local_items[3])); TEST_ASSERT_EQUAL(2, hidrip_next_item(&pstate)); TEST_ASSERT_EQUAL(0, pstate.global_items[pstate.stack_index][3]); TEST_ASSERT_EQUAL(0, pstate.usage_count); } + +void test_collections(void) +{ + uint8_t tb[] = { + 0xA1, 0x01, // Collection (Application) + 0xA1, 0x00, // Collection (Physical) + 0xC0, // End Collection + 0xC0, // End Collection + }; + + tuh_hid_rip_state_t pstate; + hidrip_init_state(&pstate, (uint8_t*)&tb, sizeof(tb)); + TEST_ASSERT_EQUAL(2, hidrip_next_item(&pstate)); + TEST_ASSERT_EQUAL(1, pstate.collections_count); + TEST_ASSERT_EQUAL(2, hidrip_next_item(&pstate)); + TEST_ASSERT_EQUAL(2, pstate.collections_count); + TEST_ASSERT_EQUAL(&tb[0], pstate.collections[0]); + TEST_ASSERT_EQUAL(&tb[2], pstate.collections[1]); + TEST_ASSERT_EQUAL(1, hidrip_next_item(&pstate)); + TEST_ASSERT_EQUAL(1, pstate.collections_count); + TEST_ASSERT_EQUAL(1, hidrip_next_item(&pstate)); + TEST_ASSERT_EQUAL(0, pstate.collections_count); +} + From 27013e9a27a1ce7bf75cb9af515c515977cdfff1 Mon Sep 17 00:00:00 2001 From: Phil Date: Sat, 5 Feb 2022 08:51:14 +0000 Subject: [PATCH 16/71] HID micro parser --- src/class/hid/hid_ri.c | 20 +++++++++--------- src/class/hid/hid_ri.h | 20 +++++++++--------- src/class/hid/hid_rip.c | 35 +++++++++++++++++++++++++++++--- src/class/hid/hid_rip.h | 45 ++++++++++++++++++++++++++++++++++++----- 4 files changed, 92 insertions(+), 28 deletions(-) diff --git a/src/class/hid/hid_ri.c b/src/class/hid/hid_ri.c index f03e3fb931..a3fb37a9ab 100644 --- a/src/class/hid/hid_ri.c +++ b/src/class/hid/hid_ri.c @@ -26,31 +26,31 @@ #if ((TUSB_OPT_HOST_ENABLED && CFG_TUH_HID) || _UNITY_TEST_) -uint8_t hidri_short_data_length(uint8_t *ri) { +uint8_t hidri_short_data_length(const uint8_t *ri) { // 0 -> 0, 1 -> 1, 2 -> 2, 3 -> 4 return (1 << (*ri & 3)) >> 1; } -uint8_t hidri_short_type(uint8_t *ri) { +uint8_t hidri_short_type(const uint8_t *ri) { return (*ri >> 2) & 3; } -uint8_t hidri_short_tag(uint8_t *ri) { +uint8_t hidri_short_tag(const uint8_t *ri) { return (*ri >> 4) & 15; } -bool hidri_is_long(uint8_t *ri) { +bool hidri_is_long(const uint8_t *ri) { return *ri == 0xfe; } -uint32_t hidri_short_udata32(uint8_t *ri) { +uint32_t hidri_short_udata32(const uint8_t *ri) { uint32_t d = 0; uint8_t l = hidri_short_data_length(ri++); for(uint8_t i = 0; i < l; ++i) d |= ((uint32_t)(*ri++)) << (i << 3); return d; } -int32_t hidri_short_data32(uint8_t *ri) { +int32_t hidri_short_data32(const uint8_t *ri) { int32_t d = 0; uint8_t l = hidri_short_data_length(ri++); bool negative = false; @@ -67,19 +67,19 @@ int32_t hidri_short_data32(uint8_t *ri) { return d; } -uint8_t hidri_long_data_length(uint8_t *ri) { +uint8_t hidri_long_data_length(const uint8_t *ri) { return ri[1]; } -uint8_t hidri_long_tag(uint8_t *ri) { +uint8_t hidri_long_tag(const uint8_t *ri) { return ri[2]; } -uint8_t* hidri_long_item_data(uint8_t *ri) { +const uint8_t* hidri_long_item_data(const uint8_t *ri) { return ri + 3; } -int16_t hidri_size(uint8_t *ri, uint16_t l) { +int16_t hidri_size(const uint8_t *ri, uint16_t l) { // Make sure there is enough room for the header if (l < 1) return 0; // Calculate the short item length diff --git a/src/class/hid/hid_ri.h b/src/class/hid/hid_ri.h index e427ca17b0..2a5ced1d31 100644 --- a/src/class/hid/hid_ri.h +++ b/src/class/hid/hid_ri.h @@ -45,31 +45,31 @@ //--------------------------------------------------------------------+ // Get the length of a short item -uint8_t hidri_short_data_length(uint8_t *ri); +uint8_t hidri_short_data_length(const uint8_t *ri); // Get the type of a short item -uint8_t hidri_short_type(uint8_t *ri); +uint8_t hidri_short_type(const uint8_t *ri); // Get the tag from a short item -uint8_t hidri_short_tag(uint8_t *ri); +uint8_t hidri_short_tag(const uint8_t *ri); // Test if the item is a long item -bool hidri_is_long(uint8_t *ri); +bool hidri_is_long(const uint8_t *ri); // Get the short item data unsigned -uint32_t hidri_short_udata32(uint8_t *ri); +uint32_t hidri_short_udata32(const uint8_t *ri); // Get the short item data signed (with sign extend to uint32) -int32_t hidri_short_data32(uint8_t *ri); +int32_t hidri_short_data32(const uint8_t *ri); // Get the data length of a long item -uint8_t hidri_long_data_length(uint8_t *ri); +uint8_t hidri_long_data_length(const uint8_t *ri); // Get the tag from a long item -uint8_t hidri_long_tag(uint8_t *ri); +uint8_t hidri_long_tag(const uint8_t *ri); // Get a pointer to the data in a long item -uint8_t* hidri_long_item_data(uint8_t *ri); +const uint8_t* hidri_long_item_data(const uint8_t *ri); // Get the size of the item in bytes // @@ -81,7 +81,7 @@ uint8_t* hidri_long_item_data(uint8_t *ri); // 0 -> eof, // -1 -> missing short bytes, // -2 -> missing long bytes -int16_t hidri_size(uint8_t *ri, uint16_t l); +int16_t hidri_size(const uint8_t *ri, uint16_t l); #ifdef __cplusplus } diff --git a/src/class/hid/hid_rip.c b/src/class/hid/hid_rip.c index 1ee0114e3c..c48d76ddfd 100644 --- a/src/class/hid/hid_rip.c +++ b/src/class/hid/hid_rip.c @@ -25,7 +25,7 @@ #include "hid_rip.h" #include "hid.h" -void hidrip_init_state(tuh_hid_rip_state_t *state, uint8_t *report, uint16_t length) +void hidrip_init_state(tuh_hid_rip_state_t *state, const uint8_t *report, uint16_t length) { state->cursor = report; state->length = length; @@ -41,7 +41,7 @@ int16_t hidrip_next_item(tuh_hid_rip_state_t *state) { if (state->length == 0) return 0; - uint8_t *ri = state->cursor; + const uint8_t *ri = state->cursor; int16_t il = state->item_length; if (il < 0) return il; @@ -83,7 +83,7 @@ int16_t hidrip_next_item(tuh_hid_rip_state_t *state) case RI_LOCAL_USAGE: { uint32_t usage = hidri_short_udata32(ri); if (hidri_short_data_length(ri) <= 2) { - uint8_t* usage_page_item = state->global_items[state->stack_index][RI_GLOBAL_USAGE_PAGE]; + const uint8_t* usage_page_item = state->global_items[state->stack_index][RI_GLOBAL_USAGE_PAGE]; uint32_t usage_page = usage_page_item ? hidri_short_udata32(usage_page_item) : 0; usage |= usage_page << 16; } @@ -118,4 +118,33 @@ int16_t hidrip_next_item(tuh_hid_rip_state_t *state) return il; } +const uint8_t* hidrip_global(tuh_hid_rip_state_t *state, uint8_t tag) +{ + return state->global_items[state->stack_index][tag]; +} + +const uint8_t* hidrip_local(tuh_hid_rip_state_t *state, uint8_t tag) +{ + return state->local_items[tag]; +} + +uint8_t hidrip_parse_report_descriptor(tuh_hid_report_info_t* report_info_arr, uint8_t arr_count, uint8_t const* desc_report, uint16_t desc_len) +{ + // Prepare the summary array + tu_memclr(report_info_arr, arr_count*sizeof(tuh_hid_report_info_t)); + uint8_t report_num = 0; + tuh_hid_report_info_t* info = report_info_arr; + uint8_t ri_report_count = 0; + uint8_t ri_report_size = 0; + + tuh_hid_rip_state_t pstate; + hidrip_init_state(&pstate, desc_report, desc_len); + + // Remember each item length as it may contain error codes + int il = 0; + while(il = hidrip_next_item(&pstate)) { + + } +} + diff --git a/src/class/hid/hid_rip.h b/src/class/hid/hid_rip.h index 67d8a40fb6..37702488e4 100644 --- a/src/class/hid/hid_rip.h +++ b/src/class/hid/hid_rip.h @@ -28,6 +28,9 @@ #include "tusb.h" #include "hid_ri.h" +// TODO this probably does not belong in here +#include "hid_host.h" + #ifdef __cplusplus extern "C" { #endif @@ -38,6 +41,8 @@ // Implementation intended to minimise memory footprint, // mildly at the expense of performance. // +// Iterates through report items and manages state rules. +// // See: // https://www.usb.org/sites/default/files/hid1_11.pdf // https://eleccelerator.com/usbdescreqparser/ @@ -50,20 +55,50 @@ #define HID_REPORT_MAX_COLLECTION_DEPTH 20 typedef struct tuh_hid_rip_state { - uint8_t* cursor; + const uint8_t* cursor; uint16_t length; int16_t item_length; uint8_t stack_index; uint8_t usage_count; uint8_t collections_count; - uint8_t* global_items[HID_REPORT_STACK_SIZE][16]; - uint8_t* local_items[16]; - uint8_t* collections[HID_REPORT_MAX_COLLECTION_DEPTH]; + const uint8_t* global_items[HID_REPORT_STACK_SIZE][16]; + const uint8_t* local_items[16]; + const uint8_t* collections[HID_REPORT_MAX_COLLECTION_DEPTH]; uint32_t usages[HID_REPORT_MAX_USAGES]; } tuh_hid_rip_state_t; -void hidrip_init_state(tuh_hid_rip_state_t *state, uint8_t *report, uint16_t length); +// Initialise a report item descriptor parser +void hidrip_init_state(tuh_hid_rip_state_t *state, const uint8_t *report, uint16_t length); + +// Move to the next item in the report +// +// returns +// 0 for eof +// <0 for error +// int16_t hidrip_next_item(tuh_hid_rip_state_t *state); +// Accessor for the curren value of a global item +// +// Returns a pointer to the start of the item of null +const uint8_t* hidrip_global(tuh_hid_rip_state_t *state, uint8_t tag); + +// Accessor for the curren value of a local item +// +// Returns a pointer to the start of the item of null +const uint8_t* hidrip_local(tuh_hid_rip_state_t *state, uint8_t tag); + +// Fetch some basic information from the HID report descriptor +// +// Experimental replacement for tuh_hid_parse_report_descriptor +// Possibly implementation in hid_host.c should just be replaced. +// Handy here for now as I can test it and not break the rest of the stack +// +// TODO this probably does not belong in here +uint8_t hidrip_parse_report_descriptor(tuh_hid_report_info_t* report_info_arr, uint8_t arr_count, uint8_t const* desc_report, uint16_t desc_len); + + + + #endif From 2ec43d70fdea706734c09cb5bc2492d59aa11bc5 Mon Sep 17 00:00:00 2001 From: Phil Date: Sat, 5 Feb 2022 13:39:30 +0000 Subject: [PATCH 17/71] HID micro parser --- src/class/hid/hid_rip.c | 8 +++++-- src/class/hid/hid_rip.h | 3 +++ test/test/class/hid/test_hid_rip.c | 34 ++++++++++++++++++++++++++++++ 3 files changed, 43 insertions(+), 2 deletions(-) diff --git a/src/class/hid/hid_rip.c b/src/class/hid/hid_rip.c index c48d76ddfd..bc7cb6704d 100644 --- a/src/class/hid/hid_rip.c +++ b/src/class/hid/hid_rip.c @@ -128,6 +128,11 @@ const uint8_t* hidrip_local(tuh_hid_rip_state_t *state, uint8_t tag) return state->local_items[tag]; } +const uint8_t* hidrip_current_item(tuh_hid_rip_state_t *state) +{ + return state->cursor; +} + uint8_t hidrip_parse_report_descriptor(tuh_hid_report_info_t* report_info_arr, uint8_t arr_count, uint8_t const* desc_report, uint16_t desc_len) { // Prepare the summary array @@ -139,10 +144,9 @@ uint8_t hidrip_parse_report_descriptor(tuh_hid_report_info_t* report_info_arr, u tuh_hid_rip_state_t pstate; hidrip_init_state(&pstate, desc_report, desc_len); - - // Remember each item length as it may contain error codes int il = 0; while(il = hidrip_next_item(&pstate)) { + const uint8_t *ri = hidrip_current_item(&pstate); } } diff --git a/src/class/hid/hid_rip.h b/src/class/hid/hid_rip.h index 37702488e4..9e49ecee0e 100644 --- a/src/class/hid/hid_rip.h +++ b/src/class/hid/hid_rip.h @@ -88,6 +88,9 @@ const uint8_t* hidrip_global(tuh_hid_rip_state_t *state, uint8_t tag); // Returns a pointer to the start of the item of null const uint8_t* hidrip_local(tuh_hid_rip_state_t *state, uint8_t tag); +// Returns a pointer to the start of the last parsed item +const uint8_t* hidrip_current_item(tuh_hid_rip_state_t *state); + // Fetch some basic information from the HID report descriptor // // Experimental replacement for tuh_hid_parse_report_descriptor diff --git a/test/test/class/hid/test_hid_rip.c b/test/test/class/hid/test_hid_rip.c index a644ba2744..57d8c54d5a 100644 --- a/test/test/class/hid/test_hid_rip.c +++ b/test/test/class/hid/test_hid_rip.c @@ -97,6 +97,40 @@ void test_globals_recorded(void) TEST_ASSERT_EQUAL(0x55, hidri_short_data32(pstate.global_items[pstate.stack_index][1])); } +void test_globals_overwritten(void) +{ + uint8_t tb[] = { + 0x05, 0x01, // Usage Page (Generic Desktop Ctrls) + 0x05, 0x09, // USAGE_PAGE (Button) + }; + + tuh_hid_rip_state_t pstate; + hidrip_init_state(&pstate, (uint8_t*)&tb, sizeof(tb)); + TEST_ASSERT_EQUAL(2, hidrip_next_item(&pstate)); + TEST_ASSERT_EQUAL(2, hidrip_next_item(&pstate)); + TEST_ASSERT_EQUAL(0, pstate.stack_index); + TEST_ASSERT_EQUAL(0x09, hidri_short_udata32(hidrip_global(&pstate, 0))); +} + +void test_push_pop(void) +{ + uint8_t tb[] = { + 0x05, 0x01, // Usage Page (Generic Desktop Ctrls) + 0xA4, // Push + 0x05, 0x09, // USAGE_PAGE (Button) + 0xB4, // Pop + }; + + tuh_hid_rip_state_t pstate; + hidrip_init_state(&pstate, (uint8_t*)&tb, sizeof(tb)); + TEST_ASSERT_EQUAL(2, hidrip_next_item(&pstate)); + TEST_ASSERT_EQUAL(1, hidrip_next_item(&pstate)); + TEST_ASSERT_EQUAL(2, hidrip_next_item(&pstate)); + TEST_ASSERT_EQUAL(1, hidrip_next_item(&pstate)); + TEST_ASSERT_EQUAL(0, pstate.stack_index); + TEST_ASSERT_EQUAL(0x01, hidri_short_udata32(hidrip_global(&pstate, 0))); +} + void test_main_clears_local(void) { uint8_t tb[] = { From 2a1ae023aa9f6545b031c1e81d5581e935dea843 Mon Sep 17 00:00:00 2001 From: Phil Date: Sat, 5 Feb 2022 14:24:35 +0000 Subject: [PATCH 18/71] HID micro parser --- src/class/hid/hid_host.h | 4 +- src/class/hid/hid_rip.c | 89 +++++++++++++++++++++++++++++- src/class/hid/hid_rip.h | 4 ++ test/test/class/hid/test_hid_rip.c | 17 ++++++ 4 files changed, 110 insertions(+), 4 deletions(-) diff --git a/src/class/hid/hid_host.h b/src/class/hid/hid_host.h index fe09b03b2f..8b3cf463d1 100644 --- a/src/class/hid/hid_host.h +++ b/src/class/hid/hid_host.h @@ -54,8 +54,8 @@ typedef struct uint16_t usage_page; // TODO still use the endpoint size for now -// uint8_t in_len; // length of IN report -// uint8_t out_len; // length of OUT report + uint16_t in_len; // length of IN report in bits + uint16_t out_len; // length of OUT report in bits } tuh_hid_report_info_t; //--------------------------------------------------------------------+ diff --git a/src/class/hid/hid_rip.c b/src/class/hid/hid_rip.c index bc7cb6704d..04cf1a9506 100644 --- a/src/class/hid/hid_rip.c +++ b/src/class/hid/hid_rip.c @@ -133,6 +133,24 @@ const uint8_t* hidrip_current_item(tuh_hid_rip_state_t *state) return state->cursor; } +uint32_t hidrip_report_total_size_bits(tuh_hid_rip_state_t *state) +{ + const uint8_t* ri_report_size = hidrip_global(state, RI_GLOBAL_REPORT_SIZE); + const uint8_t* ri_report_count = hidrip_global(state, RI_GLOBAL_REPORT_COUNT); + + if (ri_report_size != NULL && ri_report_count != NULL) + { + uint32_t report_size = hidri_short_udata32(ri_report_size); + uint32_t report_count = hidri_short_udata32(ri_report_count); + return report_size * report_count; + } + else + { + TU_LOG2("HID report parser cannot calc total report size in bits\r\n"); + return 0; + } +} + uint8_t hidrip_parse_report_descriptor(tuh_hid_report_info_t* report_info_arr, uint8_t arr_count, uint8_t const* desc_report, uint16_t desc_len) { // Prepare the summary array @@ -145,9 +163,76 @@ uint8_t hidrip_parse_report_descriptor(tuh_hid_report_info_t* report_info_arr, u tuh_hid_rip_state_t pstate; hidrip_init_state(&pstate, desc_report, desc_len); int il = 0; - while(il = hidrip_next_item(&pstate)) { + uint32_t outer_usage = 0; + while(il = hidrip_next_item(&pstate)) + { const uint8_t *ri = hidrip_current_item(&pstate); - + // Skip past long items + if (!hidri_is_long(ri)) + { + uint8_t const tag = hidri_short_tag(ri); + uint8_t const type = hidri_short_type(ri); + switch(type) + { + case RI_TYPE_MAIN: { + switch (tag) + { + case RI_MAIN_INPUT: { + info->in_len += hidrip_report_total_size_bits(&pstate); + break; + } + case RI_MAIN_OUTPUT: { + info->out_len += hidrip_report_total_size_bits(&pstate); + break; + } + default: break; + } + break; + } + case RI_TYPE_GLOBAL: + switch(tag) + { + case RI_GLOBAL_REPORT_ID: + // info->report_id = data8; + break; + + case RI_GLOBAL_REPORT_SIZE: + // ri_report_size = data8; + break; + + case RI_GLOBAL_REPORT_COUNT: + // ri_report_count = data8; + break; + + default: break; + } + break; + + case RI_TYPE_LOCAL: + switch(tag) + { + case RI_LOCAL_USAGE: + // only take in account the "usage" before starting REPORT ID + if ( pstate.collections_count == 0 ) { + // info->usage = data8; + } + break; + + default: break; + } + break; + + // error + default: break; + } + + + + + + + + } } } diff --git a/src/class/hid/hid_rip.h b/src/class/hid/hid_rip.h index 9e49ecee0e..1fc6bf0e85 100644 --- a/src/class/hid/hid_rip.h +++ b/src/class/hid/hid_rip.h @@ -91,6 +91,10 @@ const uint8_t* hidrip_local(tuh_hid_rip_state_t *state, uint8_t tag); // Returns a pointer to the start of the last parsed item const uint8_t* hidrip_current_item(tuh_hid_rip_state_t *state); +// Return report_size * report_count +uint32_t hidrip_report_total_size_bits(tuh_hid_rip_state_t *state); + + // Fetch some basic information from the HID report descriptor // // Experimental replacement for tuh_hid_parse_report_descriptor diff --git a/test/test/class/hid/test_hid_rip.c b/test/test/class/hid/test_hid_rip.c index 57d8c54d5a..cab981815b 100644 --- a/test/test/class/hid/test_hid_rip.c +++ b/test/test/class/hid/test_hid_rip.c @@ -131,6 +131,10 @@ void test_push_pop(void) TEST_ASSERT_EQUAL(0x01, hidri_short_udata32(hidrip_global(&pstate, 0))); } +// TODO test stack overflow + +// TODO test stack underflow + void test_main_clears_local(void) { uint8_t tb[] = { @@ -178,3 +182,16 @@ void test_collections(void) TEST_ASSERT_EQUAL(0, pstate.collections_count); } +void test_total_size_bits(void) +{ + uint8_t tb[] = { + 0x75, 0x08, // REPORT_SIZE (8) + 0x95, 0x02, // REPORT_COUNT (2) + }; + + tuh_hid_rip_state_t pstate; + hidrip_init_state(&pstate, (uint8_t*)&tb, sizeof(tb)); + TEST_ASSERT_EQUAL(2, hidrip_next_item(&pstate)); + TEST_ASSERT_EQUAL(2, hidrip_next_item(&pstate)); + TEST_ASSERT_EQUAL(16, hidrip_report_total_size_bits(&pstate)); +} From daecfb3e65f000cf886b2e7fdd599d360336fe17 Mon Sep 17 00:00:00 2001 From: Phil Date: Sat, 5 Feb 2022 14:53:53 +0000 Subject: [PATCH 19/71] HID micro parser --- src/class/hid/hid_host.h | 2 +- src/class/hid/hid_ri.c | 4 +++ src/class/hid/hid_ri.h | 3 ++ src/class/hid/hid_rip.c | 54 +++++++++++++++---------------- test/test/class/hid/test_hid_ri.c | 13 ++++++++ 5 files changed, 48 insertions(+), 28 deletions(-) diff --git a/src/class/hid/hid_host.h b/src/class/hid/hid_host.h index 8b3cf463d1..a90599ee57 100644 --- a/src/class/hid/hid_host.h +++ b/src/class/hid/hid_host.h @@ -50,7 +50,7 @@ typedef struct { uint8_t report_id; - uint8_t usage; + uint16_t usage; uint16_t usage_page; // TODO still use the endpoint size for now diff --git a/src/class/hid/hid_ri.c b/src/class/hid/hid_ri.c index a3fb37a9ab..e36ead3ca6 100644 --- a/src/class/hid/hid_ri.c +++ b/src/class/hid/hid_ri.c @@ -50,6 +50,10 @@ uint32_t hidri_short_udata32(const uint8_t *ri) { return d; } +uint8_t hidri_short_udata8(const uint8_t *ri) { + return hidri_short_data_length(ri) > 0 ? ri[1] : 0; +} + int32_t hidri_short_data32(const uint8_t *ri) { int32_t d = 0; uint8_t l = hidri_short_data_length(ri++); diff --git a/src/class/hid/hid_ri.h b/src/class/hid/hid_ri.h index 2a5ced1d31..224f210107 100644 --- a/src/class/hid/hid_ri.h +++ b/src/class/hid/hid_ri.h @@ -59,6 +59,9 @@ bool hidri_is_long(const uint8_t *ri); // Get the short item data unsigned uint32_t hidri_short_udata32(const uint8_t *ri); +// Get the short item data unsigned +uint8_t hidri_short_udata8(const uint8_t *ri); + // Get the short item data signed (with sign extend to uint32) int32_t hidri_short_data32(const uint8_t *ri); diff --git a/src/class/hid/hid_rip.c b/src/class/hid/hid_rip.c index 04cf1a9506..9a76ddf63e 100644 --- a/src/class/hid/hid_rip.c +++ b/src/class/hid/hid_rip.c @@ -164,10 +164,11 @@ uint8_t hidrip_parse_report_descriptor(tuh_hid_report_info_t* report_info_arr, u hidrip_init_state(&pstate, desc_report, desc_len); int il = 0; uint32_t outer_usage = 0; + + // TODO perhaps hidrip_next_item should return the item pointer?? while(il = hidrip_next_item(&pstate)) { const uint8_t *ri = hidrip_current_item(&pstate); - // Skip past long items if (!hidri_is_long(ri)) { uint8_t const tag = hidri_short_tag(ri); @@ -189,51 +190,50 @@ uint8_t hidrip_parse_report_descriptor(tuh_hid_report_info_t* report_info_arr, u } break; } - case RI_TYPE_GLOBAL: + case RI_TYPE_GLOBAL: { switch(tag) { - case RI_GLOBAL_REPORT_ID: - // info->report_id = data8; - break; - - case RI_GLOBAL_REPORT_SIZE: - // ri_report_size = data8; - break; - - case RI_GLOBAL_REPORT_COUNT: - // ri_report_count = data8; - break; - + case RI_GLOBAL_REPORT_ID: { + if (info->in_len > 0 || info->out_len > 0) { + info++; + report_num++; + } + info->report_id = hidri_short_udata8(hidrip_current_item(&pstate)); + break; + } default: break; } - break; - - case RI_TYPE_LOCAL: + break; + } + case RI_TYPE_LOCAL: { switch(tag) { case RI_LOCAL_USAGE: // only take in account the "usage" before starting REPORT ID if ( pstate.collections_count == 0 ) { - // info->usage = data8; + uint32_t eusage = pstate.usages[pstate.usage_count - 1]; + info->usage = eusage & 0xffff; + info->usage_page = eusage >> 16; } break; default: break; } - break; - + break; + } // error default: break; } - - - - - - - } } + + for ( uint8_t i = 0; i < report_num; i++ ) + { + info = report_info_arr+i; + TU_LOG2("%u: id = %u, usage_page = %u, usage = %u\r\n", i, info->report_id, info->usage_page, info->usage); + } + + return report_num; } diff --git a/test/test/class/hid/test_hid_ri.c b/test/test/class/hid/test_hid_ri.c index c850350c59..e3cdd13fe0 100644 --- a/test/test/class/hid/test_hid_ri.c +++ b/test/test/class/hid/test_hid_ri.c @@ -97,6 +97,19 @@ void test_physical_max_315(void) TEST_ASSERT_EQUAL(3, hidri_size(tb, 3)); } +void test_physical_max_123(void) { + uint8_t tb[] = { 0x46, 0x7B, 0x00 }; /* Physical Maximum (123) */ + + TEST_ASSERT_EQUAL(2, hidri_short_data_length(tb)); + TEST_ASSERT_EQUAL(1, hidri_short_type(tb)); + TEST_ASSERT_EQUAL(4, hidri_short_tag(tb)); + TEST_ASSERT_EQUAL(false, hidri_is_long(tb)); + TEST_ASSERT_EQUAL(123, hidri_short_udata32(tb)); + TEST_ASSERT_EQUAL(123, hidri_short_udata8(tb)); + TEST_ASSERT_EQUAL(123, hidri_short_data32(tb)); + TEST_ASSERT_EQUAL(3, hidri_size(tb, 3)); +} + void test_logical_min_neg_127(void) { uint8_t tb[] = { 0x15, 0x81 }; /* LOGICAL_MINIMUM (-127) */ From e561f94b091bfa7ed0cc9ec59e56199e88a4611b Mon Sep 17 00:00:00 2001 From: Phil Date: Sat, 5 Feb 2022 15:17:46 +0000 Subject: [PATCH 20/71] HID micro parser --- src/class/hid/hid_rip.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/class/hid/hid_rip.c b/src/class/hid/hid_rip.c index 9a76ddf63e..26a0c116ff 100644 --- a/src/class/hid/hid_rip.c +++ b/src/class/hid/hid_rip.c @@ -163,7 +163,6 @@ uint8_t hidrip_parse_report_descriptor(tuh_hid_report_info_t* report_info_arr, u tuh_hid_rip_state_t pstate; hidrip_init_state(&pstate, desc_report, desc_len); int il = 0; - uint32_t outer_usage = 0; // TODO perhaps hidrip_next_item should return the item pointer?? while(il = hidrip_next_item(&pstate)) From 92ca20bcac815283d29c096c94c3a24ba2e4d98f Mon Sep 17 00:00:00 2001 From: Phil Date: Sat, 5 Feb 2022 15:41:16 +0000 Subject: [PATCH 21/71] HID micro parser --- src/class/hid/hid_rip.c | 51 +++++++++++++++++++++--------- src/class/hid/hid_rip.h | 8 ++--- test/test/class/hid/test_hid_rip.c | 50 ++++++++++++++--------------- 3 files changed, 64 insertions(+), 45 deletions(-) diff --git a/src/class/hid/hid_rip.c b/src/class/hid/hid_rip.c index 26a0c116ff..b42fd7ebb7 100644 --- a/src/class/hid/hid_rip.c +++ b/src/class/hid/hid_rip.c @@ -37,14 +37,16 @@ void hidrip_init_state(tuh_hid_rip_state_t *state, const uint8_t *report, uint16 memset(&state->local_items, 0, sizeof(uint8_t*) * 16); } -int16_t hidrip_next_item(tuh_hid_rip_state_t *state) +const uint8_t* hidrip_next_item(tuh_hid_rip_state_t *state) { - if (state->length == 0) return 0; + // Already at eof + if (state->length == 0) return NULL; const uint8_t *ri = state->cursor; int16_t il = state->item_length; - if (il < 0) return il; + // Previous error encountered so do nothing + if (il < 0) return NULL; if (il > 0 && hidri_short_type(ri) == RI_TYPE_MAIN) { // Clear down local state after a main item @@ -56,10 +58,21 @@ int16_t hidrip_next_item(tuh_hid_rip_state_t *state) ri += il; state->cursor = ri; state->length -= il; - + + // Normal eof + if (state->length == 0) { + state->item_length = 0; + return NULL; + } + // Check the report item is valid state->item_length = il = hidri_size(ri, state->length); - + + if (il <= 0) { + // record error somewhere + return NULL; + } + if (il > 0 && !hidri_is_long(ri)) { // For now ignore long items. uint8_t short_type = hidri_short_type(ri); uint8_t short_tag = hidri_short_tag(ri); @@ -68,11 +81,15 @@ int16_t hidrip_next_item(tuh_hid_rip_state_t *state) state->global_items[state->stack_index][short_tag] = ri; switch (short_tag) { case RI_GLOBAL_PUSH: - if (++state->stack_index == HID_REPORT_STACK_SIZE) return -1; // TODO enum? Stack overflow + if (++state->stack_index == HID_REPORT_STACK_SIZE) { + return NULL; // TODO enum? Stack overflow + } memcpy(&state->global_items[state->stack_index], &state->global_items[state->stack_index - 1], sizeof(uint8_t*) * 16); break; case RI_GLOBAL_POP: - if (state->stack_index-- == 0) return -2; // TODO enum? Stack underflow + if (state->stack_index-- == 0) { + return NULL; // TODO enum? Stack underflow + } break; default: break; @@ -87,7 +104,9 @@ int16_t hidrip_next_item(tuh_hid_rip_state_t *state) uint32_t usage_page = usage_page_item ? hidri_short_udata32(usage_page_item) : 0; usage |= usage_page << 16; } - if (state->usage_count == HID_REPORT_MAX_USAGES) return -3; // TODO enum? Max usages overflow + if (state->usage_count == HID_REPORT_MAX_USAGES) { + return NULL; // TODO enum? Max usages overflow + } state->usages[state->usage_count++] = usage; break; } @@ -99,12 +118,16 @@ int16_t hidrip_next_item(tuh_hid_rip_state_t *state) case RI_TYPE_MAIN: { switch(short_tag) { case RI_MAIN_COLLECTION: { - if (state->collections_count == HID_REPORT_MAX_COLLECTION_DEPTH) return -4; // TODO enum? Max collections overflow + if (state->collections_count == HID_REPORT_MAX_COLLECTION_DEPTH) { + return NULL; // TODO enum? Max collections overflow + } state->collections[state->collections_count++] = ri; break; } case RI_MAIN_COLLECTION_END: - if (state->collections_count-- == 0) return -5; // TODO enum? Max collections underflow + if (state->collections_count-- == 0) { + return NULL; // TODO enum? Max collections underflow + } break; default: break; @@ -115,7 +138,7 @@ int16_t hidrip_next_item(tuh_hid_rip_state_t *state) break; } } - return il; + return ri; } const uint8_t* hidrip_global(tuh_hid_rip_state_t *state, uint8_t tag) @@ -163,11 +186,9 @@ uint8_t hidrip_parse_report_descriptor(tuh_hid_report_info_t* report_info_arr, u tuh_hid_rip_state_t pstate; hidrip_init_state(&pstate, desc_report, desc_len); int il = 0; - - // TODO perhaps hidrip_next_item should return the item pointer?? - while(il = hidrip_next_item(&pstate)) + const uint8_t *ri; + while((ri = hidrip_next_item(&pstate)) != NULL) { - const uint8_t *ri = hidrip_current_item(&pstate); if (!hidri_is_long(ri)) { uint8_t const tag = hidri_short_tag(ri); diff --git a/src/class/hid/hid_rip.h b/src/class/hid/hid_rip.h index 1fc6bf0e85..2e9cfebda5 100644 --- a/src/class/hid/hid_rip.h +++ b/src/class/hid/hid_rip.h @@ -72,11 +72,9 @@ void hidrip_init_state(tuh_hid_rip_state_t *state, const uint8_t *report, uint16 // Move to the next item in the report // -// returns -// 0 for eof -// <0 for error +// returns pointer to next item or null // -int16_t hidrip_next_item(tuh_hid_rip_state_t *state); +const uint8_t* hidrip_next_item(tuh_hid_rip_state_t *state); // Accessor for the curren value of a global item // @@ -88,7 +86,7 @@ const uint8_t* hidrip_global(tuh_hid_rip_state_t *state, uint8_t tag); // Returns a pointer to the start of the item of null const uint8_t* hidrip_local(tuh_hid_rip_state_t *state, uint8_t tag); -// Returns a pointer to the start of the last parsed item +// Returns a pointer to the start of the item or NULL for eof const uint8_t* hidrip_current_item(tuh_hid_rip_state_t *state); // Return report_size * report_count diff --git a/test/test/class/hid/test_hid_rip.c b/test/test/class/hid/test_hid_rip.c index cab981815b..e6df0b8ae0 100644 --- a/test/test/class/hid/test_hid_rip.c +++ b/test/test/class/hid/test_hid_rip.c @@ -51,16 +51,16 @@ void test_next_simple(void) tuh_hid_rip_state_t pstate; hidrip_init_state(&pstate, (uint8_t*)&tb, sizeof(tb)); - TEST_ASSERT_EQUAL(2, hidrip_next_item(&pstate)); + TEST_ASSERT_EQUAL(&tb[0], hidrip_next_item(&pstate)); TEST_ASSERT_EQUAL(2, pstate.item_length); TEST_ASSERT_EQUAL(0x05, *pstate.cursor); - TEST_ASSERT_EQUAL(2, hidrip_next_item(&pstate)); + TEST_ASSERT_EQUAL(&tb[2], hidrip_next_item(&pstate)); TEST_ASSERT_EQUAL(2, pstate.item_length); TEST_ASSERT_EQUAL(0x09, *pstate.cursor); - TEST_ASSERT_EQUAL(2, hidrip_next_item(&pstate)); + TEST_ASSERT_EQUAL(&tb[4], hidrip_next_item(&pstate)); TEST_ASSERT_EQUAL(2, pstate.item_length); TEST_ASSERT_EQUAL(0xA1, *pstate.cursor); - TEST_ASSERT_EQUAL(0, hidrip_next_item(&pstate)); + TEST_ASSERT_EQUAL(NULL, hidrip_next_item(&pstate)); TEST_ASSERT_EQUAL(0, pstate.item_length); } @@ -73,9 +73,9 @@ void test_usage_with_page(void) tuh_hid_rip_state_t pstate; hidrip_init_state(&pstate, (uint8_t*)&tb, sizeof(tb)); - TEST_ASSERT_EQUAL(2, hidrip_next_item(&pstate)); + TEST_ASSERT_EQUAL(&tb[0], hidrip_next_item(&pstate)); TEST_ASSERT_EQUAL(0x01, hidri_short_udata32(pstate.cursor)); - TEST_ASSERT_EQUAL(2, hidrip_next_item(&pstate)); + TEST_ASSERT_EQUAL(&tb[2], hidrip_next_item(&pstate)); TEST_ASSERT_EQUAL(1, pstate.usage_count); TEST_ASSERT_EQUAL(0x02, hidri_short_udata32(pstate.cursor)); TEST_ASSERT_EQUAL(0x00010002, pstate.usages[0]); @@ -90,8 +90,8 @@ void test_globals_recorded(void) tuh_hid_rip_state_t pstate; hidrip_init_state(&pstate, (uint8_t*)&tb, sizeof(tb)); - TEST_ASSERT_EQUAL(2, hidrip_next_item(&pstate)); - TEST_ASSERT_EQUAL(2, hidrip_next_item(&pstate)); + TEST_ASSERT_EQUAL(&tb[0], hidrip_next_item(&pstate)); + TEST_ASSERT_EQUAL(&tb[2], hidrip_next_item(&pstate)); TEST_ASSERT_EQUAL(0, pstate.stack_index); TEST_ASSERT_EQUAL(0x01, hidri_short_udata32(pstate.global_items[pstate.stack_index][0])); TEST_ASSERT_EQUAL(0x55, hidri_short_data32(pstate.global_items[pstate.stack_index][1])); @@ -106,8 +106,8 @@ void test_globals_overwritten(void) tuh_hid_rip_state_t pstate; hidrip_init_state(&pstate, (uint8_t*)&tb, sizeof(tb)); - TEST_ASSERT_EQUAL(2, hidrip_next_item(&pstate)); - TEST_ASSERT_EQUAL(2, hidrip_next_item(&pstate)); + TEST_ASSERT_EQUAL(&tb[0], hidrip_next_item(&pstate)); + TEST_ASSERT_EQUAL(&tb[2], hidrip_next_item(&pstate)); TEST_ASSERT_EQUAL(0, pstate.stack_index); TEST_ASSERT_EQUAL(0x09, hidri_short_udata32(hidrip_global(&pstate, 0))); } @@ -123,10 +123,10 @@ void test_push_pop(void) tuh_hid_rip_state_t pstate; hidrip_init_state(&pstate, (uint8_t*)&tb, sizeof(tb)); - TEST_ASSERT_EQUAL(2, hidrip_next_item(&pstate)); - TEST_ASSERT_EQUAL(1, hidrip_next_item(&pstate)); - TEST_ASSERT_EQUAL(2, hidrip_next_item(&pstate)); - TEST_ASSERT_EQUAL(1, hidrip_next_item(&pstate)); + TEST_ASSERT_EQUAL(&tb[0], hidrip_next_item(&pstate)); + TEST_ASSERT_EQUAL(&tb[2], hidrip_next_item(&pstate)); + TEST_ASSERT_EQUAL(&tb[3], hidrip_next_item(&pstate)); + TEST_ASSERT_EQUAL(&tb[5], hidrip_next_item(&pstate)); TEST_ASSERT_EQUAL(0, pstate.stack_index); TEST_ASSERT_EQUAL(0x01, hidri_short_udata32(hidrip_global(&pstate, 0))); } @@ -147,14 +147,14 @@ void test_main_clears_local(void) tuh_hid_rip_state_t pstate; hidrip_init_state(&pstate, (uint8_t*)&tb, sizeof(tb)); - TEST_ASSERT_EQUAL(2, hidrip_next_item(&pstate)); - TEST_ASSERT_EQUAL(2, hidrip_next_item(&pstate)); - TEST_ASSERT_EQUAL(2, hidrip_next_item(&pstate)); - TEST_ASSERT_EQUAL(2, hidrip_next_item(&pstate)); + TEST_ASSERT_EQUAL(&tb[0], hidrip_next_item(&pstate)); + TEST_ASSERT_EQUAL(&tb[2], hidrip_next_item(&pstate)); + TEST_ASSERT_EQUAL(&tb[4], hidrip_next_item(&pstate)); + TEST_ASSERT_EQUAL(&tb[6], hidrip_next_item(&pstate)); TEST_ASSERT_EQUAL(1, pstate.usage_count); TEST_ASSERT_EQUAL(&tb[4], pstate.local_items[3]); TEST_ASSERT_EQUAL(4, hidri_short_data32(pstate.local_items[3])); - TEST_ASSERT_EQUAL(2, hidrip_next_item(&pstate)); + TEST_ASSERT_EQUAL(&tb[8], hidrip_next_item(&pstate)); TEST_ASSERT_EQUAL(0, pstate.global_items[pstate.stack_index][3]); TEST_ASSERT_EQUAL(0, pstate.usage_count); } @@ -170,15 +170,15 @@ void test_collections(void) tuh_hid_rip_state_t pstate; hidrip_init_state(&pstate, (uint8_t*)&tb, sizeof(tb)); - TEST_ASSERT_EQUAL(2, hidrip_next_item(&pstate)); + TEST_ASSERT_EQUAL(&tb[0], hidrip_next_item(&pstate)); TEST_ASSERT_EQUAL(1, pstate.collections_count); - TEST_ASSERT_EQUAL(2, hidrip_next_item(&pstate)); + TEST_ASSERT_EQUAL(&tb[2], hidrip_next_item(&pstate)); TEST_ASSERT_EQUAL(2, pstate.collections_count); TEST_ASSERT_EQUAL(&tb[0], pstate.collections[0]); TEST_ASSERT_EQUAL(&tb[2], pstate.collections[1]); - TEST_ASSERT_EQUAL(1, hidrip_next_item(&pstate)); + TEST_ASSERT_EQUAL(&tb[4], hidrip_next_item(&pstate)); TEST_ASSERT_EQUAL(1, pstate.collections_count); - TEST_ASSERT_EQUAL(1, hidrip_next_item(&pstate)); + TEST_ASSERT_EQUAL(&tb[5], hidrip_next_item(&pstate)); TEST_ASSERT_EQUAL(0, pstate.collections_count); } @@ -191,7 +191,7 @@ void test_total_size_bits(void) tuh_hid_rip_state_t pstate; hidrip_init_state(&pstate, (uint8_t*)&tb, sizeof(tb)); - TEST_ASSERT_EQUAL(2, hidrip_next_item(&pstate)); - TEST_ASSERT_EQUAL(2, hidrip_next_item(&pstate)); + TEST_ASSERT_EQUAL(&tb[0], hidrip_next_item(&pstate)); + TEST_ASSERT_EQUAL(&tb[2], hidrip_next_item(&pstate)); TEST_ASSERT_EQUAL(16, hidrip_report_total_size_bits(&pstate)); } From 63aecd2490c4dd8a296e531522357c9d7c2b95ff Mon Sep 17 00:00:00 2001 From: Phil Date: Sat, 5 Feb 2022 18:09:17 +0000 Subject: [PATCH 22/71] HID micro parser --- src/class/hid/hid_host.c | 177 ++++++++++------------------ src/class/hid/hid_ri.c | 5 +- src/class/hid/hid_rip.c | 86 +------------- src/class/hid/hid_rip.h | 16 --- src/host/hcd.h | 2 +- test/project.yml | 4 + test/test/class/hid/test_hid_host.c | 51 ++++++++ test/test/class/hid/test_hid_ri.c | 3 + 8 files changed, 128 insertions(+), 216 deletions(-) create mode 100644 test/test/class/hid/test_hid_host.c diff --git a/src/class/hid/hid_host.c b/src/class/hid/hid_host.c index f19f1ba810..0f01aef279 100644 --- a/src/class/hid/hid_host.c +++ b/src/class/hid/hid_host.c @@ -32,6 +32,7 @@ #include "host/usbh_classdriver.h" #include "hid_host.h" +#include "hid_rip.h" //--------------------------------------------------------------------+ // MACRO CONSTANT TYPEDEF @@ -452,140 +453,84 @@ static void config_driver_mount_complete(uint8_t dev_addr, uint8_t instance, uin //--------------------------------------------------------------------+ // Report Descriptor Parser //--------------------------------------------------------------------+ - -uint8_t tuh_hid_parse_report_descriptor(tuh_hid_report_info_t* report_info_arr, uint8_t arr_count, uint8_t const* desc_report, uint16_t desc_len) +uint8_t tuh_hid_parse_report_descriptor(tuh_hid_report_info_t* report_info_arr, uint8_t arr_count, uint8_t const* desc_report, uint16_t desc_len) { - // Report Item 6.2.2.2 USB HID 1.11 - union TU_ATTR_PACKED - { - uint8_t byte; - struct TU_ATTR_PACKED - { - uint8_t size : 2; - uint8_t type : 2; - uint8_t tag : 4; - }; - } header; - + // Prepare the summary array tu_memclr(report_info_arr, arr_count*sizeof(tuh_hid_report_info_t)); - uint8_t report_num = 0; tuh_hid_report_info_t* info = report_info_arr; - - // current parsed report count & size from descriptor -// uint8_t ri_report_count = 0; -// uint8_t ri_report_size = 0; - - uint8_t ri_collection_depth = 0; - - while(desc_len && report_num < arr_count) + uint8_t ri_report_count = 0; + uint8_t ri_report_size = 0; + + tuh_hid_rip_state_t pstate; + hidrip_init_state(&pstate, desc_report, desc_len); + int il = 0; + const uint8_t *ri; + while((ri = hidrip_next_item(&pstate)) != NULL) { - header.byte = *desc_report++; - desc_len--; - - uint8_t const tag = header.tag; - uint8_t const type = header.type; - uint8_t const size = header.size; - - uint8_t const data8 = desc_report[0]; - - TU_LOG(3, "tag = %d, type = %d, size = %d, data = ", tag, type, size); - for(uint32_t i=0; iin_len += hidrip_report_total_size_bits(&pstate); + break; } + case RI_MAIN_OUTPUT: { + info->out_len += hidrip_report_total_size_bits(&pstate); + break; + } + default: break; + } break; - - default: break; } - break; - - case RI_TYPE_GLOBAL: - switch(tag) - { - case RI_GLOBAL_USAGE_PAGE: - // only take in account the "usage page" before REPORT ID - if ( ri_collection_depth == 0 ) memcpy(&info->usage_page, desc_report, size); - break; - - case RI_GLOBAL_LOGICAL_MIN : break; - case RI_GLOBAL_LOGICAL_MAX : break; - case RI_GLOBAL_PHYSICAL_MIN : break; - case RI_GLOBAL_PHYSICAL_MAX : break; - - case RI_GLOBAL_REPORT_ID: - info->report_id = data8; - break; - - case RI_GLOBAL_REPORT_SIZE: -// ri_report_size = data8; - break; - - case RI_GLOBAL_REPORT_COUNT: -// ri_report_count = data8; + case RI_TYPE_GLOBAL: { + switch(tag) + { + case RI_GLOBAL_REPORT_ID: { + if (info->in_len > 0 || info->out_len > 0) { + info++; + report_num++; + } + info->report_id = hidri_short_udata8(hidrip_current_item(&pstate)); + break; + } + default: break; + } break; - - case RI_GLOBAL_UNIT_EXPONENT : break; - case RI_GLOBAL_UNIT : break; - case RI_GLOBAL_PUSH : break; - case RI_GLOBAL_POP : break; - - default: break; } - break; - - case RI_TYPE_LOCAL: - switch(tag) - { - case RI_LOCAL_USAGE: - // only take in account the "usage" before starting REPORT ID - if ( ri_collection_depth == 0 ) info->usage = data8; + case RI_TYPE_LOCAL: { + switch(tag) + { + case RI_LOCAL_USAGE: + // only take in account the "usage" before starting REPORT ID + if ( pstate.collections_count == 0 ) { + uint32_t eusage = pstate.usages[pstate.usage_count - 1]; + info->usage = eusage & 0xffff; + info->usage_page = eusage >> 16; + } + break; + + default: break; + } break; - - case RI_LOCAL_USAGE_MIN : break; - case RI_LOCAL_USAGE_MAX : break; - case RI_LOCAL_DESIGNATOR_INDEX : break; - case RI_LOCAL_DESIGNATOR_MIN : break; - case RI_LOCAL_DESIGNATOR_MAX : break; - case RI_LOCAL_STRING_INDEX : break; - case RI_LOCAL_STRING_MIN : break; - case RI_LOCAL_STRING_MAX : break; - case RI_LOCAL_DELIMITER : break; - default: break; } - break; - - // error - default: break; + // error + default: break; + } } - - desc_report += size; - desc_len -= size; } - + for ( uint8_t i = 0; i < report_num; i++ ) { info = report_info_arr+i; - TU_LOG2("%u: id = %u, usage_page = %u, usage = %u\r\n", i, info->report_id, info->usage_page, info->usage); + TU_LOG2("%u: id = %02X, usage_page = %04X, usage = %04X\r\n", i, info->report_id, info->usage_page, info->usage); + printf("%u: id = %02X, usage_page = %04X, usage = %04X\r\n", i, info->report_id, info->usage_page, info->usage); } return report_num; diff --git a/src/class/hid/hid_ri.c b/src/class/hid/hid_ri.c index e36ead3ca6..2e832baa77 100644 --- a/src/class/hid/hid_ri.c +++ b/src/class/hid/hid_ri.c @@ -21,11 +21,12 @@ * * This file is part of the TinyUSB stack. */ - -#include "hid_ri.h" +#include "tusb_option.h" #if ((TUSB_OPT_HOST_ENABLED && CFG_TUH_HID) || _UNITY_TEST_) +#include "hid_ri.h" + uint8_t hidri_short_data_length(const uint8_t *ri) { // 0 -> 0, 1 -> 1, 2 -> 2, 3 -> 4 return (1 << (*ri & 3)) >> 1; diff --git a/src/class/hid/hid_rip.c b/src/class/hid/hid_rip.c index b42fd7ebb7..25e0fcbbcc 100644 --- a/src/class/hid/hid_rip.c +++ b/src/class/hid/hid_rip.c @@ -22,6 +22,10 @@ * This file is part of the TinyUSB stack. */ +#include "tusb_option.h" + +#if ((TUSB_OPT_HOST_ENABLED && CFG_TUH_HID) || _UNITY_TEST_) + #include "hid_rip.h" #include "hid.h" @@ -174,86 +178,6 @@ uint32_t hidrip_report_total_size_bits(tuh_hid_rip_state_t *state) } } -uint8_t hidrip_parse_report_descriptor(tuh_hid_report_info_t* report_info_arr, uint8_t arr_count, uint8_t const* desc_report, uint16_t desc_len) -{ - // Prepare the summary array - tu_memclr(report_info_arr, arr_count*sizeof(tuh_hid_report_info_t)); - uint8_t report_num = 0; - tuh_hid_report_info_t* info = report_info_arr; - uint8_t ri_report_count = 0; - uint8_t ri_report_size = 0; - - tuh_hid_rip_state_t pstate; - hidrip_init_state(&pstate, desc_report, desc_len); - int il = 0; - const uint8_t *ri; - while((ri = hidrip_next_item(&pstate)) != NULL) - { - if (!hidri_is_long(ri)) - { - uint8_t const tag = hidri_short_tag(ri); - uint8_t const type = hidri_short_type(ri); - switch(type) - { - case RI_TYPE_MAIN: { - switch (tag) - { - case RI_MAIN_INPUT: { - info->in_len += hidrip_report_total_size_bits(&pstate); - break; - } - case RI_MAIN_OUTPUT: { - info->out_len += hidrip_report_total_size_bits(&pstate); - break; - } - default: break; - } - break; - } - case RI_TYPE_GLOBAL: { - switch(tag) - { - case RI_GLOBAL_REPORT_ID: { - if (info->in_len > 0 || info->out_len > 0) { - info++; - report_num++; - } - info->report_id = hidri_short_udata8(hidrip_current_item(&pstate)); - break; - } - default: break; - } - break; - } - case RI_TYPE_LOCAL: { - switch(tag) - { - case RI_LOCAL_USAGE: - // only take in account the "usage" before starting REPORT ID - if ( pstate.collections_count == 0 ) { - uint32_t eusage = pstate.usages[pstate.usage_count - 1]; - info->usage = eusage & 0xffff; - info->usage_page = eusage >> 16; - } - break; - - default: break; - } - break; - } - // error - default: break; - } - } - } - - for ( uint8_t i = 0; i < report_num; i++ ) - { - info = report_info_arr+i; - TU_LOG2("%u: id = %u, usage_page = %u, usage = %u\r\n", i, info->report_id, info->usage_page, info->usage); - } - - return report_num; -} +#endif diff --git a/src/class/hid/hid_rip.h b/src/class/hid/hid_rip.h index 2e9cfebda5..d7832afb17 100644 --- a/src/class/hid/hid_rip.h +++ b/src/class/hid/hid_rip.h @@ -28,9 +28,6 @@ #include "tusb.h" #include "hid_ri.h" -// TODO this probably does not belong in here -#include "hid_host.h" - #ifdef __cplusplus extern "C" { #endif @@ -92,18 +89,5 @@ const uint8_t* hidrip_current_item(tuh_hid_rip_state_t *state); // Return report_size * report_count uint32_t hidrip_report_total_size_bits(tuh_hid_rip_state_t *state); - -// Fetch some basic information from the HID report descriptor -// -// Experimental replacement for tuh_hid_parse_report_descriptor -// Possibly implementation in hid_host.c should just be replaced. -// Handy here for now as I can test it and not break the rest of the stack -// -// TODO this probably does not belong in here -uint8_t hidrip_parse_report_descriptor(tuh_hid_report_info_t* report_info_arr, uint8_t arr_count, uint8_t const* desc_report, uint16_t desc_len); - - - - #endif diff --git a/src/host/hcd.h b/src/host/hcd.h index eb53d2e80e..0bcca796a2 100644 --- a/src/host/hcd.h +++ b/src/host/hcd.h @@ -82,7 +82,7 @@ typedef struct } hcd_event_t; -#if TUSB_OPT_HOST_ENABLED +#if TUSB_OPT_HOST_ENABLED || _UNITY_TEST_ // Max number of endpoints per device enum { // TODO better computation diff --git a/test/project.yml b/test/project.yml index dc4a9cb28c..cca876b47e 100644 --- a/test/project.yml +++ b/test/project.yml @@ -49,6 +49,10 @@ - *common_defines :test_preprocess: - *common_defines + :test_hid_host: + - *common_defines + - CFG_TUSB_RHPORT0_MODE + - CFG_TUH_HID :cmock: :mock_prefix: mock_ diff --git a/test/test/class/hid/test_hid_host.c b/test/test/class/hid/test_hid_host.c new file mode 100644 index 0000000000..0638c03f5b --- /dev/null +++ b/test/test/class/hid/test_hid_host.c @@ -0,0 +1,51 @@ +/* + * 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. + * + * This file is part of the TinyUSB stack. + */ + +#include "unity.h" + +// Files to test +#include "tusb_option.h" + +#include "hid_host.h" + +TEST_FILE("hid_ri.c") +TEST_FILE("hid_rip.c") +TEST_FILE("hid_host.c") + +void setUp(void) +{ +} + +void tearDown(void) +{ +} + +//--------------------------------------------------------------------+ +// Tests +//--------------------------------------------------------------------+ +void test_nothing() { + + +} + diff --git a/test/test/class/hid/test_hid_ri.c b/test/test/class/hid/test_hid_ri.c index e3cdd13fe0..09805497ee 100644 --- a/test/test/class/hid/test_hid_ri.c +++ b/test/test/class/hid/test_hid_ri.c @@ -26,6 +26,9 @@ #include "unity.h" // Files to test +#include "hid_host.h" + + #include "hid_ri.h" TEST_FILE("hid_ri.c") From 8f5792f8b430ff6adc7646d849a7849261c10fe7 Mon Sep 17 00:00:00 2001 From: Phil Date: Sat, 5 Feb 2022 22:23:23 +0000 Subject: [PATCH 23/71] HID micro parser --- src/class/hid/hid_host.c | 88 +---------------------------- src/class/hid/hid_host.h | 17 +----- src/class/hid/hid_rip.c | 86 ++++++++++++++++++++++++++++ src/class/hid/hid_rip.h | 19 +++++++ test/project.yml | 4 -- test/test/class/hid/test_hid_host.c | 51 ----------------- test/test/class/hid/test_hid_ri.c | 4 -- test/test/class/hid/test_hid_rip.c | 41 ++++++++++++++ 8 files changed, 148 insertions(+), 162 deletions(-) delete mode 100644 test/test/class/hid/test_hid_host.c diff --git a/src/class/hid/hid_host.c b/src/class/hid/hid_host.c index 0f01aef279..065b2059a9 100644 --- a/src/class/hid/hid_host.c +++ b/src/class/hid/hid_host.c @@ -26,7 +26,7 @@ #include "tusb_option.h" -#if (TUSB_OPT_HOST_ENABLED && CFG_TUH_HID) +#if ((TUSB_OPT_HOST_ENABLED && CFG_TUH_HID) || _UNITY_TEST_) #include "host/usbh.h" #include "host/usbh_classdriver.h" @@ -450,92 +450,6 @@ static void config_driver_mount_complete(uint8_t dev_addr, uint8_t instance, uin usbh_driver_set_config_complete(dev_addr, hid_itf->itf_num); } -//--------------------------------------------------------------------+ -// Report Descriptor Parser -//--------------------------------------------------------------------+ -uint8_t tuh_hid_parse_report_descriptor(tuh_hid_report_info_t* report_info_arr, uint8_t arr_count, uint8_t const* desc_report, uint16_t desc_len) -{ - // Prepare the summary array - tu_memclr(report_info_arr, arr_count*sizeof(tuh_hid_report_info_t)); - uint8_t report_num = 0; - tuh_hid_report_info_t* info = report_info_arr; - uint8_t ri_report_count = 0; - uint8_t ri_report_size = 0; - - tuh_hid_rip_state_t pstate; - hidrip_init_state(&pstate, desc_report, desc_len); - int il = 0; - const uint8_t *ri; - while((ri = hidrip_next_item(&pstate)) != NULL) - { - if (!hidri_is_long(ri)) - { - uint8_t const tag = hidri_short_tag(ri); - uint8_t const type = hidri_short_type(ri); - switch(type) - { - case RI_TYPE_MAIN: { - switch (tag) - { - case RI_MAIN_INPUT: { - info->in_len += hidrip_report_total_size_bits(&pstate); - break; - } - case RI_MAIN_OUTPUT: { - info->out_len += hidrip_report_total_size_bits(&pstate); - break; - } - default: break; - } - break; - } - case RI_TYPE_GLOBAL: { - switch(tag) - { - case RI_GLOBAL_REPORT_ID: { - if (info->in_len > 0 || info->out_len > 0) { - info++; - report_num++; - } - info->report_id = hidri_short_udata8(hidrip_current_item(&pstate)); - break; - } - default: break; - } - break; - } - case RI_TYPE_LOCAL: { - switch(tag) - { - case RI_LOCAL_USAGE: - // only take in account the "usage" before starting REPORT ID - if ( pstate.collections_count == 0 ) { - uint32_t eusage = pstate.usages[pstate.usage_count - 1]; - info->usage = eusage & 0xffff; - info->usage_page = eusage >> 16; - } - break; - - default: break; - } - break; - } - // error - default: break; - } - } - } - - for ( uint8_t i = 0; i < report_num; i++ ) - { - info = report_info_arr+i; - TU_LOG2("%u: id = %02X, usage_page = %04X, usage = %04X\r\n", i, info->report_id, info->usage_page, info->usage); - printf("%u: id = %02X, usage_page = %04X, usage = %04X\r\n", i, info->report_id, info->usage_page, info->usage); - } - - return report_num; -} - //--------------------------------------------------------------------+ // Helper //--------------------------------------------------------------------+ diff --git a/src/class/hid/hid_host.h b/src/class/hid/hid_host.h index a90599ee57..3cec5fe6a0 100644 --- a/src/class/hid/hid_host.h +++ b/src/class/hid/hid_host.h @@ -28,6 +28,7 @@ #define _TUSB_HID_HOST_H_ #include "hid.h" +#include "hid_rip.h" #ifdef __cplusplus extern "C" { @@ -46,18 +47,6 @@ #define CFG_TUH_HID_EPOUT_BUFSIZE 64 #endif - -typedef struct -{ - uint8_t report_id; - uint16_t usage; - uint16_t usage_page; - - // TODO still use the endpoint size for now - uint16_t in_len; // length of IN report in bits - uint16_t out_len; // length of OUT report in bits -} tuh_hid_report_info_t; - //--------------------------------------------------------------------+ // Interface API //--------------------------------------------------------------------+ @@ -71,10 +60,6 @@ bool tuh_hid_mounted(uint8_t dev_addr, uint8_t instance); // Get interface supported protocol (bInterfaceProtocol) check out hid_interface_protocol_enum_t for possible values uint8_t tuh_hid_interface_protocol(uint8_t dev_addr, uint8_t instance); -// Parse report descriptor into array of report_info struct and return number of reports. -// For complicated report, application should write its own parser. -uint8_t tuh_hid_parse_report_descriptor(tuh_hid_report_info_t* reports_info_arr, uint8_t arr_count, uint8_t const* desc_report, uint16_t desc_len) TU_ATTR_UNUSED; - //--------------------------------------------------------------------+ // Control Endpoint API //--------------------------------------------------------------------+ diff --git a/src/class/hid/hid_rip.c b/src/class/hid/hid_rip.c index 25e0fcbbcc..60d251e9a8 100644 --- a/src/class/hid/hid_rip.c +++ b/src/class/hid/hid_rip.c @@ -178,6 +178,92 @@ uint32_t hidrip_report_total_size_bits(tuh_hid_rip_state_t *state) } } +//--------------------------------------------------------------------+ +// Report Descriptor Parser +//--------------------------------------------------------------------+ +uint8_t tuh_hid_parse_report_descriptor(tuh_hid_report_info_t* report_info_arr, uint8_t arr_count, uint8_t const* desc_report, uint16_t desc_len) +{ + // Prepare the summary array + tu_memclr(report_info_arr, arr_count*sizeof(tuh_hid_report_info_t)); + uint8_t report_num = 0; + tuh_hid_report_info_t* info = report_info_arr; + uint8_t ri_report_count = 0; + uint8_t ri_report_size = 0; + + tuh_hid_rip_state_t pstate; + hidrip_init_state(&pstate, desc_report, desc_len); + int il = 0; + const uint8_t *ri; + while((ri = hidrip_next_item(&pstate)) != NULL) + { + if (!hidri_is_long(ri)) + { + uint8_t const tag = hidri_short_tag(ri); + uint8_t const type = hidri_short_type(ri); + switch(type) + { + case RI_TYPE_MAIN: { + switch (tag) + { + case RI_MAIN_INPUT: { + info->in_len += hidrip_report_total_size_bits(&pstate); + break; + } + case RI_MAIN_OUTPUT: { + info->out_len += hidrip_report_total_size_bits(&pstate); + break; + } + default: break; + } + break; + } + case RI_TYPE_GLOBAL: { + switch(tag) + { + case RI_GLOBAL_REPORT_ID: { + if (info->in_len > 0 || info->out_len > 0) { + info++; + report_num++; + } + info->report_id = hidri_short_udata8(hidrip_current_item(&pstate)); + break; + } + default: break; + } + break; + } + case RI_TYPE_LOCAL: { + switch(tag) + { + case RI_LOCAL_USAGE: + // only take in account the "usage" before starting REPORT ID + if ( pstate.collections_count == 0 ) { + uint32_t eusage = pstate.usages[pstate.usage_count - 1]; + info->usage = eusage & 0xffff; + info->usage_page = eusage >> 16; + } + break; + + default: break; + } + break; + } + // error + default: break; + } + } + } + + for ( uint8_t i = 0; i < report_num; i++ ) + { + info = report_info_arr+i; + TU_LOG2("%u: id = %02X, usage_page = %04X, usage = %04X\r\n", i, info->report_id, info->usage_page, info->usage); + printf("%u: id = %02X, usage_page = %04X, usage = %04X\r\n", i, info->report_id, info->usage_page, info->usage); + } + + return report_num; +} + #endif diff --git a/src/class/hid/hid_rip.h b/src/class/hid/hid_rip.h index d7832afb17..e4447ba42e 100644 --- a/src/class/hid/hid_rip.h +++ b/src/class/hid/hid_rip.h @@ -27,6 +27,8 @@ #include "tusb.h" #include "hid_ri.h" +#include "hid.h" +#include "tusb_compiler.h" #ifdef __cplusplus extern "C" { @@ -64,6 +66,19 @@ typedef struct tuh_hid_rip_state { uint32_t usages[HID_REPORT_MAX_USAGES]; } tuh_hid_rip_state_t; + +typedef struct +{ + uint8_t report_id; + uint16_t usage; + uint16_t usage_page; + + // TODO still use the endpoint size for now + uint16_t in_len; // length of IN report in bits + uint16_t out_len; // length of OUT report in bits +} tuh_hid_report_info_t; + + // Initialise a report item descriptor parser void hidrip_init_state(tuh_hid_rip_state_t *state, const uint8_t *report, uint16_t length); @@ -89,5 +104,9 @@ const uint8_t* hidrip_current_item(tuh_hid_rip_state_t *state); // Return report_size * report_count uint32_t hidrip_report_total_size_bits(tuh_hid_rip_state_t *state); +// Parse report descriptor into array of report_info struct and return number of reports. +// For complicated report, application should write its own parser. +uint8_t tuh_hid_parse_report_descriptor(tuh_hid_report_info_t* reports_info_arr, uint8_t arr_count, uint8_t const* desc_report, uint16_t desc_len) TU_ATTR_UNUSED; + #endif diff --git a/test/project.yml b/test/project.yml index cca876b47e..dc4a9cb28c 100644 --- a/test/project.yml +++ b/test/project.yml @@ -49,10 +49,6 @@ - *common_defines :test_preprocess: - *common_defines - :test_hid_host: - - *common_defines - - CFG_TUSB_RHPORT0_MODE - - CFG_TUH_HID :cmock: :mock_prefix: mock_ diff --git a/test/test/class/hid/test_hid_host.c b/test/test/class/hid/test_hid_host.c deleted file mode 100644 index 0638c03f5b..0000000000 --- a/test/test/class/hid/test_hid_host.c +++ /dev/null @@ -1,51 +0,0 @@ -/* - * 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. - * - * This file is part of the TinyUSB stack. - */ - -#include "unity.h" - -// Files to test -#include "tusb_option.h" - -#include "hid_host.h" - -TEST_FILE("hid_ri.c") -TEST_FILE("hid_rip.c") -TEST_FILE("hid_host.c") - -void setUp(void) -{ -} - -void tearDown(void) -{ -} - -//--------------------------------------------------------------------+ -// Tests -//--------------------------------------------------------------------+ -void test_nothing() { - - -} - diff --git a/test/test/class/hid/test_hid_ri.c b/test/test/class/hid/test_hid_ri.c index 09805497ee..04563c7cd7 100644 --- a/test/test/class/hid/test_hid_ri.c +++ b/test/test/class/hid/test_hid_ri.c @@ -25,10 +25,6 @@ #include "unity.h" -// Files to test -#include "hid_host.h" - - #include "hid_ri.h" TEST_FILE("hid_ri.c") diff --git a/test/test/class/hid/test_hid_rip.c b/test/test/class/hid/test_hid_rip.c index e6df0b8ae0..2ad60452db 100644 --- a/test/test/class/hid/test_hid_rip.c +++ b/test/test/class/hid/test_hid_rip.c @@ -195,3 +195,44 @@ void test_total_size_bits(void) TEST_ASSERT_EQUAL(&tb[2], hidrip_next_item(&pstate)); TEST_ASSERT_EQUAL(16, hidrip_report_total_size_bits(&pstate)); } + + +void test_hid_parse_report_descriptor_single_report() { + const uint8_t const tb[] = { + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x02, // USAGE (Mouse) + 0xa1, 0x01, // COLLECTION (Application) + 0x09, 0x01, // USAGE (Pointer) + 0xa1, 0x00, // COLLECTION (Physical) + 0x05, 0x09, // USAGE_PAGE (Button) + 0x19, 0x01, // USAGE_MINIMUM (Button 1) + 0x29, 0x03, // USAGE_MAXIMUM (Button 3) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x95, 0x03, // REPORT_COUNT (3) + 0x75, 0x01, // REPORT_SIZE (1) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x05, // REPORT_SIZE (5) + 0x81, 0x03, // INPUT (Cnst,Var,Abs) + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x30, // USAGE (X) + 0x09, 0x31, // USAGE (Y) + 0x15, 0x81, // LOGICAL_MINIMUM (-127) + 0x25, 0x7f, // LOGICAL_MAXIMUM (127) + 0x75, 0x08, // REPORT_SIZE (8) + 0x95, 0x02, // REPORT_COUNT (2) + 0x81, 0x06, // INPUT (Data,Var,Rel) + 0xc0, // END_COLLECTION + 0xc0 // END_COLLECTION + }; + + tuh_hid_report_info_t report_info[3]; + + + tuh_hid_parse_report_descriptor(report_info, 3, (const uint8_t*)&tb, sizeof(tb)); + +} + + + From fd4466853ee46118bcb7fa534fc342d58ef7fdb7 Mon Sep 17 00:00:00 2001 From: Phil Date: Sat, 5 Feb 2022 22:43:50 +0000 Subject: [PATCH 24/71] HID micro parser --- src/class/hid/hid_rip.c | 4 ++-- test/test/class/hid/test_hid_rip.c | 10 +++++++--- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/src/class/hid/hid_rip.c b/src/class/hid/hid_rip.c index 60d251e9a8..b39037e0d3 100644 --- a/src/class/hid/hid_rip.c +++ b/src/class/hid/hid_rip.c @@ -254,14 +254,14 @@ uint8_t tuh_hid_parse_report_descriptor(tuh_hid_report_info_t* report_info_arr, } } - for ( uint8_t i = 0; i < report_num; i++ ) + for ( uint8_t i = 0; i < report_num + 1; i++ ) { info = report_info_arr+i; TU_LOG2("%u: id = %02X, usage_page = %04X, usage = %04X\r\n", i, info->report_id, info->usage_page, info->usage); printf("%u: id = %02X, usage_page = %04X, usage = %04X\r\n", i, info->report_id, info->usage_page, info->usage); } - return report_num; + return report_num + 1; } #endif diff --git a/test/test/class/hid/test_hid_rip.c b/test/test/class/hid/test_hid_rip.c index 2ad60452db..d7fa09fbfd 100644 --- a/test/test/class/hid/test_hid_rip.c +++ b/test/test/class/hid/test_hid_rip.c @@ -229,9 +229,13 @@ void test_hid_parse_report_descriptor_single_report() { tuh_hid_report_info_t report_info[3]; - - tuh_hid_parse_report_descriptor(report_info, 3, (const uint8_t*)&tb, sizeof(tb)); - + uint8_t report_count = tuh_hid_parse_report_descriptor(report_info, 3, (const uint8_t*)&tb, sizeof(tb)); + TEST_ASSERT_EQUAL(1, report_count); + TEST_ASSERT_EQUAL(1, report_info[0].usage_page); + TEST_ASSERT_EQUAL(2, report_info[0].usage); + TEST_ASSERT_EQUAL(2, report_info[0].usage); + TEST_ASSERT_EQUAL(3*1 + 1*5 + 8*2, report_info[0].in_len); + TEST_ASSERT_EQUAL(0, report_info[0].out_len); } From f7ad24c256242362e43221ec6a442ad6503a1276 Mon Sep 17 00:00:00 2001 From: Phil Date: Sat, 5 Feb 2022 23:04:15 +0000 Subject: [PATCH 25/71] HID micro parser --- test/test/class/hid/test_hid_rip.c | 44 ++++++++++++++++++++++++++++-- 1 file changed, 42 insertions(+), 2 deletions(-) diff --git a/test/test/class/hid/test_hid_rip.c b/test/test/class/hid/test_hid_rip.c index d7fa09fbfd..daf6d0f339 100644 --- a/test/test/class/hid/test_hid_rip.c +++ b/test/test/class/hid/test_hid_rip.c @@ -197,7 +197,7 @@ void test_total_size_bits(void) } -void test_hid_parse_report_descriptor_single_report() { +void test_hid_parse_report_descriptor_single_mouse_report() { const uint8_t const tb[] = { 0x05, 0x01, // USAGE_PAGE (Generic Desktop) 0x09, 0x02, // USAGE (Mouse) @@ -233,10 +233,50 @@ void test_hid_parse_report_descriptor_single_report() { TEST_ASSERT_EQUAL(1, report_count); TEST_ASSERT_EQUAL(1, report_info[0].usage_page); TEST_ASSERT_EQUAL(2, report_info[0].usage); - TEST_ASSERT_EQUAL(2, report_info[0].usage); + TEST_ASSERT_EQUAL(0, report_info[0].report_id); TEST_ASSERT_EQUAL(3*1 + 1*5 + 8*2, report_info[0].in_len); TEST_ASSERT_EQUAL(0, report_info[0].out_len); } +void test_hid_parse_report_descriptor_single_gamepad_report() { + const uint8_t const tb[] = { + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x05, // USAGE (Game Pad) + 0xa1, 0x01, // COLLECTION (Application) + 0xa1, 0x00, // COLLECTION (Physical) + // ReportID - 8 bits + 0x85, 0x01, // REPORT_ID (1) + // X & Y - 2x8 = 16 bits + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x30, // USAGE (X) + 0x09, 0x31, // USAGE (Y) + 0x15, 0x81, // LOGICAL_MINIMUM (-127) + 0x25, 0x7f, // LOGICAL_MAXIMUM (127) + 0x75, 0x08, // REPORT_SIZE (8) + 0x95, 0x02, // REPORT_COUNT (2) + 0x81, 0x02, // INPUT (Data,Var,Abs) + // Buttons - 8 bits + 0x05, 0x09, // USAGE_PAGE (Button) + 0x19, 0x01, // USAGE_MINIMUM (Button 1) + 0x29, 0x08, // USAGE_MAXIMUM (Button 8) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x75, 0x08, // REPORT_SIZE (8) + 0x95, 0x01, // REPORT_COUNT (1) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0xc0, // END_COLLECTION + 0xc0 // END_COLLECTION + }; + + tuh_hid_report_info_t report_info[3]; + + uint8_t report_count = tuh_hid_parse_report_descriptor(report_info, 3, (const uint8_t*)&tb, sizeof(tb)); + TEST_ASSERT_EQUAL(1, report_count); + TEST_ASSERT_EQUAL(1, report_info[0].usage_page); + TEST_ASSERT_EQUAL(5, report_info[0].usage); + TEST_ASSERT_EQUAL(1, report_info[0].report_id); + TEST_ASSERT_EQUAL(8*2 + 8*1, report_info[0].in_len); + TEST_ASSERT_EQUAL(0, report_info[0].out_len); +} From af7d3ca23ea69b07c66a353cc5bc86628befebf5 Mon Sep 17 00:00:00 2001 From: Phil Date: Sat, 5 Feb 2022 23:12:25 +0000 Subject: [PATCH 26/71] HID micro parser --- test/test/class/hid/test_hid_rip.c | 41 ++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/test/test/class/hid/test_hid_rip.c b/test/test/class/hid/test_hid_rip.c index daf6d0f339..05078c058c 100644 --- a/test/test/class/hid/test_hid_rip.c +++ b/test/test/class/hid/test_hid_rip.c @@ -279,4 +279,45 @@ void test_hid_parse_report_descriptor_single_gamepad_report() { TEST_ASSERT_EQUAL(0, report_info[0].out_len); } +void test_hid_parse_report_descriptor_dual_report() { + const uint8_t const tb[] = { + 0x09, 0x01, // Usage (Consumer Control) + 0xA1, 0x01, // Collection (Application) + + 0x85, 0x01, // Report ID (1) + 0x05, 0x0C, // Usage Page (Consumer) + 0x15, 0x00, // Logical Minimum (0) + 0x25, 0x01, // Logical Maximum (1) + 0x75, 0x01, // Report Size (1) + 0x95, 0x01, // Report Count (1) + 0x09, 0xE2, // Usage (Mute) + 0x81, 0x62, // Input (Data,Var,Abs,No Wrap,Linear,No Preferred State,Null State) + + 0x85, 0x02, // Report ID (2) + 0x05, 0x0C, // Usage Page (Consumer) + 0x15, 0x00, // Logical Minimum (0) + 0x25, 0x01, // Logical Maximum (1) + 0x75, 0x01, // Report Size (1) + 0x95, 0x01, // Report Count (1) + 0x09, 0xE2, // Usage (Mute) + 0x81, 0x62, // Input (Data,Var,Abs,No Wrap,Linear,No Preferred State,Null State) + 0xC0, // End Collection + }; + + tuh_hid_report_info_t report_info[3]; + + uint8_t report_count = tuh_hid_parse_report_descriptor(report_info, 3, (const uint8_t*)&tb, sizeof(tb)); + TEST_ASSERT_EQUAL(2, report_count); + TEST_ASSERT_EQUAL(0, report_info[0].usage_page); + TEST_ASSERT_EQUAL(1, report_info[0].usage); + TEST_ASSERT_EQUAL(1, report_info[0].report_id); + TEST_ASSERT_EQUAL(1*1, report_info[0].in_len); + TEST_ASSERT_EQUAL(0, report_info[0].out_len); + TEST_ASSERT_EQUAL(0, report_info[1].usage_page); + TEST_ASSERT_EQUAL(1, report_info[1].usage); + TEST_ASSERT_EQUAL(2, report_info[1].report_id); + TEST_ASSERT_EQUAL(1*1, report_info[1].in_len); + TEST_ASSERT_EQUAL(0, report_info[1].out_len); +} + From d31a61e3735d6b9d31980ad22cb1634d4187198c Mon Sep 17 00:00:00 2001 From: Phil Date: Sun, 6 Feb 2022 07:53:29 +0000 Subject: [PATCH 27/71] HID micro parser --- src/class/hid/hid_rip.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/src/class/hid/hid_rip.c b/src/class/hid/hid_rip.c index b39037e0d3..08009ef61f 100644 --- a/src/class/hid/hid_rip.c +++ b/src/class/hid/hid_rip.c @@ -186,13 +186,12 @@ uint8_t tuh_hid_parse_report_descriptor(tuh_hid_report_info_t* report_info_arr, // Prepare the summary array tu_memclr(report_info_arr, arr_count*sizeof(tuh_hid_report_info_t)); uint8_t report_num = 0; + uint16_t usage = 0; + uint16_t usage_page = 0; + tuh_hid_report_info_t* info = report_info_arr; - uint8_t ri_report_count = 0; - uint8_t ri_report_size = 0; - tuh_hid_rip_state_t pstate; hidrip_init_state(&pstate, desc_report, desc_len); - int il = 0; const uint8_t *ri; while((ri = hidrip_next_item(&pstate)) != NULL) { @@ -207,10 +206,14 @@ uint8_t tuh_hid_parse_report_descriptor(tuh_hid_report_info_t* report_info_arr, { case RI_MAIN_INPUT: { info->in_len += hidrip_report_total_size_bits(&pstate); + info->usage = usage; + info->usage_page = usage_page; break; } case RI_MAIN_OUTPUT: { info->out_len += hidrip_report_total_size_bits(&pstate); + info->usage = usage; + info->usage_page = usage_page; break; } default: break; @@ -225,7 +228,7 @@ uint8_t tuh_hid_parse_report_descriptor(tuh_hid_report_info_t* report_info_arr, info++; report_num++; } - info->report_id = hidri_short_udata8(hidrip_current_item(&pstate)); + info->report_id = hidri_short_udata8(ri); break; } default: break; @@ -239,8 +242,8 @@ uint8_t tuh_hid_parse_report_descriptor(tuh_hid_report_info_t* report_info_arr, // only take in account the "usage" before starting REPORT ID if ( pstate.collections_count == 0 ) { uint32_t eusage = pstate.usages[pstate.usage_count - 1]; - info->usage = eusage & 0xffff; - info->usage_page = eusage >> 16; + usage = eusage & 0xffff; + usage_page = eusage >> 16; } break; From 9229f02f43da838f6ae46276294dde3c16ba0e41 Mon Sep 17 00:00:00 2001 From: Phil Date: Sun, 6 Feb 2022 07:58:53 +0000 Subject: [PATCH 28/71] HID micro parser --- src/class/hid/hid_ri.c | 34 ++++----- src/class/hid/hid_ri.h | 22 +++--- src/class/hid/hid_rip.c | 52 +++++++------- src/class/hid/hid_rip.h | 12 ++-- test/test/class/hid/test_hid_ri.c | 108 ++++++++++++++--------------- test/test/class/hid/test_hid_rip.c | 82 +++++++++++----------- 6 files changed, 155 insertions(+), 155 deletions(-) diff --git a/src/class/hid/hid_ri.c b/src/class/hid/hid_ri.c index 2e832baa77..85e1742556 100644 --- a/src/class/hid/hid_ri.c +++ b/src/class/hid/hid_ri.c @@ -27,37 +27,37 @@ #include "hid_ri.h" -uint8_t hidri_short_data_length(const uint8_t *ri) { +uint8_t tuh_hid_ri_short_data_length(const uint8_t *ri) { // 0 -> 0, 1 -> 1, 2 -> 2, 3 -> 4 return (1 << (*ri & 3)) >> 1; } -uint8_t hidri_short_type(const uint8_t *ri) { +uint8_t tuh_hid_ri_short_type(const uint8_t *ri) { return (*ri >> 2) & 3; } -uint8_t hidri_short_tag(const uint8_t *ri) { +uint8_t tuh_hid_ri_short_tag(const uint8_t *ri) { return (*ri >> 4) & 15; } -bool hidri_is_long(const uint8_t *ri) { +bool tuh_hid_ri_is_long(const uint8_t *ri) { return *ri == 0xfe; } -uint32_t hidri_short_udata32(const uint8_t *ri) { +uint32_t tuh_hid_ri_short_udata32(const uint8_t *ri) { uint32_t d = 0; - uint8_t l = hidri_short_data_length(ri++); + uint8_t l = tuh_hid_ri_short_data_length(ri++); for(uint8_t i = 0; i < l; ++i) d |= ((uint32_t)(*ri++)) << (i << 3); return d; } -uint8_t hidri_short_udata8(const uint8_t *ri) { - return hidri_short_data_length(ri) > 0 ? ri[1] : 0; +uint8_t tuh_hid_ri_short_udata8(const uint8_t *ri) { + return tuh_hid_ri_short_data_length(ri) > 0 ? ri[1] : 0; } -int32_t hidri_short_data32(const uint8_t *ri) { +int32_t tuh_hid_ri_short_data32(const uint8_t *ri) { int32_t d = 0; - uint8_t l = hidri_short_data_length(ri++); + uint8_t l = tuh_hid_ri_short_data_length(ri++); bool negative = false; for(uint8_t i = 0; i < 4; ++i) { if (i < l) { @@ -72,28 +72,28 @@ int32_t hidri_short_data32(const uint8_t *ri) { return d; } -uint8_t hidri_long_data_length(const uint8_t *ri) { +uint8_t tuh_hid_ri_long_data_length(const uint8_t *ri) { return ri[1]; } -uint8_t hidri_long_tag(const uint8_t *ri) { +uint8_t tuh_hid_ri_long_tag(const uint8_t *ri) { return ri[2]; } -const uint8_t* hidri_long_item_data(const uint8_t *ri) { +const uint8_t* tuh_hid_ri_long_item_data(const uint8_t *ri) { return ri + 3; } -int16_t hidri_size(const uint8_t *ri, uint16_t l) { +int16_t tuh_hid_ri_size(const uint8_t *ri, uint16_t l) { // Make sure there is enough room for the header if (l < 1) return 0; // Calculate the short item length - uint16_t sl = 1 + hidri_short_data_length(ri); + uint16_t sl = 1 + tuh_hid_ri_short_data_length(ri); // check it fits if (l < sl) return -1; // Check if we need to worry about a long item - if (hidri_is_long(ri)) { - uint16_t ll = hidri_long_data_length(ri); + if (tuh_hid_ri_is_long(ri)) { + uint16_t ll = tuh_hid_ri_long_data_length(ri); uint16_t tl = sl + ll; if (l < tl) return -2; return tl; diff --git a/src/class/hid/hid_ri.h b/src/class/hid/hid_ri.h index 224f210107..ec63fb91a1 100644 --- a/src/class/hid/hid_ri.h +++ b/src/class/hid/hid_ri.h @@ -45,34 +45,34 @@ //--------------------------------------------------------------------+ // Get the length of a short item -uint8_t hidri_short_data_length(const uint8_t *ri); +uint8_t tuh_hid_ri_short_data_length(const uint8_t *ri); // Get the type of a short item -uint8_t hidri_short_type(const uint8_t *ri); +uint8_t tuh_hid_ri_short_type(const uint8_t *ri); // Get the tag from a short item -uint8_t hidri_short_tag(const uint8_t *ri); +uint8_t tuh_hid_ri_short_tag(const uint8_t *ri); // Test if the item is a long item -bool hidri_is_long(const uint8_t *ri); +bool tuh_hid_ri_is_long(const uint8_t *ri); // Get the short item data unsigned -uint32_t hidri_short_udata32(const uint8_t *ri); +uint32_t tuh_hid_ri_short_udata32(const uint8_t *ri); // Get the short item data unsigned -uint8_t hidri_short_udata8(const uint8_t *ri); +uint8_t tuh_hid_ri_short_udata8(const uint8_t *ri); // Get the short item data signed (with sign extend to uint32) -int32_t hidri_short_data32(const uint8_t *ri); +int32_t tuh_hid_ri_short_data32(const uint8_t *ri); // Get the data length of a long item -uint8_t hidri_long_data_length(const uint8_t *ri); +uint8_t tuh_hid_ri_long_data_length(const uint8_t *ri); // Get the tag from a long item -uint8_t hidri_long_tag(const uint8_t *ri); +uint8_t tuh_hid_ri_long_tag(const uint8_t *ri); // Get a pointer to the data in a long item -const uint8_t* hidri_long_item_data(const uint8_t *ri); +const uint8_t* tuh_hid_ri_long_item_data(const uint8_t *ri); // Get the size of the item in bytes // @@ -84,7 +84,7 @@ const uint8_t* hidri_long_item_data(const uint8_t *ri); // 0 -> eof, // -1 -> missing short bytes, // -2 -> missing long bytes -int16_t hidri_size(const uint8_t *ri, uint16_t l); +int16_t tuh_hid_ri_size(const uint8_t *ri, uint16_t l); #ifdef __cplusplus } diff --git a/src/class/hid/hid_rip.c b/src/class/hid/hid_rip.c index 08009ef61f..27153965c9 100644 --- a/src/class/hid/hid_rip.c +++ b/src/class/hid/hid_rip.c @@ -29,7 +29,7 @@ #include "hid_rip.h" #include "hid.h" -void hidrip_init_state(tuh_hid_rip_state_t *state, const uint8_t *report, uint16_t length) +void tuh_hid_rip_init_state(tuh_hid_rip_state_t *state, const uint8_t *report, uint16_t length) { state->cursor = report; state->length = length; @@ -41,7 +41,7 @@ void hidrip_init_state(tuh_hid_rip_state_t *state, const uint8_t *report, uint16 memset(&state->local_items, 0, sizeof(uint8_t*) * 16); } -const uint8_t* hidrip_next_item(tuh_hid_rip_state_t *state) +const uint8_t* tuh_hid_rip_next_item(tuh_hid_rip_state_t *state) { // Already at eof if (state->length == 0) return NULL; @@ -52,7 +52,7 @@ const uint8_t* hidrip_next_item(tuh_hid_rip_state_t *state) // Previous error encountered so do nothing if (il < 0) return NULL; - if (il > 0 && hidri_short_type(ri) == RI_TYPE_MAIN) { + if (il > 0 && tuh_hid_ri_short_type(ri) == RI_TYPE_MAIN) { // Clear down local state after a main item memset(&state->local_items, 0, sizeof(uint8_t*) * 16); state->usage_count = 0; @@ -70,16 +70,16 @@ const uint8_t* hidrip_next_item(tuh_hid_rip_state_t *state) } // Check the report item is valid - state->item_length = il = hidri_size(ri, state->length); + state->item_length = il = tuh_hid_ri_size(ri, state->length); if (il <= 0) { // record error somewhere return NULL; } - if (il > 0 && !hidri_is_long(ri)) { // For now ignore long items. - uint8_t short_type = hidri_short_type(ri); - uint8_t short_tag = hidri_short_tag(ri); + if (il > 0 && !tuh_hid_ri_is_long(ri)) { // For now ignore long items. + uint8_t short_type = tuh_hid_ri_short_type(ri); + uint8_t short_tag = tuh_hid_ri_short_tag(ri); switch (short_type) { case RI_TYPE_GLOBAL: state->global_items[state->stack_index][short_tag] = ri; @@ -102,10 +102,10 @@ const uint8_t* hidrip_next_item(tuh_hid_rip_state_t *state) case RI_TYPE_LOCAL: switch(short_tag) { case RI_LOCAL_USAGE: { - uint32_t usage = hidri_short_udata32(ri); - if (hidri_short_data_length(ri) <= 2) { + uint32_t usage = tuh_hid_ri_short_udata32(ri); + if (tuh_hid_ri_short_data_length(ri) <= 2) { const uint8_t* usage_page_item = state->global_items[state->stack_index][RI_GLOBAL_USAGE_PAGE]; - uint32_t usage_page = usage_page_item ? hidri_short_udata32(usage_page_item) : 0; + uint32_t usage_page = usage_page_item ? tuh_hid_ri_short_udata32(usage_page_item) : 0; usage |= usage_page << 16; } if (state->usage_count == HID_REPORT_MAX_USAGES) { @@ -145,30 +145,30 @@ const uint8_t* hidrip_next_item(tuh_hid_rip_state_t *state) return ri; } -const uint8_t* hidrip_global(tuh_hid_rip_state_t *state, uint8_t tag) +const uint8_t* tuh_hid_rip_global(tuh_hid_rip_state_t *state, uint8_t tag) { return state->global_items[state->stack_index][tag]; } -const uint8_t* hidrip_local(tuh_hid_rip_state_t *state, uint8_t tag) +const uint8_t* tuh_hid_rip_local(tuh_hid_rip_state_t *state, uint8_t tag) { return state->local_items[tag]; } -const uint8_t* hidrip_current_item(tuh_hid_rip_state_t *state) +const uint8_t* tuh_hid_rip_current_item(tuh_hid_rip_state_t *state) { return state->cursor; } -uint32_t hidrip_report_total_size_bits(tuh_hid_rip_state_t *state) +uint32_t tuh_hid_rip_report_total_size_bits(tuh_hid_rip_state_t *state) { - const uint8_t* ri_report_size = hidrip_global(state, RI_GLOBAL_REPORT_SIZE); - const uint8_t* ri_report_count = hidrip_global(state, RI_GLOBAL_REPORT_COUNT); + const uint8_t* ri_report_size = tuh_hid_rip_global(state, RI_GLOBAL_REPORT_SIZE); + const uint8_t* ri_report_count = tuh_hid_rip_global(state, RI_GLOBAL_REPORT_COUNT); if (ri_report_size != NULL && ri_report_count != NULL) { - uint32_t report_size = hidri_short_udata32(ri_report_size); - uint32_t report_count = hidri_short_udata32(ri_report_count); + uint32_t report_size = tuh_hid_ri_short_udata32(ri_report_size); + uint32_t report_count = tuh_hid_ri_short_udata32(ri_report_count); return report_size * report_count; } else @@ -191,27 +191,27 @@ uint8_t tuh_hid_parse_report_descriptor(tuh_hid_report_info_t* report_info_arr, tuh_hid_report_info_t* info = report_info_arr; tuh_hid_rip_state_t pstate; - hidrip_init_state(&pstate, desc_report, desc_len); + tuh_hid_rip_init_state(&pstate, desc_report, desc_len); const uint8_t *ri; - while((ri = hidrip_next_item(&pstate)) != NULL) + while((ri = tuh_hid_rip_next_item(&pstate)) != NULL) { - if (!hidri_is_long(ri)) + if (!tuh_hid_ri_is_long(ri)) { - uint8_t const tag = hidri_short_tag(ri); - uint8_t const type = hidri_short_type(ri); + uint8_t const tag = tuh_hid_ri_short_tag(ri); + uint8_t const type = tuh_hid_ri_short_type(ri); switch(type) { case RI_TYPE_MAIN: { switch (tag) { case RI_MAIN_INPUT: { - info->in_len += hidrip_report_total_size_bits(&pstate); + info->in_len += tuh_hid_rip_report_total_size_bits(&pstate); info->usage = usage; info->usage_page = usage_page; break; } case RI_MAIN_OUTPUT: { - info->out_len += hidrip_report_total_size_bits(&pstate); + info->out_len += tuh_hid_rip_report_total_size_bits(&pstate); info->usage = usage; info->usage_page = usage_page; break; @@ -228,7 +228,7 @@ uint8_t tuh_hid_parse_report_descriptor(tuh_hid_report_info_t* report_info_arr, info++; report_num++; } - info->report_id = hidri_short_udata8(ri); + info->report_id = tuh_hid_ri_short_udata8(ri); break; } default: break; diff --git a/src/class/hid/hid_rip.h b/src/class/hid/hid_rip.h index e4447ba42e..1ebf2ca52a 100644 --- a/src/class/hid/hid_rip.h +++ b/src/class/hid/hid_rip.h @@ -80,29 +80,29 @@ typedef struct // Initialise a report item descriptor parser -void hidrip_init_state(tuh_hid_rip_state_t *state, const uint8_t *report, uint16_t length); +void tuh_hid_rip_init_state(tuh_hid_rip_state_t *state, const uint8_t *report, uint16_t length); // Move to the next item in the report // // returns pointer to next item or null // -const uint8_t* hidrip_next_item(tuh_hid_rip_state_t *state); +const uint8_t* tuh_hid_rip_next_item(tuh_hid_rip_state_t *state); // Accessor for the curren value of a global item // // Returns a pointer to the start of the item of null -const uint8_t* hidrip_global(tuh_hid_rip_state_t *state, uint8_t tag); +const uint8_t* tuh_hid_rip_global(tuh_hid_rip_state_t *state, uint8_t tag); // Accessor for the curren value of a local item // // Returns a pointer to the start of the item of null -const uint8_t* hidrip_local(tuh_hid_rip_state_t *state, uint8_t tag); +const uint8_t* tuh_hid_rip_local(tuh_hid_rip_state_t *state, uint8_t tag); // Returns a pointer to the start of the item or NULL for eof -const uint8_t* hidrip_current_item(tuh_hid_rip_state_t *state); +const uint8_t* tuh_hid_rip_current_item(tuh_hid_rip_state_t *state); // Return report_size * report_count -uint32_t hidrip_report_total_size_bits(tuh_hid_rip_state_t *state); +uint32_t tuh_hid_rip_report_total_size_bits(tuh_hid_rip_state_t *state); // Parse report descriptor into array of report_info struct and return number of reports. // For complicated report, application should write its own parser. diff --git a/test/test/class/hid/test_hid_ri.c b/test/test/class/hid/test_hid_ri.c index 04563c7cd7..7f277de203 100644 --- a/test/test/class/hid/test_hid_ri.c +++ b/test/test/class/hid/test_hid_ri.c @@ -43,95 +43,95 @@ void test_short_item_length(void) { uint8_t tb[] = { 0x00, 0x01, 0x02, 0x03 }; - TEST_ASSERT_EQUAL(0, hidri_short_data_length(&tb[0])); - TEST_ASSERT_EQUAL(1, hidri_short_data_length(&tb[1])); - TEST_ASSERT_EQUAL(2, hidri_short_data_length(&tb[2])); - TEST_ASSERT_EQUAL(4, hidri_short_data_length(&tb[3])); + TEST_ASSERT_EQUAL(0, tuh_hid_ri_short_data_length(&tb[0])); + TEST_ASSERT_EQUAL(1, tuh_hid_ri_short_data_length(&tb[1])); + TEST_ASSERT_EQUAL(2, tuh_hid_ri_short_data_length(&tb[2])); + TEST_ASSERT_EQUAL(4, tuh_hid_ri_short_data_length(&tb[3])); } void test_short_item_size_check(void) { uint8_t tb[] = { 0x46, 0x3B, 0x01 }; /* Physical Maximum (315) */ - TEST_ASSERT_EQUAL( 3, hidri_size(tb, 3)); - TEST_ASSERT_EQUAL(-1, hidri_size(tb, 2)); - TEST_ASSERT_EQUAL(-1, hidri_size(tb, 1)); - TEST_ASSERT_EQUAL( 0, hidri_size(tb, 0)); + TEST_ASSERT_EQUAL( 3, tuh_hid_ri_size(tb, 3)); + TEST_ASSERT_EQUAL(-1, tuh_hid_ri_size(tb, 2)); + TEST_ASSERT_EQUAL(-1, tuh_hid_ri_size(tb, 1)); + TEST_ASSERT_EQUAL( 0, tuh_hid_ri_size(tb, 0)); } void test_long_item(void) { uint8_t tb[] = { 0xfe, 0xff, 0x81, 0x01 }; - TEST_ASSERT_EQUAL(true, hidri_is_long(tb)); - TEST_ASSERT_EQUAL(2, hidri_short_data_length(tb)); - TEST_ASSERT_EQUAL(255, hidri_long_data_length(tb)); - TEST_ASSERT_EQUAL(0x81, hidri_long_tag(tb)); - TEST_ASSERT_EQUAL(1, hidri_long_item_data(tb)[0]); - TEST_ASSERT_EQUAL(3 + 255, hidri_size(tb, 3 + 255)); + TEST_ASSERT_EQUAL(true, tuh_hid_ri_is_long(tb)); + TEST_ASSERT_EQUAL(2, tuh_hid_ri_short_data_length(tb)); + TEST_ASSERT_EQUAL(255, tuh_hid_ri_long_data_length(tb)); + TEST_ASSERT_EQUAL(0x81, tuh_hid_ri_long_tag(tb)); + TEST_ASSERT_EQUAL(1, tuh_hid_ri_long_item_data(tb)[0]); + TEST_ASSERT_EQUAL(3 + 255, tuh_hid_ri_size(tb, 3 + 255)); } void test_long_item_size_check(void) { uint8_t tb[] = { 0xfe, 0xff, 0x81, 0x01 }; - TEST_ASSERT_EQUAL(3 + 255, hidri_size(tb, 3 + 255)); - TEST_ASSERT_EQUAL(-2, hidri_size(tb, 3 + 254)); - TEST_ASSERT_EQUAL(-2, hidri_size(tb, 3)); - TEST_ASSERT_EQUAL(-1, hidri_size(tb, 2)); - TEST_ASSERT_EQUAL(-1, hidri_size(tb, 1)); - TEST_ASSERT_EQUAL( 0, hidri_size(tb, 0)); + TEST_ASSERT_EQUAL(3 + 255, tuh_hid_ri_size(tb, 3 + 255)); + TEST_ASSERT_EQUAL(-2, tuh_hid_ri_size(tb, 3 + 254)); + TEST_ASSERT_EQUAL(-2, tuh_hid_ri_size(tb, 3)); + TEST_ASSERT_EQUAL(-1, tuh_hid_ri_size(tb, 2)); + TEST_ASSERT_EQUAL(-1, tuh_hid_ri_size(tb, 1)); + TEST_ASSERT_EQUAL( 0, tuh_hid_ri_size(tb, 0)); } void test_physical_max_315(void) { uint8_t tb[] = { 0x46, 0x3B, 0x01 }; /* Physical Maximum (315) */ - TEST_ASSERT_EQUAL(2, hidri_short_data_length(tb)); - TEST_ASSERT_EQUAL(1, hidri_short_type(tb)); - TEST_ASSERT_EQUAL(4, hidri_short_tag(tb)); - TEST_ASSERT_EQUAL(false, hidri_is_long(tb)); - TEST_ASSERT_EQUAL(315, hidri_short_udata32(tb)); - TEST_ASSERT_EQUAL(315, hidri_short_data32(tb)); - TEST_ASSERT_EQUAL(3, hidri_size(tb, 3)); + TEST_ASSERT_EQUAL(2, tuh_hid_ri_short_data_length(tb)); + TEST_ASSERT_EQUAL(1, tuh_hid_ri_short_type(tb)); + TEST_ASSERT_EQUAL(4, tuh_hid_ri_short_tag(tb)); + TEST_ASSERT_EQUAL(false, tuh_hid_ri_is_long(tb)); + TEST_ASSERT_EQUAL(315, tuh_hid_ri_short_udata32(tb)); + TEST_ASSERT_EQUAL(315, tuh_hid_ri_short_data32(tb)); + TEST_ASSERT_EQUAL(3, tuh_hid_ri_size(tb, 3)); } void test_physical_max_123(void) { uint8_t tb[] = { 0x46, 0x7B, 0x00 }; /* Physical Maximum (123) */ - TEST_ASSERT_EQUAL(2, hidri_short_data_length(tb)); - TEST_ASSERT_EQUAL(1, hidri_short_type(tb)); - TEST_ASSERT_EQUAL(4, hidri_short_tag(tb)); - TEST_ASSERT_EQUAL(false, hidri_is_long(tb)); - TEST_ASSERT_EQUAL(123, hidri_short_udata32(tb)); - TEST_ASSERT_EQUAL(123, hidri_short_udata8(tb)); - TEST_ASSERT_EQUAL(123, hidri_short_data32(tb)); - TEST_ASSERT_EQUAL(3, hidri_size(tb, 3)); + TEST_ASSERT_EQUAL(2, tuh_hid_ri_short_data_length(tb)); + TEST_ASSERT_EQUAL(1, tuh_hid_ri_short_type(tb)); + TEST_ASSERT_EQUAL(4, tuh_hid_ri_short_tag(tb)); + TEST_ASSERT_EQUAL(false, tuh_hid_ri_is_long(tb)); + TEST_ASSERT_EQUAL(123, tuh_hid_ri_short_udata32(tb)); + TEST_ASSERT_EQUAL(123, tuh_hid_ri_short_udata8(tb)); + TEST_ASSERT_EQUAL(123, tuh_hid_ri_short_data32(tb)); + TEST_ASSERT_EQUAL(3, tuh_hid_ri_size(tb, 3)); } void test_logical_min_neg_127(void) { uint8_t tb[] = { 0x15, 0x81 }; /* LOGICAL_MINIMUM (-127) */ - TEST_ASSERT_EQUAL(1, hidri_short_data_length(tb)); - TEST_ASSERT_EQUAL(1, hidri_short_type(tb)); - TEST_ASSERT_EQUAL(1, hidri_short_tag(tb)); - TEST_ASSERT_EQUAL(false, hidri_is_long(tb)); - TEST_ASSERT_EQUAL(0x81, hidri_short_udata32(tb)); - TEST_ASSERT_EQUAL(-127, hidri_short_data32(tb)); - TEST_ASSERT_EQUAL(2, hidri_size(tb, 2)); + TEST_ASSERT_EQUAL(1, tuh_hid_ri_short_data_length(tb)); + TEST_ASSERT_EQUAL(1, tuh_hid_ri_short_type(tb)); + TEST_ASSERT_EQUAL(1, tuh_hid_ri_short_tag(tb)); + TEST_ASSERT_EQUAL(false, tuh_hid_ri_is_long(tb)); + TEST_ASSERT_EQUAL(0x81, tuh_hid_ri_short_udata32(tb)); + TEST_ASSERT_EQUAL(-127, tuh_hid_ri_short_data32(tb)); + TEST_ASSERT_EQUAL(2, tuh_hid_ri_size(tb, 2)); } void test_logical_min_neg_32768(void) { uint8_t tb[] = { 0x16, 0x00, 0x80 }; // Logical Minimum (-32768) - TEST_ASSERT_EQUAL(2, hidri_short_data_length(tb)); - TEST_ASSERT_EQUAL(1, hidri_short_type(tb)); - TEST_ASSERT_EQUAL(1, hidri_short_tag(tb)); - TEST_ASSERT_EQUAL(false, hidri_is_long(tb)); - TEST_ASSERT_EQUAL(-32768, hidri_short_data32(tb)); - TEST_ASSERT_EQUAL(3, hidri_size(tb, 3)); + TEST_ASSERT_EQUAL(2, tuh_hid_ri_short_data_length(tb)); + TEST_ASSERT_EQUAL(1, tuh_hid_ri_short_type(tb)); + TEST_ASSERT_EQUAL(1, tuh_hid_ri_short_tag(tb)); + TEST_ASSERT_EQUAL(false, tuh_hid_ri_is_long(tb)); + TEST_ASSERT_EQUAL(-32768, tuh_hid_ri_short_data32(tb)); + TEST_ASSERT_EQUAL(3, tuh_hid_ri_size(tb, 3)); } // https://eleccelerator.com/usbdescreqparser/ says this should be -2147483648, @@ -140,12 +140,12 @@ void test_logical_min_neg_2147483647(void) { uint8_t tb[] = { 0x17, 0x01, 0x00, 0x00, 0x80 }; // Logical Minimum (-2147483647) - TEST_ASSERT_EQUAL(4, hidri_short_data_length(tb)); - TEST_ASSERT_EQUAL(1, hidri_short_type(tb)); - TEST_ASSERT_EQUAL(1, hidri_short_tag(tb)); - TEST_ASSERT_EQUAL(false, hidri_is_long(tb)); - TEST_ASSERT_EQUAL(-2147483647, hidri_short_data32(tb)); - TEST_ASSERT_EQUAL(5, hidri_size(tb, 5)); + TEST_ASSERT_EQUAL(4, tuh_hid_ri_short_data_length(tb)); + TEST_ASSERT_EQUAL(1, tuh_hid_ri_short_type(tb)); + TEST_ASSERT_EQUAL(1, tuh_hid_ri_short_tag(tb)); + TEST_ASSERT_EQUAL(false, tuh_hid_ri_is_long(tb)); + TEST_ASSERT_EQUAL(-2147483647, tuh_hid_ri_short_data32(tb)); + TEST_ASSERT_EQUAL(5, tuh_hid_ri_size(tb, 5)); } diff --git a/test/test/class/hid/test_hid_rip.c b/test/test/class/hid/test_hid_rip.c index 05078c058c..11f5796248 100644 --- a/test/test/class/hid/test_hid_rip.c +++ b/test/test/class/hid/test_hid_rip.c @@ -50,17 +50,17 @@ void test_next_simple(void) }; tuh_hid_rip_state_t pstate; - hidrip_init_state(&pstate, (uint8_t*)&tb, sizeof(tb)); - TEST_ASSERT_EQUAL(&tb[0], hidrip_next_item(&pstate)); + tuh_hid_rip_init_state(&pstate, (uint8_t*)&tb, sizeof(tb)); + TEST_ASSERT_EQUAL(&tb[0], tuh_hid_rip_next_item(&pstate)); TEST_ASSERT_EQUAL(2, pstate.item_length); TEST_ASSERT_EQUAL(0x05, *pstate.cursor); - TEST_ASSERT_EQUAL(&tb[2], hidrip_next_item(&pstate)); + TEST_ASSERT_EQUAL(&tb[2], tuh_hid_rip_next_item(&pstate)); TEST_ASSERT_EQUAL(2, pstate.item_length); TEST_ASSERT_EQUAL(0x09, *pstate.cursor); - TEST_ASSERT_EQUAL(&tb[4], hidrip_next_item(&pstate)); + TEST_ASSERT_EQUAL(&tb[4], tuh_hid_rip_next_item(&pstate)); TEST_ASSERT_EQUAL(2, pstate.item_length); TEST_ASSERT_EQUAL(0xA1, *pstate.cursor); - TEST_ASSERT_EQUAL(NULL, hidrip_next_item(&pstate)); + TEST_ASSERT_EQUAL(NULL, tuh_hid_rip_next_item(&pstate)); TEST_ASSERT_EQUAL(0, pstate.item_length); } @@ -72,12 +72,12 @@ void test_usage_with_page(void) }; tuh_hid_rip_state_t pstate; - hidrip_init_state(&pstate, (uint8_t*)&tb, sizeof(tb)); - TEST_ASSERT_EQUAL(&tb[0], hidrip_next_item(&pstate)); - TEST_ASSERT_EQUAL(0x01, hidri_short_udata32(pstate.cursor)); - TEST_ASSERT_EQUAL(&tb[2], hidrip_next_item(&pstate)); + tuh_hid_rip_init_state(&pstate, (uint8_t*)&tb, sizeof(tb)); + TEST_ASSERT_EQUAL(&tb[0], tuh_hid_rip_next_item(&pstate)); + TEST_ASSERT_EQUAL(0x01, tuh_hid_ri_short_udata32(pstate.cursor)); + TEST_ASSERT_EQUAL(&tb[2], tuh_hid_rip_next_item(&pstate)); TEST_ASSERT_EQUAL(1, pstate.usage_count); - TEST_ASSERT_EQUAL(0x02, hidri_short_udata32(pstate.cursor)); + TEST_ASSERT_EQUAL(0x02, tuh_hid_ri_short_udata32(pstate.cursor)); TEST_ASSERT_EQUAL(0x00010002, pstate.usages[0]); } @@ -89,12 +89,12 @@ void test_globals_recorded(void) }; tuh_hid_rip_state_t pstate; - hidrip_init_state(&pstate, (uint8_t*)&tb, sizeof(tb)); - TEST_ASSERT_EQUAL(&tb[0], hidrip_next_item(&pstate)); - TEST_ASSERT_EQUAL(&tb[2], hidrip_next_item(&pstate)); + tuh_hid_rip_init_state(&pstate, (uint8_t*)&tb, sizeof(tb)); + TEST_ASSERT_EQUAL(&tb[0], tuh_hid_rip_next_item(&pstate)); + TEST_ASSERT_EQUAL(&tb[2], tuh_hid_rip_next_item(&pstate)); TEST_ASSERT_EQUAL(0, pstate.stack_index); - TEST_ASSERT_EQUAL(0x01, hidri_short_udata32(pstate.global_items[pstate.stack_index][0])); - TEST_ASSERT_EQUAL(0x55, hidri_short_data32(pstate.global_items[pstate.stack_index][1])); + TEST_ASSERT_EQUAL(0x01, tuh_hid_ri_short_udata32(pstate.global_items[pstate.stack_index][0])); + TEST_ASSERT_EQUAL(0x55, tuh_hid_ri_short_data32(pstate.global_items[pstate.stack_index][1])); } void test_globals_overwritten(void) @@ -105,11 +105,11 @@ void test_globals_overwritten(void) }; tuh_hid_rip_state_t pstate; - hidrip_init_state(&pstate, (uint8_t*)&tb, sizeof(tb)); - TEST_ASSERT_EQUAL(&tb[0], hidrip_next_item(&pstate)); - TEST_ASSERT_EQUAL(&tb[2], hidrip_next_item(&pstate)); + tuh_hid_rip_init_state(&pstate, (uint8_t*)&tb, sizeof(tb)); + TEST_ASSERT_EQUAL(&tb[0], tuh_hid_rip_next_item(&pstate)); + TEST_ASSERT_EQUAL(&tb[2], tuh_hid_rip_next_item(&pstate)); TEST_ASSERT_EQUAL(0, pstate.stack_index); - TEST_ASSERT_EQUAL(0x09, hidri_short_udata32(hidrip_global(&pstate, 0))); + TEST_ASSERT_EQUAL(0x09, tuh_hid_ri_short_udata32(tuh_hid_rip_global(&pstate, 0))); } void test_push_pop(void) @@ -122,13 +122,13 @@ void test_push_pop(void) }; tuh_hid_rip_state_t pstate; - hidrip_init_state(&pstate, (uint8_t*)&tb, sizeof(tb)); - TEST_ASSERT_EQUAL(&tb[0], hidrip_next_item(&pstate)); - TEST_ASSERT_EQUAL(&tb[2], hidrip_next_item(&pstate)); - TEST_ASSERT_EQUAL(&tb[3], hidrip_next_item(&pstate)); - TEST_ASSERT_EQUAL(&tb[5], hidrip_next_item(&pstate)); + tuh_hid_rip_init_state(&pstate, (uint8_t*)&tb, sizeof(tb)); + TEST_ASSERT_EQUAL(&tb[0], tuh_hid_rip_next_item(&pstate)); + TEST_ASSERT_EQUAL(&tb[2], tuh_hid_rip_next_item(&pstate)); + TEST_ASSERT_EQUAL(&tb[3], tuh_hid_rip_next_item(&pstate)); + TEST_ASSERT_EQUAL(&tb[5], tuh_hid_rip_next_item(&pstate)); TEST_ASSERT_EQUAL(0, pstate.stack_index); - TEST_ASSERT_EQUAL(0x01, hidri_short_udata32(hidrip_global(&pstate, 0))); + TEST_ASSERT_EQUAL(0x01, tuh_hid_ri_short_udata32(tuh_hid_rip_global(&pstate, 0))); } // TODO test stack overflow @@ -146,15 +146,15 @@ void test_main_clears_local(void) }; tuh_hid_rip_state_t pstate; - hidrip_init_state(&pstate, (uint8_t*)&tb, sizeof(tb)); - TEST_ASSERT_EQUAL(&tb[0], hidrip_next_item(&pstate)); - TEST_ASSERT_EQUAL(&tb[2], hidrip_next_item(&pstate)); - TEST_ASSERT_EQUAL(&tb[4], hidrip_next_item(&pstate)); - TEST_ASSERT_EQUAL(&tb[6], hidrip_next_item(&pstate)); + tuh_hid_rip_init_state(&pstate, (uint8_t*)&tb, sizeof(tb)); + TEST_ASSERT_EQUAL(&tb[0], tuh_hid_rip_next_item(&pstate)); + TEST_ASSERT_EQUAL(&tb[2], tuh_hid_rip_next_item(&pstate)); + TEST_ASSERT_EQUAL(&tb[4], tuh_hid_rip_next_item(&pstate)); + TEST_ASSERT_EQUAL(&tb[6], tuh_hid_rip_next_item(&pstate)); TEST_ASSERT_EQUAL(1, pstate.usage_count); TEST_ASSERT_EQUAL(&tb[4], pstate.local_items[3]); - TEST_ASSERT_EQUAL(4, hidri_short_data32(pstate.local_items[3])); - TEST_ASSERT_EQUAL(&tb[8], hidrip_next_item(&pstate)); + TEST_ASSERT_EQUAL(4, tuh_hid_ri_short_data32(pstate.local_items[3])); + TEST_ASSERT_EQUAL(&tb[8], tuh_hid_rip_next_item(&pstate)); TEST_ASSERT_EQUAL(0, pstate.global_items[pstate.stack_index][3]); TEST_ASSERT_EQUAL(0, pstate.usage_count); } @@ -169,16 +169,16 @@ void test_collections(void) }; tuh_hid_rip_state_t pstate; - hidrip_init_state(&pstate, (uint8_t*)&tb, sizeof(tb)); - TEST_ASSERT_EQUAL(&tb[0], hidrip_next_item(&pstate)); + tuh_hid_rip_init_state(&pstate, (uint8_t*)&tb, sizeof(tb)); + TEST_ASSERT_EQUAL(&tb[0], tuh_hid_rip_next_item(&pstate)); TEST_ASSERT_EQUAL(1, pstate.collections_count); - TEST_ASSERT_EQUAL(&tb[2], hidrip_next_item(&pstate)); + TEST_ASSERT_EQUAL(&tb[2], tuh_hid_rip_next_item(&pstate)); TEST_ASSERT_EQUAL(2, pstate.collections_count); TEST_ASSERT_EQUAL(&tb[0], pstate.collections[0]); TEST_ASSERT_EQUAL(&tb[2], pstate.collections[1]); - TEST_ASSERT_EQUAL(&tb[4], hidrip_next_item(&pstate)); + TEST_ASSERT_EQUAL(&tb[4], tuh_hid_rip_next_item(&pstate)); TEST_ASSERT_EQUAL(1, pstate.collections_count); - TEST_ASSERT_EQUAL(&tb[5], hidrip_next_item(&pstate)); + TEST_ASSERT_EQUAL(&tb[5], tuh_hid_rip_next_item(&pstate)); TEST_ASSERT_EQUAL(0, pstate.collections_count); } @@ -190,10 +190,10 @@ void test_total_size_bits(void) }; tuh_hid_rip_state_t pstate; - hidrip_init_state(&pstate, (uint8_t*)&tb, sizeof(tb)); - TEST_ASSERT_EQUAL(&tb[0], hidrip_next_item(&pstate)); - TEST_ASSERT_EQUAL(&tb[2], hidrip_next_item(&pstate)); - TEST_ASSERT_EQUAL(16, hidrip_report_total_size_bits(&pstate)); + tuh_hid_rip_init_state(&pstate, (uint8_t*)&tb, sizeof(tb)); + TEST_ASSERT_EQUAL(&tb[0], tuh_hid_rip_next_item(&pstate)); + TEST_ASSERT_EQUAL(&tb[2], tuh_hid_rip_next_item(&pstate)); + TEST_ASSERT_EQUAL(16, tuh_hid_rip_report_total_size_bits(&pstate)); } From af0e05ff6852a459f710b9d22c6bebbadefa2670 Mon Sep 17 00:00:00 2001 From: Phil Date: Sun, 6 Feb 2022 08:11:18 +0000 Subject: [PATCH 29/71] HID micro parser --- src/class/hid/hid_ri.c | 5 +++++ src/class/hid/hid_ri.h | 3 +++ src/class/hid/hid_rip.c | 8 ++++---- test/test/class/hid/test_hid_ri.c | 10 +++++++++- 4 files changed, 21 insertions(+), 5 deletions(-) diff --git a/src/class/hid/hid_ri.c b/src/class/hid/hid_ri.c index 85e1742556..42f25b7cde 100644 --- a/src/class/hid/hid_ri.c +++ b/src/class/hid/hid_ri.c @@ -103,4 +103,9 @@ int16_t tuh_hid_ri_size(const uint8_t *ri, uint16_t l) { } } +void tuh_hid_ri_split_usage(uint32_t eusage, uint16_t *usage, uint16_t *usage_page) { + *usage = eusage & 0xffff; + *usage_page = eusage >> 16; +} + #endif diff --git a/src/class/hid/hid_ri.h b/src/class/hid/hid_ri.h index ec63fb91a1..b36b5f69b3 100644 --- a/src/class/hid/hid_ri.h +++ b/src/class/hid/hid_ri.h @@ -86,6 +86,9 @@ const uint8_t* tuh_hid_ri_long_item_data(const uint8_t *ri); // -2 -> missing long bytes int16_t tuh_hid_ri_size(const uint8_t *ri, uint16_t l); +// Split an extended usage into local and page values +void tuh_hid_ri_split_usage(uint32_t eusage, uint16_t *usage, uint16_t *usage_page); + #ifdef __cplusplus } #endif diff --git a/src/class/hid/hid_rip.c b/src/class/hid/hid_rip.c index 27153965c9..b2972b1198 100644 --- a/src/class/hid/hid_rip.c +++ b/src/class/hid/hid_rip.c @@ -37,8 +37,8 @@ void tuh_hid_rip_init_state(tuh_hid_rip_state_t *state, const uint8_t *report, u state->stack_index = 0; state->usage_count = 0; state->collections_count = 0; - memset(&state->global_items, 0, sizeof(uint8_t*) * HID_REPORT_STACK_SIZE * 16); - memset(&state->local_items, 0, sizeof(uint8_t*) * 16); + tu_memclr(&state->global_items, sizeof(uint8_t*) * HID_REPORT_STACK_SIZE * 16); + tu_memclr(&state->local_items, sizeof(uint8_t*) * 16); } const uint8_t* tuh_hid_rip_next_item(tuh_hid_rip_state_t *state) @@ -54,7 +54,7 @@ const uint8_t* tuh_hid_rip_next_item(tuh_hid_rip_state_t *state) if (il > 0 && tuh_hid_ri_short_type(ri) == RI_TYPE_MAIN) { // Clear down local state after a main item - memset(&state->local_items, 0, sizeof(uint8_t*) * 16); + tu_memclr(&state->local_items, sizeof(uint8_t*) * 16); state->usage_count = 0; } @@ -239,7 +239,7 @@ uint8_t tuh_hid_parse_report_descriptor(tuh_hid_report_info_t* report_info_arr, switch(tag) { case RI_LOCAL_USAGE: - // only take in account the "usage" before starting REPORT ID + // only take into account the "usage" before starting REPORT ID if ( pstate.collections_count == 0 ) { uint32_t eusage = pstate.usages[pstate.usage_count - 1]; usage = eusage & 0xffff; diff --git a/test/test/class/hid/test_hid_ri.c b/test/test/class/hid/test_hid_ri.c index 7f277de203..b20e3ce3aa 100644 --- a/test/test/class/hid/test_hid_ri.c +++ b/test/test/class/hid/test_hid_ri.c @@ -148,6 +148,14 @@ void test_logical_min_neg_2147483647(void) TEST_ASSERT_EQUAL(5, tuh_hid_ri_size(tb, 5)); } - +void test_split_usage(void) { + uint16_t usage; + uint16_t usage_page; + + tuh_hid_ri_split_usage(0xFA23832B, &usage, &usage_page); + + TEST_ASSERT_EQUAL(0x832B, usage); + TEST_ASSERT_EQUAL(0xFA23, usage_page); +} From d4beada4130c098e5c09cadfc45dc50f22457e8a Mon Sep 17 00:00:00 2001 From: Phil Date: Sun, 6 Feb 2022 08:22:06 +0000 Subject: [PATCH 30/71] HID micro parser --- src/class/hid/hid_rip.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/class/hid/hid_rip.c b/src/class/hid/hid_rip.c index b2972b1198..d7ef88451b 100644 --- a/src/class/hid/hid_rip.c +++ b/src/class/hid/hid_rip.c @@ -242,8 +242,7 @@ uint8_t tuh_hid_parse_report_descriptor(tuh_hid_report_info_t* report_info_arr, // only take into account the "usage" before starting REPORT ID if ( pstate.collections_count == 0 ) { uint32_t eusage = pstate.usages[pstate.usage_count - 1]; - usage = eusage & 0xffff; - usage_page = eusage >> 16; + tuh_hid_ri_split_usage(eusage, &usage, &usage_page); } break; @@ -260,8 +259,8 @@ uint8_t tuh_hid_parse_report_descriptor(tuh_hid_report_info_t* report_info_arr, for ( uint8_t i = 0; i < report_num + 1; i++ ) { info = report_info_arr+i; - TU_LOG2("%u: id = %02X, usage_page = %04X, usage = %04X\r\n", i, info->report_id, info->usage_page, info->usage); - printf("%u: id = %02X, usage_page = %04X, usage = %04X\r\n", i, info->report_id, info->usage_page, info->usage); + TU_LOG2("%u: id = %02X, usage_page = %04X, usage = %04X, in_len = %u, out_len = %u\r\n", i, info->report_id, info->usage_page, info->usage, info->in_len, info->out_len); + printf("%u: id = %02X, usage_page = %04X, usage = %04X, in_len = %u, out_len = %u\r\n", i, info->report_id, info->usage_page, info->usage, info->in_len, info->out_len); } return report_num + 1; From 13e59371b5cc0b64e2642c64b47e298b453b7e1d Mon Sep 17 00:00:00 2001 From: Phil Date: Sun, 6 Feb 2022 09:09:10 +0000 Subject: [PATCH 31/71] HID micro parser --- src/class/hid/hid_ri.c | 6 +++--- src/class/hid/hid_ri.h | 9 ++++++--- src/class/hid/hid_rip.h | 3 +++ 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/src/class/hid/hid_ri.c b/src/class/hid/hid_ri.c index 42f25b7cde..c651e60aae 100644 --- a/src/class/hid/hid_ri.c +++ b/src/class/hid/hid_ri.c @@ -86,16 +86,16 @@ const uint8_t* tuh_hid_ri_long_item_data(const uint8_t *ri) { int16_t tuh_hid_ri_size(const uint8_t *ri, uint16_t l) { // Make sure there is enough room for the header - if (l < 1) return 0; + if (l < 1) return TUH_HID_RI_EOF; // Calculate the short item length uint16_t sl = 1 + tuh_hid_ri_short_data_length(ri); // check it fits - if (l < sl) return -1; + if (l < sl) return TUH_HID_RI_ERR_MISSING_SHORT; // Check if we need to worry about a long item if (tuh_hid_ri_is_long(ri)) { uint16_t ll = tuh_hid_ri_long_data_length(ri); uint16_t tl = sl + ll; - if (l < tl) return -2; + if (l < tl) return TUH_HID_RI_ERR_MISSING_LONG; return tl; } else { diff --git a/src/class/hid/hid_ri.h b/src/class/hid/hid_ri.h index b36b5f69b3..9fd9151aa4 100644 --- a/src/class/hid/hid_ri.h +++ b/src/class/hid/hid_ri.h @@ -74,6 +74,9 @@ uint8_t tuh_hid_ri_long_tag(const uint8_t *ri); // Get a pointer to the data in a long item const uint8_t* tuh_hid_ri_long_item_data(const uint8_t *ri); +#define TUH_HID_RI_EOF 0 +#define TUH_HID_RI_ERR_MISSING_SHORT -1 +#define TUH_HID_RI_ERR_MISSING_LONG -2 // Get the size of the item in bytes // // Important: @@ -81,9 +84,9 @@ const uint8_t* tuh_hid_ri_long_item_data(const uint8_t *ri); // and check the return code for eof or error. // // return values: -// 0 -> eof, -// -1 -> missing short bytes, -// -2 -> missing long bytes +// TUH_HID_RI_EOF : no more values +// TUH_HID_RI_ERR_MISSING_SHORT : missing short bytes, +// TUH_HID_RI_ERR_MISSING_LONG : missing long bytes int16_t tuh_hid_ri_size(const uint8_t *ri, uint16_t l); // Split an extended usage into local and page values diff --git a/src/class/hid/hid_rip.h b/src/class/hid/hid_rip.h index 1ebf2ca52a..05720e980f 100644 --- a/src/class/hid/hid_rip.h +++ b/src/class/hid/hid_rip.h @@ -74,6 +74,7 @@ typedef struct uint16_t usage_page; // TODO still use the endpoint size for now + // Note: these currently do not include the Report ID byte uint16_t in_len; // length of IN report in bits uint16_t out_len; // length of OUT report in bits } tuh_hid_report_info_t; @@ -102,6 +103,8 @@ const uint8_t* tuh_hid_rip_local(tuh_hid_rip_state_t *state, uint8_t tag); const uint8_t* tuh_hid_rip_current_item(tuh_hid_rip_state_t *state); // Return report_size * report_count +// +// Note: this currently does not include the Report ID byte uint32_t tuh_hid_rip_report_total_size_bits(tuh_hid_rip_state_t *state); // Parse report descriptor into array of report_info struct and return number of reports. From 94e240930b08b4a468f0085c5e93ca47eda4d965 Mon Sep 17 00:00:00 2001 From: Phil Date: Sun, 6 Feb 2022 09:25:10 +0000 Subject: [PATCH 32/71] HID micro parser --- src/class/hid/hid_rip.c | 21 +++++++++++++++------ src/class/hid/hid_rip.h | 11 +++++++++++ test/test/class/hid/test_hid_rip.c | 6 ++++++ 3 files changed, 32 insertions(+), 6 deletions(-) diff --git a/src/class/hid/hid_rip.c b/src/class/hid/hid_rip.c index d7ef88451b..996b70552d 100644 --- a/src/class/hid/hid_rip.c +++ b/src/class/hid/hid_rip.c @@ -22,6 +22,8 @@ * This file is part of the TinyUSB stack. */ +// TODO log error conditions + #include "tusb_option.h" #if ((TUSB_OPT_HOST_ENABLED && CFG_TUH_HID) || _UNITY_TEST_) @@ -39,6 +41,7 @@ void tuh_hid_rip_init_state(tuh_hid_rip_state_t *state, const uint8_t *report, u state->collections_count = 0; tu_memclr(&state->global_items, sizeof(uint8_t*) * HID_REPORT_STACK_SIZE * 16); tu_memclr(&state->local_items, sizeof(uint8_t*) * 16); + state->status = HID_RIP_OK; } const uint8_t* tuh_hid_rip_next_item(tuh_hid_rip_state_t *state) @@ -73,7 +76,7 @@ const uint8_t* tuh_hid_rip_next_item(tuh_hid_rip_state_t *state) state->item_length = il = tuh_hid_ri_size(ri, state->length); if (il <= 0) { - // record error somewhere + state->status = HID_RIP_ITEM_ERR; return NULL; } @@ -86,13 +89,15 @@ const uint8_t* tuh_hid_rip_next_item(tuh_hid_rip_state_t *state) switch (short_tag) { case RI_GLOBAL_PUSH: if (++state->stack_index == HID_REPORT_STACK_SIZE) { - return NULL; // TODO enum? Stack overflow + state->status = HID_RIP_STACK_OVERFLOW; + return NULL; } memcpy(&state->global_items[state->stack_index], &state->global_items[state->stack_index - 1], sizeof(uint8_t*) * 16); break; case RI_GLOBAL_POP: if (state->stack_index-- == 0) { - return NULL; // TODO enum? Stack underflow + state->status = HID_RIP_STACK_UNDERFLOW; + return NULL; } break; default: @@ -109,7 +114,8 @@ const uint8_t* tuh_hid_rip_next_item(tuh_hid_rip_state_t *state) usage |= usage_page << 16; } if (state->usage_count == HID_REPORT_MAX_USAGES) { - return NULL; // TODO enum? Max usages overflow + state->status = HID_RIP_USAGES_OVERFLOW; + return NULL; } state->usages[state->usage_count++] = usage; break; @@ -123,14 +129,16 @@ const uint8_t* tuh_hid_rip_next_item(tuh_hid_rip_state_t *state) switch(short_tag) { case RI_MAIN_COLLECTION: { if (state->collections_count == HID_REPORT_MAX_COLLECTION_DEPTH) { - return NULL; // TODO enum? Max collections overflow + state->status = HID_RIP_COLLECTIONS_OVERFLOW; + return NULL; } state->collections[state->collections_count++] = ri; break; } case RI_MAIN_COLLECTION_END: if (state->collections_count-- == 0) { - return NULL; // TODO enum? Max collections underflow + state->status = HID_RIP_COLLECTIONS_UNDERFLOW; + return NULL; } break; default: @@ -260,6 +268,7 @@ uint8_t tuh_hid_parse_report_descriptor(tuh_hid_report_info_t* report_info_arr, { info = report_info_arr+i; TU_LOG2("%u: id = %02X, usage_page = %04X, usage = %04X, in_len = %u, out_len = %u\r\n", i, info->report_id, info->usage_page, info->usage, info->in_len, info->out_len); + // TODO remove following line after testing printf("%u: id = %02X, usage_page = %04X, usage = %04X, in_len = %u, out_len = %u\r\n", i, info->report_id, info->usage_page, info->usage, info->in_len, info->out_len); } diff --git a/src/class/hid/hid_rip.h b/src/class/hid/hid_rip.h index 05720e980f..a6f36aae90 100644 --- a/src/class/hid/hid_rip.h +++ b/src/class/hid/hid_rip.h @@ -53,6 +53,16 @@ #define HID_REPORT_MAX_USAGES 20 #define HID_REPORT_MAX_COLLECTION_DEPTH 20 +typedef enum tuh_hid_rip_err { + HID_RIP_OK, + HID_RIP_ITEM_ERR, // Issue decoding a single report item + HID_RIP_STACK_OVERFLOW, // Too many pushes + HID_RIP_STACK_UNDERFLOW, // Too many pops + HID_RIP_USAGES_OVERFLOW, // Too many usages + HID_RIP_COLLECTIONS_OVERFLOW, // Too many collections + HID_RIP_COLLECTIONS_UNDERFLOW // More collection starts than ends +} tuh_hid_rip_err_t; + typedef struct tuh_hid_rip_state { const uint8_t* cursor; uint16_t length; @@ -64,6 +74,7 @@ typedef struct tuh_hid_rip_state { const uint8_t* local_items[16]; const uint8_t* collections[HID_REPORT_MAX_COLLECTION_DEPTH]; uint32_t usages[HID_REPORT_MAX_USAGES]; + tuh_hid_rip_err_t status; } tuh_hid_rip_state_t; diff --git a/test/test/class/hid/test_hid_rip.c b/test/test/class/hid/test_hid_rip.c index 11f5796248..c8844692bd 100644 --- a/test/test/class/hid/test_hid_rip.c +++ b/test/test/class/hid/test_hid_rip.c @@ -135,6 +135,12 @@ void test_push_pop(void) // TODO test stack underflow +// TODO test usage overflow + +// TODO test collection overflow + +// TODO test collection underflow + void test_main_clears_local(void) { uint8_t tb[] = { From 9c9a163251407af26efa2f44c3a269de311cdfe0 Mon Sep 17 00:00:00 2001 From: Phil Date: Sun, 6 Feb 2022 15:22:00 +0000 Subject: [PATCH 33/71] HID micro parser --- src/class/hid/hid_rip.c | 10 +++++++++- src/class/hid/hid_rip.h | 10 ++++++---- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/src/class/hid/hid_rip.c b/src/class/hid/hid_rip.c index 996b70552d..f8a5c81856 100644 --- a/src/class/hid/hid_rip.c +++ b/src/class/hid/hid_rip.c @@ -41,7 +41,7 @@ void tuh_hid_rip_init_state(tuh_hid_rip_state_t *state, const uint8_t *report, u state->collections_count = 0; tu_memclr(&state->global_items, sizeof(uint8_t*) * HID_REPORT_STACK_SIZE * 16); tu_memclr(&state->local_items, sizeof(uint8_t*) * 16); - state->status = HID_RIP_OK; + state->status = HID_RIP_INIT; } const uint8_t* tuh_hid_rip_next_item(tuh_hid_rip_state_t *state) @@ -69,6 +69,7 @@ const uint8_t* tuh_hid_rip_next_item(tuh_hid_rip_state_t *state) // Normal eof if (state->length == 0) { state->item_length = 0; + state->status = HID_RIP_EOF; return NULL; } @@ -77,6 +78,7 @@ const uint8_t* tuh_hid_rip_next_item(tuh_hid_rip_state_t *state) if (il <= 0) { state->status = HID_RIP_ITEM_ERR; + TU_LOG2("HID Report item parser: Attempt to read HID Report item returned %d\r\n", il); return NULL; } @@ -90,6 +92,7 @@ const uint8_t* tuh_hid_rip_next_item(tuh_hid_rip_state_t *state) case RI_GLOBAL_PUSH: if (++state->stack_index == HID_REPORT_STACK_SIZE) { state->status = HID_RIP_STACK_OVERFLOW; + TU_LOG2("HID Report item parser: stack overflow\r\n"); return NULL; } memcpy(&state->global_items[state->stack_index], &state->global_items[state->stack_index - 1], sizeof(uint8_t*) * 16); @@ -97,6 +100,7 @@ const uint8_t* tuh_hid_rip_next_item(tuh_hid_rip_state_t *state) case RI_GLOBAL_POP: if (state->stack_index-- == 0) { state->status = HID_RIP_STACK_UNDERFLOW; + TU_LOG2("HID Report item parser: stack underflow\r\n"); return NULL; } break; @@ -115,6 +119,7 @@ const uint8_t* tuh_hid_rip_next_item(tuh_hid_rip_state_t *state) } if (state->usage_count == HID_REPORT_MAX_USAGES) { state->status = HID_RIP_USAGES_OVERFLOW; + TU_LOG2("HID Report item parser: usage overflow\r\n"); return NULL; } state->usages[state->usage_count++] = usage; @@ -130,6 +135,7 @@ const uint8_t* tuh_hid_rip_next_item(tuh_hid_rip_state_t *state) case RI_MAIN_COLLECTION: { if (state->collections_count == HID_REPORT_MAX_COLLECTION_DEPTH) { state->status = HID_RIP_COLLECTIONS_OVERFLOW; + TU_LOG2("HID Report item parser: collections overflow\r\n"); return NULL; } state->collections[state->collections_count++] = ri; @@ -138,6 +144,7 @@ const uint8_t* tuh_hid_rip_next_item(tuh_hid_rip_state_t *state) case RI_MAIN_COLLECTION_END: if (state->collections_count-- == 0) { state->status = HID_RIP_COLLECTIONS_UNDERFLOW; + TU_LOG2("HID Report item parser: collections underflow\r\n"); return NULL; } break; @@ -150,6 +157,7 @@ const uint8_t* tuh_hid_rip_next_item(tuh_hid_rip_state_t *state) break; } } + state->status = HID_RIP_TTEM_OK; return ri; } diff --git a/src/class/hid/hid_rip.h b/src/class/hid/hid_rip.h index a6f36aae90..7897ca7e56 100644 --- a/src/class/hid/hid_rip.h +++ b/src/class/hid/hid_rip.h @@ -53,15 +53,17 @@ #define HID_REPORT_MAX_USAGES 20 #define HID_REPORT_MAX_COLLECTION_DEPTH 20 -typedef enum tuh_hid_rip_err { - HID_RIP_OK, +typedef enum tuh_hid_rip_status { + HID_RIP_INIT = 0, // Initial state + HID_RIP_EOF, // No more items + HID_RIP_TTEM_OK, // Last item parsed ok HID_RIP_ITEM_ERR, // Issue decoding a single report item HID_RIP_STACK_OVERFLOW, // Too many pushes HID_RIP_STACK_UNDERFLOW, // Too many pops HID_RIP_USAGES_OVERFLOW, // Too many usages HID_RIP_COLLECTIONS_OVERFLOW, // Too many collections HID_RIP_COLLECTIONS_UNDERFLOW // More collection starts than ends -} tuh_hid_rip_err_t; +} tuh_hid_rip_status_t; typedef struct tuh_hid_rip_state { const uint8_t* cursor; @@ -74,7 +76,7 @@ typedef struct tuh_hid_rip_state { const uint8_t* local_items[16]; const uint8_t* collections[HID_REPORT_MAX_COLLECTION_DEPTH]; uint32_t usages[HID_REPORT_MAX_USAGES]; - tuh_hid_rip_err_t status; + tuh_hid_rip_status_t status; } tuh_hid_rip_state_t; From 5838a6343fc90c246d15b001c06f0d8e72b97832 Mon Sep 17 00:00:00 2001 From: Phil Date: Sun, 6 Feb 2022 21:01:57 +0000 Subject: [PATCH 34/71] HID micro parser --- src/class/hid/hid_ri.c | 6 +++--- src/class/hid/hid_ri.h | 12 ++++++------ src/class/hid/hid_rip.c | 2 -- 3 files changed, 9 insertions(+), 11 deletions(-) diff --git a/src/class/hid/hid_ri.c b/src/class/hid/hid_ri.c index c651e60aae..8fa2a97840 100644 --- a/src/class/hid/hid_ri.c +++ b/src/class/hid/hid_ri.c @@ -86,16 +86,16 @@ const uint8_t* tuh_hid_ri_long_item_data(const uint8_t *ri) { int16_t tuh_hid_ri_size(const uint8_t *ri, uint16_t l) { // Make sure there is enough room for the header - if (l < 1) return TUH_HID_RI_EOF; + if (l < 1) return HID_RI_EOF; // Calculate the short item length uint16_t sl = 1 + tuh_hid_ri_short_data_length(ri); // check it fits - if (l < sl) return TUH_HID_RI_ERR_MISSING_SHORT; + if (l < sl) return HID_RI_ERR_MISSING_SHORT; // Check if we need to worry about a long item if (tuh_hid_ri_is_long(ri)) { uint16_t ll = tuh_hid_ri_long_data_length(ri); uint16_t tl = sl + ll; - if (l < tl) return TUH_HID_RI_ERR_MISSING_LONG; + if (l < tl) return HID_RI_ERR_MISSING_LONG; return tl; } else { diff --git a/src/class/hid/hid_ri.h b/src/class/hid/hid_ri.h index 9fd9151aa4..5961516a65 100644 --- a/src/class/hid/hid_ri.h +++ b/src/class/hid/hid_ri.h @@ -74,9 +74,9 @@ uint8_t tuh_hid_ri_long_tag(const uint8_t *ri); // Get a pointer to the data in a long item const uint8_t* tuh_hid_ri_long_item_data(const uint8_t *ri); -#define TUH_HID_RI_EOF 0 -#define TUH_HID_RI_ERR_MISSING_SHORT -1 -#define TUH_HID_RI_ERR_MISSING_LONG -2 +#define HID_RI_EOF 0 +#define HID_RI_ERR_MISSING_SHORT -1 +#define HID_RI_ERR_MISSING_LONG -2 // Get the size of the item in bytes // // Important: @@ -84,9 +84,9 @@ const uint8_t* tuh_hid_ri_long_item_data(const uint8_t *ri); // and check the return code for eof or error. // // return values: -// TUH_HID_RI_EOF : no more values -// TUH_HID_RI_ERR_MISSING_SHORT : missing short bytes, -// TUH_HID_RI_ERR_MISSING_LONG : missing long bytes +// HID_RI_EOF : no more values +// HID_RI_ERR_MISSING_SHORT : missing short bytes, +// HID_RI_ERR_MISSING_LONG : missing long bytes int16_t tuh_hid_ri_size(const uint8_t *ri, uint16_t l); // Split an extended usage into local and page values diff --git a/src/class/hid/hid_rip.c b/src/class/hid/hid_rip.c index f8a5c81856..6628988d52 100644 --- a/src/class/hid/hid_rip.c +++ b/src/class/hid/hid_rip.c @@ -22,8 +22,6 @@ * This file is part of the TinyUSB stack. */ -// TODO log error conditions - #include "tusb_option.h" #if ((TUSB_OPT_HOST_ENABLED && CFG_TUH_HID) || _UNITY_TEST_) From ab9a626b267f2c96c258a0a6e5c6014a85dfcafb Mon Sep 17 00:00:00 2001 From: Phil Date: Sun, 6 Feb 2022 21:23:30 +0000 Subject: [PATCH 35/71] HID micro parser --- test/test/class/hid/test_hid_rip.c | 86 ++++++++++++++++++++++++++++-- 1 file changed, 81 insertions(+), 5 deletions(-) diff --git a/test/test/class/hid/test_hid_rip.c b/test/test/class/hid/test_hid_rip.c index c8844692bd..b4715e9b38 100644 --- a/test/test/class/hid/test_hid_rip.c +++ b/test/test/class/hid/test_hid_rip.c @@ -131,15 +131,91 @@ void test_push_pop(void) TEST_ASSERT_EQUAL(0x01, tuh_hid_ri_short_udata32(tuh_hid_rip_global(&pstate, 0))); } -// TODO test stack overflow +void test_stack_overflow(void) +{ + uint8_t tb[HID_REPORT_STACK_SIZE]; + memset(tb, 0xA4, sizeof(tb)); // Push + + tuh_hid_rip_state_t pstate; + tuh_hid_rip_init_state(&pstate, (uint8_t*)&tb, sizeof(tb)); + TEST_ASSERT_EQUAL(pstate.status, HID_RIP_INIT); + for (int i = 0; i < HID_REPORT_STACK_SIZE - 1; ++i) { + TEST_ASSERT_EQUAL(&tb[i], tuh_hid_rip_next_item(&pstate)); + TEST_ASSERT_EQUAL(pstate.status, HID_RIP_TTEM_OK); + } + TEST_ASSERT_EQUAL(NULL, tuh_hid_rip_next_item(&pstate)); + TEST_ASSERT_EQUAL(pstate.status, HID_RIP_STACK_OVERFLOW); +} -// TODO test stack underflow +void test_stack_underflow(void) +{ + uint8_t tb[] = { + 0xA4, // Push + 0xB4, // Pop + 0xB4, // Pop + }; + + tuh_hid_rip_state_t pstate; + tuh_hid_rip_init_state(&pstate, (uint8_t*)&tb, sizeof(tb)); + TEST_ASSERT_EQUAL(pstate.status, HID_RIP_INIT); + TEST_ASSERT_EQUAL(&tb[0], tuh_hid_rip_next_item(&pstate)); + TEST_ASSERT_EQUAL(pstate.status, HID_RIP_TTEM_OK); + TEST_ASSERT_EQUAL(&tb[1], tuh_hid_rip_next_item(&pstate)); + TEST_ASSERT_EQUAL(pstate.status, HID_RIP_TTEM_OK); + TEST_ASSERT_EQUAL(0, tuh_hid_rip_next_item(&pstate)); + TEST_ASSERT_EQUAL(pstate.status, HID_RIP_STACK_UNDERFLOW); +} -// TODO test usage overflow +void test_usage_overflow(void) +{ + uint8_t tb[HID_REPORT_MAX_USAGES + 1]; + memset(tb, 0x08, sizeof(tb)); // Usage + + tuh_hid_rip_state_t pstate; + tuh_hid_rip_init_state(&pstate, (uint8_t*)&tb, sizeof(tb)); + TEST_ASSERT_EQUAL(pstate.status, HID_RIP_INIT); + for (int i = 0; i < HID_REPORT_MAX_USAGES; ++i) { + TEST_ASSERT_EQUAL(&tb[i], tuh_hid_rip_next_item(&pstate)); + TEST_ASSERT_EQUAL(pstate.status, HID_RIP_TTEM_OK); + } + TEST_ASSERT_EQUAL(NULL, tuh_hid_rip_next_item(&pstate)); + TEST_ASSERT_EQUAL(pstate.status, HID_RIP_USAGES_OVERFLOW); +} -// TODO test collection overflow +void test_collection_overflow(void) +{ + uint8_t tb[HID_REPORT_MAX_COLLECTION_DEPTH + 1]; + memset(tb, 0xA0, sizeof(tb)); // Collection start + + tuh_hid_rip_state_t pstate; + tuh_hid_rip_init_state(&pstate, (uint8_t*)&tb, sizeof(tb)); + TEST_ASSERT_EQUAL(pstate.status, HID_RIP_INIT); + for (int i = 0; i < HID_REPORT_MAX_COLLECTION_DEPTH; ++i) { + TEST_ASSERT_EQUAL(&tb[i], tuh_hid_rip_next_item(&pstate)); + TEST_ASSERT_EQUAL(pstate.status, HID_RIP_TTEM_OK); + } + TEST_ASSERT_EQUAL(NULL, tuh_hid_rip_next_item(&pstate)); + TEST_ASSERT_EQUAL(pstate.status, HID_RIP_COLLECTIONS_OVERFLOW); +} -// TODO test collection underflow +void test_collection_underflow(void) +{ + uint8_t tb[] = { + 0xA0, // Collection start + 0xC0, // Collection end + 0xC0, // Collection end + }; + + tuh_hid_rip_state_t pstate; + tuh_hid_rip_init_state(&pstate, (uint8_t*)&tb, sizeof(tb)); + TEST_ASSERT_EQUAL(pstate.status, HID_RIP_INIT); + TEST_ASSERT_EQUAL(&tb[0], tuh_hid_rip_next_item(&pstate)); + TEST_ASSERT_EQUAL(pstate.status, HID_RIP_TTEM_OK); + TEST_ASSERT_EQUAL(&tb[1], tuh_hid_rip_next_item(&pstate)); + TEST_ASSERT_EQUAL(pstate.status, HID_RIP_TTEM_OK); + TEST_ASSERT_EQUAL(0, tuh_hid_rip_next_item(&pstate)); + TEST_ASSERT_EQUAL(pstate.status, HID_RIP_COLLECTIONS_UNDERFLOW); +} void test_main_clears_local(void) { From c4aecdcaf813a85eefe28b82ad4073fa9d167315 Mon Sep 17 00:00:00 2001 From: Phil Date: Sun, 6 Feb 2022 21:29:43 +0000 Subject: [PATCH 36/71] HID micro parser --- test/test/class/hid/test_hid_rip.c | 65 ++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) diff --git a/test/test/class/hid/test_hid_rip.c b/test/test/class/hid/test_hid_rip.c index b4715e9b38..60d0918623 100644 --- a/test/test/class/hid/test_hid_rip.c +++ b/test/test/class/hid/test_hid_rip.c @@ -402,4 +402,69 @@ void test_hid_parse_report_descriptor_dual_report() { TEST_ASSERT_EQUAL(0, report_info[1].out_len); } +void test_hid_parse_report_descriptor_joystick_report() { + const uint8_t const tb[] = { + 0x05, 0x01, // Usage Page (Generic Desktop Ctrls) + 0x09, 0x04, // Usage (Joystick) + 0xA1, 0x01, // Collection (Application) + 0x09, 0x01, // Usage (Pointer) + 0xA1, 0x00, // Collection (Physical) + 0x05, 0x01, // Usage Page (Generic Desktop Ctrls) + 0x09, 0x30, // Usage (X) + 0x09, 0x31, // Usage (Y) + 0x15, 0x00, // Logical Minimum (0) + 0x26, 0xFF, 0x03, // Logical Maximum (1023) + 0x35, 0x00, // Physical Minimum (0) + 0x46, 0xFF, 0x03, // Physical Maximum (1023) + 0x65, 0x00, // Unit (None) + 0x75, 0x0A, // Report Size (10) + 0x95, 0x02, // Report Count (2) + 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0x09, 0x35, // Usage (Rz) + 0x09, 0x32, // Usage (Z) + 0x15, 0x00, // Logical Minimum (0) + 0x26, 0xFF, 0x01, // Logical Maximum (511) + 0x35, 0x00, // Physical Minimum (0) + 0x46, 0xFF, 0x01, // Physical Maximum (511) + 0x65, 0x00, // Unit (None) + 0x75, 0x09, // Report Size (9) + 0x95, 0x02, // Report Count (2) + 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0x75, 0x01, // Report Size (1) + 0x95, 0x02, // Report Count (2) + 0x81, 0x01, // Input (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0x09, 0x39, // Usage (Hat switch) + 0x15, 0x01, // Logical Minimum (1) + 0x25, 0x08, // Logical Maximum (8) + 0x35, 0x00, // Physical Minimum (0) + 0x46, 0x3B, 0x01, // Physical Maximum (315) + 0x65, 0x14, // Unit (System: English Rotation, Length: Centimeter) + 0x75, 0x08, // Report Size (8) + 0x95, 0x01, // Report Count (1) + 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0x05, 0x09, // Usage Page (Button) + 0x19, 0x01, // Usage Minimum (0x01) + 0x29, 0x0C, // Usage Maximum (0x0C) + 0x15, 0x00, // Logical Minimum (0) + 0x25, 0x01, // Logical Maximum (1) + 0x35, 0x00, // Physical Minimum (0) + 0x45, 0x01, // Physical Maximum (1) + 0x75, 0x01, // Report Size (1) + 0x95, 0x0C, // Report Count (12) + 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0x75, 0x01, // Report Size (1) + 0x95, 0x04, // Report Count (4) + 0x81, 0x01, // Input (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0xC0, // End Collection + 0xC0, // End Collection + }; + tuh_hid_report_info_t report_info[3]; + uint8_t report_count = tuh_hid_parse_report_descriptor(report_info, 3, (const uint8_t*)&tb, sizeof(tb)); + TEST_ASSERT_EQUAL(1, report_count); + TEST_ASSERT_EQUAL(1, report_info[0].usage_page); + TEST_ASSERT_EQUAL(4, report_info[0].usage); + TEST_ASSERT_EQUAL(0, report_info[0].report_id); + TEST_ASSERT_EQUAL(64, report_info[0].in_len); + TEST_ASSERT_EQUAL(0, report_info[0].out_len); +} From 9b42234b6e040aa32ec1a38463aa5e54a560e41e Mon Sep 17 00:00:00 2001 From: Phil Date: Mon, 7 Feb 2022 20:27:03 +0000 Subject: [PATCH 37/71] HID micro parser --- examples/host/hid_controller/Makefile | 2 ++ src/class/hid/hid_rip.h | 2 +- src/host/hcd.h | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/examples/host/hid_controller/Makefile b/examples/host/hid_controller/Makefile index c58df562b9..e7315a79ef 100644 --- a/examples/host/hid_controller/Makefile +++ b/examples/host/hid_controller/Makefile @@ -19,6 +19,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_ri.c \ + src/class/hid/hid_rip.c \ src/class/msc/msc_host.c \ src/host/hub.c \ src/host/usbh.c \ diff --git a/src/class/hid/hid_rip.h b/src/class/hid/hid_rip.h index 7897ca7e56..69bf8ee41e 100644 --- a/src/class/hid/hid_rip.h +++ b/src/class/hid/hid_rip.h @@ -54,7 +54,7 @@ #define HID_REPORT_MAX_COLLECTION_DEPTH 20 typedef enum tuh_hid_rip_status { - HID_RIP_INIT = 0, // Initial state + HID_RIP_INIT = 0, // Initial state HID_RIP_EOF, // No more items HID_RIP_TTEM_OK, // Last item parsed ok HID_RIP_ITEM_ERR, // Issue decoding a single report item diff --git a/src/host/hcd.h b/src/host/hcd.h index 0bcca796a2..eb53d2e80e 100644 --- a/src/host/hcd.h +++ b/src/host/hcd.h @@ -82,7 +82,7 @@ typedef struct } hcd_event_t; -#if TUSB_OPT_HOST_ENABLED || _UNITY_TEST_ +#if TUSB_OPT_HOST_ENABLED // Max number of endpoints per device enum { // TODO better computation From 6456411235ac657c6fc75fbcdae2ab4807063adb Mon Sep 17 00:00:00 2001 From: Phil Date: Mon, 7 Feb 2022 20:39:29 +0000 Subject: [PATCH 38/71] HID micro parser --- src/class/hid/hid_host.c | 2 +- src/class/hid/hid_rip.c | 4 +--- test/test/class/hid/test_hid_rip.c | 5 +++-- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/src/class/hid/hid_host.c b/src/class/hid/hid_host.c index 065b2059a9..56a97716b0 100644 --- a/src/class/hid/hid_host.c +++ b/src/class/hid/hid_host.c @@ -26,7 +26,7 @@ #include "tusb_option.h" -#if ((TUSB_OPT_HOST_ENABLED && CFG_TUH_HID) || _UNITY_TEST_) +#if (TUSB_OPT_HOST_ENABLED && CFG_TUH_HID) #include "host/usbh.h" #include "host/usbh_classdriver.h" diff --git a/src/class/hid/hid_rip.c b/src/class/hid/hid_rip.c index 6628988d52..536c7b6887 100644 --- a/src/class/hid/hid_rip.c +++ b/src/class/hid/hid_rip.c @@ -238,7 +238,7 @@ uint8_t tuh_hid_parse_report_descriptor(tuh_hid_report_info_t* report_info_arr, switch(tag) { case RI_GLOBAL_REPORT_ID: { - if (info->in_len > 0 || info->out_len > 0) { + if (info->report_id > 0 || info->in_len > 0 || info->out_len > 0) { info++; report_num++; } @@ -274,8 +274,6 @@ uint8_t tuh_hid_parse_report_descriptor(tuh_hid_report_info_t* report_info_arr, { info = report_info_arr+i; TU_LOG2("%u: id = %02X, usage_page = %04X, usage = %04X, in_len = %u, out_len = %u\r\n", i, info->report_id, info->usage_page, info->usage, info->in_len, info->out_len); - // TODO remove following line after testing - printf("%u: id = %02X, usage_page = %04X, usage = %04X, in_len = %u, out_len = %u\r\n", i, info->report_id, info->usage_page, info->usage, info->in_len, info->out_len); } return report_num + 1; diff --git a/test/test/class/hid/test_hid_rip.c b/test/test/class/hid/test_hid_rip.c index 60d0918623..2482ed7745 100644 --- a/test/test/class/hid/test_hid_rip.c +++ b/test/test/class/hid/test_hid_rip.c @@ -380,7 +380,8 @@ void test_hid_parse_report_descriptor_dual_report() { 0x15, 0x00, // Logical Minimum (0) 0x25, 0x01, // Logical Maximum (1) 0x75, 0x01, // Report Size (1) - 0x95, 0x01, // Report Count (1) + 0x95, 0x02, // Report Count (2) + 0x09, 0xE2, // Usage (Mute) 0x09, 0xE2, // Usage (Mute) 0x81, 0x62, // Input (Data,Var,Abs,No Wrap,Linear,No Preferred State,Null State) 0xC0, // End Collection @@ -398,7 +399,7 @@ void test_hid_parse_report_descriptor_dual_report() { TEST_ASSERT_EQUAL(0, report_info[1].usage_page); TEST_ASSERT_EQUAL(1, report_info[1].usage); TEST_ASSERT_EQUAL(2, report_info[1].report_id); - TEST_ASSERT_EQUAL(1*1, report_info[1].in_len); + TEST_ASSERT_EQUAL(1*2, report_info[1].in_len); TEST_ASSERT_EQUAL(0, report_info[1].out_len); } From a05d6448f0a27840711217a11eb803c52449a485 Mon Sep 17 00:00:00 2001 From: Phil Date: Mon, 7 Feb 2022 21:48:40 +0000 Subject: [PATCH 39/71] HID micro parser --- src/class/hid/hid_rip.h | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/class/hid/hid_rip.h b/src/class/hid/hid_rip.h index 69bf8ee41e..892e81bd3c 100644 --- a/src/class/hid/hid_rip.h +++ b/src/class/hid/hid_rip.h @@ -42,6 +42,16 @@ // // Iterates through report items and manages state rules. // +// Expected usage: +// +// tuh_hid_rip_state_t pstate; +// tuh_hid_rip_init_state(&pstate, desc_report, desc_len); +// const uint8_t *ri; +// while((ri = tuh_hid_rip_next_item(&pstate)) != NULL) +// { +// ... +// } +// // See: // https://www.usb.org/sites/default/files/hid1_11.pdf // https://eleccelerator.com/usbdescreqparser/ From 90471952dfef56f3c81b140ca27cd0347fd473ed Mon Sep 17 00:00:00 2001 From: fruit-bat Date: Tue, 8 Feb 2022 22:42:24 +0000 Subject: [PATCH 40/71] Update hid_rip.h --- src/class/hid/hid_rip.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/class/hid/hid_rip.h b/src/class/hid/hid_rip.h index 892e81bd3c..76551f6ac7 100644 --- a/src/class/hid/hid_rip.h +++ b/src/class/hid/hid_rip.h @@ -72,7 +72,7 @@ typedef enum tuh_hid_rip_status { HID_RIP_STACK_UNDERFLOW, // Too many pops HID_RIP_USAGES_OVERFLOW, // Too many usages HID_RIP_COLLECTIONS_OVERFLOW, // Too many collections - HID_RIP_COLLECTIONS_UNDERFLOW // More collection starts than ends + HID_RIP_COLLECTIONS_UNDERFLOW // More collection ends than starts } tuh_hid_rip_status_t; typedef struct tuh_hid_rip_state { From 9ad4ed8fad25a8daccd15ed5e381702a5cfa34fa Mon Sep 17 00:00:00 2001 From: Phil Date: Thu, 10 Feb 2022 21:59:59 +0000 Subject: [PATCH 41/71] HID micro parser --- examples/host/cdc_msc_hid/src/hid_app.c | 29 +++++++++++- src/class/hid/hid_rip.h | 5 +- test/test/class/hid/test_hid_rip.c | 62 +++++++++++++++++++++++++ 3 files changed, 93 insertions(+), 3 deletions(-) diff --git a/examples/host/cdc_msc_hid/src/hid_app.c b/examples/host/cdc_msc_hid/src/hid_app.c index 11437c2b4a..ebfa5eac09 100644 --- a/examples/host/cdc_msc_hid/src/hid_app.c +++ b/examples/host/cdc_msc_hid/src/hid_app.c @@ -67,6 +67,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 Descrtipion \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); @@ -113,6 +117,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; @@ -289,8 +294,30 @@ static void process_generic_report(uint8_t dev_addr, uint8_t instance, uint8_t c // Assume mouse follow boot report layout process_mouse_report( (hid_mouse_report_t const*) report ); break; + + case HID_USAGE_DESKTOP_JOYSTICK: + TU_LOG1("HID receive joystick report "); + for(int i = 0; i < len; ++i) { + printf("%02x", report[i]); + } + printf("\r\n"); + break; + + case HID_USAGE_DESKTOP_GAMEPAD: + TU_LOG1("HID receive gamepad report "); + for(int i = 0; i < len; ++i) { + printf("%02x", report[i]); + } + printf("\r\n"); + break; - default: break; + default: + TU_LOG1("HID usage unknown usage:%d\r\n", rpt_info->usage); + + break; } } + else { + TU_LOG1("HID usage unknown page:%d, usage:%d\r\n", rpt_info->usage_page, rpt_info->usage); + } } diff --git a/src/class/hid/hid_rip.h b/src/class/hid/hid_rip.h index 892e81bd3c..d7c792fb81 100644 --- a/src/class/hid/hid_rip.h +++ b/src/class/hid/hid_rip.h @@ -49,6 +49,7 @@ // const uint8_t *ri; // while((ri = tuh_hid_rip_next_item(&pstate)) != NULL) // { +// // ri points to the current hid report item // ... // } // @@ -112,12 +113,12 @@ void tuh_hid_rip_init_state(tuh_hid_rip_state_t *state, const uint8_t *report, u // const uint8_t* tuh_hid_rip_next_item(tuh_hid_rip_state_t *state); -// Accessor for the curren value of a global item +// Accessor for the current value of a global item // // Returns a pointer to the start of the item of null const uint8_t* tuh_hid_rip_global(tuh_hid_rip_state_t *state, uint8_t tag); -// Accessor for the curren value of a local item +// Accessor for the current value of a local item // // Returns a pointer to the start of the item of null const uint8_t* tuh_hid_rip_local(tuh_hid_rip_state_t *state, uint8_t tag); diff --git a/test/test/class/hid/test_hid_rip.c b/test/test/class/hid/test_hid_rip.c index 2482ed7745..62a41b55d6 100644 --- a/test/test/class/hid/test_hid_rip.c +++ b/test/test/class/hid/test_hid_rip.c @@ -469,3 +469,65 @@ void test_hid_parse_report_descriptor_joystick_report() { TEST_ASSERT_EQUAL(64, report_info[0].in_len); TEST_ASSERT_EQUAL(0, report_info[0].out_len); } + +void test_hid_parse_greenasia_report() { + const uint8_t const tb[] = { + 0x05, 0x01, // Usage Page (Generic Desktop Ctrls) + 0x09, 0x04, // Usage (Joystick) + 0xA1, 0x01, // Collection (Application) + 0xA1, 0x02, // Collection (Logical) + 0x75, 0x08, // Report Size (8) + 0x95, 0x05, // Report Count (5) + 0x15, 0x00, // Logical Minimum (0) + 0x26, 0xFF, 0x00, // Logical Maximum (255) + 0x35, 0x00, // Physical Minimum (0) + 0x46, 0xFF, 0x00, // Physical Maximum (255) + 0x09, 0x32, // Usage (Z) + 0x09, 0x35, // Usage (Rz) + 0x09, 0x30, // Usage (X) + 0x09, 0x31, // Usage (Y) + 0x09, 0x00, // Usage (Undefined) + 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0x75, 0x04, // Report Size (4) + 0x95, 0x01, // Report Count (1) + 0x25, 0x07, // Logical Maximum (7) + 0x46, 0x3B, 0x01, // Physical Maximum (315) + 0x65, 0x14, // Unit (System: English Rotation, Length: Centimeter) + 0x09, 0x39, // Usage (Hat switch) + 0x81, 0x42, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,Null State) + 0x65, 0x00, // Unit (None) + 0x75, 0x01, // Report Size (1) + 0x95, 0x0C, // Report Count (12) + 0x25, 0x01, // Logical Maximum (1) + 0x45, 0x01, // Physical Maximum (1) + 0x05, 0x09, // Usage Page (Button) + 0x19, 0x01, // Usage Minimum (0x01) + 0x29, 0x0C, // Usage Maximum (0x0C) + 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0x06, 0x00, 0xFF, // Usage Page (Vendor Defined 0xFF00) + 0x75, 0x01, // Report Size (1) + 0x95, 0x08, // Report Count (8) + 0x25, 0x01, // Logical Maximum (1) + 0x45, 0x01, // Physical Maximum (1) + 0x09, 0x01, // Usage (0x01) + 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0xC0, // End Collection + 0xA1, 0x02, // Collection (Logical) + 0x75, 0x08, // Report Size (8) + 0x95, 0x04, // Report Count (4) + 0x46, 0xFF, 0x00, // Physical Maximum (255) + 0x26, 0xFF, 0x00, // Logical Maximum (255) + 0x09, 0x02, // Usage (0x02) + 0x91, 0x02, // Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) + 0xC0, // End Collection + 0xC0, // End Collection + }; + tuh_hid_report_info_t report_info[3]; + + uint8_t report_count = tuh_hid_parse_report_descriptor(report_info, 3, (const uint8_t*)&tb, sizeof(tb)); + TEST_ASSERT_EQUAL(1, report_count); +} + + + + From 54d845a6df196d8f29be1d21538c9e1b267a3bdc Mon Sep 17 00:00:00 2001 From: Phil Date: Fri, 11 Feb 2022 06:56:57 +0000 Subject: [PATCH 42/71] HID micro parser --- test/test/class/hid/test_hid_rip.c | 57 ++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/test/test/class/hid/test_hid_rip.c b/test/test/class/hid/test_hid_rip.c index 62a41b55d6..ecfc8bbc83 100644 --- a/test/test/class/hid/test_hid_rip.c +++ b/test/test/class/hid/test_hid_rip.c @@ -528,6 +528,63 @@ void test_hid_parse_greenasia_report() { TEST_ASSERT_EQUAL(1, report_count); } +void test_hid_parse_speedlink_report() { + const uint8_t const tb[] = { + 0x05, 0x01, // Usage Page (Generic Desktop Ctrls) + 0x09, 0x04, // Usage (Joystick) + 0xA1, 0x01, // Collection (Application) + 0xA1, 0x02, // Collection (Logical) + 0x75, 0x08, // Report Size (8) + 0x95, 0x05, // Report Count (5) + 0x15, 0x00, // Logical Minimum (0) + 0x26, 0xFF, 0x00, // Logical Maximum (255) + 0x35, 0x00, // Physical Minimum (0) + 0x46, 0xFF, 0x00, // Physical Maximum (255) + 0x09, 0x30, // Usage (X) + 0x09, 0x31, // Usage (Y) + 0x09, 0x32, // Usage (Z) + 0x09, 0x32, // Usage (Z) + 0x09, 0x35, // Usage (Rz) + 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0x75, 0x04, // Report Size (4) + 0x95, 0x01, // Report Count (1) + 0x25, 0x07, // Logical Maximum (7) + 0x46, 0x3B, 0x01, // Physical Maximum (315) + 0x65, 0x14, // Unit (System: English Rotation, Length: Centimeter) + 0x09, 0x39, // Usage (Hat switch) + 0x81, 0x42, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,Null State) + 0x65, 0x00, // Unit (None) + 0x75, 0x01, // Report Size (1) + 0x95, 0x0C, // Report Count (12) + 0x25, 0x01, // Logical Maximum (1) + 0x45, 0x01, // Physical Maximum (1) + 0x05, 0x09, // Usage Page (Button) + 0x19, 0x01, // Usage Minimum (0x01) + 0x29, 0x0C, // Usage Maximum (0x0C) + 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0x06, 0x00, 0xFF, // Usage Page (Vendor Defined 0xFF00) + 0x75, 0x01, // Report Size (1) + 0x95, 0x08, // Report Count (8) + 0x25, 0x01, // Logical Maximum (1) + 0x45, 0x01, // Physical Maximum (1) + 0x09, 0x01, // Usage (0x01) + 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0xC0, // End Collection + 0xA1, 0x02, // Collection (Logical) + 0x75, 0x08, // Report Size (8) + 0x95, 0x07, // Report Count (7) + 0x46, 0xFF, 0x00, // Physical Maximum (255) + 0x26, 0xFF, 0x00, // Logical Maximum (255) + 0x09, 0x02, // Usage (0x02) + 0x91, 0x02, // Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) + 0xC0, // End Collection + 0xC0, // End Collection + }; + tuh_hid_report_info_t report_info[3]; + + uint8_t report_count = tuh_hid_parse_report_descriptor(report_info, 3, (const uint8_t*)&tb, sizeof(tb)); + TEST_ASSERT_EQUAL(1, report_count); +} From 3d87d3634bd349b0a35c617c067600b94442f972 Mon Sep 17 00:00:00 2001 From: Phil Date: Fri, 11 Feb 2022 21:19:38 +0000 Subject: [PATCH 43/71] HID micro parser --- src/class/hid/hid_rip.c | 28 ++++++++++++++++++++++++++++ src/class/hid/hid_rip.h | 14 ++++++++++++++ test/test/class/hid/test_hid_rip.c | 17 ++++++++++++++++- 3 files changed, 58 insertions(+), 1 deletion(-) diff --git a/src/class/hid/hid_rip.c b/src/class/hid/hid_rip.c index 536c7b6887..3af3220d7d 100644 --- a/src/class/hid/hid_rip.c +++ b/src/class/hid/hid_rip.c @@ -192,6 +192,34 @@ uint32_t tuh_hid_rip_report_total_size_bits(tuh_hid_rip_state_t *state) } } +uint32_t tuh_hid_report_bits_u32(uint8_t const* report, uint8_t start, uint8_t length) +{ + const int16_t bit_offset_start = start & 7; + const int16_t l = length + bit_offset_start; + const uint8_t *p = report + (start >> 3); + uint32_t acc = ((uint32_t)*p++) >> bit_offset_start; + for(uint16_t i = 1; (i << 3) < l; ++i) { + acc |= ((uint32_t)*p++) << ((i << 3) - bit_offset_start); + } + const uint32_t m = (((uint32_t)1) << length) - 1; + return acc & m; +} + +int32_t tuh_hid_report_bits_i32(uint8_t const* report, uint8_t start, uint8_t length) +{ + const int16_t bit_offset_start = start & 7; + const int16_t l = length + bit_offset_start; + const uint8_t *p = report + (start >> 3); + uint32_t acc = ((uint32_t)*p++) >> bit_offset_start; + for(uint16_t i = 1; (i << 3) < l; ++i) { + acc |= ((uint32_t)*p++) << ((i << 3) - bit_offset_start); + } + const uint32_t lp0 = ((uint32_t)1) << (length - 1); + const uint32_t lp1 = lp0 << 1; + // Mask or sign extend + return acc & lp0 ? acc | -lp1 : acc & (lp1 - 1); +} + //--------------------------------------------------------------------+ // Report Descriptor Parser //--------------------------------------------------------------------+ diff --git a/src/class/hid/hid_rip.h b/src/class/hid/hid_rip.h index e52bb0f3de..3d3bb0ce50 100644 --- a/src/class/hid/hid_rip.h +++ b/src/class/hid/hid_rip.h @@ -131,9 +131,23 @@ const uint8_t* tuh_hid_rip_current_item(tuh_hid_rip_state_t *state); // Note: this currently does not include the Report ID byte uint32_t tuh_hid_rip_report_total_size_bits(tuh_hid_rip_state_t *state); +//--------------------------------------------------------------------+ +// Report Descriptor Parser +// // Parse report descriptor into array of report_info struct and return number of reports. // For complicated report, application should write its own parser. +//--------------------------------------------------------------------+ uint8_t tuh_hid_parse_report_descriptor(tuh_hid_report_info_t* reports_info_arr, uint8_t arr_count, uint8_t const* desc_report, uint16_t desc_len) TU_ATTR_UNUSED; +//--------------------------------------------------------------------+ +// Helpers for extracting values from a HID Report +//--------------------------------------------------------------------+ + +// Helper to get some bits from a HID report as an unsigned 32 bit number +uint32_t tuh_hid_report_bits_u32(uint8_t const* report, uint8_t start, uint8_t length); + +// Helper to get some bits from a HID report as a signed 32 bit number +int32_t tuh_hid_report_bits_i32(uint8_t const* report, uint8_t start, uint8_t length); + #endif diff --git a/test/test/class/hid/test_hid_rip.c b/test/test/class/hid/test_hid_rip.c index ecfc8bbc83..57a47d456e 100644 --- a/test/test/class/hid/test_hid_rip.c +++ b/test/test/class/hid/test_hid_rip.c @@ -586,5 +586,20 @@ void test_hid_parse_speedlink_report() { TEST_ASSERT_EQUAL(1, report_count); } +void test_tuh_hid_report_bits_u32() { + const uint8_t const tb[] = { + 0x50, 0x05, 0x8f, 0xff + }; + TEST_ASSERT_EQUAL(0x55, tuh_hid_report_bits_u32(tb, 4, 8)); + TEST_ASSERT_EQUAL(0x8f, tuh_hid_report_bits_u32(tb, 16, 8)); + TEST_ASSERT_EQUAL(0xff8f0550, tuh_hid_report_bits_u32(tb, 0, 32)); +} - +void test_tuh_hid_report_bits_i32() { + const uint8_t const tb[] = { + 0x50, 0x05, 0x8f, 0xff + }; + TEST_ASSERT_EQUAL(0x55, tuh_hid_report_bits_i32(tb, 4, 8)); + TEST_ASSERT_EQUAL(0xffffff8f, tuh_hid_report_bits_i32(tb, 16, 8)); + TEST_ASSERT_EQUAL(0xff8f0550, tuh_hid_report_bits_i32(tb, 0, 32)); +} From 954b3bc371021749b746bf1e7c38b4258ab43473 Mon Sep 17 00:00:00 2001 From: Phil Date: Sat, 12 Feb 2022 15:45:44 +0000 Subject: [PATCH 44/71] HID micro parser --- examples/host/cdc_msc_hid/CMakeLists.txt | 3 +- examples/host/cdc_msc_hid/Makefile | 2 + examples/host/cdc_msc_hid/src/hid_app.c | 2 +- examples/host/cdc_msc_hid/src/hid_joy.c | 93 ++++++++++ examples/host/cdc_msc_hid/src/hid_joy.h | 72 ++++++++ test/project.yml | 1 + .../examples/host/cdc_msc_hid/test_hid_joy.c | 166 ++++++++++++++++++ 7 files changed, 337 insertions(+), 2 deletions(-) create mode 100644 examples/host/cdc_msc_hid/src/hid_joy.c create mode 100644 examples/host/cdc_msc_hid/src/hid_joy.h create mode 100644 test/test/examples/host/cdc_msc_hid/test_hid_joy.c diff --git a/examples/host/cdc_msc_hid/CMakeLists.txt b/examples/host/cdc_msc_hid/CMakeLists.txt index 0a99bc3a9a..e1802badb2 100644 --- a/examples/host/cdc_msc_hid/CMakeLists.txt +++ b/examples/host/cdc_msc_hid/CMakeLists.txt @@ -15,6 +15,7 @@ add_executable(${PROJECT}) # Example source target_sources(${PROJECT} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/src/hid_app.c + ${CMAKE_CURRENT_SOURCE_DIR}/src/hid_joy.c ${CMAKE_CURRENT_SOURCE_DIR}/src/main.c ${CMAKE_CURRENT_SOURCE_DIR}/src/msc_app.c ) @@ -26,4 +27,4 @@ target_include_directories(${PROJECT} PUBLIC # Configure compilation flags and libraries for the example... see the corresponding function # in hw/bsp/FAMILY/family.cmake for details. -family_configure_host_example(${PROJECT}) \ No newline at end of file +family_configure_host_example(${PROJECT}) diff --git a/examples/host/cdc_msc_hid/Makefile b/examples/host/cdc_msc_hid/Makefile index ce0dd1a40d..fb66831d58 100644 --- a/examples/host/cdc_msc_hid/Makefile +++ b/examples/host/cdc_msc_hid/Makefile @@ -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 \ diff --git a/examples/host/cdc_msc_hid/src/hid_app.c b/examples/host/cdc_msc_hid/src/hid_app.c index ebfa5eac09..6d6f2db94c 100644 --- a/examples/host/cdc_msc_hid/src/hid_app.c +++ b/examples/host/cdc_msc_hid/src/hid_app.c @@ -38,7 +38,7 @@ static uint8_t const keycode2ascii[128][2] = { HID_KEYCODE_TO_ASCII }; -// Each HID instance can has multiple reports +// Each HID instance can have multiple reports static struct { uint8_t report_count; diff --git a/examples/host/cdc_msc_hid/src/hid_joy.c b/examples/host/cdc_msc_hid/src/hid_joy.c new file mode 100644 index 0000000000..a94403a565 --- /dev/null +++ b/examples/host/cdc_msc_hid/src/hid_joy.c @@ -0,0 +1,93 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2021, Ha Thach (tinyusb.org) + * + * 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_joy.h" +#include "hid_rip.h" + +static uint8_t hid_simple_joysick_count = 0; +static tusb_hid_simple_joysick_t hid_simple_joysicks[HID_MAX_JOYSTICKS]; + +#define HID_EUSAGE(G, L) ((G << 16) | L) + +static bool tuh_hid_joystick_check_usage(uint32_t eusage) { + // Check outer usage + switch(eusage) { + case HID_EUSAGE(HID_USAGE_PAGE_DESKTOP, HID_USAGE_DESKTOP_JOYSTICK): return true; + case HID_EUSAGE(HID_USAGE_PAGE_DESKTOP, HID_USAGE_DESKTOP_GAMEPAD): return true; + default: return false; + } +} + +uint8_t tuh_hid_joystick_parse_report_descriptor(uint8_t const* desc_report, uint16_t desc_len) { + if (hid_simple_joysick_count < HID_MAX_JOYSTICKS) { + uint32_t eusage = 0; + tuh_hid_rip_state_t pstate; + tuh_hid_rip_init_state(&pstate, desc_report, desc_len); + const uint8_t *ri; + while((ri = tuh_hid_rip_next_item(&pstate)) != NULL) + { + if (!tuh_hid_ri_is_long(ri)) + { + uint8_t const tag = tuh_hid_ri_short_tag(ri); + uint8_t const type = tuh_hid_ri_short_type(ri); + switch(type) + { + case RI_TYPE_MAIN: { + switch (tag) + { + case RI_MAIN_INPUT: { + if (tuh_hid_joystick_check_usage(eusage)) { + // This is what we care about for the joystick + + // TODO Check the outer usage is joystick/gamepad + // TODO Keep track of the report id, when it changes move to next joystick definition?? + } + break; + } + default: break; + } + break; + } + case RI_TYPE_LOCAL: { + switch(tag) + { + case RI_LOCAL_USAGE: { + if (pstate.collections_count == 0) { + eusage = pstate.usages[pstate.usage_count - 1]; + } + break; + } + default: break; + } + break; + } + default: break; + } + } + } + } + return hid_simple_joysick_count; +} + diff --git a/examples/host/cdc_msc_hid/src/hid_joy.h b/examples/host/cdc_msc_hid/src/hid_joy.h new file mode 100644 index 0000000000..4104fd3c5a --- /dev/null +++ b/examples/host/cdc_msc_hid/src/hid_joy.h @@ -0,0 +1,72 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2021, Ha Thach (tinyusb.org) + * + * 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. + * + */ + +#ifndef _TUSB_HID_JOY_H_ +#define _TUSB_HID_JOY_H_ + +#include "tusb.h" + +#ifdef __cplusplus + extern "C" { +#endif + +#define HID_MAX_JOYSTICKS 2 + +typedef struct { + union TU_ATTR_PACKED + { + uint8_t byte; + struct TU_ATTR_PACKED + { + bool is_signed : 1; + bool byte_aligned : 1; // TODO More efficient fetch from report if set + }; + } flags; + uint8_t start; + uint8_t length; +} tusb_hid_simple_axis_t; + +typedef struct { + uint8_t start; + uint8_t length; +} tusb_hid_simple_buttons_t; + +// Very simple representation of a joystick to try and map to +// (and this will be quite tricky enough). +typedef struct { + uint8_t instance; + uint8_t report_id; + tusb_hid_simple_axis_t axis_x1; + tusb_hid_simple_axis_t axis_y1; + tusb_hid_simple_axis_t axis_x2; + tusb_hid_simple_axis_t axis_y2; + tusb_hid_simple_buttons_t hat_buttons; + tusb_hid_simple_buttons_t buttons; +} tusb_hid_simple_joysick_t; + + +uint8_t tuh_hid_joystick_parse_report_descriptor(uint8_t const* desc_report, uint16_t desc_len); + +#endif diff --git a/test/project.yml b/test/project.yml index dc4a9cb28c..08a4fdcbb3 100644 --- a/test/project.yml +++ b/test/project.yml @@ -36,6 +36,7 @@ - -:test/support :source: - ../src/** + - ../examples/** :support: - test/support diff --git a/test/test/examples/host/cdc_msc_hid/test_hid_joy.c b/test/test/examples/host/cdc_msc_hid/test_hid_joy.c new file mode 100644 index 0000000000..b8b13b9f92 --- /dev/null +++ b/test/test/examples/host/cdc_msc_hid/test_hid_joy.c @@ -0,0 +1,166 @@ +/* + * 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. + * + * This file is part of the TinyUSB stack. + */ + + +#include "unity.h" + +// Files to test +#include "hid_rip.h" +#include "hid_joy.h" +TEST_FILE("hid_ri.c") +TEST_FILE("hid_rip.c") +TEST_FILE("hid_joy.c") + +void setUp(void) +{ +} + +void tearDown(void) +{ +} + +//--------------------------------------------------------------------+ +// Tests +//--------------------------------------------------------------------+ +void test_nothing() { + const uint8_t const tb[] = { + 0x05, 0x01, // Usage Page (Generic Desktop Ctrls) + 0x09, 0x04, // Usage (Joystick) + }; + TEST_ASSERT_EQUAL(0, tuh_hid_joystick_parse_report_descriptor(tb, sizeof(tb))); +} + + +void test_hid_parse_greenasia_report() { + const uint8_t const tb[] = { + 0x05, 0x01, // Usage Page (Generic Desktop Ctrls) + 0x09, 0x04, // Usage (Joystick) + 0xA1, 0x01, // Collection (Application) + 0xA1, 0x02, // Collection (Logical) + 0x75, 0x08, // Report Size (8) + 0x95, 0x05, // Report Count (5) + 0x15, 0x00, // Logical Minimum (0) + 0x26, 0xFF, 0x00, // Logical Maximum (255) + 0x35, 0x00, // Physical Minimum (0) + 0x46, 0xFF, 0x00, // Physical Maximum (255) + 0x09, 0x32, // Usage (Z) + 0x09, 0x35, // Usage (Rz) + 0x09, 0x30, // Usage (X) + 0x09, 0x31, // Usage (Y) + 0x09, 0x00, // Usage (Undefined) + 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0x75, 0x04, // Report Size (4) + 0x95, 0x01, // Report Count (1) + 0x25, 0x07, // Logical Maximum (7) + 0x46, 0x3B, 0x01, // Physical Maximum (315) + 0x65, 0x14, // Unit (System: English Rotation, Length: Centimeter) + 0x09, 0x39, // Usage (Hat switch) + 0x81, 0x42, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,Null State) + 0x65, 0x00, // Unit (None) + 0x75, 0x01, // Report Size (1) + 0x95, 0x0C, // Report Count (12) + 0x25, 0x01, // Logical Maximum (1) + 0x45, 0x01, // Physical Maximum (1) + 0x05, 0x09, // Usage Page (Button) + 0x19, 0x01, // Usage Minimum (0x01) + 0x29, 0x0C, // Usage Maximum (0x0C) + 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0x06, 0x00, 0xFF, // Usage Page (Vendor Defined 0xFF00) + 0x75, 0x01, // Report Size (1) + 0x95, 0x08, // Report Count (8) + 0x25, 0x01, // Logical Maximum (1) + 0x45, 0x01, // Physical Maximum (1) + 0x09, 0x01, // Usage (0x01) + 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0xC0, // End Collection + 0xA1, 0x02, // Collection (Logical) + 0x75, 0x08, // Report Size (8) + 0x95, 0x04, // Report Count (4) + 0x46, 0xFF, 0x00, // Physical Maximum (255) + 0x26, 0xFF, 0x00, // Logical Maximum (255) + 0x09, 0x02, // Usage (0x02) + 0x91, 0x02, // Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) + 0xC0, // End Collection + 0xC0, // End Collection + }; + tuh_hid_joystick_parse_report_descriptor(tb, sizeof(tb)); + +} + +void test_hid_parse_speedlink_report() { + const uint8_t const tb[] = { + 0x05, 0x01, // Usage Page (Generic Desktop Ctrls) + 0x09, 0x04, // Usage (Joystick) + 0xA1, 0x01, // Collection (Application) + 0xA1, 0x02, // Collection (Logical) + 0x75, 0x08, // Report Size (8) + 0x95, 0x05, // Report Count (5) + 0x15, 0x00, // Logical Minimum (0) + 0x26, 0xFF, 0x00, // Logical Maximum (255) + 0x35, 0x00, // Physical Minimum (0) + 0x46, 0xFF, 0x00, // Physical Maximum (255) + 0x09, 0x30, // Usage (X) + 0x09, 0x31, // Usage (Y) + 0x09, 0x32, // Usage (Z) + 0x09, 0x32, // Usage (Z) + 0x09, 0x35, // Usage (Rz) + 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0x75, 0x04, // Report Size (4) + 0x95, 0x01, // Report Count (1) + 0x25, 0x07, // Logical Maximum (7) + 0x46, 0x3B, 0x01, // Physical Maximum (315) + 0x65, 0x14, // Unit (System: English Rotation, Length: Centimeter) + 0x09, 0x39, // Usage (Hat switch) + 0x81, 0x42, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,Null State) + 0x65, 0x00, // Unit (None) + 0x75, 0x01, // Report Size (1) + 0x95, 0x0C, // Report Count (12) + 0x25, 0x01, // Logical Maximum (1) + 0x45, 0x01, // Physical Maximum (1) + 0x05, 0x09, // Usage Page (Button) + 0x19, 0x01, // Usage Minimum (0x01) + 0x29, 0x0C, // Usage Maximum (0x0C) + 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0x06, 0x00, 0xFF, // Usage Page (Vendor Defined 0xFF00) + 0x75, 0x01, // Report Size (1) + 0x95, 0x08, // Report Count (8) + 0x25, 0x01, // Logical Maximum (1) + 0x45, 0x01, // Physical Maximum (1) + 0x09, 0x01, // Usage (0x01) + 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0xC0, // End Collection + 0xA1, 0x02, // Collection (Logical) + 0x75, 0x08, // Report Size (8) + 0x95, 0x07, // Report Count (7) + 0x46, 0xFF, 0x00, // Physical Maximum (255) + 0x26, 0xFF, 0x00, // Logical Maximum (255) + 0x09, 0x02, // Usage (0x02) + 0x91, 0x02, // Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) + 0xC0, // End Collection + 0xC0, // End Collection + }; + +} + + From 34e0cd5bffa2befc509749f2ef6c3f283bae378d Mon Sep 17 00:00:00 2001 From: Phil Date: Sat, 12 Feb 2022 18:21:28 +0000 Subject: [PATCH 45/71] HID micro parser --- examples/host/cdc_msc_hid/src/hid_joy.c | 39 ++++++- examples/host/cdc_msc_hid/src/hid_joy.h | 36 +++++- .../examples/host/cdc_msc_hid/test_hid_joy.c | 105 +++++++++++++----- 3 files changed, 146 insertions(+), 34 deletions(-) diff --git a/examples/host/cdc_msc_hid/src/hid_joy.c b/examples/host/cdc_msc_hid/src/hid_joy.c index a94403a565..f6b42d14fa 100644 --- a/examples/host/cdc_msc_hid/src/hid_joy.c +++ b/examples/host/cdc_msc_hid/src/hid_joy.c @@ -1,8 +1,6 @@ /* * The MIT License (MIT) * - * Copyright (c) 2021, Ha Thach (tinyusb.org) - * * 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 @@ -21,10 +19,12 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. * + * Test me with: + * + * ceedling test:pattern[hid_joy] */ #include "hid_joy.h" -#include "hid_rip.h" static uint8_t hid_simple_joysick_count = 0; static tusb_hid_simple_joysick_t hid_simple_joysicks[HID_MAX_JOYSTICKS]; @@ -35,11 +35,42 @@ static bool tuh_hid_joystick_check_usage(uint32_t eusage) { // Check outer usage switch(eusage) { case HID_EUSAGE(HID_USAGE_PAGE_DESKTOP, HID_USAGE_DESKTOP_JOYSTICK): return true; - case HID_EUSAGE(HID_USAGE_PAGE_DESKTOP, HID_USAGE_DESKTOP_GAMEPAD): return true; + case HID_EUSAGE(HID_USAGE_PAGE_DESKTOP, HID_USAGE_DESKTOP_GAMEPAD): return true; // TODO not sure about this one default: return false; } } + + +// 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_joystick_get_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_joystick_data_t* jdata) // 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); + + // We need to know how the size of the data + if (ri_report_size == NULL || ri_report_count == NULL) return false; + + jdata->report_size = tuh_hid_ri_short_udata32(ri_report_size); + jdata->report_count = tuh_hid_ri_short_udata32(ri_report_count); + jdata->report_id = ri_report_id ? tuh_hid_ri_short_udata8(ri_report_id) : 0; + jdata->logical_min = ri_logical_min ? tuh_hid_ri_short_data32(ri_logical_min) : 0; + jdata->logical_max = ri_logical_max ? tuh_hid_ri_short_data32(ri_logical_max) : 0; + jdata->input_flags.byte = tuh_hid_ri_short_udata8(ri_input); + + return true; +} + uint8_t tuh_hid_joystick_parse_report_descriptor(uint8_t const* desc_report, uint16_t desc_len) { if (hid_simple_joysick_count < HID_MAX_JOYSTICKS) { uint32_t eusage = 0; diff --git a/examples/host/cdc_msc_hid/src/hid_joy.h b/examples/host/cdc_msc_hid/src/hid_joy.h index 4104fd3c5a..f8c488e8a0 100644 --- a/examples/host/cdc_msc_hid/src/hid_joy.h +++ b/examples/host/cdc_msc_hid/src/hid_joy.h @@ -1,8 +1,6 @@ /* * The MIT License (MIT) * - * Copyright (c) 2021, Ha Thach (tinyusb.org) - * * 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 @@ -27,6 +25,7 @@ #define _TUSB_HID_JOY_H_ #include "tusb.h" +#include "hid_rip.h" #ifdef __cplusplus extern "C" { @@ -34,6 +33,21 @@ #define HID_MAX_JOYSTICKS 2 +typedef union TU_ATTR_PACKED +{ + uint8_t byte; + struct TU_ATTR_PACKED + { + bool data_const : 1; + bool array_variable : 1; + bool absolute_relative : 1; + bool nowrap_wrap : 1; + bool linear_nonlinear : 1; + bool prefered_noprefered : 1; + bool nonull_null : 1; + }; +} tusb_hid_ri_intput_flags_t; + typedef struct { union TU_ATTR_PACKED { @@ -66,6 +80,24 @@ typedef struct { tusb_hid_simple_buttons_t buttons; } tusb_hid_simple_joysick_t; +typedef struct { + uint32_t report_size; // TODO make this a uint8_t and range check before assignment + uint32_t report_count; // TODO make this a uint8_t and range check before assignment + uint8_t report_id; + uint32_t logical_min; + uint32_t logical_max; + tusb_hid_ri_intput_flags_t input_flags; +} tuh_hid_joystick_data_t; + +// 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_joystick_get_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_joystick_data_t* jdata); // Data structure to complete uint8_t tuh_hid_joystick_parse_report_descriptor(uint8_t const* desc_report, uint16_t desc_len); diff --git a/test/test/examples/host/cdc_msc_hid/test_hid_joy.c b/test/test/examples/host/cdc_msc_hid/test_hid_joy.c index b8b13b9f92..1ea413069d 100644 --- a/test/test/examples/host/cdc_msc_hid/test_hid_joy.c +++ b/test/test/examples/host/cdc_msc_hid/test_hid_joy.c @@ -32,28 +32,7 @@ TEST_FILE("hid_ri.c") TEST_FILE("hid_rip.c") TEST_FILE("hid_joy.c") -void setUp(void) -{ -} - -void tearDown(void) -{ -} - -//--------------------------------------------------------------------+ -// Tests -//--------------------------------------------------------------------+ -void test_nothing() { - const uint8_t const tb[] = { - 0x05, 0x01, // Usage Page (Generic Desktop Ctrls) - 0x09, 0x04, // Usage (Joystick) - }; - TEST_ASSERT_EQUAL(0, tuh_hid_joystick_parse_report_descriptor(tb, sizeof(tb))); -} - - -void test_hid_parse_greenasia_report() { - const uint8_t const tb[] = { +static const uint8_t const tb_greenasia[] = { 0x05, 0x01, // Usage Page (Generic Desktop Ctrls) 0x09, 0x04, // Usage (Joystick) 0xA1, 0x01, // Collection (Application) @@ -103,13 +82,9 @@ void test_hid_parse_greenasia_report() { 0x91, 0x02, // Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) 0xC0, // End Collection 0xC0, // End Collection - }; - tuh_hid_joystick_parse_report_descriptor(tb, sizeof(tb)); +}; -} - -void test_hid_parse_speedlink_report() { - const uint8_t const tb[] = { +static const uint8_t const tb_speedlink[] = { 0x05, 0x01, // Usage Page (Generic Desktop Ctrls) 0x09, 0x04, // Usage (Joystick) 0xA1, 0x01, // Collection (Application) @@ -161,6 +136,80 @@ void test_hid_parse_speedlink_report() { 0xC0, // End Collection }; +void setUp(void) +{ +} + +void tearDown(void) +{ +} + +//--------------------------------------------------------------------+ +// Tests +//--------------------------------------------------------------------+ +void test_nothing() { + const uint8_t const tb[] = { + 0x05, 0x01, // Usage Page (Generic Desktop Ctrls) + 0x09, 0x04, // Usage (Joystick) + }; + TEST_ASSERT_EQUAL(0, tuh_hid_joystick_parse_report_descriptor(tb, sizeof(tb))); +} + +void test_tuh_hid_joystick_get_data() { + tuh_hid_joystick_data_t joystick_data; + tuh_hid_rip_state_t pstate; + tuh_hid_rip_init_state(&pstate, tb_speedlink, sizeof(tb_speedlink)); + const uint8_t *ri; + + while((ri = tuh_hid_rip_next_item(&pstate)) != NULL ) if (ri >= &tb_speedlink[32]) break; + TEST_ASSERT_EQUAL(&tb_speedlink[32], ri); // Move to the first input in the speedlink description + TEST_ASSERT_EQUAL(true, tuh_hid_joystick_get_data(&pstate, ri, &joystick_data)); + + TEST_ASSERT_EQUAL(8, joystick_data.report_size); + TEST_ASSERT_EQUAL(5, joystick_data.report_count); + TEST_ASSERT_EQUAL(0, joystick_data.report_id); + TEST_ASSERT_EQUAL(0, joystick_data.logical_min); + TEST_ASSERT_EQUAL(255, joystick_data.logical_max); + + TEST_ASSERT_EQUAL(false, joystick_data.input_flags.data_const); + TEST_ASSERT_EQUAL(true, joystick_data.input_flags.array_variable); + TEST_ASSERT_EQUAL(false, joystick_data.input_flags.absolute_relative); + TEST_ASSERT_EQUAL(false, joystick_data.input_flags.nowrap_wrap); + TEST_ASSERT_EQUAL(false, joystick_data.input_flags.linear_nonlinear); + TEST_ASSERT_EQUAL(false, joystick_data.input_flags.prefered_noprefered); + TEST_ASSERT_EQUAL(false, joystick_data.input_flags.nonull_null); + + while((ri = tuh_hid_rip_next_item(&pstate)) != NULL ) if (ri >= &tb_speedlink[47]) break; + TEST_ASSERT_EQUAL(&tb_speedlink[47], ri); // Move to the second input in the speedlink description + TEST_ASSERT_EQUAL(true, tuh_hid_joystick_get_data(&pstate, ri, &joystick_data)); + + // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) + TEST_ASSERT_EQUAL(4, joystick_data.report_size); + TEST_ASSERT_EQUAL(1, joystick_data.report_count); + TEST_ASSERT_EQUAL(0, joystick_data.report_id); + TEST_ASSERT_EQUAL(0, joystick_data.logical_min); + TEST_ASSERT_EQUAL(7, joystick_data.logical_max); + + // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,Null State) + TEST_ASSERT_EQUAL(false, joystick_data.input_flags.data_const); + TEST_ASSERT_EQUAL(true, joystick_data.input_flags.array_variable); + TEST_ASSERT_EQUAL(false, joystick_data.input_flags.absolute_relative); + TEST_ASSERT_EQUAL(false, joystick_data.input_flags.nowrap_wrap); + TEST_ASSERT_EQUAL(false, joystick_data.input_flags.linear_nonlinear); + TEST_ASSERT_EQUAL(false, joystick_data.input_flags.prefered_noprefered); + TEST_ASSERT_EQUAL(true, joystick_data.input_flags.nonull_null); +} + + +void test_hid_parse_greenasia_report() { + + // tuh_hid_joystick_parse_report_descriptor(tb, sizeof(tb)); + +} + +void test_hid_parse_speedlink_report() { + + } From aea8893b0ca0361d01dc95f7b516181e580509c7 Mon Sep 17 00:00:00 2001 From: Phil Date: Sat, 12 Feb 2022 22:52:19 +0000 Subject: [PATCH 46/71] HID micro parser --- examples/host/cdc_msc_hid/src/hid_joy.c | 68 +++++++++++++++++-- examples/host/cdc_msc_hid/src/hid_joy.h | 15 +++- .../examples/host/cdc_msc_hid/test_hid_joy.c | 39 ++++++++++- 3 files changed, 113 insertions(+), 9 deletions(-) diff --git a/examples/host/cdc_msc_hid/src/hid_joy.c b/examples/host/cdc_msc_hid/src/hid_joy.c index f6b42d14fa..3414b5780a 100644 --- a/examples/host/cdc_msc_hid/src/hid_joy.c +++ b/examples/host/cdc_msc_hid/src/hid_joy.c @@ -40,8 +40,6 @@ static bool tuh_hid_joystick_check_usage(uint32_t eusage) { } } - - // Fetch some data from the HID parser // // The data fetched here may be relevant to multiple usage items @@ -57,9 +55,12 @@ bool tuh_hid_joystick_get_data( 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) return false; + if (ri_report_size == NULL || ri_report_count == NULL || ri_usage_page == NULL) return false; jdata->report_size = tuh_hid_ri_short_udata32(ri_report_size); jdata->report_count = tuh_hid_ri_short_udata32(ri_report_count); @@ -67,10 +68,69 @@ bool tuh_hid_joystick_get_data( jdata->logical_min = ri_logical_min ? tuh_hid_ri_short_data32(ri_logical_min) : 0; jdata->logical_max = ri_logical_max ? tuh_hid_ri_short_data32(ri_logical_max) : 0; jdata->input_flags.byte = tuh_hid_ri_short_udata8(ri_input); + jdata->usage_page = tuh_hid_ri_short_udata32(ri_usage_page); + jdata->usage_min = ri_usage_min ? tuh_hid_ri_short_udata32(ri_usage_min) : 0; + jdata->usage_max = ri_usage_max ? tuh_hid_ri_short_udata32(ri_usage_max) : 0; + jdata->usage_is_range = (ri_usage_min != NULL) && (ri_usage_max != NULL); return true; } +void tuh_hid_joystick_process_usages( + tuh_hid_rip_state_t *pstate, + tuh_hid_joystick_data_t* jdata, + uint32_t bitpos) +{ + if (jdata->input_flags.data_const) { + printf("const bits %d \n", jdata->report_size * jdata->report_count); + return; + } + + // If there are no specific usages look for a range + // TODO What is the correct behaviour if there are both? + if (pstate->usage_count == 0 && !jdata->usage_is_range) { + printf("no usage - skipping bits %d \n", jdata->report_size * jdata->report_count); + return; + } + + if (jdata->input_flags.data_const) { + printf("skipping const bits %d \n", jdata->report_size * jdata->report_count); + return; + } + + // TODO Naive, assumes buttons are defined in a range + if (jdata->usage_is_range) { + if (jdata->usage_page == HID_USAGE_PAGE_BUTTON) { + printf("Buttons %d to %d\n", jdata->usage_min, jdata->usage_max); + return; + } + } + + for (uint8_t i = 0; i < jdata->report_count; ++i) { + uint32_t eusage = pstate->usages[i < pstate->usage_count ? i : pstate->usage_count - 1]; + switch (eusage) { + // Seems to be common usage for gamepads. + // Probably needs a lot more thought... + case HID_EUSAGE(HID_USAGE_PAGE_DESKTOP, HID_USAGE_DESKTOP_X): + case HID_EUSAGE(HID_USAGE_PAGE_DESKTOP, HID_USAGE_DESKTOP_Y): + case HID_EUSAGE(HID_USAGE_PAGE_DESKTOP, HID_USAGE_DESKTOP_Z): + case HID_EUSAGE(HID_USAGE_PAGE_DESKTOP, HID_USAGE_DESKTOP_RZ): + printf("Axis\n"); + break; + + case HID_EUSAGE(HID_USAGE_PAGE_DESKTOP, HID_USAGE_DESKTOP_HAT_SWITCH): + printf("Hat\n"); + break; + + default: break; + } + + + bitpos += jdata->report_size; + } + +} + uint8_t tuh_hid_joystick_parse_report_descriptor(uint8_t const* desc_report, uint16_t desc_len) { if (hid_simple_joysick_count < HID_MAX_JOYSTICKS) { uint32_t eusage = 0; diff --git a/examples/host/cdc_msc_hid/src/hid_joy.h b/examples/host/cdc_msc_hid/src/hid_joy.h index f8c488e8a0..b7411b3411 100644 --- a/examples/host/cdc_msc_hid/src/hid_joy.h +++ b/examples/host/cdc_msc_hid/src/hid_joy.h @@ -83,10 +83,14 @@ typedef struct { typedef struct { uint32_t report_size; // TODO make this a uint8_t and range check before assignment uint32_t report_count; // TODO make this a uint8_t and range check before assignment - uint8_t report_id; uint32_t logical_min; uint32_t logical_max; + uint16_t usage_page; + uint16_t usage_min; + uint16_t usage_max; + uint8_t report_id; tusb_hid_ri_intput_flags_t input_flags; + bool usage_is_range; } tuh_hid_joystick_data_t; // Fetch some data from the HID parser @@ -97,7 +101,14 @@ typedef struct { bool tuh_hid_joystick_get_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_joystick_data_t* jdata); // Data structure to complete + tuh_hid_joystick_data_t* jdata // Data structure to complete +); + +void tuh_hid_joystick_process_usages( + tuh_hid_rip_state_t *pstate, + tuh_hid_joystick_data_t* jdata, + uint32_t bitpos +); uint8_t tuh_hid_joystick_parse_report_descriptor(uint8_t const* desc_report, uint16_t desc_len); diff --git a/test/test/examples/host/cdc_msc_hid/test_hid_joy.c b/test/test/examples/host/cdc_msc_hid/test_hid_joy.c index 1ea413069d..195cc6e85c 100644 --- a/test/test/examples/host/cdc_msc_hid/test_hid_joy.c +++ b/test/test/examples/host/cdc_msc_hid/test_hid_joy.c @@ -170,7 +170,9 @@ void test_tuh_hid_joystick_get_data() { TEST_ASSERT_EQUAL(0, joystick_data.report_id); TEST_ASSERT_EQUAL(0, joystick_data.logical_min); TEST_ASSERT_EQUAL(255, joystick_data.logical_max); - + TEST_ASSERT_EQUAL(false, joystick_data.usage_is_range); + + // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) TEST_ASSERT_EQUAL(false, joystick_data.input_flags.data_const); TEST_ASSERT_EQUAL(true, joystick_data.input_flags.array_variable); TEST_ASSERT_EQUAL(false, joystick_data.input_flags.absolute_relative); @@ -179,17 +181,20 @@ void test_tuh_hid_joystick_get_data() { TEST_ASSERT_EQUAL(false, joystick_data.input_flags.prefered_noprefered); TEST_ASSERT_EQUAL(false, joystick_data.input_flags.nonull_null); + tuh_hid_joystick_process_usages(&pstate, &joystick_data, 0); + + while((ri = tuh_hid_rip_next_item(&pstate)) != NULL ) if (ri >= &tb_speedlink[47]) break; TEST_ASSERT_EQUAL(&tb_speedlink[47], ri); // Move to the second input in the speedlink description TEST_ASSERT_EQUAL(true, tuh_hid_joystick_get_data(&pstate, ri, &joystick_data)); - // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) TEST_ASSERT_EQUAL(4, joystick_data.report_size); TEST_ASSERT_EQUAL(1, joystick_data.report_count); TEST_ASSERT_EQUAL(0, joystick_data.report_id); TEST_ASSERT_EQUAL(0, joystick_data.logical_min); TEST_ASSERT_EQUAL(7, joystick_data.logical_max); - + TEST_ASSERT_EQUAL(false, joystick_data.usage_is_range); + // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,Null State) TEST_ASSERT_EQUAL(false, joystick_data.input_flags.data_const); TEST_ASSERT_EQUAL(true, joystick_data.input_flags.array_variable); @@ -198,6 +203,34 @@ void test_tuh_hid_joystick_get_data() { TEST_ASSERT_EQUAL(false, joystick_data.input_flags.linear_nonlinear); TEST_ASSERT_EQUAL(false, joystick_data.input_flags.prefered_noprefered); TEST_ASSERT_EQUAL(true, joystick_data.input_flags.nonull_null); + + tuh_hid_joystick_process_usages(&pstate, &joystick_data, 40); + + + while((ri = tuh_hid_rip_next_item(&pstate)) != NULL ) if (ri >= &tb_speedlink[65]) break; + TEST_ASSERT_EQUAL(&tb_speedlink[65], ri); // Move to the second input in the speedlink description + TEST_ASSERT_EQUAL(true, tuh_hid_joystick_get_data(&pstate, ri, &joystick_data)); + + TEST_ASSERT_EQUAL(1, joystick_data.report_size); + TEST_ASSERT_EQUAL(12, joystick_data.report_count); + TEST_ASSERT_EQUAL(0, joystick_data.report_id); + TEST_ASSERT_EQUAL(0, joystick_data.logical_min); + TEST_ASSERT_EQUAL(1, joystick_data.logical_max); + TEST_ASSERT_EQUAL(true, joystick_data.usage_is_range); + TEST_ASSERT_EQUAL(1, joystick_data.usage_min); + TEST_ASSERT_EQUAL(12, joystick_data.usage_max); + + // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) + TEST_ASSERT_EQUAL(false, joystick_data.input_flags.data_const); + TEST_ASSERT_EQUAL(true, joystick_data.input_flags.array_variable); + TEST_ASSERT_EQUAL(false, joystick_data.input_flags.absolute_relative); + TEST_ASSERT_EQUAL(false, joystick_data.input_flags.nowrap_wrap); + TEST_ASSERT_EQUAL(false, joystick_data.input_flags.linear_nonlinear); + TEST_ASSERT_EQUAL(false, joystick_data.input_flags.prefered_noprefered); + TEST_ASSERT_EQUAL(false, joystick_data.input_flags.nonull_null); + + tuh_hid_joystick_process_usages(&pstate, &joystick_data, 44); // 56 + } From 86d3c0def04ced2ecd2db26681bf9bc6b2a8b6a9 Mon Sep 17 00:00:00 2001 From: Phil Date: Sun, 13 Feb 2022 07:36:49 +0000 Subject: [PATCH 47/71] HID micro parser --- examples/host/cdc_msc_hid/src/hid_joy.c | 65 +++++++---------- src/class/hid/hid_ri.c | 4 ++ src/class/hid/hid_ri.h | 5 ++ src/class/hid/hid_rip.c | 92 ++++++++++--------------- src/class/hid/hid_rip.h | 9 +++ test/test/class/hid/test_hid_ri.c | 2 + 6 files changed, 80 insertions(+), 97 deletions(-) diff --git a/examples/host/cdc_msc_hid/src/hid_joy.c b/examples/host/cdc_msc_hid/src/hid_joy.c index 3414b5780a..2ad855a084 100644 --- a/examples/host/cdc_msc_hid/src/hid_joy.c +++ b/examples/host/cdc_msc_hid/src/hid_joy.c @@ -29,13 +29,11 @@ static uint8_t hid_simple_joysick_count = 0; static tusb_hid_simple_joysick_t hid_simple_joysicks[HID_MAX_JOYSTICKS]; -#define HID_EUSAGE(G, L) ((G << 16) | L) - static bool tuh_hid_joystick_check_usage(uint32_t eusage) { // Check outer usage switch(eusage) { - case HID_EUSAGE(HID_USAGE_PAGE_DESKTOP, HID_USAGE_DESKTOP_JOYSTICK): return true; - case HID_EUSAGE(HID_USAGE_PAGE_DESKTOP, HID_USAGE_DESKTOP_GAMEPAD): return true; // TODO not sure about this one + case HID_RIP_EUSAGE(HID_USAGE_PAGE_DESKTOP, HID_USAGE_DESKTOP_JOYSTICK): return true; + case HID_RIP_EUSAGE(HID_USAGE_PAGE_DESKTOP, HID_USAGE_DESKTOP_GAMEPAD): return true; // TODO not sure about this one default: return false; } } @@ -111,14 +109,14 @@ void tuh_hid_joystick_process_usages( switch (eusage) { // Seems to be common usage for gamepads. // Probably needs a lot more thought... - case HID_EUSAGE(HID_USAGE_PAGE_DESKTOP, HID_USAGE_DESKTOP_X): - case HID_EUSAGE(HID_USAGE_PAGE_DESKTOP, HID_USAGE_DESKTOP_Y): - case HID_EUSAGE(HID_USAGE_PAGE_DESKTOP, HID_USAGE_DESKTOP_Z): - case HID_EUSAGE(HID_USAGE_PAGE_DESKTOP, HID_USAGE_DESKTOP_RZ): + case HID_RIP_EUSAGE(HID_USAGE_PAGE_DESKTOP, HID_USAGE_DESKTOP_X): + case HID_RIP_EUSAGE(HID_USAGE_PAGE_DESKTOP, HID_USAGE_DESKTOP_Y): + case HID_RIP_EUSAGE(HID_USAGE_PAGE_DESKTOP, HID_USAGE_DESKTOP_Z): + case HID_RIP_EUSAGE(HID_USAGE_PAGE_DESKTOP, HID_USAGE_DESKTOP_RZ): printf("Axis\n"); break; - case HID_EUSAGE(HID_USAGE_PAGE_DESKTOP, HID_USAGE_DESKTOP_HAT_SWITCH): + case HID_RIP_EUSAGE(HID_USAGE_PAGE_DESKTOP, HID_USAGE_DESKTOP_HAT_SWITCH): printf("Hat\n"); break; @@ -137,45 +135,28 @@ uint8_t tuh_hid_joystick_parse_report_descriptor(uint8_t const* desc_report, uin tuh_hid_rip_state_t pstate; tuh_hid_rip_init_state(&pstate, desc_report, desc_len); const uint8_t *ri; - while((ri = tuh_hid_rip_next_item(&pstate)) != NULL) + while((ri = tuh_hid_rip_next_short_item(&pstate)) != NULL) { - if (!tuh_hid_ri_is_long(ri)) + uint8_t const type_and_tag = tuh_hid_ri_short_type_and_tag(ri); + + switch(type_and_tag) { - uint8_t const tag = tuh_hid_ri_short_tag(ri); - uint8_t const type = tuh_hid_ri_short_type(ri); - switch(type) - { - case RI_TYPE_MAIN: { - switch (tag) - { - case RI_MAIN_INPUT: { - if (tuh_hid_joystick_check_usage(eusage)) { - // This is what we care about for the joystick + case HID_RI_TYPE_AND_TAG(RI_TYPE_MAIN, RI_MAIN_INPUT): { + if (tuh_hid_joystick_check_usage(eusage)) { + // This is what we care about for the joystick - // TODO Check the outer usage is joystick/gamepad - // TODO Keep track of the report id, when it changes move to next joystick definition?? - } - break; - } - default: break; - } - break; + // TODO Check the outer usage is joystick/gamepad + // TODO Keep track of the report id, when it changes move to next joystick definition?? } - case RI_TYPE_LOCAL: { - switch(tag) - { - case RI_LOCAL_USAGE: { - if (pstate.collections_count == 0) { - eusage = pstate.usages[pstate.usage_count - 1]; - } - break; - } - default: break; - } - break; + break; + } + case HID_RI_TYPE_AND_TAG(RI_TYPE_LOCAL, RI_LOCAL_USAGE): { + if (pstate.collections_count == 0) { + eusage = pstate.usages[pstate.usage_count - 1]; } - default: break; + break; } + default: break; } } } diff --git a/src/class/hid/hid_ri.c b/src/class/hid/hid_ri.c index 8fa2a97840..a5a6c25526 100644 --- a/src/class/hid/hid_ri.c +++ b/src/class/hid/hid_ri.c @@ -40,6 +40,10 @@ uint8_t tuh_hid_ri_short_tag(const uint8_t *ri) { return (*ri >> 4) & 15; } +uint8_t tuh_hid_ri_short_type_and_tag(const uint8_t *ri) { + return (*ri) & 0xfc; +} + bool tuh_hid_ri_is_long(const uint8_t *ri) { return *ri == 0xfe; } diff --git a/src/class/hid/hid_ri.h b/src/class/hid/hid_ri.h index 5961516a65..afa9cf4e15 100644 --- a/src/class/hid/hid_ri.h +++ b/src/class/hid/hid_ri.h @@ -31,6 +31,8 @@ extern "C" { #endif +#define HID_RI_TYPE_AND_TAG(TYPE, TAG) ((TAG << 4) | (TYPE << 2)) + //--------------------------------------------------------------------+ // HID Report Description Item functions // @@ -53,6 +55,9 @@ uint8_t tuh_hid_ri_short_type(const uint8_t *ri); // Get the tag from a short item uint8_t tuh_hid_ri_short_tag(const uint8_t *ri); +// Get the tag and type with length bits set to 0 +uint8_t tuh_hid_ri_short_type_and_tag(const uint8_t *ri); + // Test if the item is a long item bool tuh_hid_ri_is_long(const uint8_t *ri); diff --git a/src/class/hid/hid_rip.c b/src/class/hid/hid_rip.c index 3af3220d7d..b85f9f88f1 100644 --- a/src/class/hid/hid_rip.c +++ b/src/class/hid/hid_rip.c @@ -159,6 +159,13 @@ const uint8_t* tuh_hid_rip_next_item(tuh_hid_rip_state_t *state) return ri; } +const uint8_t* tuh_hid_rip_next_short_item(tuh_hid_rip_state_t *state) +{ + const uint8_t* ri; + while((ri = tuh_hid_rip_next_item(state)) != NULL) if (!tuh_hid_ri_is_long(ri)) break; + return ri; +} + const uint8_t* tuh_hid_rip_global(tuh_hid_rip_state_t *state, uint8_t tag) { return state->global_items[state->stack_index][tag]; @@ -235,66 +242,41 @@ uint8_t tuh_hid_parse_report_descriptor(tuh_hid_report_info_t* report_info_arr, tuh_hid_rip_state_t pstate; tuh_hid_rip_init_state(&pstate, desc_report, desc_len); const uint8_t *ri; - while((ri = tuh_hid_rip_next_item(&pstate)) != NULL) + while((ri = tuh_hid_rip_next_short_item(&pstate)) != NULL) { - if (!tuh_hid_ri_is_long(ri)) + uint8_t const type_and_tag = tuh_hid_ri_short_type_and_tag(ri); + + switch(type_and_tag) { - uint8_t const tag = tuh_hid_ri_short_tag(ri); - uint8_t const type = tuh_hid_ri_short_type(ri); - switch(type) - { - case RI_TYPE_MAIN: { - switch (tag) - { - case RI_MAIN_INPUT: { - info->in_len += tuh_hid_rip_report_total_size_bits(&pstate); - info->usage = usage; - info->usage_page = usage_page; - break; - } - case RI_MAIN_OUTPUT: { - info->out_len += tuh_hid_rip_report_total_size_bits(&pstate); - info->usage = usage; - info->usage_page = usage_page; - break; - } - default: break; - } - break; - } - case RI_TYPE_GLOBAL: { - switch(tag) - { - case RI_GLOBAL_REPORT_ID: { - if (info->report_id > 0 || info->in_len > 0 || info->out_len > 0) { - info++; - report_num++; - } - info->report_id = tuh_hid_ri_short_udata8(ri); - break; - } - default: break; - } - break; + case HID_RI_TYPE_AND_TAG(RI_TYPE_MAIN, RI_MAIN_INPUT): { + info->in_len += tuh_hid_rip_report_total_size_bits(&pstate); + info->usage = usage; + info->usage_page = usage_page; + break; + } + case HID_RI_TYPE_AND_TAG(RI_TYPE_MAIN, RI_MAIN_OUTPUT): { + info->out_len += tuh_hid_rip_report_total_size_bits(&pstate); + info->usage = usage; + info->usage_page = usage_page; + break; + } + case HID_RI_TYPE_AND_TAG(RI_TYPE_GLOBAL, RI_GLOBAL_REPORT_ID): { + if (info->report_id > 0 || info->in_len > 0 || info->out_len > 0) { + info++; + report_num++; } - case RI_TYPE_LOCAL: { - switch(tag) - { - case RI_LOCAL_USAGE: - // only take into account the "usage" before starting REPORT ID - if ( pstate.collections_count == 0 ) { - uint32_t eusage = pstate.usages[pstate.usage_count - 1]; - tuh_hid_ri_split_usage(eusage, &usage, &usage_page); - } - break; - - default: break; - } - break; + info->report_id = tuh_hid_ri_short_udata8(ri); + break; + } + case HID_RI_TYPE_AND_TAG(RI_TYPE_LOCAL, RI_LOCAL_USAGE): { + // only take into account the "usage" before starting REPORT ID + if ( pstate.collections_count == 0 ) { + uint32_t eusage = pstate.usages[pstate.usage_count - 1]; + tuh_hid_ri_split_usage(eusage, &usage, &usage_page); } - // error - default: break; + break; } + default: break; } } diff --git a/src/class/hid/hid_rip.h b/src/class/hid/hid_rip.h index 3d3bb0ce50..9eed0a0615 100644 --- a/src/class/hid/hid_rip.h +++ b/src/class/hid/hid_rip.h @@ -64,6 +64,9 @@ #define HID_REPORT_MAX_USAGES 20 #define HID_REPORT_MAX_COLLECTION_DEPTH 20 +#define HID_RIP_EUSAGE(G, L) ((G << 16) | L) + + typedef enum tuh_hid_rip_status { HID_RIP_INIT = 0, // Initial state HID_RIP_EOF, // No more items @@ -113,6 +116,12 @@ void tuh_hid_rip_init_state(tuh_hid_rip_state_t *state, const uint8_t *report, u // const uint8_t* tuh_hid_rip_next_item(tuh_hid_rip_state_t *state); +// Move to the next short item in the report +// +// returns pointer to next item or null +// +const uint8_t* tuh_hid_rip_next_short_item(tuh_hid_rip_state_t *state); + // Accessor for the current value of a global item // // Returns a pointer to the start of the item of null diff --git a/test/test/class/hid/test_hid_ri.c b/test/test/class/hid/test_hid_ri.c index b20e3ce3aa..27ab5985cd 100644 --- a/test/test/class/hid/test_hid_ri.c +++ b/test/test/class/hid/test_hid_ri.c @@ -90,6 +90,7 @@ void test_physical_max_315(void) TEST_ASSERT_EQUAL(2, tuh_hid_ri_short_data_length(tb)); TEST_ASSERT_EQUAL(1, tuh_hid_ri_short_type(tb)); TEST_ASSERT_EQUAL(4, tuh_hid_ri_short_tag(tb)); + TEST_ASSERT_EQUAL(HID_RI_TYPE_AND_TAG(1, 4), tuh_hid_ri_short_type_and_tag(tb)); TEST_ASSERT_EQUAL(false, tuh_hid_ri_is_long(tb)); TEST_ASSERT_EQUAL(315, tuh_hid_ri_short_udata32(tb)); TEST_ASSERT_EQUAL(315, tuh_hid_ri_short_data32(tb)); @@ -116,6 +117,7 @@ void test_logical_min_neg_127(void) TEST_ASSERT_EQUAL(1, tuh_hid_ri_short_data_length(tb)); TEST_ASSERT_EQUAL(1, tuh_hid_ri_short_type(tb)); TEST_ASSERT_EQUAL(1, tuh_hid_ri_short_tag(tb)); + TEST_ASSERT_EQUAL(HID_RI_TYPE_AND_TAG(1, 1), tuh_hid_ri_short_type_and_tag(tb)); TEST_ASSERT_EQUAL(false, tuh_hid_ri_is_long(tb)); TEST_ASSERT_EQUAL(0x81, tuh_hid_ri_short_udata32(tb)); TEST_ASSERT_EQUAL(-127, tuh_hid_ri_short_data32(tb)); From 43fca5b1934320d35b8c07e65950270440ccf30a Mon Sep 17 00:00:00 2001 From: Phil Date: Sun, 13 Feb 2022 10:05:19 +0000 Subject: [PATCH 48/71] HID micro parser --- examples/host/cdc_msc_hid/src/hid_joy.c | 74 +++++++++++++++++-- examples/host/cdc_msc_hid/src/hid_joy.h | 14 +++- .../examples/host/cdc_msc_hid/test_hid_joy.c | 23 ++++-- 3 files changed, 93 insertions(+), 18 deletions(-) diff --git a/examples/host/cdc_msc_hid/src/hid_joy.c b/examples/host/cdc_msc_hid/src/hid_joy.c index 2ad855a084..fecbd1a365 100644 --- a/examples/host/cdc_msc_hid/src/hid_joy.c +++ b/examples/host/cdc_msc_hid/src/hid_joy.c @@ -29,7 +29,8 @@ static uint8_t hid_simple_joysick_count = 0; static tusb_hid_simple_joysick_t hid_simple_joysicks[HID_MAX_JOYSTICKS]; -static bool tuh_hid_joystick_check_usage(uint32_t eusage) { +static bool tuh_hid_joystick_check_usage(uint32_t eusage) +{ // Check outer usage switch(eusage) { case HID_RIP_EUSAGE(HID_USAGE_PAGE_DESKTOP, HID_USAGE_DESKTOP_JOYSTICK): return true; @@ -38,6 +39,49 @@ static bool tuh_hid_joystick_check_usage(uint32_t eusage) { } } +// TODO Test +tusb_hid_simple_joysick_t* tuh_hid_get_simple_joystick(uint8_t hid_instance, uint8_t report_id) +{ + for(uint8_t i = 0; i < HID_MAX_JOYSTICKS; ++i) { + tusb_hid_simple_joysick_t* simple_joystick = &hid_simple_joysicks[i]; + if (simple_joystick->active && simple_joystick->hid_instance == hid_instance && simple_joystick->report_id == report_id) return simple_joystick; + } + return NULL; +} + +void tuh_hid_free_simple_joysticks() { + for(uint8_t i = 0; i < HID_MAX_JOYSTICKS; ++i) { + hid_simple_joysicks[i].active = false; + } +} + +// TODO Test +void tuh_hid_free_simple_joystick(uint8_t hid_instance) { + for(uint8_t i = 0; i < HID_MAX_JOYSTICKS; ++i) { + tusb_hid_simple_joysick_t* simple_joystick = &hid_simple_joysicks[i]; + if (simple_joystick->hid_instance == hid_instance) simple_joystick->active = false; + } +} + +// TODO Test +tusb_hid_simple_joysick_t* tuh_hid_allocate_simple_joystick(uint8_t hid_instance, uint8_t report_id) { + for(uint8_t i = 0; i < HID_MAX_JOYSTICKS; ++i) { + tusb_hid_simple_joysick_t* simple_joystick = &hid_simple_joysicks[i]; + if (!simple_joystick->active) { + tu_memclr(simple_joystick, sizeof(tusb_hid_simple_joysick_t)); + simple_joystick->active = true; + simple_joystick->hid_instance = hid_instance; + simple_joystick->report_id = report_id; + } + } +} + +// get or create +tusb_hid_simple_joysick_t* tuh_hid_obtain_simple_joystick(uint8_t hid_instance, uint8_t report_id) { + tusb_hid_simple_joysick_t* jdata = tuh_hid_get_simple_joystick(hid_instance, report_id); + return jdata ? jdata : tuh_hid_allocate_simple_joystick(hid_instance, report_id); +} + // Fetch some data from the HID parser // // The data fetched here may be relevant to multiple usage items @@ -77,7 +121,8 @@ bool tuh_hid_joystick_get_data( void tuh_hid_joystick_process_usages( tuh_hid_rip_state_t *pstate, tuh_hid_joystick_data_t* jdata, - uint32_t bitpos) + uint32_t bitpos, + uint8_t hid_instance) { if (jdata->input_flags.data_const) { printf("const bits %d \n", jdata->report_size * jdata->report_count); @@ -95,11 +140,20 @@ void tuh_hid_joystick_process_usages( printf("skipping const bits %d \n", jdata->report_size * jdata->report_count); return; } + + tusb_hid_simple_joysick_t* simple_joystick = tuh_hid_obtain_simple_joystick(hid_instance, jdata->report_id); + + if (simple_joystick == NULL) { + printf("Failed to allocate joystick for HID instance %d, report ID %d\n", hid_instance, jdata->report_id); + return; + } // TODO Naive, assumes buttons are defined in a range if (jdata->usage_is_range) { if (jdata->usage_page == HID_USAGE_PAGE_BUTTON) { - printf("Buttons %d to %d\n", jdata->usage_min, jdata->usage_max); + tusb_hid_simple_buttons_t* simple_buttons = &simple_joystick->buttons; + simple_buttons->start = bitpos; + simple_buttons->length = jdata->report_count; return; } } @@ -116,10 +170,16 @@ void tuh_hid_joystick_process_usages( printf("Axis\n"); break; - case HID_RIP_EUSAGE(HID_USAGE_PAGE_DESKTOP, HID_USAGE_DESKTOP_HAT_SWITCH): - printf("Hat\n"); + case HID_RIP_EUSAGE(HID_USAGE_PAGE_DESKTOP, HID_USAGE_DESKTOP_HAT_SWITCH): { + // HAT buttons seem a bit crazy on joypads... + // they appear to act like a 4 bit button array, roughly arranged to represent directions. + // Multiple bits are set if multiple buttons are pressed. + // There are probably 10^18 ways of describing and interpreting this item alone. Yay. + tusb_hid_simple_buttons_t* simple_buttons = &simple_joystick->hat_buttons; + simple_buttons->start = bitpos; + simple_buttons->length = jdata->report_count * jdata->report_size; break; - + } default: break; } @@ -129,7 +189,7 @@ void tuh_hid_joystick_process_usages( } -uint8_t tuh_hid_joystick_parse_report_descriptor(uint8_t const* desc_report, uint16_t desc_len) { +uint8_t tuh_hid_joystick_parse_report_descriptor(uint8_t const* desc_report, uint16_t desc_len, uint8_t hid_instance) { if (hid_simple_joysick_count < HID_MAX_JOYSTICKS) { uint32_t eusage = 0; tuh_hid_rip_state_t pstate; diff --git a/examples/host/cdc_msc_hid/src/hid_joy.h b/examples/host/cdc_msc_hid/src/hid_joy.h index b7411b3411..3e4a9ad8e8 100644 --- a/examples/host/cdc_msc_hid/src/hid_joy.h +++ b/examples/host/cdc_msc_hid/src/hid_joy.h @@ -70,8 +70,9 @@ typedef struct { // Very simple representation of a joystick to try and map to // (and this will be quite tricky enough). typedef struct { - uint8_t instance; + uint8_t hid_instance; uint8_t report_id; + bool active; tusb_hid_simple_axis_t axis_x1; tusb_hid_simple_axis_t axis_y1; tusb_hid_simple_axis_t axis_x2; @@ -107,9 +108,16 @@ bool tuh_hid_joystick_get_data( void tuh_hid_joystick_process_usages( tuh_hid_rip_state_t *pstate, tuh_hid_joystick_data_t* jdata, - uint32_t bitpos + uint32_t bitpos, + uint8_t hid_instance ); -uint8_t tuh_hid_joystick_parse_report_descriptor(uint8_t const* desc_report, uint16_t desc_len); +uint8_t tuh_hid_joystick_parse_report_descriptor(uint8_t const* desc_report, uint16_t desc_len, uint8_t hid_instance); + +tusb_hid_simple_joysick_t* tuh_hid_get_simple_joystick(uint8_t hid_instance, uint8_t report_id); +void tuh_hid_free_simple_joystick(uint8_t hid_instance); +void tuh_hid_free_simple_joysticks(); +tusb_hid_simple_joysick_t* tuh_hid_allocate_simple_joystick(uint8_t hid_instance, uint8_t report_id); +tusb_hid_simple_joysick_t* tuh_hid_obtain_simple_joystick(uint8_t hid_instance, uint8_t report_id); #endif diff --git a/test/test/examples/host/cdc_msc_hid/test_hid_joy.c b/test/test/examples/host/cdc_msc_hid/test_hid_joy.c index 195cc6e85c..d74932eb3b 100644 --- a/test/test/examples/host/cdc_msc_hid/test_hid_joy.c +++ b/test/test/examples/host/cdc_msc_hid/test_hid_joy.c @@ -138,6 +138,7 @@ static const uint8_t const tb_speedlink[] = { void setUp(void) { + tuh_hid_free_simple_joysticks(); } void tearDown(void) @@ -152,12 +153,13 @@ void test_nothing() { 0x05, 0x01, // Usage Page (Generic Desktop Ctrls) 0x09, 0x04, // Usage (Joystick) }; - TEST_ASSERT_EQUAL(0, tuh_hid_joystick_parse_report_descriptor(tb, sizeof(tb))); + TEST_ASSERT_EQUAL(0, tuh_hid_joystick_parse_report_descriptor(tb, sizeof(tb), 1)); } void test_tuh_hid_joystick_get_data() { tuh_hid_joystick_data_t joystick_data; tuh_hid_rip_state_t pstate; + tusb_hid_simple_joysick_t* simple_joystick; tuh_hid_rip_init_state(&pstate, tb_speedlink, sizeof(tb_speedlink)); const uint8_t *ri; @@ -181,7 +183,7 @@ void test_tuh_hid_joystick_get_data() { TEST_ASSERT_EQUAL(false, joystick_data.input_flags.prefered_noprefered); TEST_ASSERT_EQUAL(false, joystick_data.input_flags.nonull_null); - tuh_hid_joystick_process_usages(&pstate, &joystick_data, 0); + tuh_hid_joystick_process_usages(&pstate, &joystick_data, 0, 9); while((ri = tuh_hid_rip_next_item(&pstate)) != NULL ) if (ri >= &tb_speedlink[47]) break; @@ -204,8 +206,11 @@ void test_tuh_hid_joystick_get_data() { TEST_ASSERT_EQUAL(false, joystick_data.input_flags.prefered_noprefered); TEST_ASSERT_EQUAL(true, joystick_data.input_flags.nonull_null); - tuh_hid_joystick_process_usages(&pstate, &joystick_data, 40); - + tuh_hid_joystick_process_usages(&pstate, &joystick_data, 40, 9); + simple_joystick = tuh_hid_get_simple_joystick(9, 0); + TEST_ASSERT_NOT_NULL(simple_joystick); + TEST_ASSERT_EQUAL(40, simple_joystick->hat_buttons.start); + TEST_ASSERT_EQUAL(4, simple_joystick->hat_buttons.length); while((ri = tuh_hid_rip_next_item(&pstate)) != NULL ) if (ri >= &tb_speedlink[65]) break; TEST_ASSERT_EQUAL(&tb_speedlink[65], ri); // Move to the second input in the speedlink description @@ -229,14 +234,16 @@ void test_tuh_hid_joystick_get_data() { TEST_ASSERT_EQUAL(false, joystick_data.input_flags.prefered_noprefered); TEST_ASSERT_EQUAL(false, joystick_data.input_flags.nonull_null); - tuh_hid_joystick_process_usages(&pstate, &joystick_data, 44); // 56 - + tuh_hid_joystick_process_usages(&pstate, &joystick_data, 44, 9); // 56 + simple_joystick = tuh_hid_get_simple_joystick(9, 0); + TEST_ASSERT_NOT_NULL(simple_joystick); + TEST_ASSERT_EQUAL(44, simple_joystick->buttons.start); + TEST_ASSERT_EQUAL(12, simple_joystick->buttons.length); } - void test_hid_parse_greenasia_report() { - // tuh_hid_joystick_parse_report_descriptor(tb, sizeof(tb)); + // tuh_hid_joystick_parse_report_descriptor(tb, sizeof(tb), 1); } From 79cabf63478cf8020121c9c9527e201eb04b28e1 Mon Sep 17 00:00:00 2001 From: Phil Date: Sun, 13 Feb 2022 11:31:18 +0000 Subject: [PATCH 49/71] HID micro parser --- examples/host/cdc_msc_hid/src/hid_joy.c | 92 ++++--- .../examples/host/cdc_msc_hid/test_hid_joy.c | 245 +++++++++++------- 2 files changed, 215 insertions(+), 122 deletions(-) diff --git a/examples/host/cdc_msc_hid/src/hid_joy.c b/examples/host/cdc_msc_hid/src/hid_joy.c index fecbd1a365..3745fd47d7 100644 --- a/examples/host/cdc_msc_hid/src/hid_joy.c +++ b/examples/host/cdc_msc_hid/src/hid_joy.c @@ -26,7 +26,6 @@ #include "hid_joy.h" -static uint8_t hid_simple_joysick_count = 0; static tusb_hid_simple_joysick_t hid_simple_joysicks[HID_MAX_JOYSTICKS]; static bool tuh_hid_joystick_check_usage(uint32_t eusage) @@ -72,8 +71,10 @@ tusb_hid_simple_joysick_t* tuh_hid_allocate_simple_joystick(uint8_t hid_instance simple_joystick->active = true; simple_joystick->hid_instance = hid_instance; simple_joystick->report_id = report_id; + return simple_joystick; } } + return NULL; } // get or create @@ -118,11 +119,23 @@ bool tuh_hid_joystick_get_data( return true; } +static void tuh_hid_joystick_process_axis( + tuh_hid_joystick_data_t* jdata, + uint32_t bitpos, + uint8_t hid_instance, + tusb_hid_simple_axis_t* simple_axis) +{ + simple_axis->start = bitpos; + simple_axis->length = jdata->report_size; + simple_axis->flags.is_signed = jdata->logical_min < 0; + simple_axis->flags.byte_aligned = ((bitpos & 7) == 0) && ((jdata->report_size & 7) == 0); +} + void tuh_hid_joystick_process_usages( tuh_hid_rip_state_t *pstate, tuh_hid_joystick_data_t* jdata, uint32_t bitpos, - uint8_t hid_instance) + uint8_t hid_instance) { if (jdata->input_flags.data_const) { printf("const bits %d \n", jdata->report_size * jdata->report_count); @@ -163,13 +176,18 @@ void tuh_hid_joystick_process_usages( switch (eusage) { // Seems to be common usage for gamepads. // Probably needs a lot more thought... - case HID_RIP_EUSAGE(HID_USAGE_PAGE_DESKTOP, HID_USAGE_DESKTOP_X): + case HID_RIP_EUSAGE(HID_USAGE_PAGE_DESKTOP, HID_USAGE_DESKTOP_X): + tuh_hid_joystick_process_axis(jdata, bitpos, hid_instance, &simple_joystick->axis_x1); + break; case HID_RIP_EUSAGE(HID_USAGE_PAGE_DESKTOP, HID_USAGE_DESKTOP_Y): - case HID_RIP_EUSAGE(HID_USAGE_PAGE_DESKTOP, HID_USAGE_DESKTOP_Z): - case HID_RIP_EUSAGE(HID_USAGE_PAGE_DESKTOP, HID_USAGE_DESKTOP_RZ): - printf("Axis\n"); + tuh_hid_joystick_process_axis(jdata, bitpos, hid_instance, &simple_joystick->axis_y1); + break; + case HID_RIP_EUSAGE(HID_USAGE_PAGE_DESKTOP, HID_USAGE_DESKTOP_Z): // Why oh why? + tuh_hid_joystick_process_axis(jdata, bitpos, hid_instance, &simple_joystick->axis_x2); break; - + case HID_RIP_EUSAGE(HID_USAGE_PAGE_DESKTOP, HID_USAGE_DESKTOP_RZ): // Why oh why? + tuh_hid_joystick_process_axis(jdata, bitpos, hid_instance, &simple_joystick->axis_y2); + break; case HID_RIP_EUSAGE(HID_USAGE_PAGE_DESKTOP, HID_USAGE_DESKTOP_HAT_SWITCH): { // HAT buttons seem a bit crazy on joypads... // they appear to act like a 4 bit button array, roughly arranged to represent directions. @@ -177,49 +195,53 @@ void tuh_hid_joystick_process_usages( // There are probably 10^18 ways of describing and interpreting this item alone. Yay. tusb_hid_simple_buttons_t* simple_buttons = &simple_joystick->hat_buttons; simple_buttons->start = bitpos; - simple_buttons->length = jdata->report_count * jdata->report_size; + simple_buttons->length = jdata->report_size; break; } default: break; } - - bitpos += jdata->report_size; } - } uint8_t tuh_hid_joystick_parse_report_descriptor(uint8_t const* desc_report, uint16_t desc_len, uint8_t hid_instance) { - if (hid_simple_joysick_count < HID_MAX_JOYSTICKS) { - uint32_t eusage = 0; - tuh_hid_rip_state_t pstate; - tuh_hid_rip_init_state(&pstate, desc_report, desc_len); - const uint8_t *ri; - while((ri = tuh_hid_rip_next_short_item(&pstate)) != NULL) + uint32_t eusage = 0; + tuh_hid_rip_state_t pstate; + tuh_hid_rip_init_state(&pstate, desc_report, desc_len); + const uint8_t *ri; + uint32_t bitpos = 0; // TODO Think about if this could be uint8_t or uint16_t + while((ri = tuh_hid_rip_next_short_item(&pstate)) != NULL) + { + uint8_t const type_and_tag = tuh_hid_ri_short_type_and_tag(ri); + + switch(type_and_tag) { - uint8_t const type_and_tag = tuh_hid_ri_short_type_and_tag(ri); - - switch(type_and_tag) - { - case HID_RI_TYPE_AND_TAG(RI_TYPE_MAIN, RI_MAIN_INPUT): { - if (tuh_hid_joystick_check_usage(eusage)) { - // This is what we care about for the joystick - - // TODO Check the outer usage is joystick/gamepad - // TODO Keep track of the report id, when it changes move to next joystick definition?? + case HID_RI_TYPE_AND_TAG(RI_TYPE_MAIN, RI_MAIN_INPUT): { + if (tuh_hid_joystick_check_usage(eusage)) { + tuh_hid_joystick_data_t joystick_data; + if(tuh_hid_joystick_get_data(&pstate, ri, &joystick_data)) { + tuh_hid_joystick_process_usages(&pstate, &joystick_data, bitpos, hid_instance); + bitpos += joystick_data.report_size * joystick_data.report_count; } - break; } - case HID_RI_TYPE_AND_TAG(RI_TYPE_LOCAL, RI_LOCAL_USAGE): { - if (pstate.collections_count == 0) { - eusage = pstate.usages[pstate.usage_count - 1]; - } - break; + break; + } + case HID_RI_TYPE_AND_TAG(RI_TYPE_LOCAL, RI_LOCAL_USAGE): { + if (pstate.collections_count == 0) { + eusage = pstate.usages[pstate.usage_count - 1]; } - default: break; + break; } + case HID_RI_TYPE_AND_TAG(RI_TYPE_MAIN, RI_MAIN_COLLECTION_END): { + if (pstate.collections_count == 0) { + // End of application collection. + printf("End of application collection.\n"); + bitpos = 0; + } + break; + } + default: break; } } - return hid_simple_joysick_count; } diff --git a/test/test/examples/host/cdc_msc_hid/test_hid_joy.c b/test/test/examples/host/cdc_msc_hid/test_hid_joy.c index d74932eb3b..5509fa75bd 100644 --- a/test/test/examples/host/cdc_msc_hid/test_hid_joy.c +++ b/test/test/examples/host/cdc_msc_hid/test_hid_joy.c @@ -157,99 +157,170 @@ void test_nothing() { } void test_tuh_hid_joystick_get_data() { - tuh_hid_joystick_data_t joystick_data; - tuh_hid_rip_state_t pstate; - tusb_hid_simple_joysick_t* simple_joystick; - tuh_hid_rip_init_state(&pstate, tb_speedlink, sizeof(tb_speedlink)); - const uint8_t *ri; - - while((ri = tuh_hid_rip_next_item(&pstate)) != NULL ) if (ri >= &tb_speedlink[32]) break; - TEST_ASSERT_EQUAL(&tb_speedlink[32], ri); // Move to the first input in the speedlink description - TEST_ASSERT_EQUAL(true, tuh_hid_joystick_get_data(&pstate, ri, &joystick_data)); - - TEST_ASSERT_EQUAL(8, joystick_data.report_size); - TEST_ASSERT_EQUAL(5, joystick_data.report_count); - TEST_ASSERT_EQUAL(0, joystick_data.report_id); - TEST_ASSERT_EQUAL(0, joystick_data.logical_min); - TEST_ASSERT_EQUAL(255, joystick_data.logical_max); - TEST_ASSERT_EQUAL(false, joystick_data.usage_is_range); - - // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) - TEST_ASSERT_EQUAL(false, joystick_data.input_flags.data_const); - TEST_ASSERT_EQUAL(true, joystick_data.input_flags.array_variable); - TEST_ASSERT_EQUAL(false, joystick_data.input_flags.absolute_relative); - TEST_ASSERT_EQUAL(false, joystick_data.input_flags.nowrap_wrap); - TEST_ASSERT_EQUAL(false, joystick_data.input_flags.linear_nonlinear); - TEST_ASSERT_EQUAL(false, joystick_data.input_flags.prefered_noprefered); - TEST_ASSERT_EQUAL(false, joystick_data.input_flags.nonull_null); - - tuh_hid_joystick_process_usages(&pstate, &joystick_data, 0, 9); - - - while((ri = tuh_hid_rip_next_item(&pstate)) != NULL ) if (ri >= &tb_speedlink[47]) break; - TEST_ASSERT_EQUAL(&tb_speedlink[47], ri); // Move to the second input in the speedlink description - TEST_ASSERT_EQUAL(true, tuh_hid_joystick_get_data(&pstate, ri, &joystick_data)); - - TEST_ASSERT_EQUAL(4, joystick_data.report_size); - TEST_ASSERT_EQUAL(1, joystick_data.report_count); - TEST_ASSERT_EQUAL(0, joystick_data.report_id); - TEST_ASSERT_EQUAL(0, joystick_data.logical_min); - TEST_ASSERT_EQUAL(7, joystick_data.logical_max); - TEST_ASSERT_EQUAL(false, joystick_data.usage_is_range); - - // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,Null State) - TEST_ASSERT_EQUAL(false, joystick_data.input_flags.data_const); - TEST_ASSERT_EQUAL(true, joystick_data.input_flags.array_variable); - TEST_ASSERT_EQUAL(false, joystick_data.input_flags.absolute_relative); - TEST_ASSERT_EQUAL(false, joystick_data.input_flags.nowrap_wrap); - TEST_ASSERT_EQUAL(false, joystick_data.input_flags.linear_nonlinear); - TEST_ASSERT_EQUAL(false, joystick_data.input_flags.prefered_noprefered); - TEST_ASSERT_EQUAL(true, joystick_data.input_flags.nonull_null); - - tuh_hid_joystick_process_usages(&pstate, &joystick_data, 40, 9); - simple_joystick = tuh_hid_get_simple_joystick(9, 0); - TEST_ASSERT_NOT_NULL(simple_joystick); - TEST_ASSERT_EQUAL(40, simple_joystick->hat_buttons.start); - TEST_ASSERT_EQUAL(4, simple_joystick->hat_buttons.length); - - while((ri = tuh_hid_rip_next_item(&pstate)) != NULL ) if (ri >= &tb_speedlink[65]) break; - TEST_ASSERT_EQUAL(&tb_speedlink[65], ri); // Move to the second input in the speedlink description - TEST_ASSERT_EQUAL(true, tuh_hid_joystick_get_data(&pstate, ri, &joystick_data)); - - TEST_ASSERT_EQUAL(1, joystick_data.report_size); - TEST_ASSERT_EQUAL(12, joystick_data.report_count); - TEST_ASSERT_EQUAL(0, joystick_data.report_id); - TEST_ASSERT_EQUAL(0, joystick_data.logical_min); - TEST_ASSERT_EQUAL(1, joystick_data.logical_max); - TEST_ASSERT_EQUAL(true, joystick_data.usage_is_range); - TEST_ASSERT_EQUAL(1, joystick_data.usage_min); - TEST_ASSERT_EQUAL(12, joystick_data.usage_max); - - // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) - TEST_ASSERT_EQUAL(false, joystick_data.input_flags.data_const); - TEST_ASSERT_EQUAL(true, joystick_data.input_flags.array_variable); - TEST_ASSERT_EQUAL(false, joystick_data.input_flags.absolute_relative); - TEST_ASSERT_EQUAL(false, joystick_data.input_flags.nowrap_wrap); - TEST_ASSERT_EQUAL(false, joystick_data.input_flags.linear_nonlinear); - TEST_ASSERT_EQUAL(false, joystick_data.input_flags.prefered_noprefered); - TEST_ASSERT_EQUAL(false, joystick_data.input_flags.nonull_null); - - tuh_hid_joystick_process_usages(&pstate, &joystick_data, 44, 9); // 56 - simple_joystick = tuh_hid_get_simple_joystick(9, 0); - TEST_ASSERT_NOT_NULL(simple_joystick); - TEST_ASSERT_EQUAL(44, simple_joystick->buttons.start); - TEST_ASSERT_EQUAL(12, simple_joystick->buttons.length); -} + tuh_hid_joystick_data_t joystick_data; + tuh_hid_rip_state_t pstate; + tusb_hid_simple_joysick_t* simple_joystick; + tuh_hid_rip_init_state(&pstate, tb_speedlink, sizeof(tb_speedlink)); + const uint8_t *ri; -void test_hid_parse_greenasia_report() { + while((ri = tuh_hid_rip_next_item(&pstate)) != NULL ) if (ri >= &tb_speedlink[32]) break; + TEST_ASSERT_EQUAL(&tb_speedlink[32], ri); // Move to the first input in the speedlink description + TEST_ASSERT_EQUAL(true, tuh_hid_joystick_get_data(&pstate, ri, &joystick_data)); - // tuh_hid_joystick_parse_report_descriptor(tb, sizeof(tb), 1); + TEST_ASSERT_EQUAL(8, joystick_data.report_size); + TEST_ASSERT_EQUAL(5, joystick_data.report_count); + TEST_ASSERT_EQUAL(0, joystick_data.report_id); + TEST_ASSERT_EQUAL(0, joystick_data.logical_min); + TEST_ASSERT_EQUAL(255, joystick_data.logical_max); + TEST_ASSERT_EQUAL(false, joystick_data.usage_is_range); -} + // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) + TEST_ASSERT_EQUAL(false, joystick_data.input_flags.data_const); + TEST_ASSERT_EQUAL(true, joystick_data.input_flags.array_variable); + TEST_ASSERT_EQUAL(false, joystick_data.input_flags.absolute_relative); + TEST_ASSERT_EQUAL(false, joystick_data.input_flags.nowrap_wrap); + TEST_ASSERT_EQUAL(false, joystick_data.input_flags.linear_nonlinear); + TEST_ASSERT_EQUAL(false, joystick_data.input_flags.prefered_noprefered); + TEST_ASSERT_EQUAL(false, joystick_data.input_flags.nonull_null); -void test_hid_parse_speedlink_report() { + tuh_hid_joystick_process_usages(&pstate, &joystick_data, 0, 9); + simple_joystick = tuh_hid_get_simple_joystick(9, 0); + TEST_ASSERT_NOT_NULL(simple_joystick); + // x1 + TEST_ASSERT_EQUAL(0, simple_joystick->axis_x1.start); + TEST_ASSERT_EQUAL(8, simple_joystick->axis_x1.length); + TEST_ASSERT_EQUAL(false, simple_joystick->axis_x1.flags.is_signed); + TEST_ASSERT_EQUAL(true, simple_joystick->axis_x1.flags.byte_aligned); + // y1 + TEST_ASSERT_EQUAL(8, simple_joystick->axis_y1.start); + TEST_ASSERT_EQUAL(8, simple_joystick->axis_y1.length); + TEST_ASSERT_EQUAL(false, simple_joystick->axis_y1.flags.is_signed); + TEST_ASSERT_EQUAL(true, simple_joystick->axis_y1.flags.byte_aligned); + // x2 + TEST_ASSERT_EQUAL(24, simple_joystick->axis_x2.start); + TEST_ASSERT_EQUAL(8, simple_joystick->axis_x2.length); + TEST_ASSERT_EQUAL(false, simple_joystick->axis_x2.flags.is_signed); + TEST_ASSERT_EQUAL(true, simple_joystick->axis_x2.flags.byte_aligned); + // y2 + TEST_ASSERT_EQUAL(32, simple_joystick->axis_y2.start); + TEST_ASSERT_EQUAL(8, simple_joystick->axis_y2.length); + TEST_ASSERT_EQUAL(false, simple_joystick->axis_y2.flags.is_signed); + TEST_ASSERT_EQUAL(true, simple_joystick->axis_y2.flags.byte_aligned); + + while((ri = tuh_hid_rip_next_item(&pstate)) != NULL ) if (ri >= &tb_speedlink[47]) break; + TEST_ASSERT_EQUAL(&tb_speedlink[47], ri); // Move to the second input in the speedlink description + TEST_ASSERT_EQUAL(true, tuh_hid_joystick_get_data(&pstate, ri, &joystick_data)); + + TEST_ASSERT_EQUAL(4, joystick_data.report_size); + TEST_ASSERT_EQUAL(1, joystick_data.report_count); + TEST_ASSERT_EQUAL(0, joystick_data.report_id); + TEST_ASSERT_EQUAL(0, joystick_data.logical_min); + TEST_ASSERT_EQUAL(7, joystick_data.logical_max); + TEST_ASSERT_EQUAL(false, joystick_data.usage_is_range); + + // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,Null State) + TEST_ASSERT_EQUAL(false, joystick_data.input_flags.data_const); + TEST_ASSERT_EQUAL(true, joystick_data.input_flags.array_variable); + TEST_ASSERT_EQUAL(false, joystick_data.input_flags.absolute_relative); + TEST_ASSERT_EQUAL(false, joystick_data.input_flags.nowrap_wrap); + TEST_ASSERT_EQUAL(false, joystick_data.input_flags.linear_nonlinear); + TEST_ASSERT_EQUAL(false, joystick_data.input_flags.prefered_noprefered); + TEST_ASSERT_EQUAL(true, joystick_data.input_flags.nonull_null); + + tuh_hid_joystick_process_usages(&pstate, &joystick_data, 40, 9); + simple_joystick = tuh_hid_get_simple_joystick(9, 0); + TEST_ASSERT_NOT_NULL(simple_joystick); + TEST_ASSERT_EQUAL(40, simple_joystick->hat_buttons.start); + TEST_ASSERT_EQUAL(4, simple_joystick->hat_buttons.length); + while((ri = tuh_hid_rip_next_item(&pstate)) != NULL ) if (ri >= &tb_speedlink[65]) break; + TEST_ASSERT_EQUAL(&tb_speedlink[65], ri); // Move to the second input in the speedlink description + TEST_ASSERT_EQUAL(true, tuh_hid_joystick_get_data(&pstate, ri, &joystick_data)); + TEST_ASSERT_EQUAL(1, joystick_data.report_size); + TEST_ASSERT_EQUAL(12, joystick_data.report_count); + TEST_ASSERT_EQUAL(0, joystick_data.report_id); + TEST_ASSERT_EQUAL(0, joystick_data.logical_min); + TEST_ASSERT_EQUAL(1, joystick_data.logical_max); + TEST_ASSERT_EQUAL(true, joystick_data.usage_is_range); + TEST_ASSERT_EQUAL(1, joystick_data.usage_min); + TEST_ASSERT_EQUAL(12, joystick_data.usage_max); + + // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) + TEST_ASSERT_EQUAL(false, joystick_data.input_flags.data_const); + TEST_ASSERT_EQUAL(true, joystick_data.input_flags.array_variable); + TEST_ASSERT_EQUAL(false, joystick_data.input_flags.absolute_relative); + TEST_ASSERT_EQUAL(false, joystick_data.input_flags.nowrap_wrap); + TEST_ASSERT_EQUAL(false, joystick_data.input_flags.linear_nonlinear); + TEST_ASSERT_EQUAL(false, joystick_data.input_flags.prefered_noprefered); + TEST_ASSERT_EQUAL(false, joystick_data.input_flags.nonull_null); + + tuh_hid_joystick_process_usages(&pstate, &joystick_data, 44, 9); // 56 + simple_joystick = tuh_hid_get_simple_joystick(9, 0); + TEST_ASSERT_NOT_NULL(simple_joystick); + TEST_ASSERT_EQUAL(44, simple_joystick->buttons.start); + TEST_ASSERT_EQUAL(12, simple_joystick->buttons.length); +} + +void test_hid_parse_greenasia_report() { + tuh_hid_joystick_parse_report_descriptor(tb_speedlink, sizeof(tb_speedlink), 9); + tusb_hid_simple_joysick_t* simple_joystick = tuh_hid_get_simple_joystick(9, 0); + TEST_ASSERT_NOT_NULL(simple_joystick); + // x1 + TEST_ASSERT_EQUAL(0, simple_joystick->axis_x1.start); + TEST_ASSERT_EQUAL(8, simple_joystick->axis_x1.length); + TEST_ASSERT_EQUAL(false, simple_joystick->axis_x1.flags.is_signed); + TEST_ASSERT_EQUAL(true, simple_joystick->axis_x1.flags.byte_aligned); + // y1 + TEST_ASSERT_EQUAL(8, simple_joystick->axis_y1.start); + TEST_ASSERT_EQUAL(8, simple_joystick->axis_y1.length); + TEST_ASSERT_EQUAL(false, simple_joystick->axis_y1.flags.is_signed); + TEST_ASSERT_EQUAL(true, simple_joystick->axis_y1.flags.byte_aligned); + // x2 + TEST_ASSERT_EQUAL(24, simple_joystick->axis_x2.start); + TEST_ASSERT_EQUAL(8, simple_joystick->axis_x2.length); + TEST_ASSERT_EQUAL(false, simple_joystick->axis_x2.flags.is_signed); + TEST_ASSERT_EQUAL(true, simple_joystick->axis_x2.flags.byte_aligned); + // y2 + TEST_ASSERT_EQUAL(32, simple_joystick->axis_y2.start); + TEST_ASSERT_EQUAL(8, simple_joystick->axis_y2.length); + TEST_ASSERT_EQUAL(false, simple_joystick->axis_y2.flags.is_signed); + TEST_ASSERT_EQUAL(true, simple_joystick->axis_y2.flags.byte_aligned); + TEST_ASSERT_EQUAL(40, simple_joystick->hat_buttons.start); + TEST_ASSERT_EQUAL(4, simple_joystick->hat_buttons.length); + TEST_ASSERT_EQUAL(44, simple_joystick->buttons.start); + TEST_ASSERT_EQUAL(12, simple_joystick->buttons.length); +} + +void test_hid_parse_speedlink_report() { + tuh_hid_joystick_parse_report_descriptor(tb_greenasia, sizeof(tb_greenasia), 9); + tusb_hid_simple_joysick_t* simple_joystick = tuh_hid_get_simple_joystick(9, 0); + TEST_ASSERT_NOT_NULL(simple_joystick); + // x1 + TEST_ASSERT_EQUAL(16, simple_joystick->axis_x1.start); + TEST_ASSERT_EQUAL(8, simple_joystick->axis_x1.length); + TEST_ASSERT_EQUAL(false, simple_joystick->axis_x1.flags.is_signed); + TEST_ASSERT_EQUAL(true, simple_joystick->axis_x1.flags.byte_aligned); + // y1 + TEST_ASSERT_EQUAL(24, simple_joystick->axis_y1.start); + TEST_ASSERT_EQUAL(8, simple_joystick->axis_y1.length); + TEST_ASSERT_EQUAL(false, simple_joystick->axis_y1.flags.is_signed); + TEST_ASSERT_EQUAL(true, simple_joystick->axis_y1.flags.byte_aligned); + // x2 + TEST_ASSERT_EQUAL(0, simple_joystick->axis_x2.start); + TEST_ASSERT_EQUAL(8, simple_joystick->axis_x2.length); + TEST_ASSERT_EQUAL(false, simple_joystick->axis_x2.flags.is_signed); + TEST_ASSERT_EQUAL(true, simple_joystick->axis_x2.flags.byte_aligned); + // y2 + TEST_ASSERT_EQUAL(8, simple_joystick->axis_y2.start); + TEST_ASSERT_EQUAL(8, simple_joystick->axis_y2.length); + TEST_ASSERT_EQUAL(false, simple_joystick->axis_y2.flags.is_signed); + TEST_ASSERT_EQUAL(true, simple_joystick->axis_y2.flags.byte_aligned); + + TEST_ASSERT_EQUAL(40, simple_joystick->hat_buttons.start); + TEST_ASSERT_EQUAL(4, simple_joystick->hat_buttons.length); + TEST_ASSERT_EQUAL(44, simple_joystick->buttons.start); + TEST_ASSERT_EQUAL(12, simple_joystick->buttons.length); } From dc08e4eb5dd14ea1f56e4fc15320d6d950dcca96 Mon Sep 17 00:00:00 2001 From: Phil Date: Sun, 13 Feb 2022 14:58:10 +0000 Subject: [PATCH 50/71] HID micro parser --- examples/host/cdc_msc_hid/src/hid_app.c | 16 +++++++++-- examples/host/cdc_msc_hid/src/hid_joy.c | 38 +++++++++++++++++++++++-- examples/host/cdc_msc_hid/src/hid_joy.h | 3 +- 3 files changed, 51 insertions(+), 6 deletions(-) diff --git a/examples/host/cdc_msc_hid/src/hid_app.c b/examples/host/cdc_msc_hid/src/hid_app.c index 6d6f2db94c..2e8814f10d 100644 --- a/examples/host/cdc_msc_hid/src/hid_app.c +++ b/examples/host/cdc_msc_hid/src/hid_app.c @@ -25,6 +25,7 @@ #include "bsp/board.h" #include "tusb.h" +#include "hid_joy.h" //--------------------------------------------------------------------+ // MACRO TYPEDEF CONSTANT ENUM DECLARATION @@ -83,6 +84,8 @@ void tuh_hid_mount_cb(uint8_t dev_addr, uint8_t instance, uint8_t const* desc_re { 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_joystick_parse_report_descriptor(desc_report, desc_len, instance); } // request to receive report @@ -97,6 +100,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); + + // Free up any joystick definitions + tuh_hid_free_simple_joystick(instance); } // Invoked when received report from device via interrupt endpoint @@ -242,7 +248,8 @@ static void process_generic_report(uint8_t dev_addr, uint8_t instance, uint8_t c 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; - + uint8_t rpt_id = 0; + if ( rpt_count == 1 && rpt_info_arr[0].report_id == 0) { // Simple report without report ID as 1st byte @@ -250,7 +257,7 @@ static void process_generic_report(uint8_t dev_addr, uint8_t instance, uint8_t c }else { // Composite report, 1st byte is report ID, data starts from 2nd byte - uint8_t const rpt_id = report[0]; + rpt_id = report[0]; // Find report id in the arrray for(uint8_t i=0; ilength == 0) return 0; + return simple_axis->flags.is_signed ? + tuh_hid_report_bits_i32(report, simple_axis->start, simple_axis->length): + (int32_t)tuh_hid_report_bits_u32(report, simple_axis->start, simple_axis->length); +} + +void tusb_hid_print_simple_joysick_report(tusb_hid_simple_joysick_t* simple_joystick, const uint8_t* report, uint8_t report_length) +{ + if (simple_joystick == NULL ) { + printf("NULL joystick definition\n"); + } + + // TODO Check the report is long enough!! + + // TODO move to struct + int32_t x1 = tuh_hid_simple_joystick_get_axis_value(&simple_joystick->axis_x1, report); + int32_t y1 = tuh_hid_simple_joystick_get_axis_value(&simple_joystick->axis_y1, report); + int32_t x2 = tuh_hid_simple_joystick_get_axis_value(&simple_joystick->axis_x2, report); + int32_t y2 = tuh_hid_simple_joystick_get_axis_value(&simple_joystick->axis_y2, report); + + uint32_t hat_buttons = tuh_hid_report_bits_u32(report, simple_joystick->hat_buttons.start, simple_joystick->hat_buttons.length); + uint32_t buttons = tuh_hid_report_bits_u32(report, simple_joystick->buttons.start, simple_joystick->buttons.length); + + printf("x1=%4ld, y1=%4ld, x2=%4ld, y2=%4ld, hat=%01X, buttons=%04X\n", + x1, + y1, + x2, + y2, + hat_buttons, + buttons); +} diff --git a/examples/host/cdc_msc_hid/src/hid_joy.h b/examples/host/cdc_msc_hid/src/hid_joy.h index 3e4a9ad8e8..ccec0ebc29 100644 --- a/examples/host/cdc_msc_hid/src/hid_joy.h +++ b/examples/host/cdc_msc_hid/src/hid_joy.h @@ -25,7 +25,7 @@ #define _TUSB_HID_JOY_H_ #include "tusb.h" -#include "hid_rip.h" +#include "class/hid/hid_rip.h" #ifdef __cplusplus extern "C" { @@ -119,5 +119,6 @@ void tuh_hid_free_simple_joystick(uint8_t hid_instance); void tuh_hid_free_simple_joysticks(); tusb_hid_simple_joysick_t* tuh_hid_allocate_simple_joystick(uint8_t hid_instance, uint8_t report_id); tusb_hid_simple_joysick_t* tuh_hid_obtain_simple_joystick(uint8_t hid_instance, uint8_t report_id); +void tusb_hid_print_simple_joysick_report(tusb_hid_simple_joysick_t* simple_joystick, const uint8_t* report, uint8_t report_length); #endif From f056cfe82fec45afd6c1ee159702d694a80f3e6c Mon Sep 17 00:00:00 2001 From: Phil Date: Sun, 13 Feb 2022 15:10:02 +0000 Subject: [PATCH 51/71] HID micro parser --- examples/host/cdc_msc_hid/src/hid_joy.c | 20 ++++++------------- examples/host/cdc_msc_hid/src/hid_joy.h | 2 +- .../examples/host/cdc_msc_hid/test_hid_joy.c | 12 +++++------ 3 files changed, 13 insertions(+), 21 deletions(-) diff --git a/examples/host/cdc_msc_hid/src/hid_joy.c b/examples/host/cdc_msc_hid/src/hid_joy.c index 137cae55b9..1151c51b1e 100644 --- a/examples/host/cdc_msc_hid/src/hid_joy.c +++ b/examples/host/cdc_msc_hid/src/hid_joy.c @@ -182,22 +182,15 @@ void tuh_hid_joystick_process_usages( case HID_RIP_EUSAGE(HID_USAGE_PAGE_DESKTOP, HID_USAGE_DESKTOP_Y): tuh_hid_joystick_process_axis(jdata, bitpos, hid_instance, &simple_joystick->axis_y1); break; - case HID_RIP_EUSAGE(HID_USAGE_PAGE_DESKTOP, HID_USAGE_DESKTOP_Z): // Why oh why? + case HID_RIP_EUSAGE(HID_USAGE_PAGE_DESKTOP, HID_USAGE_DESKTOP_Z): tuh_hid_joystick_process_axis(jdata, bitpos, hid_instance, &simple_joystick->axis_x2); break; - case HID_RIP_EUSAGE(HID_USAGE_PAGE_DESKTOP, HID_USAGE_DESKTOP_RZ): // Why oh why? + case HID_RIP_EUSAGE(HID_USAGE_PAGE_DESKTOP, HID_USAGE_DESKTOP_RZ): tuh_hid_joystick_process_axis(jdata, bitpos, hid_instance, &simple_joystick->axis_y2); break; - case HID_RIP_EUSAGE(HID_USAGE_PAGE_DESKTOP, HID_USAGE_DESKTOP_HAT_SWITCH): { - // HAT buttons seem a bit crazy on joypads... - // they appear to act like a 4 bit button array, roughly arranged to represent directions. - // Multiple bits are set if multiple buttons are pressed. - // There are probably 10^18 ways of describing and interpreting this item alone. Yay. - tusb_hid_simple_buttons_t* simple_buttons = &simple_joystick->hat_buttons; - simple_buttons->start = bitpos; - simple_buttons->length = jdata->report_size; + case HID_RIP_EUSAGE(HID_USAGE_PAGE_DESKTOP, HID_USAGE_DESKTOP_HAT_SWITCH): + tuh_hid_joystick_process_axis(jdata, bitpos, hid_instance, &simple_joystick->hat); break; - } default: break; } bitpos += jdata->report_size; @@ -265,8 +258,7 @@ void tusb_hid_print_simple_joysick_report(tusb_hid_simple_joysick_t* simple_joys int32_t y1 = tuh_hid_simple_joystick_get_axis_value(&simple_joystick->axis_y1, report); int32_t x2 = tuh_hid_simple_joystick_get_axis_value(&simple_joystick->axis_x2, report); int32_t y2 = tuh_hid_simple_joystick_get_axis_value(&simple_joystick->axis_y2, report); - - uint32_t hat_buttons = tuh_hid_report_bits_u32(report, simple_joystick->hat_buttons.start, simple_joystick->hat_buttons.length); + int32_t hat = tuh_hid_simple_joystick_get_axis_value(&simple_joystick->hat, report); uint32_t buttons = tuh_hid_report_bits_u32(report, simple_joystick->buttons.start, simple_joystick->buttons.length); printf("x1=%4ld, y1=%4ld, x2=%4ld, y2=%4ld, hat=%01X, buttons=%04X\n", @@ -274,6 +266,6 @@ void tusb_hid_print_simple_joysick_report(tusb_hid_simple_joysick_t* simple_joys y1, x2, y2, - hat_buttons, + hat, buttons); } diff --git a/examples/host/cdc_msc_hid/src/hid_joy.h b/examples/host/cdc_msc_hid/src/hid_joy.h index ccec0ebc29..55e622f9fd 100644 --- a/examples/host/cdc_msc_hid/src/hid_joy.h +++ b/examples/host/cdc_msc_hid/src/hid_joy.h @@ -77,7 +77,7 @@ typedef struct { tusb_hid_simple_axis_t axis_y1; tusb_hid_simple_axis_t axis_x2; tusb_hid_simple_axis_t axis_y2; - tusb_hid_simple_buttons_t hat_buttons; + tusb_hid_simple_axis_t hat; tusb_hid_simple_buttons_t buttons; } tusb_hid_simple_joysick_t; diff --git a/test/test/examples/host/cdc_msc_hid/test_hid_joy.c b/test/test/examples/host/cdc_msc_hid/test_hid_joy.c index 5509fa75bd..2211c3f88e 100644 --- a/test/test/examples/host/cdc_msc_hid/test_hid_joy.c +++ b/test/test/examples/host/cdc_msc_hid/test_hid_joy.c @@ -230,8 +230,8 @@ void test_tuh_hid_joystick_get_data() { tuh_hid_joystick_process_usages(&pstate, &joystick_data, 40, 9); simple_joystick = tuh_hid_get_simple_joystick(9, 0); TEST_ASSERT_NOT_NULL(simple_joystick); - TEST_ASSERT_EQUAL(40, simple_joystick->hat_buttons.start); - TEST_ASSERT_EQUAL(4, simple_joystick->hat_buttons.length); + TEST_ASSERT_EQUAL(40, simple_joystick->hat.start); + TEST_ASSERT_EQUAL(4, simple_joystick->hat.length); while((ri = tuh_hid_rip_next_item(&pstate)) != NULL ) if (ri >= &tb_speedlink[65]) break; TEST_ASSERT_EQUAL(&tb_speedlink[65], ri); // Move to the second input in the speedlink description @@ -286,8 +286,8 @@ void test_hid_parse_greenasia_report() { TEST_ASSERT_EQUAL(8, simple_joystick->axis_y2.length); TEST_ASSERT_EQUAL(false, simple_joystick->axis_y2.flags.is_signed); TEST_ASSERT_EQUAL(true, simple_joystick->axis_y2.flags.byte_aligned); - TEST_ASSERT_EQUAL(40, simple_joystick->hat_buttons.start); - TEST_ASSERT_EQUAL(4, simple_joystick->hat_buttons.length); + TEST_ASSERT_EQUAL(40, simple_joystick->hat.start); + TEST_ASSERT_EQUAL(4, simple_joystick->hat.length); TEST_ASSERT_EQUAL(44, simple_joystick->buttons.start); TEST_ASSERT_EQUAL(12, simple_joystick->buttons.length); } @@ -317,8 +317,8 @@ void test_hid_parse_speedlink_report() { TEST_ASSERT_EQUAL(false, simple_joystick->axis_y2.flags.is_signed); TEST_ASSERT_EQUAL(true, simple_joystick->axis_y2.flags.byte_aligned); - TEST_ASSERT_EQUAL(40, simple_joystick->hat_buttons.start); - TEST_ASSERT_EQUAL(4, simple_joystick->hat_buttons.length); + TEST_ASSERT_EQUAL(40, simple_joystick->hat.start); + TEST_ASSERT_EQUAL(4, simple_joystick->hat.length); TEST_ASSERT_EQUAL(44, simple_joystick->buttons.start); TEST_ASSERT_EQUAL(12, simple_joystick->buttons.length); } From 9beba25f9908578416e71ca90b71db23b9bab312 Mon Sep 17 00:00:00 2001 From: Phil Date: Sun, 13 Feb 2022 17:10:58 +0000 Subject: [PATCH 52/71] HID micro parser --- examples/host/cdc_msc_hid/src/hid_joy.c | 8 ++--- examples/host/cdc_msc_hid/src/hid_joy.h | 8 ++--- src/class/hid/hid_rip.c | 45 +++++++++++++++++++++++-- src/class/hid/hid_rip.h | 14 ++++++-- test/test/class/hid/test_hid_rip.c | 33 ++++++++++++++++++ 5 files changed, 95 insertions(+), 13 deletions(-) diff --git a/examples/host/cdc_msc_hid/src/hid_joy.c b/examples/host/cdc_msc_hid/src/hid_joy.c index 1151c51b1e..24192ffc6f 100644 --- a/examples/host/cdc_msc_hid/src/hid_joy.c +++ b/examples/host/cdc_msc_hid/src/hid_joy.c @@ -239,10 +239,7 @@ uint8_t tuh_hid_joystick_parse_report_descriptor(uint8_t const* desc_report, uin int32_t tuh_hid_simple_joystick_get_axis_value(tusb_hid_simple_axis_t* simple_axis, const uint8_t* report) { - if (simple_axis->length == 0) return 0; - return simple_axis->flags.is_signed ? - tuh_hid_report_bits_i32(report, simple_axis->start, simple_axis->length): - (int32_t)tuh_hid_report_bits_u32(report, simple_axis->start, simple_axis->length); + return tuh_hid_report_i32(report, simple_axis->start, simple_axis->length, simple_axis->flags.is_signed); } void tusb_hid_print_simple_joysick_report(tusb_hid_simple_joysick_t* simple_joystick, const uint8_t* report, uint8_t report_length) @@ -268,4 +265,5 @@ void tusb_hid_print_simple_joysick_report(tusb_hid_simple_joysick_t* simple_joys y2, hat, buttons); -} +} + diff --git a/examples/host/cdc_msc_hid/src/hid_joy.h b/examples/host/cdc_msc_hid/src/hid_joy.h index 55e622f9fd..688b6a56ef 100644 --- a/examples/host/cdc_msc_hid/src/hid_joy.h +++ b/examples/host/cdc_msc_hid/src/hid_joy.h @@ -58,13 +58,13 @@ typedef struct { bool byte_aligned : 1; // TODO More efficient fetch from report if set }; } flags; - uint8_t start; - uint8_t length; + uint16_t start; + uint16_t length; } tusb_hid_simple_axis_t; typedef struct { - uint8_t start; - uint8_t length; + uint16_t start; + uint16_t length; } tusb_hid_simple_buttons_t; // Very simple representation of a joystick to try and map to diff --git a/src/class/hid/hid_rip.c b/src/class/hid/hid_rip.c index b85f9f88f1..41a25b3e45 100644 --- a/src/class/hid/hid_rip.c +++ b/src/class/hid/hid_rip.c @@ -199,7 +199,7 @@ uint32_t tuh_hid_rip_report_total_size_bits(tuh_hid_rip_state_t *state) } } -uint32_t tuh_hid_report_bits_u32(uint8_t const* report, uint8_t start, uint8_t length) +uint32_t tuh_hid_report_bits_u32(uint8_t const* report, uint16_t start, uint16_t length) { const int16_t bit_offset_start = start & 7; const int16_t l = length + bit_offset_start; @@ -212,7 +212,7 @@ uint32_t tuh_hid_report_bits_u32(uint8_t const* report, uint8_t start, uint8_t l return acc & m; } -int32_t tuh_hid_report_bits_i32(uint8_t const* report, uint8_t start, uint8_t length) +int32_t tuh_hid_report_bits_i32(uint8_t const* report, uint16_t start, uint16_t length) { const int16_t bit_offset_start = start & 7; const int16_t l = length + bit_offset_start; @@ -227,6 +227,47 @@ int32_t tuh_hid_report_bits_i32(uint8_t const* report, uint8_t start, uint8_t le return acc & lp0 ? acc | -lp1 : acc & (lp1 - 1); } +// Helper to get some bytes from a HID report as an unsigned 32 bit number +uint32_t tuh_hid_report_bytes_u32(uint8_t const* report, uint16_t start, uint16_t length) +{ + const uint8_t *p = report + start; + uint32_t acc = 0; + for(uint16_t i = 0; i < length; ++i) { + acc |= (uint32_t)*p++; + } + return acc; +} + +// Helper to get some bytes from a HID report as a signed 32 bit number +int32_t tuh_hid_report_bytes_i32(uint8_t const* report, uint16_t start, uint16_t length) +{ + const uint8_t *p = report + start; + uint32_t acc = 0; + for(uint16_t i = 0; i < length; ++i) { + acc |= (uint32_t)*p++; + } + const uint32_t lp0 = ((uint32_t)1) << (length + 2); + const uint32_t lp1 = lp0 << 1; + // sign extend + return acc & lp0 ? acc | -lp1 : acc; +} + +// Helper to get a value from a HID report +int32_t tuh_hid_report_i32(const uint8_t* report, uint16_t start, uint16_t length, bool is_signed) +{ + if (length == 0) return 0; + if ((start | length) & 7) { + return is_signed ? + tuh_hid_report_bits_i32(report, start, length): + (int32_t)tuh_hid_report_bits_u32(report, start, length); + } + else { + return is_signed ? + tuh_hid_report_bytes_i32(report, start >> 3, length >> 3): + (int32_t)tuh_hid_report_bytes_u32(report, start >> 3, length >> 3); + } +} + //--------------------------------------------------------------------+ // Report Descriptor Parser //--------------------------------------------------------------------+ diff --git a/src/class/hid/hid_rip.h b/src/class/hid/hid_rip.h index 9eed0a0615..0e7ad898ba 100644 --- a/src/class/hid/hid_rip.h +++ b/src/class/hid/hid_rip.h @@ -153,10 +153,20 @@ uint8_t tuh_hid_parse_report_descriptor(tuh_hid_report_info_t* reports_info_arr, //--------------------------------------------------------------------+ // Helper to get some bits from a HID report as an unsigned 32 bit number -uint32_t tuh_hid_report_bits_u32(uint8_t const* report, uint8_t start, uint8_t length); +uint32_t tuh_hid_report_bits_u32(uint8_t const* report, uint16_t start, uint16_t length); // Helper to get some bits from a HID report as a signed 32 bit number -int32_t tuh_hid_report_bits_i32(uint8_t const* report, uint8_t start, uint8_t length); +int32_t tuh_hid_report_bits_i32(uint8_t const* report, uint16_t start, uint16_t length); + +// Helper to get some bytes from a HID report as an unsigned 32 bit number +uint32_t tuh_hid_report_bytes_u32(uint8_t const* report, uint16_t start, uint16_t length); + +// Helper to get some bytes from a HID report as a signed 32 bit number +int32_t tuh_hid_report_bytes_i32(uint8_t const* report, uint16_t start, uint16_t length); + +// Helper to get a value from a HID report +// Not suitable if the value can be > 2^31 +int32_t tuh_hid_report_i32(const uint8_t* report, uint16_t start, uint16_t length, bool is_signed); #endif diff --git a/test/test/class/hid/test_hid_rip.c b/test/test/class/hid/test_hid_rip.c index 57a47d456e..eedd5f4e8b 100644 --- a/test/test/class/hid/test_hid_rip.c +++ b/test/test/class/hid/test_hid_rip.c @@ -603,3 +603,36 @@ void test_tuh_hid_report_bits_i32() { TEST_ASSERT_EQUAL(0xffffff8f, tuh_hid_report_bits_i32(tb, 16, 8)); TEST_ASSERT_EQUAL(0xff8f0550, tuh_hid_report_bits_i32(tb, 0, 32)); } + +void test_tuh_hid_report_bytes_u32() { + const uint8_t const tb[] = { + 0x50, 0x05, 0x8f, 0xff + }; + TEST_ASSERT_EQUAL(0x0550, tuh_hid_report_bytes_u32(tb, 0, 2)); + TEST_ASSERT_EQUAL(0x8f05, tuh_hid_report_bytes_u32(tb, 1, 2)); + TEST_ASSERT_EQUAL(0xff8f05, tuh_hid_report_bytes_u32(tb, 1, 3)); + TEST_ASSERT_EQUAL(0xff8f0550, tuh_hid_report_bytes_u32(tb, 0, 4)); +} + +void test_tuh_hid_report_bytes_i32() { + const uint8_t const tb[] = { + 0x50, 0x05, 0x8f, 0xff + }; + TEST_ASSERT_EQUAL(0x0550, tuh_hid_report_bytes_i32(tb, 0, 2)); + TEST_ASSERT_EQUAL(0xffff8f05, tuh_hid_report_bytes_i32(tb, 1, 2)); + TEST_ASSERT_EQUAL(0xffff8f05, tuh_hid_report_bytes_i32(tb, 1, 3)); + TEST_ASSERT_EQUAL(0xff8f0550, tuh_hid_report_bytes_i32(tb, 0, 4)); +} + +void test_tuh_hid_report_i32() { + const uint8_t const tb[] = { + 0x50, 0x05, 0x8f, 0xff + }; + TEST_ASSERT_EQUAL(0x55, tuh_hid_report_i32(tb, 4, 8, false)); + TEST_ASSERT_EQUAL(0x8f, tuh_hid_report_i32(tb, 16, 8, false)); + TEST_ASSERT_EQUAL(0xff8f0550, tuh_hid_report_i32(tb, 0, 32, false)); + + TEST_ASSERT_EQUAL(0x55, tuh_hid_report_i32(tb, 4, 8, true)); + TEST_ASSERT_EQUAL(0xffffff8f, tuh_hid_report_i32(tb, 16, 8, true)); + TEST_ASSERT_EQUAL(0xff8f0550, tuh_hid_report_i32(tb, 0, 32, true)); +} From 2942026e74e8a9b2a33783ac08505ab76a4e6943 Mon Sep 17 00:00:00 2001 From: Phil Date: Sun, 13 Feb 2022 18:23:05 +0000 Subject: [PATCH 53/71] HID micro parser --- examples/host/cdc_msc_hid/src/hid_app.c | 11 ++--- examples/host/cdc_msc_hid/src/hid_joy.c | 43 ++++++++++--------- examples/host/cdc_msc_hid/src/hid_joy.h | 15 ++++++- src/class/hid/hid_rip.c | 8 ++-- test/test/class/hid/test_hid_rip.c | 2 + .../examples/host/cdc_msc_hid/test_hid_joy.c | 12 ------ 6 files changed, 48 insertions(+), 43 deletions(-) diff --git a/examples/host/cdc_msc_hid/src/hid_app.c b/examples/host/cdc_msc_hid/src/hid_app.c index 2e8814f10d..2f104a8934 100644 --- a/examples/host/cdc_msc_hid/src/hid_app.c +++ b/examples/host/cdc_msc_hid/src/hid_app.c @@ -304,14 +304,15 @@ static void process_generic_report(uint8_t dev_addr, uint8_t instance, uint8_t c case HID_USAGE_DESKTOP_JOYSTICK: TU_LOG1("HID receive joystick report "); - for(int i = 0; i < len; ++i) { - printf("%02x", report[i]); - } - printf("\r\n"); +// for(int i = 0; i < len; ++i) { +// printf("%02x", report[i]); +// } +// printf("\r\n"); tusb_hid_simple_joysick_t* simple_joystick = tuh_hid_get_simple_joystick(instance, rpt_id); if (simple_joystick != NULL) { - tusb_hid_print_simple_joysick_report(simple_joystick, report, len); + tusb_hid_simple_joysick_process_report(simple_joystick, report, len); + tusb_hid_print_simple_joysick_report(simple_joystick); } break; diff --git a/examples/host/cdc_msc_hid/src/hid_joy.c b/examples/host/cdc_msc_hid/src/hid_joy.c index 24192ffc6f..f9334179d1 100644 --- a/examples/host/cdc_msc_hid/src/hid_joy.c +++ b/examples/host/cdc_msc_hid/src/hid_joy.c @@ -128,7 +128,6 @@ static void tuh_hid_joystick_process_axis( simple_axis->start = bitpos; simple_axis->length = jdata->report_size; simple_axis->flags.is_signed = jdata->logical_min < 0; - simple_axis->flags.byte_aligned = ((bitpos & 7) == 0) && ((jdata->report_size & 7) == 0); } void tuh_hid_joystick_process_usages( @@ -242,28 +241,30 @@ int32_t tuh_hid_simple_joystick_get_axis_value(tusb_hid_simple_axis_t* simple_ax return tuh_hid_report_i32(report, simple_axis->start, simple_axis->length, simple_axis->flags.is_signed); } -void tusb_hid_print_simple_joysick_report(tusb_hid_simple_joysick_t* simple_joystick, const uint8_t* report, uint8_t report_length) -{ - if (simple_joystick == NULL ) { - printf("NULL joystick definition\n"); - } +void tusb_hid_simple_joysick_process_report(tusb_hid_simple_joysick_t* simple_joystick, const uint8_t* report, uint8_t report_length) { // TODO Check the report is long enough!! - // TODO move to struct - int32_t x1 = tuh_hid_simple_joystick_get_axis_value(&simple_joystick->axis_x1, report); - int32_t y1 = tuh_hid_simple_joystick_get_axis_value(&simple_joystick->axis_y1, report); - int32_t x2 = tuh_hid_simple_joystick_get_axis_value(&simple_joystick->axis_x2, report); - int32_t y2 = tuh_hid_simple_joystick_get_axis_value(&simple_joystick->axis_y2, report); - int32_t hat = tuh_hid_simple_joystick_get_axis_value(&simple_joystick->hat, report); - uint32_t buttons = tuh_hid_report_bits_u32(report, simple_joystick->buttons.start, simple_joystick->buttons.length); - - printf("x1=%4ld, y1=%4ld, x2=%4ld, y2=%4ld, hat=%01X, buttons=%04X\n", - x1, - y1, - x2, - y2, - hat, - buttons); + tusb_hid_simple_joysick_values_t* values = &simple_joystick->values; + values->x1 = tuh_hid_simple_joystick_get_axis_value(&simple_joystick->axis_x1, report); + values->y1 = tuh_hid_simple_joystick_get_axis_value(&simple_joystick->axis_y1, report); + values->x2 = tuh_hid_simple_joystick_get_axis_value(&simple_joystick->axis_x2, report); + values->y2 = tuh_hid_simple_joystick_get_axis_value(&simple_joystick->axis_y2, report); + values->hat = tuh_hid_simple_joystick_get_axis_value(&simple_joystick->hat, report); + values->buttons = tuh_hid_report_bits_u32(report, simple_joystick->buttons.start, simple_joystick->buttons.length); + simple_joystick->has_values = true; +} + +void tusb_hid_print_simple_joysick_report(tusb_hid_simple_joysick_t* simple_joystick) +{ + if (simple_joystick->has_values) { + printf("x1=%4ld, y1=%4ld, x2=%4ld, y2=%4ld, hat=%01X, buttons=%04X\n", + simple_joystick->values.x1, + simple_joystick->values.y1, + simple_joystick->values.x2, + simple_joystick->values.y2, + simple_joystick->values.hat, + simple_joystick->values.buttons); + } } diff --git a/examples/host/cdc_msc_hid/src/hid_joy.h b/examples/host/cdc_msc_hid/src/hid_joy.h index 688b6a56ef..e47b826a95 100644 --- a/examples/host/cdc_msc_hid/src/hid_joy.h +++ b/examples/host/cdc_msc_hid/src/hid_joy.h @@ -55,7 +55,6 @@ typedef struct { struct TU_ATTR_PACKED { bool is_signed : 1; - bool byte_aligned : 1; // TODO More efficient fetch from report if set }; } flags; uint16_t start; @@ -69,16 +68,27 @@ typedef struct { // Very simple representation of a joystick to try and map to // (and this will be quite tricky enough). +typedef struct { + int32_t x1; + int32_t y1; + int32_t x2; + int32_t y2; + int32_t hat; + uint32_t buttons; +} tusb_hid_simple_joysick_values_t; + typedef struct { uint8_t hid_instance; uint8_t report_id; bool active; + bool has_values; tusb_hid_simple_axis_t axis_x1; tusb_hid_simple_axis_t axis_y1; tusb_hid_simple_axis_t axis_x2; tusb_hid_simple_axis_t axis_y2; tusb_hid_simple_axis_t hat; tusb_hid_simple_buttons_t buttons; + tusb_hid_simple_joysick_values_t values; } tusb_hid_simple_joysick_t; typedef struct { @@ -119,6 +129,7 @@ void tuh_hid_free_simple_joystick(uint8_t hid_instance); void tuh_hid_free_simple_joysticks(); tusb_hid_simple_joysick_t* tuh_hid_allocate_simple_joystick(uint8_t hid_instance, uint8_t report_id); tusb_hid_simple_joysick_t* tuh_hid_obtain_simple_joystick(uint8_t hid_instance, uint8_t report_id); -void tusb_hid_print_simple_joysick_report(tusb_hid_simple_joysick_t* simple_joystick, const uint8_t* report, uint8_t report_length); +void tusb_hid_simple_joysick_process_report(tusb_hid_simple_joysick_t* simple_joystick, const uint8_t* report, uint8_t report_length); +void tusb_hid_print_simple_joysick_report(tusb_hid_simple_joysick_t* simple_joystick); #endif diff --git a/src/class/hid/hid_rip.c b/src/class/hid/hid_rip.c index 41a25b3e45..a7ad63a659 100644 --- a/src/class/hid/hid_rip.c +++ b/src/class/hid/hid_rip.c @@ -231,9 +231,10 @@ int32_t tuh_hid_report_bits_i32(uint8_t const* report, uint16_t start, uint16_t uint32_t tuh_hid_report_bytes_u32(uint8_t const* report, uint16_t start, uint16_t length) { const uint8_t *p = report + start; + if (length == 1) return (uint32_t)*p; uint32_t acc = 0; for(uint16_t i = 0; i < length; ++i) { - acc |= (uint32_t)*p++; + acc |= ((uint32_t)*p++) << (i << 3); } return acc; } @@ -242,11 +243,12 @@ uint32_t tuh_hid_report_bytes_u32(uint8_t const* report, uint16_t start, uint16_ int32_t tuh_hid_report_bytes_i32(uint8_t const* report, uint16_t start, uint16_t length) { const uint8_t *p = report + start; + if (length == 1) return (int32_t)(int8_t)*p; uint32_t acc = 0; for(uint16_t i = 0; i < length; ++i) { - acc |= (uint32_t)*p++; + acc |= ((uint32_t)*p++) << (i << 3); } - const uint32_t lp0 = ((uint32_t)1) << (length + 2); + const uint32_t lp0 = ((uint32_t)1) << ((length << 3) - 1); const uint32_t lp1 = lp0 << 1; // sign extend return acc & lp0 ? acc | -lp1 : acc; diff --git a/test/test/class/hid/test_hid_rip.c b/test/test/class/hid/test_hid_rip.c index eedd5f4e8b..0c22b0ae48 100644 --- a/test/test/class/hid/test_hid_rip.c +++ b/test/test/class/hid/test_hid_rip.c @@ -612,6 +612,7 @@ void test_tuh_hid_report_bytes_u32() { TEST_ASSERT_EQUAL(0x8f05, tuh_hid_report_bytes_u32(tb, 1, 2)); TEST_ASSERT_EQUAL(0xff8f05, tuh_hid_report_bytes_u32(tb, 1, 3)); TEST_ASSERT_EQUAL(0xff8f0550, tuh_hid_report_bytes_u32(tb, 0, 4)); + TEST_ASSERT_EQUAL(0x8f, tuh_hid_report_bytes_u32(tb, 2, 1)); } void test_tuh_hid_report_bytes_i32() { @@ -622,6 +623,7 @@ void test_tuh_hid_report_bytes_i32() { TEST_ASSERT_EQUAL(0xffff8f05, tuh_hid_report_bytes_i32(tb, 1, 2)); TEST_ASSERT_EQUAL(0xffff8f05, tuh_hid_report_bytes_i32(tb, 1, 3)); TEST_ASSERT_EQUAL(0xff8f0550, tuh_hid_report_bytes_i32(tb, 0, 4)); + TEST_ASSERT_EQUAL(0xffffff8f, tuh_hid_report_bytes_i32(tb, 2, 1)); } void test_tuh_hid_report_i32() { diff --git a/test/test/examples/host/cdc_msc_hid/test_hid_joy.c b/test/test/examples/host/cdc_msc_hid/test_hid_joy.c index 2211c3f88e..3518b947ad 100644 --- a/test/test/examples/host/cdc_msc_hid/test_hid_joy.c +++ b/test/test/examples/host/cdc_msc_hid/test_hid_joy.c @@ -190,22 +190,18 @@ void test_tuh_hid_joystick_get_data() { TEST_ASSERT_EQUAL(0, simple_joystick->axis_x1.start); TEST_ASSERT_EQUAL(8, simple_joystick->axis_x1.length); TEST_ASSERT_EQUAL(false, simple_joystick->axis_x1.flags.is_signed); - TEST_ASSERT_EQUAL(true, simple_joystick->axis_x1.flags.byte_aligned); // y1 TEST_ASSERT_EQUAL(8, simple_joystick->axis_y1.start); TEST_ASSERT_EQUAL(8, simple_joystick->axis_y1.length); TEST_ASSERT_EQUAL(false, simple_joystick->axis_y1.flags.is_signed); - TEST_ASSERT_EQUAL(true, simple_joystick->axis_y1.flags.byte_aligned); // x2 TEST_ASSERT_EQUAL(24, simple_joystick->axis_x2.start); TEST_ASSERT_EQUAL(8, simple_joystick->axis_x2.length); TEST_ASSERT_EQUAL(false, simple_joystick->axis_x2.flags.is_signed); - TEST_ASSERT_EQUAL(true, simple_joystick->axis_x2.flags.byte_aligned); // y2 TEST_ASSERT_EQUAL(32, simple_joystick->axis_y2.start); TEST_ASSERT_EQUAL(8, simple_joystick->axis_y2.length); TEST_ASSERT_EQUAL(false, simple_joystick->axis_y2.flags.is_signed); - TEST_ASSERT_EQUAL(true, simple_joystick->axis_y2.flags.byte_aligned); while((ri = tuh_hid_rip_next_item(&pstate)) != NULL ) if (ri >= &tb_speedlink[47]) break; TEST_ASSERT_EQUAL(&tb_speedlink[47], ri); // Move to the second input in the speedlink description @@ -270,22 +266,18 @@ void test_hid_parse_greenasia_report() { TEST_ASSERT_EQUAL(0, simple_joystick->axis_x1.start); TEST_ASSERT_EQUAL(8, simple_joystick->axis_x1.length); TEST_ASSERT_EQUAL(false, simple_joystick->axis_x1.flags.is_signed); - TEST_ASSERT_EQUAL(true, simple_joystick->axis_x1.flags.byte_aligned); // y1 TEST_ASSERT_EQUAL(8, simple_joystick->axis_y1.start); TEST_ASSERT_EQUAL(8, simple_joystick->axis_y1.length); TEST_ASSERT_EQUAL(false, simple_joystick->axis_y1.flags.is_signed); - TEST_ASSERT_EQUAL(true, simple_joystick->axis_y1.flags.byte_aligned); // x2 TEST_ASSERT_EQUAL(24, simple_joystick->axis_x2.start); TEST_ASSERT_EQUAL(8, simple_joystick->axis_x2.length); TEST_ASSERT_EQUAL(false, simple_joystick->axis_x2.flags.is_signed); - TEST_ASSERT_EQUAL(true, simple_joystick->axis_x2.flags.byte_aligned); // y2 TEST_ASSERT_EQUAL(32, simple_joystick->axis_y2.start); TEST_ASSERT_EQUAL(8, simple_joystick->axis_y2.length); TEST_ASSERT_EQUAL(false, simple_joystick->axis_y2.flags.is_signed); - TEST_ASSERT_EQUAL(true, simple_joystick->axis_y2.flags.byte_aligned); TEST_ASSERT_EQUAL(40, simple_joystick->hat.start); TEST_ASSERT_EQUAL(4, simple_joystick->hat.length); TEST_ASSERT_EQUAL(44, simple_joystick->buttons.start); @@ -300,22 +292,18 @@ void test_hid_parse_speedlink_report() { TEST_ASSERT_EQUAL(16, simple_joystick->axis_x1.start); TEST_ASSERT_EQUAL(8, simple_joystick->axis_x1.length); TEST_ASSERT_EQUAL(false, simple_joystick->axis_x1.flags.is_signed); - TEST_ASSERT_EQUAL(true, simple_joystick->axis_x1.flags.byte_aligned); // y1 TEST_ASSERT_EQUAL(24, simple_joystick->axis_y1.start); TEST_ASSERT_EQUAL(8, simple_joystick->axis_y1.length); TEST_ASSERT_EQUAL(false, simple_joystick->axis_y1.flags.is_signed); - TEST_ASSERT_EQUAL(true, simple_joystick->axis_y1.flags.byte_aligned); // x2 TEST_ASSERT_EQUAL(0, simple_joystick->axis_x2.start); TEST_ASSERT_EQUAL(8, simple_joystick->axis_x2.length); TEST_ASSERT_EQUAL(false, simple_joystick->axis_x2.flags.is_signed); - TEST_ASSERT_EQUAL(true, simple_joystick->axis_x2.flags.byte_aligned); // y2 TEST_ASSERT_EQUAL(8, simple_joystick->axis_y2.start); TEST_ASSERT_EQUAL(8, simple_joystick->axis_y2.length); TEST_ASSERT_EQUAL(false, simple_joystick->axis_y2.flags.is_signed); - TEST_ASSERT_EQUAL(true, simple_joystick->axis_y2.flags.byte_aligned); TEST_ASSERT_EQUAL(40, simple_joystick->hat.start); TEST_ASSERT_EQUAL(4, simple_joystick->hat.length); From 42bd4770451056f746910172a56d85a85e6a576b Mon Sep 17 00:00:00 2001 From: Phil Date: Mon, 14 Feb 2022 07:43:17 +0000 Subject: [PATCH 54/71] HID micro parser --- examples/host/cdc_msc_hid/src/hid_joy.c | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/examples/host/cdc_msc_hid/src/hid_joy.c b/examples/host/cdc_msc_hid/src/hid_joy.c index f9334179d1..44c1198b42 100644 --- a/examples/host/cdc_msc_hid/src/hid_joy.c +++ b/examples/host/cdc_msc_hid/src/hid_joy.c @@ -136,10 +136,7 @@ void tuh_hid_joystick_process_usages( uint32_t bitpos, uint8_t hid_instance) { - if (jdata->input_flags.data_const) { - printf("const bits %d \n", jdata->report_size * jdata->report_count); - return; - } + if (jdata->input_flags.data_const) return; // If there are no specific usages look for a range // TODO What is the correct behaviour if there are both? @@ -147,11 +144,6 @@ void tuh_hid_joystick_process_usages( printf("no usage - skipping bits %d \n", jdata->report_size * jdata->report_count); return; } - - if (jdata->input_flags.data_const) { - printf("skipping const bits %d \n", jdata->report_size * jdata->report_count); - return; - } tusb_hid_simple_joysick_t* simple_joystick = tuh_hid_obtain_simple_joystick(hid_instance, jdata->report_id); From 721474acf27894b20d8d470351bb358204893b1a Mon Sep 17 00:00:00 2001 From: Phil Date: Mon, 14 Feb 2022 08:04:52 +0000 Subject: [PATCH 55/71] HID micro parser --- .../examples/host/cdc_msc_hid/test_hid_joy.c | 115 +++++++++++++++++- 1 file changed, 114 insertions(+), 1 deletion(-) diff --git a/test/test/examples/host/cdc_msc_hid/test_hid_joy.c b/test/test/examples/host/cdc_msc_hid/test_hid_joy.c index 3518b947ad..0aecdf013b 100644 --- a/test/test/examples/host/cdc_msc_hid/test_hid_joy.c +++ b/test/test/examples/host/cdc_msc_hid/test_hid_joy.c @@ -135,6 +135,63 @@ static const uint8_t const tb_speedlink[] = { 0xC0, // End Collection 0xC0, // End Collection }; + +static const uint8_t const tb_apple[] = { + 0x05, 0x01, // Usage Page (Generic Desktop Ctrls) + 0x09, 0x04, // Usage (Joystick) + 0xA1, 0x01, // Collection (Application) + 0x09, 0x01, // Usage (Pointer) + 0xA1, 0x00, // Collection (Physical) + 0x05, 0x01, // Usage Page (Generic Desktop Ctrls) + 0x09, 0x30, // Usage (X) + 0x09, 0x31, // Usage (Y) + 0x15, 0x00, // Logical Minimum (0) + 0x26, 0xFF, 0x03, // Logical Maximum (1023) + 0x35, 0x00, // Physical Minimum (0) + 0x46, 0xFF, 0x03, // Physical Maximum (1023) + 0x65, 0x00, // Unit (None) + 0x75, 0x0A, // Report Size (10) + 0x95, 0x02, // Report Count (2) + 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0x09, 0x35, // Usage (Rz) + 0x09, 0x32, // Usage (Z) + 0x15, 0x00, // Logical Minimum (0) + 0x26, 0xFF, 0x01, // Logical Maximum (511) + 0x35, 0x00, // Physical Minimum (0) + 0x46, 0xFF, 0x01, // Physical Maximum (511) + 0x65, 0x00, // Unit (None) + 0x75, 0x09, // Report Size (9) + 0x95, 0x02, // Report Count (2) + 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0x75, 0x01, // Report Size (1) + 0x95, 0x02, // Report Count (2) + 0x81, 0x01, // Input (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0x09, 0x39, // Usage (Hat switch) + 0x15, 0x01, // Logical Minimum (1) + 0x25, 0x08, // Logical Maximum (8) + 0x35, 0x00, // Physical Minimum (0) + 0x46, 0x3B, 0x01, // Physical Maximum (315) + 0x65, 0x14, // Unit (System: English Rotation, Length: Centimeter) + 0x75, 0x08, // Report Size (8) + 0x95, 0x01, // Report Count (1) + 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0x05, 0x09, // Usage Page (Button) + 0x19, 0x01, // Usage Minimum (0x01) + 0x29, 0x0C, // Usage Maximum (0x0C) + 0x15, 0x00, // Logical Minimum (0) + 0x25, 0x01, // Logical Maximum (1) + 0x35, 0x00, // Physical Minimum (0) + 0x45, 0x01, // Physical Maximum (1) + 0x75, 0x01, // Report Size (1) + 0x95, 0x0C, // Report Count (12) + 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0x75, 0x01, // Report Size (1) + 0x95, 0x04, // Report Count (4) + 0x81, 0x01, // Input (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0xC0, // End Collection + 0xC0, // End Collection +}; + void setUp(void) { @@ -311,4 +368,60 @@ void test_hid_parse_speedlink_report() { TEST_ASSERT_EQUAL(12, simple_joystick->buttons.length); } - +void test_apple_joystick() { + // Thanks to https://jenswilly.dk/2012/10/parsing-usb-joystick-hid-data/ + + // 10 bits of X-axis data (for values from 0 to 1023) + // 10 bits of Y-axis data (for values from 0 to 1023) + // 9 bits of Rz-axis (yaw or rotation) data (for values from 0-511) + // 9 bits of Z-axis (throttle) data (for values from 0-511) + // 2 "constant" bits – i.e. unused padding bits + // 8 bits of hat switch data (though values are only from 1-8) + // 12 bits of button states (12 buttons of 0 or 1 values) + // 4 bits of padding + tuh_hid_joystick_parse_report_descriptor(tb_apple, sizeof(tb_apple), 9); + tusb_hid_simple_joysick_t* simple_joystick = tuh_hid_get_simple_joystick(9, 0); + TEST_ASSERT_NOT_NULL(simple_joystick); + // x1 + TEST_ASSERT_EQUAL(0, simple_joystick->axis_x1.start); + TEST_ASSERT_EQUAL(10, simple_joystick->axis_x1.length); + TEST_ASSERT_EQUAL(false, simple_joystick->axis_x1.flags.is_signed); + // y1 + TEST_ASSERT_EQUAL(10, simple_joystick->axis_y1.start); + TEST_ASSERT_EQUAL(10, simple_joystick->axis_y1.length); + TEST_ASSERT_EQUAL(false, simple_joystick->axis_y1.flags.is_signed); + // x2 + TEST_ASSERT_EQUAL(29, simple_joystick->axis_x2.start); + TEST_ASSERT_EQUAL(9, simple_joystick->axis_x2.length); + TEST_ASSERT_EQUAL(false, simple_joystick->axis_x2.flags.is_signed); + // y2 + TEST_ASSERT_EQUAL(20, simple_joystick->axis_y2.start); + TEST_ASSERT_EQUAL(9, simple_joystick->axis_y2.length); + TEST_ASSERT_EQUAL(false, simple_joystick->axis_y2.flags.is_signed); + + TEST_ASSERT_EQUAL(40, simple_joystick->hat.start); + TEST_ASSERT_EQUAL(8, simple_joystick->hat.length); + + TEST_ASSERT_EQUAL(48, simple_joystick->buttons.start); + TEST_ASSERT_EQUAL(12, simple_joystick->buttons.length); + + // Raw hex: e9 31 e8 ef 3f 00 00 00 + // + // Binary 11101001 00110001 11101000 11101111 00111111 00000000 00000000 00000000 + // field XXXXXXXX YYYYYYXX RRRRYYYY ZZZRRRRR --ZZZZZZ HHHHHHHH BBBBBBBB ----BBBB + // bit no. 76543210 54321098 32109876 21087654 --876543 76543210 76543210 ----BA98 + // + // X = X-axis: b0111101001 = 489 + // Y = Y-axis: b1000001100 = 524 + // R = Rz-axis: b011111110 = 254 + // Z = Z-axis: b111111111 = 511 + // H = hat: b00000000 = 0 (centered) + // B = buttons b000000000000 = 0 (no buttons pressed) + // - = padding + + uint8_t report[] = {0xe9, 0x31, 0xe8, 0xef, 0x3f, 0x00, 0x00, 0x00}; + tusb_hid_simple_joysick_process_report(simple_joystick, report, sizeof(report)); + TEST_ASSERT_EQUAL(true, simple_joystick->has_values); + TEST_ASSERT_EQUAL(489, simple_joystick->values.x1); + // TODO +} From 6ea3805399f2b7f5f55bbad103511ed1162286e9 Mon Sep 17 00:00:00 2001 From: Phil Date: Mon, 14 Feb 2022 19:21:56 +0000 Subject: [PATCH 56/71] HID micro parser --- test/test/examples/host/cdc_msc_hid/test_hid_joy.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/test/test/examples/host/cdc_msc_hid/test_hid_joy.c b/test/test/examples/host/cdc_msc_hid/test_hid_joy.c index 0aecdf013b..0f44d78f9f 100644 --- a/test/test/examples/host/cdc_msc_hid/test_hid_joy.c +++ b/test/test/examples/host/cdc_msc_hid/test_hid_joy.c @@ -423,5 +423,9 @@ void test_apple_joystick() { tusb_hid_simple_joysick_process_report(simple_joystick, report, sizeof(report)); TEST_ASSERT_EQUAL(true, simple_joystick->has_values); TEST_ASSERT_EQUAL(489, simple_joystick->values.x1); - // TODO + TEST_ASSERT_EQUAL(524, simple_joystick->values.y1); + TEST_ASSERT_EQUAL(511, simple_joystick->values.x2); + TEST_ASSERT_EQUAL(254, simple_joystick->values.y2); + TEST_ASSERT_EQUAL(0, simple_joystick->values.hat); + TEST_ASSERT_EQUAL(0, simple_joystick->values.buttons); } From 52dd993d4b7d66cb165eecfa1c485c499a991a74 Mon Sep 17 00:00:00 2001 From: Phil Date: Mon, 14 Feb 2022 20:28:34 +0000 Subject: [PATCH 57/71] HID micro parser --- examples/host/cdc_msc_hid/src/hid_joy.c | 21 ++++++++++------ examples/host/cdc_msc_hid/src/hid_joy.h | 7 ++++-- .../examples/host/cdc_msc_hid/test_hid_joy.c | 25 ++++++++++++++++++- 3 files changed, 42 insertions(+), 11 deletions(-) diff --git a/examples/host/cdc_msc_hid/src/hid_joy.c b/examples/host/cdc_msc_hid/src/hid_joy.c index 44c1198b42..2917516722 100644 --- a/examples/host/cdc_msc_hid/src/hid_joy.c +++ b/examples/host/cdc_msc_hid/src/hid_joy.c @@ -128,6 +128,8 @@ static void tuh_hid_joystick_process_axis( simple_axis->start = bitpos; simple_axis->length = 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; } void tuh_hid_joystick_process_usages( @@ -151,6 +153,9 @@ void tuh_hid_joystick_process_usages( printf("Failed to allocate joystick for HID instance %d, report ID %d\n", hid_instance, jdata->report_id); return; } + + // update the report length in bytes + simple_joystick->report_length = (uint8_t)((bitpos + (jdata->report_size * jdata->report_count) + 7) >> 3); // TODO Naive, assumes buttons are defined in a range if (jdata->usage_is_range) { @@ -217,10 +222,8 @@ uint8_t tuh_hid_joystick_parse_report_descriptor(uint8_t const* desc_report, uin } break; } - case HID_RI_TYPE_AND_TAG(RI_TYPE_MAIN, RI_MAIN_COLLECTION_END): { - if (pstate.collections_count == 0) { - bitpos = 0; - } + case HID_RI_TYPE_AND_TAG(RI_TYPE_GLOBAL, RI_GLOBAL_REPORT_ID): { + bitpos = 0; break; } default: break; @@ -233,10 +236,12 @@ int32_t tuh_hid_simple_joystick_get_axis_value(tusb_hid_simple_axis_t* simple_ax return tuh_hid_report_i32(report, simple_axis->start, simple_axis->length, simple_axis->flags.is_signed); } -void tusb_hid_simple_joysick_process_report(tusb_hid_simple_joysick_t* simple_joystick, const uint8_t* report, uint8_t report_length) { - - // TODO Check the report is long enough!! - +void tusb_hid_simple_joysick_process_report(tusb_hid_simple_joysick_t* simple_joystick, const uint8_t* report, uint8_t report_length) + { + if (simple_joystick->report_length > report_length) { + TU_LOG1("HID joystick report too small\r\n"); + return; + } tusb_hid_simple_joysick_values_t* values = &simple_joystick->values; values->x1 = tuh_hid_simple_joystick_get_axis_value(&simple_joystick->axis_x1, report); values->y1 = tuh_hid_simple_joystick_get_axis_value(&simple_joystick->axis_y1, report); diff --git a/examples/host/cdc_msc_hid/src/hid_joy.h b/examples/host/cdc_msc_hid/src/hid_joy.h index e47b826a95..5b1a1c82be 100644 --- a/examples/host/cdc_msc_hid/src/hid_joy.h +++ b/examples/host/cdc_msc_hid/src/hid_joy.h @@ -59,6 +59,8 @@ typedef struct { } flags; uint16_t start; uint16_t length; + int32_t logical_min; + int32_t logical_max; } tusb_hid_simple_axis_t; typedef struct { @@ -80,6 +82,7 @@ typedef struct { typedef struct { uint8_t hid_instance; uint8_t report_id; + uint8_t report_length; // requied report length in bytes bool active; bool has_values; tusb_hid_simple_axis_t axis_x1; @@ -92,8 +95,8 @@ typedef struct { } tusb_hid_simple_joysick_t; typedef struct { - uint32_t report_size; // TODO make this a uint8_t and range check before assignment - uint32_t report_count; // TODO make this a uint8_t and range check before assignment + uint32_t report_size; + uint32_t report_count; uint32_t logical_min; uint32_t logical_max; uint16_t usage_page; diff --git a/test/test/examples/host/cdc_msc_hid/test_hid_joy.c b/test/test/examples/host/cdc_msc_hid/test_hid_joy.c index 0f44d78f9f..b07f84ed13 100644 --- a/test/test/examples/host/cdc_msc_hid/test_hid_joy.c +++ b/test/test/examples/host/cdc_msc_hid/test_hid_joy.c @@ -195,7 +195,7 @@ static const uint8_t const tb_apple[] = { void setUp(void) { - tuh_hid_free_simple_joysticks(); + tuh_hid_free_simple_joysticks(); } void tearDown(void) @@ -247,18 +247,27 @@ void test_tuh_hid_joystick_get_data() { TEST_ASSERT_EQUAL(0, simple_joystick->axis_x1.start); TEST_ASSERT_EQUAL(8, simple_joystick->axis_x1.length); TEST_ASSERT_EQUAL(false, simple_joystick->axis_x1.flags.is_signed); + TEST_ASSERT_EQUAL(0, simple_joystick->axis_x1.logical_min); + TEST_ASSERT_EQUAL(255, simple_joystick->axis_x1.logical_max); + // y1 TEST_ASSERT_EQUAL(8, simple_joystick->axis_y1.start); TEST_ASSERT_EQUAL(8, simple_joystick->axis_y1.length); TEST_ASSERT_EQUAL(false, simple_joystick->axis_y1.flags.is_signed); + TEST_ASSERT_EQUAL(0, simple_joystick->axis_y1.logical_min); + TEST_ASSERT_EQUAL(255, simple_joystick->axis_y1.logical_max); // x2 TEST_ASSERT_EQUAL(24, simple_joystick->axis_x2.start); TEST_ASSERT_EQUAL(8, simple_joystick->axis_x2.length); TEST_ASSERT_EQUAL(false, simple_joystick->axis_x2.flags.is_signed); + TEST_ASSERT_EQUAL(0, simple_joystick->axis_x2.logical_min); + TEST_ASSERT_EQUAL(255, simple_joystick->axis_x2.logical_max); // y2 TEST_ASSERT_EQUAL(32, simple_joystick->axis_y2.start); TEST_ASSERT_EQUAL(8, simple_joystick->axis_y2.length); TEST_ASSERT_EQUAL(false, simple_joystick->axis_y2.flags.is_signed); + TEST_ASSERT_EQUAL(0, simple_joystick->axis_y2.logical_min); + TEST_ASSERT_EQUAL(255, simple_joystick->axis_y2.logical_max); while((ri = tuh_hid_rip_next_item(&pstate)) != NULL ) if (ri >= &tb_speedlink[47]) break; TEST_ASSERT_EQUAL(&tb_speedlink[47], ri); // Move to the second input in the speedlink description @@ -313,6 +322,8 @@ void test_tuh_hid_joystick_get_data() { TEST_ASSERT_NOT_NULL(simple_joystick); TEST_ASSERT_EQUAL(44, simple_joystick->buttons.start); TEST_ASSERT_EQUAL(12, simple_joystick->buttons.length); + + TEST_ASSERT_EQUAL(7, simple_joystick->report_length); } void test_hid_parse_greenasia_report() { @@ -339,6 +350,8 @@ void test_hid_parse_greenasia_report() { TEST_ASSERT_EQUAL(4, simple_joystick->hat.length); TEST_ASSERT_EQUAL(44, simple_joystick->buttons.start); TEST_ASSERT_EQUAL(12, simple_joystick->buttons.length); + + TEST_ASSERT_EQUAL(8, simple_joystick->report_length); } void test_hid_parse_speedlink_report() { @@ -366,6 +379,8 @@ void test_hid_parse_speedlink_report() { TEST_ASSERT_EQUAL(4, simple_joystick->hat.length); TEST_ASSERT_EQUAL(44, simple_joystick->buttons.start); TEST_ASSERT_EQUAL(12, simple_joystick->buttons.length); + + TEST_ASSERT_EQUAL(8, simple_joystick->report_length); } void test_apple_joystick() { @@ -386,6 +401,8 @@ void test_apple_joystick() { TEST_ASSERT_EQUAL(0, simple_joystick->axis_x1.start); TEST_ASSERT_EQUAL(10, simple_joystick->axis_x1.length); TEST_ASSERT_EQUAL(false, simple_joystick->axis_x1.flags.is_signed); + TEST_ASSERT_EQUAL(0, simple_joystick->axis_x1.logical_min); + TEST_ASSERT_EQUAL(1023, simple_joystick->axis_x1.logical_max); // y1 TEST_ASSERT_EQUAL(10, simple_joystick->axis_y1.start); TEST_ASSERT_EQUAL(10, simple_joystick->axis_y1.length); @@ -428,4 +445,10 @@ void test_apple_joystick() { TEST_ASSERT_EQUAL(254, simple_joystick->values.y2); TEST_ASSERT_EQUAL(0, simple_joystick->values.hat); TEST_ASSERT_EQUAL(0, simple_joystick->values.buttons); + + TEST_ASSERT_EQUAL(8, simple_joystick->report_length); } + +// TODO Test multiple report IDs + + From 94060ec04837bf33549390625e1e105ffea2f7d8 Mon Sep 17 00:00:00 2001 From: Phil Date: Tue, 15 Feb 2022 21:57:08 +0000 Subject: [PATCH 58/71] HID micro parser --- examples/host/cdc_msc_hid/CMakeLists.txt | 3 +- examples/host/cdc_msc_hid/src/hid_app.c | 4 +- .../src/{hid_joy.c => hid_host_joy.c} | 20 ++-- .../src/{hid_joy.h => hid_host_joy.h} | 29 ++++- .../host/cdc_msc_hid/src/hid_host_utils.c | 99 +++++++++++++++++ .../host/cdc_msc_hid/src/hid_host_utils.h | 56 ++++++++++ src/class/hid/hid_rip.c | 71 ------------- src/class/hid/hid_rip.h | 20 ---- test/test/class/hid/test_hid_rip.c | 53 ---------- .../{test_hid_joy.c => test_hid_host_joy.c} | 57 ++++++++-- .../host/cdc_msc_hid/test_hid_host_utils.c | 100 ++++++++++++++++++ 11 files changed, 345 insertions(+), 167 deletions(-) rename examples/host/cdc_msc_hid/src/{hid_joy.c => hid_host_joy.c} (95%) rename examples/host/cdc_msc_hid/src/{hid_joy.h => hid_host_joy.h} (81%) create mode 100644 examples/host/cdc_msc_hid/src/hid_host_utils.c create mode 100644 examples/host/cdc_msc_hid/src/hid_host_utils.h rename test/test/examples/host/cdc_msc_hid/{test_hid_joy.c => test_hid_host_joy.c} (91%) create mode 100644 test/test/examples/host/cdc_msc_hid/test_hid_host_utils.c diff --git a/examples/host/cdc_msc_hid/CMakeLists.txt b/examples/host/cdc_msc_hid/CMakeLists.txt index e1802badb2..8d7f04d9a1 100644 --- a/examples/host/cdc_msc_hid/CMakeLists.txt +++ b/examples/host/cdc_msc_hid/CMakeLists.txt @@ -15,7 +15,8 @@ add_executable(${PROJECT}) # Example source target_sources(${PROJECT} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/src/hid_app.c - ${CMAKE_CURRENT_SOURCE_DIR}/src/hid_joy.c + ${CMAKE_CURRENT_SOURCE_DIR}/src/hid_host_utils.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 ) diff --git a/examples/host/cdc_msc_hid/src/hid_app.c b/examples/host/cdc_msc_hid/src/hid_app.c index 2f104a8934..82332cea4e 100644 --- a/examples/host/cdc_msc_hid/src/hid_app.c +++ b/examples/host/cdc_msc_hid/src/hid_app.c @@ -25,7 +25,7 @@ #include "bsp/board.h" #include "tusb.h" -#include "hid_joy.h" +#include "hid_host_joy.h" //--------------------------------------------------------------------+ // MACRO TYPEDEF CONSTANT ENUM DECLARATION @@ -102,7 +102,7 @@ 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); // Free up any joystick definitions - tuh_hid_free_simple_joystick(instance); + tuh_hid_free_simple_joysticks_for_instance(instance); } // Invoked when received report from device via interrupt endpoint diff --git a/examples/host/cdc_msc_hid/src/hid_joy.c b/examples/host/cdc_msc_hid/src/hid_host_joy.c similarity index 95% rename from examples/host/cdc_msc_hid/src/hid_joy.c rename to examples/host/cdc_msc_hid/src/hid_host_joy.c index 2917516722..bf88ccc3fe 100644 --- a/examples/host/cdc_msc_hid/src/hid_joy.c +++ b/examples/host/cdc_msc_hid/src/hid_host_joy.c @@ -21,10 +21,11 @@ * * Test me with: * - * ceedling test:pattern[hid_joy] + * ceedling test:pattern[hid_host_joy] */ -#include "hid_joy.h" +#include "hid_host_joy.h" +#include "hid_host_utils.h" static tusb_hid_simple_joysick_t hid_simple_joysicks[HID_MAX_JOYSTICKS]; @@ -38,7 +39,6 @@ static bool tuh_hid_joystick_check_usage(uint32_t eusage) } } -// TODO Test tusb_hid_simple_joysick_t* tuh_hid_get_simple_joystick(uint8_t hid_instance, uint8_t report_id) { for(uint8_t i = 0; i < HID_MAX_JOYSTICKS; ++i) { @@ -54,15 +54,13 @@ void tuh_hid_free_simple_joysticks() { } } -// TODO Test -void tuh_hid_free_simple_joystick(uint8_t hid_instance) { +void tuh_hid_free_simple_joysticks_for_instance(uint8_t hid_instance) { for(uint8_t i = 0; i < HID_MAX_JOYSTICKS; ++i) { tusb_hid_simple_joysick_t* simple_joystick = &hid_simple_joysicks[i]; if (simple_joystick->hid_instance == hid_instance) simple_joystick->active = false; } } -// TODO Test tusb_hid_simple_joysick_t* tuh_hid_allocate_simple_joystick(uint8_t hid_instance, uint8_t report_id) { for(uint8_t i = 0; i < HID_MAX_JOYSTICKS; ++i) { tusb_hid_simple_joysick_t* simple_joystick = &hid_simple_joysicks[i]; @@ -154,10 +152,10 @@ void tuh_hid_joystick_process_usages( return; } - // update the report length in bytes + // Update the report length in bytes simple_joystick->report_length = (uint8_t)((bitpos + (jdata->report_size * jdata->report_count) + 7) >> 3); - // TODO Naive, assumes buttons are defined in a range + // Naive, assumes buttons are defined in a range if (jdata->usage_is_range) { if (jdata->usage_page == HID_USAGE_PAGE_BUTTON) { tusb_hid_simple_buttons_t* simple_buttons = &simple_joystick->buttons; @@ -199,7 +197,7 @@ uint8_t tuh_hid_joystick_parse_report_descriptor(uint8_t const* desc_report, uin tuh_hid_rip_state_t pstate; tuh_hid_rip_init_state(&pstate, desc_report, desc_len); const uint8_t *ri; - uint32_t bitpos = 0; // TODO Think about if this could be uint8_t or uint16_t + uint32_t bitpos = 0; while((ri = tuh_hid_rip_next_short_item(&pstate)) != NULL) { uint8_t const type_and_tag = tuh_hid_ri_short_type_and_tag(ri); @@ -255,7 +253,9 @@ void tusb_hid_simple_joysick_process_report(tusb_hid_simple_joysick_t* simple_jo void tusb_hid_print_simple_joysick_report(tusb_hid_simple_joysick_t* simple_joystick) { if (simple_joystick->has_values) { - printf("x1=%4ld, y1=%4ld, x2=%4ld, y2=%4ld, hat=%01X, buttons=%04X\n", + printf("hid=%3ld, report_id=%3ld, x1=%4ld, y1=%4ld, x2=%4ld, y2=%4ld, hat=%01X, buttons=%04X\n", + simple_joystick->hid_instance, + simple_joystick->report_id, simple_joystick->values.x1, simple_joystick->values.y1, simple_joystick->values.x2, diff --git a/examples/host/cdc_msc_hid/src/hid_joy.h b/examples/host/cdc_msc_hid/src/hid_host_joy.h similarity index 81% rename from examples/host/cdc_msc_hid/src/hid_joy.h rename to examples/host/cdc_msc_hid/src/hid_host_joy.h index 5b1a1c82be..5fa3638d77 100644 --- a/examples/host/cdc_msc_hid/src/hid_joy.h +++ b/examples/host/cdc_msc_hid/src/hid_host_joy.h @@ -31,7 +31,7 @@ extern "C" { #endif -#define HID_MAX_JOYSTICKS 2 +#define HID_MAX_JOYSTICKS 4 typedef union TU_ATTR_PACKED { @@ -79,6 +79,7 @@ typedef struct { uint32_t buttons; } tusb_hid_simple_joysick_values_t; +// Simple joystick definitions and values typedef struct { uint8_t hid_instance; uint8_t report_id; @@ -94,6 +95,7 @@ typedef struct { tusb_hid_simple_joysick_values_t values; } tusb_hid_simple_joysick_t; +// Intermediate data structure used while parsing joystick HID report descriptors typedef struct { uint32_t report_size; uint32_t report_count; @@ -118,6 +120,8 @@ bool tuh_hid_joystick_get_data( tuh_hid_joystick_data_t* jdata // Data structure to complete ); +// Process the HID descriptor usages +// These are handled when an 'input' item is encountered. void tuh_hid_joystick_process_usages( tuh_hid_rip_state_t *pstate, tuh_hid_joystick_data_t* jdata, @@ -125,14 +129,35 @@ void tuh_hid_joystick_process_usages( uint8_t hid_instance ); +// Parse a HID report description for a joystick uint8_t tuh_hid_joystick_parse_report_descriptor(uint8_t const* desc_report, uint16_t desc_len, uint8_t hid_instance); +// Fetch a previously allocated simple joystick tusb_hid_simple_joysick_t* tuh_hid_get_simple_joystick(uint8_t hid_instance, uint8_t report_id); -void tuh_hid_free_simple_joystick(uint8_t hid_instance); + +// Free a previously allocated simple joystick +void tuh_hid_free_simple_joysticks_for_instance(uint8_t hid_instance); + +// Free all previously allocated simple joysticks void tuh_hid_free_simple_joysticks(); + +// Allocate a new simple joystick tusb_hid_simple_joysick_t* tuh_hid_allocate_simple_joystick(uint8_t hid_instance, uint8_t report_id); + +// If it exists, return an exisiting simple joystick, else allocate a new one tusb_hid_simple_joysick_t* tuh_hid_obtain_simple_joystick(uint8_t hid_instance, uint8_t report_id); + +// Process a HID report +// The report pointer should be advanced beyond the report ID byte. +// The length should not include the report ID byte. +// The length should be in bytes. void tusb_hid_simple_joysick_process_report(tusb_hid_simple_joysick_t* simple_joystick, const uint8_t* report, uint8_t report_length); + +// Send an axis and button report to stdout +// +// e.g. +// hid= 0, report_id= 0, x1= 0, y1= 0, x2= 127, y2= 127, hat=F, buttons=0008 +// void tusb_hid_print_simple_joysick_report(tusb_hid_simple_joysick_t* simple_joystick); #endif diff --git a/examples/host/cdc_msc_hid/src/hid_host_utils.c b/examples/host/cdc_msc_hid/src/hid_host_utils.c new file mode 100644 index 0000000000..4e3ae247e7 --- /dev/null +++ b/examples/host/cdc_msc_hid/src/hid_host_utils.c @@ -0,0 +1,99 @@ +/* + * 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. + * + * Test me with: + * + * ceedling test:pattern[hid_host_utils] + */ + +#include "hid_host_utils.h" + +uint32_t tuh_hid_report_bits_u32(uint8_t const* report, uint16_t start, uint16_t length) +{ + const int16_t bit_offset_start = start & 7; + const int16_t l = length + bit_offset_start; + const uint8_t *p = report + (start >> 3); + uint32_t acc = ((uint32_t)*p++) >> bit_offset_start; + for(uint16_t i = 1; (i << 3) < l; ++i) { + acc |= ((uint32_t)*p++) << ((i << 3) - bit_offset_start); + } + const uint32_t m = (((uint32_t)1) << length) - 1; + return acc & m; +} + +int32_t tuh_hid_report_bits_i32(uint8_t const* report, uint16_t start, uint16_t length) +{ + const int16_t bit_offset_start = start & 7; + const int16_t l = length + bit_offset_start; + const uint8_t *p = report + (start >> 3); + uint32_t acc = ((uint32_t)*p++) >> bit_offset_start; + for(uint16_t i = 1; (i << 3) < l; ++i) { + acc |= ((uint32_t)*p++) << ((i << 3) - bit_offset_start); + } + const uint32_t lp0 = ((uint32_t)1) << (length - 1); + const uint32_t lp1 = lp0 << 1; + // Mask or sign extend + return acc & lp0 ? acc | -lp1 : acc & (lp1 - 1); +} + +// Helper to get some bytes from a HID report as an unsigned 32 bit number +uint32_t tuh_hid_report_bytes_u32(uint8_t const* report, uint16_t start, uint16_t length) +{ + const uint8_t *p = report + start; + if (length == 1) return (uint32_t)*p; + uint32_t acc = 0; + for(uint16_t i = 0; i < length; ++i) { + acc |= ((uint32_t)*p++) << (i << 3); + } + return acc; +} + +// Helper to get some bytes from a HID report as a signed 32 bit number +int32_t tuh_hid_report_bytes_i32(uint8_t const* report, uint16_t start, uint16_t length) +{ + const uint8_t *p = report + start; + if (length == 1) return (int32_t)(int8_t)*p; + uint32_t acc = 0; + for(uint16_t i = 0; i < length; ++i) { + acc |= ((uint32_t)*p++) << (i << 3); + } + const uint32_t lp0 = ((uint32_t)1) << ((length << 3) - 1); + const uint32_t lp1 = lp0 << 1; + // sign extend + return acc & lp0 ? acc | -lp1 : acc; +} + +// Helper to get a value from a HID report +int32_t tuh_hid_report_i32(const uint8_t* report, uint16_t start, uint16_t length, bool is_signed) +{ + if (length == 0) return 0; + if ((start | length) & 7) { + return is_signed ? + tuh_hid_report_bits_i32(report, start, length): + (int32_t)tuh_hid_report_bits_u32(report, start, length); + } + else { + return is_signed ? + tuh_hid_report_bytes_i32(report, start >> 3, length >> 3): + (int32_t)tuh_hid_report_bytes_u32(report, start >> 3, length >> 3); + } +} + diff --git a/examples/host/cdc_msc_hid/src/hid_host_utils.h b/examples/host/cdc_msc_hid/src/hid_host_utils.h new file mode 100644 index 0000000000..7998e153cf --- /dev/null +++ b/examples/host/cdc_msc_hid/src/hid_host_utils.h @@ -0,0 +1,56 @@ +/* + * 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. + * + */ + +#ifndef _TUSB_HID_HOST_UTILS_H_ +#define _TUSB_HID_HOST_UTILS_H_ + +#include "tusb.h" +#include "class/hid/hid_rip.h" + +#ifdef __cplusplus + extern "C" { +#endif + +//--------------------------------------------------------------------+ +// Helpers for extracting values from a HID Report +//--------------------------------------------------------------------+ + +// Helper to get some bits from a HID report as an unsigned 32 bit number +uint32_t tuh_hid_report_bits_u32(uint8_t const* report, uint16_t start, uint16_t length); + +// Helper to get some bits from a HID report as a signed 32 bit number +int32_t tuh_hid_report_bits_i32(uint8_t const* report, uint16_t start, uint16_t length); + +// Helper to get some bytes from a HID report as an unsigned 32 bit number +uint32_t tuh_hid_report_bytes_u32(uint8_t const* report, uint16_t start, uint16_t length); + +// Helper to get some bytes from a HID report as a signed 32 bit number +int32_t tuh_hid_report_bytes_i32(uint8_t const* report, uint16_t start, uint16_t length); + +// Helper to get a value from a HID report +// Not suitable if the value can be > 2^31 +// Chooses between bytewise and bitwise fetches +int32_t tuh_hid_report_i32(const uint8_t* report, uint16_t start, uint16_t length, bool is_signed); + +#endif + diff --git a/src/class/hid/hid_rip.c b/src/class/hid/hid_rip.c index a7ad63a659..9dee49068a 100644 --- a/src/class/hid/hid_rip.c +++ b/src/class/hid/hid_rip.c @@ -199,77 +199,6 @@ uint32_t tuh_hid_rip_report_total_size_bits(tuh_hid_rip_state_t *state) } } -uint32_t tuh_hid_report_bits_u32(uint8_t const* report, uint16_t start, uint16_t length) -{ - const int16_t bit_offset_start = start & 7; - const int16_t l = length + bit_offset_start; - const uint8_t *p = report + (start >> 3); - uint32_t acc = ((uint32_t)*p++) >> bit_offset_start; - for(uint16_t i = 1; (i << 3) < l; ++i) { - acc |= ((uint32_t)*p++) << ((i << 3) - bit_offset_start); - } - const uint32_t m = (((uint32_t)1) << length) - 1; - return acc & m; -} - -int32_t tuh_hid_report_bits_i32(uint8_t const* report, uint16_t start, uint16_t length) -{ - const int16_t bit_offset_start = start & 7; - const int16_t l = length + bit_offset_start; - const uint8_t *p = report + (start >> 3); - uint32_t acc = ((uint32_t)*p++) >> bit_offset_start; - for(uint16_t i = 1; (i << 3) < l; ++i) { - acc |= ((uint32_t)*p++) << ((i << 3) - bit_offset_start); - } - const uint32_t lp0 = ((uint32_t)1) << (length - 1); - const uint32_t lp1 = lp0 << 1; - // Mask or sign extend - return acc & lp0 ? acc | -lp1 : acc & (lp1 - 1); -} - -// Helper to get some bytes from a HID report as an unsigned 32 bit number -uint32_t tuh_hid_report_bytes_u32(uint8_t const* report, uint16_t start, uint16_t length) -{ - const uint8_t *p = report + start; - if (length == 1) return (uint32_t)*p; - uint32_t acc = 0; - for(uint16_t i = 0; i < length; ++i) { - acc |= ((uint32_t)*p++) << (i << 3); - } - return acc; -} - -// Helper to get some bytes from a HID report as a signed 32 bit number -int32_t tuh_hid_report_bytes_i32(uint8_t const* report, uint16_t start, uint16_t length) -{ - const uint8_t *p = report + start; - if (length == 1) return (int32_t)(int8_t)*p; - uint32_t acc = 0; - for(uint16_t i = 0; i < length; ++i) { - acc |= ((uint32_t)*p++) << (i << 3); - } - const uint32_t lp0 = ((uint32_t)1) << ((length << 3) - 1); - const uint32_t lp1 = lp0 << 1; - // sign extend - return acc & lp0 ? acc | -lp1 : acc; -} - -// Helper to get a value from a HID report -int32_t tuh_hid_report_i32(const uint8_t* report, uint16_t start, uint16_t length, bool is_signed) -{ - if (length == 0) return 0; - if ((start | length) & 7) { - return is_signed ? - tuh_hid_report_bits_i32(report, start, length): - (int32_t)tuh_hid_report_bits_u32(report, start, length); - } - else { - return is_signed ? - tuh_hid_report_bytes_i32(report, start >> 3, length >> 3): - (int32_t)tuh_hid_report_bytes_u32(report, start >> 3, length >> 3); - } -} - //--------------------------------------------------------------------+ // Report Descriptor Parser //--------------------------------------------------------------------+ diff --git a/src/class/hid/hid_rip.h b/src/class/hid/hid_rip.h index 0e7ad898ba..4009004037 100644 --- a/src/class/hid/hid_rip.h +++ b/src/class/hid/hid_rip.h @@ -148,25 +148,5 @@ uint32_t tuh_hid_rip_report_total_size_bits(tuh_hid_rip_state_t *state); //--------------------------------------------------------------------+ uint8_t tuh_hid_parse_report_descriptor(tuh_hid_report_info_t* reports_info_arr, uint8_t arr_count, uint8_t const* desc_report, uint16_t desc_len) TU_ATTR_UNUSED; -//--------------------------------------------------------------------+ -// Helpers for extracting values from a HID Report -//--------------------------------------------------------------------+ - -// Helper to get some bits from a HID report as an unsigned 32 bit number -uint32_t tuh_hid_report_bits_u32(uint8_t const* report, uint16_t start, uint16_t length); - -// Helper to get some bits from a HID report as a signed 32 bit number -int32_t tuh_hid_report_bits_i32(uint8_t const* report, uint16_t start, uint16_t length); - -// Helper to get some bytes from a HID report as an unsigned 32 bit number -uint32_t tuh_hid_report_bytes_u32(uint8_t const* report, uint16_t start, uint16_t length); - -// Helper to get some bytes from a HID report as a signed 32 bit number -int32_t tuh_hid_report_bytes_i32(uint8_t const* report, uint16_t start, uint16_t length); - -// Helper to get a value from a HID report -// Not suitable if the value can be > 2^31 -int32_t tuh_hid_report_i32(const uint8_t* report, uint16_t start, uint16_t length, bool is_signed); - #endif diff --git a/test/test/class/hid/test_hid_rip.c b/test/test/class/hid/test_hid_rip.c index 0c22b0ae48..9a186d3c60 100644 --- a/test/test/class/hid/test_hid_rip.c +++ b/test/test/class/hid/test_hid_rip.c @@ -585,56 +585,3 @@ void test_hid_parse_speedlink_report() { uint8_t report_count = tuh_hid_parse_report_descriptor(report_info, 3, (const uint8_t*)&tb, sizeof(tb)); TEST_ASSERT_EQUAL(1, report_count); } - -void test_tuh_hid_report_bits_u32() { - const uint8_t const tb[] = { - 0x50, 0x05, 0x8f, 0xff - }; - TEST_ASSERT_EQUAL(0x55, tuh_hid_report_bits_u32(tb, 4, 8)); - TEST_ASSERT_EQUAL(0x8f, tuh_hid_report_bits_u32(tb, 16, 8)); - TEST_ASSERT_EQUAL(0xff8f0550, tuh_hid_report_bits_u32(tb, 0, 32)); -} - -void test_tuh_hid_report_bits_i32() { - const uint8_t const tb[] = { - 0x50, 0x05, 0x8f, 0xff - }; - TEST_ASSERT_EQUAL(0x55, tuh_hid_report_bits_i32(tb, 4, 8)); - TEST_ASSERT_EQUAL(0xffffff8f, tuh_hid_report_bits_i32(tb, 16, 8)); - TEST_ASSERT_EQUAL(0xff8f0550, tuh_hid_report_bits_i32(tb, 0, 32)); -} - -void test_tuh_hid_report_bytes_u32() { - const uint8_t const tb[] = { - 0x50, 0x05, 0x8f, 0xff - }; - TEST_ASSERT_EQUAL(0x0550, tuh_hid_report_bytes_u32(tb, 0, 2)); - TEST_ASSERT_EQUAL(0x8f05, tuh_hid_report_bytes_u32(tb, 1, 2)); - TEST_ASSERT_EQUAL(0xff8f05, tuh_hid_report_bytes_u32(tb, 1, 3)); - TEST_ASSERT_EQUAL(0xff8f0550, tuh_hid_report_bytes_u32(tb, 0, 4)); - TEST_ASSERT_EQUAL(0x8f, tuh_hid_report_bytes_u32(tb, 2, 1)); -} - -void test_tuh_hid_report_bytes_i32() { - const uint8_t const tb[] = { - 0x50, 0x05, 0x8f, 0xff - }; - TEST_ASSERT_EQUAL(0x0550, tuh_hid_report_bytes_i32(tb, 0, 2)); - TEST_ASSERT_EQUAL(0xffff8f05, tuh_hid_report_bytes_i32(tb, 1, 2)); - TEST_ASSERT_EQUAL(0xffff8f05, tuh_hid_report_bytes_i32(tb, 1, 3)); - TEST_ASSERT_EQUAL(0xff8f0550, tuh_hid_report_bytes_i32(tb, 0, 4)); - TEST_ASSERT_EQUAL(0xffffff8f, tuh_hid_report_bytes_i32(tb, 2, 1)); -} - -void test_tuh_hid_report_i32() { - const uint8_t const tb[] = { - 0x50, 0x05, 0x8f, 0xff - }; - TEST_ASSERT_EQUAL(0x55, tuh_hid_report_i32(tb, 4, 8, false)); - TEST_ASSERT_EQUAL(0x8f, tuh_hid_report_i32(tb, 16, 8, false)); - TEST_ASSERT_EQUAL(0xff8f0550, tuh_hid_report_i32(tb, 0, 32, false)); - - TEST_ASSERT_EQUAL(0x55, tuh_hid_report_i32(tb, 4, 8, true)); - TEST_ASSERT_EQUAL(0xffffff8f, tuh_hid_report_i32(tb, 16, 8, true)); - TEST_ASSERT_EQUAL(0xff8f0550, tuh_hid_report_i32(tb, 0, 32, true)); -} diff --git a/test/test/examples/host/cdc_msc_hid/test_hid_joy.c b/test/test/examples/host/cdc_msc_hid/test_hid_host_joy.c similarity index 91% rename from test/test/examples/host/cdc_msc_hid/test_hid_joy.c rename to test/test/examples/host/cdc_msc_hid/test_hid_host_joy.c index b07f84ed13..e98fdf50ef 100644 --- a/test/test/examples/host/cdc_msc_hid/test_hid_joy.c +++ b/test/test/examples/host/cdc_msc_hid/test_hid_host_joy.c @@ -27,10 +27,11 @@ // Files to test #include "hid_rip.h" -#include "hid_joy.h" +#include "hid_host_joy.h" TEST_FILE("hid_ri.c") TEST_FILE("hid_rip.c") -TEST_FILE("hid_joy.c") +TEST_FILE("hid_host_utils.c") +TEST_FILE("hid_host_joy.c") static const uint8_t const tb_greenasia[] = { 0x05, 0x01, // Usage Page (Generic Desktop Ctrls) @@ -205,12 +206,52 @@ void tearDown(void) //--------------------------------------------------------------------+ // Tests //--------------------------------------------------------------------+ -void test_nothing() { - const uint8_t const tb[] = { - 0x05, 0x01, // Usage Page (Generic Desktop Ctrls) - 0x09, 0x04, // Usage (Joystick) - }; - TEST_ASSERT_EQUAL(0, tuh_hid_joystick_parse_report_descriptor(tb, sizeof(tb), 1)); + +// TODO +void test_simple_joystick_allocator() { + TEST_ASSERT_NULL(tuh_hid_get_simple_joystick(1, 2)); + TEST_ASSERT_NULL(tuh_hid_get_simple_joystick(1, 3)); + TEST_ASSERT_NULL(tuh_hid_get_simple_joystick(2, 3)); + TEST_ASSERT_NULL(tuh_hid_get_simple_joystick(2, 2)); + TEST_ASSERT_NOT_NULL(tuh_hid_allocate_simple_joystick(1, 2)); + TEST_ASSERT_NOT_NULL(tuh_hid_allocate_simple_joystick(1, 3)); + TEST_ASSERT_NOT_NULL(tuh_hid_allocate_simple_joystick(2, 3)); + TEST_ASSERT_NOT_NULL(tuh_hid_allocate_simple_joystick(2, 2)); + TEST_ASSERT_NOT_NULL(tuh_hid_get_simple_joystick(1, 2)); + TEST_ASSERT_NOT_NULL(tuh_hid_get_simple_joystick(1, 3)); + TEST_ASSERT_NOT_NULL(tuh_hid_get_simple_joystick(2, 3)); + TEST_ASSERT_NOT_NULL(tuh_hid_get_simple_joystick(2, 2)); + tuh_hid_free_simple_joysticks_for_instance(1); + TEST_ASSERT_NULL(tuh_hid_get_simple_joystick(1, 2)); + TEST_ASSERT_NULL(tuh_hid_get_simple_joystick(1, 3)); + tuh_hid_free_simple_joysticks_for_instance(1); + TEST_ASSERT_NULL(tuh_hid_get_simple_joystick(1, 2)); + TEST_ASSERT_NULL(tuh_hid_get_simple_joystick(1, 3)); +} + +void test_simple_joystick_allocate_too_many() { + for (int i =0; i < HID_MAX_JOYSTICKS; ++i) { + TEST_ASSERT_NOT_NULL(tuh_hid_allocate_simple_joystick(1, i + 1)); + } + TEST_ASSERT_NULL(tuh_hid_allocate_simple_joystick(2, 1)); +} + +void test_simple_joystick_free_all() { + TEST_ASSERT_NOT_NULL(tuh_hid_allocate_simple_joystick(1, 3)); + TEST_ASSERT_NOT_NULL(tuh_hid_allocate_simple_joystick(2, 3)); + tuh_hid_free_simple_joysticks(); + TEST_ASSERT_NULL(tuh_hid_get_simple_joystick(1, 3)); + TEST_ASSERT_NULL(tuh_hid_get_simple_joystick(2, 3)); +} + +void test_simple_joystick_obtain() { + tusb_hid_simple_joysick_t* j1 = tuh_hid_allocate_simple_joystick(1, 3); + TEST_ASSERT_NOT_NULL(j1); + TEST_ASSERT_EQUAL(j1, tuh_hid_obtain_simple_joystick(1, 3)); + TEST_ASSERT_NULL(tuh_hid_get_simple_joystick(2, 3)); + tusb_hid_simple_joysick_t* j2 = tuh_hid_allocate_simple_joystick(2, 3); + TEST_ASSERT_NOT_NULL(j2); + TEST_ASSERT_NOT_EQUAL(j1,j2); } void test_tuh_hid_joystick_get_data() { diff --git a/test/test/examples/host/cdc_msc_hid/test_hid_host_utils.c b/test/test/examples/host/cdc_msc_hid/test_hid_host_utils.c new file mode 100644 index 0000000000..ddc8db7c59 --- /dev/null +++ b/test/test/examples/host/cdc_msc_hid/test_hid_host_utils.c @@ -0,0 +1,100 @@ +/* + * 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. + * + * This file is part of the TinyUSB stack. + */ + + +#include "unity.h" + +// Files to test +#include "hid_host_utils.h" +TEST_FILE("hid_host_utils.c") + +void setUp(void) +{ +} + +void tearDown(void) +{ +} + +//--------------------------------------------------------------------+ +// Tests +//--------------------------------------------------------------------+ + +void test_tuh_hid_report_bits_u32() { + const uint8_t const tb[] = { + 0x50, 0x05, 0x8f, 0xff + }; + TEST_ASSERT_EQUAL(0x55, tuh_hid_report_bits_u32(tb, 4, 8)); + TEST_ASSERT_EQUAL(0x8f, tuh_hid_report_bits_u32(tb, 16, 8)); + TEST_ASSERT_EQUAL(0xff8f0550, tuh_hid_report_bits_u32(tb, 0, 32)); +} + +void test_tuh_hid_report_bits_i32() { + const uint8_t const tb[] = { + 0x50, 0x05, 0x8f, 0xff + }; + TEST_ASSERT_EQUAL(0x55, tuh_hid_report_bits_i32(tb, 4, 8)); + TEST_ASSERT_EQUAL(0xffffff8f, tuh_hid_report_bits_i32(tb, 16, 8)); + TEST_ASSERT_EQUAL(0xff8f0550, tuh_hid_report_bits_i32(tb, 0, 32)); +} + +void test_tuh_hid_report_bytes_u32() { + const uint8_t const tb[] = { + 0x50, 0x05, 0x8f, 0xff + }; + TEST_ASSERT_EQUAL(0x0550, tuh_hid_report_bytes_u32(tb, 0, 2)); + TEST_ASSERT_EQUAL(0x8f05, tuh_hid_report_bytes_u32(tb, 1, 2)); + TEST_ASSERT_EQUAL(0xff8f05, tuh_hid_report_bytes_u32(tb, 1, 3)); + TEST_ASSERT_EQUAL(0xff8f0550, tuh_hid_report_bytes_u32(tb, 0, 4)); + TEST_ASSERT_EQUAL(0x8f, tuh_hid_report_bytes_u32(tb, 2, 1)); +} + +void test_tuh_hid_report_bytes_i32() { + const uint8_t const tb[] = { + 0x50, 0x05, 0x8f, 0xff + }; + TEST_ASSERT_EQUAL(0x0550, tuh_hid_report_bytes_i32(tb, 0, 2)); + TEST_ASSERT_EQUAL(0xffff8f05, tuh_hid_report_bytes_i32(tb, 1, 2)); + TEST_ASSERT_EQUAL(0xffff8f05, tuh_hid_report_bytes_i32(tb, 1, 3)); + TEST_ASSERT_EQUAL(0xff8f0550, tuh_hid_report_bytes_i32(tb, 0, 4)); + TEST_ASSERT_EQUAL(0xffffff8f, tuh_hid_report_bytes_i32(tb, 2, 1)); +} + +void test_tuh_hid_report_i32() { + const uint8_t const tb[] = { + 0x50, 0x05, 0x8f, 0xff + }; + TEST_ASSERT_EQUAL(0x55, tuh_hid_report_i32(tb, 4, 8, false)); + TEST_ASSERT_EQUAL(0x8f, tuh_hid_report_i32(tb, 16, 8, false)); + TEST_ASSERT_EQUAL(0xff8f0550, tuh_hid_report_i32(tb, 0, 32, false)); + + TEST_ASSERT_EQUAL(0x55, tuh_hid_report_i32(tb, 4, 8, true)); + TEST_ASSERT_EQUAL(0xffffff8f, tuh_hid_report_i32(tb, 16, 8, true)); + TEST_ASSERT_EQUAL(0xff8f0550, tuh_hid_report_i32(tb, 0, 32, true)); +} + + +// TODO Test multiple report IDs + + From 62fbea6e08101fbecb4a868e5f40fca1808ad2bd Mon Sep 17 00:00:00 2001 From: Phil Date: Wed, 16 Feb 2022 23:42:06 +0000 Subject: [PATCH 59/71] HID micro parser --- examples/host/cdc_msc_hid/CMakeLists.txt | 1 + examples/host/cdc_msc_hid/src/hid_app.c | 207 ++++++++++-------- examples/host/cdc_msc_hid/src/hid_host_joy.c | 64 +++--- examples/host/cdc_msc_hid/src/hid_host_joy.h | 29 ++- .../host/cdc_msc_hid/src/hid_host_parse.c | 94 ++++++++ .../host/cdc_msc_hid/src/hid_host_parse.h | 64 ++++++ .../host/cdc_msc_hid/test_hid_host_joy.c | 84 +++---- 7 files changed, 370 insertions(+), 173 deletions(-) create mode 100644 examples/host/cdc_msc_hid/src/hid_host_parse.c create mode 100644 examples/host/cdc_msc_hid/src/hid_host_parse.h diff --git a/examples/host/cdc_msc_hid/CMakeLists.txt b/examples/host/cdc_msc_hid/CMakeLists.txt index 8d7f04d9a1..490e387a67 100644 --- a/examples/host/cdc_msc_hid/CMakeLists.txt +++ b/examples/host/cdc_msc_hid/CMakeLists.txt @@ -16,6 +16,7 @@ add_executable(${PROJECT}) 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_parse.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 diff --git a/examples/host/cdc_msc_hid/src/hid_app.c b/examples/host/cdc_msc_hid/src/hid_app.c index 82332cea4e..3528ad8eff 100644 --- a/examples/host/cdc_msc_hid/src/hid_app.c +++ b/examples/host/cdc_msc_hid/src/hid_app.c @@ -26,6 +26,7 @@ #include "bsp/board.h" #include "tusb.h" #include "hid_host_joy.h" +#include "hid_host_parse.h" //--------------------------------------------------------------------+ // MACRO TYPEDEF CONSTANT ENUM DECLARATION @@ -39,13 +40,6 @@ static uint8_t const keycode2ascii[128][2] = { HID_KEYCODE_TO_ASCII }; -// Each HID instance can have 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); @@ -55,6 +49,40 @@ 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) +{ + 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) +{ + 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 "); + 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_gamepad_report(tusb_hid_host_info_t* info, const uint8_t* report, uint8_t report_length, uint8_t 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 //--------------------------------------------------------------------+ @@ -68,7 +96,7 @@ 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 Descrtipion \r\n"); + printf("HID Report Description \r\n"); for(int i = 0; i < desc_len; ++i) printf("%02X ", desc_report[i]); printf("\r\n"); @@ -82,10 +110,67 @@ 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); - tuh_hid_joystick_parse_report_descriptor(desc_report, desc_len, instance); + 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); + break; + } + case HID_USAGE_DESKTOP_JOYSTICK: { + printf("HID receive joystick report description\r\n"); + tuh_hid_allocate_info(dev_addr, instance, has_report_id, &handle_joystick_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; + + case HID_USAGE_DESKTOP_JOYSTICK: + TU_LOG1("HID receive joystick report "); + // for(int i = 0; i < len; ++i) { + // printf("%02x", report[i]); + // } + // printf("\r\n"); + + + break; + + case HID_USAGE_DESKTOP_GAMEPAD: + TU_LOG1("HID receive gamepad report "); + for(int i = 0; i < len; ++i) { + printf("%02x", report[i]); + } + printf("\r\n"); + break; +*/ + default: + TU_LOG1("HID usage unknown usage:%d\r\n", report->usage); + + break; + } + } + else { + + } + } + + tuh_hid_joystick_parse_report_descriptor(desc_report, desc_len, dev_addr, instance); } // request to receive report @@ -101,8 +186,11 @@ 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); + // Free up host info structure + tuh_hid_free_info(dev_addr, instance); + // Free up any joystick definitions - tuh_hid_free_simple_joysticks_for_instance(instance); + tuh_hid_free_simple_joysticks_for_instance(dev_addr, instance); } // Invoked when received report from device via interrupt endpoint @@ -243,94 +331,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; - uint8_t rpt_id = 0; + tusb_hid_host_info_t* info = tuh_hid_get_info(dev_addr, instance); - if ( rpt_count == 1 && rpt_info_arr[0].report_id == 0) + if (info == NULL) { - // Simple report without report ID as 1st byte - rpt_info = &rpt_info_arr[0]; - }else - { - // Composite report, 1st byte is report ID, data starts from 2nd byte - rpt_id = report[0]; - - // Find report id in the arrray - for(uint8_t i=0; iusage_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; - - case HID_USAGE_DESKTOP_JOYSTICK: - TU_LOG1("HID receive joystick report "); -// for(int i = 0; i < len; ++i) { -// printf("%02x", report[i]); -// } -// printf("\r\n"); - - tusb_hid_simple_joysick_t* simple_joystick = tuh_hid_get_simple_joystick(instance, rpt_id); - if (simple_joystick != NULL) { - tusb_hid_simple_joysick_process_report(simple_joystick, report, len); - tusb_hid_print_simple_joysick_report(simple_joystick); - } - break; - - case HID_USAGE_DESKTOP_GAMEPAD: - TU_LOG1("HID receive gamepad report "); - for(int i = 0; i < len; ++i) { - printf("%02x", report[i]); - } - printf("\r\n"); - break; - - default: - TU_LOG1("HID usage unknown usage:%d\r\n", rpt_info->usage); - - break; - } - } - else { - TU_LOG1("HID usage unknown page:%d, usage:%d\r\n", rpt_info->usage_page, rpt_info->usage); + if (info->has_report_id) { + rpt_id = report[0]; + report++; + len--; } + + info->handler(info, report, len, rpt_id); } diff --git a/examples/host/cdc_msc_hid/src/hid_host_joy.c b/examples/host/cdc_msc_hid/src/hid_host_joy.c index bf88ccc3fe..2c31a99789 100644 --- a/examples/host/cdc_msc_hid/src/hid_host_joy.c +++ b/examples/host/cdc_msc_hid/src/hid_host_joy.c @@ -39,36 +39,44 @@ static bool tuh_hid_joystick_check_usage(uint32_t eusage) } } -tusb_hid_simple_joysick_t* tuh_hid_get_simple_joystick(uint8_t hid_instance, uint8_t report_id) +tusb_hid_simple_joysick_t* tuh_hid_get_simple_joystick(uint8_t dev_addr, uint8_t instance, uint8_t report_id) { + tusb_hid_simple_joysick_key_t key; + key.elements.dev_addr = dev_addr; + key.elements.instance = instance; + key.elements.report_id = report_id; + key.elements.in_use = 1; + uint32_t combined = key.combined; + for(uint8_t i = 0; i < HID_MAX_JOYSTICKS; ++i) { tusb_hid_simple_joysick_t* simple_joystick = &hid_simple_joysicks[i]; - if (simple_joystick->active && simple_joystick->hid_instance == hid_instance && simple_joystick->report_id == report_id) return simple_joystick; + if (simple_joystick->key.combined == combined) return simple_joystick; } return NULL; } void tuh_hid_free_simple_joysticks() { for(uint8_t i = 0; i < HID_MAX_JOYSTICKS; ++i) { - hid_simple_joysicks[i].active = false; + hid_simple_joysicks[i].key.elements.in_use = false; } } -void tuh_hid_free_simple_joysticks_for_instance(uint8_t hid_instance) { +void tuh_hid_free_simple_joysticks_for_instance(uint8_t dev_addr, uint8_t instance) { for(uint8_t i = 0; i < HID_MAX_JOYSTICKS; ++i) { tusb_hid_simple_joysick_t* simple_joystick = &hid_simple_joysicks[i]; - if (simple_joystick->hid_instance == hid_instance) simple_joystick->active = false; + if (simple_joystick->key.elements.dev_addr == dev_addr && simple_joystick->key.elements.instance == instance) simple_joystick->key.elements.in_use = 0; } } -tusb_hid_simple_joysick_t* tuh_hid_allocate_simple_joystick(uint8_t hid_instance, uint8_t report_id) { +tusb_hid_simple_joysick_t* tuh_hid_allocate_simple_joystick(uint8_t dev_addr, uint8_t instance, uint8_t report_id) { for(uint8_t i = 0; i < HID_MAX_JOYSTICKS; ++i) { tusb_hid_simple_joysick_t* simple_joystick = &hid_simple_joysicks[i]; - if (!simple_joystick->active) { + if (!simple_joystick->key.elements.in_use) { tu_memclr(simple_joystick, sizeof(tusb_hid_simple_joysick_t)); - simple_joystick->active = true; - simple_joystick->hid_instance = hid_instance; - simple_joystick->report_id = report_id; + simple_joystick->key.elements.in_use = 1;; + simple_joystick->key.elements.instance = instance; + simple_joystick->key.elements.report_id = report_id; + simple_joystick->key.elements.dev_addr = dev_addr; return simple_joystick; } } @@ -76,9 +84,9 @@ tusb_hid_simple_joysick_t* tuh_hid_allocate_simple_joystick(uint8_t hid_instance } // get or create -tusb_hid_simple_joysick_t* tuh_hid_obtain_simple_joystick(uint8_t hid_instance, uint8_t report_id) { - tusb_hid_simple_joysick_t* jdata = tuh_hid_get_simple_joystick(hid_instance, report_id); - return jdata ? jdata : tuh_hid_allocate_simple_joystick(hid_instance, report_id); +tusb_hid_simple_joysick_t* tuh_hid_obtain_simple_joystick(uint8_t dev_addr, uint8_t instance, uint8_t report_id) { + tusb_hid_simple_joysick_t* jdata = tuh_hid_get_simple_joystick(dev_addr, instance, report_id); + return jdata ? jdata : tuh_hid_allocate_simple_joystick(dev_addr, instance, report_id); } // Fetch some data from the HID parser @@ -120,7 +128,7 @@ bool tuh_hid_joystick_get_data( static void tuh_hid_joystick_process_axis( tuh_hid_joystick_data_t* jdata, uint32_t bitpos, - uint8_t hid_instance, + uint8_t instance, tusb_hid_simple_axis_t* simple_axis) { simple_axis->start = bitpos; @@ -134,7 +142,8 @@ void tuh_hid_joystick_process_usages( tuh_hid_rip_state_t *pstate, tuh_hid_joystick_data_t* jdata, uint32_t bitpos, - uint8_t hid_instance) + uint8_t dev_addr, + uint8_t instance) { if (jdata->input_flags.data_const) return; @@ -145,10 +154,10 @@ void tuh_hid_joystick_process_usages( return; } - tusb_hid_simple_joysick_t* simple_joystick = tuh_hid_obtain_simple_joystick(hid_instance, jdata->report_id); + tusb_hid_simple_joysick_t* simple_joystick = tuh_hid_obtain_simple_joystick(dev_addr, instance, jdata->report_id); if (simple_joystick == NULL) { - printf("Failed to allocate joystick for HID instance %d, report ID %d\n", hid_instance, jdata->report_id); + printf("Failed to allocate joystick for HID dev_addr %d, instance %d, report ID %d\n", dev_addr, instance, jdata->report_id); return; } @@ -171,19 +180,19 @@ void tuh_hid_joystick_process_usages( // Seems to be common usage for gamepads. // Probably needs a lot more thought... case HID_RIP_EUSAGE(HID_USAGE_PAGE_DESKTOP, HID_USAGE_DESKTOP_X): - tuh_hid_joystick_process_axis(jdata, bitpos, hid_instance, &simple_joystick->axis_x1); + tuh_hid_joystick_process_axis(jdata, bitpos, instance, &simple_joystick->axis_x1); break; case HID_RIP_EUSAGE(HID_USAGE_PAGE_DESKTOP, HID_USAGE_DESKTOP_Y): - tuh_hid_joystick_process_axis(jdata, bitpos, hid_instance, &simple_joystick->axis_y1); + tuh_hid_joystick_process_axis(jdata, bitpos, instance, &simple_joystick->axis_y1); break; case HID_RIP_EUSAGE(HID_USAGE_PAGE_DESKTOP, HID_USAGE_DESKTOP_Z): - tuh_hid_joystick_process_axis(jdata, bitpos, hid_instance, &simple_joystick->axis_x2); + tuh_hid_joystick_process_axis(jdata, bitpos, instance, &simple_joystick->axis_x2); break; case HID_RIP_EUSAGE(HID_USAGE_PAGE_DESKTOP, HID_USAGE_DESKTOP_RZ): - tuh_hid_joystick_process_axis(jdata, bitpos, hid_instance, &simple_joystick->axis_y2); + tuh_hid_joystick_process_axis(jdata, bitpos, instance, &simple_joystick->axis_y2); break; case HID_RIP_EUSAGE(HID_USAGE_PAGE_DESKTOP, HID_USAGE_DESKTOP_HAT_SWITCH): - tuh_hid_joystick_process_axis(jdata, bitpos, hid_instance, &simple_joystick->hat); + tuh_hid_joystick_process_axis(jdata, bitpos, instance, &simple_joystick->hat); break; default: break; } @@ -191,7 +200,7 @@ void tuh_hid_joystick_process_usages( } } -uint8_t tuh_hid_joystick_parse_report_descriptor(uint8_t const* desc_report, uint16_t desc_len, uint8_t hid_instance) +uint8_t tuh_hid_joystick_parse_report_descriptor(uint8_t const* desc_report, uint16_t desc_len, uint8_t dev_addr, uint8_t instance) { uint32_t eusage = 0; tuh_hid_rip_state_t pstate; @@ -208,7 +217,7 @@ uint8_t tuh_hid_joystick_parse_report_descriptor(uint8_t const* desc_report, uin if (tuh_hid_joystick_check_usage(eusage)) { tuh_hid_joystick_data_t joystick_data; if(tuh_hid_joystick_get_data(&pstate, ri, &joystick_data)) { - tuh_hid_joystick_process_usages(&pstate, &joystick_data, bitpos, hid_instance); + tuh_hid_joystick_process_usages(&pstate, &joystick_data, bitpos, dev_addr, instance); bitpos += joystick_data.report_size * joystick_data.report_count; } } @@ -253,9 +262,10 @@ void tusb_hid_simple_joysick_process_report(tusb_hid_simple_joysick_t* simple_jo void tusb_hid_print_simple_joysick_report(tusb_hid_simple_joysick_t* simple_joystick) { if (simple_joystick->has_values) { - printf("hid=%3ld, report_id=%3ld, x1=%4ld, y1=%4ld, x2=%4ld, y2=%4ld, hat=%01X, buttons=%04X\n", - simple_joystick->hid_instance, - simple_joystick->report_id, + printf("dev_addr=%3d, instance=%3d, report_id=%3d, x1=%4ld, y1=%4ld, x2=%4ld, y2=%4ld, hat=%01X, buttons=%04X\n", + simple_joystick->key.elements.dev_addr, + simple_joystick->key.elements.instance, + simple_joystick->key.elements.report_id, simple_joystick->values.x1, simple_joystick->values.y1, simple_joystick->values.x2, diff --git a/examples/host/cdc_msc_hid/src/hid_host_joy.h b/examples/host/cdc_msc_hid/src/hid_host_joy.h index 5fa3638d77..0b63a78eab 100644 --- a/examples/host/cdc_msc_hid/src/hid_host_joy.h +++ b/examples/host/cdc_msc_hid/src/hid_host_joy.h @@ -79,12 +79,22 @@ typedef struct { uint32_t buttons; } tusb_hid_simple_joysick_values_t; +typedef union TU_ATTR_PACKED +{ + uint32_t combined; + struct TU_ATTR_PACKED + { + uint8_t instance :8; + uint8_t dev_addr :8; + uint8_t report_id :8; + uint8_t in_use :8; + } elements; +} tusb_hid_simple_joysick_key_t; + // Simple joystick definitions and values typedef struct { - uint8_t hid_instance; - uint8_t report_id; + tusb_hid_simple_joysick_key_t key; uint8_t report_length; // requied report length in bytes - bool active; bool has_values; tusb_hid_simple_axis_t axis_x1; tusb_hid_simple_axis_t axis_y1; @@ -126,26 +136,27 @@ void tuh_hid_joystick_process_usages( tuh_hid_rip_state_t *pstate, tuh_hid_joystick_data_t* jdata, uint32_t bitpos, - uint8_t hid_instance + uint8_t dev_addr, + uint8_t instance ); // Parse a HID report description for a joystick -uint8_t tuh_hid_joystick_parse_report_descriptor(uint8_t const* desc_report, uint16_t desc_len, uint8_t hid_instance); +uint8_t tuh_hid_joystick_parse_report_descriptor(uint8_t const* desc_report, uint16_t desc_len, uint8_t dev_addr, uint8_t instance); // Fetch a previously allocated simple joystick -tusb_hid_simple_joysick_t* tuh_hid_get_simple_joystick(uint8_t hid_instance, uint8_t report_id); +tusb_hid_simple_joysick_t* tuh_hid_get_simple_joystick(uint8_t dev_addr, uint8_t instance, uint8_t report_id); // Free a previously allocated simple joystick -void tuh_hid_free_simple_joysticks_for_instance(uint8_t hid_instance); +void tuh_hid_free_simple_joysticks_for_instance(uint8_t dev_addr, uint8_t instance); // Free all previously allocated simple joysticks void tuh_hid_free_simple_joysticks(); // Allocate a new simple joystick -tusb_hid_simple_joysick_t* tuh_hid_allocate_simple_joystick(uint8_t hid_instance, uint8_t report_id); +tusb_hid_simple_joysick_t* tuh_hid_allocate_simple_joystick(uint8_t dev_addr, uint8_t instance, uint8_t report_id); // If it exists, return an exisiting simple joystick, else allocate a new one -tusb_hid_simple_joysick_t* tuh_hid_obtain_simple_joystick(uint8_t hid_instance, uint8_t report_id); +tusb_hid_simple_joysick_t* tuh_hid_obtain_simple_joystick(uint8_t dev_addr, uint8_t instance, uint8_t report_id); // Process a HID report // The report pointer should be advanced beyond the report ID byte. diff --git a/examples/host/cdc_msc_hid/src/hid_host_parse.c b/examples/host/cdc_msc_hid/src/hid_host_parse.c new file mode 100644 index 0000000000..130f6d0bf7 --- /dev/null +++ b/examples/host/cdc_msc_hid/src/hid_host_parse.c @@ -0,0 +1,94 @@ +/* + * 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. + * + * Test me with: + * + * ceedling test:pattern[hid_host_joy] + */ + +#include "hid_host_parse.h" +#include "hid_host_utils.h" + +static tusb_hid_host_info_t hid_info[HID_HOST_MAX_SIMPLE_DEVICES]; + +tusb_hid_host_info_t* tuh_hid_get_info(uint8_t dev_addr, uint8_t instance) +{ + tusb_hid_host_info_key_t key; + key.combined = 0; + key.elements.dev_addr = dev_addr; + key.elements.instance = instance; + key.elements.in_use = 1; + uint32_t combined = key.combined; + + for(uint8_t i = 0; i < HID_HOST_MAX_SIMPLE_DEVICES; ++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) +{ + info->key.elements.in_use = 0; + // May also want to call some unmount function + // ... +} + +void tuh_hid_free_all_info() +{ + for(uint8_t i = 0; i < HID_HOST_MAX_SIMPLE_DEVICES; ++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 < HID_HOST_MAX_SIMPLE_DEVICES; ++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)) +{ + for(uint8_t i = 0; i < HID_HOST_MAX_SIMPLE_DEVICES; ++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; + return info; + } + } + printf("FAILED TO ALLOCATE INFO\n"); + return NULL; +} + + diff --git a/examples/host/cdc_msc_hid/src/hid_host_parse.h b/examples/host/cdc_msc_hid/src/hid_host_parse.h new file mode 100644 index 0000000000..ee3fad0863 --- /dev/null +++ b/examples/host/cdc_msc_hid/src/hid_host_parse.h @@ -0,0 +1,64 @@ +/* + * 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. + * + */ + +#ifndef _TUSB_HID_HOST_PARSE_H_ +#define _TUSB_HID_HOST_PARSE_H_ + +#include "tusb.h" + +#ifdef __cplusplus + extern "C" { +#endif + +// Perhaps this should be derived from other config +#define HID_HOST_MAX_SIMPLE_DEVICES 8 + +typedef union TU_ATTR_PACKED +{ + uint32_t combined; + struct TU_ATTR_PACKED + { + uint8_t instance :8; + uint8_t dev_addr :8; + uint8_t in_use :8; + } elements; +} tusb_hid_host_info_key_t; + +typedef struct tusb_hid_host_info { + tusb_hid_host_info_key_t key; + bool has_report_id; + void (*handler)(struct tusb_hid_host_info* info, const uint8_t* report, uint8_t report_length, uint8_t report_id); +} tusb_hid_host_info_t; + +tusb_hid_host_info_t* tuh_hid_get_info(uint8_t dev_addr, uint8_t instance); + +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 tuh_hid_free_info(uint8_t dev_addr, uint8_t instance); + +#endif + diff --git a/test/test/examples/host/cdc_msc_hid/test_hid_host_joy.c b/test/test/examples/host/cdc_msc_hid/test_hid_host_joy.c index e98fdf50ef..4a159a7ae6 100644 --- a/test/test/examples/host/cdc_msc_hid/test_hid_host_joy.c +++ b/test/test/examples/host/cdc_msc_hid/test_hid_host_joy.c @@ -207,49 +207,50 @@ void tearDown(void) // Tests //--------------------------------------------------------------------+ -// TODO void test_simple_joystick_allocator() { - TEST_ASSERT_NULL(tuh_hid_get_simple_joystick(1, 2)); - TEST_ASSERT_NULL(tuh_hid_get_simple_joystick(1, 3)); - TEST_ASSERT_NULL(tuh_hid_get_simple_joystick(2, 3)); - TEST_ASSERT_NULL(tuh_hid_get_simple_joystick(2, 2)); - TEST_ASSERT_NOT_NULL(tuh_hid_allocate_simple_joystick(1, 2)); - TEST_ASSERT_NOT_NULL(tuh_hid_allocate_simple_joystick(1, 3)); - TEST_ASSERT_NOT_NULL(tuh_hid_allocate_simple_joystick(2, 3)); - TEST_ASSERT_NOT_NULL(tuh_hid_allocate_simple_joystick(2, 2)); - TEST_ASSERT_NOT_NULL(tuh_hid_get_simple_joystick(1, 2)); - TEST_ASSERT_NOT_NULL(tuh_hid_get_simple_joystick(1, 3)); - TEST_ASSERT_NOT_NULL(tuh_hid_get_simple_joystick(2, 3)); - TEST_ASSERT_NOT_NULL(tuh_hid_get_simple_joystick(2, 2)); - tuh_hid_free_simple_joysticks_for_instance(1); - TEST_ASSERT_NULL(tuh_hid_get_simple_joystick(1, 2)); - TEST_ASSERT_NULL(tuh_hid_get_simple_joystick(1, 3)); - tuh_hid_free_simple_joysticks_for_instance(1); - TEST_ASSERT_NULL(tuh_hid_get_simple_joystick(1, 2)); - TEST_ASSERT_NULL(tuh_hid_get_simple_joystick(1, 3)); + TEST_ASSERT_NULL(tuh_hid_get_simple_joystick(5, 1, 2)); + TEST_ASSERT_NULL(tuh_hid_get_simple_joystick(5, 1, 3)); + TEST_ASSERT_NULL(tuh_hid_get_simple_joystick(4, 2, 3)); + TEST_ASSERT_NULL(tuh_hid_get_simple_joystick(4, 5, 2)); + TEST_ASSERT_NOT_NULL(tuh_hid_allocate_simple_joystick(5, 1, 2)); + TEST_ASSERT_NOT_NULL(tuh_hid_allocate_simple_joystick(5, 1, 3)); + TEST_ASSERT_NOT_NULL(tuh_hid_allocate_simple_joystick(4, 2, 3)); + TEST_ASSERT_NOT_NULL(tuh_hid_allocate_simple_joystick(4, 5, 2)); + TEST_ASSERT_NOT_NULL(tuh_hid_get_simple_joystick(5, 1, 2)); + TEST_ASSERT_NOT_NULL(tuh_hid_get_simple_joystick(5, 1, 3)); + TEST_ASSERT_NOT_NULL(tuh_hid_get_simple_joystick(4, 2, 3)); + TEST_ASSERT_NOT_NULL(tuh_hid_get_simple_joystick(4, 5, 2)); + tuh_hid_free_simple_joysticks_for_instance(5, 1); + TEST_ASSERT_NULL(tuh_hid_get_simple_joystick(5, 1, 2)); + TEST_ASSERT_NULL(tuh_hid_get_simple_joystick(5, 1, 3)); + TEST_ASSERT_NOT_NULL(tuh_hid_get_simple_joystick(4, 2, 3)); + TEST_ASSERT_NOT_NULL(tuh_hid_get_simple_joystick(4, 5, 2)); + tuh_hid_free_simple_joysticks_for_instance(4, 5); + TEST_ASSERT_NULL(tuh_hid_get_simple_joystick(4, 5, 2)); + TEST_ASSERT_NOT_NULL(tuh_hid_get_simple_joystick(4, 2, 3)); } void test_simple_joystick_allocate_too_many() { for (int i =0; i < HID_MAX_JOYSTICKS; ++i) { - TEST_ASSERT_NOT_NULL(tuh_hid_allocate_simple_joystick(1, i + 1)); + TEST_ASSERT_NOT_NULL(tuh_hid_allocate_simple_joystick(1, i + 1, 4)); } - TEST_ASSERT_NULL(tuh_hid_allocate_simple_joystick(2, 1)); + TEST_ASSERT_NULL(tuh_hid_allocate_simple_joystick(2, 1, 0)); } void test_simple_joystick_free_all() { - TEST_ASSERT_NOT_NULL(tuh_hid_allocate_simple_joystick(1, 3)); - TEST_ASSERT_NOT_NULL(tuh_hid_allocate_simple_joystick(2, 3)); + TEST_ASSERT_NOT_NULL(tuh_hid_allocate_simple_joystick(7, 1, 3)); + TEST_ASSERT_NOT_NULL(tuh_hid_allocate_simple_joystick(0, 2, 3)); tuh_hid_free_simple_joysticks(); - TEST_ASSERT_NULL(tuh_hid_get_simple_joystick(1, 3)); - TEST_ASSERT_NULL(tuh_hid_get_simple_joystick(2, 3)); + TEST_ASSERT_NULL(tuh_hid_get_simple_joystick(7, 1, 3)); + TEST_ASSERT_NULL(tuh_hid_get_simple_joystick(0, 2, 3)); } void test_simple_joystick_obtain() { - tusb_hid_simple_joysick_t* j1 = tuh_hid_allocate_simple_joystick(1, 3); + tusb_hid_simple_joysick_t* j1 = tuh_hid_allocate_simple_joystick(7, 1, 3); TEST_ASSERT_NOT_NULL(j1); - TEST_ASSERT_EQUAL(j1, tuh_hid_obtain_simple_joystick(1, 3)); - TEST_ASSERT_NULL(tuh_hid_get_simple_joystick(2, 3)); - tusb_hid_simple_joysick_t* j2 = tuh_hid_allocate_simple_joystick(2, 3); + TEST_ASSERT_EQUAL(j1, tuh_hid_obtain_simple_joystick(7, 1, 3)); + TEST_ASSERT_NULL(tuh_hid_get_simple_joystick(7, 2, 3)); + tusb_hid_simple_joysick_t* j2 = tuh_hid_allocate_simple_joystick(7, 2, 3); TEST_ASSERT_NOT_NULL(j2); TEST_ASSERT_NOT_EQUAL(j1,j2); } @@ -281,8 +282,8 @@ void test_tuh_hid_joystick_get_data() { TEST_ASSERT_EQUAL(false, joystick_data.input_flags.prefered_noprefered); TEST_ASSERT_EQUAL(false, joystick_data.input_flags.nonull_null); - tuh_hid_joystick_process_usages(&pstate, &joystick_data, 0, 9); - simple_joystick = tuh_hid_get_simple_joystick(9, 0); + tuh_hid_joystick_process_usages(&pstate, &joystick_data, 0, 5, 9); + simple_joystick = tuh_hid_get_simple_joystick(5, 9, 0); TEST_ASSERT_NOT_NULL(simple_joystick); // x1 TEST_ASSERT_EQUAL(0, simple_joystick->axis_x1.start); @@ -330,8 +331,8 @@ void test_tuh_hid_joystick_get_data() { TEST_ASSERT_EQUAL(false, joystick_data.input_flags.prefered_noprefered); TEST_ASSERT_EQUAL(true, joystick_data.input_flags.nonull_null); - tuh_hid_joystick_process_usages(&pstate, &joystick_data, 40, 9); - simple_joystick = tuh_hid_get_simple_joystick(9, 0); + tuh_hid_joystick_process_usages(&pstate, &joystick_data, 40, 5, 9); + simple_joystick = tuh_hid_get_simple_joystick(5, 9, 0); TEST_ASSERT_NOT_NULL(simple_joystick); TEST_ASSERT_EQUAL(40, simple_joystick->hat.start); TEST_ASSERT_EQUAL(4, simple_joystick->hat.length); @@ -358,8 +359,8 @@ void test_tuh_hid_joystick_get_data() { TEST_ASSERT_EQUAL(false, joystick_data.input_flags.prefered_noprefered); TEST_ASSERT_EQUAL(false, joystick_data.input_flags.nonull_null); - tuh_hid_joystick_process_usages(&pstate, &joystick_data, 44, 9); // 56 - simple_joystick = tuh_hid_get_simple_joystick(9, 0); + tuh_hid_joystick_process_usages(&pstate, &joystick_data, 44, 5, 9); // 56 + simple_joystick = tuh_hid_get_simple_joystick(5, 9, 0); TEST_ASSERT_NOT_NULL(simple_joystick); TEST_ASSERT_EQUAL(44, simple_joystick->buttons.start); TEST_ASSERT_EQUAL(12, simple_joystick->buttons.length); @@ -368,8 +369,8 @@ void test_tuh_hid_joystick_get_data() { } void test_hid_parse_greenasia_report() { - tuh_hid_joystick_parse_report_descriptor(tb_speedlink, sizeof(tb_speedlink), 9); - tusb_hid_simple_joysick_t* simple_joystick = tuh_hid_get_simple_joystick(9, 0); + tuh_hid_joystick_parse_report_descriptor(tb_speedlink, sizeof(tb_speedlink), 5, 9); + tusb_hid_simple_joysick_t* simple_joystick = tuh_hid_get_simple_joystick(5, 9, 0); TEST_ASSERT_NOT_NULL(simple_joystick); // x1 TEST_ASSERT_EQUAL(0, simple_joystick->axis_x1.start); @@ -396,8 +397,8 @@ void test_hid_parse_greenasia_report() { } void test_hid_parse_speedlink_report() { - tuh_hid_joystick_parse_report_descriptor(tb_greenasia, sizeof(tb_greenasia), 9); - tusb_hid_simple_joysick_t* simple_joystick = tuh_hid_get_simple_joystick(9, 0); + tuh_hid_joystick_parse_report_descriptor(tb_greenasia, sizeof(tb_greenasia), 5, 9); + tusb_hid_simple_joysick_t* simple_joystick = tuh_hid_get_simple_joystick(5, 9, 0); TEST_ASSERT_NOT_NULL(simple_joystick); // x1 TEST_ASSERT_EQUAL(16, simple_joystick->axis_x1.start); @@ -435,8 +436,8 @@ void test_apple_joystick() { // 8 bits of hat switch data (though values are only from 1-8) // 12 bits of button states (12 buttons of 0 or 1 values) // 4 bits of padding - tuh_hid_joystick_parse_report_descriptor(tb_apple, sizeof(tb_apple), 9); - tusb_hid_simple_joysick_t* simple_joystick = tuh_hid_get_simple_joystick(9, 0); + tuh_hid_joystick_parse_report_descriptor(tb_apple, sizeof(tb_apple), 5, 9); + tusb_hid_simple_joysick_t* simple_joystick = tuh_hid_get_simple_joystick(5, 9, 0); TEST_ASSERT_NOT_NULL(simple_joystick); // x1 TEST_ASSERT_EQUAL(0, simple_joystick->axis_x1.start); @@ -493,3 +494,4 @@ void test_apple_joystick() { // TODO Test multiple report IDs + From 9891f6b92ff17a0094d90cb92f0ed3f8baf93e42 Mon Sep 17 00:00:00 2001 From: Phil Date: Thu, 17 Feb 2022 07:06:59 +0000 Subject: [PATCH 60/71] HID micro parser --- examples/host/cdc_msc_hid/CMakeLists.txt | 2 +- examples/host/cdc_msc_hid/src/hid_app.c | 48 ++++++------------- .../src/{hid_host_parse.c => hid_host_info.c} | 7 +-- .../src/{hid_host_parse.h => hid_host_info.h} | 6 +-- examples/host/cdc_msc_hid/src/hid_host_joy.h | 2 +- 5 files changed, 21 insertions(+), 44 deletions(-) rename examples/host/cdc_msc_hid/src/{hid_host_parse.c => hid_host_info.c} (95%) rename examples/host/cdc_msc_hid/src/{hid_host_parse.h => hid_host_info.h} (95%) diff --git a/examples/host/cdc_msc_hid/CMakeLists.txt b/examples/host/cdc_msc_hid/CMakeLists.txt index 490e387a67..0864181598 100644 --- a/examples/host/cdc_msc_hid/CMakeLists.txt +++ b/examples/host/cdc_msc_hid/CMakeLists.txt @@ -16,7 +16,7 @@ add_executable(${PROJECT}) 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_parse.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 diff --git a/examples/host/cdc_msc_hid/src/hid_app.c b/examples/host/cdc_msc_hid/src/hid_app.c index 3528ad8eff..fadf6b9b8d 100644 --- a/examples/host/cdc_msc_hid/src/hid_app.c +++ b/examples/host/cdc_msc_hid/src/hid_app.c @@ -26,7 +26,7 @@ #include "bsp/board.h" #include "tusb.h" #include "hid_host_joy.h" -#include "hid_host_parse.h" +#include "hid_host_info.h" //--------------------------------------------------------------------+ // MACRO TYPEDEF CONSTANT ENUM DECLARATION @@ -133,41 +133,23 @@ void tuh_hid_mount_cb(uint8_t dev_addr, uint8_t instance, uint8_t const* desc_re printf("HID receive joystick report description\r\n"); tuh_hid_allocate_info(dev_addr, instance, has_report_id, &handle_joystick_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; - - case HID_USAGE_DESKTOP_JOYSTICK: - TU_LOG1("HID receive joystick report "); - // for(int i = 0; i < len; ++i) { - // printf("%02x", report[i]); - // } - // printf("\r\n"); - - - break; - - case HID_USAGE_DESKTOP_GAMEPAD: - TU_LOG1("HID receive gamepad report "); - for(int i = 0; i < len; ++i) { - printf("%02x", report[i]); - } - printf("\r\n"); - break; -*/ - default: + } + 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); + 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); + break; + } + default: { TU_LOG1("HID usage unknown usage:%d\r\n", report->usage); - - break; + break; + } } } - else { - - } } tuh_hid_joystick_parse_report_descriptor(desc_report, desc_len, dev_addr, instance); diff --git a/examples/host/cdc_msc_hid/src/hid_host_parse.c b/examples/host/cdc_msc_hid/src/hid_host_info.c similarity index 95% rename from examples/host/cdc_msc_hid/src/hid_host_parse.c rename to examples/host/cdc_msc_hid/src/hid_host_info.c index 130f6d0bf7..3f3b10a454 100644 --- a/examples/host/cdc_msc_hid/src/hid_host_parse.c +++ b/examples/host/cdc_msc_hid/src/hid_host_info.c @@ -19,20 +19,15 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. * - * Test me with: - * - * ceedling test:pattern[hid_host_joy] */ -#include "hid_host_parse.h" -#include "hid_host_utils.h" +#include "hid_host_info.h" static tusb_hid_host_info_t hid_info[HID_HOST_MAX_SIMPLE_DEVICES]; tusb_hid_host_info_t* tuh_hid_get_info(uint8_t dev_addr, uint8_t instance) { tusb_hid_host_info_key_t key; - key.combined = 0; key.elements.dev_addr = dev_addr; key.elements.instance = instance; key.elements.in_use = 1; diff --git a/examples/host/cdc_msc_hid/src/hid_host_parse.h b/examples/host/cdc_msc_hid/src/hid_host_info.h similarity index 95% rename from examples/host/cdc_msc_hid/src/hid_host_parse.h rename to examples/host/cdc_msc_hid/src/hid_host_info.h index ee3fad0863..63a34d138f 100644 --- a/examples/host/cdc_msc_hid/src/hid_host_parse.h +++ b/examples/host/cdc_msc_hid/src/hid_host_info.h @@ -38,9 +38,9 @@ typedef union TU_ATTR_PACKED uint32_t combined; struct TU_ATTR_PACKED { - uint8_t instance :8; - uint8_t dev_addr :8; - uint8_t in_use :8; + uint8_t instance :8; + uint8_t dev_addr :8; + uint16_t in_use :16; } elements; } tusb_hid_host_info_key_t; diff --git a/examples/host/cdc_msc_hid/src/hid_host_joy.h b/examples/host/cdc_msc_hid/src/hid_host_joy.h index 0b63a78eab..d2431d1707 100644 --- a/examples/host/cdc_msc_hid/src/hid_host_joy.h +++ b/examples/host/cdc_msc_hid/src/hid_host_joy.h @@ -167,7 +167,7 @@ void tusb_hid_simple_joysick_process_report(tusb_hid_simple_joysick_t* simple_jo // Send an axis and button report to stdout // // e.g. -// hid= 0, report_id= 0, x1= 0, y1= 0, x2= 127, y2= 127, hat=F, buttons=0008 +// dev_addr= 1, instance= 0, report_id= 0, x1= 127, y1= 127, x2= 127, y2= 127, hat=F, buttons=0000 // void tusb_hid_print_simple_joysick_report(tusb_hid_simple_joysick_t* simple_joystick); From 0be1bac6507b078a69d27e79fcca1f96d8900447 Mon Sep 17 00:00:00 2001 From: Phil Date: Thu, 17 Feb 2022 17:25:48 +0000 Subject: [PATCH 61/71] HID micro parser --- examples/host/cdc_msc_hid/src/hid_app.c | 29 +++++++++++-------- examples/host/cdc_msc_hid/src/hid_host_info.c | 24 +++++++++------ examples/host/cdc_msc_hid/src/hid_host_info.h | 24 +++++++++++---- examples/host/cdc_msc_hid/src/hid_host_joy.c | 12 ++++++++ examples/host/cdc_msc_hid/src/hid_host_joy.h | 15 ++++++++++ .../host/cdc_msc_hid/test_hid_host_joy.c | 22 ++++++++++++++ 6 files changed, 99 insertions(+), 27 deletions(-) diff --git a/examples/host/cdc_msc_hid/src/hid_app.c b/examples/host/cdc_msc_hid/src/hid_app.c index fadf6b9b8d..e4c74f9d34 100644 --- a/examples/host/cdc_msc_hid/src/hid_app.c +++ b/examples/host/cdc_msc_hid/src/hid_app.c @@ -63,7 +63,7 @@ void handle_mouse_report(tusb_hid_host_info_t* info, const uint8_t* report, uint 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 "); + 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, @@ -74,6 +74,13 @@ void handle_joystick_report(tusb_hid_host_info_t* info, const uint8_t* report, u 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) { TU_LOG1("HID receive gamepad report "); @@ -126,22 +133,25 @@ void tuh_hid_mount_cb(uint8_t dev_addr, uint8_t instance, uint8_t const* desc_re { 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); + 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"); - tuh_hid_allocate_info(dev_addr, instance, has_report_id, &handle_joystick_report); + 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); + 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); + 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: { @@ -150,9 +160,7 @@ void tuh_hid_mount_cb(uint8_t dev_addr, uint8_t instance, uint8_t const* desc_re } } } - } - - tuh_hid_joystick_parse_report_descriptor(desc_report, desc_len, dev_addr, instance); + } } // request to receive report @@ -168,11 +176,8 @@ 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); - // Free up host info structure + // Invoke unmount functions adn free up host info structure tuh_hid_free_info(dev_addr, instance); - - // Free up any joystick definitions - tuh_hid_free_simple_joysticks_for_instance(dev_addr, instance); } // Invoked when received report from device via interrupt endpoint diff --git a/examples/host/cdc_msc_hid/src/hid_host_info.c b/examples/host/cdc_msc_hid/src/hid_host_info.c index 3f3b10a454..3c18490473 100644 --- a/examples/host/cdc_msc_hid/src/hid_host_info.c +++ b/examples/host/cdc_msc_hid/src/hid_host_info.c @@ -23,7 +23,7 @@ #include "hid_host_info.h" -static tusb_hid_host_info_t hid_info[HID_HOST_MAX_SIMPLE_DEVICES]; +static tusb_hid_host_info_t hid_info[HCD_MAX_ENDPOINT]; tusb_hid_host_info_t* tuh_hid_get_info(uint8_t dev_addr, uint8_t instance) { @@ -33,7 +33,10 @@ tusb_hid_host_info_t* tuh_hid_get_info(uint8_t dev_addr, uint8_t instance) key.elements.in_use = 1; uint32_t combined = key.combined; - for(uint8_t i = 0; i < HID_HOST_MAX_SIMPLE_DEVICES; ++i) { + // Linear search for endpoint, which is fine while HCD_MAX_ENDPOINT + // is small. Perhaps a 'bsearch' version should be used if HCD_MAX_ENDPOINT + // is large. + for(uint8_t i = 0; i < HCD_MAX_ENDPOINT; ++i) { tusb_hid_host_info_t* info = &hid_info[i]; if (info->key.combined == combined) return info; } @@ -42,21 +45,22 @@ tusb_hid_host_info_t* tuh_hid_get_info(uint8_t dev_addr, uint8_t instance) 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; - // May also want to call some unmount function - // ... } void tuh_hid_free_all_info() { - for(uint8_t i = 0; i < HID_HOST_MAX_SIMPLE_DEVICES; ++i) { + for(uint8_t i = 0; i < HCD_MAX_ENDPOINT; ++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 < HID_HOST_MAX_SIMPLE_DEVICES; ++i) { + for(uint8_t i = 0; i < HCD_MAX_ENDPOINT; ++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); @@ -68,9 +72,10 @@ 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 (*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 < HID_HOST_MAX_SIMPLE_DEVICES; ++i) { + for(uint8_t i = 0; i < HCD_MAX_ENDPOINT; ++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)); @@ -79,10 +84,11 @@ tusb_hid_host_info_t* tuh_hid_allocate_info( info->key.elements.instance = instance; info->has_report_id = has_report_id; info->handler = handler; + info->unmount = unmount; return info; } } - printf("FAILED TO ALLOCATE INFO\n"); + TU_LOG1("FAILED TO ALLOCATE INFO for dev_addr=%d, instance=%d\r\n", dev_addr, instance); return NULL; } diff --git a/examples/host/cdc_msc_hid/src/hid_host_info.h b/examples/host/cdc_msc_hid/src/hid_host_info.h index 63a34d138f..59559fc038 100644 --- a/examples/host/cdc_msc_hid/src/hid_host_info.h +++ b/examples/host/cdc_msc_hid/src/hid_host_info.h @@ -19,10 +19,22 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. * + * + * This module provides a place to store information about host endpoints. + * + * It records: + * A flag which indicates whether reports start with an identifier byte + * A 'handler' function to process a report + * An optional 'unmount' function called when the instance is removed + * + * Each 'info' record is indexed by the device address and instance number. + * + * [ It might be nice if the main library gave some support for managing + * state like this... particularly if it avoided more arrays & lookups ] */ -#ifndef _TUSB_HID_HOST_PARSE_H_ -#define _TUSB_HID_HOST_PARSE_H_ +#ifndef _TUSB_HID_HOST_INFO_H_ +#define _TUSB_HID_HOST_INFO_H_ #include "tusb.h" @@ -30,9 +42,6 @@ extern "C" { #endif -// Perhaps this should be derived from other config -#define HID_HOST_MAX_SIMPLE_DEVICES 8 - typedef union TU_ATTR_PACKED { uint32_t combined; @@ -48,6 +57,7 @@ typedef struct tusb_hid_host_info { tusb_hid_host_info_key_t key; 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); } tusb_hid_host_info_t; tusb_hid_host_info_t* tuh_hid_get_info(uint8_t dev_addr, uint8_t instance); @@ -56,7 +66,9 @@ 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 (*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) +); void tuh_hid_free_info(uint8_t dev_addr, uint8_t instance); diff --git a/examples/host/cdc_msc_hid/src/hid_host_joy.c b/examples/host/cdc_msc_hid/src/hid_host_joy.c index 2c31a99789..a1091cb296 100644 --- a/examples/host/cdc_msc_hid/src/hid_host_joy.c +++ b/examples/host/cdc_msc_hid/src/hid_host_joy.c @@ -275,3 +275,15 @@ void tusb_hid_print_simple_joysick_report(tusb_hid_simple_joysick_t* simple_joys } } +uint8_t tuh_hid_get_simple_joysticks(tusb_hid_simple_joysick_t** simple_joysticks, uint8_t max_simple_joysticks) +{ + uint8_t j = 0; + for(uint8_t i = 0; i < HID_MAX_JOYSTICKS && j < max_simple_joysticks; ++i) { + tusb_hid_simple_joysick_t* simple_joystick = &hid_simple_joysicks[i]; + if (simple_joystick->key.elements.in_use) { + simple_joysticks[j++] = simple_joystick; + } + } + return j; +} + diff --git a/examples/host/cdc_msc_hid/src/hid_host_joy.h b/examples/host/cdc_msc_hid/src/hid_host_joy.h index d2431d1707..6f75ba6f70 100644 --- a/examples/host/cdc_msc_hid/src/hid_host_joy.h +++ b/examples/host/cdc_msc_hid/src/hid_host_joy.h @@ -19,6 +19,18 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. * + * + * This module contains an example of mapping a HID report to a simplified + * local joystick definition. This simple model has: + * 2x XY axes (X, Y and Z, Rz) + * 1x HAT control + * up to 32x Buttons (but have to be defined in one range in the HID description) + * + * Applications will still need to allow mapping of axis and buttons to + * particlar functions. + * + * There are many ways a HID report can describe a joystick and this code + * only copes with a few of them. */ #ifndef _TUSB_HID_JOY_H_ @@ -171,4 +183,7 @@ void tusb_hid_simple_joysick_process_report(tusb_hid_simple_joysick_t* simple_jo // void tusb_hid_print_simple_joysick_report(tusb_hid_simple_joysick_t* simple_joystick); +// Populate an array of the attached joysticks +uint8_t tuh_hid_get_simple_joysticks(tusb_hid_simple_joysick_t** simple_joysticks, uint8_t max_simple_joysticks); + #endif diff --git a/test/test/examples/host/cdc_msc_hid/test_hid_host_joy.c b/test/test/examples/host/cdc_msc_hid/test_hid_host_joy.c index 4a159a7ae6..bfe2a54667 100644 --- a/test/test/examples/host/cdc_msc_hid/test_hid_host_joy.c +++ b/test/test/examples/host/cdc_msc_hid/test_hid_host_joy.c @@ -491,6 +491,28 @@ void test_apple_joystick() { TEST_ASSERT_EQUAL(8, simple_joystick->report_length); } +void test_get_simple_joysticks() { + static tusb_hid_simple_joysick_t* hid_simple_joysicks[4]; + uint8_t jcount; + jcount = tuh_hid_get_simple_joysticks(hid_simple_joysicks, 4); + TEST_ASSERT_EQUAL(0, jcount); + tuh_hid_joystick_parse_report_descriptor(tb_speedlink, sizeof(tb_speedlink), 5, 9); + jcount = tuh_hid_get_simple_joysticks(hid_simple_joysicks, 4); + TEST_ASSERT_EQUAL(1, jcount); + TEST_ASSERT_EQUAL(tuh_hid_get_simple_joystick(5, 9, 0), hid_simple_joysicks[0]); + tuh_hid_joystick_parse_report_descriptor(tb_apple, sizeof(tb_apple), 1, 3); + jcount = tuh_hid_get_simple_joysticks(hid_simple_joysicks, 1); + TEST_ASSERT_EQUAL(1, jcount); + jcount = tuh_hid_get_simple_joysticks(hid_simple_joysicks, 4); + TEST_ASSERT_EQUAL(2, jcount); + TEST_ASSERT_EQUAL(tuh_hid_get_simple_joystick(5, 9, 0), hid_simple_joysicks[0]); + TEST_ASSERT_EQUAL(tuh_hid_get_simple_joystick(1, 3, 0), hid_simple_joysicks[1]); + tuh_hid_free_simple_joysticks_for_instance(5, 9); + jcount = tuh_hid_get_simple_joysticks(hid_simple_joysicks, 4); + TEST_ASSERT_EQUAL(1, jcount); + TEST_ASSERT_EQUAL(tuh_hid_get_simple_joystick(1, 3, 0), hid_simple_joysicks[0]); +} + // TODO Test multiple report IDs From 7a22ce3cd2122ca44da45a4efcc01d4566dc19ef Mon Sep 17 00:00:00 2001 From: Phil Date: Fri, 18 Feb 2022 19:21:36 +0000 Subject: [PATCH 62/71] HID micro parser --- examples/host/cdc_msc_hid/src/hid_host_info.h | 3 +++ examples/host/cdc_msc_hid/src/hid_host_joy.h | 4 ++++ examples/host/cdc_msc_hid/src/hid_host_utils.h | 4 ++++ src/class/hid/hid_ri.h | 2 +- src/class/hid/hid_rip.h | 3 +++ 5 files changed, 15 insertions(+), 1 deletion(-) diff --git a/examples/host/cdc_msc_hid/src/hid_host_info.h b/examples/host/cdc_msc_hid/src/hid_host_info.h index 59559fc038..29659d918f 100644 --- a/examples/host/cdc_msc_hid/src/hid_host_info.h +++ b/examples/host/cdc_msc_hid/src/hid_host_info.h @@ -72,5 +72,8 @@ tusb_hid_host_info_t* tuh_hid_allocate_info( void tuh_hid_free_info(uint8_t dev_addr, uint8_t instance); +#ifdef __cplusplus +} #endif +#endif /* _TUSB_HID_HOST_INFO_H_ */ diff --git a/examples/host/cdc_msc_hid/src/hid_host_joy.h b/examples/host/cdc_msc_hid/src/hid_host_joy.h index 6f75ba6f70..739cc8d664 100644 --- a/examples/host/cdc_msc_hid/src/hid_host_joy.h +++ b/examples/host/cdc_msc_hid/src/hid_host_joy.h @@ -186,4 +186,8 @@ void tusb_hid_print_simple_joysick_report(tusb_hid_simple_joysick_t* simple_joys // Populate an array of the attached joysticks uint8_t tuh_hid_get_simple_joysticks(tusb_hid_simple_joysick_t** simple_joysticks, uint8_t max_simple_joysticks); +#ifdef __cplusplus +} #endif + +#endif /* _TUSB_HID_JOY_H_ */ diff --git a/examples/host/cdc_msc_hid/src/hid_host_utils.h b/examples/host/cdc_msc_hid/src/hid_host_utils.h index 7998e153cf..4661c13a3d 100644 --- a/examples/host/cdc_msc_hid/src/hid_host_utils.h +++ b/examples/host/cdc_msc_hid/src/hid_host_utils.h @@ -52,5 +52,9 @@ int32_t tuh_hid_report_bytes_i32(uint8_t const* report, uint16_t start, uint16_t // Chooses between bytewise and bitwise fetches int32_t tuh_hid_report_i32(const uint8_t* report, uint16_t start, uint16_t length, bool is_signed); +#ifdef __cplusplus +} #endif +#endif /* _TUSB_HID_HOST_UTILS_H_ */ + diff --git a/src/class/hid/hid_ri.h b/src/class/hid/hid_ri.h index afa9cf4e15..1de4a79e96 100644 --- a/src/class/hid/hid_ri.h +++ b/src/class/hid/hid_ri.h @@ -101,4 +101,4 @@ void tuh_hid_ri_split_usage(uint32_t eusage, uint16_t *usage, uint16_t *usage_pa } #endif -#endif /* _TUSB_HID_HOST_H_ */ +#endif /* _TUSB_HID_RI_H_ */ diff --git a/src/class/hid/hid_rip.h b/src/class/hid/hid_rip.h index 4009004037..c1da1cc574 100644 --- a/src/class/hid/hid_rip.h +++ b/src/class/hid/hid_rip.h @@ -148,5 +148,8 @@ uint32_t tuh_hid_rip_report_total_size_bits(tuh_hid_rip_state_t *state); //--------------------------------------------------------------------+ uint8_t tuh_hid_parse_report_descriptor(tuh_hid_report_info_t* reports_info_arr, uint8_t arr_count, uint8_t const* desc_report, uint16_t desc_len) TU_ATTR_UNUSED; +#ifdef __cplusplus +} #endif +#endif /* _TUSB_HID_RIP_H_ */ From 74619ea3f9bf2a3f0358c69684e9c5af1cb5f1f7 Mon Sep 17 00:00:00 2001 From: Phil Date: Fri, 18 Feb 2022 22:39:11 +0000 Subject: [PATCH 63/71] HID micro parser --- examples/host/cdc_msc_hid/src/hid_host_joy.c | 6 +++--- examples/host/cdc_msc_hid/src/hid_host_joy.h | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/examples/host/cdc_msc_hid/src/hid_host_joy.c b/examples/host/cdc_msc_hid/src/hid_host_joy.c index a1091cb296..0013477330 100644 --- a/examples/host/cdc_msc_hid/src/hid_host_joy.c +++ b/examples/host/cdc_msc_hid/src/hid_host_joy.c @@ -150,7 +150,7 @@ void tuh_hid_joystick_process_usages( // If there are no specific usages look for a range // TODO What is the correct behaviour if there are both? if (pstate->usage_count == 0 && !jdata->usage_is_range) { - printf("no usage - skipping bits %d \n", jdata->report_size * jdata->report_count); + printf("no usage - skipping bits %lu \n", jdata->report_size * jdata->report_count); return; } @@ -200,7 +200,7 @@ void tuh_hid_joystick_process_usages( } } -uint8_t tuh_hid_joystick_parse_report_descriptor(uint8_t const* desc_report, uint16_t desc_len, uint8_t dev_addr, uint8_t instance) +void tuh_hid_joystick_parse_report_descriptor(uint8_t const* desc_report, uint16_t desc_len, uint8_t dev_addr, uint8_t instance) { uint32_t eusage = 0; tuh_hid_rip_state_t pstate; @@ -262,7 +262,7 @@ void tusb_hid_simple_joysick_process_report(tusb_hid_simple_joysick_t* simple_jo void tusb_hid_print_simple_joysick_report(tusb_hid_simple_joysick_t* simple_joystick) { if (simple_joystick->has_values) { - printf("dev_addr=%3d, instance=%3d, report_id=%3d, x1=%4ld, y1=%4ld, x2=%4ld, y2=%4ld, hat=%01X, buttons=%04X\n", + printf("dev_addr=%3d, instance=%3d, report_id=%3d, x1=%4ld, y1=%4ld, x2=%4ld, y2=%4ld, hat=%01lX, buttons=%04lX\n", simple_joystick->key.elements.dev_addr, simple_joystick->key.elements.instance, simple_joystick->key.elements.report_id, diff --git a/examples/host/cdc_msc_hid/src/hid_host_joy.h b/examples/host/cdc_msc_hid/src/hid_host_joy.h index 739cc8d664..55209246df 100644 --- a/examples/host/cdc_msc_hid/src/hid_host_joy.h +++ b/examples/host/cdc_msc_hid/src/hid_host_joy.h @@ -153,7 +153,7 @@ void tuh_hid_joystick_process_usages( ); // Parse a HID report description for a joystick -uint8_t tuh_hid_joystick_parse_report_descriptor(uint8_t const* desc_report, uint16_t desc_len, uint8_t dev_addr, uint8_t instance); +void tuh_hid_joystick_parse_report_descriptor(uint8_t const* desc_report, uint16_t desc_len, uint8_t dev_addr, uint8_t instance); // Fetch a previously allocated simple joystick tusb_hid_simple_joysick_t* tuh_hid_get_simple_joystick(uint8_t dev_addr, uint8_t instance, uint8_t report_id); From a9a661839fbb2125eedb2e2d3f44df16c601196a Mon Sep 17 00:00:00 2001 From: Phil Date: Sat, 19 Feb 2022 22:28:22 +0000 Subject: [PATCH 64/71] HID micro parser --- src/class/hid/hid_rip.c | 12 ++ test/test/class/hid/test_hid_rip.c | 121 ++++++++++++++++++ .../host/cdc_msc_hid/test_hid_host_joy.c | 3 +- 3 files changed, 135 insertions(+), 1 deletion(-) diff --git a/src/class/hid/hid_rip.c b/src/class/hid/hid_rip.c index 9dee49068a..e98a7f37fb 100644 --- a/src/class/hid/hid_rip.c +++ b/src/class/hid/hid_rip.c @@ -221,18 +221,30 @@ uint8_t tuh_hid_parse_report_descriptor(tuh_hid_report_info_t* report_info_arr, switch(type_and_tag) { case HID_RI_TYPE_AND_TAG(RI_TYPE_MAIN, RI_MAIN_INPUT): { + if (report_num >= arr_count) { + TU_LOG1("HID report description contains more than the maximum %d reports\r\n", arr_count); + return report_num; + } info->in_len += tuh_hid_rip_report_total_size_bits(&pstate); info->usage = usage; info->usage_page = usage_page; break; } case HID_RI_TYPE_AND_TAG(RI_TYPE_MAIN, RI_MAIN_OUTPUT): { + if (report_num >= arr_count) { + TU_LOG1("HID report description contains more than the maximum %d reports\r\n", arr_count); + return report_num; + } info->out_len += tuh_hid_rip_report_total_size_bits(&pstate); info->usage = usage; info->usage_page = usage_page; break; } case HID_RI_TYPE_AND_TAG(RI_TYPE_GLOBAL, RI_GLOBAL_REPORT_ID): { + if (report_num >= arr_count) { + TU_LOG1("HID report description contains more than the maximum %d reports\r\n", arr_count); + return report_num; + } if (info->report_id > 0 || info->in_len > 0 || info->out_len > 0) { info++; report_num++; diff --git a/test/test/class/hid/test_hid_rip.c b/test/test/class/hid/test_hid_rip.c index 9a186d3c60..82f8749171 100644 --- a/test/test/class/hid/test_hid_rip.c +++ b/test/test/class/hid/test_hid_rip.c @@ -585,3 +585,124 @@ void test_hid_parse_speedlink_report() { uint8_t report_count = tuh_hid_parse_report_descriptor(report_info, 3, (const uint8_t*)&tb, sizeof(tb)); TEST_ASSERT_EQUAL(1, report_count); } + +void test_hid_parse_keyboard_and_trackpad_report() { + const uint8_t const tb[] = { + 0x05, 0x01, // Usage Page (Generic Desktop Ctrls) + 0x09, 0x02, // Usage (Mouse) + 0xA1, 0x01, // Collection (Application) + 0x85, 0x02, // Report ID (2) + 0x09, 0x01, // Usage (Pointer) + 0xA1, 0x00, // Collection (Physical) + 0x05, 0x09, // Usage Page (Button) + 0x19, 0x01, // Usage Minimum (0x01) + 0x29, 0x10, // Usage Maximum (0x10) + 0x15, 0x00, // Logical Minimum (0) + 0x25, 0x01, // Logical Maximum (1) + 0x95, 0x10, // Report Count (16) + 0x75, 0x01, // Report Size (1) + 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0x05, 0x01, // Usage Page (Generic Desktop Ctrls) + 0x16, 0x01, 0xF8, // Logical Minimum (-2047) + 0x26, 0xFF, 0x07, // Logical Maximum (2047) + 0x75, 0x0C, // Report Size (12) + 0x95, 0x02, // Report Count (2) + 0x09, 0x30, // Usage (X) + 0x09, 0x31, // Usage (Y) + 0x81, 0x06, // Input (Data,Var,Rel,No Wrap,Linear,Preferred State,No Null Position) + 0x15, 0x81, // Logical Minimum (-127) + 0x25, 0x7F, // Logical Maximum (127) + 0x75, 0x08, // Report Size (8) + 0x95, 0x01, // Report Count (1) + 0x09, 0x38, // Usage (Wheel) + 0x81, 0x06, // Input (Data,Var,Rel,No Wrap,Linear,Preferred State,No Null Position) + 0x05, 0x0C, // Usage Page (Consumer) + 0x0A, 0x38, 0x02, // Usage (AC Pan) + 0x95, 0x01, // Report Count (1) + 0x81, 0x06, // Input (Data,Var,Rel,No Wrap,Linear,Preferred State,No Null Position) + 0xC0, // End Collection + 0xC0, // End Collection + 0x05, 0x0C, // Usage Page (Consumer) + 0x09, 0x01, // Usage (Consumer Control) + 0xA1, 0x01, // Collection (Application) + 0x85, 0x03, // Report ID (3) + 0x75, 0x10, // Report Size (16) + 0x95, 0x02, // Report Count (2) + 0x15, 0x01, // Logical Minimum (1) + 0x26, 0x8C, 0x02, // Logical Maximum (652) + 0x19, 0x01, // Usage Minimum (Consumer Control) + 0x2A, 0x8C, 0x02, // Usage Maximum (AC Send) + 0x81, 0x00, // Input (Data,Array,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0xC0, // End Collection + 0x05, 0x01, // Usage Page (Generic Desktop Ctrls) + 0x09, 0x80, // Usage (Sys Control) + 0xA1, 0x01, // Collection (Application) + 0x85, 0x04, // Report ID (4) + 0x75, 0x02, // Report Size (2) + 0x95, 0x01, // Report Count (1) + 0x15, 0x01, // Logical Minimum (1) + 0x25, 0x03, // Logical Maximum (3) + 0x09, 0x82, // Usage (Sys Sleep) + 0x09, 0x81, // Usage (Sys Power Down) + 0x09, 0x83, // Usage (Sys Wake Up) + 0x81, 0x60, // Input (Data,Array,Abs,No Wrap,Linear,No Preferred State,Null State) + 0x75, 0x06, // Report Size (6) + 0x81, 0x03, // Input (Const,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0xC0, // End Collection + 0x06, 0xBC, 0xFF, // Usage Page (Vendor Defined 0xFFBC) + 0x09, 0x88, // Usage (0x88) + 0xA1, 0x01, // Collection (Application) + 0x85, 0x08, // Report ID (8) + 0x19, 0x01, // Usage Minimum (0x01) + 0x29, 0xFF, // Usage Maximum (0xFF) + 0x15, 0x01, // Logical Minimum (1) + 0x26, 0xFF, 0x00, // Logical Maximum (255) + 0x75, 0x08, // Report Size (8) + 0x95, 0x01, // Report Count (1) + 0x81, 0x00, // Input (Data,Array,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0xC0, // End Collection + }; + tuh_hid_report_info_t report_info[5]; + + uint8_t report_count; + report_count = tuh_hid_parse_report_descriptor(report_info, 1, (const uint8_t*)&tb, sizeof(tb)); + TEST_ASSERT_EQUAL(1, report_count); + report_count = tuh_hid_parse_report_descriptor(report_info, 2, (const uint8_t*)&tb, sizeof(tb)); + TEST_ASSERT_EQUAL(2, report_count); + report_count = tuh_hid_parse_report_descriptor(report_info, 3, (const uint8_t*)&tb, sizeof(tb)); + TEST_ASSERT_EQUAL(3, report_count); + report_count = tuh_hid_parse_report_descriptor(report_info, 4, (const uint8_t*)&tb, sizeof(tb)); + TEST_ASSERT_EQUAL(4, report_count); + report_count = tuh_hid_parse_report_descriptor(report_info, 5, (const uint8_t*)&tb, sizeof(tb)); + TEST_ASSERT_EQUAL(4, report_count); + + TEST_ASSERT_EQUAL(1, report_info[0].usage_page); + TEST_ASSERT_EQUAL(2, report_info[0].usage); + TEST_ASSERT_EQUAL(2, report_info[0].report_id); + TEST_ASSERT_EQUAL(56, report_info[0].in_len); + TEST_ASSERT_EQUAL(0, report_info[0].out_len); + + TEST_ASSERT_EQUAL(0xC, report_info[1].usage_page); + TEST_ASSERT_EQUAL(0x1, report_info[1].usage); + TEST_ASSERT_EQUAL(3, report_info[1].report_id); + TEST_ASSERT_EQUAL(32, report_info[1].in_len); + TEST_ASSERT_EQUAL(0, report_info[1].out_len); + + TEST_ASSERT_EQUAL(1, report_info[2].usage_page); + TEST_ASSERT_EQUAL(0x80, report_info[2].usage); + TEST_ASSERT_EQUAL(4, report_info[2].report_id); + TEST_ASSERT_EQUAL(8, report_info[2].in_len); + TEST_ASSERT_EQUAL(0, report_info[2].out_len); + + TEST_ASSERT_EQUAL(0xFFBC, report_info[3].usage_page); + TEST_ASSERT_EQUAL(0x88, report_info[3].usage); + TEST_ASSERT_EQUAL(8, report_info[3].report_id); + TEST_ASSERT_EQUAL(8, report_info[3].in_len); + TEST_ASSERT_EQUAL(0, report_info[3].out_len); +} + + + + + + diff --git a/test/test/examples/host/cdc_msc_hid/test_hid_host_joy.c b/test/test/examples/host/cdc_msc_hid/test_hid_host_joy.c index bfe2a54667..2fcb855108 100644 --- a/test/test/examples/host/cdc_msc_hid/test_hid_host_joy.c +++ b/test/test/examples/host/cdc_msc_hid/test_hid_host_joy.c @@ -513,7 +513,8 @@ void test_get_simple_joysticks() { TEST_ASSERT_EQUAL(tuh_hid_get_simple_joystick(1, 3, 0), hid_simple_joysicks[0]); } -// TODO Test multiple report IDs +// TODO Test with report ID +// anyone got a joystick that reports with an ID? From dd359ecbbe4ac1ddadb0596947775c7ddfe0ab78 Mon Sep 17 00:00:00 2001 From: Phil Date: Wed, 23 Feb 2022 22:24:44 +0000 Subject: [PATCH 65/71] Fix for 64bit test environment --- examples/host/cdc_msc_hid/src/hid_host_joy.c | 4 ++-- src/class/hid/hid_rip.h | 1 - .../host/cdc_msc_hid/test_hid_host_utils.c | 23 ++++++++----------- 3 files changed, 12 insertions(+), 16 deletions(-) diff --git a/examples/host/cdc_msc_hid/src/hid_host_joy.c b/examples/host/cdc_msc_hid/src/hid_host_joy.c index 0013477330..40bf74f9fb 100644 --- a/examples/host/cdc_msc_hid/src/hid_host_joy.c +++ b/examples/host/cdc_msc_hid/src/hid_host_joy.c @@ -150,7 +150,7 @@ void tuh_hid_joystick_process_usages( // If there are no specific usages look for a range // TODO What is the correct behaviour if there are both? if (pstate->usage_count == 0 && !jdata->usage_is_range) { - printf("no usage - skipping bits %lu \n", jdata->report_size * jdata->report_count); + printf("no usage - skipping bits %u \n", jdata->report_size * jdata->report_count); return; } @@ -262,7 +262,7 @@ void tusb_hid_simple_joysick_process_report(tusb_hid_simple_joysick_t* simple_jo void tusb_hid_print_simple_joysick_report(tusb_hid_simple_joysick_t* simple_joystick) { if (simple_joystick->has_values) { - printf("dev_addr=%3d, instance=%3d, report_id=%3d, x1=%4ld, y1=%4ld, x2=%4ld, y2=%4ld, hat=%01lX, buttons=%04lX\n", + printf("dev_addr=%3d, instance=%3d, report_id=%3d, x1=%4d, y1=%4d, x2=%4d, y2=%4d, hat=%01X, buttons=%04X\n", simple_joystick->key.elements.dev_addr, simple_joystick->key.elements.instance, simple_joystick->key.elements.report_id, diff --git a/src/class/hid/hid_rip.h b/src/class/hid/hid_rip.h index c1da1cc574..951aa1a47b 100644 --- a/src/class/hid/hid_rip.h +++ b/src/class/hid/hid_rip.h @@ -28,7 +28,6 @@ #include "tusb.h" #include "hid_ri.h" #include "hid.h" -#include "tusb_compiler.h" #ifdef __cplusplus extern "C" { diff --git a/test/test/examples/host/cdc_msc_hid/test_hid_host_utils.c b/test/test/examples/host/cdc_msc_hid/test_hid_host_utils.c index ddc8db7c59..bbe0a13760 100644 --- a/test/test/examples/host/cdc_msc_hid/test_hid_host_utils.c +++ b/test/test/examples/host/cdc_msc_hid/test_hid_host_utils.c @@ -47,7 +47,7 @@ void test_tuh_hid_report_bits_u32() { }; TEST_ASSERT_EQUAL(0x55, tuh_hid_report_bits_u32(tb, 4, 8)); TEST_ASSERT_EQUAL(0x8f, tuh_hid_report_bits_u32(tb, 16, 8)); - TEST_ASSERT_EQUAL(0xff8f0550, tuh_hid_report_bits_u32(tb, 0, 32)); + TEST_ASSERT_EQUAL((uint32_t)0xff8f0550UL, tuh_hid_report_bits_u32(tb, 0, 32)); } void test_tuh_hid_report_bits_i32() { @@ -55,8 +55,8 @@ void test_tuh_hid_report_bits_i32() { 0x50, 0x05, 0x8f, 0xff }; TEST_ASSERT_EQUAL(0x55, tuh_hid_report_bits_i32(tb, 4, 8)); - TEST_ASSERT_EQUAL(0xffffff8f, tuh_hid_report_bits_i32(tb, 16, 8)); - TEST_ASSERT_EQUAL(0xff8f0550, tuh_hid_report_bits_i32(tb, 0, 32)); + TEST_ASSERT_EQUAL(-113, tuh_hid_report_bits_i32(tb, 16, 8)); // int32_t 0xffffff8f == -113 + TEST_ASSERT_EQUAL(-7404208, tuh_hid_report_bits_i32(tb, 0, 32)); // int32_t 0xff8f0550 == -7404208 } void test_tuh_hid_report_bytes_u32() { @@ -75,10 +75,10 @@ void test_tuh_hid_report_bytes_i32() { 0x50, 0x05, 0x8f, 0xff }; TEST_ASSERT_EQUAL(0x0550, tuh_hid_report_bytes_i32(tb, 0, 2)); - TEST_ASSERT_EQUAL(0xffff8f05, tuh_hid_report_bytes_i32(tb, 1, 2)); - TEST_ASSERT_EQUAL(0xffff8f05, tuh_hid_report_bytes_i32(tb, 1, 3)); - TEST_ASSERT_EQUAL(0xff8f0550, tuh_hid_report_bytes_i32(tb, 0, 4)); - TEST_ASSERT_EQUAL(0xffffff8f, tuh_hid_report_bytes_i32(tb, 2, 1)); + TEST_ASSERT_EQUAL(-28923, tuh_hid_report_bytes_i32(tb, 1, 2)); // int32_t 0xffff8f05 == -28923 + TEST_ASSERT_EQUAL(-28923, tuh_hid_report_bytes_i32(tb, 1, 3)); // int32_t 0xffff8f05 == -28923 + TEST_ASSERT_EQUAL(-7404208, tuh_hid_report_bytes_i32(tb, 0, 4)); // int32_t 0xff8f0550 == -7404208 + TEST_ASSERT_EQUAL(-113, tuh_hid_report_bytes_i32(tb, 2, 1)); // int32_t 0xffffff8f == -113 } void test_tuh_hid_report_i32() { @@ -87,14 +87,11 @@ void test_tuh_hid_report_i32() { }; TEST_ASSERT_EQUAL(0x55, tuh_hid_report_i32(tb, 4, 8, false)); TEST_ASSERT_EQUAL(0x8f, tuh_hid_report_i32(tb, 16, 8, false)); - TEST_ASSERT_EQUAL(0xff8f0550, tuh_hid_report_i32(tb, 0, 32, false)); + TEST_ASSERT_EQUAL(-7404208, tuh_hid_report_i32(tb, 0, 32, false)); // int32_t 0xff8f0550 == -7404208 TEST_ASSERT_EQUAL(0x55, tuh_hid_report_i32(tb, 4, 8, true)); - TEST_ASSERT_EQUAL(0xffffff8f, tuh_hid_report_i32(tb, 16, 8, true)); - TEST_ASSERT_EQUAL(0xff8f0550, tuh_hid_report_i32(tb, 0, 32, true)); + TEST_ASSERT_EQUAL(-113, tuh_hid_report_i32(tb, 16, 8, true)); // int32_t 0xffffff8f == -113 + TEST_ASSERT_EQUAL(-7404208, tuh_hid_report_i32(tb, 0, 32, true)); // int32_t 0xff8f0550 == -7404208 } -// TODO Test multiple report IDs - - From d503ea499444d3547d4a56dc3e5635f8ce0cb3f1 Mon Sep 17 00:00:00 2001 From: Phil Date: Sat, 26 Feb 2022 16:13:14 +0000 Subject: [PATCH 66/71] fix build on 64bit compiler --- examples/host/cdc_msc_hid/src/hid_host_utils.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/examples/host/cdc_msc_hid/src/hid_host_utils.c b/examples/host/cdc_msc_hid/src/hid_host_utils.c index 4e3ae247e7..cbc60d5f5f 100644 --- a/examples/host/cdc_msc_hid/src/hid_host_utils.c +++ b/examples/host/cdc_msc_hid/src/hid_host_utils.c @@ -35,8 +35,9 @@ uint32_t tuh_hid_report_bits_u32(uint8_t const* report, uint16_t start, uint16_t for(uint16_t i = 1; (i << 3) < l; ++i) { acc |= ((uint32_t)*p++) << ((i << 3) - bit_offset_start); } - const uint32_t m = (((uint32_t)1) << length) - 1; - return acc & m; + const uint32_t lp0 = ((uint32_t)1) << (length - 1); + const uint32_t lp1 = lp0 << 1; + return acc & (lp1 - 1); } int32_t tuh_hid_report_bits_i32(uint8_t const* report, uint16_t start, uint16_t length) From 193fd0dd29af813ccbeea2bd30a6cce7cce3d756 Mon Sep 17 00:00:00 2001 From: Phil Date: Sun, 6 Mar 2022 22:52:27 +0000 Subject: [PATCH 67/71] Use strict C function prototypes --- examples/host/cdc_msc_hid/src/hid_host_info.c | 2 +- examples/host/cdc_msc_hid/src/hid_host_joy.c | 2 +- examples/host/cdc_msc_hid/src/hid_host_joy.h | 6 +++--- test/test/class/hid/test_hid_rip.c | 14 +++++++------- .../host/cdc_msc_hid/test_hid_host_joy.c | 18 +++++++++--------- .../host/cdc_msc_hid/test_hid_host_utils.c | 10 +++++----- 6 files changed, 26 insertions(+), 26 deletions(-) diff --git a/examples/host/cdc_msc_hid/src/hid_host_info.c b/examples/host/cdc_msc_hid/src/hid_host_info.c index 3c18490473..d9c308bdf0 100644 --- a/examples/host/cdc_msc_hid/src/hid_host_info.c +++ b/examples/host/cdc_msc_hid/src/hid_host_info.c @@ -51,7 +51,7 @@ void tuh_hid_free_sinlge_info(tusb_hid_host_info_t* info) info->key.elements.in_use = 0; } -void tuh_hid_free_all_info() +void tuh_hid_free_all_info(void) { for(uint8_t i = 0; i < HCD_MAX_ENDPOINT; ++i) { tuh_hid_free_sinlge_info(&hid_info[i]); diff --git a/examples/host/cdc_msc_hid/src/hid_host_joy.c b/examples/host/cdc_msc_hid/src/hid_host_joy.c index 40bf74f9fb..2ab4570ae0 100644 --- a/examples/host/cdc_msc_hid/src/hid_host_joy.c +++ b/examples/host/cdc_msc_hid/src/hid_host_joy.c @@ -55,7 +55,7 @@ tusb_hid_simple_joysick_t* tuh_hid_get_simple_joystick(uint8_t dev_addr, uint8_t return NULL; } -void tuh_hid_free_simple_joysticks() { +void tuh_hid_free_simple_joysticks(void) { for(uint8_t i = 0; i < HID_MAX_JOYSTICKS; ++i) { hid_simple_joysicks[i].key.elements.in_use = false; } diff --git a/examples/host/cdc_msc_hid/src/hid_host_joy.h b/examples/host/cdc_msc_hid/src/hid_host_joy.h index 55209246df..e0477841a0 100644 --- a/examples/host/cdc_msc_hid/src/hid_host_joy.h +++ b/examples/host/cdc_msc_hid/src/hid_host_joy.h @@ -121,8 +121,8 @@ typedef struct { typedef struct { uint32_t report_size; uint32_t report_count; - uint32_t logical_min; - uint32_t logical_max; + int32_t logical_min; + int32_t logical_max; uint16_t usage_page; uint16_t usage_min; uint16_t usage_max; @@ -162,7 +162,7 @@ tusb_hid_simple_joysick_t* tuh_hid_get_simple_joystick(uint8_t dev_addr, uint8_t void tuh_hid_free_simple_joysticks_for_instance(uint8_t dev_addr, uint8_t instance); // Free all previously allocated simple joysticks -void tuh_hid_free_simple_joysticks(); +void tuh_hid_free_simple_joysticks(void); // Allocate a new simple joystick tusb_hid_simple_joysick_t* tuh_hid_allocate_simple_joystick(uint8_t dev_addr, uint8_t instance, uint8_t report_id); diff --git a/test/test/class/hid/test_hid_rip.c b/test/test/class/hid/test_hid_rip.c index 82f8749171..1f336e38d2 100644 --- a/test/test/class/hid/test_hid_rip.c +++ b/test/test/class/hid/test_hid_rip.c @@ -279,7 +279,7 @@ void test_total_size_bits(void) } -void test_hid_parse_report_descriptor_single_mouse_report() { +void test_hid_parse_report_descriptor_single_mouse_report(void) { const uint8_t const tb[] = { 0x05, 0x01, // USAGE_PAGE (Generic Desktop) 0x09, 0x02, // USAGE (Mouse) @@ -320,7 +320,7 @@ void test_hid_parse_report_descriptor_single_mouse_report() { TEST_ASSERT_EQUAL(0, report_info[0].out_len); } -void test_hid_parse_report_descriptor_single_gamepad_report() { +void test_hid_parse_report_descriptor_single_gamepad_report(void) { const uint8_t const tb[] = { 0x05, 0x01, // USAGE_PAGE (Generic Desktop) 0x09, 0x05, // USAGE (Game Pad) @@ -361,7 +361,7 @@ void test_hid_parse_report_descriptor_single_gamepad_report() { TEST_ASSERT_EQUAL(0, report_info[0].out_len); } -void test_hid_parse_report_descriptor_dual_report() { +void test_hid_parse_report_descriptor_dual_report(void) { const uint8_t const tb[] = { 0x09, 0x01, // Usage (Consumer Control) 0xA1, 0x01, // Collection (Application) @@ -403,7 +403,7 @@ void test_hid_parse_report_descriptor_dual_report() { TEST_ASSERT_EQUAL(0, report_info[1].out_len); } -void test_hid_parse_report_descriptor_joystick_report() { +void test_hid_parse_report_descriptor_joystick_report(void) { const uint8_t const tb[] = { 0x05, 0x01, // Usage Page (Generic Desktop Ctrls) 0x09, 0x04, // Usage (Joystick) @@ -470,7 +470,7 @@ void test_hid_parse_report_descriptor_joystick_report() { TEST_ASSERT_EQUAL(0, report_info[0].out_len); } -void test_hid_parse_greenasia_report() { +void test_hid_parse_greenasia_report(void) { const uint8_t const tb[] = { 0x05, 0x01, // Usage Page (Generic Desktop Ctrls) 0x09, 0x04, // Usage (Joystick) @@ -528,7 +528,7 @@ void test_hid_parse_greenasia_report() { TEST_ASSERT_EQUAL(1, report_count); } -void test_hid_parse_speedlink_report() { +void test_hid_parse_speedlink_report(void) { const uint8_t const tb[] = { 0x05, 0x01, // Usage Page (Generic Desktop Ctrls) 0x09, 0x04, // Usage (Joystick) @@ -586,7 +586,7 @@ void test_hid_parse_speedlink_report() { TEST_ASSERT_EQUAL(1, report_count); } -void test_hid_parse_keyboard_and_trackpad_report() { +void test_hid_parse_keyboard_and_trackpad_report(void) { const uint8_t const tb[] = { 0x05, 0x01, // Usage Page (Generic Desktop Ctrls) 0x09, 0x02, // Usage (Mouse) diff --git a/test/test/examples/host/cdc_msc_hid/test_hid_host_joy.c b/test/test/examples/host/cdc_msc_hid/test_hid_host_joy.c index 2fcb855108..7fab2f1155 100644 --- a/test/test/examples/host/cdc_msc_hid/test_hid_host_joy.c +++ b/test/test/examples/host/cdc_msc_hid/test_hid_host_joy.c @@ -207,7 +207,7 @@ void tearDown(void) // Tests //--------------------------------------------------------------------+ -void test_simple_joystick_allocator() { +void test_simple_joystick_allocator(void) { TEST_ASSERT_NULL(tuh_hid_get_simple_joystick(5, 1, 2)); TEST_ASSERT_NULL(tuh_hid_get_simple_joystick(5, 1, 3)); TEST_ASSERT_NULL(tuh_hid_get_simple_joystick(4, 2, 3)); @@ -230,14 +230,14 @@ void test_simple_joystick_allocator() { TEST_ASSERT_NOT_NULL(tuh_hid_get_simple_joystick(4, 2, 3)); } -void test_simple_joystick_allocate_too_many() { +void test_simple_joystick_allocate_too_many(void) { for (int i =0; i < HID_MAX_JOYSTICKS; ++i) { TEST_ASSERT_NOT_NULL(tuh_hid_allocate_simple_joystick(1, i + 1, 4)); } TEST_ASSERT_NULL(tuh_hid_allocate_simple_joystick(2, 1, 0)); } -void test_simple_joystick_free_all() { +void test_simple_joystick_free_all(void) { TEST_ASSERT_NOT_NULL(tuh_hid_allocate_simple_joystick(7, 1, 3)); TEST_ASSERT_NOT_NULL(tuh_hid_allocate_simple_joystick(0, 2, 3)); tuh_hid_free_simple_joysticks(); @@ -245,7 +245,7 @@ void test_simple_joystick_free_all() { TEST_ASSERT_NULL(tuh_hid_get_simple_joystick(0, 2, 3)); } -void test_simple_joystick_obtain() { +void test_simple_joystick_obtain(void) { tusb_hid_simple_joysick_t* j1 = tuh_hid_allocate_simple_joystick(7, 1, 3); TEST_ASSERT_NOT_NULL(j1); TEST_ASSERT_EQUAL(j1, tuh_hid_obtain_simple_joystick(7, 1, 3)); @@ -255,7 +255,7 @@ void test_simple_joystick_obtain() { TEST_ASSERT_NOT_EQUAL(j1,j2); } -void test_tuh_hid_joystick_get_data() { +void test_tuh_hid_joystick_get_data(void) { tuh_hid_joystick_data_t joystick_data; tuh_hid_rip_state_t pstate; tusb_hid_simple_joysick_t* simple_joystick; @@ -368,7 +368,7 @@ void test_tuh_hid_joystick_get_data() { TEST_ASSERT_EQUAL(7, simple_joystick->report_length); } -void test_hid_parse_greenasia_report() { +void test_hid_parse_greenasia_report(void) { tuh_hid_joystick_parse_report_descriptor(tb_speedlink, sizeof(tb_speedlink), 5, 9); tusb_hid_simple_joysick_t* simple_joystick = tuh_hid_get_simple_joystick(5, 9, 0); TEST_ASSERT_NOT_NULL(simple_joystick); @@ -396,7 +396,7 @@ void test_hid_parse_greenasia_report() { TEST_ASSERT_EQUAL(8, simple_joystick->report_length); } -void test_hid_parse_speedlink_report() { +void test_hid_parse_speedlink_report(void) { tuh_hid_joystick_parse_report_descriptor(tb_greenasia, sizeof(tb_greenasia), 5, 9); tusb_hid_simple_joysick_t* simple_joystick = tuh_hid_get_simple_joystick(5, 9, 0); TEST_ASSERT_NOT_NULL(simple_joystick); @@ -425,7 +425,7 @@ void test_hid_parse_speedlink_report() { TEST_ASSERT_EQUAL(8, simple_joystick->report_length); } -void test_apple_joystick() { +void test_apple_joystick(void) { // Thanks to https://jenswilly.dk/2012/10/parsing-usb-joystick-hid-data/ // 10 bits of X-axis data (for values from 0 to 1023) @@ -491,7 +491,7 @@ void test_apple_joystick() { TEST_ASSERT_EQUAL(8, simple_joystick->report_length); } -void test_get_simple_joysticks() { +void test_get_simple_joysticks(void) { static tusb_hid_simple_joysick_t* hid_simple_joysicks[4]; uint8_t jcount; jcount = tuh_hid_get_simple_joysticks(hid_simple_joysicks, 4); diff --git a/test/test/examples/host/cdc_msc_hid/test_hid_host_utils.c b/test/test/examples/host/cdc_msc_hid/test_hid_host_utils.c index bbe0a13760..5805d33e59 100644 --- a/test/test/examples/host/cdc_msc_hid/test_hid_host_utils.c +++ b/test/test/examples/host/cdc_msc_hid/test_hid_host_utils.c @@ -41,7 +41,7 @@ void tearDown(void) // Tests //--------------------------------------------------------------------+ -void test_tuh_hid_report_bits_u32() { +void test_tuh_hid_report_bits_u32(void) { const uint8_t const tb[] = { 0x50, 0x05, 0x8f, 0xff }; @@ -50,7 +50,7 @@ void test_tuh_hid_report_bits_u32() { TEST_ASSERT_EQUAL((uint32_t)0xff8f0550UL, tuh_hid_report_bits_u32(tb, 0, 32)); } -void test_tuh_hid_report_bits_i32() { +void test_tuh_hid_report_bits_i32(void) { const uint8_t const tb[] = { 0x50, 0x05, 0x8f, 0xff }; @@ -59,7 +59,7 @@ void test_tuh_hid_report_bits_i32() { TEST_ASSERT_EQUAL(-7404208, tuh_hid_report_bits_i32(tb, 0, 32)); // int32_t 0xff8f0550 == -7404208 } -void test_tuh_hid_report_bytes_u32() { +void test_tuh_hid_report_bytes_u32(void) { const uint8_t const tb[] = { 0x50, 0x05, 0x8f, 0xff }; @@ -70,7 +70,7 @@ void test_tuh_hid_report_bytes_u32() { TEST_ASSERT_EQUAL(0x8f, tuh_hid_report_bytes_u32(tb, 2, 1)); } -void test_tuh_hid_report_bytes_i32() { +void test_tuh_hid_report_bytes_i32(void) { const uint8_t const tb[] = { 0x50, 0x05, 0x8f, 0xff }; @@ -81,7 +81,7 @@ void test_tuh_hid_report_bytes_i32() { TEST_ASSERT_EQUAL(-113, tuh_hid_report_bytes_i32(tb, 2, 1)); // int32_t 0xffffff8f == -113 } -void test_tuh_hid_report_i32() { +void test_tuh_hid_report_i32(void) { const uint8_t const tb[] = { 0x50, 0x05, 0x8f, 0xff }; From d0f36505ead1334aabe6351beed9ac6ba4238cf7 Mon Sep 17 00:00:00 2001 From: Phil Date: Wed, 9 Mar 2022 22:08:52 +0000 Subject: [PATCH 68/71] Fix for Wall Werror --- examples/host/cdc_msc_hid/src/hid_app.c | 14 ++++++++++++++ examples/host/cdc_msc_hid/src/hid_host_joy.c | 15 +++++++-------- examples/host/cdc_msc_hid/src/hid_host_joy.h | 7 ++++--- 3 files changed, 25 insertions(+), 11 deletions(-) diff --git a/examples/host/cdc_msc_hid/src/hid_app.c b/examples/host/cdc_msc_hid/src/hid_app.c index e4c74f9d34..edd7e14856 100644 --- a/examples/host/cdc_msc_hid/src/hid_app.c +++ b/examples/host/cdc_msc_hid/src/hid_app.c @@ -51,12 +51,22 @@ void hid_app_task(void) 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); } @@ -83,6 +93,10 @@ void handle_joystick_unmount(tusb_hid_host_info_t* info) { 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]); diff --git a/examples/host/cdc_msc_hid/src/hid_host_joy.c b/examples/host/cdc_msc_hid/src/hid_host_joy.c index 2ab4570ae0..70d50d1ef1 100644 --- a/examples/host/cdc_msc_hid/src/hid_host_joy.c +++ b/examples/host/cdc_msc_hid/src/hid_host_joy.c @@ -128,7 +128,6 @@ bool tuh_hid_joystick_get_data( static void tuh_hid_joystick_process_axis( tuh_hid_joystick_data_t* jdata, uint32_t bitpos, - uint8_t instance, tusb_hid_simple_axis_t* simple_axis) { simple_axis->start = bitpos; @@ -150,7 +149,7 @@ void tuh_hid_joystick_process_usages( // If there are no specific usages look for a range // TODO What is the correct behaviour if there are both? if (pstate->usage_count == 0 && !jdata->usage_is_range) { - printf("no usage - skipping bits %u \n", jdata->report_size * jdata->report_count); + printf("no usage - skipping bits %lu \n", jdata->report_size * jdata->report_count); return; } @@ -180,19 +179,19 @@ void tuh_hid_joystick_process_usages( // Seems to be common usage for gamepads. // Probably needs a lot more thought... case HID_RIP_EUSAGE(HID_USAGE_PAGE_DESKTOP, HID_USAGE_DESKTOP_X): - tuh_hid_joystick_process_axis(jdata, bitpos, instance, &simple_joystick->axis_x1); + tuh_hid_joystick_process_axis(jdata, bitpos, &simple_joystick->axis_x1); break; case HID_RIP_EUSAGE(HID_USAGE_PAGE_DESKTOP, HID_USAGE_DESKTOP_Y): - tuh_hid_joystick_process_axis(jdata, bitpos, instance, &simple_joystick->axis_y1); + tuh_hid_joystick_process_axis(jdata, bitpos, &simple_joystick->axis_y1); break; case HID_RIP_EUSAGE(HID_USAGE_PAGE_DESKTOP, HID_USAGE_DESKTOP_Z): - tuh_hid_joystick_process_axis(jdata, bitpos, instance, &simple_joystick->axis_x2); + tuh_hid_joystick_process_axis(jdata, bitpos, &simple_joystick->axis_x2); break; case HID_RIP_EUSAGE(HID_USAGE_PAGE_DESKTOP, HID_USAGE_DESKTOP_RZ): - tuh_hid_joystick_process_axis(jdata, bitpos, instance, &simple_joystick->axis_y2); + tuh_hid_joystick_process_axis(jdata, bitpos, &simple_joystick->axis_y2); break; case HID_RIP_EUSAGE(HID_USAGE_PAGE_DESKTOP, HID_USAGE_DESKTOP_HAT_SWITCH): - tuh_hid_joystick_process_axis(jdata, bitpos, instance, &simple_joystick->hat); + tuh_hid_joystick_process_axis(jdata, bitpos, &simple_joystick->hat); break; default: break; } @@ -262,7 +261,7 @@ void tusb_hid_simple_joysick_process_report(tusb_hid_simple_joysick_t* simple_jo void tusb_hid_print_simple_joysick_report(tusb_hid_simple_joysick_t* simple_joystick) { if (simple_joystick->has_values) { - printf("dev_addr=%3d, instance=%3d, report_id=%3d, x1=%4d, y1=%4d, x2=%4d, y2=%4d, hat=%01X, buttons=%04X\n", + printf("dev_addr=%3d, instance=%3d, report_id=%3d, x1=%4ld, y1=%4ld, x2=%4ld, y2=%4ld, hat=%01lX, buttons=%04lX\n", simple_joystick->key.elements.dev_addr, simple_joystick->key.elements.instance, simple_joystick->key.elements.report_id, diff --git a/examples/host/cdc_msc_hid/src/hid_host_joy.h b/examples/host/cdc_msc_hid/src/hid_host_joy.h index e0477841a0..3a4dc37f1c 100644 --- a/examples/host/cdc_msc_hid/src/hid_host_joy.h +++ b/examples/host/cdc_msc_hid/src/hid_host_joy.h @@ -33,10 +33,11 @@ * only copes with a few of them. */ -#ifndef _TUSB_HID_JOY_H_ -#define _TUSB_HID_JOY_H_ +#ifndef _TUSB_HID_HOST_JOY_H_ +#define _TUSB_HID_HOST_JOY_H_ #include "tusb.h" +#include "host/hcd.h" #include "class/hid/hid_rip.h" #ifdef __cplusplus @@ -190,4 +191,4 @@ uint8_t tuh_hid_get_simple_joysticks(tusb_hid_simple_joysick_t** simple_joystick } #endif -#endif /* _TUSB_HID_JOY_H_ */ +#endif /* _TUSB_HID_HOST_JOY_H_ */ From 2706708a1df542a550d9b4e9e075521563f7c67c Mon Sep 17 00:00:00 2001 From: Phil Date: Fri, 11 Mar 2022 18:51:30 +0000 Subject: [PATCH 69/71] Fix ceedling test build --- examples/host/cdc_msc_hid/src/hid_host_info.c | 10 +++++----- examples/host/cdc_msc_hid/src/hid_host_joy.h | 1 - test/project.yml | 2 +- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/examples/host/cdc_msc_hid/src/hid_host_info.c b/examples/host/cdc_msc_hid/src/hid_host_info.c index d9c308bdf0..98e42646be 100644 --- a/examples/host/cdc_msc_hid/src/hid_host_info.c +++ b/examples/host/cdc_msc_hid/src/hid_host_info.c @@ -23,7 +23,7 @@ #include "hid_host_info.h" -static tusb_hid_host_info_t hid_info[HCD_MAX_ENDPOINT]; +static tusb_hid_host_info_t hid_info[CFG_TUH_ENDPOINT_MAX]; tusb_hid_host_info_t* tuh_hid_get_info(uint8_t dev_addr, uint8_t instance) { @@ -36,7 +36,7 @@ tusb_hid_host_info_t* tuh_hid_get_info(uint8_t dev_addr, uint8_t instance) // Linear search for endpoint, which is fine while HCD_MAX_ENDPOINT // is small. Perhaps a 'bsearch' version should be used if HCD_MAX_ENDPOINT // is large. - for(uint8_t i = 0; i < HCD_MAX_ENDPOINT; ++i) { + for(uint8_t i = 0; i < CFG_TUH_ENDPOINT_MAX; ++i) { tusb_hid_host_info_t* info = &hid_info[i]; if (info->key.combined == combined) return info; } @@ -53,14 +53,14 @@ void tuh_hid_free_sinlge_info(tusb_hid_host_info_t* info) void tuh_hid_free_all_info(void) { - for(uint8_t i = 0; i < HCD_MAX_ENDPOINT; ++i) { + for(uint8_t i = 0; i < CFG_TUH_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 < HCD_MAX_ENDPOINT; ++i) { + for(uint8_t i = 0; i < CFG_TUH_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); @@ -75,7 +75,7 @@ tusb_hid_host_info_t* tuh_hid_allocate_info( 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 < HCD_MAX_ENDPOINT; ++i) { + for(uint8_t i = 0; i < CFG_TUH_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)); diff --git a/examples/host/cdc_msc_hid/src/hid_host_joy.h b/examples/host/cdc_msc_hid/src/hid_host_joy.h index 3a4dc37f1c..09fb738f93 100644 --- a/examples/host/cdc_msc_hid/src/hid_host_joy.h +++ b/examples/host/cdc_msc_hid/src/hid_host_joy.h @@ -37,7 +37,6 @@ #define _TUSB_HID_HOST_JOY_H_ #include "tusb.h" -#include "host/hcd.h" #include "class/hid/hid_rip.h" #ifdef __cplusplus diff --git a/test/project.yml b/test/project.yml index 08a4fdcbb3..4f6f4284ad 100644 --- a/test/project.yml +++ b/test/project.yml @@ -36,7 +36,7 @@ - -:test/support :source: - ../src/** - - ../examples/** + - ../examples/host/cdc_msc_hid/* :support: - test/support From 7276ef02e65e85951544ff489d23bb73b898e69f Mon Sep 17 00:00:00 2001 From: Phil Date: Sun, 17 Jul 2022 15:28:57 +0100 Subject: [PATCH 70/71] change CFG_TUH_ENDPOINT_MAX to TUP_DCD_ENDPOINT_MAX in example --- examples/host/cdc_msc_hid/src/hid_host_info.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/examples/host/cdc_msc_hid/src/hid_host_info.c b/examples/host/cdc_msc_hid/src/hid_host_info.c index 98e42646be..fbe088b83d 100644 --- a/examples/host/cdc_msc_hid/src/hid_host_info.c +++ b/examples/host/cdc_msc_hid/src/hid_host_info.c @@ -23,7 +23,7 @@ #include "hid_host_info.h" -static tusb_hid_host_info_t hid_info[CFG_TUH_ENDPOINT_MAX]; +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) { @@ -36,7 +36,7 @@ tusb_hid_host_info_t* tuh_hid_get_info(uint8_t dev_addr, uint8_t instance) // Linear search for endpoint, which is fine while HCD_MAX_ENDPOINT // is small. Perhaps a 'bsearch' version should be used if HCD_MAX_ENDPOINT // is large. - for(uint8_t i = 0; i < CFG_TUH_ENDPOINT_MAX; ++i) { + 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; } @@ -53,14 +53,14 @@ void tuh_hid_free_sinlge_info(tusb_hid_host_info_t* info) void tuh_hid_free_all_info(void) { - for(uint8_t i = 0; i < CFG_TUH_ENDPOINT_MAX; ++i) { + 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 < CFG_TUH_ENDPOINT_MAX; ++i) { + 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); @@ -75,7 +75,7 @@ tusb_hid_host_info_t* tuh_hid_allocate_info( 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 < CFG_TUH_ENDPOINT_MAX; ++i) { + 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)); From 7ba041aff0cad55f13a4cde9e43669379ca74c16 Mon Sep 17 00:00:00 2001 From: Phil Date: Sun, 17 Jul 2022 15:32:04 +0100 Subject: [PATCH 71/71] change CFG_TUH_ENDPOINT_MAX to TUP_DCD_ENDPOINT_MAX in example --- examples/host/cdc_msc_hid/src/hid_host_info.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/host/cdc_msc_hid/src/hid_host_info.c b/examples/host/cdc_msc_hid/src/hid_host_info.c index fbe088b83d..1f10ccaced 100644 --- a/examples/host/cdc_msc_hid/src/hid_host_info.c +++ b/examples/host/cdc_msc_hid/src/hid_host_info.c @@ -33,8 +33,8 @@ tusb_hid_host_info_t* tuh_hid_get_info(uint8_t dev_addr, uint8_t instance) key.elements.in_use = 1; uint32_t combined = key.combined; - // Linear search for endpoint, which is fine while HCD_MAX_ENDPOINT - // is small. Perhaps a 'bsearch' version should be used if HCD_MAX_ENDPOINT + // 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];