Files
scanengine-3/hardware
Thomas Ales 76ed7828cc Helios: read CRLF replies as lines, not as CR plus dead air
The rig transcript (tools/helios_lds_probe.py) settles where the panel's
32 mA came from, and it was never the laser: LDS reads 100 mA, answers for
itself, and takes a write of 900 mA on the first attempt. 32 is LCE — bit
5, "Door switch open" — arriving in the diode-current field.

Every reply is CRLF-terminated and padded with a blank line or two:

    b'LDS =    100 mA\r\n\r\n'
    b'LCE =     32\r\nBit 15..0: 0000 0000 0010 0000\r\n\r\n\r\n'

_read_line() read up to CR, so the final LF of every reply stayed in the
buffer, and the next read waited out the whole port timeout for a CR that
only the next command would bring. A second of dead air per query: replayed
against the transcript's byte timing, one status poll took 8.6 s against
the 1 s interval that schedules it. That is also what let the values drift
apart — a query whose deadline goes to a blocked read gives up while its
own reply is still on the wire, the next query flushes the port mid-line,
and the fragment it reads is "     32", the value half of LCE's reply.

Lines are now framed on CR, LF or CRLF out of a receive buffer that
_discard_input() clears along with the port, so nothing survives a flush
half-read. The same replay now polls in 0.59 s.

Tests carry the transcript's real framing (padded values, trailing blank
lines) instead of the tidied "LER = 0" it was guessed to be, plus the two
regressions: a late fragment must not become the next query's value, and a
reply must be readable without waiting out the port.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-08 08:01:27 -05:00
..