summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorScott Shawcroft <scott@adafruit.com>2021-02-19 18:34:03 -0800
committerGitHub <noreply@github.com>2021-02-19 18:34:03 -0800
commit7b6f89a074feb849e03287e2fa3f39eb4b04e6ee (patch)
treedbe916f5c070b3724d1c5ad5232be8fe8493242f
parent220f86f873f8d8e2d00a82672470ef40fc68e147 (diff)
parent985e02093690d835ef5adf8d253e1f0405d86538 (diff)
Merge pull request #4215 from dhalbert/secondary-cdc
Second USB CDC (serial) channel
-rwxr-xr-xmain.c26
-rw-r--r--ports/atmel-samd/Makefile2
-rw-r--r--ports/atmel-samd/boards/sparkfun_samd21_mini/mpconfigboard.mk1
-rwxr-xr-xports/atmel-samd/common-hal/supervisor/Runtime.c4
-rw-r--r--ports/atmel-samd/mpconfigport.mk22
-rwxr-xr-xports/cxd56/common-hal/supervisor/Runtime.c4
-rw-r--r--ports/cxd56/mpconfigport.mk3
-rw-r--r--ports/esp32s2/boards/lilygo_ttgo_t8_s2_st7789/mpconfigboard.mk1
-rw-r--r--ports/esp32s2/boards/microdev_micro_s2/mpconfigboard.mk1
-rw-r--r--ports/esp32s2/boards/unexpectedmaker_feathers2/mpconfigboard.mk1
-rw-r--r--ports/esp32s2/boards/unexpectedmaker_feathers2_prerelease/mpconfigboard.mk1
-rw-r--r--ports/esp32s2/common-hal/supervisor/Runtime.c6
-rw-r--r--ports/esp32s2/mpconfigport.mk13
-rw-r--r--ports/litex/common-hal/supervisor/Runtime.c6
-rw-r--r--ports/litex/mpconfigport.mk3
-rwxr-xr-xports/mimxrt10xx/common-hal/supervisor/Runtime.c4
-rw-r--r--ports/mimxrt10xx/mpconfigport.mk3
-rw-r--r--ports/nrf/bluetooth/ble_uart.c4
-rw-r--r--ports/nrf/boards/pca10100/mpconfigboard.mk1
-rw-r--r--ports/nrf/boards/simmel/mpconfigboard.mk3
-rwxr-xr-xports/nrf/common-hal/supervisor/Runtime.c4
-rw-r--r--ports/nrf/mpconfigport.mk3
-rw-r--r--ports/nrf/supervisor/serial.c10
-rwxr-xr-xports/raspberrypi/common-hal/supervisor/Runtime.c4
-rw-r--r--ports/raspberrypi/mpconfigport.mk1
-rw-r--r--ports/stm/boards/stm32f412zg_discovery/mpconfigboard.mk2
-rw-r--r--ports/stm/boards/thunderpack_v12/mpconfigboard.mk4
-rwxr-xr-xports/stm/common-hal/supervisor/Runtime.c6
-rw-r--r--ports/stm/mpconfigport.mk7
-rw-r--r--py/circuitpy_defns.mk9
-rw-r--r--py/circuitpy_mpconfig.h24
-rw-r--r--py/circuitpy_mpconfig.mk99
-rw-r--r--py/stream.c32
-rw-r--r--py/stream.h4
-rw-r--r--shared-bindings/_bleio/CharacteristicBuffer.c4
-rw-r--r--shared-bindings/busio/UART.c4
-rwxr-xr-xshared-bindings/supervisor/Runtime.c47
-rwxr-xr-xshared-bindings/supervisor/Runtime.h8
-rw-r--r--shared-bindings/usb_cdc/Serial.c293
-rw-r--r--shared-bindings/usb_cdc/Serial.h53
-rw-r--r--shared-bindings/usb_cdc/__init__.c59
-rw-r--r--shared-bindings/usb_cdc/__init__.h32
-rw-r--r--shared-module/usb_cdc/Serial.c147
-rw-r--r--shared-module/usb_cdc/Serial.h39
-rw-r--r--shared-module/usb_cdc/__init__.c61
-rw-r--r--shared-module/usb_cdc/__init__.h34
-rw-r--r--supervisor/shared/serial.c1
-rw-r--r--supervisor/shared/usb/tusb_config.h7
-rw-r--r--supervisor/shared/usb/usb.c7
-rw-r--r--supervisor/shared/usb/usb_desc.c2
-rw-r--r--supervisor/supervisor.mk270
-rw-r--r--tools/gen_usb_descriptor.py1093
m---------tools/usb_descriptor0
53 files changed, 1796 insertions, 683 deletions
diff --git a/main.c b/main.c
index 7bfa565df..7df6e293a 100755
--- a/main.c
+++ b/main.c
@@ -69,6 +69,19 @@
#include "shared-bindings/alarm/__init__.h"
#endif
+#if CIRCUITPY_BLEIO
+#include "shared-bindings/_bleio/__init__.h"
+#include "supervisor/shared/bluetooth.h"
+#endif
+
+#if CIRCUITPY_BOARD
+#include "shared-module/board/__init__.h"
+#endif
+
+#if CIRCUITPY_CANIO
+#include "common-hal/canio/CAN.h"
+#endif
+
#if CIRCUITPY_DISPLAYIO
#include "shared-module/displayio/__init__.h"
#endif
@@ -81,17 +94,8 @@
#include "shared-module/network/__init__.h"
#endif
-#if CIRCUITPY_BOARD
-#include "shared-module/board/__init__.h"
-#endif
-
-#if CIRCUITPY_BLEIO
-#include "shared-bindings/_bleio/__init__.h"
-#include "supervisor/shared/bluetooth.h"
-#endif
-
-#if CIRCUITPY_CANIO
-#include "common-hal/canio/CAN.h"
+#if CIRCUITPY_USB_CDC
+#include "shared-module/usb_cdc/__init__.h"
#endif
#if CIRCUITPY_WIFI
diff --git a/ports/atmel-samd/Makefile b/ports/atmel-samd/Makefile
index 58c1c0d60..48724af0c 100644
--- a/ports/atmel-samd/Makefile
+++ b/ports/atmel-samd/Makefile
@@ -122,7 +122,7 @@ CFLAGS += -ftree-vrp
$(echo PERIPHERALS_CHIP_FAMILY=$(PERIPHERALS_CHIP_FAMILY))
#Debugging/Optimization
ifeq ($(DEBUG), 1)
- CFLAGS += -ggdb3 -Og
+ CFLAGS += -ggdb3 -Og -Os
# You may want to disable -flto if it interferes with debugging.
CFLAGS += -flto -flto-partition=none
# You may want to enable these flags to make setting breakpoints easier.
diff --git a/ports/atmel-samd/boards/sparkfun_samd21_mini/mpconfigboard.mk b/ports/atmel-samd/boards/sparkfun_samd21_mini/mpconfigboard.mk
index 9460d0009..aef38661b 100644
--- a/ports/atmel-samd/boards/sparkfun_samd21_mini/mpconfigboard.mk
+++ b/ports/atmel-samd/boards/sparkfun_samd21_mini/mpconfigboard.mk
@@ -11,3 +11,4 @@ LONGINT_IMPL = NONE
CIRCUITPY_FULL_BUILD = 0
SUPEROPT_GC = 0
+SUPEROPT_VM = 0
diff --git a/ports/atmel-samd/common-hal/supervisor/Runtime.c b/ports/atmel-samd/common-hal/supervisor/Runtime.c
index 6be38f216..974f26cec 100755
--- a/ports/atmel-samd/common-hal/supervisor/Runtime.c
+++ b/ports/atmel-samd/common-hal/supervisor/Runtime.c
@@ -28,10 +28,10 @@
#include "shared-bindings/supervisor/Runtime.h"
#include "supervisor/serial.h"
-bool common_hal_get_serial_connected(void) {
+bool common_hal_supervisor_runtime_get_serial_connected(void) {
return (bool) serial_connected();
}
-bool common_hal_get_serial_bytes_available(void) {
+bool common_hal_supervisor_runtime_get_serial_bytes_available(void) {
return (bool) serial_bytes_available();
}
diff --git a/ports/atmel-samd/mpconfigport.mk b/ports/atmel-samd/mpconfigport.mk
index fb9cdf2e6..e47acfb36 100644
--- a/ports/atmel-samd/mpconfigport.mk
+++ b/ports/atmel-samd/mpconfigport.mk
@@ -18,7 +18,16 @@ ifeq ($(LONGINT_IMPL),LONGLONG)
MPY_TOOL_LONGINT_IMPL = -mlongint-impl=longlong
endif
+INTERNAL_LIBM = 1
+
+USB_SERIAL_NUMBER_LENGTH = 32
+
+# Number of USB endpoint pairs.
+USB_NUM_EP = 8
+
+######################################################################
# Put samd21-only choices here.
+
ifeq ($(CHIP_FAMILY),samd21)
# The ?='s allow overriding in mpconfigboard.mk.
@@ -40,7 +49,9 @@ CIRCUITPY_SDCARDIO ?= 0
CIRCUITPY_FRAMEBUFFERIO ?= 0
# SAMD21 needs separate endpoint pairs for MSC BULK IN and BULK OUT, otherwise it's erratic.
+# Because of that, there aren't enough endpoints for a secondary CDC serial connection.
USB_MSC_EP_NUM_OUT = 1
+CIRCUITPY_USB_CDC = 0
CIRCUITPY_ULAB = 0
@@ -55,9 +66,13 @@ CIRCUITPY_TERMINALIO = 0
endif
endif # samd21
+######################################################################
+######################################################################
# Put samd51-only choices here.
+
ifeq ($(CHIP_FAMILY),samd51)
+
# No native touchio on SAMD51.
CIRCUITPY_TOUCHIO_USE_NATIVE = 0
@@ -70,9 +85,4 @@ CIRCUITPY_RGBMATRIX ?= $(CIRCUITPY_FULL_BUILD)
CIRCUITPY_FRAMEBUFFERIO ?= $(CIRCUITPY_FULL_BUILD)
endif # samd51
-
-INTERNAL_LIBM = 1
-
-USB_SERIAL_NUMBER_LENGTH = 32
-
-USB_NUM_EP = 8
+######################################################################
diff --git a/ports/cxd56/common-hal/supervisor/Runtime.c b/ports/cxd56/common-hal/supervisor/Runtime.c
index a0d9e70ab..eeeb1430f 100755
--- a/ports/cxd56/common-hal/supervisor/Runtime.c
+++ b/ports/cxd56/common-hal/supervisor/Runtime.c
@@ -27,10 +27,10 @@
#include "shared-bindings/supervisor/Runtime.h"
#include "supervisor/serial.h"
-bool common_hal_get_serial_connected(void) {
+bool common_hal_supervisor_runtime_get_serial_connected(void) {
return (bool) serial_connected();
}
-bool common_hal_get_serial_bytes_available(void) {
+bool common_hal_supervisor_runtime_get_serial_bytes_available(void) {
return (bool) serial_bytes_available();
}
diff --git a/ports/cxd56/mpconfigport.mk b/ports/cxd56/mpconfigport.mk
index e1ffc79d0..33a993ad9 100644
--- a/ports/cxd56/mpconfigport.mk
+++ b/ports/cxd56/mpconfigport.mk
@@ -7,6 +7,9 @@ USB_CDC_EP_NUM_DATA_IN = 1
USB_MSC_EP_NUM_OUT = 5
USB_MSC_EP_NUM_IN = 4
+# Number of USB endpoint pairs.
+USB_NUM_EP = 6
+
MPY_TOOL_LONGINT_IMPL = -mlongint-impl=mpz
CIRCUITPY_AUDIOBUSIO = 0
diff --git a/ports/esp32s2/boards/lilygo_ttgo_t8_s2_st7789/mpconfigboard.mk b/ports/esp32s2/boards/lilygo_ttgo_t8_s2_st7789/mpconfigboard.mk
index 38a7ed1fb..79b45fd92 100644
--- a/ports/esp32s2/boards/lilygo_ttgo_t8_s2_st7789/mpconfigboard.mk
+++ b/ports/esp32s2/boards/lilygo_ttgo_t8_s2_st7789/mpconfigboard.mk
@@ -2,7 +2,6 @@ USB_VID = 0x303a
USB_PID = 0x8007
USB_PRODUCT = "TTGO T8 ESP32-S2"
USB_MANUFACTURER = "LILYGO"
-USB_DEVICES = "CDC,MSC,HID"
INTERNAL_FLASH_FILESYSTEM = 1
LONGINT_IMPL = MPZ
diff --git a/ports/esp32s2/boards/microdev_micro_s2/mpconfigboard.mk b/ports/esp32s2/boards/microdev_micro_s2/mpconfigboard.mk
index 515617095..783e7ad4c 100644
--- a/ports/esp32s2/boards/microdev_micro_s2/mpconfigboard.mk
+++ b/ports/esp32s2/boards/microdev_micro_s2/mpconfigboard.mk
@@ -2,7 +2,6 @@ USB_VID = 0x239A
USB_PID = 0x80C6
USB_PRODUCT = "microS2"
USB_MANUFACTURER = "microDev"
-USB_DEVICES = "CDC,MSC,HID"
INTERNAL_FLASH_FILESYSTEM = 1
LONGINT_IMPL = MPZ
diff --git a/ports/esp32s2/boards/unexpectedmaker_feathers2/mpconfigboard.mk b/ports/esp32s2/boards/unexpectedmaker_feathers2/mpconfigboard.mk
index 9857c0761..d045cc214 100644
--- a/ports/esp32s2/boards/unexpectedmaker_feathers2/mpconfigboard.mk
+++ b/ports/esp32s2/boards/unexpectedmaker_feathers2/mpconfigboard.mk
@@ -2,7 +2,6 @@ USB_VID = 0x239A
USB_PID = 0x80AC
USB_PRODUCT = "FeatherS2"
USB_MANUFACTURER = "UnexpectedMaker"
-USB_DEVICES = "CDC,MSC,HID"
INTERNAL_FLASH_FILESYSTEM = 1
LONGINT_IMPL = MPZ
diff --git a/ports/esp32s2/boards/unexpectedmaker_feathers2_prerelease/mpconfigboard.mk b/ports/esp32s2/boards/unexpectedmaker_feathers2_prerelease/mpconfigboard.mk
index 9857c0761..d045cc214 100644
--- a/ports/esp32s2/boards/unexpectedmaker_feathers2_prerelease/mpconfigboard.mk
+++ b/ports/esp32s2/boards/unexpectedmaker_feathers2_prerelease/mpconfigboard.mk
@@ -2,7 +2,6 @@ USB_VID = 0x239A
USB_PID = 0x80AC
USB_PRODUCT = "FeatherS2"
USB_MANUFACTURER = "UnexpectedMaker"
-USB_DEVICES = "CDC,MSC,HID"
INTERNAL_FLASH_FILESYSTEM = 1
LONGINT_IMPL = MPZ
diff --git a/ports/esp32s2/common-hal/supervisor/Runtime.c b/ports/esp32s2/common-hal/supervisor/Runtime.c
index ea663f897..974f26cec 100644
--- a/ports/esp32s2/common-hal/supervisor/Runtime.c
+++ b/ports/esp32s2/common-hal/supervisor/Runtime.c
@@ -28,10 +28,10 @@
#include "shared-bindings/supervisor/Runtime.h"
#include "supervisor/serial.h"
-bool common_hal_get_serial_connected(void) {
+bool common_hal_supervisor_runtime_get_serial_connected(void) {
return (bool) serial_connected();
}
-bool common_hal_get_serial_bytes_available(void) {
- return (bool) serial_bytes_available();
+bool common_hal_supervisor_runtime_get_serial_bytes_available(void) {
+ return (bool) serial_bytes_available();
}
diff --git a/ports/esp32s2/mpconfigport.mk b/ports/esp32s2/mpconfigport.mk
index b273c02ee..5073d8812 100644
--- a/ports/esp32s2/mpconfigport.mk
+++ b/ports/esp32s2/mpconfigport.mk
@@ -28,6 +28,8 @@ CIRCUITPY_FREQUENCYIO = 1
CIRCUITPY_I2CPERIPHERAL = 0
CIRCUITPY_ROTARYIO = 1
CIRCUITPY_NVM = 1
+CIRCUITPY_PS2IO ?= 1
+CIRCUITPY_TOUCHIO_USE_NATIVE ?= 1
# We don't have enough endpoints to include MIDI.
CIRCUITPY_USB_MIDI ?= 0
CIRCUITPY_USB_HID ?= 1
@@ -35,14 +37,9 @@ CIRCUITPY_USB_HID ?= 1
CIRCUITPY_USB_VENDOR ?= 0
CIRCUITPY_WIFI = 1
CIRCUITPY_WATCHDOG ?= 1
-CIRCUITPY_ESPIDF = 1
-
-ifndef CIRCUITPY_PS2IO
-CIRCUITPY_PS2IO = 1
-endif
-ifndef CIRCUITPY_TOUCHIO_USE_NATIVE
-CIRCUITPY_TOUCHIO_USE_NATIVE = 1
-endif
+CIRCUITPY_ESPIDF = 1
CIRCUITPY_MODULE ?= none
+
+USB_NUM_EP = 5
diff --git a/ports/litex/common-hal/supervisor/Runtime.c b/ports/litex/common-hal/supervisor/Runtime.c
index ea663f897..974f26cec 100644
--- a/ports/litex/common-hal/supervisor/Runtime.c
+++ b/ports/litex/common-hal/supervisor/Runtime.c
@@ -28,10 +28,10 @@
#include "shared-bindings/supervisor/Runtime.h"
#include "supervisor/serial.h"
-bool common_hal_get_serial_connected(void) {
+bool common_hal_supervisor_runtime_get_serial_connected(void) {
return (bool) serial_connected();
}
-bool common_hal_get_serial_bytes_available(void) {
- return (bool) serial_bytes_available();
+bool common_hal_supervisor_runtime_get_serial_bytes_available(void) {
+ return (bool) serial_bytes_available();
}
diff --git a/ports/litex/mpconfigport.mk b/ports/litex/mpconfigport.mk
index 003fb5c2c..af6a94e64 100644
--- a/ports/litex/mpconfigport.mk
+++ b/ports/litex/mpconfigport.mk
@@ -6,6 +6,9 @@ MPY_TOOL_LONGINT_IMPL = -mlongint-impl=mpz
# Internal math library is substantially smaller than toolchain one
INTERNAL_LIBM = 1
+# Number of USB endpoint pairs.
+USB_NUM_EP = 16
+
# Chip supplied serial number, in bytes
USB_SERIAL_NUMBER_LENGTH = 30
diff --git a/ports/mimxrt10xx/common-hal/supervisor/Runtime.c b/ports/mimxrt10xx/common-hal/supervisor/Runtime.c
index 6be38f216..974f26cec 100755
--- a/ports/mimxrt10xx/common-hal/supervisor/Runtime.c
+++ b/ports/mimxrt10xx/common-hal/supervisor/Runtime.c
@@ -28,10 +28,10 @@
#include "shared-bindings/supervisor/Runtime.h"
#include "supervisor/serial.h"
-bool common_hal_get_serial_connected(void) {
+bool common_hal_supervisor_runtime_get_serial_connected(void) {
return (bool) serial_connected();
}
-bool common_hal_get_serial_bytes_available(void) {
+bool common_hal_supervisor_runtime_get_serial_bytes_available(void) {
return (bool) serial_bytes_available();
}
diff --git a/ports/mimxrt10xx/mpconfigport.mk b/ports/mimxrt10xx/mpconfigport.mk
index b4cc9586a..de594b14b 100644
--- a/ports/mimxrt10xx/mpconfigport.mk
+++ b/ports/mimxrt10xx/mpconfigport.mk
@@ -17,6 +17,9 @@ INTERNAL_LIBM = 1
USB_SERIAL_NUMBER_LENGTH = 32
USB_HIGHSPEED = 1
+# Number of USB endpoint pairs.
+USB_NUM_EP = 8
+
INTERNAL_FLASH_FILESYSTEM = 1
CIRCUITPY_AUDIOIO = 0
diff --git a/ports/nrf/bluetooth/ble_uart.c b/ports/nrf/bluetooth/ble_uart.c
index 1e7a319bd..1b87b82d1 100644
--- a/ports/nrf/bluetooth/ble_uart.c
+++ b/ports/nrf/bluetooth/ble_uart.c
@@ -40,7 +40,7 @@
#include "shared-bindings/_bleio/Service.h"
#include "shared-bindings/_bleio/UUID.h"
-#if CIRCUITPY_SERIAL_BLE
+#if CIRCUITPY_REPL_BLE
static const char default_name[] = "CP-REPL"; // max 8 chars or uuid won't fit in adv data
static const char NUS_UUID[] = "6e400001-b5a3-f393-e0a9-e50e24dcca9e";
@@ -190,4 +190,4 @@ void mp_hal_stdout_tx_strn(const char *str, size_t len) {
}
}
-#endif // CIRCUITPY_SERIAL_BLE
+#endif // CIRCUITPY_REPL_BLE
diff --git a/ports/nrf/boards/pca10100/mpconfigboard.mk b/ports/nrf/boards/pca10100/mpconfigboard.mk
index c8cba2877..fbb9987c2 100644
--- a/ports/nrf/boards/pca10100/mpconfigboard.mk
+++ b/ports/nrf/boards/pca10100/mpconfigboard.mk
@@ -29,6 +29,7 @@ CIRCUITPY_BUSDEVICE = 0
MICROPY_PY_ASYNC_AWAIT = 0
SUPEROPT_GC = 0
+SUPEROPT_VM = 0
# Override optimization to keep binary small
OPTIMIZATION_FLAGS = -Os
diff --git a/ports/nrf/boards/simmel/mpconfigboard.mk b/ports/nrf/boards/simmel/mpconfigboard.mk
index 6bc05a7f0..52743d340 100644
--- a/ports/nrf/boards/simmel/mpconfigboard.mk
+++ b/ports/nrf/boards/simmel/mpconfigboard.mk
@@ -3,8 +3,6 @@ USB_PID = 0xc051
USB_PRODUCT = "Simmel"
USB_MANUFACTURER = "Betrusted"
-CIRCUITPY_DEVICES="CDC,MSC,HID"
-
MCU_CHIP = nrf52833
# SPI_FLASH_FILESYSTEM = 1
@@ -31,6 +29,7 @@ CIRCUITPY_RTC = 1
CIRCUITPY_SDCARDIO = 0
CIRCUITPY_TOUCHIO = 0
CIRCUITPY_ULAB = 0
+CIRCUITPY_USB_CDC = 0
CIRCUITPY_USB_MIDI = 0
CIRCUITPY_WATCHDOG = 1
diff --git a/ports/nrf/common-hal/supervisor/Runtime.c b/ports/nrf/common-hal/supervisor/Runtime.c
index ea663f897..a24e86cdf 100755
--- a/ports/nrf/common-hal/supervisor/Runtime.c
+++ b/ports/nrf/common-hal/supervisor/Runtime.c
@@ -28,10 +28,10 @@
#include "shared-bindings/supervisor/Runtime.h"
#include "supervisor/serial.h"
-bool common_hal_get_serial_connected(void) {
+bool common_hal_supervisor_runtime_get_serial_connected(void) {
return (bool) serial_connected();
}
-bool common_hal_get_serial_bytes_available(void) {
+bool common_hal_supervisor_runtime_get_serial_bytes_available(void) {
return (bool) serial_bytes_available();
}
diff --git a/ports/nrf/mpconfigport.mk b/ports/nrf/mpconfigport.mk
index 9560064fb..83924ff79 100644
--- a/ports/nrf/mpconfigport.mk
+++ b/ports/nrf/mpconfigport.mk
@@ -11,6 +11,9 @@ INTERNAL_LIBM = 1
USB_SERIAL_NUMBER_LENGTH = 16
+# Number of USB endpoint pairs.
+USB_NUM_EP = 8
+
# All nRF ports have longints.
LONGINT_IMPL = MPZ
diff --git a/ports/nrf/supervisor/serial.c b/ports/nrf/supervisor/serial.c
index b19e9267c..2c2c0116f 100644
--- a/ports/nrf/supervisor/serial.c
+++ b/ports/nrf/supervisor/serial.c
@@ -28,15 +28,15 @@
#include "supervisor/serial.h"
-#if CIRCUITPY_SERIAL_BLE
+#if CIRCUITPY_REPL_BLE
#include "ble_uart.h"
-#elif CIRCUITPY_SERIAL_UART
+#elif CIRCUITPY_REPL_UART
#include <string.h>
#include "nrf_gpio.h"
#include "nrfx_uarte.h"
#endif
-#if CIRCUITPY_SERIAL_BLE
+#if CIRCUITPY_REPL_BLE
void serial_init(void) {
ble_uart_init();
@@ -58,7 +58,7 @@ void serial_write(const char *text) {
ble_uart_stdout_tx_str(text);
}
-#elif CIRCUITPY_SERIAL_UART
+#elif CIRCUITPY_REPL_UART
uint8_t serial_received_char;
nrfx_uarte_t serial_instance = NRFX_UARTE_INSTANCE(0);
@@ -124,4 +124,4 @@ void serial_write_substring(const char *text, uint32_t len) {
}
}
-#endif // CIRCUITPY_SERIAL_UART
+#endif // CIRCUITPY_REPL_UART
diff --git a/ports/raspberrypi/common-hal/supervisor/Runtime.c b/ports/raspberrypi/common-hal/supervisor/Runtime.c
index 6be38f216..974f26cec 100755
--- a/ports/raspberrypi/common-hal/supervisor/Runtime.c
+++ b/ports/raspberrypi/common-hal/supervisor/Runtime.c
@@ -28,10 +28,10 @@
#include "shared-bindings/supervisor/Runtime.h"
#include "supervisor/serial.h"
-bool common_hal_get_serial_connected(void) {
+bool common_hal_supervisor_runtime_get_serial_connected(void) {
return (bool) serial_connected();
}
-bool common_hal_get_serial_bytes_available(void) {
+bool common_hal_supervisor_runtime_get_serial_bytes_available(void) {
return (bool) serial_bytes_available();
}
diff --git a/ports/raspberrypi/mpconfigport.mk b/ports/raspberrypi/mpconfigport.mk
index b93e4dcc7..ab85c59f9 100644
--- a/ports/raspberrypi/mpconfigport.mk
+++ b/ports/raspberrypi/mpconfigport.mk
@@ -50,4 +50,5 @@ INTERNAL_LIBM = 1
USB_SERIAL_NUMBER_LENGTH = 16
+# Number of USB endpoint pairs.
USB_NUM_EP = 8
diff --git a/ports/stm/boards/stm32f412zg_discovery/mpconfigboard.mk b/ports/stm/boards/stm32f412zg_discovery/mpconfigboard.mk
index c99eb1a00..28874f9c6 100644
--- a/ports/stm/boards/stm32f412zg_discovery/mpconfigboard.mk
+++ b/ports/stm/boards/stm32f412zg_discovery/mpconfigboard.mk
@@ -16,5 +16,3 @@ MCU_PACKAGE = LQFP144
LD_COMMON = boards/common_default.ld
LD_FILE = boards/STM32F412_fs.ld
-
-CIRCUITPY_USB_HID = 1
diff --git a/ports/stm/boards/thunderpack_v12/mpconfigboard.mk b/ports/stm/boards/thunderpack_v12/mpconfigboard.mk
index a2e1da101..4436f04b7 100644
--- a/ports/stm/boards/thunderpack_v12/mpconfigboard.mk
+++ b/ports/stm/boards/thunderpack_v12/mpconfigboard.mk
@@ -2,7 +2,9 @@ USB_VID = 0x239A
USB_PID = 0x8071
USB_PRODUCT = "Thunderpack STM32F411"
USB_MANUFACTURER = "Jeremy Gillick"
-USB_DEVICES = "CDC,MSC"
+
+# Turn off HID devices
+CIRCUITPY_USB_HID = 0
LONGINT_IMPL = NONE
diff --git a/ports/stm/common-hal/supervisor/Runtime.c b/ports/stm/common-hal/supervisor/Runtime.c
index ea663f897..974f26cec 100755
--- a/ports/stm/common-hal/supervisor/Runtime.c
+++ b/ports/stm/common-hal/supervisor/Runtime.c
@@ -28,10 +28,10 @@
#include "shared-bindings/supervisor/Runtime.h"
#include "supervisor/serial.h"
-bool common_hal_get_serial_connected(void) {
+bool common_hal_supervisor_runtime_get_serial_connected(void) {
return (bool) serial_connected();
}
-bool common_hal_get_serial_bytes_available(void) {
- return (bool) serial_bytes_available();
+bool common_hal_supervisor_runtime_get_serial_bytes_available(void) {
+ return (bool) serial_bytes_available();
}
diff --git a/ports/stm/mpconfigport.mk b/ports/stm/mpconfigport.mk
index bcecaa517..fe257fc50 100644
--- a/ports/stm/mpconfigport.mk
+++ b/ports/stm/mpconfigport.mk
@@ -8,6 +8,7 @@ ifeq ($(MCU_VARIANT),STM32F405xx)
CIRCUITPY_FRAMEBUFFERIO ?= 1
CIRCUITPY_RGBMATRIX ?= 1
CIRCUITPY_SDIOIO ?= 1
+ # Number of USB endpoint pairs.
USB_NUM_EP = 4
endif
@@ -23,6 +24,8 @@ ifeq ($(MCU_SERIES),F4)
CIRCUITPY_RTC ?= 0
CIRCUITPY_USB_MIDI ?= 0
CIRCUITPY_USB_HID ?= 0
+
+ USB_NUM_EP = 4
endif
ifeq ($(MCU_SERIES),H7)
@@ -40,6 +43,8 @@ ifeq ($(MCU_SERIES),H7)
CIRCUITPY_RTC ?= 0
CIRCUITPY_USB_HID ?= 0
CIRCUITPY_USB_MIDI ?= 0
+
+ USB_NUM_EP = 9
endif
ifeq ($(MCU_SERIES),F7)
@@ -56,4 +61,6 @@ ifeq ($(MCU_SERIES),F7)
CIRCUITPY_RTC ?= 0
CIRCUITPY_USB_HID ?= 0
CIRCUITPY_USB_MIDI ?= 0
+
+ USB_NUM_EP = 6
endif
diff --git a/py/circuitpy_defns.mk b/py/circuitpy_defns.mk
index 47870ede1..943c99f93 100644
--- a/py/circuitpy_defns.mk
+++ b/py/circuitpy_defns.mk
@@ -132,9 +132,6 @@ endif
ifeq ($(CIRCUITPY_AUDIOMP3),1)
SRC_PATTERNS += audiomp3/%
endif
-ifeq ($(CIRCUITPY_BITOPS),1)
-SRC_PATTERNS += bitops/%
-endif
ifeq ($(CIRCUITPY_BITBANGIO),1)
SRC_PATTERNS += bitbangio/%
endif
@@ -142,6 +139,9 @@ endif
ifeq ($(CIRCUITPY_BITBANG_APA102),1)
SRC_PATTERNS += bitbangio/SPI%
endif
+ifeq ($(CIRCUITPY_BITOPS),1)
+SRC_PATTERNS += bitops/%
+endif
ifeq ($(CIRCUITPY_BLEIO),1)
SRC_PATTERNS += _bleio/%
endif
@@ -289,6 +289,9 @@ endif
ifeq ($(CIRCUITPY_UHEAP),1)
SRC_PATTERNS += uheap/%
endif
+ifeq ($(CIRCUITPY_USB_CDC),1)
+SRC_PATTERNS += usb_cdc/%
+endif
ifeq ($(CIRCUITPY_USB_HID),1)
SRC_PATTERNS += usb_hid/%
endif
diff --git a/py/circuitpy_mpconfig.h b/py/circuitpy_mpconfig.h
index d72146c42..cbe668289 100644
--- a/py/circuitpy_mpconfig.h
+++ b/py/circuitpy_mpconfig.h
@@ -299,6 +299,13 @@ extern const struct _mp_obj_module_t audiopwmio_module;
#define BINASCII_MODULE
#endif
+#if CIRCUITPY_BITBANGIO
+#define BITBANGIO_MODULE { MP_OBJ_NEW_QSTR(MP_QSTR_bitbangio), (mp_obj_t)&bitbangio_module },
+extern const struct _mp_obj_module_t bitbangio_module;
+#else
+#define BITBANGIO_MODULE
+#endif
+
#if CIRCUITPY_BITOPS
extern const struct _mp_obj_module_t bitops_module;
#define BITOPS_MODULE { MP_OBJ_NEW_QSTR(MP_QSTR_bitops),(mp_obj_t)&bitops_module },
@@ -307,13 +314,6 @@ extern const struct _mp_obj_module_t bitops_module;
#endif
-#if CIRCUITPY_BITBANGIO
-#define BITBANGIO_MODULE { MP_OBJ_NEW_QSTR(MP_QSTR_bitbangio), (mp_obj_t)&bitbangio_module },
-extern const struct _mp_obj_module_t bitbangio_module;
-#else
-#define BITBANGIO_MODULE
-#endif
-
#if CIRCUITPY_BLEIO
#define BLEIO_MODULE { MP_OBJ_NEW_QSTR(MP_QSTR__bleio), (mp_obj_t)&bleio_module },
extern const struct _mp_obj_module_t bleio_module;
@@ -744,6 +744,13 @@ extern const struct _mp_obj_module_t uheap_module;
#define UHEAP_MODULE
#endif
+#if CIRCUITPY_USB_CDC
+extern const struct _mp_obj_module_t usb_cdc_module;
+#define USB_CDC_MODULE { MP_OBJ_NEW_QSTR(MP_QSTR_usb_cdc),(mp_obj_t)&usb_cdc_module },
+#else
+#define USB_CDC_MODULE
+#endif
+
#if CIRCUITPY_USB_HID
extern const struct _mp_obj_module_t usb_hid_module;
#define USB_HID_MODULE { MP_OBJ_NEW_QSTR(MP_QSTR_usb_hid),(mp_obj_t)&usb_hid_module },
@@ -827,8 +834,8 @@ extern const struct _mp_obj_module_t msgpack_module;
AUDIOMP3_MODULE \
AUDIOPWMIO_MODULE \
BINASCII_MODULE \
- BITOPS_MODULE \
BITBANGIO_MODULE \
+ BITOPS_MODULE \
BLEIO_MODULE \
BOARD_MODULE \
BUSDEVICE_MODULE \
@@ -884,6 +891,7 @@ extern const struct _mp_obj_module_t msgpack_module;
SUPERVISOR_MODULE \
TOUCHIO_MODULE \
UHEAP_MODULE \
+ USB_CDC_MODULE \
USB_HID_MODULE \
USB_MIDI_MODULE \
USTACK_MODULE \
diff --git a/py/circuitpy_mpconfig.mk b/py/circuitpy_mpconfig.mk
index 6244ed136..9d8e53ea7 100644
--- a/py/circuitpy_mpconfig.mk
+++ b/py/circuitpy_mpconfig.mk
@@ -89,12 +89,15 @@ CFLAGS += -DCIRCUITPY_AUDIOMP3=$(CIRCUITPY_AUDIOMP3)
CIRCUITPY_BINASCII ?= $(CIRCUITPY_FULL_BUILD)
CFLAGS += -DCIRCUITPY_BINASCII=$(CIRCUITPY_BINASCII)
-CIRCUITPY_BITOPS ?= 0
-CFLAGS += -DCIRCUITPY_BITOPS=$(CIRCUITPY_BITOPS)
+CIRCUITPY_BITBANG_APA102 ?= 0
+CFLAGS += -DCIRCUITPY_BITBANG_APA102=$(CIRCUITPY_BITBANG_APA102)
CIRCUITPY_BITBANGIO ?= $(CIRCUITPY_FULL_BUILD)
CFLAGS += -DCIRCUITPY_BITBANGIO=$(CIRCUITPY_BITBANGIO)
+CIRCUITPY_BITOPS ?= 0
+CFLAGS += -DCIRCUITPY_BITOPS=$(CIRCUITPY_BITOPS)
+
# _bleio can be supported on most any board via HCI
CIRCUITPY_BLEIO_HCI ?= $(CIRCUITPY_FULL_BUILD)
CFLAGS += -DCIRCUITPY_BLEIO_HCI=$(CIRCUITPY_BLEIO_HCI)
@@ -103,6 +106,9 @@ CFLAGS += -DCIRCUITPY_BLEIO_HCI=$(CIRCUITPY_BLEIO_HCI)
CIRCUITPY_BLEIO ?= $(CIRCUITPY_BLEIO_HCI)
CFLAGS += -DCIRCUITPY_BLEIO=$(CIRCUITPY_BLEIO)
+CIRCUITPY_BLE_FILE_SERVICE ?= 0
+CFLAGS += -DCIRCUITPY_BLE_FILE_SERVICE=$(CIRCUITPY_BLE_FILE_SERVICE)
+
CIRCUITPY_BOARD ?= 1
CFLAGS += -DCIRCUITPY_BOARD=$(CIRCUITPY_BOARD)
@@ -130,6 +136,13 @@ CFLAGS += -DCIRCUITPY_COUNTIO=$(CIRCUITPY_COUNTIO)
CIRCUITPY_DISPLAYIO ?= $(CIRCUITPY_FULL_BUILD)
CFLAGS += -DCIRCUITPY_DISPLAYIO=$(CIRCUITPY_DISPLAYIO)
+CIRCUITPY_DUALBANK ?= 0
+CFLAGS += -DCIRCUITPY_DUALBANK=$(CIRCUITPY_DUALBANK)
+
+# Enabled micropython.native decorator (experimental)
+CIRCUITPY_ENABLE_MPY_NATIVE ?= 0
+CFLAGS += -DCIRCUITPY_ENABLE_MPY_NATIVE=$(CIRCUITPY_ENABLE_MPY_NATIVE)
+
CIRCUITPY_ERRNO ?= $(CIRCUITPY_FULL_BUILD)
CFLAGS += -DCIRCUITPY_ERRNO=$(CIRCUITPY_ERRNO)
@@ -182,6 +195,9 @@ CFLAGS += -DCIRCUITPY_MEMORYMONITOR=$(CIRCUITPY_MEMORYMONITOR)
CIRCUITPY_MICROCONTROLLER ?= 1
CFLAGS += -DCIRCUITPY_MICROCONTROLLER=$(CIRCUITPY_MICROCONTROLLER)
+CIRCUITPY_MSGPACK ?= $(CIRCUITPY_FULL_BUILD)
+CFLAGS += -DCIRCUITPY_MSGPACK=$(CIRCUITPY_MSGPACK)
+
CIRCUITPY_NEOPIXEL_WRITE ?= 1
CFLAGS += -DCIRCUITPY_NEOPIXEL_WRITE=$(CIRCUITPY_NEOPIXEL_WRITE)
@@ -195,8 +211,8 @@ CFLAGS += -DCIRCUITPY_NVM=$(CIRCUITPY_NVM)
CIRCUITPY_OS ?= 1
CFLAGS += -DCIRCUITPY_OS=$(CIRCUITPY_OS)
-CIRCUITPY_DUALBANK ?= 0
-CFLAGS += -DCIRCUITPY_DUALBANK=$(CIRCUITPY_DUALBANK)
+CIRCUITPY_PEW ?= 0
+CFLAGS += -DCIRCUITPY_PEW=$(CIRCUITPY_PEW)
CIRCUITPY_PIXELBUF ?= $(CIRCUITPY_FULL_BUILD)
CFLAGS += -DCIRCUITPY_PIXELBUF=$(CIRCUITPY_PIXELBUF)
@@ -219,6 +235,20 @@ CFLAGS += -DCIRCUITPY_RANDOM=$(CIRCUITPY_RANDOM)
CIRCUITPY_RE ?= $(CIRCUITPY_FULL_BUILD)
CFLAGS += -DCIRCUITPY_RE=$(CIRCUITPY_RE)
+CIRCUITPY_REPL_BLE ?= 0
+CFLAGS += -DCIRCUITPY_REPL_BLE=$(CIRCUITPY_REPL_BLE)
+
+CIRCUITPY_REPL_UART ?= 0
+CFLAGS += -DCIRCUITPY_REPL_UART=$(CIRCUITPY_REPL_UART)
+
+CIRCUITPY_REPL_USB ?= 1
+CFLAGS += -DCIRCUITPY_REPL_USB=$(CIRCUITPY_REPL_USB)
+
+# Should busio.I2C() check for pullups?
+# Some boards in combination with certain peripherals may not want this.
+CIRCUITPY_REQUIRE_I2C_PULLUPS ?= 1
+CFLAGS += -DCIRCUITPY_REQUIRE_I2C_PULLUPS=$(CIRCUITPY_REQUIRE_I2C_PULLUPS)
+
# CIRCUITPY_RP2PIO is handled in the raspberrypi tree.
# Only for rp2 chips.
# Assume not a rp2 build.
@@ -285,46 +315,54 @@ CFLAGS += -DCIRCUITPY_TOUCHIO=$(CIRCUITPY_TOUCHIO)
CIRCUITPY_UHEAP ?= 0
CFLAGS += -DCIRCUITPY_UHEAP=$(CIRCUITPY_UHEAP)
+# Secondary CDC is usually available if there are at least 8 endpoints.
+CIRCUITPY_USB_CDC ?= $(shell expr $(USB_NUM_EP) '>=' 8)
+CFLAGS += -DCIRCUITPY_USB_CDC=$(CIRCUITPY_USB_CDC)
+
CIRCUITPY_USB_HID ?= 1
CFLAGS += -DCIRCUITPY_USB_HID=$(CIRCUITPY_USB_HID)
+CIRCUITPY_USB_HID_CONSUMER ?= 1
+CFLAGS += -DCIRCUITPY_USB_HID_CONSUMER=$(CIRCUITPY_USB_HID_CONSUMER)
+
+CIRCUITPY_USB_HID_DIGITIZER ?= 0
+CFLAGS += -DCIRCUITPY_USB_HID_DIGITIZER=$(CIRCUITPY_USB_HID_DIGITIZER)
+
+CIRCUITPY_USB_HID_GAMEPAD ?= 1
+CFLAGS += -DCIRCUITPY_USB_HID_GAMEPAD=$(CIRCUITPY_USB_HID_GAMEPAD)
+
+CIRCUITPY_USB_HID_KEYBOARD ?= 1
+CFLAGS += -DCIRCUITPY_USB_HID_KEYBOARD=$(CIRCUITPY_USB_HID_KEYBOARD)
+
+CIRCUITPY_USB_HID_MOUSE ?= 1
+CFLAGS += -DCIRCUITPY_USB_HID_MOUSE=$(CIRCUITPY_USB_HID_MOUSE)
+
+CIRCUITPY_USB_HID_SYS_CONTROL ?= 0
+CFLAGS += -DCIRCUITPY_USB_HID_CONTROL=$(CIRCUITPY_USB_HID_CONTROL)
+
+CIRCUITPY_USB_HID_XAC_COMPATIBLE_GAMEPAD ?= 0
+CFLAGS += -DCIRCUITPY_USB_HID_XAC_COMPATIBLE_GAMEPAD=$(CIRCUITPY_USB_HID_XAC_COMPATIBLE_GAMEPAD)
+
CIRCUITPY_USB_MIDI ?= 1
CFLAGS += -DCIRCUITPY_USB_MIDI=$(CIRCUITPY_USB_MIDI)
+CIRCUITPY_USB_MSC ?= 1
+CFLAGS += -DCIRCUITPY_USB_MSC=$(CIRCUITPY_USB_MSC)
+
# Defaulting this to OFF initially because it has only been tested on a
# limited number of platforms, and the other platforms do not have this
# setting in their mpconfigport.mk and/or mpconfigboard.mk files yet.
CIRCUITPY_USB_VENDOR ?= 0
CFLAGS += -DCIRCUITPY_USB_VENDOR=$(CIRCUITPY_USB_VENDOR)
-CIRCUITPY_PEW ?= 0
-CFLAGS += -DCIRCUITPY_PEW=$(CIRCUITPY_PEW)
+ifndef USB_NUM_EP
+$(error "USB_NUM_EP (number of USB endpoint pairs)must be defined")
+endif
# For debugging.
CIRCUITPY_USTACK ?= 0
CFLAGS += -DCIRCUITPY_USTACK=$(CIRCUITPY_USTACK)
-# Non-module conditionals
-
-CIRCUITPY_BITBANG_APA102 ?= 0
-CFLAGS += -DCIRCUITPY_BITBANG_APA102=$(CIRCUITPY_BITBANG_APA102)
-
-# Should busio.I2C() check for pullups?
-# Some boards in combination with certain peripherals may not want this.
-CIRCUITPY_REQUIRE_I2C_PULLUPS ?= 1
-CFLAGS += -DCIRCUITPY_REQUIRE_I2C_PULLUPS=$(CIRCUITPY_REQUIRE_I2C_PULLUPS)
-
-# REPL over BLE
-CIRCUITPY_SERIAL_BLE ?= 0
-CFLAGS += -DCIRCUITPY_SERIAL_BLE=$(CIRCUITPY_SERIAL_BLE)
-
-CIRCUITPY_BLE_FILE_SERVICE ?= 0
-CFLAGS += -DCIRCUITPY_BLE_FILE_SERVICE=$(CIRCUITPY_BLE_FILE_SERVICE)
-
-# REPL over UART
-CIRCUITPY_SERIAL_UART ?= 0
-CFLAGS += -DCIRCUITPY_SERIAL_UART=$(CIRCUITPY_SERIAL_UART)
-
# ulab numerics library
CIRCUITPY_ULAB ?= $(CIRCUITPY_FULL_BUILD)
CFLAGS += -DCIRCUITPY_ULAB=$(CIRCUITPY_ULAB)
@@ -335,10 +373,3 @@ CFLAGS += -DCIRCUITPY_WATCHDOG=$(CIRCUITPY_WATCHDOG)
CIRCUITPY_WIFI ?= 0
CFLAGS += -DCIRCUITPY_WIFI=$(CIRCUITPY_WIFI)
-
-# Enabled micropython.native decorator (experimental)
-CIRCUITPY_ENABLE_MPY_NATIVE ?= 0
-CFLAGS += -DCIRCUITPY_ENABLE_MPY_NATIVE=$(CIRCUITPY_ENABLE_MPY_NATIVE)
-
-CIRCUITPY_MSGPACK ?= $(CIRCUITPY_FULL_BUILD)
-CFLAGS += -DCIRCUITPY_MSGPACK=$(CIRCUITPY_MSGPACK)
diff --git a/py/stream.c b/py/stream.c
index ae702bb1b..0813c1d7f 100644
--- a/py/stream.c
+++ b/py/stream.c
@@ -99,14 +99,22 @@ const mp_stream_p_t *mp_get_stream_raise(mp_obj_t self_in, int flags) {
STATIC mp_obj_t stream_read_generic(size_t n_args, const mp_obj_t *args, byte flags) {
// What to do if sz < -1? Python docs don't specify this case.
- // CPython does a readall, but here we silently let negatives through,
- // and they will cause a MemoryError.
+ // CPython does a readall, let's do the same.
mp_int_t sz;
- if (n_args == 1 || args[1] == mp_const_none || ((sz = mp_obj_get_int(args[1])) == -1)) {
- return stream_readall(args[0]);
- }
-
const mp_stream_p_t *stream_p = mp_get_stream(args[0]);
+ if (stream_p->pyserial_read_compatibility) {
+ // Pyserial defaults to sz=1 if not specified.
+ if (n_args == 1) {
+ sz = 1;
+ } else {
+ // Pyserial treats negative size as 0.
+ sz = MAX(0, mp_obj_get_int(args[1]));
+ }
+ } else {
+ if (n_args == 1 || args[1] == mp_const_none || (sz = mp_obj_get_int(args[1])) <= -1) {
+ return stream_readall(args[0]);
+ }
+ }
#if MICROPY_PY_BUILTINS_STR_UNICODE
if (stream_p->is_text) {
@@ -284,7 +292,7 @@ STATIC mp_obj_t stream_readinto(size_t n_args, const mp_obj_t *args) {
// https://docs.python.org/3/library/socket.html#socket.socket.recv_into
mp_uint_t len = bufinfo.len;
if (n_args > 2) {
- if (mp_get_stream(args[0])->pyserial_compatibility) {
+ if (mp_get_stream(args[0])->pyserial_readinto_compatibility) {
mp_raise_ValueError(translate("length argument not allowed for this type"));
}
len = mp_obj_get_int(args[2]);
@@ -297,7 +305,10 @@ STATIC mp_obj_t stream_readinto(size_t n_args, const mp_obj_t *args) {
mp_uint_t out_sz = mp_stream_read_exactly(args[0], bufinfo.buf, len, &error);
if (error != 0) {
if (mp_is_nonblocking_error(error)) {
- return mp_const_none;
+ // pyserial readinto never returns None, just 0.
+ return mp_get_stream(args[0])->pyserial_dont_return_none_compatibility
+ ? MP_OBJ_NEW_SMALL_INT(0)
+ : mp_const_none;
}
mp_raise_OSError(error);
} else {
@@ -323,7 +334,10 @@ STATIC mp_obj_t stream_readall(mp_obj_t self_in) {
// If we read nothing, return None, just like read().
// Otherwise, return data read so far.
if (total_size == 0) {
- return mp_const_none;
+ // pyserial read() never returns None, just b''.
+ return stream_p->pyserial_dont_return_none_compatibility
+ ? mp_const_empty_bytes
+ : mp_const_none;
}
break;
}
diff --git a/py/stream.h b/py/stream.h
index be6b23d40..c05dcfc50 100644
--- a/py/stream.h
+++ b/py/stream.h
@@ -72,7 +72,9 @@ typedef struct _mp_stream_p_t {
mp_uint_t (*write)(mp_obj_t obj, const void *buf, mp_uint_t size, int *errcode);
mp_uint_t (*ioctl)(mp_obj_t obj, mp_uint_t request, uintptr_t arg, int *errcode);
mp_uint_t is_text : 1; // default is bytes, set this for text stream
- bool pyserial_compatibility: 1; // adjust API to match pyserial more closely
+ bool pyserial_readinto_compatibility: 1; // Disallow size parameter in readinto()
+ bool pyserial_read_compatibility: 1; // Disallow omitting read(size) size parameter
+ bool pyserial_dont_return_none_compatibility: 1; // Don't return None for read() or readinto()
} mp_stream_p_t;
MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_stream_read_obj);
diff --git a/shared-bindings/_bleio/CharacteristicBuffer.c b/shared-bindings/_bleio/CharacteristicBuffer.c
index 4d6c836c1..333b275ff 100644
--- a/shared-bindings/_bleio/CharacteristicBuffer.c
+++ b/shared-bindings/_bleio/CharacteristicBuffer.c
@@ -231,8 +231,8 @@ STATIC const mp_stream_p_t characteristic_buffer_stream_p = {
.write = bleio_characteristic_buffer_write,
.ioctl = bleio_characteristic_buffer_ioctl,
.is_text = false,
- // Match PySerial when possible, such as disallowing optional length argument for .readinto()
- .pyserial_compatibility = true,
+ // Disallow readinto() size parameter.
+ .pyserial_readinto_compatibility = true,
};
diff --git a/shared-bindings/busio/UART.c b/shared-bindings/busio/UART.c
index bf0b7e721..f48109fde 100644
--- a/shared-bindings/busio/UART.c
+++ b/shared-bindings/busio/UART.c
@@ -415,8 +415,8 @@ STATIC const mp_stream_p_t uart_stream_p = {
.write = busio_uart_write,
.ioctl = busio_uart_ioctl,
.is_text = false,
- // Match PySerial when possible, such as disallowing optional length argument for .readinto()
- .pyserial_compatibility = true,
+ // Disallow optional length argument for .readinto()
+ .pyserial_readinto_compatibility = true,
};
const mp_obj_type_t busio_uart_type = {
diff --git a/shared-bindings/supervisor/Runtime.c b/shared-bindings/supervisor/Runtime.c
index 8e0259a3b..283c8a1d6 100755
--- a/shared-bindings/supervisor/Runtime.c
+++ b/shared-bindings/supervisor/Runtime.c
@@ -55,59 +55,46 @@ STATIC supervisor_run_reason_t _run_reason;
//| serial_connected: bool
//| """Returns the USB serial communication status (read-only)."""
//|
-
-STATIC mp_obj_t supervisor_get_serial_connected(mp_obj_t self){
- if (!common_hal_get_serial_connected()) {
- return mp_const_false;
- }
- else {
- return mp_const_true;
- }
+STATIC mp_obj_t supervisor_runtime_get_serial_connected(mp_obj_t self){
+ return mp_obj_new_bool(common_hal_supervisor_runtime_get_serial_connected());
}
-MP_DEFINE_CONST_FUN_OBJ_1(supervisor_get_serial_connected_obj, supervisor_get_serial_connected);
+MP_DEFINE_CONST_FUN_OBJ_1(supervisor_runtime_get_serial_connected_obj, supervisor_runtime_get_serial_connected);
-const mp_obj_property_t supervisor_serial_connected_obj = {
+const mp_obj_property_t supervisor_runtime_serial_connected_obj = {
.base.type = &mp_type_property,
- .proxy = {(mp_obj_t)&supervisor_get_serial_connected_obj,
+ .proxy = {(mp_obj_t)&supervisor_runtime_get_serial_connected_obj,
(mp_obj_t)&mp_const_none_obj,
(mp_obj_t)&mp_const_none_obj},
};
-
//| serial_bytes_available: int
//| """Returns the whether any bytes are available to read
//| on the USB serial input. Allows for polling to see whether
//| to call the built-in input() or wait. (read-only)"""
//|
-STATIC mp_obj_t supervisor_get_serial_bytes_available(mp_obj_t self){
- if (!common_hal_get_serial_bytes_available()) {
- return mp_const_false;
- }
- else {
- return mp_const_true;
- }
+STATIC mp_obj_t supervisor_runtime_get_serial_bytes_available(mp_obj_t self){
+ return mp_obj_new_bool(common_hal_supervisor_runtime_get_serial_bytes_available());
}
-MP_DEFINE_CONST_FUN_OBJ_1(supervisor_get_serial_bytes_available_obj, supervisor_get_serial_bytes_available);
+MP_DEFINE_CONST_FUN_OBJ_1(supervisor_runtime_get_serial_bytes_available_obj, supervisor_runtime_get_serial_bytes_available);
-const mp_obj_property_t supervisor_serial_bytes_available_obj = {
+const mp_obj_property_t supervisor_runtime_serial_bytes_available_obj = {
.base.type = &mp_type_property,
- .proxy = {(mp_obj_t)&supervisor_get_serial_bytes_available_obj,
+ .proxy = {(mp_obj_t)&supervisor_runtime_get_serial_bytes_available_obj,
(mp_obj_t)&mp_const_none_obj,
(mp_obj_t)&mp_const_none_obj},
};
-
//| run_reason: RunReason
//| """Returns why CircuitPython started running this particular time."""
//|
-STATIC mp_obj_t supervisor_get_run_reason(mp_obj_t self) {
+STATIC mp_obj_t supervisor_runtime_get_run_reason(mp_obj_t self) {
return cp_enum_find(&supervisor_run_reason_type, _run_reason);
}
-MP_DEFINE_CONST_FUN_OBJ_1(supervisor_get_run_reason_obj, supervisor_get_run_reason);
+MP_DEFINE_CONST_FUN_OBJ_1(supervisor_runtime_get_run_reason_obj, supervisor_runtime_get_run_reason);
-const mp_obj_property_t supervisor_run_reason_obj = {
+const mp_obj_property_t supervisor_runtime_run_reason_obj = {
.base.type = &mp_type_property,
- .proxy = {(mp_obj_t)&supervisor_get_run_reason_obj,
+ .proxy = {(mp_obj_t)&supervisor_runtime_get_run_reason_obj,
(mp_obj_t)&mp_const_none_obj,
(mp_obj_t)&mp_const_none_obj},
};
@@ -117,9 +104,9 @@ void supervisor_set_run_reason(supervisor_run_reason_t run_reason) {
}
STATIC const mp_rom_map_elem_t supervisor_runtime_locals_dict_table[] = {
- { MP_ROM_QSTR(MP_QSTR_serial_connected), MP_ROM_PTR(&supervisor_serial_connected_obj) },
- { MP_ROM_QSTR(MP_QSTR_serial_bytes_available), MP_ROM_PTR(&supervisor_serial_bytes_available_obj) },
- { MP_ROM_QSTR(MP_QSTR_run_reason), MP_ROM_PTR(&supervisor_run_reason_obj) },
+ { MP_ROM_QSTR(MP_QSTR_serial_connected), MP_ROM_PTR(&supervisor_runtime_serial_connected_obj) },
+ { MP_ROM_QSTR(MP_QSTR_serial_bytes_available), MP_ROM_PTR(&supervisor_runtime_serial_bytes_available_obj) },
+ { MP_ROM_QSTR(MP_QSTR_run_reason), MP_ROM_PTR(&supervisor_runtime_run_reason_obj) },
};
STATIC MP_DEFINE_CONST_DICT(supervisor_runtime_locals_dict, supervisor_runtime_locals_dict_table);
diff --git a/shared-bindings/supervisor/Runtime.h b/shared-bindings/supervisor/Runtime.h
index 51ed7604d..6874ac744 100755
--- a/shared-bindings/supervisor/Runtime.h
+++ b/shared-bindings/supervisor/Runtime.h
@@ -36,12 +36,12 @@ extern const mp_obj_type_t supervisor_runtime_type;
void supervisor_set_run_reason(supervisor_run_reason_t run_reason);
-bool common_hal_get_serial_connected(void);
+bool common_hal_supervisor_runtime_get_serial_connected(void);
-bool common_hal_get_serial_bytes_available(void);
+bool common_hal_supervisor_runtime_get_serial_bytes_available(void);
//TODO: placeholders for future functions
-//bool common_hal_get_repl_active(void);
-//bool common_hal_get_usb_enumerated(void);
+//bool common_hal_get_supervisor_runtime_repl_active(void);
+//bool common_hal_get_supervisor_runtime_usb_enumerated(void);
#endif // MICROPY_INCLUDED_SHARED_BINDINGS_SUPERVISOR_RUNTIME_H
diff --git a/shared-bindings/usb_cdc/Serial.c b/shared-bindings/usb_cdc/Serial.c
new file mode 100644
index 000000000..c813dce5b
--- /dev/null
+++ b/shared-bindings/usb_cdc/Serial.c
@@ -0,0 +1,293 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021 Dan Halbert for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <stdint.h>
+
+#include "shared-bindings/usb_cdc/Serial.h"
+#include "shared-bindings/util.h"
+
+#include "py/ioctl.h"
+#include "py/objproperty.h"
+#include "py/runtime.h"
+#include "py/stream.h"
+#include "supervisor/shared/translate.h"
+
+//| class Serial:
+//| """Receives cdc commands over USB"""
+//|
+//| def __init__(self) -> None:
+//| """You cannot create an instance of `usb_cdc.Serial`.
+//|
+//| Serial objects are pre-constructed for each CDC device in the USB
+//| descriptor and added to the ``usb_cdc.ports`` tuple."""
+//| ...
+//|
+
+//| def read(self, size: int = 1) -> bytes:
+//| """Read at most ``size`` bytes. If ``size`` exceeds the internal buffer size
+//| only the bytes in the buffer will be read. If `timeout` is > 0 or ``None``,
+//| and fewer than ``size`` bytes are available, keep waiting until the timeout
+//| expires or ``size`` bytes are available.
+//|
+//| :return: Data read
+//| :rtype: bytes"""
+//| ...
+//|
+//| def readinto(self, buf: WriteableBuffer) -> int:
+//| """Read bytes into the ``buf``. If ``nbytes`` is specified then read at most
+//| that many bytes, subject to `timeout`. Otherwise, read at most ``len(buf)`` bytes.
+//|
+//| :return: number of bytes read and stored into ``buf``
+//| :rtype: bytes"""
+//| ...
+//|
+//| def write(self, buf: ReadableBuffer) -> int:
+//| """Write as many bytes as possible from the buffer of bytes.
+//|
+//| :return: the number of bytes written
+//| :rtype: int"""
+//| ...
+//|
+//| def flush(self) -> None:
+//| """Force out any unwritten bytes, waiting until they are written."""
+//| ...
+//|
+
+// These three methods are used by the shared stream methods.
+STATIC mp_uint_t usb_cdc_serial_read_stream(mp_obj_t self_in, void *buf_in, mp_uint_t size, int *errcode) {
+ usb_cdc_serial_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ byte *buf = buf_in;
+
+ // make sure we want at least 1 char
+ if (size == 0) {
+ return 0;
+ }
+
+ return common_hal_usb_cdc_serial_read(self, buf, size, errcode);
+}
+
+STATIC mp_uint_t usb_cdc_serial_write_stream(mp_obj_t self_in, const void *buf_in, mp_uint_t size, int *errcode) {
+ usb_cdc_serial_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ const byte *buf = buf_in;
+
+ return common_hal_usb_cdc_serial_write(self, buf, size, errcode);
+}
+
+STATIC mp_uint_t usb_cdc_serial_ioctl_stream(mp_obj_t self_in, mp_uint_t request, mp_uint_t arg, int *errcode) {
+ usb_cdc_serial_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ mp_uint_t ret = 0;
+ switch (request) {
+ case MP_IOCTL_POLL: {
+ mp_uint_t flags = arg;
+ ret = 0;
+ if ((flags & MP_IOCTL_POLL_RD) && common_hal_usb_cdc_serial_get_in_waiting(self) > 0) {
+ ret |= MP_IOCTL_POLL_RD;
+ }
+ if ((flags & MP_IOCTL_POLL_WR) && common_hal_usb_cdc_serial_get_out_waiting(self) == 0) {
+ ret |= MP_IOCTL_POLL_WR;
+ }
+ break;
+ }
+
+ case MP_STREAM_FLUSH:
+ common_hal_usb_cdc_serial_flush(self);
+ break;
+
+ default:
+ *errcode = MP_EINVAL;
+ ret = MP_STREAM_ERROR;
+ }
+ return ret;
+}
+
+//| connected: bool
+//| """True if this Serial is connected to a host. (read-only)"""
+//|
+STATIC mp_obj_t usb_cdc_serial_get_connected(mp_obj_t self_in) {
+ usb_cdc_serial_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ return mp_obj_new_bool(common_hal_usb_cdc_serial_get_connected(self));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(usb_cdc_serial_get_connected_obj, usb_cdc_serial_get_connected);
+
+const mp_obj_property_t usb_cdc_serial_connected_obj = {
+ .base.type = &mp_type_property,
+ .proxy = {(mp_obj_t)&usb_cdc_serial_get_connected_obj,
+ (mp_obj_t)&mp_const_none_obj,
+ (mp_obj_t)&mp_const_none_obj},
+};
+
+//| in_waiting: int
+//| """Returns the number of bytes waiting to be read on the USB serial input. (read-only)"""
+//|
+STATIC mp_obj_t usb_cdc_serial_get_in_waiting(mp_obj_t self_in) {
+ usb_cdc_serial_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ return mp_obj_new_int(common_hal_usb_cdc_serial_get_in_waiting(self));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(usb_cdc_serial_get_in_waiting_obj, usb_cdc_serial_get_in_waiting);
+
+const mp_obj_property_t usb_cdc_serial_in_waiting_obj = {
+ .base.type = &mp_type_property,
+ .proxy = {(mp_obj_t)&usb_cdc_serial_get_in_waiting_obj,
+ (mp_obj_t)&mp_const_none_obj,
+ (mp_obj_t)&mp_const_none_obj},
+};
+
+//| out_waiting: int
+//| """Returns the number of bytes waiting to be written on the USB serial output. (read-only)"""
+//|
+STATIC mp_obj_t usb_cdc_serial_get_out_waiting(mp_obj_t self_in) {
+ usb_cdc_serial_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ return mp_obj_new_int(common_hal_usb_cdc_serial_get_out_waiting(self));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(usb_cdc_serial_get_out_waiting_obj, usb_cdc_serial_get_out_waiting);
+
+const mp_obj_property_t usb_cdc_serial_out_waiting_obj = {
+ .base.type = &mp_type_property,
+ .proxy = {(mp_obj_t)&usb_cdc_serial_get_out_waiting_obj,
+ (mp_obj_t)&mp_const_none_obj,
+ (mp_obj_t)&mp_const_none_obj},
+};
+
+//| def reset_input_buffer(self) -> None:
+//| """Clears any unread bytes."""
+//| ...
+//|
+STATIC mp_obj_t usb_cdc_serial_reset_input_buffer(mp_obj_t self_in) {
+ usb_cdc_serial_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ common_hal_usb_cdc_serial_reset_input_buffer(self);
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_1(usb_cdc_serial_reset_input_buffer_obj, usb_cdc_serial_reset_input_buffer);
+
+//| def reset_output_buffer(self) -> None:
+//| """Clears any unwritten bytes."""
+//| ...
+//|
+STATIC mp_obj_t usb_cdc_serial_reset_output_buffer(mp_obj_t self_in) {
+ usb_cdc_serial_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ common_hal_usb_cdc_serial_reset_output_buffer(self);
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_1(usb_cdc_serial_reset_output_buffer_obj, usb_cdc_serial_reset_output_buffer);
+
+//| timeout: Optional[float]
+//| """The initial value of `timeout` is ``None``. If ``None``, wait indefinitely to satisfy
+//| the conditions of a read operation. If 0, do not wait. If > 0, wait only ``timeout`` seconds."""
+//|
+STATIC mp_obj_t usb_cdc_serial_get_timeout(mp_obj_t self_in) {
+ usb_cdc_serial_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ mp_float_t timeout = common_hal_usb_cdc_serial_get_timeout(self);
+ return (timeout < 0.0f) ? mp_const_none : mp_obj_new_float(self->timeout);
+}
+MP_DEFINE_CONST_FUN_OBJ_1(usb_cdc_serial_get_timeout_obj, usb_cdc_serial_get_timeout);
+
+STATIC mp_obj_t usb_cdc_serial_set_timeout(mp_obj_t self_in, mp_obj_t timeout_in) {
+ usb_cdc_serial_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ common_hal_usb_cdc_serial_set_timeout(self,
+ timeout_in == mp_const_none ? -1.0f : mp_obj_get_float(timeout_in));
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_2(usb_cdc_serial_set_timeout_obj, usb_cdc_serial_set_timeout);
+
+const mp_obj_property_t usb_cdc_serial_timeout_obj = {
+ .base.type = &mp_type_property,
+ .proxy = {(mp_obj_t)&usb_cdc_serial_get_timeout_obj,
+ (mp_obj_t)&usb_cdc_serial_set_timeout_obj,
+ (mp_obj_t)&mp_const_none_obj},
+};
+
+//| write_timeout: Optional[float]
+//| """The initial value of `write_timeout` is ``None``. If ``None``, wait indefinitely to finish
+//| writing all the bytes passed to ``write()``.If 0, do not wait.
+//| If > 0, wait only ``write_timeout`` seconds."""
+//|
+STATIC mp_obj_t usb_cdc_serial_get_write_timeout(mp_obj_t self_in) {
+ usb_cdc_serial_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ mp_float_t write_timeout = common_hal_usb_cdc_serial_get_write_timeout(self);
+ return (write_timeout < 0.0f) ? mp_const_none : mp_obj_new_float(self->write_timeout);
+}
+MP_DEFINE_CONST_FUN_OBJ_1(usb_cdc_serial_get_write_timeout_obj, usb_cdc_serial_get_write_timeout);
+
+STATIC mp_obj_t usb_cdc_serial_set_write_timeout(mp_obj_t self_in, mp_obj_t write_timeout_in) {
+ usb_cdc_serial_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ common_hal_usb_cdc_serial_set_write_timeout(self,
+ write_timeout_in == mp_const_none ? -1.0f : mp_obj_get_float(write_timeout_in));
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_2(usb_cdc_serial_set_write_timeout_obj, usb_cdc_serial_set_write_timeout);
+
+const mp_obj_property_t usb_cdc_serial_write_timeout_obj = {
+ .base.type = &mp_type_property,
+ .proxy = {(mp_obj_t)&usb_cdc_serial_get_write_timeout_obj,
+ (mp_obj_t)&usb_cdc_serial_set_write_timeout_obj,
+ (mp_obj_t)&mp_const_none_obj},
+};
+
+
+STATIC const mp_rom_map_elem_t usb_cdc_serial_locals_dict_table[] = {
+ // Standard stream methods.
+ { MP_ROM_QSTR(MP_QSTR_flush), MP_ROM_PTR(&mp_stream_flush_obj) },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_read), MP_ROM_PTR(&mp_stream_read_obj) },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&mp_stream_readinto_obj) },
+ { MP_ROM_QSTR(MP_QSTR_readline), MP_ROM_PTR(&mp_stream_unbuffered_readline_obj)},
+ { MP_ROM_QSTR(MP_QSTR_readlines), MP_ROM_PTR(&mp_stream_unbuffered_readlines_obj)},
+ { MP_OBJ_NEW_QSTR(MP_QSTR_write), MP_ROM_PTR(&mp_stream_write_obj) },
+
+ // Other pyserial-inspired attributes.
+ { MP_OBJ_NEW_QSTR(MP_QSTR_in_waiting), MP_ROM_PTR(&usb_cdc_serial_in_waiting_obj) },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_out_waiting), MP_ROM_PTR(&usb_cdc_serial_out_waiting_obj) },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_reset_input_buffer), MP_ROM_PTR(&usb_cdc_serial_reset_input_buffer_obj) },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_reset_output_buffer), MP_ROM_PTR(&usb_cdc_serial_reset_output_buffer_obj) },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_timeout), MP_ROM_PTR(&usb_cdc_serial_timeout_obj) },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_write_timeout), MP_ROM_PTR(&usb_cdc_serial_write_timeout_obj) },
+
+ // Not in pyserial protocol.
+ { MP_OBJ_NEW_QSTR(MP_QSTR_connected), MP_ROM_PTR(&usb_cdc_serial_connected_obj) },
+
+
+
+};
+STATIC MP_DEFINE_CONST_DICT(usb_cdc_serial_locals_dict, usb_cdc_serial_locals_dict_table);
+
+STATIC const mp_stream_p_t usb_cdc_serial_stream_p = {
+ MP_PROTO_IMPLEMENT(MP_QSTR_protocol_stream)
+ .read = usb_cdc_serial_read_stream,
+ .write = usb_cdc_serial_write_stream,
+ .ioctl = usb_cdc_serial_ioctl_stream,
+ .is_text = false,
+ .pyserial_read_compatibility = true,
+ .pyserial_readinto_compatibility = true,
+ .pyserial_dont_return_none_compatibility = true,
+};
+
+const mp_obj_type_t usb_cdc_serial_type = {
+ { &mp_type_type },
+ .name = MP_QSTR_Serial,
+ .getiter = mp_identity_getiter,
+ .iternext = mp_stream_unbuffered_iter,
+ .protocol = &usb_cdc_serial_stream_p,
+ .locals_dict = (mp_obj_dict_t*)&usb_cdc_serial_locals_dict,
+};
diff --git a/shared-bindings/usb_cdc/Serial.h b/shared-bindings/usb_cdc/Serial.h
new file mode 100644
index 000000000..cdf5c3a91
--- /dev/null
+++ b/shared-bindings/usb_cdc/Serial.h
@@ -0,0 +1,53 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021 Dan Halbert for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_USB_CDC_SERIAL_H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_USB_CDC_SERIAL_H
+
+#include "shared-module/usb_cdc/Serial.h"
+
+extern const mp_obj_type_t usb_cdc_serial_type;
+
+extern size_t common_hal_usb_cdc_serial_read(usb_cdc_serial_obj_t *self, uint8_t *data, size_t len, int *errcode);
+extern size_t common_hal_usb_cdc_serial_write(usb_cdc_serial_obj_t *self, const uint8_t *data, size_t len, int *errcode);
+
+extern uint32_t common_hal_usb_cdc_serial_get_in_waiting(usb_cdc_serial_obj_t *self);
+extern uint32_t common_hal_usb_cdc_serial_get_out_waiting(usb_cdc_serial_obj_t *self);
+
+extern void common_hal_usb_cdc_serial_reset_input_buffer(usb_cdc_serial_obj_t *self);
+extern uint32_t common_hal_usb_cdc_serial_reset_output_buffer(usb_cdc_serial_obj_t *self);
+
+extern uint32_t common_hal_usb_cdc_serial_flush(usb_cdc_serial_obj_t *self);
+
+extern bool common_hal_usb_cdc_serial_get_connected(usb_cdc_serial_obj_t *self);
+
+extern mp_float_t common_hal_usb_cdc_serial_get_timeout(usb_cdc_serial_obj_t *self);
+extern void common_hal_usb_cdc_serial_set_timeout(usb_cdc_serial_obj_t *self, mp_float_t timeout);
+
+extern mp_float_t common_hal_usb_cdc_serial_get_write_timeout(usb_cdc_serial_obj_t *self);
+extern void common_hal_usb_cdc_serial_set_write_timeout(usb_cdc_serial_obj_t *self, mp_float_t write_timeout);
+
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_USB_CDC_SERIAL_H
diff --git a/shared-bindings/usb_cdc/__init__.c b/shared-bindings/usb_cdc/__init__.c
new file mode 100644
index 000000000..eb9c25e00
--- /dev/null
+++ b/shared-bindings/usb_cdc/__init__.c
@@ -0,0 +1,59 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021 Dan Halbertfor Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <stdint.h>
+
+#include "py/obj.h"
+#include "py/runtime.h"
+
+#include "shared-bindings/usb_cdc/__init__.h"
+#include "shared-bindings/usb_cdc/Serial.h"
+
+#include "py/runtime.h"
+
+//| """USB CDC Serial streams
+//|
+//| The `usb_cdc` module allows access to USB CDC (serial) communications."""
+//|
+//| serials: Tuple[Serial, ...]
+//| """Tuple of all CDC streams. Each item is a `Serial`.
+//| ``serials[0]`` is the USB REPL connection.
+//| ``serials[1]`` is a second USB serial connection, unconnected to the REPL.
+//| """
+//|
+
+static const mp_map_elem_t usb_cdc_module_globals_table[] = {
+ { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_usb_cdc) },
+ { MP_ROM_QSTR(MP_QSTR_Serial), MP_OBJ_FROM_PTR(&usb_cdc_serial_type) },
+ { MP_ROM_QSTR(MP_QSTR_serials), MP_OBJ_FROM_PTR(&usb_cdc_serials_tuple) },
+};
+
+static MP_DEFINE_CONST_DICT(usb_cdc_module_globals, usb_cdc_module_globals_table);
+
+const mp_obj_module_t usb_cdc_module = {
+ .base = { &mp_type_module },
+ .globals = (mp_obj_dict_t*)&usb_cdc_module_globals,
+};
diff --git a/shared-bindings/usb_cdc/__init__.h b/shared-bindings/usb_cdc/__init__.h
new file mode 100644
index 000000000..e81d243e6
--- /dev/null
+++ b/shared-bindings/usb_cdc/__init__.h
@@ -0,0 +1,32 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021 Dan Halbert for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_USB_CDC___INIT___H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_USB_CDC___INIT___H
+
+#include "shared-module/usb_cdc/__init__.h"
+
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_USB_CDC___INIT___H
diff --git a/shared-module/usb_cdc/Serial.c b/shared-module/usb_cdc/Serial.c
new file mode 100644
index 000000000..6037fddcc
--- /dev/null
+++ b/shared-module/usb_cdc/Serial.c
@@ -0,0 +1,147 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021 Dan Halbert for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "lib/utils/interrupt_char.h"
+#include "shared-module/usb_cdc/Serial.h"
+#include "supervisor/shared/tick.h"
+
+#include "tusb.h"
+
+size_t common_hal_usb_cdc_serial_read(usb_cdc_serial_obj_t *self, uint8_t *data, size_t len, int *errcode) {
+
+ const bool wait_forever = self->timeout < 0.0f;
+ const bool wait_for_timeout = self->timeout > 0.0f;
+
+ // Read up to len bytes immediately.
+ // The number of bytes read will not be larger than what is already in the TinyUSB FIFO.
+ uint32_t total_num_read = tud_cdc_n_read(self->idx, data, len);
+
+ if (wait_forever || wait_for_timeout) {
+ // Read more if we have time.
+ uint64_t timeout_ms = self->timeout * 1000; // Junk value if timeout < 0.
+ uint64_t start_ticks = supervisor_ticks_ms64();
+
+ uint32_t num_read = 0;
+ while (total_num_read < len &&
+ (wait_forever || supervisor_ticks_ms64() - start_ticks <= timeout_ms)) {
+
+ // Wait for a bit, and check for ctrl-C.
+ RUN_BACKGROUND_TASKS;
+ if (mp_hal_is_interrupted()) {
+ return 0;
+ }
+
+ // Advance buffer pointer and reduce number of bytes that need to be read.
+ len -= num_read;
+ data += num_read;
+
+ // Try to read another batch of bytes.
+ num_read = tud_cdc_n_read(self->idx, data, len);
+ total_num_read += num_read;
+ }
+ }
+
+ return total_num_read;
+}
+
+size_t common_hal_usb_cdc_serial_write(usb_cdc_serial_obj_t *self, const uint8_t *data, size_t len, int *errcode) {
+ const bool wait_forever = self->write_timeout < 0.0f;
+ const bool wait_for_timeout = self->write_timeout > 0.0f;
+
+ // Write as many bytes as possible immediately.
+ // The number of bytes written at once will not be larger than what can fit in the TinyUSB FIFO.
+ uint32_t total_num_written = tud_cdc_n_write(self->idx, data, len);
+ tud_cdc_n_write_flush(self->idx);
+
+ if (wait_forever || wait_for_timeout) {
+ // Write more if we have time.
+ uint64_t timeout_ms = self->write_timeout * 1000; // Junk value if write_timeout < 0.
+ uint64_t start_ticks = supervisor_ticks_ms64();
+
+ uint32_t num_written = 0;
+ while (total_num_written < len &&
+ (wait_forever || supervisor_ticks_ms64() - start_ticks <= timeout_ms)) {
+
+ // Wait for a bit, and check for ctrl-C.
+ RUN_BACKGROUND_TASKS;
+ if (mp_hal_is_interrupted()) {
+ return 0;
+ }
+
+ // Advance buffer pointer and reduce number of bytes that need to be written.
+ len -= num_written;
+ data += num_written;
+
+ // Try to write another batch of bytes.
+ num_written = tud_cdc_n_write(self->idx, data, len);
+ tud_cdc_n_write_flush(self->idx);
+ total_num_written += num_written;
+ }
+ }
+
+ return total_num_written;
+}
+
+uint32_t common_hal_usb_cdc_serial_get_in_waiting(usb_cdc_serial_obj_t *self) {
+ return tud_cdc_n_available(self->idx);
+}
+
+uint32_t common_hal_usb_cdc_serial_get_out_waiting(usb_cdc_serial_obj_t *self) {
+ // Return number of FIFO bytes currently occupied.
+ return CFG_TUD_CDC_TX_BUFSIZE - tud_cdc_n_write_available(self->idx);
+}
+
+void common_hal_usb_cdc_serial_reset_input_buffer(usb_cdc_serial_obj_t *self) {
+ tud_cdc_n_read_flush(self->idx);
+}
+
+uint32_t common_hal_usb_cdc_serial_reset_output_buffer(usb_cdc_serial_obj_t *self) {
+ return tud_cdc_n_write_clear(self->idx);
+}
+
+uint32_t common_hal_usb_cdc_serial_flush(usb_cdc_serial_obj_t *self) {
+ return tud_cdc_n_write_flush(self->idx);
+}
+
+bool common_hal_usb_cdc_serial_get_connected(usb_cdc_serial_obj_t *self) {
+ return tud_cdc_n_connected(self->idx);
+}
+
+mp_float_t common_hal_usb_cdc_serial_get_timeout(usb_cdc_serial_obj_t *self) {
+ return self->timeout;
+}
+
+void common_hal_usb_cdc_serial_set_timeout(usb_cdc_serial_obj_t *self, mp_float_t timeout) {
+ self->timeout = timeout;
+}
+
+mp_float_t common_hal_usb_cdc_serial_get_write_timeout(usb_cdc_serial_obj_t *self) {
+ return self->write_timeout;
+}
+
+void common_hal_usb_cdc_serial_set_write_timeout(usb_cdc_serial_obj_t *self, mp_float_t write_timeout) {
+ self->write_timeout = write_timeout;
+}
diff --git a/shared-module/usb_cdc/Serial.h b/shared-module/usb_cdc/Serial.h
new file mode 100644
index 000000000..ddf78eefa
--- /dev/null
+++ b/shared-module/usb_cdc/Serial.h
@@ -0,0 +1,39 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021 Dan Halbert for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef SHARED_MODULE_USB_CDC_SERIAL_H
+#define SHARED_MODULE_USB_CDC_SERIAL_H
+
+#include "py/obj.h"
+
+typedef struct {
+ mp_obj_base_t base;
+ mp_float_t timeout; // if negative, wait forever.
+ mp_float_t write_timeout; // if negative, wait forever.
+ uint8_t idx; // which CDC device?
+} usb_cdc_serial_obj_t;
+
+#endif // SHARED_MODULE_USB_CDC_SERIAL_H
diff --git a/shared-module/usb_cdc/__init__.c b/shared-module/usb_cdc/__init__.c
new file mode 100644
index 000000000..fe05cb107
--- /dev/null
+++ b/shared-module/usb_cdc/__init__.c
@@ -0,0 +1,61 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021 Dan Halbert for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "genhdr/autogen_usb_descriptor.h"
+#include "py/gc.h"
+#include "py/obj.h"
+#include "py/mphal.h"
+#include "py/runtime.h"
+#include "py/objtuple.h"
+#include "shared-bindings/usb_cdc/__init__.h"
+#include "shared-bindings/usb_cdc/Serial.h"
+#include "tusb.h"
+
+#if CFG_TUD_CDC != 2
+#error CFG_TUD_CDC must be exactly 2
+#endif
+
+static usb_cdc_serial_obj_t serial_objs[CFG_TUD_CDC] = {
+ { .base.type = &usb_cdc_serial_type,
+ .timeout = -1.0f,
+ .write_timeout = -1.0f,
+ .idx = 0,
+ }, {
+ .base.type = &usb_cdc_serial_type,
+ .timeout = -1.0f,
+ .write_timeout = -1.0f,
+ .idx = 1,
+ }
+};
+
+const mp_rom_obj_tuple_t usb_cdc_serials_tuple = {
+ .base.type = &mp_type_tuple,
+ .len = CFG_TUD_CDC,
+ .items = {
+ &serial_objs[0],
+ &serial_objs[1],
+ },
+};
diff --git a/shared-module/usb_cdc/__init__.h b/shared-module/usb_cdc/__init__.h
new file mode 100644
index 000000000..9de3eb2fa
--- /dev/null
+++ b/shared-module/usb_cdc/__init__.h
@@ -0,0 +1,34 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021 Dan Halbert for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef SHARED_MODULE_USB_CDC___INIT___H
+#define SHARED_MODULE_USB_CDC___INIT___H
+
+#include "py/objtuple.h"
+
+extern const mp_rom_obj_tuple_t usb_cdc_serials_tuple;
+
+#endif /* SHARED_MODULE_USB_CDC___INIT___H */
diff --git a/supervisor/shared/serial.c b/supervisor/shared/serial.c
index b9feb04f2..9cc12de51 100644
--- a/supervisor/shared/serial.c
+++ b/supervisor/shared/serial.c
@@ -118,7 +118,6 @@ bool serial_bytes_available(void) {
return tud_cdc_available() > 0;
#endif
}
-
void serial_write_substring(const char* text, uint32_t length) {
if (length == 0) {
return;
diff --git a/supervisor/shared/usb/tusb_config.h b/supervisor/shared/usb/tusb_config.h
index d3a35f537..bff7bd6b5 100644
--- a/supervisor/shared/usb/tusb_config.h
+++ b/supervisor/shared/usb/tusb_config.h
@@ -61,10 +61,15 @@
// DEVICE CONFIGURATION
//--------------------------------------------------------------------+
-#define CFG_TUD_ENDOINT0_SIZE 64
+#define CFG_TUD_ENDPOINT0_SIZE 64
//------------- CLASS -------------//
+
+// Could be 2 if secondary CDC channel requested.
+#ifndef CFG_TUD_CDC
#define CFG_TUD_CDC 1
+#endif
+
#define CFG_TUD_MSC 1
#define CFG_TUD_HID CIRCUITPY_USB_HID
#define CFG_TUD_MIDI CIRCUITPY_USB_MIDI
diff --git a/supervisor/shared/usb/usb.c b/supervisor/shared/usb/usb.c
index 43564d5d5..5b020b8a0 100644
--- a/supervisor/shared/usb/usb.c
+++ b/supervisor/shared/usb/usb.c
@@ -26,7 +26,6 @@
#include "py/objstr.h"
#include "shared-bindings/microcontroller/Processor.h"
-#include "shared-module/usb_midi/__init__.h"
#include "supervisor/background_callback.h"
#include "supervisor/port.h"
#include "supervisor/serial.h"
@@ -35,6 +34,10 @@
#include "lib/utils/interrupt_char.h"
#include "lib/mp-readline/readline.h"
+#if CIRCUITPY_USB_MIDI
+#include "shared-module/usb_midi/__init__.h"
+#endif
+
#include "tusb.h"
#if CIRCUITPY_USB_VENDOR
@@ -216,7 +219,7 @@ bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_requ
return true;
}
-#endif CIRCUITPY_USB_VENDOR
+#endif // CIRCUITPY_USB_VENDOR
#if MICROPY_KBD_EXCEPTION
diff --git a/supervisor/shared/usb/usb_desc.c b/supervisor/shared/usb/usb_desc.c
index 080187ebc..419a70ab3 100644
--- a/supervisor/shared/usb/usb_desc.c
+++ b/supervisor/shared/usb/usb_desc.c
@@ -43,12 +43,14 @@ uint8_t const * tud_descriptor_configuration_cb(uint8_t index) {
return usb_desc_cfg;
}
+#if CIRCUITPY_USB_HID
// Invoked when received GET HID REPORT DESCRIPTOR
// Application return pointer to descriptor
// Descriptor contents must exist long enough for transfer to complete
uint8_t const * tud_hid_descriptor_report_cb(void) {
return hid_report_descriptor;
}
+#endif
// Invoked when received GET STRING DESCRIPTOR request
// Application return pointer to descriptor, whose contents must exist long enough for transfer to complete
diff --git a/supervisor/supervisor.mk b/supervisor/supervisor.mk
index f559e004e..374b7a72b 100644
--- a/supervisor/supervisor.mk
+++ b/supervisor/supervisor.mk
@@ -14,23 +14,15 @@ SRC_SUPERVISOR = \
supervisor/shared/tick.c \
supervisor/shared/translate.c
-ifndef $(NO_USB)
- NO_USB = $(wildcard supervisor/usb.c)
-endif
+NO_USB ?= $(wildcard supervisor/usb.c)
-ifndef INTERNAL_FLASH_FILESYSTEM
-INTERNAL_FLASH_FILESYSTEM = 0
-endif
+INTERNAL_FLASH_FILESYSTEM ?= 0
CFLAGS += -DINTERNAL_FLASH_FILESYSTEM=$(INTERNAL_FLASH_FILESYSTEM)
-ifndef QSPI_FLASH_FILESYSTEM
-QSPI_FLASH_FILESYSTEM = 0
-endif
+QSPI_FLASH_FILESYSTEM ?= 0
CFLAGS += -DQSPI_FLASH_FILESYSTEM=$(QSPI_FLASH_FILESYSTEM)
-ifndef SPI_FLASH_FILESYSTEM
-SPI_FLASH_FILESYSTEM = 0
-endif
+SPI_FLASH_FILESYSTEM ?= 0
CFLAGS += -DSPI_FLASH_FILESYSTEM=$(SPI_FLASH_FILESYSTEM)
ifeq ($(CIRCUITPY_BLEIO),1)
@@ -41,154 +33,180 @@ endif
# (Right now INTERNAL_FLASH_FILESYSTEM and (Q)SPI_FLASH_FILESYSTEM are mutually exclusive.
# But that might not be true in the future.)
ifdef EXTERNAL_FLASH_DEVICES
- CFLAGS += -DEXTERNAL_FLASH_DEVICES=$(EXTERNAL_FLASH_DEVICES) \
- -DEXTERNAL_FLASH_DEVICE_COUNT=$(EXTERNAL_FLASH_DEVICE_COUNT)
-
- SRC_SUPERVISOR += supervisor/shared/external_flash/external_flash.c
- ifeq ($(SPI_FLASH_FILESYSTEM),1)
- SRC_SUPERVISOR += supervisor/shared/external_flash/spi_flash.c
- else
- endif
- ifeq ($(QSPI_FLASH_FILESYSTEM),1)
- SRC_SUPERVISOR += supervisor/qspi_flash.c supervisor/shared/external_flash/qspi_flash.c
- endif
+ CFLAGS += -DEXTERNAL_FLASH_DEVICES=$(EXTERNAL_FLASH_DEVICES) \
+ -DEXTERNAL_FLASH_DEVICE_COUNT=$(EXTERNAL_FLASH_DEVICE_COUNT)
+
+ SRC_SUPERVISOR += supervisor/shared/external_flash/external_flash.c
+ ifeq ($(SPI_FLASH_FILESYSTEM),1)
+ SRC_SUPERVISOR += supervisor/shared/external_flash/spi_flash.c
+ endif
+ ifeq ($(QSPI_FLASH_FILESYSTEM),1)
+ SRC_SUPERVISOR += supervisor/qspi_flash.c supervisor/shared/external_flash/qspi_flash.c
+ endif
else
- ifeq ($(DISABLE_FILESYSTEM),1)
- SRC_SUPERVISOR += supervisor/stub/internal_flash.c
- else
- SRC_SUPERVISOR += supervisor/internal_flash.c
- endif
+ ifeq ($(DISABLE_FILESYSTEM),1)
+ SRC_SUPERVISOR += supervisor/stub/internal_flash.c
+ else
+ SRC_SUPERVISOR += supervisor/internal_flash.c
+ endif
endif
ifeq ($(USB),FALSE)
- ifeq ($(wildcard supervisor/serial.c),)
- SRC_SUPERVISOR += supervisor/stub/serial.c
- else
- SRC_SUPERVISOR += supervisor/serial.c
- endif
+ ifeq ($(wildcard supervisor/serial.c),)
+ SRC_SUPERVISOR += supervisor/stub/serial.c
+ else
+ SRC_SUPERVISOR += supervisor/serial.c
+ endif
else
- SRC_SUPERVISOR += \
- lib/tinyusb/src/common/tusb_fifo.c \
- lib/tinyusb/src/device/usbd.c \
- lib/tinyusb/src/device/usbd_control.c \
- lib/tinyusb/src/class/msc/msc_device.c \
- lib/tinyusb/src/class/cdc/cdc_device.c \
- lib/tinyusb/src/tusb.c \
- supervisor/shared/serial.c \
- supervisor/shared/workflow.c \
- supervisor/usb.c \
- supervisor/shared/usb/usb_desc.c \
- supervisor/shared/usb/usb.c \
- supervisor/shared/usb/usb_msc_flash.c \
- $(BUILD)/autogen_usb_descriptor.c
-
- ifeq ($(CIRCUITPY_USB_HID), 1)
- SRC_SUPERVISOR += \
- lib/tinyusb/src/class/hid/hid_device.c \
- shared-bindings/usb_hid/__init__.c \
- shared-bindings/usb_hid/Device.c \
- shared-module/usb_hid/__init__.c \
- shared-module/usb_hid/Device.c
- endif
-
- ifeq ($(CIRCUITPY_USB_MIDI), 1)
- SRC_SUPERVISOR += \
- lib/tinyusb/src/class/midi/midi_device.c \
- shared-bindings/usb_midi/__init__.c \
- shared-bindings/usb_midi/PortIn.c \
- shared-bindings/usb_midi/PortOut.c \
- shared-module/usb_midi/__init__.c \
- shared-module/usb_midi/PortIn.c \
- 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
+ SRC_SUPERVISOR += \
+ lib/tinyusb/src/class/cdc/cdc_device.c \
+ lib/tinyusb/src/common/tusb_fifo.c \
+ lib/tinyusb/src/device/usbd.c \
+ lib/tinyusb/src/device/usbd_control.c \
+ lib/tinyusb/src/tusb.c \
+ supervisor/shared/serial.c \
+ supervisor/shared/workflow.c \
+ supervisor/usb.c \
+ supervisor/shared/usb/usb_desc.c \
+ supervisor/shared/usb/usb.c \
+ $(BUILD)/autogen_usb_descriptor.c \
+
+ ifeq ($(CIRCUITPY_USB_CDC), 1)
+ SRC_SUPERVISOR += \
+ shared-bindings/usb_cdc/__init__.c \
+ shared-bindings/usb_cdc/Serial.c \
+ shared-module/usb_cdc/__init__.c \
+ shared-module/usb_cdc/Serial.c \
+
+ endif
+
+ ifeq ($(CIRCUITPY_USB_HID), 1)
+ SRC_SUPERVISOR += \
+ lib/tinyusb/src/class/hid/hid_device.c \
+ shared-bindings/usb_hid/__init__.c \
+ shared-bindings/usb_hid/Device.c \
+ shared-module/usb_hid/__init__.c \
+ shared-module/usb_hid/Device.c \
+
+ endif
+
+ ifeq ($(CIRCUITPY_USB_MIDI), 1)
+ SRC_SUPERVISOR += \
+ lib/tinyusb/src/class/midi/midi_device.c \
+ shared-bindings/usb_midi/__init__.c \
+ shared-bindings/usb_midi/PortIn.c \
+ shared-bindings/usb_midi/PortOut.c \
+ shared-module/usb_midi/__init__.c \
+ shared-module/usb_midi/PortIn.c \
+ shared-module/usb_midi/PortOut.c \
+
+ endif
+
+ ifeq ($(CIRCUITPY_USB_MSC), 1)
+ SRC_SUPERVISOR += \
+ lib/tinyusb/src/class/msc/msc_device.c \
+ supervisor/shared/usb/usb_msc_flash.c \
+
+ endif
+
+ ifeq ($(CIRCUITPY_USB_VENDOR), 1)
+ SRC_SUPERVISOR += \
+ lib/tinyusb/src/class/vendor/vendor_device.c \
+
+ endif
+
+ CFLAGS += -DUSB_AVAILABLE
endif
SUPERVISOR_O = $(addprefix $(BUILD)/, $(SRC_SUPERVISOR:.c=.o))
ifeq ($(CIRCUITPY_DISPLAYIO), 1)
- SRC_SUPERVISOR += \
- supervisor/shared/display.c
+ SRC_SUPERVISOR += \
+ supervisor/shared/display.c
- ifeq ($(CIRCUITPY_TERMINALIO), 1)
- SUPERVISOR_O += $(BUILD)/autogen_display_resources.o
- endif
+ ifeq ($(CIRCUITPY_TERMINALIO), 1)
+ SUPERVISOR_O += $(BUILD)/autogen_display_resources.o
+ endif
endif
-ifndef USB_INTERFACE_NAME
-USB_INTERFACE_NAME = "CircuitPython"
+
+USB_INTERFACE_NAME ?= "CircuitPython"
+
+ifneq ($(USB_VID),)
+CFLAGS += -DUSB_VID=$(USB_VID)
+CFLAGS += -DSUB_PID=$(USB_PID)
+CFLAGS += -DUSB_MANUFACTURER=$(USB_MANUFACTURER)
+CFLAGS += -DUSB_PRODUCT=$(USB_PRODUCT)
endif
# In the following URL, don't include the https:// prefix.
# It gets added automatically.
-ifndef USB_WEBUSB_URL
-USB_WEBUSB_URL = "circuitpython.org"
+USB_WEBUSB_URL ?= "circuitpython.org"
+
+ifeq ($(CIRCUITPY_REPL_USB),1)
+USB_DEVICES += CDC
endif
-USB_DEVICES_COMPUTED := CDC,MSC
+ifeq ($(CIRCUITPY_USB_HID),1)
+USB_DEVICES += HID
+endif
ifeq ($(CIRCUITPY_USB_MIDI),1)
-USB_DEVICES_COMPUTED := $(USB_DEVICES_COMPUTED),AUDIO
+USB_DEVICES += AUDIO
endif
-ifeq ($(CIRCUITPY_USB_HID),1)
-USB_DEVICES_COMPUTED := $(USB_DEVICES_COMPUTED),HID
+ifeq ($(CIRCUITPY_USB_MSC),1)
+USB_DEVICES += MSC
endif
-ifeq ($(CIRCUITPY_USB_VENDOR),1)
-USB_DEVICES_COMPUTED := $(USB_DEVICES_COMPUTED),VENDOR
+ifeq ($(CIRCUITPY_USB_CDC),1)
+# Inform TinyUSB there are two CDC devices.
+CFLAGS += -DCFG_TUD_CDC=2
+USB_DEVICES += CDC2
endif
-USB_DEVICES ?= "$(USB_DEVICES_COMPUTED)"
-
-ifndef USB_HID_DEVICES
-USB_HID_DEVICES = "KEYBOARD,MOUSE,CONSUMER,GAMEPAD"
+ifeq ($(CIRCUITPY_USB_VENDOR),1)
+USB_DEVICES += VENDOR
endif
-ifndef USB_HIGHSPEED
-USB_HIGHSPEED = 0
+USB_HID_DEVICES =
+ifeq ($(CIRCUITPY_USB_HID_CONSUMER),1)
+USB_HID_DEVICES += CONSUMER
endif
-
-ifndef USB_CDC_EP_NUM_NOTIFICATION
-USB_CDC_EP_NUM_NOTIFICATION = 0
+ifeq ($(CIRCUITPY_USB_HID_DIGITIZER),1)
+USB_HID_DEVICES += DIGITIZER
endif
-
-ifndef USB_CDC_EP_NUM_DATA_OUT
-USB_CDC_EP_NUM_DATA_OUT = 0
+ifeq ($(CIRCUITPY_USB_HID_GAMEPAD),1)
+USB_HID_DEVICES += GAMEPAD
endif
-
-ifndef USB_CDC_EP_NUM_DATA_IN
-USB_CDC_EP_NUM_DATA_IN = 0
+ifeq ($(CIRCUITPY_USB_HID_KEYBOARD),1)
+USB_HID_DEVICES += KEYBOARD
endif
-
-ifndef USB_MSC_EP_NUM_OUT
-USB_MSC_EP_NUM_OUT = 0
+ifeq ($(CIRCUITPY_USB_HID_MOUSE),1)
+USB_HID_DEVICES += MOUSE
endif
-
-ifndef USB_MSC_EP_NUM_IN
-USB_MSC_EP_NUM_IN = 0
+ifeq ($(CIRCUITPY_USB_HID_SYS_CONTROL),1)
+USB_HID_DEVICES += SYS_CONTROL
endif
-
-ifndef USB_HID_EP_NUM_OUT
-USB_HID_EP_NUM_OUT = 0
+ifeq ($(CIRCUITPY_USB_HID_XAC_COMPATIBLE_GAMEPAD),1)
+USB_HID_DEVICES += XAC_COMPATIBLE_GAMEPAD
endif
-ifndef USB_HID_EP_NUM_IN
-USB_HID_EP_NUM_IN = 0
+# RAW is not compatible with other HID devices.
+ifeq ($(CIRCUITPY_USB_HID_RAW),1)
+ ifneq ($(CIRCUITPY_USB_HID_DEVICES,)
+ $(error HID RAW must not be combined with other HID devices)
endif
-
-ifndef USB_MIDI_EP_NUM_OUT
-USB_MIDI_EP_NUM_OUT = 0
+USB_HID_DEVICES += MOUSE
endif
-ifndef USB_MIDI_EP_NUM_IN
-USB_MIDI_EP_NUM_IN = 0
-endif
+USB_HIGHSPEED ?= 0
-ifndef USB_NUM_EP
-USB_NUM_EP = 0
-endif
+USB_CDC_EP_NUM_NOTIFICATION ?= 0
+USB_CDC_EP_NUM_DATA_OUT ?= 0
+USB_CDC_EP_NUM_DATA_IN ?= 0
+USB_MSC_EP_NUM_OUT ?= 0
+USB_MSC_EP_NUM_IN ?= 0
+USB_HID_EP_NUM_OUT ?= 0
+USB_HID_EP_NUM_IN ?= 0
+USB_MIDI_EP_NUM_OUT ?= 0
+USB_MIDI_EP_NUM_IN ?= 0
+USB_NUM_EP ?= 0
USB_DESCRIPTOR_ARGS = \
--manufacturer $(USB_MANUFACTURER)\
@@ -197,8 +215,8 @@ USB_DESCRIPTOR_ARGS = \
--pid $(USB_PID)\
--serial_number_length $(USB_SERIAL_NUMBER_LENGTH)\
--interface_name $(USB_INTERFACE_NAME)\
- --devices $(USB_DEVICES)\
- --hid_devices $(USB_HID_DEVICES)\
+ --devices "$(USB_DEVICES)"\
+ --hid_devices "$(USB_HID_DEVICES)"\
--max_ep $(USB_NUM_EP) \
--cdc_ep_num_notification $(USB_CDC_EP_NUM_NOTIFICATION)\
--cdc_ep_num_data_out $(USB_CDC_EP_NUM_DATA_OUT)\
diff --git a/tools/gen_usb_descriptor.py b/tools/gen_usb_descriptor.py
index 80dddeb00..089d00ff2 100644
--- a/tools/gen_usb_descriptor.py
+++ b/tools/gen_usb_descriptor.py
@@ -12,70 +12,130 @@ sys.path.append("../../tools/usb_descriptor")
from adafruit_usb_descriptor import audio, audio10, cdc, hid, midi, msc, standard, util
import hid_report_descriptors
-DEFAULT_INTERFACE_NAME = 'CircuitPython'
-ALL_DEVICES='CDC,MSC,AUDIO,HID,VENDOR'
-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,RAW'
-ALL_HID_DEVICES_SET=frozenset(ALL_HID_DEVICES.split(','))
+DEFAULT_INTERFACE_NAME = "CircuitPython"
+ALL_DEVICES = "CDC CDC2 MSC AUDIO HID VENDOR"
+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 RAW"
+)
+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_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', default=False, action='store_true',
- help='descriptor for highspeed device')
-parser.add_argument('--manufacturer', type=str,
- help='manufacturer of the device')
-parser.add_argument('--product', type=str,
- help='product name of the device')
-parser.add_argument('--vid', type=lambda x: int(x, 16),
- help='vendor id')
-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: tuple(l.split(',')), default=DEFAULT_DEVICES,
- help='devices to include in descriptor (AUDIO includes MIDI support)')
-parser.add_argument('--hid_devices', type=lambda l: tuple(l.split(',')), default=DEFAULT_HID_DEVICES,
- help='HID devices to include in HID report descriptor')
-parser.add_argument('--interface_name', type=str,
- help='The name/prefix to use in the interface descriptions',
- default=DEFAULT_INTERFACE_NAME)
-parser.add_argument('--no-renumber_endpoints', dest='renumber_endpoints', action='store_false',
- help='use to not renumber endpoint')
-parser.add_argument('--cdc_ep_num_notification', type=int, default=0,
- help='endpoint number of CDC NOTIFICATION')
-parser.add_argument('--cdc_ep_num_data_out', type=int, default=0,
- help='endpoint number of CDC DATA OUT')
-parser.add_argument('--cdc_ep_num_data_in', type=int, default=0,
- help='endpoint number of CDC DATA IN')
-parser.add_argument('--msc_ep_num_out', type=int, default=0,
- help='endpoint number of MSC OUT')
-parser.add_argument('--msc_ep_num_in', type=int, default=0,
- help='endpoint number of MSC IN')
-parser.add_argument('--hid_ep_num_out', type=int, default=0,
- help='endpoint number of HID OUT')
-parser.add_argument('--hid_ep_num_in', type=int, default=0,
- help='endpoint number of HID IN')
-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,
- 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)
-parser.add_argument('--output_h_file', type=argparse.FileType('w', encoding='UTF-8'), required=True)
+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",
+ help="descriptor for highspeed device",
+)
+parser.add_argument("--manufacturer", type=str, help="manufacturer of the device")
+parser.add_argument("--product", type=str, help="product name of the device")
+parser.add_argument("--vid", type=lambda x: int(x, 16), help="vendor id")
+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: tuple(l.split()),
+ default=DEFAULT_DEVICES,
+ help="devices to include in descriptor (AUDIO includes MIDI support)",
+)
+parser.add_argument(
+ "--hid_devices",
+ type=lambda l: tuple(l.split()),
+ default=DEFAULT_HID_DEVICES,
+ help="HID devices to include in HID report descriptor",
+)
+parser.add_argument(
+ "--interface_name",
+ type=str,
+ help="The name/prefix to use in the interface descriptions",
+ default=DEFAULT_INTERFACE_NAME,
+)
+parser.add_argument(
+ "--no-renumber_endpoints",
+ dest="renumber_endpoints",
+ action="store_false",
+ help="use to not renumber endpoint",
+)
+parser.add_argument(
+ "--cdc_ep_num_notification",
+ type=int,
+ default=0,
+ help="endpoint number of CDC NOTIFICATION",
+)
+parser.add_argument(
+ "--cdc2_ep_num_notification",
+ type=int,
+ default=0,
+ help="endpoint number of CDC2 NOTIFICATION",
+)
+parser.add_argument(
+ "--cdc_ep_num_data_out", type=int, default=0, help="endpoint number of CDC DATA OUT"
+)
+parser.add_argument(
+ "--cdc_ep_num_data_in", type=int, default=0, help="endpoint number of CDC DATA IN"
+)
+parser.add_argument(
+ "--cdc2_ep_num_data_out",
+ type=int,
+ default=0,
+ help="endpoint number of CDC2 DATA OUT",
+)
+parser.add_argument(
+ "--cdc2_ep_num_data_in", type=int, default=0, help="endpoint number of CDC2 DATA IN"
+)
+parser.add_argument(
+ "--msc_ep_num_out", type=int, default=0, help="endpoint number of MSC OUT"
+)
+parser.add_argument(
+ "--msc_ep_num_in", type=int, default=0, help="endpoint number of MSC IN"
+)
+parser.add_argument(
+ "--hid_ep_num_out", type=int, default=0, help="endpoint number of HID OUT"
+)
+parser.add_argument(
+ "--hid_ep_num_in", type=int, default=0, help="endpoint number of HID IN"
+)
+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(
+ "--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(
+ "--output_h_file", type=argparse.FileType("w", encoding="UTF-8"), required=True
+)
args = parser.parse_args()
@@ -87,47 +147,67 @@ unknown_hid_devices = list(frozenset(args.hid_devices) - ALL_HID_DEVICES_SET)
if unknown_hid_devices:
raise ValueError("Unknown HID devices(s)", unknown_hid_devices)
+include_cdc = "CDC" in args.devices
+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")
+
if not args.renumber_endpoints:
- if 'CDC' in args.devices:
+ if include_cdc:
if args.cdc_ep_num_notification == 0:
raise ValueError("CDC notification endpoint number must not be 0")
- elif args.cdc_ep_num_data_out == 0:
+ if args.cdc_ep_num_data_out == 0:
raise ValueError("CDC data OUT endpoint number must not be 0")
- elif args.cdc_ep_num_data_in == 0:
+ if args.cdc_ep_num_data_in == 0:
raise ValueError("CDC data IN endpoint number must not be 0")
- if 'MSC' in args.devices:
+ if include_cdc2:
+ if args.cdc2_ep_num_notification == 0:
+ raise ValueError("CDC2 notification endpoint number must not be 0")
+ if args.cdc2_ep_num_data_out == 0:
+ raise ValueError("CDC2 data OUT endpoint number must not be 0")
+ if args.cdc2_ep_num_data_in == 0:
+ raise ValueError("CDC2 data IN endpoint number must not be 0")
+
+ if include_msc:
if args.msc_ep_num_out == 0:
raise ValueError("MSC endpoint OUT number must not be 0")
- elif args.msc_ep_num_in == 0:
+ if args.msc_ep_num_in == 0:
raise ValueError("MSC endpoint IN number must not be 0")
- if 'HID' in args.devices:
+ if include_hid:
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:
+ if args.hid_ep_num_in == 0:
raise ValueError("HID endpoint IN number must not be 0")
- if 'AUDIO' in args.devices:
+ if include_audio:
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:
+ if args.midi_ep_num_in == 0:
raise ValueError("MIDI endpoint IN number must not be 0")
- if 'VENDOR' in args.devices:
+ 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:
+ if 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 = {}
index_to_variable = {}
strings = []
@classmethod
- def index(cls, string, *, variable_name = None):
+ def index(cls, string, *, variable_name=None):
if string in cls.string_to_index:
idx = cls.string_to_index[string]
if not cls.index_to_variable[idx]:
@@ -145,11 +225,12 @@ class StringIndex:
return cls.strings
-
# langid must be the 0th string descriptor
LANGID_INDEX = StringIndex.index("\u0409", variable_name="language_id")
assert LANGID_INDEX == 0
-SERIAL_NUMBER_INDEX = StringIndex.index("S" * args.serial_number_length, variable_name="usb_serial_number")
+SERIAL_NUMBER_INDEX = StringIndex.index(
+ "S" * args.serial_number_length, variable_name="usb_serial_number"
+)
device = standard.DeviceDescriptor(
description="top",
@@ -157,212 +238,279 @@ device = standard.DeviceDescriptor(
idProduct=args.pid,
iManufacturer=StringIndex.index(args.manufacturer),
iProduct=StringIndex.index(args.product),
- iSerialNumber=SERIAL_NUMBER_INDEX)
+ iSerialNumber=SERIAL_NUMBER_INDEX,
+)
# Interface numbers are interface-set local and endpoints are interface local
# until util.join_interfaces renumbers them.
-cdc_union = cdc.Union(
- description="CDC comm",
- bMasterInterface=0x00, # Adjust this after interfaces are renumbered.
- bSlaveInterface_list=[0x01]) # Adjust this after interfaces are renumbered.
-
-cdc_call_management = cdc.CallManagement(
- description="CDC comm",
- bmCapabilities=0x01,
- bDataInterface=0x01) # Adjust this after interfaces are renumbered.
-
-cdc_comm_interface = standard.InterfaceDescriptor(
- description="CDC comm",
- bInterfaceClass=cdc.CDC_CLASS_COMM, # Communications Device Class
- bInterfaceSubClass=cdc.CDC_SUBCLASS_ACM, # Abstract control model
- bInterfaceProtocol=cdc.CDC_PROTOCOL_NONE,
- iInterface=StringIndex.index("{} CDC control".format(args.interface_name)),
- subdescriptors=[
- cdc.Header(
- description="CDC comm",
- bcdCDC=0x0110),
- cdc_call_management,
- cdc.AbstractControlManagement(
- description="CDC comm",
- bmCapabilities=0x02),
- cdc_union,
- standard.EndpointDescriptor(
- description="CDC comm in",
- bEndpointAddress=args.cdc_ep_num_notification | standard.EndpointDescriptor.DIRECTION_IN,
- bmAttributes=standard.EndpointDescriptor.TYPE_INTERRUPT,
- wMaxPacketSize=0x0040,
- bInterval=0x10)
- ])
-
-cdc_data_interface = standard.InterfaceDescriptor(
- description="CDC data",
- bInterfaceClass=cdc.CDC_CLASS_DATA,
- iInterface=StringIndex.index("{} CDC data".format(args.interface_name)),
- subdescriptors=[
- standard.EndpointDescriptor(
- description="CDC data out",
- bEndpointAddress=args.cdc_ep_num_data_out | standard.EndpointDescriptor.DIRECTION_OUT,
- bmAttributes=standard.EndpointDescriptor.TYPE_BULK,
- bInterval=0,
- wMaxPacketSize=512 if args.highspeed else 64),
- standard.EndpointDescriptor(
- description="CDC data in",
- bEndpointAddress=args.cdc_ep_num_data_in | standard.EndpointDescriptor.DIRECTION_IN,
- bmAttributes=standard.EndpointDescriptor.TYPE_BULK,
- bInterval=0,
- wMaxPacketSize=512 if args.highspeed else 64),
- ])
-
-cdc_interfaces = [cdc_comm_interface, cdc_data_interface]
-
-msc_interfaces = [
- standard.InterfaceDescriptor(
- description="MSC",
- bInterfaceClass=msc.MSC_CLASS,
- bInterfaceSubClass=msc.MSC_SUBCLASS_TRANSPARENT,
- bInterfaceProtocol=msc.MSC_PROTOCOL_BULK,
- iInterface=StringIndex.index("{} Mass Storage".format(args.interface_name)),
+
+def make_cdc_union(name):
+ return cdc.Union(
+ description="{} comm".format(name),
+ # Set bMasterInterface and bSlaveInterface_list to proper values after interfaces are renumbered.
+ bMasterInterface=0x00,
+ bSlaveInterface_list=[0x01],
+ )
+
+
+def make_cdc_call_management(name):
+ # Set bDataInterface to proper value after interfaces are renumbered.
+ return cdc.CallManagement(
+ description="{} comm".format(name), bmCapabilities=0x01, bDataInterface=0x01
+ )
+
+
+def make_cdc_comm_interface(
+ name, cdc_union, cdc_call_management, cdc_ep_num_notification
+):
+ return standard.InterfaceDescriptor(
+ description="{} comm".format(name),
+ bInterfaceClass=cdc.CDC_CLASS_COMM, # Communications Device Class
+ bInterfaceSubClass=cdc.CDC_SUBCLASS_ACM, # Abstract control model
+ bInterfaceProtocol=cdc.CDC_PROTOCOL_NONE,
+ iInterface=StringIndex.index("{} {} control".format(args.interface_name, name)),
+ subdescriptors=[
+ cdc.Header(description="{} comm".format(name), bcdCDC=0x0110),
+ cdc_call_management,
+ cdc.AbstractControlManagement(
+ description="{} comm".format(name), bmCapabilities=0x02
+ ),
+ cdc_union,
+ standard.EndpointDescriptor(
+ description="{} comm in".format(name),
+ bEndpointAddress=cdc_ep_num_notification
+ | standard.EndpointDescriptor.DIRECTION_IN,
+ bmAttributes=standard.EndpointDescriptor.TYPE_INTERRUPT,
+ wMaxPacketSize=0x0040,
+ bInterval=0x10,
+ ),
+ ],
+ )
+
+
+def make_cdc_data_interface(name, cdc_ep_num_data_in, cdc_ep_num_data_out):
+ return standard.InterfaceDescriptor(
+ description="{} data".format(name),
+ bInterfaceClass=cdc.CDC_CLASS_DATA,
+ iInterface=StringIndex.index("{} {} data".format(args.interface_name, name)),
subdescriptors=[
standard.EndpointDescriptor(
- description="MSC in",
- bEndpointAddress=args.msc_ep_num_in | standard.EndpointDescriptor.DIRECTION_IN,
+ description="{} data out".format(name),
+ bEndpointAddress=cdc_ep_num_data_out
+ | standard.EndpointDescriptor.DIRECTION_OUT,
bmAttributes=standard.EndpointDescriptor.TYPE_BULK,
bInterval=0,
- wMaxPacketSize=512 if args.highspeed else 64),
+ wMaxPacketSize=512 if args.highspeed else 64,
+ ),
standard.EndpointDescriptor(
- description="MSC out",
- bEndpointAddress=(args.msc_ep_num_out | standard.EndpointDescriptor.DIRECTION_OUT),
+ description="{} data in".format(name),
+ bEndpointAddress=cdc_ep_num_data_in
+ | standard.EndpointDescriptor.DIRECTION_IN,
bmAttributes=standard.EndpointDescriptor.TYPE_BULK,
bInterval=0,
- wMaxPacketSize=512 if args.highspeed else 64),
- ]
+ wMaxPacketSize=512 if args.highspeed else 64,
+ ),
+ ],
)
-]
-# When there's only one hid_device, it shouldn't have a report id.
-# Otherwise, report ids are assigned sequentially:
-# args.hid_devices[0] has report_id 1
-# args.hid_devices[1] has report_id 2
-# etc.
-report_ids = {}
+if include_cdc:
+ cdc_union = make_cdc_union("CDC")
+ cdc_call_management = make_cdc_call_management("CDC")
+ cdc_comm_interface = make_cdc_comm_interface(
+ "CDC", cdc_union, cdc_call_management, args.cdc_ep_num_notification
+ )
+ cdc_data_interface = make_cdc_data_interface(
+ "CDC", args.cdc_ep_num_data_in, args.cdc_ep_num_data_out
+ )
-if len(args.hid_devices) == 1:
- name = args.hid_devices[0]
- combined_hid_report_descriptor = hid.ReportDescriptor(
- description=name,
- report_descriptor=bytes(hid_report_descriptors.REPORT_DESCRIPTOR_FUNCTIONS[name](0)))
- report_ids[name] = 0
-else:
- report_id = 1
- concatenated_descriptors = bytearray()
- for name in args.hid_devices:
- concatenated_descriptors.extend(
- bytes(hid_report_descriptors.REPORT_DESCRIPTOR_FUNCTIONS[name](report_id)))
- report_ids[name] = report_id
- report_id += 1
- combined_hid_report_descriptor = hid.ReportDescriptor(
- description="MULTIDEVICE",
- report_descriptor=bytes(concatenated_descriptors))
-
-# ASF4 expects keyboard and generic devices to have both in and out endpoints,
-# and will fail (possibly silently) if both are not supplied.
-hid_endpoint_in_descriptor = standard.EndpointDescriptor(
- description="HID in",
- bEndpointAddress=args.hid_ep_num_in | standard.EndpointDescriptor.DIRECTION_IN,
- bmAttributes=standard.EndpointDescriptor.TYPE_INTERRUPT,
- bInterval=8)
-
-hid_endpoint_out_descriptor = standard.EndpointDescriptor(
- description="HID out",
- bEndpointAddress=args.hid_ep_num_out | standard.EndpointDescriptor.DIRECTION_OUT,
- bmAttributes=standard.EndpointDescriptor.TYPE_INTERRUPT,
- bInterval=8)
-
-hid_interfaces = [
- standard.InterfaceDescriptor(
- description="HID Multiple Devices",
- bInterfaceClass=hid.HID_CLASS,
- bInterfaceSubClass=hid.HID_SUBCLASS_NOBOOT,
- bInterfaceProtocol=hid.HID_PROTOCOL_NONE,
- iInterface=StringIndex.index("{} HID".format(args.interface_name)),
- subdescriptors=[
- hid.HIDDescriptor(
- description="HID",
- wDescriptorLength=len(bytes(combined_hid_report_descriptor))),
- hid_endpoint_in_descriptor,
- hid_endpoint_out_descriptor,
- ]
- ),
+ cdc_interfaces = [cdc_comm_interface, cdc_data_interface]
+
+if include_cdc2:
+ cdc2_union = make_cdc_union("CDC2")
+ cdc2_call_management = make_cdc_call_management("CDC2")
+ cdc2_comm_interface = make_cdc_comm_interface(
+ "CDC2", cdc2_union, cdc2_call_management, args.cdc2_ep_num_notification
+ )
+ cdc2_data_interface = make_cdc_data_interface(
+ "CDC2", args.cdc2_ep_num_data_in, args.cdc2_ep_num_data_out
+ )
+
+ cdc2_interfaces = [cdc2_comm_interface, cdc2_data_interface]
+
+if include_msc:
+ msc_interfaces = [
+ standard.InterfaceDescriptor(
+ description="MSC",
+ bInterfaceClass=msc.MSC_CLASS,
+ bInterfaceSubClass=msc.MSC_SUBCLASS_TRANSPARENT,
+ bInterfaceProtocol=msc.MSC_PROTOCOL_BULK,
+ iInterface=StringIndex.index("{} Mass Storage".format(args.interface_name)),
+ subdescriptors=[
+ standard.EndpointDescriptor(
+ description="MSC in",
+ bEndpointAddress=args.msc_ep_num_in
+ | standard.EndpointDescriptor.DIRECTION_IN,
+ bmAttributes=standard.EndpointDescriptor.TYPE_BULK,
+ bInterval=0,
+ wMaxPacketSize=512 if args.highspeed else 64,
+ ),
+ standard.EndpointDescriptor(
+ description="MSC out",
+ bEndpointAddress=(
+ args.msc_ep_num_out | standard.EndpointDescriptor.DIRECTION_OUT
+ ),
+ bmAttributes=standard.EndpointDescriptor.TYPE_BULK,
+ bInterval=0,
+ wMaxPacketSize=512 if args.highspeed else 64,
+ ),
+ ],
+ )
]
-# Audio!
-# In and out here are relative to CircuitPython
-
-# USB OUT -> midi_in_jack_emb -> midi_out_jack_ext -> CircuitPython
-midi_in_jack_emb = midi.InJackDescriptor(
- description="MIDI PC -> {}".format(args.interface_name),
- bJackType=midi.JACK_TYPE_EMBEDDED,
- iJack=StringIndex.index("{} usb_midi.ports[0]".format(args.interface_name)))
-midi_out_jack_ext = midi.OutJackDescriptor(
- description="MIDI data out to user code.",
- bJackType=midi.JACK_TYPE_EXTERNAL,
- input_pins=[(midi_in_jack_emb, 1)],
- iJack=0)
-
-# USB IN <- midi_out_jack_emb <- midi_in_jack_ext <- CircuitPython
-midi_in_jack_ext = midi.InJackDescriptor(
- description="MIDI data in from user code.",
- bJackType=midi.JACK_TYPE_EXTERNAL,
- iJack=0)
-midi_out_jack_emb = midi.OutJackDescriptor(
- description="MIDI PC <- {}".format(args.interface_name),
- bJackType=midi.JACK_TYPE_EMBEDDED,
- input_pins=[(midi_in_jack_ext, 1)],
- iJack=StringIndex.index("{} usb_midi.ports[1]".format(args.interface_name)))
-
-
-audio_midi_interface = standard.InterfaceDescriptor(
- description="Midi goodness",
- bInterfaceClass=audio.AUDIO_CLASS_DEVICE,
- bInterfaceSubClass=audio.AUDIO_SUBCLASS_MIDI_STREAMING,
- bInterfaceProtocol=audio.AUDIO_PROTOCOL_V1,
- iInterface=StringIndex.index("{} MIDI".format(args.interface_name)),
- subdescriptors=[
- midi.Header(
- jacks_and_elements=[
- midi_in_jack_emb,
- midi_in_jack_ext,
- midi_out_jack_emb,
- midi_out_jack_ext
+
+if include_hid:
+ # When there's only one hid_device, it shouldn't have a report id.
+ # Otherwise, report ids are assigned sequentially:
+ # args.hid_devices[0] has report_id 1
+ # args.hid_devices[1] has report_id 2
+ # etc.
+
+ report_ids = {}
+
+ if len(args.hid_devices) == 1:
+ name = args.hid_devices[0]
+ combined_hid_report_descriptor = hid.ReportDescriptor(
+ description=name,
+ report_descriptor=bytes(
+ hid_report_descriptors.REPORT_DESCRIPTOR_FUNCTIONS[name](0)
+ ),
+ )
+ report_ids[name] = 0
+ else:
+ report_id = 1
+ concatenated_descriptors = bytearray()
+ for name in args.hid_devices:
+ concatenated_descriptors.extend(
+ bytes(
+ hid_report_descriptors.REPORT_DESCRIPTOR_FUNCTIONS[name](report_id)
+ )
+ )
+ report_ids[name] = report_id
+ report_id += 1
+ combined_hid_report_descriptor = hid.ReportDescriptor(
+ description="MULTIDEVICE", report_descriptor=bytes(concatenated_descriptors)
+ )
+
+ # ASF4 expects keyboard and generic devices to have both in and out endpoints,
+ # and will fail (possibly silently) if both are not supplied.
+ hid_endpoint_in_descriptor = standard.EndpointDescriptor(
+ description="HID in",
+ bEndpointAddress=args.hid_ep_num_in | standard.EndpointDescriptor.DIRECTION_IN,
+ bmAttributes=standard.EndpointDescriptor.TYPE_INTERRUPT,
+ bInterval=8,
+ )
+
+ hid_endpoint_out_descriptor = standard.EndpointDescriptor(
+ description="HID out",
+ bEndpointAddress=args.hid_ep_num_out
+ | standard.EndpointDescriptor.DIRECTION_OUT,
+ bmAttributes=standard.EndpointDescriptor.TYPE_INTERRUPT,
+ bInterval=8,
+ )
+
+ hid_interfaces = [
+ standard.InterfaceDescriptor(
+ description="HID Multiple Devices",
+ bInterfaceClass=hid.HID_CLASS,
+ bInterfaceSubClass=hid.HID_SUBCLASS_NOBOOT,
+ bInterfaceProtocol=hid.HID_PROTOCOL_NONE,
+ iInterface=StringIndex.index("{} HID".format(args.interface_name)),
+ subdescriptors=[
+ hid.HIDDescriptor(
+ description="HID",
+ wDescriptorLength=len(bytes(combined_hid_report_descriptor)),
+ ),
+ hid_endpoint_in_descriptor,
+ hid_endpoint_out_descriptor,
],
),
- standard.EndpointDescriptor(
- description="MIDI data out to {}".format(args.interface_name),
- bEndpointAddress=args.midi_ep_num_out | standard.EndpointDescriptor.DIRECTION_OUT,
- bmAttributes=standard.EndpointDescriptor.TYPE_BULK,
- bInterval=0,
- wMaxPacketSize=512 if args.highspeed else 64),
- midi.DataEndpointDescriptor(baAssocJack=[midi_in_jack_emb]),
- standard.EndpointDescriptor(
- description="MIDI data in from {}".format(args.interface_name),
- bEndpointAddress=args.midi_ep_num_in | standard.EndpointDescriptor.DIRECTION_IN,
- bmAttributes=standard.EndpointDescriptor.TYPE_BULK,
- bInterval = 0x0,
- wMaxPacketSize=512 if args.highspeed else 64),
- midi.DataEndpointDescriptor(baAssocJack=[midi_out_jack_emb]),
- ])
-
-cs_ac_interface = audio10.AudioControlInterface(
+ ]
+
+if include_audio:
+ # Audio!
+ # In and out here are relative to CircuitPython
+
+ # USB OUT -> midi_in_jack_emb -> midi_out_jack_ext -> CircuitPython
+ midi_in_jack_emb = midi.InJackDescriptor(
+ description="MIDI PC -> {}".format(args.interface_name),
+ bJackType=midi.JACK_TYPE_EMBEDDED,
+ iJack=StringIndex.index("{} usb_midi.ports[0]".format(args.interface_name)),
+ )
+ midi_out_jack_ext = midi.OutJackDescriptor(
+ description="MIDI data out to user code.",
+ bJackType=midi.JACK_TYPE_EXTERNAL,
+ input_pins=[(midi_in_jack_emb, 1)],
+ iJack=0,
+ )
+
+ # USB IN <- midi_out_jack_emb <- midi_in_jack_ext <- CircuitPython
+ midi_in_jack_ext = midi.InJackDescriptor(
+ description="MIDI data in from user code.",
+ bJackType=midi.JACK_TYPE_EXTERNAL,
+ iJack=0,
+ )
+ midi_out_jack_emb = midi.OutJackDescriptor(
+ description="MIDI PC <- {}".format(args.interface_name),
+ bJackType=midi.JACK_TYPE_EMBEDDED,
+ input_pins=[(midi_in_jack_ext, 1)],
+ iJack=StringIndex.index("{} usb_midi.ports[1]".format(args.interface_name)),
+ )
+
+ audio_midi_interface = standard.InterfaceDescriptor(
+ description="Midi goodness",
+ bInterfaceClass=audio.AUDIO_CLASS_DEVICE,
+ bInterfaceSubClass=audio.AUDIO_SUBCLASS_MIDI_STREAMING,
+ bInterfaceProtocol=audio.AUDIO_PROTOCOL_V1,
+ iInterface=StringIndex.index("{} MIDI".format(args.interface_name)),
+ subdescriptors=[
+ midi.Header(
+ jacks_and_elements=[
+ midi_in_jack_emb,
+ midi_in_jack_ext,
+ midi_out_jack_emb,
+ midi_out_jack_ext,
+ ],
+ ),
+ standard.EndpointDescriptor(
+ description="MIDI data out to {}".format(args.interface_name),
+ bEndpointAddress=args.midi_ep_num_out
+ | standard.EndpointDescriptor.DIRECTION_OUT,
+ bmAttributes=standard.EndpointDescriptor.TYPE_BULK,
+ bInterval=0,
+ wMaxPacketSize=512 if args.highspeed else 64,
+ ),
+ midi.DataEndpointDescriptor(baAssocJack=[midi_in_jack_emb]),
+ standard.EndpointDescriptor(
+ description="MIDI data in from {}".format(args.interface_name),
+ bEndpointAddress=args.midi_ep_num_in
+ | standard.EndpointDescriptor.DIRECTION_IN,
+ bmAttributes=standard.EndpointDescriptor.TYPE_BULK,
+ bInterval=0x0,
+ wMaxPacketSize=512 if args.highspeed else 64,
+ ),
+ midi.DataEndpointDescriptor(baAssocJack=[midi_out_jack_emb]),
+ ],
+ )
+
+ cs_ac_interface = audio10.AudioControlInterface(
description="Empty audio control",
- audio_streaming_interfaces = [],
- midi_streaming_interfaces = [
- audio_midi_interface
- ]
+ audio_streaming_interfaces=[],
+ midi_streaming_interfaces=[audio_midi_interface],
)
-audio_control_interface = standard.InterfaceDescriptor(
+ audio_control_interface = standard.InterfaceDescriptor(
description="All the audio",
bInterfaceClass=audio.AUDIO_CLASS_DEVICE,
bInterfaceSubClass=audio.AUDIO_SUBCLASS_CONTROL,
@@ -370,89 +518,124 @@ audio_control_interface = standard.InterfaceDescriptor(
iInterface=StringIndex.index("{} Audio".format(args.interface_name)),
subdescriptors=[
cs_ac_interface,
- ])
-
-# 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
-
-# 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)
-
-# We do the following conditionally to avoid adding unused entries to the StringIndex table
-if 'VENDOR' in args.devices:
+ ],
+ )
+
+ # 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
+ )
+
+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
+ 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 'CDC' in args.devices:
+if include_cdc:
interfaces_to_join.append(cdc_interfaces)
-if 'MSC' in args.devices:
+if include_cdc2:
+ interfaces_to_join.append(cdc2_interfaces)
+
+if include_msc:
interfaces_to_join.append(msc_interfaces)
-if 'HID' in args.devices:
+if include_hid:
interfaces_to_join.append(hid_interfaces)
-if 'AUDIO' in args.devices:
+if include_audio:
interfaces_to_join.append(audio_interfaces)
-if 'VENDOR' in args.devices:
+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.
-interfaces = util.join_interfaces(interfaces_to_join, renumber_endpoints=args.renumber_endpoints)
+interfaces = util.join_interfaces(
+ interfaces_to_join, renumber_endpoints=args.renumber_endpoints
+)
if args.max_ep != 0:
for interface in interfaces:
for subdescriptor in interface.subdescriptors:
- endpoint_address = getattr(subdescriptor, 'bEndpointAddress', 0) & 0x7f
+ 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 & 0x7f, interface.description, args.max_ep))
+ raise ValueError(
+ "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:
- print("Unable to check whether maximum number of endpoints is respected", file=sys.stderr)
+ print(
+ "Unable to check whether maximum number of endpoints is respected",
+ file=sys.stderr,
+ )
# Now adjust the CDC interface cross-references.
-cdc_union.bMasterInterface = cdc_comm_interface.bInterfaceNumber
-cdc_union.bSlaveInterface_list = [cdc_data_interface.bInterfaceNumber]
+if include_cdc:
+ cdc_union.bMasterInterface = cdc_comm_interface.bInterfaceNumber
+ cdc_union.bSlaveInterface_list = [cdc_data_interface.bInterfaceNumber]
+
+ cdc_call_management.bDataInterface = cdc_data_interface.bInterfaceNumber
-cdc_call_management.bDataInterface = cdc_data_interface.bInterfaceNumber
+if include_cdc2:
+ cdc2_union.bMasterInterface = cdc2_comm_interface.bInterfaceNumber
+ cdc2_union.bSlaveInterface_list = [cdc2_data_interface.bInterfaceNumber]
-cdc_iad = standard.InterfaceAssociationDescriptor(
- description="CDC IAD",
- bFirstInterface=cdc_comm_interface.bInterfaceNumber,
- bInterfaceCount=len(cdc_interfaces),
- bFunctionClass=cdc.CDC_CLASS_COMM, # Communications Device Class
- bFunctionSubClass=cdc.CDC_SUBCLASS_ACM, # Abstract control model
- bFunctionProtocol=cdc.CDC_PROTOCOL_NONE)
+ cdc2_call_management.bDataInterface = cdc2_data_interface.bInterfaceNumber
+
+
+def make_cdc_iad(cdc_comm_interface, name):
+ return standard.InterfaceAssociationDescriptor(
+ description="{} IAD".format(name),
+ bFirstInterface=cdc_comm_interface.bInterfaceNumber,
+ bInterfaceCount=len(cdc_interfaces),
+ bFunctionClass=cdc.CDC_CLASS_COMM, # Communications Device Class
+ bFunctionSubClass=cdc.CDC_SUBCLASS_ACM, # Abstract control model
+ bFunctionProtocol=cdc.CDC_PROTOCOL_NONE,
+ )
+
+
+if include_cdc:
+ cdc_iad = make_cdc_iad(cdc_comm_interface, "CDC")
+if include_cdc2:
+ cdc2_iad = make_cdc_iad(cdc2_comm_interface, "CDC2")
descriptor_list = []
-if 'CDC' in args.devices:
+if include_cdc:
# 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
@@ -462,37 +645,47 @@ if 'CDC' in args.devices:
descriptor_list.append(cdc_iad)
descriptor_list.extend(cdc_interfaces)
-if 'MSC' in args.devices:
+if include_cdc2:
+ descriptor_list.append(cdc2_iad)
+ descriptor_list.extend(cdc2_interfaces)
+
+if include_msc:
descriptor_list.extend(msc_interfaces)
-if 'HID' in args.devices:
+if include_hid:
descriptor_list.extend(hid_interfaces)
-if 'AUDIO' in args.devices:
+if include_audio:
# 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 'VENDOR' in args.devices:
+if include_vendor:
descriptor_list.extend(vendor_interfaces)
# Finally, build the composite descriptor.
configuration = standard.ConfigurationDescriptor(
description="Composite configuration",
- wTotalLength=(standard.ConfigurationDescriptor.bLength +
- sum([len(bytes(x)) for x in descriptor_list])),
- bNumInterfaces=len(interfaces))
+ wTotalLength=(
+ standard.ConfigurationDescriptor.bLength
+ + sum([len(bytes(x)) for x in descriptor_list])
+ ),
+ bNumInterfaces=len(interfaces),
+)
descriptor_list.insert(0, configuration)
-string_descriptors = [standard.StringDescriptor(string) for string in StringIndex.strings_in_order()]
+string_descriptors = [
+ standard.StringDescriptor(string) for string in StringIndex.strings_in_order()
+]
serial_number_descriptor = string_descriptors[SERIAL_NUMBER_INDEX]
c_file = args.output_c_file
h_file = args.output_h_file
-c_file.write("""\
+c_file.write(
+ """\
#include <stdint.h>
#include "tusb.h"
@@ -500,34 +693,49 @@ c_file.write("""\
#include "shared-bindings/usb_hid/Device.h"
#include "{H_FILE_NAME}"
-""".format(H_FILE_NAME=h_file.name))
+""".format(
+ H_FILE_NAME=h_file.name
+ )
+)
-c_file.write("""\
+c_file.write(
+ """\
// {DESCRIPTION} : {CLASS}
-""".format(DESCRIPTION=device.description,
- CLASS=device.__class__))
+""".format(
+ DESCRIPTION=device.description, CLASS=device.__class__
+ )
+)
-c_file.write("""\
+c_file.write(
+ """\
const uint8_t usb_desc_dev[] = {
-""")
+"""
+)
for b in bytes(device):
c_file.write("0x{:02x}, ".format(b))
-c_file.write("""\
+c_file.write(
+ """\
};
-""")
+"""
+)
-c_file.write("""\
+c_file.write(
+ """\
const uint8_t usb_desc_cfg[] = {
-""")
+"""
+)
# Write out all the regular descriptors as one long array (that's how ASF4 does it).
descriptor_length = 0
for descriptor in descriptor_list:
- c_file.write("""\
+ c_file.write(
+ """\
// {DESCRIPTION} : {CLASS}
-""".format(DESCRIPTION=descriptor.description,
- CLASS=descriptor.__class__))
+""".format(
+ DESCRIPTION=descriptor.description, CLASS=descriptor.__class__
+ )
+ )
b = bytes(descriptor)
notes = descriptor.notes()
@@ -545,17 +753,22 @@ for descriptor in descriptor_list:
i += length
descriptor_length += len(b)
-c_file.write("""\
+c_file.write(
+ """\
};
-""")
+"""
+)
pointers_to_strings = []
for idx, descriptor in enumerate(string_descriptors):
- c_file.write("""\
+ c_file.write(
+ """\
// {DESCRIPTION} : {CLASS}
-""".format(DESCRIPTION=descriptor.description,
- CLASS=descriptor.__class__))
+""".format(
+ DESCRIPTION=descriptor.description, CLASS=descriptor.__class__
+ )
+ )
b = bytes(descriptor)
notes = descriptor.notes()
@@ -569,41 +782,59 @@ for idx, descriptor in enumerate(string_descriptors):
const = "const "
if variable_name == "usb_serial_number":
const = ""
- c_file.write("""\
+ c_file.write(
+ """\
{const}uint16_t {NAME}[] = {{
-""".format(const=const, NAME=variable_name))
+""".format(
+ const=const, NAME=variable_name
+ )
+ )
pointers_to_strings.append("{name}".format(name=variable_name))
n = 0
while i < len(b):
length = b[i]
for j in range(length // 2):
- c_file.write("0x{:04x}, ".format(b[i + 2*j + 1] << 8 | b[i + 2*j]))
+ c_file.write("0x{:04x}, ".format(b[i + 2 * j + 1] << 8 | b[i + 2 * j]))
n += 1
c_file.write("\n")
i += length
- c_file.write("""\
+ c_file.write(
+ """\
};
-""")
+"""
+ )
-c_file.write("""\
+c_file.write(
+ """\
// array of pointer to string descriptors
uint16_t const * const string_desc_arr [] =
{
-""")
-c_file.write(""",\
+"""
+)
+c_file.write(
+ """,\
-""".join(pointers_to_strings))
+""".join(
+ pointers_to_strings
+ )
+)
-c_file.write("""
+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 the values we need for the .h file.
-h_file.write("""\
+h_file.write(
+ """\
#ifndef MICROPY_INCLUDED_AUTOGEN_USB_DESCRIPTOR_H
#define MICROPY_INCLUDED_AUTOGEN_USB_DESCRIPTOR_H
@@ -614,32 +845,43 @@ 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}"
// Product name included in Inquiry response, max 16 bytes
#define CFG_TUD_MSC_PRODUCT "{msc_product}"
-"""
-.format(serial_number_length=len(bytes(serial_number_descriptor)) // 2,
+""".format(
+ serial_number_length=len(bytes(serial_number_descriptor)) // 2,
device_length=len(bytes(device)),
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',
- hid_num_devices=len(args.hid_devices),
+ rhport0_mode="OPT_MODE_DEVICE | OPT_MODE_HIGH_SPEED"
+ if args.highspeed
+ else "OPT_MODE_DEVICE",
msc_vendor=args.manufacturer[:8],
- msc_product=args.product[:16]))
+ msc_product=args.product[:16],
+ )
+)
-if 'VENDOR' in args.devices:
- h_file.write("""\
+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_report_descriptor_length=len(bytes(combined_hid_report_descriptor)),
+ hid_num_devices=len(args.hid_devices),
+ )
+ )
+
+if include_vendor:
+ h_file.write(
+ """\
enum
{
VENDOR_REQUEST_WEBUSB = 1,
@@ -652,43 +894,75 @@ extern uint8_t const desc_ms_os_20[];
// if we try do define this here (TODO figure this out!)
//extern const tusb_desc_webusb_url_t desc_webusb_url;
-""")
+"""
+ )
-h_file.write("""\
+h_file.write(
+ """\
#endif // MICROPY_INCLUDED_AUTOGEN_USB_DESCRIPTOR_H
-""")
-# Write out the report descriptor and info
+"""
+)
-c_file.write("""\
+if include_hid:
+ # 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))
+""".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("""\
+ for b in bytes(combined_hid_report_descriptor):
+ c_file.write("0x{:02x}, ".format(b))
+
+ c_file.write(
+ """\
};
-""")
+"""
+ )
-# Write out USB HID report buffer definitions.
-for name in args.hid_devices:
- c_file.write("""\
+ # Write out USB HID report buffer definitions.
+ for name in args.hid_devices:
+ 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))
-
- if hid_report_descriptors.HID_DEVICE_DATA[name].out_report_length > 0:
- c_file.write("""\
+""".format(
+ name=name.lower(),
+ report_length=hid_report_descriptors.HID_DEVICE_DATA[
+ name
+ ].report_length,
+ )
+ )
+
+ 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("""
+""".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,
@@ -699,37 +973,54 @@ for name in args.hid_devices:
.out_report_buffer = {out_report_buffer},
.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))
-c_file.write("""\
+""".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,
+ )
+ )
+ 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,
}},
.len = {num_devices},
.items = {{
-""".format(num_devices=len(args.hid_devices)))
-for idx in range(len(args.hid_devices)):
- c_file.write("""\
+""".format(
+ num_devices=len(args.hid_devices)
+ )
+ )
+ for idx in range(len(args.hid_devices)):
+ c_file.write(
+ """\
(mp_obj_t) &usb_hid_devices[{idx}],
-""".format(idx=idx))
-c_file.write("""\
+""".format(
+ idx=idx
+ )
+ )
+ c_file.write(
+ """\
},
};
-""")
+"""
+ )
-if 'VENDOR' in args.devices:
- # Mimic what the tinyusb webusb demo does in it's main.c file
- c_file.write("""
+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 =
@@ -819,4 +1110,8 @@ 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))
+""".format(
+ webusb_url=args.webusb_url,
+ webusb_interface=vendor_interface.bInterfaceNumber,
+ )
+ )
diff --git a/tools/usb_descriptor b/tools/usb_descriptor
-Subproject 701cafc50e2e574dccaf7a340eedbd64a0b41a4
+Subproject 2eaa6114b209fe7f0a795eda8d6a7b3b93d76d2