Skip to content

fix: self-heal the LCD after USB write failures (reconnect + open() correctness)#2

Open
tekgnosis-net wants to merge 5 commits into
ananthb:mainfrom
tekgnosis-net:fix/lcd-reconnect
Open

fix: self-heal the LCD after USB write failures (reconnect + open() correctness)#2
tekgnosis-net wants to merge 5 commits into
ananthb:mainfrom
tekgnosis-net:fix/lcd-reconnect

Conversation

@tekgnosis-net

Copy link
Copy Markdown

Problem

The daemon opens the LCD once at startup. If the device hits a USB write failure or re-enumerates mid-run, nothing re-establishes it — the panel reverts to its built-in default screen and stays there until the service is manually restarted. The existing try_lcd_reconnect() only triggers when the device was absent at startup (lcd == None); it never fires for a device that was working and then dropped, because nothing ever sets the handle back to None.

Changes

  • LcdHealth — a small, hardware-free state machine that tracks consecutive write outcomes. After N consecutive failures (default 10) it demotes the handle to None (dropping the HidDevice releases the libusb interface claim), which lets the existing try_lcd_reconnect() reopen the device. If recovery keeps failing past a configurable window, it exits so systemd relaunches a fresh process. Transient single failures (interspersed with successes) never trip the threshold.
  • Throttled logging — write errors are logged once, then at most once per interval, instead of flooding the journal.
  • open() correctness — require the display interface (interface 1, output-only) and drop the fallback that could open the wrong (input) interface.
  • Configurable reconnect interval (default 5s; was hard-coded 30s) plus new config keys (lcd_failure_threshold, lcd_reconnect_interval_ms, lcd_exit_after_ms, lcd_error_log_interval_ms).
  • The libusb backend is retained intentionally — interface 1 is output-only and has no hidraw node, so hidraw can't drive it.

Testing

  • 7 unit tests for the LcdHealth logic (threshold, success-reset, exit-only-after-connect, log throttle) — pure, deterministic, no hardware.
  • Validated live on an HT32 panel (Proxmox host): simulated a USB drop via authorized=0/1; observed demote after 10 failures → reopen interface 1 → reconnected, fully in-process (no restart). cargo test + clippy -D warnings clean.

Pure, hardware-free state machine for failure-streak demote/reconnect
decisions, exit-to-systemd timing, and throttled error logging. 7 unit tests.
lcd_failure_threshold, lcd_reconnect_interval_ms, lcd_exit_after_ms,
lcd_error_log_interval_ms with sane defaults.
…back

Interface 1 is the only display interface (output-only, no hidraw node).
The old devices.first() fallback could open interface 0 (input device).
…hrottle)

Record every device write outcome into LcdHealth. On a sustained failure
streak, drop the handle to None (releasing the libusb claim) so the existing
try_lcd_reconnect() reopens it; throttle the error log; and exit-to-systemd as
a last resort. Replaces error-propagation at the heartbeat/render call sites.
Replace the hard-coded 30s reconnect rate-limit with lcd_reconnect_interval_ms
(default 5s) for faster recovery. The main.rs loop log-throttle is already
correct as of 0.8.1, so it is left unchanged.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant