srdx_advertise.sg + srdx_twopi_test.sg (sigil-os ac5329f) complete the two-Pi SRDX session bringup layer. The advertisement protocol solves the bare-metal discovery problem: two Pi 4Bs on the same LAN, no DHCP, no DNS, no IP pre-configuration — the host broadcasts raw 32B ADV frames and the viewer discovers it. The integration test validates the full bringup flow from ADV build/parse through Mode-2 fallback logic to netplay tick paths. This is the last OS-side piece before two-Pi hardware session testing on real silicon.
SRDX Two-Pi Session Bringup — Advertisement Protocol + Integration Test
The bare-metal discovery problem
When two Pi 4Bs run sigilOS on a LAN, neither has a pre-known IP address. There's no DHCP server on a bare-metal demo table, no DNS, no configuration file. The host Pi needs to broadcast its presence; the viewer Pi needs to find it without being told where to look.
srdx_advertise.sg solves this with a minimal raw-frame broadcast protocol over the same NIC transport that SRDX already uses (sys 113-116: raw-send/recv). The host broadcasts a 32B ADV frame every ~60 frames; the viewer polls raw_recv and parses the frame. When a valid ADV is received, the viewer has the host's MAC and port — enough to initiate the SRDX negotiate phase.
ADV frames carry no secrets. MAC and port are safe to broadcast on a local LAN. Session credentials are exchanged in the negotiate phase (HELLO→READY, srdx_negotiate_host/srdx_negotiate_viewer), not in ADV.
ADV frame format — 32 bytes over raw NIC
SRDA (0x53, 0x52, 0x44, 0x41) — 4 bytes. srdx_adv_parse checks this first; any frame without the magic is silently discarded.negotiate_host call.port % 256 at [16], port / 256 at [17].Host + viewer API
adv_buf. Writes magic, version=1, MAC from NIC register, port LE-encoded. Called once at session init; the resulting buffer is broadcast repeatedly.srdx_adv_build(adv_buf) + raw_send(sys 113). Call ~every 60 frames on the host side. Fires-and-forgets; raw_send returns immediately regardless of whether any viewer received it.raw_recv(sys 116) into adv_buf. Returns 0 if no frame received this poll (non-blocking). Called in the viewer's discovery loop.out_mac (6 bytes), decode port from LE at [16-17] into out_port. Returns 0 on success, -1 if magic mismatch. The viewer calls this on every received frame; non-SRDX frames are discarded silently.Two-Pi real-hardware session flow
The complete bringup sequence, from power-on to active session:
HOST Pi VIEWER Pi
─────────────────────────────────── ─────────────────────────────────────
srdx_link() → ok srdx_link() → ok
srdx_adv_build(adv_buf)
[every 60 frames]: [discovery poll loop]:
srdx_adv_send(adv_buf) ────────→ srdx_adv_recv(adv_buf) → 0 (miss)
srdx_adv_send(adv_buf) ────────→ srdx_adv_recv(adv_buf) → 32B
srdx_adv_parse → mac + port
←──────── srdx_negotiate_viewer(mac, port)
srdx_negotiate_host()
HELLO→READY handshake ←────────→ HELLO→READY handshake
[active session]:
Mode-2: srdx_netplay_tick() Mode-2: srdx_netplay_tick()
Mode-1 fallback: pixel stream Mode-1 fallback: pixel stream
No IP addresses. No pre-configuration. The only shared knowledge is that both devices are on the same LAN and running sigilOS.
srdx_twopi_test.sg — integration test
| Check | What it verifies |
|---|---|
| ADV build magic | adv_buf[0-3] = 'SRDA' after srdx_adv_build |
| ADV build port LE | port=5900: adv_buf[16]=0x10, adv_buf[17]=0x17 (5900=0x1710) |
| ADV build MAC copy | MAC bytes [8-13] match NIC register source |
| ADV parse magic valid | srdx_adv_parse on valid frame → 0, mac+port extracted |
| ADV parse magic invalid | srdx_adv_parse on junk frame → -1 |
| Mode-2 fallback: empty ring | srdx_mode2_should_fallback(ring, 0 frames) → 0 (no fallback) |
| Mode-2 fallback: in-range | ring not desync, peer_seq within window → 0 |
| Mode-2 fallback: desync | ring desync flag set → 1 (should fall back to Mode-1) |
| netplay tick no-peer | srdx_netplay_tick(session, no peer) → rollback=0 |
| Mode-1 fallback tick | OVL w=0 (no overlay) → srdx_tick returns 0 |
PASS: TWOPI-PASS adv=ok parse=ok fallback=ok tick=ok