Skip to content

serial: investigate hardware (RTS/CTS) + software (XON/XOFF) flow control for sustained sends #9

@johnjezl

Description

@johnjezl

Split from #8, which now tracks send pacing (the proven, low-risk mitigation). This issue is the investigation into proper flow control as a more robust fix. It is intentionally an investigation, not a build ticket — there are unverified preconditions and an unexplained artifact to resolve before we commit to a mechanism.

Background

Sustained back-to-back labctl serial send calls to the SLM-OS shell on a Pi 5 drop contiguous mid-payload byte windows (full evidence in #8). Pacing (#8) mitigates by inserting gaps between writes. Flow control would do the same automatically via back-pressure, without the driver having to guess chunk sizes/delays — if the wiring and both endpoints support it.

Option A — Hardware flow control (RTS/CTS)

ser2net's serialdev connector accepts an RTSCTS serial option; plumbing a per-port flag through is mechanically easy. The hard part is the three preconditions, any of which makes it a no-op or a footgun:

  1. Cabling. The lab's console adapters are CP2102 USB-serial (confirmed on pi-5-1: Silicon_Labs_CP2102…). These console harnesses are almost certainly 3-wire (TX/RX/GND). RTS/CTS needs those lines physically wired through to the Pi 5 header — most don't have them.
  2. SBC side. The receiving SLM-OS shell must enable crtscts on its tty and actually assert RTS when its RX FIFO fills. That's custom firmware behavior — unverified.
  3. Footgun. Enabling RTSCTS in ser2net when CTS is never asserted (unwired) makes writes block/hang rather than degrade. A misconfigured flag would silently break the console. Needs a guard and/or very clear docs.

Option B — Software flow control (XON/XOFF)

Not in the original request but worth evaluating: XON/XOFF works over the existing 3-wire cables (no recabling). For a text command shell it may be entirely adequate. Caveat: 0x11/0x13 become reserved control bytes — unsuitable for binary payloads, but replay-step traffic is text. This may be the cheaper middle ground between pacing and RTS/CTS.

Open question to resolve first

The #8 evidence includes a detail that pure FIFO overrun does not explain: a stray printable byte appearing as its own command on the next line. Overrun = bytes vanish and the command comes out short; a surviving byte landing on a new line implies reordering or a second mechanism (line-discipline interaction, echo, or \r framing). If there is a second bug, flow control won't catch it. Reconcile this before picking a mechanism.

Scope (if/when we build)

  • Ser2NetPort (src/labctl/serial/ser2net.py) gains a flow-control field; the config generator emits the option.
  • The serial_ports table (src/labctl/core/database.py) currently persists only baud_rate — a persistent per-port setting needs a new column + schema migration, manager wiring, and CLI surface.
  • CLI flag on port config to enable/disable.

Acceptance criteria

  1. Confirm (on the bench) whether pi-5 console cabling carries RTS/CTS, and whether the SLM-OS tty asserts RTS under FIFO pressure.
  2. Resolve the stray-byte artifact above.
  3. Decide mechanism — RTS/CTS, XON/XOFF, or "pacing (serial: per-byte / per-chunk send pacing for labctl serial send #8) is sufficient, don't build flow control" — and record it in docs/DECISIONS.md.
  4. Only then, implement the chosen option with a guard against the unwired-CTS hang.

References

🤖 Generated with Claude Code

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions