doc: add class docs

Signed-off-by: HiFiPhile <admin@hifiphile.com>
This commit is contained in:
HiFiPhile
2026-08-01 19:22:52 +02:00
parent f3021b337f
commit cd9bbed39f
18 changed files with 2028 additions and 317 deletions

View File

@ -0,0 +1,131 @@
*****
Audio
*****
Role: device only. TinyUSB supports USB Audio Class 1.0 and 2.0 streaming.
The descriptors define the topology, formats, channels, rates, controls, and
alternate settings; the application supplies or consumes the audio samples.
Start from an example
=====================
Audio descriptors and buffer sizes are tightly coupled. Copy the closest
example, confirm that it enumerates, and then change one property at a time:
* :doc:`../../examples/device/audio_test` -- one-channel UAC2 microphone;
* :doc:`../../examples/device/audio_4_channel_mic` -- four-channel microphone;
* :doc:`../../examples/device/uac2_speaker_fb` -- speaker with feedback;
* :doc:`../../examples/device/uac2_headset` -- bidirectional headset;
* :doc:`../../examples/device/audio_test_multi_rate` -- UAC1 at full speed,
UAC2 at high speed, with multiple rates.
Configuration
=============
Set ``CFG_TUD_AUDIO`` to the number of audio functions. The principal options
are:
.. list-table::
:header-rows: 1
:widths: 37 16 47
* - Option
- Default
- What it controls
* - ``CFG_TUD_AUDIO_CTRL_BUF_SZ``
- ``64`` bytes
- Largest class control payload, such as a RANGE or channel-cluster
response. Increase it to fit the largest advertised control.
* - ``CFG_TUD_AUDIO_ENABLE_EP_IN``
- ``0``
- Enables microphone/device-to-host streaming.
* - ``CFG_TUD_AUDIO_ENABLE_EP_OUT``
- ``0``
- Enables speaker/host-to-device streaming.
* - ``CFG_TUD_AUDIO_FUNC_n_EP_IN_SZ_MAX`` /
``CFG_TUD_AUDIO_FUNC_n_EP_OUT_SZ_MAX``
- Required per enabled direction
- Maximum endpoint packet size across that function's alternate settings.
* - ``CFG_TUD_AUDIO_FUNC_n_EP_IN_SW_BUF_SZ`` /
``CFG_TUD_AUDIO_FUNC_n_EP_OUT_SW_BUF_SZ``
- ``0``
- Software FIFO size. Set it to at least the corresponding maximum
endpoint size when using the FIFO APIs.
* - ``CFG_TUD_AUDIO_EP_IN_FLOW_CONTROL``
- ``1``
- Adapts IN packet consumption to the FIFO fill level to reduce
underruns/overruns.
* - ``CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP``
- ``0``
- Enables an explicit feedback endpoint, normally required by an
asynchronous speaker.
* - ``CFG_TUD_AUDIO_ENABLE_INTERRUPT_EP``
- ``0``
- Enables the AudioControl interrupt endpoint for status notifications.
For each enabled direction, define the maximum endpoint size used by any
advertised alternate setting, for example
``CFG_TUD_AUDIO_FUNC_1_EP_IN_SZ_MAX``. A software FIFO such as
``CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ`` must be at least that large. Use
``TUD_AUDIO_EP_SIZE()`` as the examples do; high-speed audio has more service
intervals per millisecond than full-speed audio.
Data path
=========
.. list-table::
:header-rows: 1
:widths: 34 66
* - Operation
- Main API
* - ``tud_audio_mounted()`` / ``tud_audio_version()``
- Tests whether function zero is configured and returns its negotiated
Audio Class version.
* - ``tud_audio_available()`` / ``tud_audio_read()``
- Reports and removes speaker bytes from the OUT software FIFO. The read
count can be shorter than requested.
* - ``tud_audio_write()``
- Copies microphone bytes into the IN software FIFO and returns the number
accepted.
* - ``tud_audio_clear_ep_*_ff()``
- Discards queued samples in the selected endpoint FIFO, useful when a
streaming alternate setting closes.
* - ``tud_audio_get_ep_*_ff()``
- Returns the underlying FIFO object for advanced zero-copy or DMA
integration; the application must preserve its invariants.
* - ``tud_audio_n_fb_set()``
- Supplies the feedback value for one audio function when application
feedback mode is used. Pass 16.16 samples per frame; TinyUSB converts
it to full-speed 10.14 format when required.
* - ``tud_audio_feedback_update()``
- Updates internally calculated feedback from elapsed master-clock cycles
and returns the current 16.16 value, or zero on error.
* - ``tud_audio_n_*()``
- Selects a function explicitly with ``func_id``; helpers without ``n``
operate on function zero.
The host starts and stops a stream by selecting interface alternate settings.
Use ``tud_audio_set_itf_cb()`` and ``tud_audio_set_itf_close_ep_cb()`` to start
or stop the application-side I2S/DMA path. Do not produce or consume samples
merely because the device is mounted; wait until the streaming interface is
active.
Control requests
================
Implement the ``tud_audio_get_req_*_cb()`` and ``tud_audio_set_req_*_cb()``
callbacks for every control advertised by the descriptors, such as clock
frequency, clock validity, mute, and volume. A descriptor that advertises a
control but stalls its normal requests is likely to be rejected or behave
poorly on a host.
Asynchronous speakers normally need a feedback endpoint. Enable
``CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP`` and either configure the feedback method
through ``tud_audio_feedback_params_cb()`` or provide feedback with
``tud_audio_n_fb_set()``. Begin with the speaker-feedback example; incorrect
feedback causes periodic underruns or overruns even when the nominal sample
rates match.
Specifications used: *USB Device Class Definition for Audio Devices*, Release
1.0 and Release 2.0, plus *Audio Data Formats*, Release 2.0.

View File

@ -0,0 +1,75 @@
*************
Bluetooth HCI
*************
Role: device only. This driver transports Bluetooth HCI commands, events, and
ACL data over USB. It does not implement a Bluetooth controller, Link Manager,
or host stack; the application must provide that functionality.
Configuration and descriptors
=============================
Enable ``CFG_TUD_BTH`` and use ``TUD_BTH_DESCRIPTOR`` in the configuration
descriptor.
.. list-table::
:header-rows: 1
:widths: 38 17 45
* - Option
- Default
- What it controls
* - ``CFG_TUD_BTH_ISO_ALT_COUNT``
- Required
- Number of isochronous voice alternate settings. Pass one paired
IN/OUT packet size per setting to ``TUD_BTH_DESCRIPTOR``.
* - ``CFG_TUD_BTH_EVENT_EPSIZE``
- ``16`` bytes
- Maximum HCI event interrupt-IN packet.
* - ``CFG_TUD_BTH_DATA_EPSIZE``
- ``64`` bytes
- ACL bulk endpoint packet size. Keep it consistent with the descriptor
and active bus speed.
* - ``CFG_TUD_BTH_HISTORICAL_COMPATIBLE``
- ``0``
- Uses the legacy HCI command request value required by some historical
controller implementations.
Set ``CFG_TUD_BTH_HISTORICAL_COMPATIBLE`` only for a controller that requires
the legacy ``bRequest = 0xe0`` behavior described by the Bluetooth Core
specification. It is not a general compatibility switch.
Data path
=========
.. list-table::
:header-rows: 1
:widths: 38 62
* - API or callback
- What it does
* - ``tud_bt_hci_cmd_cb()``
- Delivers one host HCI command to the controller implementation.
* - ``tud_bt_acl_data_received_cb()``
- Delivers received host-to-controller ACL bytes.
* - ``tud_bt_event_send()``
- Queues a controller-to-host HCI event; ``false`` means it was not
accepted.
* - ``tud_bt_acl_data_send()``
- Queues controller-to-host ACL data; ``false`` means it was not accepted.
* - ``tud_bt_event_sent_cb()`` /
``tud_bt_acl_data_sent_cb()``
- Reports completion and releases the corresponding application-owned
send buffer.
The host delivers HCI commands through ``tud_bt_hci_cmd_cb()`` and ACL data
through ``tud_bt_acl_data_received_cb()``. The controller sends HCI events with
``tud_bt_event_send()`` and ACL data with ``tud_bt_acl_data_send()``.
The send APIs do not copy the whole packet. Keep each buffer valid and
unchanged until ``tud_bt_event_sent_cb()`` or ``tud_bt_acl_data_sent_cb()``.
Check the boolean return value before considering a packet queued.
There is currently no dedicated Bluetooth device example. Use the public API
in ``src/class/bth/bth_device.h`` together with the Bluetooth Core USB
Transport and HCI packet formats.

View File

@ -0,0 +1,169 @@
**********
CDC Serial
**********
Roles: device and host. The standard driver implements CDC ACM virtual serial
ports. The host driver can also expose FTDI, CP210x, CH34x, and PL2303 USB
serial adapters through the same ``tuh_cdc_*`` API.
Device
======
Enable ``CFG_TUD_CDC`` with the required port count and add one
``TUD_CDC_DESCRIPTOR`` per port.
.. list-table::
:header-rows: 1
:widths: 36 18 46
* - Option
- Default
- What it controls
* - ``CFG_TUD_CDC_RX_BUFSIZE`` / ``CFG_TUD_CDC_TX_BUFSIZE``
- Device bulk maximum
- Software FIFO capacity in each direction. Larger FIFOs absorb longer
application scheduling gaps.
* - ``CFG_TUD_CDC_RX_EPSIZE`` / ``CFG_TUD_CDC_TX_EPSIZE``
- Device bulk maximum
- Endpoint transfer buffer and descriptor packet size. Use
speed-appropriate values.
* - ``CFG_TUD_CDC_NOTIFY``
- ``0``
- Enables the interrupt notification endpoint and serial-state API.
* - ``CFG_TUD_CDC_RX_PERSISTENT`` / ``CFG_TUD_CDC_TX_PERSISTENT``
- ``0``
- Keeps the corresponding FIFO contents across disconnect/reconnect.
Enable only when stale bytes are intentional.
* - ``CFG_TUD_CDC_RX_NEED_ZLP``
- ``0``
- Enables multi-packet receive transfers terminated by a host-sent
zero-length packet. Enable only when the host side supports this
framing.
* - ``CFG_TUD_CDC_TX_OVERWRITABLE_IF_NOT_CONNECTED``
- ``1``
- Allows writes made before DTR connection to replace old queued data
rather than permanently filling the FIFO.
Use speed-dependent values from an example when the device can enumerate at
high speed. ``CFG_TUD_CDC_NOTIFY`` enables serial-state notifications.
The common data path is:
.. code-block:: c
void tud_cdc_rx_cb(uint8_t itf) {
uint8_t buf[64];
uint32_t count = tud_cdc_n_available(itf);
uint32_t room = tud_cdc_n_write_available(itf);
if (count > sizeof(buf)) count = sizeof(buf);
if (count > room) count = room;
count = tud_cdc_n_read(itf, buf, count);
if (count && tud_cdc_n_write(itf, buf, count) == count) {
tud_cdc_n_write_flush(itf);
}
}
Use ``tud_cdc_n_connected()`` when transmission should depend on DTR. A port
can be mounted while a terminal has not opened it. Handle line settings in
``tud_cdc_line_state_cb()`` and ``tud_cdc_line_coding_cb()`` if they affect the
physical UART; TinyUSB does not configure that UART for you.
.. list-table::
:header-rows: 1
:widths: 39 61
* - Device API or callback
- What it does
* - ``tud_cdc_n_connected()`` / ``tud_cdc_n_ready()``
- Tests DTR connection, or whether the port is connected and can accept
output now.
* - ``tud_cdc_n_available()`` / ``tud_cdc_n_read()``
- Reports and removes bytes received from the host.
* - ``tud_cdc_n_write_available()`` / ``tud_cdc_n_write()``
- Reports TX FIFO room and copies as many bytes as fit; preserve any
unwritten remainder.
* - ``tud_cdc_n_write_flush()``
- Starts transmission of buffered bytes without waiting for the FIFO to
fill.
* - ``tud_cdc_rx_cb()`` / ``tud_cdc_tx_complete_cb()``
- Announces newly buffered receive data or completion of a transmit
transfer.
* - ``tud_cdc_line_state_cb()`` / ``tud_cdc_line_coding_cb()``
- Reports host DTR/RTS and baud/data/parity/stop settings so a UART bridge
can apply them.
See :doc:`../../examples/device/cdc_dual_ports` for multiple ports and
:doc:`../../examples/device/cdc_msc` for a composite device.
Host
====
Set ``CFG_TUH_CDC`` to the required number of serial interfaces. Enable only
the adapter families needed by the product:
.. code-block:: c
#define CFG_TUH_CDC 1
#define CFG_TUH_CDC_FTDI 1
#define CFG_TUH_CDC_CP210X 1
#define CFG_TUH_CDC_CH34X 1
#define CFG_TUH_CDC_PL2303 1
The RX/TX software FIFO and endpoint buffers default to
``TUH_EPSIZE_BULK_MAX`` through ``CFG_TUH_CDC_RX_BUFSIZE``,
``CFG_TUH_CDC_TX_BUFSIZE``, ``CFG_TUH_CDC_RX_EPSIZE``, and
``CFG_TUH_CDC_TX_EPSIZE``. Increase FIFO sizes to tolerate application
latency; endpoint sizes normally stay at the host bulk maximum. Optional
``CFG_TUH_CDC_LINE_CODING_ON_ENUM`` and
``CFG_TUH_CDC_LINE_CONTROL_ON_ENUM`` values apply initial serial settings as
part of enumeration.
``tuh_cdc_mount_cb(idx)`` reports a ready interface. Read data in
``tuh_cdc_rx_cb(idx)`` using ``tuh_cdc_read_available()`` and
``tuh_cdc_read()``. Queue output with ``tuh_cdc_write()`` and call
``tuh_cdc_write_flush()`` when it should leave promptly.
Line-control functions such as ``tuh_cdc_set_baudrate()`` and
``tuh_cdc_set_line_coding()`` accept a completion callback. Their ``_sync``
forms block and should only be used where the host task can continue running.
Support varies by adapter family; in particular, the combined line-coding call
is not implemented for every non-CDC adapter.
.. list-table::
:header-rows: 1
:widths: 39 61
* - Host API or callback
- What it does
* - ``tuh_cdc_mounted()`` / ``tuh_cdc_itf_get_info()``
- Tests an interface index and returns its address, interface descriptor,
and serial-driver type.
* - ``tuh_cdc_read_available()`` / ``tuh_cdc_read()``
- Reports and removes bytes buffered from the serial device.
* - ``tuh_cdc_write()`` / ``tuh_cdc_write_flush()``
- Copies output into the class FIFO and starts a USB transfer.
* - ``tuh_cdc_set_control_line_state()`` /
``tuh_cdc_set_line_coding()``
- Queues DTR/RTS or baud/framing changes and calls the supplied completion
callback.
* - ``tuh_cdc_mount_cb()`` / ``tuh_cdc_umount_cb()``
- Creates or removes application state for a serial interface index.
* - ``tuh_cdc_rx_cb()`` / ``tuh_cdc_tx_complete_cb()``
- Announces buffered input or completion of queued class output.
The :doc:`../../examples/host/cdc_msc_hid` example shows enumeration, 115200
8N1 setup, and bidirectional I/O.
Practical notes
===============
* USB CDC transfers bytes, not UART timing. Baud rate and framing are host
requests that an application may honor, translate, or ignore.
* A write call can accept fewer bytes than requested. Preserve and retry the
remainder instead of silently dropping it.
* For interactive traffic, flush after a logical message. For throughput,
allow the FIFO to fill and flush less often.
Specifications used: *Communications Devices Class*, Revision 1.2 (Errata 1),
and *CDC PSTN Subclass*, Revision 1.2, which defines ACM.

View File

@ -0,0 +1,159 @@
********************
Using Device Classes
********************
A device class needs three matching pieces: a nonzero ``CFG_TUD_*`` instance
count, class descriptors in the configuration descriptor, and the required
application callbacks. Start from the nearest device example instead of
writing descriptors from scratch.
Setup checklist
===============
1. Enable the device stack and each class in ``tusb_config.h``. A class value
is normally the maximum number of simultaneous class instances, not a
boolean.
2. Add the matching ``TUD_*_DESCRIPTOR`` macro to the configuration descriptor
and include its ``TUD_*_DESC_LEN`` in the total length.
3. Assign unique interface numbers and endpoint addresses. Some functions use
more than one interface; for example, CDC ACM normally uses two.
4. Implement the descriptor and class callbacks used by the example.
5. Call ``tud_task()`` regularly, or run it in a dedicated RTOS task.
For example, one CDC ACM function starts with:
.. code-block:: c
// tusb_config.h
#define CFG_TUD_ENABLED 1
#define CFG_TUD_CDC 1
// One entry inside the configuration descriptor
TUD_CDC_DESCRIPTOR(ITF_NUM_CDC, 0, EPNUM_CDC_NOTIF, 8,
EPNUM_CDC_OUT, EPNUM_CDC_IN, 64),
See :doc:`../../integration` for stack initialization and the full descriptor
callback pattern.
Common configuration options
============================
These options apply before the class-specific settings described on the other
pages. Defaults come from ``src/tusb_option.h``.
.. list-table::
:header-rows: 1
:widths: 30 18 52
* - Option
- Default
- What it controls
* - ``CFG_TUD_ENABLED``
- Root-port mode
- Enables the device stack. Set it explicitly when the selected root-port
mode does not already select device operation.
* - ``CFG_TUD_MAX_SPEED``
- Root-port mode
- Highest speed for which the device stack and descriptors are built.
High-speed devices also need valid qualifier and other-speed
descriptors.
* - ``CFG_TUD_ENDPOINT0_SIZE``
- ``64`` bytes
- Control endpoint maximum packet size. It must match ``bMaxPacketSize0``
in the device descriptor and the controller's capability.
* - ``CFG_TUD_ENDPOINT0_BUFSIZE``
- Endpoint 0 size
- Staging space for control transfers. Increase it when a class control
request must hold more than one endpoint packet.
* - ``CFG_TUD_INTERFACE_MAX``
- ``16``
- Maximum total USB interfaces across the active configuration, including
every interface used by composite functions.
* - ``CFG_TUD_TASK_EVENTS_PER_RUN``
- ``16``
- Maximum events handled by one ``tud_task_ext()`` call. ``0`` removes
the limit; a smaller value reduces one-call latency at the cost of more
task invocations.
* - ``CFG_TUD_ENDPPOINT_MAX``
- Controller maximum
- Highest endpoint-number pool retained by the stack. Lowering it can
save RAM, but it must cover every configured endpoint number.
* - ``CFG_TUD_MEM_SECTION`` / ``CFG_TUD_MEM_ALIGN``
- Common USB settings / 4-byte alignment
- Places and aligns controller-facing buffers for DMA. Override these
when the device controller requires a particular RAM region or
alignment.
``CFG_TUD_ENDPPOINT_MAX`` contains the double ``P`` for compatibility; use the
spelling shown above.
Core API and callbacks
======================
.. list-table::
:header-rows: 1
:widths: 36 64
* - API or callback
- What it does
* - ``tusb_init()``
- Initializes a root port with an explicit role and speed. Call it before
the task function and check its boolean result.
* - ``tud_task()`` / ``tud_task_ext()``
- Dispatches bus, control, class, and completion events. The extended
form selects a wait timeout and states whether the call is from an ISR.
* - ``tud_connected()`` / ``tud_mounted()`` / ``tud_ready()``
- Reports progressively stronger states: bus activity, configured by the
host, and configured plus not suspended. Use ``tud_ready()`` before
initiating normal traffic.
* - ``tud_suspended()`` / ``tud_remote_wakeup()``
- Tests suspend state and requests remote wakeup. Wakeup succeeds only
when the host enabled it and the device is suspended.
* - ``tud_disconnect()`` / ``tud_connect()``
- Controls the USB pull-up to force a logical detach or attach. These
return ``false`` when the controller cannot provide the operation.
* - ``tud_mount_cb()`` / ``tud_umount_cb()``
- Announces configuration and removal. Initialize or discard
configuration-dependent application state here.
* - ``tud_suspend_cb()`` / ``tud_resume_cb()``
- Announces bus power-state changes. The suspend callback also reports
whether remote wakeup was enabled by the host.
* - ``tud_descriptor_*_cb()``
- Supplies device, configuration, string, BOS, and high-speed companion
descriptors on request. Returned storage must remain valid through the
control transfer.
* - ``tud_control_xfer()`` / ``tud_control_status()``
- Completes the data/status stages of an application-handled control
request. The data length is truncated to the request's ``wLength``.
Interfaces and instances
========================
Single-instance helpers such as ``tud_cdc_read()`` operate on instance zero.
Their ``_n_`` forms, such as ``tud_cdc_n_read(itf, ...)``, select a class
instance when the corresponding ``CFG_TUD_*`` value is greater than one.
Class instance numbers are not necessarily USB ``bInterfaceNumber`` values.
Endpoint direction is always described from the USB device's point of view:
* IN sends data from the device to the host.
* OUT receives data from the host at the device.
Buffers and callbacks
=====================
Class callbacks run when ``tud_task()`` processes an event, unless a header
explicitly labels a helper as ISR-safe. Keep callbacks short and move lengthy
work to an application task.
Buffered write APIs return the number of bytes accepted, which can be shorter
than requested. Check the return value and use the class's flush function when
latency matters. Size endpoint and software buffers for the active bus speed;
copy the full-speed/high-speed pattern from an example that supports both.
Before testing on hardware, verify that:
* the configuration descriptor's total length and interface count are exact;
* every endpoint address is unique within the configuration;
* descriptor packet sizes agree with the relevant ``CFG_TUD_*_EPSIZE`` values;
* callbacks never retain a pointer whose documented lifetime has ended.

View File

@ -0,0 +1,92 @@
***
DFU
***
Role: device only. Device Firmware Upgrade (DFU) has two distinct states:
runtime mode, where normal firmware advertises that it can reboot into an
updater, and DFU mode, where firmware images are transferred.
Runtime mode
============
Enable ``CFG_TUD_DFU_RUNTIME`` and add ``TUD_DFU_RT_DESCRIPTOR``. When the
host sends DFU_DETACH, TinyUSB calls ``tud_dfu_runtime_reboot_to_dfu_cb()``.
Store any required boot flag, safely stop the application, and reset into the
DFU image from that callback.
The descriptor's detach attributes must describe the actual behavior. In
particular, do not set ``bitWillDetach`` unless the callback will initiate the
detach/reset without a USB reset from the host.
See :doc:`../../examples/device/dfu_runtime`.
.. list-table::
:header-rows: 1
:widths: 38 62
* - Descriptor attribute
- Meaning
* - ``DFU_ATTR_CAN_DOWNLOAD``
- Host may send firmware to the device.
* - ``DFU_ATTR_CAN_UPLOAD``
- Host may read firmware from the device; omit it when disclosure is not
intended.
* - ``DFU_ATTR_MANIFESTATION_TOLERANT``
- Device can remain in DFU mode after manifestation without reset.
* - ``DFU_ATTR_WILL_DETACH``
- Device performs its own detach/reset after DFU_DETACH. Clear it when
the host must issue the USB reset.
DFU mode
========
Enable ``CFG_TUD_DFU`` and set ``CFG_TUD_DFU_XFER_BUFSIZE`` to exactly the
``wTransferSize`` passed to ``TUD_DFU_DESCRIPTOR``. Alternate settings can
represent partitions or targets; their string descriptors should clearly name
the target presented by each ``alt`` value.
.. list-table::
:header-rows: 1
:widths: 38 62
* - Callback/API
- Application responsibility
* - ``tud_dfu_download_cb()``
- Program one downloaded block, then call
``tud_dfu_finish_flashing()`` when the operation completes.
* - ``tud_dfu_upload_cb()``
- Fill the buffer with at most the requested number of bytes and return
the count.
* - ``tud_dfu_manifest_cb()``
- Validate/finalize the image, then call ``tud_dfu_finish_flashing()``.
* - ``tud_dfu_get_timeout_cb()``
- Return an honest poll timeout for the current target and state.
* - ``tud_dfu_abort_cb()``
- Cancel pending storage work and return the target to a safe state.
* - ``tud_dfu_detach_cb()``
- Handles DFU_DETACH while in DFU mode; normally records state and resets
or returns to runtime firmware according to the descriptor attributes.
* - ``tud_dfu_finish_flashing()``
- Completes a previously started download or manifestation. An error
status moves the state machine into the DFU error state.
Storage can be asynchronous: retain the operation state, return from the
callback, and call ``tud_dfu_finish_flashing(status)`` later. Pass
``DFU_STATUS_OK`` only after the data is durably written or manifestation is
complete.
The :doc:`../../examples/device/dfu` example exposes two alternate settings
and can be exercised with ``dfu-util``.
Production safety
=================
Treat all DFU fields and image bytes as untrusted. Bounds-check ``alt``, block
number, offset, and length before accessing storage. A production updater
should authenticate the complete image, reject rollback when required, avoid
overwriting its recovery path, and remain bootable after loss of power at any
point. TinyUSB implements the USB transport and DFU state machine; it does not
provide those product-specific security guarantees.
Specification used: *USB Device Class Specification for Device Firmware
Upgrade*, Version 1.1.

View File

@ -0,0 +1,168 @@
***
HID
***
Roles: device and host. Human Interface Device (HID) transfers input, output,
and feature reports described by a compact HID report descriptor.
Device
======
Enable ``CFG_TUD_HID`` for the required number of HID interfaces and set
``CFG_TUD_HID_EP_BUFSIZE`` to the largest report transferred on an interrupt
endpoint. Use ``TUD_HID_DESCRIPTOR`` for IN-only HID or
``TUD_HID_INOUT_DESCRIPTOR`` when an interrupt OUT endpoint is required.
``CFG_TUD_HID_EP_BUFSIZE`` defaults to 64 bytes and allocates one endpoint
buffer per enabled HID instance. It must include the report ID byte when the
report descriptor uses IDs. Increasing it permits longer reports but consumes
static RAM; it does not change the report descriptor automatically.
Define a report descriptor and return it from
``tud_hid_descriptor_report_cb()``. TinyUSB provides templates including
``TUD_HID_REPORT_DESC_KEYBOARD()``, ``TUD_HID_REPORT_DESC_MOUSE()``, and
``TUD_HID_REPORT_DESC_GENERIC_INOUT()``. When several report types share one
interface, give each a distinct ``HID_REPORT_ID()`` and include that ID in API
calls and report handling.
Send only when the interface is ready:
.. code-block:: c
if (tud_hid_ready()) {
tud_hid_keyboard_report(REPORT_ID_KEYBOARD, modifier, keycodes);
}
Use ``tud_hid_report()`` for a custom layout. Handle host-to-device output or
feature reports in ``tud_hid_set_report_cb()`` and provide requested input or
feature data in ``tud_hid_get_report_cb()``. The bytes and lengths must match
the report descriptor exactly.
.. list-table::
:header-rows: 1
:widths: 40 60
* - Device API or callback
- What it does
* - ``tud_hid_n_ready()``
- Tests whether the interrupt IN endpoint for an instance can accept a
report.
* - ``tud_hid_n_report()``
- Copies and queues a custom input report. ``false`` means it was not
queued; the caller may reuse its source buffer after the call returns.
* - ``tud_hid_n_keyboard_report()`` /
``tud_hid_n_mouse_report()`` /
``tud_hid_n_gamepad_report()``
- Builds and queues a standard TinyUSB report structure. Its descriptor
template must match the chosen helper.
* - ``tud_hid_descriptor_report_cb()``
- Returns the report descriptor for an instance. The returned storage
must remain valid.
* - ``tud_hid_get_report_cb()``
- Fills a control GET_REPORT response and returns its byte count. Returning
zero stalls the request.
* - ``tud_hid_set_report_cb()``
- Receives an output or feature report from either the control endpoint or
interrupt OUT endpoint.
* - ``tud_hid_set_protocol_cb()`` / ``tud_hid_set_idle_cb()``
- Applies host boot/report protocol and idle-rate requests. HID idle rate
units are 4 ms.
* - ``tud_hid_report_complete_cb()`` /
``tud_hid_report_failed_cb()``
- Announces that the internal endpoint buffer is reusable, or reports the
number of bytes transferred before failure.
For keyboards and buttons, send a release report as well as the press report;
otherwise the host can retain a stuck key. The
:doc:`../../examples/device/hid_composite` and
:doc:`../../examples/device/hid_generic_inout` examples show both patterns.
Host
====
Set ``CFG_TUH_HID`` to the maximum simultaneous HID interfaces, not merely the
number of physical devices. A keyboard with media controls or a composite
controller can expose several interfaces. Size
``CFG_TUH_HID_EPIN_BUFSIZE`` and ``CFG_TUH_HID_EPOUT_BUFSIZE`` for the largest
reports the application accepts.
.. list-table::
:header-rows: 1
:widths: 39 17 44
* - Option
- Default
- What it controls
* - ``CFG_TUH_HID_EPIN_BUFSIZE``
- ``64`` bytes
- Largest interrupt IN report that can be received per HID instance.
* - ``CFG_TUH_HID_EPOUT_BUFSIZE``
- ``64`` bytes
- Largest interrupt OUT report that can be sent per HID instance.
* - ``CFG_TUH_HID_SET_PROTOCOL_ON_ENUM``
- ``1``
- Sends SET_PROTOCOL during enumeration for boot-capable interfaces.
Set it to ``0`` if the application will select protocol later.
``tuh_hid_mount_cb()`` supplies ``dev_addr``, interface ``idx``, and the report
descriptor. Parse and retain the information needed to decode later reports,
then queue the first receive:
.. code-block:: c
void tuh_hid_mount_cb(uint8_t dev_addr, uint8_t idx,
uint8_t const *desc, uint16_t desc_len) {
parse_report_descriptor(desc, desc_len);
tuh_hid_receive_report(dev_addr, idx);
}
void tuh_hid_report_received_cb(uint8_t dev_addr, uint8_t idx,
uint8_t const *report, uint16_t len) {
process_report(report, len);
tuh_hid_receive_report(dev_addr, idx); // Re-arm interrupt IN.
}
If a report descriptor is larger than ``CFG_TUH_ENUMERATION_BUFSIZE``, the
mount callback can receive ``desc == NULL`` and ``desc_len == 0``. Increase
the enumeration buffer or handle that case without dereferencing the pointer.
Use ``tuh_hid_send_report()`` for an interrupt OUT report and
``tuh_hid_get_report()``/``tuh_hid_set_report()`` for control transfers. Boot
keyboards and mice can use boot protocol; all other devices require report
protocol and parsing of their descriptor.
.. list-table::
:header-rows: 1
:widths: 40 60
* - Host API or callback
- What it does
* - ``tuh_hid_mounted()`` / ``tuh_hid_itf_get_info()``
- Tests a device/interface pair and retrieves its cached interface
descriptor information.
* - ``tuh_hid_interface_protocol()`` / ``tuh_hid_get_protocol()``
- Distinguishes keyboard/mouse/none interface protocol from the active
boot/report transfer protocol.
* - ``tuh_hid_receive_ready()`` / ``tuh_hid_receive_report()``
- Tests and arms one interrupt IN transfer. Re-arm it after every receive
callback for continuous input.
* - ``tuh_hid_send_ready()`` / ``tuh_hid_send_report()``
- Tests and queues one interrupt OUT report. The send callback releases
the internal endpoint buffer; the source is copied before return.
* - ``tuh_hid_get_report()`` / ``tuh_hid_set_report()``
- Starts a control endpoint report request. Completion callbacks report
zero length on a stall or transfer error; keep the caller's report
buffer valid until that callback.
* - ``tuh_hid_set_protocol()``
- Requests boot or report protocol on boot-capable interfaces; completion
is reported asynchronously.
* - ``tuh_hid_mount_cb()`` / ``tuh_hid_umount_cb()``
- Supplies the report descriptor at mount and announces when the interface
index is no longer valid.
See :doc:`../../examples/host/cdc_msc_hid` for keyboard/mouse handling and
:doc:`../../examples/host/hid_controller` for controller input and output.
Specification used: *Device Class Definition for Human Interface Devices
(HID)*, Version 1.11. HID Usage Tables define the individual usage pages and
codes used inside report descriptors.

View File

@ -0,0 +1,142 @@
******************
Using Host Classes
******************
TinyUSB provides application-level host drivers for CDC serial, HID, MIDI 1.0,
MIDI 2.0, and Mass Storage. A host application is asynchronous: a mount
callback reports a ready interface, I/O is queued, and completion or receive
callbacks advance the application state.
Setup checklist
===============
1. Enable ``CFG_TUH_ENABLED`` and set each ``CFG_TUH_*`` pool size in
``tusb_config.h``. HID and MIDI values count interfaces, so allow for more
than one interface per physical device.
2. Set ``CFG_TUH_DEVICE_MAX`` for the number of attached devices and enable
``CFG_TUH_HUB`` if hubs are required.
3. Initialize a host-capable root port and provide VBUS as required by the
board.
4. Call ``tuh_task()`` continuously, or run it in a dedicated RTOS task.
5. Start class I/O from its mount callback and requeue receive transfers where
the class guide requires it.
Typical configuration:
.. code-block:: c
#define CFG_TUH_ENABLED 1
#define CFG_TUH_DEVICE_MAX 4
#define CFG_TUH_HUB 1
#define CFG_TUH_CDC 1
#define CFG_TUH_HID (3 * CFG_TUH_DEVICE_MAX)
#define CFG_TUH_MSC 1
Common configuration options
============================
.. list-table::
:header-rows: 1
:widths: 30 18 52
* - Option
- Default
- What it controls
* - ``CFG_TUH_ENABLED``
- Root-port mode
- Enables the host stack. The board must also supply VBUS and a
host-capable controller/PHY.
* - ``CFG_TUH_MAX_SPEED``
- Root-port mode
- Highest bus speed supported by the host build. It does not make a
full-speed-only controller operate at high speed.
* - ``CFG_TUH_DEVICE_MAX``
- ``1``
- Number of USB device addresses tracked simultaneously, including hubs.
* - ``CFG_TUH_HUB``
- ``0``
- Number of hubs supported simultaneously. Hub ports can require higher
device and class pool counts.
* - ``CFG_TUH_ENUMERATION_BUFSIZE``
- ``256`` bytes
- Temporary descriptor buffer used during enumeration. Increase it for
long configuration or HID report descriptors; this consumes static RAM.
* - ``CFG_TUH_TASK_EVENTS_PER_RUN``
- ``16``
- Maximum events handled by one ``tuh_task_ext()`` call. ``0`` is
unlimited.
* - ``CFG_TUH_MEM_SECTION`` / ``CFG_TUH_MEM_ALIGN``
- Common USB settings / 4-byte alignment
- Places and aligns host-controller buffers for DMA-accessible RAM.
* - ``CFG_TUSB_OS``
- ``OPT_OS_NONE``
- Selects TinyUSB's synchronization backend. Set the matching OS option
when host APIs and ``tuh_task()`` run in different RTOS tasks.
Each ``CFG_TUH_<CLASS>`` value sizes a simultaneous interface pool. It is not
a VID/PID allowlist and, for composite devices, may need to exceed
``CFG_TUH_DEVICE_MAX``.
Core API and callbacks
======================
.. list-table::
:header-rows: 1
:widths: 36 64
* - API or callback
- What it does
* - ``tusb_init()``
- Initializes a root port with host role and selected speed. Call it
after board/VBUS setup and check its boolean result.
* - ``tuh_task()`` / ``tuh_task_ext()``
- Advances enumeration and transfers and dispatches callbacks. The
extended form controls wait timeout and ISR context.
* - ``tuh_mount_cb()`` / ``tuh_umount_cb()``
- Announces a configured device or detachment. Class mount callbacks
provide the interface-specific indices used for I/O.
* - ``tuh_mounted()`` / ``tuh_ready()`` / ``tuh_connected()``
- Tests whether an address is configured/ready or has merely shown bus
activity. Do not start class I/O based only on ``tuh_connected()``.
* - ``tuh_vid_pid_get()`` / ``tuh_speed_get()`` / ``tuh_bus_info_get()``
- Returns cached identity, speed, and hub/root-port location for an
enumerated address.
* - ``tuh_descriptor_get_device_local()``
- Copies the cached device descriptor without issuing a USB transfer.
Other ``tuh_descriptor_get_*()`` calls queue or perform control
transfers to fetch descriptors.
* - ``tuh_control_xfer()``
- Submits a control transfer described by ``tuh_xfer_t``. A non-null
completion callback makes it asynchronous; a null callback blocks.
* - ``tuh_edpt_xfer()``
- Submits a bulk or interrupt endpoint transfer. Application class
drivers normally use their class-specific wrappers instead.
Synchronous host control calls are forbidden from the host task when
``CFG_TUSB_OS_HAS_SCHEDULER`` is true: that task is needed to make the same
transfer complete. Prefer callbacks for portable application code.
Addresses and indices
=====================
``dev_addr`` identifies an enumerated USB device. Classes that may expose
multiple interfaces also use a class ``idx``. Preserve both values supplied by
the mount callback and use the same pair for later API calls. An index can be
reused after unmount, so discard associated application state in the unmount
callback.
Transfer lifetime
=================
Unless an API explicitly documents a copy, keep a transfer buffer valid and
unchanged until its completion callback. Buffers used directly by a host
controller may also require alignment, cache maintenance, or placement in
DMA-accessible memory; follow the board's HCD requirements.
Do not block ``tuh_task()`` while waiting for a callback that only it can
dispatch. Prefer the asynchronous APIs. Where a class provides a synchronous
helper, use it only from a context in which the host task can still run.
Start with :doc:`../../examples/host/cdc_msc_hid` for CDC, HID, and MSC,
:doc:`../../examples/host/midi_rx` for MIDI 1.0, or
:doc:`../../examples/host/midi2_host` for MIDI 2.0.

View File

@ -0,0 +1,96 @@
*************
Class Drivers
*************
Class drivers implement USB protocols such as CDC serial, HID, mass storage,
and MIDI. Enable only the classes your product uses: device APIs start with
``tud_`` and host APIs start with ``tuh_``.
Start with :doc:`device` or :doc:`host`, then use the class page for its
configuration, data flow, callbacks, and examples. The API lists below focus
on the calls normally needed by an application; the public headers remain the
complete API reference.
Support matrix
==============
.. list-table::
:header-rows: 1
:widths: 24 18 18 40
* - Class
- Device
- Host
- Guide
* - Audio 1.0/2.0
- Yes
- No
- :doc:`audio`
* - Bluetooth HCI
- Yes
- No
- :doc:`bluetooth`
* - CDC serial
- Yes
- Yes
- :doc:`cdc`
* - DFU 1.1
- Yes
- No
- :doc:`dfu`
* - HID 1.11
- Yes
- Yes
- :doc:`hid`
* - MIDI 1.0/2.0
- Yes
- Yes
- :doc:`midi`
* - Mass Storage (BOT)
- Yes
- Yes
- :doc:`msc`
* - Media Transfer (MTP)
- Yes
- No
- :doc:`mtp`
* - Network (ECM/RNDIS/NCM)
- Yes
- No
- :doc:`network`
* - Printer
- Yes
- No
- :doc:`printer`
* - Test and Measurement (USBTMC)
- Yes
- No
- :doc:`usbtmc`
* - Vendor-specific
- Yes
- Custom driver
- :doc:`vendor`
* - Video 1.5
- Yes
- No
- :doc:`video`
.. toctree::
:maxdepth: 1
:hidden:
device
host
audio
bluetooth
cdc
dfu
hid
midi
msc
mtp
network
printer
usbtmc
vendor
video

View File

@ -0,0 +1,214 @@
****
MIDI
****
Roles: device and host. TinyUSB has separate drivers for USB-MIDI 1.0 event
packets and USB-MIDI 2.0 Universal MIDI Packets (UMP). Enable the driver that
matches the data model used by the application.
MIDI 1.0 device
===============
Enable ``CFG_TUD_MIDI``, tune ``CFG_TUD_MIDI_RX_BUFSIZE`` and
``CFG_TUD_MIDI_TX_BUFSIZE`` if needed, and add ``TUD_MIDI_DESCRIPTOR``.
.. list-table::
:header-rows: 1
:widths: 38 18 44
* - Option
- Default
- What it controls
* - ``CFG_TUD_MIDI_RX_BUFSIZE`` / ``CFG_TUD_MIDI_TX_BUFSIZE``
- Required when enabled
- Software FIFO bytes per interface. Define both, normally at least as
large as the matching endpoint buffer.
* - ``CFG_TUD_MIDI_RX_EPSIZE`` / ``CFG_TUD_MIDI_TX_EPSIZE``
- Device bulk maximum
- Endpoint transfer buffer and descriptor packet size.
Use ``tud_midi_stream_read()``/``tud_midi_stream_write()`` for MIDI byte
streams on the first interface and cable. Use ``tud_midi_n_*`` to select an
interface or cable, and the ``*_packet_*`` APIs when the application already
works with 4-byte USB-MIDI event packets. Drain received data in
``tud_midi_rx_cb()``.
.. list-table::
:header-rows: 1
:widths: 42 58
* - API or callback
- What it does
* - ``tud_midi_n_available()`` /
``tud_midi_n_stream_read()``
- Reports and reads MIDI bytes for one interface and virtual cable.
* - ``tud_midi_n_demux_stream_read()``
- Reads bytes from one cable at a time and returns that cable number. Do
not mix it with the legacy stream reader on the same interface.
* - ``tud_midi_n_stream_write()``
- Packetizes a MIDI byte stream and returns the number of source bytes
accepted.
* - ``tud_midi_n_packet_read_n()`` /
``tud_midi_n_packet_write_n()``
- Reads or writes complete 4-byte USB-MIDI event packets and returns a
packet count.
* - ``tud_midi_rx_cb()``
- Announces received data. Drain the FIFO so later OUT transfers have
room.
See :doc:`../../examples/device/midi_test`.
MIDI 1.0 host
=============
Set ``CFG_TUH_MIDI`` to the number of simultaneous MIDI streaming interfaces.
The following options size each instance:
.. list-table::
:header-rows: 1
:widths: 38 18 44
* - Option
- Default
- What it controls
* - ``CFG_TUH_MIDI_RX_BUFSIZE`` / ``CFG_TUH_MIDI_TX_BUFSIZE``
- Host bulk maximum
- Software FIFO capacity for received and queued event packets.
* - ``CFG_TUH_MIDI_EP_BUFSIZE``
- Host bulk maximum
- Endpoint transfer buffer size.
* - ``CFG_TUH_MIDI_STREAM_API``
- ``1``
- Enables byte-stream packetization/depacketization. Disable it to save
code size when the application uses only raw 4-byte event packets.
``tuh_midi_descriptor_cb()`` reports descriptor information before the
interface is ready; begin I/O in ``tuh_midi_mount_cb()``. Receive data in
``tuh_midi_rx_cb()`` with ``tuh_midi_stream_read()`` or
``tuh_midi_packet_read_n()``. Writes remain buffered until an endpoint packet
is ready or ``tuh_midi_write_flush()`` is called.
The RX and TX cable counts can differ. Query them with
``tuh_midi_get_rx_cable_count()`` and ``tuh_midi_get_tx_cable_count()`` before
selecting a cable. See :doc:`../../examples/host/midi_rx`.
``tuh_midi_read_available()`` reports raw FIFO bytes, while
``tuh_midi_stream_read()`` returns decoded MIDI stream bytes and a cable
number. ``tuh_midi_packet_read_n()`` keeps the USB event-packet format.
``tuh_midi_write_flush()`` starts a short buffered transfer and returns the
number of bytes submitted. Mount/unmount callbacks define the lifetime of the
``idx``; RX/TX callbacks announce new input and newly available TX space.
MIDI 2.0 device
===============
Enable ``CFG_TUD_MIDI2`` and add ``TUD_MIDI2_DESCRIPTOR``. The descriptor
contains alternate setting 0 for USB-MIDI 1.0 fallback and alternate setting 1
for UMP, as required by the MIDI 2.0 class specification.
.. code-block:: c
#define CFG_TUD_MIDI2 1
#define CFG_TUD_MIDI2_RX_BUFSIZE 256
#define CFG_TUD_MIDI2_TX_BUFSIZE 256
.. list-table::
:header-rows: 1
:widths: 38 18 44
* - Option
- Default
- What it controls
* - ``CFG_TUD_MIDI2_RX_EPSIZE`` / ``CFG_TUD_MIDI2_TX_EPSIZE``
- Device bulk maximum
- Endpoint transfer buffers and descriptor packet sizes.
* - ``CFG_TUD_MIDI2_RX_BUFSIZE`` / ``CFG_TUD_MIDI2_TX_BUFSIZE``
- Matching endpoint size
- UMP FIFO bytes per interface.
* - ``CFG_TUD_MIDI2_NUM_GROUPS``
- ``1``
- Number of UMP groups exposed by the default Group Terminal Block.
* - ``CFG_TUD_MIDI2_EP_NAME`` / ``CFG_TUD_MIDI2_PRODUCT_ID``
- TinyUSB strings
- Default endpoint name and product identifier returned by UMP discovery.
* - ``CFG_TUD_MIDI2_BLOCK_STRIDX``
- ``0``
- Optional string-descriptor index for the Function Block; zero means no
string.
On alternate setting 1, read and write arrays of 32-bit words with
``tud_midi2_ump_read()`` and ``tud_midi2_ump_write()``. On alternate setting
0, use ``tud_midi2_packet_read()`` and ``tud_midi2_packet_write()`` for 4-byte
USB-MIDI 1.0 event packets. Query ``tud_midi2_alt_setting()`` and
``tud_midi2_protocol()`` when choosing the format to send.
Drain the RX FIFO completely in the callback:
.. code-block:: c
void tud_midi2_rx_cb(uint8_t itf) {
uint32_t words[16];
uint32_t count;
while ((count = tud_midi2_n_ump_read(itf, words, 16)) != 0) {
process_ump(words, count); // Track message size from each MT field.
}
}
``tud_midi2_ump_read()`` returns available words, which can end at the caller's
``max_words`` limit. Parse UMP message boundaries from the Message Type field
and preserve an incomplete message between reads when using a small buffer.
The driver handles standard UMP Stream discovery and protocol negotiation.
Override ``tud_midi2_gtb_desc_cb()`` to describe a custom Group Terminal Block
topology and ``tud_midi2_fb_name_cb()`` for Function Block names. Use
``tud_midi2_stream_msg_cb()`` only when the application must override a built-in
Stream response.
``tud_midi2_n_available()`` returns queued bytes, whereas
``tud_midi2_n_ump_read()`` and ``tud_midi2_n_ump_write()`` return 32-bit word
counts. The packet APIs return counts of 4-byte MIDI 1.0 event packets.
``tud_midi2_set_itf_cb()`` announces the active alternate setting so the
application can switch its parser and producer.
See :doc:`../../examples/device/midi2_device` for alternate-setting and
protocol fallback.
MIDI 2.0 host
=============
Set ``CFG_TUH_MIDI2`` to the required interface count. The host driver detects
both alternate settings, selects the highest available protocol, and completes
``SET_INTERFACE`` before reporting the mount.
``CFG_TUH_MIDI2_RX_BUFSIZE`` and ``CFG_TUH_MIDI2_TX_BUFSIZE`` default to the
host bulk maximum and allocate FIFO storage per instance. Increase them when
the application can be delayed for several USB transfers; keep UMP data
32-bit aligned in application buffers.
Callback order is important:
.. code-block:: text
descriptor callback -> protocol/alternate selection -> mount callback
-> RX/TX callbacks -> unmount callback
``tuh_midi2_descriptor_cb()`` is informational; the interface is not yet ready.
Start I/O only after ``tuh_midi2_mount_cb()``. In ``tuh_midi2_rx_cb()``, call
``tuh_midi2_ump_read()`` in a loop until it returns zero. Queue output with
``tuh_midi2_ump_write()`` and use ``tuh_midi2_write_flush()`` when latency
matters.
Use ``tuh_midi2_get_protocol_version()`` and
``tuh_midi2_get_alt_setting_active()`` to inspect the selected transport. The
:doc:`../../examples/host/midi2_host` example parses the UMP Message Type field
to determine whether each message occupies 1, 2, 3, or 4 words.
``tuh_midi2_ump_write()`` returns the number of words accepted and
``tuh_midi2_write_flush()`` returns the number of bytes submitted. Preserve
unaccepted words and retry after ``tuh_midi2_tx_cb()``. Treat the data supplied
to ``tuh_midi2_descriptor_cb()`` as informational only; the interface becomes
usable at ``tuh_midi2_mount_cb()`` and invalid at ``tuh_midi2_umount_cb()``.
Specification used: *USB Device Class Definition for MIDI Devices*, Release
2.0. It defines the MIDI 1.0-compatible alternate setting, the native UMP
alternate setting, Group Terminal Blocks, and discovery behavior.

View File

@ -0,0 +1,125 @@
************
Mass Storage
************
Roles: device and host. TinyUSB implements the USB Mass Storage Bulk-Only
Transport (BOT) and common SCSI commands. It exposes logical blocks; a
filesystem such as FatFs is a separate application layer.
Device
======
Enable ``CFG_TUD_MSC`` and set ``CFG_TUD_MSC_EP_BUFSIZE``. Add one
``TUD_MSC_DESCRIPTOR`` for each Mass Storage function. Multiple logical units
(LUNs) normally share one function and are selected through the ``lun``
callback argument.
``CFG_TUD_MSC_EP_BUFSIZE`` has no default and is required when MSC is enabled.
It is the class transfer-buffer size per instance, not the media capacity.
Using at least one logical block is efficient; larger values improve large
transfers at the cost of static RAM. Keep it below 65536 bytes and consistent
with controller/DMA constraints.
The minimum storage callbacks are:
.. list-table::
:header-rows: 1
:widths: 38 62
* - Callback
- Purpose
* - ``tud_msc_inquiry_cb()``
- Return fixed-width vendor, product, and revision fields.
* - ``tud_msc_test_unit_ready_cb()``
- Report whether media is present and usable.
* - ``tud_msc_capacity_cb()``
- Return the logical block count and block size.
* - ``tud_msc_read10_cb()``
- Read ``bufsize`` bytes from ``lba`` plus ``offset``.
* - ``tud_msc_write10_cb()``
- Write ``bufsize`` bytes to ``lba`` plus ``offset``.
* - ``tud_msc_scsi_cb()``
- Handle commands not implemented by the class driver.
* - ``tud_msc_get_maxlun_cb()``
- Returns the highest valid zero-based LUN number; implement it for
multiple LUNs.
* - ``tud_msc_is_writable_cb()``
- Reports write protection before WRITE10.
* - ``tud_msc_start_stop_cb()``
- Handles load/eject and start/stop requests, including safe-eject policy.
Read and write callbacks may cover only part of a logical block. Honor both
``lba`` and ``offset`` instead of assuming one callback per block. On failure,
set useful sense data with ``tud_msc_set_sense()`` and return
``TUD_MSC_RET_ERROR``.
For temporarily busy media, return ``TUD_MSC_RET_BUSY``; TinyUSB will invoke
the callback again with the same parameters. For true background I/O, return
``TUD_MSC_RET_ASYNC`` and later call ``tud_msc_async_io_done()`` with the byte
count or error. Do not report a write complete until data has reached the
durability level promised by the product. ``tud_msc_write10_complete_cb()`` is
a useful place to flush a cache.
See :doc:`../../examples/device/cdc_msc` for a RAM disk and
:doc:`../../examples/device/msc_dual_lun` for multiple LUNs.
Host
====
Set ``CFG_TUH_MSC`` to the maximum simultaneous Mass Storage devices and
``CFG_TUH_MSC_MAXLUN`` to the LUN limit per device. After
``tuh_msc_mount_cb(dev_addr)``, query cached geometry with
``tuh_msc_get_block_count()`` and ``tuh_msc_get_block_size()``.
``CFG_TUH_MSC_MAXLUN`` defaults to 4 and allocates cached state per possible
LUN for every enabled MSC device. Set it to the maximum needed by the product,
not necessarily the maximum value a device claims.
``tuh_msc_read10()`` and ``tuh_msc_write10()`` are asynchronous. Keep the
buffer valid, correctly aligned, cache coherent, and accessible to the USB
controller until the ``tuh_msc_complete_cb_t`` callback runs. Check
``tuh_msc_ready()`` before starting another command and inspect the completion
callback's transfer result and command status.
.. list-table::
:header-rows: 1
:widths: 40 60
* - Host API or callback
- What it does
* - ``tuh_msc_mounted()`` / ``tuh_msc_ready()``
- Tests whether the MSC device is present or currently able to accept a
new SCSI command.
* - ``tuh_msc_get_maxlun()`` /
``tuh_msc_get_block_count()`` /
``tuh_msc_get_block_size()``
- Returns cached LUN range and geometry populated during enumeration.
* - ``tuh_msc_read10()`` / ``tuh_msc_write10()``
- Queues an integral number of logical blocks and completes through the
supplied callback.
* - ``tuh_msc_inquiry()`` / ``tuh_msc_request_sense()``
- Queues standard SCSI identification or detailed-error requests into an
application-owned response buffer.
* - ``tuh_msc_scsi_command()``
- Queues a caller-built command block wrapper for commands without a
convenience API.
* - ``tuh_msc_mount_cb()`` / ``tuh_msc_umount_cb()``
- Announces cached capacity availability or invalidates all filesystem and
media state for the address.
TinyUSB does not mount a filesystem automatically. Connect the sector API to
your filesystem's disk I/O layer and invalidate that state in
``tuh_msc_umount_cb()``. The :doc:`../../examples/host/msc_file_explorer`
example demonstrates this with FatFs.
Practical notes
===============
* Hosts cache filesystem data. Physical removal or firmware reset without an
eject/unmount can lose data even when USB transfers succeeded.
* Use the medium-present and write-protect responses consistently; mismatched
capacity or readiness information causes repeated SCSI recovery traffic.
* Validate every LUN and block range before calculating a storage address.
Specification used: *USB Mass Storage Class Bulk-Only Transport*, Revision
1.0. Command formats and sense data come from the applicable SCSI command set.

View File

@ -0,0 +1,112 @@
***
MTP
***
Role: device only. Media Transfer Protocol (MTP) presents objects and object
metadata rather than a host-mounted block device. It is a better fit than MSC
when device firmware and the host must access managed files concurrently.
Configuration
=============
Set ``CFG_TUD_MTP`` to 1 and add ``TUD_MTP_DESCRIPTOR``. Configure the endpoint
and control buffers, then advertise only operations, events, properties, and
formats that the application actually implements:
.. code-block:: c
#define CFG_TUD_MTP 1
#define CFG_TUD_MTP_EP_BUFSIZE 512
#define CFG_TUD_MTP_EP_CONTROL_BUFSIZE 16
#define CFG_TUD_MTP_DEVICEINFO_SUPPORTED_OPERATIONS \
MTP_OP_GET_DEVICE_INFO, MTP_OP_OPEN_SESSION, MTP_OP_CLOSE_SESSION
.. list-table::
:header-rows: 1
:widths: 45 15 40
* - Option
- Default
- What it controls
* - ``CFG_TUD_MTP_EP_BUFSIZE``
- Required
- Shared bulk data buffer and maximum data chunk. Larger values improve
throughput but consume static RAM.
* - ``CFG_TUD_MTP_EP_CONTROL_BUFSIZE``
- Required
- Staging buffer for MTP class control requests and responses.
* - ``CFG_TUD_MTP_DEVICEINFO_EXTENSIONS``
- Required
- MTP extension string returned by GetDeviceInfo; use an empty string when
no extension is implemented.
* - ``CFG_TUD_MTP_DEVICEINFO_SUPPORTED_OPERATIONS``
- Required
- Operation codes the host is told it may issue.
* - ``CFG_TUD_MTP_DEVICEINFO_SUPPORTED_EVENTS``
- Required
- Event codes the device may send on the interrupt endpoint.
* - ``CFG_TUD_MTP_DEVICEINFO_SUPPORTED_DEVICE_PROPERTIES``
- Required
- Device property codes supported by the application.
* - ``CFG_TUD_MTP_DEVICEINFO_CAPTURE_FORMATS`` /
``CFG_TUD_MTP_DEVICEINFO_PLAYBACK_FORMATS``
- Required
- Object formats the device can create or expose for playback.
The other ``CFG_TUD_MTP_DEVICEINFO_*`` lists describe supported events, device
properties, capture formats, and playback formats. These lists form the
GetDeviceInfo response and are a contract with the host.
Application flow
================
.. list-table::
:header-rows: 1
:widths: 42 58
* - API or callback
- What it does
* - ``tud_mtp_mounted()``
- Tests whether all three MTP endpoints are open.
* - ``tud_mtp_command_received_cb()``
- Delivers the operation container and starts the application transaction
state machine. A negative return stalls the bulk endpoints.
* - ``tud_mtp_data_send()`` / ``tud_mtp_data_receive()``
- Starts or continues the operation's data phase. ``false`` means the
transfer could not be queued in the current phase.
* - ``tud_mtp_response_send()``
- Queues the final response container with the current transaction ID.
* - ``tud_mtp_event_send()``
- Copies and queues one asynchronous event. Retry later when it returns
``false`` because the event endpoint is busy.
* - ``tud_mtp_data_xfer_cb()``
- Supplies or consumes the next chunk of a multi-packet data phase.
* - ``tud_mtp_data_complete_cb()`` /
``tud_mtp_response_complete_cb()``
- Advances application state after the entire data or response phase.
* - ``tud_mtp_request_*_cb()``
- Handles cancel, reset, status, extended-event, and vendor control
requests. Return ``false`` or a negative length where documented to
stall an unsupported request.
``tud_mtp_command_received_cb()`` receives an operation container. The
application performs any data phase with ``tud_mtp_data_send()`` or
``tud_mtp_data_receive()``, then completes the transaction with
``tud_mtp_response_send()``. Use ``tud_mtp_event_send()`` for asynchronous
events such as ObjectAdded.
The ``tud_mtp_data_xfer_cb()``, ``tud_mtp_data_complete_cb()``, and
``tud_mtp_response_complete_cb()`` callbacks advance multi-stage transfers.
Control callbacks handle cancel, reset, status, and vendor requests. Validate
container lengths, object handles, property codes, and storage bounds before
using them.
The :doc:`../../examples/device/mtp` example is the recommended template. It
implements a small in-memory object store, core session/object operations, an
upload, and an event. Replace its storage functions while preserving the
command/data/response state machine.
TinyUSB supplies the USB transport and MTP containers; it does not provide a
filesystem, object database, stable handle allocation, or access arbitration.
Those remain application responsibilities.

View File

@ -0,0 +1,121 @@
***********
USB Network
***********
Role: device only. TinyUSB can present an Ethernet-style interface using
CDC-ECM, RNDIS, or CDC-NCM. The application connects Ethernet frames to a
network stack such as lwIP.
Choose one driver
=================
``CFG_TUD_ECM_RNDIS`` and ``CFG_TUD_NCM`` are mutually exclusive.
* The ECM/RNDIS driver can expose separate configurations so Windows selects
RNDIS and macOS selects ECM; Linux can use either.
* NCM aggregates Ethernet datagrams into Network Transfer Blocks and is the
preferred starting point for current, higher-throughput designs. Windows
binding may require the Microsoft OS 2.0 descriptors shown by the example.
Use the matching descriptor macro: ``TUD_CDC_ECM_DESCRIPTOR``,
``TUD_RNDIS_DESCRIPTOR``, or ``TUD_CDC_NCM_DESCRIPTOR``. Provide a unique
48-bit ``tud_network_mac_address`` and return the same address as a 12-digit
hexadecimal USB string descriptor where the class descriptor references it.
Configuration options
=====================
.. list-table::
:header-rows: 1
:widths: 42 16 42
* - Option
- Default
- What it controls
* - ``CFG_TUD_ECM_RNDIS`` / ``CFG_TUD_NCM``
- ``0``
- Selects one network class implementation. Enabling both is a build
error.
* - ``CFG_TUD_NET_MTU``
- ``1514`` bytes
- Maximum Ethernet frame including its 14-byte Ethernet header.
* - ``CFG_TUD_NCM_OUT_NTB_MAX_SIZE``
- ``3200`` bytes
- Largest host-to-device NTB received. Linux expects at least 2048 bytes.
* - ``CFG_TUD_NCM_IN_NTB_MAX_SIZE``
- ``3200`` bytes
- Largest device-to-host NTB assembled for transmission.
* - ``CFG_TUD_NCM_OUT_NTB_N`` / ``CFG_TUD_NCM_IN_NTB_N``
- ``1`` each
- Number of receive/transmit NTB buffers. Increasing these can reduce
stalls at a proportional RAM cost; benchmark before changing them.
* - ``CFG_TUD_NCM_IN_MAX_DATAGRAMS_PER_NTB``
- ``8``
- Maximum Ethernet frames TinyUSB aggregates into a transmit NTB.
* - ``CFG_TUD_NCM_OUT_MAX_DATAGRAMS_PER_NTB``
- ``6``
- Maximum frames the device tells the host to place in one receive NTB.
Frame flow
==========
For host-to-device frames, TinyUSB calls
``tud_network_recv_cb(src, size)``. Copy or pass the frame to the network stack
and call ``tud_network_recv_renew()`` when the supplied packet storage is no
longer needed. Return ``false`` if the frame cannot be accepted.
For device-to-host frames:
1. Call ``tud_network_can_xmit(size)``.
2. If it returns true, call ``tud_network_xmit(ref, arg)`` once.
3. TinyUSB calls ``tud_network_xmit_cb(dst, ref, arg)``; copy the complete
Ethernet frame into ``dst`` and return its length.
Use ``tud_network_link_state()`` to notify the host when the logical or physical
link changes. A mounted USB device is not necessarily a link-up network
interface.
.. list-table::
:header-rows: 1
:widths: 40 60
* - API or callback
- What it does
* - ``tud_network_recv_cb()``
- Offers one received Ethernet frame. Return ``true`` only if the
application accepted the buffer or copied the frame.
* - ``tud_network_recv_renew()``
- Releases the offered receive storage and permits the next host packet.
* - ``tud_network_can_xmit()`` / ``tud_network_xmit()``
- Reserves room and requests one device-to-host frame. Call ``xmit`` only
once after a successful capacity check.
* - ``tud_network_xmit_cb()``
- Copies the complete frame into TinyUSB's destination and returns its
actual byte length.
* - ``tud_network_init_cb()``
- Resets the application network state when the ECM/RNDIS driver is
initialized or reset.
* - ``tud_network_set_packet_filter_cb()``
- Reports NCM host filter bits so the application can adjust multicast or
promiscuous delivery.
* - ``tud_network_default_link_state_cb()`` /
``tud_network_link_state()``
- Supplies the initial NCM link state and later sends link up/down changes
to the host.
NCM sizing
==========
NCM buffer sizes have a direct RAM/throughput tradeoff. The class requires an
OUT NTB size of at least 2048 bytes. Begin with one IN and one OUT NTB, then
measure before increasing ``CFG_TUD_NCM_IN_NTB_MAX_SIZE``,
``CFG_TUD_NCM_OUT_NTB_MAX_SIZE``, or their ``*_NTB_N`` counts. Keep descriptor
capabilities and runtime responses consistent with the enabled NCM features.
The :doc:`../../examples/device/net_lwip_webserver` example includes NCM and
ECM/RNDIS descriptor sets, lwIP integration, DHCP, DNS, link-state changes, and
host setup notes.
Specifications used: *CDC Ethernet Control Model*, Revision 1.2, and *CDC
Network Control Model*, Revision 1.0 (Errata 1). RNDIS is a vendor protocol,
not a USB-IF CDC subclass.

View File

@ -0,0 +1,91 @@
*******
Printer
*******
Role: device only. The Printer class provides bulk OUT data from a host print
spooler, optional bulk IN data for a bidirectional printer, and standard device
ID, port-status, and soft-reset requests.
Configuration
=============
Enable ``CFG_TUD_PRINTER`` and define the RX/TX FIFO and endpoint sizes. Add a
``TUD_PRINTER_DESCRIPTOR``; protocol 2 is the bidirectional interface used by
the TinyUSB example.
.. code-block:: c
#define CFG_TUD_PRINTER 1
#define CFG_TUD_PRINTER_RX_BUFSIZE 64
#define CFG_TUD_PRINTER_TX_BUFSIZE 64
#define CFG_TUD_PRINTER_RX_EPSIZE 64
#define CFG_TUD_PRINTER_TX_EPSIZE 64
.. list-table::
:header-rows: 1
:widths: 42 17 41
* - Option
- Default
- What it controls
* - ``CFG_TUD_PRINTER_RX_BUFSIZE`` /
``CFG_TUD_PRINTER_TX_BUFSIZE``
- Required when enabled
- Software FIFO capacity per printer interface. TX is still allocated
even if the application normally only receives print data.
* - ``CFG_TUD_PRINTER_RX_EPSIZE`` /
``CFG_TUD_PRINTER_TX_EPSIZE``
- Device bulk maximum
- Endpoint transfer buffer and descriptor packet size in each direction.
Data received from the host is available through
``tud_printer_read_available()`` and ``tud_printer_read()``. Send status or
bidirectional data with ``tud_printer_write()`` and flush when the response
should leave promptly. Use the ``tud_printer_n_*`` forms for multiple
interfaces.
.. list-table::
:header-rows: 1
:widths: 42 58
* - Data API or callback
- What it does
* - ``tud_printer_n_read_available()`` /
``tud_printer_n_read()``
- Reports and removes bytes sent by the print spooler.
* - ``tud_printer_n_write_available()`` /
``tud_printer_n_write()``
- Reports TX room and copies as much bidirectional response data as fits.
* - ``tud_printer_n_write_flush()``
- Starts a short TX transfer and returns the number of bytes submitted.
* - ``tud_printer_n_read_flush()`` /
``tud_printer_n_write_clear()``
- Discards pending receive or transmit FIFO data, for example on soft
reset.
* - ``tud_printer_rx_cb()`` /
``tud_printer_tx_complete_cb()``
- Announces new input or newly available TX capacity.
Control callbacks
=================
``tud_printer_get_device_id_cb()`` must return an IEEE 1284 device ID. Its
first two bytes are the big-endian total length, including those two bytes, and
the buffer must remain valid through transfer completion. A typical text body
is ``MFG:Vendor;MDL:Model;CMD:PCL;CLS:PRINTER;``.
Return current online, error, and paper state from
``tud_printer_get_port_status_cb()`` using
``tusb_printer_port_status_t``. In ``tud_printer_soft_reset_cb()``, cancel the
current print job and reset the class-facing parser without resetting unrelated
parts of a composite device.
``tud_printer_request_complete_cb()`` marks the end of the control transfer and
is the safe point to reuse request-specific application state, including a
dynamically selected device-ID buffer.
See :doc:`../../examples/device/printer_to_cdc` for bidirectional data and all
three class requests.
Specification used: *USB Device Class Definition for Printing Devices*,
Version 1.1.

View File

@ -0,0 +1,110 @@
******
USBTMC
******
Role: device only. USB Test and Measurement Class (USBTMC) carries instrument
commands and responses. The optional USB488 subclass adds IEEE-488-style
status, trigger, and service-request behavior; SCPI command parsing remains an
application concern.
Configuration and descriptors
=============================
Enable ``CFG_TUD_USBTMC``. Set ``CFG_TUD_USBTMC_ENABLE_488`` when USB488 is
implemented and ``CFG_TUD_USBTMC_ENABLE_INT_EP`` when an interrupt IN endpoint
is present. Construct the configuration from
``TUD_USBTMC_IF_DESCRIPTOR``, ``TUD_USBTMC_BULK_DESCRIPTORS``, and, when
enabled, ``TUD_USBTMC_INT_DESCRIPTOR``.
.. list-table::
:header-rows: 1
:widths: 42 16 42
* - Option
- Default
- What it controls
* - ``CFG_TUD_USBTMC``
- ``0``
- Enables the device class. The current driver exposes one instrument
interface.
* - ``CFG_TUD_USBTMC_ENABLE_488``
- ``1``
- Builds USB488 capability, status-byte, and trigger support. Set it to
``0`` for base USBTMC only.
* - ``CFG_TUD_USBTMC_ENABLE_INT_EP``
- Example-defined
- Selects whether the example descriptor includes the notification
endpoint; keep this consistent with the capabilities response.
* - ``CFG_TUD_USBTMC_INT_EP_SIZE``
- ``2`` bytes
- Internal interrupt notification buffer. It must fit the notification
format and descriptor packet size.
Return a static capabilities structure from
``tud_usbtmc_get_capabilities_cb()``. Its flags must agree with the descriptor
and callbacks actually implemented.
Message flow
============
.. list-table::
:header-rows: 1
:widths: 45 55
* - API or callback
- What it does
* - ``tud_usbtmc_open_cb()``
- Announces an opened interface; initialize instrument transaction state
and arrange the first bus read.
* - ``tud_usbtmc_msgBulkOut_start_cb()`` /
``tud_usbtmc_msg_data_cb()``
- Accepts a device-dependent OUT header and subsequent payload chunks.
Return ``false`` when the message cannot be accepted.
* - ``tud_usbtmc_msgBulkIn_request_cb()``
- Receives a host request for instrument data and should queue the response
when ready.
* - ``tud_usbtmc_transmit_dev_msg_data()``
- Queues response data with EOM/termination flags. The source remains
application-owned and must stay unchanged until completion.
* - ``tud_usbtmc_msgBulkIn_complete_cb()``
- Releases the response buffer and lets the application queue more data or
restart command reception.
* - ``tud_usbtmc_transmit_notification_data()``
- Copies one interrupt notification when that endpoint is present;
``false`` means the previous notification is still pending.
* - ``tud_usbtmc_start_bus_read()``
- Arms the next bulk OUT transfer. Call it after every path that becomes
ready to receive another command.
* - ``tud_usbtmc_initiate_*_cb()`` / ``tud_usbtmc_check_*_cb()``
- Starts and reports progress for abort/clear control requests.
* - ``tud_usbtmc_get_stb_cb()`` /
``tud_usbtmc_msg_trigger_cb()``
- Supplies the USB488 status byte and handles a USB488 trigger message.
For host-to-instrument messages, TinyUSB calls
``tud_usbtmc_msgBulkOut_start_cb()`` followed by one or more
``tud_usbtmc_msg_data_cb()`` calls. ``transfer_complete`` marks a USB transfer,
not necessarily the end of the USBTMC message; use the message header and EOM
information to frame commands.
When the host requests instrument data, prepare a response in
``tud_usbtmc_msgBulkIn_request_cb()`` and queue it with
``tud_usbtmc_transmit_dev_msg_data()``. The driver retains the buffer pointer,
so keep the data valid and unchanged until
``tud_usbtmc_msgBulkIn_complete_cb()``.
Call ``tud_usbtmc_start_bus_read()`` during or soon after open and after each
message/completion path that is ready to accept another command. Failing to
restart the read is a common reason an instrument answers once and then stops.
Implement abort and clear callbacks as a coherent state machine: stop the
pending operation, report progress through the corresponding check callback,
and restart the bus read when recovery completes. With USB488 enabled,
``tud_usbtmc_get_stb_cb()`` supplies the status byte and
``tud_usbtmc_msg_trigger_cb()`` handles trigger messages.
The :doc:`../../examples/device/usbtmc` example implements ``*IDN?``, USB488
status/trigger handling, abort/clear, and a PyVISA test script.
Specifications used: *USB Test and Measurement Class Specification*, Revision
1.0, and *USBTMC USB488 Subclass Specification*, Revision 1.0.

View File

@ -0,0 +1,118 @@
***************
Vendor-specific
***************
The device driver provides bulk, and optionally interrupt or isochronous,
transfers for a vendor-defined interface. There is no generic vendor protocol:
the device descriptors, request semantics, framing, and host software are part
of the product's protocol.
Device
======
Enable ``CFG_TUD_VENDOR`` and add ``TUD_VENDOR_DESCRIPTOR`` for the usual pair
of bulk endpoints. Buffered mode is the practical default.
.. list-table::
:header-rows: 1
:widths: 43 17 40
* - Option
- Default
- What it controls
* - ``CFG_TUD_VENDOR_RX_BUFSIZE`` /
``CFG_TUD_VENDOR_TX_BUFSIZE``
- Device bulk maximum
- Software FIFO bytes. Setting either to zero selects direct mode for
both directions.
* - ``CFG_TUD_VENDOR_RX_EPSIZE`` /
``CFG_TUD_VENDOR_TX_EPSIZE``
- Device bulk maximum
- Bulk endpoint transfer buffers and descriptor packet sizes.
* - ``CFG_TUD_VENDOR_RX_MANUAL_XFER``
- ``0``
- Requires the application to call ``tud_vendor_n_read_xfer()`` to arm
each buffered bulk OUT transfer.
* - ``CFG_TUD_VENDOR_RX_NEED_ZLP``
- ``0``
- Allows multi-packet receive termination by a zero-length packet; enable
only when the custom host protocol sends that terminator.
* - ``CFG_TUD_VENDOR_EP_INT_OUT`` /
``CFG_TUD_VENDOR_EP_INT_IN``
- ``0``
- Enables optional direct interrupt endpoints. Their buffer-size options
default to 64 bytes.
* - ``CFG_TUD_VENDOR_EP_ISO_OUT`` /
``CFG_TUD_VENDOR_EP_ISO_IN``
- ``0``
- Enables optional direct isochronous endpoints. They require alternate
settings; their buffers default to 64 bytes.
* - ``CFG_TUD_VENDOR_ALT_SETTINGS``
- ``0``
- Enables alternate-setting tracking. It requires direct mode and is
required by the optional isochronous endpoints.
Use ``tud_vendor_available()``/``tud_vendor_read()`` for OUT data and
``tud_vendor_write()``/``tud_vendor_write_flush()`` for IN data. In buffered
mode, ``tud_vendor_rx_cb()`` is only a notification; read the FIFO rather than
using its null buffer argument.
For direct transfers, configure zero RX/TX FIFO sizes and follow the ownership
rules in ``vendor_device.h``. Optional interrupt, isochronous, and alternate
setting support is controlled by ``CFG_TUD_VENDOR_EP_*`` and
``CFG_TUD_VENDOR_ALT_SETTINGS``. Interrupt and isochronous OUT endpoints must
be explicitly re-armed after their receive callbacks.
.. list-table::
:header-rows: 1
:widths: 43 57
* - API or callback
- What it does
* - ``tud_vendor_n_mounted()``
- Tests whether an instance has any configured bulk, interrupt, or
isochronous endpoint open.
* - ``tud_vendor_n_available()`` / ``tud_vendor_n_read()``
- Reports and removes bulk OUT FIFO bytes in buffered mode.
* - ``tud_vendor_n_write_available()`` /
``tud_vendor_n_write()``
- Reports room and copies as many bulk IN bytes as fit. In direct mode the
copy is limited to one endpoint buffer.
* - ``tud_vendor_n_write_flush()``
- Starts a short buffered IN transfer and returns the number of bytes
submitted.
* - ``tud_vendor_rx_cb()`` / ``tud_vendor_tx_cb()``
- Announces received data or completed output. In direct mode, consume or
copy the receive pointer before returning from the callback.
* - ``tud_vendor_n_int_read_xfer()`` /
``tud_vendor_n_iso_read_xfer()``
- Arms one optional OUT transfer; re-arm after each receive callback.
* - ``tud_vendor_n_int_write()`` /
``tud_vendor_n_iso_write()``
- Copies and queues at most one optional endpoint buffer and returns the
accepted byte count.
* - ``tud_vendor_n_alt()``
- Returns the host-selected alternate setting when support is enabled.
Handle vendor control requests in ``tud_vendor_control_xfer_cb()`` and perform
the data/status stage with ``tud_control_xfer()`` or
``tud_control_status()``. Validate ``bmRequestType``, ``bRequest``,
``wIndex``, ``wValue``, and ``wLength`` before accepting a request.
The :doc:`../../examples/device/webusb_serial` example combines a vendor bulk
interface with WebUSB and Microsoft OS 2.0 descriptors.
Host
====
A host cannot interpret an arbitrary vendor interface from its class code.
TinyUSB does not currently offer a supported, protocol-neutral
``tuh_vendor_*`` application API. For a simple fixed device, enable
``CFG_TUH_API_EDPT_XFER`` and use the descriptor/endpoint APIs demonstrated by
:doc:`../../examples/host/bare_api`. For a reusable protocol, implement a
custom host class driver that matches devices by descriptors and VID/PID and
owns their enumeration and transfer state.
Define framing, version negotiation, maximum message lengths, timeouts, and
error recovery before deploying a vendor protocol. Never cast unvalidated
wire data directly to an application structure.

View File

@ -0,0 +1,104 @@
*****
Video
*****
Role: device only. The USB Video Class (UVC) driver streams application-owned
video frames and handles the standard probe/commit negotiation used by host
camera software.
Start from an example
=====================
UVC descriptors contain a linked control topology plus one or more formats,
frames, intervals, and streaming alternate settings. Start from
:doc:`../../examples/device/video_capture` and change the format or dimensions
incrementally. Use :doc:`../../examples/device/video_capture_2ch` for multiple
control/streaming functions.
Configuration
=============
``CFG_TUD_VIDEO`` counts VideoControl interfaces and
``CFG_TUD_VIDEO_STREAMING`` counts VideoStreaming interfaces. Set
``CFG_TUD_VIDEO_STREAMING_EP_BUFSIZE`` to at least the payload size used by the
stream. The examples use ``CFG_TUD_VIDEO_STREAMING_BULK`` to choose bulk or
isochronous descriptors; the endpoint type in those descriptors is what the
driver follows.
.. list-table::
:header-rows: 1
:widths: 43 16 41
* - Option
- Default
- What it controls
* - ``CFG_TUD_VIDEO``
- ``0``
- Number of VideoControl functions retained by the driver.
* - ``CFG_TUD_VIDEO_STREAMING``
- ``0``
- Total VideoStreaming interfaces across all control functions.
* - ``CFG_TUD_VIDEO_STREAMING_EP_BUFSIZE``
- Required
- Per-stream USB payload buffer, including the UVC payload header. If it
is smaller than the negotiated payload, TinyUSB caps each transfer to
this size.
* - ``CFG_TUD_VIDEO_STREAMING_BULK``
- Example-defined
- Chooses between the example's bulk and isochronous descriptor layouts;
it is not interpreted by the class driver itself.
The helpers in ``src/class/video/video.h`` build individual UVC descriptor
blocks; unlike simpler classes, there is no single descriptor macro for every
camera topology. Verify entity IDs, terminal links, class-specific total
lengths, format/frame counts, endpoint addresses, and alternate settings as a
unit.
Frame flow
==========
.. list-table::
:header-rows: 1
:widths: 43 57
* - API or callback
- What it does
* - ``tud_video_n_connected()``
- Tests whether a VideoControl function is mounted.
* - ``tud_video_n_streaming()``
- Tests whether the host selected an active streaming alternate setting
for a control/stream pair.
* - ``tud_video_n_frame_xfer()``
- Queues one non-empty frame. ``false`` means no active endpoint, probe is
in progress, or another frame is still owned by the driver.
* - ``tud_video_frame_xfer_complete_cb()``
- Releases the queued frame after all of its UVC payloads complete.
* - ``tud_video_commit_cb()``
- Validates and applies the host's committed format, frame index, and
interval; return a ``video_error_code_t`` value.
* - ``tud_video_power_mode_cb()``
- Applies a host power-mode control request or returns an appropriate UVC
error.
* - ``tud_video_prepare_payload_cb()``
- Fills payload bytes on demand when the frame was queued with a null data
pointer; honor the requested offset and maximum length.
Wait for ``tud_video_n_streaming(ctl_idx, stm_idx)`` before submitting a frame.
Queue it with ``tud_video_n_frame_xfer()`` and do not modify or reuse the buffer
until ``tud_video_frame_xfer_complete_cb()``.
Implement ``tud_video_commit_cb()`` to inspect and adopt the format, frame, and
interval committed by the host. Generate frames at the negotiated interval;
continuing at a hard-coded rate can overflow or starve the stream.
For data generated directly into USB payloads, submit a null frame buffer with
the intended frame size and fill each request in
``tud_video_prepare_payload_cb()``. Respect the supplied length and offset and
avoid lengthy work in the callback.
Isochronous endpoints reserve periodic bandwidth and tolerate a missed packet;
bulk endpoints retry errors but provide no bandwidth guarantee. Check that the
advertised maximum packet size is feasible for the controller and bus speed.
Specification used: *USB Device Class Definition for Video Devices*, Revision
1.5.

View File

@ -1,316 +0,0 @@
***************
Class Drivers
***************
USB Class Drivers implement specific USB device classes (CDC, HID, MSC, MIDI, Audio, etc.) and are the main interface between the USB core and application code.
MIDI 2.0 Device Driver
=======================
Overview
--------
The MIDI 2.0 Device driver enables TinyUSB to act as a USB MIDI 2.0 device. It implements both Alt Setting 0 (MIDI 1.0 fallback) and Alt Setting 1 (native UMP) as required by the USB-MIDI 2.0 specification.
**Key Features:**
- **Dual Alt Settings**: Alt 0 (MIDI 1.0) and Alt 1 (UMP native) per USB-MIDI 2.0 spec
- **Protocol Negotiation**: Endpoint Discovery, Config Request/Notify, Function Block Discovery
- **Group Terminal Block**: Served via GET_DESCRIPTOR automatically
- **Atomic UMP Framing**: Read/write with correct message boundaries
- **Memory Safe**: No dynamic allocation, static instances
Configuration
-------------
Enable MIDI 2.0 Device support in ``tusb_config.h``:
.. code-block:: c
#define CFG_TUD_ENABLED 1
#define CFG_TUD_MIDI2 1
Optional configuration:
.. code-block:: c
#define CFG_TUD_MIDI2_TX_BUFSIZE 256
#define CFG_TUD_MIDI2_RX_BUFSIZE 256
#define CFG_TUD_MIDI2_TX_EPSIZE 64
#define CFG_TUD_MIDI2_RX_EPSIZE 64
#define CFG_TUD_MIDI2_NUM_GROUPS 1 // 1..16
#define CFG_TUD_MIDI2_NUM_FUNCTION_BLOCKS 1 // 1..32
#define CFG_TUD_MIDI2_EP_NAME "TinyUSB MIDI 2.0"
#define CFG_TUD_MIDI2_PRODUCT_ID "TinyUSB-MIDI2"
Public API
----------
Query Functions
^^^^^^^^^^^^^^^
.. code-block:: c
bool tud_midi2_mounted(void);
uint32_t tud_midi2_available(void);
uint8_t tud_midi2_alt_setting(void);
bool tud_midi2_negotiated(void);
uint8_t tud_midi2_protocol(void);
I/O Functions
^^^^^^^^^^^^^
.. code-block:: c
uint32_t tud_midi2_ump_read(uint32_t* words, uint32_t max_words);
uint32_t tud_midi2_ump_write(const uint32_t* words, uint32_t count);
uint32_t tud_midi2_packet_read(uint8_t packets[], uint32_t max_packets);
uint32_t tud_midi2_packet_write(const uint8_t packets[], uint32_t count);
Callbacks
^^^^^^^^^
.. code-block:: c
void tud_midi2_rx_cb(uint8_t itf);
void tud_midi2_set_itf_cb(uint8_t itf, uint8_t alt);
bool tud_midi2_get_req_itf_cb(uint8_t rhport, const tusb_control_request_t* request);
MIDI 2.0 Host Driver
=====================
Overview
--------
The MIDI 2.0 Host driver enables TinyUSB to enumerate and communicate with USB MIDI 2.0 devices. It implements the USB MIDI 2.0 specification, supporting both MIDI 1.0 legacy devices and modern MIDI 2.0 devices with UMP (Universal MIDI Packet) protocol.
**Key Features:**
- **Reactive Architecture**: Auto-detects Alt Setting 1 (MIDI 2.0) capability during enumeration
- **Auto-Selection**: Automatically selects the highest available protocol and issues SET_INTERFACE to activate Alt Setting 1 when MIDI 2.0 is detected
- **Transparent Stream Messages**: All data (UMP packets + Stream Messages) flow through callbacks
- **Memory Safe**: No dynamic allocation, fixed-size instances per device
Configuration
-------------
Enable MIDI 2.0 Host support in ``tusb_config.h``:
.. code-block:: c
#define CFG_TUH_ENABLED 1
#define CFG_TUH_MIDI2 4 // Number of MIDI 2.0 devices to support
Optional buffer configuration:
.. code-block:: c
#define CFG_TUH_MIDI2_RX_BUFSIZE (4 * TUH_EPSIZE_BULK_MAX)
#define CFG_TUH_MIDI2_TX_BUFSIZE (4 * TUH_EPSIZE_BULK_MAX)
Enumeration Lifecycle
---------------------
When a MIDI 2.0 device is connected, the host stack invokes callbacks in this order:
.. code-block:: none
Device Connected
|
[Host detects Alt 0 and Alt 1 descriptors]
|
tuh_midi2_descriptor_cb() <- Device detected, NOT yet ready
|
[Auto-select highest protocol]
|
tuh_midi2_mount_cb() <- Device ready to use
|
[Application can read/write data]
|
tuh_midi2_rx_cb() <- Data arrived
tuh_midi2_tx_cb() <- TX buffer space available
|
[Device disconnects]
|
tuh_midi2_umount_cb() <- Device removed
Public API
----------
Query Functions
^^^^^^^^^^^^^^^
.. code-block:: c
bool tuh_midi2_mounted(uint8_t idx);
uint8_t tuh_midi2_get_protocol_version(uint8_t idx); // 0=MIDI 1.0, 1=MIDI 2.0
uint8_t tuh_midi2_get_alt_setting_active(uint8_t idx); // 0 or 1
uint8_t tuh_midi2_get_cable_count(uint8_t idx);
I/O Functions
^^^^^^^^^^^^^
Read and write UMP (Universal MIDI Packet) data:
.. code-block:: c
uint32_t tuh_midi2_ump_read(uint8_t idx, uint32_t* words, uint32_t max_words);
uint32_t tuh_midi2_ump_write(uint8_t idx, const uint32_t* words, uint32_t count);
uint32_t tuh_midi2_write_flush(uint8_t idx);
Callbacks
---------
Application can define weak callback implementations to respond to device events.
Descriptor Callback
^^^^^^^^^^^^^^^^^^^
Invoked when device is detected but not yet ready for I/O:
.. code-block:: c
void tuh_midi2_descriptor_cb(uint8_t idx, const tuh_midi2_descriptor_cb_t *desc_cb_data) {
printf("MIDI %s device detected\r\n",
desc_cb_data->protocol_version == 0 ? "1.0" : "2.0");
}
Mount Callback
^^^^^^^^^^^^^^
Invoked when device is ready for I/O:
.. code-block:: c
void tuh_midi2_mount_cb(uint8_t idx, const tuh_midi2_mount_cb_t *mount_cb_data) {
printf("Device mounted at idx=%u, protocol=%u, alt_setting=%u\r\n",
idx, mount_cb_data->protocol_version, mount_cb_data->alt_setting_active);
}
RX Callback
^^^^^^^^^^^
Invoked when data arrives from device (both UMP packets and Stream Messages):
.. code-block:: c
void tuh_midi2_rx_cb(uint8_t idx, uint32_t xferred_bytes) {
uint32_t words[4];
uint32_t n = tuh_midi2_ump_read(idx, words, 4);
for (uint32_t i = 0; i < n; i++) {
uint8_t mt = (words[i] >> 28) & 0x0F;
if (mt == 0x0F) {
// Stream Message - app handles discovery, negotiation, etc.
} else {
// Regular MIDI UMP packet
}
}
}
TX Callback
^^^^^^^^^^^
Invoked when TX buffer space becomes available:
.. code-block:: c
void tuh_midi2_tx_cb(uint8_t idx, uint32_t xferred_bytes) {
// Buffer space available for writing
}
Unmount Callback
^^^^^^^^^^^^^^^^
Invoked when device is disconnected:
.. code-block:: c
void tuh_midi2_umount_cb(uint8_t idx) {
printf("Device at idx=%u disconnected\r\n", idx);
}
Complete Example
----------------
.. code-block:: c
#include "tusb.h"
void tuh_midi2_mount_cb(uint8_t idx, const tuh_midi2_mount_cb_t *mount_cb_data) {
printf("MIDI 2.0 device mounted\r\n");
}
void tuh_midi2_rx_cb(uint8_t idx, uint32_t xferred_bytes) {
uint32_t words[4];
uint32_t n = tuh_midi2_ump_read(idx, words, 4);
for (uint32_t i = 0; i < n; i++) {
printf("RX: 0x%08lx\r\n", words[i]);
}
}
void tuh_midi2_umount_cb(uint8_t idx) {
printf("MIDI 2.0 device disconnected\r\n");
}
int main(void) {
board_init();
tusb_rhport_init_t host_init = {.role = TUSB_ROLE_HOST, .speed = TUSB_SPEED_AUTO};
tusb_init(BOARD_TUH_RHPORT, &host_init);
while (1) {
tuh_task();
}
}
Architecture
------------
The MIDI 2.0 Host driver uses a **reactive, callback-driven architecture** that mirrors the proven patterns in TinyUSB's existing device drivers (CDC, HID, etc.):
- **Auto-Detection**: Host automatically detects Alt Setting 1 capability
- **Auto-Selection**: Selects highest protocol available and issues SET_INTERFACE
- **Transparent I/O**: Stream Messages and UMP packets flow through callbacks
- **Callback-Driven**: App receives events via callbacks (descriptor, mount, rx, tx, unmount)
Differences from MIDI 1.0 Host
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
.. list-table::
:header-rows: 1
* - Aspect
- MIDI 1.0 Host
- MIDI 2.0 Host
* - Alt Settings
- Parses only Alt 0
- Parses Alt 0 + Alt 1
* - Data Format
- 4-byte MIDI packets
- UMP (32/64/128-bit)
* - Version Detection
- None
- bcdMSC from descriptor
* - GTB
- N/A
- Presence detection
* - Stream Messages
- N/A
- Transparent passthrough
* - Callbacks
- descriptor_cb, mount_cb, rx_cb, umount_cb
- descriptor_cb, mount_cb, rx_cb, tx_cb, umount_cb
* - Public API
- tuh_midi_*
- tuh_midi2_*
Implementation Notes
--------------------
- All internal state is statically allocated (no dynamic allocation)
- Endpoint streams use TinyUSB's tu_edpt_stream_t for buffered I/O
- Protocol version detection via bcdMSC field
- Alt Setting is automatically selected during mount
- Compatible with all TinyUSB-supported MCU families

View File

@ -9,7 +9,7 @@ Complete reference documentation for TinyUSB APIs, configuration, and supported
architecture
usb_concepts
class_drivers
class/index
boards
dependencies
concurrency