Skip to content

Commit

Permalink
Merge pull request #1385 from tlyu/tusb-desc
Browse files Browse the repository at this point in the history
convert report descriptors to TinyUSB macros
  • Loading branch information
obra authored Mar 4, 2024
2 parents 4cdafd1 + 7787c70 commit 5996bd0
Show file tree
Hide file tree
Showing 18 changed files with 1,455 additions and 605 deletions.
157 changes: 5 additions & 152 deletions plugins/KeyboardioHID/src/BootKeyboard/BootKeyboard.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
Copyright (c) 2014-2015 NicoHood
Copyright (c) 2015-2018 Keyboard.io, Inc
Copyright (c) 2015-2024 Keyboard.io, Inc
See the readme for credit to other people.
Expand All @@ -24,163 +24,16 @@ THE SOFTWARE.
*/

#include "BootKeyboard.h"
#include "DescriptorPrimitives.h"
#include "HIDReportObserver.h"
#include "HID-Settings.h"
#include "tusb_hid.h"

// See Appendix B of USB HID spec
static const uint8_t boot_keyboard_hid_descriptor_[] PROGMEM = {
// Keyboard
D_USAGE_PAGE,
D_PAGE_GENERIC_DESKTOP,
D_USAGE,
D_USAGE_KEYBOARD,

D_COLLECTION,
D_APPLICATION,

// LEDs
D_REPORT_COUNT,
0x8,
D_REPORT_SIZE,
0x1,
D_USAGE_PAGE,
D_PAGE_LEDS,
D_USAGE_MINIMUM,
0x1,
D_USAGE_MAXIMUM,
0x8,
D_LOGICAL_MINIMUM,
0x0,
D_LOGICAL_MAXIMUM,
0x1,
D_OUTPUT,
(D_DATA | D_VARIABLE | D_ABSOLUTE),

// Modifiers
D_USAGE_PAGE,
D_PAGE_KEYBOARD,
D_USAGE_MINIMUM,
HID_KEYBOARD_FIRST_MODIFIER,
D_USAGE_MAXIMUM,
HID_KEYBOARD_LAST_MODIFIER,
// D_LOGICAL_MINIMUM, 0x0, // redundant; already 0
// D_LOGICAL_MAXIMUM, 0x1, // redundant; already 1
// D_REPORT_SIZE, 0x1, // redundant; already 1
// D_REPORT_COUNT, 0x8, // redundant; already 8
D_INPUT,
(D_DATA | D_VARIABLE | D_ABSOLUTE),

// Reserved byte
D_REPORT_COUNT,
0x1,
D_REPORT_SIZE,
0x8,
D_INPUT,
(D_CONSTANT),

// Non-modifiers
D_REPORT_COUNT,
BOOT_KEY_BYTES,
// D_REPORT_SIZE, 0x8, // redundant; already 8
// D_LOGICAL_MINIMUM, HID_FIRST_KEY, // redundant; already 0
D_MULTIBYTE(D_LOGICAL_MAXIMUM),
HID_LAST_KEY,
0x0, // make sure it's not negative
// D_USAGE_PAGE, D_PAGE_KEYBOARD, // redundant; already KEYBOARD
D_USAGE_MINIMUM,
HID_FIRST_KEY,
D_USAGE_MAXIMUM,
HID_LAST_KEY,
D_INPUT,
(D_DATA | D_ARRAY | D_ABSOLUTE),
D_END_COLLECTION,
DESCRIPTOR_BOOT_KEYBOARD(),
};

static const uint8_t hybrid_keyboard_hid_descriptor_[] PROGMEM = {
// Hybrid Boot/NKRO Keyboard
D_USAGE_PAGE,
D_PAGE_GENERIC_DESKTOP,
D_USAGE,
D_USAGE_KEYBOARD,

D_COLLECTION,
D_APPLICATION,

/* 5 LEDs for num lock etc, 3 left for advanced, custom usage */
D_USAGE_PAGE,
D_PAGE_LEDS,
D_USAGE_MINIMUM,
0x01,
D_USAGE_MAXIMUM,
0x08,
D_LOGICAL_MINIMUM,
0x00,
D_LOGICAL_MAXIMUM,
0x01,
D_REPORT_SIZE,
0x01,
D_REPORT_COUNT,
0x08,
D_OUTPUT,
(D_DATA | D_VARIABLE | D_ABSOLUTE),

D_USAGE_PAGE,
D_PAGE_KEYBOARD,

/* Key modifier byte for both boot and NKRO */
D_USAGE_MINIMUM,
HID_KEYBOARD_FIRST_MODIFIER,
D_USAGE_MAXIMUM,
HID_KEYBOARD_LAST_MODIFIER,
// D_LOGICAL_MINIMUM, 0x00, // redundant; already 0
// D_LOGICAL_MAXIMUM, 0x01, // redundant; already 1
// D_REPORT_SIZE, 0x01, // redundant; already 1
// D_REPORT_COUNT, 0x08, // redundant; already 8
D_INPUT,
(D_DATA | D_VARIABLE | D_ABSOLUTE),

/* Send rest of boot report as padding, so HID-aware hosts will ignore */
D_REPORT_SIZE,
0x8,
D_REPORT_COUNT,
0x7,
D_INPUT,
(D_CONSTANT),

/* NKRO key bitmap */

// Padding 4 bits, to skip NO_EVENT & 3 error states.
D_REPORT_SIZE,
0x1,
D_REPORT_COUNT,
0x04,
D_INPUT,
(D_CONSTANT),

// Actual non-modifier keys
D_USAGE_MINIMUM,
HID_KEYBOARD_A_AND_A,
D_USAGE_MAXIMUM,
HID_LAST_KEY,
// D_LOGICAL_MINIMUM, 0x00, // redundant; already 0
// D_LOGICAL_MAXIMUM, 0x01, // redundant; already 1
// D_REPORT_SIZE, 0x01, // redundant; already 1
D_REPORT_COUNT,
(NKRO_KEY_BITS - 4),
D_INPUT,
(D_DATA | D_VARIABLE | D_ABSOLUTE),

#if (NKRO_KEY_BITS % 8)
// Padding to round up the report to byte boundary.
// D_REPORT_SIZE, 0x01, // redundant; already 1
D_REPORT_COUNT,
(8 - (NKRO_KEY_BITS % 8)),
D_INPUT,
(D_CONSTANT),
#endif

D_END_COLLECTION,
DESCRIPTOR_HYBRID_KEYBOARD(),
};

BootKeyboard_::BootKeyboard_(uint8_t bootkb_only_)
Expand All @@ -202,7 +55,7 @@ int BootKeyboard_::getInterface(uint8_t *interfaceCount) {
desclen = sizeof(hybrid_keyboard_hid_descriptor_);
}
HIDDescriptor hidInterface = {
D_INTERFACE(pluggedInterface, 1, USB_DEVICE_CLASS_HUMAN_INTERFACE, HID_SUBCLASS_BOOT_INTERFACE, HID_PROTOCOL_KEYBOARD),
D_INTERFACE(pluggedInterface, 1, USB_DEVICE_CLASS_HUMAN_INTERFACE, HID_SUBCLASS_BOOT, HID_PROTOCOL_KEYBOARD),
D_HIDREPORT(desclen),
D_ENDPOINT(USB_ENDPOINT_IN(pluggedEndpoint), USB_ENDPOINT_TYPE_INTERRUPT, USB_EP_SIZE, 0x01),
};
Expand Down
97 changes: 96 additions & 1 deletion plugins/KeyboardioHID/src/BootKeyboard/BootKeyboard.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
Copyright (c) 2014-2015 NicoHood
Copyright (c) 2015-2018 Keyboard.io, Inc
Copyright (c) 2015-2024 Keyboard.io, Inc
See the readme for credit to other people.
Expand Down Expand Up @@ -40,6 +40,101 @@ THE SOFTWARE.
#define NKRO_KEY_BITS (4 + HID_LAST_KEY - HID_KEYBOARD_A_AND_A + 1)
#define NKRO_KEY_BYTES ((NKRO_KEY_BITS + 7) / 8)

// See Appendix B of USB HID spec
#define DESCRIPTOR_BOOT_KEYBOARD(...) \
HID_USAGE_PAGE(HID_USAGE_PAGE_DESKTOP), \
HID_USAGE(HID_USAGE_DESKTOP_KEYBOARD), \
HID_COLLECTION(HID_COLLECTION_APPLICATION), \
\
/* Report ID, if any */ \
__VA_ARGS__ \
\
/* LEDs */ \
HID_REPORT_COUNT(8), \
HID_REPORT_SIZE(1), \
HID_USAGE_PAGE(HID_USAGE_PAGE_LED), \
HID_USAGE_MIN(1), \
HID_USAGE_MAX(8), \
HID_LOGICAL_MIN(0), \
HID_LOGICAL_MAX(1), \
HID_OUTPUT(HID_DATA | HID_VARIABLE | HID_ABSOLUTE), \
\
/* Modifiers */ \
HID_USAGE_PAGE(HID_USAGE_PAGE_KEYBOARD), \
HID_USAGE_MIN(HID_KEYBOARD_FIRST_MODIFIER), \
HID_USAGE_MAX(HID_KEYBOARD_LAST_MODIFIER), \
HID_INPUT(HID_DATA | HID_VARIABLE | HID_ABSOLUTE), \
\
/* Reserved byte */ \
HID_REPORT_COUNT(1), \
HID_REPORT_SIZE(8), \
HID_INPUT(HID_CONSTANT), \
\
/* Non-modifiers */ \
HID_REPORT_COUNT(BOOT_KEY_BYTES), \
HID_LOGICAL_MAX_N(HID_LAST_KEY, 2), \
HID_USAGE_MIN(HID_FIRST_KEY), \
HID_USAGE_MAX(HID_LAST_KEY), \
HID_INPUT(HID_DATA | HID_ARRAY | HID_ABSOLUTE), \
\
HID_COLLECTION_END

// Padding to round up the report to byte boundary.
#if (NKRO_KEY_BITS % 8)
#define DESCRIPTOR_HYBRID_KEYBOARD_PADDING \
HID_REPORT_COUNT(8 - (NKRO_KEY_BITS % 8)), \
HID_INPUT(HID_CONSTANT),
#else
#define DESCRIPTOR_HYBRID_KEYBOARD_PADDING /* empty */
#endif

#define DESCRIPTOR_HYBRID_KEYBOARD(...) \
HID_USAGE_PAGE(HID_USAGE_PAGE_DESKTOP), \
HID_USAGE(HID_USAGE_DESKTOP_KEYBOARD), \
HID_COLLECTION(HID_COLLECTION_APPLICATION), \
\
/* Report ID, if any */ \
__VA_ARGS__ \
\
/* 5 LEDs for num lock etc, 3 left for advanced, custom usage */ \
HID_USAGE_PAGE(HID_USAGE_PAGE_LED), \
HID_USAGE_MIN(1), \
HID_USAGE_MAX(8), \
HID_LOGICAL_MIN(0), \
HID_LOGICAL_MAX(1), \
HID_REPORT_SIZE(1), \
HID_REPORT_COUNT(8), \
HID_OUTPUT(HID_DATA | HID_VARIABLE | HID_ABSOLUTE), \
\
/* Key modifier byte for both boot and NKRO */ \
HID_USAGE_PAGE(HID_USAGE_PAGE_KEYBOARD), \
HID_USAGE_MIN(HID_KEYBOARD_FIRST_MODIFIER), \
HID_USAGE_MAX(HID_KEYBOARD_LAST_MODIFIER), \
HID_INPUT(HID_DATA | HID_VARIABLE | HID_ABSOLUTE), \
\
/* Send rest of boot report as padding, so HID-aware hosts will ignore */ \
HID_REPORT_SIZE(8), \
HID_REPORT_COUNT(7), \
HID_INPUT(HID_CONSTANT), \
\
/* NKRO key bitmap */ \
\
/* Padding 4 bits, to skip NO_EVENT & 3 error states. */ \
HID_REPORT_SIZE(1), \
HID_REPORT_COUNT(4), \
HID_INPUT(HID_CONSTANT), \
\
/* Actual non-modifier keys */ \
HID_USAGE_MIN(HID_KEYBOARD_A_AND_A), \
HID_USAGE_MAX(HID_LAST_KEY), \
HID_REPORT_COUNT(NKRO_KEY_BITS - 4), \
HID_INPUT(HID_DATA | HID_VARIABLE | HID_ABSOLUTE), \
\
/* Padding (if needed )*/ \
DESCRIPTOR_HYBRID_KEYBOARD_PADDING \
\
HID_COLLECTION_END

/*
* Keep the current key states in a NKRO bitmap. We'll convert it to Boot
* Protocol as needed.
Expand Down
Loading

0 comments on commit 5996bd0

Please sign in to comment.