using RioJoy.Core.Calibration; using RioJoy.Core.Protocol; using Xunit; namespace RioJoy.Core.Tests.Calibration; public class AxisCalibratorTests { // AnalogReport(throttle, leftPedal, rightPedal, joystickY, joystickX) private static AnalogReport Report( short throttle = 0, short left = 0, short right = 0, short y = 0, short x = 0) => new(throttle, left, right, y, x); // --- Throttle (Z) -------------------------------------------------------- [Fact] public void Throttle_BelowStart_IsProportional() { var cal = new AxisCalibrator(); cal.ResetThrottle(); // At-rest after reset: throttle equals its tracked start ⇒ centered at 0. Assert.Equal(0, cal.Update(Report(throttle: 0)).Z); // Pulled back 400 of 800 → half range × 32 = 16000. Assert.Equal(16000, cal.Update(Report(throttle: -400)).Z); // Full back (800) → 32000. Assert.Equal(32000, cal.Update(Report(throttle: -800)).Z); } [Fact] public void Throttle_OutOfRange_Saturates() { Assert.Equal(0, new AxisCalibrator().Update(Report(throttle: 900)).Z); // > +range Assert.Equal(32000, new AxisCalibrator().Update(Report(throttle: -900)).Z); // < -range } [Fact] public void Throttle_Invert_Flips() { var cal = new AxisCalibrator(new AxisCalibrationConfig { InvertZ = true }); // throttle=900 → raw 0 → inverted to Max. Assert.Equal(AxisOutputs.Max, cal.Update(Report(throttle: 900)).Z); } // --- Pedals (Rx / Ry / Rz) ---------------------------------------------- [Fact] public void Pedals_EnableZR_CentersRxRy_AndMixesRudder() { var cal = new AxisCalibrator(); // EnableZR default true AxisOutputs o = cal.Update(Report(left: 0, right: 0)); Assert.Equal(AxisOutputs.Center, o.Rx); Assert.Equal(AxisOutputs.Center, o.Ry); Assert.Equal(AxisOutputs.Center, o.Rz); // rudder with both pedals at rest } [Fact] public void Pedals_DisableZR_DriveRxDirectly_AndCenterRz() { var cal = new AxisCalibrator(new AxisCalibrationConfig { EnableZR = false }); // First sample sets the auto-range start; second (less depressed) produces a value. cal.Update(Report(left: -100)); AxisOutputs o = cal.Update(Report(left: 0)); // lP = (-100) - 0 = -100 → ×1000/500 = -200 → |·|×32 = 6400. Assert.Equal(6400, o.Rx); Assert.Equal(AxisOutputs.Center, o.Rz); // Rz centered when ZR disabled // The pedal readouts mirror Rx/Ry when there is no mix. Assert.Equal(o.Rx, cal.LeftPedalOutput); Assert.Equal(o.Ry, cal.RightPedalOutput); } [Fact] public void PedalOutputs_TrackPedals_EvenWithZrMix() { var cal = new AxisCalibrator(); // EnableZR default true cal.Update(Report(left: -100, right: -100)); AxisOutputs o = cal.Update(Report(left: 0, right: 0)); // The mix centers Rx/Ry, but the pedal readouts still track the pedals // (same math as the ZR-off Rx/Ry: 6400 for this deflection). Assert.Equal(AxisOutputs.Center, o.Rx); Assert.Equal(AxisOutputs.Center, o.Ry); Assert.Equal(6400, cal.LeftPedalOutput); Assert.Equal(6400, cal.RightPedalOutput); } // --- Joystick (X / Y) ---------------------------------------------------- [Fact] public void Joystick_AtZero_IsCentered() { AxisOutputs o = new AxisCalibrator().Update(Report(x: 0, y: 0)); Assert.Equal(AxisOutputs.Center, o.X); Assert.Equal(AxisOutputs.Center, o.Y); } [Fact] public void JoystickX_RightAndLeft_MoveOppositeSidesOfCenter() { // Right (positive raw) → below center; with auto-range seeded by this sample. Assert.Equal(52, new AxisCalibrator().Update(Report(x: 80)).X); // Left (negative raw) → above center. Assert.Equal(32733, new AxisCalibrator().Update(Report(x: -80)).X); } [Fact] public void JoystickX_Invert_Flips() { var cal = new AxisCalibrator(new AxisCalibrationConfig { InvertX = true }); Assert.Equal(AxisOutputs.Max - 52, cal.Update(Report(x: 80)).X); } [Fact] public void ResetHorizontalJoystick_RecentersX() { var cal = new AxisCalibrator(); Assert.Equal(52, cal.Update(Report(x: 80)).X); cal.ResetHorizontalJoystick(); // After reset, X holds center until the stick next moves off zero. Assert.Equal(AxisOutputs.Center, cal.Update(Report(x: 0)).X); } [Fact] public void Outputs_AreClampedToAxisRange() { // The init-state throttle quirk yields a value far over range on the first // poll at rest; the documented 0..Max clamp guards it. Assert.Equal(AxisOutputs.Max, new AxisCalibrator().Update(Report(throttle: 0)).Z); } }