OXYGENHUB

HTTP Contract

Andy McCall edited this page · 2 revisions

HTTP Contract

The normative spec is SPEC.md in the repo; this page is the readable tour. Contract version 0.6.0 (semver — clients assert on the MAJOR). Every minor has been purely additive:

LevelAdded
0.1/status, /screenshot, GET /mem, /regs, /step, /pause, /resume
0.2/key, /reset
0.3POST /mem (write), /audio
0.4/pointer
0.5/pad
0.6/perf (performance metrics), /status.capabilities

A server advertises the highest level whose backend callbacks are all present (contract is cumulative), and from 0.6 lists each group it serves in capabilities, so a client can ask for perf directly.

Principles

  • Opt-in. The server is OFF by default; it starts only with a control-port flag. Zero cost to normal use.
  • Localhost only. It MUST bind 127.0.0.1. /mem and input injection are a memory-read / remote-control surface and never leave the machine.
  • The contract is the HTTP surface, not the flag. Each emulator names its flag idiomatically (x16emu: -controlport N; FAB: --control-port N). Only the endpoints are normative.
  • Determinism is first-class. Every state read observes a consistent machine captured at an instruction/frame boundary — never a torn read from the HTTP thread.

Endpoints

GET /status

{ "contract":"0.6.0", "emulator":"x16emu-enhanced", "platform":"x16",
  "frame":12345, "paused":true, "running":true,
  "capabilities":["mem","regs","screenshot","step","key","reset",
                  "mem-write","audio","pointer","pad","perf"] }

frame is the monotonic completed-frame counter — the determinism anchor. Clients MUST reject a mismatched contract MAJOR. capabilities (0.6) is absent on older servers: read contract there.

GET /screenshot

Binary PPM P6, 8-bit RGB, image/x-portable-pixmap. The most recent complete frame (never a half-scanned one). Read width/height from the PPM header — don't hardcode.

GET /mem?addr=&len=[&bank=]

Raw bytes (application/octet-stream). addr decimal or 0x-hex, in the platform's address space. bank is an optional selector for banked platforms (X16); omitted → current bank; ignored on flat-memory platforms. Reads use the debug path (no side effects).

GET /regs

Registers as JSON; keys are platform-specific (see Per-Platform Notes).

POST /step?frames=N

Advance exactly N complete frames (default 1), then halt. Returns { "frame": <new counter> }. Meaningful when paused; on a free-running machine the server pauses, runs N, and stays paused.

POST /pause / POST /resume

Halt / free-run. Returns { "paused": true|false }.

POST /key?text=|code=[&down=] / POST /reset (0.2)

Inject a key: text= a character, or code= a raw platform key code; down=1 holds it, down=0 releases, neither taps (press and release). /reset resets the machine (the one time frame may go backwards).

POST /mem?addr=[&bank=] (0.3)

The body's bytes written at addr (a debug poke). Returns {"written": n}.

GET /audio (0.3)

The sound synthesised since the last call, as a PCM WAV; read the rate and channels from its header. Under pause + step it is exactly the stepped frames' sound. X-Rrdc-Audio-Dropped counts samples lost to overflow.

POST /pointer?x=&y=|dx=&dy=[&buttons=] / GET /pointer (0.4)

Move and click through the platform's own pointer path; read back {x, y, buttons}. bit0 primary, bit1 secondary.

POST /pad?index=[&buttons=][&connected=] / GET /pad?index= (0.5)

A virtual game controller, in one canonical layout everywhere (bit0 LEFT, 1 RIGHT, 2 UP, 3 DOWN, 4 A, 5 B, 6 X, 7 Y, 8 START, 9 SELECT, 10 L, 11 R). A pad is a level: what it holds persists across /step until changed. connected=0 unplugs it.

GET /perf / POST /perf (0.6)

How much of each frame the program uses, in guest CPU cycles: the frame's budget, the last completed frame (total, work, idle, IRQ, main), statistics windows (min, mean, p50, p95, p99, max, overruns), the program's own breakdown by zone, raw per-frame records (since= the last frame seen, so none is missed), and a platform section. POST /perf takes a JSON body of settings. The whole of it, with examples and graphs, is Performance Metrics.

Conventions

  • JSON is application/json. Errors: 4xx/5xx with {"error":"..."}.
  • Unknown path → 404; wrong method → 405; unimplemented callback → 501.
  • A CORS Access-Control-Allow-Origin: * header is sent so browser tools work.

Consistency (normative)

  • /mem, /regs, /screenshot are serviced at an instruction/frame boundary on the emulator thread — the HTTP thread never reads CPU/RAM mid-instruction.
  • /screenshot serves a complete-frame snapshot.
  • /perf is answered on the emulator thread and describes completed frames only.
  • frame increments once per completed video frame and never goes backwards (except across /reset).