refactor(bldc_haptics): standard OTA / coredump / haptics modules + discovery - #768
refactor(bldc_haptics): standard OTA / coredump / haptics modules + discovery#768finger563 wants to merge 8 commits into
Conversation
The bldc_haptics example was the one framed-USB example still driving a raw
stream_frame::StreamParser (with a manual `frame.module == kModule` filter)
instead of an espp::Dispatcher, so it could not advertise itself to the browser
Device Hub. Migrate it and advertise.
- Replace the raw parser + module filter with an espp::Dispatcher: register the
haptics protocol on module 2 (proto::kModule) with a handler that gates on
!is_reply() (unchanged semantics), and feed()/reset() the dispatcher from the
USB RX worker. The example's OTA subset + haptics commands all ride module 2's
message types, so this stays a single-module protocol.
- Advertise it: register_module(..., ModuleInfo{"BLDC Haptics",
"haptics_console.html", ...}), set_device_info(usb_cfg.product), and
serve_discovery() routed through the existing tx_mutex-guarded usb_send.
- Add the dispatcher component to the example's EXTRA_COMPONENT_DIRS and to the
main component's REQUIRES.
Also complete the dispatcher README module-id table (add 2 = BLDC haptics,
6 = MCP266).
This finishes the set: every framed-USB example (ota, coredump, can_bridge,
mcp266, haptics) now advertises over the reserved discovery module 0xFF.
Verified: builds clean, manager-off, on IDF v6.0.1 (esp32s3).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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.
Pull request overview
Migrates the bldc_haptics framed-USB example from a raw StreamParser + manual module filtering to espp::Dispatcher, and enables capability discovery advertising so it can be listed by the browser Device Hub.
Changes:
- Replace
StreamParserparsing/filtering withespp::Dispatcherrouting on module 2. - Advertise the module and serve discovery responses via the existing USB TX path.
- Wire the new component dependency in CMake and update dispatcher module-id documentation.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| components/dispatcher/README.md | Adds missing module-id entries for BLDC haptics (2) and MCP266 (6). |
| components/bldc_haptics/example/main/bldc_haptics_example.cpp | Switches to Dispatcher, registers/advertises module 2, and routes discovery replies through USB send. |
| components/bldc_haptics/example/main/CMakeLists.txt | Adds dispatcher to the example main component requirements. |
| components/bldc_haptics/example/CMakeLists.txt | Adds dispatcher to EXTRA_COMPONENT_DIRS for the example build. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| // same tx_mutex-guarded usb_send as every other frame. | ||
| dispatcher.serve_discovery( | ||
| [&](std::span<const uint8_t> f) { usb_send(std::vector<uint8_t>(f.begin(), f.end())); }); |
|
✅Static analysis result - no issues found! ✅ |
Bring the haptics example in line with the other framed-USB examples: instead of multiplexing an OTA subset + a crash-report command into the haptics protocol (module 2), run the STANDARD protocols on their own dispatcher modules so the device is discovered as three modules and the plain ota / coredump web consoles work against it directly. - OTA -> module 0: a handler speaking the espp ota_stream protocol (Begin/Data/ Finish/Abort -> make_ok/make_error), reusing the existing espp::Ota. Removed the Ota* message types from haptics_usb_protocol.hpp + the cases from the haptics handler. - Core dump -> module 4: an espp::CoreDump + espp::CoreDumpService (full download/ erase protocol). The dump is no longer erased at boot (the coredump console downloads + erases it); the boot-time summary log stays. Removed GetCrash/Crash from the haptics protocol + the raw esp_core_dump usage. - Haptics stays module 2 (commands + telemetry only). - Register + advertise all three (OTA / Core Dump / BLDC Haptics); add the coredump component to the example deps. Web console cleanup (drop the now-moved OTA + crash UI) follows in a separate commit. Verified: builds clean, manager-off, IDF v6.0.1 (esp32s3). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Now that OTA is dispatcher module 0 and core dump is module 4 (not multiplexed into the haptics protocol), remove their UI from the haptics console: the device hub discovers all three modules and links to the standard ota_console / coredump_console, which speak those modules directly. - webapp/index.html: remove the Firmware-update (OTA) panel + upload flow, the GET_CRASH fetch, the OTA/crash message types + progress plumbing, and the now- unused constants/CSS. Haptics controls + telemetry are unchanged. - PROTOCOL.md: module 2 now documents haptics only; note OTA=module 0 / coredump=module 4 as separate standard protocols. - README.md: point firmware update / crash inspection at the ota / coredump consoles (and the device hub) instead of an inline panel. Web app passes node --check; no dangling references remain. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…e checks
The haptics console refactor left a call to updateUploadUI() (removed along
with the OTA upload panel) inside setConnectedUI(). Since setConnectedUI runs
early in connect(), it threw a ReferenceError before the RX pump and the init
handshake started -- the page connected (dial showed "waiting for telemetry")
but never sent GET_INFO / SET_STREAMING, so no telemetry ever arrived. Drop
the stale call.
Also harden the ota / coredump / haptics WebUSB consoles:
- default device filter is now VID-only (any espp device, VID 0x1209) instead
of VID+PID, so a multi-module device is offered in every console; "show all
devices" uses {filters:[{}]} (ota_console's invalid acceptAllDevices fixed).
- on connect each console queries the reserved dispatcher discovery module
(0xFF ListModules, reusing Dispatcher::describe's TLV) and warns if its own
module is not advertised, then continues anyway; firmware without the
discovery module simply never replies and is tolerated silently.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The OTA cases that used this std::error_code moved to handle_ota_frame (which has its own), leaving handle_frame's `ec` unused -- cppcheck's unusedVariable failed the static-analysis gate. Remove it. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
🔵 Needs a closer look
The cross-layer firmware, protocol, discovery, and console changes warrant final human review despite only minor findings.
Review details
Suppressed comments (3)
components/bldc_haptics/example/PROTOCOL.md:47
- The protocol no longer has two unsolicited frame kinds after
OTA_PROGRESSwas removed; only telemetry remains. Please make this singular so implementers are not told to expect a second undocumented event.
sending the next. Two device-to-host frame kinds may arrive *unsolicited* and
must be tolerated at any time:
- `TELEMETRY (0x93)` — when streaming is enabled.
components/bldc_haptics/example/webapp/index.html:513
- The adjacent comment still says the default matches this example's exact VID/PID, but the changed filter now matches every PID under the espp VID; the checkbox broadens that further to all USB devices. Update the comment to match the selector behavior.
: { filters: [{ vendorId: DEFAULT_VID }] }; // any espp device (VID 0x1209), any PID
components/coredump/web/coredump_console.html:617
- The adjacent comment still describes an exact example VID/PID default and says the checkbox only adds other espp devices. The new selector already includes every espp PID by default, while the checkbox includes all USB vendors, so the documentation is now misleading.
: { filters: [{ vendorId: DEFAULT_VID }] }; // any espp device (VID 0x1209), any PID
- Files reviewed: 10/10 changed files
- Comments generated: 2
- Review effort level: Balanced
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Addresses the review note on the discovery reply path: usb_send took a `const std::vector<uint8_t>&`, so the serve_discovery and CoreDumpService reply callbacks (which receive a std::span) had to copy their bytes into a fresh vector on every reply. usb_send now takes `std::span<const uint8_t>` and calls write_vendor (which already accepts a span) directly: - the vector-building callers (proto::build / ota_stream make_*) still work via the implicit vector->span conversion, no copy; - the discovery and coredump callbacks forward their span with no allocation. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Modernize the bldc_haptics example: standard OTA / coredump / haptics modules + discovery
Brings the
bldc_hapticsexample fully in line with the other framed-USB examplesand wires it into dispatcher capability discovery (#767).
1. Migrate to
espp::Dispatcher+ advertiseThe example drove a raw
stream_frame::StreamParserwith a manualframe.module == kModulefilter. It now routes through anespp::Dispatcherandadvertises itself for capability discovery, so the browser Device Hub lists it.
2. Split OTA / core dump onto their own modules
Instead of multiplexing an OTA subset + a crash-report command into the haptics
protocol (module 2), the example now runs the standard protocols on their own
dispatcher modules:
ota_streamprotocol, reusingthe existing
espp::Ota. The plainota_console.htmlupdates this device.espp::CoreDump+espp::CoreDumpService(fulldownload/erase). The dump is no longer erased at boot (the console downloads +
erases it); the boot summary log stays.
coredump_console.htmlworks against it.All three are registered + advertised (OTA / Core Dump / BLDC Haptics), so the hub
discovers a device with three modules and links to each dedicated console.
3. Drop the inline OTA / crash UI from the haptics console
webapp/index.htmlloses its Firmware-update panel + crash fetch (and theassociated protocol types / plumbing) — the hub + dedicated consoles cover it.
PROTOCOL.md / README updated accordingly.
Verified
node --checkwith no dangling references.🤖 Generated with Claude Code