Repository navigation
feat(usb_device): generic CDC + vendor + MSC reference example; ODrive USB example moves to odrive_native - #834
Conversation
…e out of usb_device The composite ODrive device (ASCII over CDC, native / Fibre over the vendor interface, HID gamepad) is specific to the ODrive protocols, so it now lives with them as components/odrive_native/usb_example (history preserved; same behaviour, descriptors and VID/PID 0x1209/0x0d32). usb_device/example becomes the generic USB device reference example (next commit). CI, docs (its own page under the odrive_native component), Doxygen example paths and the usb_device header snippets are updated. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DFjjnq3XCTRAXENSxsCxJU
… with the standard USB services One espp::UsbDevice with the three interface classes the component provides: CDC and vendor (WebUSB) each carry the espp framed protocol through their own DispatcherWorker, serving SystemService, MonitorService, OtaService and CoreDumpService (discoverable, one send mutex per transport, RX overflow -> OtaService::on_rx_overflow()); MSC exposes a wear-levelled FAT partition in flash as a removable drive, on which the firmware writes a README before handing it to the host. VID 0x1209 / PID 0x0d38 (unused by the other examples); 4 MB table: otadata, ota_0 / ota_1 (1536K each; the app is 722K), coredump 64K, storage 896K. Builds for esp32s3 (CI, manager off). Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DFjjnq3XCTRAXENSxsCxJU
There was a problem hiding this comment.
Warning
Copilot couldn't run its full agentic review because it didn't start before the timeout. Make sure your repository has a runner available, or add a copilot-code-review.yml file specifying one with the runs-on attribute. See the docs for more details.
Copilot review overview
Review effort: Lite
Findings: 2
Open (5)
SRC_DIRS "."will compile every.cppin this directory. Since… · Newespp::UsbDevice::Config usb_cfg;may leave scalar fields uninitialized ifConfigis an… · New Using C++ iostreams (std::ifstream/std::ofstream) in an ESP-IDF example can significantly… · New Using C++ iostreams (std::ifstream/std::ofstream) in an ESP-IDF example can significantly… · New The surrounding Doxygen section header (immediately above) still describes this as “composite CDC +… · New
What changed in this PR
Moves the ODrive-specific composite USB example under odrive_native, and rewrites components/usb_device/example into a generic reference composite (CDC + vendor/WebUSB + MSC) showcasing the standard espp USB services.
Changes:
- Relocates the ODrive-compatible USB composite example to
components/odrive_native/usb_exampleand wires it into docs + CI. - Replaces
components/usb_device/examplewith a generic CDC+vendor/WebUSB+MSC reference example (services + flash-backed MSC drive). - Updates Doxygen example paths and header snippet references to the new generic example.
| File | Description |
|---|---|
| doc/en/motor_control/odrive_usb_example.md | Adds doc page that includes the moved ODrive USB example README. |
| doc/en/motor_control/odrive_native.rst | Adds the ODrive USB example page to the odrive_native toctree. |
| doc/Doxyfile | Updates Doxygen example paths for the moved ODrive USB example and new generic usb_device example. |
| components/usb_device/include/usb_device.hpp | Points Doxygen snippet to the new usb_device_example.cpp. |
| components/usb_device/include/usb_cdc.hpp | Points Doxygen snippet to the new usb_device_example.cpp. |
| components/usb_device/example/sdkconfig.defaults | Updates sdkconfig defaults for generic CDC+vendor+MSC + services + partition table. |
| components/usb_device/example/partitions.csv | Adds custom 4MB OTA+coredump+storage partition table for the generic example. |
| components/usb_device/example/main/usb_device_example.cpp | Adds the new generic composite USB device example with services and MSC drive. |
| components/usb_device/example/main/usb_cdc_example.cpp | Renames snippet tags (file still present in generic example directory). |
| components/usb_device/example/main/CMakeLists.txt | Updates component requirements for the new generic example. |
| components/usb_device/example/README.md | Rewrites README from ODrive-specific to generic services + MSC example. |
| components/usb_device/example/HARDWARE_TEST.md | Updates flash instructions, but currently points to the moved ODrive path. |
| components/usb_device/example/CMakeLists.txt | Updates build modes (manager on/off), EXTRA_COMPONENT_DIRS, and project name for generic example. |
| components/odrive_native/usb_example/sdkconfig.defaults | Adds sdkconfig defaults for the moved ODrive USB example. |
| components/odrive_native/usb_example/main/CMakeLists.txt | Adds main component registration for the moved ODrive USB example. |
| components/odrive_native/usb_example/README.md | Adds README for the moved ODrive USB example. |
| components/odrive_native/usb_example/CMakeLists.txt | Adds project CMakeLists for the moved ODrive USB example. |
| components/odrive_native/README.md | Mentions the new usb_example under odrive_native. |
| .github/workflows/build.yml | Adds CI build for the moved ODrive USB example and forces manager-off build for generic usb_device example. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
…itle (review) Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DFjjnq3XCTRAXENSxsCxJU
|
✅Static analysis result - no issues found! ✅ |
There was a problem hiding this comment.
Warning
Copilot couldn't run its full agentic review because it didn't start before the timeout. Make sure your repository has a runner available, or add a copilot-code-review.yml file specifying one with the runs-on attribute. See the docs for more details.
Copilot review overview
Review effort: Lite
Findings: 1
Open (4)
SRC_DIRS "."will compile all source files in this directory. With the new… · New In ESP-IDF projects it’s more reliable to setCMAKE_CXX_STANDARDafter the IDFproject(...)is… · Newusb_cfgis default-initialized, which can leave scalar fields uninitialized if… · New This is theUsbCdcheader’s “UsbCdc Example” section, but it now references the composite… · New
Resolved since last review (5)
espp::UsbDevice::Config usb_cfg;may leave scalar fields uninitialized ifConfigis an…SRC_DIRS "."will compile every.cppin this directory. Since… The surrounding Doxygen section header (immediately above) still describes this as “composite CDC +… Using C++ iostreams (std::ifstream/std::ofstream) in an ESP-IDF example can significantly… Using C++ iostreams (std::ifstream/std::ofstream) in an ESP-IDF example can significantly…
…xplains the composite example (#835) Post-merge review of #834: the example sets CMAKE_CXX_STANDARD after project() like the ODrive USB example, and the UsbCdc header's example section says the snippet is the composite device (CDC next to vendor + MSC). Claude-Session: https://claude.ai/code/session_01DFjjnq3XCTRAXENSxsCxJU Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>



Summary
Two things, as requested:
1. The ODrive-compatible USB device example moves to
components/odrive_native/usb_example(git mv, history preserved). It is the ODrive-specific composite device (ODrive ASCII over CDC, native / Fibre over the vendor interface, HID gamepad; VID/PID0x1209/0x0d32), so it lives with the ODrive protocols now: same behaviour and descriptors, main source renamed toodrive_usb_example.cpp, paths fixed in its README /HARDWARE_TEST.md, its own doc page under theodrive_nativecomponent (doc/en/motor_control/odrive_usb_example.md, in that page's toctree), theodrive_nativeREADME mentions it, CI builds it for esp32s3 (component manager on, as before), Doxygen's example paths updated, and theusb_deviceheader snippets now point at the new generic example.2.
components/usb_device/exampleis rewritten as the generic reference: oneespp::UsbDevicewith the three interface classes the component provides, plus the standard espp USB services and the dispatcher:DispatcherWorkerespp_*CLIs over the serial portDispatcherWorkerstorage, 896K) with aREADME.txtthe firmware writes at boot before handing the drive to the hostBoth framed links register
SystemService(reboot + bootloader allowed, logging veto callback),MonitorService,OtaService(overespp::Ota, rollback like the ota example, RX overflow ->on_rx_overflow()) andCoreDumpService(overespp::CoreDump), one instance per link,serve_discovery("espp USB Device")on both, one send mutex per transport. VID0x1209/ PID0x0d38(0x0d32/34/36/37 are taken by the ODrive, OTA, coredump and system examples). Boot logs the enumerated interfaces; a 10 s heartbeat logs free heap and who owns the drive.msc_example(SD card / T-Dongle-S3) is unchanged.Partition table (4 MB):
nvs,otadata,phy_init,ota_0/ota_11536K each,coredump64K,storage896K. sdkconfig: custom table, coredump to flash, rollback, FreeRTOS stats / trace / core id, TinyUSB CDC + vendor + MSC, 4096-byte wear-levelling sectors with a 4096-byte MSC buffer, FAT labels, console on UART0.Test plan
components/usb_device/examplebuilds for esp32s3 withIDF_COMPONENT_MANAGER=0(as CI); the app is 722 KB (47 % of an OTA slot); the generated sdkconfig has the custom table, coredump-to-flash, rollback, run-time stats, MSC enabled with a 4096-byte buffer and 4096-byte WL sectors.components/odrive_native/usb_examplebuilds for esp32s3 with the component manager on (as CI).README.txt, ejecting hands it back (heartbeat log); system console over WebUSB and over Web Serial (info, heap / tasks, reboot, reboot into the bootloader); OTA from the OTA console; a crash trigger + coredump console download.HARDWARE_TEST.md).🤖 Generated with Claude Code
https://claude.ai/code/session_01DFjjnq3XCTRAXENSxsCxJU