This commit is contained in:
Dan Halbert 2019-09-03 14:44:46 -04:00
parent 1d973a0803
commit 42f5edbd33
7 changed files with 155 additions and 21 deletions

View File

@ -3,6 +3,9 @@ USB_VID = 0x239A
USB_PID = 0x8019
USB_PRODUCT = "CircuitPlayground Express"
USB_MANUFACTURER = "Adafruit Industries LLC"
#USB_HID_DEVICES = KEYBOARD,XAC_COMPATIBLE_GAMEPAD
USB_HID_DEVICES = XAC_COMPATIBLE_GAMEPAD
CHIP_VARIANT = SAMD21G18A
CHIP_FAMILY = samd21

View File

@ -1,12 +1,16 @@
LD_FILE = boards/samd21x18-bootloader.ld
USB_VID = 0x239A
USB_PID = 0x801F
USB_HID_DEVICES=MOUSE,KEYBOARD,XAC_COMPATIBLE_GAMEPAD
USB_PRODUCT = "Trinket M0"
USB_MANUFACTURER = "Adafruit Industries LLC"
CHIP_VARIANT = SAMD21E18A
CHIP_FAMILY = samd21
INTERNAL_FLASH_FILESYSTEM = 1
LONGINT_IMPL = NONE
CIRCUITPY_SMALL_BUILD = 1

View File

@ -48,9 +48,7 @@ void common_hal_usb_hid_device_send_report(usb_hid_device_obj_t *self, uint8_t*
// Wait until interface is ready, timeout = 2 seconds
uint64_t end_ticks = ticks_ms + 2000;
while ( (ticks_ms < end_ticks) && !tud_hid_ready() ) {
#ifdef MICROPY_VM_HOOK_LOOP
MICROPY_VM_HOOK_LOOP;
#endif
RUN_BACKGROUND_TASKS;
}
if ( !tud_hid_ready() ) {

View File

@ -53,6 +53,10 @@ static uint8_t sys_control_report_buffer[USB_HID_REPORT_LENGTH_SYS_CONTROL];
static uint8_t gamepad_report_buffer[USB_HID_REPORT_LENGTH_GAMEPAD];
#endif
#ifdef USB_HID_REPORT_ID_XAC_COMPATIBLE_GAMEPAD
static uint8_t xac_compatible_gamepad_report_buffer[USB_HID_REPORT_LENGTH_XAC_COMPATIBLE_GAMEPAD];
#endif
#ifdef USB_HID_REPORT_ID_DIGITIZER
static uint8_t digitizer_report_buffer[USB_HID_REPORT_LENGTH_DIGITIZER];
#endif
@ -113,6 +117,17 @@ usb_hid_device_obj_t usb_hid_devices[] = {
},
#endif
#ifdef USB_HID_REPORT_ID_XAC_COMPATIBLE_GAMEPAD
{
.base = { .type = &usb_hid_device_type } ,
.report_buffer = xac_compatible_gamepad_report_buffer ,
.report_id = USB_HID_REPORT_ID_XAC_COMPATIBLE_GAMEPAD ,
.report_length = USB_HID_REPORT_LENGTH_XAC_COMPATIBLE_GAMEPAD ,
.usage_page = HID_USAGE_PAGE_DESKTOP ,
.usage = HID_USAGE_DESKTOP_GAMEPAD ,
},
#endif
#ifdef USB_HID_REPORT_ID_DIGITIZER
{
.base = { .type = &usb_hid_device_type } ,
@ -149,6 +164,9 @@ mp_obj_tuple_t common_hal_usb_hid_devices = {
#endif
#if USB_HID_NUM_DEVICES >= 6
(mp_obj_t) &usb_hid_devices[5],
#endif
#if USB_HID_NUM_DEVICES >= 7
#error "Too many USB HID devices"
#endif
}
};

View File

@ -81,6 +81,14 @@ else
CFLAGS += -DUSB_AVAILABLE
endif
ifndef USB_DEVICES
USB_DEVICES = "CDC,MSC,AUDIO,HID"
endif
ifndef USB_HID_DEVICES
USB_HID_DEVICES = "KEYBOARD,MOUSE,CONSUMER,GAMEPAD"
endif
SUPERVISOR_O = $(addprefix $(BUILD)/, $(SRC_SUPERVISOR:.c=.o)) $(BUILD)/autogen_display_resources.o
$(BUILD)/supervisor/shared/translate.o: $(HEADER_BUILD)/qstrdefs.generated.h
@ -98,6 +106,8 @@ autogen_usb_descriptor.intermediate: ../../tools/gen_usb_descriptor.py Makefile
--vid $(USB_VID)\
--pid $(USB_PID)\
--serial_number_length $(USB_SERIAL_NUMBER_LENGTH)\
--devices $(USB_DEVICES) \
--hid_devices $(USB_HID_DEVICES) \
--output_c_file $(BUILD)/autogen_usb_descriptor.c\
--output_h_file $(BUILD)/genhdr/autogen_usb_descriptor.h

View File

@ -8,6 +8,15 @@ sys.path.append("../../tools/usb_descriptor")
from adafruit_usb_descriptor import audio, audio10, cdc, hid, midi, msc, standard, util
import hid_report_descriptors
ALL_DEVICES='CDC,MSC,AUDIO,HID'
ALL_DEVICES_SET=frozenset(ALL_DEVICES.split(','))
DEFAULT_DEVICES='CDC,MSC,AUDIO,HID'
ALL_HID_DEVICES='KEYBOARD,MOUSE,CONSUMER,SYS_CONTROL,GAMEPAD,DIGITIZER,XAC_COMPATIBLE_GAMEPAD'
ALL_HID_DEVICES_SET=frozenset(ALL_HID_DEVICES.split(','))
# Digitizer works on Linux but conflicts with mouse, so omit it.
DEFAULT_HID_DEVICES='KEYBOARD,MOUSE,CONSUMER,GAMEPAD'
parser = argparse.ArgumentParser(description='Generate USB descriptors.')
parser.add_argument('--manufacturer', type=str,
help='manufacturer of the device')
@ -19,11 +28,24 @@ parser.add_argument('--pid', type=lambda x: int(x, 16),
help='product id')
parser.add_argument('--serial_number_length', type=int, default=32,
help='length needed for the serial number in digits')
parser.add_argument('--devices', type=lambda l: frozenset(l.split(',')), default=DEFAULT_DEVICES,
help='devices to include in descriptor (AUDIO includes MIDI support)')
parser.add_argument('--hid_devices', type=lambda l: frozenset(l.split(',')), default=DEFAULT_HID_DEVICES,
help='HID devices to include in HID report descriptor')
parser.add_argument('--output_c_file', type=argparse.FileType('w'), required=True)
parser.add_argument('--output_h_file', type=argparse.FileType('w'), required=True)
args = parser.parse_args()
unknown_devices = list(args.devices - ALL_DEVICES_SET)
if unknown_devices:
raise ValueError("Unknown device(s)", unknown_devices)
unknown_hid_devices = list(args.hid_devices - ALL_HID_DEVICES_SET)
if unknown_hid_devices:
raise ValueError("Unknown HID devices(s)", unknown_hid_devices)
class StringIndex:
"""Assign a monotonically increasing index to each unique string. Start with 0."""
string_to_index = {}
@ -138,16 +160,27 @@ msc_interfaces = [
)
]
# Include only these HID devices.
# DIGITIZER works on Linux but conflicts with MOUSE, so leave it out for now.
hid_devices = ("KEYBOARD", "MOUSE", "CONSUMER", "GAMEPAD")
# Sort by Report ID for consistency.
hid_devices = sorted(args.hid_devices, key=lambda name: hid_report_descriptors.REPORT_IDS[name])
combined_hid_report_descriptor = hid.ReportDescriptor(
# When there's only one hid_device, it can't be in a composite descriptor.
# It has no report id (indicated by 0), so remove the existing one.
#if len(hid_devices) == 1:
if False:
name = hid_devices[0]
combined_hid_report_descriptor = hid.ReportDescriptor(
description=name,
report_descriptor=hid_report_descriptors.remove_report_id(
hid_report_descriptors.REPORT_DESCRIPTORS[name].report_descriptor))
hid_report_ids_dict = { name : 0 }
else:
combined_hid_report_descriptor = hid.ReportDescriptor(
description="MULTIDEVICE",
report_descriptor=b''.join(
hid_report_descriptors.REPORT_DESCRIPTORS[name].report_descriptor for name in hid_devices ))
hid_report_ids_dict = { name: hid_report_descriptors.REPORT_IDS[name] for name in hid_devices }
hid_report_ids_dict = { name: hid_report_descriptors.REPORT_IDS[name] for name in hid_devices }
hid_report_lengths_dict = { name: hid_report_descriptors.REPORT_LENGTHS[name] for name in hid_devices }
hid_max_report_length = max(hid_report_lengths_dict.values())
@ -271,19 +304,27 @@ cdc_iad = standard.InterfaceAssociationDescriptor(
bFunctionProtocol=cdc.CDC_PROTOCOL_NONE)
descriptor_list = []
descriptor_list.append(cdc_iad)
descriptor_list.extend(cdc_interfaces)
descriptor_list.extend(msc_interfaces)
# Only add the control interface because other audio interfaces are managed by it to ensure the
# correct ordering.
descriptor_list.append(audio_control_interface)
# Put the CDC IAD just before the CDC interfaces.
# There appears to be a bug in the Windows composite USB driver that requests the
# HID report descriptor with the wrong interface number if the HID interface is not given
# first. However, it still fetches the descriptor anyway. We could reorder the interfaces but
# the Windows 7 Adafruit_usbser.inf file thinks CDC is at Interface 0, so we'll leave it
# there for backwards compatibility.
descriptor_list.extend(hid_interfaces)
if 'CDC' in args.devices:
# Put the CDC IAD just before the CDC interfaces.
# There appears to be a bug in the Windows composite USB driver that requests the
# HID report descriptor with the wrong interface number if the HID interface is not given
# first. However, it still fetches the descriptor anyway. We could reorder the interfaces but
# the Windows 7 Adafruit_usbser.inf file thinks CDC is at Interface 0, so we'll leave it
# there for backwards compatibility.
descriptor_list.append(cdc_iad)
descriptor_list.extend(cdc_interfaces)
if 'MSC' in args.devices:
descriptor_list.extend(msc_interfaces)
if 'AUDIO' in args.devices:
# Only add the control interface because other audio interfaces are managed by it to ensure the
# correct ordering.
descriptor_list.append(audio_control_interface)
if 'HID' in args.devices:
descriptor_list.extend(hid_interfaces)
configuration = standard.ConfigurationDescriptor(
description="Composite configuration",

View File

@ -31,6 +31,11 @@ HID specific descriptors
from adafruit_usb_descriptor import hid
def remove_report_id(report_descriptor_bytes):
#return report_descriptor_bytes
report_id_pos = report_descriptor_bytes.index(0x85)
return report_descriptor_bytes[:report_id_pos] + report_descriptor_bytes[report_id_pos + 2:]
REPORT_IDS = {
"KEYBOARD" : 1,
"MOUSE" : 2,
@ -38,6 +43,9 @@ REPORT_IDS = {
"SYS_CONTROL" : 4,
"GAMEPAD" : 5,
"DIGITIZER" : 6,
"XAC_COMPATIBLE_GAMEPAD" : 7,
# RAW must not have a report ID, so it can't be used with other devices.
"RAW" : 0,
}
# Byte count for each kind of report. Length does not include report ID in first byte.
@ -48,6 +56,8 @@ REPORT_LENGTHS = {
"SYS_CONTROL" : 1,
"GAMEPAD" : 6,
"DIGITIZER" : 5,
"XAC_COMPATIBLE_GAMEPAD" : 3,
"RAW" : 64,
}
KEYBOARD_WITH_ID = hid.ReportDescriptor(
@ -228,6 +238,54 @@ DIGITIZER_WITH_ID = hid.ReportDescriptor(
0xC0, # End Collection
]))
XAC_COMPATIBLE_GAMEPAD_WITH_ID = hid.ReportDescriptor(
description="XAC",
report_descriptor=bytes([
# This descriptor mimics the simple joystick from PDP that the XBox likes
0x05, 0x01, # Usage Page (Desktop),
0x09, 0x05, # Usage (Gamepad),
0xA1, 0x01, # Collection (Application),
0x85, REPORT_IDS["XAC_COMPATIBLE_GAMEPAD"], # Report ID (n)
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, 0x08, # Report Count (8),
0x05, 0x09, # Usage Page (Button),
0x19, 0x01, # Usage Minimum (01h),
0x29, 0x08, # Usage Maximum (08h),
0x81, 0x02, # Input (Variable),
0x05, 0x01, # Usage Page (Desktop),
0x26, 0xFF, 0x00, # Logical Maximum (255),
0x46, 0xFF, 0x00, # Physical Maximum (255),
0x09, 0x30, # Usage (X),
0x09, 0x31, # Usage (Y),
0x75, 0x08, # Report Size (8),
0x95, 0x02, # Report Count (2),
0x81, 0x02, # Input (Variable),
0xC0 # End Collection
]))
RAW = hid.ReportDescriptor(
description="RAW",
report_descriptor=bytes([
# Provide vendor-defined
0x06, 0xAF, 0xFF, # Usage Page (Vendor 0xFFAF "Adafruit"),
0x09, 0xAF, # Usage (AF),
0xA1, 0x01, # Collection (Application),
0x75, 0x08, # Report Size (8),
0x15, 0x00, # Logical Minimum (0),
0x26, 0xFF, 0x00 # Logical Maximum (255),
0x95, 0x08, # Report Count (8),
0x09, 0x01 # Usage(xxx)
0x81, 0x02 # Input (Variable)
0x95, 0x08, # Report Count (8),
0x09, 0x02, # Usage(xxx)
0x91, 0x02, # Input (Variable)
0xC0 # End Collection
]))
# Byte count for each kind of report. Length does not include report ID in first byte.
REPORT_DESCRIPTORS = {
"KEYBOARD" : KEYBOARD_WITH_ID,
@ -236,4 +294,6 @@ REPORT_DESCRIPTORS = {
"SYS_CONTROL" : SYS_CONTROL_WITH_ID,
"GAMEPAD" : GAMEPAD_WITH_ID,
"DIGITIZER" : DIGITIZER_WITH_ID,
"XAC_COMPATIBLE_GAMEPAD" : XAC_COMPATIBLE_GAMEPAD_WITH_ID,
"RAW" : RAW_WITH_ID,
}