156 lines
5.2 KiB
C#
156 lines
5.2 KiB
C#
using System;
|
|
using System.Collections.Concurrent;
|
|
using System.Threading;
|
|
using Xylem.Common.CommonCore.ThreadWatcher;
|
|
using Xylem.Common.Hardware.Interfaces.Ports.PortCore.EventArguments;
|
|
using Xylem.Common.Hardware.Interfaces.Protocols.ProtocolCore.EventArguments;
|
|
using Xylem.Common.Hardware.Interfaces.Protocols.TransmitProtocol;
|
|
|
|
namespace Xylem.Common.Hardware.Interfaces.Protocols.ProtocolCore
|
|
{
|
|
/// <inheritdoc />
|
|
/// <summary>
|
|
/// Base for all protocol types
|
|
/// </summary>
|
|
public abstract class BaseProtocol : IProtocol
|
|
{
|
|
private readonly CancellationTokenSource _decodingToken = new CancellationTokenSource();
|
|
|
|
/// <inheritdoc />
|
|
public abstract event EventHandler<BaseDataEventArgs> OnRecordIsDecoded;
|
|
|
|
/// <inheritdoc />
|
|
public virtual event EventHandler<BasePortDataEventArgs> OnRecordReadyToSend;
|
|
|
|
private readonly ConcurrentQueue<IPortDataEventArgs> _decodingFifo = new ConcurrentQueue<IPortDataEventArgs>();
|
|
|
|
//initially do not signal event
|
|
private readonly AutoResetEvent _onSyncDecodingThread = new AutoResetEvent(false);
|
|
private readonly Thread _decodingThread;
|
|
|
|
/// <summary>
|
|
/// Ident is a combined string of Slot, Port, Protocol and Type
|
|
/// </summary>
|
|
protected readonly String Ident;
|
|
private ITransmitProtocol _transmitProtocol;
|
|
/// <summary>
|
|
/// Starting decoding thread
|
|
/// </summary>
|
|
/// <remarks date="2018-Feb-14" author="T.Wiedebusch">
|
|
/// - Initial
|
|
/// </remarks>
|
|
protected BaseProtocol(String ident)
|
|
{
|
|
Ident = ident;
|
|
//assign thread to loop
|
|
_decodingThread = new Thread(DecodingThreadLoop) { Name = $"{Ident} Decoding thread" };
|
|
//start DecodingThread
|
|
ThreadWatcher.Instance.Start(_decodingThread);
|
|
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
/// <summary>
|
|
/// Kill the decoding thread
|
|
/// </summary>
|
|
/// <remarks date="2018-Feb-14" author="T.Wiedebusch">
|
|
/// - Initial
|
|
/// </remarks>
|
|
/// <remarks date="2023-Oct-25" author="T.Wiedebusch">
|
|
/// - try catch block.
|
|
/// </remarks>
|
|
public virtual void Dispose()
|
|
{
|
|
try
|
|
{
|
|
//Cancel receive tokens
|
|
_decodingToken.Cancel();
|
|
|
|
//Run thread again to notice CancellationToken has changed
|
|
_onSyncDecodingThread.Set();
|
|
|
|
//this timeout counter is being used for dispose only
|
|
var timeoutCounter = 100;
|
|
|
|
while (_decodingThread.ThreadState != ThreadState.Stopped && timeoutCounter > 0)
|
|
{
|
|
Thread.Sleep(1);
|
|
timeoutCounter -= 1;
|
|
//Run thread again to notice CancellationToken has changed
|
|
_onSyncDecodingThread.Set();
|
|
}
|
|
|
|
if (_decodingThread.ThreadState != ThreadState.Stopped)
|
|
{
|
|
//if thread still running, he stuck so try to abort
|
|
// try to avoid abort (takes age to run and is not safe)
|
|
_decodingThread.Abort();
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
throw new ApplicationException(ex.Message);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Fill FIFO with received data
|
|
/// </summary>
|
|
/// <remarks date="2018-Feb-14" author="T.Wiedebusch">
|
|
/// - Initial
|
|
/// </remarks>
|
|
public void FillDecodingBuffer(IPortDataEventArgs data)
|
|
{
|
|
if (_decodingToken.IsCancellationRequested) return;
|
|
|
|
//put data to FIFO
|
|
_decodingFifo.Enqueue(data);
|
|
|
|
//put DecodingThread state from WaitSleepJoin to Running
|
|
_onSyncDecodingThread.Set();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Decoding thread loop calling the individual decoding
|
|
/// </summary>
|
|
/// <remarks date="2018-Feb-14" author="T.Wiedebusch">
|
|
/// - Initial
|
|
/// </remarks>
|
|
private void DecodingThreadLoop()
|
|
{
|
|
try
|
|
{
|
|
while (!_decodingToken.IsCancellationRequested)
|
|
{
|
|
while (_decodingFifo.TryDequeue(out var receivedRecord))
|
|
{
|
|
DecodeRecord(receivedRecord);
|
|
}
|
|
|
|
//put DecodingThread to WaitSleepJoin until next data arrived
|
|
_onSyncDecodingThread.WaitOne();
|
|
}
|
|
}
|
|
catch (ThreadAbortException)
|
|
{ }
|
|
}
|
|
|
|
/// <summary>
|
|
/// The decoding routine
|
|
/// </summary>
|
|
/// <param name="data"></param>
|
|
protected abstract void DecodeRecord(IPortDataEventArgs data);
|
|
|
|
/// <inheritdoc />
|
|
public ITransmitProtocol GetTransmitProtocol()
|
|
{
|
|
return _transmitProtocol;
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public void SetTransmitProtocol(ITransmitProtocol transmitProtocol)
|
|
{
|
|
_transmitProtocol = transmitProtocol;
|
|
}
|
|
}
|
|
} |