Compare commits
2 Commits
main
...
vpx-emulat
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8c6547acbd | ||
|
|
32751448c6 |
@@ -26,7 +26,10 @@ Static triage of the extracted Raspberry Pi based root filesystem in this worksp
|
|||||||
- [Analysis Evidence Map](analysis-evidence-map.md) - compact map from `analysis/` datasets to findings, confidence, and follow-up work.
|
- [Analysis Evidence Map](analysis-evidence-map.md) - compact map from `analysis/` datasets to findings, confidence, and follow-up work.
|
||||||
- [Artifact Index](artifact-index.md) - hashes and generated artifact inventory.
|
- [Artifact Index](artifact-index.md) - hashes and generated artifact inventory.
|
||||||
- [Next Analysis Targets](next-analysis-targets.md) - prioritized open work.
|
- [Next Analysis Targets](next-analysis-targets.md) - prioritized open work.
|
||||||
- [Docker/QEMU Emulation](docker-qemu-emulation.md) - what currently boots, what is visible, and why the game is not fully playable.
|
- [Docker/QEMU Emulation](docker-qemu-emulation.md) - Docker/VNC analysis path plus the verified native HVF/Cocoa game-display baseline.
|
||||||
|
- [Process-Level Game Emulation](process-level-emulation.md) - userspace capsule, launcher, software cabinet bridge, debugging, and validation boundary.
|
||||||
|
- [VPX Table Recreation](vpx-table-recreation.md) - clean-room Pokemon Pro table sources, evidence basis, build/runtime validation, and remaining physical-accuracy boundary.
|
||||||
|
- [Native macOS Playable Table](native-playable-table.md) - QEMU rules/display/audio joined to VPX physics through the supervised playfield bridge.
|
||||||
|
|
||||||
## System and Software
|
## System and Software
|
||||||
|
|
||||||
@@ -41,10 +44,14 @@ Static triage of the extracted Raspberry Pi based root filesystem in this worksp
|
|||||||
|
|
||||||
- [Main Game Behavior Notes](main-game-behavior.md)
|
- [Main Game Behavior Notes](main-game-behavior.md)
|
||||||
- [Conagent Reverse Engineering](conagent-re.md)
|
- [Conagent Reverse Engineering](conagent-re.md)
|
||||||
|
- [QR Code Analysis](qr-code-analysis.md)
|
||||||
- [Conagent Machine Emulator](conagent-machine-emulator.md)
|
- [Conagent Machine Emulator](conagent-machine-emulator.md)
|
||||||
- [Netbridge Reverse Engineering and Emulator](netbridge-re.md)
|
- [Netbridge Reverse Engineering and Emulator](netbridge-re.md)
|
||||||
- [Magikarp Topper Serial Key and Emulator](topper-serial-key-emulator.md)
|
- [Magikarp Topper Serial Key and Emulator](topper-serial-key-emulator.md)
|
||||||
- [Docker/QEMU Emulation](docker-qemu-emulation.md)
|
- [Docker/QEMU Emulation](docker-qemu-emulation.md)
|
||||||
|
- [Process-Level Game Emulation](process-level-emulation.md)
|
||||||
|
- [VPX Table Recreation](vpx-table-recreation.md)
|
||||||
|
- [Native macOS Playable Table](native-playable-table.md)
|
||||||
|
|
||||||
## Assets and Radium Format
|
## Assets and Radium Format
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,128 @@
|
|||||||
# Artifact Index
|
# Artifact Index
|
||||||
|
|
||||||
|
## Target Firmware Evidence
|
||||||
|
|
||||||
|
These files are unmodified target-root artifacts used for static protocol
|
||||||
|
recovery.
|
||||||
|
|
||||||
|
| SHA-256 | Target path | Notes |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| `f8eb96998a32ff86008663f7f07f2df76c32a9c86200f690c215dc36917391a9` | `/games/pokemon_pro/spike3/powerdist/powerdist_ext.hex` | 32,799-byte Intel HEX image; command `0x15` poll and unsolicited sequence-0 cabinet-input report paths are documented in `netbridge-re.md`. |
|
||||||
|
|
||||||
|
## Process Emulator Source Artifacts
|
||||||
|
|
||||||
|
These are clean-room source files. Their generated capsule, run logs, copied
|
||||||
|
Mesa runtime, framebuffers, audio, and traced packs live under
|
||||||
|
`emulation/work/` and are intentionally excluded from Git.
|
||||||
|
|
||||||
|
| Path | Notes |
|
||||||
|
| --- | --- |
|
||||||
|
| `spike3-emu` | Unified `prepare`, `run`, `debug`, `trace`, `shell`, `pack`, and safe legacy-clean entry point. |
|
||||||
|
| `emulation/process/spike3_emu.py` | Read-only process capsule builder/runner, Docker/native/qemu-user selection, display/audio sidecars, trace packer, and GDB helper generator. |
|
||||||
|
| `emulation/process/config.default.json` | Versioned software-only runtime defaults. |
|
||||||
|
| `emulation/process/Dockerfile` | Host-architecture runtime with ARM64 Mesa libraries, tracing/debug tools, Xvfb, x11vnc, and noVNC. |
|
||||||
|
| `emulation/process/test_spike3_emu.py` | Launcher, isolation, preload-order, framebuffer-loop, trace, and debugger unit tests. |
|
||||||
|
| `emulation/stubs/spike3machine_client.c` | AArch64 preload bridge from target SPI/I2C/GPIO calls to the versioned machine broker. |
|
||||||
|
| `emulation/stubs/spike3emu_display_contract.h` | Shared DMA-BUF attribute and software-decoder contract helpers for the display shim tests. |
|
||||||
|
| `emulation/tests/spike3emu_display_contract_test.c` | Host/AArch64 contract tests for DMA-BUF attribute parsing and the V4L2-to-software decoder alias. |
|
||||||
|
| `emulation/tests/mesa_fbo_smoke.c` | Standalone surfaceless Mesa GLES test requiring a complete texture-backed FBO, nonzero readback, and no GL error; source compilation is verified, ARM64 runtime execution remains pending. |
|
||||||
|
| `analysis/spike-machine-emulator/` | Versioned broker, persistent EEPROM/amplifier models, SPI/GPIO/UART/nodebus cabinet model, replay/fault support, client, and tests. |
|
||||||
|
| `analysis/spike-machine-emulator/profiles/pokemon-pro.json` | Configurable provisional Pokémon switch/output mapping. |
|
||||||
|
| `emulation/vpx-plugin/` | Pinned ARM64 macOS VPX ControllerPlugin source, package builder, configuration, and table-side VBS adapter. |
|
||||||
|
|
||||||
|
Generated capsule manifests record hashes for `/games/pokemon_pro/game`, both
|
||||||
|
Radium `image.bin` files, Godot `main.pck`, the menu/display executables, the
|
||||||
|
extracted loader, both generated preload DSOs, and the copied Mesa overlay.
|
||||||
|
|
||||||
|
## VPX Clean Rebuild and Historical Recreation Artifacts
|
||||||
|
|
||||||
|
The active clean-room implementation is under `emulation/vpx-rebuild/`. Its
|
||||||
|
maintained and generated artifacts are:
|
||||||
|
|
||||||
|
| Path | Artifact role | Validation and handling caveat |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| `emulation/playfield-contract/pokemon-pro-hardware.json` | Canonical geometry-free contract for 45 switches, 11 sensors, 9 cabinet controls, 13 drivers, and 113 logical lamps. | Static contract/consumer validation is recorded in `emulation/playfield-contract/VALIDATION.md`; it is not live-game proof. |
|
||||||
|
| `emulation/vpx-rebuild/design/geometry.json` | Clean-room Pro XY/Z, mechanism, collision, and physics source of truth. | Top-down placement is registered to official evidence; installed Z, force, friction, clearance, and timing values still need physical-machine measurement. |
|
||||||
|
| `emulation/vpx-rebuild/design/lights.json` | Independent 113-lamp trace and confidence records. | Exact-address mapping is statically validated; rendered response still needs final integrated capture. |
|
||||||
|
| `emulation/vpx-rebuild/design/REFERENCE.md` | Edition scope, official/secondary source URLs, and accuracy boundary. | Official Stern evidence wins over secondary sources. |
|
||||||
|
| `emulation/vpx-rebuild/assets/playfield/pokemon-pro-official-registered.png` | Deterministically registered 952x2115 private-use base image. | Official photograph contains baked-in hardware/lighting; not a licensed bare-playfield scan and not redistributable by this assessment. |
|
||||||
|
| `emulation/vpx-rebuild/assets/models/` | Original procedural VPX mechanism and toy meshes. | Simulation models, not production CAD or direct physical scans. |
|
||||||
|
| `emulation/vpx-rebuild/assets/sounds/` | Original procedural CC0 bank containing 69 mechanical/physics source events. | Contains no copied game samples; QEMU remains the source of licensed music, speech, and game effects. |
|
||||||
|
| `emulation/vpx-rebuild/script/PokemonPro_Rebuild.vbs.in` | Clean standalone/SPIKE3 table behavior and integration template. | Maintained input; generated `source/script.vbs` and distribution sidecar must not be hand-edited. |
|
||||||
|
| `emulation/vpx-rebuild/tools/generate_table.py` | Deterministic unpacked-VPX source generator and contract binder. | Generator/source checks do not establish live gameplay. |
|
||||||
|
| `emulation/vpx-rebuild/source/` | Generated diff-friendly VPX source. | Rebuilt from maintained inputs; do not hand-edit. |
|
||||||
|
| `emulation/vpx-rebuild/dist/PokemonPro_Rebuild.vpx` | Active private-use VPX 10.8.1 assembled table selected by the default launcher; 5,902,336 bytes, SHA-256 `ddce5d48033ee3c6e67248910a73897293e8b9c36eee29df164160a93572a30e`. | Generated output; exact current hash also appears in `qa/rebuild-validation.json` and `qa/runtime-smoke.log`. |
|
||||||
|
| `emulation/vpx-rebuild/dist/PokemonPro_Rebuild.vbs` | Sidecar matching the active assembled table. | Generated output; round-trip script equality is checked by `build.sh`. |
|
||||||
|
| `emulation/vpx-rebuild/qa/rebuild-validation.json` | Machine-readable current 359-item build, asset, contract, geometry, lamp, and round-trip report. | A `pass` is static/generated-source evidence, not physical-machine calibration or a complete game. |
|
||||||
|
| `emulation/vpx-rebuild/qa/runtime-smoke.log` | Exact-current-table VPX 10.8.1 runtime-load record: table/VBS load, script compile/start, Metal initialization, two frames, clean close, and exit code 0. | Uses bounded `CaptureAttract`, not interactive `-Play`; it proves runtime/render startup but not a shot or full mechanism sequence. |
|
||||||
|
| `emulation/vpx-rebuild/qa/vpx-playfield-capture.png` | 1024x1024 frame from the exact-current-table runtime smoke; SHA-256 `5c99e798e467c8475b2c1aa48a4134881d9293d915aafde4e998ed6ebea5871c`. | Render-review evidence; photographed base art still contains baked-in hardware and lighting. |
|
||||||
|
|
||||||
|
The registered photograph, service manual, Pokemon/Stern imagery, and assembled
|
||||||
|
table must remain within the authorized private-use boundary. The table does
|
||||||
|
not embed target machine code or the game's scoring rules. See
|
||||||
|
`vpx-table-recreation.md` for the separated static, VPX-runtime, integrated,
|
||||||
|
and hardware validation states.
|
||||||
|
|
||||||
|
The following SHA-256 table is the preserved earlier VPX/bridge milestone.
|
||||||
|
Entries under `emulation/vpx/` describe the deprecated greybox/manual workflow;
|
||||||
|
they are retained for audit and are not inputs or defaults for the clean
|
||||||
|
rebuild. Shared plugin, launcher, guest-helper, and emulator paths may still be
|
||||||
|
active, but the hashes below are milestone hashes rather than an assertion
|
||||||
|
that every shared file is unchanged today.
|
||||||
|
|
||||||
|
| SHA-256 | Path | Notes |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| `fd64431a28fb08a880acff091dc752301b785a2c93fe3985f9fb316db01026a0` | `emulation/vpx/PokemonPro_Greybox.vpx` | Deprecated historical VPX 10.8.1 greybox milestone hash; the current working copy may differ. The clean rebuild does not inspect or write it, and it is not an input or runtime default. |
|
||||||
|
| `652b59cbfa3d38bae9194e096a9a15d6e9e7ea73b077707aced2827a774b8a84` | `emulation/vpx/layout.json` | Historical greybox geometry/mapping manifest; superseded for active electrical mapping by `emulation/playfield-contract/pokemon-pro-hardware.json`. |
|
||||||
|
| `0e5047593cc1b4f6e53fb9324165c08adf8b1c6d1c7ad430281fd581c1278eeb` | `emulation/vpx-plugin/tests/test_bridge.cpp` | VPX bridge protocol fixture with the live-verified Service Back, Up, Down, and Enter CPU-SPI addresses; exercised by the plugin mapping, reconnect, and 10,000-pulse tests. |
|
||||||
|
| `18028e0065d4260799264ec255999a8e4ced4c7e4213484379752d360e1f4768` | `emulation/vpx/PokemonPro_Greybox.vbs` | Deprecated historical greybox controller/QA sidecar; not the active clean-table script. |
|
||||||
|
| `127c653b08aa275afd86141bef1ad7d44a48525f034d1bdd1a0188671d61bd04` | `emulation/vpx/manual/PokemonPro_Manual.vpx` | Historical editor-owned derivative of the greybox workflow; not the active clean-table source of truth. |
|
||||||
|
| `560f8108ed1224945a5597f8d960e266fea5feea74f813a17b3a6a7ea2233ad8` | `emulation/vpx/prepare-manual-table.sh` | Creates the protected manual table, refreshes only its generated controller sidecar, and backs up before an explicit reset. |
|
||||||
|
| `1c9826c3c302b24d66ccce780eb65b75ead20be59dcd062667d921e9effb6f11` | `emulation/vpx/edit-manual-macos.sh` | Opens the manual table in standalone VPX with an isolated preferences path and prints Live Editor save guidance. |
|
||||||
|
| `ebb09dfb3b708f2b1e363c49f59ca78b7e64067ab50a9d598b4d2d5c07dfa972` | `emulation/vpx/test-manual-macos.sh` | Fast standalone physics launcher for the editor-owned table. |
|
||||||
|
| `95819aec421da92aa2a6305c0b5e9bebb56ad18f86400212e85d6b42badaedc7` | `emulation/scripts/run-playable-manual-macos.sh` | Full native QEMU/HVF and VPX integration launcher using the editor-owned table. |
|
||||||
|
| `2777d9a83a42a2ef076e6956bd8c15bfc54e1cff99eddbd012385fd5db90db5b` | `emulation/scripts/run-playable-macos.sh` | Native cabinet supervisor with matching VPX/QEMU-focus control instructions and automatic generated-rootfs guest-helper refresh. |
|
||||||
|
| `b7a864e250907952e83239a6b3dd69923bca86fed0816a3c5a99a026b92edcf5` | `emulation/scripts/run-macos.sh` | Native QEMU/HVF supervisor with playfield bridge and explicit optional/required conagent backend collision handling. |
|
||||||
|
| `d08a4f577ed481371d16f734e360553ea19f49c8afab83d2c4d528af51abc270` | `emulation/guest-tools/keyboard-switch-relay.c` | AArch64 guest relay using the cabinet map when QEMU Cocoa has focus: Shift flippers, `1` Start, `5` coin, Return/Space Action, and `7`/`8`/`9`/`0` service controls. Installed binary SHA-256 `55054003950873900b5ce203292846f158b861060dbdd2e04b5be4a8afa1869c` was verified from the rebuilt ext4 image. |
|
||||||
|
| `732437382c6bc88df080e3a9c1cf66803eb35b1e6f736a76896ab35d8f48c0e2` | `emulation/vpx/tools/generate_layout.py` | Deterministic hardware, geometry, physics, asset-registration, live-corrected service CPU-SPI, and power-distribution route manifest generator. |
|
||||||
|
| `cedb8d18f491d06c1dde2b5aa2fdee9f4786001ac0be029e672d25204e97f709` | `emulation/vpx/tools/generate_table.py` | Rounded collision paths, layered VPX source, controller integration, QA, and exact cabinet-route validation. |
|
||||||
|
| `836e26f693990680688780befa5d826c37d656d827f9448f68ececcede777230` | `emulation/VPX_EMULATOR_STATUS.md` | Current implementation inventory, repaired CPU-SPI/powerdist input paths, persistent-provisioning stop point, manual geometry workflow, and acceptance checklist for branch `vpx-emulator`. |
|
||||||
|
| `e13eb92e99a806ea86625de8cc426876929625190f763bfe93cd2e821efd3f88` | `emulation/vpx/tools/verify_collision_topology.py` | Static assertions for continuous collision/visual rail inventory and runtime/editor flags. |
|
||||||
|
| `829c929b4ed51d2d7544cfae1aeb0b8571b50e1d71de299bcfdc0535844372e1` | `emulation/vpx/qa/collision-topology.json` | Per-path polygon area, winding, vertex, and self-intersection report. |
|
||||||
|
| `e3ed8627e92c9175791c6aad0a2868df7dd66ac53602663431c6cd0c7a98a52a` | `emulation/vpx/qa/collision-validation.json` | Passing 13-collision/13-visual topology summary with zero legacy segments and intersections. |
|
||||||
|
| `526e2a4e5695496e6662fe44ddc8406b700a551b142a6da95bd74bb8adc8e00f` | `emulation/vpx/qa-mechanisms.sh` | Live VPX assertions for both outlanes, center drain, Town VUK, Poke Ball hold, and shooter serve. |
|
||||||
|
| `32b0c8fa4f5330cd9051d456c7209575bbd764f460c9e655d48ffcc89b23ddc1` | `emulation/vpx/qa-plunger.sh` | Full-pull VPX assertion requiring the served ball to clear the shooter mouth into the main playfield. |
|
||||||
|
| `d66b99d4029b08906549e44b2c0f7ab26153313d2eea1d168e824e4fe75a705e` | `emulation/vpx/layer-map.json` | Stable 16-layer VPX construction/collision/visual/electrical/QA editor map. |
|
||||||
|
| `254eb1167d1355003fe28fa1becc1209ff7fb1f53544cf696295b546c5c49e0e` | `emulation/vpx/assets/models/star_post.obj` | Blender-authored normalized ten-lobed post mesh. |
|
||||||
|
| `0c2adad60a3c0b3491f371630013106d18c3327dd2173b2bf238e23705e1c25e` | `emulation/vpx/assets/models/stepped_metal_post.obj` | Blender-authored normalized stepped guide-post mesh. |
|
||||||
|
| `d58c3f812fa0ba98461abf0220692a72ba3dfaec52b0fcaee0ca3d02ef70bc84` | `emulation/vpx/assets/models/pop_bumper_cap.obj` | Blender-authored normalized pop-bumper cap mesh. |
|
||||||
|
| `976a2c72f13a654541e8d558b69c2dd6974e33a3f787b5926d98067e34d89f8d` | `emulation/vpx/assets/cad-reference/Star_Post_PL-00172-OT.SLDPRT` | Unmodified Pinball Makers private-development star-post reference. |
|
||||||
|
| `bb313ef15bf3bcf25f6faa1e3d6a40e0a8d683b828b32572aaaf9752e1697326` | `emulation/vpx/assets/cad-reference/Post_Faceted_1_inch_C-11561-20.SLDPRT` | Unmodified Pinball Makers private-development faceted-post reference. |
|
||||||
|
| `cb78b416be8f3c946313517766ecd3077dd05fdecea8f6ec162f9c9b0d4d3413` | `emulation/vpx/assets/cad-reference/WPC_Pop_Bumper_Assy_B-9414.zip` | Unmodified Pinball Makers WPC pop-bumper CAD assembly reference. |
|
||||||
|
| `50a1906b5c609cd3a84970b6a6e9b0be839b4d0a588d8b27361936ab6537d6bb` | `emulation/vpx/reference/Pokemon_Pro_web.pdf` | Preserved 10,227,248-byte service manual. |
|
||||||
|
| `09477fe9bd50cfeba34bbff2eac5c272fc79eed6a6ed07fc40da636c5fde977b` | `emulation/vpx/reference/pokemon_playfield_pro.png` | Preserved 451x998 target-root playfield locator. |
|
||||||
|
| `b2804f794eb119712420ad575479fb8febcc39df0e505f9942c162614819819c` | `emulation/vpx/reference/photos/pokemon-pro-overhead.png` | Preserved user-supplied overhead machine photograph. |
|
||||||
|
| `6ba469672627125d13798d1e80d460f85a5ce4ab9d4798c9947715ebbe1cfe70` | `emulation/vpx/reference/photos/pokemon-pro-lower-detail.png` | Preserved user-supplied lower-playfield detail photograph. |
|
||||||
|
| `1a1af7fa16dde9c84deb2fbc19de44b9c860cd5ef4dc3a65d48a3cbfdbb214a3` | `emulation/vpx/reference/photos/pokemon-pro-player-view.png` | Preserved user-supplied player-view photograph. |
|
||||||
|
| `acb797ec6c2a03079c1a427e0350de0dfabb0c33688eb45e60b52824c04317eb` | `emulation/vpx/reference/photos/pokemon-pro-overhead-registered.png` | Reproducible 451x998 overhead-photo crop for locator comparison. |
|
||||||
|
| `5383b79d5a955b91059ca5d67806d719d89655ec293e4bd0cc84b8a5adede03f` | `emulation/vpx/qa/layout-overlay.png` | Actual buffered collision polygons, centerlines, ramps, mechanisms, and hardware over the locator. |
|
||||||
|
| `595faa3cc12de55ad10ef3324593140473a3eb3e4778471797845c39a31ae243` | `emulation/vpx/qa/photo-geometry-overlay.png` | The same buffered collision review over the registered overhead photograph. |
|
||||||
|
| `8084af0ed94f87c20487f0ba02a182015365a3c51c00d0358d679e4e5267d62f` | `emulation/vpx/qa/vpx-playfield-capture.png` | Inspected live desktop render of continuous rounded visual rails and initialized mechanisms. |
|
||||||
|
| `3351926b55d81ea7c77e3df016aa05167dbf786e3a1985537770a1d95da309b7` | `emulation/vpx/qa/vpx-cabinet-capture.png` | Inspected live fullscreen render rotated into physical portrait orientation. |
|
||||||
|
| `6b1a65cbbf9569fd720075f60ee3687b99fdf439313fc85bb887231afd44dfbe` | `emulation/vpx/qa/mechanism-runtime.log` | Passing continuous-collision evidence for both outlanes, three drains, both kickers, and shooter service. |
|
||||||
|
| `06cf7cd0b2a61579ec7bce7637565d1bccd9dcd803a18e0053cce94859005f3b` | `emulation/vpx/qa/plunger-runtime.log` | Passing continuous-shooter-rail main-playfield-entry evidence. |
|
||||||
|
|
||||||
|
Key source hashes for the 2026-07-11 process/VPX milestone:
|
||||||
|
|
||||||
|
| SHA-256 | Path |
|
||||||
|
| --- | --- |
|
||||||
|
| `502868bdf619ef66a2af612f1d70ac5c7d8811e8999a8b55039c10aff7d56f40` | `emulation/process/spike3_emu.py` |
|
||||||
|
| `31ca5928aefb1d17ec4153a35ec01f87cb84bf5e8e3059b82efd37bd1ae7f2ea` | `analysis/spike-machine-emulator/service.py` |
|
||||||
|
| `a6065c0b13beca83fb9c1a64702ba163b5e1664cdfb3bb64985a4b6b326cf91e` | `analysis/spike-machine-emulator/machine.py` |
|
||||||
|
| `57be1144bafd4dfe3ba852e36ba015487b548df1229dcb2869884abd67bf6101` | `emulation/dashboard/server.py` |
|
||||||
|
| `1da09b43b43e920f8f95183281cf3c3291f7d013a0da8e6ac60cc0f776b6dbee` | `emulation/vpx-plugin/Spike3Controller.cpp` |
|
||||||
|
| `5c8bb043378669334b587d0e443b7a6ded5530c886d87f9bd1e30fb7fe7cb12c` | `emulation/tests/mesa_fbo_smoke.c` |
|
||||||
|
|
||||||
## Main Game Artifacts
|
## Main Game Artifacts
|
||||||
|
|
||||||
| SHA-256 | Path |
|
| SHA-256 | Path |
|
||||||
@@ -104,9 +227,9 @@ These files are workspace-local generated artifacts, not target-root files.
|
|||||||
| `b5ddb933f125cf6b54b81c56f4e3430ded50d843c045a49f0727a1f7ebc5f66f` | `rootfs-triage-wiki/scripts/harvest_loose_openable_assets.py` | Static loose-asset copier for PNG, TTF, MP4, and MOV files. |
|
| `b5ddb933f125cf6b54b81c56f4e3430ded50d843c045a49f0727a1f7ebc5f66f` | `rootfs-triage-wiki/scripts/harvest_loose_openable_assets.py` | Static loose-asset copier for PNG, TTF, MP4, and MOV files. |
|
||||||
| `257cb2d9ba653385aba63157a3bc143bb479c5188071ef529996d3f5da258b71` | `analysis/topper-emulator/topper_emulator.py` | MicroPython SPIKE node-board emulator for the Magikarp topper serial-key path; 6,452 bytes. |
|
| `257cb2d9ba653385aba63157a3bc143bb479c5188071ef529996d3f5da258b71` | `analysis/topper-emulator/topper_emulator.py` | MicroPython SPIKE node-board emulator for the Magikarp topper serial-key path; 6,452 bytes. |
|
||||||
| `32263b75f49aefba04596c196f85cc4ae4477eb536f767fcdeac7c0d5fc40e9b` | `analysis/topper-emulator/README.md` | Emulator notes and recovered command summary; 5,820 bytes. |
|
| `32263b75f49aefba04596c196f85cc4ae4477eb536f767fcdeac7c0d5fc40e9b` | `analysis/topper-emulator/README.md` | Emulator notes and recovered command summary; 5,820 bytes. |
|
||||||
| `5b510902f4027e364702a61338ff613bde2b77d8441ba2703b343e642cac0453` | `analysis/netbridge-emulator/netbridge_emu.py` | Python host-side emulator for the RP2040 netbridge UART protocol, bridge commands, CRC response, PTY/socket serving, and a stub nodebus device. |
|
| `75c5c40ec0835140c3ee26474144777e69eb0947f57d428b72000470f0a77aaa` | `analysis/netbridge-emulator/netbridge_emu.py` | Live netbridge and `spike3-playfield/v1` service with manifest cabinet aliases, CPU-SPI routing, polled and unsolicited powerdist input reports, ordered output, and safe QEMU synchronization. |
|
||||||
| `542b9835e6b6d8107d68cc6d62bfdfe85995fe61029c36ffcdba3e0295f6d455` | `analysis/netbridge-emulator/test_netbridge_emu.py` | Unit tests for host frame escaping/checksum, version response, firmware CRC response, and node serial-key command. |
|
| `7fcbb6b3752ddf7212d996660871d4b96b3f83666266e82fb027e4478bd46769` | `analysis/netbridge-emulator/test_netbridge_emu.py` | Sixty-eight protocol, routing, active-low wire-state, unsolicited UART, event-pump, output, synchronization, and recovery tests. |
|
||||||
| `b7a05a1f4d3cffc7d163e26afed6fa5402ee1a94df1687447dc1aefe067e03cd` | `analysis/netbridge-emulator/README.md` | Runbook and porting notes for the host-side netbridge emulator. |
|
| `e4e8828d0a0bcf7c533f67d03d69e83fd9bab93278d6ac8f084a2699b12be8f0` | `analysis/netbridge-emulator/README.md` | Runbook and porting notes for the host-side netbridge emulator. |
|
||||||
| `a27f5e00f09a014391418f6822dc6c5481c224ef0cf42786b8b290ecd508d9c3` | `analysis/netbridge-pico-firmware/CMakeLists.txt` | Pico SDK and portable host-test build file for the RP2040 netbridge firmware recreation. |
|
| `a27f5e00f09a014391418f6822dc6c5481c224ef0cf42786b8b290ecd508d9c3` | `analysis/netbridge-pico-firmware/CMakeLists.txt` | Pico SDK and portable host-test build file for the RP2040 netbridge firmware recreation. |
|
||||||
| `d01867dc66873799b966cf24b7574d9e389277f1556d88b92fd61342ea760222` | `analysis/netbridge-pico-firmware/include/netbridge_protocol.h` | Shared host-frame protocol and model API for the Pico firmware recreation. |
|
| `d01867dc66873799b966cf24b7574d9e389277f1556d88b92fd61342ea760222` | `analysis/netbridge-pico-firmware/include/netbridge_protocol.h` | Shared host-frame protocol and model API for the Pico firmware recreation. |
|
||||||
| `918b434ad6c8b4a0455b4eea0bd7ed8c341fb4e709bc6012c0aa43b4c074601e` | `analysis/netbridge-pico-firmware/src/netbridge_protocol.c` | Portable STX/ETX/ESC frame encoder/decoder for the Pico firmware recreation. |
|
| `918b434ad6c8b4a0455b4eea0bd7ed8c341fb4e709bc6012c0aa43b4c074601e` | `analysis/netbridge-pico-firmware/src/netbridge_protocol.c` | Portable STX/ETX/ESC frame encoder/decoder for the Pico firmware recreation. |
|
||||||
@@ -137,7 +260,7 @@ These files are workspace-local generated support artifacts, not target-root evi
|
|||||||
| `61f62ec692e91cddcd1dd81d7edb32aaeb7951f80c82f64b472fa54f9009e217` | `emulation/README.md` | User-facing emulator runbook, optional netbridge mode, and current limitations. |
|
| `61f62ec692e91cddcd1dd81d7edb32aaeb7951f80c82f64b472fa54f9009e217` | `emulation/README.md` | User-facing emulator runbook, optional netbridge mode, and current limitations. |
|
||||||
| `239ddcc7b6928582df66273cd557bf939dbc14f792f554c6ee2e6d4844ac00ca` | `rootfs-triage-wiki/docker-qemu-emulation.md` | Wiki page documenting implementation, verified progress, optional netbridge wiring, and the current display and hardware blockers. |
|
| `239ddcc7b6928582df66273cd557bf939dbc14f792f554c6ee2e6d4844ac00ca` | `rootfs-triage-wiki/docker-qemu-emulation.md` | Wiki page documenting implementation, verified progress, optional netbridge wiring, and the current display and hardware blockers. |
|
||||||
| `62eddb1582076ca9e07b3910e71673e7d15e4cd3599d73ce51e3a4148e5b95ad` | `rootfs-triage-wiki/analysis-evidence-map.md` | Cross-reference from durable `analysis/` outputs to wiki findings, confidence boundaries, and open enrichment work. |
|
| `62eddb1582076ca9e07b3910e71673e7d15e4cd3599d73ce51e3a4148e5b95ad` | `rootfs-triage-wiki/analysis-evidence-map.md` | Cross-reference from durable `analysis/` outputs to wiki findings, confidence boundaries, and open enrichment work. |
|
||||||
| `ac568dc027509f7c30475f444490771cdfa37e2510deeb32cda29367ee5ec78a` | `rootfs-triage-wiki/netbridge-re.md` | Wiki page documenting Ghidra-backed netbridge protocol recovery, emulator use, Docker wiring, and Pico firmware recreation. |
|
| `3ec9bb35a9fc74f992f84fc71405b5dda9c8c096312263902dfc850597ff8a98` | `rootfs-triage-wiki/netbridge-re.md` | Wiki page documenting Ghidra-backed netbridge and power-distribution protocol recovery, emulator use, Docker wiring, and Pico firmware recreation. |
|
||||||
|
|
||||||
## Generated Static Triage Artifacts
|
## Generated Static Triage Artifacts
|
||||||
|
|
||||||
|
|||||||
@@ -17,7 +17,18 @@ Static-analysis boundary: this page documents the emulator scaffold and evidence
|
|||||||
|
|
||||||
## Current Status
|
## Current Status
|
||||||
|
|
||||||
The emulator is a working analysis scaffold, not yet a playable machine emulator. It boots the generated AArch64 guest, exposes logs and a browser-visible framebuffer, and runs far enough to identify deterministic display and hardware dependencies. It does not yet produce a real game frame or model the complete SPIKE hardware environment.
|
This page primarily documents the older Docker/VNC analysis scaffold. That
|
||||||
|
path still provides a useful browser framebuffer and diagnostics, but it is not
|
||||||
|
the gameplay path. The current playable implementation runs QEMU natively with
|
||||||
|
HVF, Cocoa, and CoreAudio and joins it to a native VPX table; see
|
||||||
|
`native-playable-table.md`.
|
||||||
|
|
||||||
|
The native path now produces a genuine 1920x1080 Pokémon game frame with the
|
||||||
|
llvmpipe compatibility stack. The generated guest and netbridge are connected
|
||||||
|
end to end: VPX contacts enter the same node model consumed by the real game,
|
||||||
|
and real lamp/driver writes return to VPX through the supervised playfield
|
||||||
|
protocol. This does not make the emulator an exact electrical model of every
|
||||||
|
SPIKE board.
|
||||||
|
|
||||||
| Layer | Status | Evidence / remaining issue |
|
| Layer | Status | Evidence / remaining issue |
|
||||||
| --- | --- | --- |
|
| --- | --- | --- |
|
||||||
@@ -25,17 +36,24 @@ The emulator is a working analysis scaffold, not yet a playable machine emulator
|
|||||||
| Browser access | Working | noVNC and the dashboard respond, and `capture-vnc.py` records nonblack 1360x768 frames. |
|
| Browser access | Working | noVNC and the dashboard respond, and `capture-vnc.py` records nonblack 1360x768 frames. |
|
||||||
| DRM device discovery | Working | `virtio_gpu` creates `/dev/dri/card0`, `/dev/dri/renderD128`, and `fb0`; the guest provides the target-compatible `card1` alias. |
|
| DRM device discovery | Working | `virtio_gpu` creates `/dev/dri/card0`, `/dev/dri/renderD128`, and `fb0`; the guest provides the target-compatible `card1` alias. |
|
||||||
| Mesa EGL/GLES initialization | Working with compatibility overlay | The native probe reaches EGL and OpenGL ES 3.1 with Mesa softpipe; fbdev mode reaches a real surfaceless display and pbuffer. |
|
| Mesa EGL/GLES initialization | Working with compatibility overlay | The native probe reaches EGL and OpenGL ES 3.1 with Mesa softpipe; fbdev mode reaches a real surfaceless display and pbuffer. |
|
||||||
| Target display output | Blocked | The game-created EGLImage/FBO remains incomplete. Mesa reports `GL_INVALID_FRAMEBUFFER_OPERATION`, so the captured image is the shim's fallback bands rather than a rendered game frame. |
|
| Native target display | Working software-rendered baseline | HVF/Cocoa plus Debian llvmpipe produced a complete 1920x1080 game frame. This is CPU rendering, not Apple-GPU acceleration. |
|
||||||
| Audio startup | Partially bypassed | A null ALSA default clears the earlier missing-PCM abort; real amplifier behavior and audio output are not emulated. |
|
| Native audio | Working baseline | QEMU HDA/CoreAudio carries the real game audio; VPX supplies only mechanical table sounds. |
|
||||||
| Netbridge/nodebus | Scaffolded, not end-to-end verified | A Python netbridge model and optional `/dev/ttyAMA5` wiring exist, but the full guest boot with that mode has not been validated and OpenOCD programming may block before UART exchange. |
|
| Netbridge/nodebus | Working playable subset | The real game consumes VPX cabinet/playfield contacts and publishes mapped lamp/driver output. The model is not a complete electrical reproduction of every node. |
|
||||||
| Switch dashboard | Logging only | Events reach the guest log but are not translated into SPIKE nodebus state. |
|
| Switch dashboard | Diagnostic only | The browser remains optional; native VPX is the authoritative gameplay source when `physics_authority=vpx`. |
|
||||||
| Video decode | Blocked after display setup | HEVC/V4L2 initialization still expects target hardware capabilities not supplied by the current QEMU machine. |
|
| Video decode | Working compatibility path | The host VideoToolbox bridge is preferred on macOS, with the existing guest software decoder retained as fallback. |
|
||||||
|
|
||||||
### Why It Does Not Fully Work Yet
|
### Remaining fidelity boundary
|
||||||
|
|
||||||
The extracted software assumes a Raspberry Pi graphics and I/O stack, while QEMU exposes a generic `virtio-gpu` machine. The compatibility layer can satisfy discovery calls and create a real Mesa context, but it cannot yet reproduce the exact GBM/EGLImage-to-framebuffer path used by the game. That is the immediate reason no genuine game frame reaches noVNC.
|
The extracted software assumes Raspberry Pi graphics and I/O while QEMU
|
||||||
|
exposes generic VirtIO devices. The working native baseline therefore retains
|
||||||
|
a narrow compatibility overlay and CPU renderer. Docker/VNC can still hit the
|
||||||
|
historical EGLImage/FBO fallback path even though Cocoa displays the real game.
|
||||||
|
|
||||||
After that display path is fixed, the game still expects several independent machine subsystems: OpenOCD-managed RP2040 netbridge firmware, SPIKE nodebus devices, TAS/MAX amplifier register behavior, physical switches/lamps/coils, and V4L2 HEVC decode. Those are separate emulation targets; success in one does not imply that the others are modeled.
|
Several machine subsystems remain behavioral models rather than electrical
|
||||||
|
replicas: the RP2040 netbridge, SPIKE nodes, TAS/MAX amplifiers, cabinet buses,
|
||||||
|
and video decode devices. VPX supplies the missing physical playfield, but its
|
||||||
|
ramp elevations, forces, and materials remain evidence-tagged estimates where
|
||||||
|
the manual has no direct measurement.
|
||||||
|
|
||||||
## Evidence Basis
|
## Evidence Basis
|
||||||
|
|
||||||
@@ -48,7 +66,9 @@ Confirmed string/import evidence:
|
|||||||
- `/games/pokemon_pro/spike3/spike_menu/game` has matching GBM/EGL/DRM strings at offsets including `0x382cd0` (`/sys/class/drm`), `0x383030` (`/dev/dri/card1`), `0x383058` (`/dev/dri/card0`), and `0x383730` (`drmModeSetCrtc fail`); see `analysis/static-triage/spike_menu_game.strings`.
|
- `/games/pokemon_pro/spike3/spike_menu/game` has matching GBM/EGL/DRM strings at offsets including `0x382cd0` (`/sys/class/drm`), `0x383030` (`/dev/dri/card1`), `0x383058` (`/dev/dri/card0`), and `0x383730` (`drmModeSetCrtc fail`); see `analysis/static-triage/spike_menu_game.strings`.
|
||||||
- `/etc/init.d/S12lvds_panel` launches `/games/spike3/bin/boot_display` early, and `/etc/init.d/game_monitor` later stops `boot_display` before launching `/games/game`.
|
- `/etc/init.d/S12lvds_panel` launches `/games/spike3/bin/boot_display` early, and `/etc/init.d/game_monitor` later stops `boot_display` before launching `/games/game`.
|
||||||
|
|
||||||
Implementation consequence: the first emulator path uses QEMU `virtio-gpu` and browser-visible VNC/noVNC, not X11 forwarding.
|
Implementation consequence: both paths use QEMU `virtio-gpu`, not X11
|
||||||
|
forwarding. Docker exposes VNC/noVNC for analysis; playable macOS uses native
|
||||||
|
Cocoa directly.
|
||||||
|
|
||||||
## Implemented Files
|
## Implemented Files
|
||||||
|
|
||||||
@@ -176,6 +196,7 @@ Confirmed results:
|
|||||||
- Rootfs cache recheck on 2026-07-07 after the final shim rebuild: a second one-shot prepare logged `rootfs cache hit; reusing /workspace/emulation/work/rootfs.ext4`.
|
- Rootfs cache recheck on 2026-07-07 after the final shim rebuild: a second one-shot prepare logged `rootfs cache hit; reusing /workspace/emulation/work/rootfs.ext4`.
|
||||||
- Mesa dependency verification on 2026-07-07: adding missing ARM64 loader dependencies (`libX11-xcb`, `libwayland-client`, `libxcb-dri2`, `libxcb-present`, `libxcb-randr`, `libxcb-sync`, `libxcb-xfixes`, and `libxshmfence`) changed `display-probe` from `EGL_BAD_PARAMETER` to a successful native GBM/EGL initialization. The probe log reports `EGL_MESA_platform_gbm`, `EGL_MESA_platform_surfaceless`, successful `eglInitialize`, and Mesa DRI loading from `/usr/local/spike-emu/mesa-dri/kms_swrast_dri.so`.
|
- Mesa dependency verification on 2026-07-07: adding missing ARM64 loader dependencies (`libX11-xcb`, `libwayland-client`, `libxcb-dri2`, `libxcb-present`, `libxcb-randr`, `libxcb-sync`, `libxcb-xfixes`, and `libxshmfence`) changed `display-probe` from `EGL_BAD_PARAMETER` to a successful native GBM/EGL initialization. The probe log reports `EGL_MESA_platform_gbm`, `EGL_MESA_platform_surfaceless`, successful `eglInitialize`, and Mesa DRI loading from `/usr/local/spike-emu/mesa-dri/kms_swrast_dri.so`.
|
||||||
- Native path verification on 2026-07-07: forcing `SPIKE3_DISPLAY_BACKEND=native` reaches `OpenGL ES 3.1 Mesa 22.3.6` / `renderer: softpipe`, but `/games/game` repeatedly logs `failed to make image from buffer object` and `failed to create framebuffer`; native is therefore not the default auto presentation path.
|
- Native path verification on 2026-07-07: forcing `SPIKE3_DISPLAY_BACKEND=native` reaches `OpenGL ES 3.1 Mesa 22.3.6` / `renderer: softpipe`, but `/games/game` repeatedly logs `failed to make image from buffer object` and `failed to create framebuffer`; native is therefore not the default auto presentation path.
|
||||||
|
- Native llvmpipe verification on 2026-07-14: `SPIKE3_GRAPHICS_STACK=debian-llvmpipe SPIKE3_CAPTURE_TARGET_LOGS=1 emulation/scripts/run-macos.sh` booted the ARM64 guest with HVF and the Cocoa display. The target log reports `OpenGL API OpenGL ES 3.2 Mesa 22.3.6 - Compatibility - Using Device: Mesa/X.org - llvmpipe (LLVM 15.0.6, 128 bits)`. QEMU monitor `screendump` produced `emulation/work/llvmpipe-test.ppm` (1920x1080), converted to `emulation/work/llvmpipe-test.png`, and the capture contains a complete Pokémon game frame. A host `ps` snapshot 22 seconds after launch reported QEMU at 534% CPU and 6.1% memory. This confirms functional multithreaded CPU rendering; it is not Apple-GPU acceleration. Repeated `failed to queue page flip: Invalid argument` messages remain in the serial log but did not prevent the captured frame. Because live animation was smooth, `run-macos.sh` now selects `debian-llvmpipe` by default; `SPIKE3_GRAPHICS_STACK=buildroot-software` retains the former behavior when explicitly requested.
|
||||||
- fbdev/surfaceless verification on 2026-07-07: forcing `SPIKE3_DISPLAY_BACKEND=fbdev` uses the real Mesa surfaceless display and an implicit pbuffer (`eglMakeCurrent ... draw=<pbuffer> read=<pbuffer>`). This clears the `eglChooseConfig num=0` retry path, but the target-created framebuffer remains incomplete. The serial log shows `failed framebuffer check for created target buffer`, `failed to create framebuffer`, and repeated `GL_INVALID_FRAMEBUFFER_OPERATION` from `glClear`, `glDrawArrays`, and `glDrawElements`. The capture `emulation/work/game-fbdev-implicit-pbuffer.ppm` is nonblank but still only shows the fallback color bands because no valid target swap/copy occurs.
|
- fbdev/surfaceless verification on 2026-07-07: forcing `SPIKE3_DISPLAY_BACKEND=fbdev` uses the real Mesa surfaceless display and an implicit pbuffer (`eglMakeCurrent ... draw=<pbuffer> read=<pbuffer>`). This clears the `eglChooseConfig num=0` retry path, but the target-created framebuffer remains incomplete. The serial log shows `failed framebuffer check for created target buffer`, `failed to create framebuffer`, and repeated `GL_INVALID_FRAMEBUFFER_OPERATION` from `glClear`, `glDrawArrays`, and `glDrawElements`. The capture `emulation/work/game-fbdev-implicit-pbuffer.ppm` is nonblank but still only shows the fallback color bands because no valid target swap/copy occurs.
|
||||||
- Netbridge wiring verification on 2026-07-07: `python3 -m unittest discover -s analysis/netbridge-emulator`, Python bytecode compilation, and `bash -n` over the changed Docker/QEMU shell scripts all pass. The full `SPIKE3_NETBRIDGE_EMU=1` Docker boot has not yet been run, so guest acceptance of the emulated `/dev/ttyAMA5` path remains an open validation item.
|
- Netbridge wiring verification on 2026-07-07: `python3 -m unittest discover -s analysis/netbridge-emulator`, Python bytecode compilation, and `bash -n` over the changed Docker/QEMU shell scripts all pass. The full `SPIKE3_NETBRIDGE_EMU=1` Docker boot has not yet been run, so guest acceptance of the emulated `/dev/ttyAMA5` path remains an open validation item.
|
||||||
|
|
||||||
|
|||||||
254
native-playable-table.md
Normal file
254
native-playable-table.md
Normal file
@@ -0,0 +1,254 @@
|
|||||||
|
# Native macOS Playable Table
|
||||||
|
|
||||||
|
## Status
|
||||||
|
|
||||||
|
The native playable-cabinet implementation lives under `emulation/`. It
|
||||||
|
combines two independently useful runtimes:
|
||||||
|
|
||||||
|
- QEMU 11 with HVF runs the generated ARM64 guest and genuine Pokémon Pro game
|
||||||
|
code. Its Cocoa window and CoreAudio output are the backbox, game display,
|
||||||
|
music, speech, and game effects.
|
||||||
|
- Visual Pinball X 10.8.1 owns the physical balls, collision geometry,
|
||||||
|
switches, trough inventory, and moving playfield mechanisms.
|
||||||
|
|
||||||
|
The default VPX frontend is now the clean-room table assembled at
|
||||||
|
`emulation/vpx-rebuild/dist/PokemonPro_Rebuild.vpx`. The supported first
|
||||||
|
release is deliberately two-window. It does not use VNC,
|
||||||
|
noVNC, browser capture, JPEG screendumps, or the dashboard for gameplay. The
|
||||||
|
dashboard remains an optional diagnostic monitor. This is an
|
||||||
|
evidence-calibrated playable development recreation; it is not a
|
||||||
|
measurement-validated replica of ramp heights, coil forces, or rebound curves.
|
||||||
|
|
||||||
|
The one-command Finder entry point is `emulation/run-playable.command`; the
|
||||||
|
terminal entry point is `emulation/scripts/run-playable-macos.sh`.
|
||||||
|
|
||||||
|
### Clean rebuild workflow
|
||||||
|
|
||||||
|
With no table override, `emulation/scripts/run-playable-macos.sh` runs
|
||||||
|
`emulation/vpx-rebuild/build.sh` and selects
|
||||||
|
`emulation/vpx-rebuild/dist/PokemonPro_Rebuild.vpx`. The maintained sources are
|
||||||
|
`design/geometry.json`, `design/lights.json`, the VBS template, procedural
|
||||||
|
assets, and generator under `emulation/vpx-rebuild/`; generated `source/` and
|
||||||
|
`dist/` files must not be hand-edited. `emulation/vpx-rebuild/run-standalone.sh`
|
||||||
|
provides the short no-QEMU physics/render path.
|
||||||
|
|
||||||
|
`SPIKE3_VPX_TABLE` still permits an explicit custom table. If that table needs
|
||||||
|
a preparation step, set `SPIKE3_VPX_BUILD`; setting the custom table without a
|
||||||
|
build override prevents the clean rebuild script from modifying it. The
|
||||||
|
historical `emulation/vpx/PokemonPro_Greybox.vpx` and
|
||||||
|
`emulation/vpx/manual/PokemonPro_Manual.vpx` are deprecated historical
|
||||||
|
artifacts. The clean workflow does not inspect or write either file, and
|
||||||
|
neither is the active geometry source or default.
|
||||||
|
|
||||||
|
### Current stop point (2026-07-20)
|
||||||
|
|
||||||
|
The bridge now ingests host events immediately and routes service controls over
|
||||||
|
active-low CPU-SPI. Start and Action use the installed power-distribution
|
||||||
|
command `0x15` path, including unsolicited input reports. The genuine display
|
||||||
|
has acknowledged service navigation, and protocol tests cover a Start change
|
||||||
|
without a preceding host poll. Those are transport results, not a completed
|
||||||
|
game.
|
||||||
|
|
||||||
|
The clean table and canonical hardware contract pass their static validators.
|
||||||
|
`emulation/vpx-rebuild/qa/runtime-smoke.log` records a bounded VPX 10.8.1
|
||||||
|
`CaptureAttract` pass on the exact current table SHA-256
|
||||||
|
`ddce5d48033ee3c6e67248910a73897293e8b9c36eee29df164160a93572a30e`,
|
||||||
|
with table/VBS load, script compile/start, Metal initialization, two rendered
|
||||||
|
frames, clean close, and exit code 0. In integrated modes,
|
||||||
|
the clean script publishes physical contacts, consumes exact-address lamp
|
||||||
|
components, preserves ordered driver pulses, establishes reconnect baselines,
|
||||||
|
and releases transients/mechanisms on disconnect. Cabinet edges move the
|
||||||
|
flippers locally while cabinet/EOS state is still sent to the genuine game.
|
||||||
|
|
||||||
|
The final clean table also completed the supervised native QEMU/VPX startup
|
||||||
|
gate on 2026-07-20. The accepted session reached `Playable cabinet connected`
|
||||||
|
with synchronized VPX physics, 392 lamp updates, 7 LED frames, 1 driver pulse,
|
||||||
|
stable captive-ball contacts, and QEMU-keyboard coin/Start press-release
|
||||||
|
records. The default hardware-output wait is 420 seconds because normal game
|
||||||
|
initialization can take about five minutes. A transient bridge blip is accepted
|
||||||
|
only after a later synchronized reconnect; unrecovered disconnects still fail
|
||||||
|
closed.
|
||||||
|
|
||||||
|
The remaining immediate cabinet gate is completing and preserving a genuine
|
||||||
|
normal game cycle. The generated QEMU disk is writable and persistent, but the
|
||||||
|
current conagent `data_store` model is memory-only. After that gate, the final clean table still needs a captured normal game,
|
||||||
|
multiball, full physical shot coverage, integrated RGB/driver/mechanism traces,
|
||||||
|
restart recovery, and a 60-minute inventory soak. Earlier greybox/manual
|
||||||
|
runtime logs remain useful historical bridge evidence, but they do not prove
|
||||||
|
the clean table's geometry or final trajectories.
|
||||||
|
|
||||||
|
## Runtime ownership
|
||||||
|
|
||||||
|
| Concern | Authority |
|
||||||
|
| --- | --- |
|
||||||
|
| Rules, scoring, player/ball progression | Genuine game process in QEMU |
|
||||||
|
| Display, music, speech, game effects | QEMU Cocoa/CoreAudio |
|
||||||
|
| Ball physics and collision geometry | Native VPX at a 1,000 Hz physics step |
|
||||||
|
| Physical switch state and pulses | VPX table script and controller plugin |
|
||||||
|
| Lamps and mechanism driver commands | Genuine game through netbridge |
|
||||||
|
| Mechanical ball/rubber/flipper/gate sounds | VPX only |
|
||||||
|
| Window placement and focus | Native macOS helper |
|
||||||
|
|
||||||
|
`emulation/playfield-contract/pokemon-pro-hardware.json` is the canonical
|
||||||
|
geometry-free mapping. It records 45 playfield switches, 11 sensors, 9 cabinet
|
||||||
|
controls, 13 drivers, and 113 logical lamps expanded to 176 component bindings
|
||||||
|
at 150 exact SPIKE addresses. The plugin mapping header is generated from this
|
||||||
|
contract by `emulation/vpx-plugin/generate-layout-mapping.py`; it is not a
|
||||||
|
second handwritten address map. Ball inventory and placement live separately
|
||||||
|
in the clean geometry/script rather than becoming transport fields.
|
||||||
|
|
||||||
|
## Playfield protocol and safe recovery
|
||||||
|
|
||||||
|
`analysis/netbridge-emulator/netbridge_emu.py` provides a persistent,
|
||||||
|
loopback-only JSONL endpoint at `127.0.0.1:8091` using
|
||||||
|
`spike3-playfield/v1`. VPX sends `hello`, `switch.set`, `switch.pulse`,
|
||||||
|
`cabinet.set`, `release_transient`, and `heartbeat`. The bridge sends complete
|
||||||
|
`snapshot` records, coalescible `lamp.delta` records, lossless ordered
|
||||||
|
`driver.pulse` records, and `status` records.
|
||||||
|
|
||||||
|
Every server record has a process-unique `bridge_session`, a monotonic launcher
|
||||||
|
`bridge_generation`, sequence, model revision, and monotonic timestamp. A new
|
||||||
|
connection is not considered ready after TCP connect or `hello`. The bridge
|
||||||
|
first sends a disconnected snapshot and `synchronizing`; the plugin releases
|
||||||
|
transients, restores stable switch/cabinet state, and sends a heartbeat as an
|
||||||
|
ordering barrier. The bridge reports `ready` and sends QEMU monitor `cont` only
|
||||||
|
after that barrier and after the guest UART is connected.
|
||||||
|
|
||||||
|
With `physics_authority=vpx`, the netbridge synthetic shooter, trough, outlane,
|
||||||
|
VUK, flipper-EOS, and ball-return shortcuts are disabled from process start.
|
||||||
|
On a VPX disconnect, transient contacts open, VPX mechanisms de-energize,
|
||||||
|
stable trough/held-ball contacts remain, and QEMU receives monitor `stop`. A
|
||||||
|
supervised bridge restart removes the old readiness record, restores only
|
||||||
|
stable contacts plus lamp/driver snapshot baselines, assigns a new session and
|
||||||
|
generation, and never replays cumulative driver counts as new pulses.
|
||||||
|
|
||||||
|
The implementation and synchronization tests are in
|
||||||
|
`analysis/netbridge-emulator/test_netbridge_emu.py`. The native supervisor is
|
||||||
|
`emulation/scripts/run-macos.sh`; the outer cabinet lifecycle and identity
|
||||||
|
checks are in `emulation/scripts/run-playable-macos.sh`.
|
||||||
|
|
||||||
|
## VPX plugin and table modes
|
||||||
|
|
||||||
|
`emulation/vpx-plugin/` is rebased to the installed VPX commit
|
||||||
|
`ca80d1604e6a525db2a3f6d1ec704fc651d573fa`. Its builder checks the exact Git
|
||||||
|
revision, host binary SHA-256, ARM64 architecture, and bundle version before
|
||||||
|
writing `emulation/work/vpx-plugin/Spike3Controller/vpx-host-attestation.txt`.
|
||||||
|
The playable launcher copies the attested app to a private workspace runtime,
|
||||||
|
installs the matching plugin there, and ad-hoc signs that private copy. It does
|
||||||
|
not modify the user's source VPX app.
|
||||||
|
|
||||||
|
Network work runs on a background thread. Bounded queues keep socket I/O away
|
||||||
|
from VPX's render/physics thread; lamp state is coalesced, while driver events
|
||||||
|
retain order and cumulative counters. Reconnect snapshots establish a driver
|
||||||
|
counter baseline and cannot become stale physical events.
|
||||||
|
|
||||||
|
The table has explicit modes:
|
||||||
|
|
||||||
|
- `standalone`: provides local serving, flipper/plunger control, and mechanism
|
||||||
|
behavior for no-QEMU physics/render checks.
|
||||||
|
- `spike3`: QEMU is authoritative for lamps and every driver-driven mechanism.
|
||||||
|
- `qa-spike3`: integrated handshake/input/output acceptance without falling
|
||||||
|
back to standalone behavior.
|
||||||
|
|
||||||
|
In integrated mode, a missing controller is fail-safe: the table remains in
|
||||||
|
SPIKE mode, disables standalone serving/GI, de-energizes driver-controlled
|
||||||
|
mechanisms, and logs the error. Flippers are the deliberate exception to game
|
||||||
|
driver ownership: cabinet buttons actuate them locally and publish their
|
||||||
|
cabinet/EOS states to the bridge. Slings, pops, trough eject, auto-launch,
|
||||||
|
posts, gate, Meowth motor, and ejects move only from mapped game driver pulses.
|
||||||
|
|
||||||
|
## Physics and private visual assets
|
||||||
|
|
||||||
|
`emulation/vpx-rebuild/design/geometry.json` is the active clean-room geometry
|
||||||
|
and physics source. It fixes a 952 by 2115 VPX plane, 6.5-degree pitch, and
|
||||||
|
standard 50-unit-diameter ball. XY references follow the full 451 by 998 Pro
|
||||||
|
locator registration; Z paths, clearances, restitution, friction, coil force,
|
||||||
|
and mechanism timing remain simulation values until measured on a physical Pro
|
||||||
|
machine. `design/lights.json` independently records lamp placement and
|
||||||
|
confidence rather than deriving visual coordinates from the transport map.
|
||||||
|
|
||||||
|
The deterministically registered official Pro photograph is the provisional
|
||||||
|
playfield texture; it retains photographed hardware, shadows, and lighting
|
||||||
|
under the separately rendered VPX geometry. Original procedural meshes provide
|
||||||
|
posts, hardware, toys, and mechanisms, and the CC0 mechanical bank supplies
|
||||||
|
physics audio without copying game samples. The table, official photograph,
|
||||||
|
Pokemon/Stern imagery, reference manual, and assembled output are private-use
|
||||||
|
artifacts and are excluded from any redistributable package.
|
||||||
|
|
||||||
|
## Controls and native windows
|
||||||
|
|
||||||
|
The launcher writes a private VPX input profile without overwriting existing
|
||||||
|
service bindings. Defaults are:
|
||||||
|
|
||||||
|
| Input | Function |
|
||||||
|
| --- | --- |
|
||||||
|
| Left/Right Shift or LB/RB | Flippers |
|
||||||
|
| Return, Space, A, or right trigger | Action/launch |
|
||||||
|
| `1` or Menu | Start |
|
||||||
|
| `5` or View | Coin |
|
||||||
|
| `7`/`8`/`9`/`0` or D-pad | Service back/down/up/enter |
|
||||||
|
|
||||||
|
The QEMU guest keyboard relay now implements the same map as VPX. Previously,
|
||||||
|
only Shift was a cabinet control when the Cocoa backbox had focus; Return and
|
||||||
|
`1` through `9` still used an obsolete diagnostic switch map. That produced the
|
||||||
|
observed failure where flippers navigated Guided Setup while Start, coin,
|
||||||
|
Action, and service keys did nothing useful. The corrected relay maps `1`,
|
||||||
|
`5`, Return/Space, and `7`/`8`/`9`/`0` to the named cabinet inputs above.
|
||||||
|
|
||||||
|
The 2026-07-15 generated rootfs was rebuilt with the correction. The installed
|
||||||
|
AArch64 `/usr/local/spike-emu/bin/keyboard-switch-relay` was extracted from the
|
||||||
|
ext4 image and matched an independent source build at SHA-256
|
||||||
|
`55054003950873900b5ce203292846f158b861060dbdd2e04b5be4a8afa1869c`.
|
||||||
|
A headless QEMU monitor test injected all ten keys and
|
||||||
|
`emulation/work/logs/keyboard-relay.log` recorded matching press/release pairs
|
||||||
|
for both flippers, Start, coin, Action twice, and all four service controls.
|
||||||
|
That event-name check alone was insufficient: CPU and powerdist contacts do
|
||||||
|
not pass through a node input-bank poll. The playfield bridge now runs a
|
||||||
|
bounded host-event pump which routes those edges to their real transports
|
||||||
|
immediately while leaving ordinary node-bus edges queued until the relevant
|
||||||
|
bank read. The cabinet aliases and routes are loaded from
|
||||||
|
`emulation/playfield-contract/pokemon-pro-hardware.json`.
|
||||||
|
|
||||||
|
VPX normally receives focus. On two displays the AppKit/Accessibility helper attempts a
|
||||||
|
fullscreen VPX playfield plus fullscreen QEMU backbox. On one display it uses
|
||||||
|
approximately 65% for VPX and 35% for a 16:9 backbox. If Accessibility access
|
||||||
|
is declined or a window does not expose fullscreen through AX, both processes
|
||||||
|
remain running and the launcher prints the saved placement log and manual
|
||||||
|
layout.
|
||||||
|
|
||||||
|
## Verification boundary
|
||||||
|
|
||||||
|
The reproducible checks are split by what they prove:
|
||||||
|
|
||||||
|
- `python3 -m unittest discover -s analysis/netbridge-emulator -v` verifies
|
||||||
|
recovered serial behavior, protocol ordering, output identity, safe pause,
|
||||||
|
snapshot restore, synchronization, and lossless driver delivery.
|
||||||
|
- `emulation/vpx-plugin/tests/run-tests.sh` verifies the generated mapping,
|
||||||
|
background client, ordered input edges, output records, driver baseline, and
|
||||||
|
reconnect behavior against a loopback server.
|
||||||
|
- `python3 emulation/playfield-contract/validate_contract.py --json` verifies
|
||||||
|
the geometry-free schema, channel counts/routes, manual evidence, consumer
|
||||||
|
loading, and generated-header parity.
|
||||||
|
- `emulation/vpx-rebuild/build.sh` regenerates assets/source, verifies the
|
||||||
|
assembled VPX, compares the round-trip VBS, and runs contract/object,
|
||||||
|
geometry, clearance, lamp-route, audio, and no-ball-teleport checks recorded
|
||||||
|
in `emulation/vpx-rebuild/qa/rebuild-validation.json`.
|
||||||
|
- `emulation/vpx-rebuild/qa/runtime-smoke.log` records the exact current table
|
||||||
|
loading, compiling/starting its script, rendering two frames, and closing
|
||||||
|
with exit code 0 under VPX 10.8.1 `CaptureAttract`. It does not claim
|
||||||
|
interactive ball or mechanism coverage.
|
||||||
|
- The accepted live cabinet startup proves the real QEMU game returned lamp,
|
||||||
|
LED, and driver output through the final table/plugin path and received
|
||||||
|
QEMU-keyboard coin/Start edges. It does not prove a complete normal game.
|
||||||
|
|
||||||
|
Do not infer a normal three-ball game, multiball, measured frame-rate percentile,
|
||||||
|
or 60-minute invariant soak from the static/unit suites. Those acceptance rows
|
||||||
|
must remain explicitly open until their corresponding native run logs exist.
|
||||||
|
|
||||||
|
## Optional composed backbox
|
||||||
|
|
||||||
|
QEMU D-Bus shared-memory scanout is a follow-up only. It must demonstrate
|
||||||
|
correct page flips, sustained 60 fps for ten minutes, and no more than one
|
||||||
|
added frame before being connected to a VPX Backglass/ScoreView texture. The
|
||||||
|
working two-window Cocoa path remains the fallback; VNC/browser/screendump
|
||||||
|
capture is not an accepted gameplay fallback.
|
||||||
@@ -8,6 +8,7 @@ Target artifacts:
|
|||||||
- `/games/pokemon_pro/spike3/netbridge/spike3-swd.cfg`
|
- `/games/pokemon_pro/spike3/netbridge/spike3-swd.cfg`
|
||||||
- `/games/pokemon_pro/spike3/netbridge/rp2040.cfg`
|
- `/games/pokemon_pro/spike3/netbridge/rp2040.cfg`
|
||||||
- `/games/pokemon_pro/spike3/netbridge/version.txt`
|
- `/games/pokemon_pro/spike3/netbridge/version.txt`
|
||||||
|
- `/games/pokemon_pro/spike3/powerdist/powerdist_ext.hex`
|
||||||
|
|
||||||
Generated artifacts:
|
Generated artifacts:
|
||||||
|
|
||||||
@@ -160,6 +161,35 @@ CRC32(0, &__logical_binary_start, 0x12a40)
|
|||||||
|
|
||||||
For this ELF, `__logical_binary_start` maps to file offset `0x1100`. A Python `binascii.crc32` over `games/pokemon_pro/spike3/netbridge/netbridge.elf[0x1100:0x1100+0x12a40]` gives `0x357f5327`.
|
For this ELF, `__logical_binary_start` maps to file offset `0x1100`. A Python `binascii.crc32` over `games/pokemon_pro/spike3/netbridge/netbridge.elf[0x1100:0x1100+0x12a40]` gives `0x357f5327`.
|
||||||
|
|
||||||
|
## Power-Distribution Cabinet Inputs
|
||||||
|
|
||||||
|
Confirmed static facts:
|
||||||
|
|
||||||
|
- SHA-256 of `/games/pokemon_pro/spike3/powerdist/powerdist_ext.hex` is `f8eb96998a32ff86008663f7f07f2df76c32a9c86200f690c215dc36917391a9`; it is a 32,799-byte Intel HEX file whose decoded address range starts at `0x3800`.
|
||||||
|
- In `netbridge.elf`, `HOST_Update` at `0x10001210` calls `POWERDIST_IsSpike3`. For a SPIKE 3 controller, commands `0x10..0x1f` are passed to `POWERDIST_SendCmd` at `0x100020b4`; the legacy non-SPIKE-3 command `0x15` fallback is the unrelated one-byte `0xff` response.
|
||||||
|
- `POWERDIST_Update` at `0x10002174` parses controller frames and forwards their original command, sequence, and payload to the Pi with `HOSTUART_SendMessage`. These frames are not restricted to replies to a Pi request.
|
||||||
|
- Disassembling the decoded power-distribution image as Thumb code at `0x3800` shows command `0x15` dispatch at `0x427c`. It calls `0x475c` and returns exactly one payload byte.
|
||||||
|
- Function `0x46b4` composes that byte from raw GPIO P0_8, P0_9, and P0_11 as bits 0, 1, and 2. The installed cabinet map assigns Action to bit 0 and Start to bit 1; bit 2 is the coin-door power interlock state.
|
||||||
|
- Most importantly, the controller's input-change path at `0x407a` calls the frame sender at `0x3f9c` with command `0x15`, sequence `0`, a one-byte payload, and length `1`. A separate command handler at `0x428a` provides the same state for explicit polls.
|
||||||
|
|
||||||
|
The last point explains the VPX failure introduced while adding the first
|
||||||
|
power-distribution model. The emulator answered explicit `0x15` polls but did
|
||||||
|
not reproduce the controller's unsolicited change report, so a Start edge
|
||||||
|
could exist inside the emulator without ever reaching game code. The repaired
|
||||||
|
UART service queues every changed Start/Action state as command `0x15`,
|
||||||
|
sequence `0`, and drains those frames independently of incoming host traffic.
|
||||||
|
An integration test uses a socket pair to prove that a Start transition emits
|
||||||
|
`15 00 01` at the decoded protocol level without first sending a poll.
|
||||||
|
|
||||||
|
Reproduction commands used for the static controller pass:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
arm-none-eabi-objcopy -I ihex -O binary \
|
||||||
|
games/pokemon_pro/spike3/powerdist/powerdist_ext.hex /tmp/powerdist_ext.bin
|
||||||
|
arm-none-eabi-objdump -D -b binary -m arm -M force-thumb \
|
||||||
|
--adjust-vma=0x3800 /tmp/powerdist_ext.bin
|
||||||
|
```
|
||||||
|
|
||||||
## Nodebus Layer
|
## Nodebus Layer
|
||||||
|
|
||||||
`NODE_Init` configures a mixed PIO/hardware-UART nodebus:
|
`NODE_Init` configures a mixed PIO/hardware-UART nodebus:
|
||||||
@@ -220,6 +250,8 @@ It currently provides:
|
|||||||
- Firmware CRC response `0x357f5327`.
|
- Firmware CRC response `0x357f5327`.
|
||||||
- PTY, serial-device, and Unix-socket serving modes for QEMU or host-side serial plumbing.
|
- PTY, serial-device, and Unix-socket serving modes for QEMU or host-side serial plumbing.
|
||||||
- Existing-node stub at address `0x0a` with Magikarp/topper-oriented commands `0xf2`, `0xfc`, `0xfd`, `0xfe`, and `0xff`.
|
- Existing-node stub at address `0x0a` with Magikarp/topper-oriented commands `0xf2`, `0xfc`, `0xfd`, `0xfe`, and `0xff`.
|
||||||
|
- Power-distribution command `0x15` polling plus unsolicited sequence-0
|
||||||
|
Start/Action change reports matching the installed controller firmware.
|
||||||
|
|
||||||
Run:
|
Run:
|
||||||
|
|
||||||
@@ -243,8 +275,8 @@ Verification performed:
|
|||||||
|
|
||||||
```text
|
```text
|
||||||
python3 -m unittest discover -s analysis/netbridge-emulator
|
python3 -m unittest discover -s analysis/netbridge-emulator
|
||||||
....
|
...................................................................
|
||||||
Ran 4 tests in 0.000s
|
Ran 67 tests
|
||||||
OK
|
OK
|
||||||
|
|
||||||
python3 -m py_compile analysis/netbridge-emulator/netbridge_emu.py analysis/netbridge-emulator/test_netbridge_emu.py
|
python3 -m py_compile analysis/netbridge-emulator/netbridge_emu.py analysis/netbridge-emulator/test_netbridge_emu.py
|
||||||
|
|||||||
@@ -1,5 +1,72 @@
|
|||||||
# Next Analysis Targets
|
# Next Analysis Targets
|
||||||
|
|
||||||
|
## Priority 0: Native playable acceptance and calibration
|
||||||
|
|
||||||
|
The QEMU/HVF Cocoa game path, loopback `spike3-playfield/v1` bridge, safe
|
||||||
|
pause/restart synchronization, VPX 10.8.1 controller-plugin rebase, generated
|
||||||
|
hardware-contract mapping, clean-room dual-mode VPX table, private controller
|
||||||
|
profile, and native two-window launcher are implemented; see
|
||||||
|
`native-playable-table.md` and `vpx-table-recreation.md`. The default launcher
|
||||||
|
now builds and selects
|
||||||
|
`emulation/vpx-rebuild/dist/PokemonPro_Rebuild.vpx`. The deprecated
|
||||||
|
`emulation/vpx/PokemonPro_Greybox.vpx` is historical evidence that the clean
|
||||||
|
rebuild does not inspect or write; it is not a build input or runtime default.
|
||||||
|
|
||||||
|
The input transport blockers are now repaired and live-checked. The table uses
|
||||||
|
`VPXActionKey(25..28)`; power-distribution command `0x15` carries active-low
|
||||||
|
Action/Start/door state; CPU-SPI `0-SW-23` is correctly aligned; and service
|
||||||
|
Back/Up/Down/Enter use CPU-SPI `0-SW-8/9/10/11`. Immediate host-event ingestion
|
||||||
|
replaces the broken dependency on node-bus polling. The genuine display
|
||||||
|
accepted service Up/Down/Back, and the guest acknowledged the exact raw states.
|
||||||
|
|
||||||
|
The final clean table now passes the supervised native startup gate: the
|
||||||
|
2026-07-20 run reached `Playable cabinet connected`, returned 392 lamp updates,
|
||||||
|
7 LED frames, and 1 driver pulse, kept both captive optos stable, and delivered
|
||||||
|
QEMU-keyboard coin/Start edges. The launcher now allows 420 seconds because
|
||||||
|
normal game initialization can take about five minutes. The next blocking
|
||||||
|
integration target is a complete normal game and persistence check. If a fresh
|
||||||
|
image enters Guided Setup, complete Save & Exit through the repaired panel,
|
||||||
|
trace any subsequent invalid-machine decision, identify the minimum genuine
|
||||||
|
NVRAM or conagent-backed setup records, persist them across two reboots, and
|
||||||
|
prove the second boot reaches attract mode and accepts Start.
|
||||||
|
|
||||||
|
The clean table and geometry-free hardware contract pass their static
|
||||||
|
validators. `emulation/vpx-rebuild/qa/runtime-smoke.log` records a bounded VPX
|
||||||
|
10.8.1 `CaptureAttract` pass on 2026-07-20: it loaded the table and VBS,
|
||||||
|
compiled/started the script, rendered two frames, and closed with exit code 0.
|
||||||
|
The final smoke now matches the current distribution SHA-256
|
||||||
|
`ddce5d48033ee3c6e67248910a73897293e8b9c36eee29df164160a93572a30e`.
|
||||||
|
It is not interactive play or a substitute for the QEMU-connected acceptance
|
||||||
|
below.
|
||||||
|
|
||||||
|
After those blockers, continue acceptance and calibration:
|
||||||
|
|
||||||
|
- Complete and preserve a normal game plus a multiball sequence through the
|
||||||
|
genuine rules on the final clean table, without dashboard ball-motion
|
||||||
|
shortcuts.
|
||||||
|
- Exercise the shooter lane, both orbits, every ramp, both outlanes/returns,
|
||||||
|
pops, QEMU-authoritative slings, Pokedex captive chain, Town VUK, right-ramp
|
||||||
|
hold/Pikachu post, gates, spinner, targets, and Meowth movement with physical
|
||||||
|
VPX balls. Treat contact injection as transport coverage, not shot proof.
|
||||||
|
- Capture exact-address RGB lamp behavior, ordered driver pulses, retained-ball
|
||||||
|
ownership, disconnect fail-safe, and reconnect baselines in one integrated
|
||||||
|
run of the final table.
|
||||||
|
- Record input-to-visible-flipper and bridge-output-to-mechanism p95/p99 from
|
||||||
|
live native traces, plus rendered fps/1% low under simultaneous QEMU load.
|
||||||
|
- Preserve a full 60-minute inventory soak and explicit QEMU, bridge, and VPX
|
||||||
|
restart logs before declaring the long-run acceptance row complete.
|
||||||
|
- Compare `emulation/vpx-rebuild/design/geometry.json` with a physical Pro
|
||||||
|
machine: measure ramp Z/clearance, post and toy footprints, Pikachu post
|
||||||
|
direction/stroke, Meowth crank travel, coil timing, pitch, and ball/rubber
|
||||||
|
behavior. Replace estimated or simulation-tuned values only with recorded
|
||||||
|
evidence.
|
||||||
|
- Acquire a licensed stripped/bare-playfield scan to replace the official
|
||||||
|
registered photograph, whose baked-in hardware and lighting remain visible
|
||||||
|
beneath VPX geometry. Re-run visual and runtime QA after that asset change.
|
||||||
|
- Test QEMU D-Bus shared-memory scanout only after the two-window release is
|
||||||
|
stable. Retain Cocoa rather than adopting a VNC/browser capture fallback if
|
||||||
|
page-flip, 60 fps, or one-frame latency gates fail.
|
||||||
|
|
||||||
The current derived-data inventory and confidence boundaries are summarized in `analysis-evidence-map.md`. This page tracks only the work that remains or still needs stronger validation.
|
The current derived-data inventory and confidence boundaries are summarized in `analysis-evidence-map.md`. This page tracks only the work that remains or still needs stronger validation.
|
||||||
|
|
||||||
## Priority 1: Main Game Binary
|
## Priority 1: Main Game Binary
|
||||||
@@ -26,7 +93,8 @@ Suggested first passes:
|
|||||||
|
|
||||||
Follow-up passes:
|
Follow-up passes:
|
||||||
|
|
||||||
- Continue from `emulation/`: QEMU now boots the generated rootfs, exposes noVNC/dashboard, uses cached rootfs preparation, loads `virtio_gpu`, creates `/dev/dri/card0` plus `/dev/dri/renderD128`, and reaches `boot-display`, `spike-menu`, and `/games/game`. The generated rootfs includes a display probe, `fbdev` fallback interposer, Mesa surfaceless/pbuffer support, synthetic GLES/GBM/EGLImage fallbacks, GPIO sysfs stubs, framebuffer diagnostic renderer, and null ALSA default. Verified captures include nonblank `emulation/work/boot-display-fbo-wrap.ppm`, `emulation/work/spike-menu-gpio-wrap.ppm`, `emulation/work/game-gl-limits.ppm`, `emulation/work/game-fbdev-real-egl.png`, and the earlier diagnostic screen in `emulation/work/game-diagnostic.png`. The prior black-screen, missing-ALSA-default, boot-display framebuffer retry, SPIKE-menu GPIO 25 spam, Mesa loader dependency, and zero-varying shader blockers are cleared. The current display blocker is the main game's target-created EGLImage/FBO path: `eglMakeCurrent` succeeds with a real pbuffer, but the framebuffer remains incomplete and Mesa reports `GL_INVALID_FRAMEBUFFER_OPERATION`, so VNC still shows fallback color bands instead of a game frame. Other current blockers are TAS/MAX amp register verify reads and bridge/netbridge startup failures (`OpenOCD init failed`, `netbridge image CRC mismatch`, `failed to init bridge thread`). The next pass should fix or fake the FBO attachment path, then decide which bridge/netbridge and audio paths need modeling versus inert stubs.
|
- Exercise the new process-level lane documented in `process-level-emulation.md`. Static validation resolves all 51 target runtime libraries and matching `GLIBC_2.39`/`GLIBCXX_3.4.32` nodes; launcher/unit/syntax checks and the Apple Silicon ARM64 container build pass without executing the target. The initial `prepare` run exposed a nested `/games/spike3` alias bug which is now fixed and regression-tested; the post-fix run was blocked by the local Codex Docker approval/usage gate. The next acceptance sequence is `prepare`, `boot-display`, `spike-menu`, then `game`: execute the Mesa FBO smoke test, verify changing noVNC frames on port 6081, nonzero WAV capture, five-minute attract stability, one synthetic-ball Start/flipper/drain cycle from the dashboard, a qemu-user smoke run, and live GDB attachment. Record each failure from the timestamped `emulation/work/runs/` bundle rather than treating source completion as playability.
|
||||||
|
- Continue from `emulation/`: QEMU now boots the generated rootfs, exposes noVNC/dashboard, uses cached rootfs preparation, loads `virtio_gpu`, creates `/dev/dri/card0` plus `/dev/dri/renderD128`, and reaches `boot-display`, `spike-menu`, and `/games/game`. The generated rootfs includes a display probe, `fbdev` fallback interposer, Mesa surfaceless/pbuffer support, synthetic GLES/GBM/EGLImage fallbacks, GPIO sysfs stubs, framebuffer diagnostic renderer, and null ALSA default. Verified captures include nonblank `emulation/work/boot-display-fbo-wrap.ppm`, `emulation/work/spike-menu-gpio-wrap.ppm`, `emulation/work/game-gl-limits.ppm`, `emulation/work/game-fbdev-real-egl.png`, and the earlier diagnostic screen in `emulation/work/game-diagnostic.png`. The prior black-screen, missing-ALSA-default, boot-display framebuffer retry, SPIKE-menu GPIO 25 spam, Mesa loader dependency, and zero-varying shader blockers are cleared. The Docker/VNC softpipe path still encounters the target-created EGLImage/FBO issue and fallback color bands. The native macOS HVF/Cocoa path now has a verified complete 1920x1080 game-frame capture with the opt-in Debian Mesa 22.3.6 llvmpipe stack, although it uses about 5.3 host CPU cores and logs rejected page flips. Other current blockers are TAS/MAX amp register verify reads and bridge/netbridge startup failures (`OpenOCD init failed`, `netbridge image CRC mismatch`, `failed to init bridge thread`). The next display pass should measure llvmpipe frame pacing against softpipe and then investigate an Apple-GPU-backed VirtIO/translation path separately from the working CPU-rendered baseline.
|
||||||
- Validate `analysis/topper-emulator/topper_emulator.py` on live hardware or a nodebus capture.
|
- Validate `analysis/topper-emulator/topper_emulator.py` on live hardware or a nodebus capture.
|
||||||
- Recover the exact Magikarp topper `IDENTITY_BOARD_PART_ID` expected by command `0xfe`.
|
- Recover the exact Magikarp topper `IDENTITY_BOARD_PART_ID` expected by command `0xfe`.
|
||||||
- Confirm physical UART pins, baud, voltage level, and any netbridge timing/break behavior required for a MicroPython node.
|
- Confirm physical UART pins, baud, voltage level, and any netbridge timing/break behavior required for a MicroPython node.
|
||||||
@@ -89,7 +157,7 @@ Follow-up passes:
|
|||||||
|
|
||||||
## Priority 4: Netbridge Debug Path
|
## Priority 4: Netbridge Debug Path
|
||||||
|
|
||||||
Status: first-pass strings, ELF program-header review, targeted Ghidra decompilation, host protocol recovery, a Python host-side emulator scaffold, Docker/QEMU optional serial wiring, and a Pico SDK firmware recreation are complete; see `package-image-firmware.md`, `netbridge-re.md`, and `docker-qemu-emulation.md`.
|
Status: first-pass strings, ELF program-header review, targeted Ghidra decompilation, host protocol recovery, power-distribution command `0x15` static recovery, a Python host-side emulator scaffold, Docker/QEMU optional serial wiring, and a Pico SDK firmware recreation are complete; see `package-image-firmware.md`, `netbridge-re.md`, and `docker-qemu-emulation.md`.
|
||||||
|
|
||||||
Targets:
|
Targets:
|
||||||
|
|
||||||
@@ -108,6 +176,10 @@ Findings:
|
|||||||
- `netbridge.elf` is a 32-bit ARM static executable with code mapped at `0x10000000` and RAM at `0x20000000`/`0x20040000`.
|
- `netbridge.elf` is a 32-bit ARM static executable with code mapped at `0x10000000` and RAM at `0x20000000`/`0x20040000`.
|
||||||
- Strings include `uart_node.c`, `NODEBUS_Poll`, `NODEUART_Write`, `UART_NodeRxIrq`, and `WS2812_NodeSetLED`.
|
- Strings include `uart_node.c`, `NODEBUS_Poll`, `NODEUART_Write`, `UART_NodeRxIrq`, and `WS2812_NodeSetLED`.
|
||||||
- Ghidra decompilation identifies the Pi-facing host UART as 2,000,000 baud STX/ETX/ESC framed messages on RP2040 GPIO 16/17, with `0x30` returning firmware CRC `0x357f5327` and `0x41` carrying direct nodebus requests.
|
- Ghidra decompilation identifies the Pi-facing host UART as 2,000,000 baud STX/ETX/ESC framed messages on RP2040 GPIO 16/17, with `0x30` returning firmware CRC `0x357f5327` and `0x41` carrying direct nodebus requests.
|
||||||
|
- Static disassembly of `powerdist_ext.hex` confirms that command `0x15`
|
||||||
|
returns GPIO P0_8/P0_9/P0_11 in bits 0/1/2 and emits an unsolicited
|
||||||
|
sequence-0 report whenever a debounced cabinet input changes. The Python
|
||||||
|
emulator now reproduces both the poll and asynchronous paths.
|
||||||
- `analysis/netbridge-emulator/netbridge_emu.py` implements the recovered host frame codec, core bridge commands, CRC response, PTY serving mode, and a stub node at address `0x0a`.
|
- `analysis/netbridge-emulator/netbridge_emu.py` implements the recovered host frame codec, core bridge commands, CRC response, PTY serving mode, and a stub node at address `0x0a`.
|
||||||
- `analysis/netbridge-pico-firmware/` implements the same recovered protocol as a Pico SDK firmware recreation with a portable host-core test.
|
- `analysis/netbridge-pico-firmware/` implements the same recovered protocol as a Pico SDK firmware recreation with a portable host-core test.
|
||||||
- Docker/QEMU now has an optional `SPIKE3_NETBRIDGE_EMU=1` path that starts the Python emulator on `emulation/work/netbridge.sock`, attaches it as a second PL011 serial, maps guest `/dev/ttyAMA5` to the real serial, and lets the preload shim pass that path through.
|
- Docker/QEMU now has an optional `SPIKE3_NETBRIDGE_EMU=1` path that starts the Python emulator on `emulation/work/netbridge.sock`, attaches it as a second PL011 serial, maps guest `/dev/ttyAMA5` to the real serial, and lets the preload shim pass that path through.
|
||||||
@@ -122,12 +194,12 @@ Follow-up passes:
|
|||||||
|
|
||||||
## Priority 5: Node Firmware
|
## Priority 5: Node Firmware
|
||||||
|
|
||||||
Status: first-pass Intel HEX range parsing complete for top-level node firmware; see `package-image-firmware.md`.
|
Status: first-pass Intel HEX range parsing is complete for top-level node firmware, and the power-distribution `0x15` input path has been disassembled; see `package-image-firmware.md` and `netbridge-re.md`.
|
||||||
|
|
||||||
Targets:
|
Targets:
|
||||||
|
|
||||||
- All `*-LPC*.hex` files under `/games/pokemon_pro`.
|
- All `*-LPC*.hex` files under `/games/pokemon_pro`.
|
||||||
- `/games/pokemon_pro/spike3/powerdist/powerdist_ext.hex`.
|
- `/games/pokemon_pro/spike3/powerdist/powerdist_ext.hex` (input-report path complete; other commands remain open).
|
||||||
|
|
||||||
Why:
|
Why:
|
||||||
|
|
||||||
|
|||||||
@@ -131,4 +131,7 @@ Parsed ranges:
|
|||||||
| `/games/pokemon_pro/ws2812node-LPC1313-1_33_0.hex` | 900 | 14336 | `0x1000` | `0x47ff` |
|
| `/games/pokemon_pro/ws2812node-LPC1313-1_33_0.hex` | 900 | 14336 | `0x1000` | `0x47ff` |
|
||||||
| `/games/pokemon_pro/ws2812pinnode-LPC1313-1_33_0.hex` | 1157 | 18432 | `0x1000` | `0x57ff` |
|
| `/games/pokemon_pro/ws2812pinnode-LPC1313-1_33_0.hex` | 1157 | 18432 | `0x1000` | `0x57ff` |
|
||||||
|
|
||||||
`/games/pokemon_pro/spike3/powerdist/powerdist_ext.hex` is present in the `.sidx` package index and remains a separate follow-up target for power-distribution firmware parsing.
|
`/games/pokemon_pro/spike3/powerdist/powerdist_ext.hex` is present in the
|
||||||
|
`.sidx` package index. Its command `0x15` cabinet-input poll and unsolicited
|
||||||
|
change-report paths have now been recovered; other power-distribution commands
|
||||||
|
remain follow-up targets. See `netbridge-re.md`.
|
||||||
|
|||||||
120
process-level-emulation.md
Normal file
120
process-level-emulation.md
Normal file
@@ -0,0 +1,120 @@
|
|||||||
|
# Process-Level Game Emulation
|
||||||
|
|
||||||
|
## Scope
|
||||||
|
|
||||||
|
The process lane runs only the extracted AArch64 game/display target, game
|
||||||
|
assets, extracted loader/library runtime, generated Mesa overlay, and clean-room
|
||||||
|
machine model. It does not boot Buildroot and does not modify extracted evidence.
|
||||||
|
|
||||||
|
Implementation entry points:
|
||||||
|
|
||||||
|
- `spike3-emu`
|
||||||
|
- `emulation/process/spike3_emu.py`
|
||||||
|
- `emulation/process/config.default.json`
|
||||||
|
- `emulation/process/Dockerfile`
|
||||||
|
|
||||||
|
Generated state is confined to `emulation/work/capsule/`,
|
||||||
|
`emulation/work/runs/`, and `emulation/work/packs/`; all three are excluded from
|
||||||
|
Git.
|
||||||
|
|
||||||
|
## Confirmed Static Runtime Contract
|
||||||
|
|
||||||
|
The launcher's dependency resolver was run against:
|
||||||
|
|
||||||
|
- `/games/pokemon_pro/game`
|
||||||
|
- `/games/pokemon_pro/spike3/spike_menu/game`
|
||||||
|
- `/games/pokemon_pro/spike3/bin/boot_display`
|
||||||
|
|
||||||
|
It resolves 51 unique `DT_NEEDED` libraries with no unresolved SONAMEs. The
|
||||||
|
highest required and provided version nodes both match: `GLIBC_2.39` and
|
||||||
|
`GLIBCXX_3.4.32`. This confirms that the extracted loader, glibc, and libstdc++
|
||||||
|
must remain the process runtime; substituting Debian bookworm's older
|
||||||
|
libstdc++ would be incompatible.
|
||||||
|
|
||||||
|
The initial asset capsule retains the full read-only
|
||||||
|
`/games/pokemon_pro` directory. `trace` inventories actual file opens, and
|
||||||
|
`pack --profile traced` creates a generated minimal tree whose copied files are
|
||||||
|
verified against the read-only source with SHA-256.
|
||||||
|
|
||||||
|
## Runtime Architecture
|
||||||
|
|
||||||
|
| Layer | Implementation |
|
||||||
|
| --- | --- |
|
||||||
|
| Host selection | Apple Silicon uses an ARM64 Linux container; AArch64 Linux uses native execution; x86-64 Linux uses qemu-user. |
|
||||||
|
| Isolation | Bubblewrap mounts game and target libraries read-only, creates an offline target network namespace, and binds only generated writable state. |
|
||||||
|
| Machine I/O | `libspike3machine_client.so` connects `/dev/spidev4.0`, `/dev/i2c-10`, GPIO, and netbridge calls to `emulation/work/machine.sock`. |
|
||||||
|
| Display | `libspike3emu_stub.so` writes XRGB frames to a generated regular `/dev/fb0`; ffplay loops the frame into Xvfb, then x11vnc/noVNC serves port 6081. |
|
||||||
|
| Controls | Dashboard port 8090 uses the private Unix RPC socket; loopback-only TCP port 8091 serves VPX and other external controllers. |
|
||||||
|
| Audio | ALSA is converted to fixed 48 kHz stereo S16LE file output and finalized as `audio.wav` per run. |
|
||||||
|
| Debugging | Native uses extracted `gdbserver`; qemu-user uses `-g`; generated helpers resolve the PIE slide and named Ghidra offsets. |
|
||||||
|
| System fallback | `--engine system` delegates to the existing `qemu-system-aarch64`/virtio-gpu/noVNC workbench. |
|
||||||
|
|
||||||
|
Generated safe command replacements log and block `reboot`, `halt`, `poweroff`,
|
||||||
|
`shutdown`, and hostname changes. OpenOCD is replaced by a controlled stub whose
|
||||||
|
exit status defaults to success. The machine service implements no physical
|
||||||
|
outputs; the launcher's `hardware` backend is deliberately refused.
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
```sh
|
||||||
|
./spike3-emu prepare
|
||||||
|
./spike3-emu run boot-display
|
||||||
|
./spike3-emu run spike-menu
|
||||||
|
./spike3-emu run game
|
||||||
|
./spike3-emu debug game
|
||||||
|
./spike3-emu trace game
|
||||||
|
./spike3-emu pack --profile traced
|
||||||
|
./spike3-emu clean --legacy-system
|
||||||
|
./spike3-emu clean --legacy-system --yes
|
||||||
|
```
|
||||||
|
|
||||||
|
Run artifacts include effective configuration, stdout, syscall trace, broker
|
||||||
|
transactions, display-service logs, asset hashes, blocked commands, PCM/WAV
|
||||||
|
capture, GDB setup, and exit status.
|
||||||
|
|
||||||
|
## Verified Runtime Results (2026-07-11)
|
||||||
|
|
||||||
|
`./spike3-emu prepare` completed on Apple Silicon with 51 resolved libraries.
|
||||||
|
A repeat preparation completed from the dependency/config fingerprint cache in
|
||||||
|
0.56 seconds. Docker inspection reported the image as `linux/arm64`, 340,201,729
|
||||||
|
content bytes (1.36 GB virtual size). No QEMU process is used in process mode.
|
||||||
|
|
||||||
|
The ARM64 Mesa smoke command completed with framebuffer status `0x8cd5`, pixel
|
||||||
|
`64,128,191,255`, EGL 1.4, and no GL error. Live `boot-display`, `spike-menu`,
|
||||||
|
and `game` runs loaded the HLE preload and executed the target. The menu/game
|
||||||
|
accepted netbridge CRC `0x357f5327`. Dashboard port 8090 returned broker state,
|
||||||
|
and a direct JSONL request to `127.0.0.1:8091` returned a revisioned
|
||||||
|
`state.delta`. Manual Start/launch/drain events changed the virtual lifecycle.
|
||||||
|
|
||||||
|
A one-shot `docker stats --no-stream` sample shortly after game startup was
|
||||||
|
129.78% CPU, 200.9 MiB resident usage, and 63 container processes. The native
|
||||||
|
game reached its netbridge CRC check in about 5.1 seconds in that run. This is a
|
||||||
|
startup sample, not a five-minute steady-state benchmark. `docker top` showed
|
||||||
|
the extracted `ld-linux-aarch64.so.1` launching `/games/game` under bubblewrap
|
||||||
|
and no `qemu-system-*` or `qemu-aarch64` process. The legacy cleaner dry-run
|
||||||
|
reported 6,505,625,192 removable bytes (6 GiB rootfs plus a 63,173,402-byte
|
||||||
|
macOS runtime cache); those files were deliberately not removed automatically.
|
||||||
|
Changing-game FPS is not measurable until the connector failure is resolved.
|
||||||
|
|
||||||
|
The remaining display limit is confirmed: software EGL and the synthetic DRM
|
||||||
|
resource inventory initialize, but the proprietary window helper reports
|
||||||
|
`failed to get DRM connector for display_number 1`; GBM buffers are therefore
|
||||||
|
not allocated. Current nonzero framebuffer captures are HLE diagnostic frames,
|
||||||
|
not genuine changing game frames. Short runs produced no WAV data. Five-minute
|
||||||
|
attract mode, a target-observed full three-ball game, live GDB attachment, and
|
||||||
|
VPX round-trip remain open.
|
||||||
|
|
||||||
|
Unit verification is 14 launcher tests, 25 machine-model tests, and 3 dashboard
|
||||||
|
tests. Two machine socket-bind tests skip only because the managed test sandbox
|
||||||
|
denies AF_UNIX/AF_INET binds; the live Docker TCP and Unix paths were exercised.
|
||||||
|
|
||||||
|
## VPX Bridge
|
||||||
|
|
||||||
|
`emulation/vpx-plugin/` is pinned to VPX commit
|
||||||
|
`215129065954d265100e4fa7ff063154c6fedf5d`. Its build produced a Mach-O ARM64
|
||||||
|
ControllerPlugin dylib with `Spike3ControllerPluginLoad` and
|
||||||
|
`Spike3ControllerPluginUnload` exports. It forwards standard cabinet actions,
|
||||||
|
publishes SPIKE binary inputs/controlled devices, reconnects safely, and exposes
|
||||||
|
the `Spike3.Controller` script API. `example-spike3.vbs` covers target, lane,
|
||||||
|
trough, and drain events. VPX is not installed in `/Applications` on this host,
|
||||||
|
so actual VPX loading and bidirectional table verification are not claimed.
|
||||||
384
qr-code-analysis.md
Normal file
384
qr-code-analysis.md
Normal file
@@ -0,0 +1,384 @@
|
|||||||
|
# QR Code Analysis
|
||||||
|
|
||||||
|
## Scope
|
||||||
|
|
||||||
|
The QR code system on Pokemon Pro involves **two separate code paths**:
|
||||||
|
|
||||||
|
1. **QR Code Generation** — The game uses Nayuki's `qrcodegen` library to generate QR codes (WiFi config, Stern Insider Connected login, support URLs) and display them on-screen.
|
||||||
|
2. **QR Code Scanning** — A standalone hardware scanner module connected to the game via a `node4` bridge board (LPC812/LPC1124 MCU on the SPIKE-3 nodebus) and a serial UART.
|
||||||
|
|
||||||
|
**Important finding**: The QR code scanning functionality is in the **main game binary** (`/games/pokemon_pro/game`), **not** in `conagent`. The `conagent` binary has no QR-related strings or code. See `conagent-re.md` for the connectivity agent's separate role.
|
||||||
|
|
||||||
|
## Source Binary
|
||||||
|
|
||||||
|
- Target: `/games/pokemon_pro/game`
|
||||||
|
- Workspace path: `games/pokemon_pro/game`
|
||||||
|
- SHA-256: (see `artifact-index.md`)
|
||||||
|
- Type: stripped AArch64 PIE ELF, 52,829,400 bytes
|
||||||
|
- Embedded library: `qrcodegen` (Nayuki's QR Code Generator, C library)
|
||||||
|
|
||||||
|
## QR Code Generation
|
||||||
|
|
||||||
|
### Library: qrcodegen
|
||||||
|
|
||||||
|
The game embeds **Nayuki's QR Code Generator** library (`qrcodegen.c` at file offset `0x25e6c88`). This is a standalone C library that generates QR code symbol data from text input. Confirmed API functions:
|
||||||
|
|
||||||
|
| Function | Offset | Purpose |
|
||||||
|
|---|---|---|
|
||||||
|
| `qrcodegen_encodeSegmentsAdvanced` | `0x26028f8` | Core encoding entry point |
|
||||||
|
| `qrcodegen_getSize` | `0x2602760` | Get QR code module size |
|
||||||
|
| `qrcodegen_getModule` | `0x2602998` | Get individual module bit |
|
||||||
|
| `qrcodegen_isNumeric` | `0x2602728` | Check if text is numeric mode |
|
||||||
|
| `qrcodegen_isAlphanumeric` | `0x26029b0` | Check if text is alphanumeric mode |
|
||||||
|
| `qrcodegen_makeBytes` | `0x2602a00` | Create byte segment |
|
||||||
|
| `qrcodegen_makeNumeric` | `0x2602a18` | Create numeric segment |
|
||||||
|
| `qrcodegen_makeAlphanumeric` | `0x2602a38` | Create alphanumeric segment |
|
||||||
|
| `qrcodegen_makeEci` | `0x2602a30` | Create ECI segment |
|
||||||
|
|
||||||
|
Internal assertion strings confirm library version constraints:
|
||||||
|
- `qrcodegen_VERSION_MIN <= version && version <= qrcodegen_VERSION_MAX` (0x25e6c98)
|
||||||
|
- `21 <= qrsize && qrsize <= 177` (0x25e6d90)
|
||||||
|
- `0 <= (int)ecl && (int)ecl < 4` (0x25e7070)
|
||||||
|
|
||||||
|
### QR Code Output: BMP Files
|
||||||
|
|
||||||
|
Generated QR codes are rendered as **BMP image files**:
|
||||||
|
|
||||||
|
| Path | Offset | Purpose |
|
||||||
|
|---|---|---|
|
||||||
|
| `/tmp/qrx_.bmp` | `0x25db068` | Temporary QR code image |
|
||||||
|
| `/tmp/login.bmp` | `0x25e1760` | Login QR code output |
|
||||||
|
| `/connectivity/qr_code_storage/%d.bmp` | `0x25e26e8` + `0x25e2718` | Persistent QR code storage |
|
||||||
|
|
||||||
|
### QR Code Configuration Properties
|
||||||
|
|
||||||
|
QR code display properties are configured via a JSON-like object with these fields (all at offsets `0x25db270`–`0x25db2e0`):
|
||||||
|
|
||||||
|
| Field | Type | Purpose |
|
||||||
|
|---|---|---|
|
||||||
|
| `qrCodeText` | string | The text/URL to encode in the QR code |
|
||||||
|
| `qrCodeAppendMachineUuid` | bool | Whether to append machine UUID to text |
|
||||||
|
| `qrCodeStartTime` | timestamp | QR code validity window start |
|
||||||
|
| `qrCodeEndTime` | timestamp | QR code validity window end |
|
||||||
|
| `qrCodeXPosition` | int | Screen X position |
|
||||||
|
| `qrCodeYPosition` | int | Screen Y position |
|
||||||
|
| `qrCodeSize` | int | QR code size in pixels |
|
||||||
|
|
||||||
|
### Generated QR Code Types
|
||||||
|
|
||||||
|
| Type | String Context | Offset |
|
||||||
|
|---|---|---|
|
||||||
|
| Stern Insider Connected login | `Stern Insider Connected™ QR code.` | `0x25a7dba` |
|
||||||
|
| Connected Login QR | `Connected™ Login QR code.` | `0x25a7e99` |
|
||||||
|
| WiFi QR Code | `Scan WiFi QR Code` | `0x25a8360` |
|
||||||
|
| Quick Registration | `Connectivity/QrCodes/quick_registration_qr_code` | `0x25e1cf8` |
|
||||||
|
| Support | `Connectivity/QrCodes/support` | `0x25dc7e8` |
|
||||||
|
| Tech Support | `SCAN THIS QR CODE TO REACH OUR TECH SUPPORT TEAM` | `0x25dc231` |
|
||||||
|
|
||||||
|
## QR Code Scanning — Hardware Architecture
|
||||||
|
|
||||||
|
### Physical Components
|
||||||
|
|
||||||
|
The QR scanner system consists of:
|
||||||
|
|
||||||
|
1. **Scanner module** — A standalone 2D barcode scan engine (OEM part `part:520-9865-00` at `0x25b8c20`). The specific module model (Zebra, Honeywell, Newland, etc.) is not identifiable from strings; the firmware is a thin bridge without scanner-brand identifiers.
|
||||||
|
2. **Node4 bridge board** — A `node4` SPIKE-3 nodebus peripheral with dual firmware options:
|
||||||
|
- `node4-LPC812-1_33_0.hex` (LPC812, Cortex-M0+, 12 KB decoded)
|
||||||
|
- `node4-LPC1124_303-1_33_0.hex` (LPC1124, Cortex-M0+, 14 KB decoded)
|
||||||
|
3. **Connections**:
|
||||||
|
- Ribbon cable from scanner module to node4 board
|
||||||
|
- RJ45 nodebus cable from node4 to the game system
|
||||||
|
4. **GPIO antenna switch**: Two RF antennas on `gpiochip1` lines 3 (`ant1`) and 7 (`ant2`), controlled via `libgpiod.so.2`
|
||||||
|
|
||||||
|
### Serial Interface
|
||||||
|
|
||||||
|
The game communicates with the scanner module via **serial UART**:
|
||||||
|
|
||||||
|
| Path | Selection Logic | Offset |
|
||||||
|
|---|---|---|
|
||||||
|
| `/dev/ttyAMA2` | Default (kernel release byte != '5') | `0x25e9468` |
|
||||||
|
| `/dev/ttyAMA5` | Kernel release byte == '5' | `0x25e9478` |
|
||||||
|
|
||||||
|
Selection function at VA `0x94b8b0`: Uses `uname()` to check a kernel release byte, compares to `0x35` (`'5'`), selects ttyAMA5 on match, ttyAMA2 otherwise.
|
||||||
|
|
||||||
|
### Serial Configuration (VA `0x92d350`)
|
||||||
|
|
||||||
|
- **Open**: `open(path, O_RDWR | O_NOCTTY)`
|
||||||
|
- **Termios2**: Uses `TCGETS2` (ioctl `0x541e`) / `TCSETS2` (ioctl `0x541f`) — `struct termios2` for raw baud rates
|
||||||
|
- **Data bits**: 8 data bits, no parity
|
||||||
|
- **Stop bits**: 1 stop bit (configurable to 2 via `config[5] == 2`)
|
||||||
|
- **Local mode**: `CLOCAL | CREAD` (`0x880`)
|
||||||
|
- **Baud rate**: Configurable via 4-entry table indexed by `config[4] - 5`; actual rates not extractable from static analysis (uses non-standard termios2 CBAUD encodings)
|
||||||
|
- **Flow control**: `tcflow(fd, TCOON)`, `tcflush(fd, TCIOFLUSH)`
|
||||||
|
- **Timeout**: 1000 ms via `tcdrain`
|
||||||
|
|
||||||
|
### Node4 Bridge Firmware
|
||||||
|
|
||||||
|
The `node4` firmware files are thin, simple firmware images (6-11 ARM Thumb function entries) that bridge between:
|
||||||
|
|
||||||
|
- **Scanner side**: UART connection to the scanner module (baud rate divisors suggest 57600 for LPC812, 9600/230400/38400 for LPC1124)
|
||||||
|
- **Nodebus side**: SPIKE-3 nodebus protocol with node address `0x04`
|
||||||
|
|
||||||
|
The firmware does **not** contain:
|
||||||
|
- Scanner decode libraries (zbar, quirc, etc.)
|
||||||
|
- Scanner brand identifiers or protocol tables
|
||||||
|
- Any human-readable strings at all
|
||||||
|
|
||||||
|
This confirms the scanner module is a pre-integrated 2D barcode engine that handles decode internally, and the node4 board is a thin UART-to-nodebus bridge.
|
||||||
|
|
||||||
|
## QR Scanner Protocol
|
||||||
|
|
||||||
|
### Bridge Protocol (VA `0x94b9d0`–`0x94bbfc`)
|
||||||
|
|
||||||
|
The game communicates with the bridge (and through it to the scanner) using a custom framed protocol:
|
||||||
|
|
||||||
|
- **Buffer size**: 256 bytes (`mov w2, #0x100`)
|
||||||
|
- **Frame format**: `STX` + escaped body (cmd, seq, payload, checksum) + `ETX`
|
||||||
|
- **STX**: `0x02` — start of frame
|
||||||
|
- **ETX**: `0x03` — end of frame, triggers message processing
|
||||||
|
- **ESC**: `0x1B` — escape byte; next byte has bit `0x80` set
|
||||||
|
- **Checksum**: `(-sum(body)) & 0xFF`, verified before dispatch
|
||||||
|
- **Valid commands**: `0x10` through `0x41` (checked via `sub w0, w2, #0x10; cmp w0, #0x31`)
|
||||||
|
- **Command 0x30**: Firmware CRC handler at VA `0x953fc0`
|
||||||
|
- **Error handling**: "bridge rx checksum error", "message overrun", "too many message", "bridge %s unknown command: 0x%02x"
|
||||||
|
|
||||||
|
### Scanner Status Register (16 states)
|
||||||
|
|
||||||
|
The game tracks scanner status via an enum/string table at `0x25b8a40`–`0x25b8c00`:
|
||||||
|
|
||||||
|
| Offset | String | Meaning |
|
||||||
|
|---|---|---|
|
||||||
|
| `0x25b8a40` | `QR SCANNER BACKLIGHT` | Backlight control command |
|
||||||
|
| `0x25b8a58` | `QR SCANNER STATUS READY` | Scanner is ready for a scan |
|
||||||
|
| `0x25b8a70` | `QR SCANNER STATUS STRING` | Text string decoded from QR |
|
||||||
|
| `0x25b8a90` | `QR SCANNER STATUS ENCODED DATA` | Raw binary encoded data received |
|
||||||
|
| `0x25b8ab0` | `QR SCANNER STATUS MISSED STRING` | A scan was started but no decode |
|
||||||
|
| `0x25b8ad0` | `QR SCANNER STATUS OVERRUN` | Buffer overrun condition |
|
||||||
|
| `0x25b8af0` | `QR SCANNER STATUS UNSUPPORTED_AP` | Unsupported access point (WiFi) |
|
||||||
|
| `0x25b8b18` | `QR SCANNER STATUS FIFO OVERRUN` | Hardware FIFO overrun |
|
||||||
|
| `0x25b8b38` | `QR SCANNER STATUS CONFIG` | Configuration change event |
|
||||||
|
| `0x25b8b58` | `QR SCANNER STATUS ERROR` | Generic error |
|
||||||
|
| `0x25b8b70` | `QR SCANNER STATUS ERR1` | Error code 1 |
|
||||||
|
| `0x25b8b88` | `QR SCANNER STATUS ERR2` | Error code 2 |
|
||||||
|
| `0x25b8ba0` | `QR SCANNER STATUS ERR3` | Error code 3 |
|
||||||
|
| `0x25b8bb8` | `QR SCANNER STATUS ERR4` | Error code 4 |
|
||||||
|
| `0x25b8bd0` | `QR SCANNER STATUS ERR5` | Error code 5 |
|
||||||
|
| `0x25b8be8` | `QR SCANNER STATUS ERR6` | Error code 6 |
|
||||||
|
| `0x25b8c00` | `QR SCANNER STATUS NO READER` | Scanner disconnected |
|
||||||
|
|
||||||
|
### GPIO Antenna Switch (VA `0x950260`)
|
||||||
|
|
||||||
|
The QR scanner has a **dual-antenna RF switch** controlled via `gpiochip1`:
|
||||||
|
|
||||||
|
| GPIO | Label | Function |
|
||||||
|
|---|---|---|
|
||||||
|
| Line 3 | `ant1` | Antenna 1 |
|
||||||
|
| Line 7 | `ant2` | Antenna 2 |
|
||||||
|
|
||||||
|
Control logic:
|
||||||
|
- `arg=0`: Both antennas off (low)
|
||||||
|
- `arg=1`: `ant1` high, `ant2` low
|
||||||
|
- `arg=2`: `ant2` high, `ant1` low
|
||||||
|
|
||||||
|
## QR Parsing Classes
|
||||||
|
|
||||||
|
### C++ Class Hierarchy
|
||||||
|
|
||||||
|
The game uses C++ classes for QR code parsing, identified from RTTI/vtable references at `0x25fe1c0`–`0x25fe2d0`:
|
||||||
|
|
||||||
|
| Class | Offset | Role |
|
||||||
|
|---|---|---|
|
||||||
|
| `QrOfflineParser` | `0x25fe1c0` | Parses offline/local QR codes |
|
||||||
|
| `NetworkQrParser` | `0x25fe218` | Parses network/connectivity QR codes |
|
||||||
|
| `QrOfflineListener` | `0x25fe2d0` | Listens for offline QR scan events |
|
||||||
|
| `NetworkDataInterface` | `0x25fe1d8` | Base interface for network data |
|
||||||
|
| `CommandInterface` | `0x25fe1f0` | Base interface for commands |
|
||||||
|
| `NetworkData` | `0x25fe208` | Network data container |
|
||||||
|
|
||||||
|
### QR Code Format: `REG:T:`
|
||||||
|
|
||||||
|
The game uses a **proprietary QR code data format** identified by the prefix `REG:T:` at `0x25dbe30`:
|
||||||
|
|
||||||
|
- `REG:T:WPA` (offset `0x25dbe30`) — WiFi configuration QR code
|
||||||
|
- `REG:T:ETH` (offset `0x25dbe40`) — Ethernet/machine registration QR code
|
||||||
|
|
||||||
|
The format extends `REG:T:{TYPE}:{key}:{value}:{key}:{value}:...` with fields parsed programmatically.
|
||||||
|
|
||||||
|
### WiFi QR Data Flow
|
||||||
|
|
||||||
|
When a `REG:T:WPA` QR code is scanned:
|
||||||
|
|
||||||
|
1. `NetworkQrParser` extracts SSID, PSK, and encryption type
|
||||||
|
2. Validation: `"Not a valid WiFi QR code"` (`0x25a7200`)
|
||||||
|
3. Game builds `wpa_supplicant` config block:
|
||||||
|
```
|
||||||
|
ssid="%s"
|
||||||
|
scan_ssid=1
|
||||||
|
key_mgmt=%s (WPA-PSK)
|
||||||
|
pairwise=%s (TKIP or "CCMP TKIP")
|
||||||
|
group=%s
|
||||||
|
psk=%s
|
||||||
|
```
|
||||||
|
4. Writes to `/etc/wpa_supplicant.conf` (`0x25dfd68`)
|
||||||
|
5. Controls WiFi via `wpa_supplicant` control interface:
|
||||||
|
- `ADD_NETWORK` (`0x25d5688`)
|
||||||
|
- `SET_NETWORK` (`0x25d5808`)
|
||||||
|
- `ENABLE_NETWORK %s` (`0x25d5780`)
|
||||||
|
- `CTRL-EVENT-CONNECTED` (`0x25d57e8`)
|
||||||
|
- `CTRL-EVENT-DISCONNECTED` (`0x25d57e8`)
|
||||||
|
6. Control socket: `/var/run/wpa_supplicant/wlan0` (`0x25d5708`)
|
||||||
|
7. Also uses `/usr/sbin/wpa_cli status` (`0x25e26b8`)
|
||||||
|
|
||||||
|
### Stern Insider Connected QR Data Flow
|
||||||
|
|
||||||
|
When a Stern Insider Connected login QR code is scanned:
|
||||||
|
|
||||||
|
1. `QrOfflineParser` extracts user UUID from QR code
|
||||||
|
2. Flow: `QERT_SCANNED_USER_ACCOUNT` (`0x25dedd0`) → `ScannedUserAccountUUID` (`0x25dd568`) → `AuthenticatePlayer` (`0x25dd590`)
|
||||||
|
3. Player UUID is sent to backend via `PLAYER_AUTHENTICATE` (`0x25ecf18`)
|
||||||
|
4. Audit counters track results:
|
||||||
|
- `AUD_CONNECTIVITY_USERS_SCANNED` (`0x2594d60`)
|
||||||
|
- `AUD_CONNECTIVITY_USERS_JOINED` (`0x2594d80`)
|
||||||
|
- `AUD_CONNECTIVITY_BAD_QR_SCANS` (`0x2594ea8`)
|
||||||
|
- `AUD_CONNECTIVITY_BAD_USER_SCANS` (`0x2594e88`)
|
||||||
|
|
||||||
|
## Exploit Surface Analysis
|
||||||
|
|
||||||
|
### High Priority Targets
|
||||||
|
|
||||||
|
#### 1. `REG:T:WPA` → wpa_supplicant Command Injection
|
||||||
|
|
||||||
|
**Risk**: HIGH. The QR code content is parsed and passed to `wpa_supplicant` control interface commands (`ADD_NETWORK`, `SET_NETWORK`, `ENABLE_NETWORK`). If the SSID or PSK fields are not properly sanitized, an attacker could:
|
||||||
|
|
||||||
|
- Inject arbitrary `wpa_cli` or `wpa_supplicant` control interface commands
|
||||||
|
- Write to `/etc/wpa_supplicant.conf` with crafted content
|
||||||
|
- Potentially execute shell commands via the control interface
|
||||||
|
|
||||||
|
**Evidence**: The game uses `wpa_cli` at `/usr/sbin/wpa_cli status` (`0x25e26b8`). The control socket at `/var/run/wpa_supplicant/wlan0` (`0x25d5708`) accepts textual commands. SSID and PSK are inserted into format strings (`ssid="%s"`, `psk="%s"`) — if these use `sprintf`/`snprintf` without length limits, buffer overflow is possible.
|
||||||
|
|
||||||
|
#### 2. Serial Bridge Buffer Handling
|
||||||
|
|
||||||
|
**Risk**: MEDIUM-HIGH. The bridge protocol uses a **256-byte buffer** with a **1000 ms timeout**. The frame format uses STX/ETX/ESC framing with checksum. Potential issues:
|
||||||
|
|
||||||
|
- Buffer overflow if a message larger than 256 bytes is sent (the `read()` call reads up to 256 bytes, but the parser accumulates across multiple reads)
|
||||||
|
- Escape sequence mishandling (ESC `0x1B` sets bit 0x80 on next byte — crafted sequences could cause state confusion)
|
||||||
|
- Checksum bypass (the checksum is a simple sum complement)
|
||||||
|
|
||||||
|
#### 3. RapidJSON Parsing of QR Content
|
||||||
|
|
||||||
|
**Risk**: MEDIUM. The game uses **RapidJSON** library to parse QR-related data. Failure messages:
|
||||||
|
|
||||||
|
- `Failed to parse JSON.` (`0x259e9e0`)
|
||||||
|
- `INVALID JSON: expected "achievement_descriptors"` (`0x25dff48`)
|
||||||
|
- `INVALID JSON: expected "machine"` (`0x25e0088`)
|
||||||
|
- `INVALID JSON: failed to parse "machine"` (`0x25e00b0`)
|
||||||
|
|
||||||
|
RapidJSON assertion failures at `0x25d6348`–`0x25d6f20` (internal type checks). If assertions are compiled in (debug build), malformed JSON can crash the process. If assertions are compiled out, type confusion bugs may be exploitable.
|
||||||
|
|
||||||
|
#### 4. `qrCodeText` Buffer Handling
|
||||||
|
|
||||||
|
**Risk**: MEDIUM. The `qrCodeText` field is a raw string field that gets encoded into QR code data. If the text is used in `sprintf`/`snprintf` for display or file path construction without proper bounds checking, it could be a buffer overflow vector. QR codes are saved to `/connectivity/qr_code_storage/%d.bmp` using a numeric index — if the index is attacker-controlled, format string injection via `%d` is possible.
|
||||||
|
|
||||||
|
#### 5. Nodebus Secure Protocol
|
||||||
|
|
||||||
|
**Risk**: MEDIUM. The netbridge emulator (`netbridge_emu.py`) documents that secure nodebus requests (command `0x11`) use XOR encryption with session key rotation when `wire_address & 0xC0 == 0xC0`. If the encryption is weak or the session key derivation is predictable, a physical attacker with nodebus access could forge QR scan results.
|
||||||
|
|
||||||
|
### Medium Priority Targets
|
||||||
|
|
||||||
|
#### 6. GPIO Antenna Bypass
|
||||||
|
|
||||||
|
The dual-antenna system uses GPIO lines 3 and 7 on `gpiochip1`. If the antenna selection logic can be influenced by QR scan data, an attacker could potentially read from or interfere with the RF path.
|
||||||
|
|
||||||
|
#### 7. Audit Counter Manipulation
|
||||||
|
|
||||||
|
Audit counters (`AUD_CONNECTIVITY_BAD_QR_SCANS`, `AUD_CONNECTIVITY_USERS_SCANNED`, etc.) are tracked in shared memory or audit logs. If the QR parser crashes before incrementing error counters, brute-force scanning of QR codes could go undetected.
|
||||||
|
|
||||||
|
#### 8. Node4 Firmware Update Path
|
||||||
|
|
||||||
|
The `node4` bridge board has an LPC812/LPC1124 MCU that can be firmware-updated over the nodebus. If the update path is triggered by a crafted nodebus message, an attacker could flash malicious firmware that intercepts or modifies QR scan data.
|
||||||
|
|
||||||
|
### Low Priority / Design Notes
|
||||||
|
|
||||||
|
#### 9. `/tmp/qrx_.bmp` Race Condition
|
||||||
|
|
||||||
|
The QR code BMP is written to `/tmp/qrx_.bmp` — a predictable path in a world-writable directory. A local attacker could replace the QR code image between generation and display, but this requires local code execution on the Raspberry Pi.
|
||||||
|
|
||||||
|
#### 10. Pre-Generated QR Code Assets
|
||||||
|
|
||||||
|
The game includes pre-generated QR code images:
|
||||||
|
- `assets/nuk/images/Connectivity/QrCodes/quick_registration_qr_code.png`
|
||||||
|
- `assets/nuk/images/Connectivity/Icons/ScanQR/ScanQR.png`
|
||||||
|
|
||||||
|
These are imported into Godot but have **no script or scene references** — they are orphaned assets. The `quick_registration_qr_code.png` is a static QR code that may encode a fixed URL or machine identifier.
|
||||||
|
|
||||||
|
## Audit Counter Strings
|
||||||
|
|
||||||
|
| Offset | String | Purpose |
|
||||||
|
|---|---|---|
|
||||||
|
| `0x2594d60` | `AUD_CONNECTIVITY_USERS_SCANNED` | Users scanned via QR |
|
||||||
|
| `0x2594d80` | `AUD_CONNECTIVITY_USERS_JOINED` | Users joined via QR |
|
||||||
|
| `0x2594e88` | `AUD_CONNECTIVITY_BAD_USER_SCANS` | Failed user QR scans |
|
||||||
|
| `0x2594ea8` | `AUD_CONNECTIVITY_BAD_QR_SCANS` | Failed QR scans overall |
|
||||||
|
| `0x2594ec8` | `AUD_CONNECTIVITY_NET_CONNECTION_BAD_ACTION` | Bad network action |
|
||||||
|
| `0x25964b0` | `AUD_RULE_AREA_DISCOVER_POKEMON_SCAN_STARTED` | In-game scan started |
|
||||||
|
| `0x25964e0` | `AUD_RULE_AREA_DISCOVER_POKEMON_SCANNED` | In-game scan completed |
|
||||||
|
| `0x2596508` | `AUD_RULE_AREA_DISCOVER_POKEMON_SCAN_FAILED` | In-game scan failed |
|
||||||
|
|
||||||
|
## Godot UI Classes
|
||||||
|
|
||||||
|
| Class Name | Offset | Role |
|
||||||
|
|---|---|---|
|
||||||
|
| `NetPlayQrCode` | `0x25db058` | QR code display in network play |
|
||||||
|
| `NetWrongQrOverlay` | `0x25d9d20` | Error overlay for invalid QR |
|
||||||
|
| `MenuPageQrAdjustments` | `0x25ff0e8` | Menu page for QR adjustments |
|
||||||
|
| `QrRC` | `0x280770f` | QR resource class (abbreviated) |
|
||||||
|
|
||||||
|
## Diagnostic Messages
|
||||||
|
|
||||||
|
| Offset | String |
|
||||||
|
|---|---|
|
||||||
|
| `0x25dd3e8` | `Check QR scanner RJ45 nodebus cable` |
|
||||||
|
| `0x25dd410` | `Check QR scanner ribbon cable` |
|
||||||
|
| `0x25a85e0` | `Pull Interlock Switch To Power QR Scanner` |
|
||||||
|
| `0x25a5528` | `This login QR code is no longer valid` |
|
||||||
|
| `0x25a5578` | `This machine is not registered with Insider Connected` |
|
||||||
|
|
||||||
|
## Key Differences from conagent
|
||||||
|
|
||||||
|
The QR code system is **entirely separate** from `conagent`:
|
||||||
|
|
||||||
|
| Aspect | conagent | QR Scanner (game binary) |
|
||||||
|
|---|---|---|
|
||||||
|
| Binary | `/games/pokemon_pro/conagent` | `/games/pokemon_pro/game` |
|
||||||
|
| Role | Backend connectivity agent | Main game process |
|
||||||
|
| QR code gen | None | Uses `qrcodegen` library |
|
||||||
|
| QR code scan | None | Via hardware scanner + node4 bridge |
|
||||||
|
| WiFi config | No | Yes, via `wpa_supplicant` |
|
||||||
|
| User auth | API token/device auth | QR-based player UUID scan |
|
||||||
|
|
||||||
|
## Follow-up Targets
|
||||||
|
|
||||||
|
1. **Binary-level analysis**: Use Ghidra to decompile:
|
||||||
|
- `QrOfflineParser::parse` (find via vtable xref from `0x25fe1c0`)
|
||||||
|
- `NetworkQrParser::parse` (find via vtable xref from `0x25fe218`)
|
||||||
|
- The `REG:T:WPA` string splitting and SSID/PSK extraction code
|
||||||
|
- The `wpa_cli` control interface invocation site
|
||||||
|
- The serial bridge read/parse loop at VA `0x94b9d0`
|
||||||
|
|
||||||
|
2. **Dynamic testing**: If hardware or emulation is available:
|
||||||
|
- Fuzz the serial bridge protocol with crafted STX/ETX/ESC frames
|
||||||
|
- Test `REG:T:WPA` with SSID/PSK containing shell metacharacters
|
||||||
|
- Test `REG:T:WPA` with oversized SSID (>256 bytes) for buffer overflow
|
||||||
|
- Test RapidJSON parsing with malformed JSON in QR code content
|
||||||
|
|
||||||
|
3. **Node4 firmware analysis**: Disassemble `node4-LPC812-1_33_0.hex` and `node4-LPC1124_303-1_33_0.hex` as ARM Thumb to:
|
||||||
|
- Recover the UART baud rate configuration
|
||||||
|
- Understand the scanner module command passthrough protocol
|
||||||
|
- Verify the firmware update mechanism
|
||||||
|
|
||||||
|
4. **Physical inspection**: If hardware is available:
|
||||||
|
- Identify the scanner module model from the PCB
|
||||||
|
- Check if the scanner module has its own debug/firmware update port
|
||||||
|
- Verify the baud rate and protocol between node4 MCU and scanner module
|
||||||
|
|
||||||
|
5. **Nodebus security audit**: Verify the XOR encryption scheme for secure nodebus commands and assess whether it can be bypassed to inject forged QR scan results.
|
||||||
File diff suppressed because one or more lines are too long
193
vpx-table-recreation.md
Normal file
193
vpx-table-recreation.md
Normal file
@@ -0,0 +1,193 @@
|
|||||||
|
# Pokemon Pro VPX Clean Rebuild
|
||||||
|
|
||||||
|
## Status
|
||||||
|
|
||||||
|
The active Visual Pinball X implementation is the from-scratch Stern Pokemon
|
||||||
|
Pro rebuild under `emulation/vpx-rebuild/`. Its local assembled output is
|
||||||
|
`emulation/vpx-rebuild/dist/PokemonPro_Rebuild.vpx`; the default native cabinet
|
||||||
|
launcher builds and selects that file through
|
||||||
|
`emulation/scripts/run-playable-macos.sh`.
|
||||||
|
|
||||||
|
`emulation/vpx/PokemonPro_Greybox.vpx` is deprecated historical work. The clean
|
||||||
|
rebuild generator does not inspect or write it, and it is not a generator
|
||||||
|
input, geometry source, build dependency, or runtime default. The rebuild also
|
||||||
|
does not import the legacy `emulation/vpx/layout.json`, script, materials,
|
||||||
|
models, or coordinates.
|
||||||
|
|
||||||
|
The clean table targets the **Pro** edition only. VPX owns balls, contacts,
|
||||||
|
collision, mechanical motion, rendering, and mechanical sound. The genuine
|
||||||
|
game running in QEMU remains authoritative for rules, scoring, display, music,
|
||||||
|
speech, lamp levels, and ordered mechanism-driver pulses. The complete native
|
||||||
|
cabinet path is documented in `native-playable-table.md`.
|
||||||
|
|
||||||
|
## Evidence and edition scope
|
||||||
|
|
||||||
|
The design basis and source URLs are recorded in
|
||||||
|
`emulation/vpx-rebuild/design/REFERENCE.md`. The official product-family page
|
||||||
|
provided for edition verification is
|
||||||
|
<https://www.sternpinball.com/game/pokemon/>. Primary evidence is:
|
||||||
|
|
||||||
|
- Stern's official Pokemon Pro product photography and feature information;
|
||||||
|
- the official Pokemon Pro service and game manual, preserved locally as
|
||||||
|
`emulation/vpx/reference/Pokemon_Pro_web.pdf` with SHA-256
|
||||||
|
`50a1906b5c609cd3a84970b6a6e9b0be839b4d0a588d8b27361936ab6537d6bb`;
|
||||||
|
- Stern's Pro/Premium/LE feature matrix and official overview/gameplay video;
|
||||||
|
and
|
||||||
|
- the extracted target-root Pro locator
|
||||||
|
`/games/pokemon_pro/assets/nuk/images/Test/pokemon_playfield_pro.png`.
|
||||||
|
|
||||||
|
The 451 by 998 locator is registered to a 952 by 2115 VPX-unit playfield. It is
|
||||||
|
used for XY placement, while official manual assemblies and photographs
|
||||||
|
constrain paths and mechanism identities. The table implements the Pro layout:
|
||||||
|
two lower flippers and slings, dual inlanes/outlanes, right shooter lane,
|
||||||
|
Bulbasaur outer-left orbit, Squirtle left ramp, Pikachu right ramp, Charmander
|
||||||
|
right orbit/spinner, two Tall Grass pops, six BATTLE targets, motorized Meowth,
|
||||||
|
the Pokedex captive/Newton-ball area, Town scoop/VUK, static Pro Poke Ball with
|
||||||
|
stop post, and the Pro Psyduck stand-up target.
|
||||||
|
|
||||||
|
Premium/LE-only moving Poke Ball, animatronic Pikachu, arena magnet, whirlpool,
|
||||||
|
and Psyduck scoop behavior are excluded. Secondary photographs are useful for
|
||||||
|
cross-checking, but official Stern evidence controls when sources differ.
|
||||||
|
|
||||||
|
## Sources of truth and generated artifacts
|
||||||
|
|
||||||
|
The rebuild is generator-owned. Its maintained inputs are:
|
||||||
|
|
||||||
|
| Path | Role |
|
||||||
|
| --- | --- |
|
||||||
|
| `emulation/vpx-rebuild/design/geometry.json` | Clean-room XY/Z, collision, mechanism, and physics design with evidence/provenance fields. |
|
||||||
|
| `emulation/vpx-rebuild/design/lights.json` | Independent trace of 113 logical Pro lamp locations and exact component bindings. |
|
||||||
|
| `emulation/playfield-contract/pokemon-pro-hardware.json` | Geometry-free switch, sensor, cabinet, driver, and lamp contract. |
|
||||||
|
| `emulation/vpx-rebuild/script/PokemonPro_Rebuild.vbs.in` | Table behavior and SPIKE 3 integration template. |
|
||||||
|
| `emulation/vpx-rebuild/assets/` | Registered private playfield image plus original procedural models and mechanical audio. |
|
||||||
|
| `emulation/vpx-rebuild/tools/generate_table.py` | Deterministic unpacked-VPX source generator. |
|
||||||
|
|
||||||
|
`emulation/vpx-rebuild/source/` is generated and must not be hand-edited.
|
||||||
|
`emulation/vpx-rebuild/dist/PokemonPro_Rebuild.vpx` and its `.vbs` sidecar are
|
||||||
|
local build outputs. `emulation/vpx-rebuild/qa/` contains the validation report,
|
||||||
|
round-trip extraction, overlays, captures, and runtime logs. The final verified
|
||||||
|
2026-07-20 distribution is 5,902,336 bytes with SHA-256
|
||||||
|
`ddce5d48033ee3c6e67248910a73897293e8b9c36eee29df164160a93572a30e`;
|
||||||
|
the same value is recorded in `qa/rebuild-validation.json` and the matching
|
||||||
|
runtime-smoke log.
|
||||||
|
|
||||||
|
## Physical and visual implementation
|
||||||
|
|
||||||
|
The generator constructs native VPX walls, rails, posts, rubbers, flippers,
|
||||||
|
slings, targets, spinner, gates, kickers, bumpers, ramps, wireforms, plunger,
|
||||||
|
lights, and procedural models. Major retained-ball mechanisms have explicit
|
||||||
|
physical ownership: the Town VUK owns its captured ball, the right-ramp hold
|
||||||
|
kicker retains its ball until the Pikachu post driver releases it, and the
|
||||||
|
Pokedex captive chain is bounded by guides, a Newton target, and a one-way
|
||||||
|
retainer gate. Driver commands are queued briefly for their spatial mechanism
|
||||||
|
envelope rather than moving an unrelated ball. The validator rejects scripted
|
||||||
|
ball teleports.
|
||||||
|
|
||||||
|
The captive lower/upper optos use circular VPX occupancy volumes and aggregate
|
||||||
|
`BallCntOver` state across all three retained balls. Their construction kickers
|
||||||
|
are disabled seed-only loaders. This avoids the custom polygon trigger's z=50
|
||||||
|
grazing plane, which produced hundreds of thousands of false make/break edges
|
||||||
|
in the first integrated attempt. The accepted run published one initial state
|
||||||
|
per opto and no continuing idle chatter.
|
||||||
|
|
||||||
|
The current playfield base is deterministically registered from Stern's
|
||||||
|
official Pro photograph. It preserves authentic visible artwork but is not a
|
||||||
|
bare playfield scan: photographed rails, toys, shadows, and lamps remain baked
|
||||||
|
under separately rendered VPX geometry. Provenance and rejected cleanup
|
||||||
|
experiments are recorded in
|
||||||
|
`emulation/vpx-rebuild/assets/playfield/PROVENANCE.md`. A licensed, stripped
|
||||||
|
playfield scan remains necessary before the base art can be called
|
||||||
|
publication-quality.
|
||||||
|
|
||||||
|
The active build has 113 logical lamps expanded through the hardware contract
|
||||||
|
to 176 component bindings at 150 exact SPIKE addresses, including 30 RGB
|
||||||
|
logical lamps. Integrated mode consumes exact-address `L` records so separate
|
||||||
|
red, green, and blue levels are retained; the lossy maximum-component
|
||||||
|
compatibility getter is not the primary render path. GI, feature lamps, and
|
||||||
|
flashers are represented by VPX light emitters over the registered trace.
|
||||||
|
|
||||||
|
Mechanical and physics audio is an original procedural CC0 bank under
|
||||||
|
`emulation/vpx-rebuild/assets/sounds/`. Its 69 synthesized source events cover
|
||||||
|
rolling surfaces and impact, flipper, sling, bumper, target, gate, spinner,
|
||||||
|
kicker, plunger, drain, and mechanism behavior. The assembled table registers
|
||||||
|
the variants and aliases needed by the script. It does not copy sound samples
|
||||||
|
from the game image; QEMU continues to provide licensed music, speech, and game
|
||||||
|
effects.
|
||||||
|
|
||||||
|
## Electrical contract and integration behavior
|
||||||
|
|
||||||
|
`emulation/playfield-contract/pokemon-pro-hardware.json` is the canonical
|
||||||
|
geometry-free mapping. Static validation records 45 switches, 11 sensors, 9
|
||||||
|
cabinet controls, 13 drivers, and 113 logical lamps. The controller plugin and
|
||||||
|
netbridge load its compatibility projection directly, while the clean rebuild
|
||||||
|
uses its richer channel records for VPX object/event bindings.
|
||||||
|
|
||||||
|
Physical make/break contacts publish both edges; momentary targets, pops,
|
||||||
|
slings, and spinner events publish pulses. The Town VUK and right-ramp hold are
|
||||||
|
real kicker-owned states rather than dummy triggers. Start and Action retain
|
||||||
|
their installed power-distribution command `0x15` routing, and the service
|
||||||
|
panel retains its live-corrected CPU-SPI routing.
|
||||||
|
|
||||||
|
In `spike3` and `qa-spike3`, one `D` record is one ordered mechanism pulse.
|
||||||
|
Snapshot driver counts establish reconnect baselines and are never replayed as
|
||||||
|
new physical actions. Flippers are the documented exception: cabinet edges
|
||||||
|
move them locally and publish cabinet/EOS state because the live node-board
|
||||||
|
path does not produce ordinary flipper driver pulses. A disconnected controller
|
||||||
|
causes transient contacts and energized mechanisms to release; it does not
|
||||||
|
silently fall back to standalone rules. Reconnect restores stable state and
|
||||||
|
lamp/driver baselines before new events are accepted.
|
||||||
|
|
||||||
|
## Build and run
|
||||||
|
|
||||||
|
The deterministic build regenerates the registered playfield, procedural
|
||||||
|
models, and audio; generates unpacked source; assembles and imports VBS with
|
||||||
|
`vpxtool`; verifies and round-trip extracts the compound file; compares the
|
||||||
|
script; and runs the rebuild validator:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
emulation/vpx-rebuild/build.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
Run the table without QEMU for a physics/rendering check:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
emulation/vpx-rebuild/run-standalone.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
Run the native QEMU/VPX cabinet path:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
emulation/scripts/run-playable-macos.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
The default controls are left/right Shift for flippers, Return for
|
||||||
|
plunger/action, `1` for Start, `5` for coin, and the configured VPX nudge keys.
|
||||||
|
The QEMU window relays the same cabinet and service controls through the
|
||||||
|
hardware contract.
|
||||||
|
|
||||||
|
## Validation record and remaining acceptance
|
||||||
|
|
||||||
|
The following claims have different evidence boundaries and must not be
|
||||||
|
collapsed into one "playable" result:
|
||||||
|
|
||||||
|
| Layer | Current evidence | What it does not prove |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| Hardware contract | `python3 emulation/playfield-contract/validate_contract.py --json` passes schema, counts, routes, evidence, consumer loading, and generated-header parity. | Live bridge traffic, rendered lamps, mechanism motion, or gameplay. |
|
||||||
|
| Generated table | `emulation/vpx-rebuild/build.sh` passes audio validation, `vpxtool verify`, exact VBS round-trip comparison, contract/object checks, collision/clearance checks, lamp routes, and the no-ball-teleport rule; details are in `qa/rebuild-validation.json`. | Real-machine dimensions, every shot trajectory, long-session behavior, or QEMU rules progression. |
|
||||||
|
| VPX runtime load | `emulation/vpx-rebuild/qa/runtime-smoke.log` records a bounded VPX 10.8.1 `CaptureAttract` pass on the exact current table SHA-256 `ddce5d48033ee3c6e67248910a73897293e8b9c36eee29df164160a93572a30e`: table/VBS load, script compile/start, Metal initialization, two captured frames, clean close, and exit code 0. | Interactive ball/shot coverage, audible-output quality, or every mechanism sequence. |
|
||||||
|
| Integrated cabinet | The 2026-07-20 native run reached `Playable cabinet connected` with QEMU authoritative, VPX physics synchronized, 392 lamp updates, 7 LED frames, 1 driver pulse, stable captive contacts, and QEMU-keyboard coin/Start press-release records. Shutdown left the bridge disconnected and the QEMU monitor stopped. Plugin/netbridge suites also cover reconnect baselines and ordered delivery. | A complete normal game, multiball, every mechanism/shot, or long-session performance. |
|
||||||
|
| Physical accuracy | Official locator/manual/photo registration supports edition, identities, and top-down placement. | Measured ramp Z, clearances, coil forces, friction/restitution, toy travel, or production-hardware timing. |
|
||||||
|
|
||||||
|
The next acceptance gate is a complete normal game on this final build,
|
||||||
|
including trough serve, launch, scoring shots, retained-ball mechanisms,
|
||||||
|
drain/next ball, and game over, followed by restart/inventory checks. A
|
||||||
|
multiball sequence, every full ramp/orbit trajectory,
|
||||||
|
60-minute soak, frame-time percentiles, and direct comparison with a physical
|
||||||
|
Pokemon Pro remain open. In particular, Meowth crank motion and Pikachu post
|
||||||
|
travel are evidence-backed simulations whose production-hardware direction,
|
||||||
|
stroke, and timing still need direct confirmation.
|
||||||
|
|
||||||
|
The official photograph, Pokemon/Stern character imagery, service manual, and
|
||||||
|
assembled private-use table are assessment artifacts. Do not publish them
|
||||||
|
without the relevant rights. The procedural mechanical audio is CC0, but that
|
||||||
|
does not make the complete table redistributable.
|
||||||
Reference in New Issue
Block a user