SSPC-Tester/Driver/PCIE8586/Pcie8586Probe/Acquisition/RingHistoryBuffer.cs

83 lines
2.2 KiB
C#

using Pcie8586Probe.Models;
namespace Pcie8586Probe.Acquisition;
public sealed class RingHistoryBuffer
{
private readonly object _gate = new();
private readonly Queue<SampleBlock> _blocks = new();
private readonly long _maxSamplesPerChannel;
private long _samplesPerChannel;
public RingHistoryBuffer(double sampleRateHz, double seconds, int maxBytes = 500 * 1024 * 1024)
{
if (sampleRateHz <= 0) throw new ArgumentOutOfRangeException(nameof(sampleRateHz));
if (seconds <= 0) throw new ArgumentOutOfRangeException(nameof(seconds));
var requested = (long)Math.Ceiling(sampleRateHz * seconds);
var memoryBound = Math.Max(1, maxBytes / (8L * 8L));
_maxSamplesPerChannel = Math.Max(1, Math.Min(requested, memoryBound));
}
public long SamplesPerChannel
{
get
{
lock (_gate)
{
return _samplesPerChannel;
}
}
}
public void Add(SampleBlock block)
{
if (block.SamplesPerChannel == 0)
{
return;
}
lock (_gate)
{
_blocks.Enqueue(block);
_samplesPerChannel += block.SamplesPerChannel;
while (_samplesPerChannel > _maxSamplesPerChannel && _blocks.Count > 0)
{
var removed = _blocks.Dequeue();
_samplesPerChannel -= removed.SamplesPerChannel;
}
}
}
public SampleBlock? Snapshot()
{
lock (_gate)
{
if (_blocks.Count == 0)
{
return null;
}
return SampleBlockAssembler.Concat(_blocks);
}
}
public SampleBlock? Slice(long startInclusive, long endExclusive)
{
if (startInclusive < 0 || endExclusive <= startInclusive)
{
return null;
}
var snapshot = Snapshot();
if (snapshot is null || startInclusive >= snapshot.SamplesPerChannel)
{
return null;
}
var end = Math.Min(endExclusive, snapshot.SamplesPerChannel);
return SampleBlockAssembler.Slice(snapshot, (int)startInclusive, (int)(end - startInclusive));
}
}