Made the interface disposable and refactoring

This commit is contained in:
Felix Weiß
2022-07-18 09:55:36 +02:00
parent 6c411d7318
commit fe2d2b9fb9
3 changed files with 209 additions and 87 deletions

View File

@@ -4,16 +4,35 @@ using MewtocolNet;
using MewtocolNet.Logging;
using MewtocolNet.Registers;
namespace Examples {
namespace Examples;
class Program {
class Program {
static void Main(string[] args) {
Console.WriteLine("Enter your scenario number:\n" +
"1 = Permanent connection\n" +
"2 = Dispose connection");
var line = Console.ReadLine();
if(line == "1") {
Scenario1();
}
if (line == "2") {
Scenario2();
}
Console.ReadLine();
}
static void Scenario1 () {
Task.Factory.StartNew(async () => {
//attaching the logger
Logger.LogLevel = LogLevel.Verbose;
Logger.LogLevel = LogLevel.Critical;
Logger.OnNewLogMessage((date, msg) => {
Console.WriteLine($"{date.ToString("HH:mm:ss")} {msg}");
});
@@ -42,28 +61,16 @@ namespace Examples {
await interf.SetRegisterAsync(nameof(registers.TestInt32), 100);
_ = Task.Factory.StartNew(async () => {
while(true) {
for (int i = 0; i < 5; i++) {
var bytes = await interf.ReadByteRange(1020, 20);
await interf.SetRegisterAsync(nameof(registers.TestBool1), !registers.TestBool1);
await interf.SetRegisterAsync(nameof(registers.TestInt32), registers.TestInt32 + 100);
await Task.Delay(1333);
}
await Task.Delay(10000);
}
});
//adds 10 each time the plc connects to the PLCs INT regíster
//interf.SetRegister(nameof(registers.TestInt16), (short)(registers.TestInt16 + 10));
interf.SetRegister(nameof(registers.TestInt16), (short)(registers.TestInt16 + 10));
//adds 1 each time the plc connects to the PLCs DINT regíster
//interf.SetRegister(nameof(registers.TestInt32), (registers.TestInt32 + 1));
interf.SetRegister(nameof(registers.TestInt32), (registers.TestInt32 + 1));
//adds 11.11 each time the plc connects to the PLCs REAL regíster
//interf.SetRegister(nameof(registers.TestFloat32), (float)(registers.TestFloat32 + 11.11));
interf.SetRegister(nameof(registers.TestFloat32), (float)(registers.TestFloat32 + 11.11));
//writes 'Hello' to the PLCs string register
//interf.SetRegister(nameof(registers.TestString2), "Hello");
interf.SetRegister(nameof(registers.TestString2), "Hello");
//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));
});
@@ -72,7 +79,51 @@ namespace Examples {
});
Console.ReadLine();
}
static void Scenario2 () {
Logger.LogLevel = LogLevel.Critical;
Logger.OnNewLogMessage((date, msg) => {
Console.WriteLine($"{date.ToString("HH:mm:ss")} {msg}");
});
Task.Factory.StartNew(async () => {
using(var interf = new MewtocolInterface("10.237.191.3")) {
await interf.ConnectAsync();
if(interf.IsConnected) {
var plcInf = await interf.GetPLCInfoAsync();
Console.WriteLine(plcInf);
}
interf.Disconnect();
}
using (var interf = new MewtocolInterface("10.237.191.3")) {
await interf.ConnectAsync();
if (interf.IsConnected) {
var plcInf = await interf.GetPLCInfoAsync();
Console.WriteLine(plcInf);
}
interf.Disconnect();
}
});
}
}

View File

@@ -15,7 +15,6 @@ namespace MewtocolNet {
public partial class MewtocolInterface {
internal event Action PolledCycle;
internal CancellationTokenSource cTokenAutoUpdater;
internal bool ContinousReaderRunning;
internal bool usePoller = false;
@@ -24,7 +23,6 @@ namespace MewtocolNet {
internal void KillPoller () {
ContinousReaderRunning = false;
cTokenAutoUpdater?.Cancel();
}
@@ -38,21 +36,26 @@ namespace MewtocolNet {
Task.Factory.StartNew(async () => {
cTokenAutoUpdater = new CancellationTokenSource();
Logger.Log("Poller is attaching", LogLevel.Info, this);
int it = 0;
ContinousReaderRunning = true;
while (it < Registers.Count + 1) {
while (ContinousReaderRunning) {
if (it >= Registers.Count) {
if (it >= Registers.Count + 1) {
it = 0;
//invoke cycle polled event
InvokePolledCycleDone();
continue;
}
if (it >= Registers.Count) {
await GetPLCInfoAsync();
it++;
continue;
}
var reg = Registers[it];
if (reg is NRegister<short> shortReg) {

View File

@@ -21,7 +21,7 @@ namespace MewtocolNet {
/// <summary>
/// The PLC com interface class
/// </summary>
public partial class MewtocolInterface : INotifyPropertyChanged {
public partial class MewtocolInterface : INotifyPropertyChanged, IDisposable {
/// <summary>
/// Gets triggered when the PLC connection was established
@@ -43,6 +43,15 @@ namespace MewtocolNet {
/// </summary>
public event PropertyChangedEventHandler PropertyChanged;
private int connectTimeout = 1000;
/// <summary>
/// The initial connection timeout in milliseconds
/// </summary>
public int ConnectTimeout {
get { return connectTimeout; }
set { connectTimeout = value; }
}
private bool isConnected;
/// <summary>
/// The current connection state of the interface
@@ -55,6 +64,16 @@ namespace MewtocolNet {
}
}
private bool disposed;
/// <summary>
/// True if the current interface was disposed
/// </summary>
public bool Disposed {
get { return disposed; }
private set { disposed = value; }
}
private PLCInfo plcInfo;
/// <summary>
/// Generic information about the connected PLC
@@ -75,6 +94,7 @@ namespace MewtocolNet {
private string ip;
private int port;
private int stationNumber;
private int cycleTimeMs = 25;
/// <summary>
/// The current IP of the PLC connection
@@ -89,7 +109,6 @@ namespace MewtocolNet {
/// </summary>
public int StationNumber => stationNumber;
private int cycleTimeMs = 25;
/// <summary>
/// The duration of the last message cycle
/// </summary>
@@ -135,7 +154,6 @@ namespace MewtocolNet {
RegisterChanged += (o) => {
string address = $"{o.GetRegisterString()}{o.MemoryAdress}".PadRight(5, (char)32);
;
Logger.Log($"{address} " +
$"{(o.Name != null ? $"({o.Name}) " : "")}" +
@@ -200,14 +218,14 @@ namespace MewtocolNet {
}
/// <summary>
/// Closes all permanent polling
/// Closes the connection all cyclic polling
/// </summary>
public void Disconnect () {
if (!IsConnected)
return;
OnMajorSocketException();
OnMajorSocketExceptionWhileConnected();
}
@@ -225,6 +243,70 @@ namespace MewtocolNet {
#endregion
#region TCP connection state handling
private async Task ConnectTCP () {
if (!IPAddress.TryParse(ip, out var targetIP)) {
throw new ArgumentException("The IP adress of the PLC was no valid format");
}
try {
client = new TcpClient() {
ReceiveBufferSize = RecBufferSize,
NoDelay = false,
ExclusiveAddressUse = true,
};
var result = client.BeginConnect(targetIP, port, null, null);
var success = result.AsyncWaitHandle.WaitOne(TimeSpan.FromMilliseconds(ConnectTimeout));
if(!success) {
OnMajorSocketExceptionWhileConnecting();
return;
}
stream = client.GetStream();
stream.ReadTimeout = 1000;
Console.WriteLine($"Connected {client.Connected}");
await Task.CompletedTask;
} catch (SocketException) {
OnMajorSocketExceptionWhileConnecting();
}
}
private void OnMajorSocketExceptionWhileConnecting () {
Logger.Log("The PLC connection timed out", LogLevel.Error, this);
CycleTimeMs = 0;
IsConnected = false;
KillPoller();
}
private void OnMajorSocketExceptionWhileConnected () {
if (IsConnected) {
Logger.Log("The PLC connection was closed", LogLevel.Error, this);
CycleTimeMs = 0;
IsConnected = false;
Disconnected?.Invoke();
KillPoller();
client.Close();
}
}
#endregion
#region Register Collection
/// <summary>
@@ -547,25 +629,6 @@ namespace MewtocolNet {
#region Low level command handling
private async Task ConnectTCP () {
var targetIP = IPAddress.Parse(ip);
client = new TcpClient() {
ReceiveBufferSize = RecBufferSize,
NoDelay = false,
ExclusiveAddressUse = true
};
await client.ConnectAsync(targetIP, port);
stream = client.GetStream();
stream.ReadTimeout = 1000;
Console.WriteLine($"Connected {client.Connected}");
}
/// <summary>
/// Calculates checksum and sends a command to the PLC then awaits results
/// </summary>
@@ -668,12 +731,12 @@ namespace MewtocolNet {
Logger.Log($"Critical IO exception on receive", LogLevel.Critical, this);
return null;
} catch (SocketException) {
OnMajorSocketException();
OnMajorSocketExceptionWhileConnected();
return null;
}
if(!string.IsNullOrEmpty(response.ToString())) {
Logger.Log($"<-- IN MSG (TXT): {response} ({response.Length} bytes)", LogLevel.Critical, this);
Logger.Log($"<-- IN MSG: {response}", LogLevel.Critical, this);
return response.ToString();
} else {
return null;
@@ -681,17 +744,22 @@ namespace MewtocolNet {
}
private void OnMajorSocketException () {
#endregion
if (IsConnected) {
#region Disposing
Logger.Log("The PLC connection was closed", LogLevel.Error, this);
CycleTimeMs = 0;
IsConnected = false;
Disconnected?.Invoke();
KillPoller();
/// <summary>
/// Disposes the current interface and clears all its members
/// </summary>
public void Dispose () {
}
if (Disposed) return;
Disconnect();
GC.SuppressFinalize(this);
Disposed = true;
}