3434#include < pico/usb_reset_interface.h>
3535#include < hardware/watchdog.h>
3636
37+ #ifdef __FREERTOS
38+ #include " FreeRTOS.h"
39+ #include " task.h"
40+ #include " timers.h"
41+ #include " semphr.h"
42+ #endif
43+
44+ RP2040USB USB;
45+
3746// Big, global USB mutex, shared with all USB devices to make sure we don't
3847// have multiple cores updating the TUSB state in parallel
3948mutex_t __usb_mutex;
4049
4150// USB processing will be a periodic timer task
4251#define USB_TASK_INTERVAL 1000
43- static int __usb_task_irq;
4452
4553#ifndef USBD_VID
4654#define USBD_VID (0x2E8A ) // Raspberry Pi
@@ -108,7 +116,7 @@ static int ffs(uint32_t v) {
108116 return 0 ;
109117}
110118
111- uint8_t usbRegisterEndpointIn () {
119+ uint8_t RP2040USB::registerEndpointIn () {
112120 if (!_endpointIn) {
113121 return 0 ; // ERROR, out of EPs
114122 }
@@ -117,11 +125,11 @@ uint8_t usbRegisterEndpointIn() {
117125 return 0x80 + firstFree;
118126}
119127
120- void usbUnregisterEndpointIn (int ep) {
128+ void RP2040USB::unregisterEndpointIn (int ep) {
121129 _endpointIn |= 1 << ep;
122130}
123131
124- uint8_t usbRegisterEndpointOut () {
132+ uint8_t RP2040USB::registerEndpointOut () {
125133 if (!_endpointOut) {
126134 return 0 ; // ERROR, out of EPs
127135 }
@@ -130,7 +138,7 @@ uint8_t usbRegisterEndpointOut() {
130138 return firstFree;
131139}
132140
133- void usbUnregisterEndpointOut (int ep) {
141+ void RP2040USB::unregisterEndpointOut (int ep) {
134142 _endpointOut |= (1 << (ep - 0x80 ));
135143}
136144
@@ -198,33 +206,33 @@ static unsigned int usbFindID(Entry *head, unsigned int localid) {
198206 return x;
199207}
200208
201- uint8_t usbFindHIDReportID (unsigned int localid) {
209+ uint8_t RP2040USB::findHIDReportID (unsigned int localid) {
202210 return usbFindID (_hids, localid) + 1 ; // HID reports start at 1
203211}
204212
205- uint8_t usbFindInterfaceID (unsigned int localid) {
213+ uint8_t RP2040USB::findInterfaceID (unsigned int localid) {
206214 return usbFindID (_interfaces, localid);
207215}
208216
209217// Called by a HID device to register a report. Returns the *local* ID which must be mapped to the HID report ID
210- uint8_t usbRegisterHIDDevice (const uint8_t *descriptor, size_t len, int ordering, uint32_t vidMask) {
218+ uint8_t RP2040USB::registerHIDDevice (const uint8_t *descriptor, size_t len, int ordering, uint32_t vidMask) {
211219 return AddEntry (&_hids, 0 , descriptor, len, ordering, vidMask);
212220}
213221
214- void usbUnregisterHIDDevice (unsigned int localid) {
222+ void RP2040USB::unregisterHIDDevice (unsigned int localid) {
215223 RemoveEntry (&_hids, localid);
216224}
217225
218226// Called by an object at global init time to add a new interface (non-HID, like CDC or Picotool)
219- uint8_t usbRegisterInterface (int interfaces, const uint8_t *descriptor, size_t len, int ordering, uint32_t vidMask) {
227+ uint8_t RP2040USB::registerInterface (int interfaces, const uint8_t *descriptor, size_t len, int ordering, uint32_t vidMask) {
220228 return AddEntry (&_interfaces, interfaces, descriptor, len, ordering, vidMask);
221229}
222230
223- void usbUnregisterInterface (unsigned int localid) {
231+ void RP2040USB::unregisterInterface (unsigned int localid) {
224232 RemoveEntry (&_interfaces, localid);
225233}
226234
227- uint8_t usbRegisterString (const char *str) {
235+ uint8_t RP2040USB::registerString (const char *str) {
228236 if (usbd_desc_str_alloc <= usbd_desc_str_cnt) {
229237 usbd_desc_str_alloc += 4 ;
230238 usbd_desc_str = (const char **)realloc (usbd_desc_str, usbd_desc_str_alloc * sizeof (usbd_desc_str[0 ]));
@@ -246,22 +254,22 @@ uint8_t usbRegisterString(const char *str) {
246254
247255static uint16_t _forceVID = 0 ;
248256static uint16_t _forcePID = 0 ;
249- void usbSetVIDPID (uint16_t vid, uint16_t pid) {
257+ void RP2040USB::setVIDPID (uint16_t vid, uint16_t pid) {
250258 _forceVID = vid;
251259 _forcePID = pid;
252260}
253261
254262static uint8_t _forceManuf = 0 ;
255263static uint8_t _forceProd = 0 ;
256264static uint8_t _forceSerial = 0 ;
257- void usbSetManufacturer (const char *str) {
258- _forceManuf = usbRegisterString (str);
265+ void RP2040USB::setManufacturer (const char *str) {
266+ _forceManuf = USB. registerString (str);
259267}
260- void usbSetProduct (const char *str) {
261- _forceProd = usbRegisterString (str);
268+ void RP2040USB::setProduct (const char *str) {
269+ _forceProd = USB. registerString (str);
262270}
263- void usbSetSerialNumber (const char *str) {
264- _forceSerial = usbRegisterString (str);
271+ void RP2040USB::setSerialNumber (const char *str) {
272+ _forceSerial = USB. registerString (str);
265273}
266274
267275static tusb_desc_device_t usbd_desc_device;
@@ -282,9 +290,9 @@ const uint8_t *tud_descriptor_device_cb(void) {
282290 .idVendor = _forceVID ? _forceVID : (uint16_t )USBD_VID,
283291 .idProduct = _forcePID ? _forcePID : (uint16_t )USBD_PID,
284292 .bcdDevice = 0x0100 ,
285- .iManufacturer = _forceManuf ? _forceManuf : usbRegisterString (USB_MANUFACTURER),
286- .iProduct = _forceProd ? _forceProd : usbRegisterString (USB_PRODUCT),
287- .iSerialNumber = _forceSerial ? _forceSerial : usbRegisterString (idString),
293+ .iManufacturer = _forceManuf ? _forceManuf : USB. registerString (USB_MANUFACTURER),
294+ .iProduct = _forceProd ? _forceProd : USB. registerString (USB_PRODUCT),
295+ .iSerialNumber = _forceSerial ? _forceSerial : USB. registerString (idString),
288296 .bNumConfigurations = 1
289297 };
290298
@@ -373,14 +381,14 @@ void __SetupUSBDescriptor() {
373381 if (GetDescHIDReport (&hid_report_len)) {
374382 uint8_t hid_desc[TUD_HID_DESC_LEN] = {
375383 // Interface number, string index, protocol, report descriptor len, EP In & Out address, size & polling interval
376- TUD_HID_DESCRIPTOR (1 /* placeholder*/ , 0 , HID_ITF_PROTOCOL_NONE, hid_report_len, __hid_endpoint = usbRegisterEndpointIn (), CFG_TUD_HID_EP_BUFSIZE, (uint8_t )usb_hid_poll_interval)
384+ TUD_HID_DESCRIPTOR (1 /* placeholder*/ , 0 , HID_ITF_PROTOCOL_NONE, hid_report_len, __hid_endpoint = USB. registerEndpointIn (), CFG_TUD_HID_EP_BUFSIZE, (uint8_t )usb_hid_poll_interval)
377385 };
378- __hid_interface = usbRegisterInterface (1 , hid_desc, sizeof (hid_desc), 10 , 0 );
386+ __hid_interface = USB. registerInterface (1 , hid_desc, sizeof (hid_desc), 10 , 0 );
379387 }
380388
381389#ifdef ENABLE_PICOTOOL_USB
382- uint8_t picotool_desc[] = { TUD_RPI_RESET_DESCRIPTOR (1 , usbRegisterString (" Reset" )) };
383- usbRegisterInterface (1 , picotool_desc, sizeof (picotool_desc), 100 , 0 );
390+ uint8_t picotool_desc[] = { TUD_RPI_RESET_DESCRIPTOR (1 , USB. registerString (" Reset" )) };
391+ USB. registerInterface (1 , picotool_desc, sizeof (picotool_desc), 100 , 0 );
384392#endif
385393
386394 usbd_desc_cfg_len = TUD_CONFIG_DESC_LEN; // Always have a config descriptor
@@ -393,7 +401,7 @@ void __SetupUSBDescriptor() {
393401
394402 uint8_t tud_cfg_desc[TUD_CONFIG_DESC_LEN] = {
395403 // Config number, interface count, string index, total length, attribute, power in mA
396- TUD_CONFIG_DESCRIPTOR (1 , interface_count, usbRegisterString (" " ), usbd_desc_cfg_len, TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP, USBD_MAX_POWER_MA)
404+ TUD_CONFIG_DESCRIPTOR (1 , interface_count, USB. registerString (" " ), usbd_desc_cfg_len, TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP, USBD_MAX_POWER_MA)
397405 };
398406
399407 // Allocate the "real" HID report descriptor
@@ -441,7 +449,28 @@ const uint16_t *tud_descriptor_string_cb(uint8_t index, uint16_t langid) {
441449 return desc_str;
442450}
443451
452+ #ifdef __FREERTOS
453+ void __freertos_usb_task (void *param) {
454+ (void ) param;
455+
456+ Serial.begin (115200 );
457+
458+ USB.initted = true ;
444459
460+ while (true ) {
461+ BaseType_t ss = xTaskGetSchedulerState ();
462+ if (ss != taskSCHEDULER_SUSPENDED) {
463+ auto m = __get_freertos_mutex_for_ptr (&__usb_mutex);
464+ if (xSemaphoreTake (m, 0 )) {
465+ tud_task ();
466+ xSemaphoreGive (m);
467+ }
468+ }
469+ vTaskDelay (1 / portTICK_PERIOD_MS);
470+ }
471+ }
472+ #else
473+ static int __usb_task_irq;
445474static void usb_irq () {
446475 // if the mutex is already owned, then we are in user code
447476 // in this file which will do a tud_task itself, so we'll just do nothing
@@ -456,34 +485,40 @@ static int64_t timer_task(__unused alarm_id_t id, __unused void *user_data) {
456485 irq_set_pending (__usb_task_irq);
457486 return USB_TASK_INTERVAL;
458487}
488+ #endif
459489
460- void usbDisconnect () {
490+ void RP2040USB::disconnect () {
491+ bool wasConnected = tud_connected ();
461492#ifdef __FREERTOS
462493 auto m = __get_freertos_mutex_for_ptr (&__usb_mutex);
463494 xSemaphoreTake (m, portMAX_DELAY);
464495 tud_disconnect ();
465- vTaskDelay (500 / portTICK_PERIOD_MS);
496+ if (wasConnected) {
497+ vTaskDelay (500 / portTICK_PERIOD_MS);
498+ }
466499 xSemaphoreGive (m);
467500#else
468501 mutex_enter_blocking (&__usb_mutex);
469502 tud_disconnect ();
470- sleep_ms (500 );
503+ if (wasConnected) {
504+ sleep_ms (500 );
505+ }
471506 mutex_exit (&__usb_mutex);
472507#endif
473508 // Ensure when we reconnect we make the new descriptor
474509 free (usbd_desc_cfg);
475510 usbd_desc_cfg = nullptr ;
476511 usbd_desc_cfg_len = 0 ;
477512 if (__hid_report) {
478- usbUnregisterInterface (__hid_interface);
479- usbUnregisterEndpointIn (__hid_endpoint);
513+ unregisterInterface (__hid_interface);
514+ unregisterEndpointIn (__hid_endpoint);
480515 }
481516 free (__hid_report);
482517 __hid_report = nullptr ;
483518 __hid_report_len = 0 ;
484519}
485520
486- void usbConnect () {
521+ void RP2040USB::connect () {
487522 __SetupDescHIDReport ();
488523 __SetupUSBDescriptor ();
489524
@@ -499,9 +534,12 @@ void usbConnect() {
499534#endif
500535}
501536
502- void __USBStart () __attribute__((weak));
503537
504- void __USBStart () {
538+
539+
540+
541+
542+ void RP2040USB::begin () {
505543 if (tusb_inited ()) {
506544 // Already called
507545 return ;
@@ -514,15 +552,21 @@ void __USBStart() {
514552
515553 tusb_init ();
516554
555+ #ifdef __FREERTOS
556+ // Make high prio and locked to core 0
557+ TaskHandle_t usbTask;
558+ xTaskCreate (__freertos_usb_task, " USB" , 256 , 0 , configMAX_PRIORITIES - 2 , &usbTask);
559+ vTaskCoreAffinitySet (usbTask, 1 << 0 );
560+ #else
517561 __usb_task_irq = user_irq_claim_unused (true );
518562 irq_set_exclusive_handler (__usb_task_irq, usb_irq);
519563 irq_set_enabled (__usb_task_irq, true );
520-
521564 add_alarm_in_us (USB_TASK_INTERVAL, timer_task, nullptr , true );
565+ #endif
522566}
523567
524568
525- bool __USBHIDReady () {
569+ bool RP2040USB::HIDReady () {
526570 uint32_t start = millis ();
527571 const uint32_t timeout = 500 ;
528572
0 commit comments