make_patch.py gains --baud31250: one byte beyond the wedge patch — the SCI init operand at $D62B ($30 -> $02). BAUD $30 = /13 prescale, /1 divider (2MHz E / 208 = 9615); $02 = /1, /4 -> 31250 exactly, 3.3x faster. The init write also confirms the 8MHz crystal, which is why 19200/38400 are unreachable and why 62500/125k are left alone pending an ISR cycle count. - 24 bytes changed vs original (sha256 9f866cf3...); re-disassembly diff vs the classic patched image shows exactly the one operand line, and the classic build still reproduces 3fc8170c... (script regression-safe). - PC side: SerialPortTransport takes an optional baudRate (default 9600, runtime untouched); RioSerialMonitor + --mash accept --baud 31250. - Caveats documented in README/ANALYSIS: non-standard rate (FTDI-class adapters only, no 16550s); native games still speak 9600 so this chip is bench/RIOJoy-only; validate the wedge patch at 9600 first. 275 tests green; mash --selftest regression unchanged (FAIL/exit-1). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
173 lines
6.9 KiB
C#
173 lines
6.9 KiB
C#
using System.Diagnostics;
|
|
using RioJoy.Core.Editing;
|
|
using RioJoy.Core.Mapping;
|
|
using RioJoy.Core.Protocol;
|
|
using RioJoy.Core.Serial;
|
|
|
|
// Hardware bringup monitor: open the RIO COM port, run the real serial link, and
|
|
// log every event (buttons, keypad, axis, version/check, control bytes, framing).
|
|
// It flashes all lamps once to prove the PC -> RIO output path, then echoes a lamp
|
|
// on each button press so a physical press lights up.
|
|
// dotnet run --project tools/RioSerialMonitor -- [port] [seconds] [--baud rate]
|
|
// Firmware wedge-patch validation (RIO_TAP mash test, see MashTest.cs):
|
|
// dotnet run --project tools/RioSerialMonitor -- --mash [port] [seconds]
|
|
// [--label baseline|patched] [--no-lamps] [--wedge seconds] [--baud rate]
|
|
// --baud: 31250 for the retuned firmware variant (rio-firmware --baud31250).
|
|
// Exit: 0 = ran, 2 = could not open the port (mash: 1 = wedge detected).
|
|
|
|
if (args.Contains("--mash"))
|
|
return await RioSerialMonitor.MashTest.RunAsync(args);
|
|
|
|
int baud = 9600;
|
|
var positional = new List<string>();
|
|
for (int i = 0; i < args.Length; i++)
|
|
{
|
|
if (args[i] == "--baud" && i + 1 < args.Length && int.TryParse(args[i + 1], out int b)) { baud = b; i++; }
|
|
else positional.Add(args[i]);
|
|
}
|
|
string port = positional.Count > 0 ? positional[0] : "COM1";
|
|
int seconds = positional.Count > 1 && int.TryParse(positional[1], out int s) ? s : 30;
|
|
|
|
Dictionary<int, string> groupOf = CockpitPanel.Buttons().ToDictionary(b => b.Address, b => b.Group.Title);
|
|
string Name(int addr) => groupOf.TryGetValue(addr, out string? g) ? $"0x{addr:X2} ({g})" : $"0x{addr:X2}";
|
|
|
|
var gate = new object();
|
|
var sw = Stopwatch.StartNew();
|
|
void Log(string msg)
|
|
{
|
|
lock (gate) Console.WriteLine($"[{sw.Elapsed.TotalSeconds,6:F2}s] {msg}");
|
|
}
|
|
|
|
Console.WriteLine($"== RIO serial monitor :: {port} @ {baud} 8N1 for {seconds}s ==");
|
|
|
|
SerialPortTransport transport;
|
|
try
|
|
{
|
|
transport = new SerialPortTransport(port, baud);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Console.WriteLine($" FAILED to open {port}: {ex.GetType().Name}: {ex.Message}");
|
|
Console.WriteLine(" (Is the tray app or another program holding the port? Is the cable on the right COM?)");
|
|
return 2;
|
|
}
|
|
|
|
Console.WriteLine($" opened {transport.Description}");
|
|
var link = new RioSerialLink(transport);
|
|
|
|
int packets = 0, presses = 0, releases = 0, analog = 0, controls = 0, framing = 0;
|
|
var seen = new SortedSet<int>();
|
|
VersionInfo? version = null;
|
|
var checks = new List<CheckStatus>();
|
|
|
|
// Analog: log on meaningful change only (it polls ~18x/sec). Track per-field range.
|
|
const int Deadband = 30;
|
|
AnalogReport lastLogged = default;
|
|
bool haveAnalog = false;
|
|
TimeSpan lastAnalogLog = TimeSpan.Zero;
|
|
var min = new short[5]; var max = new short[5];
|
|
for (int i = 0; i < min.Length; i++) { min[i] = short.MaxValue; max[i] = short.MinValue; }
|
|
|
|
void Track(AnalogReport r)
|
|
{
|
|
Span<short> v = stackalloc short[] { r.Throttle, r.LeftPedal, r.RightPedal, r.JoystickY, r.JoystickX };
|
|
for (int i = 0; i < 5; i++) { if (v[i] < min[i]) min[i] = v[i]; if (v[i] > max[i]) max[i] = v[i]; }
|
|
}
|
|
|
|
bool Changed(AnalogReport a, AnalogReport b) =>
|
|
Math.Abs(a.Throttle - b.Throttle) > Deadband || Math.Abs(a.LeftPedal - b.LeftPedal) > Deadband ||
|
|
Math.Abs(a.RightPedal - b.RightPedal) > Deadband || Math.Abs(a.JoystickY - b.JoystickY) > Deadband ||
|
|
Math.Abs(a.JoystickX - b.JoystickX) > Deadband;
|
|
|
|
link.PacketReceived += p =>
|
|
{
|
|
packets++;
|
|
byte[] pl = p.Payload;
|
|
switch (p.Command)
|
|
{
|
|
case RioCommand.ButtonPressed when pl[0] < RioAddress.ButtonCount:
|
|
{
|
|
int a = RioAddress.FromButton(pl[0]); presses++; seen.Add(a);
|
|
Log($"BUTTON DOWN {Name(a)}");
|
|
_ = link.SetLampAsync((byte)a, RioLampState.SolidBright); // light it
|
|
break;
|
|
}
|
|
case RioCommand.ButtonReleased when pl[0] < RioAddress.ButtonCount:
|
|
{
|
|
int a = RioAddress.FromButton(pl[0]); releases++; seen.Add(a);
|
|
Log($"button up {Name(a)}");
|
|
_ = link.SetLampAsync((byte)a, RioLampState.SolidDim);
|
|
break;
|
|
}
|
|
case RioCommand.KeyPressed when pl[0] is 0 or 1 && pl[1] <= 0x0F:
|
|
{
|
|
int a = RioAddress.FromKeypad(pl[0], pl[1]); presses++; seen.Add(a);
|
|
Log($"KEYPAD DOWN pad{pl[0]} key 0x{pl[1]:X} -> {Name(a)}");
|
|
break;
|
|
}
|
|
case RioCommand.KeyReleased when pl[0] is 0 or 1 && pl[1] <= 0x0F:
|
|
{
|
|
int a = RioAddress.FromKeypad(pl[0], pl[1]); releases++; seen.Add(a);
|
|
Log($"keypad up pad{pl[0]} key 0x{pl[1]:X} -> {Name(a)}");
|
|
break;
|
|
}
|
|
}
|
|
};
|
|
|
|
link.AnalogReceived += r =>
|
|
{
|
|
analog++;
|
|
Track(r);
|
|
if (!haveAnalog || (Changed(r, lastLogged) && sw.Elapsed - lastAnalogLog > TimeSpan.FromMilliseconds(200)))
|
|
{
|
|
Log($"analog {r}");
|
|
lastLogged = r; haveAnalog = true; lastAnalogLog = sw.Elapsed;
|
|
}
|
|
};
|
|
|
|
link.VersionReceived += v => { version = v; Log($"VERSION reply: firmware {v}"); };
|
|
link.CheckReceived += c => { checks.Add(c); Log($"CHECK reply: {c}"); };
|
|
link.ControlReceived += b => { controls++; Log($"control byte 0x{b:X2} ({(Enum.IsDefined(typeof(RioControl), (RioControl)b) ? (RioControl)b : (object)"?")})"); };
|
|
link.FramingError += () => { framing++; Log("FRAMING ERROR (resync)"); };
|
|
|
|
using var cts = new CancellationTokenSource();
|
|
Task run = link.RunAsync(cts.Token);
|
|
|
|
await Task.Delay(400);
|
|
Log("requesting firmware version + board/lamp check...");
|
|
await link.RequestVersionAsync();
|
|
await link.RequestCheckAsync();
|
|
await Task.Delay(900);
|
|
|
|
Log("lamp test: all lamps BRIGHT for 1.5s (watch the MFD)...");
|
|
for (int a = 0; a <= RioAddress.MaxAddress; a++) _ = link.SetLampAsync((byte)a, RioLampState.SolidBright);
|
|
await Task.Delay(1500);
|
|
for (int a = 0; a <= RioAddress.MaxAddress; a++) _ = link.SetLampAsync((byte)a, RioLampState.SolidOff);
|
|
|
|
Log(">>> NOW: press the MFD buttons, press keypad keys, and move the axis <<<");
|
|
Log(">>> a pressed button should light up <<<");
|
|
|
|
await Task.Delay(TimeSpan.FromSeconds(seconds));
|
|
cts.Cancel();
|
|
try { await run; } catch { /* shutdown */ }
|
|
transport.Dispose();
|
|
|
|
Console.WriteLine();
|
|
Console.WriteLine("== summary ==");
|
|
Console.WriteLine($" packets={packets} presses={presses} releases={releases} analog={analog} control={controls} framing={framing}");
|
|
Console.WriteLine($" firmware version : {(version is null ? "(no reply)" : version.ToString())}");
|
|
Console.WriteLine($" check items : {(checks.Count == 0 ? "(none)" : string.Join(", ", checks))}");
|
|
Console.WriteLine($" addresses seen : {(seen.Count == 0 ? "(none)" : string.Join(", ", seen.Select(Name)))}");
|
|
if (haveAnalog)
|
|
{
|
|
string[] axes = { "Throttle", "LeftPedal", "RightPedal", "JoyY", "JoyX" };
|
|
Console.WriteLine(" analog raw range (min..max), the live axis is the one that moved:");
|
|
for (int i = 0; i < 5; i++)
|
|
Console.WriteLine($" {axes[i],-10}: {min[i],6} .. {max[i],-6} (span {max[i] - min[i]})");
|
|
}
|
|
else
|
|
{
|
|
Console.WriteLine(" analog: (no analog replies received)");
|
|
}
|
|
return 0;
|