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 linux dfu-util tool to test.

ECM_RNDIS and NCM

https://en.wikipedia.org/wiki/Ethernet_over_USB

Not yet implemented. USB::ECM_RNDIS::Device and USB::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

USB::HID::HostDevice

CDC

USB::CDC::HostDevice

MSC

Allows attachment of USB storage. USB::MSC::HostDevice See Basic IFS for a real-world example.

VENDOR

Support access to custom devices. USB::MSC::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

template<typename T>
inline const T *as() const

Less clumsy way to cast descriptor to a specific type.

Template Parameters:

T – TinyUSB defines structures beginning with ‘tusb_desc_’

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>

Public Members

uint8_t value
uint8_t id
uint8_t type
uint8_t reserved
struct USB::Descriptor::Type::[anonymous] [anonymous]
struct DescriptorList
#include <Descriptors.h>

Buffer containing list of descriptors.

Supports C++ iteration.

Subclassed by USB::HID::Report

class Iterator
#include <Descriptors.h>
template<size_t max_chars>
struct StringDescriptor : public USB::Descriptor
#include <Descriptors.h>

Template for making a USB string descriptor.

Public Functions

inline StringDescriptor()

Construct an empty string descriptor.

inline StringDescriptor(const char *str, size_t charCount)

Construct a string descriptor containing text.

Parameters:
  • str – ASCII text (unicode page #0 only)

  • charCount – Number of characters in string

Public Members

uint16_t text[max_chars]

UTF16-LE encoded text (no NUL terminator)

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

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.

Public Members

uint8_t dev_addr = {255}

Device address (from 1)

uint8_t idx = {255}

Index or instance value specific to class.

const char *name

Optional name for this interface instance.

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

Enums

enum class Event

Values:

enumerator rx_data
enumerator tx_done
enumerator line_break

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

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

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 len) 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

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.

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.

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

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

struct Report : public USB::DescriptorList
#include <HostDevice.h>
class HostDevice : public USB::HostInterface
#include <HostDevice.h>
namespace MIDI

Enums

enum class Event

Values:

enumerator rx
union Packet
#include <Device.h>

Public Members

uint8_t data[4]
uint8_t code
uint8_t cable_number
uint8_t m0
uint8_t m1
uint8_t m2
struct USB::MIDI::Packet::[anonymous] [anonymous]
class Device : public USB::DeviceInterface
#include <Device.h>
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.

Public Functions

inline virtual Type getType() const override

Obtain device type.

virtual String getName() const override

Obtain unique device name.

virtual uint32_t getId() const override

Obtain device ID.

Return values:

uint32_t – typically flash chip ID

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

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)

namespace NCM
class Device : public USB::DeviceInterface
#include <Device.h>

Not currently implemented.

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

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.

virtual bool transferComplete(const Transfer &txfr) = 0

Called when a non-control USB transfer has completed.

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.

struct Transfer
#include <HostDevice.h>

Structure passed to ‘transferComplete’ method.

References

Used by

Environment Variables

SoC support

  • esp32s2

  • esp32s3

  • host

  • rp2040

Submodule: `tinyusb <>`__