-
Notifications
You must be signed in to change notification settings - Fork 1.1k
micropython/usb/usb-device/usb/device/core.py: Add alternate setting support plus a few fixes and improvements. #1031
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
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -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,11 @@ 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 | ||
|
Comment on lines
+171
to
+173
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What's happening here is that we're expanding the This is why the documentation says the strings arguments should be strings - the values provided by the Python caller should be strings, these values are internal placeholders to pad the index out. I assume the off-by-one is a real bug, though - I'm guessing you found that strings were reported wrong without this? |
||
| 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 +208,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 +670,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 +686,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 +797,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,15 +822,15 @@ 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 | ||
| 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) | ||
|
|
@@ -834,13 +841,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 +874,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) | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Confused by this as PR description says:
... and it is indeed not used, from what I can see?