Repository navigation
v0.1.1 — three live-test bug fixes + auto-pause screenshot
Three real bugs surfaced by the first end-to-end live test of v0.1.0 against PPSSPP v1.20.3 + a PSP homebrew. Protocol mapping was right in the abstract but wrong in three details — all caught and fixed.
Fixed
-
Memory reads were returning
undefined— PPSSPP'smemory.read_u8/_u16/_u32responses use the field namevalue, notuintValue(which I'd assumed from the singular-registercpu.getReg/setRegresponses, which DO useuintValue). Memory r/w round-trip now validated end-to-end: write0xDEADBEEFto0x08800000+ read back = match. -
cpu.getAllRegsresponse shape was wrong — I'd assumed{categories: [{name, registers: [{name, uintValue}]}]}. Actual PPSSPP shape is{categories: [{name, registerNames: [...], uintValues: [...], floatValues: [...]}]}— parallel arrays, not an array of objects. Rewrote the handler with bounds-aware parallel indexing. -
cpu.steppingandcpu.resumewere hanging — PPSSPP source documents these as "No immediate response. Once CPU is stepping, a 'cpu.stepping' event will be sent." (async broadcast with no ticket). My ticketedcall()was waiting 10s for a reply that never comes. AddedPpssppClient.fireAndForget(event, params)andPpssppClient.waitForState(predicate, opts)which pollscpu.status(which IS synchronous) until the state change is detected.ppsspp_pause/ppsspp_resume/ the screenshot internal pause/resume now use this pattern.
Changed
ppsspp_screenshotnow auto-pauses + auto-resumes — PPSSPP'sgpu.buffer.screenshotrequires CPU or GPU to be stepping (otherwise "Neither CPU or GPU is stepping" error). The tool now transparentlycpu.steppings, captures, andcpu.resumes. If the caller had already paused, it leaves the state alone on exit. Also requeststype: "base64"explicitly (PPSSPP's default is"uri"which returns adata:image/png;base64,...prefix); belt-and-suspenders URI-prefix stripping kept as a fallback.
Added
scripts/smoke.cjs— live test harness that connects to PPSSPP, exercises every major event path (ping, game.status, memory r/w, pause/resume, registers, screenshot, breakpoints), and reports per-event status. Used to surface all three bugs above. Run withPPSSPP_PORT=<port> node scripts/smoke.cjs.
Known limitations
gpu.buffer.screenshotis backend-dependent — observed "Could not download output" on a homebrew where the GPU readback path can't fetch the framebuffer. This is a PPSSPP-side limitation (the GPU backend's framebuffer readback support varies), not a bug in our code. Likely works on commercial PSP games with normal rendering.
Validated live
Smoke-tested end-to-end against PPSSPP v1.20.3 (Windows x64) running BTC Miner PSP:
| Event | Result |
|---|---|
WebSocket handshake (debugger.ppsspp.org subprotocol) |
✅ |
version (ping) |
✅ returns PPSSPP v1.20.3 |
game.status |
✅ returns full game metadata |
memory.read_u8/u16/u32 |
✅ returns value field |
memory.read (range, base64) |
✅ |
memory.write_u32 + read-back |
✅ |
cpu.stepping (fire-and-forget + poll) |
✅ |
cpu.resume (fire-and-forget + poll) |
✅ |
cpu.getAllRegs (parallel arrays) |
✅ |
cpu.breakpoint.list |
✅ |
gpu.buffer.screenshot |
Upgrade
npm install -g mcp-ppsspp@0.1.1The bridge protocol is the same — no PPSSPP-side changes required.