Skip to content

Commit 94ba027

Browse files
committed
simpler generation of HID device tables
1 parent 42f5edb commit 94ba027

3 files changed

Lines changed: 346 additions & 453 deletions

File tree

shared-module/usb_hid/__init__.c

Lines changed: 1 addition & 146 deletions
Original file line numberDiff line numberDiff line change
@@ -24,149 +24,4 @@
2424
* THE SOFTWARE.
2525
*/
2626

27-
#include "py/obj.h"
28-
#include "py/mphal.h"
29-
#include "py/runtime.h"
30-
31-
#include "genhdr/autogen_usb_descriptor.h"
32-
#include "shared-module/usb_hid/Device.h"
33-
#include "shared-bindings/usb_hid/Device.h"
34-
#include "tusb.h"
35-
36-
#ifdef USB_HID_REPORT_ID_KEYBOARD
37-
static uint8_t keyboard_report_buffer[USB_HID_REPORT_LENGTH_KEYBOARD];
38-
#endif
39-
40-
#ifdef USB_HID_REPORT_ID_MOUSE
41-
static uint8_t mouse_report_buffer[USB_HID_REPORT_LENGTH_MOUSE];
42-
#endif
43-
44-
#ifdef USB_HID_REPORT_ID_CONSUMER
45-
static uint8_t consumer_report_buffer[USB_HID_REPORT_LENGTH_CONSUMER];
46-
#endif
47-
48-
#ifdef USB_HID_REPORT_ID_SYS_CONTROL
49-
static uint8_t sys_control_report_buffer[USB_HID_REPORT_LENGTH_SYS_CONTROL];
50-
#endif
51-
52-
#ifdef USB_HID_REPORT_ID_GAMEPAD
53-
static uint8_t gamepad_report_buffer[USB_HID_REPORT_LENGTH_GAMEPAD];
54-
#endif
55-
56-
#ifdef USB_HID_REPORT_ID_XAC_COMPATIBLE_GAMEPAD
57-
static uint8_t xac_compatible_gamepad_report_buffer[USB_HID_REPORT_LENGTH_XAC_COMPATIBLE_GAMEPAD];
58-
#endif
59-
60-
#ifdef USB_HID_REPORT_ID_DIGITIZER
61-
static uint8_t digitizer_report_buffer[USB_HID_REPORT_LENGTH_DIGITIZER];
62-
#endif
63-
64-
usb_hid_device_obj_t usb_hid_devices[] = {
65-
#ifdef USB_HID_REPORT_ID_KEYBOARD
66-
{
67-
.base = { .type = &usb_hid_device_type } ,
68-
.report_buffer = keyboard_report_buffer ,
69-
.report_id = USB_HID_REPORT_ID_KEYBOARD ,
70-
.report_length = USB_HID_REPORT_LENGTH_KEYBOARD ,
71-
.usage_page = HID_USAGE_PAGE_DESKTOP ,
72-
.usage = HID_USAGE_DESKTOP_KEYBOARD ,
73-
},
74-
#endif
75-
76-
#ifdef USB_HID_REPORT_ID_MOUSE
77-
{
78-
.base = { .type = &usb_hid_device_type } ,
79-
.report_buffer = mouse_report_buffer ,
80-
.report_id = USB_HID_REPORT_ID_MOUSE ,
81-
.report_length = USB_HID_REPORT_LENGTH_MOUSE ,
82-
.usage_page = HID_USAGE_PAGE_DESKTOP ,
83-
.usage = HID_USAGE_DESKTOP_MOUSE ,
84-
},
85-
#endif
86-
87-
#ifdef USB_HID_REPORT_ID_CONSUMER
88-
{
89-
.base = { .type = &usb_hid_device_type } ,
90-
.report_buffer = consumer_report_buffer ,
91-
.report_id = USB_HID_REPORT_ID_CONSUMER ,
92-
.report_length = USB_HID_REPORT_LENGTH_CONSUMER ,
93-
.usage_page = HID_USAGE_PAGE_CONSUMER ,
94-
.usage = HID_USAGE_CONSUMER_CONTROL ,
95-
},
96-
#endif
97-
98-
#ifdef USB_HID_REPORT_ID_SYS_CONTROL
99-
{
100-
.base = { .type = &usb_hid_device_type } ,
101-
.report_buffer = sys_control_report_buffer ,
102-
.report_id = USB_HID_REPORT_ID_SYS_CONTROL ,
103-
.report_length = USB_HID_REPORT_LENGTH_SYS_CONTROL ,
104-
.usage_page = HID_USAGE_PAGE_DESKTOP ,
105-
.usage = HID_USAGE_DESKTOP_SYSTEM_CONTROL ,
106-
},
107-
#endif
108-
109-
#ifdef USB_HID_REPORT_ID_GAMEPAD
110-
{
111-
.base = { .type = &usb_hid_device_type } ,
112-
.report_buffer = gamepad_report_buffer ,
113-
.report_id = USB_HID_REPORT_ID_GAMEPAD ,
114-
.report_length = USB_HID_REPORT_LENGTH_GAMEPAD ,
115-
.usage_page = HID_USAGE_PAGE_DESKTOP ,
116-
.usage = HID_USAGE_DESKTOP_GAMEPAD ,
117-
},
118-
#endif
119-
120-
#ifdef USB_HID_REPORT_ID_XAC_COMPATIBLE_GAMEPAD
121-
{
122-
.base = { .type = &usb_hid_device_type } ,
123-
.report_buffer = xac_compatible_gamepad_report_buffer ,
124-
.report_id = USB_HID_REPORT_ID_XAC_COMPATIBLE_GAMEPAD ,
125-
.report_length = USB_HID_REPORT_LENGTH_XAC_COMPATIBLE_GAMEPAD ,
126-
.usage_page = HID_USAGE_PAGE_DESKTOP ,
127-
.usage = HID_USAGE_DESKTOP_GAMEPAD ,
128-
},
129-
#endif
130-
131-
#ifdef USB_HID_REPORT_ID_DIGITIZER
132-
{
133-
.base = { .type = &usb_hid_device_type } ,
134-
.report_buffer = digitizer_report_buffer ,
135-
.report_id = USB_HID_REPORT_ID_DIGITIZER ,
136-
.report_length = USB_HID_REPORT_LENGTH_DIGITIZER ,
137-
.usage_page = 0x0D ,
138-
.usage = 0x02 ,
139-
},
140-
#endif
141-
};
142-
143-
144-
mp_obj_tuple_t common_hal_usb_hid_devices = {
145-
.base = {
146-
.type = &mp_type_tuple,
147-
},
148-
.len = USB_HID_NUM_DEVICES,
149-
.items = {
150-
#if USB_HID_NUM_DEVICES >= 1
151-
(mp_obj_t) &usb_hid_devices[0],
152-
#endif
153-
#if USB_HID_NUM_DEVICES >= 2
154-
(mp_obj_t) &usb_hid_devices[1],
155-
#endif
156-
#if USB_HID_NUM_DEVICES >= 3
157-
(mp_obj_t) &usb_hid_devices[2],
158-
#endif
159-
#if USB_HID_NUM_DEVICES >= 4
160-
(mp_obj_t) &usb_hid_devices[3],
161-
#endif
162-
#if USB_HID_NUM_DEVICES >= 5
163-
(mp_obj_t) &usb_hid_devices[4],
164-
#endif
165-
#if USB_HID_NUM_DEVICES >= 6
166-
(mp_obj_t) &usb_hid_devices[5],
167-
#endif
168-
#if USB_HID_NUM_DEVICES >= 7
169-
#error "Too many USB HID devices"
170-
#endif
171-
}
172-
};
27+
// Nothing needed here. Tables of HID devices are in autogen_usb_descriptor.c.

tools/gen_usb_descriptor.py

Lines changed: 76 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
ALL_DEVICES_SET=frozenset(ALL_DEVICES.split(','))
1313
DEFAULT_DEVICES='CDC,MSC,AUDIO,HID'
1414

15-
ALL_HID_DEVICES='KEYBOARD,MOUSE,CONSUMER,SYS_CONTROL,GAMEPAD,DIGITIZER,XAC_COMPATIBLE_GAMEPAD'
15+
ALL_HID_DEVICES='KEYBOARD,MOUSE,CONSUMER,SYS_CONTROL,GAMEPAD,DIGITIZER,XAC_COMPATIBLE_GAMEPAD,RAW'
1616
ALL_HID_DEVICES_SET=frozenset(ALL_HID_DEVICES.split(','))
1717
# Digitizer works on Linux but conflicts with mouse, so omit it.
1818
DEFAULT_HID_DEVICES='KEYBOARD,MOUSE,CONSUMER,GAMEPAD'
@@ -28,20 +28,20 @@
2828
help='product id')
2929
parser.add_argument('--serial_number_length', type=int, default=32,
3030
help='length needed for the serial number in digits')
31-
parser.add_argument('--devices', type=lambda l: frozenset(l.split(',')), default=DEFAULT_DEVICES,
31+
parser.add_argument('--devices', type=lambda l: tuple(l.split(',')), default=DEFAULT_DEVICES,
3232
help='devices to include in descriptor (AUDIO includes MIDI support)')
33-
parser.add_argument('--hid_devices', type=lambda l: frozenset(l.split(',')), default=DEFAULT_HID_DEVICES,
33+
parser.add_argument('--hid_devices', type=lambda l: tuple(l.split(',')), default=DEFAULT_HID_DEVICES,
3434
help='HID devices to include in HID report descriptor')
3535
parser.add_argument('--output_c_file', type=argparse.FileType('w'), required=True)
3636
parser.add_argument('--output_h_file', type=argparse.FileType('w'), required=True)
3737

3838
args = parser.parse_args()
3939

40-
unknown_devices = list(args.devices - ALL_DEVICES_SET)
40+
unknown_devices = list(frozenset(args.devices) - ALL_DEVICES_SET)
4141
if unknown_devices:
4242
raise ValueError("Unknown device(s)", unknown_devices)
4343

44-
unknown_hid_devices = list(args.hid_devices - ALL_HID_DEVICES_SET)
44+
unknown_hid_devices = list(frozenset(args.hid_devices) - ALL_HID_DEVICES_SET)
4545
if unknown_hid_devices:
4646
raise ValueError("Unknown HID devices(s)", unknown_hid_devices)
4747

@@ -160,29 +160,27 @@ def strings_in_order(cls):
160160
)
161161
]
162162

163-
# Sort by Report ID for consistency.
164-
hid_devices = sorted(args.hid_devices, key=lambda name: hid_report_descriptors.REPORT_IDS[name])
163+
# When there's only one hid_device, it shouldn't have a report id.
164+
# Otherwise, report ids are assigned sequentially:
165+
# args.hid_devices[0] has report_id 1
166+
# args.hid_devices[1] has report_id 2
167+
# etc.
165168

166-
# When there's only one hid_device, it can't be in a composite descriptor.
167-
# It has no report id (indicated by 0), so remove the existing one.
168-
169-
#if len(hid_devices) == 1:
170-
if False:
171-
name = hid_devices[0]
169+
if len(args.hid_devices) == 1:
170+
name = args.hid_devices[0]
172171
combined_hid_report_descriptor = hid.ReportDescriptor(
173172
description=name,
174-
report_descriptor=hid_report_descriptors.remove_report_id(
175-
hid_report_descriptors.REPORT_DESCRIPTORS[name].report_descriptor))
176-
hid_report_ids_dict = { name : 0 }
173+
report_descriptor=bytes(hid_report_descriptors.REPORT_DESCRIPTOR_FUNCTIONS[name](0)))
177174
else:
175+
report_id = 1
176+
concatenated_descriptors = bytearray()
177+
for name in args.hid_devices:
178+
concatenated_descriptors.extend(
179+
bytes(hid_report_descriptors.REPORT_DESCRIPTOR_FUNCTIONS[name](report_id)))
180+
report_id += 1
178181
combined_hid_report_descriptor = hid.ReportDescriptor(
179-
description="MULTIDEVICE",
180-
report_descriptor=b''.join(
181-
hid_report_descriptors.REPORT_DESCRIPTORS[name].report_descriptor for name in hid_devices ))
182-
hid_report_ids_dict = { name: hid_report_descriptors.REPORT_IDS[name] for name in hid_devices }
183-
184-
hid_report_lengths_dict = { name: hid_report_descriptors.REPORT_LENGTHS[name] for name in hid_devices }
185-
hid_max_report_length = max(hid_report_lengths_dict.values())
182+
description="MULTIDEVICE",
183+
report_descriptor=bytes(concatenated_descriptors))
186184

187185
# ASF4 expects keyboard and generic devices to have both in and out endpoints,
188186
# and will fail (possibly silently) if both are not supplied.
@@ -343,6 +341,8 @@ def strings_in_order(cls):
343341
c_file.write("""\
344342
#include <stdint.h>
345343
344+
#include "py/objtuple.h"
345+
#include "shared-bindings/usb_hid/Device.h"
346346
#include "{H_FILE_NAME}"
347347
348348
""".format(H_FILE_NAME=h_file.name))
@@ -461,7 +461,9 @@ def strings_in_order(cls):
461461
uint16_t usb_serial_number[{serial_number_length}];
462462
uint16_t const * const string_desc_arr [{string_descriptor_length}];
463463
464-
const uint8_t hid_report_descriptor[{HID_REPORT_DESCRIPTOR_LENGTH}];
464+
const uint8_t hid_report_descriptor[{hid_report_descriptor_length}];
465+
466+
#define USB_HID_NUM_DEVICES {hid_num_devices}
465467
466468
// Vendor name included in Inquiry response, max 8 bytes
467469
#define CFG_TUD_MSC_VENDOR "{msc_vendor}"
@@ -475,44 +477,67 @@ def strings_in_order(cls):
475477
configuration_length=descriptor_length,
476478
max_configuration_length=max(hid_descriptor_length, descriptor_length),
477479
string_descriptor_length=len(pointers_to_strings),
478-
HID_REPORT_DESCRIPTOR_LENGTH=len(bytes(combined_hid_report_descriptor)),
480+
hid_report_descriptor_length=len(bytes(combined_hid_report_descriptor)),
481+
hid_num_devices=len(args.hid_devices),
479482
msc_vendor=args.manufacturer[:8],
480483
msc_product=args.product[:16]))
481484

482-
# #define the report ID's used in the combined HID descriptor
483-
for name, id in hid_report_ids_dict.items():
484-
h_file.write("""\
485-
#define USB_HID_REPORT_ID_{name} {id}
486-
""".format(name=name,
487-
id=id))
488-
489-
h_file.write("\n")
490-
491-
# #define the report sizes used in the combined HID descriptor
492-
for name, length in hid_report_lengths_dict.items():
493-
h_file.write("""\
494-
#define USB_HID_REPORT_LENGTH_{name} {length}
495-
""".format(name=name,
496-
length=length))
497-
498-
h_file.write("\n")
499-
500-
h_file.write("""\
501-
#define USB_HID_NUM_DEVICES {num_devices}
502-
#define USB_HID_MAX_REPORT_LENGTH {max_length}
503-
""".format(num_devices=len(hid_report_lengths_dict),
504-
max_length=hid_max_report_length))
505-
506-
507-
508485
# Write out the report descriptor and info
509486
c_file.write("""\
510487
const uint8_t hid_report_descriptor[{HID_DESCRIPTOR_LENGTH}] = {{
511488
""".format(HID_DESCRIPTOR_LENGTH=hid_descriptor_length))
512489

513490
for b in bytes(combined_hid_report_descriptor):
514491
c_file.write("0x{:02x}, ".format(b))
492+
c_file.write("""\
493+
};
494+
495+
""")
496+
497+
# Write out USB HID report buffer definitions.
498+
for report_id, name in enumerate(args.hid_devices, start=1):
499+
c_file.write("""\
500+
static uint8_t {name}_report_buffer[{report_length}];
501+
""".format(name=name.lower(), report_length=hid_report_descriptors.HID_DEVICE_DATA[name].report_length))
502+
503+
# Write out table of device objects.
515504
c_file.write("""
505+
usb_hid_device_obj_t usb_hid_devices[] = {
506+
""");
507+
for report_id, name in enumerate(args.hid_devices, start=1):
508+
device_data = hid_report_descriptors.HID_DEVICE_DATA[name]
509+
c_file.write("""\
510+
{{
511+
.base = {{ .type = &usb_hid_device_type }},
512+
.report_buffer = {name}_report_buffer,
513+
.report_id = {report_id:},
514+
.report_length = {report_length},
515+
.usage_page = {usage_page:#04x},
516+
.usage = {usage:#04x},
517+
}},
518+
""".format(name=name.lower(), report_id=report_id,
519+
report_length=device_data.report_length,
520+
usage_page=device_data.usage_page,
521+
usage=device_data.usage))
522+
c_file.write("""\
523+
};
524+
""")
525+
526+
# Write out tuple of device objects.
527+
c_file.write("""
528+
mp_obj_tuple_t common_hal_usb_hid_devices = {{
529+
.base = {{
530+
.type = &mp_type_tuple,
531+
}},
532+
.len = {num_devices},
533+
.items = {{
534+
""".format(num_devices=len(args.hid_devices)))
535+
for idx in range(len(args.hid_devices)):
536+
c_file.write("""\
537+
(mp_obj_t) &usb_hid_devices[{idx}],
538+
""".format(idx=idx))
539+
c_file.write("""\
540+
},
516541
};
517542
""")
518543

0 commit comments

Comments
 (0)