USB
Sming library for TinyUSB.
Note that TinyUSB uses a large number of configuration variables and callback functions, so is compiled and linked directly with the application rather than as a separate library.
Device stack
The TinyUSB example applications generally consist of these three things:
- tusb_config.h
Contains definitions such as which classes are supported, how many endpoints (each), buffer sizes, etc.
- usb_descriptors.c
Provides descriptor/report structure definitions, interface and endpoint assignments and string definitions, with callback function implementations to provide these to the TinyUSB stack.
- main.c and other translation units
Implements class-specific callbacks.
Applications may choose to use the raw TinyUSB API; this is demonstrated in the HID Composite Device sample sample. A drawback of this approach is that the configuration files have to be composed manually, which requires some knowledge of TinyUSB and can also be error-prone.
Instead, the configuration can be described in a JSON file and the configuration generated by the library.
The format of this file is defined in schema.json.
For vscode, the .usbcfg
file extension is association with this schema by make ide-vscode
.
This enables use of auto-completion in the editor. See Using with MS Visual Studio Code.
This approach is demonstrated in the Basic Device sample.
In the application component.mk
file, set USB_CONFIG
to the name of the configuration file.
The configuration will be validated and configuration files generated in, for example, out/Rp2040/debug/USB
.
Device classes
C++ Device implementations are provided for some of the standard interfaces. Use is demonstrated in the Basic Device sample.
- CDC
Communications Device Class.
USB::CDC::Device
.TinyUSB implements only the ACM modes which apparently have issues with Windows. Appears in linux as
/dev/ttyACM0
, etc.- DFU
Device Firmware Update.
USB::DFU::Device
. Use the linuxdfu-util
tool to test.- ECM_RNDIS and NCM
https://en.wikipedia.org/wiki/Ethernet_over_USB
Not yet implemented.
USB::ECM_RNDIS::Device
andUSB::NCM::Device
.- HID
Human Interface Device.
USB::HID::Device
.- MIDI
Musical Instrument Digital Interface (over USB).
USB::MIDI::Device
.- MSC
Mass Storage Class.
USB::MSC::Device
.- VENDOR
Devices are identifed by VID:PID and require appropriate host driver.
USB::VENDOR::Device
. TinyUSB implements a simple read/write interface for this class. This is implemented like a serial port to allow asynchronous streaming, etc.
Host stack
See Basic Host for an example.
Note
At present, there is no host support for Esp32. Samples will build for Rp2040 only.
- HUB
When connected to a hub (or multiple hubs) this must be defined in the configuration.
- HID
- CDC
- MSC
Allows attachment of USB storage.
USB::MSC::HostDevice
See Basic IFS for a real-world example.- VENDOR
Support access to custom devices.
USB::VENDOR::HostDevice
. The sample contains a demonstration for connecting an original XBOX-360 joypad controller.
Configuration variables
- USB_DEBUG_LEVEL
default: 0 (disable)
Set to a value from 1-3 to enable debug output messages from the TinyUSB stack.
- USB_CONFIG
default: undefined
This identifies the name of the JSON USB configuration file for the application. This allows the TinyUSB configuration data to be generated rather than written manually.
API
-
namespace USB
Typedefs
-
using GetDeviceDescriptor = Delegate<const tusb_desc_device_t*(const tusb_desc_device_t &desc)>
Callback to support provision of dynamic device descriptors.
Application typically copies the source descriptor to a statically allocated buffer, then amends values as required.
- Param desc:
The statically configured device descriptor
- Param const:
tusb_desc_device_t* Application returns a pointer to a statically allocated descriptor to use
-
using GetDescriptorString = Delegate<const Descriptor*(uint8_t index)>
Application-provided callback to customise string responses.
Note
Returned descriptor MUST NOT be on the stack! Typically this is statically allocated.
- Param index:
String index to fetch (STRING_INDEX_xxxx)
- Retval const:
StringDescriptor* Pointer to persistent buffer containing descriptor. Return nullptr to use default value from string table.
Functions
-
void onGetDeviceDescriptor(GetDeviceDescriptor callback)
-
void onGetDescriptorSting(GetDescriptorString callback)
-
bool begin()
-
struct Descriptor
- #include <Descriptors.h>
Structure of a USB descriptor.
Subclassed by USB::StringDescriptor< max_chars >
Public Functions
Public Members
-
uint8_t length
Total size (in bytes) including this header.
-
uint8_t type
e.g. TUSB_DESC_STRING
-
union Type
- #include <Descriptors.h>
-
uint8_t length
-
struct DescriptorList
- #include <Descriptors.h>
Buffer containing list of descriptors.
Supports C++ iteration.
Subclassed by USB::HID::Report
-
class Iterator
- #include <Descriptors.h>
-
class Iterator
-
template<size_t max_chars>
struct StringDescriptor : public USB::Descriptor - #include <Descriptors.h>
Template for making a USB string descriptor.
-
class DeviceInterface
- #include <DeviceInterface.h>
Base class to support a USB device interface implementation.
Subclassed by USB::CDC::Device, USB::DFU::Device, USB::ECM_RNDIS::Device, USB::HID::Device, USB::MIDI::Device, USB::MSC::Device, USB::NCM::Device, USB::VENDOR::Device
Public Functions
-
inline DeviceInterface(uint8_t instance, const char *name)
Constructor.
- Parameters:
instance – TinyUSB instance or index (class-specific)
name – Declared name for this interface instance
-
inline DeviceInterface(uint8_t instance, const char *name)
-
class HostInterface
- #include <HostInterface.h>
Common base class to support Host USB access.
Subclassed by USB::CDC::HostDevice, USB::HID::HostDevice, USB::MSC::HostDevice, USB::VENDOR::HostDevice
Public Functions
-
inline void begin(const Instance &inst)
Descendant classes should override this method to peform initialisation.
-
inline virtual void end()
Called when device is disconnected. Override as required.
-
struct Instance
- #include <HostInterface.h>
Identifies a TinyUSB host interface.
-
inline void begin(const Instance &inst)
-
namespace CDC
Typedefs
-
using MountCallback = Delegate<HostDevice*(const HostInterface::Instance &inst)>
Application callback to notify connection of a new device.
- Param inst:
TinyUSB device instance
- Retval HostDevice*:
Application returns pointer to implementation, or nullptr to ignore this device
-
using UnmountCallback = Delegate<void(HostDevice &dev)>
Application callback to notify disconnection of a device.
- Param dev:
The device which has been disconnected
Functions
-
void onMount(MountCallback callback)
Application should call this method to receive device connection notifications.
- Parameters:
callback –
-
void onUnmount(UnmountCallback callback)
Application should call this method to receive device disconnection notifications.
- Parameters:
callback –
-
class Device : public USB::DeviceInterface, public USB::CDC::UsbSerial
- #include <Device.h>
Serial device implementation, in ACM mode.
Public Functions
-
inline virtual size_t setRxBufferSize(size_t size) override
Sets receiving buffer size.
- Parameters:
size – requested size
- Return values:
size_t – actual size
-
inline virtual size_t setTxBufferSize(size_t size) override
Sets transmit buffer size.
- Parameters:
size – requested size
- Return values:
size_t – actual size
-
inline virtual int available() override
Return the total length of the stream.
- Return values:
int – -1 is returned when the size cannot be determined
-
inline virtual bool isFinished() override
Check if all data has been read.
- Return values:
bool – True on success.
-
inline virtual int read() override
Read one character and moves the stream pointer.
- Return values:
The – character that was read or -1 if none is available
-
inline virtual size_t readBytes(char *buffer, size_t length) override
Read chars from stream into buffer.
Terminates if length characters have been read or timeout (see setTimeout). Returns the number of characters placed in the buffer (0 means no valid data found).
Note
Inherited classes may provide more efficient implementations without timeout.
-
inline virtual int peek() override
Read a character without advancing the stream pointer.
- Return values:
int – The character that was read or -1 if none is available
-
inline virtual void clear(SerialMode mode = SERIAL_FULL) override
Clear the serial port transmit/receive buffers.
Note
All un-read buffered data is removed and any error condition cleared
- Parameters:
mode – Whether to flush TX, RX or both (the default)
-
virtual size_t write(const uint8_t *buffer, size_t size) override
Write chars to stream.
Note
Although this is defined in the Print class, ReadWriteStream uses this as the core output method so descendants are required to implement it
- Parameters:
buffer – Pointer to buffer to write to the stream
size – Quantity of chars to write
- Return values:
size_t – Quantity of chars written to stream
-
inline virtual size_t setRxBufferSize(size_t size) override
-
class HostDevice : public USB::HostInterface, public USB::CDC::UsbSerial
- #include <HostDevice.h>
Implements CDC interface for a connected serial device.
Public Functions
-
inline virtual size_t setRxBufferSize(size_t size) override
Sets receiving buffer size.
- Parameters:
size – requested size
- Return values:
size_t – actual size
-
inline virtual size_t setTxBufferSize(size_t size) override
Sets transmit buffer size.
- Parameters:
size – requested size
- Return values:
size_t – actual size
-
inline virtual int available() override
Return the total length of the stream.
- Return values:
int – -1 is returned when the size cannot be determined
-
inline virtual bool isFinished() override
Check if all data has been read.
- Return values:
bool – True on success.
-
inline virtual int read() override
Read one character and moves the stream pointer.
- Return values:
The – character that was read or -1 if none is available
-
inline virtual size_t readBytes(char *buffer, size_t length) override
Read chars from stream into buffer.
Terminates if length characters have been read or timeout (see setTimeout). Returns the number of characters placed in the buffer (0 means no valid data found).
Note
Inherited classes may provide more efficient implementations without timeout.
-
inline virtual int peek() override
Read a character without advancing the stream pointer.
- Return values:
int – The character that was read or -1 if none is available
-
inline virtual void clear(SerialMode mode = SERIAL_FULL) override
Clear the serial port transmit/receive buffers.
Note
All un-read buffered data is removed and any error condition cleared
- Parameters:
mode – Whether to flush TX, RX or both (the default)
-
virtual size_t write(const uint8_t *buffer, size_t size) override
Write chars to stream.
Note
Although this is defined in the Print class, ReadWriteStream uses this as the core output method so descendants are required to implement it
- Parameters:
buffer – Pointer to buffer to write to the stream
size – Quantity of chars to write
- Return values:
size_t – Quantity of chars written to stream
-
inline virtual size_t setRxBufferSize(size_t size) override
-
class UsbSerial : public ReadWriteStream
- #include <UsbSerial.h>
Base class for both device and host serial port modes.
- Todo:
We could inherit from HardwareSerial here, or preferably provide an abstract base class for all serial devices.
Subclassed by USB::CDC::Device, USB::CDC::HostDevice, USB::VENDOR::Device
Public Functions
-
virtual size_t setRxBufferSize(size_t size) = 0
Sets receiving buffer size.
- Parameters:
size – requested size
- Return values:
size_t – actual size
-
virtual size_t setTxBufferSize(size_t size) = 0
Sets transmit buffer size.
- Parameters:
size – requested size
- Return values:
size_t – actual size
-
inline void setTxWait(bool wait)
Governs write behaviour when UART transmit buffers are full.
- Parameters:
wait – If false, writes will return short count; applications can use the txComplete callback to send more data. If true, writes will wait for more buffer space so that all requested data is written
-
inline virtual uint16_t readMemoryBlock(char *buf, int max_len) override
Read a block of memory.
- Todo:
Should IDataSourceStream::readMemoryBlock return same data type as its bufSize param?
- Parameters:
data – Pointer to the data to be read
bufSize – Quantity of chars to read
- Return values:
uint16_t – Quantity of chars read
-
inline virtual bool seek(int) override
Move read cursor.
- Parameters:
len – Relative cursor adjustment
- Return values:
bool – True on success.
-
virtual void clear(SerialMode mode = SERIAL_FULL) = 0
Clear the serial port transmit/receive buffers.
Note
All un-read buffered data is removed and any error condition cleared
- Parameters:
mode – Whether to flush TX, RX or both (the default)
-
void systemDebugOutput(bool enabled)
Configure serial port for system debug output and redirect output from debugf.
Note
If enabled, port will issue system debug messages
- Parameters:
enabled – True to enable this port for system debug output
-
unsigned getStatus()
Get status error flags and clear them.
See also
SerialStatus
- Return values:
unsigned – Status flags, combination of SerialStatus bits
-
using MountCallback = Delegate<HostDevice*(const HostInterface::Instance &inst)>
-
namespace DFU
-
class Callbacks
- #include <Device.h>
Applications must implement this class and pass an instance to Device::begin().
Public Functions
-
virtual uint32_t getTimeout(Alternate alt, dfu_state_t state) = 0
Invoked right before tud_dfu_download_cb() (state=DFU_DNBUSY) or tud_dfu_manifest_cb() (state=DFU_MANIFEST)
Application return timeout in milliseconds (bwPollTimeout) for the next download/manifest operation. During this period, USB host won’t try to communicate with us.
-
virtual void download(Alternate alt, uint32_t offset, const void *data, uint16_t length) = 0
Invoked when received DFU_DNLOAD (wLength>0) following by DFU_GETSTATUS (state=DFU_DNBUSY) requests.
This callback could be returned before flashing op is complete (async). Once finished flashing, application must call
complete()
-
virtual void manifest(Alternate alt) = 0
Invoked when download process is complete, received DFU_DNLOAD (wLength=0) following by DFU_GETSTATUS (state=Manifest)
Application can do checksum, or actual flashing if buffered entire image previously. Once finished flashing, application must call
Device::finishFlashing()
-
virtual uint16_t upload(Alternate alt, uint32_t offset, void *data, uint16_t length) = 0
Invoked when received DFU_UPLOAD request Application must populate data with up to length bytes and return the number of written bytes.
-
virtual void abort(Alternate alt) = 0
Invoked when the Host has terminated a download or upload transfer.
-
virtual void detach() = 0
Invoked when a DFU_DETACH request is received.
-
virtual uint32_t getTimeout(Alternate alt, dfu_state_t state) = 0
-
class Device : public USB::DeviceInterface
- #include <Device.h>
Public Static Functions
-
static inline void complete(dfu_status_t status)
Applications call this method from download and manifest callbacks.
This mechanism supports use of asynchronous writes.
-
static inline void complete(dfu_status_t status)
-
class Callbacks
-
namespace ECM_RNDIS
-
class Device : public USB::DeviceInterface
- #include <Device.h>
Public Functions
-
inline DeviceInterface(uint8_t instance, const char *name)
Constructor.
- Parameters:
instance – TinyUSB instance or index (class-specific)
name – Declared name for this interface instance
-
inline DeviceInterface(uint8_t instance, const char *name)
-
class Device : public USB::DeviceInterface
-
namespace HID
Typedefs
-
using MountCallback = Delegate<HostDevice*(const HostInterface::Instance &inst, const Report &report)>
Application callback to notify connection of a new device.
- Param inst:
TinyUSB device instance
- Param report:
HID report descriptors for this interface
- Retval HostDevice*:
Application returns pointer to implementation, or nullptr to ignore this device
-
using UnmountCallback = Delegate<void(HostDevice &dev)>
Application callback to notify disconnection of a device.
- Param dev:
The device which has been disconnected
Functions
-
void onMount(MountCallback callback)
Application should call this method to receive device connection notifications.
- Parameters:
callback –
-
void onUnmount(UnmountCallback callback)
Application should call this method to receive device disconnection notifications.
- Parameters:
callback –
-
class Device : public USB::DeviceInterface
- #include <Device.h>
Public Functions
-
inline DeviceInterface(uint8_t instance, const char *name)
Constructor.
- Parameters:
instance – TinyUSB instance or index (class-specific)
name – Declared name for this interface instance
-
inline DeviceInterface(uint8_t instance, const char *name)
-
struct Report : public USB::DescriptorList
- #include <HostDevice.h>
-
class HostDevice : public USB::HostInterface
- #include <HostDevice.h>
-
using MountCallback = Delegate<HostDevice*(const HostInterface::Instance &inst, const Report &report)>
-
namespace MIDI
-
-
union Packet
- #include <Device.h>
-
class Device : public USB::DeviceInterface
- #include <Device.h>
-
union Packet
-
namespace MSC
Typedefs
-
using MountCallback = Delegate<HostDevice*(const HostInterface::Instance &inst)>
Application callback to notify connection of a new device.
- Param inst:
TinyUSB device instance
- Retval HostDevice*:
Application returns pointer to implementation, or nullptr to ignore this device
-
using UnmountCallback = Delegate<void(HostDevice &dev)>
Application callback to notify disconnection of a device.
- Param dev:
The device which has been disconnected
Functions
-
void onMount(MountCallback callback)
Application should call this method to receive device connection notifications.
- Parameters:
callback –
-
void onUnmount(UnmountCallback callback)
Application should call this method to receive device disconnection notifications.
- Parameters:
callback –
-
class LogicalUnit : public Storage::Disk::BlockDevice
- #include <Device.h>
A physical device instance managed by an MSC interface.
-
class Device : public USB::DeviceInterface
- #include <Device.h>
Public Functions
-
inline DeviceInterface(uint8_t instance, const char *name)
Constructor.
- Parameters:
instance – TinyUSB instance or index (class-specific)
name – Declared name for this interface instance
-
inline DeviceInterface(uint8_t instance, const char *name)
-
struct Inquiry
- #include <HostDevice.h>
Information provided by SCSI inquiry operation.
-
class HostDevice : public USB::HostInterface
- #include <HostDevice.h>
A USB mass storage device supports one or more logical units, each of which is a physical storage device.
Public Types
-
using EnumCallback = Delegate<bool(LogicalUnit &unit, const Inquiry &inquiry)>
Callback passed to enumerate() method.
- Param unit:
The logical unit attached to a device
- Param inquiry:
Detailed information
- Retval bool:
true to continue enumeration, false to stop
Public Functions
-
virtual void end()
Called when device is disconnected. Override as required.
-
bool enumerate(EnumCallback callback)
Enumerate all logical units managed by this device.
- Parameters:
callback – Invoked for each discovered Logical Unit
-
inline LogicalUnit *operator[](unsigned lun) const
Access a specific logical unit by number.
- Parameters:
lun – The logical Unit Number
- Return values:
LogicalUnit* – The corresponding LU, or nullptr if invalid
-
inline size_t getSectorSize(uint8_t lun) const
Get the declared block/sector size for a unit.
- Parameters:
lun – The logical Unit Number
- Return values:
size_t – Block size in bytes, or 0 if invalid
-
inline storage_size_t getSectorCount(uint8_t lun) const
Get the number of blocks/sectors for a unit.
- Parameters:
lun – The logical Unit Number
- Return values:
size_t – Number of blocks, 0 if invalid
-
bool read_sectors(uint8_t lun, uint32_t lba, void *dst, size_t size)
Read data from a unit.
- Parameters:
lun – The logical Unit Number
lba – Starting Logical Block Address
dst – Buffer to store data
size – Number of sectors to read
- Return values:
bool – true on success
-
bool write_sectors(uint8_t lun, uint32_t lba, const void *src, size_t size)
Write data to a unit.
- Parameters:
lun – The logical Unit Number
lba – Starting Logical Block Address
src – Data to write
size – Number of sectors to write
- Return values:
bool – true on success
-
bool wait()
Wait for all outstanding operations to complete.
Write operations are asynchronous so calling this method ensures that the operation has completed.
- Parameters:
lun – The logical Unit Number
- Return values:
bool – false on error (e.g. device forceably disconnected)
-
using EnumCallback = Delegate<bool(LogicalUnit &unit, const Inquiry &inquiry)>
-
using MountCallback = Delegate<HostDevice*(const HostInterface::Instance &inst)>
-
namespace NCM
-
class Device : public USB::DeviceInterface
- #include <Device.h>
Not currently implemented.
-
class Device : public USB::DeviceInterface
-
namespace VENDOR
Typedefs
-
using MountCallback = Delegate<HostDevice*(const HostInterface::Instance &inst, const HostDevice::Config &cfg)>
Application callback to notify connection of a new device.
- Param inst:
TinyUSB device instance
- Param cfg:
HostDevice configuration
- Retval HostDevice*:
Application returns pointer to implementation, or nullptr to ignore this device
-
using UnmountCallback = Delegate<void(HostDevice &dev)>
Application callback to notify disconnection of a device.
- Param dev:
The device which has been disconnected
Functions
-
void onMount(MountCallback callback)
Application should call this method to receive device connection notifications.
- Parameters:
callback –
-
void onUnmount(UnmountCallback callback)
Application should call this method to receive device disconnection notifications.
- Parameters:
callback –
-
class Device : public USB::DeviceInterface, public USB::CDC::UsbSerial
- #include <Device.h>
The TinyUSB vendor API is very much like a serial port. Each instance corresponds to a bi-directional interface.
Public Functions
-
inline virtual size_t setRxBufferSize(size_t size) override
Sets receiving buffer size.
- Parameters:
size – requested size
- Return values:
size_t – actual size
-
inline virtual size_t setTxBufferSize(size_t size) override
Sets transmit buffer size.
- Parameters:
size – requested size
- Return values:
size_t – actual size
-
inline virtual int available() override
Return the total length of the stream.
- Return values:
int – -1 is returned when the size cannot be determined
-
inline virtual bool isFinished() override
Check if all data has been read.
- Return values:
bool – True on success.
-
inline virtual int read() override
Read one character and moves the stream pointer.
- Return values:
The – character that was read or -1 if none is available
-
inline virtual size_t readBytes(char *buffer, size_t length) override
Read chars from stream into buffer.
Terminates if length characters have been read or timeout (see setTimeout). Returns the number of characters placed in the buffer (0 means no valid data found).
Note
Inherited classes may provide more efficient implementations without timeout.
-
inline virtual int peek() override
Read a character without advancing the stream pointer.
- Return values:
int – The character that was read or -1 if none is available
-
inline virtual void clear(SerialMode mode = SERIAL_FULL) override
Clear the serial port transmit/receive buffers.
Note
All un-read buffered data is removed and any error condition cleared
- Parameters:
mode – Whether to flush TX, RX or both (the default)
-
virtual size_t write(const uint8_t *buffer, size_t size) override
Write chars to stream.
Note
Although this is defined in the Print class, ReadWriteStream uses this as the core output method so descendants are required to implement it
- Parameters:
buffer – Pointer to buffer to write to the stream
size – Quantity of chars to write
- Return values:
size_t – Quantity of chars written to stream
-
inline virtual size_t setRxBufferSize(size_t size) override
-
class HostDevice : public USB::HostInterface
- #include <HostDevice.h>
Base class to use for custom devices.
Public Functions
-
inline virtual void end() override
Called when device is disconnected. Override as required.
-
virtual bool setConfig(uint8_t itf_num) = 0
Set active configuration.
Implementations typically start communicating.
-
struct Config
- #include <HostDevice.h>
Device configuration received during mount procedure.
Public Members
-
uint16_t vid
Vendor ID.
-
uint16_t pid
Product ID.
-
DescriptorList list
Interface descriptor list.
-
uint16_t vid
-
struct Transfer
- #include <HostDevice.h>
Structure passed to ‘transferComplete’ method.
-
inline virtual void end() override
-
using MountCallback = Delegate<HostDevice*(const HostInterface::Instance &inst, const HostDevice::Config &cfg)>
-
using GetDeviceDescriptor = Delegate<const tusb_desc_device_t*(const tusb_desc_device_t &desc)>
References
Used by
Basic Device Sample
Basic Host Sample
CDC MSC HID Host sample Sample
HID Composite Device sample Sample
Environment Variables
SoC support
esp32s2
esp32s3
host
rp2040
rp2350