summaryrefslogtreecommitdiff
path: root/tools
diff options
context:
space:
mode:
authorDan Halbert <halbert@halwitz.org>2021-02-11 18:50:02 -0500
committerDan Halbert <halbert@halwitz.org>2021-02-11 18:50:02 -0500
commitf0564b49862eaef0b9752b62d80ef00e3e12a3ee (patch)
tree79a48a30955bdc7ae4e1971135809a0593130417 /tools
parent1b7f3d11e73be5cb0f7a97a528fedad87624b97f (diff)
parent206109763f3d8b8dc92a5f5bf1bfabb49ce9c7b7 (diff)
merge from upstream; complicated webusb merge
Diffstat (limited to 'tools')
-rw-r--r--tools/gen_display_resources.py4
-rw-r--r--tools/gen_usb_descriptor.py332
2 files changed, 262 insertions, 74 deletions
diff --git a/tools/gen_display_resources.py b/tools/gen_display_resources.py
index 6657b6a27..141e6ee2a 100644
--- a/tools/gen_display_resources.py
+++ b/tools/gen_display_resources.py
@@ -8,8 +8,8 @@ import os
import struct
import sys
-sys.path.append("bitmap_font")
-sys.path.append("../../tools/bitmap_font")
+sys.path.insert(0, "bitmap_font")
+sys.path.insert(0, "../../tools/bitmap_font")
from adafruit_bitmap_font import bitmap_font
diff --git a/tools/gen_usb_descriptor.py b/tools/gen_usb_descriptor.py
index 199cdf9cf..b056f853a 100644
--- a/tools/gen_usb_descriptor.py
+++ b/tools/gen_usb_descriptor.py
@@ -13,7 +13,7 @@ from adafruit_usb_descriptor import audio, audio10, cdc, hid, midi, msc, standar
import hid_report_descriptors
DEFAULT_INTERFACE_NAME = "CircuitPython"
-ALL_DEVICES = "CDC CDC2 MSC AUDIO HID"
+ALL_DEVICES = "CDC CDC2 MSC AUDIO HID VENDOR"
ALL_DEVICES_SET = frozenset(ALL_DEVICES.split())
DEFAULT_DEVICES = "CDC MSC AUDIO HID"
@@ -24,6 +24,11 @@ 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"
+# In the following URL, don't include the https:// because that prefix gets added automatically
+DEFAULT_WEBUSB_URL = (
+ "circuitpython.org" # In the future, this may become a specific landing page
+)
+
parser = argparse.ArgumentParser(description="Generate USB descriptors.")
parser.add_argument(
"--highspeed",
@@ -99,6 +104,18 @@ parser.add_argument(
"--max_ep", type=int, default=0, help="total number of endpoints available"
)
parser.add_argument(
+ "--webusb_url",
+ type=str,
+ help="The URL to include in the WebUSB URL Descriptor",
+ default=DEFAULT_WEBUSB_URL,
+)
+parser.add_argument(
+ "--vendor_ep_num_out", type=int, default=0, help="endpoint number of VENDOR OUT"
+)
+parser.add_argument(
+ "--vendor_ep_num_in", type=int, default=0, help="endpoint number of VENDOR IN"
+)
+parser.add_argument(
"--output_c_file", type=argparse.FileType("w", encoding="UTF-8"), required=True
)
parser.add_argument(
@@ -120,6 +137,7 @@ include_cdc2 = "CDC2" in args.devices
include_msc = "MSC" in args.devices
include_hid = "HID" in args.devices
include_audio = "AUDIO" in args.devices
+include_vendor = "VENDOR" in args.devices
if not include_cdc and include_cdc2:
raise ValueError("CDC2 requested without CDC")
@@ -154,6 +172,12 @@ if not args.renumber_endpoints:
elif args.midi_ep_num_in == 0:
raise ValueError("MIDI endpoint IN number must not be 0")
+ if include_vendor:
+ if args.vendor_ep_num_out == 0:
+ raise ValueError("VENDOR endpoint OUT number must not be 0")
+ elif args.vendor_ep_num_in == 0:
+ raise ValueError("VENDOR endpoint IN number must not be 0")
+
class StringIndex:
"""Assign a monotonically increasing index to each unique string. Start with 0."""
@@ -273,7 +297,7 @@ if include_cdc:
cdc_comm_interface = make_cdc_comm_interface("CDC", cdc_union)
cdc_data_interface = make_cdc_data_interface("CDC")
- cdc_interfaces = [cdc_comm_interface, cdc_data_interface]
+cdc_interfaces = [cdc_comm_interface, cdc_data_interface]
if include_cdc2:
cdc2_union = make_cdc_union("CDC2")
@@ -472,6 +496,38 @@ if include_audio:
+ cs_ac_interface.midi_streaming_interfaces
)
+if include_vendor:
+ # Vendor-specific interface, for example WebUSB
+ vendor_endpoint_in_descriptor = standard.EndpointDescriptor(
+ description="VENDOR in",
+ bEndpointAddress=args.vendor_ep_num_in
+ | standard.EndpointDescriptor.DIRECTION_IN,
+ bmAttributes=standard.EndpointDescriptor.TYPE_BULK,
+ bInterval=16,
+ )
+
+ vendor_endpoint_out_descriptor = standard.EndpointDescriptor(
+ description="VENDOR out",
+ bEndpointAddress=args.vendor_ep_num_out
+ | standard.EndpointDescriptor.DIRECTION_OUT,
+ bmAttributes=standard.EndpointDescriptor.TYPE_BULK,
+ bInterval=16,
+ )
+
+ vendor_interface = standard.InterfaceDescriptor(
+ description="VENDOR",
+ bInterfaceClass=0xFF, # Vendor-specific
+ bInterfaceSubClass=0x00,
+ bInterfaceProtocol=0x00,
+ iInterface=StringIndex.index("{} VENDOR".format(args.interface_name)),
+ subdescriptors=[
+ vendor_endpoint_in_descriptor,
+ vendor_endpoint_out_descriptor,
+ ],
+ )
+
+ vendor_interfaces = [vendor_interface]
+
interfaces_to_join = []
if include_cdc:
@@ -489,6 +545,9 @@ if include_hid:
if include_audio:
interfaces_to_join.append(audio_interfaces)
+if include_vendor:
+ interfaces_to_join.append(vendor_interfaces)
+
# util.join_interfaces() will renumber the endpoints to make them unique across descriptors,
# and renumber the interfaces in order. But we still need to fix up certain
# interface cross-references.
@@ -502,7 +561,7 @@ if args.max_ep != 0:
endpoint_address = getattr(subdescriptor, "bEndpointAddress", 0) & 0x7F
if endpoint_address >= args.max_ep:
raise ValueError(
- "Endpoint address %d of %s must be less than %d"
+ "Endpoint address %d of '%s' must be less than %d; you have probably run out of endpoints"
% (endpoint_address & 0x7F, interface.description, args.max_ep)
)
else:
@@ -569,6 +628,9 @@ if include_audio:
# correct ordering.
descriptor_list.append(audio_control_interface)
+if include_vendor:
+ descriptor_list.extend(vendor_interfaces)
+
# Finally, build the composite descriptor.
configuration = standard.ConfigurationDescriptor(
@@ -594,6 +656,7 @@ c_file.write(
"""\
#include <stdint.h>
+#include "tusb.h"
#include "py/objtuple.h"
#include "shared-bindings/usb_hid/Device.h"
#include "{H_FILE_NAME}"
@@ -732,9 +795,12 @@ c_file.write(
c_file.write("\n")
-hid_descriptor_length = len(bytes(combined_hid_report_descriptor))
+if include_hid:
+ hid_descriptor_length = len(bytes(combined_hid_report_descriptor))
+else:
+ hid_descriptor_length = 0
-# Now we values we need for the .h file.
+# Now the values we need for the .h file.
h_file.write(
"""\
#ifndef MICROPY_INCLUDED_AUTOGEN_USB_DESCRIPTOR_H
@@ -747,12 +813,8 @@ extern const uint8_t usb_desc_cfg[{configuration_length}];
extern uint16_t usb_serial_number[{serial_number_length}];
extern uint16_t const * const string_desc_arr [{string_descriptor_length}];
-extern const uint8_t hid_report_descriptor[{hid_report_descriptor_length}];
-
#define CFG_TUSB_RHPORT0_MODE ({rhport0_mode})
-#define USB_HID_NUM_DEVICES {hid_num_devices}
-
// Vendor name included in Inquiry response, max 8 bytes
#define CFG_TUD_MSC_VENDOR "{msc_vendor}"
@@ -765,7 +827,6 @@ extern const uint8_t hid_report_descriptor[{hid_report_descriptor_length}];
configuration_length=descriptor_length,
max_configuration_length=max(hid_descriptor_length, descriptor_length),
string_descriptor_length=len(pointers_to_strings),
- hid_report_descriptor_length=len(bytes(combined_hid_report_descriptor)),
rhport0_mode="OPT_MODE_DEVICE | OPT_MODE_HIGH_SPEED"
if args.highspeed
else "OPT_MODE_DEVICE",
@@ -775,62 +836,96 @@ extern const uint8_t hid_report_descriptor[{hid_report_descriptor_length}];
)
)
-# Write out the report descriptor and info
-c_file.write(
- """\
-const uint8_t hid_report_descriptor[{HID_DESCRIPTOR_LENGTH}] = {{
+if include_hid:
+ h_file.write(
+ """\
+extern const uint8_t hid_report_descriptor[{hid_report_descriptor_length}];
+
+#define USB_HID_NUM_DEVICES {hid_num_devices}
""".format(
- HID_DESCRIPTOR_LENGTH=hid_descriptor_length
+ hid_report_descriptor_length=len(bytes(combined_hid_report_descriptor)),
)
)
-for b in bytes(combined_hid_report_descriptor):
- c_file.write("0x{:02x}, ".format(b))
-c_file.write(
- """\
+if include_vendor:
+ h_file.write(
+ """\
+enum
+{
+ VENDOR_REQUEST_WEBUSB = 1,
+ VENDOR_REQUEST_MICROSOFT = 2
};
+extern uint8_t const desc_ms_os_20[];
+
+// Currently getting compile-time errors in files like tusb_fifo.c
+// if we try do define this here (TODO figure this out!)
+//extern const tusb_desc_webusb_url_t desc_webusb_url;
+
+"""
+ )
+
+h_file.write(
+ """\
+#endif // MICROPY_INCLUDED_AUTOGEN_USB_DESCRIPTOR_H
"""
)
-# Write out USB HID report buffer definitions.
-for name in args.hid_devices:
+if include_hid:
+ # Write out the report descriptor and info
c_file.write(
"""\
-static uint8_t {name}_report_buffer[{report_length}];
-""".format(
- name=name.lower(),
- report_length=hid_report_descriptors.HID_DEVICE_DATA[name].report_length,
- )
+const uint8_t hid_report_descriptor[{HID_DESCRIPTOR_LENGTH}] = {{
+""".format(HID_DESCRIPTOR_LENGTH=hid_descriptor_length))
+
+ for b in bytes(combined_hid_report_descriptor):
+ c_file.write("0x{:02x}, ".format(b))
+
+ c_file.write(
+ """\
+};
+
+"""
)
- if hid_report_descriptors.HID_DEVICE_DATA[name].out_report_length > 0:
+ # Write out USB HID report buffer definitions.
+ for name in args.hid_devices:
c_file.write(
"""\
-static uint8_t {name}_out_report_buffer[{report_length}];
+static uint8_t {name}_report_buffer[{report_length}];
""".format(
name=name.lower(),
- report_length=hid_report_descriptors.HID_DEVICE_DATA[
- name
- ].out_report_length,
+ report_length=hid_report_descriptors.HID_DEVICE_DATA[name].report_length,
)
)
-# Write out table of device objects.
-c_file.write(
- """
+ if hid_report_descriptors.HID_DEVICE_DATA[name].out_report_length > 0:
+ c_file.write(
+ """\
+static uint8_t {name}_out_report_buffer[{report_length}];
+""".format(
+ name=name.lower(),
+ report_length=hid_report_descriptors.HID_DEVICE_DATA[
+ name
+ ].out_report_length,
+ )
+ )
+
+ # Write out table of device objects.
+ c_file.write(
+ """\
usb_hid_device_obj_t usb_hid_devices[] = {
"""
-)
-for name in args.hid_devices:
- device_data = hid_report_descriptors.HID_DEVICE_DATA[name]
- out_report_buffer = (
- "{}_out_report_buffer".format(name.lower())
- if device_data.out_report_length > 0
- else "NULL"
)
- c_file.write(
- """\
+ for name in args.hid_devices:
+ device_data = hid_report_descriptors.HID_DEVICE_DATA[name]
+ out_report_buffer = (
+ "{}_out_report_buffer".format(name.lower())
+ if device_data.out_report_length > 0
+ else "NULL"
+ )
+ c_file.write(
+ """\
{{
.base = {{ .type = &usb_hid_device_type }},
.report_buffer = {name}_report_buffer,
@@ -842,24 +937,24 @@ for name in args.hid_devices:
.out_report_length = {out_report_length},
}},
""".format(
- name=name.lower(),
- report_id=report_ids[name],
- report_length=device_data.report_length,
- usage_page=device_data.usage_page,
- usage=device_data.usage,
- out_report_buffer=out_report_buffer,
- out_report_length=device_data.out_report_length,
+ name=name.lower(),
+ report_id=report_ids[name],
+ report_length=device_data.report_length,
+ usage_page=device_data.usage_page,
+ usage=device_data.usage,
+ out_report_buffer=out_report_buffer,
+ out_report_length=device_data.out_report_length,
+ )
)
- )
-c_file.write(
- """\
+ c_file.write(
+ """\
};
"""
-)
+ )
-# Write out tuple of device objects.
-c_file.write(
- """
+ # Write out tuple of device objects.
+ c_file.write(
+ """
mp_obj_tuple_t common_hal_usb_hid_devices = {{
.base = {{
.type = &mp_type_tuple,
@@ -867,26 +962,119 @@ mp_obj_tuple_t common_hal_usb_hid_devices = {{
.len = {num_devices},
.items = {{
""".format(
- num_devices=len(args.hid_devices)
+ num_devices=len(args.hid_devices)
+ )
)
-)
-for idx in range(len(args.hid_devices)):
- c_file.write(
- """\
+ for idx in range(len(args.hid_devices)):
+ c_file.write(
+ """\
(mp_obj_t) &usb_hid_devices[{idx}],
""".format(
- idx=idx
+ idx=idx
+ )
)
- )
-c_file.write(
- """\
+ c_file.write(
+ """\
},
};
"""
-)
+ )
-h_file.write(
- """\
-#endif // MICROPY_INCLUDED_AUTOGEN_USB_DESCRIPTOR_H
-"""
-)
+if include_vendor:
+ # Mimic what the tinyusb webusb demo does in its main.c file
+ c_file.write(
+ """
+#define URL "{webusb_url}"
+
+const tusb_desc_webusb_url_t desc_webusb_url =
+{{
+ .bLength = 3 + sizeof(URL) - 1,
+ .bDescriptorType = 3, // WEBUSB URL type
+ .bScheme = 1, // 0: http, 1: https, 255: ""
+ .url = URL
+}};
+
+// These next two hardcoded descriptors were pulled from the usb_descriptor.c file
+// of the tinyusb webusb_serial demo. TODO - this is probably something else to
+// integrate into the adafruit_usb_descriptors project...
+
+//--------------------------------------------------------------------+
+// BOS Descriptor
+//--------------------------------------------------------------------+
+
+/* Microsoft OS 2.0 registry property descriptor
+Per MS requirements https://msdn.microsoft.com/en-us/library/windows/hardware/hh450799(v=vs.85).aspx
+device should create DeviceInterfaceGUIDs. It can be done by driver and
+in case of real PnP solution device should expose MS "Microsoft OS 2.0
+registry property descriptor". Such descriptor can insert any record
+into Windows registry per device/configuration/interface. In our case it
+will insert "DeviceInterfaceGUIDs" multistring property.
+
+GUID is freshly generated and should be OK to use.
+
+https://developers.google.com/web/fundamentals/native-hardware/build-for-webusb/
+(Section Microsoft OS compatibility descriptors)
+*/
+
+#define BOS_TOTAL_LEN (TUD_BOS_DESC_LEN + TUD_BOS_WEBUSB_DESC_LEN + TUD_BOS_MICROSOFT_OS_DESC_LEN)
+
+#define MS_OS_20_DESC_LEN 0xB2
+
+// BOS Descriptor is required for webUSB
+uint8_t const desc_bos[] =
+{{
+ // total length, number of device caps
+ TUD_BOS_DESCRIPTOR(BOS_TOTAL_LEN, 2),
+
+ // Vendor Code, iLandingPage
+ TUD_BOS_WEBUSB_DESCRIPTOR(VENDOR_REQUEST_WEBUSB, 1),
+
+ // Microsoft OS 2.0 descriptor
+ TUD_BOS_MS_OS_20_DESCRIPTOR(MS_OS_20_DESC_LEN, VENDOR_REQUEST_MICROSOFT)
+}};
+
+uint8_t const * tud_descriptor_bos_cb(void)
+{{
+ return desc_bos;
+}}
+
+
+#define ITF_NUM_VENDOR {webusb_interface} // used in this next descriptor
+
+uint8_t const desc_ms_os_20[] =
+{{
+ // Set header: length, type, windows version, total length
+ U16_TO_U8S_LE(0x000A), U16_TO_U8S_LE(MS_OS_20_SET_HEADER_DESCRIPTOR), U32_TO_U8S_LE(0x06030000), U16_TO_U8S_LE(MS_OS_20_DESC_LEN),
+
+ // Configuration subset header: length, type, configuration index, reserved, configuration total length
+ U16_TO_U8S_LE(0x0008), U16_TO_U8S_LE(MS_OS_20_SUBSET_HEADER_CONFIGURATION), 0, 0, U16_TO_U8S_LE(MS_OS_20_DESC_LEN-0x0A),
+
+ // Function Subset header: length, type, first interface, reserved, subset length
+ U16_TO_U8S_LE(0x0008), U16_TO_U8S_LE(MS_OS_20_SUBSET_HEADER_FUNCTION), ITF_NUM_VENDOR, 0, U16_TO_U8S_LE(MS_OS_20_DESC_LEN-0x0A-0x08),
+
+ // MS OS 2.0 Compatible ID descriptor: length, type, compatible ID, sub compatible ID
+ U16_TO_U8S_LE(0x0014), U16_TO_U8S_LE(MS_OS_20_FEATURE_COMPATBLE_ID), 'W', 'I', 'N', 'U', 'S', 'B', 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // sub-compatible
+
+ // MS OS 2.0 Registry property descriptor: length, type
+ U16_TO_U8S_LE(MS_OS_20_DESC_LEN-0x0A-0x08-0x08-0x14), U16_TO_U8S_LE(MS_OS_20_FEATURE_REG_PROPERTY),
+ U16_TO_U8S_LE(0x0007), U16_TO_U8S_LE(0x002A), // wPropertyDataType, wPropertyNameLength and PropertyName "DeviceInterfaceGUIDs\0" in UTF-16
+ 'D', 0x00, 'e', 0x00, 'v', 0x00, 'i', 0x00, 'c', 0x00, 'e', 0x00, 'I', 0x00, 'n', 0x00, 't', 0x00, 'e', 0x00,
+ 'r', 0x00, 'f', 0x00, 'a', 0x00, 'c', 0x00, 'e', 0x00, 'G', 0x00, 'U', 0x00, 'I', 0x00, 'D', 0x00, 's', 0x00, 0x00, 0x00,
+ U16_TO_U8S_LE(0x0050), // wPropertyDataLength
+ //bPropertyData: “{{975F44D9-0D08-43FD-8B3E-127CA8AFFF9D}}”.
+ '{{', 0x00, '9', 0x00, '7', 0x00, '5', 0x00, 'F', 0x00, '4', 0x00, '4', 0x00, 'D', 0x00, '9', 0x00, '-', 0x00,
+ '0', 0x00, 'D', 0x00, '0', 0x00, '8', 0x00, '-', 0x00, '4', 0x00, '3', 0x00, 'F', 0x00, 'D', 0x00, '-', 0x00,
+ '8', 0x00, 'B', 0x00, '3', 0x00, 'E', 0x00, '-', 0x00, '1', 0x00, '2', 0x00, '7', 0x00, 'C', 0x00, 'A', 0x00,
+ '8', 0x00, 'A', 0x00, 'F', 0x00, 'F', 0x00, 'F', 0x00, '9', 0x00, 'D', 0x00, '}}', 0x00, 0x00, 0x00, 0x00, 0x00
+}};
+
+TU_VERIFY_STATIC(sizeof(desc_ms_os_20) == MS_OS_20_DESC_LEN, "Incorrect size");
+
+// End of section about desc_ms_os_20
+
+""".format(
+ webusb_url=args.webusb_url,
+ webusb_interface=vendor_interface.bInterfaceNumber,
+ )
+ )