diff --git a/MewtocolNet/Exceptions/MewtocolException.cs b/MewtocolNet/Exceptions/MewtocolException.cs
index 46c948e..445fd78 100644
--- a/MewtocolNet/Exceptions/MewtocolException.cs
+++ b/MewtocolNet/Exceptions/MewtocolException.cs
@@ -19,13 +19,20 @@ namespace MewtocolNet.Exceptions {
internal static MewtocolException DupeRegister (IRegisterInternal register) {
- return new MewtocolException($"The mewtocol interface already contains this register: {register.GetRegisterPLCName()}");
+ return new MewtocolException($"The mewtocol interface already contains this register: {register.GetMewName()}");
}
internal static MewtocolException DupeNameRegister (IRegisterInternal register) {
- return new MewtocolException($"The mewtocol interface registers already contains a register with the name: {register.GetRegisterPLCName()}");
+ return new MewtocolException($"The mewtocol interface registers already contains a register with the name: {register.GetMewName()}");
+
+ }
+
+ internal static MewtocolException OverlappingRegister (IRegisterInternal registerA, IRegisterInternal registerB) {
+
+ throw new MewtocolException($"The register: {registerA.GetRegisterWordRangeString()} " +
+ $"has overlapping addresses with: {registerB.GetRegisterWordRangeString()}");
}
diff --git a/MewtocolNet/Helpers/MewtocolHelpers.cs b/MewtocolNet/Helpers/MewtocolHelpers.cs
index 91fbcfb..6a144c9 100644
--- a/MewtocolNet/Helpers/MewtocolHelpers.cs
+++ b/MewtocolNet/Helpers/MewtocolHelpers.cs
@@ -14,50 +14,6 @@ namespace MewtocolNet {
///
public static class MewtocolHelpers {
- #region Value PLC Humanizers
-
- ///
- /// Gets the TimeSpan as a PLC representation string fe.
- ///
- /// T#1h10m30s20ms
- ///
- ///
- ///
- ///
- public static string AsPLCTime (this TimeSpan timespan) {
-
- if (timespan == null || timespan == TimeSpan.Zero)
- return $"T#0s";
-
- StringBuilder sb = new StringBuilder("T#");
-
- int millis = timespan.Milliseconds;
- int seconds = timespan.Seconds;
- int minutes = timespan.Minutes;
- int hours = timespan.Hours;
-
- if (hours > 0) sb.Append($"{hours}h");
- if (minutes > 0) sb.Append($"{minutes}m");
- if (seconds > 0) sb.Append($"{seconds}s");
- if (millis > 0) sb.Append($"{millis}ms");
-
- return sb.ToString();
-
- }
-
- ///
- /// Turns a bit array into a 0 and 1 string
- ///
- public static string ToBitString(this BitArray arr) {
-
- var bits = new bool[arr.Length];
- arr.CopyTo(bits, 0);
- return string.Join("", bits.Select(x => x ? "1" : "0"));
-
- }
-
- #endregion
-
#region Byte and string operation helpers
///
diff --git a/MewtocolNet/Helpers/PlcFormat.cs b/MewtocolNet/Helpers/PlcFormat.cs
new file mode 100644
index 0000000..e080859
--- /dev/null
+++ b/MewtocolNet/Helpers/PlcFormat.cs
@@ -0,0 +1,89 @@
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Globalization;
+using System.Linq;
+using System.Text;
+using System.Text.RegularExpressions;
+
+namespace MewtocolNet {
+
+ public static class PlcFormat {
+
+ ///
+ /// Gets the TimeSpan as a PLC representation string fe.
+ ///
+ /// T#1h10m30s20ms
+ ///
+ ///
+ ///
+ ///
+ public static string ToPlcTime (this TimeSpan timespan) {
+
+ if (timespan == null || timespan == TimeSpan.Zero)
+ return $"T#0s";
+
+ StringBuilder sb = new StringBuilder("T#");
+
+ int millis = timespan.Milliseconds;
+ int seconds = timespan.Seconds;
+ int minutes = timespan.Minutes;
+ int hours = timespan.Hours;
+ int days = timespan.Days;
+
+ if (days > 0) sb.Append($"{days}d");
+ if (hours > 0) sb.Append($"{hours}h");
+ if (minutes > 0) sb.Append($"{minutes}m");
+ if (seconds > 0) sb.Append($"{seconds}s");
+ if (millis > 0) sb.Append($"{millis}ms");
+
+ return sb.ToString();
+
+ }
+
+ public static TimeSpan ParsePlcTime (string plcTimeFormat) {
+
+ var reg = new Regex(@"(?:T|t)#(?:(?[0-9]{1,2})d)?(?:(?[0-9]{1,2})h)?(?:(?[0-9]{1,2})m)?(?:(?[0-9]{1,2})s)?(?:(?[0-9]{1,3})ms)?");
+ var match = reg.Match(plcTimeFormat);
+
+ if(match.Success) {
+
+ var days = match.Groups["d"].Value;
+ var hours = match.Groups["h"].Value;
+ var minutes = match.Groups["m"].Value;
+ var seconds = match.Groups["s"].Value;
+ var milliseconds = match.Groups["ms"].Value;
+
+ TimeSpan retTime = TimeSpan.Zero;
+
+ if (!string.IsNullOrEmpty(days)) retTime += TimeSpan.FromDays(int.Parse(days));
+ if (!string.IsNullOrEmpty(hours)) retTime += TimeSpan.FromHours(int.Parse(hours));
+ if (!string.IsNullOrEmpty(minutes)) retTime += TimeSpan.FromMinutes(int.Parse(minutes));
+ if (!string.IsNullOrEmpty(seconds)) retTime += TimeSpan.FromSeconds(int.Parse(seconds));
+ if (!string.IsNullOrEmpty(milliseconds)) retTime += TimeSpan.FromMilliseconds(int.Parse(milliseconds));
+
+ if ((retTime.TotalMilliseconds % 10) != 0)
+ throw new NotSupportedException("Plc times can't have a millisecond component lower than 10ms");
+
+ return retTime;
+
+ }
+
+ return TimeSpan.Zero;
+
+ }
+
+ ///
+ /// Turns a bit array into a 0 and 1 string
+ ///
+ public static string ToBitString(this BitArray arr) {
+
+ var bits = new bool[arr.Length];
+ arr.CopyTo(bits, 0);
+ return string.Join("", bits.Select(x => x ? "1" : "0"));
+
+ }
+
+ }
+
+}
diff --git a/MewtocolNet/IPlc.cs b/MewtocolNet/IPlc.cs
index 1386b93..b92a434 100644
--- a/MewtocolNet/IPlc.cs
+++ b/MewtocolNet/IPlc.cs
@@ -77,7 +77,14 @@ namespace MewtocolNet {
/// Append the checksum and bcc automatically
/// Timout to wait for a response
/// Returns the result
- Task SendCommandAsync(string _msg, bool withTerminator = true, int timeoutMs = -1);
+ Task SendCommandAsync(string _msg, bool withTerminator = true, int timeoutMs = -1, Action onReceiveProgress = null);
+
+ ///
+ /// Changes the PLCs operation mode to the given one
+ ///
+ /// True for run mode, false for prog mode
+ /// The success state of the write operation
+ Task SetOperationModeAsync(bool setRun);
///
/// Use this to await the first poll iteration after connecting,
diff --git a/MewtocolNet/MewtocolInterface.cs b/MewtocolNet/MewtocolInterface.cs
index 2c14b27..a1ac273 100644
--- a/MewtocolNet/MewtocolInterface.cs
+++ b/MewtocolNet/MewtocolInterface.cs
@@ -143,6 +143,7 @@ namespace MewtocolNet {
private protected MewtocolInterface () {
Connected += MewtocolInterface_Connected;
+ RegisterChanged += OnRegisterChanged;
void MewtocolInterface_Connected(PLCInfo obj) {
@@ -153,16 +154,15 @@ namespace MewtocolNet {
}
- RegisterChanged += (o) => {
+ }
- var asInternal = (IRegisterInternal)o;
+ private void OnRegisterChanged(IRegister o) {
- string address = $"{asInternal.GetRegisterString()}{asInternal.GetStartingMemoryArea()}".PadRight(5, (char)32);
+ var asInternal = (IRegisterInternal)o;
- Logger.Log($"{address} " +
- $"{(o.Name != null ? $"({o.Name}) " : "")}" +
- $"changed to \"{asInternal.GetValueString()}\"", LogLevel.Change, this);
- };
+ Logger.Log($"{asInternal.GetMewName()} " +
+ $"{(o.Name != null ? $"({o.Name}) " : "")}" +
+ $"changed to \"{asInternal.GetValueString()}\"", LogLevel.Change, this);
}
@@ -195,15 +195,15 @@ namespace MewtocolNet {
}
///
- public virtual string GetConnectionInfo() => throw new NotImplementedException();
+ public virtual string GetConnectionInfo () => throw new NotImplementedException();
///
- public async Task SendCommandAsync(string _msg, bool withTerminator = true, int timeoutMs = -1) {
+ public async Task SendCommandAsync (string _msg, bool withTerminator = true, int timeoutMs = -1, Action onReceiveProgress = null) {
//send request
queuedMessages++;
- var tempResponse = queue.Enqueue(async () => await SendFrameAsync(_msg, withTerminator, withTerminator));
+ var tempResponse = queue.Enqueue(async () => await SendFrameAsync(_msg, withTerminator, withTerminator, onReceiveProgress));
if (await Task.WhenAny(tempResponse, Task.Delay(timeoutMs)) != tempResponse) {
// timeout logic
@@ -217,7 +217,7 @@ namespace MewtocolNet {
}
- private protected async Task SendFrameAsync (string frame, bool useBcc = true, bool useCr = true) {
+ private protected async Task SendFrameAsync (string frame, bool useBcc = true, bool useCr = true, Action onReceiveProgress = null) {
try {
@@ -236,13 +236,27 @@ namespace MewtocolNet {
byte[] writeBuffer = Encoding.UTF8.GetBytes(frame);
stream.Write(writeBuffer, 0, writeBuffer.Length);
+ //calculate the expected number of frames from the message request
+ int? wordsCountRequested = null;
+ if(onReceiveProgress != null) {
+
+ var match = Regex.Match(frame, @"RDD(?[0-9]{5})(?[0-9]{5})");
+
+ if (match.Success) {
+ var from = int.Parse(match.Groups["from"].Value);
+ var to = int.Parse(match.Groups["to"].Value);
+ wordsCountRequested = (to - from) + 1;
+ }
+
+ }
+
//calc upstream speed
CalcUpstreamSpeed(writeBuffer.Length);
Logger.Log($"[---------CMD START--------]", LogLevel.Critical, this);
Logger.Log($"--> OUT MSG: {frame.Replace("\r", "(CR)")}", LogLevel.Critical, this);
- var readResult = await ReadCommandAsync();
+ var readResult = await ReadCommandAsync(wordsCountRequested, onReceiveProgress);
//did not receive bytes but no errors, the com port was not configured right
if (readResult.Item1.Length == 0) {
@@ -294,7 +308,7 @@ namespace MewtocolNet {
}
- private protected async Task<(byte[], bool)> ReadCommandAsync () {
+ private protected async Task<(byte[], bool)> ReadCommandAsync (int? wordsCountRequested = null, Action onReceiveProgress = null) {
//read total
List totalResponse = new List();
@@ -303,6 +317,7 @@ namespace MewtocolNet {
try {
bool needsRead = false;
+ int readFrames = 0;
do {
@@ -327,6 +342,15 @@ namespace MewtocolNet {
if (commandRes == CommandState.RequestedNextFrame) {
+ //calc frame progress
+ if(onReceiveProgress != null && wordsCountRequested != null) {
+
+ var frameBytesCount = tempMsg.Length - 6;
+ double prog = (double)frameBytesCount / wordsCountRequested.Value;
+ onReceiveProgress(prog);
+
+ }
+
//request next frame
var writeBuffer = Encoding.UTF8.GetBytes("%01**&\r");
await stream.WriteAsync(writeBuffer, 0, writeBuffer.Length);
@@ -334,6 +358,8 @@ namespace MewtocolNet {
}
+ readFrames++;
+
} while (needsRead);
} catch (OperationCanceledException) { }
@@ -342,7 +368,7 @@ namespace MewtocolNet {
}
- private protected CommandState ParseBufferFrame(byte[] received) {
+ private protected CommandState ParseBufferFrame (byte[] received) {
const char CR = '\r';
const char DELIMITER = '&';
@@ -405,8 +431,8 @@ namespace MewtocolNet {
private protected virtual void OnConnected (PLCInfo plcinf) {
- Logger.Log("Connected", LogLevel.Info, this);
- Logger.Log($"\n\n{plcinf.ToString()}\n\n", LogLevel.Verbose, this);
+ Logger.Log("Connected to PLC", LogLevel.Info, this);
+ Logger.Log($"{plcinf.ToString()}", LogLevel.Verbose, this);
IsConnected = true;
@@ -440,17 +466,6 @@ namespace MewtocolNet {
}
- private protected void ClearRegisterVals() {
-
- for (int i = 0; i < RegistersUnderlying.Count; i++) {
-
- var reg = (IRegisterInternal)RegistersUnderlying[i];
- reg.ClearValue();
-
- }
-
- }
-
private void SetUpstreamStopWatchStart () {
if (speedStopwatchUpstr == null) {
diff --git a/MewtocolNet/MewtocolInterfaceRegisterHandling.cs b/MewtocolNet/MewtocolInterfaceRegisterHandling.cs
index 51bb07f..8c188bf 100644
--- a/MewtocolNet/MewtocolInterfaceRegisterHandling.cs
+++ b/MewtocolNet/MewtocolInterfaceRegisterHandling.cs
@@ -168,7 +168,6 @@ namespace MewtocolNet {
if((bool)register.Value != resultBitArray[k]) {
register.SetValueFromPLC(resultBitArray[k]);
- InvokeRegisterChanged(register);
}
}
@@ -192,7 +191,6 @@ namespace MewtocolNet {
if (lastVal != readout) {
rwReg.SetValueFromPLC(readout);
- InvokeRegisterChanged(reg);
}
}
@@ -218,16 +216,21 @@ namespace MewtocolNet {
string propName = prop.Name;
foreach (var attr in attributes) {
- if (attr is RegisterAttribute cAttribute && prop.PropertyType.IsAllowedPlcCastingType()) {
+ if (attr is RegisterAttribute cAttribute) {
+
+ if(!prop.PropertyType.IsAllowedPlcCastingType()) {
+ throw new MewtocolException($"The register attribute property type is not allowed ({prop.PropertyType})");
+ }
var dotnetType = prop.PropertyType;
AddRegister(new RegisterBuildInfo {
+ mewAddress = cAttribute.MewAddress,
memoryAddress = cAttribute.MemoryArea,
specialAddress = cAttribute.SpecialAddress,
memorySizeBytes = cAttribute.ByteLength,
registerType = cAttribute.RegisterType,
- dotnetCastType = dotnetType,
+ dotnetCastType = dotnetType.IsEnum ? dotnetType.UnderlyingSystemType : dotnetType,
collectionType = collection.GetType(),
name = prop.Name,
});
@@ -345,6 +348,9 @@ namespace MewtocolNet {
#region Register Adding
+ ///
+ public void AddRegister(IRegister register) => AddRegister(register as BaseRegister);
+
///
public void AddRegister(BaseRegister register) {
@@ -354,14 +360,14 @@ namespace MewtocolNet {
if (CheckDuplicateNameRegister(register))
throw MewtocolException.DupeNameRegister(register);
+ if (CheckOverlappingRegister(register, out var regB))
+ throw MewtocolException.OverlappingRegister(register, regB);
+
register.attachedInterface = this;
RegistersUnderlying.Add(register);
}
- ///
- public void AddRegister(IRegister register) => AddRegister(register as BaseRegister);
-
internal void AddRegister (RegisterBuildInfo buildInfo) {
var builtRegister = buildInfo.Build();
@@ -379,6 +385,9 @@ namespace MewtocolNet {
if(CheckDuplicateNameRegister(builtRegister))
throw MewtocolException.DupeNameRegister(builtRegister);
+ if (CheckOverlappingRegister(builtRegister, out var regB))
+ throw MewtocolException.OverlappingRegister(builtRegister, regB);
+
builtRegister.attachedInterface = this;
RegistersUnderlying.Add(builtRegister);
@@ -406,6 +415,38 @@ namespace MewtocolNet {
}
+ private bool CheckOverlappingRegister (IRegisterInternal instance, out IRegisterInternal regB) {
+
+ //ignore bool registers, they have their own address spectrum
+ regB = null;
+ if (instance is BoolRegister) return false;
+
+ uint addressFrom = instance.MemoryAddress;
+ uint addressTo = addressFrom + instance.GetRegisterAddressLen();
+
+ var foundOverlapping = RegistersInternal.FirstOrDefault(x => {
+
+ //ignore bool registers, they have their own address spectrum
+ if (x is BoolRegister) return false;
+
+ uint addressF = x.MemoryAddress;
+ uint addressT = addressF + x.GetRegisterAddressLen();
+
+ bool matchingBaseAddress = addressFrom < addressT && addressF < addressTo;
+
+ return matchingBaseAddress;
+
+ });
+
+ if (foundOverlapping != null) {
+ regB = foundOverlapping;
+ return true;
+ }
+
+ return false;
+
+ }
+
#endregion
#region Register accessing
@@ -428,6 +469,18 @@ namespace MewtocolNet {
#region Event Invoking
+ private protected void ClearRegisterVals() {
+
+ for (int i = 0; i < RegistersUnderlying.Count; i++) {
+
+ var reg = (IRegisterInternal)RegistersUnderlying[i];
+ reg.ClearValue();
+
+ }
+
+ }
+
+
internal void PropertyRegisterWasSet(string propName, object value) {
_ = SetRegisterAsync(GetRegister(propName), value);
diff --git a/MewtocolNet/MewtocolInterfaceRequests.cs b/MewtocolNet/MewtocolInterfaceRequests.cs
index 94015f3..6e3f7d7 100644
--- a/MewtocolNet/MewtocolInterfaceRequests.cs
+++ b/MewtocolNet/MewtocolInterfaceRequests.cs
@@ -64,12 +64,8 @@ namespace MewtocolNet {
#region Operation mode changing
- ///
- /// Changes the PLCs operation mode to the given one
- ///
- /// The mode to change to
- /// The success state of the write operation
- public async Task SetOperationMode (bool setRun) {
+ ///
+ public async Task SetOperationModeAsync (bool setRun) {
string modeChar = setRun ? "R" : "P";
@@ -77,7 +73,7 @@ namespace MewtocolNet {
var result = await SendCommandAsync(requeststring);
if (result.Success) {
- Logger.Log($"operation mode was changed to {(setRun ? "Run" : "Prog")}", LogLevel.Info, this);
+ Logger.Log($"Operation mode was changed to {(setRun ? "Run" : "Prog")}", LogLevel.Info, this);
} else {
Logger.Log("Operation mode change failed", LogLevel.Error, this);
}
@@ -116,14 +112,15 @@ namespace MewtocolNet {
}
///
- /// Reads the bytes from the start adress for counts byte length
+ /// Reads the bytes from the start adress for counts byte length,
+ /// doesn't block the receive thread
///
/// Start adress
/// Number of bytes to get
/// Flips bytes from big to mixed endian
/// Gets invoked when the progress changes, contains the progress as a double
/// A byte array or null of there was an error
- public async Task ReadByteRange(int start, int count, bool flipBytes = true, Action onProgress = null) {
+ public async Task ReadByteRangeNonBlocking (int start, int count, bool flipBytes = true, Action onProgress = null) {
var byteList = new List();
@@ -131,12 +128,13 @@ namespace MewtocolNet {
if (count % 2 != 0)
wordLength++;
+ int blockSize = 8;
//read blocks of max 4 words per msg
- for (int i = 0; i < wordLength; i += 8) {
+ for (int i = 0; i < wordLength; i += blockSize) {
int curWordStart = start + i;
- int curWordEnd = curWordStart + 7;
+ int curWordEnd = curWordStart + blockSize - 1;
string startStr = curWordStart.ToString().PadLeft(5, '0');
string endStr = (curWordEnd).ToString().PadLeft(5, '0');
@@ -146,7 +144,7 @@ namespace MewtocolNet {
if (result.Success && !string.IsNullOrEmpty(result.Response)) {
- var bytes = result.Response.ParseDTByteString(8 * 4).HexStringToByteArray();
+ var bytes = result.Response.ParseDTByteString(blockSize * 4).HexStringToByteArray();
if (bytes == null) return null;
@@ -246,38 +244,15 @@ namespace MewtocolNet {
//returns a byte array 1 long and with the byte beeing 0 or 1
if (toWriteType == typeof(BoolRegister)) {
- string requeststring = $"%{GetStationNumber()}#WCS{_toWrite.BuildMewtocolQuery()}{(data[0] == 1 ? "1" : "0")}";
- var result = await SendCommandAsync(requeststring);
- return result.Success;
+ string reqStr = $"%{GetStationNumber()}#WCS{_toWrite.BuildMewtocolQuery()}{(data[0] == 1 ? "1" : "0")}";
+ var res = await SendCommandAsync(reqStr);
+ return res.Success;
}
- //writes a byte array 2 bytes or 4 bytes long depending on the data size
- if (toWriteType.IsGenericType && toWriteType.GetGenericTypeDefinition() == typeof(NumberRegister<>)) {
-
- string requeststring = $"%{GetStationNumber()}#WD{_toWrite.BuildMewtocolQuery()}{data.ToHexString()}";
- var result = await SendCommandAsync(requeststring);
- return result.Success;
-
- }
-
- //returns a byte array with variable size
- if (toWriteType == typeof(BytesRegister)) {
-
- throw new NotImplementedException("Not imp");
-
- }
-
- //writes to the string area
- if (toWriteType == typeof(StringRegister)) {
-
- string requeststring = $"%{GetStationNumber()}#WD{_toWrite.BuildMewtocolQuery()}{data.ToHexString()}";
- var result = await SendCommandAsync(requeststring);
- return result.Success;
-
- }
-
- return false;
+ string requeststring = $"%{GetStationNumber()}#WD{_toWrite.BuildMewtocolQuery()}{data.ToHexString()}";
+ var result = await SendCommandAsync(requeststring);
+ return result.Success;
}
diff --git a/MewtocolNet/RegisterAttributes/RegisterAttribute.cs b/MewtocolNet/RegisterAttributes/RegisterAttribute.cs
index cd79645..a08b29a 100644
--- a/MewtocolNet/RegisterAttributes/RegisterAttribute.cs
+++ b/MewtocolNet/RegisterAttributes/RegisterAttribute.cs
@@ -1,4 +1,5 @@
-using System;
+using MewtocolNet.RegisterBuilding;
+using System;
namespace MewtocolNet.RegisterAttributes {
@@ -10,31 +11,39 @@ namespace MewtocolNet.RegisterAttributes {
internal RegisterType? RegisterType;
- internal int MemoryArea = 0;
- internal int ByteLength = 2;
+ internal uint MemoryArea = 0;
+ internal uint ByteLength = 2;
internal byte SpecialAddress = 0x0;
internal BitCount BitCount;
internal int AssignedBitIndex = -1;
+ internal string MewAddress = null;
+
+ public RegisterAttribute(string mewAddress) {
+
+ MewAddress = mewAddress;
+
+ }
+
///
/// Attribute for string type or numeric registers
///
/// The area in the plcs memory
- public RegisterAttribute(int memoryArea) {
+ public RegisterAttribute(uint memoryArea) {
MemoryArea = memoryArea;
}
- public RegisterAttribute(int memoryArea, int byteLength) {
+ public RegisterAttribute(uint memoryArea, uint byteLength) {
MemoryArea = memoryArea;
ByteLength = byteLength;
}
- public RegisterAttribute(int memoryArea, BitCount bitCount) {
+ public RegisterAttribute(uint memoryArea, BitCount bitCount) {
MemoryArea = memoryArea;
BitCount = bitCount;
@@ -44,7 +53,7 @@ namespace MewtocolNet.RegisterAttributes {
}
- public RegisterAttribute(int memoryArea, BitCount bitCount, int bitIndex) {
+ public RegisterAttribute(uint memoryArea, BitCount bitCount, int bitIndex) {
MemoryArea = memoryArea;
BitCount = bitCount;
@@ -68,7 +77,7 @@ namespace MewtocolNet.RegisterAttributes {
///
/// Attribute for boolean registers
///
- public RegisterAttribute(IOType type, int memoryArea, byte spAdress = 0x0) {
+ public RegisterAttribute(IOType type, uint memoryArea, byte spAdress = 0x0) {
MemoryArea = memoryArea;
RegisterType = (RegisterType)(int)type;
diff --git a/MewtocolNet/RegisterBuilding/BuilderStep.cs b/MewtocolNet/RegisterBuilding/BuilderStep.cs
new file mode 100644
index 0000000..3c08159
--- /dev/null
+++ b/MewtocolNet/RegisterBuilding/BuilderStep.cs
@@ -0,0 +1,267 @@
+using MewtocolNet.Registers;
+using System;
+using System.Collections;
+using System.Runtime.InteropServices;
+
+namespace MewtocolNet.RegisterBuilding {
+
+ public static class BuilderStepExtensions {
+
+ public static BuilderStep AsType (this BuilderStepBase baseStep) {
+
+ if (!typeof(T).IsAllowedPlcCastingType()) {
+
+ throw new NotSupportedException($"The dotnet type {typeof(T)}, is not supported for PLC type casting");
+
+ }
+
+ var castStp = new BuilderStep();
+
+ if (baseStep.SpecialAddress != null) castStp.SpecialAddress = baseStep.SpecialAddress;
+
+ castStp.Name = baseStep.Name;
+ castStp.RegType = baseStep.RegType;
+ castStp.MemAddress = baseStep.MemAddress;
+ castStp.MemByteSize = baseStep.MemByteSize;
+ castStp.dotnetVarType = typeof(T);
+ castStp.plcVarType = null;
+ castStp.wasCasted = true;
+
+ return castStp;
+
+ }
+
+ public static BuilderStep AsType (this BuilderStepBase baseStep, Type type) {
+
+ if (!type.IsAllowedPlcCastingType()) {
+
+ throw new NotSupportedException($"The dotnet type {type}, is not supported for PLC type casting");
+
+ }
+
+ var castStp = new BuilderStep();
+
+ if (baseStep.SpecialAddress != null) castStp.SpecialAddress = baseStep.SpecialAddress;
+
+ castStp.Name = baseStep.Name;
+ castStp.RegType = baseStep.RegType;
+ castStp.MemAddress = baseStep.MemAddress;
+ castStp.MemByteSize = baseStep.MemByteSize;
+ castStp.dotnetVarType = type;
+ castStp.plcVarType = null;
+ castStp.wasCasted = true;
+
+ return castStp;
+
+ }
+
+ public static IRegister Build (this BuilderStepBase step) {
+
+ //if no casting method in builder was called => autocast the type from the RegisterType
+ if (!step.wasCasted && step.MemByteSize == null) step.AutoType();
+
+ //fallbacks if no casting builder was given
+ BuilderStepBase.GetFallbackDotnetType(step);
+
+ BaseRegister builtReg;
+
+ var bInfo = new RegisterBuildInfo {
+
+ name = step.Name,
+ specialAddress = step.SpecialAddress,
+ memoryAddress = step.MemAddress,
+ memorySizeBytes = step.MemByteSize,
+ memorySizeBits = step.MemBitSize,
+ registerType = step.RegType,
+ dotnetCastType = step.dotnetVarType,
+
+ };
+
+ builtReg = bInfo.Build();
+
+ BuilderStepBase.AddToRegisterList(step, builtReg);
+
+ return builtReg;
+
+ }
+
+ public static IRegister Build(this BuilderStep step) {
+
+ //fallbacks if no casting builder was given
+ BuilderStepBase.GetFallbackDotnetType(step);
+
+ BaseRegister builtReg;
+
+ var bInfo = new RegisterBuildInfo {
+
+ name = step.Name,
+ specialAddress = step.SpecialAddress,
+ memoryAddress = step.MemAddress,
+ memorySizeBytes = step.MemByteSize,
+ memorySizeBits = step.MemBitSize,
+ registerType = step.RegType,
+ dotnetCastType = step.dotnetVarType,
+
+ };
+
+ if (step.dotnetVarType.IsEnum) {
+
+ builtReg = bInfo.Build();
+
+ } else {
+
+ builtReg = bInfo.Build();
+
+ }
+
+ BuilderStepBase.AddToRegisterList(step, builtReg);
+
+ return builtReg;
+
+ }
+
+ }
+
+ public abstract class BuilderStepBase {
+
+ internal MewtocolInterface forInterface;
+
+ internal bool wasCasted = false;
+
+ internal string OriginalInput;
+
+ internal string Name;
+ internal RegisterType RegType;
+
+ internal uint MemAddress;
+
+ internal uint? MemByteSize;
+ internal ushort? MemBitSize;
+ internal byte? SpecialAddress;
+
+ internal PlcVarType? plcVarType;
+ internal Type dotnetVarType;
+
+ internal BuilderStepBase AutoType() {
+
+ switch (RegType) {
+ case RegisterType.X:
+ case RegisterType.Y:
+ case RegisterType.R:
+ dotnetVarType = typeof(bool);
+ break;
+ case RegisterType.DT:
+ dotnetVarType = typeof(short);
+ break;
+ case RegisterType.DDT:
+ dotnetVarType = typeof(int);
+ break;
+ case RegisterType.DT_BYTE_RANGE:
+ dotnetVarType = typeof(string);
+ break;
+ }
+
+ plcVarType = null;
+
+ wasCasted = true;
+
+ return this;
+
+ }
+
+ internal static void GetFallbackDotnetType (BuilderStepBase step) {
+
+ bool isBoolean = step.RegType.IsBoolean();
+ bool isTypeNotDefined = step.plcVarType == null && step.dotnetVarType == null;
+
+ if (isTypeNotDefined && step.RegType == RegisterType.DT) {
+
+ step.dotnetVarType = typeof(short);
+
+ }
+ if (isTypeNotDefined && step.RegType == RegisterType.DDT) {
+
+ step.dotnetVarType = typeof(int);
+
+ } else if (isTypeNotDefined && isBoolean) {
+
+ step.dotnetVarType = typeof(bool);
+
+ } else if (isTypeNotDefined && step.RegType == RegisterType.DT_BYTE_RANGE) {
+
+ step.dotnetVarType = typeof(string);
+
+ }
+
+ if (step.plcVarType != null) {
+
+ step.dotnetVarType = step.plcVarType.Value.GetDefaultDotnetType();
+
+ }
+
+ }
+
+ internal static void AddToRegisterList(BuilderStepBase step, BaseRegister instance) {
+
+ if (step.forInterface == null) return;
+
+ step.forInterface.AddRegister(instance);
+
+ }
+
+ }
+
+ public class BuilderStep : BuilderStepBase { }
+
+ public class BuilderStep : BuilderStepBase {
+
+ public BuilderStep AsPlcType (PlcVarType varType) {
+
+ dotnetVarType = null;
+ plcVarType = varType;
+
+ wasCasted = true;
+
+ return this;
+
+ }
+
+ public BuilderStep AsBytes (uint byteLength) {
+
+ if (RegType != RegisterType.DT) {
+
+ throw new NotSupportedException($"Cant use the {nameof(AsBytes)} converter on a non {nameof(RegisterType.DT)} register");
+
+ }
+
+ MemByteSize = byteLength;
+ dotnetVarType = typeof(byte[]);
+ plcVarType = null;
+
+ wasCasted = true;
+
+ return this;
+
+ }
+
+ public BuilderStep AsBits(ushort bitCount = 16) {
+
+ if (RegType != RegisterType.DT) {
+
+ throw new NotSupportedException($"Cant use the {nameof(AsBits)} converter on a non {nameof(RegisterType.DT)} register");
+
+ }
+
+ MemBitSize = bitCount;
+ dotnetVarType = typeof(BitArray);
+ plcVarType = null;
+
+ wasCasted = true;
+
+ return this;
+
+ }
+
+ }
+
+}
diff --git a/MewtocolNet/RegisterBuilding/FinalizerExtensions.cs b/MewtocolNet/RegisterBuilding/FinalizerExtensions.cs
deleted file mode 100644
index 683232c..0000000
--- a/MewtocolNet/RegisterBuilding/FinalizerExtensions.cs
+++ /dev/null
@@ -1,78 +0,0 @@
-using MewtocolNet.Registers;
-using System;
-using System.Linq;
-using System.Reflection;
-
-namespace MewtocolNet.RegisterBuilding {
-
- public static class FinalizerExtensions {
-
- public static IRegister Build(this RegisterBuilderStep step) {
-
- //if no casting method in builder was called => autocast the type from the RegisterType
- if (!step.wasCasted)
- step.AutoType();
-
- //fallbacks if no casting builder was given
- step.GetFallbackDotnetType();
-
- var builtReg = new RegisterBuildInfo {
-
- name = step.Name,
- specialAddress = step.SpecialAddress,
- memoryAddress = step.MemAddress,
- memorySizeBytes = step.MemByteSize,
- registerType = step.RegType,
- dotnetCastType = step.dotnetVarType,
-
- }.Build();
-
- step.AddToRegisterList(builtReg);
-
- return builtReg;
-
- }
-
- private static void GetFallbackDotnetType(this RegisterBuilderStep step) {
-
- bool isBoolean = step.RegType.IsBoolean();
- bool isTypeNotDefined = step.plcVarType == null && step.dotnetVarType == null;
-
- if (isTypeNotDefined && step.RegType == RegisterType.DT) {
-
- step.dotnetVarType = typeof(short);
-
- }
- if (isTypeNotDefined && step.RegType == RegisterType.DDT) {
-
- step.dotnetVarType = typeof(int);
-
- } else if (isTypeNotDefined && isBoolean) {
-
- step.dotnetVarType = typeof(bool);
-
- } else if (isTypeNotDefined && step.RegType == RegisterType.DT_BYTE_RANGE) {
-
- step.dotnetVarType = typeof(string);
-
- }
-
- if (step.plcVarType != null) {
-
- step.dotnetVarType = step.plcVarType.Value.GetDefaultDotnetType();
-
- }
-
- }
-
- private static void AddToRegisterList(this RegisterBuilderStep step, BaseRegister instance) {
-
- if (step.forInterface == null) return;
-
- step.forInterface.AddRegister(instance);
-
- }
-
- }
-
-}
diff --git a/MewtocolNet/RegisterBuilding/ParseResult.cs b/MewtocolNet/RegisterBuilding/ParseResult.cs
index b851848..909d9af 100644
--- a/MewtocolNet/RegisterBuilding/ParseResult.cs
+++ b/MewtocolNet/RegisterBuilding/ParseResult.cs
@@ -6,7 +6,7 @@
public string hardFailReason;
- public RegisterBuilderStep stepData;
+ public BuilderStep stepData;
}
diff --git a/MewtocolNet/RegisterBuilding/RegBuilder.cs b/MewtocolNet/RegisterBuilding/RegBuilder.cs
index 5e54978..580a7ae 100644
--- a/MewtocolNet/RegisterBuilding/RegBuilder.cs
+++ b/MewtocolNet/RegisterBuilding/RegBuilder.cs
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Data.Common;
+using System.Diagnostics;
using System.Globalization;
using System.Text.RegularExpressions;
@@ -18,6 +19,7 @@ namespace MewtocolNet.RegisterBuilding {
(x) => TryBuildBoolean(x),
(x) => TryBuildNumericBased(x),
+ (x) => TryBuildByteRangeBased(x),
};
@@ -32,7 +34,7 @@ namespace MewtocolNet.RegisterBuilding {
public static RegBuilder Factory { get; private set; } = new RegBuilder();
- public RegisterBuilderStep FromPlcRegName (string plcAddrName, string name = null) {
+ public BuilderStep FromPlcRegName (string plcAddrName, string name = null) {
foreach (var method in parseMethods) {
@@ -45,6 +47,7 @@ namespace MewtocolNet.RegisterBuilding {
res.stepData.OriginalInput = plcAddrName;
res.stepData.forInterface = forInterface;
+
return res.stepData;
} else if(res.state == ParseResultState.FailedHard) {
@@ -77,7 +80,7 @@ namespace MewtocolNet.RegisterBuilding {
string special = match.Groups["special"].Value;
IOType regType;
- int areaAdd = 0;
+ uint areaAdd = 0;
byte specialAdd = 0x0;
//try cast the prefix
@@ -90,7 +93,7 @@ namespace MewtocolNet.RegisterBuilding {
}
- if(!string.IsNullOrEmpty(area) && !int.TryParse(area, out areaAdd) ) {
+ if(!string.IsNullOrEmpty(area) && !uint.TryParse(area, out areaAdd) ) {
return new ParseResult {
state = ParseResultState.FailedHard,
@@ -102,7 +105,7 @@ namespace MewtocolNet.RegisterBuilding {
//special address not given
if(string.IsNullOrEmpty(special) && !string.IsNullOrEmpty(area)) {
- var isAreaInt = int.TryParse(area, NumberStyles.Number, CultureInfo.InvariantCulture, out var areaInt);
+ var isAreaInt = uint.TryParse(area, NumberStyles.Number, CultureInfo.InvariantCulture, out var areaInt);
if (isAreaInt && areaInt >= 0 && areaInt <= 9) {
@@ -142,7 +145,11 @@ namespace MewtocolNet.RegisterBuilding {
return new ParseResult {
state = ParseResultState.Success,
- stepData = new RegisterBuilderStep ((RegisterType)(int)regType, areaAdd, specialAdd),
+ stepData = new BuilderStep {
+ RegType = (RegisterType)(int)regType,
+ MemAddress = areaAdd,
+ SpecialAddress = specialAdd,
+ }
};
}
@@ -150,7 +157,7 @@ namespace MewtocolNet.RegisterBuilding {
// one to two word registers
private static ParseResult TryBuildNumericBased (string plcAddrName) {
- var patternByte = new Regex(@"(?DT|DDT)(?[0-9]{1,5})");
+ var patternByte = new Regex(@"^(?DT|DDT)(?[0-9]{1,5})$");
var match = patternByte.Match(plcAddrName);
@@ -159,12 +166,11 @@ namespace MewtocolNet.RegisterBuilding {
state = ParseResultState.FailedSoft
};
-
string prefix = match.Groups["prefix"].Value;
string area = match.Groups["area"].Value;
RegisterType regType;
- int areaAdd = 0;
+ uint areaAdd = 0;
//try cast the prefix
if (!Enum.TryParse(prefix, out regType)) {
@@ -176,7 +182,7 @@ namespace MewtocolNet.RegisterBuilding {
}
- if (!string.IsNullOrEmpty(area) && !int.TryParse(area, out areaAdd)) {
+ if (!string.IsNullOrEmpty(area) && !uint.TryParse(area, out areaAdd)) {
return new ParseResult {
state = ParseResultState.FailedHard,
@@ -187,7 +193,76 @@ namespace MewtocolNet.RegisterBuilding {
return new ParseResult {
state = ParseResultState.Success,
- stepData = new RegisterBuilderStep(regType, areaAdd),
+ stepData = new BuilderStep {
+ RegType = regType,
+ MemAddress = areaAdd,
+ },
+ };
+
+ }
+
+ // one to two word registers
+ private static ParseResult TryBuildByteRangeBased (string plcAddrName) {
+
+ var split = plcAddrName.Split('-');
+
+ if(split.Length > 2)
+ return new ParseResult {
+ state = ParseResultState.FailedHard,
+ hardFailReason = $"Cannot parse '{plcAddrName}', to many delimters '-'"
+ };
+
+ uint[] addresses = new uint[2];
+
+ for (int i = 0; i < split.Length; i++) {
+
+ string addr = split[i];
+ var patternByte = new Regex(@"(?DT|DDT)(?[0-9]{1,5})");
+
+ var match = patternByte.Match(addr);
+
+ if (!match.Success)
+ return new ParseResult {
+ state = ParseResultState.FailedSoft
+ };
+
+ string prefix = match.Groups["prefix"].Value;
+ string area = match.Groups["area"].Value;
+
+ RegisterType regType;
+ uint areaAdd = 0;
+
+ //try cast the prefix
+ if (!Enum.TryParse(prefix, out regType) || regType != RegisterType.DT) {
+
+ return new ParseResult {
+ state = ParseResultState.FailedHard,
+ hardFailReason = $"Cannot parse '{plcAddrName}', the prefix is not allowed for word range registers"
+ };
+
+ }
+
+ if (!string.IsNullOrEmpty(area) && !uint.TryParse(area, out areaAdd)) {
+
+ return new ParseResult {
+ state = ParseResultState.FailedHard,
+ hardFailReason = $"Cannot parse '{plcAddrName}', the area address: '{area}' is wrong"
+ };
+
+ }
+
+ addresses[i] = areaAdd;
+
+ }
+
+ return new ParseResult {
+ state = ParseResultState.Success,
+ stepData = new BuilderStep {
+ RegType = RegisterType.DT_BYTE_RANGE,
+ dotnetVarType = typeof(byte[]),
+ MemAddress = addresses[0],
+ MemByteSize = (addresses[1] - addresses[0] + 1) * 2,
+ }
};
}
diff --git a/MewtocolNet/RegisterBuilding/RegisterBuildInfo.cs b/MewtocolNet/RegisterBuilding/RegisterBuildInfo.cs
index 7e88f4a..e6b8de3 100644
--- a/MewtocolNet/RegisterBuilding/RegisterBuildInfo.cs
+++ b/MewtocolNet/RegisterBuilding/RegisterBuildInfo.cs
@@ -1,15 +1,22 @@
-using MewtocolNet.Registers;
+using MewtocolNet.Exceptions;
+using MewtocolNet.Registers;
using System;
using System.Collections;
+using System.Data.Common;
using System.Reflection;
+using System.Runtime.InteropServices;
namespace MewtocolNet.RegisterBuilding {
internal struct RegisterBuildInfo {
+ internal string mewAddress;
+
internal string name;
- internal int memoryAddress;
- internal int memorySizeBytes;
+ internal uint memoryAddress;
+
+ internal uint? memorySizeBytes;
+ internal ushort? memorySizeBits;
internal byte? specialAddress;
internal RegisterType? registerType;
@@ -18,10 +25,37 @@ namespace MewtocolNet.RegisterBuilding {
internal BaseRegister Build () {
+ //Has mew address use this before the default checks
+ if (mewAddress != null) return BuildFromMewAddress();
+
+ //parse enums
+ if (dotnetCastType.IsEnum) {
+
+ //-------------------------------------------
+ //as numeric register with enum target
+
+ var underlying = Enum.GetUnderlyingType(dotnetCastType);
+ var enuSize = Marshal.SizeOf(underlying);
+
+ if (enuSize > 4)
+ throw new NotSupportedException("Enums not based on 16 or 32 bit numbers are not supported");
+
+ Type myParameterizedSomeClass = typeof(NumberRegister<>).MakeGenericType(dotnetCastType);
+ ConstructorInfo constr = myParameterizedSomeClass.GetConstructor(new Type[] { typeof(uint), typeof(string) });
+
+ var parameters = new object[] { memoryAddress, name };
+ var instance = (BaseRegister)constr.Invoke(parameters);
+
+ if (collectionType != null)
+ instance.WithCollectionType(collectionType);
+
+ return instance;
+
+ }
+
+ //parse all others where the type is known
RegisterType regType = registerType ?? dotnetCastType.ToRegisterTypeDefault();
-
Type registerClassType = dotnetCastType.GetDefaultRegisterHoldingType();
-
bool isBytesRegister = !registerClassType.IsGenericType && registerClassType == typeof(BytesRegister);
bool isStringRegister = !registerClassType.IsGenericType && registerClassType == typeof(StringRegister);
@@ -30,7 +64,7 @@ namespace MewtocolNet.RegisterBuilding {
//-------------------------------------------
//as numeric register with boolean bit target
//create a new bregister instance
- var instance = new BytesRegister(memoryAddress, memorySizeBytes, name);
+ var instance = new BytesRegister(memoryAddress, memorySizeBytes.Value, name);
if (collectionType != null)
instance.WithCollectionType(collectionType);
@@ -42,13 +76,11 @@ namespace MewtocolNet.RegisterBuilding {
//-------------------------------------------
//as numeric register
- var areaAddr = memoryAddress;
-
//create a new bregister instance
var flags = BindingFlags.Public | BindingFlags.Instance;
//int _adress, Type _enumType = null, string _name = null
- var parameters = new object[] { areaAddr, null, name };
+ var parameters = new object[] { memoryAddress, name };
var instance = (BaseRegister)Activator.CreateInstance(registerClassType, flags, null, parameters, null);
if(collectionType != null)
@@ -62,7 +94,14 @@ namespace MewtocolNet.RegisterBuilding {
//-------------------------------------------
//as byte range register
- var instance = new BytesRegister(memoryAddress, memorySizeBytes, name);
+
+ BytesRegister instance;
+
+ if(memorySizeBits != null) {
+ instance = new BytesRegister(memoryAddress, memorySizeBits.Value, name);
+ } else {
+ instance = new BytesRegister(memoryAddress, memorySizeBytes.Value, name);
+ }
if (collectionType != null)
instance.WithCollectionType(collectionType);
@@ -106,6 +145,12 @@ namespace MewtocolNet.RegisterBuilding {
}
+ private BaseRegister BuildFromMewAddress () {
+
+ return (BaseRegister)RegBuilder.Factory.FromPlcRegName(mewAddress, name).AsType(dotnetCastType).Build();
+
+ }
+
}
}
diff --git a/MewtocolNet/RegisterBuilding/RegisterBuilderStep.cs b/MewtocolNet/RegisterBuilding/RegisterBuilderStep.cs
deleted file mode 100644
index c334a72..0000000
--- a/MewtocolNet/RegisterBuilding/RegisterBuilderStep.cs
+++ /dev/null
@@ -1,114 +0,0 @@
-using System;
-
-namespace MewtocolNet.RegisterBuilding {
-
- public class RegisterBuilderStep {
-
- internal MewtocolInterface forInterface;
-
- internal bool wasCasted = false;
-
- internal string OriginalInput;
-
- internal string Name;
- internal RegisterType RegType;
- internal int MemAddress;
- internal int MemByteSize;
- internal byte? SpecialAddress;
-
- internal PlcVarType? plcVarType;
- internal Type dotnetVarType;
-
- public RegisterBuilderStep() => throw new NotSupportedException("Cant make a new instance of RegisterBuilderStep, use the builder pattern");
-
- internal RegisterBuilderStep(RegisterType regType, int memAddr) {
-
- RegType = regType;
- MemAddress = memAddr;
-
- }
-
- internal RegisterBuilderStep(RegisterType regType, int memAddr, byte specialAddr) {
-
- RegType = regType;
- MemAddress = memAddr;
- SpecialAddress = specialAddr;
-
- }
-
- public RegisterBuilderStep AsPlcType(PlcVarType varType) {
-
- dotnetVarType = null;
- plcVarType = varType;
-
- wasCasted = true;
-
- return this;
-
- }
-
- public RegisterBuilderStep AsType() {
-
- if (!typeof(T).IsAllowedPlcCastingType()) {
-
- throw new NotSupportedException($"The dotnet type {typeof(T)}, is not supported for PLC type casting");
-
- }
-
- dotnetVarType = typeof(T);
- plcVarType = null;
-
- wasCasted = true;
-
- return this;
-
- }
-
- public RegisterBuilderStep AsBytes (int byteLength) {
-
- if (RegType != RegisterType.DT) {
-
- throw new NotSupportedException($"Cant use the AsByte converter on a non DT register");
-
- }
-
- MemByteSize = byteLength;
- dotnetVarType = typeof(byte[]);
- plcVarType = null;
-
- wasCasted = true;
-
- return this;
-
- }
-
- internal RegisterBuilderStep AutoType() {
-
- switch (RegType) {
- case RegisterType.X:
- case RegisterType.Y:
- case RegisterType.R:
- dotnetVarType = typeof(bool);
- break;
- case RegisterType.DT:
- dotnetVarType = typeof(short);
- break;
- case RegisterType.DDT:
- dotnetVarType = typeof(int);
- break;
- case RegisterType.DT_BYTE_RANGE:
- dotnetVarType = typeof(string);
- break;
- }
-
- plcVarType = null;
-
- wasCasted = true;
-
- return this;
-
- }
-
- }
-
-}
diff --git a/MewtocolNet/Registers/BaseRegister.cs b/MewtocolNet/Registers/BaseRegister.cs
index 5a74bad..ac3f8d5 100644
--- a/MewtocolNet/Registers/BaseRegister.cs
+++ b/MewtocolNet/Registers/BaseRegister.cs
@@ -13,10 +13,10 @@ namespace MewtocolNet.Registers {
public event Action
public class BytesRegister : BaseRegister {
- internal int addressLength;
+ internal uint addressLength;
///
/// The rgisters memory length
///
- public int AddressLength => addressLength;
+ public uint AddressLength => addressLength;
- internal short ReservedSize { get; set; }
+ internal uint ReservedBytesSize { get; private set; }
+
+ internal ushort? ReservedBitSize { get; private set; }
///
- /// Defines a register containing a string
+ /// Defines a register containing bytes
///
- public BytesRegister(int _address, int _reservedByteSize, string _name = null) {
+ public BytesRegister(uint _address, uint _reservedByteSize, string _name = null) {
- if (_address > 99999) throw new NotSupportedException("Memory adresses cant be greater than 99999");
name = _name;
memoryAddress = _address;
- ReservedSize = (short)_reservedByteSize;
+ ReservedBytesSize = _reservedByteSize;
//calc mem length
//because one register is always 1 word (2 bytes) long, if the bytecount is uneven we get the trailing word too
- var byteSize = _reservedByteSize;
- if (_reservedByteSize % 2 != 0) byteSize++;
+ var byteSize = ReservedBytesSize;
+ if (ReservedBytesSize % 2 != 0) byteSize++;
RegisterType = RegisterType.DT_BYTE_RANGE;
- addressLength = (byteSize / 2) - 1;
+ addressLength = Math.Max((byteSize / 2), 1);
+
+ CheckAddressOverflow(memoryAddress, addressLength);
+
+ lastValue = null;
}
- public override string GetValueString() => Value == null ? "null" : ((byte[])Value).ToHexString("-");
+ public BytesRegister(uint _address, ushort _reservedBitSize, string _name = null) {
+
+ name = _name;
+ memoryAddress = _address;
+ ReservedBytesSize = (uint)Math.Max(1, _reservedBitSize / 8);
+ ReservedBitSize = _reservedBitSize;
+
+ //calc mem length
+ //because one register is always 1 word (2 bytes) long, if the bytecount is uneven we get the trailing word too
+ var byteSize = ReservedBytesSize;
+ if (ReservedBytesSize % 2 != 0) byteSize++;
+
+ RegisterType = RegisterType.DT_BYTE_RANGE;
+ addressLength = Math.Max((byteSize / 2), 1);
+
+ CheckAddressOverflow(memoryAddress, addressLength);
+
+ lastValue = null;
+
+ }
+
+ public override string GetValueString() {
+
+ if (Value == null) return "null";
+
+ if(Value != null && Value is BitArray bitArr) {
+
+ return bitArr.ToBitString();
+
+ } else {
+
+ return ((byte[])Value).ToHexString("-");
+
+ }
+
+ }
///
public override string BuildMewtocolQuery() {
@@ -48,7 +89,7 @@ namespace MewtocolNet.Registers {
StringBuilder asciistring = new StringBuilder("D");
asciistring.Append(MemoryAddress.ToString().PadLeft(5, '0'));
- asciistring.Append((MemoryAddress + AddressLength).ToString().PadLeft(5, '0'));
+ asciistring.Append((MemoryAddress + AddressLength - 1).ToString().PadLeft(5, '0'));
return asciistring.ToString();
}
@@ -56,10 +97,20 @@ namespace MewtocolNet.Registers {
///
public override void SetValueFromPLC (object val) {
- lastValue = (byte[])val;
+ bool changeTriggerBitArr = val is BitArray bitArr &&
+ lastValue is BitArray bitArr2 &&
+ (bitArr.ToBitString() != bitArr2.ToBitString());
- TriggerChangedEvnt(this);
- TriggerNotifyChange();
+ bool changeTriggerGeneral = (lastValue?.ToString() != val?.ToString());
+
+ if (changeTriggerBitArr || changeTriggerGeneral) {
+
+ lastValue = val;
+
+ TriggerNotifyChange();
+ attachedInterface.InvokeRegisterChanged(this);
+
+ }
}
@@ -69,6 +120,9 @@ namespace MewtocolNet.Registers {
///
public override void ClearValue() => SetValueFromPLC(null);
+ ///
+ public override uint GetRegisterAddressLen() => AddressLength;
+
///
public override async Task ReadAsync() {
@@ -77,7 +131,13 @@ namespace MewtocolNet.Registers {
var read = await attachedInterface.ReadRawRegisterAsync(this);
if (read == null) return null;
- var parsed = PlcValueParser.Parse(this, read);
+ object parsed;
+
+ if(ReservedBitSize != null) {
+ parsed = PlcValueParser.Parse(this, read);
+ } else {
+ parsed = PlcValueParser.Parse(this, read);
+ }
SetValueFromPLC(parsed);
return parsed;
@@ -89,8 +149,17 @@ namespace MewtocolNet.Registers {
if (!attachedInterface.IsConnected) return false;
- var res = await attachedInterface.WriteRawRegisterAsync(this, (byte[])data);
+ byte[] encoded;
+
+ if (ReservedBitSize != null) {
+ encoded = PlcValueParser.Encode(this, (BitArray)data);
+ } else {
+ encoded = PlcValueParser.Encode(this, (byte[])data);
+ }
+
+ var res = await attachedInterface.WriteRawRegisterAsync(this, encoded);
if (res) SetValueFromPLC(data);
+
return res;
}
diff --git a/MewtocolNet/Registers/Interfaces/IRegister.cs b/MewtocolNet/Registers/Interfaces/IRegister.cs
index 18aa8d8..c75937b 100644
--- a/MewtocolNet/Registers/Interfaces/IRegister.cs
+++ b/MewtocolNet/Registers/Interfaces/IRegister.cs
@@ -1,4 +1,5 @@
-using System;
+using MewtocolNet.Registers;
+using System;
using System.Text;
using System.Threading.Tasks;
@@ -37,7 +38,7 @@ namespace MewtocolNet {
///
/// The plc memory address of the register
///
- int MemoryAddress { get; }
+ uint MemoryAddress { get; }
///
/// Gets the value of the register as the plc representation string
@@ -67,7 +68,6 @@ namespace MewtocolNet {
/// True if successfully set
Task WriteAsync(object data);
-
}
}
diff --git a/MewtocolNet/Registers/Interfaces/IRegisterInternal.cs b/MewtocolNet/Registers/Interfaces/IRegisterInternal.cs
index e5b7a3a..01b24d3 100644
--- a/MewtocolNet/Registers/Interfaces/IRegisterInternal.cs
+++ b/MewtocolNet/Registers/Interfaces/IRegisterInternal.cs
@@ -17,7 +17,7 @@ namespace MewtocolNet {
object Value { get; }
- int MemoryAddress { get; }
+ uint MemoryAddress { get; }
// setters
@@ -37,7 +37,7 @@ namespace MewtocolNet {
string GetContainerName();
- string GetRegisterPLCName();
+ string GetMewName();
byte? GetSpecialAddress();
@@ -47,6 +47,9 @@ namespace MewtocolNet {
string BuildMewtocolQuery();
+ uint GetRegisterAddressLen();
+
+ string GetRegisterWordRangeString();
//others
diff --git a/MewtocolNet/Registers/NumberRegister.cs b/MewtocolNet/Registers/NumberRegister.cs
index 2f8a4ab..6d1d433 100644
--- a/MewtocolNet/Registers/NumberRegister.cs
+++ b/MewtocolNet/Registers/NumberRegister.cs
@@ -14,66 +14,63 @@ namespace MewtocolNet.Registers {
/// The type of the numeric value
public class NumberRegister : BaseRegister {
- internal Type enumType { get; set; }
-
///
/// Defines a register containing a number
///
/// Memory start adress max 99999
/// Name of the register
- public NumberRegister (int _address, string _name = null) {
-
- if (_address > 99999) throw new NotSupportedException("Memory adresses cant be greater than 99999");
+ public NumberRegister (uint _address, string _name = null) {
memoryAddress = _address;
name = _name;
Type numType = typeof(T);
+ uint areaLen = 0;
- var allowedTypes = PlcValueParser.GetAllowDotnetTypes();
- if (!allowedTypes.Contains(numType))
- throw new NotSupportedException($"The type {numType} is not allowed for Number Registers");
+ if (typeof(T).IsEnum) {
- var areaLen = (Marshal.SizeOf(numType) / 2) - 1;
- RegisterType = areaLen >= 1 ? RegisterType.DDT : RegisterType.DT;
+ //for enums
- lastValue = default(T);
+ var underlyingType = typeof(T).GetEnumUnderlyingType(); //the numeric type
+ areaLen = (uint)(Marshal.SizeOf(underlyingType) / 2) - 1;
- }
+ if (areaLen == 0) RegisterType = RegisterType.DT;
+ if (areaLen == 1) RegisterType = RegisterType.DDT;
+ if (areaLen >= 2) RegisterType = RegisterType.DT_BYTE_RANGE;
- ///
- /// Defines a register containing a number
- ///
- /// Memory start adress max 99999
- /// Enum type to parse as
- /// Name of the register
- public NumberRegister(int _address, Type _enumType, string _name = null) {
+ lastValue = null;
+ Console.WriteLine();
- if (_address > 99999) throw new NotSupportedException("Memory adresses cant be greater than 99999");
+ } else {
- memoryAddress = _address;
- name = _name;
+ //for all others known pre-defined numeric structs
- Type numType = typeof(T);
+ var allowedTypes = PlcValueParser.GetAllowDotnetTypes();
+ if (!allowedTypes.Contains(numType))
+ throw new NotSupportedException($"The type {numType} is not allowed for Number Registers");
- var allowedTypes = PlcValueParser.GetAllowDotnetTypes();
- if (!allowedTypes.Contains(numType))
- throw new NotSupportedException($"The type {numType} is not allowed for Number Registers");
+ areaLen = (uint)(Marshal.SizeOf(numType) / 2) - 1;
+ RegisterType = areaLen >= 1 ? RegisterType.DDT : RegisterType.DT;
- var areaLen = (Marshal.SizeOf(numType) / 2) - 1;
- RegisterType = areaLen >= 1 ? RegisterType.DDT : RegisterType.DT;
+ lastValue = null;
- enumType = _enumType;
- lastValue = default(T);
+ }
+
+ CheckAddressOverflow(memoryAddress, areaLen);
}
///
public override void SetValueFromPLC(object val) {
- lastValue = (T)val;
- TriggerChangedEvnt(this);
- TriggerNotifyChange();
+ if (lastValue?.ToString() != val?.ToString()) {
+
+ lastValue = (T)val;
+
+ TriggerNotifyChange();
+ attachedInterface.InvokeRegisterChanged(this);
+
+ }
}
@@ -93,71 +90,42 @@ namespace MewtocolNet.Registers {
}
///
- public override string GetAsPLC() => ((TimeSpan)Value).AsPLCTime();
+ public override string GetAsPLC() {
- ///
- public override string GetValueString() {
-
- if(typeof(T) == typeof(TimeSpan)) {
-
- return $"{Value} [{((TimeSpan)Value).AsPLCTime()}]";
-
- }
-
- //is number or bitwise
- if (enumType == null) {
-
- return $"{Value}";
-
- }
-
- //is enum
- var dict = new Dictionary();
-
- foreach (var name in Enum.GetNames(enumType)) {
-
- int enumKey = (int)Enum.Parse(enumType, name);
- if (!dict.ContainsKey(enumKey)) {
- dict.Add(enumKey, name);
- }
-
- }
-
- if (enumType != null && Value is short shortVal) {
-
- if (dict.ContainsKey(shortVal)) {
-
- return $"{Value} ({dict[shortVal]})";
-
- } else {
-
- return $"{Value} (Missing Enum)";
-
- }
-
- }
-
- if (enumType != null && Value is int intVal) {
-
- if (dict.ContainsKey(intVal)) {
-
- return $"{Value} ({dict[intVal]})";
-
- } else {
-
- return $"{Value} (Missing Enum)";
-
- }
-
- }
+ if (typeof(T) == typeof(TimeSpan)) return ((TimeSpan)Value).ToPlcTime();
return Value.ToString();
}
+ ///
+ public override string GetValueString() {
+
+ if(Value != null && typeof(T) == typeof(TimeSpan)) {
+
+ return $"{Value} [{((TimeSpan)Value).ToPlcTime()}]";
+
+ }
+
+ if (Value != null && typeof(T).IsEnum) {
+
+ var underlying = Enum.GetUnderlyingType(typeof(T));
+ object val = Convert.ChangeType(Value, underlying);
+
+ return $"{Value} [{val}]";
+
+ }
+
+ return Value?.ToString() ?? "null";
+
+ }
+
///
public override void ClearValue() => SetValueFromPLC(default(T));
+ ///
+ public override uint GetRegisterAddressLen() => (uint)(RegisterType == RegisterType.DT ? 1 : 2);
+
///
public override async Task ReadAsync() {
diff --git a/MewtocolNet/Registers/StringRegister.cs b/MewtocolNet/Registers/StringRegister.cs
index 9147049..25aea63 100644
--- a/MewtocolNet/Registers/StringRegister.cs
+++ b/MewtocolNet/Registers/StringRegister.cs
@@ -1,6 +1,9 @@
-using System;
+using MewtocolNet.Exceptions;
+using MewtocolNet.Logging;
+using System;
using System.Collections.Generic;
using System.ComponentModel;
+using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;
@@ -16,20 +19,23 @@ namespace MewtocolNet.Registers {
internal short UsedSize { get; set; }
- internal int WordsSize { get; set; }
+ internal uint WordsSize { get; set; }
- private bool isCalibrated = false;
+ private bool isCalibratedFromPlc = false;
///
/// Defines a register containing a string
///
- public StringRegister (int _address, string _name = null) {
+ public StringRegister (uint _address, string _name = null) {
- if (_address > 99999) throw new NotSupportedException("Memory adresses cant be greater than 99999");
name = _name;
memoryAddress = _address;
RegisterType = RegisterType.DT_BYTE_RANGE;
+ CheckAddressOverflow(memoryAddress, 0);
+
+ lastValue = null;
+
}
///
@@ -38,7 +44,7 @@ namespace MewtocolNet.Registers {
StringBuilder asciistring = new StringBuilder("D");
asciistring.Append(MemoryAddress.ToString().PadLeft(5, '0'));
- asciistring.Append((MemoryAddress + WordsSize - 1).ToString().PadLeft(5, '0'));
+ asciistring.Append((MemoryAddress + Math.Max(1, WordsSize) - 1).ToString().PadLeft(5, '0'));
return asciistring.ToString();
}
@@ -49,10 +55,14 @@ namespace MewtocolNet.Registers {
///
public override void SetValueFromPLC (object val) {
- lastValue = (string)val;
+ if (!val.Equals(lastValue)) {
- TriggerChangedEvnt(this);
- TriggerNotifyChange();
+ lastValue = (string)val;
+
+ TriggerNotifyChange();
+ attachedInterface.InvokeRegisterChanged(this);
+
+ }
}
@@ -62,6 +72,9 @@ namespace MewtocolNet.Registers {
///
public override void ClearValue() => SetValueFromPLC("");
+ ///
+ public override uint GetRegisterAddressLen() => Math.Max(1, WordsSize);
+
///
public override async Task ReadAsync() {
@@ -69,25 +82,39 @@ namespace MewtocolNet.Registers {
//get the string params first
- if(!isCalibrated) await Calibrate();
+ if(!isCalibratedFromPlc) await CalibrateFromPLC();
var read = await attachedInterface.ReadRawRegisterAsync(this);
if (read == null) return null;
- return PlcValueParser.Parse(this, read);
+ var parsed = PlcValueParser.Parse(this, read);
+
+ SetValueFromPLC(parsed);
+
+ return parsed;
}
- private async Task Calibrate () {
+ private async Task CalibrateFromPLC () {
+
+ Logger.Log($"Calibrating string ({PLCAddressName}) from PLC source", LogLevel.Verbose, attachedInterface);
//get the string describer bytes
- var bytes = await attachedInterface.ReadByteRange(MemoryAddress, 4, false);
+ var bytes = await attachedInterface.ReadByteRangeNonBlocking((int)MemoryAddress, 4, false);
+
+ if (bytes == null || bytes.Length == 0 || bytes.All(x => x == 0x0)) {
+
+ throw new MewtocolException($"The string register ({PLCAddressName}) doesn't exist in the PLC program");
+
+ }
ReservedSize = BitConverter.ToInt16(bytes, 0);
UsedSize = BitConverter.ToInt16(bytes, 2);
- WordsSize = 2 + (ReservedSize + 1) / 2;
+ WordsSize = Math.Max(0, (uint)(2 + (ReservedSize + 1) / 2));
- isCalibrated = true;
+ CheckAddressOverflow(memoryAddress, WordsSize);
+
+ isCalibratedFromPlc = true;
}
@@ -96,10 +123,18 @@ namespace MewtocolNet.Registers {
if (!attachedInterface.IsConnected) return false;
+ if (!isCalibratedFromPlc) {
+
+ //try to calibrate from plc
+ await CalibrateFromPLC();
+
+ }
+
var res = await attachedInterface.WriteRawRegisterAsync(this, PlcValueParser.Encode(this, (string)data));
+
if (res) {
- UsedSize = (short)((string)Value).Length;
SetValueFromPLC(data);
+ UsedSize = (short)((string)Value).Length;
}
return res;
diff --git a/MewtocolNet/TypeConversion/Conversions.cs b/MewtocolNet/TypeConversion/Conversions.cs
index 53d62e4..ef513b8 100644
--- a/MewtocolNet/TypeConversion/Conversions.cs
+++ b/MewtocolNet/TypeConversion/Conversions.cs
@@ -26,10 +26,11 @@ namespace MewtocolNet.TypeConversion {
};
///
- /// All conversions for reading dataf from and to the plc
+ /// All conversions for reading data from and to the plc, excluding Enum types
///
internal static List items = new List {
+ //default bool R conversion
new PlcTypeConversion(RegisterType.R) {
HoldingRegisterType = typeof(BoolRegister),
PlcVarType = PlcVarType.BOOL,
@@ -43,6 +44,7 @@ namespace MewtocolNet.TypeConversion {
},
},
+ //default bool X conversion
new PlcTypeConversion(RegisterType.X) {
HoldingRegisterType = typeof(BoolRegister),
PlcVarType = PlcVarType.BOOL,
@@ -56,6 +58,7 @@ namespace MewtocolNet.TypeConversion {
},
},
+ //default bool Y conversion
new PlcTypeConversion(RegisterType.Y) {
HoldingRegisterType = typeof(BoolRegister),
PlcVarType = PlcVarType.BOOL,
@@ -69,6 +72,7 @@ namespace MewtocolNet.TypeConversion {
},
},
+ //default short DT conversion
new PlcTypeConversion(RegisterType.DT) {
HoldingRegisterType = typeof(NumberRegister),
PlcVarType = PlcVarType.INT,
@@ -82,6 +86,7 @@ namespace MewtocolNet.TypeConversion {
},
},
+ //default ushort DT conversion
new PlcTypeConversion(RegisterType.DT) {
HoldingRegisterType = typeof(NumberRegister),
PlcVarType = PlcVarType.UINT,
@@ -95,6 +100,7 @@ namespace MewtocolNet.TypeConversion {
},
},
+ //default int DDT conversion
new PlcTypeConversion(RegisterType.DDT) {
HoldingRegisterType = typeof(NumberRegister),
PlcVarType = PlcVarType.DINT,
@@ -108,6 +114,7 @@ namespace MewtocolNet.TypeConversion {
},
},
+ //default uint DDT conversion
new PlcTypeConversion(RegisterType.DDT) {
HoldingRegisterType = typeof(NumberRegister),
PlcVarType = PlcVarType.UDINT,
@@ -121,6 +128,7 @@ namespace MewtocolNet.TypeConversion {
},
},
+ //default float DDT conversion
new PlcTypeConversion(RegisterType.DDT) {
HoldingRegisterType = typeof(NumberRegister),
PlcVarType = PlcVarType.REAL,
@@ -139,6 +147,7 @@ namespace MewtocolNet.TypeConversion {
},
},
+ //default TimeSpan DDT conversion
new PlcTypeConversion(RegisterType.DDT) {
HoldingRegisterType = typeof(NumberRegister),
PlcVarType = PlcVarType.TIME,
@@ -157,11 +166,13 @@ namespace MewtocolNet.TypeConversion {
},
},
- new PlcTypeConversion(RegisterType.DT) {
+ //default byte array DT Range conversion
+ new PlcTypeConversion(RegisterType.DT_BYTE_RANGE) {
HoldingRegisterType = typeof(BytesRegister),
FromRaw = (reg, bytes) => bytes,
ToRaw = (reg, value) => value,
},
+ //default string DT Range conversion
new PlcTypeConversion(RegisterType.DT_BYTE_RANGE) {
HoldingRegisterType = typeof(StringRegister),
PlcVarType = PlcVarType.STRING,
@@ -195,12 +206,16 @@ namespace MewtocolNet.TypeConversion {
},
},
- new PlcTypeConversion(RegisterType.DT) {
+ //default bitn array DT conversion
+ new PlcTypeConversion(RegisterType.DT_BYTE_RANGE) {
HoldingRegisterType = typeof(BytesRegister),
- PlcVarType = PlcVarType.WORD,
FromRaw = (reg, bytes) => {
+ var byteReg = (BytesRegister)reg;
+
BitArray bitAr = new BitArray(bytes);
+ bitAr.Length = (int)byteReg.ReservedBitSize;
+
return bitAr;
},
@@ -208,6 +223,15 @@ namespace MewtocolNet.TypeConversion {
byte[] ret = new byte[(value.Length - 1) / 8 + 1];
value.CopyTo(ret, 0);
+
+ if(ret.Length % 2 != 0) {
+
+ var lst = ret.ToList();
+ lst.Add(0);
+ ret = lst.ToArray();
+
+ }
+
return ret;
},
diff --git a/MewtocolNet/TypeConversion/PlcValueParser.cs b/MewtocolNet/TypeConversion/PlcValueParser.cs
index ab873d8..cf8c887 100644
--- a/MewtocolNet/TypeConversion/PlcValueParser.cs
+++ b/MewtocolNet/TypeConversion/PlcValueParser.cs
@@ -12,9 +12,22 @@ namespace MewtocolNet {
private static List conversions => Conversions.items;
- public static T Parse(IRegister register, byte[] bytes) {
+ internal static T Parse (IRegister register, byte[] bytes) {
- var converter = conversions.FirstOrDefault(x => x.GetDotnetType() == typeof(T));
+ IPlcTypeConverter converter;
+
+ //special case for enums
+ if(typeof(T).IsEnum) {
+
+ var underlyingNumberType = typeof(T).GetEnumUnderlyingType();
+
+ converter = conversions.FirstOrDefault(x => x.GetDotnetType() == underlyingNumberType);
+
+ } else {
+
+ converter = conversions.FirstOrDefault(x => x.GetDotnetType() == typeof(T));
+
+ }
if (converter == null)
throw new MewtocolException($"A converter for the dotnet type {typeof(T)} doesn't exist");
@@ -23,9 +36,22 @@ namespace MewtocolNet {
}
- public static byte[] Encode (IRegister register, T value) {
+ internal static byte[] Encode (IRegister register, T value) {
- var converter = conversions.FirstOrDefault(x => x.GetDotnetType() == typeof(T));
+ IPlcTypeConverter converter;
+
+ //special case for enums
+ if (typeof(T).IsEnum) {
+
+ var underlyingNumberType = typeof(T).GetEnumUnderlyingType();
+
+ converter = conversions.FirstOrDefault(x => x.GetDotnetType() == underlyingNumberType);
+
+ } else {
+
+ converter = conversions.FirstOrDefault(x => x.GetDotnetType() == typeof(T));
+
+ }
if (converter == null)
throw new MewtocolException($"A converter for the dotnet type {typeof(T)} doesn't exist");
diff --git a/MewtocolNet/TypeConversion/PlcVarTypeConversions.cs b/MewtocolNet/TypeConversion/PlcVarTypeConversions.cs
index 2ff6817..79ce5f4 100644
--- a/MewtocolNet/TypeConversion/PlcVarTypeConversions.cs
+++ b/MewtocolNet/TypeConversion/PlcVarTypeConversions.cs
@@ -22,18 +22,24 @@ namespace MewtocolNet {
internal static bool IsAllowedPlcCastingType() {
+ if (typeof(T).IsEnum) return true;
+
return allowedCastingTypes.Contains(typeof(T));
}
internal static bool IsAllowedPlcCastingType(this Type type) {
+ if (type.IsEnum) return true;
+
return allowedCastingTypes.Contains(type);
}
internal static RegisterType ToRegisterTypeDefault(this Type type) {
+ if (type.IsEnum) return RegisterType.DT;
+
var found = PlcValueParser.GetDefaultRegisterType(type);
if (found != null) {
diff --git a/MewtocolTests/AutomatedPropertyRegisters.cs b/MewtocolTests/AutomatedPropertyRegisters.cs
index 9a30f15..416fcdc 100644
--- a/MewtocolTests/AutomatedPropertyRegisters.cs
+++ b/MewtocolTests/AutomatedPropertyRegisters.cs
@@ -1,13 +1,12 @@
using MewtocolNet;
-using MewtocolNet.RegisterAttributes;
using MewtocolNet.Registers;
-using System.Collections;
+using MewtocolTests.EncapsulatedTests;
using Xunit;
using Xunit.Abstractions;
namespace MewtocolTests {
- public class AutomatedPropertyRegisters {
+ public partial class AutomatedPropertyRegisters {
private readonly ITestOutputHelper output;
@@ -15,90 +14,14 @@ namespace MewtocolTests {
this.output = output;
}
- 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
- [Register(IOType.R, memoryArea: 85, spAdress: 0)]
- public bool TestBool1 { get; private set; }
-
- //corresponds to a XD input of the PLC
- [Register(IOType.X, (byte)0xD)]
- 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(899)]
- public short TestInt16 { get; private set; }
-
- [Register(342)]
- public ushort TestUInt16 { get; private set; }
-
- //corresponds to a DTD7001 - DTD7002 32 bit int register in the PLC
- [Register(7001)]
- public int TestInt32 { get; private set; }
-
- [Register(765)]
- public uint TestUInt32 { 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; }
-
- [Register(8010, BitCount.B32)]
- public BitArray TestBitRegister32 { 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, BitCount.B16, 9)]
- public bool BitValue { get; private set; }
-
- [Register(1204, BitCount.B32, 5)]
- public bool FillTest { 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; }
-
- public enum CurrentState {
- Undefined = 0,
- State1 = 1,
- State2 = 2,
- //State3 = 3,
- State4 = 4,
- State5 = 5,
- StateBetween = 100,
- State6 = 6,
- State7 = 7,
- }
-
- [Register(50)]
- public CurrentState TestEnum16 { get; private set; }
-
- [Register(51, BitCount.B32)]
- public CurrentState TestEnum32 { get; private set; }
-
- }
-
- private void TestBasicGeneration(IRegisterInternal reg, string propName, object expectValue, int expectAddr, string expectPlcName) {
+ private void Test(IRegisterInternal reg, string propName, uint expectAddr, string expectPlcName) {
Assert.NotNull(reg);
Assert.Equal(propName, reg.Name);
- Assert.Equal(expectValue, reg.Value);
+ Assert.Null(reg.Value);
Assert.Equal(expectAddr, reg.MemoryAddress);
- Assert.Equal(expectPlcName, reg.GetRegisterPLCName());
+ Assert.Equal(expectPlcName, reg.GetMewName());
output.WriteLine(reg.ToString());
@@ -106,107 +29,86 @@ namespace MewtocolTests {
//actual tests
- [Fact(DisplayName = "Boolean R generation")]
+ [Fact(DisplayName = "Boolean generation")]
public void BooleanGen() {
var interf = Mewtocol.Ethernet("192.168.0.1");
- interf.AddRegisterCollection(new TestRegisterCollection()).WithPoller();
+ interf.AddRegisterCollection(new TestBoolRegisters());
- var register = interf.GetRegister(nameof(TestRegisterCollection.TestBool1));
+ var register1 = interf.GetRegister(nameof(TestBoolRegisters.RType));
+ var register2 = interf.GetRegister(nameof(TestBoolRegisters.XType));
- //test generic properties
- TestBasicGeneration((IRegisterInternal)register, nameof(TestRegisterCollection.TestBool1), false, 85, "R85");
+ var register3 = interf.GetRegister(nameof(TestBoolRegisters.RType_MewString));
+
+ Test((IRegisterInternal)register1, nameof(TestBoolRegisters.RType), 85, "R85A");
+ Test((IRegisterInternal)register2, nameof(TestBoolRegisters.XType), 0, "XD");
+
+ Test((IRegisterInternal)register3, nameof(TestBoolRegisters.RType_MewString), 85, "R85B");
}
- [Fact(DisplayName = "Boolean input XD generation")]
- public void BooleanInputGen() {
+ [Fact(DisplayName = "Number 16 bit generation")]
+ public void N16BitGen () {
var interf = Mewtocol.Ethernet("192.168.0.1");
- interf.AddRegisterCollection(new TestRegisterCollection()).WithPoller();
+ interf.AddRegisterCollection(new Nums16Bit());
- var register = interf.GetRegister(nameof(TestRegisterCollection.TestBoolInputXD));
+ var register1 = interf.GetRegister(nameof(Nums16Bit.Int16Type));
+ var register2 = interf.GetRegister(nameof(Nums16Bit.UInt16Type));
+ var register3 = interf.GetRegister(nameof(Nums16Bit.Enum16Type));
+
+ var register4 = interf.GetRegister(nameof(Nums16Bit.Int16Type_MewString));
+ var register5 = interf.GetRegister(nameof(Nums16Bit.Enum16Type_MewString));
//test generic properties
- TestBasicGeneration((IRegisterInternal)register, nameof(TestRegisterCollection.TestBoolInputXD), false, 0, "XD");
+ Test((IRegisterInternal)register1, nameof(Nums16Bit.Int16Type), 899, "DT899");
+ Test((IRegisterInternal)register2, nameof(Nums16Bit.UInt16Type), 342, "DT342");
+ Test((IRegisterInternal)register3, nameof(Nums16Bit.Enum16Type), 50, "DT50");
+
+ Test((IRegisterInternal)register4, nameof(Nums16Bit.Int16Type_MewString), 900, "DT900");
+ Test((IRegisterInternal)register5, nameof(Nums16Bit.Enum16Type_MewString), 51, "DT51");
}
- [Fact(DisplayName = "Int16 generation")]
- public void Int16Gen() {
+ [Fact(DisplayName = "Number 32 bit generation")]
+ public void N32BitGen () {
var interf = Mewtocol.Ethernet("192.168.0.1");
- interf.AddRegisterCollection(new TestRegisterCollection()).WithPoller();
+ interf.AddRegisterCollection(new Nums32Bit());
- var register = interf.GetRegister(nameof(TestRegisterCollection.TestInt16));
+ var register1 = interf.GetRegister(nameof(Nums32Bit.Int32Type));
+ var register2 = interf.GetRegister(nameof(Nums32Bit.UInt32Type));
+ var register3 = interf.GetRegister(nameof(Nums32Bit.Enum32Type));
+ var register4 = interf.GetRegister(nameof(Nums32Bit.FloatType));
+ var register5 = interf.GetRegister(nameof(Nums32Bit.TimeSpanType));
+
+ var register6 = interf.GetRegister(nameof(Nums32Bit.Enum32Type_MewString));
+ var register7 = interf.GetRegister(nameof(Nums32Bit.TimeSpanType_MewString));
//test generic properties
- TestBasicGeneration((IRegisterInternal)register, nameof(TestRegisterCollection.TestInt16), (short)0, 899, "DT899");
+ Test((IRegisterInternal)register1, nameof(Nums32Bit.Int32Type), 7001, "DDT7001");
+ Test((IRegisterInternal)register2, nameof(Nums32Bit.UInt32Type), 765, "DDT765");
+ Test((IRegisterInternal)register3, nameof(Nums32Bit.Enum32Type), 51, "DDT51");
+ Test((IRegisterInternal)register4, nameof(Nums32Bit.FloatType), 7003, "DDT7003");
+ Test((IRegisterInternal)register5, nameof(Nums32Bit.TimeSpanType), 7012, "DDT7012");
+
+ Test((IRegisterInternal)register6, nameof(Nums32Bit.Enum32Type_MewString), 53, "DDT53");
+ Test((IRegisterInternal)register7, nameof(Nums32Bit.TimeSpanType_MewString), 7014, "DDT7014");
}
- [Fact(DisplayName = "UInt16 generation")]
- public void UInt16Gen() {
+ [Fact(DisplayName = "String generation")]
+ public void StringGen() {
var interf = Mewtocol.Ethernet("192.168.0.1");
- interf.AddRegisterCollection(new TestRegisterCollection()).WithPoller();
+ interf.AddRegisterCollection(new TestStringRegisters());
- var register = interf.GetRegister(nameof(TestRegisterCollection.TestUInt16));
+ var register1 = interf.GetRegister(nameof(TestStringRegisters.StringType));
+ var register2 = interf.GetRegister(nameof(TestStringRegisters.StringType_MewString));
//test generic properties
- TestBasicGeneration((IRegisterInternal)register, nameof(TestRegisterCollection.TestUInt16), (ushort)0, 342, "DT342");
-
- }
-
- [Fact(DisplayName = "Int32 generation")]
- public void Int32Gen() {
-
- var interf = Mewtocol.Ethernet("192.168.0.1");
- interf.AddRegisterCollection(new TestRegisterCollection()).WithPoller();
-
- var register = interf.GetRegister(nameof(TestRegisterCollection.TestInt32));
-
- //test generic properties
- TestBasicGeneration((IRegisterInternal)register, nameof(TestRegisterCollection.TestInt32), (int)0, 7001, "DDT7001");
-
- }
-
- [Fact(DisplayName = "UInt32 generation")]
- public void UInt32Gen() {
-
- var interf = Mewtocol.Ethernet("192.168.0.1");
- interf.AddRegisterCollection(new TestRegisterCollection()).WithPoller();
-
- var register = interf.GetRegister(nameof(TestRegisterCollection.TestUInt32));
-
- //test generic properties
- TestBasicGeneration((IRegisterInternal)register, nameof(TestRegisterCollection.TestUInt32), (uint)0, 765, "DDT765");
-
- }
-
- [Fact(DisplayName = "Float32 generation")]
- public void Float32Gen() {
-
- var interf = Mewtocol.Ethernet("192.168.0.1");
- interf.AddRegisterCollection(new TestRegisterCollection()).WithPoller();
-
- var register = interf.GetRegister(nameof(TestRegisterCollection.TestFloat32));
-
- //test generic properties
- TestBasicGeneration((IRegisterInternal)register, nameof(TestRegisterCollection.TestFloat32), (float)0, 7003, "DDT7003");
-
- }
-
- [Fact(DisplayName = "TimeSpan generation")]
- public void TimespanGen() {
-
- var interf = Mewtocol.Ethernet("192.168.0.1");
- interf.AddRegisterCollection(new TestRegisterCollection()).WithPoller();
-
- var register = interf.GetRegister(nameof(TestRegisterCollection.TestTime));
-
- //test generic properties
- TestBasicGeneration((IRegisterInternal)register, nameof(TestRegisterCollection.TestTime), TimeSpan.Zero, 7012, "DDT7012");
+ Test((IRegisterInternal)register1, nameof(TestStringRegisters.StringType), 7005, "DT7005");
+ Test((IRegisterInternal)register2, nameof(TestStringRegisters.StringType_MewString), 7050, "DT7050");
}
diff --git a/MewtocolTests/EncapsulatedTests/RegisterReadWriteTest.cs b/MewtocolTests/EncapsulatedTests/RegisterReadWriteTest.cs
index 529cc84..3ddf4a5 100644
--- a/MewtocolTests/EncapsulatedTests/RegisterReadWriteTest.cs
+++ b/MewtocolTests/EncapsulatedTests/RegisterReadWriteTest.cs
@@ -13,7 +13,9 @@ internal class RegisterReadWriteTest {
public object IntialValue { get; set; }
- public object AfterWriteValue { get; set; }
+ public object IntermediateValue { get; set; }
+
+ public object AfterWriteValue { get; set; }
public string RegisterPlcAddressName { get; set; }
diff --git a/MewtocolTests/EncapsulatedTests/TestRegisterCollection.cs b/MewtocolTests/EncapsulatedTests/TestRegisterCollection.cs
new file mode 100644
index 0000000..e222dc9
--- /dev/null
+++ b/MewtocolTests/EncapsulatedTests/TestRegisterCollection.cs
@@ -0,0 +1,115 @@
+using MewtocolNet;
+using MewtocolNet.RegisterAttributes;
+using System.Collections;
+
+namespace MewtocolTests.EncapsulatedTests {
+
+ public enum CurrentState : short {
+ Undefined = 0,
+ State1 = 1,
+ State2 = 2,
+ //State3 = 3, <= leave empty for test purposes
+ State4 = 4,
+ State5 = 5,
+ StateBetween = 100,
+ State6 = 6,
+ State7 = 7,
+ }
+
+ public enum CurrentState32 : int {
+ Undefined = 0,
+ State1 = 1,
+ State2 = 2,
+ //State3 = 3, <= leave empty for test purposes
+ State4 = 4,
+ State5 = 5,
+ StateBetween = 100,
+ State6 = 6,
+ State7 = 7,
+ }
+
+ public class TestBoolRegisters : RegisterCollection {
+
+ [Register(IOType.R, memoryArea: 85, spAdress: 0xA)]
+ public bool RType { get; set; }
+
+ [Register(IOType.X, (byte)0xD)]
+ public bool XType { get; set; }
+
+ [Register("R85B")]
+ public bool RType_MewString { get; set; }
+
+ }
+
+ public class Nums16Bit : RegisterCollection {
+
+
+ [Register(899)]
+ public short Int16Type { get; set; }
+
+ [Register(342)]
+ public ushort UInt16Type { get; set; }
+
+ [Register(50)]
+ public CurrentState Enum16Type { get; set; }
+
+ [Register("DT900")]
+ public short Int16Type_MewString { get; set; }
+
+ [Register("DT51")]
+ public CurrentState Enum16Type_MewString { get; set; }
+
+ }
+
+ public class Nums32Bit : RegisterCollection {
+
+ [Register(7001)]
+ public int Int32Type { get; set; }
+
+ [Register(765)]
+ public uint UInt32Type { get; set; }
+
+ [Register(51)]
+ public CurrentState32 Enum32Type { get; set; }
+
+ [Register(7003)]
+ public float FloatType { get; set; }
+
+ [Register(7012)]
+ public TimeSpan TimeSpanType { get; set; }
+
+ [Register("DDT53")]
+ public CurrentState32 Enum32Type_MewString { get; set; }
+
+ [Register("DDT7014")]
+ public TimeSpan TimeSpanType_MewString { get; set; }
+
+ }
+
+ public class TestStringRegisters : RegisterCollection {
+
+ [Register(7005, 5)]
+ public string? StringType { get; set; }
+
+ [Register("DT7050")]
+ public string? StringType_MewString { get; set; }
+
+ }
+
+ public class TestBitwiseRegisters : RegisterCollection {
+
+ [Register(7010)]
+ public BitArray TestBitRegister { get; set; }
+
+ [Register(8010, BitCount.B32)]
+ public BitArray TestBitRegister32 { get; set; }
+
+ [Register(1204, BitCount.B16, 9)]
+ public bool BitValue { get; set; }
+
+ [Register(1204, BitCount.B32, 5)]
+ public bool FillTest { get; set; }
+
+ }
+
+}
\ No newline at end of file
diff --git a/MewtocolTests/TestHelperExtensions.cs b/MewtocolTests/TestHelperExtensions.cs
index 1739279..556b409 100644
--- a/MewtocolTests/TestHelperExtensions.cs
+++ b/MewtocolTests/TestHelperExtensions.cs
@@ -13,7 +13,7 @@ namespace MewtocolTests {
this.output = output;
}
- [Fact(DisplayName = nameof(MewtocolHelpers.ToBitString))]
+ [Fact(DisplayName = nameof(PlcFormat.ToBitString))]
public void ToBitStringGeneration() {
var bitarr = new BitArray(16);
@@ -91,6 +91,25 @@ namespace MewtocolTests {
}
+ [Fact(DisplayName = nameof(PlcFormat.ParsePlcTime))]
+ public void ParsePlcTime () {
+
+ Assert.Equal(new TimeSpan(5, 30, 30, 15, 10), PlcFormat.ParsePlcTime("T#5d30h30m15s10ms"));
+ Assert.Equal(new TimeSpan(0, 30, 30, 15, 10), PlcFormat.ParsePlcTime("T#30h30m15s10ms"));
+ Assert.Equal(new TimeSpan(0, 1, 30, 15, 10), PlcFormat.ParsePlcTime("T#1h30m15s10ms"));
+ Assert.Equal(new TimeSpan(0, 0, 5, 30, 10), PlcFormat.ParsePlcTime("T#5m30s10ms"));
+ Assert.Throws(() => PlcFormat.ParsePlcTime("T#5m30s5ms"));
+
+ }
+
+ [Fact(DisplayName = nameof(PlcFormat.ToPlcTime))]
+ public void ToPlcTime() {
+
+ Assert.Equal("T#1d6h5m30s10ms", PlcFormat.ToPlcTime(new TimeSpan(0, 30, 5, 30, 10)));
+ Assert.Equal("T#6d5h30m10s", PlcFormat.ToPlcTime(new TimeSpan(6, 5, 30, 10)));
+
+ }
+
}
}
\ No newline at end of file
diff --git a/MewtocolTests/TestLivePLC.cs b/MewtocolTests/TestLivePLC.cs
index 1a94956..3a04ac5 100644
--- a/MewtocolTests/TestLivePLC.cs
+++ b/MewtocolTests/TestLivePLC.cs
@@ -3,6 +3,7 @@ using MewtocolNet.Logging;
using MewtocolNet.RegisterBuilding;
using MewtocolNet.Registers;
using MewtocolTests.EncapsulatedTests;
+using System.Collections;
using Xunit;
using Xunit.Abstractions;
@@ -41,15 +42,51 @@ namespace MewtocolTests
new RegisterReadWriteTest {
TargetRegister = new BoolRegister(IOType.R, 0xA, 10),
RegisterPlcAddressName = "R10A",
- IntialValue = false,
+ IntermediateValue = false,
AfterWriteValue = true,
},
new RegisterReadWriteTest {
TargetRegister = new NumberRegister(3000),
RegisterPlcAddressName = "DT3000",
- IntialValue = (short)0,
+ IntermediateValue = (short)0,
AfterWriteValue = (short)-513,
},
+ new RegisterReadWriteTest {
+ TargetRegister = new NumberRegister(3001),
+ RegisterPlcAddressName = "DT3001",
+ IntermediateValue = CurrentState.Undefined,
+ AfterWriteValue = CurrentState.State4,
+ },
+ new RegisterReadWriteTest {
+ TargetRegister = new NumberRegister(3002),
+ RegisterPlcAddressName = "DDT3002",
+ IntermediateValue = CurrentState32.Undefined,
+ AfterWriteValue = CurrentState32.StateBetween,
+ },
+ new RegisterReadWriteTest {
+ TargetRegister = new NumberRegister(3004),
+ RegisterPlcAddressName = "DDT3004",
+ IntermediateValue = TimeSpan.Zero,
+ AfterWriteValue = TimeSpan.FromSeconds(11),
+ },
+ new RegisterReadWriteTest {
+ TargetRegister = new NumberRegister(3006),
+ RegisterPlcAddressName = "DDT3006",
+ IntermediateValue = TimeSpan.Zero,
+ AfterWriteValue = PlcFormat.ParsePlcTime("T#50m"),
+ },
+ new RegisterReadWriteTest {
+ TargetRegister = new StringRegister(40),
+ RegisterPlcAddressName = "DT40",
+ IntermediateValue = "Hello",
+ AfterWriteValue = "TestV",
+ },
+ new RegisterReadWriteTest {
+ TargetRegister = RegBuilder.Factory.FromPlcRegName("DT3008").AsBits(5).Build(),
+ RegisterPlcAddressName = "DT3008",
+ IntermediateValue = new BitArray(new bool[] { false, false, false, false, false }),
+ AfterWriteValue = new BitArray(new bool[] { false, true, false, false, false }),
+ },
};
@@ -57,16 +94,9 @@ namespace MewtocolTests
this.output = output;
- Logger.LogLevel = LogLevel.Critical;
- Logger.OnNewLogMessage((d, l, m) => {
-
- output.WriteLine($"Mewtocol Logger: {d} {m}");
-
- });
-
}
- [Fact(DisplayName = "Connection cycle client to PLC")]
+ [Fact(DisplayName = "Connection cycle client to PLC (Ethernet)")]
public async void TestClientConnection() {
foreach (var plc in testPlcInformationData) {
@@ -87,7 +117,7 @@ namespace MewtocolTests
}
- [Fact(DisplayName = "Reading basic information from PLC")]
+ [Fact(DisplayName = "Reading basic status from PLC (Ethernet)")]
public async void TestClientReadPLCStatus() {
foreach (var plc in testPlcInformationData) {
@@ -111,42 +141,56 @@ namespace MewtocolTests
}
- [Fact(DisplayName = "Reading basic information from PLC")]
+ [Fact(DisplayName = "Reading / Writing registers from PLC (Ethernet)")]
public async void TestRegisterReadWriteAsync() {
- foreach (var plc in testPlcInformationData) {
+ Logger.LogLevel = LogLevel.Verbose;
+ Logger.OnNewLogMessage((d, l, m) => {
- output.WriteLine($"Testing: {plc.PLCName}\n");
+ output.WriteLine($"{d:HH:mm:ss:fff} {m}");
- var client = Mewtocol.Ethernet(plc.PLCIP, plc.PLCPort);
+ });
- foreach (var testRW in testRegisterRW) {
+ var plc = testPlcInformationData[0];
- client.AddRegister(testRW.TargetRegister);
+ output.WriteLine($"\n\n --- Testing: {plc.PLCName} ---\n");
- }
+ var client = Mewtocol.Ethernet(plc.PLCIP, plc.PLCPort);
- await client.ConnectAsync();
- Assert.True(client.IsConnected);
+ foreach (var testRW in testRegisterRW) {
- foreach (var testRW in testRegisterRW) {
-
- var testRegister = client.Registers.First(x => x.PLCAddressName == testRW.RegisterPlcAddressName);
-
- //test inital val
- Assert.Equal(testRW.IntialValue, testRegister.Value);
-
- await testRegister.WriteAsync(testRW.AfterWriteValue);
-
- //test after write val
- Assert.Equal(testRW.AfterWriteValue, testRegister.Value);
-
- }
-
- client.Disconnect();
+ client.AddRegister(testRW.TargetRegister);
}
+ await client.ConnectAsync();
+ Assert.True(client.IsConnected);
+
+ //cycle run mode to reset registers to inital
+ await client.SetOperationModeAsync(false);
+ await client.SetOperationModeAsync(true);
+
+ foreach (var testRW in testRegisterRW) {
+
+ var testRegister = client.Registers.First(x => x.PLCAddressName == testRW.RegisterPlcAddressName);
+
+ //test inital val
+ Assert.Null(testRegister.Value);
+
+ await testRegister.ReadAsync();
+
+ Assert.Equal(testRW.IntermediateValue, testRegister.Value);
+
+ await testRegister.WriteAsync(testRW.AfterWriteValue);
+ await testRegister.ReadAsync();
+
+ //test after write val
+ Assert.Equal(testRW.AfterWriteValue, testRegister.Value);
+
+ }
+
+ client.Disconnect();
+
}
}
diff --git a/MewtocolTests/TestRegisterBuilder.cs b/MewtocolTests/TestRegisterBuilder.cs
index 4be5918..729ac6c 100644
--- a/MewtocolTests/TestRegisterBuilder.cs
+++ b/MewtocolTests/TestRegisterBuilder.cs
@@ -1,6 +1,7 @@
using MewtocolNet;
using MewtocolNet.RegisterBuilding;
using MewtocolNet.Registers;
+using MewtocolTests.EncapsulatedTests;
using System.Collections;
using Xunit;
using Xunit.Abstractions;
@@ -162,12 +163,14 @@ public class TestRegisterBuilder {
}
[Fact(DisplayName = "Parsing as Number Register (Casted)")]
- public void TestRegisterBuildingNumericCasted() {
+ public void TestRegisterBuildingNumericCasted () {
- var expect = new NumberRegister(303, null);
- var expect2 = new NumberRegister(10002, null);
- var expect3 = new NumberRegister(400, null);
- //var expect4 = new NRegister(103, null, true);
+ var expect = new NumberRegister(303);
+ var expect2 = new NumberRegister(10002);
+ var expect3 = new NumberRegister(404);
+ var expect4 = new NumberRegister(400);
+ var expect5 = new NumberRegister(203);
+ var expect6 = new NumberRegister(204);
Assert.Equivalent(expect, RegBuilder.Factory.FromPlcRegName("DT303").AsPlcType(PlcVarType.INT).Build());
Assert.Equivalent(expect, RegBuilder.Factory.FromPlcRegName("DT303").AsType().Build());
@@ -175,32 +178,82 @@ public class TestRegisterBuilder {
Assert.Equivalent(expect2, RegBuilder.Factory.FromPlcRegName("DDT10002").AsPlcType(PlcVarType.DINT).Build());
Assert.Equivalent(expect2, RegBuilder.Factory.FromPlcRegName("DDT10002").AsType().Build());
- Assert.Equivalent(expect3, RegBuilder.Factory.FromPlcRegName("DDT400").AsPlcType(PlcVarType.TIME).Build());
- Assert.Equivalent(expect3, RegBuilder.Factory.FromPlcRegName("DDT400").AsType().Build());
+ Assert.Equivalent(expect3, RegBuilder.Factory.FromPlcRegName("DDT404").AsPlcType(PlcVarType.REAL).Build());
+ Assert.Equivalent(expect3, RegBuilder.Factory.FromPlcRegName("DDT404").AsType().Build());
- //Assert.Equivalent(expect4, RegBuilder.FromPlcRegName("DT103").AsType().Build());
+ Assert.Equivalent(expect4, RegBuilder.Factory.FromPlcRegName("DDT400").AsPlcType(PlcVarType.TIME).Build());
+ Assert.Equivalent(expect4, RegBuilder.Factory.FromPlcRegName("DDT400").AsType().Build());
+
+ Assert.Equivalent(expect5, RegBuilder.Factory.FromPlcRegName("DT203").AsType().Build());
+ Assert.Equivalent(expect6, RegBuilder.Factory.FromPlcRegName("DT204").AsType().Build());
}
[Fact(DisplayName = "Parsing as Number Register (Auto)")]
- public void TestRegisterBuildingNumericAuto() {
+ public void TestRegisterBuildingNumericAuto () {
- var expect = new NumberRegister(303, null);
- var expect2 = new NumberRegister(10002, null);
+ var expect = new NumberRegister(201);
+ var expect2 = new NumberRegister(10002);
- Assert.Equivalent(expect, RegBuilder.Factory.FromPlcRegName("DT303").Build());
+ Assert.Equivalent(expect, RegBuilder.Factory.FromPlcRegName("DT201").Build());
Assert.Equivalent(expect2, RegBuilder.Factory.FromPlcRegName("DDT10002").Build());
}
[Fact(DisplayName = "Parsing as Bytes Register (Casted)")]
- public void TestRegisterBuildingByteRangeCasted() {
+ public void TestRegisterBuildingByteRangeCasted () {
- var expect = new BytesRegister(303, 5);
-
- Assert.Equivalent(expect, RegBuilder.Factory.FromPlcRegName("DT303").AsBytes(5).Build());
+ var expect = new BytesRegister(305, (uint)35);
+ Assert.Equal((uint)18, expect.AddressLength);
+ Assert.Equivalent(expect, RegBuilder.Factory.FromPlcRegName("DT305").AsBytes(35).Build());
}
+ [Fact(DisplayName = "Parsing as Bytes Register (Auto)")]
+ public void TestRegisterBuildingByteRangeAuto () {
+
+ var expect = new BytesRegister(300, (uint)20 * 2);
+ var actual = (BytesRegister)RegBuilder.Factory.FromPlcRegName("DT300-DT319").Build();
+
+ Assert.Equal((uint)20, expect.AddressLength);
+ Assert.Equivalent(expect, actual);
+
+ }
+
+ [Fact(DisplayName = "Parsing as Bit Array")]
+ public void TestRegisterBuildingBitArray () {
+
+ var expect1 = new BytesRegister(311, (ushort)5);
+ var expect2 = new BytesRegister(312, (ushort)16);
+ var expect3 = new BytesRegister(313, (ushort)32);
+
+ var actual1 = (BytesRegister)RegBuilder.Factory.FromPlcRegName("DT311").AsBits(5).Build();
+ var actual2 = (BytesRegister)RegBuilder.Factory.FromPlcRegName("DT312").AsBits(16).Build();
+ var actual3 = (BytesRegister)RegBuilder.Factory.FromPlcRegName("DT313").AsBits(32).Build();
+
+ Assert.Equivalent(expect1, actual1);
+ Assert.Equivalent(expect2, actual2);
+ Assert.Equivalent(expect3, actual3);
+
+ Assert.Equal((uint)1, actual1.AddressLength);
+ Assert.Equal((uint)1, actual2.AddressLength);
+ Assert.Equal((uint)2, actual3.AddressLength);
+
+ }
+
+ [Fact(DisplayName = "Parsing as String Register")]
+ public void TestRegisterBuildingString () {
+
+ var expect1 = new StringRegister(314);
+
+ var actual1 = (StringRegister)RegBuilder.Factory.FromPlcRegName("DT314").AsType().Build();
+
+ Assert.Equivalent(expect1, actual1);
+
+ Assert.Equal((uint)0, actual1.WordsSize);
+
+ }
+
+
}
diff --git a/MewtocolTests/TestRegisterInterface.cs b/MewtocolTests/TestRegisterInterface.cs
index b2b8b50..674d7af 100644
--- a/MewtocolTests/TestRegisterInterface.cs
+++ b/MewtocolTests/TestRegisterInterface.cs
@@ -23,8 +23,8 @@ namespace MewtocolTests {
new NumberRegister(50),
new NumberRegister(50),
new NumberRegister(50),
- new BytesRegister(50, 30),
- new BytesRegister(50, 31),
+ new BytesRegister(50, (uint)30),
+ new BytesRegister(50, (uint)31),
};
List expectedIdents = new List {
@@ -103,7 +103,7 @@ namespace MewtocolTests {
IRegisterInternal? reg = registers[i];
string expect = expcectedIdents[i];
- Assert.Equal(expect, reg.GetRegisterPLCName());
+ Assert.Equal(expect, reg.GetMewName());
}