Phase 8A (1/2): de-Span the serial layer, swap JSON to Newtonsoft
Prepares RioJoy.Core for the net40 (Windows XP) target, which has no System.Memory, ValueTask, or System.Text.Json: - IRioTransport and the whole protocol/framing layer now use byte[] + Task (RioPacket.Payload, PacketParser/Builder, RioChecksum, replies, AnalogReport, RioHidReport). At 9600 baud Span bought nothing; the SerialPortTransport bridge copies disappear entirely. - ConfigStore/OverlayTemplateStore switch to Newtonsoft 13 with the same conventions (indented, PascalCase, string enums, null-skipping); verified against the real STJ-written config.json and regions.json (load + round-trip). System.Memory and System.Text.Json packages dropped. 275 tests green. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -29,12 +29,12 @@ public class RioHidReportTests
|
||||
{
|
||||
var report = new RioHidReport();
|
||||
report.SetAxis(JoyAxis.Z, 0x1234);
|
||||
Assert.Equal(0x34, report.Bytes[4]);
|
||||
Assert.Equal(0x12, report.Bytes[5]);
|
||||
Assert.Equal(0x34, report.ToArray()[4]);
|
||||
Assert.Equal(0x12, report.ToArray()[5]);
|
||||
|
||||
report.SetAxis(JoyAxis.Z, 70000); // over max → clamped to 32767
|
||||
Assert.Equal(0xFF, report.Bytes[4]);
|
||||
Assert.Equal(0x7F, report.Bytes[5]);
|
||||
Assert.Equal(0xFF, report.ToArray()[4]);
|
||||
Assert.Equal(0x7F, report.ToArray()[5]);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
@@ -47,7 +47,7 @@ public class RioHidReportTests
|
||||
{
|
||||
var report = new RioHidReport();
|
||||
report.SetHat(hat);
|
||||
Assert.Equal(expected, report.Bytes[12] & 0x0F);
|
||||
Assert.Equal(expected, report.ToArray()[12] & 0x0F);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
@@ -59,10 +59,10 @@ public class RioHidReportTests
|
||||
{
|
||||
var report = new RioHidReport();
|
||||
report.SetButton(button, pressed: true);
|
||||
Assert.Equal(mask, report.Bytes[byteIndex]);
|
||||
Assert.Equal(mask, report.ToArray()[byteIndex]);
|
||||
|
||||
report.SetButton(button, pressed: false);
|
||||
Assert.Equal(0, report.Bytes[byteIndex]);
|
||||
Assert.Equal(0, report.ToArray()[byteIndex]);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -80,6 +80,6 @@ public class RioHidReportTests
|
||||
report.SetButton(1, true);
|
||||
report.SetButton(2, true);
|
||||
report.SetButton(1, false);
|
||||
Assert.Equal(0x02, report.Bytes[13]); // only button 2 remains
|
||||
Assert.Equal(0x02, report.ToArray()[13]); // only button 2 remains
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,7 +41,7 @@ public class PacketBuilderTests
|
||||
byte[] packet = PacketBuilder.Build(RioCommand.AnalogReply, payload);
|
||||
|
||||
Assert.Equal((byte)RioCommand.AnalogReply, packet[0]);
|
||||
Assert.Equal(payload, packet.AsSpan(1, packet.Length - 2).ToArray());
|
||||
Assert.Equal(RioChecksum.Compute(packet.AsSpan(0, packet.Length - 1)), packet[^1]);
|
||||
Assert.Equal(payload, packet.Skip(1).Take(packet.Length - 2).ToArray());
|
||||
Assert.Equal(RioChecksum.Compute(packet, 0, packet.Length - 1), packet[packet.Length - 1]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ namespace RioJoy.Core.Tests.Protocol;
|
||||
|
||||
public class PacketParserTests
|
||||
{
|
||||
private static List<RioRxEvent> FeedAll(PacketParser parser, ReadOnlySpan<byte> data)
|
||||
private static List<RioRxEvent> FeedAll(PacketParser parser, byte[] data)
|
||||
{
|
||||
var events = new List<RioRxEvent>();
|
||||
foreach (byte b in data)
|
||||
|
||||
@@ -8,7 +8,7 @@ public class RioChecksumTests
|
||||
[Fact]
|
||||
public void Empty_IsZero()
|
||||
{
|
||||
Assert.Equal(0, RioChecksum.Compute(ReadOnlySpan<byte>.Empty));
|
||||
Assert.Equal(0, RioChecksum.Compute(new byte[0]));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
||||
@@ -23,13 +23,13 @@ internal sealed class FakeTransport : IRioTransport
|
||||
/// <summary>Signal that no more inbound data will arrive (transport closed).</summary>
|
||||
public void CompleteIncoming() => _incoming.Writer.TryComplete();
|
||||
|
||||
public async ValueTask<int> ReadAsync(Memory<byte> buffer, CancellationToken cancellationToken)
|
||||
public async Task<int> ReadAsync(byte[] buffer, CancellationToken cancellationToken)
|
||||
{
|
||||
while (await _incoming.Reader.WaitToReadAsync(cancellationToken).ConfigureAwait(false))
|
||||
{
|
||||
if (_incoming.Reader.TryRead(out byte[]? chunk))
|
||||
{
|
||||
chunk.AsSpan().CopyTo(buffer.Span);
|
||||
Array.Copy(chunk, buffer, chunk.Length);
|
||||
return chunk.Length;
|
||||
}
|
||||
}
|
||||
@@ -37,10 +37,10 @@ internal sealed class FakeTransport : IRioTransport
|
||||
return 0; // completed
|
||||
}
|
||||
|
||||
public ValueTask WriteAsync(ReadOnlyMemory<byte> data, CancellationToken cancellationToken)
|
||||
public Task WriteAsync(byte[] data, CancellationToken cancellationToken)
|
||||
{
|
||||
_writes.Writer.TryWrite(data.ToArray());
|
||||
return default; // net48 has no ValueTask.CompletedTask; default(ValueTask) is the completed task
|
||||
_writes.Writer.TryWrite((byte[])data.Clone());
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
/// <summary>Read the next outbound write, failing if none arrives in time.</summary>
|
||||
|
||||
Reference in New Issue
Block a user