Correct 04000000 finding: CheckRequest self-test leftover, not test mode

Bench refutation (display is static under axis movement; version-only
exchanges leave it alone) kills the A-9-E chord theory. Real mechanism:
the CheckRequest handler at $C5A6 runs a full self-test — sets the
test-display flag $2421, brackets itself with TestModeChange 0x8C,
lamp pattern, pod scan, five-channel encoder sweep — and returns
without repainting, leaving the channel-4 frame (04000000) as a stale
cosmetic snapshot. Board fully healthy; no reset needed. PROTOCOL.md
now warns hosts that 0x8C fires around every check. Candidate firmware
fix (repaint cave off $C5E4) noted for a future burn.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Cyd
2026-07-19 16:04:11 -05:00
co-authored by Claude Fable 5
parent fd4dd3bb12
commit 64cd933bb1
3 changed files with 47 additions and 12 deletions
+8
View File
@@ -91,6 +91,14 @@ from [`g_baRIOLengthsA`](../legacy/riovjoy2.cpp#L171).
| 0x8B | KeyReleased | RIO→PC | 2 | `pad`, `index` | | 0x8B | KeyReleased | RIO→PC | 2 | `pad`, `index` |
| 0x8C | TestModeChange | RIO→PC | 1 | `mode` (0 = exit) | | 0x8C | TestModeChange | RIO→PC | 1 | `mode` (0 = exit) |
> **TestModeChange fires on every CheckRequest too** (firmware v4.2,
> handler `$C5A6`): the board's check self-test brackets itself with
> `0x8C` mode≠0 / mode=0, flashes the lamps, and leaves a stale
> `04000000` frame on the 8-digit diagnostic display (cosmetic; see
> [hardware/display-board-1408.md](hardware/display-board-1408.md)).
> Hosts should treat `0x8C` around a check as routine, not as the
> operator entering keypad test mode.
### Reset targets (ResetRequest payload) ### Reset targets (ResetRequest payload)
`0` = general/all, `1` = throttle, `2` = left pedal, `3` = right pedal, `0` = general/all, `1` = throttle, `2` = left pedal, `3` = right pedal,
+18 -3
View File
@@ -55,9 +55,10 @@ J1 (14-pin, from the RIO's EXTERNAL DISPLAY port) is all input:
## What the RIO firmware displays (v4.2) ## What the RIO firmware displays (v4.2)
All display writes go through `$CB49` (buffer render) or five canned All display writes go through `$CB49` (buffer render) or five canned
patterns at `$CB7C$CC52`, driven from three contexts: initialization, patterns at `$CB7C$CC52`, driven from four contexts: initialization,
the built-in **test mode**, and the **serial error/crash displays** the built-in **test mode**, the **serial error/crash displays**, and
(below). During normal, healthy gameplay the display is static. the **CheckRequest self-test** (all below). During normal, healthy
gameplay the display is static.
**Normal operation:** `F0000000` — written at cold boot (`$C068`) and warm **Normal operation:** `F0000000` — written at cold boot (`$C068`) and warm
re-init (`$C64B`), then left alone. re-init (`$C64B`), then left alone.
@@ -92,6 +93,20 @@ In the axis tests `hhll` is the **live 16-bit quadrature count in hex**
and watch the number move. The channel IDs are literally the keypad keys and watch the number move. The channel IDs are literally the keypad keys
that start them, which is why the fourth axis reads `0C`. that start them, which is why the fourth axis reads `0C`.
## The CheckRequest self-test leftover: `04000000`
The host `CheckRequest` (`0x80`) triggers a full self-test in the
handler at `$C5A6`: it sets the same display flag test mode uses
(`$2421`), brackets itself with `TestModeChange 0x8C` notifications,
flashes a lamp pattern, scans the pods, and sweeps the five encoder
channels — rendering each channel's `cc00hhll` frame as it goes. It
clears the flag on exit but **never repaints the display**, so after
every status check the digits are left showing the last frame:
channel 4, usually `04000000` with idle encoders. It is a stale
snapshot (axis movement does not update it — bench-confirmed
2026-07-19), purely cosmetic, and the board keeps operating normally.
Any reset repaints `F0000000`.
## Error displays (the third use) ## Error displays (the third use)
Two more display writers live in the serial machinery — the display is Two more display writers live in the serial machinery — the display is
+21 -9
View File
@@ -498,13 +498,25 @@ sub-threshold teardowns — stock paints `E0…` at the first — and flipped
exactly at the 5th teardown to **`E0000105`** (`$3187`=00 overflows, exactly at the 5th teardown to **`E0000105`** (`$3187`=00 overflows,
`$3184`=01 give-up, `$3185`=05 teardowns), confirmed by eye on the `$3184`=01 give-up, `$3185`=05 teardowns), confirmed by eye on the
cockpit display. Mash regression (120s, lamps on, cockpit display. Mash regression (120s, lamps on,
`testlogs/riomash-patched-e0t5-9600-20260719-154259.log`): **PASS** `testlogs/riomash-patched-e0t5-9600-20260719-154259.log`): **PASS**
0 wedges, 236/236 presses, 88.0% analog fill, NAK 0, board counters 0 wedges, 236/236 presses, 88.0% analog fill, NAK 0, board counters
flat. Incidental live finding: mid-mash the cockpit keypad delivered flat. The 31250v2_e0t5 image is the same patch on the certified
the A-9-E test-mode chord plus a `4`, dropping the board into axis FastRIO base and is expected to behave identically.
test 4 (display `04000000`) — button scanning stops in test mode
(mainline parks in the test loop) while the ISR-driven serial protocol **Post-run display `04000000` — the CheckRequest self-test (corrected
keeps answering polls. Field-validates the display doc's test-mode map; finding).** The first read of this (keypad A-9-E chord entering test
exit is keypad `F` then `D`. The 31250v2_e0t5 image mode) was wrong — disproved on the bench: the display is static (axis
is the same patch on the certified FastRIO base and is expected to movement does not change it) and version-only exchanges leave it alone.
behave identically. The real mechanism is the **CheckRequest (`0x80`) handler at `$C5A6`**:
a full built-in self-test that sets the test-display flag `$2421`
(`$C5B1`), sends `TestModeChange 0x8C` to the host (`$C70E`), runs a
lamp pattern (`$D34A`), scans the pods, sweeps all five encoder
channels (`$CC53`, ending on channel 4 — whose `cc00hhll` frame is the
last thing rendered), enqueues the fault reports, clears the flag
(`$C5E1`), notifies `0x8C` again — and **returns without repainting the
display**. Every status check therefore leaves a stale
`04 00 <ch4 count>` snapshot (idle: `04000000`) on the digits. The
board is fully healthy afterwards; no reset is needed. Proper fix, if
the cosmetic bothers: a ~10-byte cave off `$C5E4` that repaints `F0`
(`JSR $CB7C`) and re-renders the E0 readout when over threshold
(`JSR $D5F2`) — candidate for the next burn, not yet built.