Skip to content

Commit 42f5edb

Browse files
committed
WIP
1 parent 1d973a0 commit 42f5edb

7 files changed

Lines changed: 156 additions & 22 deletions

File tree

ports/atmel-samd/boards/circuitplayground_express/mpconfigboard.mk

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@ USB_VID = 0x239A
33
USB_PID = 0x8019
44
USB_PRODUCT = "CircuitPlayground Express"
55
USB_MANUFACTURER = "Adafruit Industries LLC"
6+
#USB_HID_DEVICES = KEYBOARD,XAC_COMPATIBLE_GAMEPAD
7+
USB_HID_DEVICES = XAC_COMPATIBLE_GAMEPAD
8+
69

710
CHIP_VARIANT = SAMD21G18A
811
CHIP_FAMILY = samd21

ports/atmel-samd/boards/trinket_m0/mpconfigboard.mk

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,16 @@
11
LD_FILE = boards/samd21x18-bootloader.ld
22
USB_VID = 0x239A
33
USB_PID = 0x801F
4+
5+
USB_HID_DEVICES=MOUSE,KEYBOARD,XAC_COMPATIBLE_GAMEPAD
6+
47
USB_PRODUCT = "Trinket M0"
58
USB_MANUFACTURER = "Adafruit Industries LLC"
69

710
CHIP_VARIANT = SAMD21E18A
811
CHIP_FAMILY = samd21
912

13+
1014
INTERNAL_FLASH_FILESYSTEM = 1
1115
LONGINT_IMPL = NONE
1216
CIRCUITPY_SMALL_BUILD = 1

shared-module/usb_hid/Device.c

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -48,9 +48,7 @@ void common_hal_usb_hid_device_send_report(usb_hid_device_obj_t *self, uint8_t*
4848
// Wait until interface is ready, timeout = 2 seconds
4949
uint64_t end_ticks = ticks_ms + 2000;
5050
while ( (ticks_ms < end_ticks) && !tud_hid_ready() ) {
51-
#ifdef MICROPY_VM_HOOK_LOOP
52-
MICROPY_VM_HOOK_LOOP;
53-
#endif
51+
RUN_BACKGROUND_TASKS;
5452
}
5553

5654
if ( !tud_hid_ready() ) {

shared-module/usb_hid/__init__.c

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,10 @@ static uint8_t sys_control_report_buffer[USB_HID_REPORT_LENGTH_SYS_CONTROL];
5353
static uint8_t gamepad_report_buffer[USB_HID_REPORT_LENGTH_GAMEPAD];
5454
#endif
5555

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+
5660
#ifdef USB_HID_REPORT_ID_DIGITIZER
5761
static uint8_t digitizer_report_buffer[USB_HID_REPORT_LENGTH_DIGITIZER];
5862
#endif
@@ -113,6 +117,17 @@ usb_hid_device_obj_t usb_hid_devices[] = {
113117
},
114118
#endif
115119

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+
116131
#ifdef USB_HID_REPORT_ID_DIGITIZER
117132
{
118133
.base = { .type = &usb_hid_device_type } ,
@@ -149,6 +164,9 @@ mp_obj_tuple_t common_hal_usb_hid_devices = {
149164
#endif
150165
#if USB_HID_NUM_DEVICES >= 6
151166
(mp_obj_t) &usb_hid_devices[5],
167+
#endif
168+
#if USB_HID_NUM_DEVICES >= 7
169+
#error "Too many USB HID devices"
152170
#endif
153171
}
154172
};

supervisor/supervisor.mk

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,14 @@ else
8181
CFLAGS += -DUSB_AVAILABLE
8282
endif
8383

84+
ifndef USB_DEVICES
85+
USB_DEVICES = "CDC,MSC,AUDIO,HID"
86+
endif
87+
88+
ifndef USB_HID_DEVICES
89+
USB_HID_DEVICES = "KEYBOARD,MOUSE,CONSUMER,GAMEPAD"
90+
endif
91+
8492
SUPERVISOR_O = $(addprefix $(BUILD)/, $(SRC_SUPERVISOR:.c=.o)) $(BUILD)/autogen_display_resources.o
8593

8694
$(BUILD)/supervisor/shared/translate.o: $(HEADER_BUILD)/qstrdefs.generated.h
@@ -98,6 +106,8 @@ autogen_usb_descriptor.intermediate: ../../tools/gen_usb_descriptor.py Makefile
98106
--vid $(USB_VID)\
99107
--pid $(USB_PID)\
100108
--serial_number_length $(USB_SERIAL_NUMBER_LENGTH)\
109+
--devices $(USB_DEVICES) \
110+
--hid_devices $(USB_HID_DEVICES) \
101111
--output_c_file $(BUILD)/autogen_usb_descriptor.c\
102112
--output_h_file $(BUILD)/genhdr/autogen_usb_descriptor.h
103113

tools/gen_usb_descriptor.py

Lines changed: 60 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,15 @@
88
from adafruit_usb_descriptor import audio, audio10, cdc, hid, midi, msc, standard, util
99
import hid_report_descriptors
1010

11+
ALL_DEVICES='CDC,MSC,AUDIO,HID'
12+
ALL_DEVICES_SET=frozenset(ALL_DEVICES.split(','))
13+
DEFAULT_DEVICES='CDC,MSC,AUDIO,HID'
14+
15+
ALL_HID_DEVICES='KEYBOARD,MOUSE,CONSUMER,SYS_CONTROL,GAMEPAD,DIGITIZER,XAC_COMPATIBLE_GAMEPAD'
16+
ALL_HID_DEVICES_SET=frozenset(ALL_HID_DEVICES.split(','))
17+
# Digitizer works on Linux but conflicts with mouse, so omit it.
18+
DEFAULT_HID_DEVICES='KEYBOARD,MOUSE,CONSUMER,GAMEPAD'
19+
1120
parser = argparse.ArgumentParser(description='Generate USB descriptors.')
1221
parser.add_argument('--manufacturer', type=str,
1322
help='manufacturer of the device')
@@ -19,11 +28,24 @@
1928
help='product id')
2029
parser.add_argument('--serial_number_length', type=int, default=32,
2130
help='length needed for the serial number in digits')
31+
parser.add_argument('--devices', type=lambda l: frozenset(l.split(',')), default=DEFAULT_DEVICES,
32+
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,
34+
help='HID devices to include in HID report descriptor')
2235
parser.add_argument('--output_c_file', type=argparse.FileType('w'), required=True)
2336
parser.add_argument('--output_h_file', type=argparse.FileType('w'), required=True)
2437

2538
args = parser.parse_args()
2639

40+
unknown_devices = list(args.devices - ALL_DEVICES_SET)
41+
if unknown_devices:
42+
raise ValueError("Unknown device(s)", unknown_devices)
43+
44+
unknown_hid_devices = list(args.hid_devices - ALL_HID_DEVICES_SET)
45+
if unknown_hid_devices:
46+
raise ValueError("Unknown HID devices(s)", unknown_hid_devices)
47+
48+
2749
class StringIndex:
2850
"""Assign a monotonically increasing index to each unique string. Start with 0."""
2951
string_to_index = {}
@@ -138,16 +160,27 @@ def strings_in_order(cls):
138160
)
139161
]
140162

141-
# Include only these HID devices.
142-
# DIGITIZER works on Linux but conflicts with MOUSE, so leave it out for now.
143-
hid_devices = ("KEYBOARD", "MOUSE", "CONSUMER", "GAMEPAD")
144-
145-
combined_hid_report_descriptor = hid.ReportDescriptor(
163+
# Sort by Report ID for consistency.
164+
hid_devices = sorted(args.hid_devices, key=lambda name: hid_report_descriptors.REPORT_IDS[name])
165+
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]
172+
combined_hid_report_descriptor = hid.ReportDescriptor(
173+
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 }
177+
else:
178+
combined_hid_report_descriptor = hid.ReportDescriptor(
146179
description="MULTIDEVICE",
147180
report_descriptor=b''.join(
148181
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 }
149183

150-
hid_report_ids_dict = { name: hid_report_descriptors.REPORT_IDS[name] for name in hid_devices }
151184
hid_report_lengths_dict = { name: hid_report_descriptors.REPORT_LENGTHS[name] for name in hid_devices }
152185
hid_max_report_length = max(hid_report_lengths_dict.values())
153186

@@ -271,19 +304,27 @@ def strings_in_order(cls):
271304
bFunctionProtocol=cdc.CDC_PROTOCOL_NONE)
272305

273306
descriptor_list = []
274-
descriptor_list.append(cdc_iad)
275-
descriptor_list.extend(cdc_interfaces)
276-
descriptor_list.extend(msc_interfaces)
277-
# Only add the control interface because other audio interfaces are managed by it to ensure the
278-
# correct ordering.
279-
descriptor_list.append(audio_control_interface)
280-
# Put the CDC IAD just before the CDC interfaces.
281-
# There appears to be a bug in the Windows composite USB driver that requests the
282-
# HID report descriptor with the wrong interface number if the HID interface is not given
283-
# first. However, it still fetches the descriptor anyway. We could reorder the interfaces but
284-
# the Windows 7 Adafruit_usbser.inf file thinks CDC is at Interface 0, so we'll leave it
285-
# there for backwards compatibility.
286-
descriptor_list.extend(hid_interfaces)
307+
308+
if 'CDC' in args.devices:
309+
# Put the CDC IAD just before the CDC interfaces.
310+
# There appears to be a bug in the Windows composite USB driver that requests the
311+
# HID report descriptor with the wrong interface number if the HID interface is not given
312+
# first. However, it still fetches the descriptor anyway. We could reorder the interfaces but
313+
# the Windows 7 Adafruit_usbser.inf file thinks CDC is at Interface 0, so we'll leave it
314+
# there for backwards compatibility.
315+
descriptor_list.append(cdc_iad)
316+
descriptor_list.extend(cdc_interfaces)
317+
318+
if 'MSC' in args.devices:
319+
descriptor_list.extend(msc_interfaces)
320+
321+
if 'AUDIO' in args.devices:
322+
# Only add the control interface because other audio interfaces are managed by it to ensure the
323+
# correct ordering.
324+
descriptor_list.append(audio_control_interface)
325+
326+
if 'HID' in args.devices:
327+
descriptor_list.extend(hid_interfaces)
287328

288329
configuration = standard.ConfigurationDescriptor(
289330
description="Composite configuration",

tools/hid_report_descriptors.py

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,13 +31,21 @@
3131

3232
from adafruit_usb_descriptor import hid
3333

34+
def remove_report_id(report_descriptor_bytes):
35+
#return report_descriptor_bytes
36+
report_id_pos = report_descriptor_bytes.index(0x85)
37+
return report_descriptor_bytes[:report_id_pos] + report_descriptor_bytes[report_id_pos + 2:]
38+
3439
REPORT_IDS = {
3540
"KEYBOARD" : 1,
3641
"MOUSE" : 2,
3742
"CONSUMER" : 3,
3843
"SYS_CONTROL" : 4,
3944
"GAMEPAD" : 5,
4045
"DIGITIZER" : 6,
46+
"XAC_COMPATIBLE_GAMEPAD" : 7,
47+
# RAW must not have a report ID, so it can't be used with other devices.
48+
"RAW" : 0,
4149
}
4250

4351
# Byte count for each kind of report. Length does not include report ID in first byte.
@@ -48,6 +56,8 @@
4856
"SYS_CONTROL" : 1,
4957
"GAMEPAD" : 6,
5058
"DIGITIZER" : 5,
59+
"XAC_COMPATIBLE_GAMEPAD" : 3,
60+
"RAW" : 64,
5161
}
5262

5363
KEYBOARD_WITH_ID = hid.ReportDescriptor(
@@ -228,6 +238,54 @@
228238
0xC0, # End Collection
229239
]))
230240

241+
XAC_COMPATIBLE_GAMEPAD_WITH_ID = hid.ReportDescriptor(
242+
description="XAC",
243+
report_descriptor=bytes([
244+
# This descriptor mimics the simple joystick from PDP that the XBox likes
245+
0x05, 0x01, # Usage Page (Desktop),
246+
0x09, 0x05, # Usage (Gamepad),
247+
0xA1, 0x01, # Collection (Application),
248+
0x85, REPORT_IDS["XAC_COMPATIBLE_GAMEPAD"], # Report ID (n)
249+
0x15, 0x00, # Logical Minimum (0),
250+
0x25, 0x01, # Logical Maximum (1),
251+
0x35, 0x00, # Physical Minimum (0),
252+
0x45, 0x01, # Physical Maximum (1),
253+
0x75, 0x01, # Report Size (1),
254+
0x95, 0x08, # Report Count (8),
255+
0x05, 0x09, # Usage Page (Button),
256+
0x19, 0x01, # Usage Minimum (01h),
257+
0x29, 0x08, # Usage Maximum (08h),
258+
0x81, 0x02, # Input (Variable),
259+
0x05, 0x01, # Usage Page (Desktop),
260+
0x26, 0xFF, 0x00, # Logical Maximum (255),
261+
0x46, 0xFF, 0x00, # Physical Maximum (255),
262+
0x09, 0x30, # Usage (X),
263+
0x09, 0x31, # Usage (Y),
264+
0x75, 0x08, # Report Size (8),
265+
0x95, 0x02, # Report Count (2),
266+
0x81, 0x02, # Input (Variable),
267+
0xC0 # End Collection
268+
]))
269+
270+
RAW = hid.ReportDescriptor(
271+
description="RAW",
272+
report_descriptor=bytes([
273+
# Provide vendor-defined
274+
0x06, 0xAF, 0xFF, # Usage Page (Vendor 0xFFAF "Adafruit"),
275+
0x09, 0xAF, # Usage (AF),
276+
0xA1, 0x01, # Collection (Application),
277+
0x75, 0x08, # Report Size (8),
278+
0x15, 0x00, # Logical Minimum (0),
279+
0x26, 0xFF, 0x00 # Logical Maximum (255),
280+
0x95, 0x08, # Report Count (8),
281+
0x09, 0x01 # Usage(xxx)
282+
0x81, 0x02 # Input (Variable)
283+
0x95, 0x08, # Report Count (8),
284+
0x09, 0x02, # Usage(xxx)
285+
0x91, 0x02, # Input (Variable)
286+
0xC0 # End Collection
287+
]))
288+
231289
# Byte count for each kind of report. Length does not include report ID in first byte.
232290
REPORT_DESCRIPTORS = {
233291
"KEYBOARD" : KEYBOARD_WITH_ID,
@@ -236,4 +294,6 @@
236294
"SYS_CONTROL" : SYS_CONTROL_WITH_ID,
237295
"GAMEPAD" : GAMEPAD_WITH_ID,
238296
"DIGITIZER" : DIGITIZER_WITH_ID,
297+
"XAC_COMPATIBLE_GAMEPAD" : XAC_COMPATIBLE_GAMEPAD_WITH_ID,
298+
"RAW" : RAW_WITH_ID,
239299
}

0 commit comments

Comments
 (0)