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.
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_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).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.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:
'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.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.\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:
| Check | What it verifies |
|---|---|
| T1 ADV broadcast | srdx_relay_init sends valid ADV frame (magic SRDA, port LE, MAC) |
| T2 relay start | srdx_relay_init returns 0 (loopback socket ready) |
| T3 relay tick | srdx_relay_tick encodes frame, builds relay_hdr with correct RELY tag |
| T4 hdr format | relay_hdr bytes 4–7 = RELY (0x59,0x4C,0x45,0x52); seq=1; enc_len>0 |
| T5 relay run | srdx_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.