mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2026-10-06 09:57:47 +00:00
A realtime `lf read` streams samples straight to the host at the LF sample rate, around 125 kB/s. If the host stopped draining for even a moment, async_usb_write_requestWrite() returned false, and ReadLF_realtime() treated that as fatal: it returned PM3_EIO through a goto that also skipped async_usb_write_stop(). The IN endpoint was left busy, every later usb_write() then returned PM3_EIO, and the device went silent until it was physically replugged. A USB bus reset does not clear it -- EP0 keeps working, descriptors read fine, only bulk IN is dead. That is what a long `lf read` looked like from the client: a transfer that stopped early, and then a device that would not answer the next command. A busy endpoint is back pressure, not an error. The sampling loop now waits for the host, up to 100ms, and only gives up if it never comes back. Every exit path closes the async write. The spins inside the USB helpers are bounded and drop the stuck packet instead of turning into an infinite loop, which is the other half of why the device never recovered. Measured against a reader deliberately held at 41 kB/s: before, the stream died at 212238 of 300000 bytes and the unit needed a replug; after, 300000 of 300000 and it still answers. The last packet of a stream was being lost as well. The host's CDC read buffer is two max sized packets, and a bulk IN transfer only completes on a short packet or a full buffer, so a stream ending on a full 64 byte packet was left sitting in a half filled buffer. It showed as exact parity on the packet count: 513 packets requested -> 512 delivered 514 -> 514 515 packets requested -> 514 delivered 516 -> 516 async_usb_write_stop() now always sends a closing packet, the leftover partial bytes when there are any and a zero length packet otherwise, the same way usb_write() already did for its own transfers. On the client side a short transfer is reported instead of being presented as a complete read, the device is told to stop streaming on that path too, and the in place byte counter is repeated with its final value, since the loop only samples it every 10ms and the last line printed was stale. Lastly `lf read` and `lf sniff` cap the sample count to the graph buffer size. Anything past it was streamed and then discarded by getSamplesFromBufEx(), so `-s 1500000` spent about two extra seconds collecting 220000 samples that were thrown away, and printed "Received 1500000 / 1500000 bytes" followed by "Got 1280000 samples" with nothing to explain the gap. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>