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:
@@ -148,6 +148,7 @@ internal sealed class MainForm : Form
|
|||||||
// Canvas ↔ device wiring.
|
// Canvas ↔ device wiring.
|
||||||
_canvas.LampProvider = _device.GetLamp;
|
_canvas.LampProvider = _device.GetLamp;
|
||||||
_canvas.AxisProvider = _device.GetAxis;
|
_canvas.AxisProvider = _device.GetAxis;
|
||||||
|
_canvas.WireAxisProvider = _device.GetWireAxis;
|
||||||
_canvas.AddressPressed += _device.PressAddress;
|
_canvas.AddressPressed += _device.PressAddress;
|
||||||
_canvas.AddressReleased += _device.ReleaseAddress;
|
_canvas.AddressReleased += _device.ReleaseAddress;
|
||||||
_canvas.AxisMoved += (axis, value) => _device.SetAxis(axis, value);
|
_canvas.AxisMoved += (axis, value) => _device.SetAxis(axis, value);
|
||||||
@@ -192,7 +193,11 @@ internal sealed class MainForm : Form
|
|||||||
if (!_kbInput.Checked)
|
if (!_kbInput.Checked)
|
||||||
_router.ReleaseAllKeys();
|
_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
|
_device.InvertJoystickY = _invertY.Checked; // the field initializer raises no event
|
||||||
_kbLights.CheckedChanged += (_, _) =>
|
_kbLights.CheckedChanged += (_, _) =>
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -73,6 +73,12 @@ internal sealed class PanelCanvas : Control
|
|||||||
/// <summary>Current raw value of an axis (from the device).</summary>
|
/// <summary>Current raw value of an axis (from the device).</summary>
|
||||||
public Func<RioAxis, short>? AxisProvider { get; set; }
|
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>
|
/// <summary>The user pressed a panel control.</summary>
|
||||||
public event Action<int>? AddressPressed;
|
public event Action<int>? AddressPressed;
|
||||||
|
|
||||||
@@ -299,9 +305,10 @@ internal sealed class PanelCanvas : Control
|
|||||||
new Size(statusRect.Width, 0), TextFormatFlags.WordBreak).Height + 2;
|
new Size(statusRect.Width, 0), TextFormatFlags.WordBreak).Height + 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
short WireAxis(RioAxis a) => WireAxisProvider?.Invoke(a) ?? Axis(a);
|
||||||
string readout =
|
string readout =
|
||||||
$"Z {Axis(RioAxis.Throttle),4} L {Axis(RioAxis.LeftPedal),3} R {Axis(RioAxis.RightPedal),3} " +
|
$"Z {WireAxis(RioAxis.Throttle),4} L {WireAxis(RioAxis.LeftPedal),3} R {WireAxis(RioAxis.RightPedal),3} " +
|
||||||
$"X {Axis(RioAxis.JoystickX),3} Y {Axis(RioAxis.JoystickY),3}";
|
$"X {WireAxis(RioAxis.JoystickX),3} Y {WireAxis(RioAxis.JoystickY),3}";
|
||||||
TextRenderer.DrawText(g, readout, statusFont,
|
TextRenderer.DrawText(g, readout, statusFont,
|
||||||
new Rectangle(statusRect.X, readoutTop, statusRect.Width, statusRect.Bottom - readoutTop), green,
|
new Rectangle(statusRect.X, readoutTop, statusRect.Width, statusRect.Bottom - readoutTop), green,
|
||||||
TextFormatFlags.Left | TextFormatFlags.Top | TextFormatFlags.SingleLine);
|
TextFormatFlags.Left | TextFormatFlags.Top | TextFormatFlags.SingleLine);
|
||||||
|
|||||||
@@ -108,6 +108,20 @@ public sealed class VRioDevice
|
|||||||
lock (_gate) return _axes[(int)axis];
|
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>
|
/// <summary>
|
||||||
/// Move an axis. Values are clamped to the 14-bit signed range the wire
|
/// 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.
|
/// can carry; the new value is returned by the next AnalogReply.
|
||||||
@@ -281,9 +295,7 @@ public sealed class VRioDevice
|
|||||||
y = _axes[(int)RioAxis.JoystickY];
|
y = _axes[(int)RioAxis.JoystickY];
|
||||||
x = _axes[(int)RioAxis.JoystickX];
|
x = _axes[(int)RioAxis.JoystickX];
|
||||||
}
|
}
|
||||||
if (InvertJoystickY) // clamp: -Min (8192) is one past the 14-bit Max
|
Send(PacketBuilder.AnalogReply(t, l, r, WireY(y), x));
|
||||||
y = (short)Math.Min(AnalogCodec.Max, -y);
|
|
||||||
Send(PacketBuilder.AnalogReply(t, l, r, y, x));
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case RioCommand.ResetRequest:
|
case RioCommand.ResetRequest:
|
||||||
|
|||||||
@@ -77,7 +77,8 @@ public class VRioDeviceTests
|
|||||||
|
|
||||||
byte[] p = Assert.Single(wire.Packets).Payload;
|
byte[] p = Assert.Single(wire.Packets).Payload;
|
||||||
Assert.Equal(-3000, AnalogCodec.Combine(p[6], p[7]));
|
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.
|
// Full negative deflection: -Min is one past Max, so it clamps rather than throws.
|
||||||
device.SetAxis(RioAxis.JoystickY, AnalogCodec.Min);
|
device.SetAxis(RioAxis.JoystickY, AnalogCodec.Min);
|
||||||
|
|||||||
Reference in New Issue
Block a user