From 84d7a0da9dff287d6696bcea5c1517db916d5933 Mon Sep 17 00:00:00 2001 From: Kevin Banks Date: Wed, 20 Jan 2021 20:24:42 -0600 Subject: Initial steps, mostly via clone and modify. --- tools/gen_usb_descriptor.py | 47 ++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) (limited to 'tools') diff --git a/tools/gen_usb_descriptor.py b/tools/gen_usb_descriptor.py index 672f09c88..5ab4d6be1 100644 --- a/tools/gen_usb_descriptor.py +++ b/tools/gen_usb_descriptor.py @@ -2,6 +2,21 @@ # # SPDX-License-Identifier: MIT +def fix_note(note): + index = note.rfind(" object at") + if index >= 0: + note = note[:index] + ">" + return note + +def fix_notes(notes): + count = len(notes) + index = 0 + while index < count: + notes[index] = fix_note(notes[index]) + index += 1 + + return notes + import argparse import os @@ -13,7 +28,7 @@ from adafruit_usb_descriptor import audio, audio10, cdc, hid, midi, msc, standar import hid_report_descriptors DEFAULT_INTERFACE_NAME = 'CircuitPython' -ALL_DEVICES='CDC,MSC,AUDIO,HID' +ALL_DEVICES='CDC,MSC,AUDIO,HID,VENDOR' ALL_DEVICES_SET=frozenset(ALL_DEVICES.split(',')) DEFAULT_DEVICES='CDC,MSC,AUDIO,HID' @@ -62,6 +77,10 @@ parser.add_argument('--midi_ep_num_out', type=int, default=0, help='endpoint number of MIDI OUT') parser.add_argument('--midi_ep_num_in', type=int, default=0, help='endpoint number of MIDI IN') +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('--max_ep', type=int, default=0, help='total number of endpoints available') parser.add_argument('--output_c_file', type=argparse.FileType('w', encoding='UTF-8'), required=True) @@ -89,21 +108,27 @@ if not args.renumber_endpoints: if 'MSC' in args.devices: if args.msc_ep_num_out == 0: raise ValueError("MSC endpoint OUT number must not be 0") - elif args.msc_ep_num_in == 0: + elif args.msc_ep_num_in == 0: raise ValueError("MSC endpoint IN number must not be 0") if 'HID' in args.devices: if args.args.hid_ep_num_out == 0: raise ValueError("HID endpoint OUT number must not be 0") - elif args.hid_ep_num_in == 0: + elif args.hid_ep_num_in == 0: raise ValueError("HID endpoint IN number must not be 0") if 'AUDIO' in args.devices: if args.args.midi_ep_num_out == 0: raise ValueError("MIDI endpoint OUT number must not be 0") - elif args.midi_ep_num_in == 0: + elif args.midi_ep_num_in == 0: raise ValueError("MIDI endpoint IN number must not be 0") + if 'VENDOR' in args.devices: + 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.""" string_to_index = {} @@ -359,6 +384,10 @@ audio_control_interface = standard.InterfaceDescriptor( # Audio streaming interfaces must occur before MIDI ones. audio_interfaces = [audio_control_interface] + cs_ac_interface.audio_streaming_interfaces + cs_ac_interface.midi_streaming_interfaces +# TODO New code goes here to create vendor objects + +vendor_interfaces = [] # TODO Fix this! + interfaces_to_join = [] if 'CDC' in args.devices: @@ -373,6 +402,9 @@ if 'HID' in args.devices: if 'AUDIO' in args.devices: interfaces_to_join.append(audio_interfaces) +if 'VENDOR' in args.devices: + 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. @@ -425,6 +457,9 @@ if 'AUDIO' in args.devices: # correct ordering. descriptor_list.append(audio_control_interface) +if 'VENDOR' in args.devices: + descriptor_list.extend(vendor_interfaces) + # Finally, build the composite descriptor. configuration = standard.ConfigurationDescriptor( @@ -479,6 +514,7 @@ for descriptor in descriptor_list: b = bytes(descriptor) notes = descriptor.notes() + notes = fix_notes(notes) # for comparision of files beteen runs i = 0 # This prints each subdescriptor on a separate line. @@ -507,6 +543,7 @@ for idx, descriptor in enumerate(string_descriptors): b = bytes(descriptor) notes = descriptor.notes() + notes = fix_notes(notes) # for comparision of files beteen runs i = 0 # This prints each subdescriptor on a separate line. @@ -550,7 +587,7 @@ c_file.write("\n") hid_descriptor_length = len(bytes(combined_hid_report_descriptor)) -# 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 #define MICROPY_INCLUDED_AUTOGEN_USB_DESCRIPTOR_H -- cgit v1.2.3 From 9ce33a5771cd6061e81aeaf2b1c4361490c36b08 Mon Sep 17 00:00:00 2001 From: Kevin Banks Date: Fri, 22 Jan 2021 08:16:10 -0600 Subject: Now generates the WebUSB URL Descriptor. Still need to generate the Vendor Descriptors. --- tools/gen_usb_descriptor.py | 31 ++++++++++++++++++++++++++++--- 1 file changed, 28 insertions(+), 3 deletions(-) (limited to 'tools') diff --git a/tools/gen_usb_descriptor.py b/tools/gen_usb_descriptor.py index 5ab4d6be1..0f936597f 100644 --- a/tools/gen_usb_descriptor.py +++ b/tools/gen_usb_descriptor.py @@ -37,6 +37,8 @@ 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' +DEFAULT_WEBUSB_URL = 'www.circuitpython.org' # In the future, this may become a specific landing page + parser = argparse.ArgumentParser(description='Generate USB descriptors.') parser.add_argument('--highspeed', default=False, action='store_true', help='descriptor for highspeed device') @@ -77,6 +79,9 @@ parser.add_argument('--midi_ep_num_out', type=int, default=0, help='endpoint number of MIDI OUT') parser.add_argument('--midi_ep_num_in', type=int, default=0, help='endpoint number of MIDI IN') +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, @@ -623,7 +628,17 @@ extern const uint8_t hid_report_descriptor[{hid_report_descriptor_length}]; msc_vendor=args.manufacturer[:8], msc_product=args.product[:16])) +if 'VENDOR' in args.devices: + h_file.write("""\ +extern const tusb_desc_webusb_url_t desc_webusb_url; + +""") + +h_file.write("""\ +#endif // MICROPY_INCLUDED_AUTOGEN_USB_DESCRIPTOR_H +""") # Write out the report descriptor and info + c_file.write("""\ const uint8_t hid_report_descriptor[{HID_DESCRIPTOR_LENGTH}] = {{ """.format(HID_DESCRIPTOR_LENGTH=hid_descriptor_length)) @@ -692,6 +707,16 @@ c_file.write("""\ }; """) -h_file.write("""\ -#endif // MICROPY_INCLUDED_AUTOGEN_USB_DESCRIPTOR_H -""") +if 'VENDOR' in args.devices: + # Mimic what the tinyusb webusb demo does + 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 +}}; +""".format(webusb_url=args.webusb_url)) -- cgit v1.2.3 From fbfb7b68cce3fbcccc423c1013c0c3cabe6a89d0 Mon Sep 17 00:00:00 2001 From: Kevin Banks Date: Mon, 25 Jan 2021 20:37:58 -0600 Subject: Most of the code we need has been pulled in from the tinyusb webusb_serial demo. Still LOTS to do regarding descriptors. --- ports/esp32s2/Makefile | 4 +- ports/esp32s2/mpconfigport.mk | 2 + py/circuitpy_defns.mk | 3 ++ py/circuitpy_mpconfig.mk | 3 ++ supervisor/shared/serial.c | 30 +++++++++++++++ supervisor/shared/usb/tusb_config.h | 1 + supervisor/shared/usb/usb.c | 76 +++++++++++++++++++++++++++++++++++++ supervisor/supervisor.mk | 18 +++++++++ tools/gen_usb_descriptor.py | 53 +++++++++++++++++++++++--- 9 files changed, 184 insertions(+), 6 deletions(-) (limited to 'tools') diff --git a/ports/esp32s2/Makefile b/ports/esp32s2/Makefile index aac934782..b4ff0612b 100644 --- a/ports/esp32s2/Makefile +++ b/ports/esp32s2/Makefile @@ -164,7 +164,9 @@ LIBS += -lm endif # TinyUSB defines -CFLAGS += -DCFG_TUSB_MCU=OPT_MCU_ESP32S2 -DCFG_TUSB_OS=OPT_OS_FREERTOS -DCFG_TUD_CDC_RX_BUFSIZE=1024 -DCFG_TUD_CDC_TX_BUFSIZE=1024 -DCFG_TUD_MSC_BUFSIZE=4096 -DCFG_TUD_MIDI_RX_BUFSIZE=128 -DCFG_TUD_MIDI_TX_BUFSIZE=128 +CFLAGS += -DCFG_TUSB_MCU=OPT_MCU_ESP32S2 -DCFG_TUSB_OS=OPT_OS_FREERTOS -DCFG_TUD_CDC_RX_BUFSIZE=1024 -DCFG_TUD_CDC_TX_BUFSIZE=1024 +CFLAGS += -DCFG_TUD_MSC_BUFSIZE=4096 -DCFG_TUD_MIDI_RX_BUFSIZE=128 -DCFG_TUD_MIDI_TX_BUFSIZE=128 +CFLAGS += -DCFG_TUD_VENDOR_RX_BUFSIZE=128 -DCFG_TUD_VENDOR_TX_BUFSIZE=128 ###################################### diff --git a/ports/esp32s2/mpconfigport.mk b/ports/esp32s2/mpconfigport.mk index 562c60998..2d324e161 100644 --- a/ports/esp32s2/mpconfigport.mk +++ b/ports/esp32s2/mpconfigport.mk @@ -30,6 +30,8 @@ CIRCUITPY_ROTARYIO = 1 CIRCUITPY_NVM = 1 # We don't have enough endpoints to include MIDI. CIRCUITPY_USB_MIDI = 0 +# We have borrowed the VENDOR nomenclature from tinyusb. VENDOR AKA WEBUSB +CIRCUITPY_USB_VENDOR = 1 CIRCUITPY_WIFI = 1 CIRCUITPY_WATCHDOG ?= 1 CIRCUITPY_ESPIDF = 1 diff --git a/py/circuitpy_defns.mk b/py/circuitpy_defns.mk index 21bd5b965..5eb7992b1 100644 --- a/py/circuitpy_defns.mk +++ b/py/circuitpy_defns.mk @@ -288,6 +288,9 @@ endif ifeq ($(CIRCUITPY_USB_MIDI),1) SRC_PATTERNS += usb_midi/% endif +ifeq ($(CIRCUITPY_USB_VENDOR),1) +SRC_PATTERNS += usb_vendor/% +endif ifeq ($(CIRCUITPY_USTACK),1) SRC_PATTERNS += ustack/% endif diff --git a/py/circuitpy_mpconfig.mk b/py/circuitpy_mpconfig.mk index d0145a90f..6e721e1bc 100644 --- a/py/circuitpy_mpconfig.mk +++ b/py/circuitpy_mpconfig.mk @@ -270,6 +270,9 @@ CFLAGS += -DCIRCUITPY_USB_HID=$(CIRCUITPY_USB_HID) CIRCUITPY_USB_MIDI ?= 1 CFLAGS += -DCIRCUITPY_USB_MIDI=$(CIRCUITPY_USB_MIDI) +CIRCUITPY_USB_VENDOR ?= 1 +CFLAGS += -DCIRCUITPY_USB_VENDOR=$(CIRCUITPY_USB_VENDOR) + CIRCUITPY_PEW ?= 0 CFLAGS += -DCIRCUITPY_PEW=$(CIRCUITPY_PEW) diff --git a/supervisor/shared/serial.c b/supervisor/shared/serial.c index 303f89e75..b9feb04f2 100644 --- a/supervisor/shared/serial.c +++ b/supervisor/shared/serial.c @@ -47,6 +47,10 @@ busio_uart_obj_t debug_uart; byte buf_array[64]; #endif +#if CIRCUITPY_USB_VENDOR +bool tud_vendor_connected(void); +#endif + void serial_early_init(void) { #if defined(DEBUG_UART_TX) && defined(DEBUG_UART_RX) debug_uart.base.type = &busio_uart_type; @@ -66,6 +70,12 @@ void serial_init(void) { } bool serial_connected(void) { +#if CIRCUITPY_USB_VENDOR + if (tud_vendor_connected()) { + return true; + } +#endif + #if defined(DEBUG_UART_TX) && defined(DEBUG_UART_RX) return true; #else @@ -74,6 +84,14 @@ bool serial_connected(void) { } char serial_read(void) { +#if CIRCUITPY_USB_VENDOR + if (tud_vendor_connected() && tud_vendor_available() > 0) { + char tiny_buffer; + tud_vendor_read(&tiny_buffer, 1); + return tiny_buffer; + } +#endif + #if defined(DEBUG_UART_TX) && defined(DEBUG_UART_RX) if (tud_cdc_connected() && tud_cdc_available() > 0) { return (char) tud_cdc_read_char(); @@ -88,6 +106,12 @@ char serial_read(void) { } bool serial_bytes_available(void) { +#if CIRCUITPY_USB_VENDOR + if (tud_vendor_connected() && tud_vendor_available() > 0) { + return true; + } +#endif + #if defined(DEBUG_UART_TX) && defined(DEBUG_UART_RX) return common_hal_busio_uart_rx_characters_available(&debug_uart) || (tud_cdc_available() > 0); #else @@ -104,6 +128,12 @@ void serial_write_substring(const char* text, uint32_t length) { common_hal_terminalio_terminal_write(&supervisor_terminal, (const uint8_t*) text, length, &errcode); #endif +#if CIRCUITPY_USB_VENDOR + if (tud_vendor_connected()) { + tud_vendor_write(text, length); + } +#endif + uint32_t count = 0; while (count < length && tud_cdc_connected()) { count += tud_cdc_write(text + count, length - count); diff --git a/supervisor/shared/usb/tusb_config.h b/supervisor/shared/usb/tusb_config.h index 15d9fabaf..d3a35f537 100644 --- a/supervisor/shared/usb/tusb_config.h +++ b/supervisor/shared/usb/tusb_config.h @@ -68,6 +68,7 @@ #define CFG_TUD_MSC 1 #define CFG_TUD_HID CIRCUITPY_USB_HID #define CFG_TUD_MIDI CIRCUITPY_USB_MIDI +#define CFG_TUD_VENDOR CIRCUITPY_USB_VENDOR #define CFG_TUD_CUSTOM_CLASS 0 /*------------------------------------------------------------------*/ diff --git a/supervisor/shared/usb/usb.c b/supervisor/shared/usb/usb.c index ff08ade18..9b0cba8da 100644 --- a/supervisor/shared/usb/usb.c +++ b/supervisor/shared/usb/usb.c @@ -37,6 +37,26 @@ #include "tusb.h" +#if CIRCUITPY_USB_VENDOR +#include "genhdr/autogen_usb_descriptor.h" + +// The WebUSB support being conditionally added to this file is based on the +// tinyusb demo examples/device/webusb_serial. + +enum +{ + VENDOR_REQUEST_WEBUSB = 1, + VENDOR_REQUEST_MICROSOFT = 2 +}; + +extern uint8_t const desc_ms_os_20[]; +extern const tusb_desc_webusb_url_t desc_webusb_url; + +static bool web_serial_connected = false; +#endif + + + // Serial number as hex characters. This writes directly to the USB // descriptor. extern uint16_t usb_serial_number[1 + COMMON_HAL_MCU_PROCESSOR_UID_LENGTH * 2]; @@ -141,6 +161,62 @@ void tud_cdc_line_state_cb(uint8_t itf, bool dtr, bool rts) { } } +#if CIRCUITPY_USB_VENDOR +//--------------------------------------------------------------------+ +// WebUSB use vendor class +//--------------------------------------------------------------------+ + +bool tud_vendor_connected(void) +{ + return web_serial_connected; +} + +// Invoked when a control transfer occurred on an interface of this class +// Driver response accordingly to the request and the transfer stage (setup/data/ack) +// return false to stall control endpoint (e.g unsupported request) +bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request) +{ + // nothing to with DATA & ACK stage + if (stage != CONTROL_STAGE_SETUP ) return true; + + switch (request->bRequest) + { + case VENDOR_REQUEST_WEBUSB: + // match vendor request in BOS descriptor + // Get landing page url + return tud_control_xfer(rhport, request, (void*) &desc_webusb_url, desc_webusb_url.bLength); + + case VENDOR_REQUEST_MICROSOFT: + if ( request->wIndex == 7 ) + { + // Get Microsoft OS 2.0 compatible descriptor + uint16_t total_len; + memcpy(&total_len, desc_ms_os_20+8, 2); + + return tud_control_xfer(rhport, request, (void*) desc_ms_os_20, total_len); + } else + { + return false; + } + + case 0x22: + // Webserial simulate the CDC_REQUEST_SET_CONTROL_LINE_STATE (0x22) to + // connect and disconnect. + web_serial_connected = (request->wValue != 0); + + // response with status OK + return tud_control_status(rhport, request); + + default: + // stall unknown request + return false; + } + + return true; +} +#endif CIRCUITPY_USB_VENDOR + + #if MICROPY_KBD_EXCEPTION /** diff --git a/supervisor/supervisor.mk b/supervisor/supervisor.mk index a59e99e3d..70d3e146b 100644 --- a/supervisor/supervisor.mk +++ b/supervisor/supervisor.mk @@ -102,6 +102,11 @@ else shared-module/usb_midi/PortOut.c endif + ifeq ($(CIRCUITPY_USB_VENDOR), 1) + SRC_SUPERVISOR += \ + lib/tinyusb/src/class/vendor/vendor_device.c + endif + CFLAGS += -DUSB_AVAILABLE endif @@ -119,6 +124,10 @@ ifndef USB_INTERFACE_NAME USB_INTERFACE_NAME = "CircuitPython" endif +ifndef USB_WEBUSB_URL +USB_WEBUSB_URL = "www.circuitpython.org" +endif + USB_DEVICES_COMPUTED := CDC,MSC ifeq ($(CIRCUITPY_USB_MIDI),1) USB_DEVICES_COMPUTED := $(USB_DEVICES_COMPUTED),AUDIO @@ -126,6 +135,9 @@ endif ifeq ($(CIRCUITPY_USB_HID),1) USB_DEVICES_COMPUTED := $(USB_DEVICES_COMPUTED),HID endif +ifeq ($(CIRCUITPY_USB_VENDOR),1) +USB_DEVICES_COMPUTED := $(USB_DEVICES_COMPUTED),VENDOR +endif USB_DEVICES ?= "$(USB_DEVICES_COMPUTED)" ifndef USB_HID_DEVICES @@ -198,6 +210,12 @@ USB_DESCRIPTOR_ARGS = \ --output_c_file $(BUILD)/autogen_usb_descriptor.c\ --output_h_file $(BUILD)/genhdr/autogen_usb_descriptor.h +ifeq ($(CIRCUITPY_USB_VENDOR), 1) +USB_DESCRIPTOR_ARGS += \ + --vendor_ep_num_out 0 --vendor_ep_num_in 0 \ + --webusb_url $(USB_WEBUSB_URL) +endif + ifeq ($(USB_RENUMBER_ENDPOINTS), 0) USB_DESCRIPTOR_ARGS += --no-renumber_endpoints endif diff --git a/tools/gen_usb_descriptor.py b/tools/gen_usb_descriptor.py index 0f936597f..86de86d1a 100644 --- a/tools/gen_usb_descriptor.py +++ b/tools/gen_usb_descriptor.py @@ -484,6 +484,7 @@ h_file = args.output_h_file c_file.write("""\ #include +#include "tusb.h" #include "py/objtuple.h" #include "shared-bindings/usb_hid/Device.h" #include "{H_FILE_NAME}" @@ -628,11 +629,13 @@ extern const uint8_t hid_report_descriptor[{hid_report_descriptor_length}]; msc_vendor=args.manufacturer[:8], msc_product=args.product[:16])) -if 'VENDOR' in args.devices: - h_file.write("""\ -extern const tusb_desc_webusb_url_t desc_webusb_url; - -""") +# Currently getting compile-time errors in files like tusb_fifo.c +# if we try do define this here (TODO figure this out!) +#if 'VENDOR' in args.devices: +# h_file.write("""\ +#extern const tusb_desc_webusb_url_t desc_webusb_url; +# +#""") h_file.write("""\ #endif // MICROPY_INCLUDED_AUTOGEN_USB_DESCRIPTOR_H @@ -719,4 +722,44 @@ const tusb_desc_webusb_url_t desc_webusb_url = .bScheme = 1, // 0: http, 1: https, 255: "" .url = URL }}; + +// This next hardcoded descriptor was 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, especially with this next #define.. +#define ITF_NUM_VENDOR 6 // SWAG for now. + +#define MS_OS_20_DESC_LEN 0xB2 + +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)) -- cgit v1.2.3 From 1b031508e14a3cdfa2ba9c5cf158126d3f002cba Mon Sep 17 00:00:00 2001 From: Kevin Banks Date: Tue, 26 Jan 2021 20:43:19 -0600 Subject: BOS and MS_OS_2.0 descriptors have been added. Still more descriptor work TODO. --- supervisor/shared/usb/usb.c | 7 ----- tools/gen_usb_descriptor.py | 74 +++++++++++++++++++++++++++++++++++++-------- 2 files changed, 62 insertions(+), 19 deletions(-) (limited to 'tools') diff --git a/supervisor/shared/usb/usb.c b/supervisor/shared/usb/usb.c index 9b0cba8da..5db90d2fa 100644 --- a/supervisor/shared/usb/usb.c +++ b/supervisor/shared/usb/usb.c @@ -43,13 +43,6 @@ // The WebUSB support being conditionally added to this file is based on the // tinyusb demo examples/device/webusb_serial. -enum -{ - VENDOR_REQUEST_WEBUSB = 1, - VENDOR_REQUEST_MICROSOFT = 2 -}; - -extern uint8_t const desc_ms_os_20[]; extern const tusb_desc_webusb_url_t desc_webusb_url; static bool web_serial_connected = false; diff --git a/tools/gen_usb_descriptor.py b/tools/gen_usb_descriptor.py index 86de86d1a..210ca1923 100644 --- a/tools/gen_usb_descriptor.py +++ b/tools/gen_usb_descriptor.py @@ -629,13 +629,21 @@ extern const uint8_t hid_report_descriptor[{hid_report_descriptor_length}]; msc_vendor=args.manufacturer[:8], msc_product=args.product[:16])) -# Currently getting compile-time errors in files like tusb_fifo.c -# if we try do define this here (TODO figure this out!) -#if 'VENDOR' in args.devices: -# h_file.write("""\ -#extern const tusb_desc_webusb_url_t desc_webusb_url; -# -#""") +if 'VENDOR' in args.devices: + 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 @@ -711,7 +719,7 @@ c_file.write("""\ """) if 'VENDOR' in args.devices: - # Mimic what the tinyusb webusb demo does + # Mimic what the tinyusb webusb demo does in it's main.c file c_file.write(""" #define URL "{webusb_url}" @@ -723,13 +731,55 @@ const tusb_desc_webusb_url_t desc_webusb_url = .url = URL }}; -// This next hardcoded descriptor was 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, especially with this next #define.. -#define ITF_NUM_VENDOR 6 // SWAG for now. +// These next two hardcoded descriptor 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, especially with this next +// #define.. + +// SWAG for now. Will have to be manually corrected until generated by gen_usb_descriptor.py +#define ITF_NUM_VENDOR 6i + +//--------------------------------------------------------------------+ +// 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; +}} + + uint8_t const desc_ms_os_20[] = {{ // Set header: length, type, windows version, total length -- cgit v1.2.3 From 63f9b12fe61c9df6e993f92d7cfef1038523d930 Mon Sep 17 00:00:00 2001 From: Kevin Banks Date: Thu, 28 Jan 2021 20:22:31 -0600 Subject: Partially hard-coded VENDOR descriptor has been added. First build to be accessed via WebUSB. NOTE - had to disable HID (EndPoint shortage?) --- ports/esp32s2/mpconfigport.mk | 1 + tools/gen_usb_descriptor.py | 28 ++++++++++++++++++++++++++-- 2 files changed, 27 insertions(+), 2 deletions(-) (limited to 'tools') diff --git a/ports/esp32s2/mpconfigport.mk b/ports/esp32s2/mpconfigport.mk index 2d324e161..7dcd3355f 100644 --- a/ports/esp32s2/mpconfigport.mk +++ b/ports/esp32s2/mpconfigport.mk @@ -30,6 +30,7 @@ CIRCUITPY_ROTARYIO = 1 CIRCUITPY_NVM = 1 # We don't have enough endpoints to include MIDI. CIRCUITPY_USB_MIDI = 0 +CIRCUITPY_USB_HID = 0 # We have borrowed the VENDOR nomenclature from tinyusb. VENDOR AKA WEBUSB CIRCUITPY_USB_VENDOR = 1 CIRCUITPY_WIFI = 1 diff --git a/tools/gen_usb_descriptor.py b/tools/gen_usb_descriptor.py index 210ca1923..36c6f45a6 100644 --- a/tools/gen_usb_descriptor.py +++ b/tools/gen_usb_descriptor.py @@ -390,8 +390,32 @@ audio_control_interface = standard.InterfaceDescriptor( audio_interfaces = [audio_control_interface] + cs_ac_interface.audio_streaming_interfaces + cs_ac_interface.midi_streaming_interfaces # TODO New code goes here to create vendor objects +# Starting out with a clone-and-modify of the HID descriptors +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.VENDOR_CLASS, + bInterfaceSubClass=0x00, #vendor.VENDOR_SUBCLASS_???,, + bInterfaceProtocol=0x00, #vendor.VENDOR_PROTOCOL_NONE, + iInterface=StringIndex.index("{} VENDOR".format(args.interface_name)), + subdescriptors=[ + vendor_endpoint_in_descriptor, + vendor_endpoint_out_descriptor, + ] +) -vendor_interfaces = [] # TODO Fix this! +vendor_interfaces = [vendor_interface] interfaces_to_join = [] @@ -737,7 +761,7 @@ const tusb_desc_webusb_url_t desc_webusb_url = // #define.. // SWAG for now. Will have to be manually corrected until generated by gen_usb_descriptor.py -#define ITF_NUM_VENDOR 6i +#define ITF_NUM_VENDOR 3 //--------------------------------------------------------------------+ // BOS Descriptor -- cgit v1.2.3 From 817ca39f59a539fff9e0bc29259b114e34cdf609 Mon Sep 17 00:00:00 2001 From: Kevin Banks Date: Mon, 1 Feb 2021 18:35:58 -0600 Subject: ITF_NUM_VENDOR is now automatically computed at run-time --- tools/gen_usb_descriptor.py | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) (limited to 'tools') diff --git a/tools/gen_usb_descriptor.py b/tools/gen_usb_descriptor.py index 36c6f45a6..bd77be583 100644 --- a/tools/gen_usb_descriptor.py +++ b/tools/gen_usb_descriptor.py @@ -757,11 +757,7 @@ const tusb_desc_webusb_url_t desc_webusb_url = // These next two hardcoded descriptor 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, especially with this next -// #define.. - -// SWAG for now. Will have to be manually corrected until generated by gen_usb_descriptor.py -#define ITF_NUM_VENDOR 3 +// integrate into the adafruit_usb_descriptors project... //--------------------------------------------------------------------+ // BOS Descriptor @@ -804,6 +800,8 @@ uint8_t const * tud_descriptor_bos_cb(void) }} +#define ITF_NUM_VENOR {webusb_interface} // used in this next descriptor + uint8_t const desc_ms_os_20[] = {{ // Set header: length, type, windows version, total length @@ -836,4 +834,4 @@ 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)) +""".format(webusb_url=args.webusb_url, webusb_interface=vendor_interface.bInterfaceNumber)) -- cgit v1.2.3 From 1a9e4f5613d663d6bff29d21f5ff64bf653e56cc Mon Sep 17 00:00:00 2001 From: Kevin Banks Date: Mon, 1 Feb 2021 18:51:11 -0600 Subject: Restored accidentally deleted character --- tools/gen_usb_descriptor.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tools') diff --git a/tools/gen_usb_descriptor.py b/tools/gen_usb_descriptor.py index bd77be583..cf7400108 100644 --- a/tools/gen_usb_descriptor.py +++ b/tools/gen_usb_descriptor.py @@ -800,7 +800,7 @@ uint8_t const * tud_descriptor_bos_cb(void) }} -#define ITF_NUM_VENOR {webusb_interface} // used in this next descriptor +#define ITF_NUM_VENDOR {webusb_interface} // used in this next descriptor uint8_t const desc_ms_os_20[] = {{ -- cgit v1.2.3 From 00926b687a619f18deb08c1f59f868a4e9b8514a Mon Sep 17 00:00:00 2001 From: Kevin Banks Date: Wed, 3 Feb 2021 11:16:19 -0600 Subject: Trying to keep two ARM builds from overflowing their FLASH --- tools/gen_usb_descriptor.py | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) (limited to 'tools') diff --git a/tools/gen_usb_descriptor.py b/tools/gen_usb_descriptor.py index cf7400108..05d35ffc4 100644 --- a/tools/gen_usb_descriptor.py +++ b/tools/gen_usb_descriptor.py @@ -403,19 +403,21 @@ vendor_endpoint_out_descriptor = standard.EndpointDescriptor( bmAttributes=standard.EndpointDescriptor.TYPE_BULK, bInterval=16) -vendor_interface = standard.InterfaceDescriptor( - description="VENDOR", - bInterfaceClass=0xff, # vendor.VENDOR_CLASS, - bInterfaceSubClass=0x00, #vendor.VENDOR_SUBCLASS_???,, - bInterfaceProtocol=0x00, #vendor.VENDOR_PROTOCOL_NONE, - iInterface=StringIndex.index("{} VENDOR".format(args.interface_name)), - subdescriptors=[ - vendor_endpoint_in_descriptor, - vendor_endpoint_out_descriptor, - ] -) +# We do the following conditionally to avoid adding unused entries to the StringIndex table +if 'VENDOR' in args.devices: + vendor_interface = standard.InterfaceDescriptor( + description="VENDOR", + bInterfaceClass=0xff, # vendor.VENDOR_CLASS, + bInterfaceSubClass=0x00, #vendor.VENDOR_SUBCLASS_???,, + bInterfaceProtocol=0x00, #vendor.VENDOR_PROTOCOL_NONE, + iInterface=StringIndex.index("{} VENDOR".format(args.interface_name)), + subdescriptors=[ + vendor_endpoint_in_descriptor, + vendor_endpoint_out_descriptor, + ] + ) -vendor_interfaces = [vendor_interface] + vendor_interfaces = [vendor_interface] interfaces_to_join = [] -- cgit v1.2.3 From f2067730cb1986d0b325cd22545da1a0d48920aa Mon Sep 17 00:00:00 2001 From: Kevin Banks Date: Wed, 3 Feb 2021 18:51:48 -0600 Subject: Code cleanup and added a WEBUSB_README file --- WEBUSB_README.md | 91 +++++++++++++++++++++++++++++++++++++++++++++ tools/gen_usb_descriptor.py | 25 ++----------- 2 files changed, 95 insertions(+), 21 deletions(-) create mode 100644 WEBUSB_README.md (limited to 'tools') diff --git a/WEBUSB_README.md b/WEBUSB_README.md new file mode 100644 index 000000000..a4b9c4c3e --- /dev/null +++ b/WEBUSB_README.md @@ -0,0 +1,91 @@ + + +# WebUSB Serial Support + +To date, this has only been tested on one port (esp32s2), on one board (espressif_kaluga_1). + +## What it does + +If you have ever used CircuitPython on a platform with a graphical LCD display, you have probably +already seen multiple "consoles" in use (although the LCD console is "output only"). + +New compile-time option CIRCUITPY_USB_VENDOR enables an additional "console" that can be used in +parallel with the original (CDC) serial console. + +Web pages that support the WebUSB standard can connect to the "vendor" interface and activate +this WebUSB serial console at any time. + +You can type into either console, and CircuitPython output is sent to all active consoles. + +## How to enable + +Update your platform's mpconfigboard.mk file to enable and disable specific types of USB interfaces. + +CIRCUITPY_USB_HID = xxx +CIRCUITPY_USB_MIDI = xxx +CIRCUITPY_USB_VENDOR = xxx + +On at least some of the hardware platforms, the maximum number of USB endpoints is fixed. +For example, on the ESP32S2, you must pick only one of the above 3 interfaces to be enabled. + +Original espressif_kaluga_1 mpconfigboard.mk settings: + +CIRCUITPY_USB_HID = 1 +CIRCUITPY_USB_MIDI = 0 +CIRCUITPY_USB_VENDOR = 0 + +Settings to enable WebUSB instead: + +CIRCUITPY_USB_HID = 0 +CIRCUITPY_USB_MIDI = 0 +CIRCUITPY_USB_VENDOR = 1 + +Notice that to enable VENDOR, we had to give up HID. There may be platforms that can have both. + +## Implementation Notes + +CircuitPython uses the tinyusb library. + +The tinyusb library already has support for WebUSB serial. +The tinyusb examples already include a "WebUSB serial" example. + + Sidenote - The use of the term "vendor" instead of "WebUSB" was done to match tinyusb. + +Basically, this feature was ported into CircuitPython by pulling code snippets out of the +tinyusb example, and putting them where they best belonged in the CircuitPython codebase. + +There was one complication: + +tinyusb uses C preprocessor macros to define things like USB descriptors. + +CircuitPython uses a Python program (tools/gen_usb_descriptor.py) to create USB descriptors (etc.) +using "helper objects" from another repo (adafruit_usb_descriptor). This means some of the example +code had to be adapted to the new programing model, and gen_usb_descriptor gained new command-line +options to control the generated code. + +The generated files go into the "build" directory, look for autogen_usb_descriptor.c and +genhdr/autogen_usb_descriptor.h. + + +Also worth pointing out - the re-use of the CDC connect/disconnect mechanism is not actually part +of the WebUSB standard, it's more of "common idiom". We make use of it here because we need to know +when we should be paying attention to the WebUSB serial interface,and when we should ignore it.. + +## Possible future work areas + +The current code uses the existing Python infrastructure to create the Interface descriptor, but +simply outputs the code snippets from the original tinyusb demo code to create the WEBUSB_URL, +BOS, and MS_OS_20 descriptors. I suppose additional work could be done to add these to the +adafruit_usb_descriptor project, and then gen_usb_descriptor.py could be modified to make use +of them. + +Program gen_usb_descriptor.py creates objects for most interface types, regardless of whether or +not they are actually enabled. This increases the size of a generated string table. I made the +new vendor-interface-related code not do this (because some of the ARM platforms would no longer +build), but I did not go back and do this for the other interface types (CDC, MIDI, HID, etc.) +Some FLASH savings are probably possible if this is done. + diff --git a/tools/gen_usb_descriptor.py b/tools/gen_usb_descriptor.py index 05d35ffc4..ad68d0ea9 100644 --- a/tools/gen_usb_descriptor.py +++ b/tools/gen_usb_descriptor.py @@ -2,21 +2,6 @@ # # SPDX-License-Identifier: MIT -def fix_note(note): - index = note.rfind(" object at") - if index >= 0: - note = note[:index] + ">" - return note - -def fix_notes(notes): - count = len(notes) - index = 0 - while index < count: - notes[index] = fix_note(notes[index]) - index += 1 - - return notes - import argparse import os @@ -389,8 +374,7 @@ audio_control_interface = standard.InterfaceDescriptor( # Audio streaming interfaces must occur before MIDI ones. audio_interfaces = [audio_control_interface] + cs_ac_interface.audio_streaming_interfaces + cs_ac_interface.midi_streaming_interfaces -# TODO New code goes here to create vendor objects -# Starting out with a clone-and-modify of the HID descriptors +# 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, @@ -407,9 +391,9 @@ vendor_endpoint_out_descriptor = standard.EndpointDescriptor( if 'VENDOR' in args.devices: vendor_interface = standard.InterfaceDescriptor( description="VENDOR", - bInterfaceClass=0xff, # vendor.VENDOR_CLASS, - bInterfaceSubClass=0x00, #vendor.VENDOR_SUBCLASS_???,, - bInterfaceProtocol=0x00, #vendor.VENDOR_PROTOCOL_NONE, + bInterfaceClass=0xff, # Vendor-specific + bInterfaceSubClass=0x00, + bInterfaceProtocol=0x00, iInterface=StringIndex.index("{} VENDOR".format(args.interface_name)), subdescriptors=[ vendor_endpoint_in_descriptor, @@ -546,7 +530,6 @@ for descriptor in descriptor_list: b = bytes(descriptor) notes = descriptor.notes() - notes = fix_notes(notes) # for comparision of files beteen runs i = 0 # This prints each subdescriptor on a separate line. -- cgit v1.2.3 From 4d90f198ecad900cc71745087e895bcbea63b12c Mon Sep 17 00:00:00 2001 From: Kevin Banks Date: Wed, 3 Feb 2021 18:54:03 -0600 Subject: (I could have sworn I deleted that line...) --- tools/gen_usb_descriptor.py | 1 - 1 file changed, 1 deletion(-) (limited to 'tools') diff --git a/tools/gen_usb_descriptor.py b/tools/gen_usb_descriptor.py index ad68d0ea9..fb4372f0d 100644 --- a/tools/gen_usb_descriptor.py +++ b/tools/gen_usb_descriptor.py @@ -558,7 +558,6 @@ for idx, descriptor in enumerate(string_descriptors): b = bytes(descriptor) notes = descriptor.notes() - notes = fix_notes(notes) # for comparision of files beteen runs i = 0 # This prints each subdescriptor on a separate line. -- cgit v1.2.3 From e72069e241b287ea3522546cda03b3d0df70ba7f Mon Sep 17 00:00:00 2001 From: FiriaCTO <70992913+FiriaCTO@users.noreply.github.com> Date: Thu, 4 Feb 2021 16:18:36 -0600 Subject: Fix typo in comment descriptors should be plural Co-authored-by: Dan Halbert --- tools/gen_usb_descriptor.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tools') diff --git a/tools/gen_usb_descriptor.py b/tools/gen_usb_descriptor.py index fb4372f0d..bb4ecda6f 100644 --- a/tools/gen_usb_descriptor.py +++ b/tools/gen_usb_descriptor.py @@ -739,7 +739,7 @@ const tusb_desc_webusb_url_t desc_webusb_url = .url = URL }}; -// These next two hardcoded descriptor were pulled from the usb_descriptor.c file +// 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... -- cgit v1.2.3 From 1352938504539a649b185ca6b504e85e3d0203d7 Mon Sep 17 00:00:00 2001 From: Kevin Banks Date: Thu, 4 Feb 2021 16:35:42 -0600 Subject: Changed URL --- tools/gen_usb_descriptor.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'tools') diff --git a/tools/gen_usb_descriptor.py b/tools/gen_usb_descriptor.py index bb4ecda6f..80dddeb00 100644 --- a/tools/gen_usb_descriptor.py +++ b/tools/gen_usb_descriptor.py @@ -22,7 +22,8 @@ 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' -DEFAULT_WEBUSB_URL = 'www.circuitpython.org' # In the future, this may become a specific landing page +# 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', default=False, action='store_true', -- cgit v1.2.3 From 5c3371bd1a2f6687447245fda7080743b2122de7 Mon Sep 17 00:00:00 2001 From: foamyguy Date: Fri, 5 Feb 2021 18:05:37 -0600 Subject: fix bitmap_font path in display resource gen --- tools/gen_display_resources.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'tools') 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 -- cgit v1.2.3