2
2
# MIT license; Copyright (c) 2022 Angus Gratton
3
3
from micropython import const
4
4
import machine
5
- import ustruct
5
+ import struct
6
6
7
7
from .utils import split_bmRequestType , EP_IN_FLAG
8
8
@@ -78,7 +78,8 @@ def __init__(self):
78
78
descriptor_device_cb = self ._descriptor_device_cb ,
79
79
descriptor_config_cb = self ._descriptor_config_cb ,
80
80
descriptor_string_cb = self ._descriptor_string_cb ,
81
- open_driver_cb = self ._open_driver_cb ,
81
+ open_cb = self ._open_cb ,
82
+ reset_cb = self ._reset_cb ,
82
83
control_xfer_cb = self ._control_xfer_cb ,
83
84
xfer_cb = self ._xfer_cb ,
84
85
)
@@ -118,7 +119,7 @@ def _descriptor_device_cb(self):
118
119
119
120
FMT = "<BBHBBBBHHHBBBB"
120
121
# static descriptor fields
121
- f = ustruct .unpack (FMT , self ._usbd .static .desc_device )
122
+ f = struct .unpack (FMT , self ._usbd .static .desc_device )
122
123
123
124
def maybe_set (value , idx ):
124
125
# Override a numeric descriptor value or keep static value f[idx] if 'value' is None
@@ -134,7 +135,7 @@ def maybe_set_str(s, idx):
134
135
135
136
# Either copy each descriptor field directly from the static device descriptor, or 'maybe'
136
137
# override if a custom value has been set on this object
137
- return ustruct .pack (
138
+ return struct .pack (
138
139
FMT ,
139
140
f [0 ], # bLength
140
141
f [1 ], # bDescriptorType
@@ -257,7 +258,7 @@ def _update_configuration_descriptor(self, desc):
257
258
bNumInterfaces = self ._usbd .static .itf_max if self .include_static else 0
258
259
bNumInterfaces += len (self ._itfs )
259
260
260
- ustruct .pack_into (
261
+ struct .pack_into (
261
262
"<BBHBBBBB" ,
262
263
desc ,
263
264
0 ,
@@ -286,9 +287,37 @@ def _descriptor_string_cb(self, index):
286
287
except IndexError :
287
288
return None
288
289
289
- def _open_driver_cb (self , interface_desc_view ):
290
- # Singleton callback from TinyUSB custom class driver
291
- pass
290
+ def _open_cb (self , interface_desc_view ):
291
+ # Singleton callback from TinyUSB custom class driver, when USB host does
292
+ # Set Configuration. The "runtime class device" accepts all interfaces that
293
+ # it has sent in descriptors, and calls this callback.
294
+
295
+ # Walk the view of the "claimed" descriptor data provided in the
296
+ # callback and call handle_open() on each claimed interface
297
+ #
298
+ # ... this may be unnecessary at the moment, as only one configuration is supported so we
299
+ # can probably assume all the interfaces will be included.
300
+ i = 0
301
+ while i < len (interface_desc_view ):
302
+ # descriptor length, type, and index (if it's an interface descriptor)
303
+ dl , dt , di = interface_desc_view [i : i + 3 ]
304
+ if dt == _STD_DESC_INTERFACE_TYPE :
305
+ if di >= self ._usbd .static .itf_max :
306
+ di -= self ._usbd .static .itf_max
307
+ self ._itfs [di ].handle_open ()
308
+ i += dl
309
+ assert dl
310
+
311
+ def _reset_cb (self ):
312
+ # Callback when the USB device is reset by the host
313
+
314
+ # Cancel outstanding transfer callbacks
315
+ for k in self ._ep_cbs .keys ():
316
+ self ._ep_cbs [k ] = None
317
+
318
+ # Allow interfaces to respond to the reset
319
+ for itf in self ._itfs :
320
+ itf .handle_reset ()
292
321
293
322
def _submit_xfer (self , ep_addr , data , done_cb = None ):
294
323
# Singleton function to submit a USB transfer (of any type except control).
@@ -387,6 +416,7 @@ def __init__(
387
416
self .bInterfaceSubClass = bInterfaceSubClass
388
417
self .bInterfaceProtocol = bInterfaceProtocol
389
418
self .interface_str = interface_str
419
+ self ._open = False
390
420
391
421
def get_itf_descriptor (self , num_eps , itf_idx , str_idx ):
392
422
# Return the interface descriptor binary data and associated other
@@ -421,7 +451,7 @@ def get_itf_descriptor(self, num_eps, itf_idx, str_idx):
421
451
# (indexes in the descriptor data should start from 'str_idx'.)
422
452
#
423
453
# See USB 2.0 specification section 9.6.5 p267 for standard interface descriptors.
424
- desc = ustruct .pack (
454
+ desc = struct .pack (
425
455
"<" + "B" * _STD_DESC_INTERFACE_LEN ,
426
456
_STD_DESC_INTERFACE_LEN , # bLength
427
457
_STD_DESC_INTERFACE_TYPE , # bDescriptorType
@@ -466,6 +496,30 @@ def get_endpoint_descriptors(self, ep_addr, str_idx):
466
496
# start from ep_addr, optionally with the utils.EP_IN_FLAG bit set.)
467
497
return (b"" , [], [])
468
498
499
+ def handle_open (self ):
500
+ # Callback called when the USB host accepts the device configuration.
501
+ #
502
+ # Override this function to initiate any operations that the USB interface
503
+ # should do when the USB device is configured to the host.
504
+ self ._open = True
505
+
506
+ def handle_reset (self ):
507
+ # Callback called on every registered interface when the USB device is
508
+ # reset by the host. This can happen when the USB device is unplugged,
509
+ # or if the host triggers a reset for some other reason.
510
+ #
511
+ # Override this function to cancel any pending operations specific to
512
+ # the interface (outstanding USB transfers are already cancelled).
513
+ #
514
+ # At this point, no USB functionality is available - handle_open() will
515
+ # be called later if/when the USB host re-enumerates and configures the
516
+ # interface.
517
+ self ._open = False
518
+
519
+ def is_open (self ):
520
+ # Returns True if the interface is in use
521
+ return self ._open
522
+
469
523
def handle_device_control_xfer (self , stage , request ):
470
524
# Control transfer callback. Override to handle a non-standard device
471
525
# control transfer where bmRequestType Recipient is Device, Type is
@@ -486,11 +540,11 @@ def handle_device_control_xfer(self, stage, request):
486
540
# The function can call split_bmRequestType() to split bmRequestType into
487
541
# (Recipient, Type, Direction).
488
542
#
489
- # Result:
543
+ # Result, any of :
490
544
#
491
- # - True to continue the request False to STALL the endpoint A buffer
492
- # - interface object to provide a buffer to the host as part of the
493
- # - transfer, if possible.
545
+ # - True to continue the request, False to STALL the endpoint.
546
+ # - Buffer interface object to provide a buffer to the host as part of the
547
+ # transfer, if possible.
494
548
return False
495
549
496
550
def handle_interface_control_xfer (self , stage , request ):
@@ -512,7 +566,8 @@ def handle_interface_control_xfer(self, stage, request):
512
566
def handle_endpoint_control_xfer (self , stage , request ):
513
567
# Control transfer callback. Override to handle a device
514
568
# control transfer where bmRequestType Recipient is Endpoint and
515
- # the lower byte of wIndex indicates an endpoint address associated with this interface.
569
+ # the lower byte of wIndex indicates an endpoint address associated
570
+ # with this interface.
516
571
#
517
572
# bmRequestType Type will generally have any value except
518
573
# utils.REQ_TYPE_STANDARD, as Standard endpoint requests are handled by
@@ -546,4 +601,25 @@ def submit_xfer(self, ep_addr, data, done_cb=None):
546
601
#
547
602
# Note that done_cb may be called immediately, possibly before this
548
603
# function has returned to the caller.
604
+ if not self ._open :
605
+ raise RuntimeError
549
606
return get_usbdevice ()._submit_xfer (ep_addr , data , done_cb )
607
+
608
+ def set_ep_stall (self , ep_addr , stall ):
609
+ # Set or clear endpoint STALL state, according to the bool "stall" parameter.
610
+ #
611
+ # Generally endpoint STALL is handled automatically by TinyUSB, but
612
+ # there are some device classes that need to explicitly stall or unstall
613
+ # an endpoint under certain conditions.
614
+ if not self ._open or ep_addr not in get_usbdevice ()._eps :
615
+ raise RuntimeError
616
+ get_usbdevice ()._usbd .set_ep_stall (ep_addr , stall )
617
+
618
+ def get_ep_stall (self , ep_addr ):
619
+ # Get the current endpoint STALL state.
620
+ #
621
+ # Endpoint can be stalled/unstalled by host, TinyUSB stack, or calls to
622
+ # set_ep_stall().
623
+ if not self ._open or ep_addr not in get_usbdevice ()._eps :
624
+ raise RuntimeError
625
+ return get_usbdevice ()._usbd .get_ep_stall (ep_addr )
0 commit comments