3
3
# These contain the classes and utilities that are needed to
4
4
# implement a USB device, not any complete USB drivers.
5
5
#
6
- # MIT license; Copyright (c) 2022-2024 Angus Gratton
6
+ # MIT license; Copyright (c) 2022-2024 Angus Gratton, 2025 Harm Lammers
7
7
from micropython import const
8
8
import machine
9
9
import struct
10
+ import time
10
11
11
12
try :
12
13
from _thread import get_ident
@@ -108,7 +109,6 @@ def config( # noqa: PLR0913
108
109
device_class = 0 ,
109
110
device_subclass = 0 ,
110
111
device_protocol = 0 ,
111
- config_str = None ,
112
112
max_power_ma = None ,
113
113
remote_wakeup = False ,
114
114
):
@@ -166,7 +166,9 @@ def maybe_set(value, idx):
166
166
# Keep track of the interface and endpoint indexes
167
167
itf_num = builtin_driver .itf_max
168
168
ep_num = max (builtin_driver .ep_max , 1 ) # Endpoint 0 always reserved for control
169
- while len (strs ) < builtin_driver .str_max :
169
+ while len (strs ) < builtin_driver .str_max - 1 : # This is possibly unnecessary or wrong because
170
+ # https://docs.micropython.org/en/latest/library/machine.USBDevice.html
171
+ # states all string values except index 0 should be plain ASCII
170
172
strs .append (None ) # Reserve other string indexes used by builtin drivers
171
173
initial_cfg = builtin_driver .desc_cfg or (b"\x00 " * _STD_DESC_CONFIG_LEN )
172
174
@@ -204,10 +206,11 @@ def maybe_set(value, idx):
204
206
)
205
207
206
208
# Configuration string is optional but supported
207
- iConfiguration = 0
208
209
if configuration_str :
209
210
iConfiguration = len (strs )
210
211
strs .append (configuration_str )
212
+ else :
213
+ iConfiguration = 0
211
214
212
215
if max_power_ma is not None :
213
216
# Convert from mA to the units used in the descriptor
@@ -665,6 +668,7 @@ def interface(
665
668
bInterfaceSubClass = _INTERFACE_SUBCLASS_NONE ,
666
669
bInterfaceProtocol = _PROTOCOL_NONE ,
667
670
iInterface = 0 ,
671
+ bAlternateSetting = 0 ,
668
672
):
669
673
# Utility function to append a standard Interface descriptor, with
670
674
# the properties specified in the parameter list.
@@ -680,7 +684,7 @@ def interface(
680
684
_STD_DESC_INTERFACE_LEN , # bLength
681
685
_STD_DESC_INTERFACE_TYPE , # bDescriptorType
682
686
bInterfaceNumber ,
683
- 0 , # bAlternateSetting, not currently supported
687
+ bAlternateSetting ,
684
688
bNumEndpoints ,
685
689
bInterfaceClass ,
686
690
bInterfaceSubClass ,
@@ -791,17 +795,18 @@ class Buffer:
791
795
# approximate a Python-based single byte ringbuffer.
792
796
#
793
797
def __init__ (self , length ):
798
+ self ._l = length
794
799
self ._b = memoryview (bytearray (length ))
795
- # number of bytes in buffer read to read, starting at index 0. Updated
800
+ # number of bytes in buffer ready to read, starting at index 0. Updated
796
801
# by both producer & consumer.
797
802
self ._n = 0
798
- # start index of a pending write into the buffer, if any. equals
803
+ # start index of a pending write into the buffer, if any. Equals
799
804
# len(self._b) if no write is pending. Updated by producer only.
800
805
self ._w = length
801
806
802
807
def writable (self ):
803
808
# Number of writable bytes in the buffer. Assumes no pending write is outstanding.
804
- return len ( self ._b ) - self ._n
809
+ return self ._l - self ._n
805
810
806
811
def readable (self ):
807
812
# Number of readable bytes in the buffer. Assumes no pending read is outstanding.
@@ -815,16 +820,16 @@ def pend_write(self, wmax=None):
815
820
# this many bytes long.
816
821
#
817
822
# (No critical section needed as self._w is only updated by the producer.)
818
- self ._w = self ._n
819
- end = (self . _w + wmax ) if wmax else len ( self ._b )
820
- return self ._b [self . _w : end ]
823
+ self ._w = ( _w := self ._n )
824
+ end = (_w + wmax ) if wmax else self ._l
825
+ return self ._b [_w : end ]
821
826
822
827
def finish_write (self , nbytes ):
823
828
# Called by the producer to indicate it wrote nbytes into the buffer.
824
829
ist = machine .disable_irq ()
825
830
try :
826
- assert nbytes <= len ( self ._b ) - self ._w # can't say we wrote more than was pended
827
- if self ._n == self . _w :
831
+ assert nbytes <= self ._l - ( _w := self ._w ) # can't say we wrote more than was pended
832
+ if self ._n == _w :
828
833
# no data was read while the write was happening, so the buffer is already in place
829
834
# (this is the fast path)
830
835
self ._n += nbytes
@@ -834,13 +839,14 @@ def finish_write(self, nbytes):
834
839
#
835
840
# As this updates self._n we have to do it in the critical
836
841
# section, so do it byte by byte to avoid allocating.
842
+ _b = self ._b
837
843
while nbytes > 0 :
838
- self . _b [self ._n ] = self . _b [self ._w ]
844
+ _b [self ._n ] = _b [self ._w ]
839
845
self ._n += 1
840
846
self ._w += 1
841
847
nbytes -= 1
842
848
843
- self ._w = len ( self ._b )
849
+ self ._w = self ._l
844
850
finally :
845
851
machine .enable_irq (ist )
846
852
@@ -866,10 +872,11 @@ def finish_read(self, nbytes):
866
872
assert nbytes <= self ._n # can't say we read more than was available
867
873
i = 0
868
874
self ._n -= nbytes
875
+ _b = self ._b
869
876
while i < self ._n :
870
877
# consumer only read part of the buffer, so shuffle remaining
871
878
# read data back towards index 0 to avoid fragmentation
872
- self . _b [i ] = self . _b [i + nbytes ]
879
+ _b [i ] = _b [i + nbytes ]
873
880
i += 1
874
881
finally :
875
882
machine .enable_irq (ist )
@@ -881,4 +888,4 @@ def readinto(self, b):
881
888
if to_r :
882
889
b [:to_r ] = pr [:to_r ]
883
890
self .finish_read (to_r )
884
- return to_r
891
+ return to_r
0 commit comments