Files
CydandClaude Opus 4.8 24a1b64519 Phase 4: axis calibration + plasma display (RioJoy.Core)
Port the analog calibration math and the plasma/VFD command set:

- Calibration/: AxisCalibrator ports UpdateThrottle/UpdatePadal/UpdateJoystick
  (riovjoy2.cpp#L1504+) — throttle deadzone + ratchet field, pedal deadzones,
  joystick X/Y auto-ranging from observed min/max, rudder mixing (enableZR), and
  the per-axis invert flags. Stateful (start positions, last outputs, observed
  extremes) like the legacy globals, with the RIOcmd axis resets. Final outputs
  clamp to the documented 0..32766 range (also guards a legacy compounding quirk).
  AxisOutputs carries the six values; IJoystickSink gains SetAxis(JoyAxis,value)
  so calibrated axes reach the HID feeder.
- Plasma/: PlasmaCommands builds the CPlasma ESC sequences (clear/cursor/font/
  attr/box draw+fill/text) + GetFontSize + the PlasmaPosText auto-fit/centering;
  PlasmaDisplay writes them over the secondary COM transport.
- tests: 21 new xUnit tests (105 total) for throttle proportional/saturation/
  invert, pedal ZR mix vs. direct, joystick centering/direction/invert/reset, the
  output clamp, and plasma byte sequences/font sizes/auto-fit positioning.

Hardware verification of axis feel + plasma output remains; the game-specific
PlasmaScoreDraw layout is deferred to profile content (Phase 5/7).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-26 15:24:45 -05:00

77 lines
2.6 KiB
C#
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using RioJoy.Core.Plasma;
using Xunit;
namespace RioJoy.Core.Tests.Plasma;
public class PlasmaCommandsTests
{
[Fact]
public void EscSequences_AreCorrect()
{
Assert.Equal(new byte[] { 27, (byte)'@' }, PlasmaCommands.Clear());
Assert.Equal(new byte[] { 27, (byte)'L' }, PlasmaCommands.CursorHome());
Assert.Equal(new byte[] { 27, (byte)'R', 10 }, PlasmaCommands.CursorX(10));
Assert.Equal(new byte[] { 27, (byte)'Q', 20 }, PlasmaCommands.CursorY(20));
Assert.Equal(new byte[] { 27, (byte)'H', 3 }, PlasmaCommands.FontAttr(3));
Assert.Equal(new byte[] { 27, (byte)'K', 5 }, PlasmaCommands.Font(5));
}
[Fact]
public void Box_DrawAndFill_HaveExpectedLayout()
{
Assert.Equal(new byte[] { 27, (byte)'X', 1, 2, 3, 4 }, PlasmaCommands.BoxDraw(1, 2, 3, 4));
// Fill inserts a leading 0 parameter.
Assert.Equal(new byte[] { 27, (byte)'x', 0, 1, 2, 3, 4 }, PlasmaCommands.BoxFill(1, 2, 3, 4));
}
[Fact]
public void Text_EncodesOneBytePerChar()
{
Assert.Equal(new byte[] { (byte)'A', (byte)'B', (byte)'C' }, PlasmaCommands.Text("ABC"));
}
[Theory]
[InlineData(0, 5, 7)]
[InlineData(3, 5, 7)]
[InlineData(4, 10, 14)]
[InlineData(5, 10, 14)]
[InlineData(7, 5, 7)]
public void GetFontSize_MatchesLegacy(int font, int w, int h)
{
Assert.Equal(new FontSize(w, h), PlasmaCommands.GetFontSize(font));
}
[Fact]
public void ResolvePosText_ShortText_PicksFont5_AndCenters()
{
// "HELLO" (5) is non-score and ≤9 → font 5 (10×14). Centered around (56,15).
(byte x, byte y, byte font, int len) = PlasmaCommands.ResolvePosText("HELLO", 0, 0, 0);
Assert.Equal(5, font);
Assert.Equal(5, len);
Assert.Equal(31, x); // 56 - (5*10/2)
Assert.Equal(8, y); // 15 - (14/2)
}
[Fact]
public void ResolvePosText_LongText_Font2_AndCapsLength()
{
string text = new string('1', 24);
(byte x, byte y, byte font, int len) = PlasmaCommands.ResolvePosText(text, 0, 0, 0);
Assert.Equal(2, font);
Assert.Equal(20, len); // capped
Assert.Equal(6, x); // 56 - (20*5/2)
Assert.Equal(12, y); // 15 - (7/2)
}
[Fact]
public void ResolvePosText_ScoreFont_AndExplicitPosition_Unchanged()
{
// font 2 (score) keeps its font; non-zero position is not re-centered.
(byte x, byte y, byte font, int len) = PlasmaCommands.ResolvePosText("AB", 5, 6, 2);
Assert.Equal(2, font);
Assert.Equal(2, len);
Assert.Equal(5, x);
Assert.Equal(6, y);
}
}