diff --git a/src/VRio.App/MainForm.cs b/src/VRio.App/MainForm.cs index 8f2b967..a3c52a8 100644 --- a/src/VRio.App/MainForm.cs +++ b/src/VRio.App/MainForm.cs @@ -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 += (_, _) => { diff --git a/src/VRio.App/PanelCanvas.cs b/src/VRio.App/PanelCanvas.cs index 5c4fdbf..b17a99b 100644 --- a/src/VRio.App/PanelCanvas.cs +++ b/src/VRio.App/PanelCanvas.cs @@ -73,6 +73,12 @@ internal sealed class PanelCanvas : Control /// Current raw value of an axis (from the device). public Func? AxisProvider { get; set; } + /// + /// Axis value as transmitted to the host (joystick Y sign flip applied). + /// The text readout shows this; the dot and gauges track physical state. + /// + public Func? WireAxisProvider { get; set; } + /// The user pressed a panel control. public event Action? 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); diff --git a/src/VRio.Core/Device/VRioDevice.cs b/src/VRio.Core/Device/VRioDevice.cs index f169a19..c9994a6 100644 --- a/src/VRio.Core/Device/VRioDevice.cs +++ b/src/VRio.Core/Device/VRioDevice.cs @@ -108,6 +108,20 @@ public sealed class VRioDevice lock (_gate) return _axes[(int)axis]; } + /// + /// Axis value as the next AnalogReply will carry it — same as + /// except for the flip. + /// + 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; + /// /// 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: diff --git a/tests/VRio.Core.Tests/VRioDeviceTests.cs b/tests/VRio.Core.Tests/VRioDeviceTests.cs index 38a17c9..c810c12 100644 --- a/tests/VRio.Core.Tests/VRioDeviceTests.cs +++ b/tests/VRio.Core.Tests/VRioDeviceTests.cs @@ -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);