Add support for shared USB Serial, Keyboard, Mouse (#132)
Use a shared infrastructure based on TinyUSB, allow users to use sketches with ported Arduino Keyboard and Mouse libraries.
This commit is contained in:
parent
9c17986ae6
commit
4a8ac3d902
9 changed files with 460 additions and 140 deletions
6
.gitmodules
vendored
6
.gitmodules
vendored
|
|
@ -16,3 +16,9 @@
|
|||
[submodule "pico-extras"]
|
||||
path = pico-extras
|
||||
url = https://github.com/raspberrypi/pico-extras.git
|
||||
[submodule "libraries/Keyboard"]
|
||||
path = libraries/Keyboard
|
||||
url = https://github.com/earlephilhower/Keyboard
|
||||
[submodule "libraries/Mouse"]
|
||||
path = libraries/Mouse
|
||||
url = https://github.com/earlephilhower/Mouse
|
||||
|
|
|
|||
|
|
@ -32,6 +32,11 @@
|
|||
#include "hardware/watchdog.h"
|
||||
#include "pico/unique_id.h"
|
||||
|
||||
#ifndef DISABLE_USB_SERIAL
|
||||
// Ensure we are installed in the USB chain
|
||||
void __USBInstallSerial() { /* noop */ }
|
||||
#endif
|
||||
|
||||
// SerialEvent functions are weak, so when the user doesn't define them,
|
||||
// the linker just sets their address to 0 (which is checked below).
|
||||
// The Serialx_available is just a wrapper around Serialx.available(),
|
||||
|
|
@ -39,121 +44,8 @@
|
|||
// HardwareSerial instance if the user doesn't also refer to it.
|
||||
extern void serialEvent() __attribute__((weak));
|
||||
|
||||
#define PICO_STDIO_USB_TASK_INTERVAL_US 1000
|
||||
#define PICO_STDIO_USB_LOW_PRIORITY_IRQ 31
|
||||
|
||||
#define USBD_VID (0x2E8A) // Raspberry Pi
|
||||
|
||||
#ifdef SERIALUSB_PID
|
||||
#define USBD_PID (SERIALUSB_PID)
|
||||
#else
|
||||
#define USBD_PID (0x000a) // Raspberry Pi Pico SDK CDC
|
||||
#endif
|
||||
|
||||
#define USBD_DESC_LEN (TUD_CONFIG_DESC_LEN + TUD_CDC_DESC_LEN)
|
||||
#define USBD_MAX_POWER_MA (250)
|
||||
|
||||
#define USBD_ITF_CDC (0) // needs 2 interfaces
|
||||
#define USBD_ITF_MAX (2)
|
||||
|
||||
#define USBD_CDC_EP_CMD (0x81)
|
||||
#define USBD_CDC_EP_OUT (0x02)
|
||||
#define USBD_CDC_EP_IN (0x82)
|
||||
#define USBD_CDC_CMD_MAX_SIZE (8)
|
||||
#define USBD_CDC_IN_OUT_MAX_SIZE (64)
|
||||
|
||||
#define USBD_STR_0 (0x00)
|
||||
#define USBD_STR_MANUF (0x01)
|
||||
#define USBD_STR_PRODUCT (0x02)
|
||||
#define USBD_STR_SERIAL (0x03)
|
||||
#define USBD_STR_CDC (0x04)
|
||||
|
||||
// Note: descriptors returned from callbacks must exist long enough for transfer to complete
|
||||
|
||||
static const tusb_desc_device_t usbd_desc_device = {
|
||||
.bLength = sizeof(tusb_desc_device_t),
|
||||
.bDescriptorType = TUSB_DESC_DEVICE,
|
||||
.bcdUSB = 0x0200,
|
||||
.bDeviceClass = TUSB_CLASS_CDC,
|
||||
.bDeviceSubClass = MISC_SUBCLASS_COMMON,
|
||||
.bDeviceProtocol = MISC_PROTOCOL_IAD,
|
||||
.bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE,
|
||||
.idVendor = USBD_VID,
|
||||
.idProduct = USBD_PID,
|
||||
.bcdDevice = 0x0100,
|
||||
.iManufacturer = USBD_STR_MANUF,
|
||||
.iProduct = USBD_STR_PRODUCT,
|
||||
.iSerialNumber = USBD_STR_SERIAL,
|
||||
.bNumConfigurations = 1,
|
||||
};
|
||||
|
||||
static const uint8_t usbd_desc_cfg[USBD_DESC_LEN] = {
|
||||
TUD_CONFIG_DESCRIPTOR(1, USBD_ITF_MAX, USBD_STR_0, USBD_DESC_LEN,
|
||||
TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP, USBD_MAX_POWER_MA),
|
||||
|
||||
TUD_CDC_DESCRIPTOR(USBD_ITF_CDC, USBD_STR_CDC, USBD_CDC_EP_CMD,
|
||||
USBD_CDC_CMD_MAX_SIZE, USBD_CDC_EP_OUT, USBD_CDC_EP_IN, USBD_CDC_IN_OUT_MAX_SIZE),
|
||||
};
|
||||
|
||||
static char _idString[PICO_UNIQUE_BOARD_ID_SIZE_BYTES * 2 + 1];
|
||||
|
||||
static const char *const usbd_desc_str[] = {
|
||||
[USBD_STR_0] = "",
|
||||
[USBD_STR_MANUF] = "Raspberry Pi",
|
||||
[USBD_STR_PRODUCT] = "PicoArduino",
|
||||
[USBD_STR_SERIAL] = _idString,
|
||||
[USBD_STR_CDC] = "Board CDC",
|
||||
};
|
||||
|
||||
const uint8_t *tud_descriptor_device_cb(void) {
|
||||
return (const uint8_t *)&usbd_desc_device;
|
||||
}
|
||||
|
||||
const uint8_t *tud_descriptor_configuration_cb(uint8_t index) {
|
||||
(void)index;
|
||||
return usbd_desc_cfg;
|
||||
}
|
||||
|
||||
const uint16_t *tud_descriptor_string_cb(uint8_t index, uint16_t langid) {
|
||||
#define DESC_STR_MAX (20)
|
||||
static uint16_t desc_str[DESC_STR_MAX];
|
||||
|
||||
uint8_t len;
|
||||
if (index == 0) {
|
||||
desc_str[1] = 0x0409; // supported language is English
|
||||
len = 1;
|
||||
} else {
|
||||
if (index >= sizeof(usbd_desc_str) / sizeof(usbd_desc_str[0])) {
|
||||
return NULL;
|
||||
}
|
||||
const char *str = usbd_desc_str[index];
|
||||
for (len = 0; len < DESC_STR_MAX - 1 && str[len]; ++len) {
|
||||
desc_str[1 + len] = str[len];
|
||||
}
|
||||
}
|
||||
|
||||
// first byte is length (including header), second byte is string type
|
||||
desc_str[0] = (TUSB_DESC_STRING << 8) | (2 * len + 2);
|
||||
|
||||
return desc_str;
|
||||
}
|
||||
|
||||
static mutex_t usb_mutex;
|
||||
|
||||
static void low_priority_worker_irq() {
|
||||
// if the mutex is already owned, then we are in user code
|
||||
// in this file which will do a tud_task itself, so we'll just do nothing
|
||||
// until the next tick; we won't starve
|
||||
if (mutex_try_enter(&usb_mutex, NULL)) {
|
||||
tud_task();
|
||||
mutex_exit(&usb_mutex);
|
||||
}
|
||||
}
|
||||
|
||||
static int64_t timer_task(__unused alarm_id_t id, __unused void *user_data) {
|
||||
irq_set_pending(PICO_STDIO_USB_LOW_PRIORITY_IRQ);
|
||||
return PICO_STDIO_USB_TASK_INTERVAL_US;
|
||||
}
|
||||
extern mutex_t __usb_mutex;
|
||||
|
||||
void SerialUSB::begin(unsigned long baud) {
|
||||
(void) baud; //ignored
|
||||
|
|
@ -162,24 +54,6 @@ void SerialUSB::begin(unsigned long baud) {
|
|||
return;
|
||||
}
|
||||
|
||||
// Get ID string into human readable serial number
|
||||
pico_unique_board_id_t id;
|
||||
pico_get_unique_board_id(&id);
|
||||
_idString[0] = 0;
|
||||
for (auto i = 0; i < PICO_UNIQUE_BOARD_ID_SIZE_BYTES; i++) {
|
||||
char hx[3];
|
||||
sprintf(hx, "%02X", id.id[i]);
|
||||
strcat(_idString, hx);
|
||||
}
|
||||
|
||||
tusb_init();
|
||||
|
||||
irq_set_exclusive_handler(PICO_STDIO_USB_LOW_PRIORITY_IRQ, low_priority_worker_irq);
|
||||
irq_set_enabled(PICO_STDIO_USB_LOW_PRIORITY_IRQ, true);
|
||||
|
||||
mutex_init(&usb_mutex);
|
||||
add_alarm_in_us(PICO_STDIO_USB_TASK_INTERVAL_US, timer_task, NULL, true);
|
||||
|
||||
_running = true;
|
||||
}
|
||||
|
||||
|
|
@ -188,7 +62,7 @@ void SerialUSB::end() {
|
|||
}
|
||||
|
||||
int SerialUSB::peek() {
|
||||
CoreMutex m(&usb_mutex);
|
||||
CoreMutex m(&__usb_mutex);
|
||||
if (!_running || !m) {
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -198,7 +72,7 @@ int SerialUSB::peek() {
|
|||
}
|
||||
|
||||
int SerialUSB::read() {
|
||||
CoreMutex m(&usb_mutex);
|
||||
CoreMutex m(&__usb_mutex);
|
||||
if (!_running || !m) {
|
||||
return -1;
|
||||
}
|
||||
|
|
@ -210,7 +84,7 @@ int SerialUSB::read() {
|
|||
}
|
||||
|
||||
int SerialUSB::available() {
|
||||
CoreMutex m(&usb_mutex);
|
||||
CoreMutex m(&__usb_mutex);
|
||||
if (!_running || !m) {
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -219,7 +93,7 @@ int SerialUSB::available() {
|
|||
}
|
||||
|
||||
int SerialUSB::availableForWrite() {
|
||||
CoreMutex m(&usb_mutex);
|
||||
CoreMutex m(&__usb_mutex);
|
||||
if (!_running || !m) {
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -228,7 +102,7 @@ int SerialUSB::availableForWrite() {
|
|||
}
|
||||
|
||||
void SerialUSB::flush() {
|
||||
CoreMutex m(&usb_mutex);
|
||||
CoreMutex m(&__usb_mutex);
|
||||
if (!_running || !m) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -241,7 +115,7 @@ size_t SerialUSB::write(uint8_t c) {
|
|||
}
|
||||
|
||||
size_t SerialUSB::write(const uint8_t *buf, size_t length) {
|
||||
CoreMutex m(&usb_mutex);
|
||||
CoreMutex m(&__usb_mutex);
|
||||
if (!_running || !m) {
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -276,7 +150,7 @@ size_t SerialUSB::write(const uint8_t *buf, size_t length) {
|
|||
}
|
||||
|
||||
SerialUSB::operator bool() {
|
||||
CoreMutex m(&usb_mutex);
|
||||
CoreMutex m(&__usb_mutex);
|
||||
if (!_running || !m) {
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
317
cores/rp2040/USB.cpp
Normal file
317
cores/rp2040/USB.cpp
Normal file
|
|
@ -0,0 +1,317 @@
|
|||
/*
|
||||
* Shared USB for the Raspberry Pi Pico RP2040
|
||||
* Allows for multiple endpoints to share the USB controller
|
||||
*
|
||||
* Copyright (c) 2021 Earle F. Philhower, III <earlephilhower@yahoo.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <Arduino.h>
|
||||
#include "CoreMutex.h"
|
||||
|
||||
#include "tusb.h"
|
||||
#include "class/hid/hid_device.h"
|
||||
#include "class/audio/audio.h"
|
||||
#include "class/midi/midi.h"
|
||||
#include "pico/time.h"
|
||||
#include "pico/binary_info.h"
|
||||
#include "pico/bootrom.h"
|
||||
#include "hardware/irq.h"
|
||||
#include "pico/mutex.h"
|
||||
#include "hardware/watchdog.h"
|
||||
#include "pico/unique_id.h"
|
||||
|
||||
// Weak function definitions for each type of endpoint
|
||||
extern void __USBInstallSerial() __attribute__((weak));
|
||||
extern void __USBInstallKeyboard() __attribute__((weak));
|
||||
extern void __USBInstallMouse() __attribute__((weak));
|
||||
extern void __USBInstallMIDI() __attribute__((weak));
|
||||
|
||||
#define PICO_STDIO_USB_TASK_INTERVAL_US 1000
|
||||
#define PICO_STDIO_USB_LOW_PRIORITY_IRQ 31
|
||||
|
||||
#define USBD_VID (0x2E8A) // Raspberry Pi
|
||||
|
||||
#ifdef SERIALUSB_PID
|
||||
#define USBD_PID (SERIALUSB_PID)
|
||||
#else
|
||||
#define USBD_PID (0x000a) // Raspberry Pi Pico SDK CDC
|
||||
#endif
|
||||
|
||||
#define USBD_DESC_LEN (TUD_CONFIG_DESC_LEN + TUD_CDC_DESC_LEN)
|
||||
#define USBD_MAX_POWER_MA (250)
|
||||
|
||||
#define USBD_ITF_CDC (0) // needs 2 interfaces
|
||||
#define USBD_ITF_MAX (2)
|
||||
|
||||
#define USBD_CDC_EP_CMD (0x81)
|
||||
#define USBD_CDC_EP_OUT (0x02)
|
||||
#define USBD_CDC_EP_IN (0x82)
|
||||
#define USBD_CDC_CMD_MAX_SIZE (8)
|
||||
#define USBD_CDC_IN_OUT_MAX_SIZE (64)
|
||||
|
||||
#define USBD_STR_0 (0x00)
|
||||
#define USBD_STR_MANUF (0x01)
|
||||
#define USBD_STR_PRODUCT (0x02)
|
||||
#define USBD_STR_SERIAL (0x03)
|
||||
#define USBD_STR_CDC (0x04)
|
||||
|
||||
|
||||
#define EPNUM_HID 0x83
|
||||
|
||||
|
||||
#define EPNUM_MIDI 0x01
|
||||
|
||||
|
||||
static char _idString[PICO_UNIQUE_BOARD_ID_SIZE_BYTES * 2 + 1];
|
||||
|
||||
static const char *const usbd_desc_str[] = {
|
||||
[USBD_STR_0] = "",
|
||||
[USBD_STR_MANUF] = "Raspberry Pi",
|
||||
[USBD_STR_PRODUCT] = "PicoArduino",
|
||||
[USBD_STR_SERIAL] = _idString,
|
||||
[USBD_STR_CDC] = "Board CDC",
|
||||
};
|
||||
|
||||
extern "C" const uint8_t *tud_descriptor_device_cb(void) {
|
||||
static tusb_desc_device_t usbd_desc_device = {
|
||||
.bLength = sizeof(tusb_desc_device_t),
|
||||
.bDescriptorType = TUSB_DESC_DEVICE,
|
||||
.bcdUSB = 0x0200,
|
||||
.bDeviceClass = TUSB_CLASS_CDC,
|
||||
.bDeviceSubClass = MISC_SUBCLASS_COMMON,
|
||||
.bDeviceProtocol = MISC_PROTOCOL_IAD,
|
||||
.bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE,
|
||||
.idVendor = USBD_VID,
|
||||
.idProduct = USBD_PID,
|
||||
.bcdDevice = 0x0100,
|
||||
.iManufacturer = USBD_STR_MANUF,
|
||||
.iProduct = USBD_STR_PRODUCT,
|
||||
.iSerialNumber = USBD_STR_SERIAL,
|
||||
.bNumConfigurations = 1
|
||||
};
|
||||
if (__USBInstallSerial && !__USBInstallKeyboard && !__USBInstallMouse && !__USBInstallMIDI) {
|
||||
// Can use as-is, this is the default USB case
|
||||
return (const uint8_t *)&usbd_desc_device;
|
||||
}
|
||||
// Need a multi-endpoint config which will require changing the PID to help Windows not barf
|
||||
if (__USBInstallKeyboard) {
|
||||
usbd_desc_device.idProduct |= 0x8000;
|
||||
}
|
||||
if (__USBInstallMouse) {
|
||||
usbd_desc_device.idProduct |= 0x4000;
|
||||
}
|
||||
if (__USBInstallMIDI) {
|
||||
usbd_desc_device.idProduct |= 0x2000;
|
||||
}
|
||||
// Set the device class to 0 to indicate multiple device classes
|
||||
usbd_desc_device.bDeviceClass = 0;
|
||||
usbd_desc_device.bDeviceSubClass = 0;
|
||||
usbd_desc_device.bDeviceProtocol = 0;
|
||||
return (const uint8_t *)&usbd_desc_device;
|
||||
}
|
||||
|
||||
int __GetMouseReportID() {
|
||||
return __USBInstallKeyboard ? 2 : 1;
|
||||
}
|
||||
|
||||
static uint8_t *GetDescHIDReport(int *len) {
|
||||
if (__USBInstallKeyboard && __USBInstallMouse) {
|
||||
static uint8_t desc_hid_report[] = {
|
||||
TUD_HID_REPORT_DESC_KEYBOARD( HID_REPORT_ID(1) ),
|
||||
TUD_HID_REPORT_DESC_MOUSE ( HID_REPORT_ID(2) )
|
||||
};
|
||||
if (len) {
|
||||
*len = sizeof(desc_hid_report);
|
||||
}
|
||||
return desc_hid_report;
|
||||
} else if (__USBInstallKeyboard && ! __USBInstallMouse) {
|
||||
static uint8_t desc_hid_report[] = {
|
||||
TUD_HID_REPORT_DESC_KEYBOARD( HID_REPORT_ID(1) )
|
||||
};
|
||||
if (len) {
|
||||
*len = sizeof(desc_hid_report);
|
||||
}
|
||||
return desc_hid_report;
|
||||
} else { // if (!__USBInstallKeyboard && __USBInstallMouse) {
|
||||
static uint8_t desc_hid_report[] = {
|
||||
TUD_HID_REPORT_DESC_MOUSE( HID_REPORT_ID(1) )
|
||||
};
|
||||
if (len) {
|
||||
*len = sizeof(desc_hid_report);
|
||||
}
|
||||
return desc_hid_report;
|
||||
}
|
||||
}
|
||||
|
||||
// Invoked when received GET HID REPORT DESCRIPTOR
|
||||
// Application return pointer to descriptor
|
||||
// Descriptor contents must exist long enough for transfer to complete
|
||||
extern "C" uint8_t const * tud_hid_descriptor_report_cb(void)
|
||||
{
|
||||
return GetDescHIDReport(nullptr);
|
||||
}
|
||||
|
||||
|
||||
const uint8_t *tud_descriptor_configuration_cb(uint8_t index) {
|
||||
(void)index;
|
||||
int len = 0;
|
||||
static uint8_t *usbd_desc_cfg;
|
||||
|
||||
if (!usbd_desc_cfg) {
|
||||
bool hasHID = __USBInstallKeyboard || __USBInstallMouse;
|
||||
|
||||
uint8_t interface_count = (__USBInstallSerial ? 2 : 0) + (hasHID ? 1 : 0) + (__USBInstallMIDI ? 2 : 0);
|
||||
|
||||
static uint8_t cdc_desc[TUD_CDC_DESC_LEN] = {
|
||||
// Interface number, string index, protocol, report descriptor len, EP In & Out address, size & polling interval
|
||||
TUD_CDC_DESCRIPTOR(USBD_ITF_CDC, USBD_STR_CDC, USBD_CDC_EP_CMD, USBD_CDC_CMD_MAX_SIZE, USBD_CDC_EP_OUT, USBD_CDC_EP_IN, USBD_CDC_IN_OUT_MAX_SIZE)
|
||||
};
|
||||
|
||||
int hid_report_len;
|
||||
GetDescHIDReport(&hid_report_len);
|
||||
uint8_t hid_itf = __USBInstallSerial ? 2 : 0;
|
||||
static uint8_t hid_desc[TUD_HID_DESC_LEN] = {
|
||||
// Interface number, string index, protocol, report descriptor len, EP In & Out address, size & polling interval
|
||||
TUD_HID_DESCRIPTOR(hid_itf, 0, HID_PROTOCOL_NONE, hid_report_len, EPNUM_HID, CFG_TUD_HID_EP_BUFSIZE, 10)
|
||||
};
|
||||
|
||||
uint8_t midi_itf = hid_itf + (hasHID ? 1 : 0);
|
||||
static uint8_t midi_desc[TUD_MIDI_DESC_LEN] = {
|
||||
// Interface number, string index, EP Out & EP In address, EP size
|
||||
TUD_MIDI_DESCRIPTOR(midi_itf, 0, EPNUM_MIDI, 0x80 | EPNUM_MIDI, 64)
|
||||
};
|
||||
|
||||
int usbd_desc_len = TUD_CONFIG_DESC_LEN + (__USBInstallSerial ? sizeof(cdc_desc) : 0) + (hasHID ? sizeof(hid_desc) : 0) + (__USBInstallMIDI ? sizeof(midi_desc) : 0);
|
||||
|
||||
static uint8_t tud_cfg_desc[TUD_CONFIG_DESC_LEN] = {
|
||||
// Config number, interface count, string index, total length, attribute, power in mA
|
||||
TUD_CONFIG_DESCRIPTOR(1, interface_count, USBD_STR_0, usbd_desc_len, TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP, USBD_MAX_POWER_MA)
|
||||
};
|
||||
|
||||
// Combine to one descriptor
|
||||
usbd_desc_cfg = (uint8_t *)malloc(usbd_desc_len);
|
||||
bzero(usbd_desc_cfg, usbd_desc_len);
|
||||
uint8_t *ptr = usbd_desc_cfg;
|
||||
memcpy(ptr, tud_cfg_desc, sizeof(tud_cfg_desc));
|
||||
ptr += sizeof(tud_cfg_desc);
|
||||
if (__USBInstallSerial) {
|
||||
memcpy(ptr, cdc_desc, sizeof(cdc_desc));
|
||||
ptr += sizeof(cdc_desc);
|
||||
}
|
||||
if (hasHID) {
|
||||
memcpy(ptr, hid_desc, sizeof(hid_desc));
|
||||
ptr += sizeof(hid_desc);
|
||||
}
|
||||
if (__USBInstallMIDI) {
|
||||
memcpy(ptr, midi_desc, sizeof(midi_desc));
|
||||
}
|
||||
}
|
||||
return usbd_desc_cfg;
|
||||
}
|
||||
|
||||
const uint16_t *tud_descriptor_string_cb(uint8_t index, uint16_t langid) {
|
||||
#define DESC_STR_MAX (20)
|
||||
static uint16_t desc_str[DESC_STR_MAX];
|
||||
|
||||
uint8_t len;
|
||||
if (index == 0) {
|
||||
desc_str[1] = 0x0409; // supported language is English
|
||||
len = 1;
|
||||
} else {
|
||||
if (index >= sizeof(usbd_desc_str) / sizeof(usbd_desc_str[0])) {
|
||||
return NULL;
|
||||
}
|
||||
const char *str = usbd_desc_str[index];
|
||||
for (len = 0; len < DESC_STR_MAX - 1 && str[len]; ++len) {
|
||||
desc_str[1 + len] = str[len];
|
||||
}
|
||||
}
|
||||
|
||||
// first byte is length (including header), second byte is string type
|
||||
desc_str[0] = (TUSB_DESC_STRING << 8) | (2 * len + 2);
|
||||
|
||||
return desc_str;
|
||||
}
|
||||
|
||||
mutex_t __usb_mutex;
|
||||
|
||||
static void low_priority_worker_irq() {
|
||||
// if the mutex is already owned, then we are in user code
|
||||
// in this file which will do a tud_task itself, so we'll just do nothing
|
||||
// until the next tick; we won't starve
|
||||
if (mutex_try_enter(&__usb_mutex, NULL)) {
|
||||
tud_task();
|
||||
mutex_exit(&__usb_mutex);
|
||||
}
|
||||
}
|
||||
|
||||
static int64_t timer_task(__unused alarm_id_t id, __unused void *user_data) {
|
||||
irq_set_pending(PICO_STDIO_USB_LOW_PRIORITY_IRQ);
|
||||
return PICO_STDIO_USB_TASK_INTERVAL_US;
|
||||
}
|
||||
|
||||
void __StartUSB() {
|
||||
if (tusb_inited()) {
|
||||
// Already called
|
||||
return;
|
||||
}
|
||||
|
||||
// Get ID string into human readable serial number
|
||||
pico_unique_board_id_t id;
|
||||
pico_get_unique_board_id(&id);
|
||||
_idString[0] = 0;
|
||||
for (auto i = 0; i < PICO_UNIQUE_BOARD_ID_SIZE_BYTES; i++) {
|
||||
char hx[3];
|
||||
sprintf(hx, "%02X", id.id[i]);
|
||||
strcat(_idString, hx);
|
||||
}
|
||||
|
||||
mutex_init(&__usb_mutex);
|
||||
tusb_init();
|
||||
|
||||
irq_set_exclusive_handler(PICO_STDIO_USB_LOW_PRIORITY_IRQ, low_priority_worker_irq);
|
||||
irq_set_enabled(PICO_STDIO_USB_LOW_PRIORITY_IRQ, true);
|
||||
|
||||
add_alarm_in_us(PICO_STDIO_USB_TASK_INTERVAL_US, timer_task, NULL, true);
|
||||
}
|
||||
|
||||
|
||||
// Invoked when received GET_REPORT control request
|
||||
// Application must fill buffer report's content and return its length.
|
||||
// Return zero will cause the stack to STALL request
|
||||
uint16_t tud_hid_get_report_cb(uint8_t report_id, hid_report_type_t report_type, uint8_t* buffer, uint16_t reqlen)
|
||||
{
|
||||
// TODO not Implemented
|
||||
(void) report_id;
|
||||
(void) report_type;
|
||||
(void) buffer;
|
||||
(void) reqlen;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Invoked when received SET_REPORT control request or
|
||||
// received data on OUT endpoint ( Report ID = 0, Type = 0 )
|
||||
void tud_hid_set_report_cb(uint8_t report_id, hid_report_type_t report_type, uint8_t const* buffer, uint16_t bufsize)
|
||||
{
|
||||
// TODO set LED based on CAPLOCK, NUMLOCK etc...
|
||||
(void) report_id;
|
||||
(void) report_type;
|
||||
(void) buffer;
|
||||
(void) bufsize;
|
||||
}
|
||||
|
||||
|
|
@ -52,6 +52,8 @@ static void main1() {
|
|||
}
|
||||
}
|
||||
|
||||
extern void __StartUSB();
|
||||
|
||||
extern "C" int main() {
|
||||
#if F_CPU != 125000000
|
||||
set_sys_clock_khz(F_CPU / 1000, true);
|
||||
|
|
@ -59,6 +61,7 @@ extern "C" int main() {
|
|||
|
||||
mutex_init(&_pioMutex);
|
||||
initVariant();
|
||||
__StartUSB();
|
||||
|
||||
#ifndef DISABLE_USB_SERIAL
|
||||
// Enable serial port for reset/upload always
|
||||
|
|
|
|||
BIN
lib/libpico.a
BIN
lib/libpico.a
Binary file not shown.
1
libraries/Keyboard
Submodule
1
libraries/Keyboard
Submodule
|
|
@ -0,0 +1 @@
|
|||
Subproject commit b29ed09525169dcbe2964eb332780a14f2c5f466
|
||||
1
libraries/Mouse
Submodule
1
libraries/Mouse
Submodule
|
|
@ -0,0 +1 @@
|
|||
Subproject commit 7c824ec29c75dac6393d3fb18f0dd474bc270113
|
||||
|
|
@ -23,6 +23,8 @@ target_compile_options(pico PUBLIC
|
|||
$<$<COMPILE_LANGUAGE:CXX>:-fno-rtti>
|
||||
)
|
||||
|
||||
include_directories(BEFORE ${PICO_SDK_PATH}/../tools/libpico)
|
||||
|
||||
target_link_libraries(pico
|
||||
boot_stage2
|
||||
hardware_adc
|
||||
|
|
@ -63,10 +65,10 @@ target_link_libraries(pico
|
|||
pico_platform
|
||||
pico_runtime
|
||||
pico_standard_link
|
||||
pico_stdio_usb
|
||||
pico_stdlib
|
||||
pico_unique_id
|
||||
tinyusb
|
||||
tinyusb_device_unmarked
|
||||
pico_audio
|
||||
pico_audio_i2s
|
||||
)
|
||||
|
|
|
|||
116
tools/libpico/tusb_config.h
Normal file
116
tools/libpico/tusb_config.h
Normal file
|
|
@ -0,0 +1,116 @@
|
|||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2019 Ha Thach (tinyusb.org)
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _TUSB_CONFIG_H_
|
||||
#define _TUSB_CONFIG_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// COMMON CONFIGURATION
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
// defined by board.mk
|
||||
#ifndef CFG_TUSB_MCU
|
||||
#error CFG_TUSB_MCU must be defined
|
||||
#endif
|
||||
|
||||
// RHPort number used for device can be defined by board.mk, default to port 0
|
||||
#ifndef BOARD_DEVICE_RHPORT_NUM
|
||||
#define BOARD_DEVICE_RHPORT_NUM 0
|
||||
#endif
|
||||
|
||||
// RHPort max operational speed can defined by board.mk
|
||||
// Default to Highspeed for MCU with internal HighSpeed PHY (can be port specific), otherwise FullSpeed
|
||||
#ifndef BOARD_DEVICE_RHPORT_SPEED
|
||||
#if (CFG_TUSB_MCU == OPT_MCU_LPC18XX || CFG_TUSB_MCU == OPT_MCU_LPC43XX || CFG_TUSB_MCU == OPT_MCU_MIMXRT10XX || \
|
||||
CFG_TUSB_MCU == OPT_MCU_NUC505 || CFG_TUSB_MCU == OPT_MCU_CXD56)
|
||||
#define BOARD_DEVICE_RHPORT_SPEED OPT_MODE_HIGH_SPEED
|
||||
#else
|
||||
#define BOARD_DEVICE_RHPORT_SPEED OPT_MODE_FULL_SPEED
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Device mode with rhport and speed defined by board.mk
|
||||
#if BOARD_DEVICE_RHPORT_NUM == 0
|
||||
#define CFG_TUSB_RHPORT0_MODE (OPT_MODE_DEVICE | BOARD_DEVICE_RHPORT_SPEED)
|
||||
#elif BOARD_DEVICE_RHPORT_NUM == 1
|
||||
#define CFG_TUSB_RHPORT1_MODE (OPT_MODE_DEVICE | BOARD_DEVICE_RHPORT_SPEED)
|
||||
#else
|
||||
#error "Incorrect RHPort configuration"
|
||||
#endif
|
||||
|
||||
// This example doesn't use an RTOS
|
||||
//#define CFG_TUSB_OS OPT_OS_NONE
|
||||
|
||||
// CFG_TUSB_DEBUG is defined by compiler in DEBUG build
|
||||
// #define CFG_TUSB_DEBUG 0
|
||||
|
||||
/* USB DMA on some MCUs can only access a specific SRAM region with restriction on alignment.
|
||||
* Tinyusb use follows macros to declare transferring memory so that they can be put
|
||||
* into those specific section.
|
||||
* e.g
|
||||
* - CFG_TUSB_MEM SECTION : __attribute__ (( section(".usb_ram") ))
|
||||
* - CFG_TUSB_MEM_ALIGN : __attribute__ ((aligned(4)))
|
||||
*/
|
||||
#ifndef CFG_TUSB_MEM_SECTION
|
||||
#define CFG_TUSB_MEM_SECTION
|
||||
#endif
|
||||
|
||||
#ifndef CFG_TUSB_MEM_ALIGN
|
||||
#define CFG_TUSB_MEM_ALIGN __attribute__ ((aligned(4)))
|
||||
#endif
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// DEVICE CONFIGURATION
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
#ifndef CFG_TUD_ENDPOINT0_SIZE
|
||||
#define CFG_TUD_ENDPOINT0_SIZE 64
|
||||
#endif
|
||||
|
||||
//------------- CLASS -------------//
|
||||
#define CFG_TUD_HID (2)
|
||||
#define CFG_TUD_CDC (1)
|
||||
#define CFG_TUD_MSC (0)
|
||||
#define CFG_TUD_MIDI (1)
|
||||
#define CFG_TUD_VENDOR (0)
|
||||
|
||||
#define CFG_TUD_CDC_RX_BUFSIZE (256)
|
||||
#define CFG_TUD_CDC_TX_BUFSIZE (256)
|
||||
|
||||
#define CFG_TUD_MIDI_RX_BUFSIZE (64)
|
||||
#define CFG_TUD_MIDI_TX_BUFSIZE (64)
|
||||
|
||||
// HID buffer size Should be sufficient to hold ID (if any) + Data
|
||||
#define CFG_TUD_HID_EP_BUFSIZE (64)
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _TUSB_CONFIG_H_ */
|
||||
Loading…
Reference in a new issue