Skip to content

micropython/usb/usb-device/usb/device/core.py: adding alternate setting support plus a few fixes and improvements. #1030

New issue

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

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

Already on GitHub? Sign in to your account

Closed
wants to merge 2 commits into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 25 additions & 16 deletions micropython/usb/usb-device/usb/device/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -108,7 +109,6 @@
device_class=0,
device_subclass=0,
device_protocol=0,
config_str=None,
max_power_ma=None,
remote_wakeup=False,
):
Expand Down Expand Up @@ -166,7 +166,11 @@
# 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)

Expand Down Expand Up @@ -204,10 +208,11 @@
)

# 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
Expand Down Expand Up @@ -665,6 +670,7 @@
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.
Expand All @@ -680,7 +686,7 @@
_STD_DESC_INTERFACE_LEN, # bLength
_STD_DESC_INTERFACE_TYPE, # bDescriptorType
bInterfaceNumber,
0, # bAlternateSetting, not currently supported
bAlternateSetting,
bNumEndpoints,
bInterfaceClass,
bInterfaceSubClass,
Expand Down Expand Up @@ -791,17 +797,18 @@
# 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.
Expand All @@ -815,16 +822,16 @@
# 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

Check failure on line 833 in micropython/usb/usb-device/usb/device/core.py

View workflow job for this annotation

GitHub Actions / ruff

Ruff (RUF018)

micropython/usb/usb-device/usb/device/core.py:833:41: RUF018 Avoid assignment expressions in `assert` statements
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
Expand All @@ -834,13 +841,14 @@
#
# 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)

Expand All @@ -866,10 +874,11 @@
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)
Expand Down
Loading