Skip to content

Dynamic USB descriptors #4689

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 36 commits into from
May 6, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
9f30f87
Add some minimum versions to requirements-dev.txt
dhalbert Apr 6, 2021
3e5bc5a
wip
dhalbert Apr 9, 2021
2a58b66
wip: incorporate new hid descriptor building
dhalbert Apr 13, 2021
4a7e129
wip: latent usb device enabling/disabling
dhalbert Apr 14, 2021
6cb751a
wip: revamp API names
dhalbert Apr 15, 2021
51ccf8d
wip: revert usb_descriptor changes; use raw descriptors instead
dhalbert Apr 20, 2021
6b18a51
wip: working on descriptor templates
dhalbert Apr 21, 2021
64e0958
wip: descriptor building
dhalbert Apr 22, 2021
2b4c88d
wip: partial HID, still needs rework
dhalbert Apr 23, 2021
556a126
wip: getting closer
dhalbert Apr 24, 2021
aea3c4d
wip
dhalbert Apr 25, 2021
9d1fcc3
merge from main
dhalbert Apr 25, 2021
c26e49c
wip: starting to try to compile
dhalbert Apr 26, 2021
7a40b4d
very much WIP
dhalbert Apr 27, 2021
f98a546
wip: compiles
dhalbert Apr 27, 2021
8500e84
partially working
dhalbert Apr 28, 2021
587aedd
rework storage allocation
dhalbert Apr 28, 2021
f06d545
merge from adafruit
dhalbert Apr 29, 2021
abfb020
MSC, CDC, HID keyboard definitely working
dhalbert Apr 29, 2021
71a8cad
working!
dhalbert Apr 30, 2021
b5efce1
delete hid .py; undo some debugging changes
dhalbert Apr 30, 2021
3189668
bring protomatter up to date
dhalbert Apr 30, 2021
48dd54c
undo requirements-dev.txt changes
dhalbert Apr 30, 2021
b8b20fa
doc fixes
dhalbert Apr 30, 2021
cc95b71
fix type annotations
dhalbert Apr 30, 2021
be7b2b0
uncrustify with newer version of uncrustify
dhalbert Apr 30, 2021
5b5de4b
fix sHID report doc and API
dhalbert May 4, 2021
d2b5589
merge from main, including MicroPython 1.12 merge
dhalbert May 4, 2021
3e2236b
missed an uncrustify
dhalbert May 4, 2021
adc3d7d
update Python API according to review comments
dhalbert May 4, 2021
8bb3c6f
handle := defs in shared_bindings_matrix.py; update adafruit_hid
dhalbert May 4, 2021
fc8e1c4
address review comments
dhalbert May 5, 2021
c37f021
regularize and shrink many builds
dhalbert May 5, 2021
8f9c9dd
doc error
dhalbert May 5, 2021
579cdf3
fix more build errors
dhalbert May 5, 2021
843598e
fix more board builds
dhalbert May 5, 2021
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -238,7 +238,6 @@ jobs:
- "feather_mimxrt1011"
- "feather_mimxrt1062"
- "feather_nrf52840_express"
- "feather_radiofruit_zigbee"
- "feather_stm32f405_express"
- "fluff_m0"
- "gemma_m0"
Expand Down
31 changes: 1 addition & 30 deletions WEBUSB_README.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,33 +62,4 @@ The tinyusb examples already include a "WebUSB serial" example.
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.
### TODO: This needs to be reworked for dynamic USB descriptors.
3 changes: 2 additions & 1 deletion docs/shared_bindings_matrix.py
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,8 @@ def get_settings_from_makefile(port_dir, board_name):

settings = {}
for line in contents.stdout.split('\n'):
m = re.match(r'^([A-Z][A-Z0-9_]*) = (.*)$', line)
# Handle both = and := definitions.
m = re.match(r'^([A-Z][A-Z0-9_]*) :?= (.*)$', line)
if m:
settings[m.group(1)] = m.group(2)

Expand Down
32 changes: 31 additions & 1 deletion locale/circuitpython.pot
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,10 @@ msgstr ""
msgid "%q list must be a list"
msgstr ""

#: shared-bindings/usb_hid/Device.c
msgid "%q must be 1-255"
msgstr ""

#: shared-bindings/memorymonitor/AllocationAlarm.c
msgid "%q must be >= 0"
msgstr ""
Expand All @@ -99,6 +103,10 @@ msgstr ""
msgid "%q must be >= 1"
msgstr ""

#: shared-bindings/usb_hid/Device.c
msgid "%q must be None or 1-255"
msgstr ""

#: shared-module/vectorio/Polygon.c
msgid "%q must be a tuple of length 2"
msgstr ""
Expand Down Expand Up @@ -600,6 +608,11 @@ msgstr ""
msgid "Can't set CCCD on local Characteristic"
msgstr ""

#: shared-bindings/storage/__init__.c shared-bindings/usb_cdc/__init__.c
#: shared-bindings/usb_hid/__init__.c shared-bindings/usb_midi/__init__.c
msgid "Cannot change USB devices now"
msgstr ""

#: shared-bindings/_bleio/Adapter.c
msgid "Cannot create a new Adapter; use _bleio.adapter;"
msgstr ""
Expand Down Expand Up @@ -642,7 +655,7 @@ msgid "Cannot record to a file"
msgstr ""

#: shared-module/storage/__init__.c
msgid "Cannot remount '/' when USB is active."
msgid "Cannot remount '/' when visible via USB."
msgstr ""

#: ports/atmel-samd/common-hal/microcontroller/__init__.c
Expand Down Expand Up @@ -1568,6 +1581,11 @@ msgstr ""
msgid "No long integer support"
msgstr ""

#: shared-module/usb_hid/__init__.c
#, c-format
msgid "No more than %d HID devices allowed"
msgstr ""

#: shared-bindings/wifi/Radio.c
msgid "No network with that ssid"
msgstr ""
Expand Down Expand Up @@ -2176,6 +2194,14 @@ msgstr ""
msgid "USB Error"
msgstr ""

#: supervisor/shared/safe_mode.c
msgid "USB devices need more endpoints than are available."
msgstr ""

#: supervisor/shared/safe_mode.c
msgid "USB devices specify too many interface names."
msgstr ""

#: shared-bindings/_bleio/UUID.c
msgid "UUID integer value must be 0-0xffff"
msgstr ""
Expand Down Expand Up @@ -3489,6 +3515,10 @@ msgstr ""
msgid "no such attribute"
msgstr ""

#: shared-bindings/usb_hid/__init__.c
msgid "non-Device in %q"
msgstr ""

#: ports/nrf/common-hal/_bleio/Connection.c
msgid "non-UUID found in service_uuids_whitelist"
msgstr ""
Expand Down
52 changes: 48 additions & 4 deletions main.c
Original file line number Diff line number Diff line change
Expand Up @@ -95,8 +95,8 @@
#include "shared-module/network/__init__.h"
#endif

#if CIRCUITPY_USB_CDC
#include "shared-module/usb_cdc/__init__.h"
#if CIRCUITPY_USB_HID
#include "shared-module/usb_hid/__init__.h"
#endif

#if CIRCUITPY_WIFI
Expand Down Expand Up @@ -299,6 +299,10 @@ STATIC bool run_code_py(safe_mode_t safe_mode) {
supervisor_allocation* heap = allocate_remaining_memory();
start_mp(heap);

#if CIRCUITPY_USB
usb_setup_with_vm();
#endif

found_main = maybe_run_list(supported_filenames, &result);
#if CIRCUITPY_FULL_BUILD
if (!found_main){
Expand Down Expand Up @@ -497,11 +501,15 @@ STATIC void __attribute__ ((noinline)) run_boot_py(safe_mode_t safe_mode) {
}
#endif

// TODO(tannewt): Allocate temporary space to hold custom usb descriptors.
filesystem_flush();
supervisor_allocation* heap = allocate_remaining_memory();
start_mp(heap);

#if CIRCUITPY_USB
// Set up default USB values after boot.py VM starts but before running boot.py.
usb_set_defaults();
#endif

// TODO(tannewt): Re-add support for flashing boot error output.
bool found_boot = maybe_run_list(boot_py_filenames, NULL);
(void) found_boot;
Expand All @@ -514,7 +522,27 @@ STATIC void __attribute__ ((noinline)) run_boot_py(safe_mode_t safe_mode) {
boot_output_file = NULL;
#endif


#if CIRCUITPY_USB

// Some data needs to be carried over from the USB settings in boot.py
// to the next VM, while the heap is still available.
// Its size can vary, so save it temporarily on the stack,
// and then when the heap goes away, copy it in into a
// storage_allocation.

size_t size = usb_boot_py_data_size();
uint8_t usb_boot_py_data[size];
usb_get_boot_py_data(usb_boot_py_data, size);
#endif

cleanup_after_vm(heap);

#if CIRCUITPY_USB
// Now give back the data we saved from the heap going away.
usb_return_boot_py_data(usb_boot_py_data, size);
#endif

}
}

Expand All @@ -524,6 +552,11 @@ STATIC int run_repl(void) {
filesystem_flush();
supervisor_allocation* heap = allocate_remaining_memory();
start_mp(heap);

#if CIRCUITPY_USB
usb_setup_with_vm();
#endif

autoreload_suspend();
new_status_color(REPL_RUNNING);
if (pyexec_mode_kind == PYEXEC_MODE_RAW_REPL) {
Expand Down Expand Up @@ -583,7 +616,14 @@ int __attribute__((used)) main(void) {

run_boot_py(safe_mode);

// Start serial and HID after giving boot.py a chance to tweak behavior.
// Start USB after giving boot.py a chance to tweak behavior.
#if CIRCUITPY_USB
// Setup USB connection after heap is available.
// It needs the heap to build descriptors.
usb_init();
#endif

// Set up any other serial connection.
serial_init();

#if CIRCUITPY_BLEIO
Expand Down Expand Up @@ -636,6 +676,10 @@ void gc_collect(void) {
common_hal_bleio_gc_collect();
#endif

#if CIRCUITPY_USB_HID
usb_hid_gc_collect();
#endif

#if CIRCUITPY_WIFI
common_hal_wifi_gc_collect();
#endif
Expand Down
Loading