qemu: start every panel daemon, and keep Modbus off the control channel

Stage-2 init started only warden-flared and warden-modbus from the
payload, so every daemon-backed screen (Automation, MikroTik, Mining,
RS485, Starlink, Services) sat in its "not running" state on the rig
while the bench panel showed the daemons up with nothing attached. It now
starts every warden-* daemon it finds in the panel's own S-number order
(ai, automation, modbus, mikrotik, asic, starlink, stratum, flared), each
with no arguments as start-stop-daemon runs them on the panel. flare-edge
tools/rig-pull-daemons.sh copies a panel's static binaries in.

Doing that exposed a latent alias: init pointed warden-modbus's /dev/ttyS4
at /dev/ttyS0 whenever ttyS0 existed, and with --ctl that port IS the
control channel, so Modbus polls arrived inside the wake reply and the
bridge hung. run.sh now always attaches an RS485 pci-serial (a null
chardev without --rs485), and init aliases ttyS4 to ttyS1 when warden.ctl
is on the cmdline, ttyS0 otherwise.

Verified on a boot with all eight daemons: status json reports
automation.engine, mikrotik.backend, mining.available and rs485.available
true with the Modbus scan sweeping the empty UART; six daemon-backed pages
matched screenshots of the bench panel structurally (0/256 cells differ).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013aHKWzT5EF86RFKRMtAv9n
This commit is contained in:
Noah
2026-09-08 00:47:08 -06:00
co-authored by Claude Fable 5.1
parent eb16a301c0
commit 9b6428db47
4 changed files with 50 additions and 12 deletions
+17 -3
View File
@@ -47,8 +47,12 @@ mount_fatal "oem${slot}" /oem
mkdir -p /userdata/warden
# RS485: warden-modbus hardcodes /dev/ttyS4 at compile time; alias it to the
# VM's pci-serial UART when one is present (needs the virt.fragment kernel).
[ -c /dev/ttyS0 ] && ln -sf /dev/ttyS0 /dev/ttyS4
# VM's RS485 pci-serial UART (needs the virt.fragment kernel). run.sh lists
# the control channel's port first when there is one (warden.ctl on the
# cmdline), so the RS485 UART is ttyS1 then and ttyS0 otherwise. Aliasing
# ttyS0 blindly put Modbus polls on the control channel.
if grep -qw warden.ctl /proc/cmdline; then rs485="/dev/ttyS1"; else rs485="/dev/ttyS0"; fi
[ -c "$rs485" ] && ln -sf "$rs485" /dev/ttyS4
# Network: slirp user-mode net on eth0 (DHCP, fallback to QEMU's static map).
# The fallback keys off the interface actually having an address: udhcpc
@@ -86,7 +90,17 @@ if grep -qw warden.fwapply /proc/cmdline; then
export WARDEN_FW_ALLOW_APPLY=1
echo "init: OTA APPLY ENABLED (warden.fwapply)"
fi
for d in /usr/bin/warden-flared /usr/bin/warden-modbus; do
# The same daemons the panel's SysV scripts start, in their S-number order
# (S92 ai, S93 automation, S94 modbus, S95 mikrotik, S96 asic/starlink/
# stratum, S97 flared), each with no arguments and no environment, exactly
# as start-stop-daemon runs them there. A daemon that cannot live on -M virt
# (warden-ai wants the NPU) exits into its log and the UI shows the same
# "not running" it would show on a panel whose daemon died; that is the
# panel's behaviour, not a rig substitute for it. warden-watchdog stays out:
# it and a payload flared do not mix (README).
for d in /usr/bin/warden-ai /usr/bin/warden-automation /usr/bin/warden-modbus \
/usr/bin/warden-mikrotik /usr/bin/warden-asic /usr/bin/warden-starlink \
/usr/bin/warden-stratum /usr/bin/warden-flared; do
if [ -x "$d" ]; then
name="$(basename "$d")"
echo "init: starting $name"