diff --git a/components/bldc_haptics/example/main/bldc_haptics_example.cpp b/components/bldc_haptics/example/main/bldc_haptics_example.cpp index 6576fa19c..24cdc79f4 100644 --- a/components/bldc_haptics/example/main/bldc_haptics_example.cpp +++ b/components/bldc_haptics/example/main/bldc_haptics_example.cpp @@ -794,6 +794,10 @@ extern "C" void app_main(void) { } else if (start - telemetry_stall_start > kTelemetryStallTimeout) { streaming = false; // host abandoned the stream: stop flooding a full FIFO telemetry_stall_start = {}; + // Drop the queued backlog now (a tab close does not unmount, so it + // is not cleared for us) so a reconnecting host reads a clean stream + // instead of stale telemetry it might mis-parse as a command reply. + usb.vendor_write_clear(); logger.warn("Telemetry auto-paused: the host stopped draining the USB vendor " "endpoint (re-enable streaming from the web console)"); } diff --git a/components/bldc_haptics/example/webapp/index.html b/components/bldc_haptics/example/webapp/index.html index 048761e33..fcdeb533f 100644 --- a/components/bldc_haptics/example/webapp/index.html +++ b/components/bldc_haptics/example/webapp/index.html @@ -480,6 +480,9 @@

Log

let device = null, ifaceNumber = null, epIn = null, epOut = null; let manualDisconnect = false; const parser = new StreamParser(); + // True during the brief pre-handshake RX drain (see initializeDevice): stale + // frames left in the device's TX FIFO by a previous session are discarded. + let draining = false; // Single in-flight transaction: resolved by the RX pump when a frame of an // accepted reply type (or ERROR) arrives. @@ -643,6 +646,9 @@

Log

} function dispatchFrame(frame) { + // Discard everything during the brief pre-handshake RX drain: these are + // stale frames from a previous session, not replies to anything we sent. + if (draining) return; // Discovery reply (reserved module 0xFF): hand the TLV payload to a pending // module probe. Not this device's haptics module, so handle it before the // module filter below drops it. @@ -793,6 +799,15 @@

Log

async function initializeDevice() { try { + // Flush any stale frames the device queued for a previous session (its TX + // FIFO is not cleared on an abrupt tab close) before we send anything, so + // an old telemetry / reply frame can't be mis-read as the response to our + // first command. RX keeps running; dispatchFrame drops frames while + // draining is set. + draining = true; + parser.reset(); + await new Promise((resolve) => setTimeout(resolve, 150)); + draining = false; // Confirm this device serves the haptics module (best-effort warning only; // we still attempt init so the user can force it if discovery is stale). await checkModulePresent();