Skip to content

Commit f1ad79b

Browse files
committed
more usb.core.Device vid/pid error handling
This fixes a bug where common_hal_usb_core_device_get_idVendor() and common_hal_usb_core_device_get_idProduct() were ignoring the error check boolean returned by tuh_vid_pid_get(). Also, this includes a workaround for what appears to be a TinyUSB glitch with enumeration and assigning addresses. By adding a 50 ms background task loop before raising the exception after a TinyUSB failure result, somehow the vid/pid error condition magically goes away on it's own. Something subtle and weird is happening here which could use further investigation.
1 parent 42b53b7 commit f1ad79b

File tree

2 files changed

+27
-3
lines changed

2 files changed

+27
-3
lines changed

shared-module/usb/core/Device.c

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -68,17 +68,32 @@ void common_hal_usb_core_device_deinit(usb_core_device_obj_t *self) {
6868
self->device_address = 0;
6969
}
7070

71+
static void _wait_then_raise_USBError(int errno) {
72+
// 1. Spin for 50 ms in a background task loop because some USB glitches
73+
// will magically clear up if you just wait for a bit
74+
// 2. Raise the exception so the calling code knows it needs to try again
75+
const uint32_t end = supervisor_ticks_ms32() + 50;
76+
while (supervisor_ticks_ms32() < end && !mp_hal_is_interrupted()) {
77+
RUN_BACKGROUND_TASKS;
78+
}
79+
mp_raise_usb_core_USBError(errno);
80+
}
81+
7182
uint16_t common_hal_usb_core_device_get_idVendor(usb_core_device_obj_t *self) {
7283
uint16_t vid;
7384
uint16_t pid;
74-
tuh_vid_pid_get(self->device_address, &vid, &pid);
85+
if (!tuh_vid_pid_get(self->device_address, &vid, &pid)) {
86+
_wait_then_raise_USBError(USB_CORE_VID_PID_GET);
87+
}
7588
return vid;
7689
}
7790

7891
uint16_t common_hal_usb_core_device_get_idProduct(usb_core_device_obj_t *self) {
7992
uint16_t vid;
8093
uint16_t pid;
81-
tuh_vid_pid_get(self->device_address, &vid, &pid);
94+
if (!tuh_vid_pid_get(self->device_address, &vid, &pid)) {
95+
_wait_then_raise_USBError(USB_CORE_VID_PID_GET);
96+
}
8297
return pid;
8398
}
8499

@@ -135,7 +150,15 @@ static size_t _handle_timed_transfer_callback(tuh_xfer_t *xfer, mp_int_t timeout
135150
case XFER_RESULT_SUCCESS:
136151
return _actual_len;
137152
case XFER_RESULT_FAILED:
138-
mp_raise_usb_core_USBError(USB_CORE_XFER_FAIL);
153+
// TODO: swap this for mp_raise_usb_core_USBError if TinyUSB can be
154+
// improved to prevent a series of failures when usb.core.find() is called
155+
// in a tight loop after a device has been unplugged.
156+
//
157+
// This workaround adds a delay before raising the exception because, for
158+
// mysterious as-yet unknown reasons, that seems to let TinyUSB clear up
159+
// whatever fault condition is triggered by unplugging a device.
160+
//
161+
_wait_then_raise_USBError(USB_CORE_XFER_FAIL);
139162
break;
140163
case XFER_RESULT_STALLED:
141164
mp_raise_usb_core_USBError(USB_CORE_STALLED);

shared-module/usb/core/Device.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,3 +43,4 @@ typedef struct {
4343
#define USB_CORE_EDPT_XFER (7)
4444
#define USB_CORE_OPEN_ENDPOINT (8)
4545
#define USB_CORE_CONTROL_XFER (9)
46+
#define USB_CORE_VID_PID_GET (10)

0 commit comments

Comments
 (0)