diff --git a/MewtocolNet/Events/PlcConnectionArgs.cs b/MewtocolNet/Events/PlcConnectionArgs.cs
index 2409f3b..c58b83e 100644
--- a/MewtocolNet/Events/PlcConnectionArgs.cs
+++ b/MewtocolNet/Events/PlcConnectionArgs.cs
@@ -4,10 +4,6 @@ namespace MewtocolNet.Events {
public delegate void PlcConnectionEventHandler(object sender, PlcConnectionArgs e);
- public class PlcConnectionArgs : EventArgs {
-
-
-
- }
+ public class PlcConnectionArgs : EventArgs { }
}
diff --git a/MewtocolNet/Events/PlcModeArgs.cs b/MewtocolNet/Events/PlcModeArgs.cs
new file mode 100644
index 0000000..561a9ae
--- /dev/null
+++ b/MewtocolNet/Events/PlcModeArgs.cs
@@ -0,0 +1,19 @@
+using System;
+
+namespace MewtocolNet.Events {
+
+ public delegate void PlcModeChangedEventHandler(object sender, PlcModeArgs e);
+
+ public class PlcModeArgs : EventArgs {
+
+ public OPMode LastMode { get; internal set; }
+
+ public OPMode NowMode { get; internal set; }
+
+ public bool ProgToRun { get; internal set; }
+
+ public bool RunToProg { get; internal set; }
+
+ }
+
+}
diff --git a/MewtocolNet/IPlc.cs b/MewtocolNet/IPlc.cs
index ccca1d8..eb903d1 100644
--- a/MewtocolNet/IPlc.cs
+++ b/MewtocolNet/IPlc.cs
@@ -41,6 +41,11 @@ namespace MewtocolNet {
///
event RegisterChangedEventHandler RegisterChanged;
+ ///
+ /// Plc mode was changed
+ ///
+ event PlcModeChangedEventHandler ModeChanged;
+
///
/// The current connection state of the interface
///
@@ -110,7 +115,7 @@ namespace MewtocolNet {
///
/// A callback for excecuting something inside the plc connetion process
///
- Task ConnectAsync(Func onConnected = null);
+ Task ConnectAsync(Func onConnected = null);
///
/// Disconnects the device from its current plc connection
diff --git a/MewtocolNet/IPlcSerial.cs b/MewtocolNet/IPlcSerial.cs
index 81b19c2..a5d18d8 100644
--- a/MewtocolNet/IPlcSerial.cs
+++ b/MewtocolNet/IPlcSerial.cs
@@ -48,7 +48,7 @@ namespace MewtocolNet {
///
/// Tries to establish a connection with the device asynchronously
///
- Task ConnectAsync(Func callBack, Action onTryingConfig);
+ Task ConnectAsync(Func callBack, Action onTryingConfig);
}
diff --git a/MewtocolNet/MewtocolInterface.cs b/MewtocolNet/MewtocolInterface.cs
index 8e1665a..2c9755a 100644
--- a/MewtocolNet/MewtocolInterface.cs
+++ b/MewtocolNet/MewtocolInterface.cs
@@ -43,6 +43,9 @@ namespace MewtocolNet {
///
public event PropertyChangedEventHandler PropertyChanged;
+ ///
+ public event PlcModeChangedEventHandler ModeChanged;
+
#endregion
#region Private fields
@@ -85,6 +88,7 @@ namespace MewtocolNet {
internal protected System.Timers.Timer cyclicGenericUpdateCounter;
internal event Action PolledCycle;
+
internal volatile bool pollerTaskStopped = true;
internal volatile bool pollerFirstCycle;
internal MemoryAreaManager memoryManager;
@@ -184,7 +188,7 @@ namespace MewtocolNet {
public int ConnectTimeout { get; set; } = 3000;
#endregion
-
+
#region Methods
private protected MewtocolInterface() {
@@ -211,6 +215,7 @@ namespace MewtocolNet {
memoryManager.MemoryLayoutChanged += () => {
OnPropChange(nameof(MemoryAreas));
+ OnPropChange(nameof(Registers));
};
@@ -260,7 +265,7 @@ namespace MewtocolNet {
}
///
- public virtual async Task ConnectAsync(Func callBack = null) {
+ public virtual async Task ConnectAsync(Func callBack = null) {
isConnectingStage = false;
@@ -296,17 +301,19 @@ namespace MewtocolNet {
Logger.Log($">> OnConnected run complete <<", LogLevel.Verbose, this);
- //run all register collection on online tasks
- foreach (var col in registerCollections) {
+ }
- await col.OnInterfaceLinkedAndOnline(this);
+ //run all register collection on online tasks
+ foreach (var col in registerCollections) {
- }
-
- Logger.Log($">> OnConnected register collections run complete <<", LogLevel.Verbose, this);
+ await col.OnInterfaceLinkedAndOnline(this);
}
+ Logger.Log($">> OnConnected register collections run complete <<", LogLevel.Verbose, this);
+
+ return ConnectResult.Unknown;
+
}
///
@@ -315,7 +322,7 @@ namespace MewtocolNet {
///
public async Task AwaitFirstDataCycleAsync() {
- if(firstPollTask != null && !firstPollTask.IsCompleted)
+ if(firstPollTask != null && !firstPollTask.IsCompleted && IsConnected)
await firstPollTask;
await Task.CompletedTask;
@@ -430,6 +437,7 @@ namespace MewtocolNet {
if (regularSendTask != null && !regularSendTask.IsCompleted) {
//queue self
+ Logger.LogCritical($"Queued {_msg}...", this);
return await EnqueueMessage(_msg, onReceiveProgress);
}
@@ -510,6 +518,8 @@ namespace MewtocolNet {
}
+ await Task.CompletedTask;
+
}
protected async Task EnqueueMessage(string _msg, Action onReceiveProgress = null) {
@@ -1005,6 +1015,17 @@ namespace MewtocolNet {
}
+ internal void InvokeModeChanged(OPMode before, OPMode now) {
+
+ ModeChanged?.Invoke(this, new PlcModeArgs {
+ ProgToRun = !before.HasFlag(OPMode.RunMode) && now.HasFlag(OPMode.RunMode),
+ RunToProg = before.HasFlag(OPMode.RunMode) && !now.HasFlag(OPMode.RunMode),
+ LastMode = before,
+ NowMode = now,
+ });
+
+ }
+
#endregion
///
diff --git a/MewtocolNet/MewtocolInterfaceRegisterHandling.cs b/MewtocolNet/MewtocolInterfaceRegisterHandling.cs
index abcaa9c..1b86c64 100644
--- a/MewtocolNet/MewtocolInterfaceRegisterHandling.cs
+++ b/MewtocolNet/MewtocolInterfaceRegisterHandling.cs
@@ -214,26 +214,26 @@ namespace MewtocolNet {
}
pollerFirstCycle = false;
-
+
}
}
private async Task OnMultiFrameCycle() {
- //await the timed task before starting a new poller cycle
- if (heartbeatNeedsRun) {
-
- await HeartbeatTickTask();
-
- heartbeatNeedsRun = false;
-
- }
-
var sw = Stopwatch.StartNew();
await memoryManager.PollAllAreasAsync(async () => {
+ //await the timed task before starting a new poller cycle
+ if (heartbeatNeedsRun || pollerFirstCycle) {
+
+ await HeartbeatTickTask();
+
+ heartbeatNeedsRun = false;
+
+ }
+
await RunOneOpenQueuedTask();
});
diff --git a/MewtocolNet/MewtocolInterfaceRequests.cs b/MewtocolNet/MewtocolInterfaceRequests.cs
index 1db3047..5f907fe 100644
--- a/MewtocolNet/MewtocolInterfaceRequests.cs
+++ b/MewtocolNet/MewtocolInterfaceRequests.cs
@@ -49,7 +49,7 @@ namespace MewtocolNet {
PLCInfo plcInf;
//dont overwrite, use first
- if (!PLCInfo.TryFromRT(resRT.Response, out plcInf)) {
+ if (!PLCInfo.TryFromRT(resRT.Response, this, out plcInf)) {
throw new Exception("The RT message could not be parsed");
diff --git a/MewtocolNet/MewtocolInterfaceSerial.cs b/MewtocolNet/MewtocolInterfaceSerial.cs
index 3828c50..3f547e8 100644
--- a/MewtocolNet/MewtocolInterfaceSerial.cs
+++ b/MewtocolNet/MewtocolInterfaceSerial.cs
@@ -105,12 +105,12 @@ namespace MewtocolNet {
}
- public override async Task ConnectAsync(Func callBack = null) => await ConnectAsyncPriv(callBack);
+ public override async Task ConnectAsync(Func callBack = null) => await ConnectAsyncPriv(callBack);
- public async Task ConnectAsync(Func callBack = null, Action onTryingConfig = null) => await ConnectAsyncPriv(callBack, onTryingConfig);
+ public async Task ConnectAsync(Func callBack = null, Action onTryingConfig = null) => await ConnectAsyncPriv(callBack, onTryingConfig);
///
- private async Task ConnectAsyncPriv(Func callBack, Action onTryingConfig = null) {
+ private async Task ConnectAsyncPriv(Func callBack, Action onTryingConfig = null) {
var portnames = SerialPort.GetPortNames();
if (!portnames.Any(x => x == PortName))
@@ -149,6 +149,7 @@ namespace MewtocolNet {
IsConnected = true;
await base.ConnectAsync(callBack);
OnConnected(gotInfo);
+ return ConnectResult.Connected;
} else {
@@ -169,6 +170,8 @@ namespace MewtocolNet {
tryingSerialConfig -= OnTryConfig;
+ return ConnectResult.MewtocolError;
+
}
private async Task TryConnectAsyncMulti() {
diff --git a/MewtocolNet/MewtocolInterfaceTcp.cs b/MewtocolNet/MewtocolInterfaceTcp.cs
index 1f65115..9ff754f 100644
--- a/MewtocolNet/MewtocolInterfaceTcp.cs
+++ b/MewtocolNet/MewtocolInterfaceTcp.cs
@@ -69,7 +69,7 @@ namespace MewtocolNet {
}
///
- public override async Task ConnectAsync(Func callBack = null) => await ConnectAsyncPriv(callBack);
+ public override async Task ConnectAsync(Func callBack = null) => await ConnectAsyncPriv(callBack);
private void BuildTcpClient () {
@@ -107,7 +107,7 @@ namespace MewtocolNet {
}
- private async Task ConnectAsyncPriv(Func callBack = null) {
+ private async Task ConnectAsyncPriv(Func callBack = null) {
try {
@@ -118,6 +118,13 @@ namespace MewtocolNet {
BuildTcpClient();
+ var ep = (IPEndPoint)client.Client.LocalEndPoint;
+ if(ep != null) {
+ Logger.Log($"Connecting from: {ep.Address.MapToIPv4()}:{ep.Port} to {GetConnectionInfo()}", LogLevel.Info, this);
+ } else {
+ Logger.Log($"Connecting to {GetConnectionInfo()}", LogLevel.Info, this);
+ }
+
var result = client.BeginConnect(ipAddr, Port, null, null);
var success = result.AsyncWaitHandle.WaitOne(TimeSpan.FromMilliseconds(ConnectTimeout));
@@ -125,17 +132,12 @@ namespace MewtocolNet {
Logger.Log("The PLC connection timed out", LogLevel.Error, this);
OnMajorSocketExceptionWhileConnecting();
- return;
+ return ConnectResult.Timeout;
}
Logger.LogVerbose("TCP/IP Client connected", this);
- if (HostEndpoint == null) {
- var ep = (IPEndPoint)client.Client.LocalEndPoint;
- Logger.Log($"Connecting [AUTO] from: {ep.Address.MapToIPv4()}:{ep.Port} to {GetConnectionInfo()}", LogLevel.Info, this);
- }
-
//get the stream
stream = client.GetStream();
stream.ReadTimeout = 1000;
@@ -150,6 +152,7 @@ namespace MewtocolNet {
IsConnected = true;
await base.ConnectAsync(callBack);
OnConnected(plcinf);
+ return ConnectResult.Connected;
} else {
@@ -167,6 +170,8 @@ namespace MewtocolNet {
}
+ return ConnectResult.MewtocolError;
+
}
protected override async Task ReconnectAsync (int conTimeout) {
diff --git a/MewtocolNet/PLCInfo.cs b/MewtocolNet/PLCInfo.cs
index 4a91348..6557592 100644
--- a/MewtocolNet/PLCInfo.cs
+++ b/MewtocolNet/PLCInfo.cs
@@ -13,6 +13,8 @@ namespace MewtocolNet {
///
public class PLCInfo : INotifyPropertyChanged {
+ private MewtocolInterface plc;
+
private PlcType typeCode;
private string typeName;
private OPMode operationMode;
@@ -55,10 +57,17 @@ namespace MewtocolNet {
public OPMode OperationMode {
get => operationMode;
internal set {
+
+ var lastModeFlags = operationMode;
+
operationMode = value;
OnPropChange();
OnPropChange(nameof(IsRunMode));
OnPropChange(nameof(OperationModeTags));
+
+ if (plc != null && plc.IsConnected && !plc.isConnectingStage && lastModeFlags != OPMode.None)
+ plc.InvokeModeChanged(lastModeFlags, value);
+
}
}
@@ -117,6 +126,12 @@ namespace MewtocolNet {
public event PropertyChangedEventHandler PropertyChanged;
+ internal PLCInfo (MewtocolInterface onInterface) {
+
+ plc = onInterface;
+
+ }
+
internal bool TryExtendFromEXRT(string msg) {
var regexEXRT = new Regex(@"\%EE\$EX00RT00(?..)(?..)..(?..)(?..)..(?..)(?....)(?..)(?..)(?.)(?...)(?...).*", RegexOptions.IgnoreCase);
@@ -158,7 +173,7 @@ namespace MewtocolNet {
}
- internal static bool TryFromRT(string msg, out PLCInfo inf) {
+ internal static bool TryFromRT(string msg, MewtocolInterface onInterface, out PLCInfo inf) {
var regexRT = new Regex(@"\%EE\$RT(?..)(?..)(?..)(?..)..(?..)(?....).*", RegexOptions.IgnoreCase);
var match = regexRT.Match(msg);
@@ -191,7 +206,7 @@ namespace MewtocolNet {
}
- inf = new PLCInfo {
+ inf = new PLCInfo (onInterface) {
TypeCode = typeCodeFull,
CpuVersion = match.Groups["cpuver"].Value.Insert(1, "."),
ProgramCapacity = definedProgCapacity,
@@ -211,7 +226,7 @@ namespace MewtocolNet {
///
/// Plc info when its not connected
///
- public static PLCInfo None => new PLCInfo() {
+ public static PLCInfo None => new PLCInfo(null) {
SelfDiagnosticError = "",
CpuVersion = "",
diff --git a/MewtocolNet/PublicEnums/ConnectResult.cs b/MewtocolNet/PublicEnums/ConnectResult.cs
new file mode 100644
index 0000000..dac8edf
--- /dev/null
+++ b/MewtocolNet/PublicEnums/ConnectResult.cs
@@ -0,0 +1,31 @@
+namespace MewtocolNet {
+
+ ///
+ /// The result of an initial connection
+ ///
+ public enum ConnectResult {
+
+ ///
+ /// There is no known reason for the connection to fail
+ ///
+ Unknown = 0,
+ ///
+ /// The PLC did establish the connection as expected
+ ///
+ Connected = 1,
+ ///
+ /// The tcp/serial connection to the device timed out (PLC did not respond within time limits)
+ ///
+ Timeout = 2,
+ ///
+ /// The PLC sent a an error message on the type determination stage
+ ///
+ MewtocolError = 3,
+ ///
+ /// The metadata of the PLC did not match the required metadata for the interface
+ ///
+ MismatchMetadata = 4,
+
+ }
+
+}
diff --git a/MewtocolNet/Registers/Base/IRegister.cs b/MewtocolNet/Registers/Base/IRegister.cs
index f1d1f37..5d106f5 100644
--- a/MewtocolNet/Registers/Base/IRegister.cs
+++ b/MewtocolNet/Registers/Base/IRegister.cs
@@ -36,6 +36,11 @@ namespace MewtocolNet.Registers {
///
string Name { get; }
+ ///
+ /// Names of the bound properties, comma seperated
+ ///
+ string BoundPropertyNamesString { get; }
+
///
/// The poll level this register is attached to
///
diff --git a/MewtocolNet/Registers/Base/Register.cs b/MewtocolNet/Registers/Base/Register.cs
index 815c5c6..27de077 100644
--- a/MewtocolNet/Registers/Base/Register.cs
+++ b/MewtocolNet/Registers/Base/Register.cs
@@ -72,6 +72,9 @@ namespace MewtocolNet.Registers {
///
public string Name => name;
+ ///
+ public string BoundPropertyNamesString => string.Join(", ", boundProperties.Select(x => $"{x.ContainedCollection.GetType().Name}.{x.BoundProperty.Name}"));
+
///
public string PLCAddressName => GetMewName();
@@ -263,13 +266,20 @@ namespace MewtocolNet.Registers {
internal virtual object SetValueFromBytes(byte[] bytes) => throw new NotImplementedException();
- internal void WithBoundProperty(RegisterPropTarget propInfo) => boundProperties.Add(propInfo);
+ internal void WithBoundProperty(RegisterPropTarget propInfo) {
+
+ boundProperties.Add(propInfo);
+ PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(BoundPropertyNamesString)));
+
+ }
internal void WithBoundProperties(IEnumerable propInfos) {
foreach (var item in propInfos.ToArray())
boundProperties.Add(item);
+ PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(BoundPropertyNamesString)));
+
}
#region Default accessors
diff --git a/MewtocolNet/Registers/Classes/StringRegister.cs b/MewtocolNet/Registers/Classes/StringRegister.cs
index f510a6e..4579312 100644
--- a/MewtocolNet/Registers/Classes/StringRegister.cs
+++ b/MewtocolNet/Registers/Classes/StringRegister.cs
@@ -15,6 +15,8 @@ namespace MewtocolNet.Registers {
///
public class StringRegister : Register, IStringRegister {
+ internal int sizeWarning = 0;
+
internal int reservedStringLength;
internal uint byteLength;
@@ -120,15 +122,6 @@ namespace MewtocolNet.Registers {
internal override object SetValueFromBytes (byte[] bytes) {
- //if string correct the sizing of the byte hint was wrong
- var reservedSize = BitConverter.ToInt16(bytes, 0);
-
- if (reservedStringLength != reservedSize && attachedInterface.PlcInfo.IsRunMode && !attachedInterface.isConnectingStage)
- throw new NotSupportedException(
- $"The STRING register at {GetMewName()} is not correctly sized, " +
- $"the size should be STRING[{reservedSize}] instead of STRING[{reservedStringLength}]"
- );
-
AddSuccessRead();
var parsed = PlcValueParser.Parse(this, bytes);
diff --git a/MewtocolNet/UnderlyingRegisters/MemoryAreaManager.cs b/MewtocolNet/UnderlyingRegisters/MemoryAreaManager.cs
index 0fa133c..eb05d2c 100644
--- a/MewtocolNet/UnderlyingRegisters/MemoryAreaManager.cs
+++ b/MewtocolNet/UnderlyingRegisters/MemoryAreaManager.cs
@@ -1,4 +1,5 @@
-using MewtocolNet.Registers;
+using MewtocolNet.Logging;
+using MewtocolNet.Registers;
using MewtocolNet.SetupClasses;
using System;
using System.Collections.Generic;
@@ -310,10 +311,12 @@ namespace MewtocolNet.UnderlyingRegisters {
}
//update registers in poll level
- foreach (var dtArea in pollLevel.GetAllAreas().ToArray()) {
+ foreach (var area in pollLevel.GetAllAreas().ToArray()) {
+
+ Logger.LogVerbose($"Polling: {area}", this.mewInterface);
//set the whole memory area at once
- await dtArea.RequestByteReadAsync(dtArea.AddressStart, dtArea.AddressEnd);
+ await area.RequestByteReadAsync(area.AddressStart, area.AddressEnd);
await inbetweenCallback();