mirror of
https://github.com/SDRSharpR/SDRSharper.git
synced 2025-12-06 04:12:02 +01:00
306 lines
6.1 KiB
C#
306 lines
6.1 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
|
|
namespace SDRSharp.Radio
|
|
{
|
|
public sealed class ComplexFifoStream : IDisposable
|
|
{
|
|
private const int BlockSize = 8192;
|
|
|
|
private const int MaxBlocksInCache = 512;
|
|
|
|
private int _size;
|
|
|
|
private int _readPos;
|
|
|
|
private int _writePos;
|
|
|
|
private bool _terminated;
|
|
|
|
private readonly int _maxSize;
|
|
|
|
private readonly SharpEvent _writeEvent;
|
|
|
|
private readonly SharpEvent _readEvent;
|
|
|
|
private readonly Stack<UnsafeBuffer> _usedBlocks = new Stack<UnsafeBuffer>();
|
|
|
|
private readonly List<UnsafeBuffer> _blocks = new List<UnsafeBuffer>();
|
|
|
|
private int _logMax;
|
|
|
|
private string _logName = "";
|
|
|
|
private bool _logR;
|
|
|
|
private bool _logW;
|
|
|
|
public int Length => this._size;
|
|
|
|
public ComplexFifoStream()
|
|
: this(BlockMode.None)
|
|
{
|
|
}
|
|
|
|
public ComplexFifoStream(BlockMode blockMode)
|
|
: this(blockMode, 0)
|
|
{
|
|
}
|
|
|
|
public ComplexFifoStream(BlockMode blockMode, int maxSize)
|
|
{
|
|
if (blockMode == BlockMode.BlockingRead || blockMode == BlockMode.BlockingReadWrite)
|
|
{
|
|
this._readEvent = new SharpEvent(false);
|
|
}
|
|
if (blockMode == BlockMode.BlockingWrite || blockMode == BlockMode.BlockingReadWrite)
|
|
{
|
|
if (maxSize <= 0)
|
|
{
|
|
throw new ArgumentException("MaxSize should be greater than zero when in blocking write mode", "maxSize");
|
|
}
|
|
this._writeEvent = new SharpEvent(false);
|
|
}
|
|
this._maxSize = maxSize;
|
|
}
|
|
|
|
~ComplexFifoStream()
|
|
{
|
|
this.Dispose();
|
|
}
|
|
|
|
public void SetLog(string logName, int logMax, bool read = true, bool write = true)
|
|
{
|
|
this._logName = logName;
|
|
this._logMax = logMax;
|
|
this._logR = read;
|
|
this._logW = write;
|
|
}
|
|
|
|
public void Dispose()
|
|
{
|
|
this.Close();
|
|
GC.SuppressFinalize(this);
|
|
}
|
|
|
|
private unsafe UnsafeBuffer AllocBlock()
|
|
{
|
|
if (this._usedBlocks.Count > 0)
|
|
{
|
|
return this._usedBlocks.Pop();
|
|
}
|
|
return UnsafeBuffer.Create(8192, sizeof(Complex));
|
|
}
|
|
|
|
private void FreeBlock(UnsafeBuffer block)
|
|
{
|
|
if (this._usedBlocks.Count < 512)
|
|
{
|
|
this._usedBlocks.Push(block);
|
|
}
|
|
}
|
|
|
|
private UnsafeBuffer GetWBlock()
|
|
{
|
|
UnsafeBuffer unsafeBuffer;
|
|
if (this._writePos < 8192 && this._blocks.Count > 0)
|
|
{
|
|
unsafeBuffer = this._blocks[this._blocks.Count - 1];
|
|
}
|
|
else
|
|
{
|
|
unsafeBuffer = this.AllocBlock();
|
|
this._blocks.Add(unsafeBuffer);
|
|
this._writePos = 0;
|
|
}
|
|
return unsafeBuffer;
|
|
}
|
|
|
|
public void Close()
|
|
{
|
|
this.Flush();
|
|
this._terminated = true;
|
|
if (this._writeEvent != null)
|
|
{
|
|
this._writeEvent.Set();
|
|
}
|
|
if (this._readEvent != null)
|
|
{
|
|
this._readEvent.Set();
|
|
}
|
|
}
|
|
|
|
public void Flush()
|
|
{
|
|
lock (this)
|
|
{
|
|
foreach (UnsafeBuffer block in this._blocks)
|
|
{
|
|
this.FreeBlock(block);
|
|
}
|
|
this._blocks.Clear();
|
|
this._readPos = 0;
|
|
this._writePos = 0;
|
|
this._size = 0;
|
|
}
|
|
}
|
|
|
|
public unsafe int Read(Complex* buf, int ofs, int count)
|
|
{
|
|
if (this._readEvent != null)
|
|
{
|
|
while (this._size == 0 && !this._terminated)
|
|
{
|
|
if (this._logR)
|
|
{
|
|
Console.WriteLine(this._logName + ", read paused, no data");
|
|
}
|
|
this._readEvent.WaitOne();
|
|
}
|
|
if (this._terminated)
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
else if (this._size == 0)
|
|
{
|
|
Console.WriteLine(this._logName + ", read, data error");
|
|
}
|
|
int num = default(int);
|
|
lock (this)
|
|
{
|
|
num = this.DoPeek(buf, ofs, count);
|
|
this.DoAdvance(num);
|
|
}
|
|
if (this._writeEvent != null)
|
|
{
|
|
this._writeEvent.Set();
|
|
}
|
|
return num;
|
|
}
|
|
|
|
public unsafe void Write(Complex* buf, int ofs, int count)
|
|
{
|
|
if (this._writeEvent != null)
|
|
{
|
|
while (this._size >= this._maxSize && !this._terminated)
|
|
{
|
|
if (this._logW)
|
|
{
|
|
Console.WriteLine(this._logName + ", write paused, maxSize=" + this._maxSize.ToString());
|
|
}
|
|
this._writeEvent.WaitOne();
|
|
}
|
|
if (this._terminated)
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
lock (this)
|
|
{
|
|
int num2;
|
|
for (int num = count; num > 0; num -= num2)
|
|
{
|
|
num2 = Math.Min(8192 - this._writePos, num);
|
|
UnsafeBuffer wBlock = this.GetWBlock();
|
|
Complex* ptr = (Complex*)(void*)wBlock;
|
|
Utils.Memcpy(ptr + this._writePos, buf + ofs + count - num, num2 * sizeof(Complex));
|
|
this._writePos += num2;
|
|
}
|
|
this._size += count;
|
|
}
|
|
if (this._readEvent != null)
|
|
{
|
|
this._readEvent.Set();
|
|
}
|
|
}
|
|
|
|
public unsafe int Read(Complex* buf, int count)
|
|
{
|
|
return this.Read(buf, 0, count);
|
|
}
|
|
|
|
public unsafe void Write(Complex* buf, int count)
|
|
{
|
|
this.Write(buf, 0, count);
|
|
}
|
|
|
|
private int DoAdvance(int count)
|
|
{
|
|
int num = count;
|
|
while (num > 0 && this._size > 0)
|
|
{
|
|
if (this._readPos == 8192)
|
|
{
|
|
this._readPos = 0;
|
|
this.FreeBlock(this._blocks[0]);
|
|
this._blocks.RemoveAt(0);
|
|
}
|
|
int num2 = (this._blocks.Count == 1) ? Math.Min(this._writePos - this._readPos, num) : Math.Min(8192 - this._readPos, num);
|
|
this._readPos += num2;
|
|
num -= num2;
|
|
this._size -= num2;
|
|
}
|
|
return count - num;
|
|
}
|
|
|
|
public int Advance(int count)
|
|
{
|
|
if (this._readEvent != null)
|
|
{
|
|
while (this._size == 0 && !this._terminated)
|
|
{
|
|
this._readEvent.WaitOne();
|
|
}
|
|
if (this._terminated)
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
int result = default(int);
|
|
lock (this)
|
|
{
|
|
result = this.DoAdvance(count);
|
|
}
|
|
if (this._writeEvent != null)
|
|
{
|
|
this._writeEvent.Set();
|
|
}
|
|
return result;
|
|
}
|
|
|
|
private unsafe int DoPeek(Complex* buf, int ofs, int count)
|
|
{
|
|
int num = count;
|
|
int num2 = this._readPos;
|
|
int num3 = this._size;
|
|
int num4 = 0;
|
|
while (num > 0 && num3 > 0)
|
|
{
|
|
if (num2 == 8192)
|
|
{
|
|
num2 = 0;
|
|
num4++;
|
|
}
|
|
int num5 = (num4 < this._blocks.Count - 1) ? 8192 : this._writePos;
|
|
int num6 = Math.Min(num5 - num2, num);
|
|
UnsafeBuffer unsafeBuffer = this._blocks[num4];
|
|
Complex* ptr = (Complex*)(void*)unsafeBuffer;
|
|
Utils.Memcpy(buf + ofs + count - num, ptr + num2, num6 * sizeof(Complex));
|
|
num -= num6;
|
|
num2 += num6;
|
|
num3 -= num6;
|
|
}
|
|
return count - num;
|
|
}
|
|
|
|
public unsafe int Peek(Complex* buf, int ofs, int count)
|
|
{
|
|
lock (this)
|
|
{
|
|
return this.DoPeek(buf, ofs, count);
|
|
}
|
|
}
|
|
}
|
|
}
|