Three endpoint gaps, found building the Descent 3 score overlay - the boxed
place|score field the original games drew over the callsign:
plasma box <x> <y> <w> <h> draws an outlined box with a blanked interior, the
overlay chrome, as one ESC P graphics write. The wire addresses whole bytes
horizontally, so the write covers the byte-aligned span containing the box and
clears span pixels outside it; documented, with 8-px alignment the advice.
Boxes queue FIFO with rows.
plasma text gains an explicit font: a third numeric token after the position,
with text still following, so `plasma text 2 2 7` still displays "7". Auto-fit
picks the font by LENGTH - short text always rendered large, and a "1" that
must fit a 12-px box simply could not be sent before. ResolvePosText
generalizes the legacy Score-font special case: 0 = auto, nonzero honored.
Text coalescing is now per position. The global rule - any queued text
superseded every other queued text - meant the documented two-field layout
(callsign top, score bottom) could not survive its own send burst: the second
field silently ate the first whenever both were queued. A newer text now
replaces only a queued text at the same (x,y).
15 new tests; 472 pass.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Synced from the canonical copy in the game's repo: the pod display stays dark
from activation until the game sends the pilot's callsign.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The firmware parks a cursor artifact wherever text last ended, and nothing
ever turned it off - the native games did, once at startup (ESC G 0,
L4PLASMA.CPP), which is why the cabinet never showed it. Seen on the bench as
a stray block sitting in the Descent 3 nameplate.
ShowGreetingAsync now sends cursor-hidden as its first act on every plasma
open, before the clear and greeting, so every path that follows - greeting,
feedback text, bitmap rows - draws on a cursorless panel. PlasmaDisplay gains
the CursorAsync wrapper for the ESC G command the command builder already had.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The portable config a bundle shipped carried only Profiles, so every app-level
setting - ports, baud, poll rate - rode whatever that build of RIOJoy compiled
in. That matched today and would drift invisibly the day a default changes or
the FastRIO path moves AnalogPollMs. The generated config now writes them out,
so a bundle says what it runs with. Verified by building the Descent 3 bundle
and parsing the result.
profiles/descent3.json was a pre-cockpit draft: old button layout, no explicit
ports, no overlay labels. Replaced verbatim with the flown-and-confirmed Tesla
profile from the game's own repo (Descent3 venue/riojoy/tesla.riojoy.json,
which pack-dist feeds to build-pod and is the canonical copy) - explicit
COM1/COM2, the 30-mapping layout, afterburner on the thumb.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The legacy joystick math left the output unchanged when the raw sample was
exactly 0 - a case a jittering pot never produces, so on real hardware the hold
was invisible. vRIO's pad deadzone produces it constantly: every release of the
bench gamepad shapes the residual to exactly 0.0 and holds it there, one sample
per 55 ms poll. The calibrator held the last in-motion output against that
stream indefinitely, so the virtual pad froze off-center at whatever the stick
commanded the instant before release.
Flown, that read as a Descent 3 pod drifting on yaw and pitch with the stick
centered, stopping only when the release was slow enough to land an
intermediate sample inside the +/-5 band. It survived a full day of suspects -
the game's deadzone, its axis map, its focus handling, com0com, the serial
protocol - because every layer below the calibrator was correct: the freeze was
visible in joy.cpl itself, and the game's own control trace showed heading
latched at -0.38 while the wire carried perfect zeros.
Same divergence from the legacy port, same reasoning, as the throttle detent
fix above it: zero means centered, not "no information". Both axes; regression
tests pin the fast-release case and center stability across repeated zero
polls.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
No detection anywhere in the pod chain (Cyd: foreground detection is too
slow - the pad appears after the game already enumerated controllers).
--profile <name> activates immediately at startup, never runs the
auto-switch watcher, and on success signals the named manual-reset event
RIOJoy.Tray.Ready (process-lifetime, never stale) so a launcher waits on
the signal instead of counting winmm devices. Legible failures for the
launcher: exit 4 unknown profile, exit 5 activation failed with the reason
on stderr - both verified live against the built exe. Editor close
re-activates the explicit profile. build-pod start scripts now pass
--profile <Name> --exit-with <exe>; docs updated.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Same cockpit axis strategy (throttle RightThumbY unipolar, pedal-mix rudder
on RightThumbX, triggers left free for fire) and the D1X button/keypad map
as a starting point pending on-pod tuning in the editor. Triggers cover the
open-source port (Descent3) and the retail launcher (d3); plasma greeting
DESCENT 3. Pod bundle builds clean from it.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Per Cyd: no operator ever installs anything on a pod by hand. build-pod.ps1
now mirrors the universal inner layout (app/app-xp, vendor, install-core.bat
+ install-rio.ps1 reused verbatim) and bundles the flavor prerequisites
(ViGEmBus / XP .NET+KB+RioGamepadXP). New install-riojoy.bat entry point is
called from the game postinstall.bat: self-elevating, idempotent, add-only.
Deliberately no uninstall step - other podized games may share the drivers,
so they are abandoned in place. Also: deploy scripts must stay pure ASCII
(PS5.1 reads BOM-less UTF-8 as ANSI; an em dash decodes to a smart quote
that terminates strings).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Phase 10: RIO hardware exists only on pods + dev boxes, so production is one
RIOJoy copy inside each podized game folder, no resident tray. ConfigLocator
makes a config.json beside the exe win over %APPDATA%; --exit-with <exe|pid>
(CompanionTarget/CompanionExit, 60s startup grace) tears down and quits when
the game exits; a starting --exit-with instance waits up to 15s for the
predecessor mutex instead of silently exiting. deploy/build-pod.ps1 emits
the ~4.5MB drop-in (app + portable config wrapping the profile + start
script, no drivers) - verified against the shipped Descent profile. 455
tests; PLAN.md Phase 10 + INPUT-INTEGRATION.md pod section.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Documents the install-time handoff contract that previously lived only in
Program.cs comments: single-profile document + --import-profile, exit codes
(0/1/2/3), the tray-must-not-be-running rule and installer sequencing,
per-user/per-session scope, idempotent replace-by-name, and the game-repo
reference-copy convention (dxx-rebirth pattern).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Companion to OUTPUT-INTEGRATION.md: the three input surfaces (ViGEm x360
pad, SendInput scancode keyboard/mouse, RioGamepad HID), per-button routing
kinds incl. the fixed 11-button pad order, axis calibration + routing with
the triggers-are-buttons trap and the shipped Descent pattern, per-game
strategy, profile building/triggers workflow, benchless testing, checklist.
Cross-linked from README and the output guide.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
PlasmaCommands.GraphicsWrite/GraphicsRow port the display firmware graphics
command (ESC P s y x w h, MSB-left); PlasmaDisplay.RowAsync writes a locked
whole-row update; the line protocol gains `plasma row <y> <hex32>`. The
router plasma slot becomes a bounded FIFO queue: rows stream in order (a
frame must not tear), texts still coalesce to the newest, clear flushes, cap
128 with counted drops. Docs updated; 442 tests.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The display is fully dot-addressable: document the ESC P graphics write
(row format, MSB-left, changed-row streaming as Red Planet does it, and the
~0.77s full-frame budget at 9600 baud) per vRIO PlasmaProtocol.cs, recovered
from the Tesla 4.10 sources + firmware dump. Fixes the guide''s 112x32 guess
(the legacy auto-center pivot x=56 sits left of the true 128px center) and
notes the firmware cursor ranges (x 0-127, y 0-31).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Lamp address map by functional group (keypads have no lamps), 112x32 plasma
model with auto-fit font rules and update semantics, rate-budget guidance,
and recipes: rumble config, DCS Export.lua, SimHub, log tailing, vRIO/vPlasma
bench testing. Cross-linked from FEEDBACK.md (now the wire reference) and
README; corrects the lamp count there (72, per CockpitPanel, not 96).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The right-hand panel gains a "RIO port" row under Triggers: an editable
combo offering the app default (shown with its value), the machine's COM
ports, and pipe:vrio, with free text for anything else. Save stores the
endpoint in RioProfile.RioComPort (blank or the default entry = null =
follow DefaultRioComPort).
Because the editor session holds the endpoint it opened with, a saved
port change now re-arms the session live: the tray host unhooks the old
runtime's editor wiring, re-activates on the new endpoint, re-hooks, and
restores the output-gate state - so the live RIO commands and button
echo follow the new port/pipe without closing the editor.
Verified with the offline DrawToBitmap harness (layout, both default and
pipe:vrio states) plus a scripted save round-trip (default->null,
pipe:vrio->stored, blank->null, reopen shows stored COM7).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
NamedPipeTransport connects as a client to vRIO's \\.\pipe\vrio (the
DOSBox-X fork's role) and speaks the shared typed-frame contract
(PipeFraming: 0x00 data / 0x01 modem lines, null-modem crossed). The COM
path's DTR reset pulse is replayed in-band on connect. Peer disconnects
and framing violations surface as the 0-byte transport-closed read the
link already understands.
RioTransportFactory routes endpoint strings — pipe:name (vRIO's own
picker syntax) to the pipe transport, everything else to
SerialPortTransport — and is wired into RioCoordinator and all three
RioSerialMonitor modes, so profiles (RioComPort/DefaultRioComPort) and
the bench tools take pipe endpoints anywhere a COM name went.
Gotcha baked into the design: named pipes here have 0-byte buffers, so a
write blocks until the peer reads it, and vRIO also writes its lines
frame before reading — the on-connect pulse frames are therefore queued
as overlapped writes (pipe writes drain in issue order, preserving the
edge positions) instead of blocking the constructor into a mutual
write-first deadlock.
Verified end-to-end against the real VRioDevice + VRioPipeService over
\\.\pipe\vrio: version 4.2 + check replies, 137 analog polls, lamp
commands ACKed, zero framing errors. 322 tests green, both flavors.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
RioJoy.Tray --import-profile <profile.json> merges a single-profile
document (a repo's profiles/*.json) into %APPDATA%\RIOJoy\config.json
via ConfigStore.ImportProfile: same-name profiles are replaced in place
(FindProfile's case-insensitive convention), everything else appended,
all other config content preserved. Refuses (exit 3) while a tray
instance is running - a live tray rewrites the config from memory and
would silently discard the import. Documents that a Name must be stated
in the file itself: RioProfile defaults Name to 'Unnamed', so the import
checks the raw JSON, not the deserialized object. This is the profile
install story for bench machines and pods (previously: hand-paste into
the Profiles array).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Faithful port of a legacy quirk made harmful by axis routing: _throttleLast
initialized to Center and the lT==0 hold path meant the first poll at rest
compounded 16383*32 -> clamped 32766 = FULL throttle until the lever moved
past the deadzone (under the old routing this held LeftTrigger at 255 -
fire-secondary - from power-on). lT==0 now zeroes like the deadzone branch
and _throttleLast initializes to 0, the sanctioned rest value ResetAll/
ResetThrottle already used. Three regression tests replace the one that
asserted the old behavior.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
RioProfile gains a nullable AxisRouting section mapping each calibrated
axis (X/Y/Z/Rx/Ry/Rz) to a pad target (thumbs, triggers, or None) with a
Centered or UnipolarPositive conversion; the default reproduces the old
hardcoded routing exactly, so existing profiles are untouched. Routing
resolution lives in a pure, ViGEm-free AxisRouter for testability; the
sink neutralizes the pad on routing change so stale trigger state cannot
leak across profile switches.
Motivation: Descent reads the pad via SDL GameController, where the
triggers are its stock fire axis-buttons - the old fixed routing put
throttle on LeftTrigger (fires) and detent would have read as full
reverse. descent-d1x.json now routes Z->RightThumbY (UnipolarPositive,
detent = center) and Rz->RightThumbX, triggers untargeted; guarded by
tests that parse the shipped JSON through the real deserializer and
byte-compare the dxx-rebirth reference copy.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Environment drift since ~7/26 broke a pristine checkout: (1) the SDK's
AutoGenerateBindingRedirects made RAR drop RioJoy.Core.dll for the net40
Tray exe (Bcl facade 1.5.11.0 vs 2.6.8.0 mismatch) - disabled for net40
with a hand-authored app.net40.config carrying the 2.6.8.0 redirects,
which XP's CLR 4.0 does not unify on its own; (2) 25 serial-link tests
failed on System.Runtime.CompilerServices.Unsafe load - Channels 8.0's
net462 binary references Unsafe 6.0.0.0 without declaring the dependency;
pinned the package and added the redirect app.config the earlier good
builds had auto-generated.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
First profile for a non-native game shipped in-repo (profiles/ is new -
profiles previously lived only inside config.json's Profiles array).
Matches d1x-rebirth; buttons map to synthesized DXX default keys with the
kiosk never-map list honored; ViGEm pad carries stick/throttle/pedals and
twitch actions. Worksheet + rationale: dxx-rebirth repo
docs/pod-input-map.md. Known work items before Phase-2 exit there: fixed
axis routing sends throttle/rudder to the trigger axes, and
AxisCalibrationConfig has no detent-to-center field yet.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The wallpaper maker/runtime overrides the desktop with the cockpit
wallpaper on profile activation but never put the user's own back.
Now RioCoordinator captures the current wallpaper (SPI_GETDESKWALLPAPER,
via new WallpaperApplier.GetCurrent) the first time it overrides it, and
restores it (WallpaperApplier.Restore) on every GoDormant and on Dispose
— so going idle, a native game taking the port, or app exit returns the
desktop to what the user had. Capture is once-per-override so switching
between cockpit profiles keeps the real previous wallpaper; only engages
when OverlayTemplatePath is set. Builds clean on net48 + net40.
Known gap (documented in PLAN.md): a hard crash between apply and restore
leaves the cockpit wallpaper, since SPIF_UPDATEINIFILE persists it.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The physical RIO board docs (photos, schematics, GAL decode) and the
board firmware (dumps, disassembly, make_patch.py, RIO 4.3 + FastRIO
images, analysis, testlogs) describe hardware shared across all Tesla
cockpits with a lifecycle independent of this Windows app — a
native-game-only cabinet runs the firmware and never touches RIOjoy.
They now live in TeslaRel410/restoration/{rio-hardware,rio-firmware}
with full history preserved (git subtree).
Kept here: docs/PROTOCOL.md (this app's interface contract) and the
RioSerialMonitor bench harness (--mash/--e0test, C# on RioJoy.Core).
README + code comments now point at the TeslaRel410 archive.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Plain-language explanation of the reply-latch wedge for non-technical
pod owners, linked from the firmware README top. Frames the bug as a
'busy' sticky note the board forgets to take down on the give-up path,
and how RIO 4.3 fixes it.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Built with the full 4.3 flag set plus --baud31250 --widen-ackwait;
71 bytes vs stock, differing from RIOv4_3.bin in exactly two bytes
($D62B baud, $D9E7 ACK-wait) — disassembly-verified. Production table
updated; acceptance ladder on the FastRIO cockpit still required
before deployment.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The VersionReply builder at $C6EA hardcoded 4.2; --reportversion=4.3
patches the minor operand byte ($C6FF: 02->03). Verified no host
software gates on the value (legacy prints it, RIOJoy parses it, native
games ignore it — Cyd). Rebuilt RIOv4_3.bin: 69 bytes vs stock, sha
6d67a2fc7713...; docs updated. Chips burned before this edit still
announce 4.2 — re-burn to pick up the number; all other bytes match
the certified image.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Final gate passed: 120s mash at 549 presses/min sustained (heaviest
stress run of the campaign) — zero wedges, counters flat, NAK 0, all
247 resends healed. RIOv4_3rc1 renamed to RIOv4_3.bin (same bytes,
sha dc59bd51cae3...); README/ANALYSIS promote it, production table
updated (native-game cabinets -> RIOv4_3.bin; FastRIO 4.3 variant is
build-on-demand with the documented flag set + acceptance ladder).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Over-threshold check exchange repaints and re-renders a live E0 readout
(not the stale 04000000). The +2 drift in $3184 among 65 status frames
refines the counter model: $3184 = started timeout-retry sequences
(give-ups are the exhausted subset); timeout-recovered cycles exit via
the success teardown, NAK-recovered ones via $DA2F ($3185). All
observations from both bench sessions fit. Mash spot-check remains
before christening RIO 4.3.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
After the flip leaves counters over threshold, the tool now sends a
CheckRequest (ACKing every status frame) — edit-6 chips must repaint
and re-render the E0 readout; 04000000 marks a pre-rc1 chip. Analysis
records the stock-chip archaeology (stock also leaves 04000000, but the
ungated E0 readout papered over it in period — our fixes exposed it)
and RC1's below-threshold first-light PASS (version+check -> F0).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
New edit 6 (--checkrepaint, requires --e0thresh): hooks the CheckRequest
handler's final notify ($C5E4) through a 10-byte cave at $E020 that
repaints F0000000 after the self-test and re-renders the E0 readout only
when a counter is at/over threshold — no more stale 04000000 after
status checks. Candidate = 9600 native-game-compatible base + edits
1-2/5/6, 68 bytes vs stock, disassembly-verified, awaiting burn; on
verification it will be christened RIO 4.3.
All prior patched generations (wedge-only, 31250/31250v2, 62500/125000
science builds, e0t5 pair) moved to rio-firmware/archive/ with their
disassemblies; RIOv4_2.bin stays at top level as the pristine patch
source.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
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>
120s lamps-on mash on the burned 9600 e0t5 chip: 236/236 presses, 88.0%
analog fill, NAK 0, zero wedges, board counters flat — normal operation
unaffected by the E0-threshold patch. Bonus field data: the keypad
A-9-E chord fired mid-mash and dropped the board into axis test 4
(display 04000000), confirming that button scanning halts in test mode
while ISR-driven serial keeps running — visible in the log as presses
freezing at 236 while analog continued to 1919.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The display observation recalibrates the counters: $3184 = give-up
cycles (once per exhausted retry sequence, not per retransmit), $3185 =
teardowns of any reply cycle needing at least one retransmission — the
counter behind a lone E0000001. Also recorded in the error-handling
inventory: 5 retransmits per cycle, reply-await arms only after the
complete frame, NAK forces exactly one counted retransmit, late ACKs
cannot rescue a cycle. (Previous commit's doc edits had silently missed
their anchors; applied properly this time.)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Display observation (Cyd, on-cabinet): held F0000000 through the clean
handshake and four NAK-then-ACK sub-threshold cycles, flipped exactly at
the 5th teardown to E0000105. That reading recalibrates the counters:
$3184 counts give-up cycles (not per-retransmit) and $3185 counts
teardowns of any imperfect reply cycle — the counter behind the original
lone E0000001. Also recorded: 5 retransmits per cycle (not 4), reply-
await arms only after the complete frame, NAK forces exactly one counted
retransmit, and a late ACK cannot rescue a cycle once retries begin.
Tool predictor updated to the confirmed semantics.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Two-phase test against a DTR-reset board: phase A forces sub-threshold
retransmits (NAK the completed reply frame -> exactly one counted
retransmit, then ACK the retry), where the display must hold F0000000;
phase B withholds ACKs for a full give-up cycle to cross the threshold,
with the expected E0 readout predicted from observed traffic.
Bench findings while building it (9600, e0t5 chip): the reply-retry
machine sends 5 retransmits per cycle (not 4); responses are honored
only after the complete reply frame (mid-frame ACK/NAK/RESTART is
ignored); once the first retry fires the cycle runs blind to give-up;
a host NAK triggers an immediate counted retransmit.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Stock $D5F2 repaints the cockpit display to the E0 counter readout on
the FIRST increment of $3187/$3184/$3185, so one benign give-up shows
E0000001 forever. New opt-in make_patch.py edit 5 hijacks the render's
LDX #$2038 into a 30-byte cave at $E000: all three counters below N ->
exit via the routine's own epilogue (registers restored, display
untouched); any >= N -> resume the render. Counters still accumulate.
Built + disassembly-verified (not yet burned): RIOv4_2_patched_e0t5.bin
(9600) and RIOv4_2_patched_31250v2_e0t5.bin (FastRIO). Docs updated.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The display has a third use: serial error annunciator. $D5F2 renders
'E0' + three live counters (TX-ring overflow $3187, reply retries
$3184, give-up teardowns $3185); $DAB8/$DAB2 is a terminal crash
screen spelling 'dEAd' when the TX dispatcher meets an unknown command
byte. Also recorded: RX overrun is unhandled (checksum NAKs are the only
symptom), unused vectors hang in BRA-self stubs, FAULT LED = MAX690 PFO,
manual/remote reset works by pulling PFI low, RUN LED = buffered AS*,
and the MAX690 watchdog is unconnected/unserviced — software wedges
persist until reset, matching bench observations.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
New display-board-1408.md: pin-level definition of the board's outputs
(8 multiplexed hex digits via ICM7228B, isolated LPT LED monitor block,
no readback path) and, from the firmware disassembly, everything the RIO
puts on it: F0 boot banner, F1 test-mode banner (keypad sequence A-9-E
enters, D exits), and the sub-test displays — five live encoder-count
readouts, button test with input index, two lamp patterns, keypad test.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Operator-verified zero lamp misses/hangs through the slow-chord test
(62500's killer) and 392/min mash. Final run: NAK=0, 25 timeout resends
silently healing inbound response loss, counters flat, zero wedges.
--poll 20 delivered ~31Hz analog (1.7x legacy); the shortfall vs 50Hz
is additive host pacing (delay after awaited exchange), not board
saturation - noted as a future host tweak.
AppConfig gains RioBaudRate (default 9600) + AnalogPollMs (default 55),
plumbed through RioCoordinator; existing configs unchanged. Production
matrix recorded in ANALYSIS.md: 9600 patched chip for native-game
cabinets, 31250v2 + poll 20-25 + FTDI for RIOJoy cockpits.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Four photos of the 1413 Rev. 1: component side with the bolt-on Pyramid
PB-150P, solder side (etch NT 1-0A 3695), and both faces of the Pyramid
module (inputs/level pots, speaker terminals/fuse/power). Photo index
updated.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Photos of the physical board (Rev. 1) show the amplification is a stock
Pyramid PB-150P Pro Plus 4-channel car amp mounted as a module; the VWE
board is passive: 12V/remote power distribution, per-corner 3-way
crossovers (Dale IHB-3 820uH/180uH, MMP film caps, CP-5 2R pads), 6-pin
woofer/mid/tweeter corner connectors, and the LED output-check circuit.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
galdecode.py applies the GAL20V8 complex-mode fuse geometry (tables from
MAME jedutil.cpp) to GAL20v8a_5764.JED with pin names from schematic
sheet 1. Result triple-checks: schematic net names, firmware $A0xx
accesses, and the chip's UES signature — which VWE programmed as 'U7'.
Memory map: $2000-$9FFF SRAM (E-qualified), $A000 display write port,
$A010 pod-bus latch, $A020-$A03F HCTL-2016 counters (A3 byte select
via NOT_A3), $C000-$FFFF EPROM (explains the FF-padded dump), with
OE* = E&R/W as the shared read enable.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Overrides the legacy 55ms analog poll interval (e.g. --poll 20 at
31250 -> ~50Hz analog). Summary's expected-poll-slots math follows.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Slow chorded presses still glitch lamps at 62500 after three rounds of
host-side hardening (NAK-race resend -> stop-and-wait -> typed
resolution): a chord maximizes board ISR latency exactly when lamp
replies arrive, and a 2-byte RX buffer loses bytes no protocol can
recover. Full post-mortem in ANALYSIS.md; all bench evidence archived.
Final ladder: 9600 production / 31250v2 FastRIO / 62500 shelved /
125000 not viable. Stop-and-wait stays on everywhere as cheap delivery
insurance.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Bench round 3 (testlogs/riomash-patched-62500-sw): lamp glitches
persisted because reply-resolution was type-blind — an analog reply
still crossing USB from the previous poll could falsely confirm the
NEXT command (usually a lamp write) before the board judged it. Now a
reply resolves only its MATCHING pending request (analog/version/
check); ACK/NAK stay type-blind, which is safe because the board's TX
ISR prioritizes ACK/NAK ahead of reply data, so a command's ACK cannot
trail into its successor's window. Budget-exhausted drops settle 10ms
before releasing the gate so late stragglers land on an empty pending.
New test: a stray AnalogReply must not resolve a pending lamp command.
283 green; selftest regression unchanged.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
A concurrent commit (47df14c) picked up the untracked photo/PDF/JED files
at the repo root just as they were being organized into docs/hardware/.
The content is identical (same blobs); this completes the move.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Organize the restoration source material under docs/hardware/:
- 9 board photos (renamed from Signal timestamps, index in README)
- Scans_018-014.pdf: 7-sheet VWE schematic set (RIO_1407 CPU/power/IO,
PBE_1401 buttons, KEY_1402 keypad, DSP_1408 display, AMP_PLT 1413 amp)
- GAL20v8a_5764.JED: fuse map of the 1407's U7 memory decoder
README documents the board family, the 68HC11 memory map decode path,
the pod-bus signal set and jumper addressing, and cross-links PROTOCOL.md
and rio-firmware/.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>