From 942c80cbd053c863720887437b36684be4dc0b4f Mon Sep 17 00:00:00 2001 From: HLammers <62934625+HLammers@users.noreply.github.com> Date: Sat, 5 Jul 2025 11:49:36 +0200 Subject: [PATCH 1/3] Update core.py MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ⦁ Removed `import time` (not used) ⦁ Removed unused/duplicate `_Device.config` argument `config_str` ⦁ Fixed the loop reserving other string indexes used by built-in drivers `while len(strs) < builtin_driver.str_max:` to `while len(strs) < builtin\_driver.str\_max - 1:` (row 169)because str_max equals to one more than the highest string descriptor index value used by any built-in descriptor according to the [docs](https://docs.micropython.org/en/latest/library/machine.USBDevice.html) and added a comment that this loop is probably unnecessary or even wrong ⦁ Added `bAlternateSetting` as argument to `Descriptor.interface`, because it is used for USB MIDI 2.0 ⦁ Some code optimisations --- micropython/usb/usb-device/usb/device/core.py | 41 +++++++++++-------- 1 file changed, 24 insertions(+), 17 deletions(-) diff --git a/micropython/usb/usb-device/usb/device/core.py b/micropython/usb/usb-device/usb/device/core.py index 7be09ee46..3dfae98d2 100644 --- a/micropython/usb/usb-device/usb/device/core.py +++ b/micropython/usb/usb-device/usb/device/core.py @@ -3,10 +3,11 @@ # These contain the classes and utilities that are needed to # implement a USB device, not any complete USB drivers. # -# MIT license; Copyright (c) 2022-2024 Angus Gratton +# MIT license; Copyright (c) 2022-2024 Angus Gratton, 2025 Harm Lammers from micropython import const import machine import struct +import time try: from _thread import get_ident @@ -108,7 +109,6 @@ def config( # noqa: PLR0913 device_class=0, device_subclass=0, device_protocol=0, - config_str=None, max_power_ma=None, remote_wakeup=False, ): @@ -166,7 +166,9 @@ def maybe_set(value, idx): # Keep track of the interface and endpoint indexes itf_num = builtin_driver.itf_max ep_num = max(builtin_driver.ep_max, 1) # Endpoint 0 always reserved for control - while len(strs) < builtin_driver.str_max: + while len(strs) < builtin_driver.str_max - 1: # This is possibly unnecessary or wrong because + # https://docs.micropython.org/en/latest/library/machine.USBDevice.html + # states all string values except index 0 should be plain ASCII strs.append(None) # Reserve other string indexes used by builtin drivers initial_cfg = builtin_driver.desc_cfg or (b"\x00" * _STD_DESC_CONFIG_LEN) @@ -204,10 +206,11 @@ def maybe_set(value, idx): ) # Configuration string is optional but supported - iConfiguration = 0 if configuration_str: iConfiguration = len(strs) strs.append(configuration_str) + else: + iConfiguration = 0 if max_power_ma is not None: # Convert from mA to the units used in the descriptor @@ -665,6 +668,7 @@ def interface( bInterfaceSubClass=_INTERFACE_SUBCLASS_NONE, bInterfaceProtocol=_PROTOCOL_NONE, iInterface=0, + bAlternateSetting=0, ): # Utility function to append a standard Interface descriptor, with # the properties specified in the parameter list. @@ -680,7 +684,7 @@ def interface( _STD_DESC_INTERFACE_LEN, # bLength _STD_DESC_INTERFACE_TYPE, # bDescriptorType bInterfaceNumber, - 0, # bAlternateSetting, not currently supported + bAlternateSetting, bNumEndpoints, bInterfaceClass, bInterfaceSubClass, @@ -791,17 +795,18 @@ class Buffer: # approximate a Python-based single byte ringbuffer. # def __init__(self, length): + self._l = length self._b = memoryview(bytearray(length)) - # number of bytes in buffer read to read, starting at index 0. Updated + # number of bytes in buffer ready to read, starting at index 0. Updated # by both producer & consumer. self._n = 0 - # start index of a pending write into the buffer, if any. equals + # start index of a pending write into the buffer, if any. Equals # len(self._b) if no write is pending. Updated by producer only. self._w = length def writable(self): # Number of writable bytes in the buffer. Assumes no pending write is outstanding. - return len(self._b) - self._n + return self._l - self._n def readable(self): # Number of readable bytes in the buffer. Assumes no pending read is outstanding. @@ -815,16 +820,16 @@ def pend_write(self, wmax=None): # this many bytes long. # # (No critical section needed as self._w is only updated by the producer.) - self._w = self._n - end = (self._w + wmax) if wmax else len(self._b) - return self._b[self._w : end] + self._w = (_w := self._n) + end = (_w + wmax) if wmax else self._l + return self._b[_w : end] def finish_write(self, nbytes): # Called by the producer to indicate it wrote nbytes into the buffer. ist = machine.disable_irq() try: - assert nbytes <= len(self._b) - self._w # can't say we wrote more than was pended - if self._n == self._w: + assert nbytes <= self._l - (_w := self._w) # can't say we wrote more than was pended + if self._n == _w: # no data was read while the write was happening, so the buffer is already in place # (this is the fast path) self._n += nbytes @@ -834,13 +839,14 @@ def finish_write(self, nbytes): # # As this updates self._n we have to do it in the critical # section, so do it byte by byte to avoid allocating. + _b = self._b while nbytes > 0: - self._b[self._n] = self._b[self._w] + _b[self._n] = _b[self._w] self._n += 1 self._w += 1 nbytes -= 1 - self._w = len(self._b) + self._w = self._l finally: machine.enable_irq(ist) @@ -866,10 +872,11 @@ def finish_read(self, nbytes): assert nbytes <= self._n # can't say we read more than was available i = 0 self._n -= nbytes + _b = self._b while i < self._n: # consumer only read part of the buffer, so shuffle remaining # read data back towards index 0 to avoid fragmentation - self._b[i] = self._b[i + nbytes] + _b[i] = _b[i + nbytes] i += 1 finally: machine.enable_irq(ist) @@ -881,4 +888,4 @@ def readinto(self, b): if to_r: b[:to_r] = pr[:to_r] self.finish_read(to_r) - return to_r + return to_r \ No newline at end of file From befd307535c734f7127ebad861c611b5a1b36055 Mon Sep 17 00:00:00 2001 From: HLammers <62934625+HLammers@users.noreply.github.com> Date: Sat, 5 Jul 2025 14:11:19 +0200 Subject: [PATCH 2/3] Update core.py Update fromatting --- micropython/usb/usb-device/usb/device/core.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/micropython/usb/usb-device/usb/device/core.py b/micropython/usb/usb-device/usb/device/core.py index 3dfae98d2..9e1ba1742 100644 --- a/micropython/usb/usb-device/usb/device/core.py +++ b/micropython/usb/usb-device/usb/device/core.py @@ -166,7 +166,9 @@ def maybe_set(value, idx): # Keep track of the interface and endpoint indexes itf_num = builtin_driver.itf_max ep_num = max(builtin_driver.ep_max, 1) # Endpoint 0 always reserved for control - while len(strs) < builtin_driver.str_max - 1: # This is possibly unnecessary or wrong because + while ( + len(strs) < builtin_driver.str_max - 1 + ): # This is possibly unnecessary or wrong because # https://docs.micropython.org/en/latest/library/machine.USBDevice.html # states all string values except index 0 should be plain ASCII strs.append(None) # Reserve other string indexes used by builtin drivers @@ -822,7 +824,7 @@ def pend_write(self, wmax=None): # (No critical section needed as self._w is only updated by the producer.) self._w = (_w := self._n) end = (_w + wmax) if wmax else self._l - return self._b[_w : end] + return self._b[_w:end] def finish_write(self, nbytes): # Called by the producer to indicate it wrote nbytes into the buffer. @@ -888,4 +890,4 @@ def readinto(self, b): if to_r: b[:to_r] = pr[:to_r] self.finish_read(to_r) - return to_r \ No newline at end of file + return to_r From 7424b120b5092b88f6b50bd97fea6f841749071c Mon Sep 17 00:00:00 2001 From: HLammers <62934625+HLammers@users.noreply.github.com> Date: Sat, 5 Jul 2025 14:33:41 +0200 Subject: [PATCH 3/3] Moved assignment out of assert statement --- micropython/usb/usb-device/usb/device/core.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/micropython/usb/usb-device/usb/device/core.py b/micropython/usb/usb-device/usb/device/core.py index 9e1ba1742..a3e603d73 100644 --- a/micropython/usb/usb-device/usb/device/core.py +++ b/micropython/usb/usb-device/usb/device/core.py @@ -830,8 +830,8 @@ def finish_write(self, nbytes): # Called by the producer to indicate it wrote nbytes into the buffer. ist = machine.disable_irq() try: - assert nbytes <= self._l - (_w := self._w) # can't say we wrote more than was pended - if self._n == _w: + assert nbytes <= self._l - self._w # can't say we wrote more than was pended + if self._n == self._w: # no data was read while the write was happening, so the buffer is already in place # (this is the fast path) self._n += nbytes