← Blog
0.7.0 · OS · SRDX · MILESTONE

SRDX Host-Side Frame Relay — OS 0.7.0 Critical Path Complete

June 22, 2026 · sigil-os 446a38b (master) · Sigil-Docs
srdx os networking relay milestone 0.7.0

srdx_relay.sg (sigil-os 446a38b) closes the OS-side SRDX loop. The host-side relay is the last OS piece before two-Pi silicon testing: it captures the live framebuffer, encodes it via srdx_encode_frame, and streams encoded frames to the viewer over the SRDX wire. Combined with viewer.sg (258d512, sigil-apps) which already holds the viewer-side decode path, the full SRDX loop is now wired — host captures fb → relay encodes → sends over raw NIC → viewer decodes → blits to canvas. QEMU PASS T1–T5.

This commit also ASCII-cleans all cc0 source files (the cc0 lexer rejects non-ASCII characters including em dashes and Unicode arrows) and fixes three bugs in net_test.sg found during the ASCII-clean pass.

No screenshot — relay is raw NIC + encoded frame stream; no framebuffer output from the relay path itself.


1. srdx_relay.sg — host-side frame relay

The relay runs on the host Pi. Each tick: capture the live framebuffer, encode all dirty tiles into the SRDX frame format (srdx_encode_frame), build the relay wire header, and send header + payload to the connected viewer.

srdx_relay_init(port)
Listen on port (5900 by default). Broadcasts ADV frames via srdx_adv_send on the raw NIC (sys 113) every ~60 ticks so the viewer can discover the host. Accepts the viewer's connection via srdx_link_accept.
srdx_relay_tick(fb, pitch, fw, fh)
Capture one frame. Calls srdx_encode_frame(fb, pitch, fw, fh, enc_buf) to encode all dirty tiles into enc_buf. Increments the sequence number (seq). Builds the relay wire header (8 bytes). Sends relay_hdr + encoded_payload via srdx_wire_raw_send (sys 113).
relay_hdr format
8-byte little-endian frame header. Bytes 0–1: seq (u16 LE) — frame sequence number, wraps at 65535. Bytes 2–3: enc_len (u16 LE) — encoded payload length in bytes. Bytes 4–7: RELY tag (0x59 0x4C 0x45 0x52 — ASCII "RELY") — identifies relay frames and protects against stray raw-NIC traffic.
srdx_relay_run(fb, pitch, fw, fh, n_ticks)
Run the relay loop for n_ticks ticks. Calls srdx_relay_tick each iteration. On real silicon, this is the main loop — runs until the viewer disconnects or the host shuts down.

ABI compatibility

The relay_hdr + encoded_payload format is consumed by viewer.sg (srdx_decode_inline) without ABI change. The viewer already expects: check relay_hdr magic → extract enc_len → decode enc_len bytes of SRDX payload → blit dirty rects. The viewer's state panel shows seq from relay_hdr.


2. cc0 ASCII-clean + net_test.sg fixes

The cc0 lexer is strict ASCII — it rejects non-ASCII bytes (Unicode arrows, em dashes, etc.) that had crept into the // comment lines of newly authored cc0 files. This commit strips them across 6 files and documents the constraint: cc0 source files must be pure ASCII 32–126 + newlines. No Unicode in Sigil or cc0 source.

Three bugs fixed in net_test.sg discovered during the clean pass:

T8b off-by-one
The final character '8' in the test string was expected at index [7] but is at [6] — corrected to [6]. The test was checking one position past the end.
T6 body_off
body_off for the test HTTP response was expected to be 21 but the actual offset after the \r\n\r\n separator is 19. Fixed.
T5/T6/T7 CRLF
\r\n string literals are not valid in the cc0 string literal model — cc0 only allows printable ASCII in string literals. CRLF pairs must be written as poke8(13); poke8(10) (carriage return + newline as separate byte writes). All CRLF occurrences in the net_test.sg HTTP response stubs replaced.

3. QEMU PASS T1–T5

No screenshot (relay is raw NIC + encoded frame stream — no framebuffer output). QEMU loopback verifies each stage:

CheckWhat it verifies
T1 ADV broadcastsrdx_relay_init sends valid ADV frame (magic SRDA, port LE, MAC)
T2 relay startsrdx_relay_init returns 0 (loopback socket ready)
T3 relay ticksrdx_relay_tick encodes frame, builds relay_hdr with correct RELY tag
T4 hdr formatrelay_hdr bytes 4–7 = RELY (0x59,0x4C,0x45,0x52); seq=1; enc_len>0
T5 relay runsrdx_relay_run(..., 3) completes 3 ticks, seq=3

PASS: SRDX-RELAY-PASS adv=ok start=ok tick=ok hdr=ok run=ok


4. SRDX end-to-end loop closed

With srdx_relay.sg on the OS and viewer.sg (sigil-apps 258d512) holding the viewer decode path, the complete SRDX loop is wired in software:

Host Pi:
  fb_tap -> srdx_encode_frame -> relay_hdr + payload -> srdx_wire_raw_send (sys 113)

Network (raw NIC):
  relay_hdr + encoded payload

Viewer Pi:
  srdx_decode_inline -> poke32 BGRA32 blit -> Lumen chrome composite -> display

Two-Pi hardware testing is the next step: flash host + viewer builds to real Pi 3 hardware, connect over gigabit, run srdx_relay_run on host and srdx_viewer IS_SCENE on viewer. The ADV discovery protocol (srdx_advertise.sg, ac5329f) handles host discovery without IP pre-config.