example

Example of the component espp/usb_device v1.2.0
# ODrive-compatible USB Device Example (CDC + Vendor/WebUSB + HID)

This example demonstrates a **composite** `espp::UsbDevice` that presents an
ODrive-compatible device with three interfaces, all backed by one simulated motor
state (matching how a real ODrive splits its protocols across interfaces):

- **CDC-ACM serial** → the **ODrive ASCII** protocol (`espp::OdriveAscii`; text,
  for a terminal or the Web Serial console).
- **vendor-specific (class 0xFF, WebUSB)** → the **ODrive native / Fibre binary**
  protocol (`espp::OdriveNative`) — the one `odrivetool` / the `fibre` library
  auto-discover and speak over USB.
- **HID** → an animated **gamepad** input device (built with the `hid-rp`
  component; visualize it with the WebHID `hid_visualizer.html`).

The device enumerates with an ODrive-like VID/PID (0x1209 / 0x0d32), separate from
the log console which stays on the USB-Serial-JTAG peripheral.

Each protocol server is transport-agnostic: the CDC RX callback feeds bytes to
`OdriveAscii::process_bytes()`, the vendor RX callback feeds bytes to
`OdriveNative::process_bytes()`, and each writes its response back out the same
interface. The HID interface periodically pushes gamepad input reports.

<!-- markdown-toc start - Don't edit this section. Run M-x markdown-toc-refresh-toc -->
**Table of Contents**

- [ODrive-compatible USB Device Example (CDC + Vendor/WebUSB + HID)](#odrive-compatible-usb-device-example-cdc--vendorwebusb--hid)
  - [Requirements](#requirements)
  - [Build](#build)
  - [Flash and Monitor](#flash-and-monitor)
  - [Usage](#usage)
  - [How it works](#how-it-works)

<!-- markdown-toc end -->

## Requirements

- An ESP32-S3 (or -S2 / -P4) with access to the native USB-OTG pins.
- ESP-IDF installed and available in your shell.
- The IDF component manager is enabled for this example so it can fetch the
  managed `espressif/esp_tinyusb` component.

The example's `sdkconfig.defaults` enables the CDC, vendor, and HID classes:

```
CONFIG_TINYUSB_CDC_ENABLED=y
CONFIG_TINYUSB_CDC_COUNT=1
CONFIG_TINYUSB_VENDOR_COUNT=1
CONFIG_TINYUSB_HID_COUNT=1
```

## Build

```sh
cd components/usb_device/example
idf.py set-target esp32s3
idf.py build
```

## Flash and Monitor

Flash / monitor over the USB-Serial-JTAG (or UART) console, which is kept separate
from the native USB interfaces:

```sh
idf.py flash monitor
```

The native USB-OTG connector will appear on the host as a new composite device:
a serial port (CDC), a vendor interface (WebUSB), and a HID gamepad, with
manufacturer "espp" and product "espp ODrive".

## Usage

**CDC serial (ODrive ASCII):** open the CDC serial port and send ODrive ASCII
commands, e.g. from Python:

```python
import serial
ser = serial.Serial('/dev/tty.usbmodemXXXX', 115200, timeout=0.5)
ser.write(b'r axis0.encoder.pos_estimate\n'); print(ser.readline())
ser.write(b'w axis0.controller.input_pos 12.34\n'); print(ser.readline())
ser.write(b'p 0 1.0 0.5 0.1\n'); print(ser.readline())
ser.write(b'f 0\n'); print(ser.readline())
```

(Writes/setpoints are silent by default — ODrive semantics; only `r`/`f` respond.)

**Vendor / WebUSB (ODrive native / Fibre):** the vendor interface (class 0xFF,
bulk IN + bulk OUT) speaks the ODrive native binary protocol. `odrivetool` / the
reference `fibre` library discover it over USB and read/write the endpoint tree;
or, from a Chromium-based browser, open the native-protocol WebUSB control panel
(`odrive_control_panel.html`) and connect. The BOS/WebUSB descriptors point to a
configurable landing-page URL. See `HARDWARE_TEST.md` and `odrive_usb_probe.py`.

**HID (gamepad):** the device also enumerates as a HID gamepad whose sticks and
buttons the firmware animates. Your OS will see a gamepad; to inspect the raw
input reports in the browser, open the WebHID `hid_visualizer.html` in Chromium
and connect.

## How it works

- `espp::UsbDevice` installs the TinyUSB driver and builds descriptors for the
  enabled CDC + vendor + HID functions, allocating interfaces / endpoints
  sequentially (the S3 USB-OTG endpoint budget fits CDC + vendor + HID).
- The vendor function advertises WebUSB + MS OS 2.0 descriptors so a browser (and
  Windows, via WinUSB) can bind it driverlessly.
- The CDC receive callback feeds bytes to `espp::OdriveAscii::process_bytes()` and
  writes the response back out via `write_cdc()`; the vendor receive callback feeds
  bytes to `espp::OdriveNative::process_bytes()` and writes back via
  `write_vendor()`. Both servers share one simulated motor state.
- The HID report descriptor is built with the `hid-rp` component
  (`espp::GamepadInputReport`); the main loop animates the state and pushes reports
  with `write_hid_report()` when the HID interface is ready.
- The log console remains on the USB-Serial-JTAG peripheral (see
  `sdkconfig.defaults.esp32s3`).

To create a project from this example, run:

idf.py create-project-from-example "espp/usb_device=1.2.0:example"

or download archive (~12.75 KB)