mirror of
https://github.com/OpenLogics/MewtocolNet.git
synced 2025-12-06 03:01:24 +00:00
Added intial connection result
This commit is contained in:
@@ -4,10 +4,6 @@ namespace MewtocolNet.Events {
|
||||
|
||||
public delegate void PlcConnectionEventHandler(object sender, PlcConnectionArgs e);
|
||||
|
||||
public class PlcConnectionArgs : EventArgs {
|
||||
|
||||
|
||||
|
||||
}
|
||||
public class PlcConnectionArgs : EventArgs { }
|
||||
|
||||
}
|
||||
|
||||
19
MewtocolNet/Events/PlcModeArgs.cs
Normal file
19
MewtocolNet/Events/PlcModeArgs.cs
Normal file
@@ -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; }
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -41,6 +41,11 @@ namespace MewtocolNet {
|
||||
/// </summary>
|
||||
event RegisterChangedEventHandler RegisterChanged;
|
||||
|
||||
/// <summary>
|
||||
/// Plc mode was changed
|
||||
/// </summary>
|
||||
event PlcModeChangedEventHandler ModeChanged;
|
||||
|
||||
/// <summary>
|
||||
/// The current connection state of the interface
|
||||
/// </summary>
|
||||
@@ -110,7 +115,7 @@ namespace MewtocolNet {
|
||||
/// </summary>
|
||||
/// <param name="onConnected">A callback for excecuting something inside the plc connetion process</param>
|
||||
/// <returns></returns>
|
||||
Task ConnectAsync(Func<Task> onConnected = null);
|
||||
Task<ConnectResult> ConnectAsync(Func<Task> onConnected = null);
|
||||
|
||||
/// <summary>
|
||||
/// Disconnects the device from its current plc connection
|
||||
|
||||
@@ -48,7 +48,7 @@ namespace MewtocolNet {
|
||||
/// <summary>
|
||||
/// Tries to establish a connection with the device asynchronously
|
||||
/// </summary>
|
||||
Task ConnectAsync(Func<Task> callBack, Action onTryingConfig);
|
||||
Task<ConnectResult> ConnectAsync(Func<Task> callBack, Action onTryingConfig);
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -43,6 +43,9 @@ namespace MewtocolNet {
|
||||
/// <inheritdoc/>
|
||||
public event PropertyChangedEventHandler PropertyChanged;
|
||||
|
||||
/// <inheritdoc/>
|
||||
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;
|
||||
@@ -211,6 +215,7 @@ namespace MewtocolNet {
|
||||
memoryManager.MemoryLayoutChanged += () => {
|
||||
|
||||
OnPropChange(nameof(MemoryAreas));
|
||||
OnPropChange(nameof(Registers));
|
||||
|
||||
};
|
||||
|
||||
@@ -260,7 +265,7 @@ namespace MewtocolNet {
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public virtual async Task ConnectAsync(Func<Task> callBack = null) {
|
||||
public virtual async Task<ConnectResult> ConnectAsync(Func<Task> 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;
|
||||
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
@@ -315,7 +322,7 @@ namespace MewtocolNet {
|
||||
/// <inheritdoc/>
|
||||
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<MewtocolFrameResponse> EnqueueMessage(string _msg, Action<double> 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
|
||||
|
||||
/// <inheritdoc/>
|
||||
|
||||
@@ -221,19 +221,19 @@ namespace MewtocolNet {
|
||||
|
||||
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();
|
||||
|
||||
});
|
||||
|
||||
@@ -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");
|
||||
|
||||
|
||||
@@ -105,12 +105,12 @@ namespace MewtocolNet {
|
||||
|
||||
}
|
||||
|
||||
public override async Task ConnectAsync(Func<Task> callBack = null) => await ConnectAsyncPriv(callBack);
|
||||
public override async Task<ConnectResult> ConnectAsync(Func<Task> callBack = null) => await ConnectAsyncPriv(callBack);
|
||||
|
||||
public async Task ConnectAsync(Func<Task> callBack = null, Action onTryingConfig = null) => await ConnectAsyncPriv(callBack, onTryingConfig);
|
||||
public async Task<ConnectResult> ConnectAsync(Func<Task> callBack = null, Action onTryingConfig = null) => await ConnectAsyncPriv(callBack, onTryingConfig);
|
||||
|
||||
/// <inheritdoc/>
|
||||
private async Task ConnectAsyncPriv(Func<Task> callBack, Action onTryingConfig = null) {
|
||||
private async Task<ConnectResult> ConnectAsyncPriv(Func<Task> 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<PLCInfo> TryConnectAsyncMulti() {
|
||||
|
||||
@@ -69,7 +69,7 @@ namespace MewtocolNet {
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override async Task ConnectAsync(Func<Task> callBack = null) => await ConnectAsyncPriv(callBack);
|
||||
public override async Task<ConnectResult> ConnectAsync(Func<Task> callBack = null) => await ConnectAsyncPriv(callBack);
|
||||
|
||||
private void BuildTcpClient () {
|
||||
|
||||
@@ -107,7 +107,7 @@ namespace MewtocolNet {
|
||||
|
||||
}
|
||||
|
||||
private async Task ConnectAsyncPriv(Func<Task> callBack = null) {
|
||||
private async Task<ConnectResult> ConnectAsyncPriv(Func<Task> 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) {
|
||||
|
||||
@@ -13,6 +13,8 @@ namespace MewtocolNet {
|
||||
/// </summary>
|
||||
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(?<icnt>..)(?<mc>..)..(?<cap>..)(?<op>..)..(?<flg>..)(?<sdiag>....)(?<ver>..)(?<hwif>..)(?<nprog>.)(?<csumpz>...)(?<psize>...).*", 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(?<cputype>..)(?<cpuver>..)(?<cap>..)(?<op>..)..(?<flg>..)(?<sdiag>....).*", 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 {
|
||||
/// <summary>
|
||||
/// Plc info when its not connected
|
||||
/// </summary>
|
||||
public static PLCInfo None => new PLCInfo() {
|
||||
public static PLCInfo None => new PLCInfo(null) {
|
||||
|
||||
SelfDiagnosticError = "",
|
||||
CpuVersion = "",
|
||||
|
||||
31
MewtocolNet/PublicEnums/ConnectResult.cs
Normal file
31
MewtocolNet/PublicEnums/ConnectResult.cs
Normal file
@@ -0,0 +1,31 @@
|
||||
namespace MewtocolNet {
|
||||
|
||||
/// <summary>
|
||||
/// The result of an initial connection
|
||||
/// </summary>
|
||||
public enum ConnectResult {
|
||||
|
||||
/// <summary>
|
||||
/// There is no known reason for the connection to fail
|
||||
/// </summary>
|
||||
Unknown = 0,
|
||||
/// <summary>
|
||||
/// The PLC did establish the connection as expected
|
||||
/// </summary>
|
||||
Connected = 1,
|
||||
/// <summary>
|
||||
/// The tcp/serial connection to the device timed out (PLC did not respond within time limits)
|
||||
/// </summary>
|
||||
Timeout = 2,
|
||||
/// <summary>
|
||||
/// The PLC sent a an error message on the type determination stage
|
||||
/// </summary>
|
||||
MewtocolError = 3,
|
||||
/// <summary>
|
||||
/// The metadata of the PLC did not match the required metadata for the interface
|
||||
/// </summary>
|
||||
MismatchMetadata = 4,
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -36,6 +36,11 @@ namespace MewtocolNet.Registers {
|
||||
/// </summary>
|
||||
string Name { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Names of the bound properties, comma seperated
|
||||
/// </summary>
|
||||
string BoundPropertyNamesString { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The poll level this register is attached to
|
||||
/// </summary>
|
||||
|
||||
@@ -72,6 +72,9 @@ namespace MewtocolNet.Registers {
|
||||
/// <inheritdoc/>
|
||||
public string Name => name;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public string BoundPropertyNamesString => string.Join(", ", boundProperties.Select(x => $"{x.ContainedCollection.GetType().Name}.{x.BoundProperty.Name}"));
|
||||
|
||||
/// <inheritdoc/>
|
||||
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<RegisterPropTarget> propInfos) {
|
||||
|
||||
foreach (var item in propInfos.ToArray())
|
||||
boundProperties.Add(item);
|
||||
|
||||
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(BoundPropertyNamesString)));
|
||||
|
||||
}
|
||||
|
||||
#region Default accessors
|
||||
|
||||
@@ -15,6 +15,8 @@ namespace MewtocolNet.Registers {
|
||||
/// </summary>
|
||||
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<string>(this, bytes);
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user