Skip to content

Commit 982b55c

Browse files
committed
run TinyUSB tasks more aggressively
This attempts to fix a problem where a Fruit Jam board crashes if you access the CIRCUITPY drive while it's rapidly polling a gamepad using usb.core.Device.read(). The fix is incomplete.
1 parent 1a6c2b9 commit 982b55c

File tree

2 files changed

+45
-5
lines changed

2 files changed

+45
-5
lines changed

shared-bindings/usb/core/__init__.c

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616
#include "shared-bindings/usb/core/__init__.h"
1717
#include "shared-bindings/usb/core/Device.h"
1818

19+
#include "lib/tinyusb/src/tusb.h"
20+
1921
//| """USB Core
2022
//|
2123
//| This is a subset of the PyUSB core module.
@@ -74,9 +76,14 @@ typedef struct {
7476

7577
// This is an internal iterator type to use with find.
7678
static mp_obj_t _next_device(usb_core_devices_obj_t *iter) {
79+
// Force TinyUSB tasks to run (RUN_BACKGROUND_TASKS does not work for this)
80+
#if CIRCUITPY_USB_DEVICE
81+
tud_task();
82+
#endif
83+
tuh_task();
7784
// Brute force check all possible device numbers for one that matches.
7885
usb_core_device_obj_t temp_device;
79-
for (size_t i = iter->next_index; i < 256; i++) {
86+
for (size_t i = iter->next_index; i <= CFG_TUH_DEVICE_MAX + CFG_TUH_HUB; i++) {
8087
if (!common_hal_usb_core_device_construct(&temp_device, i)) {
8188
continue;
8289
}

shared-module/usb/core/Device.c

Lines changed: 37 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
#include "tusb_config.h"
1111

12+
#include "lib/tinyusb/src/tusb.h"
1213
#include "lib/tinyusb/src/host/hcd.h"
1314
#include "lib/tinyusb/src/host/usbh.h"
1415
#include "py/runtime.h"
@@ -31,9 +32,24 @@ void tuh_umount_cb(uint8_t dev_addr) {
3132
_mounted_devices &= ~(1 << dev_addr);
3233
}
3334

35+
static void _force_tinyusb_tasks_to_run(void) {
36+
// TinyUSB uses state machines and task queues that require tud_task()
37+
// and tuh_task() to be called very frequently. If you try to use tuh_* API
38+
// functions when something interesting has happened (device unplugged, etc),
39+
// things can go badly wrong if you wait too long to call the task runners.
40+
// For example, although RUN_BACKGROUND_TASKS schedules TinyUSB background
41+
// tasks at 1024 Hz, that doesn't seem to be sufficient if you're rapidly
42+
// polling usb.core.Device.read().
43+
#if CIRCUITPY_USB_DEVICE
44+
tud_task();
45+
#endif
46+
tuh_task();
47+
}
48+
3449
static xfer_result_t _xfer_result;
3550
static size_t _actual_len;
3651
bool common_hal_usb_core_device_construct(usb_core_device_obj_t *self, uint8_t device_address) {
52+
_force_tinyusb_tasks_to_run();
3753
if (!tuh_inited()) {
3854
mp_raise_RuntimeError(MP_ERROR_TEXT("No usb host port initialized"));
3955
}
@@ -58,6 +74,7 @@ void common_hal_usb_core_device_deinit(usb_core_device_obj_t *self) {
5874
if (common_hal_usb_core_device_deinited(self)) {
5975
return;
6076
}
77+
_force_tinyusb_tasks_to_run();
6178
size_t open_size = sizeof(self->open_endpoints);
6279
for (size_t i = 0; i < open_size; i++) {
6380
if (self->open_endpoints[i] != 0) {
@@ -66,11 +83,13 @@ void common_hal_usb_core_device_deinit(usb_core_device_obj_t *self) {
6683
}
6784
}
6885
self->device_address = 0;
86+
_force_tinyusb_tasks_to_run();
6987
}
7088

7189
uint16_t common_hal_usb_core_device_get_idVendor(usb_core_device_obj_t *self) {
7290
uint16_t vid;
7391
uint16_t pid;
92+
_force_tinyusb_tasks_to_run();
7493
if (!tuh_vid_pid_get(self->device_address, &vid, &pid)) {
7594
mp_raise_usb_core_USBError(NULL);
7695
}
@@ -80,6 +99,7 @@ uint16_t common_hal_usb_core_device_get_idVendor(usb_core_device_obj_t *self) {
8099
uint16_t common_hal_usb_core_device_get_idProduct(usb_core_device_obj_t *self) {
81100
uint16_t vid;
82101
uint16_t pid;
102+
_force_tinyusb_tasks_to_run();
83103
if (!tuh_vid_pid_get(self->device_address, &vid, &pid)) {
84104
mp_raise_usb_core_USBError(NULL);
85105
}
@@ -97,8 +117,8 @@ static void _transfer_done_cb(tuh_xfer_t *xfer) {
97117
static bool _wait_for_callback(void) {
98118
while (!mp_hal_is_interrupted() &&
99119
_xfer_result == XFER_RESULT_INVALID) {
100-
// The background tasks include TinyUSB which will call the function
101-
// we provided above. In other words, the callback isn't in an interrupt.
120+
// The background tasks include TinyUSB which will call _transfer_done_cb().
121+
// In other words, the callback isn't in an interrupt.
102122
RUN_BACKGROUND_TASKS;
103123
}
104124
if (mp_hal_is_interrupted()) {
@@ -142,8 +162,8 @@ static size_t _handle_timed_transfer_callback(tuh_xfer_t *xfer, mp_int_t timeout
142162
while ((timeout == 0 || supervisor_ticks_ms32() - start_time < (uint32_t)timeout) &&
143163
!mp_hal_is_interrupted() &&
144164
_xfer_result == XFER_RESULT_INVALID) {
145-
// The background tasks include TinyUSB which will call the function
146-
// we provided above. In other words, the callback isn't in an interrupt.
165+
// The background tasks include TinyUSB which will call _transfer_done_cb().
166+
// In other words, the callback isn't in an interrupt.
147167
RUN_BACKGROUND_TASKS;
148168
}
149169
if (mp_hal_is_interrupted()) {
@@ -203,6 +223,7 @@ static void _get_langid(usb_core_device_obj_t *self) {
203223
mp_obj_t common_hal_usb_core_device_get_serial_number(usb_core_device_obj_t *self) {
204224
uint16_t temp_buf[127];
205225
tusb_desc_device_t descriptor;
226+
_force_tinyusb_tasks_to_run();
206227
// First, be sure not to ask TinyUSB for a non-existent string (avoid error)
207228
if (!tuh_descriptor_get_device_local(self->device_address, &descriptor)) {
208229
return mp_const_none;
@@ -224,6 +245,7 @@ mp_obj_t common_hal_usb_core_device_get_serial_number(usb_core_device_obj_t *sel
224245
mp_obj_t common_hal_usb_core_device_get_product(usb_core_device_obj_t *self) {
225246
uint16_t temp_buf[127];
226247
tusb_desc_device_t descriptor;
248+
_force_tinyusb_tasks_to_run();
227249
// First, be sure not to ask TinyUSB for a non-existent string (avoid error)
228250
if (!tuh_descriptor_get_device_local(self->device_address, &descriptor)) {
229251
return mp_const_none;
@@ -245,6 +267,7 @@ mp_obj_t common_hal_usb_core_device_get_product(usb_core_device_obj_t *self) {
245267
mp_obj_t common_hal_usb_core_device_get_manufacturer(usb_core_device_obj_t *self) {
246268
uint16_t temp_buf[127];
247269
tusb_desc_device_t descriptor;
270+
_force_tinyusb_tasks_to_run();
248271
// First, be sure not to ask TinyUSB for a non-existent string (avoid error)
249272
if (!tuh_descriptor_get_device_local(self->device_address, &descriptor)) {
250273
return mp_const_none;
@@ -266,6 +289,7 @@ mp_obj_t common_hal_usb_core_device_get_manufacturer(usb_core_device_obj_t *self
266289

267290
mp_int_t common_hal_usb_core_device_get_bus(usb_core_device_obj_t *self) {
268291
tuh_bus_info_t bus_info;
292+
_force_tinyusb_tasks_to_run();
269293
if (!tuh_bus_info_get(self->device_address, &bus_info)) {
270294
return 0;
271295
}
@@ -274,6 +298,7 @@ mp_int_t common_hal_usb_core_device_get_bus(usb_core_device_obj_t *self) {
274298

275299
mp_obj_t common_hal_usb_core_device_get_port_numbers(usb_core_device_obj_t *self) {
276300
tuh_bus_info_t bus_info;
301+
_force_tinyusb_tasks_to_run();
277302
if (!tuh_bus_info_get(self->device_address, &bus_info)) {
278303
return mp_const_none;
279304
}
@@ -297,6 +322,7 @@ mp_obj_t common_hal_usb_core_device_get_port_numbers(usb_core_device_obj_t *self
297322

298323
mp_int_t common_hal_usb_core_device_get_speed(usb_core_device_obj_t *self) {
299324
tuh_bus_info_t bus_info;
325+
_force_tinyusb_tasks_to_run();
300326
if (!tuh_bus_info_get(self->device_address, &bus_info)) {
301327
return 0;
302328
}
@@ -315,6 +341,7 @@ mp_int_t common_hal_usb_core_device_get_speed(usb_core_device_obj_t *self) {
315341
void common_hal_usb_core_device_set_configuration(usb_core_device_obj_t *self, mp_int_t configuration) {
316342
// We assume that the config index is one less than the value.
317343
uint8_t config_index = configuration - 1;
344+
_force_tinyusb_tasks_to_run();
318345
// Get the configuration descriptor and cache it. We'll use it later to open
319346
// endpoints.
320347

@@ -395,6 +422,7 @@ static bool _open_endpoint(usb_core_device_obj_t *self, mp_int_t endpoint) {
395422
}
396423

397424
mp_int_t common_hal_usb_core_device_write(usb_core_device_obj_t *self, mp_int_t endpoint, const uint8_t *buffer, mp_int_t len, mp_int_t timeout) {
425+
_force_tinyusb_tasks_to_run();
398426
if (!_open_endpoint(self, endpoint)) {
399427
mp_raise_usb_core_USBError(NULL);
400428
return 0;
@@ -408,6 +436,7 @@ mp_int_t common_hal_usb_core_device_write(usb_core_device_obj_t *self, mp_int_t
408436
}
409437

410438
mp_int_t common_hal_usb_core_device_read(usb_core_device_obj_t *self, mp_int_t endpoint, uint8_t *buffer, mp_int_t len, mp_int_t timeout) {
439+
_force_tinyusb_tasks_to_run();
411440
if (!_open_endpoint(self, endpoint)) {
412441
mp_raise_usb_core_USBError(NULL);
413442
return 0;
@@ -441,6 +470,7 @@ mp_int_t common_hal_usb_core_device_ctrl_transfer(usb_core_device_obj_t *self,
441470
.complete_cb = _transfer_done_cb,
442471
};
443472

473+
_force_tinyusb_tasks_to_run();
444474
_prepare_for_transfer();
445475
if (!tuh_control_xfer(&xfer)) {
446476
mp_raise_usb_core_USBError(NULL);
@@ -450,6 +480,7 @@ mp_int_t common_hal_usb_core_device_ctrl_transfer(usb_core_device_obj_t *self,
450480
}
451481

452482
bool common_hal_usb_core_device_is_kernel_driver_active(usb_core_device_obj_t *self, mp_int_t interface) {
483+
_force_tinyusb_tasks_to_run();
453484
#if CIRCUITPY_USB_KEYBOARD_WORKFLOW
454485
if (usb_keyboard_in_use(self->device_address, interface)) {
455486
return true;
@@ -459,12 +490,14 @@ bool common_hal_usb_core_device_is_kernel_driver_active(usb_core_device_obj_t *s
459490
}
460491

461492
void common_hal_usb_core_device_detach_kernel_driver(usb_core_device_obj_t *self, mp_int_t interface) {
493+
_force_tinyusb_tasks_to_run();
462494
#if CIRCUITPY_USB_KEYBOARD_WORKFLOW
463495
usb_keyboard_detach(self->device_address, interface);
464496
#endif
465497
}
466498

467499
void common_hal_usb_core_device_attach_kernel_driver(usb_core_device_obj_t *self, mp_int_t interface) {
500+
_force_tinyusb_tasks_to_run();
468501
#if CIRCUITPY_USB_KEYBOARD_WORKFLOW
469502
usb_keyboard_attach(self->device_address, interface);
470503
#endif

0 commit comments

Comments
 (0)