Skip to content

Commit 054dcc2

Browse files
committed
usbd: Refactor USBInterface
- Allows >1 USB interface to live in a single USBInterface object (which is confusing naming, but makes cases like MIDI much simpler.) - Also refactors the string implementation to do less allocations, string descriptors are now stored in a 'strs' list of each USBInterface instead of holding a single _strs variable in the USBDevice object.
1 parent f414610 commit 054dcc2

File tree

7 files changed

+318
-263
lines changed

7 files changed

+318
-263
lines changed

micropython/usbd/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
from .device import get_usbdevice, USBInterface
22
from .hid import HIDInterface, MouseInterface
3-
from .midi import DummyAudioInterface, MIDIInterface, MidiUSB
3+
from .midi import MIDIInterface, MIDIUSB
44
from .cdc import CDC
55
from . import utils

micropython/usbd/cdc.py

Lines changed: 31 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111
from .device import USBInterface, get_usbdevice
1212
from .utils import (
1313
Buffer,
14-
endpoint_descriptor,
1514
split_bmRequestType,
1615
STAGE_SETUP,
1716
STAGE_DATA,
@@ -23,7 +22,6 @@
2322

2423
_DEV_CLASS_MISC = const(0xEF)
2524
_CS_DESC_TYPE = const(0x24) # CS Interface type communication descriptor
26-
_ITF_ASSOCIATION_DESC_TYPE = const(0xB) # Interface Association descriptor
2725

2826
# CDC control interface definitions
2927
_INTERFACE_CLASS_CDC = const(2)
@@ -62,6 +60,7 @@
6260
# Other definitions
6361
_CDC_VERSION = const(0x0120) # release number in binary-coded decimal
6462

63+
# Number of endpoints in each interface
6564
_CDC_CONTROL_EP_NUM = const(1)
6665
_CDC_DATA_EP_NUM = const(2)
6766

@@ -93,7 +92,8 @@ class CDC(io.IOBase):
9392
# with some additional methods.
9493
#
9594
# This is a standalone class, instead of a USBInterface subclass, because
96-
# CDC consists of multiple interfaces (CDC control and CDC data)
95+
# CDC consists of multiple interfaces (CDC control and CDC data) and also
96+
# so it can derive from io.IOBase.
9797
def __init__(self, **kwargs):
9898
# For CDC to work, the device class must be set to Interface Association
9999
usb_device = get_usbdevice()
@@ -218,9 +218,7 @@ class CDCControlInterface(USBInterface):
218218
# Implements the CDC Control Interface
219219

220220
def __init__(self):
221-
super().__init__(
222-
_INTERFACE_CLASS_CDC, _INTERFACE_SUBCLASS_CDC, _PROTOCOL_NONE, _CDC_CONTROL_EP_NUM
223-
)
221+
super().__init__()
224222

225223
# Callbacks for particular changes initiated by the host
226224
self.break_cb = None # Host sent a "break" condition
@@ -233,23 +231,12 @@ def __init__(self):
233231

234232
self.ep_in = None # Set when enumeration happens
235233

236-
def descriptor_config_cb(self, desc, itf_num, str_num, ep_num):
237-
# CDC needs a Interface Association Descriptor (IAD)
238-
# two interfaces in total
239-
desc.pack(
240-
"<BBBBBBBB",
241-
8,
242-
_ITF_ASSOCIATION_DESC_TYPE,
243-
itf_num,
244-
2,
245-
_INTERFACE_CLASS_CDC,
246-
_INTERFACE_SUBCLASS_CDC,
247-
_PROTOCOL_NONE,
248-
0,
249-
)
234+
def descriptor_config_cb(self, desc, itf_num, ep_num):
235+
# CDC needs a Interface Association Descriptor (IAD) connecting the Control & Data interfaces
236+
desc.interface_assoc(itf_num, 2, _INTERFACE_CLASS_CDC, _INTERFACE_SUBCLASS_CDC)
250237

251-
# Now add the standard interface descriptor
252-
strs = super().descriptor_config_cb(desc, itf_num, str_num, ep_num)
238+
# Now add the Control interface descriptor
239+
desc.interface(itf_num, _CDC_CONTROL_EP_NUM, _INTERFACE_CLASS_CDC, _INTERFACE_SUBCLASS_CDC)
253240

254241
# Append the CDC class-specific interface descriptor
255242
# see CDC120-track, p20
@@ -258,8 +245,8 @@ def descriptor_config_cb(self, desc, itf_num, str_num, ep_num):
258245
5, # bFunctionLength
259246
_CS_DESC_TYPE, # bDescriptorType
260247
_CDC_FUNC_DESC_HEADER, # bDescriptorSubtype
261-
_CDC_VERSION,
262-
) # cdc version
248+
_CDC_VERSION, # cdc version
249+
)
263250

264251
# CDC-PSTN table3 "Call Management"
265252
# set to No
@@ -269,8 +256,8 @@ def descriptor_config_cb(self, desc, itf_num, str_num, ep_num):
269256
_CS_DESC_TYPE, # bDescriptorType
270257
_CDC_FUNC_DESC_CALL_MANAGEMENT, # bDescriptorSubtype
271258
0, # bmCapabilities - XXX no call managment so far
272-
1,
273-
) # bDataInterface - interface 1
259+
itf_num + 1, # bDataInterface - interface 1
260+
)
274261

275262
# CDC-PSTN table4 "Abstract Control"
276263
# set to support line_coding and send_break
@@ -279,8 +266,8 @@ def descriptor_config_cb(self, desc, itf_num, str_num, ep_num):
279266
4, # bFunctionLength
280267
_CS_DESC_TYPE, # bDescriptorType
281268
_CDC_FUNC_DESC_ABSTRACT_CONTROL, # bDescriptorSubtype
282-
0x6,
283-
) # bmCapabilities D1, D2
269+
0x6, # bmCapabilities D1, D2
270+
)
284271

285272
# CDC-PSTN "Union"
286273
# set control interface / data interface number
@@ -290,15 +277,13 @@ def descriptor_config_cb(self, desc, itf_num, str_num, ep_num):
290277
_CS_DESC_TYPE, # bDescriptorType
291278
_CDC_FUNC_DESC_UNION, # bDescriptorSubtype
292279
itf_num, # bControlInterface
293-
itf_num + 1, # data interface, assume this one will be assigned next
294-
) # bSubordinateInterface0 (data class itf number)
280+
itf_num + 1, # bSubordinateInterface0 (data class itf number)
281+
)
295282

296283
# Descriptor for a single endpoint
297284
self.ep_in = ep_num | EP_IN_FLAG
298285
desc.endpoint(self.ep_in, "interrupt", 8, 16)
299286

300-
return strs
301-
302287
def handle_interface_control_xfer(self, stage, request):
303288
# Handle class-specific interface control transfers
304289
bmRequestType, bRequest, wValue, _, wLength = struct.unpack("BBHHH", request)
@@ -337,26 +322,29 @@ class CDCDataInterface(USBInterface):
337322
# Implements the CDC Data Interface
338323

339324
def __init__(self):
340-
super().__init__(
341-
_CDC_ITF_DATA_CLASS, _CDC_ITF_DATA_SUBCLASS, _CDC_ITF_DATA_PROT, _CDC_DATA_EP_NUM
342-
)
325+
super().__init__()
326+
343327
self._wb = () # Optional write Buffer (IN endpoint), set by CDC.init()
344328
self._rb = () # Optional read Buffer (OUT endpoint), set by CDC.init()
345329
self._timeout = 1000 # set from CDC.init() as well
346330

347331
self.ep_in = self.ep_out = None # Set when enumeration happens
348332

349-
def descriptor_config_cb(self, pack_fn, itf_num, str_num, ep_num):
333+
def descriptor_config_cb(self, desc, itf_num, ep_num):
350334
# Add the standard interface descriptor
351-
strs = super().descriptor_config_cb(pack_fn, itf_num, str_num, ep_num)
335+
desc.interface(
336+
itf_num,
337+
_CDC_DATA_EP_NUM,
338+
_CDC_ITF_DATA_CLASS,
339+
_CDC_ITF_DATA_SUBCLASS,
340+
_CDC_ITF_DATA_PROT,
341+
)
352342

353-
# Two endpoints, bulk IN and OUT
354-
self.ep_in = ep_num | EP_IN_FLAG
343+
# Two endpoints, bulk OUT and IN
355344
self.ep_out = ep_num
356-
endpoint_descriptor(pack_fn, self.ep_out, "bulk", _BULK_EP_LEN, 0)
357-
endpoint_descriptor(pack_fn, self.ep_in, "bulk", _BULK_EP_LEN, 0)
358-
359-
return strs
345+
self.ep_in = ep_num | EP_IN_FLAG
346+
desc.endpoint(self.ep_out, "bulk", _BULK_EP_LEN, 0)
347+
desc.endpoint(self.ep_in, "bulk", _BULK_EP_LEN, 0)
360348

361349
def write(self, buf):
362350
# use a memoryview to track how much of 'buf' we've written so far

micropython/usbd/cdc_example.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,4 +21,4 @@
2121

2222
old_term = os.dupterm(cdc)
2323

24-
print("Welcome to REPL on CDC implemented in Python?")
24+
print("Welcome to REPL, running on CDC interface implemented in Python.")

0 commit comments

Comments
 (0)