This commit is contained in:
Felix Weiß
2023-07-03 01:25:29 +02:00
parent 8c2ba1f68f
commit f338acfe8a
17 changed files with 494 additions and 174 deletions

View File

@@ -22,7 +22,7 @@ public class ExampleScenarios {
public void SetupLogger () {
//attaching the logger
Logger.LogLevel = LogLevel.Verbose;
Logger.LogLevel = LogLevel.Info;
Logger.OnNewLogMessage((date, level, msg) => {
if (level == LogLevel.Error) Console.ForegroundColor = ConsoleColor.Red;
@@ -74,12 +74,28 @@ public class ExampleScenarios {
}
[Scenario("Read all kinds of example registers")]
public async Task RunReadTest () {
[Scenario("Read all kinds of example registers over ethernet")]
public async Task RunReadTestEth () {
//setting up a new PLC interface and register collection
var interf = Mewtocol.Ethernet("192.168.115.210").WithPoller();
await RunCyclicReadTest(interf);
}
[Scenario("Read all kinds of example registers over serial")]
public async Task RunReadTestSer () {
//setting up a new PLC interface and register collection
var interf = Mewtocol.SerialAuto("COM4").WithPoller();
await RunCyclicReadTest(interf);
}
private async Task RunCyclicReadTest (IPlc interf) {
//auto add all built registers to the interface
var builder = RegBuilder.ForInterface(interf);
var r0reg = builder.FromPlcRegName("R0").Build();
@@ -95,14 +111,26 @@ public class ExampleScenarios {
var stringReg = builder.FromPlcRegName("DT40").AsPlcType(PlcVarType.STRING).Build();
//connect
await interf.ConnectAsync();
if(interf is IPlcSerial serialPlc) {
await serialPlc.ConnectAsync(() => {
Console.WriteLine($"Trying config: {serialPlc.ConnectionInfo}");
});
} else {
await interf.ConnectAsync();
}
//await first register data
await interf.AwaitFirstDataAsync();
_ = Task.Factory.StartNew(async () => {
void setTitle () {
void setTitle() {
Console.Title =
$"Speed UP: {interf.BytesPerSecondUpstream} B/s, " +
@@ -112,7 +140,7 @@ public class ExampleScenarios {
}
while (interf.IsConnected) {
while (interf.IsConnected) {
setTitle();
await Task.Delay(1000);
}
@@ -127,7 +155,7 @@ public class ExampleScenarios {
//set bool
await r0reg.WriteAsync(!(bool)r0reg.Value);
//set random num
await shortReg.WriteAsync((short)new Random().Next(0, 100));
await stringReg.WriteAsync($"_{DateTime.Now.Second}s_");
@@ -135,7 +163,7 @@ public class ExampleScenarios {
sw.Stop();
foreach (var reg in interf.Registers)
Console.WriteLine(reg.ToString());
Console.WriteLine(reg.ToString());
Console.WriteLine($"Total write time for registers: {sw.Elapsed.TotalMilliseconds:N0}ms");
@@ -287,4 +315,33 @@ public class ExampleScenarios {
}
[Scenario("Test")]
public async Task Test () {
Logger.LogLevel = LogLevel.Critical;
//fpx c14 r
var plxFpx = Mewtocol.Ethernet("192.168.178.55");
await plxFpx.ConnectAsync();
await ((MewtocolInterface)plxFpx).GetSystemRegister();
//fpx-h c30 t
var plcFpxH = Mewtocol.Ethernet("192.168.115.210");
await plcFpxH.ConnectAsync();
await ((MewtocolInterface)plcFpxH).GetSystemRegister();
//fpx-h c14 r
var plcFpxHc14 = Mewtocol.Ethernet("192.168.115.212");
await plcFpxHc14.ConnectAsync();
await ((MewtocolInterface)plcFpxHc14).GetSystemRegister();
//fpx c30 t
var plcFpxc30T = Mewtocol.Ethernet("192.168.115.213");
await plcFpxc30T.ConnectAsync();
await ((MewtocolInterface)plcFpxc30T).GetSystemRegister();
await Task.Delay(-1);
}
}

View File

@@ -4,7 +4,7 @@ using System;
using System.Collections;
namespace Examples {
public class TestRegisters : RegisterCollectionBase {
public class TestRegisters : RegisterCollection {
//corresponds to a R100 boolean register in the PLC
[Register(IOType.R, 1000)]

View File

@@ -5,7 +5,7 @@ using System.Collections;
namespace Examples {
public class TestRegistersEnumBitwise : RegisterCollectionBase {
public class TestRegistersEnumBitwise : RegisterCollection {
private bool startCyclePLC;

View File

@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk.Razor">
<PropertyGroup>
<TargetFrameworks>net7.0-android;net7.0-ios;net7.0-maccatalyst</TargetFrameworks>
<TargetFrameworks>net7.0-android;</TargetFrameworks>
<TargetFrameworks Condition="$([MSBuild]::IsOSPlatform('windows'))">$(TargetFrameworks);net7.0-windows10.0.19041.0</TargetFrameworks>
<!-- Uncomment to also build the tizen app. You will need to install tizen by following this: https://github.com/Samsung/Tizen.NET -->
<!-- <TargetFrameworks>$(TargetFrameworks);net7.0-tizen</TargetFrameworks> -->
@@ -23,12 +23,10 @@
<ApplicationDisplayVersion>1.0</ApplicationDisplayVersion>
<ApplicationVersion>1</ApplicationVersion>
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'ios'">14.2</SupportedOSPlatformVersion>
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'maccatalyst'">14.0</SupportedOSPlatformVersion>
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'android'">24.0</SupportedOSPlatformVersion>
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'windows'">10.0.17763.0</SupportedOSPlatformVersion>
<TargetPlatformMinVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'windows'">10.0.17763.0</TargetPlatformMinVersion>
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'tizen'">6.5</SupportedOSPlatformVersion>
</PropertyGroup>
<ItemGroup>

View File

@@ -1,4 +1,5 @@
using System;
using MewtocolNet.Registers;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
@@ -49,6 +50,11 @@ namespace MewtocolNet {
/// </summary>
int StationNumber { get; }
/// <summary>
/// A connection info string
/// </summary>
string ConnectionInfo { get; }
/// <summary>
/// The initial connection timeout in milliseconds
/// </summary>
@@ -91,6 +97,26 @@ namespace MewtocolNet {
/// </summary>
string GetConnectionInfo();
/// <summary>
/// Adds a register to the plc
/// </summary>
void AddRegister(BaseRegister register);
/// <summary>
/// Adds a register to the plc
/// </summary>
void AddRegister(IRegister register);
/// <summary>
/// Gets a register from the plc by name
/// </summary>
IRegister GetRegister(string name);
/// <summary>
/// Gets all registers from the plc
/// </summary>
IEnumerable<IRegister> GetAllRegisters();
}
}

View File

@@ -1,4 +1,9 @@
namespace MewtocolNet {
using MewtocolNet.RegisterAttributes;
using System;
using System.Net;
using System.Threading.Tasks;
namespace MewtocolNet {
/// <summary>
/// Provides a interface for Panasonic PLCs over a ethernet connection
@@ -16,9 +21,14 @@
int Port { get; }
/// <summary>
/// Attaches a poller to the interface
/// The host ip endpoint, leave it null to use an automatic interface
/// </summary>
public IPlcEthernet WithPoller();
IPEndPoint HostEndpoint { get; set; }
/// <summary>
/// Tries to establish a connection with the device asynchronously
/// </summary>
Task ConnectAsync();
/// <summary>
/// Configures the serial interface
@@ -28,6 +38,18 @@
/// <param name="_station">Station Number of the PLC</param>
void ConfigureConnection(string _ip, int _port = 9094, int _station = 1);
/// <summary>
/// Attaches a poller to the interface
/// </summary>
IPlcEthernet WithPoller();
/// <summary>
/// Attaches a register collection object to
/// the interface that can be updated automatically.
/// </summary>
/// <param name="collection">The type of the collection base class</param>
IPlcEthernet AddRegisterCollection(RegisterCollection collection);
}
}

View File

@@ -1,4 +1,5 @@
using System;
using MewtocolNet.RegisterAttributes;
using System;
using System.Collections.Generic;
using System.IO.Ports;
using System.Text;
@@ -36,11 +37,6 @@ namespace MewtocolNet {
/// </summary>
StopBits SerialStopBits { get; }
/// <summary>
/// Attaches a poller to the interface
/// </summary>
public IPlcSerial WithPoller();
/// <summary>
/// Sets up the connection settings for the device
/// </summary>
@@ -50,7 +46,29 @@ namespace MewtocolNet {
/// <param name="_parity">The serial connection parity</param>
/// <param name="_stopBits">The serial connection stop bits</param>
/// <param name="_station">The station number of the PLC</param>
void ConfigureConnection(string _portName, int _baudRate = 19200, int _dataBits = 8, Parity _parity = Parity.Odd, StopBits _stopBits = StopBits.One, int _station = 1)
void ConfigureConnection(string _portName, int _baudRate = 19200, int _dataBits = 8, Parity _parity = Parity.Odd, StopBits _stopBits = StopBits.One, int _station = 1);
/// <summary>
/// Tries to establish a connection with the device asynchronously
/// </summary>
Task ConnectAsync();
/// <summary>
/// Tries to establish a connection with the device asynchronously
/// </summary>
Task ConnectAsync(Action onTryingConfig);
/// <summary>
/// Attaches a poller to the interface
/// </summary>
IPlcSerial WithPoller();
/// <summary>
/// Attaches a register collection object to
/// the interface that can be updated automatically.
/// </summary>
/// <param name="collection">The type of the collection base class</param>
IPlcSerial AddRegisterCollection(RegisterCollection collection);
}

View File

@@ -1,6 +1,9 @@
using System;
using MewtocolNet.Exceptions;
using System;
using System.Collections.Generic;
using System.IO.Ports;
using System.Linq;
using System.Net;
using System.Text;
namespace MewtocolNet {
@@ -13,14 +16,29 @@ namespace MewtocolNet {
/// <summary>
/// Builds a ethernet based Mewtocol Interface
/// </summary>
/// <param name="_ip"></param>
/// <param name="_port"></param>
/// <param name="_station"></param>
/// <param name="ip"></param>
/// <param name="port"></param>
/// <param name="station">Plc station number</param>
/// <returns></returns>
public static IPlcEthernet Ethernet (string _ip, int _port = 9094, int _station = 1) {
public static IPlcEthernet Ethernet (string ip, int port = 9094, int station = 1) {
var instance = new MewtocolInterfaceTcp();
instance.ConfigureConnection(_ip, _port, _station);
instance.ConfigureConnection(ip, port, station);
return instance;
}
/// <summary>
/// Builds a ethernet based Mewtocol Interface
/// </summary>
/// <param name="ip"></param>
/// <param name="port"></param>
/// <param name="station">Plc station number</param>
/// <returns></returns>
public static IPlcEthernet Ethernet(IPAddress ip, int port = 9094, int station = 1) {
var instance = new MewtocolInterfaceTcp();
instance.ConfigureConnection(ip, port, station);
return instance;
}
@@ -28,16 +46,19 @@ namespace MewtocolNet {
/// <summary>
/// Builds a serial port based Mewtocol Interface
/// </summary>
/// <param name="_portName"></param>
/// <param name="_baudRate"></param>
/// <param name="_dataBits"></param>
/// <param name="_parity"></param>
/// <param name="_stopBits"></param>
/// <param name="portName"></param>
/// <param name="baudRate"></param>
/// <param name="dataBits"></param>
/// <param name="parity"></param>
/// <param name="stopBits"></param>
/// <param name="station"></param>
/// <returns></returns>
public static IPlcSerial Serial (string _portName, BaudRate _baudRate = BaudRate._19200, DataBits _dataBits = DataBits.Eight, Parity _parity = Parity.Odd, StopBits _stopBits = StopBits.One, int _station = 1) {
public static IPlcSerial Serial (string portName, BaudRate baudRate = BaudRate._19200, DataBits dataBits = DataBits.Eight, Parity parity = Parity.Odd, StopBits stopBits = StopBits.One, int station = 1) {
TestPortName(portName);
var instance = new MewtocolInterfaceSerial();
instance.ConfigureConnection(_portName, (int)_baudRate, (int)_dataBits, _parity, _stopBits, _station);
instance.ConfigureConnection(portName, (int)baudRate, (int)dataBits, parity, stopBits, station);
return instance;
}
@@ -45,18 +66,29 @@ namespace MewtocolNet {
/// <summary>
/// Builds a serial mewtocol interface that finds the correct settings for the given port name automatically
/// </summary>
/// <param name="_portName"></param>
/// <param name="_station"></param>
/// <param name="portName"></param>
/// <param name="station"></param>
/// <returns></returns>
public static IPlcSerial SerialAuto (string _portName, int _station = 1) {
public static IPlcSerial SerialAuto (string portName, int station = 1) {
TestPortName(portName);
var instance = new MewtocolInterfaceSerial();
instance.ConfigureConnection(_portName, _station);
instance.ConfigureConnection(portName, station);
instance.ConfigureConnectionAuto();
return instance;
}
private static void TestPortName (string portName) {
var portnames = SerialPort.GetPortNames();
if (!portnames.Any(x => x == portName))
throw new MewtocolException($"The port {portName} is no valid port");
}
}
}

View File

@@ -115,6 +115,9 @@ namespace MewtocolNet {
}
}
/// <inheritdoc/>
public string ConnectionInfo => GetConnectionInfo();
#endregion
#region Public read/write Properties / Fields
@@ -151,9 +154,9 @@ namespace MewtocolNet {
};
}
/// <inheritdoc/>
public virtual Task ConnectAsync () => throw new NotImplementedException();
public virtual async Task ConnectAsync() => throw new NotImplementedException();
/// <inheritdoc/>
public async Task AwaitFirstDataAsync() => await firstPollTask;
@@ -163,7 +166,8 @@ namespace MewtocolNet {
if (!IsConnected) return;
pollCycleTask.Wait();
if(pollCycleTask != null && !pollCycleTask.IsCompleted)
pollCycleTask.Wait();
OnMajorSocketExceptionWhileConnected();
@@ -212,10 +216,16 @@ namespace MewtocolNet {
if (useCr)
frame = $"{frame}\r";
SetUpstreamStopWatchStart();
//write inital command
byte[] writeBuffer = Encoding.UTF8.GetBytes(frame);
stream.Write(writeBuffer, 0, writeBuffer.Length);
//calc upstream speed
CalcUpstreamSpeed(writeBuffer.Length);
Logger.Log($"[---------CMD START--------]", LogLevel.Critical, this);
Logger.Log($"--> OUT MSG: {frame.Replace("\r", "(CR)")}", LogLevel.Critical, this);
@@ -235,7 +245,9 @@ namespace MewtocolNet {
//error response
var gotErrorcode = CheckForErrorMsg(resString);
if (gotErrorcode != 0) {
return new MewtocolFrameResponse(gotErrorcode);
var errResponse = new MewtocolFrameResponse(gotErrorcode);
Logger.Log($"Command error: {errResponse.Error}", LogLevel.Error, this);
return errResponse;
}
//was multiframed response
@@ -281,9 +293,13 @@ namespace MewtocolNet {
do {
SetDownstreamStopWatchStart();
byte[] buffer = new byte[128];
int bytesRead = await stream.ReadAsync(buffer, 0, buffer.Length);
CalcDownstreamSpeed(bytesRead);
byte[] received = new byte[bytesRead];
Buffer.BlockCopy(buffer, 0, received, 0, bytesRead);
@@ -338,7 +354,7 @@ namespace MewtocolNet {
private protected int CheckForErrorMsg (string msg) {
//error catching
Regex errorcheck = new Regex(@"\%[0-9]{2}\!([0-9]{2})", RegexOptions.IgnoreCase);
Regex errorcheck = new Regex(@"\%..\!([0-9]{2})", RegexOptions.IgnoreCase);
Match m = errorcheck.Match(msg);
if (m.Success) {
@@ -401,7 +417,7 @@ namespace MewtocolNet {
BytesPerSecondDownstream = 0;
BytesPerSecondUpstream = 0;
CycleTimeMs = 0;
PollerCycleDurationMs = 0;
IsConnected = false;
ClearRegisterVals();
@@ -422,6 +438,53 @@ namespace MewtocolNet {
}
private void SetUpstreamStopWatchStart () {
if (speedStopwatchUpstr == null) {
speedStopwatchUpstr = Stopwatch.StartNew();
}
if (speedStopwatchUpstr.Elapsed.TotalSeconds >= 1) {
speedStopwatchUpstr.Restart();
bytesTotalCountedUpstream = 0;
}
}
private void SetDownstreamStopWatchStart () {
if (speedStopwatchDownstr == null) {
speedStopwatchDownstr = Stopwatch.StartNew();
}
if (speedStopwatchDownstr.Elapsed.TotalSeconds >= 1) {
speedStopwatchDownstr.Restart();
bytesTotalCountedDownstream = 0;
}
}
private void CalcUpstreamSpeed (int byteCount) {
bytesTotalCountedUpstream += byteCount;
var perSecUpstream = (double)((bytesTotalCountedUpstream / speedStopwatchUpstr.Elapsed.TotalMilliseconds) * 1000);
if (perSecUpstream <= 10000)
BytesPerSecondUpstream = (int)Math.Round(perSecUpstream, MidpointRounding.AwayFromZero);
}
private void CalcDownstreamSpeed (int byteCount) {
bytesTotalCountedDownstream += byteCount;
var perSecDownstream = (double)((bytesTotalCountedDownstream / speedStopwatchDownstr.Elapsed.TotalMilliseconds) * 1000);
if (perSecDownstream <= 10000)
BytesPerSecondDownstream = (int)Math.Round(perSecDownstream, MidpointRounding.AwayFromZero);
}
private protected void OnPropChange([CallerMemberName] string propertyName = null) {
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));

View File

@@ -205,15 +205,7 @@ namespace MewtocolNet {
#region Register Colleciton adding
/// <summary>
/// Attaches a register collection object to
/// the interface that can be updated automatically.
/// <para/>
/// Just create a class inheriting from <see cref="RegisterCollectionBase"/>
/// and assert some propertys with the custom <see cref="RegisterAttribute"/>.
/// </summary>
/// <param name="collection">A collection inherting the <see cref="RegisterCollectionBase"/> class</param>
public MewtocolInterface WithRegisterCollection(RegisterCollectionBase collection) {
internal MewtocolInterface WithRegisterCollection (RegisterCollection collection) {
collection.PLCInterface = this;
@@ -353,6 +345,23 @@ namespace MewtocolNet {
#region Register Adding
/// <inheritdoc/>
public void AddRegister(BaseRegister register) {
if (CheckDuplicateRegister(register))
throw MewtocolException.DupeRegister(register);
if (CheckDuplicateNameRegister(register))
throw MewtocolException.DupeNameRegister(register);
register.attachedInterface = this;
RegistersUnderlying.Add(register);
}
/// <inheritdoc/>
public void AddRegister(IRegister register) => AddRegister(register as BaseRegister);
internal void AddRegister (RegisterBuildInfo buildInfo) {
var builtRegister = buildInfo.Build();
@@ -375,19 +384,6 @@ namespace MewtocolNet {
}
public void AddRegister (BaseRegister register) {
if (CheckDuplicateRegister(register))
throw MewtocolException.DupeRegister(register);
if (CheckDuplicateNameRegister(register))
throw MewtocolException.DupeNameRegister(register);
register.attachedInterface = this;
RegistersUnderlying.Add(register);
}
private bool CheckDuplicateRegister (IRegisterInternal instance, out IRegisterInternal foundDupe) {
foundDupe = RegistersInternal.FirstOrDefault(x => x.CompareIsDuplicate(instance));
@@ -414,24 +410,15 @@ namespace MewtocolNet {
#region Register accessing
/// <summary>
/// Gets a register that was added by its name
/// </summary>
/// <returns></returns>
/// <inheritdoc/>>
public IRegister GetRegister(string name) {
return RegistersUnderlying.FirstOrDefault(x => x.Name == name);
}
#endregion
#region Register Reading
/// <summary>
/// Gets a list of all added registers
/// </summary>
public IEnumerable<IRegister> GetAllRegisters() {
/// <inheritdoc/>
public IEnumerable<IRegister> GetAllRegisters () {
return RegistersUnderlying.Cast<IRegister>();

View File

@@ -289,6 +289,86 @@ namespace MewtocolNet {
#endregion
#region Reading / Writing Plc program
public async Task ReadPLCProgramAsync () {
var cmd = SendCommandAsync($"");
}
public async Task GetSystemRegister () {
//the "." means CR or \r
await SendCommandAsync("%EE#RT");
//then get plc status extended? gets polled all time
// %EE#EX00RT00
await SendCommandAsync("%EE#EX00RT00");
//fpx C14 r
//%EE$EX00 RT
//00 Extended mode
//32 Data item count
//70 Machine type
//00 Version (Fixed to 00)
//16 Prog capacity in K
//81 Operation mode / status
//00 Link unit
//60 Error flag
//0000 Self diag error
//50 Version
//02 Hardware information
//0 Number of programs
//4100 Program size BCD
//1600 Header size (no. of words) bcd
//1604 System register size
//96230000001480004 ??
//
// PLC TYPE | Machine Code | HW Information
// FPX C14 R | 70 | 02
// FPX C30 T | 77 | 02
// FPX-H C14 R | A0 | 01
// FPX-H C30 T | A5 | 01
//then a sequence of these is sent
// Specifiy register for monitoring
// %EE#MDFFFFFF
//await SendCommandAsync("%EE#MDFFFFFF");
// reset monitor registers
// %EE#MCFFFFF -> gets ackn
//await SendCommandAsync("%EE#MCFFFFF");
// maybe some special registers?
// %EE#MCR9029R0000R0000R0000R0000R0000R0000R0000 -> gets ackn
//await SendCommandAsync("%EE#MCR9029R0000R0000R0000R0000R0000R0000R0000");
// gets requested when opening plc status
// %EE#MG
// has a response like:
//await SendCommandAsync("%EE#MG");
//var res = cmd.Response.Replace("%01$RR", "");
//var parts = res.SplitInParts(4);
//foreach (var part in parts)
// Console.WriteLine(part);
}
#endregion
#region Helpers
internal string GetStationNumber() {

View File

@@ -10,6 +10,7 @@ using System.Net;
using System.Text;
using System.Threading.Tasks;
using System.Threading;
using MewtocolNet.RegisterAttributes;
namespace MewtocolNet {
@@ -17,11 +18,23 @@ namespace MewtocolNet {
private bool autoSerial;
private event Action tryingSerialConfig;
//serial config
public string PortName { get; private set; }
public int SerialBaudRate { get; private set; }
public int SerialDataBits { get; private set; }
public Parity SerialParity { get; private set; }
/// <inheritdoc/>
public string PortName { get; private set; }
/// <inheritdoc/>
public int SerialBaudRate { get; private set; }
/// <inheritdoc/>
public int SerialDataBits { get; private set; }
/// <inheritdoc/>
public Parity SerialParity { get; private set; }
/// <inheritdoc/>
public StopBits SerialStopBits { get; private set; }
//Serial
@@ -29,7 +42,6 @@ namespace MewtocolNet {
internal MewtocolInterfaceSerial () : base() { }
/// <inheritdoc/>
public IPlcSerial WithPoller () {
@@ -38,6 +50,13 @@ namespace MewtocolNet {
}
public IPlcSerial AddRegisterCollection (RegisterCollection collection) {
WithRegisterCollection(collection);
return this;
}
/// <inheritdoc/>
public override string GetConnectionInfo() {
@@ -89,8 +108,17 @@ namespace MewtocolNet {
}
public override async Task ConnectAsync() => await ConnectAsync(null);
/// <inheritdoc/>
public override async Task ConnectAsync () {
public async Task ConnectAsync (Action onTryingConfig = null) {
void OnTryConfig() {
onTryingConfig();
}
if (onTryingConfig != null)
tryingSerialConfig += OnTryConfig;
try {
@@ -98,10 +126,12 @@ namespace MewtocolNet {
if(autoSerial) {
Logger.Log($"Connecting [AUTO CONFIGURE]: {PortName}", LogLevel.Info, this);
gotInfo = await TryConnectAsyncMulti();
} else {
Logger.Log($"Connecting [MAN]: {PortName}", LogLevel.Info, this);
gotInfo = await TryConnectAsyncSingle(PortName, SerialBaudRate, SerialDataBits, SerialParity, SerialStopBits);
}
@@ -112,7 +142,7 @@ namespace MewtocolNet {
} else {
Logger.Log("Initial connection failed", LogLevel.Info, this);
Logger.Log("Initial connection failed", LogLevel.Error, this);
OnMajorSocketExceptionWhileConnecting();
}
@@ -125,6 +155,8 @@ namespace MewtocolNet {
}
tryingSerialConfig -= OnTryConfig;
}
private async Task<PLCInfo> TryConnectAsyncMulti () {
@@ -193,19 +225,20 @@ namespace MewtocolNet {
SerialParity = par;
SerialStopBits = sbits;
OnSerialPropsChanged();
tryingSerialConfig?.Invoke();
serialClient.Open();
if (!serialClient.IsOpen) {
Logger.Log($"Failed to open [SERIAL]: {GetConnectionInfo()}", LogLevel.Verbose, this);
Logger.Log($"Failed to open [SERIAL]: {GetConnectionInfo()}", LogLevel.Critical, this);
return null;
}
stream = serialClient.BaseStream;
Logger.Log($"Opened [SERIAL]: {GetConnectionInfo()}", LogLevel.Verbose, this);
Logger.Log($"Opened [SERIAL]: {GetConnectionInfo()}", LogLevel.Critical, this);
var plcinf = await GetPLCInfoAsync(100);

View File

@@ -26,23 +26,19 @@ namespace MewtocolNet {
/// </summary>
public class MewtocolInterfaceTcp : MewtocolInterface, IPlcEthernet {
/// <summary>
/// The host ip endpoint, leave it null to use an automatic interface
/// </summary>
public IPEndPoint HostEndpoint { get; set; }
//TCP
internal TcpClient client;
//tcp/ip config
private string ip;
private int port;
private IPAddress ipAddr;
/// <inheritdoc/>
public string IpAddress => ip;
public string IpAddress => ipAddr.ToString();
/// <inheritdoc/>
public int Port => port;
public int Port { get; private set; }
/// <inheritdoc/>
public IPEndPoint HostEndpoint { get; set; }
internal MewtocolInterfaceTcp () : base() { }
@@ -54,14 +50,35 @@ namespace MewtocolNet {
}
/// <inheritdoc/>
public IPlcEthernet AddRegisterCollection (RegisterCollection collection) {
WithRegisterCollection(collection);
return this;
}
#region TCP connection state handling
/// <inheritdoc/>
public void ConfigureConnection (string _ip, int _port = 9094, int _station = 1) {
public void ConfigureConnection (string ip, int port = 9094, int station = 1) {
ip = _ip;
port = _port;
stationNumber = _station;
if (!IPAddress.TryParse(ip, out ipAddr))
throw new MewtocolException($"The ip: {ip} is no valid ip address");
Port = port;
stationNumber = station;
Disconnect();
}
/// <inheritdoc/>
public void ConfigureConnection(IPAddress ip, int port = 9094, int station = 1) {
ipAddr = ip;
Port = port;
stationNumber = station;
Disconnect();
@@ -70,10 +87,6 @@ namespace MewtocolNet {
/// <inheritdoc/>
public override async Task ConnectAsync () {
if (!IPAddress.TryParse(ip, out var targetIP)) {
throw new ArgumentException("The IP adress of the PLC was no valid format");
}
try {
if (HostEndpoint != null) {
@@ -83,29 +96,31 @@ namespace MewtocolNet {
NoDelay = false,
};
var ep = (IPEndPoint)client.Client.LocalEndPoint;
Logger.Log($"Connecting [MAN] endpoint: {ep.Address}:{ep.Port}", LogLevel.Verbose, this);
Logger.Log($"Connecting [MAN] endpoint: {ep.Address}:{ep.Port}", LogLevel.Info, this);
} else {
client = new TcpClient() {
ReceiveBufferSize = RecBufferSize,
NoDelay = false,
ExclusiveAddressUse = true,
//ExclusiveAddressUse = true,
};
}
var result = client.BeginConnect(targetIP, port, null, null);
var result = client.BeginConnect(ipAddr, Port, null, null);
var success = result.AsyncWaitHandle.WaitOne(TimeSpan.FromMilliseconds(ConnectTimeout));
if (!success || !client.Connected) {
Logger.Log("The PLC connection timed out", LogLevel.Error, this);
OnMajorSocketExceptionWhileConnecting();
return;
}
if (HostEndpoint == null) {
var ep = (IPEndPoint)client.Client.LocalEndPoint;
Logger.Log($"Connecting [AUTO] endpoint: {ep.Address.MapToIPv4()}:{ep.Port}", LogLevel.Verbose, this);
Logger.Log($"Connecting [AUTO] endpoint: {ep.Address.MapToIPv4()}:{ep.Port}", LogLevel.Info, this);
}
//get the stream
@@ -121,7 +136,7 @@ namespace MewtocolNet {
} else {
Logger.Log("Initial connection failed", LogLevel.Info, this);
Logger.Log("Initial connection failed", LogLevel.Error, this);
OnDisconnect();
}

View File

@@ -6,7 +6,7 @@ namespace MewtocolNet.RegisterAttributes {
/// <summary>
/// A register collection base with full auto read and notification support built in
/// </summary>
public class RegisterCollectionBase : INotifyPropertyChanged {
public class RegisterCollection : INotifyPropertyChanged {
/// <summary>
/// Reference to its bound interface

View File

@@ -21,7 +21,7 @@ namespace MewtocolNet.RegisterBuilding {
};
public static RegBuilder ForInterface (IPlcEthernet interf) {
public static RegBuilder ForInterface (IPlc interf) {
var rb = new RegBuilder();
rb.forInterface = interf as MewtocolInterface;

View File

@@ -15,7 +15,7 @@ namespace MewtocolTests {
this.output = output;
}
public class TestRegisterCollection : RegisterCollectionBase {
public class TestRegisterCollection : RegisterCollection {
//corresponds to a R100 boolean register in the PLC
//can also be written as R1000 because the last one is a special address
@@ -109,8 +109,8 @@ namespace MewtocolTests {
[Fact(DisplayName = "Boolean R generation")]
public void BooleanGen() {
var interf = new MewtocolInterfaceShared("192.168.0.1");
interf.WithRegisterCollection(new TestRegisterCollection()).WithPoller();
var interf = Mewtocol.Ethernet("192.168.0.1");
interf.AddRegisterCollection(new TestRegisterCollection()).WithPoller();
var register = interf.GetRegister(nameof(TestRegisterCollection.TestBool1));
@@ -122,8 +122,8 @@ namespace MewtocolTests {
[Fact(DisplayName = "Boolean input XD generation")]
public void BooleanInputGen() {
var interf = new MewtocolInterfaceShared("192.168.0.1");
interf.WithRegisterCollection(new TestRegisterCollection()).WithPoller();
var interf = Mewtocol.Ethernet("192.168.0.1");
interf.AddRegisterCollection(new TestRegisterCollection()).WithPoller();
var register = interf.GetRegister(nameof(TestRegisterCollection.TestBoolInputXD));
@@ -135,8 +135,8 @@ namespace MewtocolTests {
[Fact(DisplayName = "Int16 generation")]
public void Int16Gen() {
var interf = new MewtocolInterfaceShared("192.168.0.1");
interf.WithRegisterCollection(new TestRegisterCollection()).WithPoller();
var interf = Mewtocol.Ethernet("192.168.0.1");
interf.AddRegisterCollection(new TestRegisterCollection()).WithPoller();
var register = interf.GetRegister(nameof(TestRegisterCollection.TestInt16));
@@ -148,8 +148,8 @@ namespace MewtocolTests {
[Fact(DisplayName = "UInt16 generation")]
public void UInt16Gen() {
var interf = new MewtocolInterfaceShared("192.168.0.1");
interf.WithRegisterCollection(new TestRegisterCollection()).WithPoller();
var interf = Mewtocol.Ethernet("192.168.0.1");
interf.AddRegisterCollection(new TestRegisterCollection()).WithPoller();
var register = interf.GetRegister(nameof(TestRegisterCollection.TestUInt16));
@@ -161,8 +161,8 @@ namespace MewtocolTests {
[Fact(DisplayName = "Int32 generation")]
public void Int32Gen() {
var interf = new MewtocolInterfaceShared("192.168.0.1");
interf.WithRegisterCollection(new TestRegisterCollection()).WithPoller();
var interf = Mewtocol.Ethernet("192.168.0.1");
interf.AddRegisterCollection(new TestRegisterCollection()).WithPoller();
var register = interf.GetRegister(nameof(TestRegisterCollection.TestInt32));
@@ -174,8 +174,8 @@ namespace MewtocolTests {
[Fact(DisplayName = "UInt32 generation")]
public void UInt32Gen() {
var interf = new MewtocolInterfaceShared("192.168.0.1");
interf.WithRegisterCollection(new TestRegisterCollection()).WithPoller();
var interf = Mewtocol.Ethernet("192.168.0.1");
interf.AddRegisterCollection(new TestRegisterCollection()).WithPoller();
var register = interf.GetRegister(nameof(TestRegisterCollection.TestUInt32));
@@ -187,8 +187,8 @@ namespace MewtocolTests {
[Fact(DisplayName = "Float32 generation")]
public void Float32Gen() {
var interf = new MewtocolInterfaceShared("192.168.0.1");
interf.WithRegisterCollection(new TestRegisterCollection()).WithPoller();
var interf = Mewtocol.Ethernet("192.168.0.1");
interf.AddRegisterCollection(new TestRegisterCollection()).WithPoller();
var register = interf.GetRegister(nameof(TestRegisterCollection.TestFloat32));
@@ -200,8 +200,8 @@ namespace MewtocolTests {
[Fact(DisplayName = "TimeSpan generation")]
public void TimespanGen() {
var interf = new MewtocolInterfaceShared("192.168.0.1");
interf.WithRegisterCollection(new TestRegisterCollection()).WithPoller();
var interf = Mewtocol.Ethernet("192.168.0.1");
interf.AddRegisterCollection(new TestRegisterCollection()).WithPoller();
var register = interf.GetRegister(nameof(TestRegisterCollection.TestTime));
@@ -210,22 +210,6 @@ namespace MewtocolTests {
}
//[Fact(DisplayName = "String generation")]
//public void StringGen() {
// var interf = new MewtocolInterface("192.168.0.1");
// interf.WithRegisterCollection(new TestRegisterCollection()).WithPoller();
// var register = interf.GetRegister(nameof(TestRegisterCollection.TestString2));
// //test generic properties
// TestBasicGeneration(register, nameof(TestRegisterCollection.TestString2), null!, 7005, "DT7005");
// Assert.Equal(5, ((BytesRegister<string>)register).ReservedSize);
// Assert.Equal(4, ((BytesRegister<string>)register).MemoryLength);
//}
}
}

View File

@@ -45,10 +45,10 @@ namespace MewtocolTests
AfterWriteValue = true,
},
new RegisterReadWriteTest {
TargetRegister = new NumberRegister<int>(3000),
TargetRegister = new NumberRegister<short>(3000),
RegisterPlcAddressName = "DT3000",
IntialValue = (int)0,
AfterWriteValue = (int)-513,
IntialValue = (short)0,
AfterWriteValue = (short)-513,
},
};
@@ -73,9 +73,9 @@ namespace MewtocolTests
output.WriteLine($"Testing: {plc.PLCName}");
var cycleClient = new MewtocolInterfaceShared(plc.PLCIP, plc.PLCPort);
var cycleClient = Mewtocol.Ethernet(plc.PLCIP, plc.PLCPort);
await cycleClient.ConnectAsyncOld();
await cycleClient.ConnectAsync();
Assert.True(cycleClient.IsConnected);
@@ -94,9 +94,9 @@ namespace MewtocolTests
output.WriteLine($"Testing: {plc.PLCName}\n");
var client = new MewtocolInterfaceShared(plc.PLCIP, plc.PLCPort);
var client = Mewtocol.Ethernet(plc.PLCIP, plc.PLCPort);
await client.ConnectAsyncOld();
await client.ConnectAsync();
output.WriteLine($"{client.PlcInfo}\n");
@@ -111,38 +111,43 @@ namespace MewtocolTests
}
//[Fact(DisplayName = "Reading basic information from PLC")]
//public async void TestRegisterReadWriteAsync () {
[Fact(DisplayName = "Reading basic information from PLC")]
public async void TestRegisterReadWriteAsync() {
// foreach (var plc in testPlcInformationData) {
foreach (var plc in testPlcInformationData) {
// output.WriteLine($"Testing: {plc.PLCName}\n");
output.WriteLine($"Testing: {plc.PLCName}\n");
// var client = new MewtocolInterface(plc.PLCIP, plc.PLCPort);
var client = Mewtocol.Ethernet(plc.PLCIP, plc.PLCPort);
// foreach (var testRW in testRegisterRW) {
foreach (var testRW in testRegisterRW) {
// client.AddRegister(testRW.TargetRegister);
client.AddRegister(testRW.TargetRegister);
// }
}
// await client.ConnectAsync();
// Assert.True(client.IsConnected);
await client.ConnectAsync();
Assert.True(client.IsConnected);
// foreach (var testRW in testRegisterRW) {
foreach (var testRW in testRegisterRW) {
// client.AddRegister(testRW.TargetRegister);
var testRegister = client.Registers.First(x => x.PLCAddressName == testRW.RegisterPlcAddressName);
// }
//test inital val
Assert.Equal(testRW.IntialValue, testRegister.Value);
// Assert.Equal(client.PlcInfo.CpuInformation.Cputype, plc.Type);
// Assert.Equal(client.PlcInfo.CpuInformation.ProgramCapacity, plc.ProgCapacity);
await testRegister.WriteAsync(testRW.AfterWriteValue);
// client.Disconnect();
//test after write val
Assert.Equal(testRW.AfterWriteValue, testRegister.Value);
// }
}
//}
client.Disconnect();
}
}
}