Panel readout shows the wire values while the dot stays physical

With Invert Y checked the readout claimed "Y 80" while the AnalogReply
carried -80. The flip is factored into VRioDevice.WireY, shared by the
reply builder and the new GetWireAxis accessor; the canvas readout uses
a WireAxisProvider fed from it, and toggling the checkbox repaints so
the sign flips in place. Dot and gauges keep tracking the stick.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Cyd
2026-07-06 19:33:28 -05:00
co-authored by Claude Fable 5
parent 23204ba9c6
commit 6923c9f252
4 changed files with 32 additions and 7 deletions
+6 -1
View File
@@ -148,6 +148,7 @@ internal sealed class MainForm : Form
// Canvas ↔ device wiring.
_canvas.LampProvider = _device.GetLamp;
_canvas.AxisProvider = _device.GetAxis;
_canvas.WireAxisProvider = _device.GetWireAxis;
_canvas.AddressPressed += _device.PressAddress;
_canvas.AddressReleased += _device.ReleaseAddress;
_canvas.AxisMoved += (axis, value) => _device.SetAxis(axis, value);
@@ -192,7 +193,11 @@ internal sealed class MainForm : Form
if (!_kbInput.Checked)
_router.ReleaseAllKeys();
};
_invertY.CheckedChanged += (_, _) => _device.InvertJoystickY = _invertY.Checked;
_invertY.CheckedChanged += (_, _) =>
{
_device.InvertJoystickY = _invertY.Checked;
_canvas.Invalidate(); // the wire readout flips even though the axes didn't move
};
_device.InvertJoystickY = _invertY.Checked; // the field initializer raises no event
_kbLights.CheckedChanged += (_, _) =>
{
+9 -2
View File
@@ -73,6 +73,12 @@ internal sealed class PanelCanvas : Control
/// <summary>Current raw value of an axis (from the device).</summary>
public Func<RioAxis, short>? AxisProvider { get; set; }
/// <summary>
/// Axis value as transmitted to the host (joystick Y sign flip applied).
/// The text readout shows this; the dot and gauges track physical state.
/// </summary>
public Func<RioAxis, short>? WireAxisProvider { get; set; }
/// <summary>The user pressed a panel control.</summary>
public event Action<int>? AddressPressed;
@@ -299,9 +305,10 @@ internal sealed class PanelCanvas : Control
new Size(statusRect.Width, 0), TextFormatFlags.WordBreak).Height + 2;
}
short WireAxis(RioAxis a) => WireAxisProvider?.Invoke(a) ?? Axis(a);
string readout =
$"Z {Axis(RioAxis.Throttle),4} L {Axis(RioAxis.LeftPedal),3} R {Axis(RioAxis.RightPedal),3} " +
$"X {Axis(RioAxis.JoystickX),3} Y {Axis(RioAxis.JoystickY),3}";
$"Z {WireAxis(RioAxis.Throttle),4} L {WireAxis(RioAxis.LeftPedal),3} R {WireAxis(RioAxis.RightPedal),3} " +
$"X {WireAxis(RioAxis.JoystickX),3} Y {WireAxis(RioAxis.JoystickY),3}";
TextRenderer.DrawText(g, readout, statusFont,
new Rectangle(statusRect.X, readoutTop, statusRect.Width, statusRect.Bottom - readoutTop), green,
TextFormatFlags.Left | TextFormatFlags.Top | TextFormatFlags.SingleLine);
+15 -3
View File
@@ -108,6 +108,20 @@ public sealed class VRioDevice
lock (_gate) return _axes[(int)axis];
}
/// <summary>
/// Axis value as the next AnalogReply will carry it — same as
/// <see cref="GetAxis"/> except for the <see cref="InvertJoystickY"/> flip.
/// </summary>
public short GetWireAxis(RioAxis axis)
{
short value = GetAxis(axis);
return axis == RioAxis.JoystickY ? WireY(value) : value;
}
private short WireY(short y) => InvertJoystickY
? (short)Math.Min(AnalogCodec.Max, -y) // clamp: -Min (8192) is one past the 14-bit Max
: y;
/// <summary>
/// Move an axis. Values are clamped to the 14-bit signed range the wire
/// can carry; the new value is returned by the next AnalogReply.
@@ -281,9 +295,7 @@ public sealed class VRioDevice
y = _axes[(int)RioAxis.JoystickY];
x = _axes[(int)RioAxis.JoystickX];
}
if (InvertJoystickY) // clamp: -Min (8192) is one past the 14-bit Max
y = (short)Math.Min(AnalogCodec.Max, -y);
Send(PacketBuilder.AnalogReply(t, l, r, y, x));
Send(PacketBuilder.AnalogReply(t, l, r, WireY(y), x));
break;
case RioCommand.ResetRequest:
+2 -1
View File
@@ -77,7 +77,8 @@ public class VRioDeviceTests
byte[] p = Assert.Single(wire.Packets).Payload;
Assert.Equal(-3000, AnalogCodec.Combine(p[6], p[7]));
Assert.Equal(3000, device.GetAxis(RioAxis.JoystickY)); // the panel's view is unflipped
Assert.Equal(3000, device.GetAxis(RioAxis.JoystickY)); // the panel's dot is unflipped
Assert.Equal(-3000, device.GetWireAxis(RioAxis.JoystickY)); // the panel's readout matches the wire
// Full negative deflection: -Min is one past Max, so it clamps rather than throws.
device.SetAxis(RioAxis.JoystickY, AnalogCodec.Min);