Skip to content

Fix/19 firmware robustness - #24

Open
qquais wants to merge 7 commits into
mainfrom
fix/19-firmware-robustness
Open

qquais wants to merge 7 commits into
mainfrom
fix/19-firmware-robustness

Conversation

@qquais

@qquais qquais commented Sep 9, 2026

Copy link
Copy Markdown
Collaborator

No description provided.

@qquais
qquais requested a review from RajkumarGara September 9, 2026 23:12
@qquais qquais self-assigned this Sep 9, 2026
…drop

A single lost PONG on the office WiFi used to tear down a healthy TCP
connection and force a reconnect every ~40s. Add HeartbeatMonitor to
count consecutive misses and only drop the socket after three in a row.
Raise the PONG wait from 2s to 5s, feed the watchdog before the blocking
recv, and stop late PONGs from being written to the UART as device data.
…tness

# Conflicts:
#	src/pi/PicoScriptDeployer.py
…s, non-blocking heartbeat

The reconnect backoff slept up to 30s with the watchdog fed only once per
attempt, so with the Pi down the board rebooted itself on the third try
instead of backing off. Add sleep_fed() and a permanent 5s socket timeout so
nothing can outlast the 8.4s watchdog window; a stalled network is now a
reconnect, not a reboot.

Move the registration hello inside the try so a server that hangs up right
after accepting causes a reconnect rather than ending the program. Replace
the setblocking toggle and fixed sleep with select.poll(), which wakes the
instant the server sends a command and catches hangup/error events on the
same pass. Loop on send() via send_all() so a partial send cannot truncate a
command. Make the heartbeat non-blocking: HeartbeatMonitor now owns the
PING/PONG timing and is asked once per pass. Strip a PONG that arrives in
the same chunk as a command, mirroring how PtyServer already handles a PING
glued to device data.

Verified with 32 unit tests and a desktop simulation of the full loop
against a fake server: backoff without watchdog starvation, invalid UTF-8
relayed without disconnecting, glued PONG separated from its command, server
hangup detected immediately, and reconnect after three missed PONGs.
… join

The original firmware called wlan.connect() once, unguarded. On the first
boot after a flash the CYW43 radio is not ready and that call throws OSError
EPERM every time (seen on two boards on 2026-09-11), leaving the board frozen
at the REPL. A soft reset does not clear the radio; only a hardware reset
does.

connect_wifi() now retries with the same capped backoff TCP uses, feeding
the watchdog throughout, treats a failed join status as a failed attempt
instead of waiting forever, powers the radio down between attempts, and
after five consecutive failures resets the hardware itself. The TCP connect
loop checks wlan.isconnected() before each attempt and rejoins WiFi first if
the link has dropped mid-run.

Verified in the desktop simulation: two EPERM failures then a successful
join; a mid-run WiFi drop followed by rejoin and TCP reconnect; and an AP
that is never found, ending in machine.reset() after five attempts with the
watchdog never starved.
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.

2 participants