feat(usb_device): TX FIFO space queries + clear; clear stale TX on unmount - #774
Merged
Conversation
…mount Adds primitives for backpressure-aware streaming and clean reconnects: - vendor_write_available() / cdc_write_available(): free space (bytes) in the TX FIFO, so a streaming producer can skip/defer a frame instead of building it and having write_vendor()/write_cdc() drop it when the host stops draining. - vendor_write_clear() / cdc_write_clear(): drop any queued-but-unsent TX bytes, for when the host goes away so a stale backlog is not delivered to the next host. - tud_umount_cb(): clears both TX FIFOs on unmount (cable pull / re-enumeration / suspend), so the next host to mount starts from an empty pipe and cannot mis-parse a stale frame as the reply to its first command. All thin wrappers over TinyUSB's tud_*_write_available / tud_*_write_clear (already used internally by write_vendor/write_cdc), guarded like the existing getters. Note: an abrupt browser-tab close does NOT unmount, so that path still relies on the streaming producer's own backpressure (e.g. the bldc_haptics telemetry auto-pause) rather than tud_umount_cb. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
finger563
added a commit
that referenced
this pull request
Sep 5, 2026
…on auto-pause (#775) * fix(bldc_haptics web): drain stale RX before the connect handshake Re-applies the RX-drain that missed the #773 squash-merge. On an abrupt tab close the device's vendor TX FIFO is not cleared, so a reconnecting page could read leftover telemetry / reply frames and mis-handle them ("first Connect returns immediately, second works"). initializeDevice() now flushes the pipe (set a `draining` flag, reset the parser, let the RX pump discard for ~150 ms) before the GET_INFO handshake; dispatchFrame drops frames while draining. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(bldc_haptics): clear the vendor TX backlog when telemetry auto-pauses When the telemetry stall guard fires (host stopped draining), also drop the queued-but-unsent telemetry via usb.vendor_write_clear() (added in #774). An abrupt tab close does not unmount the device, so the FIFO is not cleared for us; clearing it here means a reconnecting host reads a clean stream instead of a stale backlog it might mis-parse as the reply to its first command. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Contributor
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
Adds TX FIFO “available” and “clear” helpers to espp::UsbDevice and ensures TX FIFOs are cleared on USB unmount to avoid delivering stale queued data after reconnects.
Changes:
- Add
vendor_write_available()/cdc_write_available()to query free TX FIFO space. - Add
vendor_write_clear()/cdc_write_clear()to discard queued TX bytes. - Clear vendor/CDC TX FIFOs from
tud_umount_cb()on device unmount.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| components/usb_device/src/usb_device.cpp | Implements FIFO-availability/clear APIs and clears TX FIFOs on unmount. |
| components/usb_device/include/usb_device.hpp | Exposes the new FIFO-availability/clear APIs with usage docs. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Comment on lines
+1170
to
+1174
| size_t UsbDevice::cdc_write_available() const { | ||
| if (!initialized_ || !config_.cdc || !tud_mounted()) | ||
| return 0; | ||
| return tud_cdc_n_write_available(kCdcPort); | ||
| } |
Comment on lines
+1183
to
+1186
| void UsbDevice::cdc_write_clear() { | ||
| if (initialized_ && config_.cdc) | ||
| tud_cdc_n_write_clear(kCdcPort); | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Adds TX-FIFO primitives to
espp::UsbDevicefor backpressure-aware streaming and clean reconnects — motivated by the bldc_haptics telemetry issue (#773) where the device kept streaming into a full FIFO after the host stopped draining.New API
vendor_write_available()/cdc_write_available()— bytes of free space currently in the TX FIFO (0 if not mounted / no interface). Lets a streaming producer check space before building a frame and skip/defer it, instead of building it and havingwrite_vendor()/write_cdc()drop it. Point-in-time hint; stable with a single serialized writer.vendor_write_clear()/cdc_write_clear()— discard queued-but-unsent TX bytes, so a stale backlog left by a departed host isn't delivered to the next one.Behavior change
tud_umount_cb()now clears both TX FIFOs on unmount (cable pull / re-enumeration / suspend), so the next host to mount starts from an empty pipe and can't mis-parse a stale frame as the reply to its first command.All are thin wrappers over TinyUSB functions the component already uses internally (
tud_vendor_write_available/tud_cdc_n_write_availablein the write paths,tud_vendor_write_clearin the vendor control handler), guarded the same way as the existingis_*_connected()getters. cppcheck-clean.🤖 Generated with Claude Code