diff --git a/Examples/Examples.csproj b/Examples/Examples.csproj
index 8b8151e..b9f9fac 100644
--- a/Examples/Examples.csproj
+++ b/Examples/Examples.csproj
@@ -6,7 +6,7 @@
Exe
- net5.0
+ net6.0
diff --git a/Examples/Program.cs b/Examples/Program.cs
index 232a912..f707c6a 100644
--- a/Examples/Program.cs
+++ b/Examples/Program.cs
@@ -1,56 +1,10 @@
using System;
using System.Threading.Tasks;
-using System.Linq;
-using System.Text.Json;
using MewtocolNet;
-using MewtocolNet.RegisterAttributes;
-using System.Collections;
using MewtocolNet.Logging;
namespace Examples {
-
- public class TestRegisters : RegisterCollectionBase {
-
- //corresponds to a R100 boolean register in the PLC
- [Register(100, RegisterType.R)]
- public bool TestBool1 { get; private set; }
-
- //corresponds to a R100 boolean register in the PLC
- [Register(RegisterType.X, SpecialAddress.D)]
- public bool TestBoolInputXD { get; private set; }
-
- //corresponds to a DT1101 - DT1104 string register in the PLC with (STRING[4])
- [Register(1101, 4)]
- public string TestString1 { get; private set; }
-
- //corresponds to a DT7000 16 bit int register in the PLC
- [Register(7000)]
- public short TestInt16 { get; private set; }
-
- //corresponds to a DTD7001 - DTD7002 32 bit int register in the PLC
- [Register(7001)]
- public int TestInt32 { get; private set; }
-
- //corresponds to a DTD7001 - DTD7002 32 bit float register in the PLC (REAL)
- [Register(7003)]
- public float TestFloat32 { get; private set; }
-
- //corresponds to a DT7005 - DT7009 string register in the PLC with (STRING[5])
- [Register(7005, 5)]
- public string TestString2 { get; private set; }
-
- //corresponds to a DT7010 as a 16bit word/int and parses the word as single bits
- [Register(7010)]
- public BitArray TestBitRegister { get; private set; }
-
- //corresponds to a DT1204 as a 16bit word/int takes the bit at index 9 and writes it back as a boolean
- [Register(1204, 9, BitCount.B16)]
- public bool BitValue { get; private set; }
-
-
- }
-
class Program {
static void Main(string[] args) {
@@ -58,7 +12,7 @@ namespace Examples {
Task.Factory.StartNew(async () => {
//attaching the logger
- Logger.LogLevel = LogLevel.Critical;
+ Logger.LogLevel = LogLevel.Verbose;
Logger.OnNewLogMessage((date, msg) => {
Console.WriteLine($"{date.ToString("HH:mm:ss")} {msg}");
});
@@ -88,8 +42,10 @@ namespace Examples {
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.TestString2), new Random().Next(0, 99999).ToString());
+ //writes 'Hello' to the PLCs string register
+ 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));
});
diff --git a/Examples/TestRegisters.cs b/Examples/TestRegisters.cs
new file mode 100644
index 0000000..1e0a21b
--- /dev/null
+++ b/Examples/TestRegisters.cs
@@ -0,0 +1,52 @@
+using MewtocolNet;
+using MewtocolNet.RegisterAttributes;
+using System;
+using System.Collections;
+
+namespace Examples {
+ public class TestRegisters : RegisterCollectionBase {
+
+ //corresponds to a R100 boolean register in the PLC
+ [Register(100, RegisterType.R)]
+ public bool TestBool1 { get; private set; }
+
+ //corresponds to a R100 boolean register in the PLC
+ [Register(RegisterType.X, SpecialAddress.D)]
+ public bool TestBoolInputXD { get; private set; }
+
+ //corresponds to a DT1101 - DT1104 string register in the PLC with (STRING[4])
+ [Register(1101, 4)]
+ public string TestString1 { get; private set; }
+
+ //corresponds to a DT7000 16 bit int register in the PLC
+ [Register(7000)]
+ public short TestInt16 { get; private set; }
+
+ //corresponds to a DTD7001 - DTD7002 32 bit int register in the PLC
+ [Register(7001)]
+ public int TestInt32 { get; private set; }
+
+ //corresponds to a DTD7001 - DTD7002 32 bit float register in the PLC (REAL)
+ [Register(7003)]
+ public float TestFloat32 { get; private set; }
+
+ //corresponds to a DT7005 - DT7009 string register in the PLC with (STRING[5])
+ [Register(7005, 5)]
+ public string TestString2 { get; private set; }
+
+ //corresponds to a DT7010 as a 16bit word/int and parses the word as single bits
+ [Register(7010)]
+ public BitArray TestBitRegister { get; private set; }
+
+ //corresponds to a DT1204 as a 16bit word/int takes the bit at index 9 and writes it back as a boolean
+ [Register(1204, 9, BitCount.B16)]
+ public bool BitValue { get; private set; }
+
+ //corresponds to a DT7012 - DT7013 as a 32bit time value that gets parsed as a timespan (TIME)
+ //the smallest value to communicate to the PLC is 10ms
+ [Register(7012)]
+ public TimeSpan TestTime { get; private set; }
+
+
+ }
+}
diff --git a/MewtocolNet/Mewtocol/DynamicInterface.cs b/MewtocolNet/Mewtocol/DynamicInterface.cs
index a596069..513c1b9 100644
--- a/MewtocolNet/Mewtocol/DynamicInterface.cs
+++ b/MewtocolNet/Mewtocol/DynamicInterface.cs
@@ -21,6 +21,13 @@ namespace MewtocolNet {
#region Register Polling
+ internal void KillPoller () {
+
+ ContinousReaderRunning = false;
+ cTokenAutoUpdater.Cancel();
+
+ }
+
///
/// Attaches a continous reader that reads back the Registers and Contacts
///
@@ -32,123 +39,134 @@ namespace MewtocolNet {
Logger.Log("Poller is attaching", LogLevel.Info, this);
- Task.Factory.StartNew(async () => {
+ try {
- var plcinf = await GetPLCInfoAsync();
- if (plcinf == null) {
- Logger.Log("PLC not reachable, stopping logger", LogLevel.Info, this);
- return;
- }
+ Task.Factory.StartNew(async () => {
- PolledCycle += MewtocolInterface_PolledCycle;
- void MewtocolInterface_PolledCycle () {
-
- StringBuilder stringBuilder = new StringBuilder();
- foreach (var reg in GetAllRegisters()) {
- string address = $"{reg.GetRegisterString()}{reg.GetStartingMemoryArea()}".PadRight(8, (char)32);
- stringBuilder.AppendLine($"{address}{(reg.Name != null ? $" ({reg.Name})" : "")}: {reg.GetValueString()}");
+ var plcinf = await GetPLCInfoAsync();
+ if (plcinf == null) {
+ Logger.Log("PLC not reachable, stopping logger", LogLevel.Info, this);
+ return;
}
- Logger.Log($"Registers loaded are: \n" +
- $"--------------------\n" +
- $"{stringBuilder.ToString()}" +
- $"--------------------",
- LogLevel.Verbose, this);
+ PolledCycle += MewtocolInterface_PolledCycle;
+ void MewtocolInterface_PolledCycle () {
- Logger.Log("Logger did its first cycle successfully", LogLevel.Info, this);
-
- PolledCycle -= MewtocolInterface_PolledCycle;
- }
+ StringBuilder stringBuilder = new StringBuilder();
+ foreach (var reg in GetAllRegisters()) {
+ string address = $"{reg.GetRegisterString()}{reg.GetStartingMemoryArea()}".PadRight(8, (char)32);
+ stringBuilder.AppendLine($"{address}{(reg.Name != null ? $" ({reg.Name})" : "")}: {reg.GetValueString()}");
+ }
- ContinousReaderRunning = true;
+ Logger.Log($"Registers loaded are: \n" +
+ $"--------------------\n" +
+ $"{stringBuilder.ToString()}" +
+ $"--------------------",
+ LogLevel.Verbose, this);
- while (true) {
+ Logger.Log("Logger did its first cycle successfully", LogLevel.Info, this);
- //do priority tasks first
- if(PriorityTasks.Count > 0) {
+ PolledCycle -= MewtocolInterface_PolledCycle;
+ }
- await PriorityTasks.FirstOrDefault(x => !x.IsCompleted);
+ ContinousReaderRunning = true;
+
+ while (ContinousReaderRunning) {
+
+ //do priority tasks first
+ if (PriorityTasks.Count > 0) {
+
+ await PriorityTasks.FirstOrDefault(x => !x.IsCompleted);
+
+ }
+
+ foreach (var registerPair in Registers) {
+
+ var reg = registerPair.Value;
+
+ if (reg is NRegister shortReg) {
+ var lastVal = shortReg.Value;
+ var readout = (await ReadNumRegister(shortReg, stationNumber)).Register.Value;
+ if (lastVal != readout) {
+ shortReg.LastValue = readout;
+ InvokeRegisterChanged(shortReg);
+ shortReg.TriggerNotifyChange();
+ }
+ }
+ if (reg is NRegister ushortReg) {
+ var lastVal = ushortReg.Value;
+ var readout = (await ReadNumRegister(ushortReg, stationNumber)).Register.Value;
+ if (lastVal != readout) {
+ ushortReg.LastValue = readout;
+ InvokeRegisterChanged(ushortReg);
+ ushortReg.TriggerNotifyChange();
+ }
+ }
+ if (reg is NRegister intReg) {
+ var lastVal = intReg.Value;
+ var readout = (await ReadNumRegister(intReg, stationNumber)).Register.Value;
+ if (lastVal != readout) {
+ intReg.LastValue = readout;
+ InvokeRegisterChanged(intReg);
+ intReg.TriggerNotifyChange();
+ }
+ }
+ if (reg is NRegister uintReg) {
+ var lastVal = uintReg.Value;
+ var readout = (await ReadNumRegister(uintReg, stationNumber)).Register.Value;
+ if (lastVal != readout) {
+ uintReg.LastValue = readout;
+ InvokeRegisterChanged(uintReg);
+ uintReg.TriggerNotifyChange();
+ }
+ }
+ if (reg is NRegister floatReg) {
+ var lastVal = floatReg.Value;
+ var readout = (await ReadNumRegister(floatReg, stationNumber)).Register.Value;
+ if (lastVal != readout) {
+ floatReg.LastValue = readout;
+ InvokeRegisterChanged(floatReg);
+ floatReg.TriggerNotifyChange();
+ }
+ }
+ if (reg is NRegister tsReg) {
+ var lastVal = tsReg.Value;
+ var readout = (await ReadNumRegister(tsReg, stationNumber)).Register.Value;
+ if (lastVal != readout) {
+ tsReg.LastValue = readout;
+ InvokeRegisterChanged(tsReg);
+ tsReg.TriggerNotifyChange();
+ }
+ }
+ if (reg is BRegister boolReg) {
+ var lastVal = boolReg.Value;
+ var readout = (await ReadBoolRegister(boolReg, stationNumber)).Register.Value;
+ if (lastVal != readout) {
+ boolReg.LastValue = readout;
+ InvokeRegisterChanged(boolReg);
+ boolReg.TriggerNotifyChange();
+ }
+ }
+ if (reg is SRegister stringReg) {
+ var lastVal = stringReg.Value;
+ var readout = (await ReadStringRegister(stringReg, stationNumber)).Register.Value;
+ if (lastVal != readout) {
+ InvokeRegisterChanged(stringReg);
+ stringReg.TriggerNotifyChange();
+ }
+
+ }
+
+ }
+
+ //invoke cycle polled event
+ InvokePolledCycleDone();
}
- //await Task.Delay(pollingDelayMs);
+ }, cTokenAutoUpdater.Token);
- foreach (var registerPair in Registers) {
-
- var reg = registerPair.Value;
-
- if (reg is NRegister shortReg) {
- var lastVal = shortReg.Value;
- var readout = (await ReadNumRegister(shortReg, stationNumber)).Register.Value;
- if (lastVal != readout) {
- shortReg.LastValue = readout;
- InvokeRegisterChanged(shortReg);
- shortReg.TriggerNotifyChange();
- }
- }
- if (reg is NRegister ushortReg) {
- var lastVal = ushortReg.Value;
- var readout = (await ReadNumRegister(ushortReg, stationNumber)).Register.Value;
- if (lastVal != readout) {
- ushortReg.LastValue = readout;
- InvokeRegisterChanged(ushortReg);
- ushortReg.TriggerNotifyChange();
- }
- }
- if (reg is NRegister intReg) {
- var lastVal = intReg.Value;
- var readout = (await ReadNumRegister(intReg, stationNumber)).Register.Value;
- if (lastVal != readout) {
- intReg.LastValue = readout;
- InvokeRegisterChanged(intReg);
- intReg.TriggerNotifyChange();
- }
- }
- if (reg is NRegister uintReg) {
- var lastVal = uintReg.Value;
- var readout = (await ReadNumRegister(uintReg, stationNumber)).Register.Value;
- if (lastVal != readout) {
- uintReg.LastValue = readout;
- InvokeRegisterChanged(uintReg);
- uintReg.TriggerNotifyChange();
- }
- }
- if (reg is NRegister floatReg) {
- var lastVal = floatReg.Value;
- var readout = (await ReadNumRegister(floatReg, stationNumber)).Register.Value;
- if (lastVal != readout) {
- floatReg.LastValue = readout;
- InvokeRegisterChanged(floatReg);
- floatReg.TriggerNotifyChange();
- }
- }
- if (reg is BRegister boolReg) {
- var lastVal = boolReg.Value;
- var readout = (await ReadBoolRegister(boolReg, stationNumber)).Register.Value;
- if (lastVal != readout) {
- boolReg.LastValue = readout;
- InvokeRegisterChanged(boolReg);
- boolReg.TriggerNotifyChange();
- }
- }
- if (reg is SRegister stringReg) {
- var lastVal = stringReg.Value;
- var readout = (await ReadStringRegister(stringReg, stationNumber)).Register.Value;
- if (lastVal != readout) {
- InvokeRegisterChanged(stringReg);
- stringReg.TriggerNotifyChange();
- }
-
- }
-
- }
-
- //invoke cycle polled event
- InvokePolledCycleDone();
-
- }
-
- }, cTokenAutoUpdater.Token);
+ } catch (TaskCanceledException) { }
}
@@ -265,6 +283,8 @@ namespace MewtocolNet {
Registers.Add(_address, new NRegister(_address, _name));
} else if (regType == typeof(string)) {
Registers.Add(_address, new SRegister(_address, _length, _name));
+ } else if (regType == typeof(TimeSpan)) {
+ Registers.Add(_address, new NRegister(_address, _name));
} else if (regType == typeof(bool)) {
Registers.Add(_address, new BRegister(_address, RegisterType.R, _name));
} else {
diff --git a/MewtocolNet/Mewtocol/MewtocolHelpers.cs b/MewtocolNet/Mewtocol/MewtocolHelpers.cs
index 4e9432e..9743194 100644
--- a/MewtocolNet/Mewtocol/MewtocolHelpers.cs
+++ b/MewtocolNet/Mewtocol/MewtocolHelpers.cs
@@ -45,12 +45,17 @@ namespace MewtocolNet {
}
internal static string ParseDTByteString (this string _onString, int _blockSize = 4) {
+
+ if (_onString == null)
+ return null;
+
var res = new Regex(@"\%([0-9]{2})\$RD(.{" + _blockSize + "})").Match(_onString);
if (res.Success) {
string val = res.Groups[2].Value;
return val;
}
return null;
+
}
internal static bool? ParseRCSingleBit (this string _onString, int _blockSize = 4) {
@@ -73,6 +78,8 @@ namespace MewtocolNet {
internal static string ReverseByteOrder (this string _onString) {
+ if(_onString == null) return null;
+
//split into 2 chars
var stringBytes = _onString.SplitInParts(2).ToList();
@@ -93,17 +100,38 @@ namespace MewtocolNet {
}
internal static string BuildDTString (this string _inString, short _stringReservedSize) {
+
StringBuilder sb = new StringBuilder();
- //06000600
- short stringSize = (short)_inString.Length;
- var sizeBytes = BitConverter.GetBytes(stringSize).ToHexString();
+
+ //clamp string lenght
+ if (_inString.Length > _stringReservedSize) {
+ _inString = _inString.Substring(0, _stringReservedSize);
+ }
+
+ //actual string content
+ var hexstring = _inString.GetAsciiHexFromString();
+
+ var sizeBytes = BitConverter.GetBytes((short)(hexstring.Length / 2)).ToHexString();
+
+ if (hexstring.Length >= 2) {
+
+ var remainderBytes = (hexstring.Length / 2) % 2;
+
+ if (remainderBytes != 0) {
+ hexstring += "20";
+ }
+
+ }
+
var reservedSizeBytes = BitConverter.GetBytes(_stringReservedSize).ToHexString();
+
//reserved string count bytes
sb.Append(reservedSizeBytes);
//string count actual bytes
sb.Append(sizeBytes);
- //actual string content
- sb.Append(_inString.GetAsciiHexFromString());
+
+
+ sb.Append(hexstring);
return sb.ToString();
}
diff --git a/MewtocolNet/Mewtocol/MewtocolInterface.cs b/MewtocolNet/Mewtocol/MewtocolInterface.cs
index fcafb13..050ef51 100644
--- a/MewtocolNet/Mewtocol/MewtocolInterface.cs
+++ b/MewtocolNet/Mewtocol/MewtocolInterface.cs
@@ -32,19 +32,24 @@ namespace MewtocolNet {
///
public event Action RegisterChanged;
+ ///
+ /// The current connection state of the interface
+ ///
+ public bool IsConnected { get; private set; }
+
///
/// Generic information about the connected PLC
///
- public PLCInfo PlcInfo {get;private set;}
+ public PLCInfo PlcInfo { get; private set; }
///
/// The registered data registers of the PLC
///
public Dictionary Registers { get; set; } = new Dictionary();
- private string ip {get;set;}
- private int port {get;set;}
- private int stationNumber {get;set;}
+ private string ip;
+ private int port;
+ private int stationNumber;
///
/// The current IP of the PLC connection
@@ -82,6 +87,8 @@ namespace MewtocolNet {
if (usePoller)
AttachPoller();
+ IsConnected = true;
+
}
RegisterChanged += (o) => {
@@ -240,6 +247,10 @@ namespace MewtocolNet {
}
+ if (prop.PropertyType == typeof(TimeSpan)) {
+ AddRegister(cAttribute.MemoryArea, _name: propName);
+ }
+
}
}
@@ -404,6 +415,12 @@ namespace MewtocolNet {
}
+ if (foundRegister.GetType() == typeof(NRegister)) {
+
+ _ = WriteNumRegister((NRegister)foundRegister, (TimeSpan)value, StationNumber);
+
+ }
+
if (foundRegister.GetType() == typeof(SRegister)) {
_ = WriteStringRegister((SRegister)foundRegister, (string)value, StationNumber);
@@ -417,7 +434,7 @@ namespace MewtocolNet {
#region Low level command handling
///
- /// Sends a command to the PLC and awaits results
+ /// Calculates checksum and sends a command to the PLC then awaits results
///
/// MEWTOCOL Formatted request string ex: %01#RT
/// Auto close of frame [true]%01#RT01\r [false]%01#RT
@@ -490,35 +507,42 @@ namespace MewtocolNet {
using (TcpClient client = new TcpClient() { ReceiveBufferSize = 64, NoDelay = true, ExclusiveAddressUse = true }) {
try {
+
await client.ConnectAsync(ip, port);
- } catch(SocketException) {
+
+ using (NetworkStream stream = client.GetStream()) {
+ var message = _blockString.ToHexASCIIBytes();
+ var messageAscii = BitConverter.ToString(message).Replace("-", " ");
+ //send request
+ using (var sendStream = new MemoryStream(message)) {
+ await sendStream.CopyToAsync(stream);
+ Logger.Log($"OUT MSG: {_blockString}", LogLevel.Critical, this);
+ //log message sent
+ ASCIIEncoding enc = new ASCIIEncoding();
+ string characters = enc.GetString(message);
+ }
+ //await result
+ StringBuilder response = new StringBuilder();
+ byte[] responseBuffer = new byte[256];
+ do {
+ int bytes = stream.Read(responseBuffer, 0, responseBuffer.Length);
+ response.Append(Encoding.UTF8.GetString(responseBuffer, 0, bytes));
+ }
+ while (stream.DataAvailable);
+ sw.Stop();
+ Logger.Log($"IN MSG ({(int)sw.Elapsed.TotalMilliseconds}ms): {_blockString}", LogLevel.Critical, this);
+ return response.ToString();
+ }
+
+ } catch(Exception) {
+
+ IsConnected = false;
+ KillPoller();
+ Logger.Log("The PLC connection was closed", LogLevel.Error, this);
return null;
+
}
- using (NetworkStream stream = client.GetStream()) {
- var message = _blockString.ToHexASCIIBytes();
- var messageAscii = BitConverter.ToString(message).Replace("-", " ");
- //send request
- using (var sendStream = new MemoryStream(message)) {
- await sendStream.CopyToAsync(stream);
- Logger.Log($"OUT MSG: {_blockString}", LogLevel.Critical, this);
- //log message sent
- ASCIIEncoding enc = new ASCIIEncoding();
- string characters = enc.GetString(message);
- }
- //await result
- StringBuilder response = new StringBuilder();
- byte[] responseBuffer = new byte[256];
- do {
- int bytes = stream.Read(responseBuffer, 0, responseBuffer.Length);
- response.Append(Encoding.UTF8.GetString(responseBuffer, 0, bytes));
- }
- while (stream.DataAvailable);
- sw.Stop();
- Logger.Log($"IN MSG ({(int)sw.Elapsed.TotalMilliseconds}ms): {_blockString}", LogLevel.Critical, this);
- return response.ToString();
- }
-
}
}
diff --git a/MewtocolNet/Mewtocol/MewtocolInterfaceRequests.cs b/MewtocolNet/Mewtocol/MewtocolInterfaceRequests.cs
index 282639c..59db7e8 100644
--- a/MewtocolNet/Mewtocol/MewtocolInterfaceRequests.cs
+++ b/MewtocolNet/Mewtocol/MewtocolInterfaceRequests.cs
@@ -53,6 +53,11 @@ namespace MewtocolNet {
#region Bool register reading / writing
+ ///
+ /// Reads the given boolean register from the PLC
+ ///
+ /// The register to read
+ /// Station number to access
public async Task ReadBoolRegister (BRegister _toRead, int _stationNumber = 1) {
string requeststring = $"%{_stationNumber.ToString().PadLeft(2, '0')}#RCS{_toRead.BuildMewtocolIdent()}";
@@ -79,6 +84,12 @@ namespace MewtocolNet {
}
+ ///
+ /// Writes to the given bool register on the PLC
+ ///
+ /// The register to write to
+ /// Station number to access
+ /// The success state of the write operation
public async Task WriteBoolRegister (BRegister _toWrite, bool value, int _stationNumber = 1) {
string requeststring = $"%{_stationNumber.ToString().PadLeft(2, '0')}#WCS{_toWrite.BuildMewtocolIdent()}{(value ? "1" : "0")}";
@@ -94,7 +105,7 @@ namespace MewtocolNet {
#region Number register reading / writing
///
- /// Reads the given numeric register from PLC
+ /// Reads the given numeric register from the PLC
///
/// Type of number (short, ushort, int, uint, float)
/// The register to read
@@ -107,6 +118,13 @@ namespace MewtocolNet {
string requeststring = $"%{_stationNumber.ToString().PadLeft(2, '0')}#RD{_toRead.BuildMewtocolIdent()}";
var result = await SendCommandAsync(requeststring);
+ if(!result.Success || string.IsNullOrEmpty(result.Response)) {
+ return new NRegisterResult {
+ Result = result,
+ Register = _toRead
+ };
+ }
+
if (numType == typeof(short)) {
var resultBytes = result.Response.ParseDTByteString(4).ReverseByteOrder();
@@ -142,6 +160,17 @@ namespace MewtocolNet {
(_toRead as NRegister).LastValue = finalFloat;
+ } else if (numType == typeof(TimeSpan)) {
+
+ var resultBytes = result.Response.ParseDTByteString(8).ReverseByteOrder();
+ //convert to unsigned int first
+ var vallong = long.Parse(resultBytes, NumberStyles.HexNumber);
+ var valMillis = vallong * 10;
+ var ts = TimeSpan.FromMilliseconds(valMillis);
+
+ //minmax writable / readable value is 10ms
+ (_toRead as NRegister).LastValue = ts;
+
}
var finalRes = new NRegisterResult {
@@ -153,12 +182,12 @@ namespace MewtocolNet {
}
///
- /// Reads the given numeric register from PLC
+ /// Reads the given numeric register from the PLC
///
/// Type of number (short, ushort, int, uint, float)
/// The register to write
/// Station number to access
- /// A result with the given NumberRegister and a result struct
+ /// The success state of the write operation
public async Task WriteNumRegister (NRegister _toWrite, T _value, int _stationNumber = 1) {
byte[] toWriteVal;
@@ -180,6 +209,15 @@ namespace MewtocolNet {
toWriteVal = BitConverter.GetBytes(fl.Value);
+ } else if (numType == typeof(TimeSpan)) {
+
+ var fl = _value as TimeSpan?;
+ if (fl == null)
+ throw new NullReferenceException("Timespan cannot be null");
+
+ var tLong = (uint)(fl.Value.TotalMilliseconds / 10);
+ toWriteVal = BitConverter.GetBytes(tLong);
+
} else {
toWriteVal = null;
}
@@ -196,14 +234,20 @@ namespace MewtocolNet {
#region String register reading / writing
- public async Task ReadStringRegister (SRegister _toRead, int _stationNumber = 1) {
+ //string is build up like this
+ //04 00 04 00 53 50 33 35 13
+ //0, 1 = reserved size
+ //1, 2 = current size
+ //3,4,5,6 = ASCII encoded chars (SP35)
+ //7,8 = checksum
- //string is build up like this
- //04 00 04 00 53 50 33 35 13
- //0, 1 = reserved size
- //1, 2 = current size
- //3,4,5,6 = ASCII encoded chars (SP35)
- //7,8 = checksum
+ ///
+ /// Reads back the value of a string register
+ ///
+ /// The register to read
+ /// The station number of the PLC
+ ///
+ public async Task ReadStringRegister (SRegister _toRead, int _stationNumber = 1) {
string requeststring = $"%{_stationNumber.ToString().PadLeft(2, '0')}#RD{_toRead.BuildMewtocolIdent()}";
var result = await SendCommandAsync(requeststring);
@@ -215,6 +259,13 @@ namespace MewtocolNet {
};
}
+ ///
+ /// Writes a string to a string register
+ ///
+ /// The register to write
+ /// The value to write, if the strings length is longer than the cap size it gets trimmed to the max char length
+ /// The station number of the PLC
+ /// The success state of the write operation
public async Task WriteStringRegister(SRegister _toWrite, string _value, int _stationNumber = 1) {
if (_value == null) _value = "";
@@ -223,13 +274,14 @@ namespace MewtocolNet {
}
string stationNum = _stationNumber.ToString().PadLeft(2, '0');
- string dataArea = _toWrite.BuildMewtocolIdent();
string dataString = _value.BuildDTString(_toWrite.ReservedSize);
+ string dataArea = _toWrite.BuildCustomIdent(dataString.Length / 4);
+
string requeststring = $"%{stationNum}#WD{dataArea}{dataString}";
- Console.WriteLine($"reserved: {_toWrite.MemoryLength}, size: {_value.Length}");
-
var result = await SendCommandAsync(requeststring);
+
+
return result.Success && result.Response.StartsWith($"%{ _stationNumber.ToString().PadLeft(2, '0')}#WD");
}
diff --git a/MewtocolNet/Mewtocol/Subregisters/NRegister.cs b/MewtocolNet/Mewtocol/Subregisters/NRegister.cs
index 49bbf5a..3232711 100644
--- a/MewtocolNet/Mewtocol/Subregisters/NRegister.cs
+++ b/MewtocolNet/Mewtocol/Subregisters/NRegister.cs
@@ -42,6 +42,8 @@ namespace MewtocolNet.Responses {
MemoryLength = 1;
} else if (numType == typeof(float)) {
MemoryLength = 1;
+ } else if (numType == typeof(TimeSpan)) {
+ MemoryLength = 1;
} else {
throw new NotSupportedException($"The type {numType} is not allowed for Number Registers");
}
diff --git a/MewtocolNet/Mewtocol/Subregisters/Register.cs b/MewtocolNet/Mewtocol/Subregisters/Register.cs
index 84f996b..2cd6b6b 100644
--- a/MewtocolNet/Mewtocol/Subregisters/Register.cs
+++ b/MewtocolNet/Mewtocol/Subregisters/Register.cs
@@ -75,6 +75,9 @@ namespace MewtocolNet.Responses {
if (this is NRegister floatReg) {
return floatReg.Value.ToString();
}
+ if (this is NRegister tsReg) {
+ return tsReg.Value.ToString();
+ }
if (this is BRegister boolReg) {
return boolReg.Value.ToString();
}
@@ -130,6 +133,9 @@ namespace MewtocolNet.Responses {
if (this is NRegister floatReg) {
return "DDT";
}
+ if (this is NRegister tsReg) {
+ return "DDT";
+ }
if (this is BRegister boolReg) {
return boolReg.RegType.ToString();
}
diff --git a/MewtocolNet/Mewtocol/Subregisters/SRegister.cs b/MewtocolNet/Mewtocol/Subregisters/SRegister.cs
index 98ca12e..6da8b4d 100644
--- a/MewtocolNet/Mewtocol/Subregisters/SRegister.cs
+++ b/MewtocolNet/Mewtocol/Subregisters/SRegister.cs
@@ -40,9 +40,25 @@ namespace MewtocolNet.Responses {
}
public override string BuildMewtocolIdent() {
+
StringBuilder asciistring = new StringBuilder("D");
+
asciistring.Append(MemoryAdress.ToString().PadLeft(5, '0'));
asciistring.Append((MemoryAdress + MemoryLength).ToString().PadLeft(5, '0'));
+
+ return asciistring.ToString();
+ }
+
+ internal string BuildCustomIdent (int overwriteWordLength) {
+
+ if (overwriteWordLength <= 0)
+ throw new Exception("overwriteWordLength cant be 0 or less");
+
+ StringBuilder asciistring = new StringBuilder("D");
+
+ asciistring.Append(MemoryAdress.ToString().PadLeft(5, '0'));
+ asciistring.Append((MemoryAdress + overwriteWordLength - 1).ToString().PadLeft(5, '0'));
+
return asciistring.ToString();
}