OXYGENHUB
3bf01e6e…46ac4d81
Code

The URL alone: https://oxygenhub.io/doomsdayone/retro-remote-debug-controller

Download ZIP

3bf01e6e95ae465b33c4034797e0a4fd662cd2be41eb4e8b6fcf2ddc46ac4d81 as it is now, without its history. Also as .tar.zst.

README.md

retro-remote-debug-controller

A tiny, portable HTTP control API for retro-platform emulators, and the shared tooling that speaks it. One contract → one test harness across every Doomsday One port.

An emulator launched with a control-port flag exposes a localhost HTTP server:

EndpointReturns
GET /statuscontract version, platform, frame counter, paused state
GET /screenshotPPM image of the live screen
GET /mem?addr=&len=&bank=raw memory bytes
GET /regsCPU registers (JSON)
POST /step?frames=advance N frames deterministically
POST /key, /reset(0.2) inject input

Why

Every one of these ports (Pac-Man on X16, Neo6502, Agon; and whatever's next) is chasing frame-exact arcade fidelity, and every one had its own fragile, platform-specific way to check state headless (write to the SD card, dump 64 KB of RAM on a magic jump, grep stdout — which lies). This replaces all of that with one contract:

  • GET /mem → assert game state (sprite table, actor positions).
  • GET /screenshot → Pillow → assert pixels, or just catch "nothing rendered" (the exact class of bug that costs an afternoon otherwise).
  • POST /step → deterministic, frame-addressable capture, so CI diffs don't flake against a free-running 60 Hz loop.

The payoff is uniformity: the same emu_control.py and the same pytest patterns drive the X16, Neo6502, and Agon emulators.

Layout

SPEC.md                 the normative HTTP contract (start here)
core/retro_control.h    portable backend vtable each emulator implements
core/retro_control.c    shared server: sockets, HTTP, PPM/JSON, marshalling  [next]
client/emu_control.py   shared pytest client
conformance/            tests an emulator runs to prove it conforms          [next]

Adopting it in an emulator (the shape)

Write the server once, adapt per fork. Each fork vendors core/ and implements ~5 callbacks, then calls the server:

#include "retro_control.h"

static retro_control_backend_t backend = {
    .platform       = "x16",
    .read_mem       = x16_read_mem,      /* debug-read, no side effects */
    .get_regs_json  = x16_get_regs_json,
    .get_framebuffer= x16_get_framebuffer,
    .step_frames    = x16_step_frames,
    .get_frame_count= x16_get_frame_count,
};

if (control_port)              /* set by -controlport / --control-port */
    retro_control_start(control_port, &backend);

The socket loop, HTTP parsing, PPM encoding, JSON framing, and the enqueue-to-emulator-thread marshalling live in the shared core — not in three different codebases.

Status

Early. SPEC.md (0.1.0) and the interfaces below are the stable target the forks build against; the server .c and conformance suite are landing next. Reference implementation: the Commander X16 fork (x16-emulator).