Skip to content

Commit edcd9d1

Browse files
Build USB descriptor from data structures, not code (#3107)
The USB descriptor and HID report descriptors were built in a hard-coded mess of code with lots of very brittle logic to ensure things lined up and were the right size. Weak functions were used to signal the core that different descriptors needed to be added, so things like the Keyboard library actually had changes done in the core proper. Move to a saner and more maintainable, global initialization stage process where global object descriptors can call a `register` function to plug in their own USB or HID descriptors to the core process.
1 parent 6f640bf commit edcd9d1

File tree

16 files changed

+288
-277
lines changed

16 files changed

+288
-277
lines changed

cores/rp2040/RP2040USB.cpp

Lines changed: 216 additions & 217 deletions
Large diffs are not rendered by default.

cores/rp2040/RP2040USB.h

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -20,29 +20,33 @@
2020
*/
2121

2222
#include <pico/mutex.h>
23+
#include <limits.h>
2324

24-
// Weak function definitions for each type of endpoint
25-
extern void __USBInstallSerial() __attribute__((weak));
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 = 0);
2629

27-
extern void __USBInstallKeyboard() __attribute__((weak));
30+
// Called by an object at global init time to add a new interface (non-HID, like CDC or Picotool)
31+
uint8_t usbRegisterInterface(int interfaces, const uint8_t *descriptor, size_t len, int ordering = INT_MAX, uint32_t vidMask = 0);
2832

29-
extern void __USBInstallJoystick() __attribute__((weak));
33+
// Get the USB HID actual report ID from the localid
34+
uint8_t usbFindHIDReportID(unsigned int localid);
3035

31-
// One or the other allowed, not both
32-
extern void __USBInstallMouse() __attribute__((weak));
33-
extern void __USBInstallAbsoluteMouse() __attribute__((weak));
36+
// Get the USB interface number from the localid
37+
uint8_t usbFindInterfaceID(unsigned int localid);
3438

35-
extern void __USBInstallMassStorage() __attribute__((weak));
39+
// Register a string for a USB descriptor
40+
uint8_t usbRegisterString(const char *str);
41+
42+
// Get an unassigned in/cmd or out endpoint number
43+
uint8_t usbRegisterEndpointIn();
44+
uint8_t usbRegisterEndpointOut();
3645

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
extern mutex_t __usb_mutex;
4049

41-
// HID report ID inquiry (report ID will vary depending on the number/type of other HID)
42-
int __USBGetKeyboardReportID();
43-
int __USBGetMouseReportID();
44-
int __USBGetJoystickReportID();
45-
4650
// Called by main() to init the USB HW/SW.
4751
void __USBStart();
4852

cores/rp2040/SerialUSB.cpp

Lines changed: 16 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -23,22 +23,10 @@
2323
#if !defined(USE_TINYUSB) && !defined(NO_USB)
2424

2525
#include <Arduino.h>
26+
#include <tusb.h>
2627
#include "CoreMutex.h"
28+
#include "RP2040USB.h"
2729

28-
#include <tusb.h>
29-
#include <pico/time.h>
30-
#include <pico/binary_info.h>
31-
#include <pico/bootrom.h>
32-
#include <hardware/irq.h>
33-
#include <pico/mutex.h>
34-
#include <hardware/watchdog.h>
35-
#include <pico/unique_id.h>
36-
#include <hardware/resets.h>
37-
38-
#ifndef DISABLE_USB_SERIAL
39-
// Ensure we are installed in the USB chain
40-
void __USBInstallSerial() { /* noop */ }
41-
#endif
4230

4331
// SerialEvent functions are weak, so when the user doesn't define them,
4432
// the linker just sets their address to 0 (which is checked below).
@@ -47,9 +35,22 @@ void __USBInstallSerial() { /* noop */ }
4735
// HardwareSerial instance if the user doesn't also refer to it.
4836
extern void serialEvent() __attribute__((weak));
4937

50-
5138
extern mutex_t __usb_mutex;
5239

40+
#define USBD_CDC_CMD_MAX_SIZE (8)
41+
#define USBD_CDC_IN_OUT_MAX_SIZE (64)
42+
43+
44+
static const uint8_t cdc_desc[TUD_CDC_DESC_LEN] = {
45+
// Interface number, string index, protocol, report descriptor len, EP In & Out address, size & polling interval
46+
TUD_CDC_DESCRIPTOR(0 /* placeholder*/, usbRegisterString("Pico Serial"), usbRegisterEndpointIn(), USBD_CDC_CMD_MAX_SIZE, usbRegisterEndpointOut(), usbRegisterEndpointIn(), USBD_CDC_IN_OUT_MAX_SIZE)
47+
};
48+
49+
SerialUSB::SerialUSB() {
50+
_id = usbRegisterInterface(2, cdc_desc, sizeof(cdc_desc), 1, 0);
51+
}
52+
53+
5354
void SerialUSB::begin(unsigned long baud) {
5455
(void) baud; //ignored
5556

cores/rp2040/SerialUSB.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626

2727
class SerialUSB : public arduino::HardwareSerial {
2828
public:
29-
SerialUSB() { }
29+
SerialUSB();
3030
void begin(unsigned long baud = 115200) override;
3131
void begin(unsigned long baud, uint16_t config) override {
3232
(void) config;
@@ -56,6 +56,7 @@ class SerialUSB : public arduino::HardwareSerial {
5656
private:
5757
bool _running = false;
5858
bool _ignoreFlowControl = false;
59+
uint8_t _id;
5960
};
6061

6162
extern SerialUSB Serial;

libraries/FatFSUSB/src/FatFSUSB.cpp

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,15 +20,15 @@
2020
#include "FatFSUSB.h"
2121
#include <FatFS.h>
2222
#include <class/msc/msc.h>
23+
#include <device/usbd.h>
24+
#include <RP2040USB.h>
2325

2426
FatFSUSBClass FatFSUSB;
25-
26-
// Ensure we are logged in to the USB framework
27-
void __USBInstallMassStorage() {
28-
/* dummy */
29-
}
27+
#define USBD_MSC_EPSIZE 64
28+
static const uint8_t msd_desc[] = { TUD_MSC_DESCRIPTOR(1 /* placeholder */, 0, usbRegisterEndpointOut(), usbRegisterEndpointIn(), USBD_MSC_EPSIZE) };
3029

3130
FatFSUSBClass::FatFSUSBClass() {
31+
_id = usbRegisterInterface(2, msd_desc, sizeof(msd_desc), 1, 0);
3232
}
3333

3434
FatFSUSBClass::~FatFSUSBClass() {

libraries/FatFSUSB/src/FatFSUSB.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ class FatFSUSBClass {
4646

4747
private:
4848
bool _started = false;
49+
uint8_t _id;
4950

5051
int32_t _sectNum = -1;
5152
uint8_t *_sectBuff = nullptr;

libraries/Joystick/src/Joystick.cpp

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -28,20 +28,17 @@
2828
#include "tusb.h"
2929
#include "class/hid/hid_device.h"
3030

31-
// Weak function override to add our descriptor to the TinyUSB list
32-
void __USBInstallJoystick() { /* noop */ }
33-
31+
static const uint8_t desc_hid_report_joystick[] = { TUD_HID_REPORT_DESC_GAMEPAD16(HID_REPORT_ID(1)) };
3432
Joystick_::Joystick_(void) {
35-
// Everything set up in HID_Joystick constructor
33+
_id = usbRegisterHIDDevice(desc_hid_report_joystick, sizeof(desc_hid_report_joystick), 30, 0x0004);
3634
}
3735

38-
39-
//immediately send an HID report
36+
// immediately send an HID report
4037
void Joystick_::send_now(void) {
4138
CoreMutex m(&__usb_mutex);
4239
tud_task();
4340
if (__USBHIDReady()) {
44-
tud_hid_n_report(0, __USBGetJoystickReportID(), &data, sizeof(data));
41+
tud_hid_n_report(0, usbFindHIDReportID(_id), &data, sizeof(data));
4542
}
4643
tud_task();
4744
}

libraries/Joystick/src/Joystick.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,5 +32,7 @@ class Joystick_ : public HID_Joystick {
3232
public:
3333
Joystick_(void);
3434
virtual void send_now(void) override;
35+
private:
36+
uint8_t _id;
3537
};
3638
extern Joystick_ Joystick;

libraries/Keyboard/src/Keyboard.cpp

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,22 +26,23 @@
2626
#include "tusb.h"
2727
#include "class/hid/hid_device.h"
2828

29-
// Weak function override to add our descriptor to the TinyUSB list
30-
void __USBInstallKeyboard() { /* noop */ }
31-
3229
//================================================================================
3330
//================================================================================
3431
// Keyboard
3532

33+
static const uint8_t desc_hid_report_keyboard[] = { TUD_HID_REPORT_DESC_KEYBOARD(HID_REPORT_ID(1))};
34+
static const uint8_t desc_hid_report_consumer[] = { TUD_HID_REPORT_DESC_CONSUMER(HID_REPORT_ID(2))};
3635
Keyboard_::Keyboard_(void) {
36+
_id = usbRegisterHIDDevice(desc_hid_report_keyboard, sizeof(desc_hid_report_keyboard), 10, 0x0001);
37+
_idConsumer = usbRegisterHIDDevice(desc_hid_report_consumer, sizeof(desc_hid_report_consumer), 11, 0x0000);
3738
// Base class clears the members we care about
3839
}
3940

4041
void Keyboard_::sendReport(KeyReport* keys) {
4142
CoreMutex m(&__usb_mutex);
4243
tud_task();
4344
if (__USBHIDReady()) {
44-
tud_hid_keyboard_report(__USBGetKeyboardReportID(), keys->modifiers, keys->keys);
45+
tud_hid_keyboard_report(usbFindHIDReportID(_id), keys->modifiers, keys->keys);
4546
}
4647
tud_task();
4748
}
@@ -50,7 +51,7 @@ void Keyboard_::sendConsumerReport(uint16_t key) {
5051
CoreMutex m(&__usb_mutex);
5152
tud_task();
5253
if (__USBHIDReady()) {
53-
tud_hid_report(__USBGetKeyboardReportID() + 1, &key, sizeof(key));
54+
tud_hid_report(usbFindHIDReportID(_idConsumer), &key, sizeof(key));
5455
}
5556
tud_task();
5657
}

libraries/Keyboard/src/Keyboard.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ class Keyboard_ : public HID_Keyboard {
3232
protected:
3333
virtual void sendReport(KeyReport* keys) override;
3434
virtual void sendConsumerReport(uint16_t key) override;
35+
uint8_t _id;
36+
uint8_t _idConsumer;
3537

3638
public:
3739
Keyboard_(void);

0 commit comments

Comments
 (0)