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; } } } }