ln.ethercat/ln.ethercat.service/EthercatProcessDataRecorder.cs

154 lines
4.5 KiB
C#

using System;
using System.Collections.Generic;
using System.Threading;
using ln.http.api;
namespace ln.ethercat.service
{
public delegate void RecordingWindowCompleted(EthercatProcessDataRecorder dataRecorder, EthercatProcessDataRecorder.RecordingWindow recordingWindow);
public delegate void ProcessDataRecordingStartStopDelegate(EthercatProcessDataRecorder dataRecorder);
public class EthercatProcessDataRecorder : IDisposable
{
public ECMaster ECMaster { get; }
public event RecordingWindowCompleted OnRecordingWindowCompleted;
public event ProcessDataRecordingStartStopDelegate OnStartRecording;
public event ProcessDataRecordingStartStopDelegate OnStopRecording;
public int RecordingWindowSize { get; set; } = 256;
public int RecordingWindowCount { get; set; } = 10;
PDO[] pdoMap;
public PDO[] CurrentPDOMap => pdoMap;
RecordingWindow[] recordingWindows;
int currentWindow;
public EthercatProcessDataRecorder(ECMaster ecMaster)
{
ECMaster = ecMaster;
}
[ESMethod]
public void Start()
{
lock (this)
{
pdoMap = ECMaster.GetPDOMap();
SetupRamStorage();
}
OnStartRecording?.Invoke(this);
ECMaster.OnStateChange += MasterStateChanged;
ECMaster.OnProcessDataExchanged += ProcessDataExchanged;
}
[ESMethod]
public void Stop()
{
lock (this)
{
if (pdoMap != null)
{
ECMaster.OnProcessDataExchanged -= ProcessDataExchanged;
ECMaster.OnStateChange -= MasterStateChanged;
OnStopRecording?.Invoke(this);
pdoMap = null;
recordingWindows = null;
}
}
}
void SetupRamStorage()
{
currentWindow = 0;
recordingWindows = new RecordingWindow[RecordingWindowCount];
for (int window=0; window < RecordingWindowCount; window++)
recordingWindows[window] = new RecordingWindow(RecordingWindowSize, pdoMap.Length);
}
void ProcessDataExchanged(ECMaster ecMaster)
{
lock (this)
{
if (pdoMap != null)
{
RecordingWindow recordingWindow = recordingWindows[currentWindow];
if (recordingWindow.GetNextRecordBuffer(out object[] currentRecord))
{
for (int n = 0; n < pdoMap.Length; n++)
currentRecord[n] = pdoMap[n].SDOValue.GetValue();
}
if (recordingWindow.Completed)
{
currentWindow++;
if (currentWindow >= recordingWindows.Length)
currentWindow = 0;
ThreadPool.QueueUserWorkItem((s)=>{
OnRecordingWindowCompleted?.Invoke(this, recordingWindow);
});
}
}
}
}
void MasterStateChanged(ECMaster ecMaster, ECSlaveState newState)
{
if (newState != ECSlaveState.OPERATIONAL)
Stop();
}
public void Dispose()
{
Stop();
}
public class RecordingWindow
{
object[][] recordedData;
int nextRecord;
public bool Completed => nextRecord >= recordedData.Length;
public RecordingWindow(int windowSize,int pdomapSize)
{
recordedData = new object[windowSize][];
for (int pos=0 ; pos < windowSize ; pos++)
{
recordedData[pos] = new object[pdomapSize];
}
Reset();
}
public void Reset()
{
nextRecord = 0;
}
public object[][] GetRecords() => recordedData;
public object[] GetRecords(int record) => recordedData[record];
public bool GetNextRecordBuffer(out object[] recordBuffer)
{
if (nextRecord < recordedData.Length)
{
recordBuffer = recordedData[nextRecord++];
return true;
}
recordBuffer = null;
return false;
}
}
}
}