aa48d8784f
Every frame of 16 bytes or more was rejected as LengthMismatch and silently dropped. Found by the new end-to-end suite; neither the host tests nor the sensor verification could reach it, because it needs real bus timing and a frame past the watermark. The watermark interrupt fires mid-frame once 16 bytes are in the FIFO. The ISR drained those, stamped last_byte_at, and started frame_gap. The remaining bytes then sat *below* the watermark and raised no interrupt at all until the PL011's receive timeout eventually fired, so frame_gap measured its 1822 us gap from a mid-frame timestamp, concluded the frame had ended while its tail was still arriving, and parsed a prefix whose LEN field disagreed with its length. Frames under 16 bytes never trip the watermark, so their only interrupt is the receive timeout, by which point every byte is drained and the timestamp is honest. That is why all five real commands worked and only an oversized PING exposed it. frame_gap now drains the FIFO itself before each decision rather than trusting a timestamp the ISR left behind, so a byte that has landed can always push the deadline back. The gap is then measured from when the byte was observed rather than when it arrived, making the reply up to one gap period later than strictly necessary; 1.8 ms is a fair price. Verified on hardware across every payload size from 0 to 59 — frames of 5 to 64 bytes — with the node's error counters accounting exactly for the faults the suite injects deliberately and nothing else. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>