diff --git a/.github/workflows/githubci.yml b/.github/workflows/githubci.yml index 535a4d37..f6dd8dd4 100644 --- a/.github/workflows/githubci.yml +++ b/.github/workflows/githubci.yml @@ -9,6 +9,10 @@ jobs: fail-fast: false matrix: arduino-platform: + # ESP32S2 + - 'funhouse' + - 'magtag' + - 'metroesp32s2' # nRF52 - 'cpb' - 'nrf52840' diff --git a/README.md b/README.md index 0ac05a18..c04129ba 100644 --- a/README.md +++ b/README.md @@ -21,11 +21,14 @@ There are 2 type of supported cores: with and without built-in support for TinyU ### Cores with built-in support -Following core has Tinyusb as either the primary usb stack or selectable via menu `Tools->USB Stack`. You only need to include `` in your sketch to use. +Following core has TinyUSB as either the primary usb stack or selectable via menu `Tools->USB Stack`. You only need to include `` in your sketch to use. -- [Adafruit_nRF52_Arduino](https://github.com/adafruit/Adafruit_nRF52_Arduino) +- [adafruit/Adafruit_nRF52_Arduino](https://github.com/adafruit/Adafruit_nRF52_Arduino) - [adafruit/ArduinoCore-samd](https://github.com/adafruit/ArduinoCore-samd) - [earlephilhower/arduino-pico](https://github.com/earlephilhower/arduino-pico) +- [espressif/arduino-esp32](https://github.com/espressif/arduino-esp32) + + ESP32 port relies on Espressif's [esp32-hal-tinyusb.c](https://github.com/espressif/arduino-esp32/blob/master/cores/esp32/esp32-hal-tinyusb.c) for building usb descriptors which requires all descriptors must be specified in usb objects declaration i.e constructors. Therefore all descriptor-related fields must be part of object declaration and descriptor-related API have no effect afterwards for this port. ### Cores without built-in support diff --git a/changelog.md b/changelog.md index acfcd7b8..ed0e4654 100644 --- a/changelog.md +++ b/changelog.md @@ -1,5 +1,12 @@ # Adafruit TinyUSB Arduino Library Changelog +## 1.5.0 - 2021.09.29 + +- Add support for ESP32-S2 core version 2.0.0 + - ESP32 port relies on Espressif's [esp32-hal-tinyusb.c](https://github.com/espressif/arduino-esp32/blob/master/cores/esp32/esp32-hal-tinyusb.c) for building usb descriptors which requires all descriptors must be specified in usb objects declaration i.e constructors. Therefore all descriptor-related fields must be part of object declaration and descriptor-related API have no effect afterwards for this port. + +- Add new constructor for Adafruit_USBD_HID(desc_report, len, protocol, interval_ms, has_out_endpoint) + ## 1.4.4 - 2021.08.18 - Update tinyusb stack diff --git a/examples/MassStorage/msc_sd/.metroesp32s2_tinyusb.test.skip b/examples/CDC/cdc_multi/.funhouse.test.skip similarity index 100% rename from examples/MassStorage/msc_sd/.metroesp32s2_tinyusb.test.skip rename to examples/CDC/cdc_multi/.funhouse.test.skip diff --git a/examples/CDC/cdc_multi/.magtag.test.skip b/examples/CDC/cdc_multi/.magtag.test.skip new file mode 100644 index 00000000..e69de29b diff --git a/examples/CDC/cdc_multi/.metroesp32s2.test.skip b/examples/CDC/cdc_multi/.metroesp32s2.test.skip new file mode 100644 index 00000000..e69de29b diff --git a/examples/CDC/no_serial/.funhouse.test.skip b/examples/CDC/no_serial/.funhouse.test.skip new file mode 100644 index 00000000..e69de29b diff --git a/examples/CDC/no_serial/.magtag.test.skip b/examples/CDC/no_serial/.magtag.test.skip new file mode 100644 index 00000000..e69de29b diff --git a/examples/CDC/no_serial/.metroesp32s2.test.skip b/examples/CDC/no_serial/.metroesp32s2.test.skip new file mode 100644 index 00000000..e69de29b diff --git a/examples/Composite/mouse_external_flash/mouse_external_flash.ino b/examples/Composite/mouse_external_flash/mouse_external_flash.ino index 836cd695..e35dfa64 100644 --- a/examples/Composite/mouse_external_flash/mouse_external_flash.ino +++ b/examples/Composite/mouse_external_flash/mouse_external_flash.ino @@ -19,6 +19,10 @@ #include "Adafruit_SPIFlash.h" #include "Adafruit_TinyUSB.h" +//--------------------------------------------------------------------+ +// MSC External Flash Config +//--------------------------------------------------------------------+ + // Uncomment to run example with FRAM // #define FRAM_CS A5 // #define FRAM_SPI SPI @@ -51,6 +55,10 @@ Adafruit_SPIFlash flash(&flashTransport); Adafruit_USBD_MSC usb_msc; +//--------------------------------------------------------------------+ +// HID Config +//--------------------------------------------------------------------+ + // HID report descriptor using TinyUSB's template // Single Report (no ID) descriptor uint8_t const desc_hid_report[] = @@ -58,19 +66,28 @@ uint8_t const desc_hid_report[] = TUD_HID_REPORT_DESC_MOUSE() }; -Adafruit_USBD_HID usb_hid; +// USB HID object. For ESP32 these values cannot be changed after this declaration +// desc report, desc len, protocol, interval, use out endpoint +Adafruit_USBD_HID usb_hid(desc_hid_report, sizeof(desc_hid_report), HID_ITF_PROTOCOL_NONE, 2, false); -#if defined ARDUINO_SAMD_CIRCUITPLAYGROUND_EXPRESS +#if defined(ARDUINO_SAMD_CIRCUITPLAYGROUND_EXPRESS) || defined(ARDUINO_NRF52840_CIRCUITPLAY) const int pin = 4; // Left Button bool activeState = true; -#elif defined ARDUINO_NRF52840_FEATHER - const int pin = 7; // UserSw + +#elif defined(ARDUINO_FUNHOUSE_ESP32S2) + const int pin = BUTTON_DOWN; + bool activeState = true; + +#elif defined PIN_BUTTON1 + const int pin = PIN_BUTTON1; bool activeState = false; + #else const int pin = 12; bool activeState = false; #endif + // the setup function runs once when you press reset or power the board void setup() { @@ -92,11 +109,12 @@ void setup() usb_msc.begin(); - // Set up button pinMode(pin, activeState ? INPUT_PULLDOWN : INPUT_PULLUP); - usb_hid.setReportDescriptor(desc_hid_report, sizeof(desc_hid_report)); + // Notes: following commented-out functions has no affect on ESP32 + // usb_hid.setReportDescriptor(desc_hid_report, sizeof(desc_hid_report)); + usb_hid.begin(); Serial.begin(115200); diff --git a/examples/Composite/mouse_ramdisk/mouse_ramdisk.ino b/examples/Composite/mouse_ramdisk/mouse_ramdisk.ino index 034c01b4..37a48118 100644 --- a/examples/Composite/mouse_ramdisk/mouse_ramdisk.ino +++ b/examples/Composite/mouse_ramdisk/mouse_ramdisk.ino @@ -16,11 +16,21 @@ #include "Adafruit_TinyUSB.h" +//--------------------------------------------------------------------+ +// MSC RAM Disk Config +//--------------------------------------------------------------------+ + // 8KB is the smallest size that windows allow to mount #define DISK_BLOCK_NUM 16 #define DISK_BLOCK_SIZE 512 #include "ramdisk.h" +Adafruit_USBD_MSC usb_msc; + +//--------------------------------------------------------------------+ +// HID Config +//--------------------------------------------------------------------+ + // HID report descriptor using TinyUSB's template // Single Report (no ID) descriptor uint8_t const desc_hid_report[] = @@ -28,13 +38,18 @@ uint8_t const desc_hid_report[] = TUD_HID_REPORT_DESC_MOUSE() }; -Adafruit_USBD_HID usb_hid; -Adafruit_USBD_MSC usb_msc; +// USB HID object. For ESP32 these values cannot be changed after this declaration +// desc report, desc len, protocol, interval, use out endpoint +Adafruit_USBD_HID usb_hid(desc_hid_report, sizeof(desc_hid_report), HID_ITF_PROTOCOL_NONE, 2, false); -#if defined ARDUINO_SAMD_CIRCUITPLAYGROUND_EXPRESS || defined ARDUINO_NRF52840_CIRCUITPLAY +#if defined(ARDUINO_SAMD_CIRCUITPLAYGROUND_EXPRESS) || defined(ARDUINO_NRF52840_CIRCUITPLAY) const int pin = 4; // Left Button bool activeState = true; +#elif defined(ARDUINO_FUNHOUSE_ESP32S2) + const int pin = BUTTON_DOWN; + bool activeState = true; + #elif defined PIN_BUTTON1 const int pin = PIN_BUTTON1; bool activeState = false; @@ -69,7 +84,9 @@ void setup() // Set up button pinMode(pin, activeState ? INPUT_PULLDOWN : INPUT_PULLUP); - usb_hid.setReportDescriptor(desc_hid_report, sizeof(desc_hid_report)); + // Notes: following commented-out functions has no affect on ESP32 + // usb_hid.setReportDescriptor(desc_hid_report, sizeof(desc_hid_report)); + usb_hid.begin(); Serial.begin(115200); diff --git a/examples/HID/hid_boot_keyboard/hid_boot_keyboard.ino b/examples/HID/hid_boot_keyboard/hid_boot_keyboard.ino index 17dfac33..1c4054b9 100644 --- a/examples/HID/hid_boot_keyboard/hid_boot_keyboard.ino +++ b/examples/HID/hid_boot_keyboard/hid_boot_keyboard.ino @@ -10,11 +10,12 @@ *********************************************************************/ #include "Adafruit_TinyUSB.h" +#include /* This sketch demonstrates USB HID keyboard. * - PIN A0-A5 is used to send digit '0' to '5' respectively * (On the RP2040, pins D0-D5 used) - * - LED will be used as Caplock indicator + * - LED and/or Neopixels will be used as Capslock indicator */ // HID report descriptor using TinyUSB's template @@ -24,20 +25,46 @@ uint8_t const desc_hid_report[] = TUD_HID_REPORT_DESC_KEYBOARD() }; -Adafruit_USBD_HID usb_hid; +// USB HID object. For ESP32 these values cannot be changed after this declaration +// desc report, desc len, protocol, interval, use out endpoint +Adafruit_USBD_HID usb_hid(desc_hid_report, sizeof(desc_hid_report), HID_ITF_PROTOCOL_KEYBOARD, 2, false); -// Array of pins and its keycode -// For keycode definition see BLEHidGeneric.h +//------------- Input Pins -------------// +// Array of pins and its keycode. +// Notes: these pins can be replaced by PIN_BUTTONn if defined in setup() #ifdef ARDUINO_ARCH_RP2040 - uint8_t pins[] = { D0, D1, D2, D3, D4, D5 }; + uint8_t pins[] = { D0, D1, D2, D3 }; #else - uint8_t pins[] = { A0, A1, A2, A3, A4, A5 }; + uint8_t pins[] = { A0, A1, A2, A3 }; #endif -uint8_t hidcode[] = { HID_KEY_ARROW_RIGHT, HID_KEY_ARROW_LEFT, HID_KEY_ARROW_DOWN, HID_KEY_ARROW_UP , HID_KEY_4, HID_KEY_5 }; - +// number of pins uint8_t pincount = sizeof(pins)/sizeof(pins[0]); +// For keycode definition check out https://github.com/hathach/tinyusb/blob/master/src/class/hid/hid.h +uint8_t hidcode[] = { HID_KEY_ARROW_RIGHT, HID_KEY_ARROW_LEFT, HID_KEY_ARROW_DOWN, HID_KEY_ARROW_UP }; + +#if defined(ARDUINO_SAMD_CIRCUITPLAYGROUND_EXPRESS) || defined(ARDUINO_NRF52840_CIRCUITPLAY) || defined(ARDUINO_FUNHOUSE_ESP32S2) + bool activeState = true; +#else + bool activeState = false; +#endif + +//------------- Neopixel -------------// +// #define PIN_NEOPIXEL 8 +#ifdef PIN_NEOPIXEL + +// How many NeoPixels are attached to the Arduino? +// use on-board defined NEOPIXEL_NUM if existed +#ifndef NEOPIXEL_NUM + #define NEOPIXEL_NUM 10 +#endif + +Adafruit_NeoPixel pixels = Adafruit_NeoPixel(NEOPIXEL_NUM, PIN_NEOPIXEL, NEO_GRB + NEO_KHZ800); + +#endif + + // the setup function runs once when you press reset or power the board void setup() { @@ -46,11 +73,14 @@ void setup() TinyUSB_Device_Init(0); #endif - usb_hid.setBootProtocol(HID_ITF_PROTOCOL_KEYBOARD); - usb_hid.setPollInterval(2); - usb_hid.setReportDescriptor(desc_hid_report, sizeof(desc_hid_report)); + // Notes: following commented-out functions has no affect on ESP32 + // usb_hid.setBootProtocol(HID_ITF_PROTOCOL_KEYBOARD); + // usb_hid.setPollInterval(2); + // usb_hid.setReportDescriptor(desc_hid_report, sizeof(desc_hid_report)); + // usb_hid.setStringDescriptor("TinyUSB Keyboard"); + + // Set up output report (on control endpoint) for Capslock indicator usb_hid.setReportCallback(NULL, hid_report_callback); - //usb_hid.setStringDescriptor("TinyUSB Keyboard"); usb_hid.begin(); @@ -58,10 +88,38 @@ void setup() pinMode(LED_BUILTIN, OUTPUT); digitalWrite(LED_BUILTIN, LOW); + // neopixel if existed +#ifdef PIN_NEOPIXEL + pixels.begin(); + pixels.setBrightness(50); + + #ifdef NEOPIXEL_POWER + pinMode(NEOPIXEL_POWER, OUTPUT); + digitalWrite(NEOPIXEL_POWER, NEOPIXEL_POWER_ON); + #endif +#endif + + // overwrite input pin with PIN_BUTTONx +#ifdef PIN_BUTTON1 + pins[0] = PIN_BUTTON1; +#endif + +#ifdef PIN_BUTTON2 + pins[1] = PIN_BUTTON2; +#endif + +#ifdef PIN_BUTTON3 + pins[2] = PIN_BUTTON3; +#endif + +#ifdef PIN_BUTTON4 + pins[3] = PIN_BUTTON4; +#endif + // Set up pin as input for (uint8_t i=0; i sentence=TinyUSB library for Arduino -paragraph=TinyUSB library for Arduino +paragraph=Support nRF5x, SAMD21, SAMD51, RP2040, ESP32-S2 category=Communication url=https://github.com/adafruit/Adafruit_TinyUSB_Arduino architectures=* diff --git a/src/Adafruit_TinyUSB.h b/src/Adafruit_TinyUSB.h index eaa42be8..d99759ec 100644 --- a/src/Adafruit_TinyUSB.h +++ b/src/Adafruit_TinyUSB.h @@ -27,8 +27,7 @@ // Error message for Core that must select TinyUSB via menu #if !defined(USE_TINYUSB) && ( defined(ARDUINO_ARCH_SAMD) || \ - (defined(ARDUINO_ARCH_RP2040) && !defined(ARDUINO_ARCH_MBED)) || \ - defined(ARDUINO_ARCH_ESP32) ) + (defined(ARDUINO_ARCH_RP2040) && !defined(ARDUINO_ARCH_MBED)) ) #error TinyUSB is not selected, please select it in "Tools->Menu->USB Stack" #endif diff --git a/src/arduino/Adafruit_TinyUSB_API.cpp b/src/arduino/Adafruit_TinyUSB_API.cpp index 9cc4ea8b..461f4d48 100644 --- a/src/arduino/Adafruit_TinyUSB_API.cpp +++ b/src/arduino/Adafruit_TinyUSB_API.cpp @@ -24,7 +24,8 @@ #include "tusb_option.h" -#if TUSB_OPT_DEVICE_ENABLED +// ESP32 will use the arduino-esp32 core initialization and Serial +#if TUSB_OPT_DEVICE_ENABLED && !defined(ARDUINO_ARCH_ESP32) #include "Adafruit_TinyUSB.h" diff --git a/src/arduino/Adafruit_USBD_CDC.cpp b/src/arduino/Adafruit_USBD_CDC.cpp index d0a25807..1743a578 100644 --- a/src/arduino/Adafruit_USBD_CDC.cpp +++ b/src/arduino/Adafruit_USBD_CDC.cpp @@ -24,7 +24,7 @@ #include "tusb_option.h" -#if TUSB_OPT_DEVICE_ENABLED && CFG_TUD_CDC +#if TUSB_OPT_DEVICE_ENABLED && CFG_TUD_CDC && !defined(ARDUINO_ARCH_ESP32) #include "Arduino.h" diff --git a/src/arduino/Adafruit_USBD_CDC.h b/src/arduino/Adafruit_USBD_CDC.h index 7c8f1f65..a76ea12b 100644 --- a/src/arduino/Adafruit_USBD_CDC.h +++ b/src/arduino/Adafruit_USBD_CDC.h @@ -27,7 +27,7 @@ #include "Adafruit_TinyUSB_API.h" -#ifdef __cplusplus +#if defined(__cplusplus) && !defined(ARDUINO_ARCH_ESP32) #include "Adafruit_USBD_Interface.h" #include "Stream.h" @@ -83,8 +83,7 @@ class Adafruit_USBD_CDC : public Stream, public Adafruit_USBD_Interface { }; // "Serial" is used with TinyUSB CDC -#if defined(USE_TINYUSB) && \ - !(defined(ARDUINO_ARCH_ESP32) && ARDUINO_SERIAL_PORT == 0) +#if defined(USE_TINYUSB) extern Adafruit_USBD_CDC Serial; #define SerialTinyUSB Serial #endif diff --git a/src/arduino/Adafruit_USBD_Device.cpp b/src/arduino/Adafruit_USBD_Device.cpp index 83463329..6b82766c 100644 --- a/src/arduino/Adafruit_USBD_Device.cpp +++ b/src/arduino/Adafruit_USBD_Device.cpp @@ -86,6 +86,86 @@ Adafruit_USBD_Device TinyUSBDevice; Adafruit_USBD_Device::Adafruit_USBD_Device(void) {} +void Adafruit_USBD_Device::setConfigurationBuffer(uint8_t *buf, + uint32_t buflen) { + if (buflen < _desc_cfg_maxlen) { + return; + } + + memcpy(buf, _desc_cfg, _desc_cfg_len); + _desc_cfg = buf; + _desc_cfg_maxlen = buflen; +} + +void Adafruit_USBD_Device::setID(uint16_t vid, uint16_t pid) { + _desc_device.idVendor = vid; + _desc_device.idProduct = pid; +} + +void Adafruit_USBD_Device::setVersion(uint16_t bcd) { + _desc_device.bcdUSB = bcd; +} + +void Adafruit_USBD_Device::setDeviceVersion(uint16_t bcd) { + _desc_device.bcdDevice = bcd; +} + +void Adafruit_USBD_Device::setLanguageDescriptor(uint16_t language_id) { + _desc_str_arr[STRID_LANGUAGE] = (const char *)((uint32_t)language_id); +} + +void Adafruit_USBD_Device::setManufacturerDescriptor(const char *s) { + _desc_str_arr[STRID_MANUFACTURER] = s; +} + +void Adafruit_USBD_Device::setProductDescriptor(const char *s) { + _desc_str_arr[STRID_PRODUCT] = s; +} + +void Adafruit_USBD_Device::task(void) { tud_task(); } + +bool Adafruit_USBD_Device::mounted(void) { return tud_mounted(); } + +bool Adafruit_USBD_Device::suspended(void) { return tud_suspended(); } + +bool Adafruit_USBD_Device::ready(void) { return tud_ready(); } + +bool Adafruit_USBD_Device::remoteWakeup(void) { return tud_remote_wakeup(); } + +bool Adafruit_USBD_Device::detach(void) { return tud_disconnect(); } + +bool Adafruit_USBD_Device::attach(void) { return tud_connect(); } + +// EPS32 use built-in core descriptor builder. +// Therefore most of descriptors are stubs only +#ifdef ARDUINO_ARCH_ESP32 + +void Adafruit_USBD_Device::clearConfiguration(void) {} + +bool Adafruit_USBD_Device::addInterface(Adafruit_USBD_Interface &itf) { + (void)itf; + return true; +} + +bool Adafruit_USBD_Device::begin(uint8_t rhport) { + (void)rhport; + return true; +} + +uint8_t Adafruit_USBD_Device::getSerialDescriptor(uint16_t *serial_utf16) { + (void)serial_utf16; + return 0; +} + +uint16_t const *Adafruit_USBD_Device::descriptor_string_cb(uint8_t index, + uint16_t langid) { + (void)index; + (void)langid; + return NULL; +} + +#else + void Adafruit_USBD_Device::clearConfiguration(void) { tusb_desc_device_t const desc_dev = {.bLength = sizeof(tusb_desc_device_t), .bDescriptorType = TUSB_DESC_DEVICE, @@ -150,7 +230,7 @@ bool Adafruit_USBD_Device::addInterface(Adafruit_USBD_Interface &itf) { // - Interface Number & string descriptor // - Endpoint address while (desc < desc_end) { - if (desc[1] == TUSB_DESC_INTERFACE) { + if (tu_desc_type(desc) == TUSB_DESC_INTERFACE) { tusb_desc_interface_t *desc_itf = (tusb_desc_interface_t *)desc; if (desc_itf->bAlternateSetting == 0) { _itf_count++; @@ -163,7 +243,7 @@ bool Adafruit_USBD_Device::addInterface(Adafruit_USBD_Interface &itf) { desc_str = NULL; } } - } else if (desc[1] == TUSB_DESC_ENDPOINT) { + } else if (tu_desc_type(desc) == TUSB_DESC_ENDPOINT) { tusb_desc_endpoint_t *desc_ep = (tusb_desc_endpoint_t *)desc; desc_ep->bEndpointAddress |= (desc_ep->bEndpointAddress & 0x80) ? _epin_count++ : _epout_count++; @@ -173,7 +253,7 @@ bool Adafruit_USBD_Device::addInterface(Adafruit_USBD_Interface &itf) { return false; } - desc += desc[0]; // next + desc += tu_desc_len(desc); } _desc_cfg_len += len; @@ -186,59 +266,6 @@ bool Adafruit_USBD_Device::addInterface(Adafruit_USBD_Interface &itf) { return true; } -void Adafruit_USBD_Device::setConfigurationBuffer(uint8_t *buf, - uint32_t buflen) { - if (buflen < _desc_cfg_maxlen) { - return; - } - - memcpy(buf, _desc_cfg, _desc_cfg_len); - _desc_cfg = buf; - _desc_cfg_maxlen = buflen; -} - -void Adafruit_USBD_Device::setID(uint16_t vid, uint16_t pid) { - _desc_device.idVendor = vid; - _desc_device.idProduct = pid; -} - -void Adafruit_USBD_Device::setVersion(uint16_t bcd) { - _desc_device.bcdUSB = bcd; -} - -void Adafruit_USBD_Device::setDeviceVersion(uint16_t bcd) { - _desc_device.bcdDevice = bcd; -} - -void Adafruit_USBD_Device::setLanguageDescriptor(uint16_t language_id) { - _desc_str_arr[STRID_LANGUAGE] = (const char *)((uint32_t)language_id); -} - -void Adafruit_USBD_Device::setManufacturerDescriptor(const char *s) { - _desc_str_arr[STRID_MANUFACTURER] = s; -} - -void Adafruit_USBD_Device::setProductDescriptor(const char *s) { - _desc_str_arr[STRID_PRODUCT] = s; -} - -uint8_t Adafruit_USBD_Device::getSerialDescriptor(uint16_t *serial_utf16) { - uint8_t serial_id[16] __attribute__((aligned(4))); - uint8_t const serial_len = TinyUSB_Port_GetSerialNumber(serial_id); - - for (uint8_t i = 0; i < serial_len; i++) { - for (uint8_t j = 0; j < 2; j++) { - const char nibble_to_hex[16] = {'0', '1', '2', '3', '4', '5', '6', '7', - '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'}; - - uint8_t nibble = (serial_id[i] >> (j * 4)) & 0xf; - serial_utf16[1 + i * 2 + (1 - j)] = nibble_to_hex[nibble]; // UTF-16-LE - } - } - - return 2 * serial_len; -} - bool Adafruit_USBD_Device::begin(uint8_t rhport) { clearConfiguration(); @@ -258,19 +285,22 @@ bool Adafruit_USBD_Device::begin(uint8_t rhport) { return true; } -void Adafruit_USBD_Device::task(void) { tud_task(); } - -bool Adafruit_USBD_Device::mounted(void) { return tud_mounted(); } - -bool Adafruit_USBD_Device::suspended(void) { return tud_suspended(); } - -bool Adafruit_USBD_Device::ready(void) { return tud_ready(); } +uint8_t Adafruit_USBD_Device::getSerialDescriptor(uint16_t *serial_utf16) { + uint8_t serial_id[16] __attribute__((aligned(4))); + uint8_t const serial_len = TinyUSB_Port_GetSerialNumber(serial_id); -bool Adafruit_USBD_Device::remoteWakeup(void) { return tud_remote_wakeup(); } + for (uint8_t i = 0; i < serial_len; i++) { + for (uint8_t j = 0; j < 2; j++) { + const char nibble_to_hex[16] = {'0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'}; -bool Adafruit_USBD_Device::detach(void) { return tud_disconnect(); } + uint8_t nibble = (serial_id[i] >> (j * 4)) & 0xf; + serial_utf16[1 + i * 2 + (1 - j)] = nibble_to_hex[nibble]; // UTF-16-LE + } + } -bool Adafruit_USBD_Device::attach(void) { return tud_connect(); } + return 2 * serial_len; +} static int strcpy_utf16(const char *s, uint16_t *buf, int bufsize); uint16_t const *Adafruit_USBD_Device::descriptor_string_cb(uint8_t index, @@ -308,6 +338,7 @@ uint16_t const *Adafruit_USBD_Device::descriptor_string_cb(uint8_t index, //--------------------------------------------------------------------+ // TinyUSB stack callbacks //--------------------------------------------------------------------+ + extern "C" { // Invoked when received GET DEVICE DESCRIPTOR @@ -493,10 +524,12 @@ static int strcpy_utf16(const char *s, uint16_t *buf, int bufsize) { } // TODO just for compiling, will move to DFU specific file -#if CFG_TUD_DFU_RUNTIME +#if CFG_TUD_DFU_RUNTIME && !defined(ARDUINO_ARCH_ESP32) void tud_dfu_runtime_reboot_to_dfu_cb(void) { // TinyUSB_Port_EnterDFU(); } #endif +#endif // ESP32 + #endif // TUSB_OPT_DEVICE_ENABLED diff --git a/src/arduino/Adafruit_USBD_Device.h b/src/arduino/Adafruit_USBD_Device.h index 6561c119..0dcbd417 100644 --- a/src/arduino/Adafruit_USBD_Device.h +++ b/src/arduino/Adafruit_USBD_Device.h @@ -28,6 +28,10 @@ #include "Adafruit_USBD_Interface.h" #include "tusb.h" +#ifdef ARDUINO_ARCH_ESP32 +#include "esp32-hal-tinyusb.h" +#endif + class Adafruit_USBD_Device { private: enum { STRING_DESCRIPTOR_MAX = 8 }; diff --git a/src/arduino/Adafruit_USBD_Interface.h b/src/arduino/Adafruit_USBD_Interface.h index 94c14c38..1cb87f19 100644 --- a/src/arduino/Adafruit_USBD_Interface.h +++ b/src/arduino/Adafruit_USBD_Interface.h @@ -36,7 +36,7 @@ class Adafruit_USBD_Interface { Adafruit_USBD_Interface(void) { _desc_str = NULL; } // Get Interface Descriptor - // Device fill descriptor and return its length + // Fill the descriptor (if buf is not NULL) and return its length virtual uint16_t getInterfaceDescriptor(uint8_t itfnum, uint8_t *buf, uint16_t bufsize) = 0; diff --git a/src/arduino/hid/Adafruit_USBD_HID.cpp b/src/arduino/hid/Adafruit_USBD_HID.cpp index b139dad3..3d0554c0 100644 --- a/src/arduino/hid/Adafruit_USBD_HID.cpp +++ b/src/arduino/hid/Adafruit_USBD_HID.cpp @@ -33,21 +33,60 @@ uint8_t const _ascii2keycode[128][2] = {HID_ASCII_TO_KEYCODE}; +// TODO multiple instances static Adafruit_USBD_HID *_hid_dev = NULL; +#ifdef ARDUINO_ARCH_ESP32 +static uint16_t hid_load_descriptor(uint8_t *dst, uint8_t *itf) { + // uint8_t str_index = tinyusb_add_string_descriptor("TinyUSB HID"); + uint8_t str_index = 0; + + TU_VERIFY(_hid_dev); + + uint8_t ep_in = tinyusb_get_free_in_endpoint(); + TU_VERIFY(ep_in != 0); + ep_in |= 0x80; + + uint8_t ep_out = 0; + if (_hid_dev->isOutEndpointEnabled()) { + ep_out = tinyusb_get_free_out_endpoint(); + TU_VERIFY(ep_out != 0); + } + + uint16_t const desc_len = + _hid_dev->makeItfDesc(*itf, dst, TUD_HID_INOUT_DESC_LEN, ep_in, ep_out); + + *itf += 1; + return desc_len; +} +#endif + //------------- IMPLEMENTATION -------------// -Adafruit_USBD_HID::Adafruit_USBD_HID(void) { - _interval_ms = 10; - _protocol = HID_ITF_PROTOCOL_NONE; - _out_endpoint = false; +Adafruit_USBD_HID::Adafruit_USBD_HID(void) + : Adafruit_USBD_HID(NULL, 0, HID_ITF_PROTOCOL_NONE, 4, false) {} + +Adafruit_USBD_HID::Adafruit_USBD_HID(uint8_t const *desc_report, uint16_t len, + uint8_t protocol, uint8_t interval_ms, + bool has_out_endpoint) { + _interval_ms = interval_ms; + _protocol = protocol; + + _out_endpoint = has_out_endpoint; _mouse_button = 0; - _desc_report = NULL; - _desc_report_len = 0; + _desc_report = desc_report; + _desc_report_len = len; _get_report_cb = NULL; _set_report_cb = NULL; + +#ifdef ARDUINO_ARCH_ESP32 + // ESP32 requires setup configuration descriptor within constructor + _hid_dev = this; + uint16_t const desc_len = getInterfaceDescriptor(0, NULL, 0); + tinyusb_enable_interface(USB_INTERFACE_HID, desc_len, hid_load_descriptor); +#endif } void Adafruit_USBD_HID::setPollInterval(uint8_t interval_ms) { @@ -58,6 +97,8 @@ void Adafruit_USBD_HID::setBootProtocol(uint8_t protocol) { _protocol = protocol; } +bool Adafruit_USBD_HID::isOutEndpointEnabled(void) { return _out_endpoint; } + void Adafruit_USBD_HID::enableOutEndpoint(bool enable) { _out_endpoint = enable; } @@ -74,18 +115,18 @@ void Adafruit_USBD_HID::setReportCallback(get_report_callback_t get_report, _set_report_cb = set_report; } -uint16_t Adafruit_USBD_HID::getInterfaceDescriptor(uint8_t itfnum, uint8_t *buf, - uint16_t bufsize) { +uint16_t Adafruit_USBD_HID::makeItfDesc(uint8_t itfnum, uint8_t *buf, + uint16_t bufsize, uint8_t ep_in, + uint8_t ep_out) { if (!_desc_report_len) { return 0; } - // usb core will automatically update endpoint number uint8_t const desc_inout[] = { - TUD_HID_INOUT_DESCRIPTOR(itfnum, 0, _protocol, _desc_report_len, EPIN, - EPOUT, CFG_TUD_HID_EP_BUFSIZE, _interval_ms)}; + TUD_HID_INOUT_DESCRIPTOR(itfnum, 0, _protocol, _desc_report_len, ep_in, + ep_out, CFG_TUD_HID_EP_BUFSIZE, _interval_ms)}; uint8_t const desc_in_only[] = { - TUD_HID_DESCRIPTOR(itfnum, 0, _protocol, _desc_report_len, EPIN, + TUD_HID_DESCRIPTOR(itfnum, 0, _protocol, _desc_report_len, ep_in, CFG_TUD_HID_EP_BUFSIZE, _interval_ms)}; uint8_t const *desc; @@ -99,14 +140,24 @@ uint16_t Adafruit_USBD_HID::getInterfaceDescriptor(uint8_t itfnum, uint8_t *buf, len = sizeof(desc_in_only); } - if (bufsize < len) { - return 0; + // null buffer is used to get the length of descriptor only + if (buf) { + if (bufsize < len) { + return 0; + } + + memcpy(buf, desc, len); } - memcpy(buf, desc, len); return len; } +uint16_t Adafruit_USBD_HID::getInterfaceDescriptor(uint8_t itfnum, uint8_t *buf, + uint16_t bufsize) { + // usb core will automatically update endpoint number + return makeItfDesc(itfnum, buf, bufsize, EPIN, EPOUT); +} + bool Adafruit_USBD_HID::begin(void) { if (!TinyUSBDevice.addInterface(*this)) { return false; diff --git a/src/arduino/hid/Adafruit_USBD_HID.h b/src/arduino/hid/Adafruit_USBD_HID.h index 90be492d..44d4050a 100644 --- a/src/arduino/hid/Adafruit_USBD_HID.h +++ b/src/arduino/hid/Adafruit_USBD_HID.h @@ -38,10 +38,16 @@ class Adafruit_USBD_HID : public Adafruit_USBD_Interface { uint16_t bufsize); Adafruit_USBD_HID(void); + Adafruit_USBD_HID(uint8_t const *desc_report, uint16_t len, + uint8_t protocol = HID_ITF_PROTOCOL_NONE, + uint8_t interval_ms = 4, bool has_out_endpoint = false); void setPollInterval(uint8_t interval_ms); void setBootProtocol(uint8_t protocol); // 0: None, 1: Keyboard, 2:Mouse + void enableOutEndpoint(bool enable); + bool isOutEndpointEnabled(void); + void setReportDescriptor(uint8_t const *desc_report, uint16_t len); void setReportCallback(get_report_callback_t get_report, set_report_callback_t set_report); @@ -73,6 +79,10 @@ class Adafruit_USBD_HID : public Adafruit_USBD_Interface { virtual uint16_t getInterfaceDescriptor(uint8_t itfnum, uint8_t *buf, uint16_t bufsize); + // internal use only + uint16_t makeItfDesc(uint8_t itfnum, uint8_t *buf, uint16_t bufsize, + uint8_t ep_in, uint8_t ep_out); + private: uint8_t _interval_ms; uint8_t _protocol; diff --git a/src/arduino/midi/Adafruit_USBD_MIDI.cpp b/src/arduino/midi/Adafruit_USBD_MIDI.cpp index 84708ffe..b78fcd2a 100644 --- a/src/arduino/midi/Adafruit_USBD_MIDI.cpp +++ b/src/arduino/midi/Adafruit_USBD_MIDI.cpp @@ -35,42 +35,85 @@ #define EPIN 0x80 #define EPSIZE 64 -Adafruit_USBD_MIDI::Adafruit_USBD_MIDI(void) : _n_cables(1) {} +// TODO multiple instances +static Adafruit_USBD_MIDI *_midi_dev = NULL; + +#ifdef ARDUINO_ARCH_ESP32 +static uint16_t midi_load_descriptor(uint8_t *dst, uint8_t *itf) { + // uint8_t str_index = tinyusb_add_string_descriptor("TinyUSB HID"); + uint8_t str_index = 0; + + uint8_t ep_in = tinyusb_get_free_in_endpoint(); + uint8_t ep_out = tinyusb_get_free_out_endpoint(); + TU_VERIFY(ep_in && ep_out); + ep_in |= 0x80; + + uint16_t desc_len = _midi_dev->getInterfaceDescriptor(0, NULL, 0); + + desc_len = _midi_dev->makeItfDesc(*itf, dst, desc_len, ep_in, ep_out); + + *itf += 2; + return desc_len; +} +#endif + +Adafruit_USBD_MIDI::Adafruit_USBD_MIDI(uint8_t n_cables) { + _n_cables = n_cables; + +#ifdef ARDUINO_ARCH_ESP32 + // ESP32 requires setup configuration descriptor within constructor + _midi_dev = this; + uint16_t const desc_len = getInterfaceDescriptor(0, NULL, 0); + tinyusb_enable_interface(USB_INTERFACE_MIDI, desc_len, midi_load_descriptor); +#endif +} void Adafruit_USBD_MIDI::setCables(uint8_t n_cables) { _n_cables = n_cables; } bool Adafruit_USBD_MIDI::begin(void) { - if (!TinyUSBDevice.addInterface(*this)) + if (!TinyUSBDevice.addInterface(*this)) { return false; + } + _midi_dev = this; return true; } -uint16_t Adafruit_USBD_MIDI::getInterfaceDescriptor(uint8_t itfnum, - uint8_t *buf, - uint16_t bufsize) { - uint16_t len = 0; +uint16_t Adafruit_USBD_MIDI::makeItfDesc(uint8_t itfnum, uint8_t *buf, + uint16_t bufsize, uint8_t ep_in, + uint8_t ep_out) { + uint16_t const desc_len = TUD_MIDI_DESC_HEAD_LEN + + TUD_MIDI_DESC_JACK_LEN * _n_cables + + 2 * TUD_MIDI_DESC_EP_LEN(_n_cables); - if (bufsize < TUD_MIDI_DESC_HEAD_LEN + TUD_MIDI_DESC_JACK_LEN * _n_cables + - TUD_MIDI_DESC_EP_LEN(_n_cables) * 2) + // null buf is for length only + if (!buf) { + return desc_len; + } + + if (bufsize < desc_len) { return 0; + } + uint16_t len = 0; + + // Header { uint8_t desc[] = {TUD_MIDI_DESC_HEAD(itfnum, 0, _n_cables)}; memcpy(buf + len, desc, sizeof(desc)); len += sizeof(desc); } + // Jack for (uint8_t i = 1; i <= _n_cables; i++) { uint8_t jack[] = {TUD_MIDI_DESC_JACK(i)}; memcpy(buf + len, jack, sizeof(jack)); len += sizeof(jack); } - // Endpoint OUT + jack mapping - usb core will automatically update endpoint - // number + // Endpoint OUT + jack mapping { - uint8_t desc[] = {TUD_MIDI_DESC_EP(EPOUT, EPSIZE, _n_cables)}; + uint8_t desc[] = {TUD_MIDI_DESC_EP(ep_out, EPSIZE, _n_cables)}; memcpy(buf + len, desc, sizeof(desc)); len += sizeof(desc); } @@ -81,10 +124,9 @@ uint16_t Adafruit_USBD_MIDI::getInterfaceDescriptor(uint8_t itfnum, len += sizeof(jack); } - // Endpoint IN + jack mapping - usb core will automatically update endpoint - // number + // Endpoint IN + jack mapping { - uint8_t desc[] = {TUD_MIDI_DESC_EP(EPIN, EPSIZE, _n_cables)}; + uint8_t desc[] = {TUD_MIDI_DESC_EP(ep_in, EPSIZE, _n_cables)}; memcpy(buf + len, desc, sizeof(desc)); len += sizeof(desc); } @@ -95,7 +137,18 @@ uint16_t Adafruit_USBD_MIDI::getInterfaceDescriptor(uint8_t itfnum, len += sizeof(jack); } - return len; + if (len != desc_len) { + // TODO should throw an error message + return 0; + } + + return desc_len; +} + +uint16_t Adafruit_USBD_MIDI::getInterfaceDescriptor(uint8_t itfnum, + uint8_t *buf, + uint16_t bufsize) { + return makeItfDesc(itfnum, buf, bufsize, EPIN, EPOUT); } int Adafruit_USBD_MIDI::read(void) { diff --git a/src/arduino/midi/Adafruit_USBD_MIDI.h b/src/arduino/midi/Adafruit_USBD_MIDI.h index 4741e8ab..0ddbbce8 100644 --- a/src/arduino/midi/Adafruit_USBD_MIDI.h +++ b/src/arduino/midi/Adafruit_USBD_MIDI.h @@ -30,7 +30,9 @@ class Adafruit_USBD_MIDI : public Stream, public Adafruit_USBD_Interface { public: - Adafruit_USBD_MIDI(void); + Adafruit_USBD_MIDI(uint8_t n_cables = 1); + + void setCables(uint8_t n_cables); bool begin(void); @@ -57,7 +59,9 @@ class Adafruit_USBD_MIDI : public Stream, public Adafruit_USBD_Interface { virtual uint16_t getInterfaceDescriptor(uint8_t itfnum, uint8_t *buf, uint16_t bufsize); - void setCables(uint8_t n_cables); + // internal use only + uint16_t makeItfDesc(uint8_t itfnum, uint8_t *buf, uint16_t bufsize, + uint8_t ep_in, uint8_t ep_out); private: uint8_t _n_cables; diff --git a/src/arduino/msc/Adafruit_USBD_MSC.cpp b/src/arduino/msc/Adafruit_USBD_MSC.cpp index 6f4d2712..4c494095 100644 --- a/src/arduino/msc/Adafruit_USBD_MSC.cpp +++ b/src/arduino/msc/Adafruit_USBD_MSC.cpp @@ -34,15 +34,41 @@ static Adafruit_USBD_MSC *_msc_dev = NULL; +#ifdef ARDUINO_ARCH_ESP32 +static uint16_t msc_load_descriptor(uint8_t *dst, uint8_t *itf) { + // uint8_t str_index = tinyusb_add_string_descriptor("TinyUSB MSC"); + uint8_t str_index = 0; + + uint8_t ep_in = tinyusb_get_free_in_endpoint(); + uint8_t ep_out = tinyusb_get_free_out_endpoint(); + TU_VERIFY(ep_in && ep_out); + ep_in |= 0x80; + + uint8_t const descriptor[TUD_MSC_DESC_LEN] = { + // Interface number, string index, EP Out & EP In address, EP size + TUD_MSC_DESCRIPTOR(*itf, str_index, ep_out, ep_in, EPSIZE)}; + + *itf += 1; + memcpy(dst, descriptor, TUD_MSC_DESC_LEN); + return TUD_MSC_DESC_LEN; +} +#endif + Adafruit_USBD_MSC::Adafruit_USBD_MSC(void) { _maxlun = 1; - memset(_lun, 0, sizeof(_lun)); + memset(_lun_info, 0, sizeof(_lun_info)); + +#ifdef ARDUINO_ARCH_ESP32 + // ESP32 requires setup configuration descriptor on declaration + tinyusb_enable_interface(USB_INTERFACE_MSC, TUD_MSC_DESC_LEN, + msc_load_descriptor); +#endif } uint16_t Adafruit_USBD_MSC::getInterfaceDescriptor(uint8_t itfnum, uint8_t *buf, uint16_t bufsize) { // usb core will automatically update endpoint number - uint8_t desc[] = {TUD_MSC_DESCRIPTOR(itfnum, 0, EPOUT, EPIN, EPSIZE)}; + uint8_t const desc[] = {TUD_MSC_DESCRIPTOR(itfnum, 0, EPOUT, EPIN, EPSIZE)}; uint16_t const len = sizeof(desc); if (bufsize < len) { @@ -59,31 +85,31 @@ uint8_t Adafruit_USBD_MSC::getMaxLun(void) { return _maxlun; } void Adafruit_USBD_MSC::setID(uint8_t lun, const char *vendor_id, const char *product_id, const char *product_rev) { - _lun[lun]._inquiry_vid = vendor_id; - _lun[lun]._inquiry_pid = product_id; - _lun[lun]._inquiry_rev = product_rev; + _lun_info[lun]._inquiry_vid = vendor_id; + _lun_info[lun]._inquiry_pid = product_id; + _lun_info[lun]._inquiry_rev = product_rev; } void Adafruit_USBD_MSC::setCapacity(uint8_t lun, uint32_t block_count, uint16_t block_size) { - _lun[lun].block_count = block_count; - _lun[lun].block_size = block_size; + _lun_info[lun].block_count = block_count; + _lun_info[lun].block_size = block_size; } void Adafruit_USBD_MSC::setUnitReady(uint8_t lun, bool ready) { - _lun[lun].unit_ready = ready; + _lun_info[lun].unit_ready = ready; } void Adafruit_USBD_MSC::setReadWriteCallback(uint8_t lun, read_callback_t rd_cb, write_callback_t wr_cb, flush_callback_t fl_cb) { - _lun[lun].rd_cb = rd_cb; - _lun[lun].wr_cb = wr_cb; - _lun[lun].fl_cb = fl_cb; + _lun_info[lun].rd_cb = rd_cb; + _lun_info[lun].wr_cb = wr_cb; + _lun_info[lun].fl_cb = fl_cb; } void Adafruit_USBD_MSC::setReadyCallback(uint8_t lun, ready_callback_t cb) { - _lun[lun].ready_cb = cb; + _lun_info[lun].ready_cb = cb; } bool Adafruit_USBD_MSC::begin(void) { @@ -116,15 +142,15 @@ void tud_msc_inquiry_cb(uint8_t lun, uint8_t vendor_id[8], } // If not set use default ID "Adafruit - Mass Storage - 1.0" - const char *vid = - (_msc_dev->_lun[lun]._inquiry_vid ? _msc_dev->_lun[lun]._inquiry_vid - : "Adafruit"); - const char *pid = - (_msc_dev->_lun[lun]._inquiry_pid ? _msc_dev->_lun[lun]._inquiry_pid - : "Mass Storage"); - const char *rev = - (_msc_dev->_lun[lun]._inquiry_rev ? _msc_dev->_lun[lun]._inquiry_rev - : "1.0"); + const char *vid = (_msc_dev->_lun_info[lun]._inquiry_vid + ? _msc_dev->_lun_info[lun]._inquiry_vid + : "Adafruit"); + const char *pid = (_msc_dev->_lun_info[lun]._inquiry_pid + ? _msc_dev->_lun_info[lun]._inquiry_pid + : "Mass Storage"); + const char *rev = (_msc_dev->_lun_info[lun]._inquiry_rev + ? _msc_dev->_lun_info[lun]._inquiry_rev + : "1.0"); memcpy(vendor_id, vid, tu_min32(strlen(vid), 8)); memcpy(product_id, pid, tu_min32(strlen(pid), 16)); @@ -138,11 +164,11 @@ bool tud_msc_test_unit_ready_cb(uint8_t lun) { return false; } - if (_msc_dev->_lun[lun].ready_cb) { - _msc_dev->_lun[lun].unit_ready = _msc_dev->_lun[lun].ready_cb(); + if (_msc_dev->_lun_info[lun].ready_cb) { + _msc_dev->_lun_info[lun].unit_ready = _msc_dev->_lun_info[lun].ready_cb(); } - return _msc_dev->_lun[lun].unit_ready; + return _msc_dev->_lun_info[lun].unit_ready; } // Callback invoked to determine disk's size @@ -152,8 +178,8 @@ void tud_msc_capacity_cb(uint8_t lun, uint32_t *block_count, return; } - *block_count = _msc_dev->_lun[lun].block_count; - *block_size = _msc_dev->_lun[lun].block_size; + *block_count = _msc_dev->_lun_info[lun].block_count; + *block_size = _msc_dev->_lun_info[lun].block_size; } // Callback invoked when received an SCSI command not in built-in list below @@ -199,11 +225,11 @@ int32_t tud_msc_read10_cb(uint8_t lun, uint32_t lba, uint32_t offset, void *buffer, uint32_t bufsize) { (void)offset; - if (!(_msc_dev && _msc_dev->_lun[lun].rd_cb)) { + if (!(_msc_dev && _msc_dev->_lun_info[lun].rd_cb)) { return -1; } - return _msc_dev->_lun[lun].rd_cb(lba, buffer, bufsize); + return _msc_dev->_lun_info[lun].rd_cb(lba, buffer, bufsize); } // Callback invoked when received WRITE10 command. @@ -212,22 +238,22 @@ int32_t tud_msc_write10_cb(uint8_t lun, uint32_t lba, uint32_t offset, uint8_t *buffer, uint32_t bufsize) { (void)offset; - if (!(_msc_dev && _msc_dev->_lun[lun].wr_cb)) { + if (!(_msc_dev && _msc_dev->_lun_info[lun].wr_cb)) { return -1; } - return _msc_dev->_lun[lun].wr_cb(lba, buffer, bufsize); + return _msc_dev->_lun_info[lun].wr_cb(lba, buffer, bufsize); } // Callback invoked when WRITE10 command is completed (status received and // accepted by host). used to flush any pending cache. void tud_msc_write10_complete_cb(uint8_t lun) { - if (!(_msc_dev && _msc_dev->_lun[lun].fl_cb)) { + if (!(_msc_dev && _msc_dev->_lun_info[lun].fl_cb)) { return; } // flush pending cache when write10 is complete - return _msc_dev->_lun[lun].fl_cb(); + return _msc_dev->_lun_info[lun].fl_cb(); } } // extern "C" diff --git a/src/arduino/msc/Adafruit_USBD_MSC.h b/src/arduino/msc/Adafruit_USBD_MSC.h index 5bd8f062..bb7c7822 100644 --- a/src/arduino/msc/Adafruit_USBD_MSC.h +++ b/src/arduino/msc/Adafruit_USBD_MSC.h @@ -91,7 +91,7 @@ class Adafruit_USBD_MSC : public Adafruit_USBD_Interface { uint16_t block_size; bool unit_ready; - } _lun[MAX_LUN]; + } _lun_info[MAX_LUN]; uint8_t _maxlun; diff --git a/src/arduino/ports/esp32/Adafruit_TinyUSB_esp32.cpp b/src/arduino/ports/esp32/Adafruit_TinyUSB_esp32.cpp index 33952bf0..5cec8849 100644 --- a/src/arduino/ports/esp32/Adafruit_TinyUSB_esp32.cpp +++ b/src/arduino/ports/esp32/Adafruit_TinyUSB_esp32.cpp @@ -26,6 +26,24 @@ #if defined(ARDUINO_ARCH_ESP32) && TUSB_OPT_DEVICE_ENABLED +#include + +// ESP32 will use the arduino-esp32 core initialization +// These port API is empty to prevent compilation error + +void TinyUSB_Port_EnterDFU(void) {} + +void TinyUSB_Port_InitDevice(uint8_t rhport) { (void)rhport; } + +uint8_t TinyUSB_Port_GetSerialNumber(uint8_t serial_id[16]) { + (void)serial_id; + return 0; +} + +#if 0 + +// This port implemented is not needed and left here for reference only + #include "sdkconfig.h" #include "soc/soc.h" @@ -54,11 +72,8 @@ #include "driver/gpio.h" #include "driver/periph_ctrl.h" -#include "esp_efuse.h" -#include "esp_efuse_table.h" -#include "esp_rom_gpio.h" - #include "esp32-hal.h" +#include "esp_rom_gpio.h" #include "esp32s2/rom/usb/chip_usb_dw_wrapper.h" #include "esp32s2/rom/usb/usb_dc.h" @@ -112,6 +127,7 @@ static void usb_device_task(void *param) { } } + void TinyUSB_Port_InitDevice(uint8_t rhport) { (void)rhport; @@ -165,5 +181,6 @@ extern "C" void yield(void) { TinyUSB_Device_FlushCDC(); vPortYield(); } +#endif // commented out -#endif // USE_TINYUSB +#endif diff --git a/src/arduino/webusb/Adafruit_USBD_WebUSB.cpp b/src/arduino/webusb/Adafruit_USBD_WebUSB.cpp index 77fc05ed..526380eb 100644 --- a/src/arduino/webusb/Adafruit_USBD_WebUSB.cpp +++ b/src/arduino/webusb/Adafruit_USBD_WebUSB.cpp @@ -38,6 +38,7 @@ enum { VENDOR_REQUEST_WEBUSB = 1, VENDOR_REQUEST_MICROSOFT = 2 }; +// TODO multiple instances static Adafruit_USBD_WebUSB *_webusb_dev = NULL; //--------------------------------------------------------------------+ @@ -75,8 +76,6 @@ uint8_t const desc_bos[] = { // Microsoft OS 2.0 descriptor TUD_BOS_MS_OS_20_DESCRIPTOR(MS_OS_20_DESC_LEN, VENDOR_REQUEST_MICROSOFT)}; -uint8_t const *tud_descriptor_bos_cb(void) { return desc_bos; } - uint8_t desc_ms_os_20[] = { // Set header: length, type, windows version, total length U16_TO_U8S_LE(0x000A), U16_TO_U8S_LE(MS_OS_20_SET_HEADER_DESCRIPTOR), @@ -118,19 +117,53 @@ uint8_t desc_ms_os_20[] = { TU_VERIFY_STATIC(sizeof(desc_ms_os_20) == MS_OS_20_DESC_LEN, "Incorrect size"); -//------------- IMPLEMENTATION -------------// +//--------------------------------------------------------------------+ +// IMPLEMENTATION +//--------------------------------------------------------------------+ + +#ifdef ARDUINO_ARCH_ESP32 +static uint16_t webusb_load_descriptor(uint8_t *dst, uint8_t *itf) { + // uint8_t str_index = tinyusb_add_string_descriptor("TinyUSB MSC"); + uint8_t str_index = 0; + + uint8_t ep_in = tinyusb_get_free_in_endpoint(); + uint8_t ep_out = tinyusb_get_free_out_endpoint(); + TU_VERIFY(ep_in && ep_out); + ep_in |= 0x80; + + uint16_t desc_len = _webusb_dev->getInterfaceDescriptor(0, NULL, 0); + + desc_len = _webusb_dev->makeItfDesc(*itf, dst, desc_len, ep_in, ep_out); + + *itf += 1; + return desc_len; +} +#endif -Adafruit_USBD_WebUSB::Adafruit_USBD_WebUSB(void) { +Adafruit_USBD_WebUSB::Adafruit_USBD_WebUSB(const void *url) { _connected = false; - _url = NULL; + _url = (const uint8_t *)url; _linestate_cb = NULL; + +#ifdef ARDUINO_ARCH_ESP32 + // ESP32 requires setup configuration descriptor within constructor + + // WebUSB requires USB version at least 2.1 (or 3.x) + USB.usbVersion(0x0210); + + _webusb_dev = this; + uint16_t const desc_len = getInterfaceDescriptor(0, NULL, 0); + tinyusb_enable_interface(USB_INTERFACE_VENDOR, desc_len, + webusb_load_descriptor); +#endif } bool Adafruit_USBD_WebUSB::begin(void) { - if (!TinyUSBDevice.addInterface(*this)) + if (!TinyUSBDevice.addInterface(*this)) { return false; + } - // WebUSB requires to change USB version from 2.0 to 2.1 + // WebUSB requires USB version at least 2.1 (or 3.x) TinyUSBDevice.setVersion(0x0210); _webusb_dev = this; @@ -146,26 +179,35 @@ void Adafruit_USBD_WebUSB::setLineStateCallback(linestate_callback_t fp) { _linestate_cb = fp; } -uint16_t Adafruit_USBD_WebUSB::getInterfaceDescriptor(uint8_t itfnum, - uint8_t *buf, - uint16_t bufsize) { - // usb core will automatically update endpoint number - uint8_t desc[] = {TUD_VENDOR_DESCRIPTOR(itfnum, 0, EPOUT, EPIN, 64)}; +uint16_t Adafruit_USBD_WebUSB::makeItfDesc(uint8_t itfnum, uint8_t *buf, + uint16_t bufsize, uint8_t ep_in, + uint8_t ep_out) { + uint8_t desc[] = {TUD_VENDOR_DESCRIPTOR(itfnum, 0, ep_out, ep_in, EPSIZE)}; uint16_t const len = sizeof(desc); - if (bufsize < len) { - return 0; - } + // null buffer for length only + if (buf) { + if (bufsize < len) { + return 0; + } - memcpy(buf, desc, len); + memcpy(buf, desc, len); - // update the bFirstInterface in MS OS 2.0 descriptor - // that is binded to WinUSB driver - desc_ms_os_20[0x0a + 0x08 + 4] = itfnum; + // update the bFirstInterface in MS OS 2.0 descriptor + // that is binded to WinUSB driver + desc_ms_os_20[0x0a + 0x08 + 4] = itfnum; + } return len; } +uint16_t Adafruit_USBD_WebUSB::getInterfaceDescriptor(uint8_t itfnum, + uint8_t *buf, + uint16_t bufsize) { + // usb core will automatically update endpoint number + return makeItfDesc(itfnum, buf, bufsize, EPIN, EPOUT); +} + bool Adafruit_USBD_WebUSB::connected(void) { return tud_vendor_mounted() && _connected; } @@ -222,8 +264,13 @@ int Adafruit_USBD_WebUSB::peek(void) { void Adafruit_USBD_WebUSB::flush(void) {} +//--------------------------------------------------------------------+ +// TinyUSB stack callbacks +//--------------------------------------------------------------------+ extern "C" { +uint8_t const *tud_descriptor_bos_cb(void) { return desc_bos; } + // Invoked when a control transfer occurred on an interface of this class // Driver response accordingly to the request and the transfer stage // (setup/data/ack) return false to stall control endpoint (e.g unsupported @@ -293,16 +340,6 @@ bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, return true; } - -// Invoked when DATA Stage of VENDOR's request is complete -bool tud_vendor_control_complete_cb(uint8_t rhport, - tusb_control_request_t const *request) { - (void)rhport; - (void)request; - - // nothing to do - return true; -} } #endif // TUSB_OPT_DEVICE_ENABLED diff --git a/src/arduino/webusb/Adafruit_USBD_WebUSB.h b/src/arduino/webusb/Adafruit_USBD_WebUSB.h index 556ec5b0..e2f64582 100644 --- a/src/arduino/webusb/Adafruit_USBD_WebUSB.h +++ b/src/arduino/webusb/Adafruit_USBD_WebUSB.h @@ -39,7 +39,7 @@ class Adafruit_USBD_WebUSB : public Stream, public Adafruit_USBD_Interface { public: typedef void (*linestate_callback_t)(bool connected); - Adafruit_USBD_WebUSB(void); + Adafruit_USBD_WebUSB(const void *url = NULL); bool begin(void); @@ -65,6 +65,10 @@ class Adafruit_USBD_WebUSB : public Stream, public Adafruit_USBD_Interface { virtual uint16_t getInterfaceDescriptor(uint8_t itfnum, uint8_t *buf, uint16_t bufsize); + // internal use only + uint16_t makeItfDesc(uint8_t itfnum, uint8_t *buf, uint16_t bufsize, + uint8_t ep_in, uint8_t ep_out); + private: bool _connected; const uint8_t *_url; diff --git a/src/class/cdc/cdc.h b/src/class/cdc/cdc.h index ed6f939d..6c311358 100644 --- a/src/class/cdc/cdc.h +++ b/src/class/cdc/cdc.h @@ -216,8 +216,8 @@ typedef enum //--------------------------------------------------------------------+ // Start of all packed definitions for compiler without per-type packed -TU_ATTR_PACKED_BEGIN -TU_ATTR_BIT_FIELD_ORDER_BEGIN +// TU_ATTR_PACKED_BEGIN +// TU_ATTR_BIT_FIELD_ORDER_BEGIN /// Header Functional Descriptor (Communication Interface) typedef struct TU_ATTR_PACKED @@ -398,8 +398,8 @@ typedef struct TU_ATTR_PACKED TU_VERIFY_STATIC(sizeof(cdc_line_control_state_t) == 2, "size is not correct"); -TU_ATTR_PACKED_END // End of all packed definitions -TU_ATTR_BIT_FIELD_ORDER_END +// TU_ATTR_PACKED_END // End of all packed definitions +// TU_ATTR_BIT_FIELD_ORDER_END #ifdef __cplusplus } diff --git a/src/common/tusb_types.h b/src/common/tusb_types.h index d52c0cde..20f832d9 100644 --- a/src/common/tusb_types.h +++ b/src/common/tusb_types.h @@ -263,8 +263,8 @@ enum //--------------------------------------------------------------------+ // Start of all packed definitions for compiler without per-type packed -TU_ATTR_PACKED_BEGIN -TU_ATTR_BIT_FIELD_ORDER_BEGIN +// TU_ATTR_PACKED_BEGIN +// TU_ATTR_BIT_FIELD_ORDER_BEGIN /// USB Device Descriptor typedef struct TU_ATTR_PACKED @@ -482,8 +482,8 @@ typedef struct TU_ATTR_PACKED{ TU_VERIFY_STATIC( sizeof(tusb_control_request_t) == 8, "size is not correct"); -TU_ATTR_PACKED_END // End of all packed definitions -TU_ATTR_BIT_FIELD_ORDER_END +// TU_ATTR_PACKED_END // End of all packed definitions +// TU_ATTR_BIT_FIELD_ORDER_END //--------------------------------------------------------------------+ // Endpoint helper