Skip to content

Commit cda7d8f

Browse files
Initial refactoring into USB class
Clean up and make the USB subsystem design into a class instead of a collection of C functions which share static local state.
1 parent 97169d2 commit cda7d8f

File tree

14 files changed

+209
-264
lines changed

14 files changed

+209
-264
lines changed

cores/rp2040/RP2040USB.cpp

Lines changed: 81 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -34,13 +34,21 @@
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
3948
mutex_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

247255
static uint16_t _forceVID = 0;
248256
static 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

254262
static uint8_t _forceManuf = 0;
255263
static uint8_t _forceProd = 0;
256264
static 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

267275
static 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;
445474
static 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

cores/rp2040/RP2040USB.h

Lines changed: 54 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -19,56 +19,72 @@
1919
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
2020
*/
2121

22+
#pragma once
23+
2224
#include <pico/mutex.h>
23-
#include <limits.h>
25+
//#include <limits.h>
2426

25-
// Called by an object at global init time to register a HID device, returns a localID to be mapped using findHIDReportID
26-
// vidMask is the bits in the VID that should be XOR'd when this device is present.
27-
// 0 means don't invert anything, OTW select a single bitmask 1<<n.
28-
uint8_t usbRegisterHIDDevice(const uint8_t *descriptor, size_t len, int ordering, uint32_t vidMask);
27+
#ifdef __cplusplus
2928

30-
// Remove a HID device from the USB descriptor. Only call after usbDisconnect or results could be unpredictable!
31-
void usbUnregisterHIDDevice(unsigned int localid);
29+
class RP2040USB {
30+
public:
31+
RP2040USB() { }
3232

33-
// Called by an object at global init time to add a new interface (non-HID, like CDC or Picotool)
34-
uint8_t usbRegisterInterface(int interfaces, const uint8_t *descriptor, size_t len, int ordering, uint32_t vidMask);
33+
// Called by an object at global init time to register a HID device, returns a localID to be mapped using findHIDReportID
34+
// vidMask is the bits in the VID that should be XOR'd when this device is present.
35+
// 0 means don't invert anything, OTW select a single bitmask 1<<n.
36+
uint8_t registerHIDDevice(const uint8_t *descriptor, size_t len, int ordering, uint32_t vidMask);
3537

36-
// Remove a USB interface from the USB descriptor. Only call after usbDisconnect or results could be unpredictable!
37-
void usbUnregisterInterface(unsigned int localid);
38+
// Remove a HID device from the USB descriptor. Only call after usbDisconnect or results could be unpredictable!
39+
void unregisterHIDDevice(unsigned int localid);
3840

39-
// Get the USB HID actual report ID from the localid
40-
uint8_t usbFindHIDReportID(unsigned int localid);
41+
// Called by an object at global init time to add a new interface (non-HID, like CDC or Picotool)
42+
uint8_t registerInterface(int interfaces, const uint8_t *descriptor, size_t len, int ordering, uint32_t vidMask);
4143

42-
// Get the USB interface number from the localid
43-
uint8_t usbFindInterfaceID(unsigned int localid);
44+
// Remove a USB interface from the USB descriptor. Only call after usbDisconnect or results could be unpredictable!
45+
void unregisterInterface(unsigned int localid);
4446

45-
// Register a string for a USB descriptor
46-
uint8_t usbRegisterString(const char *str);
47+
// Get the USB HID actual report ID from the localid
48+
uint8_t findHIDReportID(unsigned int localid);
4749

48-
// Get an unassigned in/cmd or out endpoint number
49-
uint8_t usbRegisterEndpointIn();
50-
uint8_t usbRegisterEndpointOut();
51-
void usbUnregisterEndpointIn(int ep);
52-
void usbUnregisterEndpointOut(int ep);
50+
// Get the USB interface number from the localid
51+
uint8_t findInterfaceID(unsigned int localid);
5352

54-
// Disconnects the USB connection to allow editing the HID/interface list
55-
void usbDisconnect();
53+
// Register a string for a USB descriptor
54+
uint8_t registerString(const char *str);
5655

57-
// Reconnects the USB connection to pick up the new descriptor
58-
void usbConnect();
56+
// Get an unassigned in/cmd or out endpoint number
57+
uint8_t registerEndpointIn();
58+
uint8_t registerEndpointOut();
59+
void unregisterEndpointIn(int ep);
60+
void unregisterEndpointOut(int ep);
5961

60-
// Override the hardcoded USB VID:PID, product, manufacturer, and serials
61-
void usbSetVIDPID(uint16_t vid, uint16_t pid);
62-
void usbSetManufacturer(const char *str);
63-
void usbSetProduct(const char *str);
64-
void usbSetSerialNumber(const char *str);
62+
// Disconnects the USB connection to allow editing the HID/interface list
63+
void disconnect();
6564

66-
// Big, global USB mutex, shared with all USB devices to make sure we don't
67-
// have multiple cores updating the TUSB state in parallel
68-
extern mutex_t __usb_mutex;
65+
// Reconnects the USB connection to pick up the new descriptor
66+
void connect();
67+
68+
// Override the hardcoded USB VID:PID, product, manufacturer, and serials
69+
void setVIDPID(uint16_t vid, uint16_t pid);
70+
void setManufacturer(const char *str);
71+
void setProduct(const char *str);
72+
void setSerialNumber(const char *str);
73+
74+
// Called by main() to init the USB HW/SW.
75+
void begin();
6976

70-
// Called by main() to init the USB HW/SW.
71-
void __USBStart();
77+
// Helper class for HID report sending with wait and timeout
78+
bool HIDReady();
7279

73-
// Helper class for HID report sending with wait and timeout
74-
bool __USBHIDReady();
80+
#ifdef __FREERTOS
81+
volatile bool initted = false;
82+
#endif
83+
};
84+
85+
extern RP2040USB USB;
86+
87+
#endif
88+
89+
// have multiple cores updating the TUSB state in parallel
90+
extern mutex_t __usb_mutex;

0 commit comments

Comments
 (0)