Skip to content

Commit 4a8ac3d

Browse files
Add support for shared USB Serial, Keyboard, Mouse (earlephilhower#132)
Use a shared infrastructure based on TinyUSB, allow users to use sketches with ported Arduino Keyboard and Mouse libraries.
1 parent 9c17986 commit 4a8ac3d

File tree

9 files changed

+460
-140
lines changed

9 files changed

+460
-140
lines changed

.gitmodules

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,3 +16,9 @@
1616
[submodule "pico-extras"]
1717
path = pico-extras
1818
url = https://github.com/raspberrypi/pico-extras.git
19+
[submodule "libraries/Keyboard"]
20+
path = libraries/Keyboard
21+
url = https://github.com/earlephilhower/Keyboard
22+
[submodule "libraries/Mouse"]
23+
path = libraries/Mouse
24+
url = https://github.com/earlephilhower/Mouse

cores/rp2040/SerialUSB.cpp

Lines changed: 13 additions & 139 deletions
Original file line numberDiff line numberDiff line change
@@ -32,128 +32,20 @@
3232
#include "hardware/watchdog.h"
3333
#include "pico/unique_id.h"
3434

35+
#ifndef DISABLE_USB_SERIAL
36+
// Ensure we are installed in the USB chain
37+
void __USBInstallSerial() { /* noop */ }
38+
#endif
39+
3540
// SerialEvent functions are weak, so when the user doesn't define them,
3641
// the linker just sets their address to 0 (which is checked below).
3742
// The Serialx_available is just a wrapper around Serialx.available(),
3843
// but we can refer to it weakly so we don't pull in the entire
3944
// HardwareSerial instance if the user doesn't also refer to it.
4045
extern void serialEvent() __attribute__((weak));
4146

42-
#define PICO_STDIO_USB_TASK_INTERVAL_US 1000
43-
#define PICO_STDIO_USB_LOW_PRIORITY_IRQ 31
44-
45-
#define USBD_VID (0x2E8A) // Raspberry Pi
46-
47-
#ifdef SERIALUSB_PID
48-
#define USBD_PID (SERIALUSB_PID)
49-
#else
50-
#define USBD_PID (0x000a) // Raspberry Pi Pico SDK CDC
51-
#endif
52-
53-
#define USBD_DESC_LEN (TUD_CONFIG_DESC_LEN + TUD_CDC_DESC_LEN)
54-
#define USBD_MAX_POWER_MA (250)
55-
56-
#define USBD_ITF_CDC (0) // needs 2 interfaces
57-
#define USBD_ITF_MAX (2)
58-
59-
#define USBD_CDC_EP_CMD (0x81)
60-
#define USBD_CDC_EP_OUT (0x02)
61-
#define USBD_CDC_EP_IN (0x82)
62-
#define USBD_CDC_CMD_MAX_SIZE (8)
63-
#define USBD_CDC_IN_OUT_MAX_SIZE (64)
64-
65-
#define USBD_STR_0 (0x00)
66-
#define USBD_STR_MANUF (0x01)
67-
#define USBD_STR_PRODUCT (0x02)
68-
#define USBD_STR_SERIAL (0x03)
69-
#define USBD_STR_CDC (0x04)
70-
71-
// Note: descriptors returned from callbacks must exist long enough for transfer to complete
72-
73-
static const tusb_desc_device_t usbd_desc_device = {
74-
.bLength = sizeof(tusb_desc_device_t),
75-
.bDescriptorType = TUSB_DESC_DEVICE,
76-
.bcdUSB = 0x0200,
77-
.bDeviceClass = TUSB_CLASS_CDC,
78-
.bDeviceSubClass = MISC_SUBCLASS_COMMON,
79-
.bDeviceProtocol = MISC_PROTOCOL_IAD,
80-
.bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE,
81-
.idVendor = USBD_VID,
82-
.idProduct = USBD_PID,
83-
.bcdDevice = 0x0100,
84-
.iManufacturer = USBD_STR_MANUF,
85-
.iProduct = USBD_STR_PRODUCT,
86-
.iSerialNumber = USBD_STR_SERIAL,
87-
.bNumConfigurations = 1,
88-
};
89-
90-
static const uint8_t usbd_desc_cfg[USBD_DESC_LEN] = {
91-
TUD_CONFIG_DESCRIPTOR(1, USBD_ITF_MAX, USBD_STR_0, USBD_DESC_LEN,
92-
TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP, USBD_MAX_POWER_MA),
93-
94-
TUD_CDC_DESCRIPTOR(USBD_ITF_CDC, USBD_STR_CDC, USBD_CDC_EP_CMD,
95-
USBD_CDC_CMD_MAX_SIZE, USBD_CDC_EP_OUT, USBD_CDC_EP_IN, USBD_CDC_IN_OUT_MAX_SIZE),
96-
};
97-
98-
static char _idString[PICO_UNIQUE_BOARD_ID_SIZE_BYTES * 2 + 1];
99-
100-
static const char *const usbd_desc_str[] = {
101-
[USBD_STR_0] = "",
102-
[USBD_STR_MANUF] = "Raspberry Pi",
103-
[USBD_STR_PRODUCT] = "PicoArduino",
104-
[USBD_STR_SERIAL] = _idString,
105-
[USBD_STR_CDC] = "Board CDC",
106-
};
107-
108-
const uint8_t *tud_descriptor_device_cb(void) {
109-
return (const uint8_t *)&usbd_desc_device;
110-
}
111-
112-
const uint8_t *tud_descriptor_configuration_cb(uint8_t index) {
113-
(void)index;
114-
return usbd_desc_cfg;
115-
}
116-
117-
const uint16_t *tud_descriptor_string_cb(uint8_t index, uint16_t langid) {
118-
#define DESC_STR_MAX (20)
119-
static uint16_t desc_str[DESC_STR_MAX];
120-
121-
uint8_t len;
122-
if (index == 0) {
123-
desc_str[1] = 0x0409; // supported language is English
124-
len = 1;
125-
} else {
126-
if (index >= sizeof(usbd_desc_str) / sizeof(usbd_desc_str[0])) {
127-
return NULL;
128-
}
129-
const char *str = usbd_desc_str[index];
130-
for (len = 0; len < DESC_STR_MAX - 1 && str[len]; ++len) {
131-
desc_str[1 + len] = str[len];
132-
}
133-
}
134-
135-
// first byte is length (including header), second byte is string type
136-
desc_str[0] = (TUSB_DESC_STRING << 8) | (2 * len + 2);
13747

138-
return desc_str;
139-
}
140-
141-
static mutex_t usb_mutex;
142-
143-
static void low_priority_worker_irq() {
144-
// if the mutex is already owned, then we are in user code
145-
// in this file which will do a tud_task itself, so we'll just do nothing
146-
// until the next tick; we won't starve
147-
if (mutex_try_enter(&usb_mutex, NULL)) {
148-
tud_task();
149-
mutex_exit(&usb_mutex);
150-
}
151-
}
152-
153-
static int64_t timer_task(__unused alarm_id_t id, __unused void *user_data) {
154-
irq_set_pending(PICO_STDIO_USB_LOW_PRIORITY_IRQ);
155-
return PICO_STDIO_USB_TASK_INTERVAL_US;
156-
}
48+
extern mutex_t __usb_mutex;
15749

15850
void SerialUSB::begin(unsigned long baud) {
15951
(void) baud; //ignored
@@ -162,24 +54,6 @@ void SerialUSB::begin(unsigned long baud) {
16254
return;
16355
}
16456

165-
// Get ID string into human readable serial number
166-
pico_unique_board_id_t id;
167-
pico_get_unique_board_id(&id);
168-
_idString[0] = 0;
169-
for (auto i = 0; i < PICO_UNIQUE_BOARD_ID_SIZE_BYTES; i++) {
170-
char hx[3];
171-
sprintf(hx, "%02X", id.id[i]);
172-
strcat(_idString, hx);
173-
}
174-
175-
tusb_init();
176-
177-
irq_set_exclusive_handler(PICO_STDIO_USB_LOW_PRIORITY_IRQ, low_priority_worker_irq);
178-
irq_set_enabled(PICO_STDIO_USB_LOW_PRIORITY_IRQ, true);
179-
180-
mutex_init(&usb_mutex);
181-
add_alarm_in_us(PICO_STDIO_USB_TASK_INTERVAL_US, timer_task, NULL, true);
182-
18357
_running = true;
18458
}
18559

@@ -188,7 +62,7 @@ void SerialUSB::end() {
18862
}
18963

19064
int SerialUSB::peek() {
191-
CoreMutex m(&usb_mutex);
65+
CoreMutex m(&__usb_mutex);
19266
if (!_running || !m) {
19367
return 0;
19468
}
@@ -198,7 +72,7 @@ int SerialUSB::peek() {
19872
}
19973

20074
int SerialUSB::read() {
201-
CoreMutex m(&usb_mutex);
75+
CoreMutex m(&__usb_mutex);
20276
if (!_running || !m) {
20377
return -1;
20478
}
@@ -210,7 +84,7 @@ int SerialUSB::read() {
21084
}
21185

21286
int SerialUSB::available() {
213-
CoreMutex m(&usb_mutex);
87+
CoreMutex m(&__usb_mutex);
21488
if (!_running || !m) {
21589
return 0;
21690
}
@@ -219,7 +93,7 @@ int SerialUSB::available() {
21993
}
22094

22195
int SerialUSB::availableForWrite() {
222-
CoreMutex m(&usb_mutex);
96+
CoreMutex m(&__usb_mutex);
22397
if (!_running || !m) {
22498
return 0;
22599
}
@@ -228,7 +102,7 @@ int SerialUSB::availableForWrite() {
228102
}
229103

230104
void SerialUSB::flush() {
231-
CoreMutex m(&usb_mutex);
105+
CoreMutex m(&__usb_mutex);
232106
if (!_running || !m) {
233107
return;
234108
}
@@ -241,7 +115,7 @@ size_t SerialUSB::write(uint8_t c) {
241115
}
242116

243117
size_t SerialUSB::write(const uint8_t *buf, size_t length) {
244-
CoreMutex m(&usb_mutex);
118+
CoreMutex m(&__usb_mutex);
245119
if (!_running || !m) {
246120
return 0;
247121
}
@@ -276,7 +150,7 @@ size_t SerialUSB::write(const uint8_t *buf, size_t length) {
276150
}
277151

278152
SerialUSB::operator bool() {
279-
CoreMutex m(&usb_mutex);
153+
CoreMutex m(&__usb_mutex);
280154
if (!_running || !m) {
281155
return false;
282156
}

0 commit comments

Comments
 (0)