OXYGENHUB
◆ main retro-remote-debug-controller / CHANGELOG.md
5.2 KiB · Markdown · last changed feat: contract 0.6 — GET/POST /perf, the performance metrics (budget, current frame, windows, zones, raw frames since one, a platform section) and their settings, and /status.capabilities; backend callbacks get_perf and set_perf return allocated JSON (#6) 25 days ago renderedsource blame history raw
1
# Changelog
2
3
Contract versions of the Retro Remote Debug Controller (see [SPEC.md]SPEC.md).
4
Semantic versioning: MAJOR = breaking change to an existing endpoint, MINOR =
5
additive (new endpoint / optional field), PATCH = clarification. Every minor so
6
far has been purely additive — older clients keep working, and a server
7
advertises the highest level whose backend callbacks are all present via
8
`/status.contract`.
9
10
## 0.6.0
11
- `GET /perf[?windows=][&zones=][&frames=][&since=]` — **performance metrics**:
12
  how much of each frame the program uses, in guest CPU cycles. `budget` (the
13
  frame and its budget), `current` (the last completed frame: total, work,
14
  idle, IRQ and main cycles, instructions, host time, utilisation), `windows`
15
  (min, mean, p50, p95, p99 and max per window, and overruns), `zones` (the
16
  program's own breakdown: address ranges, or regions the guest marks), raw
17
  per-frame records (`frames`, or every frame `since` one, so a harness never
18
  misses one), and `platform` for the rest. Backend callback: `get_perf`.
19
- `POST /perf` — settings as a JSON body: enabled, target FPS, idle mode,
20
  history, reset, and the zones (an address range, or a **name for a guest
21
  marker region**). Backend callback: `set_perf`.
22
- `/status.capabilities` — the endpoint groups a server serves, whatever level
23
  it reaches, so a client can ask for `perf` (or `pointer`) directly instead of
24
  inferring it from the cumulative ladder. Absent before 0.6.
25
- Both callbacks return allocated JSON the core frees, so the core stays
26
  platform-neutral: the backend owns the measurements and their shape.
27
- First backend: the enhanced X16 emulator, whose Performance panel and DAP
28
  `x16/perfStats` it answers from the same counters. Its `platform` section
29
  adds VERA's bus bandwidth per scanline and the sprite renderer's time; its
30
  guest markers are writes to `$9FBC`.
31
- Motivation: a released game that players found slow. Its port measured
32
  itself with scanline probes compiled into the game, at a cost in memory and
33
  with torn reads; the emulator already knew the answer and had no way to say
34
  it to a test.
35
36
## 0.5.0
37
- `POST /pad?index=[&buttons=][&connected=]` — present a **virtual game
38
  controller** and set what is held. `buttons` is the canonical mask (bit0 LEFT,
39
  1 RIGHT, 2 UP, 3 DOWN, 4 A, 5 B, 6 X, 7 Y, 8 START, 9 SELECT, 10 L, 11 R —
40
  the SNES/Neo6502 native order, fixed across platforms). `connected=0` unplugs.
41
  Backend callback: `set_pad`.
42
- `GET /pad?index=` — read back `{index, connected, buttons}`, so a test can tell
43
  "the input never arrived" from "it arrived and was ignored". Backend callback:
44
  `get_pad`.
45
- A pad is a **level, not an event**: the held mask persists across `/step`
46
  frames until changed, unlike `/key`'s momentary tap. Conformance asserts this
47
  directly, because it is the property that makes `/pad` worth having rather
48
  than reusing `/key`.
49
- **Virtual, not SDL.** A backend presents a device its existing read path picks
50
  up rather than driving the host's joystick API. Headless CI has no joystick,
51
  and that is precisely the case this endpoint exists for.
52
- Motivation: a real bug that shipped. A port's pad read masked the firmware's
53
  merged controller down to its d-pad and tried to recover the buttons from the
54
  wrong controller index — movement worked, fire did nothing, and there was no
55
  way to catch it without a human holding hardware.
56
57
## 0.4.0
58
- `POST /pointer?x=&y=[&buttons=]` (absolute) or `?dx=&dy=[&buttons=]` (relative)
59
  — inject a pointer move/click through the platform's native mouse path.
60
  `buttons` is a bitmask (bit0=primary, bit1=secondary); omit for a pure move.
61
  Backend callback: `set_pointer`.
62
- `GET /pointer` — read back the current pointer `{x, y, buttons}`, so a test can
63
  tell "input never arrived" from "wrong output drawn". Backend callback:
64
  `get_pointer`.
65
- First consumer: the Neo6502 fork (drives the firmware mouse), unblocking the
66
  pointer floor of the `rstar-api` RWM/RGM toolkit.
67
68
## 0.3.0
69
- `POST /mem?addr=&bank=` — write (poke) memory; bytes in the request body,
70
  returns `{"written":n}`. Backend callback: `write_mem`.
71
- `GET /audio` — drain synthesised PCM since the last call as a self-describing
72
  WAV (the audio analogue of `/screenshot`); `X-Rrdc-Audio-Dropped` header on
73
  ring overflow. Backend callback: `capture_audio`.
74
- The NEC PC-FX (Mednafen) fork joins as the fourth conforming emulator, the
75
  second to vendor the C core as a git submodule.
76
77
## 0.2.0
78
- `POST /key?text=|code=[&down=]` — inject input (press / release / tap).
79
  Backend callback: `inject_key`.
80
- `POST /reset` — soft/cold reset. Backend callback: `reset`.
81
- Contract gating introduced: a NULL callback returns 501 for its endpoint and
82
  lowers the advertised contract, keeping partial backends honest.
83
84
## 0.1.0
85
- Initial contract: `GET /status`, `GET /screenshot` (PPM), `GET /mem`,
86
  `GET /regs`, `POST /step`, `POST /pause` / `POST /resume`.
87
- Shared C core (`core/retro_control.{c,h}`) — sockets, HTTP, PPM/JSON encoding,
88
  and cooperative pause/step, driven by three loop hooks. Backend callbacks:
89
  `read_mem`, `get_regs_json`, `get_framebuffer`, `get_frame_count`.
90
- Shared pytest client (`client/emu_control.py`) and the platform-agnostic
91
  conformance suite. Reference implementation: the Commander X16 fork.