diff --git a/boards.txt b/boards.txt index 6aee90b5bb9..d9cc12af1d0 100644 --- a/boards.txt +++ b/boards.txt @@ -12,6 +12,7 @@ menu.LORAWAN_REGION=LoRaWan Region menu.LoRaWanDebugLevel=LoRaWan Debug Level menu.LoopCore=Arduino Runs On menu.EventsCore=Events Run On +menu.USBStack=USB Stack ############################################################## ### DO NOT PUT BOARDS ABOVE THE OFFICIAL ESPRESSIF BOARDS! ### @@ -295,6 +296,11 @@ esp32s2.menu.DebugLevel.debug.build.code_debug=4 esp32s2.menu.DebugLevel.verbose=Verbose esp32s2.menu.DebugLevel.verbose.build.code_debug=5 +esp32s2.menu.USBStack.idf=ESP-IDF +esp32s2.menu.USBStack.idf.build.usbstack_flags= +esp32s2.menu.USBStack.tinyusb=Adafruit TinyUSB +esp32s2.menu.USBStack.tinyusb.build.usbstack_flags=-DUSE_TINYUSB "-I{runtime.platform.path}/libraries/Adafruit_TinyUSB_Arduino/src/arduino" + ############################################################## esp32.name=ESP32 Dev Module @@ -960,6 +966,11 @@ feathers2.menu.DebugLevel.debug.build.code_debug=4 feathers2.menu.DebugLevel.verbose=Verbose feathers2.menu.DebugLevel.verbose.build.code_debug=5 +feathers2.menu.USBStack.idf=ESP-IDF +feathers2.menu.USBStack.idf.build.usbstack_flags= +feathers2.menu.USBStack.tinyusb=Adafruit TinyUSB +feathers2.menu.USBStack.tinyusb.build.usbstack_flags=-DUSE_TINYUSB "-I{runtime.platform.path}/libraries/Adafruit_TinyUSB_Arduino/src/arduino" + ############################################################## tinys2.name=UM TinyS2 @@ -1075,6 +1086,11 @@ tinys2.menu.DebugLevel.debug.build.code_debug=4 tinys2.menu.DebugLevel.verbose=Verbose tinys2.menu.DebugLevel.verbose.build.code_debug=5 +tinys2.menu.USBStack.idf=ESP-IDF +tinys2.menu.USBStack.idf.build.usbstack_flags= +tinys2.menu.USBStack.tinyusb=Adafruit TinyUSB +tinys2.menu.USBStack.tinyusb.build.usbstack_flags=-DUSE_TINYUSB "-I{runtime.platform.path}/libraries/Adafruit_TinyUSB_Arduino/src/arduino" + ############################################################## S_ODI_Ultra.name=S.ODI Ultra v1 @@ -1261,6 +1277,11 @@ micros2.menu.DebugLevel.debug.build.code_debug=4 micros2.menu.DebugLevel.verbose=Verbose micros2.menu.DebugLevel.verbose.build.code_debug=5 +micros2.menu.USBStack.idf=ESP-IDF +micros2.menu.USBStack.idf.build.usbstack_flags= +micros2.menu.USBStack.tinyusb=Adafruit TinyUSB +micros2.menu.USBStack.tinyusb.build.usbstack_flags=-DUSE_TINYUSB "-I{runtime.platform.path}/libraries/Adafruit_TinyUSB_Arduino/src/arduino" + ############################################################## magicbit.name=MagicBit @@ -2140,6 +2161,11 @@ sparkfun_esp32s2_thing_plus.menu.DebugLevel.debug.build.code_debug=4 sparkfun_esp32s2_thing_plus.menu.DebugLevel.verbose=Verbose sparkfun_esp32s2_thing_plus.menu.DebugLevel.verbose.build.code_debug=5 +sparkfun_esp32s2_thing_plus.menu.USBStack.idf=ESP-IDF +sparkfun_esp32s2_thing_plus.menu.USBStack.idf.build.usbstack_flags= +sparkfun_esp32s2_thing_plus.menu.USBStack.tinyusb=Adafruit TinyUSB +sparkfun_esp32s2_thing_plus.menu.USBStack.tinyusb.build.usbstack_flags=-DUSE_TINYUSB "-I{runtime.platform.path}/libraries/Adafruit_TinyUSB_Arduino/src/arduino" + ############################################################## sparkfun_lora_gateway_1-channel.name=SparkFun LoRa Gateway 1-Channel @@ -3326,7 +3352,7 @@ adafruit_metro_esp32s2.build.core=esp32 adafruit_metro_esp32s2.build.variant=adafruit_metro_esp32s2 adafruit_metro_esp32s2.build.board=METRO_ESP32S2 -adafruit_metro_esp32s2.build.serial=0 +adafruit_metro_esp32s2.build.serial=1 adafruit_metro_esp32s2.build.f_cpu=240000000L adafruit_metro_esp32s2.build.flash_size=4MB adafruit_metro_esp32s2.build.flash_freq=80m @@ -3449,16 +3475,21 @@ adafruit_metro_esp32s2.menu.DebugLevel.debug.build.code_debug=4 adafruit_metro_esp32s2.menu.DebugLevel.verbose=Verbose adafruit_metro_esp32s2.menu.DebugLevel.verbose.build.code_debug=5 +adafruit_metro_esp32s2.menu.USBStack.idf=ESP-IDF +adafruit_metro_esp32s2.menu.USBStack.idf.build.usbstack_flags= +adafruit_metro_esp32s2.menu.USBStack.tinyusb=Adafruit TinyUSB +adafruit_metro_esp32s2.menu.USBStack.tinyusb.build.usbstack_flags=-DUSE_TINYUSB "-I{runtime.platform.path}/libraries/Adafruit_TinyUSB_Arduino/src/arduino" + ############################################################## adafruit_magtag29_esp32s2.name=Adafruit MagTag 2.9" adafruit_magtag29_esp32s2.vid.0=0x239A -adafruit_magtag29_esp32s2.pid.0=0x80DF +adafruit_magtag29_esp32s2.pid.0=0x80E5 adafruit_magtag29_esp32s2.vid.1=0x239A -adafruit_magtag29_esp32s2.pid.1=0x00DF +adafruit_magtag29_esp32s2.pid.1=0x00E5 adafruit_magtag29_esp32s2.vid.1=0x239A -adafruit_magtag29_esp32s2.pid.1=0x80E0 +adafruit_magtag29_esp32s2.pid.1=0x80E6 adafruit_magtag29_esp32s2.upload.tool=esptool_py adafruit_magtag29_esp32s2.upload.maximum_size=1310720 @@ -3479,7 +3510,7 @@ adafruit_magtag29_esp32s2.build.core=esp32 adafruit_magtag29_esp32s2.build.variant=adafruit_magtag29_esp32s2 adafruit_magtag29_esp32s2.build.board=MAGTAG29_ESP32S2 -adafruit_magtag29_esp32s2.build.serial=0 +adafruit_magtag29_esp32s2.build.serial=1 adafruit_magtag29_esp32s2.build.f_cpu=240000000L adafruit_magtag29_esp32s2.build.flash_size=4MB adafruit_magtag29_esp32s2.build.flash_freq=80m @@ -3602,6 +3633,11 @@ adafruit_magtag29_esp32s2.menu.DebugLevel.debug.build.code_debug=4 adafruit_magtag29_esp32s2.menu.DebugLevel.verbose=Verbose adafruit_magtag29_esp32s2.menu.DebugLevel.verbose.build.code_debug=5 +adafruit_magtag29_esp32s2.menu.USBStack.idf=ESP-IDF +adafruit_magtag29_esp32s2.menu.USBStack.idf.build.usbstack_flags= +adafruit_magtag29_esp32s2.menu.USBStack.tinyusb=Adafruit TinyUSB +adafruit_magtag29_esp32s2.menu.USBStack.tinyusb.build.usbstack_flags=-DUSE_TINYUSB "-I{runtime.platform.path}/libraries/Adafruit_TinyUSB_Arduino/src/arduino" + ############################################################## @@ -3632,7 +3668,7 @@ adafruit_funhouse_esp32s2.build.core=esp32 adafruit_funhouse_esp32s2.build.variant=adafruit_funhouse_esp32s2 adafruit_funhouse_esp32s2.build.board=FUNHOUSE_ESP32S2 -adafruit_funhouse_esp32s2.build.serial=0 +adafruit_funhouse_esp32s2.build.serial=1 adafruit_funhouse_esp32s2.build.f_cpu=240000000L adafruit_funhouse_esp32s2.build.flash_size=4MB adafruit_funhouse_esp32s2.build.flash_freq=80m @@ -3755,6 +3791,11 @@ adafruit_funhouse_esp32s2.menu.DebugLevel.debug.build.code_debug=4 adafruit_funhouse_esp32s2.menu.DebugLevel.verbose=Verbose adafruit_funhouse_esp32s2.menu.DebugLevel.verbose.build.code_debug=5 +adafruit_funhouse_esp32s2.menu.USBStack.idf=ESP-IDF +adafruit_funhouse_esp32s2.menu.USBStack.idf.build.usbstack_flags= +adafruit_funhouse_esp32s2.menu.USBStack.tinyusb=Adafruit TinyUSB +adafruit_funhouse_esp32s2.menu.USBStack.tinyusb.build.usbstack_flags=-DUSE_TINYUSB "-I{runtime.platform.path}/libraries/Adafruit_TinyUSB_Arduino/src/arduino" + ############################################################## @@ -3785,7 +3826,7 @@ adafruit_feather_esp32s2_nopsram.build.core=esp32 adafruit_feather_esp32s2_nopsram.build.variant=adafruit_feather_esp32s2 adafruit_feather_esp32s2_nopsram.build.board=ADAFRUIT_FEATHER_ESP32S2_NOPSRAM -adafruit_feather_esp32s2_nopsram.build.serial=0 +adafruit_feather_esp32s2_nopsram.build.serial=1 adafruit_feather_esp32s2_nopsram.build.f_cpu=240000000L adafruit_feather_esp32s2_nopsram.build.flash_size=4MB adafruit_feather_esp32s2_nopsram.build.flash_freq=80m @@ -3908,6 +3949,11 @@ adafruit_feather_esp32s2_nopsram.menu.DebugLevel.debug.build.code_debug=4 adafruit_feather_esp32s2_nopsram.menu.DebugLevel.verbose=Verbose adafruit_feather_esp32s2_nopsram.menu.DebugLevel.verbose.build.code_debug=5 +adafruit_feather_esp32s2_nopsram.menu.USBStack.idf=ESP-IDF +adafruit_feather_esp32s2_nopsram.menu.USBStack.idf.build.usbstack_flags= +adafruit_feather_esp32s2_nopsram.menu.USBStack.tinyusb=Adafruit TinyUSB +adafruit_feather_esp32s2_nopsram.menu.USBStack.tinyusb.build.usbstack_flags=-DUSE_TINYUSB "-I{runtime.platform.path}/libraries/Adafruit_TinyUSB_Arduino/src/arduino" + ############################################################## @@ -8851,4 +8897,4 @@ esp32-trueverit-iot-driver-mkii.menu.DebugLevel.debug.build.code_debug=4 esp32-trueverit-iot-driver-mkii.menu.DebugLevel.verbose=Verbose esp32-trueverit-iot-driver-mkii.menu.DebugLevel.verbose.build.code_debug=5 -############################################################## \ No newline at end of file +############################################################## diff --git a/cores/esp32/USB.cpp b/cores/esp32/USB.cpp index 066982f69a0..9ad4b1321ac 100644 --- a/cores/esp32/USB.cpp +++ b/cores/esp32/USB.cpp @@ -14,7 +14,7 @@ #include "esp32-hal.h" #include "esp32-hal-tinyusb.h" #include "USB.h" -#if CONFIG_TINYUSB_ENABLED +#if CONFIG_TINYUSB_ENABLED && !defined(USE_TINYUSB) #ifndef USB_VID #define USB_VID USB_ESPRESSIF_VID diff --git a/cores/esp32/USB.h b/cores/esp32/USB.h index 2a5fdb7182e..f651ff1dcd7 100644 --- a/cores/esp32/USB.h +++ b/cores/esp32/USB.h @@ -14,7 +14,12 @@ #pragma once #include "sdkconfig.h" -#if CONFIG_TINYUSB_ENABLED + +#ifdef USE_TINYUSB // Adafruit TinyUSB is selected in menu + +#include "Adafruit_TinyUSB_API.h" + +#elif CONFIG_TINYUSB_ENABLED #include "Arduino.h" #include "USBCDC.h" diff --git a/cores/esp32/USBCDC.cpp b/cores/esp32/USBCDC.cpp index 36b746ecb40..6e93d5c0ca8 100644 --- a/cores/esp32/USBCDC.cpp +++ b/cores/esp32/USBCDC.cpp @@ -15,7 +15,7 @@ #include "esp32-hal-tinyusb.h" #include "USB.h" #include "USBCDC.h" -#if CONFIG_TINYUSB_ENABLED +#if CONFIG_TINYUSB_ENABLED && !defined(USE_TINYUSB) ESP_EVENT_DEFINE_BASE(ARDUINO_USB_CDC_EVENTS); esp_err_t arduino_usb_event_post(esp_event_base_t event_base, int32_t event_id, void *event_data, size_t event_data_size, TickType_t ticks_to_wait); diff --git a/cores/esp32/USBCDC.h b/cores/esp32/USBCDC.h index 541cf633933..bded8d53b3d 100644 --- a/cores/esp32/USBCDC.h +++ b/cores/esp32/USBCDC.h @@ -17,7 +17,13 @@ #include "Stream.h" #include "esp32-hal.h" -#if CONFIG_TINYUSB_CDC_ENABLED + +#ifdef USE_TINYUSB + +// Adafruit TinyUSB is selected in menu +#include "Adafruit_USBD_CDC.h" + +#elif CONFIG_TINYUSB_CDC_ENABLED #include "esp_event.h" diff --git a/cores/esp32/esp32-hal-tinyusb.c b/cores/esp32/esp32-hal-tinyusb.c index cf0bf48f6c8..ee01e1a77c9 100644 --- a/cores/esp32/esp32-hal-tinyusb.c +++ b/cores/esp32/esp32-hal-tinyusb.c @@ -1,6 +1,6 @@ #include "sdkconfig.h" -#if CONFIG_TINYUSB_ENABLED +#if CONFIG_TINYUSB_ENABLED && !defined(USE_TINYUSB) #include #include @@ -140,7 +140,7 @@ static tusb_desc_device_t tinyusb_device_descriptor = { static uint32_t tinyusb_string_descriptor_len = 4; static char * tinyusb_string_descriptor[MAX_STRING_DESCRIPTORS] = { // array of pointer to string descriptors - "\x09\x04", // 0: is supported language is English (0x0409) + (char*) "\x09\x04", // 0: is supported language is English (0x0409) USB_DEVICE_MANUFACTURER,// 1: Manufacturer USB_DEVICE_PRODUCT, // 2: Product USB_DEVICE_SERIAL, // 3: Serials, should use chip ID diff --git a/cores/esp32/esp32-hal-tinyusb.h b/cores/esp32/esp32-hal-tinyusb.h index abef6410b13..afb088a50d4 100644 --- a/cores/esp32/esp32-hal-tinyusb.h +++ b/cores/esp32/esp32-hal-tinyusb.h @@ -16,7 +16,7 @@ #include "esp32-hal.h" #if CONFIG_IDF_TARGET_ESP32S2 -#if CONFIG_TINYUSB_ENABLED +#if CONFIG_TINYUSB_ENABLED && !defined(USE_TINYUSB) #ifdef __cplusplus extern "C" { diff --git a/cores/esp32/main.cpp b/cores/esp32/main.cpp index c7ffb8bcb1a..96cd8a3e212 100644 --- a/cores/esp32/main.cpp +++ b/cores/esp32/main.cpp @@ -48,7 +48,12 @@ void loopTask(void *pvParameters) extern "C" void app_main() { #if ARDUINO_SERIAL_PORT //Serial used for USB CDC +#ifdef USE_TINYUSB + // Adafruit TinyUSB is selected in menu + TinyUSB_Device_Init(0); +#else USB.begin(); +#endif #endif loopTaskWDTEnabled = false; initArduino(); diff --git a/libraries/Adafruit_TinyUSB_Arduino/LICENSE b/libraries/Adafruit_TinyUSB_Arduino/LICENSE new file mode 100644 index 00000000000..bf05fe8f7d7 --- /dev/null +++ b/libraries/Adafruit_TinyUSB_Arduino/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2019 Ha Thach for Adafruit Industries + +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. diff --git a/libraries/Adafruit_TinyUSB_Arduino/README.md b/libraries/Adafruit_TinyUSB_Arduino/README.md new file mode 100644 index 00000000000..2ecc1dec8c8 --- /dev/null +++ b/libraries/Adafruit_TinyUSB_Arduino/README.md @@ -0,0 +1,46 @@ +# Adafruit TinyUSB Library for Arduino + +[![Build Status](https://github.com/adafruit/Adafruit_TinyUSB_Arduino/workflows/Build/badge.svg)](https://github.com/adafruit/Adafruit_TinyUSB_Arduino/actions) [![License](https://img.shields.io/badge/license-MIT-brightgreen.svg)](https://opensource.org/licenses/MIT) + +This library is a Arduino-friendly version of [TinyUSB](https://github.com/hathach/tinyusb) stack. It is designed with structure and APIs that are easily integrated to existing or new Arduino Core. Supported platform including: + +- [Adafruit_nRF52_Arduino](https://github.com/adafruit/Adafruit_nRF52_Arduino) +- [Adafruit/ArduinoCore-samd](https://github.com/adafruit/ArduinoCore-samd) selectable via menu`Tools->USB Stack->TinyUSB` +- [earlephilhower/arduino-pico](https://github.com/earlephilhower/arduino-pico) selectable via menu `Tools->USB Stack->Adafruit TinyUSB` + +Current class drivers supported are + +- Communication (CDC): which is used to implement `Serial` monitor +- Human Interface Device (HID): Generic (In & Out), Keyboard, Mouse, Gamepad etc ... +- Mass Storage Class (MSC): with multiple LUNs +- Musical Instrument Digital Interface (MIDI) +- WebUSB with vendor specific class + +For supported ArduinoCore, to use this library, you only need to have `` in your sketch. If your ArduinoCore does not support TinyUSB library yet, it is rather simple to port. + +## Class Driver API + +More document to write ... + +## Porting Guide + +It is rather easy if you want to integrate TinyUSB lib to your ArduinoCore. + +### ArduinoCore Changes + +1. Add this repo as submodule (or have local copy) at your ArduioCore/libraries/Adafruit_TinyUSB_Arduino (much like SPI). +2. Since Serial as CDC is considered as part of the core, we need to have `#include "Adafruit_USBD_CDC.h"` within your `Arduino.h`. For this to work, your `platform.txt` include path need to have `"-I{runtime.platform.path}/libraries/Adafruit_TinyUSB_Arduino/src/arduino"`. +3. In your `main.cpp` before setup() invoke the `TinyUSB_Device_Init(rhport)`. This will initialize usb device hardware and tinyusb stack and also include Serial as an instance of CDC class. +4. `TinyUSB_Device_Task()` must be called whenever there is new USB event. Depending on your core and MCU with or without RTOS. There are many ways to run the task. For example: + - Use USB IRQn to set flag then invoke function later on after exiting IRQ. + - Just invoke function after the loop(), within yield(), and delay() +5. `TinyUSB_Device_FlushCDC()` should also be called often to send out Serial data as well. +6. Note: For low power platform that make use of WFI()/WFE(), extra care is required before mcu go into low power mode. Check out my PR to circuipython for reference https://github.com/adafruit/circuitpython/pull/2956 + +### Library Changes + +In addition to core changes, library need to be ported to your platform. Don't worry, tinyusb stack has already done most of heavy-lifting. You only need to write a few APIs + +1. `TinyUSB_Port_InitDevice()` hardware specific (clock, phy) to enable usb hardware then call tud_init(). This API is called as part of TinyUSB_Device_Init() invocation. +2. `TinyUSB_Port_EnterDFU()` which is called when device need to enter DFU mode, usually by touch1200 feature +3. `TinyUSB_Port_GetSerialNumber()` which is called to get unique MCU Serial ID to used as Serial string descriptor. diff --git a/libraries/Adafruit_TinyUSB_Arduino/examples/CDC/cdc_multi/cdc_multi.ino b/libraries/Adafruit_TinyUSB_Arduino/examples/CDC/cdc_multi/cdc_multi.ino new file mode 100644 index 00000000000..8bd8500014b --- /dev/null +++ b/libraries/Adafruit_TinyUSB_Arduino/examples/CDC/cdc_multi/cdc_multi.ino @@ -0,0 +1,91 @@ +/* + This example demonstrates the use of multiple USB CDC/ACM "Virtual + Serial" ports, using Ha Thach's TinyUSB library, and the port of + that library to the Arduino environment + + https://github.com/hathach/tinyusb + https://github.com/adafruit/Adafruit_TinyUSB_Arduino + + Written by Bill Westfield (aka WestfW), June 2021. + Copyright 2021 by Bill Westfield + MIT license, check LICENSE for more information + + The example creates three virtual serial ports. Text entered on + any of the ports will be echoed to the all ports. + + The max number of CDC ports (CFG_TUD_CDC) has to be changed to at + least 2, changed in the core tusb_config.h file. +*/ + +#include + +#define LED LED_BUILTIN + +// Create extra USB Serial Ports. "Serial" is already created. +Adafruit_USBD_CDC USBSer1; + +void setup() { + pinMode(LED, OUTPUT); + + // start up all of the USB Vitual ports, and wait for them to enumerate. + Serial.begin(115200); + USBSer1.begin(115200); + + while (!Serial || !USBSer1) { + if (Serial) { + Serial.println("Waiting for other USB ports"); + } + + if (USBSer1) { + USBSer1.println("Waiting for other USB ports"); + } + + delay(1000); + } + + Serial.print("You are port 0\n\r\n0> "); + USBSer1.print("You are port 1\n\r\n1> "); +} + +int LEDstate = 0; + +void loop() { + int ch; + + ch = Serial.read(); + if (ch > 0) { + printAll(ch); + } + + ch = USBSer1.read(); + if (ch > 0) { + printAll(ch); + } + + if (delay_without_delaying(500)) { + LEDstate = !LEDstate; + digitalWrite(LED, LEDstate); + } +} + +// print to all CDC ports +void printAll(int ch) { + // always lower case + Serial.write(tolower(ch)); + + // always upper case + USBSer1.write(toupper(ch)); +} + +// Helper: non-blocking "delay" alternative. +boolean delay_without_delaying(unsigned long time) { + // return false if we're still "delaying", true if time ms has passed. + // this should look a lot like "blink without delay" + static unsigned long previousmillis = 0; + unsigned long currentmillis = millis(); + if (currentmillis - previousmillis >= time) { + previousmillis = currentmillis; + return true; + } + return false; +} diff --git a/libraries/Adafruit_TinyUSB_Arduino/examples/CDC/no_serial/no_serial.ino b/libraries/Adafruit_TinyUSB_Arduino/examples/CDC/no_serial/no_serial.ino new file mode 100644 index 00000000000..1f04357c7fc --- /dev/null +++ b/libraries/Adafruit_TinyUSB_Arduino/examples/CDC/no_serial/no_serial.ino @@ -0,0 +1,36 @@ +/********************************************************************* + Adafruit invests time and resources providing this open source code, + please support Adafruit and open-source hardware by purchasing + products from Adafruit! + + MIT license, check LICENSE for more information + Copyright (c) 2019 Ha Thach for Adafruit Industries + All text above, and the splash screen below must be included in + any redistribution +*********************************************************************/ + +#include "Adafruit_TinyUSB.h" + +/* This sketch demonstrates USB CDC Serial can be dropped by simply + * call Serial.end() within setup(). This must be called before any + * other USB interfaces (MSC / HID) begin to have a clean configuration + * + * Note: this will cause device to loose the touch1200 and require + * user manual interaction to put device into bootloader/DFU mode. + */ + +int led = LED_BUILTIN; + +void setup() +{ + Serial.end(); + pinMode(led, OUTPUT); +} + +void loop() +{ + digitalWrite(led, HIGH); + delay(1000); + digitalWrite(led, LOW); + delay(1000); +} diff --git a/libraries/Adafruit_TinyUSB_Arduino/examples/Composite/hid_generic_inout_ramdisk/README.md b/libraries/Adafruit_TinyUSB_Arduino/examples/Composite/hid_generic_inout_ramdisk/README.md new file mode 100644 index 00000000000..b963dbd7a86 --- /dev/null +++ b/libraries/Adafruit_TinyUSB_Arduino/examples/Composite/hid_generic_inout_ramdisk/README.md @@ -0,0 +1 @@ +Check the example host application in `../../HID/hid_generic_inout` \ No newline at end of file diff --git a/libraries/Adafruit_TinyUSB_Arduino/examples/Composite/hid_generic_inout_ramdisk/hid_generic_inout_ramdisk.ino b/libraries/Adafruit_TinyUSB_Arduino/examples/Composite/hid_generic_inout_ramdisk/hid_generic_inout_ramdisk.ino new file mode 100644 index 00000000000..b4ecbf34f79 --- /dev/null +++ b/libraries/Adafruit_TinyUSB_Arduino/examples/Composite/hid_generic_inout_ramdisk/hid_generic_inout_ramdisk.ino @@ -0,0 +1,135 @@ +/********************************************************************* + Adafruit invests time and resources providing this open source code, + please support Adafruit and open-source hardware by purchasing + products from Adafruit! + + MIT license, check LICENSE for more information + Copyright (c) 2019 Ha Thach for Adafruit Industries + All text above, and the splash screen below must be included in + any redistribution +*********************************************************************/ + +/* This example demonstrate HID Generic raw Input & Output. + * It will receive data from Host (In endpoint) and echo back (Out endpoint). + * HID Report descriptor use vendor for usage page (using template TUD_HID_REPORT_DESC_GENERIC_INOUT) + * + * There are 2 ways to test the sketch + * 1. Using nodejs + * - Install nodejs and nmp to your PC + * - Install execellent node-hid (https://github.com/node-hid/node-hid) by + * $ npm install node-hid + * - Run provided hid test script + * $ node hid_test.js + * + * 2. Using python hidRun + * - Python and `hid` package is required, for installation please follow https://pypi.org/project/hid/ + * - Run provided hid test script to send and receive data to this device. + * $ python3 hid_test.py + */ + +#include "Adafruit_TinyUSB.h" + +// 8KB is the smallest size that windows allow to mount +#define DISK_BLOCK_NUM 16 +#define DISK_BLOCK_SIZE 512 +#include "ramdisk.h" + +// HID report descriptor using TinyUSB's template +// Generic In Out with 64 bytes report (max) +uint8_t const desc_hid_report[] = +{ + TUD_HID_REPORT_DESC_GENERIC_INOUT(64) +}; + +Adafruit_USBD_HID usb_hid; +Adafruit_USBD_MSC usb_msc; + +// the setup function runs once when you press reset or power the board +void setup() +{ + usb_msc.setID("Adafruit", "Mass Storage", "1.0"); + + // Set disk size + usb_msc.setCapacity(DISK_BLOCK_NUM, DISK_BLOCK_SIZE); + + // Set callback + usb_msc.setReadWriteCallback(msc_read_cb, msc_write_cb, msc_flush_cb); + + // Set Lun ready (RAM disk is always ready) + usb_msc.setUnitReady(true); + + usb_msc.begin(); + + usb_hid.enableOutEndpoint(true); + usb_hid.setPollInterval(2); + usb_hid.setReportDescriptor(desc_hid_report, sizeof(desc_hid_report)); + usb_hid.setReportCallback(get_report_callback, set_report_callback); + + usb_hid.begin(); + + Serial.begin(115200); + Serial.println("Waiting for USBDevice mount"); + // wait until device mounted + while( !USBDevice.mounted() ) delay(1); + + Serial.println("Adafruit TinyUSB HID Generic In Out example"); +} + +void loop() +{ + // nothing to do +} + +// 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 get_report_callback (uint8_t report_id, hid_report_type_t report_type, uint8_t* buffer, uint16_t reqlen) +{ + // not used in this example + (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 set_report_callback(uint8_t report_id, hid_report_type_t report_type, uint8_t const* buffer, uint16_t bufsize) +{ + // This example doesn't use multiple report and report ID + (void) report_id; + (void) report_type; + + // echo back anything we received from host + usb_hid.sendReport(0, buffer, bufsize); +} + +// Callback invoked when received READ10 command. +// Copy disk's data to buffer (up to bufsize) and +// return number of copied bytes (must be multiple of block size) +int32_t msc_read_cb (uint32_t lba, void* buffer, uint32_t bufsize) +{ + uint8_t const* addr = msc_disk[lba]; + memcpy(buffer, addr, bufsize); + + return bufsize; +} + +// Callback invoked when received WRITE10 command. +// Process data in buffer to disk's storage and +// return number of written bytes (must be multiple of block size) +int32_t msc_write_cb (uint32_t lba, uint8_t* buffer, uint32_t bufsize) +{ + uint8_t* addr = msc_disk[lba]; + memcpy(addr, buffer, bufsize); + + return bufsize; +} + +// Callback invoked when WRITE10 command is completed (status received and accepted by host). +// used to flush any pending cache. +void msc_flush_cb (void) +{ + // nothing to do +} diff --git a/libraries/Adafruit_TinyUSB_Arduino/examples/Composite/hid_generic_inout_ramdisk/ramdisk.h b/libraries/Adafruit_TinyUSB_Arduino/examples/Composite/hid_generic_inout_ramdisk/ramdisk.h new file mode 100644 index 00000000000..11aae403563 --- /dev/null +++ b/libraries/Adafruit_TinyUSB_Arduino/examples/Composite/hid_generic_inout_ramdisk/ramdisk.h @@ -0,0 +1,113 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2019 Ha Thach for Adafruit Industries + * + * 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 RAMDISK_H_ +#define RAMDISK_H_ + +#define README_CONTENTS \ + "This is TinyUSB MassStorage device demo for Arduino on RAM disk." + +uint8_t msc_disk[DISK_BLOCK_NUM][DISK_BLOCK_SIZE] = { + //------------- Block0: Boot Sector -------------// + // byte_per_sector = DISK_BLOCK_SIZE; fat12_sector_num_16 = + // DISK_BLOCK_NUM; sector_per_cluster = 1; reserved_sectors = 1; fat_num = + // 1; fat12_root_entry_num = 16; sector_per_fat = 1; sector_per_track = + // 1; head_num = 1; hidden_sectors = 0; drive_number = 0x80; + // media_type = 0xf8; extended_boot_signature = 0x29; filesystem_type = + // "FAT12 "; volume_serial_number = 0x1234; volume_label = "TinyUSB MSC"; + // FAT magic code at offset 510-511 + {0xEB, 0x3C, 0x90, 0x4D, 0x53, 0x44, 0x4F, 0x53, 0x35, 0x2E, 0x30, 0x00, + 0x02, 0x01, 0x01, 0x00, 0x01, 0x10, 0x00, 0x10, 0x00, 0xF8, 0x01, 0x00, + 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x80, 0x00, 0x29, 0x34, 0x12, 0x00, 0x00, 'T', 'i', 'n', 'y', 'U', 'S', + 'B', ' ', 'M', 'S', 'C', 0x46, 0x41, 0x54, 0x31, 0x32, 0x20, 0x20, 0x20, + 0x00, 0x00, + + // Zero up to 2 last bytes of FAT magic code + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x55, 0xAA}, + + //------------- Block1: FAT12 Table -------------// + { + 0xF8, 0xFF, 0xFF, 0xFF, 0x0F // // first 2 entries must be F8FF, third + // entry is cluster end of readme file + }, + + //------------- Block2: Root Directory -------------// + { + // first entry is volume label + 'T', 'i', 'n', 'y', 'U', 'S', 'B', ' ', 'M', 'S', 'C', 0x08, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4F, 0x6D, 0x65, 0x43, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + // second entry is readme file + 'R', 'E', 'A', 'D', 'M', 'E', ' ', ' ', 'T', 'X', 'T', 0x20, 0x00, 0xC6, + 0x52, 0x6D, 0x65, 0x43, 0x65, 0x43, 0x00, 0x00, 0x88, 0x6D, 0x65, 0x43, + 0x02, 0x00, sizeof(README_CONTENTS) - 1, 0x00, 0x00, + 0x00 // readme's files size (4 Bytes) + }, + + //------------- Block3: Readme Content -------------// + README_CONTENTS}; + +#endif /* RAMDISK_H_ */ diff --git a/libraries/Adafruit_TinyUSB_Arduino/examples/Composite/mouse_external_flash/mouse_external_flash.ino b/libraries/Adafruit_TinyUSB_Arduino/examples/Composite/mouse_external_flash/mouse_external_flash.ino new file mode 100644 index 00000000000..83aa4aa88f6 --- /dev/null +++ b/libraries/Adafruit_TinyUSB_Arduino/examples/Composite/mouse_external_flash/mouse_external_flash.ino @@ -0,0 +1,163 @@ +/********************************************************************* + Adafruit invests time and resources providing this open source code, + please support Adafruit and open-source hardware by purchasing + products from Adafruit! + + MIT license, check LICENSE for more information + Copyright (c) 2019 Ha Thach for Adafruit Industries + All text above, and the splash screen below must be included in + any redistribution +*********************************************************************/ + +/* This sketch demonstrates USB Mass Storage and HID mouse (and CDC) + * - Enumerated as disk using on-board external flash + * - Press button pin will move mouse toward bottom right of monitor + */ + +#include "SPI.h" +#include "SdFat.h" +#include "Adafruit_SPIFlash.h" +#include "Adafruit_TinyUSB.h" + +// Uncomment to run example with FRAM +// #define FRAM_CS A5 +// #define FRAM_SPI SPI + +#if defined(FRAM_CS) && defined(FRAM_SPI) + Adafruit_FlashTransport_SPI flashTransport(FRAM_CS, FRAM_SPI); + +#elif defined(ARDUINO_ARCH_ESP32) + // ESP32 use same flash device that store code. + // Therefore there is no need to specify the SPI and SS + Adafruit_FlashTransport_ESP32 flashTransport; + +#else + // On-board external flash (QSPI or SPI) macros should already + // defined in your board variant if supported + // - EXTERNAL_FLASH_USE_QSPI + // - EXTERNAL_FLASH_USE_CS/EXTERNAL_FLASH_USE_SPI + #if defined(EXTERNAL_FLASH_USE_QSPI) + Adafruit_FlashTransport_QSPI flashTransport; + + #elif defined(EXTERNAL_FLASH_USE_SPI) + Adafruit_FlashTransport_SPI flashTransport(EXTERNAL_FLASH_USE_CS, EXTERNAL_FLASH_USE_SPI); + + #else + #error No QSPI/SPI flash are defined on your board variant.h ! + #endif +#endif + +Adafruit_SPIFlash flash(&flashTransport); + +Adafruit_USBD_MSC usb_msc; + +// HID report descriptor using TinyUSB's template +// Single Report (no ID) descriptor +uint8_t const desc_hid_report[] = +{ + TUD_HID_REPORT_DESC_MOUSE() +}; + +Adafruit_USBD_HID usb_hid; + +#if defined ARDUINO_SAMD_CIRCUITPLAYGROUND_EXPRESS + const int pin = 4; // Left Button + bool activeState = true; +#elif defined ARDUINO_NRF52840_FEATHER + const int pin = 7; // UserSw + 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() +{ + flash.begin(); + + pinMode(LED_BUILTIN, OUTPUT); + + // Set disk vendor id, product id and revision with string up to 8, 16, 4 characters respectively + usb_msc.setID("Adafruit", "External Flash", "1.0"); + + // Set callback + usb_msc.setReadWriteCallback(msc_read_cb, msc_write_cb, msc_flush_cb); + + // Set disk size, block size should be 512 regardless of spi flash page size + usb_msc.setCapacity(flash.size()/512, 512); + + // MSC is ready for read/write + usb_msc.setUnitReady(true); + + usb_msc.begin(); + + + // Set up button + pinMode(pin, activeState ? INPUT_PULLDOWN : INPUT_PULLUP); + + usb_hid.setReportDescriptor(desc_hid_report, sizeof(desc_hid_report)); + usb_hid.begin(); + + Serial.begin(115200); + //while ( !Serial ) delay(10); // wait for native usb + + Serial.println("Adafruit TinyUSB Mouse + Mass Storage (external flash) example"); +} + +void loop() +{ + // poll gpio once each 10 ms + delay(10); + + // button is active low + uint32_t const btn = (digitalRead(pin) == activeState); + + // Remote wakeup + if ( USBDevice.suspended() && btn ) + { + // Wake up host if we are in suspend mode + // and REMOTE_WAKEUP feature is enabled by host + tud_remote_wakeup(); + } + + /*------------- Mouse -------------*/ + if ( usb_hid.ready() ) + { + if ( btn ) + { + int8_t const delta = 5; + usb_hid.mouseMove(0, delta, delta); // no ID: right + down + + // delay a bit before attempt to send keyboard report + delay(10); + } + } +} + +// Callback invoked when received READ10 command. +// Copy disk's data to buffer (up to bufsize) and +// return number of copied bytes (must be multiple of block size) +int32_t msc_read_cb (uint32_t lba, void* buffer, uint32_t bufsize) +{ + // Note: SPIFLash Bock API: readBlocks/writeBlocks/syncBlocks + // already include 4K sector caching internally. We don't need to cache it, yahhhh!! + return flash.readBlocks(lba, (uint8_t*) buffer, bufsize/512) ? bufsize : -1; +} + +// Callback invoked when received WRITE10 command. +// Process data in buffer to disk's storage and +// return number of written bytes (must be multiple of block size) +int32_t msc_write_cb (uint32_t lba, uint8_t* buffer, uint32_t bufsize) +{ + // Note: SPIFLash Bock API: readBlocks/writeBlocks/syncBlocks + // already include 4K sector caching internally. We don't need to cache it, yahhhh!! + return flash.writeBlocks(lba, buffer, bufsize/512) ? bufsize : -1; +} + +// Callback invoked when WRITE10 command is completed (status received and accepted by host). +// used to flush any pending cache. +void msc_flush_cb (void) +{ + flash.syncBlocks(); +} diff --git a/libraries/Adafruit_TinyUSB_Arduino/examples/Composite/mouse_ramdisk/mouse_ramdisk.ino b/libraries/Adafruit_TinyUSB_Arduino/examples/Composite/mouse_ramdisk/mouse_ramdisk.ino new file mode 100644 index 00000000000..70a942b48b7 --- /dev/null +++ b/libraries/Adafruit_TinyUSB_Arduino/examples/Composite/mouse_ramdisk/mouse_ramdisk.ino @@ -0,0 +1,131 @@ +/********************************************************************* + Adafruit invests time and resources providing this open source code, + please support Adafruit and open-source hardware by purchasing + products from Adafruit! + + MIT license, check LICENSE for more information + Copyright (c) 2019 Ha Thach for Adafruit Industries + All text above, and the splash screen below must be included in + any redistribution +*********************************************************************/ + +/* This sketch demonstrates USB Mass Storage and HID mouse (and CDC) + * - Enumerated as 8KB flash disk + * - Press button pin will move mouse toward bottom right of monitor + */ + +#include "Adafruit_TinyUSB.h" + +// 8KB is the smallest size that windows allow to mount +#define DISK_BLOCK_NUM 16 +#define DISK_BLOCK_SIZE 512 +#include "ramdisk.h" + +// HID report descriptor using TinyUSB's template +// Single Report (no ID) descriptor +uint8_t const desc_hid_report[] = +{ + TUD_HID_REPORT_DESC_MOUSE() +}; + +Adafruit_USBD_HID usb_hid; +Adafruit_USBD_MSC usb_msc; + +#if defined ARDUINO_SAMD_CIRCUITPLAYGROUND_EXPRESS || defined ARDUINO_NRF52840_CIRCUITPLAY + const int pin = 4; // Left Button + 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() +{ + // Set disk vendor id, product id and revision with string up to 8, 16, 4 characters respectively + usb_msc.setID("Adafruit", "Mass Storage", "1.0"); + + // Set disk size + usb_msc.setCapacity(DISK_BLOCK_NUM, DISK_BLOCK_SIZE); + + // Set callback + usb_msc.setReadWriteCallback(msc_read_cb, msc_write_cb, msc_flush_cb); + + // Set Lun ready (RAM disk is always ready) + usb_msc.setUnitReady(true); + + usb_msc.begin(); + + // Set up button + pinMode(pin, activeState ? INPUT_PULLDOWN : INPUT_PULLUP); + + usb_hid.setReportDescriptor(desc_hid_report, sizeof(desc_hid_report)); + usb_hid.begin(); + + Serial.begin(115200); + while( !USBDevice.mounted() ) delay(1); // wait for native usb + + Serial.println("Adafruit TinyUSB Mouse + Mass Storage (ramdisk) example"); +} + +void loop() +{ + // poll gpio once each 10 ms + delay(10); + + // button is active low + uint32_t const btn = (digitalRead(pin) == activeState); + + // Remote wakeup + if ( USBDevice.suspended() && btn ) + { + // Wake up host if we are in suspend mode + // and REMOTE_WAKEUP feature is enabled by host + tud_remote_wakeup(); + } + + /*------------- Mouse -------------*/ + if ( usb_hid.ready() ) + { + if ( btn ) + { + int8_t const delta = 5; + usb_hid.mouseMove(0, delta, delta); // no ID: right + down + + // delay a bit before attempt to send keyboard report + delay(10); + } + } +} + +// Callback invoked when received READ10 command. +// Copy disk's data to buffer (up to bufsize) and +// return number of copied bytes (must be multiple of block size) +int32_t msc_read_cb (uint32_t lba, void* buffer, uint32_t bufsize) +{ + uint8_t const* addr = msc_disk[lba]; + memcpy(buffer, addr, bufsize); + + return bufsize; +} + +// Callback invoked when received WRITE10 command. +// Process data in buffer to disk's storage and +// return number of written bytes (must be multiple of block size) +int32_t msc_write_cb (uint32_t lba, uint8_t* buffer, uint32_t bufsize) +{ + uint8_t* addr = msc_disk[lba]; + memcpy(addr, buffer, bufsize); + + return bufsize; +} + +// Callback invoked when WRITE10 command is completed (status received and accepted by host). +// used to flush any pending cache. +void msc_flush_cb (void) +{ + // nothing to do +} diff --git a/libraries/Adafruit_TinyUSB_Arduino/examples/Composite/mouse_ramdisk/ramdisk.h b/libraries/Adafruit_TinyUSB_Arduino/examples/Composite/mouse_ramdisk/ramdisk.h new file mode 100644 index 00000000000..11aae403563 --- /dev/null +++ b/libraries/Adafruit_TinyUSB_Arduino/examples/Composite/mouse_ramdisk/ramdisk.h @@ -0,0 +1,113 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2019 Ha Thach for Adafruit Industries + * + * 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 RAMDISK_H_ +#define RAMDISK_H_ + +#define README_CONTENTS \ + "This is TinyUSB MassStorage device demo for Arduino on RAM disk." + +uint8_t msc_disk[DISK_BLOCK_NUM][DISK_BLOCK_SIZE] = { + //------------- Block0: Boot Sector -------------// + // byte_per_sector = DISK_BLOCK_SIZE; fat12_sector_num_16 = + // DISK_BLOCK_NUM; sector_per_cluster = 1; reserved_sectors = 1; fat_num = + // 1; fat12_root_entry_num = 16; sector_per_fat = 1; sector_per_track = + // 1; head_num = 1; hidden_sectors = 0; drive_number = 0x80; + // media_type = 0xf8; extended_boot_signature = 0x29; filesystem_type = + // "FAT12 "; volume_serial_number = 0x1234; volume_label = "TinyUSB MSC"; + // FAT magic code at offset 510-511 + {0xEB, 0x3C, 0x90, 0x4D, 0x53, 0x44, 0x4F, 0x53, 0x35, 0x2E, 0x30, 0x00, + 0x02, 0x01, 0x01, 0x00, 0x01, 0x10, 0x00, 0x10, 0x00, 0xF8, 0x01, 0x00, + 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x80, 0x00, 0x29, 0x34, 0x12, 0x00, 0x00, 'T', 'i', 'n', 'y', 'U', 'S', + 'B', ' ', 'M', 'S', 'C', 0x46, 0x41, 0x54, 0x31, 0x32, 0x20, 0x20, 0x20, + 0x00, 0x00, + + // Zero up to 2 last bytes of FAT magic code + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x55, 0xAA}, + + //------------- Block1: FAT12 Table -------------// + { + 0xF8, 0xFF, 0xFF, 0xFF, 0x0F // // first 2 entries must be F8FF, third + // entry is cluster end of readme file + }, + + //------------- Block2: Root Directory -------------// + { + // first entry is volume label + 'T', 'i', 'n', 'y', 'U', 'S', 'B', ' ', 'M', 'S', 'C', 0x08, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4F, 0x6D, 0x65, 0x43, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + // second entry is readme file + 'R', 'E', 'A', 'D', 'M', 'E', ' ', ' ', 'T', 'X', 'T', 0x20, 0x00, 0xC6, + 0x52, 0x6D, 0x65, 0x43, 0x65, 0x43, 0x00, 0x00, 0x88, 0x6D, 0x65, 0x43, + 0x02, 0x00, sizeof(README_CONTENTS) - 1, 0x00, 0x00, + 0x00 // readme's files size (4 Bytes) + }, + + //------------- Block3: Readme Content -------------// + README_CONTENTS}; + +#endif /* RAMDISK_H_ */ diff --git a/libraries/Adafruit_TinyUSB_Arduino/examples/HID/hid_composite/hid_composite.ino b/libraries/Adafruit_TinyUSB_Arduino/examples/HID/hid_composite/hid_composite.ino new file mode 100644 index 00000000000..1fe40f02297 --- /dev/null +++ b/libraries/Adafruit_TinyUSB_Arduino/examples/HID/hid_composite/hid_composite.ino @@ -0,0 +1,145 @@ +/********************************************************************* + Adafruit invests time and resources providing this open source code, + please support Adafruit and open-source hardware by purchasing + products from Adafruit! + + MIT license, check LICENSE for more information + Copyright (c) 2019 Ha Thach for Adafruit Industries + All text above, and the splash screen below must be included in + any redistribution +*********************************************************************/ + +#include "Adafruit_TinyUSB.h" + +/* This sketch demonstrates multiple report USB HID. + * Press button pin will move + * - mouse toward bottom right of monitor + * - send 'a' key + * + * Depending on the board, the button pin + * and its active state (when pressed) are different + */ +#if defined ARDUINO_SAMD_CIRCUITPLAYGROUND_EXPRESS + const int pin = 4; // Left Button + bool activeState = true; +#elif defined ARDUINO_NRF52840_FEATHER + const int pin = 7; // UserSw + bool activeState = false; +#else + const int pin = 12; + bool activeState = false; +#endif + + +// Report ID +enum +{ + RID_KEYBOARD = 1, + RID_MOUSE, + RID_CONSUMER_CONTROL, // Media, volume etc .. +}; + +// HID report descriptor using TinyUSB's template +uint8_t const desc_hid_report[] = +{ + TUD_HID_REPORT_DESC_KEYBOARD( HID_REPORT_ID(RID_KEYBOARD) ), + TUD_HID_REPORT_DESC_MOUSE ( HID_REPORT_ID(RID_MOUSE) ), + TUD_HID_REPORT_DESC_CONSUMER( HID_REPORT_ID(RID_CONSUMER_CONTROL) ) +}; + +// USB HID object +Adafruit_USBD_HID usb_hid; + +// the setup function runs once when you press reset or power the board +void setup() +{ + usb_hid.setPollInterval(2); + usb_hid.setReportDescriptor(desc_hid_report, sizeof(desc_hid_report)); + //usb_hid.setStringDescriptor("TinyUSB HID Composite"); + + usb_hid.begin(); + + // Set up button, pullup opposite to active state + pinMode(pin, activeState ? INPUT_PULLDOWN : INPUT_PULLUP); + + Serial.begin(115200); + Serial.println("Adafruit TinyUSB HID Composite example"); + + // wait until device mounted + while( !USBDevice.mounted() ) delay(1); +} + +void loop() +{ + // poll gpio once each 10 ms + delay(10); + + // Whether button is pressed + bool btn_pressed = (digitalRead(pin) == activeState); + + // Remote wakeup + if ( USBDevice.suspended() && btn_pressed ) + { + // Wake up host if we are in suspend mode + // and REMOTE_WAKEUP feature is enabled by host + USBDevice.remoteWakeup(); + } + + /*------------- Mouse -------------*/ + if ( usb_hid.ready() && btn_pressed ) + { + int8_t const delta = 5; + usb_hid.mouseMove(RID_MOUSE, delta, delta); // right + down + + // delay a bit before attempt to send keyboard report + delay(10); + } + + /*------------- Keyboard -------------*/ + if ( usb_hid.ready() ) + { + // use to send key release report + static bool has_key = false; + + if ( btn_pressed ) + { + uint8_t keycode[6] = { 0 }; + keycode[0] = HID_KEY_A; + + usb_hid.keyboardReport(RID_KEYBOARD, 0, keycode); + + has_key = true; + }else + { + // send empty key report if previously has key pressed + if (has_key) usb_hid.keyboardRelease(RID_KEYBOARD); + has_key = false; + } + + // delay a bit before attempt to send consumer report + delay(10); + } + + /*------------- Consumer Control -------------*/ + if ( usb_hid.ready() ) + { + // Consumer Control is used to control Media playback, Volume, Brightness etc ... + // Consumer report is 2-byte containing the control code of the key + // For list of control check out https://github.com/hathach/tinyusb/blob/master/src/class/hid/hid.h#L544 + + // use to send consumer release report + static bool has_consumer_key = false; + + if ( btn_pressed ) + { + // send volume down (0x00EA) + usb_hid.sendReport16(RID_CONSUMER_CONTROL, HID_USAGE_CONSUMER_VOLUME_DECREMENT); + has_consumer_key = true; + }else + { + // release the consume key by sending zero (0x0000) + if (has_consumer_key) usb_hid.sendReport16(RID_CONSUMER_CONTROL, 0); + has_consumer_key = false; + } + } +} diff --git a/libraries/Adafruit_TinyUSB_Arduino/examples/HID/hid_composite_joy_featherwing/hid_composite_joy_featherwing.ino b/libraries/Adafruit_TinyUSB_Arduino/examples/HID/hid_composite_joy_featherwing/hid_composite_joy_featherwing.ino new file mode 100644 index 00000000000..fa058a5c513 --- /dev/null +++ b/libraries/Adafruit_TinyUSB_Arduino/examples/HID/hid_composite_joy_featherwing/hid_composite_joy_featherwing.ino @@ -0,0 +1,154 @@ +/********************************************************************* + Adafruit invests time and resources providing this open source code, + please support Adafruit and open-source hardware by purchasing + products from Adafruit! + + MIT license, check LICENSE for more information + Copyright (c) 2019 Ha Thach for Adafruit Industries + All text above, and the splash screen below must be included in + any redistribution +*********************************************************************/ + +/* This sketch demonstrates USB HID Mouse and Keyboard with Joy Feather Wing. + * - The analog stick move mouse cursor + * - Button A, B, X, Y will send character a, b, x, y + * - Any actions will wake up PC host if it is in suspended (standby) mode. + * + * Joy Feather Wing: https://www.adafruit.com/product/3632 + * + * Following library is required + * - Adafruit_seesaw + */ + +#include "Adafruit_TinyUSB.h" +#include "Adafruit_seesaw.h" + +#define BUTTON_A 6 +#define BUTTON_B 7 +#define BUTTON_Y 9 +#define BUTTON_X 10 +uint32_t button_mask = (1 << BUTTON_A) | (1 << BUTTON_B) | + (1 << BUTTON_Y) | (1 << BUTTON_X); + +Adafruit_seesaw ss; + +// Report ID +enum +{ + RID_KEYBOARD = 1, + RID_MOUSE +}; + +// HID report descriptor using TinyUSB's template +uint8_t const desc_hid_report[] = +{ + TUD_HID_REPORT_DESC_KEYBOARD( HID_REPORT_ID(RID_KEYBOARD) ), + TUD_HID_REPORT_DESC_MOUSE ( HID_REPORT_ID(RID_MOUSE) ) +}; + +// USB HID object +Adafruit_USBD_HID usb_hid; + +int last_x, last_y; + +// the setup function runs once when you press reset or power the board +void setup() +{ + usb_hid.setPollInterval(2); + usb_hid.setReportDescriptor(desc_hid_report, sizeof(desc_hid_report)); + + usb_hid.begin(); + + Serial.begin(115200); + Serial.println("Adafruit TinyUSB HID Mouse with Joy FeatherWing example"); + + if(!ss.begin(0x49)){ + Serial.println("ERROR! seesaw not found"); + while(1); + } else { + Serial.println("seesaw started"); + Serial.print("version: "); + Serial.println(ss.getVersion(), HEX); + } + ss.pinModeBulk(button_mask, INPUT_PULLUP); + ss.setGPIOInterrupts(button_mask, 1); + + last_y = ss.analogRead(2); + last_x = ss.analogRead(3); + + // wait until device mounted + while( !USBDevice.mounted() ) delay(1); +} + +void loop() +{ + // poll gpio once each 10 ms + delay(10); + + // If either analog stick or any buttons is pressed + bool has_action = false; + + /*------------- Mouse -------------*/ + int y = ss.analogRead(2); + int x = ss.analogRead(3); + + // reduce the delta by half to slow down the cursor move + int dx = (x - last_x) / 2; + int dy = (y - last_y) / 2; + + if ( (abs(dx) > 3) || (abs(dy) > 3) ) + { + has_action = true; + + if ( usb_hid.ready() ) + { + usb_hid.mouseMove(RID_MOUSE, dx, dy); // no ID: right + down + + last_x = x; + last_y = y; + + // delay a bit before attempt to send keyboard report + delay(10); + } + } + + + /*------------- Keyboard -------------*/ + // button is active low, invert read value for convenience + uint32_t buttons = ~ss.digitalReadBulk(button_mask); + + if ( usb_hid.ready() ) + { + // use to prevent sending multiple consecutive zero report + static bool has_key = false; + + if ( buttons & button_mask ) + { + has_action = true; + has_key = true; + + uint8_t keycode[6] = { 0 }; + + if ( buttons & (1 << BUTTON_A) ) keycode[0] = HID_KEY_A; + if ( buttons & (1 << BUTTON_B) ) keycode[0] = HID_KEY_B; + if ( buttons & (1 << BUTTON_X) ) keycode[0] = HID_KEY_X; + if ( buttons & (1 << BUTTON_Y) ) keycode[0] = HID_KEY_Y; + + usb_hid.keyboardReport(RID_KEYBOARD, 0, keycode); + }else + { + // send empty key report if previously has key pressed + if (has_key) usb_hid.keyboardRelease(RID_KEYBOARD); + has_key = false; + } + } + + /*------------- Remote Wakeup -------------*/ + // Remote wakeup if PC is suspended and we has user interaction with joy feather wing + if ( has_action && USBDevice.suspended() ) + { + // Wake up only works if REMOTE_WAKEUP feature is enable by host + // Usually this is the case with Mouse/Keyboard device + USBDevice.remoteWakeup(); + } +} diff --git a/libraries/Adafruit_TinyUSB_Arduino/examples/HID/hid_gamepad/hid_gamepad.ino b/libraries/Adafruit_TinyUSB_Arduino/examples/HID/hid_gamepad/hid_gamepad.ino new file mode 100644 index 00000000000..334dc9f9910 --- /dev/null +++ b/libraries/Adafruit_TinyUSB_Arduino/examples/HID/hid_gamepad/hid_gamepad.ino @@ -0,0 +1,268 @@ +/********************************************************************* + Adafruit invests time and resources providing this open source code, + please support Adafruit and open-source hardware by purchasing + products from Adafruit! + + MIT license, check LICENSE for more information + Copyright (c) 2021 NeKuNeKo for Adafruit Industries + All text above, and the splash screen below must be included in + any redistribution +*********************************************************************/ + +#include "Adafruit_TinyUSB.h" + +/* This sketch demonstrates USB HID gamepad use. + * This sketch is only valid on boards which have native USB support + * and compatibility with Adafruit TinyUSB library. + * For example SAMD21, SAMD51, nRF52840. + * + * Make sure you select the TinyUSB USB stack if you have a SAMD board. + * You can test the gamepad on a Windows system by pressing WIN+R, writing Joy.cpl and pressing Enter. + */ + +// HID report descriptor using TinyUSB's template +// Single Report (no ID) descriptor +uint8_t const desc_hid_report[] = +{ + TUD_HID_REPORT_DESC_GAMEPAD() +}; + +// USB HID object +Adafruit_USBD_HID usb_hid; + +hid_gamepad_report_t gp; // defined in hid.h from Adafruit_TinyUSB_ArduinoCore +// For Gamepad Button Bit Mask see hid_gamepad_button_bm_t typedef defined in hid.h from Adafruit_TinyUSB_ArduinoCore +// For Gamepad Hat Bit Mask see hid_gamepad_hat_bm_t typedef defined in hid.h from Adafruit_TinyUSB_ArduinoCore + +void setup() +{ + Serial.begin(115200); + + usb_hid.setPollInterval(2); + usb_hid.setReportDescriptor(desc_hid_report, sizeof(desc_hid_report)); + + usb_hid.begin(); + + // wait until device mounted + while( !USBDevice.mounted() ) delay(1); + + Serial.println("Adafruit TinyUSB HID Gamepad example"); +} + +void loop() +{ +// // Remote wakeup +// if ( USBDevice.suspended() && btn ) +// { +// // Wake up host if we are in suspend mode +// // and REMOTE_WAKEUP feature is enabled by host +// USBDevice.remoteWakeup(); +// } + + if ( !usb_hid.ready() ) return; + + + // Reset buttons + Serial.println("No pressing buttons"); + gp.x = 0; + gp.y = 0; + gp.z = 0; + gp.rz = 0; + gp.rx = 0; + gp.ry = 0; + gp.hat = 0; + gp.buttons = 0; + usb_hid.sendReport(0, &gp, sizeof(gp)); + delay(2000); + + + // Hat/DPAD UP + Serial.println("Hat/DPAD UP"); + gp.hat = 1; // GAMEPAD_HAT_UP; + usb_hid.sendReport(0, &gp, sizeof(gp)); + delay(2000); + + // Hat/DPAD UP RIGHT + Serial.println("Hat/DPAD UP RIGHT"); + gp.hat = 2; // GAMEPAD_HAT_UP_RIGHT; + usb_hid.sendReport(0, &gp, sizeof(gp)); + delay(2000); + + // Hat/DPAD RIGHT + Serial.println("Hat/DPAD RIGHT"); + gp.hat = 3; // GAMEPAD_HAT_RIGHT; + usb_hid.sendReport(0, &gp, sizeof(gp)); + delay(2000); + + // Hat/DPAD DOWN RIGHT + Serial.println("Hat/DPAD DOWN RIGHT"); + gp.hat = 4; // GAMEPAD_HAT_DOWN_RIGHT; + usb_hid.sendReport(0, &gp, sizeof(gp)); + delay(2000); + + // Hat/DPAD DOWN + Serial.println("Hat/DPAD DOWN"); + gp.hat = 5; // GAMEPAD_HAT_DOWN; + usb_hid.sendReport(0, &gp, sizeof(gp)); + delay(2000); + + // Hat/DPAD DOWN LEFT + Serial.println("Hat/DPAD DOWN LEFT"); + gp.hat = 6; // GAMEPAD_HAT_DOWN_LEFT; + usb_hid.sendReport(0, &gp, sizeof(gp)); + delay(2000); + + // Hat/DPAD LEFT + Serial.println("Hat/DPAD LEFT"); + gp.hat = 7; // GAMEPAD_HAT_LEFT; + usb_hid.sendReport(0, &gp, sizeof(gp)); + delay(2000); + + // Hat/DPAD UP LEFT + Serial.println("Hat/DPAD UP LEFT"); + gp.hat = 8; // GAMEPAD_HAT_UP_LEFT; + usb_hid.sendReport(0, &gp, sizeof(gp)); + delay(2000); + + // Hat/DPAD CENTER + Serial.println("Hat/DPAD CENTER"); + gp.hat = 0; // GAMEPAD_HAT_CENTERED; + usb_hid.sendReport(0, &gp, sizeof(gp)); + delay(2000); + + + // Joystick 1 UP + Serial.println("Joystick 1 UP"); + gp.x = 0; + gp.y = -127; + usb_hid.sendReport(0, &gp, sizeof(gp)); + delay(2000); + + // Joystick 1 DOWN + Serial.println("Joystick 1 DOWN"); + gp.x = 0; + gp.y = 127; + usb_hid.sendReport(0, &gp, sizeof(gp)); + delay(2000); + + // Joystick 1 RIGHT + Serial.println("Joystick 1 RIGHT"); + gp.x = 127; + gp.y = 0; + usb_hid.sendReport(0, &gp, sizeof(gp)); + delay(2000); + + // Joystick 1 LEFT + Serial.println("Joystick 1 LEFT"); + gp.x = -127; + gp.y = 0; + usb_hid.sendReport(0, &gp, sizeof(gp)); + delay(2000); + + // Joystick 1 CENTER + Serial.println("Joystick 1 CENTER"); + gp.x = 0; + gp.y = 0; + usb_hid.sendReport(0, &gp, sizeof(gp)); + delay(2000); + + + // Joystick 2 UP + Serial.println("Joystick 2 UP"); + gp.z = 0; + gp.rz = 127; + usb_hid.sendReport(0, &gp, sizeof(gp)); + delay(2000); + + // Joystick 2 DOWN + Serial.println("Joystick 2 DOWN"); + gp.z = 0; + gp.rz = -127; + usb_hid.sendReport(0, &gp, sizeof(gp)); + delay(2000); + + // Joystick 2 RIGHT + Serial.println("Joystick 2 RIGHT"); + gp.z = 127; + gp.rz = 0; + usb_hid.sendReport(0, &gp, sizeof(gp)); + delay(2000); + + // Joystick 2 LEFT + Serial.println("Joystick 2 LEFT"); + gp.z = -127; + gp.rz = 0; + usb_hid.sendReport(0, &gp, sizeof(gp)); + delay(2000); + + // Joystick 2 CENTER + Serial.println("Joystick 2 CENTER"); + gp.z = 0; + gp.rz = 0; + usb_hid.sendReport(0, &gp, sizeof(gp)); + delay(2000); + + + // Analog Trigger 1 UP + Serial.println("Analog Trigger 1 UP"); + gp.rx = 127; + usb_hid.sendReport(0, &gp, sizeof(gp)); + delay(2000); + + // Analog Trigger 1 DOWN + Serial.println("Analog Trigger 1 DOWN"); + gp.rx = -127; + usb_hid.sendReport(0, &gp, sizeof(gp)); + delay(2000); + + // Analog Trigger 1 CENTER + Serial.println("Analog Trigger 1 CENTER"); + gp.rx = 0; + usb_hid.sendReport(0, &gp, sizeof(gp)); + delay(2000); + + + // Analog Trigger 2 UP + Serial.println("Analog Trigger 2 UP"); + gp.ry = 127; + usb_hid.sendReport(0, &gp, sizeof(gp)); + delay(2000); + + // Analog Trigger 2 DOWN + Serial.println("Analog Trigger 2 DOWN"); + gp.ry = -127; + usb_hid.sendReport(0, &gp, sizeof(gp)); + delay(2000); + + // Analog Trigger 2 CENTER + Serial.println("Analog Trigger 2 CENTER"); + gp.ry = 0; + usb_hid.sendReport(0, &gp, sizeof(gp)); + delay(2000); + + + // Test buttons (up to 32 buttons) + for (int i=0; i<32; ++i) + { + Serial.print("Pressing button "); Serial.println(i); + gp.buttons = (1U << i); + usb_hid.sendReport(0, &gp, sizeof(gp)); + delay(1000); + } + + + // Random touch + Serial.println("Random touch"); + gp.x = random(-127, 128); + gp.y = random(-127, 128); + gp.z = random(-127, 128); + gp.rz = random(-127, 128); + gp.rx = random(-127, 128); + gp.ry = random(-127, 128); + gp.hat = random(0, 9); + gp.buttons = random(0, 0xffff); + usb_hid.sendReport(0, &gp, sizeof(gp)); + delay(2000); + + // */ +} diff --git a/libraries/Adafruit_TinyUSB_Arduino/examples/HID/hid_generic_inout/README.md b/libraries/Adafruit_TinyUSB_Arduino/examples/HID/hid_generic_inout/README.md new file mode 100644 index 00000000000..3749e6b5031 --- /dev/null +++ b/libraries/Adafruit_TinyUSB_Arduino/examples/HID/hid_generic_inout/README.md @@ -0,0 +1,10 @@ +Instructions for node.js based example + +===Setup=== + +1. Upload example code to your board +2. Install node.js if you haven't already +3. Run `npm install` to install the dependencies +4. If this should fail on windows try installing the build tools via `npm i -g windows-build-tools` +5. While the board is connected run `node hid_test.js` +6. If this should fail make sure the VID and PID of your board is listed in boards.js \ No newline at end of file diff --git a/libraries/Adafruit_TinyUSB_Arduino/examples/HID/hid_generic_inout/boards.js b/libraries/Adafruit_TinyUSB_Arduino/examples/HID/hid_generic_inout/boards.js new file mode 100644 index 00000000000..bf6365b267d --- /dev/null +++ b/libraries/Adafruit_TinyUSB_Arduino/examples/HID/hid_generic_inout/boards.js @@ -0,0 +1,5 @@ +module.exports = { + "Feather_nRF52840":[0X239A,0X8029], + "Metro_nRF52840":[0X239A,0X803F], + "Circuit_Playground_Express":[0X239A,0X8018], +} \ No newline at end of file diff --git a/libraries/Adafruit_TinyUSB_Arduino/examples/HID/hid_generic_inout/hid_generic_inout.ino b/libraries/Adafruit_TinyUSB_Arduino/examples/HID/hid_generic_inout/hid_generic_inout.ino new file mode 100644 index 00000000000..60eacba2a17 --- /dev/null +++ b/libraries/Adafruit_TinyUSB_Arduino/examples/HID/hid_generic_inout/hid_generic_inout.ino @@ -0,0 +1,88 @@ +/********************************************************************* + Adafruit invests time and resources providing this open source code, + please support Adafruit and open-source hardware by purchasing + products from Adafruit! + + MIT license, check LICENSE for more information + Copyright (c) 2019 Ha Thach for Adafruit Industries + All text above, and the splash screen below must be included in + any redistribution +*********************************************************************/ + +/* This example demonstrate HID Generic raw Input & Output. + * It will receive data from Host (In endpoint) and echo back (Out endpoint). + * HID Report descriptor use vendor for usage page (using template TUD_HID_REPORT_DESC_GENERIC_INOUT) + * + * There are 2 ways to test the sketch + * 1. Using nodejs + * - Install nodejs and nmp to your PC + * - Install execellent node-hid (https://github.com/node-hid/node-hid) by + * $ npm install node-hid + * - Run provided hid test script + * $ node hid_test.js + * + * 2. Using python hidRun + * - Python and `hid` package is required, for installation please follow https://pypi.org/project/hid/ + * - Run provided hid test script to send and receive data to this device. + * $ python3 hid_test.py + */ + +#include "Adafruit_TinyUSB.h" + +// HID report descriptor using TinyUSB's template +// Generic In Out with 64 bytes report (max) +uint8_t const desc_hid_report[] = +{ + TUD_HID_REPORT_DESC_GENERIC_INOUT(64) +}; + +Adafruit_USBD_HID usb_hid; + +// the setup function runs once when you press reset or power the board +void setup() +{ + usb_hid.enableOutEndpoint(true); + usb_hid.setPollInterval(2); + usb_hid.setReportDescriptor(desc_hid_report, sizeof(desc_hid_report)); + usb_hid.setReportCallback(get_report_callback, set_report_callback); + //usb_hid.setStringDescriptor("TinyUSB HID Generic"); + + usb_hid.begin(); + + Serial.begin(115200); + + // wait until device mounted + while( !USBDevice.mounted() ) delay(1); + + Serial.println("Adafruit TinyUSB HID Generic In Out example"); +} + +void loop() +{ + // nothing to do +} + +// 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 get_report_callback (uint8_t report_id, hid_report_type_t report_type, uint8_t* buffer, uint16_t reqlen) +{ + // not used in this example + (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 set_report_callback(uint8_t report_id, hid_report_type_t report_type, uint8_t const* buffer, uint16_t bufsize) +{ + // This example doesn't use multiple report and report ID + (void) report_id; + (void) report_type; + + // echo back anything we received from host + usb_hid.sendReport(0, buffer, bufsize); +} diff --git a/libraries/Adafruit_TinyUSB_Arduino/examples/HID/hid_generic_inout/hid_test.js b/libraries/Adafruit_TinyUSB_Arduino/examples/HID/hid_generic_inout/hid_test.js new file mode 100644 index 00000000000..eed6b78e296 --- /dev/null +++ b/libraries/Adafruit_TinyUSB_Arduino/examples/HID/hid_generic_inout/hid_test.js @@ -0,0 +1,71 @@ +// IMPORTANT: install the dependency via 'npm i node-hid' in the same location as the script +// If the install fails on windows you may need to run 'npm i -g windows-build-tools' first to be able to compile native code needed for this library + +var HID = require('node-hid'); +var os = require('os') +// list of supported devices +var boards = require('./boards.js') + +var isWin = (os.platform() === 'win32'); +var devices = HID.devices(); + +// this will choose any device found in the boards.js file +var deviceInfo = devices.find(anySupportedBoard); +var reportLen = 64; + +var message = "Hello World!" + +// Turn our string into an array of integers e.g. 'ascii codes', though charCodeAt spits out UTF-16 +// This means if you have characters in your string that are not Latin-1 you will have to add additional logic for character codes above 255 +var messageBuffer = Array.from(message, function(c){return c.charCodeAt(0)}); + +// Windows wants you to prepend a 0 to whatever you send +if(isWin){ + messageBuffer.unshift(0) +} + +// Some OSes expect that you always send a buffer that equals your report length +// So lets fill up the rest of the buffer with zeros +var paddingBuf = Array(reportLen-messageBuffer.length); +paddingBuf.fill(0) +messageBuffer = messageBuffer.concat(paddingBuf) + +// check if we actually found a device and if so send our messageBuffer to it +if( deviceInfo ) { + console.log(deviceInfo) + var device = new HID.HID( deviceInfo.path ); + + // register an event listener for data coming from the device + device.on("data", function(data) { + // Print what we get from the device + console.log(data.toString('ascii')); + }); + + // the same for any error that occur + device.on("error", function(err) {console.log(err)}); + + // send our message to the device every 500ms + setInterval(function () { + device.write(messageBuffer); + },500) +} + + +function anySupportedBoard(d) { + + for (var key in boards) { + if (boards.hasOwnProperty(key)) { + if (isDevice(boards[key],d)) { + console.log("Found " + d.product); + return true; + } + } + } + return false; +} + + +function isDevice(board,d){ + return d.vendorId==board[0] && d.productId==board[1]; +} + diff --git a/libraries/Adafruit_TinyUSB_Arduino/examples/HID/hid_generic_inout/hid_test.py b/libraries/Adafruit_TinyUSB_Arduino/examples/HID/hid_generic_inout/hid_test.py new file mode 100644 index 00000000000..04129239bb8 --- /dev/null +++ b/libraries/Adafruit_TinyUSB_Arduino/examples/HID/hid_generic_inout/hid_test.py @@ -0,0 +1,18 @@ +# Install python3 HID package https://pypi.org/project/hid/ +import hid + +# default is Adafruit VID +USB_VID = 0x239A + +print("Openning HID device with VID = 0x%X" % USB_VID) + +for dict in hid.enumerate(USB_VID): + print(dict) + dev = hid.Device(dict['vendor_id'], dict['product_id']) + if dev: + while True: + # Get input from console and encode to UTF8 for array of chars. + str_out = input("Send text to HID Device : ").encode('utf-8') + dev.write(str_out) + str_in = dev.read(64) + print("Received from HID Device:", str_in, '\n') diff --git a/libraries/Adafruit_TinyUSB_Arduino/examples/HID/hid_generic_inout/package.json b/libraries/Adafruit_TinyUSB_Arduino/examples/HID/hid_generic_inout/package.json new file mode 100644 index 00000000000..9047c3279e6 --- /dev/null +++ b/libraries/Adafruit_TinyUSB_Arduino/examples/HID/hid_generic_inout/package.json @@ -0,0 +1,14 @@ +{ + "name": "hid_example", + "version": "1.0.0", + "description": "Test application for hid_generic_inout example sketch", + "main": "hid_test.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "author": "Timon, Tod E. Kurt", + "license": "MIT", + "dependencies": { + "node-hid": "^0.7.9" + } +} diff --git a/libraries/Adafruit_TinyUSB_Arduino/examples/HID/hid_keyboard/hid_keyboard.ino b/libraries/Adafruit_TinyUSB_Arduino/examples/HID/hid_keyboard/hid_keyboard.ino new file mode 100644 index 00000000000..d674eeb5af8 --- /dev/null +++ b/libraries/Adafruit_TinyUSB_Arduino/examples/HID/hid_keyboard/hid_keyboard.ino @@ -0,0 +1,141 @@ +/********************************************************************* + Adafruit invests time and resources providing this open source code, + please support Adafruit and open-source hardware by purchasing + products from Adafruit! + + MIT license, check LICENSE for more information + Copyright (c) 2019 Ha Thach for Adafruit Industries + All text above, and the splash screen below must be included in + any redistribution +*********************************************************************/ + +#include "Adafruit_TinyUSB.h" + +/* 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 + */ + +// HID report descriptor using TinyUSB's template +// Single Report (no ID) descriptor +uint8_t const desc_hid_report[] = +{ + TUD_HID_REPORT_DESC_KEYBOARD(), +}; + +Adafruit_USBD_HID usb_hid; + +// Array of pins and its keycode +// For keycode definition see BLEHidGeneric.h +#ifdef ARDUINO_ARCH_RP2040 +uint8_t pins[] = { D0, D1, D2, D3, D4, D5 }; +#else +uint8_t pins[] = { A0, A1, A2, A3, A4, A5 }; +#endif +uint8_t hidcode[] = { HID_KEY_0, HID_KEY_1, HID_KEY_2, HID_KEY_3 , HID_KEY_4, HID_KEY_5 }; + +uint8_t pincount = sizeof(pins)/sizeof(pins[0]); + +// the setup function runs once when you press reset or power the board +void setup() +{ + usb_hid.setPollInterval(2); + usb_hid.setReportDescriptor(desc_hid_report, sizeof(desc_hid_report)); + usb_hid.setReportCallback(NULL, hid_report_callback); + //usb_hid.setStringDescriptor("TinyUSB Keyboard"); + + usb_hid.begin(); + + // led pin + pinMode(LED_BUILTIN, OUTPUT); + digitalWrite(LED_BUILTIN, LOW); + + // Set up pin as input + for (uint8_t i=0; i +#include +#include +#include +#include + +// USB MIDI object +Adafruit_USBD_MIDI usb_midi; + +// Create a new instance of the Arduino MIDI Library, +// and attach usb_midi as the transport. +MIDI_CREATE_INSTANCE(Adafruit_USBD_MIDI, usb_midi, usbMIDI); + +/////////////////////////////////////////////////////////////////////////////// +//MIDI CC (change control) assignments +const int CHANNEL = 14; //MIDI channel +const int LEFT_BUTTON_CC = 4; //Play/Pause Deck A +const int RIGHT_BUTTON_CC = 19; //MIDI CC for left button: FX 1 On +const int CAP1_CONTROL = 1; //Select/Set+Store Hotcue 2 (1 is load point) +const int CAP0_CONTROL = 0; //Left fader mixes Deck B volume down +const int CAP2_CONTROL = 2; //Delete hotcue 2 point +const int CAP3_CONTROL = 3; //Remix Trigger 6-1 or Loop Size /2 +const int CAP12_CONTROL = 12; //Right fader mixes Deck A volume down +const int CAP6_CONTROL = 6; //Scratch (jog turn) Deck B +const int CAP9_CONTROL = 9; //Play/Pause Deck B +const int CAP10_CONTROL = 10; //Remix Trigger 6-4 or Loop Set 4 bar + +int leftButtonState = 0; +int rightButtonState = 0; +int leftButtonLastState = 0; +int rightButtonLastState = 0; +int cap0State = 0; +int cap0LastState = 0; +int cap1State = 0; +int cap1LastState = 0; +int cap2State = 0; +int cap2LastState = 0; +int cap3State = 0; +int cap3LastState = 0; +int cap12State = 0; +int cap12LastState = 0; +int cap6State = 0; +int cap6LastState = 0; +int cap9State = 0; +int cap9LastState = 0; +int cap10State = 0; +int cap10LastState = 0; +bool cap1ON = false; //prevents off command from being spewed +bool cap12ON = false; //prevents off command from being spewed +bool cap6ON = false; //prevents off command from being spewed + +const int CAPMIN = 25; //lowest value that's considered an intentional touch to minimize crosstalk +const int CAPSLOP = 0; //value of capacitive pad variance that's considered noise + + +/////////////////////////////////////////////////////////////////////////////// +//mic_meter code +// To keep the display 'lively,' an upper and lower range of volume +// levels are dynamically adjusted based on recent audio history, and +// the graph is fit into this range. +#define FRAMES 8 +uint16_t lvl[FRAMES], // Audio level for the prior #FRAMES frames + avgLo = 6, // Audio volume lower end of range + avgHi = 512, // Audio volume upper end of range + sum = 256 * FRAMES; // Sum of lvl[] array +uint8_t lvlIdx = 0; // Counter into lvl[] array +int16_t peak = 0; // Falling dot shows recent max +int8_t peakV = 0; // Velocity of peak dot + +/////////////////////////////////////////////////////////////////////////////// +void setup() { + + usbMIDI.begin(); + Serial.begin(115200); + + CircuitPlayground.begin(); + CircuitPlayground.setBrightness(30); //make brighter for performance, up to 255 + CircuitPlayground.clearPixels(); + for(uint8_t i=0; i maxLvl) maxLvl = lvl[i]; + } + + // Keep some minimum distance between min & max levels, + // else the display gets "jumpy." + if((maxLvl - minLvl) < 40) { + maxLvl = (minLvl < (512-40)) ? minLvl + 40 : 512; + } + avgLo = (avgLo * 7 + minLvl + 2) / 8; // Dampen min/max levels + avgHi = (maxLvl >= avgHi) ? // (fake rolling averages) + (avgHi * 3 + maxLvl + 1) / 4 : // Fast rise + (avgHi * 31 + maxLvl + 8) / 32; // Slow decay + + a = sum / FRAMES; // Average of lvl[] array + if(a <= avgLo) { // Below min? + scaled = 0; // Bargraph = zero + } else { // Else scale to fixed-point coordspace 0-2560 + scaled = 2560L * (a - avgLo) / (avgHi - avgLo); + if(scaled > 2560) scaled = 2560; + } + if(scaled >= peak) { // New peak + peakV = (scaled - peak) / 4; // Give it an upward nudge + peak = scaled; + } + + uint8_t whole = scaled / 256, // Full-brightness pixels (0-10) + frac = scaled & 255; // Brightness of fractional pixel + int whole2 = peak / 256, // Index of peak pixel + frac2 = peak & 255; // Between-pixels position of peak + uint16_t a1, a2; // Scaling factors for color blending + + for(i=0; i<10; i++) { // For each NeoPixel... + if(i <= whole) { // In currently-lit area? + r = pgm_read_byte(&reds[i]), // Look up pixel color + g = pgm_read_byte(&greens[i]), + b = pgm_read_byte(&blues[i]); + if(i == whole) { // Fraction pixel at top of range? + a1 = (uint16_t)frac + 1; // Fade toward black + r = (r * a1) >> 8; + g = (g * a1) >> 8; + b = (b * a1) >> 8; + } + } else { + r = g = b = 0; // In unlit area + } + // Composite the peak pixel atop whatever else is happening... + if(i == whole2) { // Peak pixel? + a1 = 256 - frac2; // Existing pixel blend factor 1-256 + a2 = frac2 + 1; // Peak pixel blend factor 1-256 + r = ((r * a1) + (0x84 * a2)) >> 8; // Will + g = ((g * a1) + (0x87 * a2)) >> 8; // it + b = ((b * a1) + (0xC3 * a2)) >> 8; // blend? + } else if(i == (whole2-1)) { // Just below peak pixel + a1 = frac2 + 1; // Opposite blend ratios to above, + a2 = 256 - frac2; // but same idea + r = ((r * a1) + (0x84 * a2)) >> 8; + g = ((g * a1) + (0x87 * a2)) >> 8; + b = ((b * a1) + (0xC3 * a2)) >> 8; + } + CircuitPlayground.strip.setPixelColor(i, + pgm_read_byte(&gamma8[r]), + pgm_read_byte(&gamma8[g]), + pgm_read_byte(&gamma8[b])); + } + CircuitPlayground.strip.show(); + + peak += peakV; + if(peak <= 0) { + peak = 0; + peakV = 0; + } else if(peakV >= -126) { + peakV -= 2; + } + + if(++lvlIdx >= FRAMES) lvlIdx = 0; + +/////////////////////////////////////////////////////////////////////////////// +//BUTTONS +// +//read the buttons + leftButtonState = (CircuitPlayground.leftButton()); + //not pressed = 0, pressed = 1 + rightButtonState = (CircuitPlayground.rightButton()); + +//Left Button +//compare current button states to previous button states + if(leftButtonState != leftButtonLastState){ //the state has changed + if(leftButtonState == 1){ //went from off to on, it's pressed + usbMIDI.sendControlChange(LEFT_BUTTON_CC, 1, CHANNEL); //send MIDI note ON command + CircuitPlayground.redLED(HIGH); //turn on the red LED + } + else{ //the button went from on to off, it isn't pressed + usbMIDI.sendControlChange(LEFT_BUTTON_CC, 0, CHANNEL); //send MIDI note OFF + CircuitPlayground.redLED(LOW); //turn off the red LED + } + leftButtonLastState = leftButtonState; //toggle + } + + +//Right Button + if(rightButtonState != rightButtonLastState){ + if(rightButtonState == 1){ + usbMIDI.sendControlChange(RIGHT_BUTTON_CC, 1, CHANNEL); + CircuitPlayground.redLED(HIGH); + } + else{ + usbMIDI.sendControlChange(RIGHT_BUTTON_CC, 0, CHANNEL); + CircuitPlayground.redLED(LOW); + } + rightButtonLastState = rightButtonState; + } +/////////////////////////////////////////////////////////////////////////////// +//Cap sense pads +// +//read the capacative pads + int cap1 = CircuitPlayground.readCap(1); + int cap0 = CircuitPlayground.readCap(0); + int cap2 = CircuitPlayground.readCap(2); + int cap3 = CircuitPlayground.readCap(3); + int cap12 = CircuitPlayground.readCap(12); + int cap6 = CircuitPlayground.readCap(6); + int cap9 = CircuitPlayground.readCap(9); + int cap10 = CircuitPlayground.readCap(10); + + //cap1 Crossfader Deck B + + if(cap1 > CAPMIN){ + cap1State=1; + } + else{ + cap1State=0; + } + if(cap1State != cap1LastState){ + if(cap1State==1){ + usbMIDI.sendControlChange(CAP1_CONTROL, 127, CHANNEL); + CircuitPlayground.redLED(HIGH); + } + else { + usbMIDI.sendControlChange(CAP1_CONTROL, 0, CHANNEL); + CircuitPlayground.redLED(LOW); + } + cap1LastState = cap1State; + } + + //cap0 + if(cap0 > CAPMIN){ + cap0State=1; + } + else{ + cap0State=0; + } + if(cap0State != cap0LastState){ + if(cap0State==1){ + usbMIDI.sendControlChange(CAP0_CONTROL, 1, CHANNEL); + CircuitPlayground.redLED(HIGH); + } + else { + usbMIDI.sendControlChange(CAP0_CONTROL, 0, CHANNEL); + CircuitPlayground.redLED(LOW); + } + cap0LastState = cap0State; + } + +//cap2 + if(cap2 > CAPMIN){ + cap2State=1; + } + else{ + cap2State=0; + } + if(cap2State != cap2LastState){ + if(cap2State==1){ + usbMIDI.sendControlChange(CAP2_CONTROL, 1, CHANNEL); + CircuitPlayground.redLED(HIGH); + } + else { + usbMIDI.sendControlChange(CAP2_CONTROL, 0, CHANNEL); + CircuitPlayground.redLED(LOW); + } + cap2LastState = cap2State; + } + + //cap3 + if(cap3 > CAPMIN){ + cap3State=1; + } + else{ + cap3State=0; + } + if(cap3State != cap3LastState){ + if(cap3State==1){ + usbMIDI.sendControlChange(CAP3_CONTROL, 1, CHANNEL); + CircuitPlayground.redLED(HIGH); + } + else { + usbMIDI.sendControlChange(CAP3_CONTROL, 0, CHANNEL); + CircuitPlayground.redLED(LOW); + } + cap3LastState = cap3State; + } + + //cap12 Crossfader Deck B + + if(cap12 > CAPMIN){ + cap12State=1; + } + else{ + cap12State=0; + } + if(cap12State != cap12LastState){ + if(cap12State==1){ + usbMIDI.sendControlChange(CAP12_CONTROL, 127, CHANNEL); + CircuitPlayground.redLED(HIGH); + } + else { + usbMIDI.sendControlChange(CAP12_CONTROL, 0, CHANNEL); + CircuitPlayground.redLED(LOW); + } + cap12LastState = cap12State; + } + + //cap6 + if (cap6>CAPMIN){ + int cap6NewVal = map(CircuitPlayground.readCap(6),0,200,0,127); + if (abs(cap6 - cap6NewVal>CAPSLOP)) { + cap6 = cap6NewVal; + usbMIDI.sendControlChange(CAP6_CONTROL, cap6, CHANNEL); + CircuitPlayground.redLED(HIGH); + cap6ON = true; + } + else{ + if (cap6ON==true){ + usbMIDI.sendControlChange(CAP6_CONTROL, 0, CHANNEL); //send a 0 + CircuitPlayground.redLED(LOW); + cap6ON=false; + } + } + } + + //cap9 + if(cap9 > CAPMIN){ + cap9State=1; + } + else{ + cap9State=0; + } + if(cap9State != cap9LastState){ + if(cap9State==1){ + usbMIDI.sendControlChange(CAP9_CONTROL, 1, CHANNEL); + CircuitPlayground.redLED(HIGH); + } + else { + usbMIDI.sendControlChange(CAP9_CONTROL, 0, CHANNEL); + CircuitPlayground.redLED(LOW); + } + cap9LastState = cap9State; + } + + //cap10 + if(cap10 > CAPMIN){ + cap10State=1; + } + else{ + cap10State=0; + } + if(cap10State != cap10LastState){ + if(cap10State==1){ + usbMIDI.sendControlChange(CAP10_CONTROL, 1, CHANNEL); + CircuitPlayground.redLED(HIGH); + } + else { + usbMIDI.sendControlChange(CAP10_CONTROL, 0, CHANNEL); + CircuitPlayground.redLED(LOW); + } + cap10LastState = cap10State; + } + + // MIDI Controllers should discard incoming MIDI messages. + while (usbMIDI.read()) { + } +} diff --git a/libraries/Adafruit_TinyUSB_Arduino/examples/MIDI/midi_test/midi_test.ino b/libraries/Adafruit_TinyUSB_Arduino/examples/MIDI/midi_test/midi_test.ino new file mode 100644 index 00000000000..5a40be20fe7 --- /dev/null +++ b/libraries/Adafruit_TinyUSB_Arduino/examples/MIDI/midi_test/midi_test.ino @@ -0,0 +1,110 @@ +/********************************************************************* + Adafruit invests time and resources providing this open source code, + please support Adafruit and open-source hardware by purchasing + products from Adafruit! + + MIT license, check LICENSE for more information + Copyright (c) 2019 Ha Thach for Adafruit Industries + All text above, and the splash screen below must be included in + any redistribution +*********************************************************************/ + +/* This sketch is enumerated as USB MIDI device. + * Following library is required + * - MIDI Library by Forty Seven Effects + * https://github.com/FortySevenEffects/arduino_midi_library + */ + +#include +#include +#include + +// USB MIDI object +Adafruit_USBD_MIDI usb_midi; + +// Create a new instance of the Arduino MIDI Library, +// and attach usb_midi as the transport. +MIDI_CREATE_INSTANCE(Adafruit_USBD_MIDI, usb_midi, MIDI); + +// Variable that holds the current position in the sequence. +uint32_t position = 0; + +// Store example melody as an array of note values +byte note_sequence[] = { + 74,78,81,86,90,93,98,102,57,61,66,69,73,78,81,85,88,92,97,100,97,92,88,85,81,78, + 74,69,66,62,57,62,66,69,74,78,81,86,90,93,97,102,97,93,90,85,81,78,73,68,64,61, + 56,61,64,68,74,78,81,86,90,93,98,102 +}; + +void setup() +{ + pinMode(LED_BUILTIN, OUTPUT); + + //usb_midi.setStringDescriptor("TinyUSB MIDI"); + + // Initialize MIDI, and listen to all MIDI channels + // This will also call usb_midi's begin() + MIDI.begin(MIDI_CHANNEL_OMNI); + + // Attach the handleNoteOn function to the MIDI Library. It will + // be called whenever the Bluefruit receives MIDI Note On messages. + MIDI.setHandleNoteOn(handleNoteOn); + + // Do the same for MIDI Note Off messages. + MIDI.setHandleNoteOff(handleNoteOff); + + Serial.begin(115200); + + // wait until device mounted + while( !USBDevice.mounted() ) delay(1); +} + +void loop() +{ + static uint32_t start_ms = 0; + if ( millis() - start_ms > 266 ) + { + start_ms += 266; + + // Setup variables for the current and previous + // positions in the note sequence. + int previous = position - 1; + + // If we currently are at position 0, set the + // previous position to the last note in the sequence. + if (previous < 0) { + previous = sizeof(note_sequence) - 1; + } + + // Send Note On for current position at full velocity (127) on channel 1. + MIDI.sendNoteOn(note_sequence[position], 127, 1); + + // Send Note Off for previous note. + MIDI.sendNoteOff(note_sequence[previous], 0, 1); + + // Increment position + position++; + + // If we are at the end of the sequence, start over. + if (position >= sizeof(note_sequence)) { + position = 0; + } + } + + // read any new MIDI messages + MIDI.read(); +} + +void handleNoteOn(byte channel, byte pitch, byte velocity) +{ + // Log when a note is pressed. + Serial.printf("Note on: channel = %d, pitch = %d, velocity - %d", channel, pitch, velocity); + Serial.println(); +} + +void handleNoteOff(byte channel, byte pitch, byte velocity) +{ + // Log when a note is released. + Serial.printf("Note off: channel = %d, pitch = %d, velocity - %d", channel, pitch, velocity); + Serial.println(); +} diff --git a/libraries/Adafruit_TinyUSB_Arduino/examples/MassStorage/msc_external_flash/msc_external_flash.ino b/libraries/Adafruit_TinyUSB_Arduino/examples/MassStorage/msc_external_flash/msc_external_flash.ino new file mode 100644 index 00000000000..fc1663c4f12 --- /dev/null +++ b/libraries/Adafruit_TinyUSB_Arduino/examples/MassStorage/msc_external_flash/msc_external_flash.ino @@ -0,0 +1,176 @@ +/********************************************************************* + Adafruit invests time and resources providing this open source code, + please support Adafruit and open-source hardware by purchasing + products from Adafruit! + + MIT license, check LICENSE for more information + Copyright (c) 2019 Ha Thach for Adafruit Industries + All text above, and the splash screen below must be included in + any redistribution +*********************************************************************/ + +/* This example demo how to expose on-board external Flash as USB Mass Storage. + * Following library is required + * - Adafruit_SPIFlash https://github.com/adafruit/Adafruit_SPIFlash + * - SdFat https://github.com/adafruit/SdFat + * + * Note: Adafruit fork of SdFat enabled ENABLE_EXTENDED_TRANSFER_CLASS and FAT12_SUPPORT + * in SdFatConfig.h, which is needed to run SdFat on external flash. You can use original + * SdFat library and manually change those macros + */ + +#include "SPI.h" +#include "SdFat.h" +#include "Adafruit_SPIFlash.h" +#include "Adafruit_TinyUSB.h" + +// Uncomment to run example with FRAM +// #define FRAM_CS A5 +// #define FRAM_SPI SPI + +#if defined(FRAM_CS) && defined(FRAM_SPI) + Adafruit_FlashTransport_SPI flashTransport(FRAM_CS, FRAM_SPI); + +#elif defined(ARDUINO_ARCH_ESP32) + // ESP32 use same flash device that store code. + // Therefore there is no need to specify the SPI and SS + Adafruit_FlashTransport_ESP32 flashTransport; + +#else + // On-board external flash (QSPI or SPI) macros should already + // defined in your board variant if supported + // - EXTERNAL_FLASH_USE_QSPI + // - EXTERNAL_FLASH_USE_CS/EXTERNAL_FLASH_USE_SPI + #if defined(EXTERNAL_FLASH_USE_QSPI) + Adafruit_FlashTransport_QSPI flashTransport; + + #elif defined(EXTERNAL_FLASH_USE_SPI) + Adafruit_FlashTransport_SPI flashTransport(EXTERNAL_FLASH_USE_CS, EXTERNAL_FLASH_USE_SPI); + + #else + #error No QSPI/SPI flash are defined on your board variant.h ! + #endif +#endif + +Adafruit_SPIFlash flash(&flashTransport); + +// file system object from SdFat +FatFileSystem fatfs; + +FatFile root; +FatFile file; + +// USB Mass Storage object +Adafruit_USBD_MSC usb_msc; + +// Set to true when PC write to flash +bool changed; + +// the setup function runs once when you press reset or power the board +void setup() +{ + pinMode(LED_BUILTIN, OUTPUT); + + flash.begin(); + + // Set disk vendor id, product id and revision with string up to 8, 16, 4 characters respectively + usb_msc.setID("Adafruit", "External Flash", "1.0"); + + // Set callback + usb_msc.setReadWriteCallback(msc_read_cb, msc_write_cb, msc_flush_cb); + + // Set disk size, block size should be 512 regardless of spi flash page size + usb_msc.setCapacity(flash.size()/512, 512); + + // MSC is ready for read/write + usb_msc.setUnitReady(true); + + usb_msc.begin(); + + // Init file system on the flash + fatfs.begin(&flash); + + Serial.begin(115200); + //while ( !Serial ) delay(10); // wait for native usb + + Serial.println("Adafruit TinyUSB Mass Storage External Flash example"); + Serial.print("JEDEC ID: "); Serial.println(flash.getJEDECID(), HEX); + Serial.print("Flash size: "); Serial.println(flash.size()); + + changed = true; // to print contents initially +} + +void loop() +{ + if ( changed ) + { + changed = false; + + if ( !root.open("/") ) + { + Serial.println("open root failed"); + return; + } + + Serial.println("Flash contents:"); + + // Open next file in root. + // Warning, openNext starts at the current directory position + // so a rewind of the directory may be required. + while ( file.openNext(&root, O_RDONLY) ) + { + file.printFileSize(&Serial); + Serial.write(' '); + file.printName(&Serial); + if ( file.isDir() ) + { + // Indicate a directory. + Serial.write('/'); + } + Serial.println(); + file.close(); + } + + root.close(); + + Serial.println(); + delay(1000); // refresh every 0.5 second + } +} + +// Callback invoked when received READ10 command. +// Copy disk's data to buffer (up to bufsize) and +// return number of copied bytes (must be multiple of block size) +int32_t msc_read_cb (uint32_t lba, void* buffer, uint32_t bufsize) +{ + // Note: SPIFLash Bock API: readBlocks/writeBlocks/syncBlocks + // already include 4K sector caching internally. We don't need to cache it, yahhhh!! + return flash.readBlocks(lba, (uint8_t*) buffer, bufsize/512) ? bufsize : -1; +} + +// Callback invoked when received WRITE10 command. +// Process data in buffer to disk's storage and +// return number of written bytes (must be multiple of block size) +int32_t msc_write_cb (uint32_t lba, uint8_t* buffer, uint32_t bufsize) +{ + digitalWrite(LED_BUILTIN, HIGH); + + // Note: SPIFLash Bock API: readBlocks/writeBlocks/syncBlocks + // already include 4K sector caching internally. We don't need to cache it, yahhhh!! + return flash.writeBlocks(lba, buffer, bufsize/512) ? bufsize : -1; +} + +// Callback invoked when WRITE10 command is completed (status received and accepted by host). +// used to flush any pending cache. +void msc_flush_cb (void) +{ + // sync with flash + flash.syncBlocks(); + + // clear file system's cache to force refresh + fatfs.cacheClear(); + + changed = true; + + digitalWrite(LED_BUILTIN, LOW); +} diff --git a/libraries/Adafruit_TinyUSB_Arduino/examples/MassStorage/msc_external_flash_sdcard/msc_external_flash_sdcard.ino b/libraries/Adafruit_TinyUSB_Arduino/examples/MassStorage/msc_external_flash_sdcard/msc_external_flash_sdcard.ino new file mode 100644 index 00000000000..8a5bd26a98a --- /dev/null +++ b/libraries/Adafruit_TinyUSB_Arduino/examples/MassStorage/msc_external_flash_sdcard/msc_external_flash_sdcard.ino @@ -0,0 +1,245 @@ +/********************************************************************* + Adafruit invests time and resources providing this open source code, + please support Adafruit and open-source hardware by purchasing + products from Adafruit! + + MIT license, check LICENSE for more information + Copyright (c) 2019 Ha Thach for Adafruit Industries + All text above, and the splash screen below must be included in + any redistribution +*********************************************************************/ + +/* This example exposes both external flash and SD card as mass storage (dual LUNs) + * Following library is required + * - Adafruit_SPIFlash https://github.com/adafruit/Adafruit_SPIFlash + * - SdFat https://github.com/adafruit/SdFat + * + * Note: Adafruit fork of SdFat enabled ENABLE_EXTENDED_TRANSFER_CLASS and FAT12_SUPPORT + * in SdFatConfig.h, which is needed to run SdFat on external flash. You can use original + * SdFat library and manually change those macros + */ + +#include "SPI.h" +#include "SdFat.h" +#include "Adafruit_SPIFlash.h" +#include "Adafruit_TinyUSB.h" + +// Uncomment to run example with FRAM +// #define FRAM_CS A5 +// #define FRAM_SPI SPI + +#if defined(FRAM_CS) && defined(FRAM_SPI) + Adafruit_FlashTransport_SPI flashTransport(FRAM_CS, FRAM_SPI); + +#elif defined(ARDUINO_ARCH_ESP32) + // ESP32 use same flash device that store code. + // Therefore there is no need to specify the SPI and SS + Adafruit_FlashTransport_ESP32 flashTransport; + +#else + // On-board external flash (QSPI or SPI) macros should already + // defined in your board variant if supported + // - EXTERNAL_FLASH_USE_QSPI + // - EXTERNAL_FLASH_USE_CS/EXTERNAL_FLASH_USE_SPI + #if defined(EXTERNAL_FLASH_USE_QSPI) + Adafruit_FlashTransport_QSPI flashTransport; + + #elif defined(EXTERNAL_FLASH_USE_SPI) + Adafruit_FlashTransport_SPI flashTransport(EXTERNAL_FLASH_USE_CS, EXTERNAL_FLASH_USE_SPI); + + #else + #error No QSPI/SPI flash are defined on your board variant.h ! + #endif +#endif + + +Adafruit_SPIFlash flash(&flashTransport); + +// File system object on external flash from SdFat +FatFileSystem fatfs; + +const int chipSelect = 10; + +// File system on SD Card +SdFat sd; + +// USB Mass Storage object +Adafruit_USBD_MSC usb_msc; + +// Set to true when PC write to flash +bool sd_changed = false; +bool flash_changed = false; + +// the setup function runs once when you press reset or power the board +void setup() +{ + pinMode(LED_BUILTIN, OUTPUT); + + // MSC with 2 Logical Units + usb_msc.setMaxLun(2); + + usb_msc.setID(0, "Adafruit", "External Flash", "1.0"); + usb_msc.setID(1, "Adafruit", "SD Card", "1.0"); + + // Since initialize both external flash and SD card can take time. + // If it takes too long, our board could be enumerated as CDC device only + // i.e without Mass Storage. To prevent this, we call Mass Storage begin first + // LUN readiness will always be set later on + usb_msc.begin(); + + //------------- Lun 0 for external flash -------------// + flash.begin(); + fatfs.begin(&flash); + + usb_msc.setCapacity(0, flash.size()/512, 512); + usb_msc.setReadWriteCallback(0, external_flash_read_cb, external_flash_write_cb, external_flash_flush_cb); + usb_msc.setUnitReady(0, true); + + flash_changed = true; // to print contents initially + + //------------- Lun 1 for SD card -------------// + if ( sd.begin(chipSelect, SD_SCK_MHZ(50)) ) + { + uint32_t block_count = sd.card()->cardSize(); + usb_msc.setCapacity(1, block_count, 512); + usb_msc.setReadWriteCallback(1, sdcard_read_cb, sdcard_write_cb, sdcard_flush_cb); + usb_msc.setUnitReady(1, true); + + sd_changed = true; // to print contents initially + } + + Serial.begin(115200); + //while ( !Serial ) delay(10); // wait for native usb + + Serial.println("Adafruit TinyUSB Mass Storage External Flash + SD Card example"); + delay(1000); +} + +void print_rootdir(File* rdir) +{ + File file; + + // Open next file in root. + // Warning, openNext starts at the current directory position + // so a rewind of the directory may be required. + while ( file.openNext(rdir, O_RDONLY) ) + { + file.printFileSize(&Serial); + Serial.write(' '); + file.printName(&Serial); + if ( file.isDir() ) + { + // Indicate a directory. + Serial.write('/'); + } + Serial.println(); + file.close(); + } +} + +void loop() +{ + if ( flash_changed ) + { + File root; + root = fatfs.open("/"); + + Serial.println("Flash contents:"); + print_rootdir(&root); + Serial.println(); + + root.close(); + + flash_changed = false; + } + + if ( sd_changed ) + { + File root; + root = sd.open("/"); + + Serial.println("SD contents:"); + print_rootdir(&root); + Serial.println(); + + root.close(); + + sd_changed = false; + } + + delay(1000); // refresh every 1 second +} + + +//--------------------------------------------------------------------+ +// SD Card callbacks +//--------------------------------------------------------------------+ + +int32_t sdcard_read_cb (uint32_t lba, void* buffer, uint32_t bufsize) +{ + return sd.card()->readBlocks(lba, (uint8_t*) buffer, bufsize/512) ? bufsize : -1; +} + +// Callback invoked when received WRITE10 command. +// Process data in buffer to disk's storage and +// return number of written bytes (must be multiple of block size) +int32_t sdcard_write_cb (uint32_t lba, uint8_t* buffer, uint32_t bufsize) +{ + digitalWrite(LED_BUILTIN, HIGH); + + return sd.card()->writeBlocks(lba, buffer, bufsize/512) ? bufsize : -1; +} + +// Callback invoked when WRITE10 command is completed (status received and accepted by host). +// used to flush any pending cache. +void sdcard_flush_cb (void) +{ + sd.card()->syncBlocks(); + + // clear file system's cache to force refresh + sd.cacheClear(); + + sd_changed = true; + + digitalWrite(LED_BUILTIN, LOW); +} + +//--------------------------------------------------------------------+ +// External Flash callbacks +//--------------------------------------------------------------------+ + +// Callback invoked when received READ10 command. +// Copy disk's data to buffer (up to bufsize) and +// return number of copied bytes (must be multiple of block size) +int32_t external_flash_read_cb (uint32_t lba, void* buffer, uint32_t bufsize) +{ + // Note: SPIFLash Bock API: readBlocks/writeBlocks/syncBlocks + // already include 4K sector caching internally. We don't need to cache it, yahhhh!! + return flash.readBlocks(lba, (uint8_t*) buffer, bufsize/512) ? bufsize : -1; +} + +// Callback invoked when received WRITE10 command. +// Process data in buffer to disk's storage and +// return number of written bytes (must be multiple of block size) +int32_t external_flash_write_cb (uint32_t lba, uint8_t* buffer, uint32_t bufsize) +{ + digitalWrite(LED_BUILTIN, HIGH); + + // Note: SPIFLash Bock API: readBlocks/writeBlocks/syncBlocks + // already include 4K sector caching internally. We don't need to cache it, yahhhh!! + return flash.writeBlocks(lba, buffer, bufsize/512) ? bufsize : -1; +} + +// Callback invoked when WRITE10 command is completed (status received and accepted by host). +// used to flush any pending cache. +void external_flash_flush_cb (void) +{ + flash.syncBlocks(); + + // clear file system's cache to force refresh + fatfs.cacheClear(); + + flash_changed = true; + + digitalWrite(LED_BUILTIN, LOW); +} diff --git a/libraries/Adafruit_TinyUSB_Arduino/examples/MassStorage/msc_ramdisk/msc_ramdisk.ino b/libraries/Adafruit_TinyUSB_Arduino/examples/MassStorage/msc_ramdisk/msc_ramdisk.ino new file mode 100644 index 00000000000..0274b6ef769 --- /dev/null +++ b/libraries/Adafruit_TinyUSB_Arduino/examples/MassStorage/msc_ramdisk/msc_ramdisk.ino @@ -0,0 +1,76 @@ +/********************************************************************* + Adafruit invests time and resources providing this open source code, + please support Adafruit and open-source hardware by purchasing + products from Adafruit! + + MIT license, check LICENSE for more information + Copyright (c) 2019 Ha Thach for Adafruit Industries + All text above, and the splash screen below must be included in + any redistribution +*********************************************************************/ + +#include "Adafruit_TinyUSB.h" + +// 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; + +// the setup function runs once when you press reset or power the board +void setup() +{ + // Set disk vendor id, product id and revision with string up to 8, 16, 4 characters respectively + usb_msc.setID("Adafruit", "Mass Storage", "1.0"); + + // Set disk size + usb_msc.setCapacity(DISK_BLOCK_NUM, DISK_BLOCK_SIZE); + + // Set callback + usb_msc.setReadWriteCallback(msc_read_cb, msc_write_cb, msc_flush_cb); + + // Set Lun ready (RAM disk is always ready) + usb_msc.setUnitReady(true); + + usb_msc.begin(); + + Serial.begin(115200); + //while ( !Serial ) delay(10); // wait for native usb + + Serial.println("Adafruit TinyUSB Mass Storage RAM Disk example"); +} + +void loop() +{ + // nothing to do +} + +// Callback invoked when received READ10 command. +// Copy disk's data to buffer (up to bufsize) and +// return number of copied bytes (must be multiple of block size) +int32_t msc_read_cb (uint32_t lba, void* buffer, uint32_t bufsize) +{ + uint8_t const* addr = msc_disk[lba]; + memcpy(buffer, addr, bufsize); + + return bufsize; +} + +// Callback invoked when received WRITE10 command. +// Process data in buffer to disk's storage and +// return number of written bytes (must be multiple of block size) +int32_t msc_write_cb (uint32_t lba, uint8_t* buffer, uint32_t bufsize) +{ + uint8_t* addr = msc_disk[lba]; + memcpy(addr, buffer, bufsize); + + return bufsize; +} + +// Callback invoked when WRITE10 command is completed (status received and accepted by host). +// used to flush any pending cache. +void msc_flush_cb (void) +{ + // nothing to do +} diff --git a/libraries/Adafruit_TinyUSB_Arduino/examples/MassStorage/msc_ramdisk/ramdisk.h b/libraries/Adafruit_TinyUSB_Arduino/examples/MassStorage/msc_ramdisk/ramdisk.h new file mode 100644 index 00000000000..11aae403563 --- /dev/null +++ b/libraries/Adafruit_TinyUSB_Arduino/examples/MassStorage/msc_ramdisk/ramdisk.h @@ -0,0 +1,113 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2019 Ha Thach for Adafruit Industries + * + * 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 RAMDISK_H_ +#define RAMDISK_H_ + +#define README_CONTENTS \ + "This is TinyUSB MassStorage device demo for Arduino on RAM disk." + +uint8_t msc_disk[DISK_BLOCK_NUM][DISK_BLOCK_SIZE] = { + //------------- Block0: Boot Sector -------------// + // byte_per_sector = DISK_BLOCK_SIZE; fat12_sector_num_16 = + // DISK_BLOCK_NUM; sector_per_cluster = 1; reserved_sectors = 1; fat_num = + // 1; fat12_root_entry_num = 16; sector_per_fat = 1; sector_per_track = + // 1; head_num = 1; hidden_sectors = 0; drive_number = 0x80; + // media_type = 0xf8; extended_boot_signature = 0x29; filesystem_type = + // "FAT12 "; volume_serial_number = 0x1234; volume_label = "TinyUSB MSC"; + // FAT magic code at offset 510-511 + {0xEB, 0x3C, 0x90, 0x4D, 0x53, 0x44, 0x4F, 0x53, 0x35, 0x2E, 0x30, 0x00, + 0x02, 0x01, 0x01, 0x00, 0x01, 0x10, 0x00, 0x10, 0x00, 0xF8, 0x01, 0x00, + 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x80, 0x00, 0x29, 0x34, 0x12, 0x00, 0x00, 'T', 'i', 'n', 'y', 'U', 'S', + 'B', ' ', 'M', 'S', 'C', 0x46, 0x41, 0x54, 0x31, 0x32, 0x20, 0x20, 0x20, + 0x00, 0x00, + + // Zero up to 2 last bytes of FAT magic code + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x55, 0xAA}, + + //------------- Block1: FAT12 Table -------------// + { + 0xF8, 0xFF, 0xFF, 0xFF, 0x0F // // first 2 entries must be F8FF, third + // entry is cluster end of readme file + }, + + //------------- Block2: Root Directory -------------// + { + // first entry is volume label + 'T', 'i', 'n', 'y', 'U', 'S', 'B', ' ', 'M', 'S', 'C', 0x08, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4F, 0x6D, 0x65, 0x43, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + // second entry is readme file + 'R', 'E', 'A', 'D', 'M', 'E', ' ', ' ', 'T', 'X', 'T', 0x20, 0x00, 0xC6, + 0x52, 0x6D, 0x65, 0x43, 0x65, 0x43, 0x00, 0x00, 0x88, 0x6D, 0x65, 0x43, + 0x02, 0x00, sizeof(README_CONTENTS) - 1, 0x00, 0x00, + 0x00 // readme's files size (4 Bytes) + }, + + //------------- Block3: Readme Content -------------// + README_CONTENTS}; + +#endif /* RAMDISK_H_ */ diff --git a/libraries/Adafruit_TinyUSB_Arduino/examples/MassStorage/msc_ramdisk_dual/msc_ramdisk_dual.ino b/libraries/Adafruit_TinyUSB_Arduino/examples/MassStorage/msc_ramdisk_dual/msc_ramdisk_dual.ino new file mode 100644 index 00000000000..80bb3e220e0 --- /dev/null +++ b/libraries/Adafruit_TinyUSB_Arduino/examples/MassStorage/msc_ramdisk_dual/msc_ramdisk_dual.ino @@ -0,0 +1,117 @@ +/********************************************************************* + Adafruit invests time and resources providing this open source code, + please support Adafruit and open-source hardware by purchasing + products from Adafruit! + + MIT license, check LICENSE for more information + Copyright (c) 2019 Ha Thach for Adafruit Industries + All text above, and the splash screen below must be included in + any redistribution +*********************************************************************/ + +#include "Adafruit_TinyUSB.h" + +// 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; + +// the setup function runs once when you press reset or power the board +void setup() +{ + usb_msc.setMaxLun(2); + + // Set disk size and callback for Logical Unit 0 (LUN 0) + usb_msc.setID(0, "Adafruit", "Lun0", "1.0"); + usb_msc.setCapacity(0, DISK_BLOCK_NUM, DISK_BLOCK_SIZE); + usb_msc.setReadWriteCallback(0, ram0_read_cb, ram0_write_cb, ram0_flush_cb); + usb_msc.setUnitReady(0, true); + + // Set disk size and callback for Logical Unit 1 (LUN 1) + usb_msc.setID(1, "Adafruit", "Lun1", "1.0"); + usb_msc.setCapacity(1, DISK_BLOCK_NUM, DISK_BLOCK_SIZE); + usb_msc.setReadWriteCallback(1, ram1_read_cb, ram1_write_cb, ram1_flush_cb); + usb_msc.setUnitReady(1, true); + + usb_msc.begin(); + + Serial.begin(115200); + //while ( !Serial ) delay(10); // wait for native usb + + Serial.println("Adafruit TinyUSB Mass Storage Dual RAM Disks example"); +} + +void loop() +{ + // nothing to do +} + + +//--------------------------------------------------------------------+ +// LUN 0 callback +//--------------------------------------------------------------------+ + +// Callback invoked when received READ10 command. +// Copy disk's data to buffer (up to bufsize) and +// return number of copied bytes (must be multiple of block size) +int32_t ram0_read_cb (uint32_t lba, void* buffer, uint32_t bufsize) +{ + uint8_t const* addr = msc_disk0[lba]; + memcpy(buffer, addr, bufsize); + + return bufsize; +} + +// Callback invoked when received WRITE10 command. +// Process data in buffer to disk's storage and +// return number of written bytes (must be multiple of block size) +int32_t ram0_write_cb (uint32_t lba, uint8_t* buffer, uint32_t bufsize) +{ + uint8_t* addr = msc_disk0[lba]; + memcpy(addr, buffer, bufsize); + + return bufsize; +} + +// Callback invoked when WRITE10 command is completed (status received and accepted by host). +// used to flush any pending cache. +void ram0_flush_cb (void) +{ + // nothing to do +} + + +//--------------------------------------------------------------------+ +// LUN 1 callback +//--------------------------------------------------------------------+ + +// Callback invoked when received READ10 command. +// Copy disk's data to buffer (up to bufsize) and +// return number of copied bytes (must be multiple of block size) +int32_t ram1_read_cb (uint32_t lba, void* buffer, uint32_t bufsize) +{ + uint8_t const* addr = msc_disk1[lba]; + memcpy(buffer, addr, bufsize); + + return bufsize; +} + +// Callback invoked when received WRITE10 command. +// Process data in buffer to disk's storage and +// return number of written bytes (must be multiple of block size) +int32_t ram1_write_cb (uint32_t lba, uint8_t* buffer, uint32_t bufsize) +{ + uint8_t* addr = msc_disk1[lba]; + memcpy(addr, buffer, bufsize); + + return bufsize; +} + +// Callback invoked when WRITE10 command is completed (status received and accepted by host). +// used to flush any pending cache. +void ram1_flush_cb (void) +{ + // nothing to do +} diff --git a/libraries/Adafruit_TinyUSB_Arduino/examples/MassStorage/msc_ramdisk_dual/ramdisk.h b/libraries/Adafruit_TinyUSB_Arduino/examples/MassStorage/msc_ramdisk_dual/ramdisk.h new file mode 100644 index 00000000000..6765fe85ddc --- /dev/null +++ b/libraries/Adafruit_TinyUSB_Arduino/examples/MassStorage/msc_ramdisk_dual/ramdisk.h @@ -0,0 +1,204 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2019 Ha Thach for Adafruit Industries + * + * 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 RAMDISK_H_ +#define RAMDISK_H_ + +//--------------------------------------------------------------------+ +// LUN 0 +//--------------------------------------------------------------------+ +#define README0_CONTENTS \ + "LUN0: This is TinyUSB MassStorage device demo for Arduino on RAM disk." + +uint8_t msc_disk0[DISK_BLOCK_NUM][DISK_BLOCK_SIZE] = { + //------------- Block0: Boot Sector -------------// + // byte_per_sector = DISK_BLOCK_SIZE; fat12_sector_num_16 = + // DISK_BLOCK_NUM; sector_per_cluster = 1; reserved_sectors = 1; fat_num = + // 1; fat12_root_entry_num = 16; sector_per_fat = 1; sector_per_track = + // 1; head_num = 1; hidden_sectors = 0; drive_number = 0x80; + // media_type = 0xf8; extended_boot_signature = 0x29; filesystem_type = + // "FAT12 "; volume_serial_number = 0x1234; volume_label = "TinyUSB 0 "; + // FAT magic code at offset 510-511 + {0xEB, 0x3C, 0x90, 0x4D, 0x53, 0x44, 0x4F, 0x53, 0x35, 0x2E, 0x30, 0x00, + 0x02, 0x01, 0x01, 0x00, 0x01, 0x10, 0x00, 0x10, 0x00, 0xF8, 0x01, 0x00, + 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x80, 0x00, 0x29, 0x34, 0x12, 0x00, 0x00, 'T', 'i', 'n', 'y', 'U', 'S', + 'B', ' ', '0', ' ', ' ', 0x46, 0x41, 0x54, 0x31, 0x32, 0x20, 0x20, 0x20, + 0x00, 0x00, + + // Zero up to 2 last bytes of FAT magic code + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x55, 0xAA}, + + //------------- Block1: FAT12 Table -------------// + { + 0xF8, 0xFF, 0xFF, 0xFF, 0x0F // // first 2 entries must be F8FF, third + // entry is cluster end of readme file + }, + + //------------- Block2: Root Directory -------------// + { + // first entry is volume label + 'T', 'i', 'n', 'y', 'U', 'S', 'B', ' ', '0', ' ', ' ', 0x08, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4F, 0x6D, 0x65, 0x43, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + // second entry is readme file + 'R', 'E', 'A', 'D', 'M', 'E', '0', ' ', 'T', 'X', 'T', 0x20, 0x00, 0xC6, + 0x52, 0x6D, 0x65, 0x43, 0x65, 0x43, 0x00, 0x00, 0x88, 0x6D, 0x65, 0x43, + 0x02, 0x00, sizeof(README0_CONTENTS) - 1, 0x00, 0x00, + 0x00 // readme's files size (4 Bytes) + }, + + //------------- Block3: Readme Content -------------// + README0_CONTENTS}; + +//--------------------------------------------------------------------+ +// LUN 1 +//--------------------------------------------------------------------+ +#define README1_CONTENTS \ + "LUN1: This is TinyUSB MassStorage device demo for Arduino on RAM disk." + +uint8_t msc_disk1[DISK_BLOCK_NUM][DISK_BLOCK_SIZE] = { + //------------- Block0: Boot Sector -------------// + // byte_per_sector = DISK_BLOCK_SIZE; fat12_sector_num_16 = + // DISK_BLOCK_NUM; sector_per_cluster = 1; reserved_sectors = 1; fat_num = + // 1; fat12_root_entry_num = 16; sector_per_fat = 1; sector_per_track = + // 1; head_num = 1; hidden_sectors = 0; drive_number = 0x80; + // media_type = 0xf8; extended_boot_signature = 0x29; filesystem_type = + // "FAT12 "; volume_serial_number = 0x5678; volume_label = "TinyUSB 1 "; + // FAT magic code at offset 510-511 + {0xEB, 0x3C, 0x90, 0x4D, 0x53, 0x44, 0x4F, 0x53, 0x35, 0x2E, 0x30, 0x00, + 0x02, 0x01, 0x01, 0x00, 0x01, 0x10, 0x00, 0x10, 0x00, 0xF8, 0x01, 0x00, + 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x80, 0x00, 0x29, 0x78, 0x56, 0x00, 0x00, 'T', 'i', 'n', 'y', 'U', 'S', + 'B', ' ', '1', ' ', ' ', 0x46, 0x41, 0x54, 0x31, 0x32, 0x20, 0x20, 0x20, + 0x00, 0x00, + + // Zero up to 2 last bytes of FAT magic code + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x55, 0xAA}, + + //------------- Block1: FAT12 Table -------------// + { + 0xF8, 0xFF, 0xFF, 0xFF, 0x0F // // first 2 entries must be F8FF, third + // entry is cluster end of readme file + }, + + //------------- Block2: Root Directory -------------// + { + // first entry is volume label + 'T', 'i', 'n', 'y', 'U', 'S', 'B', ' ', '1', ' ', ' ', 0x08, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4F, 0x6D, 0x65, 0x43, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + // second entry is readme file + 'R', 'E', 'A', 'D', 'M', 'E', '1', ' ', 'T', 'X', 'T', 0x20, 0x00, 0xC6, + 0x52, 0x6D, 0x65, 0x43, 0x65, 0x43, 0x00, 0x00, 0x88, 0x6D, 0x65, 0x43, + 0x02, 0x00, sizeof(README1_CONTENTS) - 1, 0x00, 0x00, + 0x00 // readme's files size (4 Bytes) + }, + + //------------- Block3: Readme Content -------------// + README1_CONTENTS}; + +#endif /* RAMDISK_H_ */ diff --git a/libraries/Adafruit_TinyUSB_Arduino/examples/MassStorage/msc_sd/msc_sd.ino b/libraries/Adafruit_TinyUSB_Arduino/examples/MassStorage/msc_sd/msc_sd.ino new file mode 100644 index 00000000000..adadc49551c --- /dev/null +++ b/libraries/Adafruit_TinyUSB_Arduino/examples/MassStorage/msc_sd/msc_sd.ino @@ -0,0 +1,102 @@ +/********************************************************************* + Adafruit invests time and resources providing this open source code, + please support Adafruit and open-source hardware by purchasing + products from Adafruit! + + MIT license, check LICENSE for more information + Copyright (c) 2019 Ha Thach for Adafruit Industries + All text above, and the splash screen below must be included in + any redistribution +*********************************************************************/ + +/* This example expose SD card as mass storage using + * default SD Library + */ + +#include "SD.h" +#include "Adafruit_TinyUSB.h" + +const int chipSelect = 10; + +Adafruit_USBD_MSC usb_msc; + +Sd2Card card; +SdVolume volume; + +// the setup function runs once when you press reset or power the board +void setup() +{ + // Set disk vendor id, product id and revision with string up to 8, 16, 4 characters respectively + usb_msc.setID("Adafruit", "SD Card", "1.0"); + + // Set read write callback + usb_msc.setReadWriteCallback(msc_read_cb, msc_write_cb, msc_flush_cb); + + // Still initialize MSC but tell usb stack that MSC is not ready to read/write + // If we don't initialize, board will be enumerated as CDC only + usb_msc.setUnitReady(false); + usb_msc.begin(); + + Serial.begin(115200); + //while ( !Serial ) delay(10); // wait for native usb + + Serial.println("Adafruit TinyUSB Mass Storage SD Card example"); + + Serial.println("\nInitializing SD card..."); + + if ( !card.init(SPI_HALF_SPEED, chipSelect) ) + { + Serial.println("initialization failed. Things to check:"); + Serial.println("* is a card inserted?"); + Serial.println("* is your wiring correct?"); + Serial.println("* did you change the chipSelect pin to match your shield or module?"); + while (1) delay(1); + } + + // Now we will try to open the 'volume'/'partition' - it should be FAT16 or FAT32 + if (!volume.init(card)) { + Serial.println("Could not find FAT16/FAT32 partition.\nMake sure you've formatted the card"); + while (1) delay(1); + } + + uint32_t block_count = volume.blocksPerCluster()*volume.clusterCount(); + + Serial.print("Volume size (MB): "); + Serial.println((block_count/2) / 1024); + + // Set disk size, SD block size is always 512 + usb_msc.setCapacity(block_count, 512); + + // MSC is ready for read/write + usb_msc.setUnitReady(true); +} + +void loop() +{ + // nothing to do +} + +// Callback invoked when received READ10 command. +// Copy disk's data to buffer (up to bufsize) and +// return number of copied bytes (must be multiple of block size) +int32_t msc_read_cb (uint32_t lba, void* buffer, uint32_t bufsize) +{ + (void) bufsize; + return card.readBlock(lba, (uint8_t*) buffer) ? 512 : -1; +} + +// Callback invoked when received WRITE10 command. +// Process data in buffer to disk's storage and +// return number of written bytes (must be multiple of block size) +int32_t msc_write_cb (uint32_t lba, uint8_t* buffer, uint32_t bufsize) +{ + (void) bufsize; + return card.writeBlock(lba, buffer) ? 512 : -1; +} + +// Callback invoked when WRITE10 command is completed (status received and accepted by host). +// used to flush any pending cache. +void msc_flush_cb (void) +{ + // nothing to do +} diff --git a/libraries/Adafruit_TinyUSB_Arduino/examples/MassStorage/msc_sdfat/msc_sdfat.ino b/libraries/Adafruit_TinyUSB_Arduino/examples/MassStorage/msc_sdfat/msc_sdfat.ino new file mode 100644 index 00000000000..b0e43080df1 --- /dev/null +++ b/libraries/Adafruit_TinyUSB_Arduino/examples/MassStorage/msc_sdfat/msc_sdfat.ino @@ -0,0 +1,145 @@ +/********************************************************************* + Adafruit invests time and resources providing this open source code, + please support Adafruit and open-source hardware by purchasing + products from Adafruit! + + MIT license, check LICENSE for more information + Copyright (c) 2019 Ha Thach for Adafruit Industries + All text above, and the splash screen below must be included in + any redistribution +*********************************************************************/ + +/* This example expose SD card as mass storage using + * SdFat Library + */ + +#include "SPI.h" +#include "SdFat.h" +#include "Adafruit_TinyUSB.h" + +const int chipSelect = 10; + +// File system on SD Card +SdFat sd; + +SdFile root; +SdFile file; + +// USB Mass Storage object +Adafruit_USBD_MSC usb_msc; + +// Set to true when PC write to flash +bool changed; + +// the setup function runs once when you press reset or power the board +void setup() +{ + pinMode(LED_BUILTIN, OUTPUT); + + // Set disk vendor id, product id and revision with string up to 8, 16, 4 characters respectively + usb_msc.setID("Adafruit", "SD Card", "1.0"); + + // Set read write callback + usb_msc.setReadWriteCallback(msc_read_cb, msc_write_cb, msc_flush_cb); + + // Still initialize MSC but tell usb stack that MSC is not ready to read/write + // If we don't initialize, board will be enumerated as CDC only + usb_msc.setUnitReady(false); + usb_msc.begin(); + + Serial.begin(115200); + //while ( !Serial ) delay(10); // wait for native usb + + Serial.println("Adafruit TinyUSB Mass Storage SD Card example"); + + Serial.print("\nInitializing SD card ... "); + Serial.print("CS = "); Serial.println(chipSelect); + + if ( !sd.begin(chipSelect, SD_SCK_MHZ(50)) ) + { + Serial.println("initialization failed. Things to check:"); + Serial.println("* is a card inserted?"); + Serial.println("* is your wiring correct?"); + Serial.println("* did you change the chipSelect pin to match your shield or module?"); + while (1) delay(1); + } + + // Size in blocks (512 bytes) + uint32_t block_count = sd.card()->cardSize(); + + Serial.print("Volume size (MB): "); + Serial.println((block_count/2) / 1024); + + // Set disk size, SD block size is always 512 + usb_msc.setCapacity(block_count, 512); + + // MSC is ready for read/write + usb_msc.setUnitReady(true); + + changed = true; // to print contents initially +} + +void loop() +{ + if ( changed ) + { + root.open("/"); + Serial.println("SD contents:"); + + // Open next file in root. + // Warning, openNext starts at the current directory position + // so a rewind of the directory may be required. + while ( file.openNext(&root, O_RDONLY) ) + { + file.printFileSize(&Serial); + Serial.write(' '); + file.printName(&Serial); + if ( file.isDir() ) + { + // Indicate a directory. + Serial.write('/'); + } + Serial.println(); + file.close(); + } + + root.close(); + + Serial.println(); + + changed = false; + delay(1000); // refresh every 0.5 second + } +} + +// Callback invoked when received READ10 command. +// Copy disk's data to buffer (up to bufsize) and +// return number of copied bytes (must be multiple of block size) +int32_t msc_read_cb (uint32_t lba, void* buffer, uint32_t bufsize) +{ + return sd.card()->readBlocks(lba, (uint8_t*) buffer, bufsize/512) ? bufsize : -1; +} + +// Callback invoked when received WRITE10 command. +// Process data in buffer to disk's storage and +// return number of written bytes (must be multiple of block size) +int32_t msc_write_cb (uint32_t lba, uint8_t* buffer, uint32_t bufsize) +{ + digitalWrite(LED_BUILTIN, HIGH); + + return sd.card()->writeBlocks(lba, buffer, bufsize/512) ? bufsize : -1; +} + +// Callback invoked when WRITE10 command is completed (status received and accepted by host). +// used to flush any pending cache. +void msc_flush_cb (void) +{ + sd.card()->syncBlocks(); + + // clear file system's cache to force refresh + sd.cacheClear(); + + changed = true; + + digitalWrite(LED_BUILTIN, LOW); +} diff --git a/libraries/Adafruit_TinyUSB_Arduino/examples/WebUSB/webusb_rgb/webusb_rgb.ino b/libraries/Adafruit_TinyUSB_Arduino/examples/WebUSB/webusb_rgb/webusb_rgb.ino new file mode 100644 index 00000000000..a081644ba41 --- /dev/null +++ b/libraries/Adafruit_TinyUSB_Arduino/examples/WebUSB/webusb_rgb/webusb_rgb.ino @@ -0,0 +1,110 @@ +/********************************************************************* + Adafruit invests time and resources providing this open source code, + please support Adafruit and open-source hardware by purchasing + products from Adafruit! + + MIT license, check LICENSE for more information + Copyright (c) 2019 Ha Thach for Adafruit Industries + All text above, and the splash screen below must be included in + any redistribution +*********************************************************************/ + +/* This sketch demonstrates WebUSB as web serial with browser with WebUSB support (e.g Chrome). + * After enumerated successfully, Browser will pop-up notification + * with URL to landing page, click on it to test + * - Click "Connect" and select device, When connected the neopixel LED will change color to Green. + * - When received color from browser in format '#RRGGBB', device will change the color of neopixel accordingly + * + * Note: + * - The WebUSB landing page notification is currently disabled in Chrome + * on Windows due to Chromium issue 656702 (https://crbug.com/656702). You have to + * go to landing page (below) to test + * + * - On Windows 7 and prior: You need to use Zadig tool to manually bind the + * WebUSB interface with the WinUSB driver for Chrome to access. From windows 8 and 10, this + * is done automatically by firmware. + */ + +#include "Adafruit_TinyUSB.h" +#include + +// Which pin on the Arduino is connected to the NeoPixels? +// On a Trinket or Gemma we suggest changing this to 1 +// use on-board neopixel PIN_NEOPIXEL if existed +#ifdef PIN_NEOPIXEL + #define PIN PIN_NEOPIXEL +#else + #define PIN 8 +#endif + +// How many NeoPixels are attached to the Arduino? +#define NUMPIXELS 10 + +// When we setup the NeoPixel library, we tell it how many pixels, and which pin to use to send signals. +// Note that for older NeoPixel strips you might need to change the third parameter--see the strandtest +// example for more information on possible values. +Adafruit_NeoPixel pixels = Adafruit_NeoPixel(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800); + +// USB WebUSB object +Adafruit_USBD_WebUSB usb_web; + +// Landing Page: scheme (0: http, 1: https), url +WEBUSB_URL_DEF(landingPage, 1 /*https*/, "adafruit.github.io/Adafruit_TinyUSB_Arduino/examples/webusb-rgb/index.html"); + +// the setup function runs once when you press reset or power the board +void setup() +{ + //usb_web.setStringDescriptor("TinyUSB WebUSB"); + usb_web.setLandingPage(&landingPage); + usb_web.setLineStateCallback(line_state_callback); + usb_web.begin(); + + Serial.begin(115200); + + // This initializes the NeoPixel with RED + pixels.begin(); + pixels.setBrightness(50); + pixels.fill(0xff0000); + pixels.show(); + + // wait until device mounted + while( !USBDevice.mounted() ) delay(1); + + Serial.println("TinyUSB WebUSB RGB example"); +} + +// convert a hex character to number +uint8_t char2num(char c) +{ + if (c >= 'a') return c - 'a' + 10; + if (c >= 'A') return c - 'A' + 10; + return c - '0'; +} + +void loop() +{ + // Landing Page 7 characters as hex color '#RRGGBB' + if (usb_web.available() < 7) return; + + uint8_t input[7]; + usb_web.readBytes(input, 7); + + // Print to serial for debugging + Serial.write(input, 7); + Serial.println(); + + uint8_t red = 16*char2num(input[1]) + char2num(input[2]); + uint8_t green = 16*char2num(input[3]) + char2num(input[4]); + uint8_t blue = 16*char2num(input[5]) + char2num(input[6]); + + uint32_t color = (red << 16) | (green << 8) | blue; + pixels.fill(color); + pixels.show(); +} + +void line_state_callback(bool connected) +{ + // connected = green, disconnected = red + pixels.fill(connected ? 0x00ff00 : 0xff0000); + pixels.show(); +} diff --git a/libraries/Adafruit_TinyUSB_Arduino/examples/WebUSB/webusb_serial/webusb_serial.ino b/libraries/Adafruit_TinyUSB_Arduino/examples/WebUSB/webusb_serial/webusb_serial.ino new file mode 100644 index 00000000000..c134710d1d9 --- /dev/null +++ b/libraries/Adafruit_TinyUSB_Arduino/examples/WebUSB/webusb_serial/webusb_serial.ino @@ -0,0 +1,81 @@ +/********************************************************************* + Adafruit invests time and resources providing this open source code, + please support Adafruit and open-source hardware by purchasing + products from Adafruit! + + MIT license, check LICENSE for more information + Copyright (c) 2019 Ha Thach for Adafruit Industries + All text above, and the splash screen below must be included in + any redistribution +*********************************************************************/ + +/* This sketch demonstrates WebUSB as web serial with browser with WebUSB support (e.g Chrome). + * After enumerated successfully, Browser will pop-up notification + * with URL to landing page, click on it to test + * - Click "Connect" and select device, When connected the on-board LED will litted up. + * - Any charters received from either webusb/Serial will be echo back to webusb and Serial + * + * Note: + * - The WebUSB landing page notification is currently disabled in Chrome + * on Windows due to Chromium issue 656702 (https://crbug.com/656702). You have to + * go to landing page (below) to test + * + * - On Windows 7 and prior: You need to use Zadig tool to manually bind the + * WebUSB interface with the WinUSB driver for Chrome to access. From windows 8 and 10, this + * is done automatically by firmware. + */ + +#include "Adafruit_TinyUSB.h" + +// USB WebUSB object +Adafruit_USBD_WebUSB usb_web; + +// Landing Page: scheme (0: http, 1: https), url +WEBUSB_URL_DEF(landingPage, 1 /*https*/, "adafruit.github.io/Adafruit_TinyUSB_Arduino/examples/webusb-serial/index.html"); + +int led_pin = LED_BUILTIN; + +// the setup function runs once when you press reset or power the board +void setup() +{ + pinMode(led_pin, OUTPUT); + digitalWrite(led_pin, LOW); + + usb_web.setLandingPage(&landingPage); + usb_web.setLineStateCallback(line_state_callback); + //usb_web.setStringDescriptor("TinyUSB WebUSB"); + usb_web.begin(); + + Serial.begin(115200); + + // wait until device mounted + while( !USBDevice.mounted() ) delay(1); + + Serial.println("TinyUSB WebUSB Serial example"); +} + +// function to echo to both Serial and WebUSB +void echo_all(char chr) +{ + Serial.write(chr); + // print extra newline for Serial + if ( chr == '\r' ) Serial.write('\n'); + + usb_web.write(chr); +} + +void loop() +{ + // from WebUSB to both Serial & webUSB + if (usb_web.available()) echo_all(usb_web.read()); + + // From Serial to both Serial & webUSB + if (Serial.available()) echo_all(Serial.read()); +} + +void line_state_callback(bool connected) +{ + digitalWrite(led_pin, connected); + + if ( connected ) usb_web.println("TinyUSB WebUSB Serial example"); +} diff --git a/libraries/Adafruit_TinyUSB_Arduino/library.properties b/libraries/Adafruit_TinyUSB_Arduino/library.properties new file mode 100644 index 00000000000..2e8e8e96409 --- /dev/null +++ b/libraries/Adafruit_TinyUSB_Arduino/library.properties @@ -0,0 +1,11 @@ +name=Adafruit TinyUSB Library +version=1.3.2 +author=Adafruit +maintainer=Adafruit +sentence=TinyUSB library for Arduino +paragraph=TinyUSB library for Arduino +category=Communication +url=https://github.com/adafruit/Adafruit_TinyUSB_Arduino +architectures=* +includes=Adafruit_TinyUSB.h +depends=Adafruit SPIFlash, MIDI Library, Adafruit seesaw Library, Adafruit NeoPixel, SdFat - Adafruit Fork, SD, Adafruit Circuit Playground diff --git a/libraries/Adafruit_TinyUSB_Arduino/src/Adafruit_TinyUSB.h b/libraries/Adafruit_TinyUSB_Arduino/src/Adafruit_TinyUSB.h new file mode 100644 index 00000000000..eab462e03b3 --- /dev/null +++ b/libraries/Adafruit_TinyUSB_Arduino/src/Adafruit_TinyUSB.h @@ -0,0 +1,53 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2019 Ha Thach for Adafruit Industries + * + * 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 ADAFRUIT_TINYUSB_H_ +#define ADAFRUIT_TINYUSB_H_ + +// 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) ) +#error TinyUSB is not selected, please select it in "Tools->Menu->USB Stack" +#endif + +#include "tusb_option.h" + +#if TUSB_OPT_DEVICE_ENABLED + +#include "arduino/Adafruit_USBD_Device.h" +#include "arduino/Adafruit_USBD_CDC.h" + +#include "arduino/hid/Adafruit_USBD_HID.h" +#include "arduino/midi/Adafruit_USBD_MIDI.h" +#include "arduino/msc/Adafruit_USBD_MSC.h" +#include "arduino/webusb/Adafruit_USBD_WebUSB.h" + +// Initialize device hardware, stack, also Serial as CDC +// Wrapper for USBDevice.begin(rhport) +void TinyUSB_Device_Init(uint8_t rhport); + +#endif + +#endif /* ADAFRUIT_TINYUSB_H_ */ diff --git a/libraries/Adafruit_TinyUSB_Arduino/src/arduino/Adafruit_TinyUSB_API.cpp b/libraries/Adafruit_TinyUSB_Arduino/src/arduino/Adafruit_TinyUSB_API.cpp new file mode 100644 index 00000000000..679361a9890 --- /dev/null +++ b/libraries/Adafruit_TinyUSB_Arduino/src/arduino/Adafruit_TinyUSB_API.cpp @@ -0,0 +1,58 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2019 Ha Thach for Adafruit Industries + * + * 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. + */ + +#include "tusb_option.h" + +#if TUSB_OPT_DEVICE_ENABLED + +#include "Adafruit_TinyUSB.h" + +//--------------------------------------------------------------------+ +// MACRO TYPEDEF CONSTANT ENUM DECLARATION +//--------------------------------------------------------------------+ +extern "C" { + +void TinyUSB_Device_Init(uint8_t rhport) { + // Init USB Device controller and stack + USBDevice.begin(rhport); +} + +// RP2040 has its own implementation since it needs mutex for dual core +#ifndef ARDUINO_ARCH_RP2040 +void TinyUSB_Device_Task(void) { + // Run tinyusb device task + tud_task(); +} +#endif + +void TinyUSB_Device_FlushCDC(void) { + uint8_t const cdc_instance = Adafruit_USBD_CDC::getInstanceCount(); + for (uint8_t instance = 0; instance < cdc_instance; instance++) { + tud_cdc_n_write_flush(instance); + } +} + +} // extern C + +#endif diff --git a/libraries/Adafruit_TinyUSB_Arduino/src/arduino/Adafruit_TinyUSB_API.h b/libraries/Adafruit_TinyUSB_Arduino/src/arduino/Adafruit_TinyUSB_API.h new file mode 100644 index 00000000000..51b203b120e --- /dev/null +++ b/libraries/Adafruit_TinyUSB_Arduino/src/arduino/Adafruit_TinyUSB_API.h @@ -0,0 +1,72 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2019 Ha Thach for Adafruit Industries + * + * 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 ADAFRUIT_TINYUSB_API_H_ +#define ADAFRUIT_TINYUSB_API_H_ + +#include +#include + +//--------------------------------------------------------------------+ +// Core API +// Should be called by BSP Core to initialize, process task +// Weak function allow compile arduino core before linking with this library +//--------------------------------------------------------------------+ +#ifdef __cplusplus +extern "C" { +#endif + +// Called by core/sketch to initialize usb device hardware and stack +// This also initialize Serial as CDC device +void TinyUSB_Device_Init(uint8_t rhport) __attribute__((weak)); + +// Called by core/sketch to handle device event +void TinyUSB_Device_Task(void) __attribute__((weak)); + +// Called by core/sketch to flush write on CDC +void TinyUSB_Device_FlushCDC(void) __attribute__((weak)); + +#ifdef __cplusplus +} +#endif + +//--------------------------------------------------------------------+ +// Port API +// Must be implemented by each BSP core/platform +//--------------------------------------------------------------------+ + +// To enter/reboot to bootloader +// usually when host disconnects cdc at baud 1200 (touch 1200) +void TinyUSB_Port_EnterDFU(void); + +// Init device hardware. +// Called by TinyUSB_Device_Init() +void TinyUSB_Port_InitDevice(uint8_t rhport); + +// Get unique serial number, needed for Serial String Descriptor +// Fill serial_id (raw bytes) and return its length (limit to 16 bytes) +// Note: Serial descriptor can be overwritten by user API +uint8_t TinyUSB_Port_GetSerialNumber(uint8_t serial_id[16]); + +#endif diff --git a/libraries/Adafruit_TinyUSB_Arduino/src/arduino/Adafruit_USBD_CDC.cpp b/libraries/Adafruit_TinyUSB_Arduino/src/arduino/Adafruit_USBD_CDC.cpp new file mode 100644 index 00000000000..8beadc635f1 --- /dev/null +++ b/libraries/Adafruit_TinyUSB_Arduino/src/arduino/Adafruit_USBD_CDC.cpp @@ -0,0 +1,253 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2019 Ha Thach for Adafruit Industries + * + * 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. + */ + +#include "tusb_option.h" + +#if TUSB_OPT_DEVICE_ENABLED && CFG_TUD_CDC + +#include "Arduino.h" + +#include "Adafruit_TinyUSB_API.h" + +#include "Adafruit_USBD_CDC.h" +#include "Adafruit_USBD_Device.h" + +// Starting endpoints; adjusted elsewhere as needed +#define EPOUT 0x00 +#define EPIN 0x80 + +// SerialTinyUSB can be macro expanding to "Serial" on supported cores +Adafruit_USBD_CDC SerialTinyUSB; + +//------------- Static member -------------// +uint8_t Adafruit_USBD_CDC::_instance_count = 0; + +uint8_t Adafruit_USBD_CDC::getInstanceCount(void) { return _instance_count; } + +Adafruit_USBD_CDC::Adafruit_USBD_CDC(void) { _instance = INVALID_INSTANCE; } + +uint16_t Adafruit_USBD_CDC::getInterfaceDescriptor(uint8_t itfnum, uint8_t *buf, + uint16_t bufsize) { + // CDC is mostly always existed for DFU + // usb core will automatically update endpoint number + uint8_t desc[] = {TUD_CDC_DESCRIPTOR(itfnum, 0, EPIN, 8, EPOUT, EPIN, 64)}; + uint16_t const len = sizeof(desc); + + if (bufsize < len) { + return 0; + } + + memcpy(buf, desc, len); + return len; +} + +// Baud and config is ignore in CDC +void Adafruit_USBD_CDC::begin(uint32_t baud) { + (void)baud; + + // already called begin() + if (isValid()) { + return; + } + + // too many instances + if (!(_instance_count < CFG_TUD_CDC)) { + return; + } + + _instance = _instance_count++; + this->setStringDescriptor("TinyUSB Serial"); + USBDevice.addInterface(*this); +} + +void Adafruit_USBD_CDC::begin(uint32_t baud, uint8_t config) { + (void)config; + this->begin(baud); +} + +void Adafruit_USBD_CDC::end(void) { + // Reset configuration descriptor without Serial as CDC + USBDevice.clearConfiguration(); + _instance_count = 0; +} + +uint32_t Adafruit_USBD_CDC::baud(void) { + if (!isValid()) { + return 0; + } + + cdc_line_coding_t coding; + tud_cdc_n_get_line_coding(_instance, &coding); + + return coding.bit_rate; +} + +uint8_t Adafruit_USBD_CDC::stopbits(void) { + if (!isValid()) { + return 0; + } + + cdc_line_coding_t coding; + tud_cdc_n_get_line_coding(_instance, &coding); + + return coding.stop_bits; +} + +uint8_t Adafruit_USBD_CDC::paritytype(void) { + if (!isValid()) { + return 0; + } + + cdc_line_coding_t coding; + tud_cdc_n_get_line_coding(_instance, &coding); + + return coding.parity; +} + +uint8_t Adafruit_USBD_CDC::numbits(void) { + if (!isValid()) { + return 0; + } + + cdc_line_coding_t coding; + tud_cdc_n_get_line_coding(_instance, &coding); + + return coding.data_bits; +} + +int Adafruit_USBD_CDC::dtr(void) { + if (!isValid()) { + return 0; + } + + return tud_cdc_n_connected(_instance); +} + +Adafruit_USBD_CDC::operator bool() { + if (!isValid()) { + return false; + } + + bool ret = tud_cdc_n_connected(_instance); + + // Add an yield to run usb background in case sketch block wait as follows + // while( !Serial ) {} + if (!ret) { + yield(); + } + return ret; +} + +int Adafruit_USBD_CDC::available(void) { + if (!isValid()) { + return 0; + } + + uint32_t count = tud_cdc_n_available(_instance); + + // Add an yield to run usb background in case sketch block wait as follows + // while( !Serial.available() ) {} + if (!count) { + yield(); + } + + return count; +} + +int Adafruit_USBD_CDC::peek(void) { + if (!isValid()) { + return -1; + } + + uint8_t ch; + return tud_cdc_n_peek(_instance, &ch) ? (int)ch : -1; +} + +int Adafruit_USBD_CDC::read(void) { + if (!isValid()) { + return -1; + } + return (int)tud_cdc_n_read_char(_instance); +} + +void Adafruit_USBD_CDC::flush(void) { + if (!isValid()) { + return; + } + + tud_cdc_n_write_flush(_instance); +} + +size_t Adafruit_USBD_CDC::write(uint8_t ch) { return write(&ch, 1); } + +size_t Adafruit_USBD_CDC::write(const uint8_t *buffer, size_t size) { + if (!isValid()) { + return 0; + } + + size_t remain = size; + while (remain && tud_cdc_n_connected(_instance)) { + size_t wrcount = tud_cdc_n_write(_instance, buffer, remain); + remain -= wrcount; + buffer += wrcount; + + // Write FIFO is full, run usb background to flush + if (remain) { + yield(); + } + } + + return size - remain; +} + +int Adafruit_USBD_CDC::availableForWrite(void) { + if (!isValid()) { + return 0; + } + return tud_cdc_n_write_available(_instance); +} + +extern "C" { + +// Invoked when cdc when line state changed e.g connected/disconnected +// Use to reset to DFU when disconnect with 1200 bps +void tud_cdc_line_state_cb(uint8_t instance, bool dtr, bool rts) { + (void)rts; + + // DTR = false is counted as disconnected + if (!dtr) { + // touch1200 only with first CDC instance (Serial) + if (instance == 0) { + cdc_line_coding_t coding; + tud_cdc_get_line_coding(&coding); + + if (coding.bit_rate == 1200) { + TinyUSB_Port_EnterDFU(); + } + } + } +} +} + +#endif // TUSB_OPT_DEVICE_ENABLED diff --git a/libraries/Adafruit_TinyUSB_Arduino/src/arduino/Adafruit_USBD_CDC.h b/libraries/Adafruit_TinyUSB_Arduino/src/arduino/Adafruit_USBD_CDC.h new file mode 100644 index 00000000000..7c8f1f65131 --- /dev/null +++ b/libraries/Adafruit_TinyUSB_Arduino/src/arduino/Adafruit_USBD_CDC.h @@ -0,0 +1,98 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2019 Ha Thach for Adafruit Industries + * + * 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 ADAFRUIT_USBD_CDC_H_ +#define ADAFRUIT_USBD_CDC_H_ + +#include "Adafruit_TinyUSB_API.h" + +#ifdef __cplusplus + +#include "Adafruit_USBD_Interface.h" +#include "Stream.h" + +class Adafruit_USBD_CDC : public Stream, public Adafruit_USBD_Interface { +public: + Adafruit_USBD_CDC(void); + + static uint8_t getInstanceCount(void); + + // fron Adafruit_USBD_Interface + virtual uint16_t getInterfaceDescriptor(uint8_t itfnum, uint8_t *buf, + uint16_t bufsize); + + void setPins(uint8_t pin_rx, uint8_t pin_tx) { + (void)pin_rx; + (void)pin_tx; + } + void begin(uint32_t baud); + void begin(uint32_t baud, uint8_t config); + void end(void); + + // return line coding set by host + uint32_t baud(void); + uint8_t stopbits(void); + uint8_t paritytype(void); + uint8_t numbits(void); + int dtr(void); + + // Stream API + virtual int available(void); + virtual int peek(void); + virtual int read(void); + virtual void flush(void); + virtual size_t write(uint8_t); + + virtual size_t write(const uint8_t *buffer, size_t size); + size_t write(const char *buffer, size_t size) { + return write((const uint8_t *)buffer, size); + } + + virtual int availableForWrite(void); + using Print::write; // pull in write(str) from Print + operator bool(); + +private: + enum { INVALID_INSTANCE = 0xffu }; + static uint8_t _instance_count; + + uint8_t _instance; + + bool isValid(void) { return _instance != INVALID_INSTANCE; } +}; + +// "Serial" is used with TinyUSB CDC +#if defined(USE_TINYUSB) && \ + !(defined(ARDUINO_ARCH_ESP32) && ARDUINO_SERIAL_PORT == 0) +extern Adafruit_USBD_CDC Serial; +#define SerialTinyUSB Serial +#endif + +// Serial is probably used with HW Uart +#ifndef SerialTinyUSB +extern Adafruit_USBD_CDC SerialTinyUSB; +#endif + +#endif // __cplusplus +#endif diff --git a/libraries/Adafruit_TinyUSB_Arduino/src/arduino/Adafruit_USBD_Device.cpp b/libraries/Adafruit_TinyUSB_Arduino/src/arduino/Adafruit_USBD_Device.cpp new file mode 100644 index 00000000000..6ad4f127e7a --- /dev/null +++ b/libraries/Adafruit_TinyUSB_Arduino/src/arduino/Adafruit_USBD_Device.cpp @@ -0,0 +1,480 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2019 Ha Thach for Adafruit Industries + * + * 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. + */ + +#include "tusb_option.h" + +#if TUSB_OPT_DEVICE_ENABLED + +#include "Adafruit_TinyUSB_API.h" + +#include "Adafruit_USBD_CDC.h" +#include "Adafruit_USBD_Device.h" + +// USB Information can be defined in variant file e.g pins_arduino.h +#include "Arduino.h" + +#ifndef USB_VID +#define USB_VID 0xcafe +#endif + +#ifndef USB_PID +#define USB_PID 0xcafe +#endif + +#ifndef USB_MANUFACTURER +#define USB_MANUFACTURER "Unknown" +#endif + +#ifndef USB_PRODUCT +#define USB_PRODUCT "Unknown" +#endif + +#ifndef USB_LANGUAGE +#define USB_LANGUAGE 0x0409 // default is English +#endif + +#ifndef USB_CONFIG_POWER +#define USB_CONFIG_POWER 100 +#endif + +enum { STRID_LANGUAGE = 0, STRID_MANUFACTURER, STRID_PRODUCT, STRID_SERIAL }; + +Adafruit_USBD_Device USBDevice; + +Adafruit_USBD_Device::Adafruit_USBD_Device(void) {} + +void Adafruit_USBD_Device::clearConfiguration(void) { + tusb_desc_device_t const desc_dev = {.bLength = sizeof(tusb_desc_device_t), + .bDescriptorType = TUSB_DESC_DEVICE, + .bcdUSB = 0x0200, + .bDeviceClass = 0, + .bDeviceSubClass = 0, + .bDeviceProtocol = 0, + .bMaxPacketSize0 = + CFG_TUD_ENDPOINT0_SIZE, + .idVendor = USB_VID, + .idProduct = USB_PID, + .bcdDevice = 0x0100, + .iManufacturer = STRID_MANUFACTURER, + .iProduct = STRID_PRODUCT, + .iSerialNumber = STRID_SERIAL, + .bNumConfigurations = 0x01}; + + _desc_device = desc_dev; + + // Config number, interface count, string index, total length, + // attribute (bit 7 set to 1), power in mA. + // Note: Total Length Interface Number will be updated later + uint8_t const dev_cfg[sizeof(tusb_desc_configuration_t)] = { + TUD_CONFIG_DESCRIPTOR(1, 0, 0, sizeof(tusb_desc_configuration_t), + TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP | TU_BIT(7), + 100), + }; + + memcpy(_desc_cfg_buffer, dev_cfg, sizeof(tusb_desc_configuration_t)); + _desc_cfg = _desc_cfg_buffer; + _desc_cfg_maxlen = sizeof(_desc_cfg_buffer); + _desc_cfg_len = sizeof(tusb_desc_configuration_t); + + _itf_count = 0; + _epin_count = _epout_count = 1; + + memset(_desc_str_arr, 0, sizeof(_desc_str_arr)); + _desc_str_arr[STRID_LANGUAGE] = (const char *)((uint32_t)USB_LANGUAGE); + _desc_str_arr[STRID_MANUFACTURER] = USB_MANUFACTURER; + _desc_str_arr[STRID_PRODUCT] = USB_PRODUCT; + // STRID_SERIAL is platform dependent + + _desc_str_count = 4; +} + +// Add interface descriptor +// - Interface number will be updated to match current count +// - Endpoint number is updated to be unique +bool Adafruit_USBD_Device::addInterface(Adafruit_USBD_Interface &itf) { + uint8_t *desc = _desc_cfg + _desc_cfg_len; + uint16_t const len = itf.getInterfaceDescriptor( + _itf_count, desc, _desc_cfg_maxlen - _desc_cfg_len); + uint8_t *desc_end = desc + len; + + const char *desc_str = itf.getStringDescriptor(); + + if (!len) { + return false; + } + + // Parse interface descriptor to update + // - Interface Number & string descriptor + // - Endpoint address + while (desc < desc_end) { + if (desc[1] == TUSB_DESC_INTERFACE) { + tusb_desc_interface_t *desc_itf = (tusb_desc_interface_t *)desc; + if (desc_itf->bAlternateSetting == 0) { + _itf_count++; + if (desc_str && (_desc_str_count < STRING_DESCRIPTOR_MAX)) { + _desc_str_arr[_desc_str_count] = desc_str; + desc_itf->iInterface = _desc_str_count; + _desc_str_count++; + + // only assign string index to first interface + desc_str = NULL; + } + } + } else if (desc[1] == 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++; + } + + if (desc[0] == 0) { + return false; + } + + desc += desc[0]; // next + } + + _desc_cfg_len += len; + + // Update configuration descriptor + tusb_desc_configuration_t *config = (tusb_desc_configuration_t *)_desc_cfg; + config->wTotalLength = _desc_cfg_len; + config->bNumInterfaces = _itf_count; + + 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(); + + // Serial is always added by default + // Use Interface Association Descriptor (IAD) for CDC + // As required by USB Specs IAD's subclass must be common class (2) and + // protocol must be IAD (1) + _desc_device.bDeviceClass = TUSB_CLASS_MISC; + _desc_device.bDeviceSubClass = MISC_SUBCLASS_COMMON; + _desc_device.bDeviceProtocol = MISC_PROTOCOL_IAD; + + SerialTinyUSB.begin(115200); + + // Init device hardware and call tusb_init() + TinyUSB_Port_InitDevice(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(); } + +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(); } + +static int strcpy_utf16(const char *s, uint16_t *buf, int bufsize); +uint16_t const *Adafruit_USBD_Device::descriptor_string_cb(uint8_t index, + uint16_t langid) { + (void)langid; + + uint8_t chr_count; + + switch (index) { + case STRID_LANGUAGE: + _desc_str[1] = ((uint16_t)((uint32_t)_desc_str_arr[STRID_LANGUAGE])); + chr_count = 1; + break; + + case STRID_SERIAL: + chr_count = getSerialDescriptor(_desc_str); + break; + + default: + // Invalid index + if (index >= _desc_str_count) { + return NULL; + } + + chr_count = strcpy_utf16(_desc_str_arr[index], _desc_str + 1, 32); + break; + } + + // first byte is length (including header), second byte is string type + _desc_str[0] = (TUSB_DESC_STRING << 8) | (2 * chr_count + 2); + + return _desc_str; +} + +//--------------------------------------------------------------------+ +// TinyUSB stack callbacks +//--------------------------------------------------------------------+ +extern "C" { + +// Invoked when received GET DEVICE DESCRIPTOR +// Application return pointer to descriptor +uint8_t const *tud_descriptor_device_cb(void) { + return (uint8_t const *)&USBDevice._desc_device; +} + +// Invoked when received GET CONFIGURATION DESCRIPTOR +// Application return pointer to descriptor, whose contents must exist long +// enough for transfer to complete +uint8_t const *tud_descriptor_configuration_cb(uint8_t index) { + (void)index; + return USBDevice._desc_cfg; +} + +// Invoked when received GET STRING DESCRIPTOR request +// Application return pointer to descriptor, whose contents must exist long +// enough for transfer to complete Note: the 0xEE index string is a Microsoft +// OS 1.0 Descriptors. +// https://docs.microsoft.com/en-us/windows-hardware/drivers/usbcon/microsoft-defined-usb-descriptors +uint16_t const *tud_descriptor_string_cb(uint8_t index, uint16_t langid) { + return USBDevice.descriptor_string_cb(index, langid); +} + +} // extern C + +//--------------------------------------------------------------------+ +// Helper +//--------------------------------------------------------------------+ +constexpr static inline bool isInvalidUtf8Octet(uint8_t t) { + // see bullets in https://tools.ietf.org/html/rfc3629#section-1 + return (t == 0xc0) || (t == 0xC1) || (t >= 0xF5); +} + +// +// This function has an UNWRITTEN CONTRACT that the buffer is either: +// 1. Pre-validated as legal UTF-8, -OR- +// 2. has a trailing zero-value octet/byte/uint8_t (aka null-terminated string) +// +// If the above are not true, this decoder may read past the end of the +// allocated buffer, by up to three bytes. +// +// U+1F47F == 👿 ("IMP") +// == 0001_1111_0100_0111_1111 ==> requires four-byte encoding in UTF-8 +// AABB BBBB CCCC CCDD DDDD ==> 0xF0 0x9F 0x91 0xBF +// +// Example sandwich and safety variables are there to cover the +// two most-common stack layouts for declared variables, in unoptimized +// code, so that the bytes surrounding those allocated for 'evilUTF8' +// are guaranteed to be non-zero and valid UTF8 continuation octets. +// uint8_t safety1 = 0; +// uint8_t sandwich1[4] = { 0x81, 0x82, 0x83, 0x84 }; +// uint8_t evilUTF8[5] = { 0xF0, 0x9F, 0x91, 0xBF, 0xF9 }; +// uint8_t sandwich2[4] = { 0x85, 0x86, 0x87, 0x88 }; +// uint8_t safety2 = 0; +// +// NOTE: evilUTF8 could just contain a single byte 0xF9 .... +// +// Attempting to decode evilUTF8 will progress to whatever is next to it on the +// stack. The above should work when optimizations are turned +// +static int8_t utf8Codepoint(const uint8_t *utf8, uint32_t *codepointp) { + const uint32_t CODEPOINT_LOWEST_SURROGATE_HALF = 0xD800; + const uint32_t CODEPOINT_HIGHEST_SURROGATE_HALF = 0xDFFF; + + *codepointp = 0xFFFD; // always initialize output to known value ... 0xFFFD + // (REPLACEMENT CHARACTER) seems the natural choice + uint32_t codepoint; + int len; + + // The upper bits define both the length of additional bytes for the + // multi-byte encoding, as well as defining how many bits of the first byte + // are included in the codepoint. Each additional byte starts with 0b10xxxxxx, + // encoding six additional bits for the codepoint. + // + // For key summary points, see: + // * https://tools.ietf.org/html/rfc3629#section-3 + // + if (isInvalidUtf8Octet(utf8[0])) { + // do not allow illegal octet sequences (e.g., 0xC0 0x80 + // should NOT decode to NULL) + return -1; + } + + if (utf8[0] < 0x80) { + // characters 0000 0000..0000 007F (up to 7 significant bits) + len = 1; + codepoint = utf8[0]; + } else if ((utf8[0] & 0xe0) == 0xc0) { + // characters 0000 0080..0000 07FF + // (up to 11 significant bits, so first byte encodes five bits) + len = 2; + codepoint = utf8[0] & 0x1f; + } else if ((utf8[0] & 0xf0) == 0xe0) { + // characters 0000 8000..0000 FFFF + // (up to 16 significant bits, so first byte encodes four bits) + len = 3; + codepoint = utf8[0] & 0x0f; + } else if ((utf8[0] & 0xf8) == 0xf0) { + // characters 0001 0000..0010 FFFF + // (up to 21 significantbits, so first byte encodes three bits) + len = 4; + codepoint = utf8[0] & 0x07; + } else { + // UTF-8 is defined to only map to Unicode -- 0x00000000..0x0010FFFF + // 5-byte and 6-byte sequences are not legal per RFC3629 + return -1; + } + + for (int i = 1; i < len; i++) { + if ((utf8[i] & 0xc0) != 0x80) { + // the additional bytes in a valid UTF-8 multi-byte encoding cannot have + // either of the top two bits set This is more restrictive than + // isInvalidUtf8Octet() + return -1; + } + codepoint <<= 6; // each continuation byte adds six bits to the codepoint + codepoint |= utf8[i] & 0x3f; // mask off the top two continuation bits, and + // add the six relevant bits + } + + // explicit validation to prevent overlong encodings + if ((len == 1) && (codepoint > 0x00007F)) { + return -1; + } else if ((len == 2) && ((codepoint < 0x000080) || (codepoint > 0x0007FF))) { + return -1; + } else if ((len == 3) && ((codepoint < 0x000800) || (codepoint > 0x00FFFF))) { + return -1; + } else if ((len == 4) && ((codepoint < 0x010000) || (codepoint > 0x10FFFF))) { + // "You might expect larger code points than U+10FFFF + // to be expressible, but Unicode is limited in Sections 12 + // of RFC3629 to match the limits of UTF-16." -- Wikipedia UTF-8 note + // See https://tools.ietf.org/html/rfc3629#section-12 + return -1; + } + + // high and low surrogate halves (U+D800 through U+DFFF) used by UTF-16 are + // not legal Unicode values ... see RFC 3629. + if ((codepoint >= CODEPOINT_LOWEST_SURROGATE_HALF) && + (codepoint <= CODEPOINT_HIGHEST_SURROGATE_HALF)) { + return -1; + } + + *codepointp = codepoint; + return len; +} + +static int strcpy_utf16(const char *s, uint16_t *buf, int bufsize) { + int i = 0; + int buflen = 0; + + while (s[i] != 0) { + uint32_t codepoint; + int8_t utf8len = utf8Codepoint((const uint8_t *)s + i, &codepoint); + + if (utf8len < 0) { + // Invalid utf8 sequence, skip it + i++; + continue; + } + + i += utf8len; + + if (codepoint <= 0xffff) { + if (buflen == bufsize) + break; + + buf[buflen++] = codepoint; + + } else { + if (buflen + 1 >= bufsize) + break; + + // Surrogate pair + codepoint -= 0x10000; + buf[buflen++] = (codepoint >> 10) + 0xd800; + buf[buflen++] = (codepoint & 0x3ff) + 0xdc00; + } + } + + return buflen; +} + +// TODO just for compiling, will move to DFU specific file +#if CFG_TUD_DFU_RUNTIME +void tud_dfu_runtime_reboot_to_dfu_cb(void) { + // TinyUSB_Port_EnterDFU(); +} +#endif + +#endif // TUSB_OPT_DEVICE_ENABLED diff --git a/libraries/Adafruit_TinyUSB_Arduino/src/arduino/Adafruit_USBD_Device.h b/libraries/Adafruit_TinyUSB_Arduino/src/arduino/Adafruit_USBD_Device.h new file mode 100644 index 00000000000..c061afeca0e --- /dev/null +++ b/libraries/Adafruit_TinyUSB_Arduino/src/arduino/Adafruit_USBD_Device.h @@ -0,0 +1,112 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2019 Ha Thach for Adafruit Industries + * + * 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 ADAFRUIT_USBD_DEVICE_H_ +#define ADAFRUIT_USBD_DEVICE_H_ + +#include "Adafruit_USBD_Interface.h" +#include "tusb.h" + +class Adafruit_USBD_Device { +private: + enum { STRING_DESCRIPTOR_MAX = 8 }; + + // Device descriptor + tusb_desc_device_t _desc_device __attribute__((aligned(4))); + + // Configuration descriptor + uint8_t *_desc_cfg; + uint8_t _desc_cfg_buffer[256]; + uint16_t _desc_cfg_len; + uint16_t _desc_cfg_maxlen; + + uint8_t _itf_count; + + uint8_t _epin_count; + uint8_t _epout_count; + + // String descriptor + const char *_desc_str_arr[STRING_DESCRIPTOR_MAX]; + uint8_t _desc_str_count; + uint16_t _desc_str[32 + 1]; // up to 32 unicode characters with headers + +public: + Adafruit_USBD_Device(void); + + //------------- Device descriptor -------------// + + // Set VID, PID + void setID(uint16_t vid, uint16_t pid); + + // Set bcdUSB version e.g 1.0, 2.0, 2.1 + void setVersion(uint16_t bcd); + + // Set bcdDevice version + void setDeviceVersion(uint16_t bcd); + + //------------- Configuration descriptor -------------// + + // Add an new interface + bool addInterface(Adafruit_USBD_Interface &itf); + + // Clear/Reset configuration descriptor + void clearConfiguration(void); + + // Provide user buffer for configuration descriptor, needed if total length > + // 256 + void setConfigurationBuffer(uint8_t *buf, uint32_t buflen); + + //------------- String descriptor -------------// + void setLanguageDescriptor(uint16_t language_id); + void setManufacturerDescriptor(const char *s); + void setProductDescriptor(const char *s); + uint8_t getSerialDescriptor(uint16_t *serial_utf16); + + //------------- Control -------------// + + bool begin(uint8_t rhport = 0); + void task(void); + + // physical disable/enable pull-up + bool detach(void); + bool attach(void); + + //------------- status -------------// + bool mounted(void); + bool suspended(void); + bool ready(void); + bool remoteWakeup(void); + +private: + uint16_t const *descriptor_string_cb(uint8_t index, uint16_t langid); + + friend uint8_t const *tud_descriptor_device_cb(void); + friend uint8_t const *tud_descriptor_configuration_cb(uint8_t index); + friend uint16_t const *tud_descriptor_string_cb(uint8_t index, + uint16_t langid); +}; + +extern Adafruit_USBD_Device USBDevice; + +#endif /* ADAFRUIT_USBD_DEVICE_H_ */ diff --git a/libraries/Adafruit_TinyUSB_Arduino/src/arduino/Adafruit_USBD_Interface.h b/libraries/Adafruit_TinyUSB_Arduino/src/arduino/Adafruit_USBD_Interface.h new file mode 100644 index 00000000000..94c14c383f5 --- /dev/null +++ b/libraries/Adafruit_TinyUSB_Arduino/src/arduino/Adafruit_USBD_Interface.h @@ -0,0 +1,47 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2021 Ha Thach (tinyusb.org) for Adafruit Industries + * + * 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 ADAFRUIT_USBD_INTERFACE_H_ +#define ADAFRUIT_USBD_INTERFACE_H_ + +#include +#include + +class Adafruit_USBD_Interface { +protected: + const char *_desc_str; + +public: + Adafruit_USBD_Interface(void) { _desc_str = NULL; } + + // Get Interface Descriptor + // Device fill descriptor and return its length + virtual uint16_t getInterfaceDescriptor(uint8_t itfnum, uint8_t *buf, + uint16_t bufsize) = 0; + + void setStringDescriptor(const char *str) { _desc_str = str; } + const char *getStringDescriptor(void) { return _desc_str; } +}; + +#endif diff --git a/libraries/Adafruit_TinyUSB_Arduino/src/arduino/hid/Adafruit_USBD_HID.cpp b/libraries/Adafruit_TinyUSB_Arduino/src/arduino/hid/Adafruit_USBD_HID.cpp new file mode 100644 index 00000000000..4a463bc8ea6 --- /dev/null +++ b/libraries/Adafruit_TinyUSB_Arduino/src/arduino/hid/Adafruit_USBD_HID.cpp @@ -0,0 +1,241 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2019 Ha Thach for Adafruit Industries + * + * 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. + */ + +#include "tusb_option.h" + +#if TUSB_OPT_DEVICE_ENABLED && CFG_TUD_HID + +#include "Adafruit_USBD_HID.h" + +#define EPOUT 0x00 +#define EPIN 0x80 + +uint8_t const _ascii2keycode[128][2] = {HID_ASCII_TO_KEYCODE}; + +static Adafruit_USBD_HID *_hid_dev = NULL; + +//------------- IMPLEMENTATION -------------// +Adafruit_USBD_HID::Adafruit_USBD_HID(void) { + _interval_ms = 10; + _protocol = HID_ITF_PROTOCOL_NONE; + + _out_endpoint = false; + _mouse_button = 0; + + _desc_report = NULL; + _desc_report_len = 0; + + _get_report_cb = NULL; + _set_report_cb = NULL; +} + +void Adafruit_USBD_HID::setPollInterval(uint8_t interval_ms) { + _interval_ms = interval_ms; +} + +void Adafruit_USBD_HID::setBootProtocol(uint8_t protocol) { + _protocol = protocol; +} + +void Adafruit_USBD_HID::enableOutEndpoint(bool enable) { + _out_endpoint = enable; +} + +void Adafruit_USBD_HID::setReportDescriptor(uint8_t const *desc_report, + uint16_t len) { + _desc_report = desc_report; + _desc_report_len = len; +} + +void Adafruit_USBD_HID::setReportCallback(get_report_callback_t get_report, + set_report_callback_t set_report) { + _get_report_cb = get_report; + _set_report_cb = set_report; +} + +uint16_t Adafruit_USBD_HID::getInterfaceDescriptor(uint8_t itfnum, uint8_t *buf, + uint16_t bufsize) { + 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)}; + uint8_t const desc_in_only[] = { + TUD_HID_DESCRIPTOR(itfnum, 0, _protocol, _desc_report_len, EPIN, + CFG_TUD_HID_EP_BUFSIZE, _interval_ms)}; + + uint8_t const *desc; + uint16_t len; + + if (_out_endpoint) { + desc = desc_inout; + len = sizeof(desc_inout); + } else { + desc = desc_in_only; + len = sizeof(desc_in_only); + } + + if (bufsize < len) { + return 0; + } + + memcpy(buf, desc, len); + return len; +} + +bool Adafruit_USBD_HID::begin(void) { + if (!USBDevice.addInterface(*this)) { + return false; + } + + _hid_dev = this; + return true; +} + +bool Adafruit_USBD_HID::ready(void) { return tud_hid_ready(); } + +bool Adafruit_USBD_HID::sendReport(uint8_t report_id, void const *report, + uint8_t len) { + return tud_hid_report(report_id, report, len); +} + +bool Adafruit_USBD_HID::sendReport8(uint8_t report_id, uint8_t num) { + return tud_hid_report(report_id, &num, sizeof(num)); +} + +bool Adafruit_USBD_HID::sendReport16(uint8_t report_id, uint16_t num) { + return tud_hid_report(report_id, &num, sizeof(num)); +} + +bool Adafruit_USBD_HID::sendReport32(uint8_t report_id, uint32_t num) { + return tud_hid_report(report_id, &num, sizeof(num)); +} + +//------------- TinyUSB callbacks -------------// +extern "C" { + +// Invoked when received GET HID REPORT DESCRIPTOR +// Application return pointer to descriptor, whose contents must exist long +// enough for transfer to complete +uint8_t const *tud_hid_descriptor_report_cb(uint8_t itf) { + (void)itf; + + if (!_hid_dev) { + return NULL; + } + + return _hid_dev->_desc_report; +} + +// 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 itf, uint8_t report_id, + hid_report_type_t report_type, uint8_t *buffer, + uint16_t reqlen) { + (void)itf; + + if (!(_hid_dev && _hid_dev->_get_report_cb)) { + return 0; + } + + return _hid_dev->_get_report_cb(report_id, report_type, buffer, reqlen); +} + +// 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 itf, uint8_t report_id, + hid_report_type_t report_type, uint8_t const *buffer, + uint16_t bufsize) { + (void)itf; + + if (!(_hid_dev && _hid_dev->_set_report_cb)) { + return; + } + + _hid_dev->_set_report_cb(report_id, report_type, buffer, bufsize); +} + +} // extern "C" + +//--------------------------------------------------------------------+ +// Keyboard +//--------------------------------------------------------------------+ + +bool Adafruit_USBD_HID::keyboardReport(uint8_t report_id, uint8_t modifier, + uint8_t keycode[6]) { + return tud_hid_keyboard_report(report_id, modifier, keycode); +} + +bool Adafruit_USBD_HID::keyboardPress(uint8_t report_id, char ch) { + uint8_t keycode[6] = {0}; + uint8_t modifier = 0; + uint8_t uch = (uint8_t)ch; + + if (_ascii2keycode[uch][0]) { + modifier = KEYBOARD_MODIFIER_LEFTSHIFT; + } + keycode[0] = _ascii2keycode[uch][1]; + + return tud_hid_keyboard_report(report_id, modifier, keycode); +} + +bool Adafruit_USBD_HID::keyboardRelease(uint8_t report_id) { + return tud_hid_keyboard_report(report_id, 0, NULL); +} + +//--------------------------------------------------------------------+ +// Mouse +//--------------------------------------------------------------------+ + +bool Adafruit_USBD_HID::mouseReport(uint8_t report_id, uint8_t buttons, + int8_t x, int8_t y, int8_t vertical, + int8_t horizontal) { + // cache mouse button for other API such as move, scroll + _mouse_button = buttons; + + return tud_hid_mouse_report(report_id, buttons, x, y, vertical, horizontal); +} + +bool Adafruit_USBD_HID::mouseMove(uint8_t report_id, int8_t x, int8_t y) { + return tud_hid_mouse_report(report_id, _mouse_button, x, y, 0, 0); +} + +bool Adafruit_USBD_HID::mouseScroll(uint8_t report_id, int8_t scroll, + int8_t pan) { + return tud_hid_mouse_report(report_id, _mouse_button, 0, 0, scroll, pan); +} + +bool Adafruit_USBD_HID::mouseButtonPress(uint8_t report_id, uint8_t buttons) { + return tud_hid_mouse_report(report_id, buttons, 0, 0, 0, 0); +} + +bool Adafruit_USBD_HID::mouseButtonRelease(uint8_t report_id) { + return tud_hid_mouse_report(report_id, 0, 0, 0, 0, 0); +} + +#endif // TUSB_OPT_DEVICE_ENABLED diff --git a/libraries/Adafruit_TinyUSB_Arduino/src/arduino/hid/Adafruit_USBD_HID.h b/libraries/Adafruit_TinyUSB_Arduino/src/arduino/hid/Adafruit_USBD_HID.h new file mode 100644 index 00000000000..90be492d758 --- /dev/null +++ b/libraries/Adafruit_TinyUSB_Arduino/src/arduino/hid/Adafruit_USBD_HID.h @@ -0,0 +1,97 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2019 Ha Thach for Adafruit Industries + * + * 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 ADAFRUIT_USBD_HID_H_ +#define ADAFRUIT_USBD_HID_H_ + +#include "arduino/Adafruit_USBD_Device.h" + +class Adafruit_USBD_HID : public Adafruit_USBD_Interface { +public: + typedef uint16_t (*get_report_callback_t)(uint8_t report_id, + hid_report_type_t report_type, + uint8_t *buffer, uint16_t reqlen); + typedef void (*set_report_callback_t)(uint8_t report_id, + hid_report_type_t report_type, + uint8_t const *buffer, + uint16_t bufsize); + + Adafruit_USBD_HID(void); + + void setPollInterval(uint8_t interval_ms); + void setBootProtocol(uint8_t protocol); // 0: None, 1: Keyboard, 2:Mouse + void enableOutEndpoint(bool enable); + void setReportDescriptor(uint8_t const *desc_report, uint16_t len); + void setReportCallback(get_report_callback_t get_report, + set_report_callback_t set_report); + + bool begin(void); + + bool ready(void); + bool sendReport(uint8_t report_id, void const *report, uint8_t len); + + // Report helpers + bool sendReport8(uint8_t report_id, uint8_t num); + bool sendReport16(uint8_t report_id, uint16_t num); + bool sendReport32(uint8_t report_id, uint32_t num); + + //------------- Keyboard API -------------// + bool keyboardReport(uint8_t report_id, uint8_t modifier, uint8_t keycode[6]); + bool keyboardPress(uint8_t report_id, char ch); + bool keyboardRelease(uint8_t report_id); + + //------------- Mouse API -------------// + bool mouseReport(uint8_t report_id, uint8_t buttons, int8_t x, int8_t y, + int8_t vertical, int8_t horizontal); + bool mouseMove(uint8_t report_id, int8_t x, int8_t y); + bool mouseScroll(uint8_t report_id, int8_t scroll, int8_t pan); + bool mouseButtonPress(uint8_t report_id, uint8_t buttons); + bool mouseButtonRelease(uint8_t report_id); + + // from Adafruit_USBD_Interface + virtual uint16_t getInterfaceDescriptor(uint8_t itfnum, uint8_t *buf, + uint16_t bufsize); + +private: + uint8_t _interval_ms; + uint8_t _protocol; + bool _out_endpoint; + uint8_t _mouse_button; + + uint16_t _desc_report_len; + uint8_t const *_desc_report; + + get_report_callback_t _get_report_cb; + set_report_callback_t _set_report_cb; + + friend uint16_t tud_hid_get_report_cb(uint8_t itf, uint8_t report_id, + hid_report_type_t report_type, + uint8_t *buffer, uint16_t reqlen); + friend void tud_hid_set_report_cb(uint8_t itf, uint8_t report_id, + hid_report_type_t report_type, + uint8_t const *buffer, uint16_t bufsize); + friend uint8_t const *tud_hid_descriptor_report_cb(uint8_t itf); +}; + +#endif /* ADAFRUIT_USBD_HID_H_ */ diff --git a/libraries/Adafruit_TinyUSB_Arduino/src/arduino/midi/Adafruit_USBD_MIDI.cpp b/libraries/Adafruit_TinyUSB_Arduino/src/arduino/midi/Adafruit_USBD_MIDI.cpp new file mode 100644 index 00000000000..7a6b91761f0 --- /dev/null +++ b/libraries/Adafruit_TinyUSB_Arduino/src/arduino/midi/Adafruit_USBD_MIDI.cpp @@ -0,0 +1,129 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2019 hathach for Adafruit Industries + * + * 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. + */ + +#include "tusb_option.h" + +#if TUSB_OPT_DEVICE_ENABLED && CFG_TUD_MIDI + +#include "Adafruit_USBD_MIDI.h" + +//--------------------------------------------------------------------+ +// MACRO TYPEDEF CONSTANT ENUM DECLARATION +//--------------------------------------------------------------------+ +#define EPOUT 0x00 +#define EPIN 0x80 +#define EPSIZE 64 + +Adafruit_USBD_MIDI::Adafruit_USBD_MIDI(void) : _n_cables(1) {} + +void Adafruit_USBD_MIDI::setCables(uint8_t n_cables) { _n_cables = n_cables; } + +bool Adafruit_USBD_MIDI::begin(void) { + if (!USBDevice.addInterface(*this)) + return false; + + return true; +} + +uint16_t Adafruit_USBD_MIDI::getInterfaceDescriptor(uint8_t itfnum, + uint8_t *buf, + uint16_t bufsize) { + uint16_t len = 0; + + if (bufsize < TUD_MIDI_DESC_HEAD_LEN + TUD_MIDI_DESC_JACK_LEN * _n_cables + + TUD_MIDI_DESC_EP_LEN(_n_cables) * 2) + return 0; + + { + uint8_t desc[] = {TUD_MIDI_DESC_HEAD(itfnum, 0, _n_cables)}; + memcpy(buf + len, desc, sizeof(desc)); + len += sizeof(desc); + } + + 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 + { + uint8_t desc[] = {TUD_MIDI_DESC_EP(EPOUT, EPSIZE, _n_cables)}; + memcpy(buf + len, desc, sizeof(desc)); + len += sizeof(desc); + } + + for (uint8_t i = 1; i <= _n_cables; i++) { + uint8_t jack[] = {TUD_MIDI_JACKID_IN_EMB(i)}; + memcpy(buf + len, jack, sizeof(jack)); + len += sizeof(jack); + } + + // Endpoint IN + jack mapping - usb core will automatically update endpoint + // number + { + uint8_t desc[] = {TUD_MIDI_DESC_EP(EPIN, EPSIZE, _n_cables)}; + memcpy(buf + len, desc, sizeof(desc)); + len += sizeof(desc); + } + + for (uint8_t i = 1; i <= _n_cables; i++) { + uint8_t jack[] = {TUD_MIDI_JACKID_OUT_EMB(i)}; + memcpy(buf + len, jack, sizeof(jack)); + len += sizeof(jack); + } + + return len; +} + +int Adafruit_USBD_MIDI::read(void) { + uint8_t ch; + return tud_midi_stream_read(&ch, 1) ? (int)ch : (-1); +} + +size_t Adafruit_USBD_MIDI::write(uint8_t b) { + return tud_midi_stream_write(0, &b, 1); +} + +int Adafruit_USBD_MIDI::available(void) { return tud_midi_available(); } + +int Adafruit_USBD_MIDI::peek(void) { + // MIDI Library doen't use peek + return -1; +} + +void Adafruit_USBD_MIDI::flush(void) { + // MIDI Library doen't use flush +} + +bool Adafruit_USBD_MIDI::writePacket(const uint8_t packet[4]) { + return tud_midi_packet_write(packet); +} + +bool Adafruit_USBD_MIDI::readPacket(uint8_t packet[4]) { + return tud_midi_packet_read(packet); +} + +#endif // TUSB_OPT_DEVICE_ENABLED diff --git a/libraries/Adafruit_TinyUSB_Arduino/src/arduino/midi/Adafruit_USBD_MIDI.h b/libraries/Adafruit_TinyUSB_Arduino/src/arduino/midi/Adafruit_USBD_MIDI.h new file mode 100644 index 00000000000..4741e8abadf --- /dev/null +++ b/libraries/Adafruit_TinyUSB_Arduino/src/arduino/midi/Adafruit_USBD_MIDI.h @@ -0,0 +1,66 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2019 hathach for Adafruit Industries + * + * 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 ADAFRUIT_USBD_MIDI_H_ +#define ADAFRUIT_USBD_MIDI_H_ + +#include "Stream.h" +#include "arduino/Adafruit_USBD_Device.h" + +class Adafruit_USBD_MIDI : public Stream, public Adafruit_USBD_Interface { +public: + Adafruit_USBD_MIDI(void); + + bool begin(void); + + // for MIDI library + bool begin(uint32_t baud) { + (void)baud; + return begin(); + } + + // Stream interface to use with MIDI Library + virtual int read(void); + virtual size_t write(uint8_t b); + virtual int available(void); + virtual int peek(void); + virtual void flush(void); + + using Stream::write; + + // Raw MIDI USB packet interface. + bool writePacket(const uint8_t packet[4]); + bool readPacket(uint8_t packet[4]); + + // from Adafruit_USBD_Interface + virtual uint16_t getInterfaceDescriptor(uint8_t itfnum, uint8_t *buf, + uint16_t bufsize); + + void setCables(uint8_t n_cables); + +private: + uint8_t _n_cables; +}; + +#endif /* ADAFRUIT_USBD_MIDI_H_ */ diff --git a/libraries/Adafruit_TinyUSB_Arduino/src/arduino/msc/Adafruit_USBD_MSC.cpp b/libraries/Adafruit_TinyUSB_Arduino/src/arduino/msc/Adafruit_USBD_MSC.cpp new file mode 100644 index 00000000000..2b1583031c2 --- /dev/null +++ b/libraries/Adafruit_TinyUSB_Arduino/src/arduino/msc/Adafruit_USBD_MSC.cpp @@ -0,0 +1,235 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2019 Ha Thach for Adafruit Industries + * + * 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. + */ + +#include "tusb_option.h" + +#if TUSB_OPT_DEVICE_ENABLED && CFG_TUD_MSC + +#include "Adafruit_USBD_MSC.h" + +#define EPOUT 0x00 +#define EPIN 0x80 +#define EPSIZE 64 // TODO must be 512 for highspeed device + +static Adafruit_USBD_MSC *_msc_dev = NULL; + +Adafruit_USBD_MSC::Adafruit_USBD_MSC(void) { + _maxlun = 1; + memset(_lun, 0, sizeof(_lun)); +} + +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)}; + uint16_t const len = sizeof(desc); + + if (bufsize < len) { + return 0; + } + + memcpy(buf, desc, len); + return len; +} + +void Adafruit_USBD_MSC::setMaxLun(uint8_t maxlun) { _maxlun = maxlun; } + +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; +} + +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; +} + +void Adafruit_USBD_MSC::setUnitReady(uint8_t lun, bool ready) { + _lun[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; +} + +void Adafruit_USBD_MSC::setReadyCallback(uint8_t lun, ready_callback_t cb) { + _lun[lun].ready_cb = cb; +} + +bool Adafruit_USBD_MSC::begin(void) { + if (!USBDevice.addInterface(*this)) { + return false; + } + + _msc_dev = this; + return true; +} + +//------------- TinyUSB callbacks -------------// +extern "C" { + +// Invoked to determine max LUN +uint8_t tud_msc_get_maxlun_cb(void) { + if (!_msc_dev) { + return 0; + } + return _msc_dev->getMaxLun(); +} + +// Invoked when received SCSI_CMD_INQUIRY +// Application fill vendor id, product id and revision with string up to 8, 16, +// 4 characters respectively +void tud_msc_inquiry_cb(uint8_t lun, uint8_t vendor_id[8], + uint8_t product_id[16], uint8_t product_rev[4]) { + if (!_msc_dev) { + return; + } + + // 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"); + + memcpy(vendor_id, vid, tu_min32(strlen(vid), 8)); + memcpy(product_id, pid, tu_min32(strlen(pid), 16)); + memcpy(product_rev, rev, tu_min32(strlen(rev), 4)); +} + +// Invoked when received Test Unit Ready command. +// return true allowing host to read/write this LUN e.g SD card inserted +bool tud_msc_test_unit_ready_cb(uint8_t lun) { + if (!_msc_dev) { + return false; + } + + if (_msc_dev->_lun[lun].ready_cb) { + _msc_dev->_lun[lun].unit_ready = _msc_dev->_lun[lun].ready_cb(); + } + + return _msc_dev->_lun[lun].unit_ready; +} + +// Callback invoked to determine disk's size +void tud_msc_capacity_cb(uint8_t lun, uint32_t *block_count, + uint16_t *block_size) { + if (!_msc_dev) { + return; + } + + *block_count = _msc_dev->_lun[lun].block_count; + *block_size = _msc_dev->_lun[lun].block_size; +} + +// Callback invoked when received an SCSI command not in built-in list below +// - READ_CAPACITY10, READ_FORMAT_CAPACITY, INQUIRY, MODE_SENSE6, REQUEST_SENSE +// - READ10 and WRITE10 has their own callbacks +int32_t tud_msc_scsi_cb(uint8_t lun, const uint8_t scsi_cmd[16], void *buffer, + uint16_t bufsize) { + const void *response = NULL; + uint16_t resplen = 0; + + switch (scsi_cmd[0]) { + case SCSI_CMD_PREVENT_ALLOW_MEDIUM_REMOVAL: + // Host is about to read/write etc ... better not to disconnect disk + resplen = 0; + break; + + default: + // Set Sense = Invalid Command Operation + tud_msc_set_sense(lun, SCSI_SENSE_ILLEGAL_REQUEST, 0x20, 0x00); + + // negative means error -> tinyusb could stall and/or response with failed + // status + resplen = -1; + break; + } + + // return len must not larger than bufsize + if (resplen > bufsize) { + resplen = bufsize; + } + + // copy response to stack's buffer if any + if (response && resplen) { + memcpy(buffer, response, resplen); + } + + return resplen; +} + +// Callback invoked when received READ10 command. +// Copy disk's data to buffer (up to bufsize) and return number of copied bytes. +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)) { + return -1; + } + + return _msc_dev->_lun[lun].rd_cb(lba, buffer, bufsize); +} + +// Callback invoked when received WRITE10 command. +// Process data in buffer to disk's storage and return number of written bytes +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)) { + return -1; + } + + return _msc_dev->_lun[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)) { + return; + } + + // flush pending cache when write10 is complete + return _msc_dev->_lun[lun].fl_cb(); +} + +} // extern "C" + +#endif // TUSB_OPT_DEVICE_ENABLED diff --git a/libraries/Adafruit_TinyUSB_Arduino/src/arduino/msc/Adafruit_USBD_MSC.h b/libraries/Adafruit_TinyUSB_Arduino/src/arduino/msc/Adafruit_USBD_MSC.h new file mode 100644 index 00000000000..5bd8f062919 --- /dev/null +++ b/libraries/Adafruit_TinyUSB_Arduino/src/arduino/msc/Adafruit_USBD_MSC.h @@ -0,0 +1,112 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2019 Ha Thach for Adafruit Industries + * + * 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 ADAFRUIT_USBD_MSC_H_ +#define ADAFRUIT_USBD_MSC_H_ + +#include "arduino/Adafruit_USBD_Device.h" + +class Adafruit_USBD_MSC : public Adafruit_USBD_Interface { +public: + typedef int32_t (*read_callback_t)(uint32_t lba, void *buffer, + uint32_t bufsize); + typedef int32_t (*write_callback_t)(uint32_t lba, uint8_t *buffer, + uint32_t bufsize); + typedef void (*flush_callback_t)(void); + typedef bool (*ready_callback_t)(void); + + Adafruit_USBD_MSC(void); + + bool begin(void); + + void setMaxLun(uint8_t maxlun); + uint8_t getMaxLun(void); + + //------------- Multiple LUN API -------------// + void setID(uint8_t lun, const char *vendor_id, const char *product_id, + const char *product_rev); + void setCapacity(uint8_t lun, uint32_t block_count, uint16_t block_size); + void setUnitReady(uint8_t lun, bool ready); + void setReadWriteCallback(uint8_t lun, read_callback_t rd_cb, + write_callback_t wr_cb, flush_callback_t fl_cb); + void setReadyCallback(uint8_t lun, ready_callback_t cb); + + //------------- Single LUN API -------------// + void setID(const char *vendor_id, const char *product_id, + const char *product_rev) { + setID(0, vendor_id, product_id, product_rev); + } + + void setCapacity(uint32_t block_count, uint16_t block_size) { + setCapacity(0, block_count, block_size); + } + + void setUnitReady(bool ready) { setUnitReady(0, ready); } + + void setReadWriteCallback(read_callback_t rd_cb, write_callback_t wr_cb, + flush_callback_t fl_cb) { + setReadWriteCallback(0, rd_cb, wr_cb, fl_cb); + } + + void setReadyCallback(ready_callback_t cb) { setReadyCallback(0, cb); } + + // from Adafruit_USBD_Interface + virtual uint16_t getInterfaceDescriptor(uint8_t itfnum, uint8_t *buf, + uint16_t bufsize); + +private: + enum { MAX_LUN = 2 }; + struct { + read_callback_t rd_cb; + write_callback_t wr_cb; + flush_callback_t fl_cb; + ready_callback_t ready_cb; + + const char *_inquiry_vid; + const char *_inquiry_pid; + const char *_inquiry_rev; + + uint32_t block_count; + uint16_t block_size; + bool unit_ready; + + } _lun[MAX_LUN]; + + uint8_t _maxlun; + + // Make all tinyusb callback friend to access private data + friend void tud_msc_inquiry_cb(uint8_t lun, uint8_t vendor_id[8], + uint8_t product_id[16], + uint8_t product_rev[4]); + friend bool tud_msc_test_unit_ready_cb(uint8_t lun); + friend void tud_msc_capacity_cb(uint8_t lun, uint32_t *block_count, + uint16_t *block_size); + friend int32_t tud_msc_read10_cb(uint8_t lun, uint32_t lba, uint32_t offset, + void *buffer, uint32_t bufsize); + friend int32_t tud_msc_write10_cb(uint8_t lun, uint32_t lba, uint32_t offset, + uint8_t *buffer, uint32_t bufsize); + friend void tud_msc_write10_complete_cb(uint8_t lun); +}; + +#endif /* ADAFRUIT_USBD_MSC_H_ */ diff --git a/libraries/Adafruit_TinyUSB_Arduino/src/arduino/ports/esp32/Adafruit_TinyUSB_esp32.cpp b/libraries/Adafruit_TinyUSB_Arduino/src/arduino/ports/esp32/Adafruit_TinyUSB_esp32.cpp new file mode 100644 index 00000000000..33952bf0360 --- /dev/null +++ b/libraries/Adafruit_TinyUSB_Arduino/src/arduino/ports/esp32/Adafruit_TinyUSB_esp32.cpp @@ -0,0 +1,169 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2019, hathach for Adafruit + * + * 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. + */ + +#include "tusb_option.h" + +#if defined(ARDUINO_ARCH_ESP32) && TUSB_OPT_DEVICE_ENABLED + +#include "sdkconfig.h" + +#include "soc/soc.h" + +#include "soc/efuse_reg.h" +#include "soc/periph_defs.h" +#include "soc/rtc_cntl_reg.h" + +#include "soc/system_reg.h" +#include "soc/timer_group_struct.h" +#include "soc/usb_periph.h" +#include "soc/usb_reg.h" +#include "soc/usb_struct.h" +#include "soc/usb_wrap_reg.h" +#include "soc/usb_wrap_struct.h" + +#include "hal/usb_hal.h" + +// compiler error with gpio_ll_get_drive_capability() +// invalid conversion from 'uint32_t' {aka 'unsigned int'} to 'gpio_drive_cap_t' +// [-fpermissive] #include "hal/gpio_ll.h" + +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" + +#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 "esp32s2/rom/usb/chip_usb_dw_wrapper.h" +#include "esp32s2/rom/usb/usb_dc.h" +#include "esp32s2/rom/usb/usb_persist.h" + +#include "arduino/Adafruit_TinyUSB_API.h" +#include "arduino/Adafruit_USBD_Device.h" + +//--------------------------------------------------------------------+ +// MACRO TYPEDEF CONSTANT ENUM DECLARATION +//--------------------------------------------------------------------+ + +static void configure_pins(usb_hal_context_t *usb) { + for (const usb_iopin_dsc_t *iopin = usb_periph_iopins; iopin->pin != -1; + ++iopin) { + if ((usb->use_external_phy) || (iopin->ext_phy_only == 0)) { + esp_rom_gpio_pad_select_gpio(iopin->pin); + if (iopin->is_output) { + esp_rom_gpio_connect_out_signal(iopin->pin, iopin->func, false, false); + } else { + esp_rom_gpio_connect_in_signal(iopin->pin, iopin->func, false); + if ((iopin->pin != GPIO_FUNC_IN_LOW) && + (iopin->pin != GPIO_FUNC_IN_HIGH)) { + // workaround for compiler error with including "hal/gpio_ll.h" + // gpio_ll_input_enable(&GPIO, (gpio_num_t) iopin->pin); + PIN_INPUT_ENABLE(GPIO_PIN_MUX_REG[iopin->pin]); + } + } + esp_rom_gpio_pad_unhold(iopin->pin); + } + } + if (!usb->use_external_phy) { + gpio_set_drive_capability((gpio_num_t)USBPHY_DM_NUM, GPIO_DRIVE_CAP_3); + gpio_set_drive_capability((gpio_num_t)USBPHY_DP_NUM, GPIO_DRIVE_CAP_3); + } +} + +//--------------------------------------------------------------------+ +// Porting API +//--------------------------------------------------------------------+ + +#define USBD_STACK_SZ (4096) + +// USB Device Driver task +// This top level thread processes all usb events and invokes callbacks +static void usb_device_task(void *param) { + (void)param; + // RTOS forever loop + while (1) { + tud_task(); + } +} + +void TinyUSB_Port_InitDevice(uint8_t rhport) { + (void)rhport; + + // Reset USB module + periph_module_reset(PERIPH_USB_MODULE); + periph_module_enable(PERIPH_USB_MODULE); + + usb_hal_context_t hal = {.use_external_phy = false}; + usb_hal_init(&hal); + configure_pins(&hal); + + // reset core, should be in dcd_esp32sx.c (do that later with more proper + // testing) + USB0.grstctl |= USB_CSFTRST; + while ((USB0.grstctl & USB_CSFTRST) == USB_CSFTRST) { + } + + tusb_init(); + + // Create a task for tinyusb device stack + xTaskCreate(usb_device_task, "usbd", USBD_STACK_SZ, NULL, + configMAX_PRIORITIES - 1, NULL); +} + +void TinyUSB_Port_EnterDFU(void) { + // Reset to Bootloader + + // Reset USB Core + USB0.grstctl |= USB_CSFTRST; + while ((USB0.grstctl & USB_CSFTRST) == USB_CSFTRST) { + } + + REG_WRITE(RTC_CNTL_OPTION1_REG, RTC_CNTL_FORCE_DOWNLOAD_BOOT); + esp_restart(); +} + +uint8_t TinyUSB_Port_GetSerialNumber(uint8_t serial_id[16]) { + /* Get the MAC address */ + const uint32_t mac0 = + __builtin_bswap32(REG_GET_FIELD(EFUSE_RD_MAC_SPI_SYS_0_REG, EFUSE_MAC_0)); + const uint16_t mac1 = __builtin_bswap16( + (uint16_t)REG_GET_FIELD(EFUSE_RD_MAC_SPI_SYS_1_REG, EFUSE_MAC_1)); + + memcpy(serial_id, &mac1, 2); + memcpy(serial_id + 2, &mac0, 4); + + return 6; +} + +extern "C" void yield(void) { + TinyUSB_Device_FlushCDC(); + vPortYield(); +} + +#endif // USE_TINYUSB diff --git a/libraries/Adafruit_TinyUSB_Arduino/src/arduino/webusb/Adafruit_USBD_WebUSB.cpp b/libraries/Adafruit_TinyUSB_Arduino/src/arduino/webusb/Adafruit_USBD_WebUSB.cpp new file mode 100644 index 00000000000..9d53bc21f36 --- /dev/null +++ b/libraries/Adafruit_TinyUSB_Arduino/src/arduino/webusb/Adafruit_USBD_WebUSB.cpp @@ -0,0 +1,308 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2019 hathach for Adafruit Industries + * + * 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. + */ + +#include "tusb_option.h" + +#if TUSB_OPT_DEVICE_ENABLED && CFG_TUD_VENDOR + +#include "Adafruit_USBD_WebUSB.h" +#include "Arduino.h" + +//--------------------------------------------------------------------+ +// MACRO TYPEDEF CONSTANT ENUM DECLARATION +//--------------------------------------------------------------------+ +#define EPOUT 0x00 +#define EPIN 0x80 +#define EPSIZE 64 + +enum { VENDOR_REQUEST_WEBUSB = 1, VENDOR_REQUEST_MICROSOFT = 2 }; + +static Adafruit_USBD_WebUSB *_webusb_dev = NULL; + +//--------------------------------------------------------------------+ +// BOS Descriptor +//--------------------------------------------------------------------+ + +/* Microsoft OS 2.0 registry property descriptor +Per MS requirements +https://msdn.microsoft.com/en-us/library/windows/hardware/hh450799(v=vs.85).aspx +device should create DeviceInterfaceGUIDs. It can be done by driver and +in case of real PnP solution device should expose MS "Microsoft OS 2.0 +registry property descriptor". Such descriptor can insert any record +into Windows registry per device/configuration/interface. In our case it +will insert "DeviceInterfaceGUIDs" multistring property. + +GUID is freshly generated and should be OK to use. + +https://developers.google.com/web/fundamentals/native-hardware/build-for-webusb/ +(Section Microsoft OS compatibility descriptors) +*/ + +#define BOS_TOTAL_LEN \ + (TUD_BOS_DESC_LEN + TUD_BOS_WEBUSB_DESC_LEN + TUD_BOS_MICROSOFT_OS_DESC_LEN) + +#define MS_OS_20_DESC_LEN 0xB2 + +// BOS Descriptor is required for webUSB +uint8_t const desc_bos[] = { + // total length, number of device caps + TUD_BOS_DESCRIPTOR(BOS_TOTAL_LEN, 2), + + // Vendor Code, iLandingPage + TUD_BOS_WEBUSB_DESCRIPTOR(VENDOR_REQUEST_WEBUSB, 1), + + // 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), + U32_TO_U8S_LE(0x06030000), U16_TO_U8S_LE(MS_OS_20_DESC_LEN), + + // Configuration subset header: length, type, configuration index, reserved, + // configuration total length + U16_TO_U8S_LE(0x0008), U16_TO_U8S_LE(MS_OS_20_SUBSET_HEADER_CONFIGURATION), + 0, 0, U16_TO_U8S_LE(MS_OS_20_DESC_LEN - 0x0A), + + // Function Subset header: length, type, first interface, reserved, subset + // length + U16_TO_U8S_LE(0x0008), U16_TO_U8S_LE(MS_OS_20_SUBSET_HEADER_FUNCTION), + 0 /*itf num*/, 0, U16_TO_U8S_LE(MS_OS_20_DESC_LEN - 0x0A - 0x08), + + // MS OS 2.0 Compatible ID descriptor: length, type, compatible ID, sub + // compatible ID + U16_TO_U8S_LE(0x0014), U16_TO_U8S_LE(MS_OS_20_FEATURE_COMPATBLE_ID), 'W', + 'I', 'N', 'U', 'S', 'B', 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, // sub-compatible + + // MS OS 2.0 Registry property descriptor: length, type + U16_TO_U8S_LE(MS_OS_20_DESC_LEN - 0x0A - 0x08 - 0x08 - 0x14), + U16_TO_U8S_LE(MS_OS_20_FEATURE_REG_PROPERTY), U16_TO_U8S_LE(0x0007), + U16_TO_U8S_LE(0x002A), // wPropertyDataType, wPropertyNameLength and + // PropertyName "DeviceInterfaceGUIDs\0" in UTF-16 + 'D', 0x00, 'e', 0x00, 'v', 0x00, 'i', 0x00, 'c', 0x00, 'e', 0x00, 'I', 0x00, + 'n', 0x00, 't', 0x00, 'e', 0x00, 'r', 0x00, 'f', 0x00, 'a', 0x00, 'c', 0x00, + 'e', 0x00, 'G', 0x00, 'U', 0x00, 'I', 0x00, 'D', 0x00, 's', 0x00, 0x00, + 0x00, + U16_TO_U8S_LE(0x0050), // wPropertyDataLength + // bPropertyData: “{975F44D9-0D08-43FD-8B3E-127CA8AFFF9D}”. + '{', 0x00, '9', 0x00, '7', 0x00, '5', 0x00, 'F', 0x00, '4', 0x00, '4', 0x00, + 'D', 0x00, '9', 0x00, '-', 0x00, '0', 0x00, 'D', 0x00, '0', 0x00, '8', 0x00, + '-', 0x00, '4', 0x00, '3', 0x00, 'F', 0x00, 'D', 0x00, '-', 0x00, '8', 0x00, + 'B', 0x00, '3', 0x00, 'E', 0x00, '-', 0x00, '1', 0x00, '2', 0x00, '7', 0x00, + 'C', 0x00, 'A', 0x00, '8', 0x00, 'A', 0x00, 'F', 0x00, 'F', 0x00, 'F', 0x00, + '9', 0x00, 'D', 0x00, '}', 0x00, 0x00, 0x00, 0x00, 0x00}; + +TU_VERIFY_STATIC(sizeof(desc_ms_os_20) == MS_OS_20_DESC_LEN, "Incorrect size"); + +//------------- IMPLEMENTATION -------------// + +Adafruit_USBD_WebUSB::Adafruit_USBD_WebUSB(void) { + _connected = false; + _url = NULL; + _linestate_cb = NULL; +} + +bool Adafruit_USBD_WebUSB::begin(void) { + if (!USBDevice.addInterface(*this)) + return false; + + // WebUSB requires to change USB version from 2.0 to 2.1 + USBDevice.setVersion(0x0210); + + _webusb_dev = this; + return true; +} + +bool Adafruit_USBD_WebUSB::setLandingPage(const void *url) { + _url = (const uint8_t *)url; + return true; +} + +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 const len = sizeof(desc); + + if (bufsize < len) { + return 0; + } + + 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; + + return len; +} + +bool Adafruit_USBD_WebUSB::connected(void) { + return tud_vendor_mounted() && _connected; +} + +Adafruit_USBD_WebUSB::operator bool() { + // Add an yield to run usb background in case sketch block wait as follows + // while( !webusb ) {} + if (!connected()) { + yield(); + } + + return connected(); +} + +int Adafruit_USBD_WebUSB::available(void) { + uint32_t count = tud_vendor_available(); + + // Add an yield to run usb background in case sketch block wait as follows + // while( !webusb.available() ) {} + if (!count) { + yield(); + } + + return count; +} + +int Adafruit_USBD_WebUSB::read(void) { + uint8_t ch; + return tud_vendor_read(&ch, 1) ? (int)ch : -1; +} + +size_t Adafruit_USBD_WebUSB::write(uint8_t b) { return this->write(&b, 1); } + +size_t Adafruit_USBD_WebUSB::write(const uint8_t *buffer, size_t size) { + size_t remain = size; + while (remain && _connected) { + size_t wrcount = tud_vendor_write(buffer, remain); + remain -= wrcount; + buffer += wrcount; + + // Write FIFO is full, run usb background to flush + if (remain) { + yield(); + } + } + + return size - remain; +} + +int Adafruit_USBD_WebUSB::peek(void) { + uint8_t ch; + return tud_vendor_peek(&ch) ? (int)ch : -1; +} + +void Adafruit_USBD_WebUSB::flush(void) {} + +extern "C" { + +// 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 +// request) +bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, + tusb_control_request_t const *request) { + if (!_webusb_dev) { + return false; + } + + // nothing to with DATA & ACK stage + if (stage != CONTROL_STAGE_SETUP) { + return true; + } + + switch (request->bmRequestType_bit.type) { + case TUSB_REQ_TYPE_VENDOR: + switch (request->bRequest) { + case VENDOR_REQUEST_WEBUSB: + // match vendor request in BOS descriptor + // Get landing page url + if (!_webusb_dev->_url) { + return false; + } + return tud_control_xfer(rhport, request, (void *)_webusb_dev->_url, + _webusb_dev->_url[0]); + + case VENDOR_REQUEST_MICROSOFT: + if (request->wIndex == 7) { + // Get Microsoft OS 2.0 compatible descriptor + uint16_t total_len; + memcpy(&total_len, desc_ms_os_20 + 8, 2); + + return tud_control_xfer(rhport, request, (void *)desc_ms_os_20, + total_len); + } else { + return false; + } + + default: + break; + } + break; + + case TUSB_REQ_TYPE_CLASS: + if (request->bRequest == 0x22) { + // Webserial simulate the CDC_REQUEST_SET_CONTROL_LINE_STATE (0x22) to + // connect and disconnect. + _webusb_dev->_connected = (request->wValue != 0); + + // response with status OK + tud_control_status(rhport, request); + + // invoked callback if any (TODO should be done at ACK stage) + if (_webusb_dev->_linestate_cb) { + _webusb_dev->_linestate_cb(_webusb_dev->_connected); + } + + return true; + } + break; + + default: + // stall unknown request + return false; + } + + 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/libraries/Adafruit_TinyUSB_Arduino/src/arduino/webusb/Adafruit_USBD_WebUSB.h b/libraries/Adafruit_TinyUSB_Arduino/src/arduino/webusb/Adafruit_USBD_WebUSB.h new file mode 100644 index 00000000000..556ec5b060a --- /dev/null +++ b/libraries/Adafruit_TinyUSB_Arduino/src/arduino/webusb/Adafruit_USBD_WebUSB.h @@ -0,0 +1,78 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2019 hathach for Adafruit Industries + * + * 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 ADAFRUIT_USBD_WEBUSB_H_ +#define ADAFRUIT_USBD_WEBUSB_H_ + +#include "Stream.h" +#include "arduino/Adafruit_USBD_Device.h" + +#define WEBUSB_URL_DEF(_name, _scheme, _url) \ + struct TU_ATTR_PACKED { \ + uint8_t bLength; \ + uint8_t bDescriptorType; \ + uint8_t bScheme; \ + char url[3 + sizeof(_url)]; \ + } const _name = {3 + sizeof(_url) - 1, 3, _scheme, _url} + +class Adafruit_USBD_WebUSB : public Stream, public Adafruit_USBD_Interface { +public: + typedef void (*linestate_callback_t)(bool connected); + Adafruit_USBD_WebUSB(void); + + bool begin(void); + + bool setLandingPage(const void *url); + void setLineStateCallback(linestate_callback_t fp); + + // Stream interface to use with MIDI Library + virtual int read(void); + virtual int available(void); + virtual int peek(void); + virtual void flush(void); + virtual size_t write(uint8_t b); + + virtual size_t write(const uint8_t *buffer, size_t size); + size_t write(const char *buffer, size_t size) { + return write((const uint8_t *)buffer, size); + } + + bool connected(void); + operator bool(); + + // from Adafruit_USBD_Interface + virtual uint16_t getInterfaceDescriptor(uint8_t itfnum, uint8_t *buf, + uint16_t bufsize); + +private: + bool _connected; + const uint8_t *_url; + linestate_callback_t _linestate_cb; + + // Make all tinyusb callback friend to access private data + friend bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, + tusb_control_request_t const *request); +}; + +#endif /* ADAFRUIT_USBD_WEBUSB_H_ */ diff --git a/platform.txt b/platform.txt index 8f828b7ebd8..20816d35c7a 100644 --- a/platform.txt +++ b/platform.txt @@ -45,7 +45,7 @@ compiler.cpp.flags.esp32s2=-mlongcalls -ffunction-sections -fdata-sections -Wno- compiler.S.flags.esp32s2=-ffunction-sections -fdata-sections -Wno-error=unused-function -Wno-error=unused-variable -Wno-error=deprecated-declarations -Wno-unused-parameter -Wno-sign-compare -ggdb -O2 -fstack-protector -fstrict-volatile-bitfields -Wno-error=unused-but-set-variable -x assembler-with-cpp -MMD -c compiler.c.elf.flags.esp32s2=-T esp32s2.rom.ld -T esp32s2.rom.api.ld -T esp32s2.rom.libgcc.ld -T esp32s2.rom.newlib-funcs.ld -T esp32s2.rom.newlib-data.ld -T esp32s2.rom.spiflash.ld -T esp32s2_out.ld -T esp32s2.project.ld -T esp32s2.peripherals.ld -mlongcalls -Wl,--cref -Wl,--gc-sections -fno-rtti -fno-lto -u esp_app_desc -u pthread_include_pthread_impl -u pthread_include_pthread_cond_impl -u pthread_include_pthread_local_storage_impl -u ld_include_panic_highint_hdl -u start_app -u __ubsan_include -Wl,--wrap=longjmp -u vfs_include_syscalls_impl -u call_user_start_cpu0 -Wl,--undefined=uxTopUsedPriority -u app_main -u newlib_include_heap_impl -u newlib_include_syscalls_impl -u newlib_include_pthread_impl -u __cxa_guard_dummy compiler.ar.flags.esp32s2=cru -build.extra_flags.esp32s2=-DARDUINO_SERIAL_PORT={build.serial} +build.extra_flags.esp32s2=-DARDUINO_SERIAL_PORT={build.serial} {build.usbstack_flags} # # ESP32S2 Support End # @@ -109,6 +109,7 @@ build.code_debug=0 build.defines= build.loop_core= build.event_core= +build.usbstack_flags= build.extra_flags=-DESP32 -DCORE_DEBUG_LEVEL={build.code_debug} {build.loop_core} {build.event_core} {build.defines} {build.extra_flags.{build.mcu}} # Custom build options diff --git a/variants/adafruit_feather_esp32s2/pins_arduino.h b/variants/adafruit_feather_esp32s2/pins_arduino.h index f84ab6fe0e2..3839a547756 100644 --- a/variants/adafruit_feather_esp32s2/pins_arduino.h +++ b/variants/adafruit_feather_esp32s2/pins_arduino.h @@ -7,7 +7,7 @@ #define USB_VID 0x239A #define USB_PID 0x80EB #define USB_MANUFACTURER "Adafruit" -#define USB_PRODUCT "Adafruit Feather ESP32-S2" +#define USB_PRODUCT "Feather ESP32-S2" #define USB_SERIAL "" diff --git a/variants/adafruit_funhouse_esp32s2/pins_arduino.h b/variants/adafruit_funhouse_esp32s2/pins_arduino.h index bef0a830970..2079d70b3de 100644 --- a/variants/adafruit_funhouse_esp32s2/pins_arduino.h +++ b/variants/adafruit_funhouse_esp32s2/pins_arduino.h @@ -8,7 +8,7 @@ #define USB_PID 0x80F9 #define USB_MANUFACTURER "Adafruit" -#define USB_PRODUCT "Adafruit Funhouse ESP32-S2" +#define USB_PRODUCT "FunHouse ESP32-S2" #define USB_SERIAL "" diff --git a/variants/adafruit_magtag29_esp32s2/pins_arduino.h b/variants/adafruit_magtag29_esp32s2/pins_arduino.h index c015aff6864..a401024f8f8 100644 --- a/variants/adafruit_magtag29_esp32s2/pins_arduino.h +++ b/variants/adafruit_magtag29_esp32s2/pins_arduino.h @@ -5,7 +5,7 @@ #define USB_VID 0x239A -#define USB_PID 0x80DF +#define USB_PID 0x80E5 #define USB_MANUFACTURER "Adafruit" #define USB_PRODUCT "EPD MagTag 2.9\" ESP32-S2" #define USB_SERIAL "" diff --git a/variants/esp32s2/pins_arduino.h b/variants/esp32s2/pins_arduino.h index 85b7455d491..5dc08f2efe2 100644 --- a/variants/esp32s2/pins_arduino.h +++ b/variants/esp32s2/pins_arduino.h @@ -3,6 +3,11 @@ #include +#define USB_VID 0x303A +#define USB_PID 0x0002 +#define USB_MANUFACTURER "Espressif Systems" +#define USB_PRODUCT "ESP32S2_DEV" + #define EXTERNAL_NUM_INTERRUPTS 46 #define NUM_DIGITAL_PINS 48 #define NUM_ANALOG_INPUTS 20