mirror of
https://git.k-space.ee/arti/vt1200.git
synced 2026-11-02 12:23:17 +02:00
A new folder so the demo can be reproduced instead of re-derived: the delivery
and the clip packing were living in throwaway scripts under /tmp, and the only
written route to a real clip was an ffmpeg recipe that packs MSB first -- the
order that mirrors every eight pixels on a display.
harness/badapple/rdebug_load.py image -> terminal RAM over the firmware's
own remote-debug service (TCP 771), then
jump to the entry from vidstream.env
harness/badapple/clip_from_video.py video -> LSB-first 1-bpp frames for
make_tiles.py --clip
harness/badapple/demo.sh ICMP gate, load, send; one command
harness/badapple/README.md setup, run in MAME, run on real hardware,
what success looks like, failure modes
The loader records the two protocol facts that cost time to find: a 512-byte
poke chunk (1024 is mis-parsed as a following opcode: "Invalid command
0xA5A5A5A5"), and that nothing can be probed after the jump, so the image is
read back BEFORE jumping and the run is observed from the machine afterwards.
Tests cover what a wrong assumption would silently corrupt -- chunk arithmetic,
the linkage the entry point is read from, and pixel 0 landing on bit 0 -- and
the tool was exercised end to end against MAME: demo.sh loaded the payload and
the terminal reported DICT_BYTES=32768, DICT_BAD=0, RX_OK=28, TILES_DROP=0
while the sender saw frames_rx=129, drops=0.
153 tests pass (7 new).
77 lines
2.8 KiB
Python
77 lines
2.8 KiB
Python
"""Tests for the rdebug loader and the clip builder.
|
|
|
|
The pieces that touch a live terminal cannot be tested here; what is tested is
|
|
everything that decides *what* gets written where, because those are the parts a
|
|
wrong assumption silently corrupts: the chunking arithmetic, the linkage the
|
|
entry point is read from, and the 1-bpp packing the terminal actually reads.
|
|
"""
|
|
import struct
|
|
|
|
import pytest
|
|
|
|
from harness.badapple import clip_from_video
|
|
from harness.badapple import rdebug_load
|
|
|
|
# --- chunking -------------------------------------------------------------
|
|
|
|
def test_chunks_are_transfer_sized_and_cover_the_image_once():
|
|
data = bytes(range(200)) * 23 # 4,600 B: not a multiple of 512
|
|
parts = rdebug_load.chunks(data, 512)
|
|
assert [len(p) for p in parts] == [512] * 8 + [504]
|
|
assert b"".join(parts) == data
|
|
|
|
|
|
def test_chunks_refuse_a_size_the_firmware_cannot_take():
|
|
# 1024 is rejected by the firmware: it reads the body's first word as the
|
|
# next opcode ("Invalid command 0xA5A5A5A5" on a 0xA5-filled chunk).
|
|
with pytest.raises(ValueError):
|
|
rdebug_load.chunks(b"x", 1024)
|
|
with pytest.raises(ValueError):
|
|
rdebug_load.chunks(b"x", 0)
|
|
|
|
|
|
def test_addresses_advance_by_the_chunk_length_in_bits():
|
|
base = 0x018C0000
|
|
assert rdebug_load.chunk_addr(base, 0) == base
|
|
assert rdebug_load.chunk_addr(base, 1) == base + 512 * 8
|
|
|
|
|
|
# --- linkage --------------------------------------------------------------
|
|
|
|
def test_env_file_gives_the_entry_and_the_pool_size(tmp_path):
|
|
env = tmp_path / "vidstream.env"
|
|
env.write_text("POOL_BYTES=249856\nSTATIC_PTR=0x01C00080\n"
|
|
"ENTRY_PTR=0x018D0270\n")
|
|
got = rdebug_load.read_env(env)
|
|
assert got["ENTRY_PTR"] == 0x018D0270
|
|
assert got["POOL_BYTES"] == 249856
|
|
|
|
|
|
def test_missing_env_file_says_so_instead_of_guessing(tmp_path, capsys):
|
|
rc = rdebug_load.main(["--image", "x.bin", "--env", str(tmp_path / "no.env")])
|
|
assert rc == 2
|
|
err = capsys.readouterr().err
|
|
assert "no build environment" in err and "build-stream.sh" in err
|
|
|
|
|
|
# --- the clip format ------------------------------------------------------
|
|
|
|
def test_packed_rows_put_pixel_zero_on_bit_zero_of_byte_zero():
|
|
"""The terminal reads bit 0 of a byte as the leftmost pixel.
|
|
|
|
Same rule the payload's encoder uses (`vidsrc.Rows.pack_row`), and the one
|
|
an MSB-first packer gets wrong in a way that only shows on a display.
|
|
"""
|
|
pixels = [[0] * 16]
|
|
pixels[0][0] = 1 # leftmost pixel of the row
|
|
pixels[0][15] = 1 # last pixel of the second byte
|
|
row = clip_from_video.pack_row(pixels[0])
|
|
assert len(row) == 2
|
|
assert row[0] == 0x01
|
|
assert row[1] == 0x80
|
|
|
|
|
|
def test_pack_row_rejects_a_short_row():
|
|
with pytest.raises(ValueError):
|
|
clip_from_video.pack_row([0] * 15)
|