mirror of
https://github.com/OpenLogics/MewtocolNet.git
synced 2025-12-06 03:01:24 +00:00
Added register builder for booleans and numerics
This commit is contained in:
@@ -4,6 +4,8 @@ using System;
|
|||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Collections;
|
using System.Collections;
|
||||||
|
using MewtocolNet.RegisterBuilding;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace Examples;
|
namespace Examples;
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
using System;
|
using MewtocolNet.RegisterBuilding;
|
||||||
|
using MewtocolNet;
|
||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
@@ -12,6 +14,9 @@ class Program {
|
|||||||
|
|
||||||
static void Main(string[] args) {
|
static void Main(string[] args) {
|
||||||
|
|
||||||
|
RegBuilder.FromPlcRegName("DT303").AsPlcType(PlcVarType.INT).Build();
|
||||||
|
var res = RegBuilder.FromPlcRegName("DT100").AsPlcType(PlcVarType.INT).Build();
|
||||||
|
|
||||||
AppDomain.CurrentDomain.UnhandledException += (s,e) => {
|
AppDomain.CurrentDomain.UnhandledException += (s,e) => {
|
||||||
Console.WriteLine(e.ExceptionObject.ToString());
|
Console.WriteLine(e.ExceptionObject.ToString());
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
using MewtocolNet.PLCEnums;
|
using System;
|
||||||
using System;
|
|
||||||
|
|
||||||
namespace MewtocolNet {
|
namespace MewtocolNet {
|
||||||
|
|
||||||
|
|||||||
@@ -12,6 +12,11 @@ namespace MewtocolNet {
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
event Action<object> ValueChanged;
|
event Action<object> ValueChanged;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Type of the underlying register
|
||||||
|
/// </summary>
|
||||||
|
RegisterType RegisterType { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The name of the register
|
/// The name of the register
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -27,6 +32,12 @@ namespace MewtocolNet {
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
int MemoryAddress { get; }
|
int MemoryAddress { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the special address of the register or -1 if it has none
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
byte? GetSpecialAddress();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Indicates if the register is processed bitwise
|
/// Indicates if the register is processed bitwise
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -93,6 +104,11 @@ namespace MewtocolNet {
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
string ToString();
|
string ToString();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Builds a readable string with all important register informations and additional infos
|
||||||
|
/// </summary>
|
||||||
|
string ToString(bool detailed);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -239,7 +239,7 @@ namespace MewtocolNet {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Checks if the register type is non numeric
|
/// Checks if the register type is boolean
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal static bool IsBoolean (this RegisterType type) {
|
internal static bool IsBoolean (this RegisterType type) {
|
||||||
|
|
||||||
@@ -247,6 +247,15 @@ namespace MewtocolNet {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Checks if the register type numeric
|
||||||
|
/// </summary>
|
||||||
|
internal static bool IsNumericDTDDT (this RegisterType type) {
|
||||||
|
|
||||||
|
return type == RegisterType.DT || type == RegisterType.DDT;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Checks if the register type is an physical in or output of the plc
|
/// Checks if the register type is an physical in or output of the plc
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
using MewtocolNet.Logging;
|
using MewtocolNet.Logging;
|
||||||
using MewtocolNet.PLCEnums;
|
|
||||||
using MewtocolNet.Registers;
|
using MewtocolNet.Registers;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
namespace MewtocolNet.PLCEnums {
|
namespace MewtocolNet {
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// CPU type of the PLC
|
/// CPU type of the PLC
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
namespace MewtocolNet.PLCEnums {
|
namespace MewtocolNet {
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// CPU type of the PLC
|
/// CPU type of the PLC
|
||||||
|
|||||||
18
MewtocolNet/PLCEnums/PlcVarType.cs
Normal file
18
MewtocolNet/PLCEnums/PlcVarType.cs
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace MewtocolNet {
|
||||||
|
|
||||||
|
public enum PlcVarType {
|
||||||
|
|
||||||
|
BOOL,
|
||||||
|
INT,
|
||||||
|
UINT,
|
||||||
|
DINT,
|
||||||
|
UDINT,
|
||||||
|
REAL,
|
||||||
|
TIME,
|
||||||
|
STRING
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
91
MewtocolNet/PLCEnums/PlcVarTypeConversions.cs
Normal file
91
MewtocolNet/PLCEnums/PlcVarTypeConversions.cs
Normal file
@@ -0,0 +1,91 @@
|
|||||||
|
using MewtocolNet.Registers;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace MewtocolNet {
|
||||||
|
internal static class PlcVarTypeConversions {
|
||||||
|
|
||||||
|
static Dictionary<PlcVarType, Type> dictTypeConv = new Dictionary<PlcVarType, Type> {
|
||||||
|
|
||||||
|
{ PlcVarType.BOOL, typeof(bool) },
|
||||||
|
{ PlcVarType.INT, typeof(short) },
|
||||||
|
{ PlcVarType.UINT, typeof(ushort) },
|
||||||
|
{ PlcVarType.DINT, typeof(int) },
|
||||||
|
{ PlcVarType.UDINT, typeof(uint) },
|
||||||
|
{ PlcVarType.REAL, typeof(float) },
|
||||||
|
{ PlcVarType.TIME, typeof(TimeSpan) },
|
||||||
|
{ PlcVarType.STRING, typeof(string) },
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
static Dictionary<PlcVarType, Type> dictRegisterConv = new Dictionary<PlcVarType, Type> {
|
||||||
|
|
||||||
|
{ PlcVarType.BOOL, typeof(BRegister) },
|
||||||
|
{ PlcVarType.INT, typeof(NRegister<short>) },
|
||||||
|
{ PlcVarType.UINT, typeof(NRegister<ushort>) },
|
||||||
|
{ PlcVarType.DINT, typeof(NRegister<int>) },
|
||||||
|
{ PlcVarType.UDINT, typeof(NRegister<uint>) },
|
||||||
|
{ PlcVarType.REAL, typeof(NRegister<float>) },
|
||||||
|
{ PlcVarType.TIME, typeof(NRegister<TimeSpan>) },
|
||||||
|
{ PlcVarType.STRING, typeof(SRegister) },
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
internal static bool IsAllowedPlcCastingType <T> () {
|
||||||
|
|
||||||
|
var inversed = dictTypeConv.ToDictionary((i) => i.Value, (i) => i.Key);
|
||||||
|
|
||||||
|
return inversed.ContainsKey(typeof(T));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static bool IsAllowedPlcCastingType (this Type type) {
|
||||||
|
|
||||||
|
var inversed = dictTypeConv.ToDictionary((i) => i.Value, (i) => i.Key);
|
||||||
|
|
||||||
|
return inversed.ContainsKey(type);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static Type ToDotnetType (this PlcVarType type) {
|
||||||
|
|
||||||
|
if(dictTypeConv.ContainsKey(type)) {
|
||||||
|
|
||||||
|
return dictTypeConv[type];
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new NotSupportedException($"The PlcVarType: '{type}' is not supported");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static PlcVarType ToPlcVarType (this Type type) {
|
||||||
|
|
||||||
|
var inversed = dictTypeConv.ToDictionary((i) => i.Value, (i) => i.Key);
|
||||||
|
|
||||||
|
if (inversed.ContainsKey(type)) {
|
||||||
|
|
||||||
|
return inversed[type];
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new NotSupportedException($"The Dotnet Type: '{type}' is not supported");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static Type ToRegisterType (this PlcVarType type) {
|
||||||
|
|
||||||
|
if (dictRegisterConv.ContainsKey(type)) {
|
||||||
|
|
||||||
|
return dictRegisterConv[type];
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new NotSupportedException($"The PlcVarType: '{type}' is not supported");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
97
MewtocolNet/RegisterBuilding/FinalizerExtensions.cs
Normal file
97
MewtocolNet/RegisterBuilding/FinalizerExtensions.cs
Normal file
@@ -0,0 +1,97 @@
|
|||||||
|
using MewtocolNet.Registers;
|
||||||
|
using System;
|
||||||
|
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();
|
||||||
|
|
||||||
|
bool isBoolean = step.RegType.IsBoolean();
|
||||||
|
bool isTypeNotDefined = step.plcVarType == null && step.dotnetVarType == null;
|
||||||
|
|
||||||
|
//fallbacks if no casting builder was given
|
||||||
|
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_START) {
|
||||||
|
|
||||||
|
step.dotnetVarType = typeof(string);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if(step.plcVarType != null) {
|
||||||
|
|
||||||
|
step.dotnetVarType = step.plcVarType.Value.ToDotnetType();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//as numeric register
|
||||||
|
if (step.RegType.IsNumericDTDDT()) {
|
||||||
|
|
||||||
|
if(step.plcVarType == null && step.dotnetVarType != null) {
|
||||||
|
|
||||||
|
step.plcVarType = step.dotnetVarType.ToPlcVarType();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
var type = step.plcVarType.Value.ToRegisterType();
|
||||||
|
|
||||||
|
var areaAddr = step.MemAddress;
|
||||||
|
var name = step.Name;
|
||||||
|
|
||||||
|
//create a new bregister instance
|
||||||
|
var flags = BindingFlags.Public | BindingFlags.Instance;
|
||||||
|
|
||||||
|
//int _adress, string _name = null, bool isBitwise = false, Type _enumType = null
|
||||||
|
var parameters = new object[] { areaAddr, name, false, null };
|
||||||
|
var instance = (IRegister)Activator.CreateInstance(type, flags, null, parameters, null);
|
||||||
|
|
||||||
|
return instance;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (step.RegType.IsBoolean()) {
|
||||||
|
|
||||||
|
var io = (IOType)(int)step.RegType;
|
||||||
|
var spAddr = step.SpecialAddress;
|
||||||
|
var areaAddr = step.MemAddress;
|
||||||
|
var name = step.Name;
|
||||||
|
|
||||||
|
//create a new bregister instance
|
||||||
|
var flags = BindingFlags.Public | BindingFlags.Instance;
|
||||||
|
var parameters = new object[] { io, spAddr.Value, areaAddr, name };
|
||||||
|
var instance = (BRegister)Activator.CreateInstance(typeof(BRegister), flags, null, parameters, null);
|
||||||
|
|
||||||
|
return instance;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (step.dotnetVarType != null) {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new Exception("Failed to build register");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
12
MewtocolNet/RegisterBuilding/ParseResult.cs
Normal file
12
MewtocolNet/RegisterBuilding/ParseResult.cs
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
namespace MewtocolNet.RegisterBuilding {
|
||||||
|
internal struct ParseResult {
|
||||||
|
|
||||||
|
public ParseResultState state;
|
||||||
|
|
||||||
|
public string hardFailReason;
|
||||||
|
|
||||||
|
public RegisterBuilderStep stepData;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
19
MewtocolNet/RegisterBuilding/ParseResultState.cs
Normal file
19
MewtocolNet/RegisterBuilding/ParseResultState.cs
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
namespace MewtocolNet.RegisterBuilding {
|
||||||
|
internal enum ParseResultState {
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The parse try failed at the intial regex match
|
||||||
|
/// </summary>
|
||||||
|
FailedSoft,
|
||||||
|
/// <summary>
|
||||||
|
/// The parse try failed at the afer- regex match
|
||||||
|
/// </summary>
|
||||||
|
FailedHard,
|
||||||
|
/// <summary>
|
||||||
|
/// The parse try did work
|
||||||
|
/// </summary>
|
||||||
|
Success,
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
184
MewtocolNet/RegisterBuilding/RegBuilder.cs
Normal file
184
MewtocolNet/RegisterBuilding/RegBuilder.cs
Normal file
@@ -0,0 +1,184 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Data.Common;
|
||||||
|
using System.Globalization;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
|
||||||
|
namespace MewtocolNet.RegisterBuilding {
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Contains useful tools for register creation
|
||||||
|
/// </summary>
|
||||||
|
public static class RegBuilder {
|
||||||
|
|
||||||
|
//methods to test the input string on
|
||||||
|
private static List<Func<string, ParseResult>> parseMethods = new List<Func<string, ParseResult>>() {
|
||||||
|
|
||||||
|
(x) => TryBuildBoolean(x),
|
||||||
|
(x) => TryBuildNumericBased(x),
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
public static RegisterBuilderStep FromPlcRegName (string plcAddrName, string name = null) {
|
||||||
|
|
||||||
|
foreach (var method in parseMethods) {
|
||||||
|
|
||||||
|
var res = method.Invoke(plcAddrName);
|
||||||
|
|
||||||
|
if(res.state == ParseResultState.Success) {
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(name))
|
||||||
|
res.stepData.Name = name;
|
||||||
|
|
||||||
|
res.stepData.OriginalInput = plcAddrName;
|
||||||
|
|
||||||
|
return res.stepData;
|
||||||
|
|
||||||
|
} else if(res.state == ParseResultState.FailedHard) {
|
||||||
|
|
||||||
|
throw new Exception(res.hardFailReason);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new Exception("Wrong input format");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//bool registers
|
||||||
|
private static ParseResult TryBuildBoolean (string plcAddrName) {
|
||||||
|
|
||||||
|
//regex to find special register values
|
||||||
|
var patternBool = new Regex(@"(?<prefix>X|Y|R)(?<area>[0-9]{0,3})(?<special>(?:[0-9]|[A-F]){1})?");
|
||||||
|
|
||||||
|
var match = patternBool.Match(plcAddrName);
|
||||||
|
|
||||||
|
if (!match.Success)
|
||||||
|
return new ParseResult {
|
||||||
|
state = ParseResultState.FailedSoft
|
||||||
|
};
|
||||||
|
|
||||||
|
string prefix = match.Groups["prefix"].Value;
|
||||||
|
string area = match.Groups["area"].Value;
|
||||||
|
string special = match.Groups["special"].Value;
|
||||||
|
|
||||||
|
IOType regType;
|
||||||
|
int areaAdd = 0;
|
||||||
|
byte specialAdd = 0x0;
|
||||||
|
|
||||||
|
//try cast the prefix
|
||||||
|
if(!Enum.TryParse(prefix, out regType)) {
|
||||||
|
|
||||||
|
return new ParseResult {
|
||||||
|
state = ParseResultState.FailedHard,
|
||||||
|
hardFailReason = $"Cannot parse '{plcAddrName}', the prefix is not allowed for boolean registers"
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!string.IsNullOrEmpty(area) && !int.TryParse(area, out areaAdd) ) {
|
||||||
|
|
||||||
|
return new ParseResult {
|
||||||
|
state = ParseResultState.FailedHard,
|
||||||
|
hardFailReason = $"Cannot parse '{plcAddrName}', the area address: '{area}' is wrong"
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//special address not given
|
||||||
|
if(string.IsNullOrEmpty(special) && !string.IsNullOrEmpty(area)) {
|
||||||
|
|
||||||
|
var isAreaInt = int.TryParse(area, NumberStyles.Number, CultureInfo.InvariantCulture, out var areaInt);
|
||||||
|
|
||||||
|
if (isAreaInt && areaInt >= 0 && areaInt <= 9) {
|
||||||
|
|
||||||
|
//area address is actually meant as special address but 0-9
|
||||||
|
specialAdd = (byte)areaInt;
|
||||||
|
areaAdd = 0;
|
||||||
|
|
||||||
|
|
||||||
|
} else if (isAreaInt && areaInt > 9) {
|
||||||
|
|
||||||
|
//area adress is meant to be the actual area address
|
||||||
|
areaAdd = areaInt;
|
||||||
|
specialAdd = 0;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
return new ParseResult {
|
||||||
|
state = ParseResultState.FailedHard,
|
||||||
|
hardFailReason = $"Cannot parse '{plcAddrName}', the special address: '{special}' is wrong 1",
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
//special address parsed as hex num
|
||||||
|
if (!byte.TryParse(special, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out specialAdd)) {
|
||||||
|
|
||||||
|
return new ParseResult {
|
||||||
|
state = ParseResultState.FailedHard,
|
||||||
|
hardFailReason = $"Cannot parse '{plcAddrName}', the special address: '{special}' is wrong 2",
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return new ParseResult {
|
||||||
|
state = ParseResultState.Success,
|
||||||
|
stepData = new RegisterBuilderStep ((RegisterType)(int)regType, areaAdd, specialAdd),
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// one to two word registers
|
||||||
|
private static ParseResult TryBuildNumericBased (string plcAddrName) {
|
||||||
|
|
||||||
|
var patternByte = new Regex(@"(?<prefix>DT|DDT)(?<area>[0-9]{1,5})");
|
||||||
|
|
||||||
|
var match = patternByte.Match(plcAddrName);
|
||||||
|
|
||||||
|
if (!match.Success)
|
||||||
|
return new ParseResult {
|
||||||
|
state = ParseResultState.FailedSoft
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
string prefix = match.Groups["prefix"].Value;
|
||||||
|
string area = match.Groups["area"].Value;
|
||||||
|
|
||||||
|
RegisterType regType;
|
||||||
|
int areaAdd = 0;
|
||||||
|
|
||||||
|
//try cast the prefix
|
||||||
|
if (!Enum.TryParse(prefix, out regType)) {
|
||||||
|
|
||||||
|
return new ParseResult {
|
||||||
|
state = ParseResultState.FailedHard,
|
||||||
|
hardFailReason = $"Cannot parse '{plcAddrName}', the prefix is not allowed for numeric registers"
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(area) && !int.TryParse(area, out areaAdd)) {
|
||||||
|
|
||||||
|
return new ParseResult {
|
||||||
|
state = ParseResultState.FailedHard,
|
||||||
|
hardFailReason = $"Cannot parse '{plcAddrName}', the area address: '{area}' is wrong"
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return new ParseResult {
|
||||||
|
state = ParseResultState.Success,
|
||||||
|
stepData = new RegisterBuilderStep(regType, areaAdd),
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
namespace MewtocolNet.RegisterBuilding {
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Contains useful tools for register creation
|
|
||||||
/// </summary>
|
|
||||||
public static class RegisterBuilder {
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Parses a register from its PLC name
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="name">The name, fe. DT100</param>
|
|
||||||
/// <param name="reg">An <see cref="IRegister"/> or null if </param>
|
|
||||||
/// <returns>True if successfully parsed</returns>
|
|
||||||
public static bool TryBuildFromName(string name, out IRegister reg) {
|
|
||||||
|
|
||||||
reg = null;
|
|
||||||
|
|
||||||
return false;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
92
MewtocolNet/RegisterBuilding/RegisterBuilderStep.cs
Normal file
92
MewtocolNet/RegisterBuilding/RegisterBuilderStep.cs
Normal file
@@ -0,0 +1,92 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace MewtocolNet.RegisterBuilding {
|
||||||
|
public class RegisterBuilderStep {
|
||||||
|
|
||||||
|
internal bool wasCasted = false;
|
||||||
|
|
||||||
|
internal string OriginalInput;
|
||||||
|
|
||||||
|
internal string Name;
|
||||||
|
internal RegisterType RegType;
|
||||||
|
internal int MemAddress;
|
||||||
|
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<T> () {
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
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_START:
|
||||||
|
dotnetVarType = typeof(string);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
plcVarType = null;
|
||||||
|
|
||||||
|
wasCasted = true;
|
||||||
|
|
||||||
|
return this;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -18,28 +18,23 @@
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
R = 2,
|
R = 2,
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Data area as a short (Register)
|
/// Single word area (Register)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
DT_short = 3,
|
DT = 3,
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Data area as an unsigned short (Register)
|
/// Double word area (Register)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
DT_ushort = 4,
|
DDT = 4,
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Double data area as an integer (Register)
|
/// Start area of a byte sequence longer than 2 words
|
||||||
/// </summary>
|
/// </summary>
|
||||||
DDT_int = 5,
|
DT_START = 5,
|
||||||
/// <summary>
|
|
||||||
/// Double data area as an unsigned integer (Register)
|
|
||||||
/// </summary>
|
|
||||||
DDT_uint = 6,
|
|
||||||
/// <summary>
|
|
||||||
/// Double data area as an floating point number (Register)
|
|
||||||
/// </summary>
|
|
||||||
DDT_float = 7,
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// this is just used as syntactic sugar,
|
||||||
|
// when creating registers that are R/X/Y typed you dont need the DT types
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The type of an input/output register
|
/// The type of an input/output register
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ namespace MewtocolNet.Registers {
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public event PropertyChangedEventHandler PropertyChanged;
|
public event PropertyChangedEventHandler PropertyChanged;
|
||||||
|
|
||||||
internal RegisterType RegType { get; private set; }
|
public RegisterType RegisterType { get; private set; }
|
||||||
|
|
||||||
internal Type collectionType;
|
internal Type collectionType;
|
||||||
|
|
||||||
@@ -80,7 +80,7 @@ namespace MewtocolNet.Registers {
|
|||||||
specialAddress = _spAddress;
|
specialAddress = _spAddress;
|
||||||
name = _name;
|
name = _name;
|
||||||
|
|
||||||
RegType = (RegisterType)(int)_io;
|
RegisterType = (RegisterType)(int)_io;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -91,13 +91,15 @@ namespace MewtocolNet.Registers {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public byte? GetSpecialAddress() => SpecialAddress;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Builds the register area name
|
/// Builds the register area name
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string BuildMewtocolQuery() {
|
public string BuildMewtocolQuery() {
|
||||||
|
|
||||||
//build area code from register type
|
//build area code from register type
|
||||||
StringBuilder asciistring = new StringBuilder(RegType.ToString());
|
StringBuilder asciistring = new StringBuilder(RegisterType.ToString());
|
||||||
|
|
||||||
string memPadded = MemoryAddress.ToString().PadLeft(4, '0');
|
string memPadded = MemoryAddress.ToString().PadLeft(4, '0');
|
||||||
string sp = SpecialAddress.ToString("X1");
|
string sp = SpecialAddress.ToString("X1");
|
||||||
@@ -127,11 +129,13 @@ namespace MewtocolNet.Registers {
|
|||||||
|
|
||||||
public Type GetCollectionType() => CollectionType;
|
public Type GetCollectionType() => CollectionType;
|
||||||
|
|
||||||
|
public RegisterType GetRegisterType() => RegisterType;
|
||||||
|
|
||||||
public string GetValueString() => Value.ToString();
|
public string GetValueString() => Value.ToString();
|
||||||
|
|
||||||
public void ClearValue() => SetValueFromPLC(false);
|
public void ClearValue() => SetValueFromPLC(false);
|
||||||
|
|
||||||
public string GetRegisterString() => RegType.ToString();
|
public string GetRegisterString() => RegisterType.ToString();
|
||||||
|
|
||||||
public string GetCombinedName() => $"{(CollectionType != null ? $"{CollectionType.Name}." : "")}{Name ?? "Unnamed"}";
|
public string GetCombinedName() => $"{(CollectionType != null ? $"{CollectionType.Name}." : "")}{Name ?? "Unnamed"}";
|
||||||
|
|
||||||
@@ -163,6 +167,22 @@ namespace MewtocolNet.Registers {
|
|||||||
|
|
||||||
public override string ToString() => $"{GetRegisterPLCName()} - Value: {GetValueString()}";
|
public override string ToString() => $"{GetRegisterPLCName()} - Value: {GetValueString()}";
|
||||||
|
|
||||||
|
public string ToString(bool additional) {
|
||||||
|
|
||||||
|
if (!additional) return this.ToString();
|
||||||
|
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
sb.AppendLine($"PLC Naming: {GetRegisterPLCName()}");
|
||||||
|
sb.AppendLine($"Name: {Name ?? "Not named"}");
|
||||||
|
sb.AppendLine($"Value: {GetValueString()}");
|
||||||
|
sb.AppendLine($"Register Type: {RegisterType}");
|
||||||
|
sb.AppendLine($"Memory Address: {MemoryAddress}");
|
||||||
|
sb.AppendLine($"Special Address: {SpecialAddress:X1}");
|
||||||
|
|
||||||
|
return sb.ToString();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,6 +22,8 @@ namespace MewtocolNet.Registers {
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public event PropertyChangedEventHandler PropertyChanged;
|
public event PropertyChangedEventHandler PropertyChanged;
|
||||||
|
|
||||||
|
public RegisterType RegisterType { get; private set; }
|
||||||
|
|
||||||
internal Type collectionType;
|
internal Type collectionType;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -87,9 +89,16 @@ namespace MewtocolNet.Registers {
|
|||||||
throw new NotSupportedException($"The type {numType} is not allowed for Number Registers");
|
throw new NotSupportedException($"The type {numType} is not allowed for Number Registers");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//set register type
|
||||||
|
if(memoryLength == 1) {
|
||||||
|
RegisterType = RegisterType.DDT;
|
||||||
|
} else {
|
||||||
|
RegisterType = RegisterType.DT;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal NRegister(int _adress, string _name = null, bool isBitwise = false, Type _enumType = null) {
|
}
|
||||||
|
|
||||||
|
public NRegister (int _adress, string _name = null, bool isBitwise = false, Type _enumType = null) {
|
||||||
|
|
||||||
if (_adress > 99999) throw new NotSupportedException("Memory adresses cant be greater than 99999");
|
if (_adress > 99999) throw new NotSupportedException("Memory adresses cant be greater than 99999");
|
||||||
memoryAdress = _adress;
|
memoryAdress = _adress;
|
||||||
@@ -111,6 +120,13 @@ namespace MewtocolNet.Registers {
|
|||||||
throw new NotSupportedException($"The type {numType} is not allowed for Number Registers");
|
throw new NotSupportedException($"The type {numType} is not allowed for Number Registers");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//set register type
|
||||||
|
if (memoryLength == 1) {
|
||||||
|
RegisterType = RegisterType.DDT;
|
||||||
|
} else {
|
||||||
|
RegisterType = RegisterType.DT;
|
||||||
|
}
|
||||||
|
|
||||||
isUsedBitwise = isBitwise;
|
isUsedBitwise = isBitwise;
|
||||||
enumType = _enumType;
|
enumType = _enumType;
|
||||||
|
|
||||||
@@ -131,6 +147,8 @@ namespace MewtocolNet.Registers {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public byte? GetSpecialAddress() => null;
|
||||||
|
|
||||||
public string GetStartingMemoryArea() => MemoryAddress.ToString();
|
public string GetStartingMemoryArea() => MemoryAddress.ToString();
|
||||||
|
|
||||||
public Type GetCollectionType() => CollectionType;
|
public Type GetCollectionType() => CollectionType;
|
||||||
@@ -267,8 +285,12 @@ namespace MewtocolNet.Registers {
|
|||||||
|
|
||||||
public void TriggerNotifyChange() => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Value"));
|
public void TriggerNotifyChange() => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Value"));
|
||||||
|
|
||||||
|
public RegisterType GetRegisterType() => RegisterType;
|
||||||
|
|
||||||
public override string ToString() => $"{GetRegisterPLCName()} - Value: {GetValueString()}";
|
public override string ToString() => $"{GetRegisterPLCName()} - Value: {GetValueString()}";
|
||||||
|
|
||||||
|
public string ToString(bool additional) => $"{GetRegisterPLCName()} - Value: {GetValueString()}";
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,6 +19,8 @@ namespace MewtocolNet.Registers {
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public event PropertyChangedEventHandler PropertyChanged;
|
public event PropertyChangedEventHandler PropertyChanged;
|
||||||
|
|
||||||
|
public RegisterType RegisterType { get; private set; }
|
||||||
|
|
||||||
internal Type collectionType;
|
internal Type collectionType;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -69,6 +71,8 @@ namespace MewtocolNet.Registers {
|
|||||||
wordsize++;
|
wordsize++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RegisterType = RegisterType.DT_START;
|
||||||
|
|
||||||
memoryLength = (int)Math.Round(wordsize + 1);
|
memoryLength = (int)Math.Round(wordsize + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -105,6 +109,8 @@ namespace MewtocolNet.Registers {
|
|||||||
return asciistring.ToString();
|
return asciistring.ToString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public byte? GetSpecialAddress() => null;
|
||||||
|
|
||||||
public Type GetCollectionType() => CollectionType;
|
public Type GetCollectionType() => CollectionType;
|
||||||
|
|
||||||
public bool IsUsedBitwise() => false;
|
public bool IsUsedBitwise() => false;
|
||||||
@@ -138,6 +144,8 @@ namespace MewtocolNet.Registers {
|
|||||||
|
|
||||||
public override string ToString() => $"{GetRegisterPLCName()} - Value: {GetValueString()}";
|
public override string ToString() => $"{GetRegisterPLCName()} - Value: {GetValueString()}";
|
||||||
|
|
||||||
|
public string ToString(bool additional) => $"{GetRegisterPLCName()} - Value: {GetValueString()}";
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
using MewtocolNet;
|
using MewtocolNet;
|
||||||
using MewtocolNet.Logging;
|
using MewtocolNet.Logging;
|
||||||
using MewtocolNet.PLCEnums;
|
|
||||||
using Xunit;
|
using Xunit;
|
||||||
using Xunit.Abstractions;
|
using Xunit.Abstractions;
|
||||||
|
|
||||||
|
|||||||
204
MewtocolTests/TestRegisterBuilder.cs
Normal file
204
MewtocolTests/TestRegisterBuilder.cs
Normal file
@@ -0,0 +1,204 @@
|
|||||||
|
using MewtocolNet;
|
||||||
|
using MewtocolNet.RegisterBuilding;
|
||||||
|
using MewtocolNet.Registers;
|
||||||
|
using System.Collections;
|
||||||
|
using Xunit;
|
||||||
|
using Xunit.Abstractions;
|
||||||
|
using static System.Net.Mime.MediaTypeNames;
|
||||||
|
|
||||||
|
namespace MewtocolTests;
|
||||||
|
|
||||||
|
public class TestRegisterBuilder {
|
||||||
|
|
||||||
|
private readonly ITestOutputHelper output;
|
||||||
|
|
||||||
|
public TestRegisterBuilder(ITestOutputHelper output) {
|
||||||
|
this.output = output;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact(DisplayName = "Parsing as BRegister List (Phyiscal Outputs)")]
|
||||||
|
public void TestParsingBRegisterY() {
|
||||||
|
|
||||||
|
var tests = new Dictionary<string, IRegister>() {
|
||||||
|
|
||||||
|
{"Y0", new BRegister(IOType.Y)},
|
||||||
|
{"Y1", new BRegister(IOType.Y, 0x1)},
|
||||||
|
{"Y2", new BRegister(IOType.Y, 0x2)},
|
||||||
|
{"Y3", new BRegister(IOType.Y, 0x3)},
|
||||||
|
{"Y4", new BRegister(IOType.Y, 0x4)},
|
||||||
|
{"Y5", new BRegister(IOType.Y, 0x5)},
|
||||||
|
{"Y6", new BRegister(IOType.Y, 0x6)},
|
||||||
|
{"Y7", new BRegister(IOType.Y, 0x7)},
|
||||||
|
{"Y8", new BRegister(IOType.Y, 0x8)},
|
||||||
|
{"Y9", new BRegister(IOType.Y, 0x9)},
|
||||||
|
|
||||||
|
{"YA", new BRegister(IOType.Y, 0xA)},
|
||||||
|
{"YB", new BRegister(IOType.Y, 0xB)},
|
||||||
|
{"YC", new BRegister(IOType.Y, 0xC)},
|
||||||
|
{"YD", new BRegister(IOType.Y, 0xD)},
|
||||||
|
{"YE", new BRegister(IOType.Y, 0xE)},
|
||||||
|
{"YF", new BRegister(IOType.Y, 0xF)},
|
||||||
|
|
||||||
|
{"Y1A", new BRegister(IOType.Y, 0xA, 1)},
|
||||||
|
{"Y10B", new BRegister(IOType.Y, 0xB, 10)},
|
||||||
|
{"Y109C", new BRegister(IOType.Y, 0xC, 109)},
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
TestBoolDict(tests);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact(DisplayName = "Parsing as BRegister List (Phyiscal Inputs)")]
|
||||||
|
public void TestParsingBRegisterX() {
|
||||||
|
|
||||||
|
var tests = new Dictionary<string, IRegister>() {
|
||||||
|
|
||||||
|
{"X0", new BRegister(IOType.X)},
|
||||||
|
{"X1", new BRegister(IOType.X, 0x1)},
|
||||||
|
{"X2", new BRegister(IOType.X, 0x2)},
|
||||||
|
{"X3", new BRegister(IOType.X, 0x3)},
|
||||||
|
{"X4", new BRegister(IOType.X, 0x4)},
|
||||||
|
{"X5", new BRegister(IOType.X, 0x5)},
|
||||||
|
{"X6", new BRegister(IOType.X, 0x6)},
|
||||||
|
{"X7", new BRegister(IOType.X, 0x7)},
|
||||||
|
{"X8", new BRegister(IOType.X, 0x8)},
|
||||||
|
{"X9", new BRegister(IOType.X, 0x9)},
|
||||||
|
|
||||||
|
{"XA", new BRegister(IOType.X, 0xA)},
|
||||||
|
{"XB", new BRegister(IOType.X, 0xB)},
|
||||||
|
{"XC", new BRegister(IOType.X, 0xC)},
|
||||||
|
{"XD", new BRegister(IOType.X, 0xD)},
|
||||||
|
{"XE", new BRegister(IOType.X, 0xE)},
|
||||||
|
{"XF", new BRegister(IOType.X, 0xF)},
|
||||||
|
|
||||||
|
{"X1A", new BRegister(IOType.X, 0xA, 1)},
|
||||||
|
{"X10B", new BRegister(IOType.X, 0xB, 10)},
|
||||||
|
{"X109C", new BRegister(IOType.X, 0xC, 109)},
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
TestBoolDict(tests);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact(DisplayName = "Parsing as BRegister List (Internal Relay)")]
|
||||||
|
public void TestParsingBRegisterR() {
|
||||||
|
|
||||||
|
var tests = new Dictionary<string, IRegister>() {
|
||||||
|
|
||||||
|
{"R0", new BRegister(IOType.R)},
|
||||||
|
{"R1", new BRegister(IOType.R, 0x1)},
|
||||||
|
{"R2", new BRegister(IOType.R, 0x2)},
|
||||||
|
{"R3", new BRegister(IOType.R, 0x3)},
|
||||||
|
{"R4", new BRegister(IOType.R, 0x4)},
|
||||||
|
{"R5", new BRegister(IOType.R, 0x5)},
|
||||||
|
{"R6", new BRegister(IOType.R, 0x6)},
|
||||||
|
{"R7", new BRegister(IOType.R, 0x7)},
|
||||||
|
{"R8", new BRegister(IOType.R, 0x8)},
|
||||||
|
{"R9", new BRegister(IOType.R, 0x9)},
|
||||||
|
|
||||||
|
{"RA", new BRegister(IOType.R, 0xA)},
|
||||||
|
{"RB", new BRegister(IOType.R, 0xB)},
|
||||||
|
{"RC", new BRegister(IOType.R, 0xC)},
|
||||||
|
{"RD", new BRegister(IOType.R, 0xD)},
|
||||||
|
{"RE", new BRegister(IOType.R, 0xE)},
|
||||||
|
{"RF", new BRegister(IOType.R, 0xF)},
|
||||||
|
|
||||||
|
{"R1A", new BRegister(IOType.R, 0xA, 1)},
|
||||||
|
{"R10B", new BRegister(IOType.R, 0xB, 10)},
|
||||||
|
{"R109C", new BRegister(IOType.R, 0xC, 109)},
|
||||||
|
{"R1000", new BRegister(IOType.R, 0x0, 100)},
|
||||||
|
{"R511", new BRegister(IOType.R, 0x0, 511)},
|
||||||
|
{"R511A", new BRegister(IOType.R, 0xA, 511)},
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
TestBoolDict(tests);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void TestBoolDict (Dictionary<string, IRegister> dict) {
|
||||||
|
|
||||||
|
foreach (var item in dict) {
|
||||||
|
|
||||||
|
try {
|
||||||
|
|
||||||
|
output.WriteLine($"Expected: {item.Key}");
|
||||||
|
|
||||||
|
var built = RegBuilder.FromPlcRegName(item.Key).AsPlcType(PlcVarType.BOOL).Build();
|
||||||
|
|
||||||
|
output.WriteLine($"{(built?.ToString(true) ?? "null")}\n");
|
||||||
|
Assert.Equivalent(item.Value, built);
|
||||||
|
|
||||||
|
} catch (Exception ex) {
|
||||||
|
|
||||||
|
output.WriteLine(ex.Message.ToString());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact(DisplayName = "Parsing as BRegister (Casted)")]
|
||||||
|
public void TestRegisterBuildingBoolCasted () {
|
||||||
|
|
||||||
|
var expect = new BRegister(IOType.R, 0x1, 0);
|
||||||
|
var expect2 = new BRegister(IOType.Y, 0xA, 103);
|
||||||
|
|
||||||
|
Assert.Equivalent(expect, RegBuilder.FromPlcRegName("R1").AsPlcType(PlcVarType.BOOL).Build());
|
||||||
|
Assert.Equivalent(expect, RegBuilder.FromPlcRegName("R1").AsType<bool>().Build());
|
||||||
|
|
||||||
|
Assert.Equivalent(expect2, RegBuilder.FromPlcRegName("Y103A").AsPlcType(PlcVarType.BOOL).Build());
|
||||||
|
Assert.Equivalent(expect2, RegBuilder.FromPlcRegName("Y103A").AsType<bool>().Build());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact(DisplayName = "Parsing as BRegister (Auto)")]
|
||||||
|
public void TestRegisterBuildingBoolAuto () {
|
||||||
|
|
||||||
|
var expect = new BRegister(IOType.R, 0x1, 0);
|
||||||
|
var expect2 = new BRegister(IOType.Y, 0xA, 103);
|
||||||
|
|
||||||
|
Assert.Equivalent(expect, RegBuilder.FromPlcRegName("R1").Build());
|
||||||
|
Assert.Equivalent(expect, RegBuilder.FromPlcRegName("R1").Build());
|
||||||
|
|
||||||
|
Assert.Equivalent(expect2, RegBuilder.FromPlcRegName("Y103A").Build());
|
||||||
|
Assert.Equivalent(expect2, RegBuilder.FromPlcRegName("Y103A").Build());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact(DisplayName = "Parsing as NRegister (Casted)")]
|
||||||
|
public void TestRegisterBuildingNumericCasted() {
|
||||||
|
|
||||||
|
var expect = new NRegister<short>(303, null);
|
||||||
|
var expect2 = new NRegister<int>(10002, null);
|
||||||
|
var expect3 = new NRegister<TimeSpan>(400, null);
|
||||||
|
//var expect4 = new NRegister<TimeSpan>(103, null, true);
|
||||||
|
|
||||||
|
Assert.Equivalent(expect, RegBuilder.FromPlcRegName("DT303").AsPlcType(PlcVarType.INT).Build());
|
||||||
|
Assert.Equivalent(expect, RegBuilder.FromPlcRegName("DT303").AsType<short>().Build());
|
||||||
|
|
||||||
|
Assert.Equivalent(expect2, RegBuilder.FromPlcRegName("DDT10002").AsPlcType(PlcVarType.DINT).Build());
|
||||||
|
Assert.Equivalent(expect2, RegBuilder.FromPlcRegName("DDT10002").AsType<int>().Build());
|
||||||
|
|
||||||
|
Assert.Equivalent(expect3, RegBuilder.FromPlcRegName("DDT400").AsPlcType(PlcVarType.TIME).Build());
|
||||||
|
Assert.Equivalent(expect3, RegBuilder.FromPlcRegName("DDT400").AsType<TimeSpan>().Build());
|
||||||
|
|
||||||
|
//Assert.Equivalent(expect4, RegBuilder.FromPlcRegName("DT103").AsType<BitArray>().Build());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact(DisplayName = "Parsing as NRegister (Auto)")]
|
||||||
|
public void TestRegisterBuildingNumericAuto() {
|
||||||
|
|
||||||
|
var expect = new NRegister<short>(303, null);
|
||||||
|
var expect2 = new NRegister<int>(10002, null);
|
||||||
|
|
||||||
|
Assert.Equivalent(expect, RegBuilder.FromPlcRegName("DT303").Build());
|
||||||
|
Assert.Equivalent(expect2, RegBuilder.FromPlcRegName("DDT10002").Build());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,78 +0,0 @@
|
|||||||
using MewtocolNet;
|
|
||||||
using MewtocolNet.Registers;
|
|
||||||
using Xunit;
|
|
||||||
using Xunit.Abstractions;
|
|
||||||
|
|
||||||
namespace MewtocolTests;
|
|
||||||
|
|
||||||
public class TestRegisterParsing {
|
|
||||||
|
|
||||||
private readonly ITestOutputHelper output;
|
|
||||||
|
|
||||||
public TestRegisterParsing(ITestOutputHelper output) {
|
|
||||||
this.output = output;
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact(DisplayName = "Parsing as BRegister (Phyiscal Outputs)")]
|
|
||||||
public void TestParsingBRegisterY() {
|
|
||||||
|
|
||||||
var tests = new Dictionary<string, IRegister>() {
|
|
||||||
|
|
||||||
{"Y0", new BRegister(IOType.Y)},
|
|
||||||
{"Y1", new BRegister(IOType.Y, 0x1)},
|
|
||||||
{"Y2", new BRegister(IOType.Y, 0x2)},
|
|
||||||
{"Y3", new BRegister(IOType.Y, 0x3)},
|
|
||||||
{"Y4", new BRegister(IOType.Y, 0x4)},
|
|
||||||
{"Y5", new BRegister(IOType.Y, 0x5)},
|
|
||||||
{"Y6", new BRegister(IOType.Y, 0x6)},
|
|
||||||
{"Y7", new BRegister(IOType.Y, 0x7)},
|
|
||||||
{"Y8", new BRegister(IOType.Y, 0x8)},
|
|
||||||
{"Y9", new BRegister(IOType.Y, 0x9)},
|
|
||||||
|
|
||||||
{"YA", new BRegister(IOType.Y, 0xA)},
|
|
||||||
{"YB", new BRegister(IOType.Y, 0xB)},
|
|
||||||
{"YC", new BRegister(IOType.Y, 0xC)},
|
|
||||||
{"YD", new BRegister(IOType.Y, 0xD)},
|
|
||||||
{"YE", new BRegister(IOType.Y, 0xE)},
|
|
||||||
{"YF", new BRegister(IOType.Y, 0xF)},
|
|
||||||
|
|
||||||
{"Y1A", new BRegister(IOType.Y, 0xA, 1)},
|
|
||||||
{"Y10B", new BRegister(IOType.Y, 0xB, 10)},
|
|
||||||
{"Y109C", new BRegister(IOType.Y, 0xC, 109)},
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact(DisplayName = "Parsing as BRegister (Phyiscal Inputs)")]
|
|
||||||
public void TestParsingBRegisterX() {
|
|
||||||
|
|
||||||
var tests = new Dictionary<string, IRegister>() {
|
|
||||||
|
|
||||||
{"X0", new BRegister(IOType.X)},
|
|
||||||
{"X1", new BRegister(IOType.X, 0x1)},
|
|
||||||
{"X2", new BRegister(IOType.X, 0x2)},
|
|
||||||
{"X3", new BRegister(IOType.X, 0x3)},
|
|
||||||
{"X4", new BRegister(IOType.X, 0x4)},
|
|
||||||
{"X5", new BRegister(IOType.X, 0x5)},
|
|
||||||
{"X6", new BRegister(IOType.X, 0x6)},
|
|
||||||
{"X7", new BRegister(IOType.X, 0x7)},
|
|
||||||
{"X8", new BRegister(IOType.X, 0x8)},
|
|
||||||
{"X9", new BRegister(IOType.X, 0x9)},
|
|
||||||
|
|
||||||
{"XA", new BRegister(IOType.X, 0xA)},
|
|
||||||
{"XB", new BRegister(IOType.X, 0xB)},
|
|
||||||
{"XC", new BRegister(IOType.X, 0xC)},
|
|
||||||
{"XD", new BRegister(IOType.X, 0xD)},
|
|
||||||
{"XE", new BRegister(IOType.X, 0xE)},
|
|
||||||
{"XF", new BRegister(IOType.X, 0xF)},
|
|
||||||
|
|
||||||
{"X1A", new BRegister(IOType.X, 0xA, 1)},
|
|
||||||
{"X10B", new BRegister(IOType.X, 0xB, 10)},
|
|
||||||
{"X109C", new BRegister(IOType.X, 0xC, 109)},
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user