using System.Text.Json; using Pcie8586Probe.Acquisition; using Pcie8586Probe.Models; namespace Pcie8586Probe.Tests; public sealed class AcquisitionTests { [Theory] [InlineData(InputRange.PlusMinus5V, 0x8000, 0.0)] [InlineData(InputRange.PlusMinus5V, 0x0000, -5.0)] [InlineData(InputRange.PlusMinus1V, 0x8000, 0.0)] [InlineData(InputRange.PlusMinus1V, 0x0000, -1.0)] public void CodeToVolts_ConvertsExpectedValues(InputRange range, ushort code, double expected) { var actual = CodeConverter.CodeToVolts(code, range); Assert.Equal(expected, actual, precision: 6); } [Fact] public void CodeToVolts_MaxCode_IsJustBelowPositiveFullScale() { Assert.InRange(CodeConverter.CodeToVolts(0xFFFF, InputRange.PlusMinus5V), 4.9998, 5.0); Assert.InRange(CodeConverter.CodeToVolts(0xFFFF, InputRange.PlusMinus1V), 0.9999, 1.0); } [Theory] [InlineData(1)] [InlineData(2)] [InlineData(4)] [InlineData(8)] public void Deinterleave_SplitsInterleavedSamples(int channelCount) { var raw = new ushort[channelCount * 3]; for (var sample = 0; sample < 3; sample++) { for (var channel = 0; channel < channelCount; channel++) { raw[sample * channelCount + channel] = (ushort)(0x8000 + channel + sample * 10); } } var result = CodeConverter.Deinterleave(raw, channelCount, InputRange.PlusMinus5V); Assert.Equal(channelCount, result.Length); for (var channel = 0; channel < channelCount; channel++) { Assert.Equal(3, result[channel].Length); Assert.Equal(CodeConverter.CodeToVolts((ushort)(0x8000 + channel), InputRange.PlusMinus5V), result[channel][0]); Assert.Equal(CodeConverter.CodeToVolts((ushort)(0x8000 + channel + 20), InputRange.PlusMinus5V), result[channel][2]); } } [Fact] public void Recorder_CapturesExactTargetLength_AndClipSlices() { var recorder = new Recorder(); recorder.Start(TimeSpan.FromMilliseconds(10), 1_000_000); var first = MakeBlock(channelCount: 2, samplesPerChannel: 6_000, start: 0); var second = MakeBlock(channelCount: 2, samplesPerChannel: 6_000, start: 6_000); Assert.Null(recorder.Add(first)); var recorded = recorder.Add(second); Assert.NotNull(recorded); Assert.Equal(10_000, recorded.SamplesPerChannel); var clip = SampleBlockAssembler.Slice(recorded, 2_000, 3_000); Assert.Equal(3_000, clip.SamplesPerChannel); Assert.Equal(recorded.Channels[0][2_000], clip.Channels[0][0]); } [Fact] public async Task WaveformWriter_WritesInterleavedFloat32AndMetadata() { var block = new SampleBlock( [ [1.0, 2.0], [3.0, 4.0] ], 1_000_000, 0, DateTimeOffset.Now); var directory = Path.Combine(Path.GetTempPath(), "Pcie8586ProbeTests", Guid.NewGuid().ToString("N")); var result = await WaveformWriter.WriteAsync(block, directory, "capture", InputRange.PlusMinus5V, CancellationToken.None); var bytes = await File.ReadAllBytesAsync(result.BinaryPath); Assert.Equal(16, bytes.Length); Assert.Equal(1.0f, BitConverter.ToSingle(bytes, 0)); Assert.Equal(3.0f, BitConverter.ToSingle(bytes, 4)); Assert.Equal(2.0f, BitConverter.ToSingle(bytes, 8)); Assert.Equal(4.0f, BitConverter.ToSingle(bytes, 12)); using var metadata = JsonDocument.Parse(await File.ReadAllTextAsync(result.MetadataPath)); Assert.Equal(2, metadata.RootElement.GetProperty("channel_count").GetInt32()); Assert.Equal("interleaved", metadata.RootElement.GetProperty("layout").GetString()); Assert.Equal("float32", metadata.RootElement.GetProperty("dtype").GetString()); } private static SampleBlock MakeBlock(int channelCount, int samplesPerChannel, long start) { var channels = new double[channelCount][]; for (var channel = 0; channel < channelCount; channel++) { channels[channel] = new double[samplesPerChannel]; for (var sample = 0; sample < samplesPerChannel; sample++) { channels[channel][sample] = channel + (start + sample) / 1_000_000.0; } } return new SampleBlock(channels, 1_000_000, start, DateTimeOffset.Now); } }