Fix pedal gauges frozen under ZR mix: feed L/R from pre-mix pedal readouts
The editor's L/R gauges read Rx/Ry, but EnableZR (on in real profiles) folds the pedals into Rz and pins Rx/Ry to center, so the bars never moved with the physical pedals. AxisCalibrator now exposes LeftPedalOutput/RightPedalOutput (the calibrated pre-mix positions) and RioRuntime.AxesUpdated carries an AxisReadout (the six virtual axes + both pedals); the strip draws L/R from the pedal readouts, Z/Rz/X/Y from the axes. With ZR off the readouts equal Rx/Ry, so nothing changes there. Verified by screenshot: Rx/Ry centered while L=75% and R=25% render correctly. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -70,6 +70,16 @@ public sealed class AxisCalibrator
|
||||
|
||||
private static int Clamp(int v) => RioJoy.Core.Compat.Net48Math.Clamp(v, 0, AxisOutputs.Max);
|
||||
|
||||
/// <summary>
|
||||
/// The calibrated left-pedal position from the last <see cref="Update"/>
|
||||
/// (<c>0..32766</c>) — always tracks the pedal, even when
|
||||
/// <see cref="AxisCalibrationConfig.EnableZR"/> centers <see cref="AxisOutputs.Rx"/>.
|
||||
/// </summary>
|
||||
public int LeftPedalOutput => Clamp(_leftPedalLast);
|
||||
|
||||
/// <summary>Right-pedal counterpart of <see cref="LeftPedalOutput"/>.</summary>
|
||||
public int RightPedalOutput => Clamp(_rightPedalLast);
|
||||
|
||||
private int Throttle(int throttle)
|
||||
{
|
||||
if (throttle < -RangeThrottle || throttle > RangeThrottle)
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
namespace RioJoy.Core.Calibration;
|
||||
|
||||
/// <summary>
|
||||
/// One live calibration sample for gauge displays: the six virtual-joystick axis
|
||||
/// outputs plus the calibrated pedal positions. The pedals are surfaced
|
||||
/// separately because the ZR mix (<see cref="AxisCalibrationConfig.EnableZR"/>)
|
||||
/// folds them into Rz and pins Rx/Ry to center — a pedal gauge fed from the axes
|
||||
/// alone would freeze while the physical pedals move.
|
||||
/// </summary>
|
||||
public readonly struct AxisReadout
|
||||
{
|
||||
/// <summary>The six virtual-joystick outputs (what the HID device receives).</summary>
|
||||
public AxisOutputs Axes { get; }
|
||||
|
||||
/// <summary>Calibrated left-pedal position (<c>0..32766</c>), before the ZR mix.</summary>
|
||||
public int LeftPedal { get; }
|
||||
|
||||
/// <summary>Calibrated right-pedal position (<c>0..32766</c>), before the ZR mix.</summary>
|
||||
public int RightPedal { get; }
|
||||
|
||||
public AxisReadout(AxisOutputs axes, int leftPedal, int rightPedal)
|
||||
{
|
||||
Axes = axes;
|
||||
LeftPedal = leftPedal;
|
||||
RightPedal = rightPedal;
|
||||
}
|
||||
}
|
||||
@@ -57,11 +57,11 @@ public sealed class RioRuntime : IRioCommandSink, IDisposable
|
||||
public event Action<int, bool>? ButtonActivity;
|
||||
|
||||
/// <summary>
|
||||
/// Raised with the six calibrated axis values after every analog reply —
|
||||
/// independent of the joystick sink, so the editor can show live gauges even
|
||||
/// while input routing is suppressed.
|
||||
/// Raised with the calibrated readout (virtual axes + pre-mix pedal positions)
|
||||
/// after every analog reply — independent of the joystick sink, so the editor
|
||||
/// can show live gauges even while input routing is suppressed.
|
||||
/// </summary>
|
||||
public event Action<AxisOutputs>? AxesUpdated;
|
||||
public event Action<AxisReadout>? AxesUpdated;
|
||||
|
||||
/// <summary>Raised with the firmware version when a <see cref="RioCommand.VersionReply"/> arrives.</summary>
|
||||
public event Action<VersionInfo>? VersionReceived;
|
||||
@@ -137,7 +137,8 @@ public sealed class RioRuntime : IRioCommandSink, IDisposable
|
||||
// Output is best-effort: a faulty joystick sink must not kill the link.
|
||||
}
|
||||
|
||||
AxesUpdated?.Invoke(axes);
|
||||
AxesUpdated?.Invoke(new AxisReadout(
|
||||
axes, _calibrator.LeftPedalOutput, _calibrator.RightPedalOutput));
|
||||
}
|
||||
|
||||
private void OnPacket(RioPacket packet)
|
||||
|
||||
@@ -32,7 +32,7 @@ internal sealed class PanelCanvas : Control
|
||||
public Func<JoyStickSetting, bool>? CalibrationProvider { get; set; }
|
||||
|
||||
private readonly HashSet<int> _livePressed = new();
|
||||
private AxisOutputs? _axes;
|
||||
private AxisReadout? _axes;
|
||||
|
||||
public int? SelectedAddress { get; private set; }
|
||||
|
||||
@@ -46,14 +46,16 @@ internal sealed class PanelCanvas : Control
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Show the latest calibrated axis values on the encoder-gauge strip. Arrives at
|
||||
/// Show the latest calibrated readout on the encoder-gauge strip. Arrives at
|
||||
/// the analog poll rate (~18 Hz), so only the strip is repainted, and only when a
|
||||
/// value actually changed.
|
||||
/// </summary>
|
||||
public void SetAxes(AxisOutputs axes)
|
||||
public void SetAxes(AxisReadout axes)
|
||||
{
|
||||
if (_axes is { } p && p.X == axes.X && p.Y == axes.Y && p.Z == axes.Z &&
|
||||
p.Rx == axes.Rx && p.Ry == axes.Ry && p.Rz == axes.Rz)
|
||||
if (_axes is { } p &&
|
||||
p.Axes.X == axes.Axes.X && p.Axes.Y == axes.Axes.Y && p.Axes.Z == axes.Axes.Z &&
|
||||
p.Axes.Rx == axes.Axes.Rx && p.Axes.Ry == axes.Axes.Ry && p.Axes.Rz == axes.Axes.Rz &&
|
||||
p.LeftPedal == axes.LeftPedal && p.RightPedal == axes.RightPedal)
|
||||
return;
|
||||
_axes = axes;
|
||||
Invalidate(new Rectangle(0, 0, Width, PanelView.TopStrip));
|
||||
|
||||
@@ -75,7 +75,7 @@ public static class PanelView
|
||||
Func<int, string?> function,
|
||||
Func<int, bool> lit,
|
||||
Func<int, bool> live,
|
||||
AxisOutputs? axes,
|
||||
AxisReadout? axes,
|
||||
int? selected)
|
||||
{
|
||||
g.Clear(Color.FromArgb(28, 28, 28));
|
||||
@@ -152,7 +152,7 @@ public static class PanelView
|
||||
}
|
||||
}
|
||||
|
||||
private static void DrawEncoderStrip(Graphics g, Font font, AxisOutputs? axes)
|
||||
private static void DrawEncoderStrip(Graphics g, Font font, AxisReadout? axes)
|
||||
{
|
||||
using var pen = new Pen(Color.FromArgb(120, 160, 120));
|
||||
using var gauge = new SolidBrush(Color.FromArgb(20, 40, 20));
|
||||
@@ -181,12 +181,13 @@ public static class PanelView
|
||||
g.FillRectangle(gauge, box);
|
||||
|
||||
// Live values from the RIO's analog stream (null when the link is down).
|
||||
// The gauges show the calibrated outputs — post invert/deadzone/mix — i.e.
|
||||
// exactly what the virtual joystick receives.
|
||||
// Z/Rz/X/Y show the virtual-joystick outputs; L and R show the calibrated
|
||||
// pedal positions from before the ZR mix, which pins Rx/Ry to center — the
|
||||
// pedal gauges must track the physical pedals either way.
|
||||
if (axes is { } a)
|
||||
{
|
||||
// Z (throttle) and the L/R pedals (Rx/Ry) fill bottom-up.
|
||||
foreach (var (box, value) in new[] { (zBox, a.Z), (lBox, a.Rx), (rBox, a.Ry) })
|
||||
// Z (throttle) and the L/R pedals fill bottom-up.
|
||||
foreach (var (box, value) in new[] { (zBox, a.Axes.Z), (lBox, a.LeftPedal), (rBox, a.RightPedal) })
|
||||
{
|
||||
int h = (int)Math.Round(box.Height * AxisGauges.Fraction(value));
|
||||
if (h > 0)
|
||||
@@ -194,7 +195,7 @@ public static class PanelView
|
||||
}
|
||||
|
||||
// Rz (mixed rudder) deflects left/right from the bar's center.
|
||||
double d = AxisGauges.Deflection(a.Rz);
|
||||
double d = AxisGauges.Deflection(a.Axes.Rz);
|
||||
int cx = rzBox.X + rzBox.Width / 2;
|
||||
int w = (int)Math.Round(rzBox.Width / 2.0 * Math.Abs(d));
|
||||
if (w > 0)
|
||||
@@ -217,8 +218,8 @@ public static class PanelView
|
||||
// (0 = left/top, matching the HID axis convention).
|
||||
if (axes is { } live)
|
||||
{
|
||||
int px = xyBox.X + (int)Math.Round(AxisGauges.Fraction(live.X) * (xyBox.Width - 1));
|
||||
int py = xyBox.Y + (int)Math.Round(AxisGauges.Fraction(live.Y) * (xyBox.Height - 1));
|
||||
int px = xyBox.X + (int)Math.Round(AxisGauges.Fraction(live.Axes.X) * (xyBox.Width - 1));
|
||||
int py = xyBox.Y + (int)Math.Round(AxisGauges.Fraction(live.Axes.Y) * (xyBox.Height - 1));
|
||||
using var dot = new SolidBrush(Color.FromArgb(150, 230, 150));
|
||||
g.FillEllipse(dot, px - 3, py - 3, 7, 7);
|
||||
}
|
||||
|
||||
@@ -466,8 +466,8 @@ public sealed class ProfileEditorForm : Form
|
||||
public void ShowLiveActivity(int address, bool pressed) =>
|
||||
RunOnUi(() => _canvas.SetLivePressed(address, pressed));
|
||||
|
||||
/// <summary>Show the live calibrated axis values on the encoder gauges (serial thread).</summary>
|
||||
public void ShowAxes(AxisOutputs axes) =>
|
||||
/// <summary>Show the live calibrated readout on the encoder gauges (serial thread).</summary>
|
||||
public void ShowAxes(AxisReadout axes) =>
|
||||
RunOnUi(() => _canvas.SetAxes(axes));
|
||||
|
||||
/// <summary>Show the firmware version from a RIO version reply (serial thread).</summary>
|
||||
|
||||
Reference in New Issue
Block a user