From 10bdd1a73ca7d3d775ed4c190cdd6b37e1106b7a Mon Sep 17 00:00:00 2001 From: "opencode.energia.arti.ee" Date: Sat, 31 Oct 2026 03:37:21 +0000 Subject: [PATCH] spec: delta wire form is grouped; status cadence has out-of-cadence reports --- .../2026-10-30-vt1200-video-streaming-design.md | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/docs/superpowers/specs/2026-10-30-vt1200-video-streaming-design.md b/docs/superpowers/specs/2026-10-30-vt1200-video-streaming-design.md index 4a64785..8e99dc9 100644 --- a/docs/superpowers/specs/2026-10-30-vt1200-video-streaming-design.md +++ b/docs/superpowers/specs/2026-10-30-vt1200-video-streaming-design.md @@ -182,9 +182,10 @@ frame start, so a frame never straddles the ring wrap and slot ownership is expl * **Dictionary**: 256 × 32×32 1-bpp (128 B each = 32 KB), built offline by k-means over the video's tiles, uploaded in chunks, held in the startup allocation. * **Frame**: header + 1,280 index bytes (40×32 grid, row major). `kind = TILES_FULL`. -* **Delta**: `kind = TILES_DELTA` + a changed-tile list: `count u16`, then - `count` × (`pos u16`, `index u8`) little-endian, where `pos` is the row-major - tile position and `index` its new dictionary entry. Deltas are the normal case. +* **Delta**: `kind = TILES_DELTA` + a changed-tile list in three blocks, little-endian: + `count u16`, then `count` × `pos u16`, then `count` × `index u8`; `pos` is the row-major + tile position and `index` its new dictionary entry. Grouped rather than interleaved, so the + decoder validates all positions before it paints anything. Deltas are the normal case. * Decoder: one cached loop; `PIXBLT B,XY` from `dict + index*128`, `DYDX=(32,32)`, `SPTCH=32` (a 32-px row is **two** words), destination XY `(ty*32, tx*32)`. * **Repair**: a `TILES_FULL` keyframe every 2 s (and on the host's first frame), so @@ -192,8 +193,11 @@ frame start, so a frame never straddles the ring wrap and slot ownership is expl ### 8.4 Host ↔ terminal back-channel -The payload already has TX. It sends a small status frame every 64 frames: -frames received, `crc` failures, drops, `CSR0` error bits, and the worst decode time. +The payload already has TX. It sends a small 16-byte status body every 64 frames — frames +received, `crc` failures, drops, `CSR0` error bits, heap free, a `dict_state` byte, and the worst +decode time in REFCNT ticks (the TMS34010 refresh counter, not µs) — plus an out-of-cadence report +after the first accepted frame and after any refused dictionary chunk, so a failed upload is +diagnosable instead of looking like a payload that never started. The host uses it to pace the stream and to force a keyframe when drops are seen. **Call:** status every 64 frames (~2 s at 30 fps); no per-frame ack.