harden USB telemetry transport
This commit is contained in:
@@ -0,0 +1,74 @@
|
||||
# Direct USB Transport Validation — 2026-08-17
|
||||
|
||||
This milestone moved framed telemetry off stdio and the USB Serial/JTAG VFS data
|
||||
path. The output task now targets a transport-neutral state machine backed by
|
||||
ESP-IDF's interrupt-driven USB Serial/JTAG driver.
|
||||
|
||||
## Transaction contract
|
||||
|
||||
- `RETRY`: the backend accepted zero bytes, so whole-frame resubmission is safe.
|
||||
- `PENDING`: the backend owns an in-flight frame. Only completion polling is
|
||||
allowed; the caller must retain and not modify the packet buffer.
|
||||
- `COMPLETE`: the backend's completion criterion is satisfied and the caller may
|
||||
reuse the packet buffer.
|
||||
- `FATAL`: a programming or backend invariant failed. The output task stops
|
||||
consuming the sample queue rather than silently discarding its in-flight data.
|
||||
|
||||
For USB, submission uses a 512-byte TX ring and a bounded 50 ms write. ESP-IDF's
|
||||
ring-buffer send is all-or-nothing for each `TRK1` frame. Once accepted, bounded
|
||||
50 ms `usb_serial_jtag_wait_tx_done()` calls continue returning `PENDING` until
|
||||
the host drains the endpoint. A timeout never resubmits the frame.
|
||||
|
||||
The VFS is switched to driver mode after readable startup output so any
|
||||
unexpected diagnostic output cannot race the driver's ISR by accessing the
|
||||
hardware FIFO directly. Firmware logs are disabled before binary telemetry
|
||||
tasks start, as before.
|
||||
|
||||
## Verification
|
||||
|
||||
The host C transport fixture compiles the production state machine with
|
||||
`-Wall -Wextra -Werror` and verifies:
|
||||
|
||||
- zero-accept submissions remain retryable;
|
||||
- accepted transfers become pending;
|
||||
- repeated pending polls never call submission again;
|
||||
- completion returns the sender to idle;
|
||||
- backend-confirmed safe retry returns to idle;
|
||||
- invalid arguments and unknown backend states fail closed.
|
||||
|
||||
The assembled ESP32-C3 prototype produced a normal 1,728-sample direct-driver
|
||||
capture with no packet gaps, sample gaps, resets, CRC failures, reported drops,
|
||||
loop overruns, trailing partial bytes, or timestamp-saturation frames.
|
||||
|
||||
For the connected-stall case, the USB endpoint was left enumerated without a
|
||||
serial reader long enough to overflow the 512-sample acquisition queue. When the
|
||||
reader opened, delivery preserved the oldest block through sequence 511 and
|
||||
resumed at sequence 1,706. The one observed gap and the cumulative device drop
|
||||
count both equal 1,194 samples. The timestamp difference across that gap is
|
||||
11,950,000 us, exactly 1,195 sample intervals. Packet gaps, CRC failures, loop
|
||||
overruns, trailing partial bytes, and timestamp-saturation flags are zero.
|
||||
|
||||
That exact validated stream is tracked as
|
||||
`tests/fixtures/direct_usb_stall.trk`, SHA-256
|
||||
`40f874b7eaa7f705524ecdd75f832e8a724252366633116ac015fc75dfd16558`, and
|
||||
its signature is asserted by the regression suite.
|
||||
|
||||
## Remaining delivery boundary
|
||||
|
||||
The stall capture begins at sample sequence 8. The flashing process still had
|
||||
the serial endpoint open long enough to drain sequences 0 through 7 before the
|
||||
capture application attached. This is not silent device-side loss; it precisely
|
||||
demonstrates the boundary of USB drain confirmation. Only an application-level
|
||||
ACK can prove that the intended receiver received and persisted a frame.
|
||||
|
||||
The planned BLE backend will use the same `PENDING` ownership rule while waiting
|
||||
for acknowledgements, retain unacknowledged frames for replay, and expose
|
||||
per-cause transport/queue counters separately.
|
||||
|
||||
## Host evidence handling
|
||||
|
||||
Live capture and offline decode now share one integrity tracker for packet and
|
||||
sample gaps/resets, timestamp anomalies, sensor status, saturation flags, drops,
|
||||
and acquisition overruns. Sequence classification is wrap-aware. The capture
|
||||
tool also accepts `--wire PATH` to preserve every serial byte before parsing,
|
||||
including startup text, corrupt frames, and trailing fragments.
|
||||
Reference in New Issue
Block a user