4 Commits

Author SHA1 Message Date
Felix Weiß
c7a6559f97 Added methods to pause/resume the auto polling 2022-09-23 16:38:14 +02:00
Felix Weiß
88a453355c Merge branch 'master' of https://github.com/WOmed/MewtocolNet 2022-09-21 16:24:08 +02:00
Felix Weiß
6f8f891760 Added poller delay
- added downstream and upstream speeds
- refactored SerialQueue
- counted version up to 0.5.5
2022-09-21 16:24:00 +02:00
Felix Weiß
8fb8d4989d Update version in package ref 2022-08-04 11:53:20 +02:00
6 changed files with 245 additions and 121 deletions

View File

@@ -32,7 +32,7 @@ class Program {
Task.Factory.StartNew(async () => { Task.Factory.StartNew(async () => {
//attaching the logger //attaching the logger
Logger.LogLevel = LogLevel.Verbose; Logger.LogLevel = LogLevel.Critical;
Logger.OnNewLogMessage((date, msg) => { Logger.OnNewLogMessage((date, msg) => {
Console.WriteLine($"{date.ToString("HH:mm:ss")} {msg}"); Console.WriteLine($"{date.ToString("HH:mm:ss")} {msg}");
}); });
@@ -44,6 +44,13 @@ class Program {
//attaching the register collection and an automatic poller //attaching the register collection and an automatic poller
interf.WithRegisterCollection(registers).WithPoller(); interf.WithRegisterCollection(registers).WithPoller();
_ = Task.Factory.StartNew(async () => {
while (true) {
Console.Title = $"Polling Paused: {interf.PollingPaused}, Speed UP: {interf.BytesPerSecondUpstream} B/s, Speed DOWN: {interf.BytesPerSecondDownstream} B/s";
await Task.Delay(1000);
}
});
await interf.ConnectAsync( await interf.ConnectAsync(
(plcinf) => { (plcinf) => {
@@ -79,6 +86,28 @@ class Program {
//set the current second to the PLCs TIME register //set the current second to the PLCs TIME register
interf.SetRegister(nameof(registers.TestTime), TimeSpan.FromSeconds(DateTime.Now.Second)); interf.SetRegister(nameof(registers.TestTime), TimeSpan.FromSeconds(DateTime.Now.Second));
//test pausing poller
bool pollerPaused = false;
while(true) {
await Task.Delay(5000);
pollerPaused = !pollerPaused;
if(pollerPaused) {
Console.WriteLine("Pausing poller");
await interf.PausePollingAsync();
Console.WriteLine("Paused poller");
} else {
interf.ResumePolling();
Console.WriteLine("Resumed poller");
}
}
}); });
} }

View File

@@ -14,15 +14,61 @@ namespace MewtocolNet {
/// </summary> /// </summary>
public partial class MewtocolInterface { public partial class MewtocolInterface {
/// <summary>
/// True if the auto poller is currently paused
/// </summary>
public bool PollingPaused => pollerIsPaused;
internal event Action PolledCycle; internal event Action PolledCycle;
internal bool ContinousReaderRunning;
internal volatile bool pollerTaskRunning;
internal volatile bool pollerTaskStopped;
internal volatile bool pollerIsPaused;
internal bool usePoller = false; internal bool usePoller = false;
#region Register Polling #region Register Polling
/// <summary>
/// Kills the poller completely
/// </summary>
internal void KillPoller () { internal void KillPoller () {
ContinousReaderRunning = false; pollerTaskRunning = false;
pollerTaskStopped = true;
}
/// <summary>
/// Pauses the polling and waits for the last message to be sent
/// </summary>
/// <returns></returns>
public async Task PausePollingAsync () {
if (!pollerTaskRunning)
return;
pollerTaskRunning = false;
while (!pollerIsPaused) {
if (pollerIsPaused)
break;
await Task.Delay(10);
}
pollerTaskRunning = false;
}
/// <summary>
/// Resumes the polling
/// </summary>
public void ResumePolling () {
pollerTaskRunning = true;
} }
@@ -31,32 +77,37 @@ namespace MewtocolNet {
/// </summary> /// </summary>
internal void AttachPoller () { internal void AttachPoller () {
if (ContinousReaderRunning) if (pollerTaskRunning)
return; return;
Task.Factory.StartNew(async () => { Task.Factory.StartNew(async () => {
Logger.Log("Poller is attaching", LogLevel.Info, this); Logger.Log("Poller is attaching", LogLevel.Info, this);
int it = 0; int iteration = 0;
ContinousReaderRunning = true;
while (ContinousReaderRunning) { pollerTaskStopped = false;
pollerTaskRunning = true;
pollerIsPaused = false;
if (it >= Registers.Count + 1) { while (!pollerTaskStopped) {
it = 0;
while (pollerTaskRunning) {
if (iteration >= Registers.Count + 1) {
iteration = 0;
//invoke cycle polled event //invoke cycle polled event
InvokePolledCycleDone(); InvokePolledCycleDone();
continue; continue;
} }
if (it >= Registers.Count) { if (iteration >= Registers.Count) {
await GetPLCInfoAsync(); await GetPLCInfoAsync();
it++; iteration++;
continue; continue;
} }
var reg = Registers[it]; var reg = Registers[iteration];
if (reg is NRegister<short> shortReg) { if (reg is NRegister<short> shortReg) {
var lastVal = shortReg.Value; var lastVal = shortReg.Value;
@@ -115,10 +166,18 @@ namespace MewtocolNet {
} }
} }
it++; iteration++;
await Task.Delay(PollerDelayMs);
} }
pollerIsPaused = !pollerTaskRunning;
}
pollerIsPaused = false;
}); });
} }

View File

@@ -52,6 +52,15 @@ namespace MewtocolNet {
set { connectTimeout = value; } set { connectTimeout = value; }
} }
private int pollerDelayMs = 0;
/// <summary>
/// Delay for each poller cycle in milliseconds, default = 0
/// </summary>
public int PollerDelayMs {
get { return pollerDelayMs; }
set { pollerDelayMs = value; }
}
/// <summary> /// <summary>
/// The host ip endpoint, leave it null to use an automatic interface /// The host ip endpoint, leave it null to use an automatic interface
/// </summary> /// </summary>
@@ -101,6 +110,9 @@ namespace MewtocolNet {
private int stationNumber; private int stationNumber;
private int cycleTimeMs = 25; private int cycleTimeMs = 25;
private int bytesTotalCountedUpstream = 0;
private int bytesTotalCountedDownstream = 0;
/// <summary> /// <summary>
/// The current IP of the PLC connection /// The current IP of the PLC connection
/// </summary> /// </summary>
@@ -125,6 +137,30 @@ namespace MewtocolNet {
} }
} }
private int bytesPerSecondUpstream = 0;
/// <summary>
/// The current transmission speed in bytes per second
/// </summary>
public int BytesPerSecondUpstream {
get { return bytesPerSecondUpstream; }
private set {
bytesPerSecondUpstream = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(BytesPerSecondUpstream)));
}
}
private int bytesPerSecondDownstream = 0;
/// <summary>
/// The current transmission speed in bytes per second
/// </summary>
public int BytesPerSecondDownstream {
get { return bytesPerSecondDownstream; }
private set {
bytesPerSecondDownstream = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(BytesPerSecondDownstream)));
}
}
internal NetworkStream stream; internal NetworkStream stream;
internal TcpClient client; internal TcpClient client;
internal readonly SerialQueue queue = new SerialQueue(); internal readonly SerialQueue queue = new SerialQueue();
@@ -132,6 +168,9 @@ namespace MewtocolNet {
internal int SendExceptionsInRow = 0; internal int SendExceptionsInRow = 0;
internal bool ImportantTaskRunning = false; internal bool ImportantTaskRunning = false;
private Stopwatch speedStopwatchUpstr;
private Stopwatch speedStopwatchDownstr;
#region Initialization #region Initialization
/// <summary> /// <summary>
@@ -736,6 +775,16 @@ namespace MewtocolNet {
var message = _blockString.ToHexASCIIBytes(); var message = _blockString.ToHexASCIIBytes();
//time measuring
if(speedStopwatchUpstr == null) {
speedStopwatchUpstr = Stopwatch.StartNew();
}
if(speedStopwatchUpstr.Elapsed.TotalSeconds >= 1) {
speedStopwatchUpstr.Restart();
bytesTotalCountedUpstream = 0;
}
//send request //send request
using (var sendStream = new MemoryStream(message)) { using (var sendStream = new MemoryStream(message)) {
await sendStream.CopyToAsync(stream); await sendStream.CopyToAsync(stream);
@@ -743,6 +792,13 @@ namespace MewtocolNet {
Logger.Log($"--> OUT MSG: {_blockString}", LogLevel.Critical, this); Logger.Log($"--> OUT MSG: {_blockString}", LogLevel.Critical, this);
} }
//calc upstream speed
bytesTotalCountedUpstream += message.Length;
var perSecUpstream = (double)((bytesTotalCountedUpstream / speedStopwatchUpstr.Elapsed.TotalMilliseconds) * 1000);
if (perSecUpstream <= 10000)
BytesPerSecondUpstream = (int)Math.Round(perSecUpstream, MidpointRounding.AwayFromZero);
//await result //await result
StringBuilder response = new StringBuilder(); StringBuilder response = new StringBuilder();
try { try {
@@ -755,6 +811,17 @@ namespace MewtocolNet {
while (!endLineCode && !startMsgCode) { while (!endLineCode && !startMsgCode) {
do { do {
//time measuring
if (speedStopwatchDownstr == null) {
speedStopwatchDownstr = Stopwatch.StartNew();
}
if (speedStopwatchDownstr.Elapsed.TotalSeconds >= 1) {
speedStopwatchDownstr.Restart();
bytesTotalCountedDownstream = 0;
}
int bytes = await stream.ReadAsync(responseBuffer, 0, responseBuffer.Length); int bytes = await stream.ReadAsync(responseBuffer, 0, responseBuffer.Length);
endLineCode = responseBuffer.Any(x => x == 0x0D); endLineCode = responseBuffer.Any(x => x == 0x0D);
@@ -777,8 +844,18 @@ namespace MewtocolNet {
} }
if(!string.IsNullOrEmpty(response.ToString())) { if(!string.IsNullOrEmpty(response.ToString())) {
Logger.Log($"<-- IN MSG: {response}", LogLevel.Critical, this); Logger.Log($"<-- IN MSG: {response}", LogLevel.Critical, this);
bytesTotalCountedDownstream += Encoding.ASCII.GetByteCount(response.ToString());
var perSecDownstream = (double)((bytesTotalCountedDownstream / speedStopwatchDownstr.Elapsed.TotalMilliseconds) * 1000);
if(perSecUpstream <= 10000)
BytesPerSecondDownstream = (int)Math.Round(perSecUpstream, MidpointRounding.AwayFromZero);
return response.ToString(); return response.ToString();
} else { } else {
return null; return null;
} }

View File

@@ -2,7 +2,7 @@
<PropertyGroup> <PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework> <TargetFramework>netstandard2.0</TargetFramework>
<PackageId>MewtocolNet</PackageId> <PackageId>MewtocolNet</PackageId>
<Version>0.5.2</Version> <Version>0.5.6</Version>
<Authors>Felix Weiss</Authors> <Authors>Felix Weiss</Authors>
<Company>Womed</Company> <Company>Womed</Company>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild> <GeneratePackageOnBuild>true</GeneratePackageOnBuild>

View File

@@ -8,47 +8,6 @@ namespace MewtocolNet.Queue {
readonly object _locker = new object(); readonly object _locker = new object();
readonly WeakReference<Task> _lastTask = new WeakReference<Task>(null); readonly WeakReference<Task> _lastTask = new WeakReference<Task>(null);
internal Task Enqueue (Action action) {
return Enqueue<bool>(() => {
action();
return true;
});
}
internal Task<T> Enqueue<T> (Func<T> function) {
lock (_locker) {
Task lastTask;
Task<T> resultTask;
if (_lastTask.TryGetTarget(out lastTask)) {
resultTask = lastTask.ContinueWith(_ => function(), TaskContinuationOptions.ExecuteSynchronously);
} else {
resultTask = Task.Run(function);
}
_lastTask.SetTarget(resultTask);
return resultTask;
}
}
internal Task Enqueue (Func<Task> asyncAction) {
lock (_locker) {
Task lastTask;
Task resultTask;
if (_lastTask.TryGetTarget(out lastTask)) {
resultTask = lastTask.ContinueWith(_ => asyncAction(), TaskContinuationOptions.ExecuteSynchronously).Unwrap();
} else {
resultTask = Task.Run(asyncAction);
}
_lastTask.SetTarget(resultTask);
return resultTask;
}
}
internal Task<T> Enqueue<T> (Func<Task<T>> asyncFunction) { internal Task<T> Enqueue<T> (Func<Task<T>> asyncFunction) {
lock (_locker) { lock (_locker) {
Task lastTask; Task lastTask;

View File

@@ -53,7 +53,7 @@ Where is the RS232/Serial support?
Install this package by using [Nuget](https://www.nuget.org/packages/MewtocolNet/) or reference Install this package by using [Nuget](https://www.nuget.org/packages/MewtocolNet/) or reference
```XML ```XML
<PackageReference Include="MewtocolNet" Version="0.5.0" /> <PackageReference Include="MewtocolNet" Version="0.5.2" />
``` ```
in your dependencies. in your dependencies.
Alternatively use the dotnet CLI and run Alternatively use the dotnet CLI and run