From a00f56074fe087ac9ea214dc274f483fd310fd43 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20Wei=C3=9F?= <72068105+Sandoun@users.noreply.github.com> Date: Mon, 14 Aug 2023 19:42:55 +0200 Subject: [PATCH] Added intial connection result --- MewtocolNet/Events/PlcConnectionArgs.cs | 6 +-- MewtocolNet/Events/PlcModeArgs.cs | 19 +++++++++ MewtocolNet/IPlc.cs | 7 +++- MewtocolNet/IPlcSerial.cs | 2 +- MewtocolNet/MewtocolInterface.cs | 39 ++++++++++++++----- .../MewtocolInterfaceRegisterHandling.cs | 20 +++++----- MewtocolNet/MewtocolInterfaceRequests.cs | 2 +- MewtocolNet/MewtocolInterfaceSerial.cs | 9 +++-- MewtocolNet/MewtocolInterfaceTcp.cs | 21 ++++++---- MewtocolNet/PLCInfo.cs | 21 ++++++++-- MewtocolNet/PublicEnums/ConnectResult.cs | 31 +++++++++++++++ MewtocolNet/Registers/Base/IRegister.cs | 5 +++ MewtocolNet/Registers/Base/Register.cs | 12 +++++- .../Registers/Classes/StringRegister.cs | 11 +----- .../UnderlyingRegisters/MemoryAreaManager.cs | 9 +++-- 15 files changed, 160 insertions(+), 54 deletions(-) create mode 100644 MewtocolNet/Events/PlcModeArgs.cs create mode 100644 MewtocolNet/PublicEnums/ConnectResult.cs 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();