WIP
parent
2dbdf5fbb9
commit
15b6cbe418
|
@ -0,0 +1,154 @@
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -34,11 +34,18 @@ namespace ln.ethercat.service
|
||||||
|
|
||||||
System.Timers.Timer timerWebsockets;
|
System.Timers.Timer timerWebsockets;
|
||||||
|
|
||||||
|
EthercatProcessDataRecorder processDataRecorder;
|
||||||
public EthercatService(string interfaceName)
|
public EthercatProcessDataRecorder ProcessDataRecorder {
|
||||||
{
|
get {
|
||||||
|
if (processDataRecorder == null)
|
||||||
|
processDataRecorder = new EthercatProcessDataRecorder(ECMaster);
|
||||||
|
return processDataRecorder;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public EthercatService(){}
|
||||||
|
|
||||||
public void Initialize()
|
public void Initialize()
|
||||||
{
|
{
|
||||||
if (EthercatInterfaceName == null)
|
if (EthercatInterfaceName == null)
|
||||||
|
|
|
@ -1,13 +1,7 @@
|
||||||
using System;
|
using System.Text;
|
||||||
using System.Data;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading;
|
|
||||||
using ln.application;
|
using ln.application;
|
||||||
using ln.ethercat.controller;
|
|
||||||
using ln.ethercat.controller.drives;
|
|
||||||
using ln.ethercat.controller.remote;
|
using ln.ethercat.controller.remote;
|
||||||
using ln.logging;
|
using ln.logging;
|
||||||
using ln.type;
|
|
||||||
|
|
||||||
namespace ln.ethercat.service
|
namespace ln.ethercat.service
|
||||||
{
|
{
|
||||||
|
@ -25,7 +19,7 @@ namespace ln.ethercat.service
|
||||||
|
|
||||||
Logging.Log(LogLevel.INFO, "ECMBind version: {0}", versionString.ToString());
|
Logging.Log(LogLevel.INFO, "ECMBind version: {0}", versionString.ToString());
|
||||||
|
|
||||||
EthercatService ethercatService = new EthercatService(args[0]);
|
EthercatService ethercatService = new EthercatService();
|
||||||
|
|
||||||
ArgumentContainer argumentContainer = new ArgumentContainer();
|
ArgumentContainer argumentContainer = new ArgumentContainer();
|
||||||
argumentContainer.AddStaticOptions<Program>();
|
argumentContainer.AddStaticOptions<Program>();
|
||||||
|
|
|
@ -88,6 +88,12 @@ namespace ln.ethercat.service.api.v1
|
||||||
|
|
||||||
[GET("/socket")]
|
[GET("/socket")]
|
||||||
HttpResponse OpenWebSocket(HttpRequest httpRequest) => new EthercatWebSocket(EthercatService);
|
HttpResponse OpenWebSocket(HttpRequest httpRequest) => new EthercatWebSocket(EthercatService);
|
||||||
|
|
||||||
|
[GET("")]
|
||||||
|
HttpResponse OpenRecorderSocket(HttpRequest httpRequest) => new RecorderWebSocket(EthercatService.ProcessDataRecorder);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -0,0 +1,64 @@
|
||||||
|
using System.Net.Http;
|
||||||
|
using ln.http.api;
|
||||||
|
using ln.http.websocket;
|
||||||
|
using ln.json;
|
||||||
|
using ln.json.mapping;
|
||||||
|
|
||||||
|
namespace ln.ethercat.service.api.v1
|
||||||
|
{
|
||||||
|
public class RecorderWebSocket : JSONEventWebSocketResponse
|
||||||
|
{
|
||||||
|
EthercatProcessDataRecorder DataRecorder;
|
||||||
|
|
||||||
|
public RecorderWebSocket(EthercatProcessDataRecorder dataRecorder)
|
||||||
|
{
|
||||||
|
OnWebSocketStateChanged += (s,state)=>{
|
||||||
|
switch (state)
|
||||||
|
{
|
||||||
|
case WebSocketState.OPEN:
|
||||||
|
dataRecorder.OnRecordingWindowCompleted += RecordingWindowCompleted;
|
||||||
|
dataRecorder.OnStartRecording += RecordingStarted;
|
||||||
|
dataRecorder.OnStopRecording += RecordingStopped;
|
||||||
|
break;
|
||||||
|
case WebSocketState.CLOSED:
|
||||||
|
dataRecorder.OnStartRecording -= RecordingStarted;
|
||||||
|
dataRecorder.OnStopRecording -= RecordingStopped;
|
||||||
|
dataRecorder.OnRecordingWindowCompleted -= RecordingWindowCompleted;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void RecordingStarted(EthercatProcessDataRecorder recorder)
|
||||||
|
{
|
||||||
|
JSONObject jsonMessage = new JSONObject();
|
||||||
|
jsonMessage.Add("event","start");
|
||||||
|
if (JSONMapper.DefaultMapper.Serialize(recorder.CurrentPDOMap, out JSONValue jsonValue))
|
||||||
|
jsonMessage.Add("value", jsonValue);
|
||||||
|
|
||||||
|
Send(jsonMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RecordingStopped(EthercatProcessDataRecorder recorder)
|
||||||
|
{
|
||||||
|
JSONObject jsonMessage = new JSONObject();
|
||||||
|
jsonMessage.Add("event","stop");
|
||||||
|
jsonMessage.Add("value", JSONNull.Instance);
|
||||||
|
|
||||||
|
Send(jsonMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RecordingWindowCompleted(EthercatProcessDataRecorder recorder, EthercatProcessDataRecorder.RecordingWindow recordingWindow)
|
||||||
|
{
|
||||||
|
JSONObject jsonMessage = new JSONObject();
|
||||||
|
jsonMessage.Add("event","window");
|
||||||
|
if (JSONMapper.DefaultMapper.Serialize(recordingWindow.GetRecords(), out JSONValue jsonRecords))
|
||||||
|
jsonMessage.Add("value", jsonRecords);
|
||||||
|
|
||||||
|
Send(jsonMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,17 +2,18 @@
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<OutputType>Exe</OutputType>
|
<OutputType>Exe</OutputType>
|
||||||
|
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
|
||||||
<TargetFramework>netcoreapp3.1</TargetFramework>
|
<TargetFramework>netcoreapp3.1</TargetFramework>
|
||||||
<Version>0.1.1</Version>
|
<Version>0.1.2</Version>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="ln.type" Version="0.1.7-ci" />
|
<PackageReference Include="ln.type" Version="0.1.7" />
|
||||||
<PackageReference Include="ln.logging" Version="1.0.2" />
|
<PackageReference Include="ln.logging" Version="1.0.2" />
|
||||||
<PackageReference Include="ln.json" Version="1.0.7" />
|
<PackageReference Include="ln.json" Version="1.0.7" />
|
||||||
<PackageReference Include="ln.http" Version="0.4.1" />
|
<PackageReference Include="ln.http" Version="0.4.1" />
|
||||||
<!--PackageReference Include="ln.http.api" Version="0.0.6-ci" /-->
|
<PackageReference Include="ln.http.api" Version="0.0.6" />
|
||||||
<ProjectReference Include="../../ln.http.api/ln.http.api/ln.http.api.csproj" />
|
<!--ProjectReference Include="../../ln.http.api/ln.http.api/ln.http.api.csproj" /-->
|
||||||
|
|
||||||
<ProjectReference Include="../ln.ethercat/ln.ethercat.csproj" />
|
<ProjectReference Include="../ln.ethercat/ln.ethercat.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
|
@ -39,6 +39,7 @@ namespace ln.ethercat
|
||||||
}
|
}
|
||||||
|
|
||||||
public delegate void ECStateChange(ECMaster sender,ECSlaveState newState);
|
public delegate void ECStateChange(ECMaster sender,ECSlaveState newState);
|
||||||
|
public delegate void ProcessDataExchanged(ECMaster ecMaster);
|
||||||
|
|
||||||
public class ECMaster
|
public class ECMaster
|
||||||
{
|
{
|
||||||
|
@ -50,6 +51,7 @@ namespace ln.ethercat
|
||||||
|
|
||||||
|
|
||||||
public event ECStateChange OnStateChange;
|
public event ECStateChange OnStateChange;
|
||||||
|
public event ProcessDataExchanged OnProcessDataExchanged;
|
||||||
|
|
||||||
public string InterfaceName { get; }
|
public string InterfaceName { get; }
|
||||||
|
|
||||||
|
@ -270,6 +272,8 @@ namespace ln.ethercat
|
||||||
ScheduleRestart();
|
ScheduleRestart();
|
||||||
stopProcessData = true;
|
stopProcessData = true;
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
OnProcessDataExchanged?.Invoke(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Thread.Sleep(INTERVALL_PROCESSDATA);
|
Thread.Sleep(INTERVALL_PROCESSDATA);
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>netcoreapp3.1</TargetFramework>
|
<TargetFramework>netcoreapp3.1</TargetFramework>
|
||||||
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
|
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
|
||||||
<Version>0.1.0-ci</Version>
|
<Version>0.1.2</Version>
|
||||||
<Authors>Harald Wolff-Thobaben</Authors>
|
<Authors>Harald Wolff-Thobaben</Authors>
|
||||||
<Company>l--n.de</Company>
|
<Company>l--n.de</Company>
|
||||||
<Description>A simple ethercat master based on SOEM (https://openethercatsociety.github.io/) </Description>
|
<Description>A simple ethercat master based on SOEM (https://openethercatsociety.github.io/) </Description>
|
||||||
|
@ -17,12 +17,12 @@
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="System.IO.Ports" Version="5.0.0" />
|
<PackageReference Include="System.IO.Ports" Version="5.0.0" />
|
||||||
<PackageReference Include="ln.type" Version="0.1.7-ci" />
|
<PackageReference Include="ln.type" Version="0.1.7" />
|
||||||
<PackageReference Include="ln.logging" Version="1.0.2" />
|
<PackageReference Include="ln.logging" Version="1.0.2" />
|
||||||
<PackageReference Include="ln.json" Version="1.0.7" />
|
<PackageReference Include="ln.json" Version="1.0.7" />
|
||||||
<PackageReference Include="ln.collections" Version="0.1.3-ci" />
|
<PackageReference Include="ln.collections" Version="0.1.3" />
|
||||||
<!--PackageReference Include="ln.http.api" Version="0.0.6-ci" /-->
|
<PackageReference Include="ln.http.api" Version="0.0.6" />
|
||||||
<ProjectReference Include="../../ln.http.api/ln.http.api/ln.http.api.csproj" />
|
<!--ProjectReference Include="../../ln.http.api/ln.http.api/ln.http.api.csproj" /-->
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|
Loading…
Reference in New Issue