mirror of
https://github.com/OpenLogics/MewtocolNet.git
synced 2025-12-06 11:11:23 +00:00
Added support for TIME types
- fixed writing string registers - refactoring and more comments - fixed dc exception handling - fixed some null reference bugs
This commit is contained in:
@@ -21,6 +21,13 @@ namespace MewtocolNet {
|
||||
|
||||
#region Register Polling
|
||||
|
||||
internal void KillPoller () {
|
||||
|
||||
ContinousReaderRunning = false;
|
||||
cTokenAutoUpdater.Cancel();
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Attaches a continous reader that reads back the Registers and Contacts
|
||||
/// </summary>
|
||||
@@ -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<short> 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<ushort> 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<int> 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<uint> 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<float> 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<TimeSpan> 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<short> 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<ushort> 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<int> 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<uint> 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<float> 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<float>(_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<TimeSpan>(_address, _name));
|
||||
} else if (regType == typeof(bool)) {
|
||||
Registers.Add(_address, new BRegister(_address, RegisterType.R, _name));
|
||||
} else {
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -32,19 +32,24 @@ namespace MewtocolNet {
|
||||
/// </summary>
|
||||
public event Action<Register> RegisterChanged;
|
||||
|
||||
/// <summary>
|
||||
/// The current connection state of the interface
|
||||
/// </summary>
|
||||
public bool IsConnected { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Generic information about the connected PLC
|
||||
/// </summary>
|
||||
public PLCInfo PlcInfo {get;private set;}
|
||||
public PLCInfo PlcInfo { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The registered data registers of the PLC
|
||||
/// </summary>
|
||||
public Dictionary<int, Register> Registers { get; set; } = new Dictionary<int, Register>();
|
||||
|
||||
private string ip {get;set;}
|
||||
private int port {get;set;}
|
||||
private int stationNumber {get;set;}
|
||||
private string ip;
|
||||
private int port;
|
||||
private int stationNumber;
|
||||
|
||||
/// <summary>
|
||||
/// 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<TimeSpan>(cAttribute.MemoryArea, _name: propName);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -404,6 +415,12 @@ namespace MewtocolNet {
|
||||
|
||||
}
|
||||
|
||||
if (foundRegister.GetType() == typeof(NRegister<TimeSpan>)) {
|
||||
|
||||
_ = WriteNumRegister((NRegister<TimeSpan>)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
|
||||
|
||||
/// <summary>
|
||||
/// Sends a command to the PLC and awaits results
|
||||
/// Calculates checksum and sends a command to the PLC then awaits results
|
||||
/// </summary>
|
||||
/// <param name="_msg">MEWTOCOL Formatted request string ex: %01#RT</param>
|
||||
/// <param name="_close">Auto close of frame [true]%01#RT01\r [false]%01#RT</param>
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -53,6 +53,11 @@ namespace MewtocolNet {
|
||||
|
||||
#region Bool register reading / writing
|
||||
|
||||
/// <summary>
|
||||
/// Reads the given boolean register from the PLC
|
||||
/// </summary>
|
||||
/// <param name="_toRead">The register to read</param>
|
||||
/// <param name="_stationNumber">Station number to access</param>
|
||||
public async Task<BRegisterResult> ReadBoolRegister (BRegister _toRead, int _stationNumber = 1) {
|
||||
|
||||
string requeststring = $"%{_stationNumber.ToString().PadLeft(2, '0')}#RCS{_toRead.BuildMewtocolIdent()}";
|
||||
@@ -79,6 +84,12 @@ namespace MewtocolNet {
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes to the given bool register on the PLC
|
||||
/// </summary>
|
||||
/// <param name="_toWrite">The register to write to</param>
|
||||
/// <param name="_stationNumber">Station number to access</param>
|
||||
/// <returns>The success state of the write operation</returns>
|
||||
public async Task<bool> 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
|
||||
|
||||
/// <summary>
|
||||
/// Reads the given numeric register from PLC
|
||||
/// Reads the given numeric register from the PLC
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Type of number (short, ushort, int, uint, float)</typeparam>
|
||||
/// <param name="_toRead">The register to read</param>
|
||||
@@ -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<T> {
|
||||
Result = result,
|
||||
Register = _toRead
|
||||
};
|
||||
}
|
||||
|
||||
if (numType == typeof(short)) {
|
||||
|
||||
var resultBytes = result.Response.ParseDTByteString(4).ReverseByteOrder();
|
||||
@@ -142,6 +160,17 @@ namespace MewtocolNet {
|
||||
|
||||
(_toRead as NRegister<float>).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<TimeSpan>).LastValue = ts;
|
||||
|
||||
}
|
||||
|
||||
var finalRes = new NRegisterResult<T> {
|
||||
@@ -153,12 +182,12 @@ namespace MewtocolNet {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads the given numeric register from PLC
|
||||
/// Reads the given numeric register from the PLC
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Type of number (short, ushort, int, uint, float)</typeparam>
|
||||
/// <param name="_toWrite">The register to write</param>
|
||||
/// <param name="_stationNumber">Station number to access</param>
|
||||
/// <returns>A result with the given NumberRegister and a result struct</returns>
|
||||
/// <returns>The success state of the write operation</returns>
|
||||
public async Task<bool> WriteNumRegister<T> (NRegister<T> _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<SRegisterResult> 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
|
||||
/// <summary>
|
||||
/// Reads back the value of a string register
|
||||
/// </summary>
|
||||
/// <param name="_toRead">The register to read</param>
|
||||
/// <param name="_stationNumber">The station number of the PLC</param>
|
||||
/// <returns></returns>
|
||||
public async Task<SRegisterResult> 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 {
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a string to a string register
|
||||
/// </summary>
|
||||
/// <param name="_toWrite">The register to write</param>
|
||||
/// <param name="_value">The value to write, if the strings length is longer than the cap size it gets trimmed to the max char length</param>
|
||||
/// <param name="_stationNumber">The station number of the PLC</param>
|
||||
/// <returns>The success state of the write operation</returns>
|
||||
public async Task<bool> 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");
|
||||
}
|
||||
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
|
||||
@@ -75,6 +75,9 @@ namespace MewtocolNet.Responses {
|
||||
if (this is NRegister<float> floatReg) {
|
||||
return floatReg.Value.ToString();
|
||||
}
|
||||
if (this is NRegister<TimeSpan> 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<float> floatReg) {
|
||||
return "DDT";
|
||||
}
|
||||
if (this is NRegister<TimeSpan> tsReg) {
|
||||
return "DDT";
|
||||
}
|
||||
if (this is BRegister boolReg) {
|
||||
return boolReg.RegType.ToString();
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user