diff --git a/Examples/ExampleScenarios.cs b/Examples/ExampleScenarios.cs index bd2244a..df60f16 100644 --- a/Examples/ExampleScenarios.cs +++ b/Examples/ExampleScenarios.cs @@ -6,6 +6,7 @@ using System.Threading.Tasks; using System.Collections; using MewtocolNet.RegisterBuilding; using System.Collections.Generic; +using MewtocolNet.Registers; namespace Examples; @@ -46,7 +47,7 @@ public class ExampleScenarios { while (interf.IsConnected) { //flip the bool register each tick and wait for it to be registered - await interf.SetRegisterAsync(nameof(registers.TestBool1), !registers.TestBool1); + //await interf.SetRegisterAsync(nameof(registers.TestBool1), !registers.TestBool1); Console.Title = $"Polling Paused: {interf.PollingPaused}, " + $"Poller active: {interf.PollerActive}, " + @@ -167,7 +168,7 @@ public class ExampleScenarios { await interf.ConnectAsync(); //use the async method to make sure the cycling is stopped - await interf.SetRegisterAsync(nameof(registers.StartCyclePLC), false); + //await interf.SetRegisterAsync(nameof(registers.StartCyclePLC), false); await Task.Delay(5000); @@ -182,4 +183,49 @@ public class ExampleScenarios { } + [Scenario("Read register test")] + public async Task RunReadTest () { + + Console.WriteLine("Starting auto enums and bitwise"); + + //setting up a new PLC interface and register collection + MewtocolInterface interf = new MewtocolInterface("192.168.115.210").WithPoller(); + + //auto add all built registers to the interface + var builder = RegBuilder.ForInterface(interf); + var r0reg = builder.FromPlcRegName("R0").Build(); + builder.FromPlcRegName("R1").Build(); + builder.FromPlcRegName("R1F").Build(); + builder.FromPlcRegName("R101A").Build(); + + var shortReg = builder.FromPlcRegName("DT35").AsPlcType(PlcVarType.INT).Build(); + builder.FromPlcRegName("DDT36").AsPlcType(PlcVarType.DINT).Build(); + + //builder.FromPlcRegName("DDT38").AsPlcType(PlcVarType.TIME).Build(); + //builder.FromPlcRegName("DT40").AsPlcType(PlcVarType.STRING).Build(); + + //connect + await interf.ConnectAsync(); + + //var res = await interf.SendCommandAsync("%01#RCSR000F"); + + while(true) { + + await interf.SetRegisterAsync(r0reg, !(bool)r0reg.Value); + await interf.SetRegisterAsync(shortReg, (short)new Random().Next(0, 100)); + + foreach (var reg in interf.Registers) { + + Console.WriteLine($"Register {reg.GetRegisterPLCName()} val: {reg.Value}"); + + } + + Console.WriteLine(); + + await Task.Delay(1000); + + } + + } + } diff --git a/Examples/Program.cs b/Examples/Program.cs index a868993..57c913f 100644 --- a/Examples/Program.cs +++ b/Examples/Program.cs @@ -14,9 +14,6 @@ class Program { 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) => { Console.WriteLine(e.ExceptionObject.ToString()); }; diff --git a/Examples/TestRegisters.cs b/Examples/TestRegisters.cs index afe76f7..4b13ca1 100644 --- a/Examples/TestRegisters.cs +++ b/Examples/TestRegisters.cs @@ -47,10 +47,10 @@ namespace Examples { public BitArray TestBitRegister { get; private set; } //corresponds to a DT1204 as a 16bit word/int takes the bit at index 9 and writes it back as a boolean - [Register(1204, 9, BitCount.B16)] + [Register(1204, BitCount.B16, 9)] public bool BitValue { get; private set; } - [Register(1204, 5, BitCount.B16)] + [Register(1204, BitCount.B16, 5)] public bool FillTest { get; private set; } //corresponds to a DT7012 - DT7013 as a 32bit time value that gets parsed as a timespan (TIME) diff --git a/Examples/TestRegistersEnumBitwise.cs b/Examples/TestRegistersEnumBitwise.cs index ea4954c..72f5ede 100644 --- a/Examples/TestRegistersEnumBitwise.cs +++ b/Examples/TestRegistersEnumBitwise.cs @@ -53,52 +53,52 @@ namespace Examples { //you can also extract single bits from DT503 - [Register(503, 0, BitCount.B16)] + [Register(503, BitCount.B16, 0)] public bool BitValue0 { get; private set; } - [Register(503, 1, BitCount.B16)] + [Register(503, BitCount.B16, 1)] public bool BitValue1 { get; private set; } - [Register(503, 2, BitCount.B16)] + [Register(503, BitCount.B16, 2)] public bool BitValue2 { get; private set; } - [Register(503, 3, BitCount.B16)] + [Register(503, BitCount.B16, 3)] public bool BitValue3 { get; private set; } - [Register(503, 4, BitCount.B16)] + [Register(503, BitCount.B16, 4)] public bool BitValue4 { get; private set; } - [Register(503, 5, BitCount.B16)] + [Register(503, BitCount.B16, 5)] public bool BitValue5 { get; private set; } - [Register(503, 6, BitCount.B16)] + [Register(503, BitCount.B16, 6)] public bool BitValue6 { get; private set; } - [Register(503, 7, BitCount.B16)] + [Register(503, BitCount.B16, 7)] public bool BitValue7 { get; private set; } - [Register(503, 8, BitCount.B16)] + [Register(503, BitCount.B16, 8)] public bool BitValue8 { get; private set; } - [Register(503, 9, BitCount.B16)] + [Register(503, BitCount.B16, 9)] public bool BitValue9 { get; private set; } - [Register(503, 10, BitCount.B16)] + [Register(503, BitCount.B16, 10)] public bool BitValue10 { get; private set; } - [Register(503, 11, BitCount.B16)] + [Register(503, BitCount.B16, 11)] public bool BitValue11 { get; private set; } - [Register(503, 12, BitCount.B16)] + [Register(503, BitCount.B16, 12)] public bool BitValue12 { get; private set; } - [Register(503, 13, BitCount.B16)] + [Register(503, BitCount.B16, 13)] public bool BitValue13 { get; private set; } - [Register(503, 14, BitCount.B16)] + [Register(503, BitCount.B16, 14)] public bool BitValue14 { get; private set; } - [Register(503, 15, BitCount.B16)] + [Register(503, BitCount.B16, 15)] public bool BitValue15 { get; private set; } } diff --git a/MewtocolNet/DynamicInterface.cs b/MewtocolNet/DynamicInterface.cs index f13ceff..1bd86c6 100644 --- a/MewtocolNet/DynamicInterface.cs +++ b/MewtocolNet/DynamicInterface.cs @@ -1,12 +1,16 @@ -using MewtocolNet.Logging; +using MewtocolNet.Exceptions; +using MewtocolNet.Logging; +using MewtocolNet.RegisterAttributes; using MewtocolNet.Registers; using System; +using System.Collections; using System.Collections.Generic; using System.Linq; using System.Reflection; using System.Threading.Tasks; -namespace MewtocolNet { +namespace MewtocolNet +{ /// /// The PLC com interface class @@ -118,61 +122,21 @@ namespace MewtocolNet { var reg = Registers[iteration]; - if (reg is NRegister shortReg) { - var lastVal = shortReg.Value; - var readout = (await ReadNumRegister(shortReg)).Register.Value; + if(reg.IsAllowedRegisterGenericType()) { + + var lastVal = reg.Value; + + var rwReg = (IRegisterInternal)reg; + + var readout = await rwReg.ReadAsync(this); + if (lastVal != readout) { - InvokeRegisterChanged(shortReg); - } - } - if (reg is NRegister ushortReg) { - var lastVal = ushortReg.Value; - var readout = (await ReadNumRegister(ushortReg)).Register.Value; - if (lastVal != readout) { - InvokeRegisterChanged(ushortReg); - } - } - if (reg is NRegister intReg) { - var lastVal = intReg.Value; - var readout = (await ReadNumRegister(intReg)).Register.Value; - if (lastVal != readout) { - InvokeRegisterChanged(intReg); - } - } - if (reg is NRegister uintReg) { - var lastVal = uintReg.Value; - var readout = (await ReadNumRegister(uintReg)).Register.Value; - if (lastVal != readout) { - InvokeRegisterChanged(uintReg); - } - } - if (reg is NRegister floatReg) { - var lastVal = floatReg.Value; - var readout = (await ReadNumRegister(floatReg)).Register.Value; - if (lastVal != readout) { - InvokeRegisterChanged(floatReg); - } - } - if (reg is NRegister tsReg) { - var lastVal = tsReg.Value; - var readout = (await ReadNumRegister(tsReg)).Register.Value; - if (lastVal != readout) { - InvokeRegisterChanged(tsReg); - } - } - if (reg is BRegister boolReg) { - var lastVal = boolReg.Value; - var readout = (await ReadBoolRegister(boolReg)).Register.Value; - if (lastVal != readout) { - InvokeRegisterChanged(boolReg); - } - } - if (reg is SRegister stringReg) { - var lastVal = stringReg.Value; - var readout = (await ReadStringRegister(stringReg)).Register.Value; - if (lastVal != readout) { - InvokeRegisterChanged(stringReg); + + rwReg.SetValueFromPLC(readout); + InvokeRegisterChanged(reg); + } + } iteration++; @@ -194,67 +158,218 @@ namespace MewtocolNet { internal void PropertyRegisterWasSet(string propName, object value) { - SetRegister(propName, value); + _ = SetRegisterAsync(GetRegister(propName), value); } #endregion + #region Register Colleciton adding + + #region Register Collection + + /// + /// Attaches a register collection object to + /// the interface that can be updated automatically. + /// + /// Just create a class inheriting from + /// and assert some propertys with the custom . + /// + /// A collection inherting the class + public MewtocolInterface WithRegisterCollection(RegisterCollectionBase collection) { + + collection.PLCInterface = this; + + var props = collection.GetType().GetProperties(); + + foreach (var prop in props) { + + var attributes = prop.GetCustomAttributes(true); + + string propName = prop.Name; + foreach (var attr in attributes) { + + if (attr is RegisterAttribute cAttribute && prop.PropertyType.IsAllowedPlcCastingType()) { + + var dotnetType = prop.PropertyType; + + AddRegister(new RegisterBuildInfo { + memoryAddress = cAttribute.MemoryArea, + specialAddress = cAttribute.SpecialAddress, + memorySizeBytes = cAttribute.ByteLength, + registerType = cAttribute.RegisterType, + dotnetCastType = dotnetType, + collectionType = collection.GetType(), + name = prop.Name, + }); + + } + + } + + } + + RegisterChanged += (reg) => { + + //register is used bitwise + if (reg.IsUsedBitwise()) { + + for (int i = 0; i < props.Length; i++) { + + var prop = props[i]; + var bitWiseFound = prop.GetCustomAttributes(true) + .FirstOrDefault(y => y.GetType() == typeof(RegisterAttribute) && ((RegisterAttribute)y).MemoryArea == reg.MemoryAddress); + + if (bitWiseFound != null) { + + var casted = (RegisterAttribute)bitWiseFound; + var bitIndex = casted.AssignedBitIndex; + + BitArray bitAr = null; + + if (reg is NumberRegister reg16) { + var bytes = BitConverter.GetBytes((short)reg16.Value); + bitAr = new BitArray(bytes); + } else if (reg is NumberRegister reg32) { + var bytes = BitConverter.GetBytes((int)reg32.Value); + bitAr = new BitArray(bytes); + } + + if (bitAr != null && bitIndex < bitAr.Length && bitIndex >= 0) { + + //set the specific bit index if needed + prop.SetValue(collection, bitAr[bitIndex]); + collection.TriggerPropertyChanged(prop.Name); + + } else if (bitAr != null) { + + //set the specific bit array if needed + prop.SetValue(collection, bitAr); + collection.TriggerPropertyChanged(prop.Name); + + } + + } + + } + + } + + //updating normal properties + var foundToUpdate = props.FirstOrDefault(x => x.Name == reg.Name); + + if (foundToUpdate != null) { + + var foundAttributes = foundToUpdate.GetCustomAttributes(true); + var foundAttr = foundAttributes.FirstOrDefault(x => x.GetType() == typeof(RegisterAttribute)); + + if (foundAttr == null) + return; + + var registerAttr = (RegisterAttribute)foundAttr; + + //check if bit parse mode + if (registerAttr.AssignedBitIndex == -1) { + + HashSet NumericTypes = new HashSet { + typeof(bool), + typeof(short), + typeof(ushort), + typeof(int), + typeof(uint), + typeof(float), + typeof(TimeSpan), + typeof(string) + }; + + var regValue = ((IRegister)reg).Value; + + if (NumericTypes.Any(x => foundToUpdate.PropertyType == x)) { + foundToUpdate.SetValue(collection, regValue); + } + + if (foundToUpdate.PropertyType.IsEnum) { + foundToUpdate.SetValue(collection, regValue); + } + + } + + collection.TriggerPropertyChanged(foundToUpdate.Name); + + } + + }; + + if (collection != null) + collection.OnInterfaceLinked(this); + + Connected += (i) => { + if (collection != null) + collection.OnInterfaceLinkedAndOnline(this); + }; + + return this; + + } + + #endregion + + #endregion + #region Register Adding - //Internal register adding for auto register collection building - internal void AddRegister(Type _colType, int _address, PropertyInfo boundProp, int _length = 1, bool _isBitwise = false, Type _enumType = null) { + internal void AddRegister (RegisterBuildInfo buildInfo) { - Type regType = typeof(T); + var builtRegister = buildInfo.Build(); - if (regType != typeof(string) && _length != 1) { - throw new NotSupportedException($"_lenght parameter only allowed for register of type string"); - } + //is bitwise and the register list already contains that area register + if(builtRegister.IsUsedBitwise() && CheckDuplicateRegister(builtRegister, out var existing)) { - if (Registers.Any(x => x.MemoryAddress == _address) && _isBitwise) { return; + } - IRegister reg = null; + if (CheckDuplicateRegister(builtRegister)) + throw MewtocolException.DupeRegister(builtRegister); - string propName = boundProp.Name; + if(CheckDuplicateNameRegister(builtRegister)) + throw MewtocolException.DupeNameRegister(builtRegister); - //rename the property name to prevent duplicate names in case of a bitwise prop - if (_isBitwise && regType == typeof(short)) - propName = $"Auto_Bitwise_DT{_address}"; + Registers.Add(builtRegister); - if (_isBitwise && regType == typeof(int)) - propName = $"Auto_Bitwise_DDT{_address}"; + } - if (regType == typeof(short)) { - reg = new NRegister(_address, propName, _isBitwise, _enumType).WithCollectionType(_colType); - } else if (regType == typeof(ushort)) { - reg = new NRegister(_address, propName).WithCollectionType(_colType); - } else if (regType == typeof(int)) { - reg = new NRegister(_address, propName, _isBitwise, _enumType).WithCollectionType(_colType); - } else if (regType == typeof(uint)) { - reg = new NRegister(_address, propName).WithCollectionType(_colType); - } else if (regType == typeof(float)) { - reg = new NRegister(_address, propName).WithCollectionType(_colType); - } else if (regType == typeof(string)) { - reg = new SRegister(_address, _length, propName).WithCollectionType(_colType); - } else if (regType == typeof(TimeSpan)) { - reg = new NRegister(_address, propName).WithCollectionType(_colType); - } else if (regType == typeof(bool)) { - reg = new BRegister(IOType.R, 0x0, _address, propName).WithCollectionType(_colType); - } + public void AddRegister(IRegister register) { - if (reg == null) { - throw new NotSupportedException($"The type {regType} is not allowed for Registers \n" + - $"Allowed are: short, ushort, int, uint, float and string"); - } + if (CheckDuplicateRegister(register)) + throw MewtocolException.DupeRegister(register); - if (Registers.Any(x => x.GetRegisterPLCName() == reg.GetRegisterPLCName()) && !_isBitwise) { - throw new NotSupportedException($"Cannot add a register multiple times, " + - $"make sure that all register attributes or AddRegister assignments have different adresses."); - } + if (CheckDuplicateNameRegister(register)) + throw MewtocolException.DupeNameRegister(register); - Registers.Add(reg); + Registers.Add(register); + + } + + private bool CheckDuplicateRegister (IRegister instance, out IRegister foundDupe) { + + foundDupe = Registers.FirstOrDefault(x => x.CompareIsDuplicate(instance)); + + return Registers.Contains(instance) || foundDupe != null; + + } + + private bool CheckDuplicateRegister(IRegister instance) { + + var foundDupe = Registers.FirstOrDefault(x => x.CompareIsDuplicate(instance)); + + return Registers.Contains(instance) || foundDupe != null; + + } + + private bool CheckDuplicateNameRegister(IRegister instance) { + + return Registers.Any(x => x.CompareIsNameDuplicate(instance)); } diff --git a/MewtocolNet/Exceptions/MewtocolException.cs b/MewtocolNet/Exceptions/MewtocolException.cs new file mode 100644 index 0000000..0601df4 --- /dev/null +++ b/MewtocolNet/Exceptions/MewtocolException.cs @@ -0,0 +1,34 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace MewtocolNet.Exceptions { + + [Serializable] + public class MewtocolException : Exception { + + public MewtocolException() { } + + public MewtocolException(string message) : base(message) { } + + public MewtocolException(string message, Exception inner) : base(message, inner) { } + + protected MewtocolException( + System.Runtime.Serialization.SerializationInfo info, + System.Runtime.Serialization.StreamingContext context) : base(info, context) { } + + public static MewtocolException DupeRegister (IRegister register) { + + return new MewtocolException($"The mewtocol interface already contains this register: {register.GetRegisterPLCName()}"); + + } + + public static MewtocolException DupeNameRegister (IRegister register) { + + return new MewtocolException($"The mewtocol interface registers already contains a register with the name: {register.Name}"); + + } + + } + +} diff --git a/MewtocolNet/IRegister.cs b/MewtocolNet/IRegister.cs index f68d60d..c442584 100644 --- a/MewtocolNet/IRegister.cs +++ b/MewtocolNet/IRegister.cs @@ -1,4 +1,5 @@ using System; +using System.Threading.Tasks; namespace MewtocolNet { diff --git a/MewtocolNet/IRegisterInternal.cs b/MewtocolNet/IRegisterInternal.cs new file mode 100644 index 0000000..9b9c5a4 --- /dev/null +++ b/MewtocolNet/IRegisterInternal.cs @@ -0,0 +1,18 @@ +using MewtocolNet.Registers; +using System; +using System.Threading.Tasks; + +namespace MewtocolNet { + internal interface IRegisterInternal { + + void WithCollectionType(Type colType); + + void SetValueFromPLC(object value); + + Task ReadAsync(MewtocolInterface interf); + + Task WriteAsync(MewtocolInterface interf, object data); + + } + +} diff --git a/MewtocolNet/MewtocolHelpers.cs b/MewtocolNet/MewtocolHelpers.cs index faee445..7da65b8 100644 --- a/MewtocolNet/MewtocolHelpers.cs +++ b/MewtocolNet/MewtocolHelpers.cs @@ -109,17 +109,17 @@ namespace MewtocolNet { } - internal static string BuildDTString(this string _inString, short _stringReservedSize) { + internal static string BuildDTString (this byte[] inBytes, short reservedSize) { StringBuilder sb = new StringBuilder(); //clamp string lenght - if (_inString.Length > _stringReservedSize) { - _inString = _inString.Substring(0, _stringReservedSize); + if (inBytes.Length > reservedSize) { + inBytes = inBytes.Take(reservedSize).ToArray(); } //actual string content - var hexstring = _inString.GetAsciiHexFromString(); + var hexstring = inBytes.ToHexString(); var sizeBytes = BitConverter.GetBytes((short)(hexstring.Length / 2)).ToHexString(); @@ -133,7 +133,7 @@ namespace MewtocolNet { } - var reservedSizeBytes = BitConverter.GetBytes(_stringReservedSize).ToHexString(); + var reservedSizeBytes = BitConverter.GetBytes(reservedSize).ToHexString(); //reserved string count bytes sb.Append(reservedSizeBytes); @@ -159,8 +159,10 @@ namespace MewtocolNet { } internal static string GetAsciiHexFromString(this string input) { + var bytes = new ASCIIEncoding().GetBytes(input); return bytes.ToHexString(); + } internal static byte[] HexStringToByteArray(this string hex) { @@ -265,6 +267,22 @@ namespace MewtocolNet { } + internal static bool CompareIsDuplicate (this IRegister reg1, IRegister compare) { + + bool valCompare = reg1.RegisterType == compare.RegisterType && + reg1.MemoryAddress == compare.MemoryAddress && + reg1.GetSpecialAddress() == compare.GetSpecialAddress(); + + return valCompare; + + } + + internal static bool CompareIsNameDuplicate(this IRegister reg1, IRegister compare) { + + return ( reg1.Name != null || compare.Name != null) && reg1.Name == compare.Name; + + } + } } \ No newline at end of file diff --git a/MewtocolNet/MewtocolInterface.cs b/MewtocolNet/MewtocolInterface.cs index 81cd8ff..273dc1e 100644 --- a/MewtocolNet/MewtocolInterface.cs +++ b/MewtocolNet/MewtocolInterface.cs @@ -308,7 +308,6 @@ namespace MewtocolNet { public MewtocolInterface WithPoller() { usePoller = true; - return this; } @@ -407,301 +406,10 @@ namespace MewtocolNet { #endregion - #region Register Collection - - /// - /// Attaches a register collection object to - /// the interface that can be updated automatically. - /// - /// Just create a class inheriting from - /// and assert some propertys with the custom . - /// - /// A collection inherting the class - public MewtocolInterface WithRegisterCollection(RegisterCollectionBase collection) { - - collection.PLCInterface = this; - - var props = collection.GetType().GetProperties(); - - foreach (var prop in props) { - - var attributes = prop.GetCustomAttributes(true); - - string propName = prop.Name; - foreach (var attr in attributes) { - - if (attr is RegisterAttribute cAttribute) { - - if (prop.PropertyType == typeof(bool) && cAttribute.AssignedBitIndex == -1) { - - //add bool register non bit assgined - Registers.Add(new BRegister((IOType)(int)cAttribute.RegisterType, cAttribute.SpecialAddress, cAttribute.MemoryArea, _name: propName).WithCollectionType(collection.GetType())); - - } - - if (prop.PropertyType == typeof(short)) { - AddRegister(collection.GetType(), cAttribute.MemoryArea, prop); - } - - if (prop.PropertyType == typeof(ushort)) { - AddRegister(collection.GetType(), cAttribute.MemoryArea, prop); - } - - if (prop.PropertyType == typeof(int)) { - AddRegister(collection.GetType(), cAttribute.MemoryArea, prop); - } - - if (prop.PropertyType == typeof(uint)) { - AddRegister(collection.GetType(), cAttribute.MemoryArea, prop); - } - - if (prop.PropertyType == typeof(float)) { - AddRegister(collection.GetType(), cAttribute.MemoryArea, prop); - } - - if (prop.PropertyType == typeof(string)) { - AddRegister(collection.GetType(), cAttribute.MemoryArea, prop, cAttribute.StringLength); - } - - if (prop.PropertyType.IsEnum) { - - if (cAttribute.BitCount == BitCount.B16) { - AddRegister(collection.GetType(), cAttribute.MemoryArea, prop, _enumType: prop.PropertyType); - } else { - AddRegister(collection.GetType(), cAttribute.MemoryArea, prop, _enumType: prop.PropertyType); - } - - } - - //read number as bit array - if (prop.PropertyType == typeof(BitArray)) { - - if (cAttribute.BitCount == BitCount.B16) { - AddRegister(collection.GetType(), cAttribute.MemoryArea, prop, _isBitwise: true); - } else { - AddRegister(collection.GetType(), cAttribute.MemoryArea, prop, _isBitwise: true); - } - - } - - //read number as bit array by invdividual properties - if (prop.PropertyType == typeof(bool) && cAttribute.AssignedBitIndex != -1) { - - //var bitwiseCount = Registers.Count(x => x.Value.isUsedBitwise); - - if (cAttribute.BitCount == BitCount.B16) { - AddRegister(collection.GetType(), cAttribute.MemoryArea, prop, _isBitwise: true); - } else { - AddRegister(collection.GetType(), cAttribute.MemoryArea, prop, _isBitwise: true); - } - - } - - if (prop.PropertyType == typeof(TimeSpan)) { - AddRegister(collection.GetType(), cAttribute.MemoryArea, prop); - } - - } - - } - - } - - RegisterChanged += (reg) => { - - //register is used bitwise - if (reg.IsUsedBitwise()) { - - for (int i = 0; i < props.Length; i++) { - - var prop = props[i]; - var bitWiseFound = prop.GetCustomAttributes(true) - .FirstOrDefault(y => y.GetType() == typeof(RegisterAttribute) && ((RegisterAttribute)y).MemoryArea == reg.MemoryAddress); - - if (bitWiseFound != null) { - - var casted = (RegisterAttribute)bitWiseFound; - var bitIndex = casted.AssignedBitIndex; - - BitArray bitAr = null; - - if (reg is NRegister reg16) { - var bytes = BitConverter.GetBytes((short)reg16.Value); - bitAr = new BitArray(bytes); - } else if (reg is NRegister reg32) { - var bytes = BitConverter.GetBytes((int)reg32.Value); - bitAr = new BitArray(bytes); - } - - if (bitAr != null && bitIndex < bitAr.Length && bitIndex >= 0) { - - //set the specific bit index if needed - prop.SetValue(collection, bitAr[bitIndex]); - collection.TriggerPropertyChanged(prop.Name); - - } else if (bitAr != null) { - - //set the specific bit array if needed - prop.SetValue(collection, bitAr); - collection.TriggerPropertyChanged(prop.Name); - - } - - } - - } - - } - - //updating normal properties - var foundToUpdate = props.FirstOrDefault(x => x.Name == reg.Name); - - if (foundToUpdate != null) { - - var foundAttributes = foundToUpdate.GetCustomAttributes(true); - var foundAttr = foundAttributes.FirstOrDefault(x => x.GetType() == typeof(RegisterAttribute)); - - if (foundAttr == null) - return; - - var registerAttr = (RegisterAttribute)foundAttr; - - //check if bit parse mode - if (registerAttr.AssignedBitIndex == -1) { - - HashSet NumericTypes = new HashSet { - typeof(bool), - typeof(short), - typeof(ushort), - typeof(int), - typeof(uint), - typeof(float), - typeof(TimeSpan), - typeof(string) - }; - - var regValue = ((IRegister)reg).Value; - - if (NumericTypes.Any(x => foundToUpdate.PropertyType == x)) { - foundToUpdate.SetValue(collection, regValue); - } - - if (foundToUpdate.PropertyType.IsEnum) { - foundToUpdate.SetValue(collection, regValue); - } - - } - - collection.TriggerPropertyChanged(foundToUpdate.Name); - - } - - }; - - if (collection != null) - collection.OnInterfaceLinked(this); - - Connected += (i) => { - if (collection != null) - collection.OnInterfaceLinkedAndOnline(this); - }; - - return this; - - } - - #endregion - - #region Register Writing - - /// - /// Sets a register in the PLCs memory - /// - /// The name the register was given to or a property name from the RegisterCollection class - /// The value to write to the register - public void SetRegister(string registerName, object value) { - - var foundRegister = GetAllRegisters().FirstOrDefault(x => x.Name == registerName); - - if (foundRegister == null) { - throw new Exception($"Register with the name {registerName} was not found"); - } - - _ = SetRegisterAsync(registerName, value); - - } - - /// - /// Sets a register in the PLCs memory asynchronously, returns the result status from the PLC - /// - /// The name the register was given to or a property name from the RegisterCollection class - /// The value to write to the register - public async Task SetRegisterAsync(string registerName, object value) { - - var foundRegister = GetAllRegisters().FirstOrDefault(x => x.Name == registerName); - - if (foundRegister == null) { - throw new Exception($"Register with the name {registerName} was not found"); - } - - if (foundRegister.GetType() == typeof(BRegister)) { - - return await WriteBoolRegister((BRegister)foundRegister, (bool)value); - - } - - if (foundRegister.GetType() == typeof(NRegister)) { - - return await WriteNumRegister((NRegister)foundRegister, (short)value); - - } - - if (foundRegister.GetType() == typeof(NRegister)) { - - return await WriteNumRegister((NRegister)foundRegister, (ushort)value); - - } - - if (foundRegister.GetType() == typeof(NRegister)) { - - return await WriteNumRegister((NRegister)foundRegister, (int)value); - - } - - if (foundRegister.GetType() == typeof(NRegister)) { - - return await WriteNumRegister((NRegister)foundRegister, (uint)value); - - } - - if (foundRegister.GetType() == typeof(NRegister)) { - - return await WriteNumRegister((NRegister)foundRegister, (float)value); - - } - - if (foundRegister.GetType() == typeof(NRegister)) { - - return await WriteNumRegister((NRegister)foundRegister, (TimeSpan)value); - - } - - if (foundRegister.GetType() == typeof(SRegister)) { - - return await WriteStringRegister((SRegister)foundRegister, (string)value); - - } - - return false; - - } - - #endregion - #region Low level command handling /// - /// Calculates checksum and sends a command to the PLC then awaits results + /// Calculates the checksum automatically and sends a command to the PLC then awaits results /// /// MEWTOCOL Formatted request string ex: %01#RT /// Returns the result diff --git a/MewtocolNet/MewtocolInterfaceRequests.cs b/MewtocolNet/MewtocolInterfaceRequests.cs index caa9e5c..6a3b9cc 100644 --- a/MewtocolNet/MewtocolInterfaceRequests.cs +++ b/MewtocolNet/MewtocolInterfaceRequests.cs @@ -4,7 +4,9 @@ using System; using System.Collections.Generic; using System.Globalization; using System.Linq; +using System.Text; using System.Text.RegularExpressions; +using System.Threading; using System.Threading.Tasks; namespace MewtocolNet { @@ -155,244 +157,110 @@ namespace MewtocolNet { #endregion - #region Bool register reading / writing + #region Raw register reading / writing - /// - /// Reads the given boolean register from the PLC - /// - /// The register to read - public async Task ReadBoolRegister(BRegister _toRead) { + internal async Task ReadRawRegisterAsync (IRegister _toRead) { - string requeststring = $"%{GetStationNumber()}#RCS{_toRead.BuildMewtocolQuery()}"; - var result = await SendCommandAsync(requeststring); + //returns a byte array 1 long and with the byte beeing 0 or 1 + if (_toRead.GetType() == typeof(BoolRegister)) { + + string requeststring = $"%{GetStationNumber()}#RCS{_toRead.BuildMewtocolQuery()}"; + var result = await SendCommandAsync(requeststring); + + var resultBool = result.Response.ParseRCSingleBit(); + if (resultBool != null) { + + return resultBool.Value ? new byte[] { 1 } : new byte[] { 0 }; + + } - if (!result.Success) { - return new BRegisterResult { - Result = result, - Register = _toRead - }; } - var resultBool = result.Response.ParseRCSingleBit(); - if (resultBool != null) { - _toRead.SetValueFromPLC(resultBool.Value); + //returns a byte array 2 bytes or 4 bytes long depending on the data size + if (_toRead.GetType().GetGenericTypeDefinition() == typeof(NumberRegister<>)) { + + string requeststring = $"%{GetStationNumber()}#RD{_toRead.BuildMewtocolQuery()}"; + var result = await SendCommandAsync(requeststring); + + if (!result.Success) + throw new Exception($"Failed to load the byte data for: {_toRead}"); + + if(_toRead.RegisterType == RegisterType.DT) { + + return result.Response.ParseDTByteString(4).HexStringToByteArray(); + + } else { + + return result.Response.ParseDTByteString(8).HexStringToByteArray(); + + } + } - var finalRes = new BRegisterResult { - Result = result, - Register = _toRead - }; + //returns a byte array with variable size + if (_toRead.GetType() == typeof(BytesRegister<>)) { - return finalRes; + string requeststring = $"%{GetStationNumber()}#RD{_toRead.BuildMewtocolQuery()}"; + var result = await SendCommandAsync(requeststring); + + if (!result.Success) + throw new Exception($"Failed to load the byte data for: {_toRead}"); + + return result.Response.ParseDTString().ReverseByteOrder().HexStringToByteArray(); + + } + + throw new Exception($"Failed to load the byte data for: {_toRead}"); } - /// - /// Writes to the given bool register on the PLC - /// - /// The register to write to - /// The value to write - /// The success state of the write operation - public async Task WriteBoolRegister(BRegister _toWrite, bool value) { + internal async Task WriteRawRegisterAsync (IRegister _toWrite, byte[] data) { - string requeststring = $"%{GetStationNumber()}#WCS{_toWrite.BuildMewtocolQuery()}{(value ? "1" : "0")}"; + //returns a byte array 1 long and with the byte beeing 0 or 1 + if (_toWrite.GetType() == typeof(BoolRegister)) { - var result = await SendCommandAsync(requeststring); + string requeststring = $"%{GetStationNumber()}#WCS{_toWrite.BuildMewtocolQuery()}{(data[0] == 1 ? "1" : "0")}"; + var result = await SendCommandAsync(requeststring); + return result.Success; - return result.Success && result.Response.StartsWith($"%{GetStationNumber()}$WC"); + } + + //returns a byte array 2 bytes or 4 bytes long depending on the data size + if (_toWrite.GetType().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 (_toWrite.GetType() == typeof(BytesRegister<>)) { + + //string stationNum = GetStationNumber(); + //string dataString = gotBytes.BuildDTString(_toWrite.ReservedSize); + //string dataArea = _toWrite.BuildCustomIdent(dataString.Length / 4); + + //string requeststring = $"%{stationNum}#WD{dataArea}{dataString}"; + + //var result = await SendCommandAsync(requeststring); + + } + + return false; } #endregion - #region Number register reading / writing + #region Register reading / writing - /// - /// Reads the given numeric register from the PLC - /// - /// Type of number (short, ushort, int, uint, float) - /// The register to read - /// A result with the given NumberRegister containing the readback value and a result struct - public async Task> ReadNumRegister(NRegister _toRead) { + public async Task SetRegisterAsync (IRegister register, object value) { - Type numType = typeof(T); + var internalReg = (IRegisterInternal)register; - string requeststring = $"%{GetStationNumber()}#RD{_toRead.BuildMewtocolQuery()}"; - var result = await SendCommandAsync(requeststring); + return await internalReg.WriteAsync(this, value); - var failedResult = new NRegisterResult { - Result = result, - Register = _toRead - }; - - if (!result.Success || string.IsNullOrEmpty(result.Response)) { - return failedResult; - } - - if (numType == typeof(short)) { - - var resultBytes = result.Response.ParseDTByteString(4).ReverseByteOrder(); - if (resultBytes == null) return failedResult; - var val = short.Parse(resultBytes, NumberStyles.HexNumber); - _toRead.SetValueFromPLC(val); - - } else if (numType == typeof(ushort)) { - - var resultBytes = result.Response.ParseDTByteString(4).ReverseByteOrder(); - if (resultBytes == null) return failedResult; - var val = ushort.Parse(resultBytes, NumberStyles.HexNumber); - _toRead.SetValueFromPLC(val); - - } else if (numType == typeof(int)) { - - var resultBytes = result.Response.ParseDTByteString(8).ReverseByteOrder(); - if (resultBytes == null) return failedResult; - var val = int.Parse(resultBytes, NumberStyles.HexNumber); - _toRead.SetValueFromPLC(val); - - } else if (numType == typeof(uint)) { - - var resultBytes = result.Response.ParseDTByteString(8).ReverseByteOrder(); - if (resultBytes == null) return failedResult; - var val = uint.Parse(resultBytes, NumberStyles.HexNumber); - _toRead.SetValueFromPLC(val); - - } else if (numType == typeof(float)) { - - var resultBytes = result.Response.ParseDTByteString(8).ReverseByteOrder(); - if (resultBytes == null) return failedResult; - //convert to unsigned int first - var val = uint.Parse(resultBytes, NumberStyles.HexNumber); - - byte[] floatVals = BitConverter.GetBytes(val); - float finalFloat = BitConverter.ToSingle(floatVals, 0); - - _toRead.SetValueFromPLC(finalFloat); - - } else if (numType == typeof(TimeSpan)) { - - var resultBytes = result.Response.ParseDTByteString(8).ReverseByteOrder(); - if (resultBytes == null) return failedResult; - //convert to unsigned int first - var vallong = long.Parse(resultBytes, NumberStyles.HexNumber); - var valMillis = vallong * 10; - var ts = TimeSpan.FromMilliseconds(valMillis); - - //minmax writable / readable value is 10ms - _toRead.SetValueFromPLC(ts); - - } - - var finalRes = new NRegisterResult { - Result = result, - Register = _toRead - }; - - return finalRes; - } - - /// - /// Reads the given numeric register from the PLC - /// - /// Type of number (short, ushort, int, uint, float) - /// The register to write - /// The value to write - /// The success state of the write operation - public async Task WriteNumRegister(NRegister _toWrite, T _value) { - - byte[] toWriteVal; - Type numType = typeof(T); - - if (numType == typeof(short)) { - toWriteVal = BitConverter.GetBytes(Convert.ToInt16(_value)); - } else if (numType == typeof(ushort)) { - toWriteVal = BitConverter.GetBytes(Convert.ToUInt16(_value)); - } else if (numType == typeof(int)) { - toWriteVal = BitConverter.GetBytes(Convert.ToInt32(_value)); - } else if (numType == typeof(uint)) { - toWriteVal = BitConverter.GetBytes(Convert.ToUInt32(_value)); - } else if (numType == typeof(float)) { - - var fl = _value as float?; - if (fl == null) - throw new NullReferenceException("Float cannot be null"); - - toWriteVal = BitConverter.GetBytes(fl.Value); - - } else if (numType == typeof(TimeSpan)) { - - var fl = _value as TimeSpan?; - if (fl == null) - throw new NullReferenceException("Timespan cannot be null"); - - var tLong = (uint)(fl.Value.TotalMilliseconds / 10); - toWriteVal = BitConverter.GetBytes(tLong); - - } else { - toWriteVal = null; - } - - string requeststring = $"%{GetStationNumber()}#WD{_toWrite.BuildMewtocolQuery()}{toWriteVal.ToHexString()}"; - - var result = await SendCommandAsync(requeststring); - - return result.Success && result.Response.StartsWith($"%{GetStationNumber()}$WD"); - - } - - #endregion - - #region String register reading / writing - - //string is build up like this - //04 00 04 00 53 50 33 35 13 - //0, 1 = reserved size - //1, 2 = current size - //3,4,5,6 = ASCII encoded chars (SP35) - //7,8 = checksum - - /// - /// Reads back the value of a string register - /// - /// The register to read - /// The station number of the PLC - /// - public async Task ReadStringRegister(SRegister _toRead, int _stationNumber = 1) { - - string requeststring = $"%{GetStationNumber()}#RD{_toRead.BuildMewtocolQuery()}"; - var result = await SendCommandAsync(requeststring); - if (result.Success) - _toRead.SetValueFromPLC(result.Response.ParseDTString()); - return new SRegisterResult { - Result = result, - Register = _toRead - }; - } - - /// - /// Writes a string to a string register - /// - /// The register to write - /// The value to write, if the strings length is longer than the cap size it gets trimmed to the max char length - /// The station number of the PLC - /// The success state of the write operation - public async Task WriteStringRegister(SRegister _toWrite, string _value, int _stationNumber = 1) { - - if (_value == null) _value = ""; - if (_value.Length > _toWrite.ReservedSize) { - throw new ArgumentException("Write string size cannot be longer than reserved string size"); - } - - string stationNum = GetStationNumber(); - string dataString = _value.BuildDTString(_toWrite.ReservedSize); - string dataArea = _toWrite.BuildCustomIdent(dataString.Length / 4); - - string requeststring = $"%{stationNum}#WD{dataArea}{dataString}"; - - var result = await SendCommandAsync(requeststring); - - - return result.Success && result.Response.StartsWith($"%{GetStationNumber()}$WD"); } #endregion diff --git a/MewtocolNet/PLCEnums/PlcVarType.cs b/MewtocolNet/PLCEnums/PlcVarType.cs index d3e13a2..d7ac5de 100644 --- a/MewtocolNet/PLCEnums/PlcVarType.cs +++ b/MewtocolNet/PLCEnums/PlcVarType.cs @@ -11,7 +11,9 @@ namespace MewtocolNet { UDINT, REAL, TIME, - STRING + STRING, + WORD, + DWORD } diff --git a/MewtocolNet/PLCEnums/PlcVarTypeConversions.cs b/MewtocolNet/PLCEnums/PlcVarTypeConversions.cs deleted file mode 100644 index 4c6653b..0000000 --- a/MewtocolNet/PLCEnums/PlcVarTypeConversions.cs +++ /dev/null @@ -1,91 +0,0 @@ -using MewtocolNet.Registers; -using System; -using System.Collections.Generic; -using System.Linq; - -namespace MewtocolNet { - internal static class PlcVarTypeConversions { - - static Dictionary dictTypeConv = new Dictionary { - - { 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 dictRegisterConv = new Dictionary { - - { PlcVarType.BOOL, typeof(BRegister) }, - { PlcVarType.INT, typeof(NRegister) }, - { PlcVarType.UINT, typeof(NRegister) }, - { PlcVarType.DINT, typeof(NRegister) }, - { PlcVarType.UDINT, typeof(NRegister) }, - { PlcVarType.REAL, typeof(NRegister) }, - { PlcVarType.TIME, typeof(NRegister) }, - { PlcVarType.STRING, typeof(SRegister) }, - - }; - - internal static bool IsAllowedPlcCastingType () { - - 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"); - - } - - } - -} diff --git a/MewtocolNet/RegisterAttributes/RegisterAttribute.cs b/MewtocolNet/RegisterAttributes/RegisterAttribute.cs index dd90c3c..cd79645 100644 --- a/MewtocolNet/RegisterAttributes/RegisterAttribute.cs +++ b/MewtocolNet/RegisterAttributes/RegisterAttribute.cs @@ -8,10 +8,12 @@ namespace MewtocolNet.RegisterAttributes { [AttributeUsage(AttributeTargets.Property, AllowMultiple = false)] public class RegisterAttribute : Attribute { - internal int MemoryArea; - internal int StringLength; - internal RegisterType RegisterType; + internal RegisterType? RegisterType; + + internal int MemoryArea = 0; + internal int ByteLength = 2; internal byte SpecialAddress = 0x0; + internal BitCount BitCount; internal int AssignedBitIndex = -1; @@ -19,11 +21,36 @@ namespace MewtocolNet.RegisterAttributes { /// Attribute for string type or numeric registers /// /// The area in the plcs memory - /// The max string length in the plc - public RegisterAttribute(int memoryArea, int stringLength = 1) { + public RegisterAttribute(int memoryArea) { MemoryArea = memoryArea; - StringLength = stringLength; + + } + + public RegisterAttribute(int memoryArea, int byteLength) { + + MemoryArea = memoryArea; + ByteLength = byteLength; + + } + + public RegisterAttribute(int memoryArea, BitCount bitCount) { + + MemoryArea = memoryArea; + BitCount = bitCount; + AssignedBitIndex = 0; + + RegisterType = BitCount == BitCount.B16 ? MewtocolNet.RegisterType.DT : MewtocolNet.RegisterType.DDT; + + } + + public RegisterAttribute(int memoryArea, BitCount bitCount, int bitIndex) { + + MemoryArea = memoryArea; + BitCount = bitCount; + AssignedBitIndex = bitIndex; + + RegisterType = BitCount == BitCount.B16 ? MewtocolNet.RegisterType.DT : MewtocolNet.RegisterType.DDT; } @@ -49,42 +76,6 @@ namespace MewtocolNet.RegisterAttributes { } - /// - /// Attribute to read numeric registers as bitwise - /// - /// The area in the plcs memory - /// The number of bits to parse - public RegisterAttribute(int memoryArea, BitCount bitcount) { - - MemoryArea = memoryArea; - StringLength = 0; - BitCount = bitcount; - - } - - /// - /// Attribute to read numeric registers as bitwise - /// - /// The area in the plcs memory - /// The number of bits to parse - /// The index of the bit that gets linked to the bool - public RegisterAttribute(int memoryArea, uint assignBit, BitCount bitcount) { - - if (assignBit > 15 && bitcount == BitCount.B16) { - throw new NotSupportedException("The assignBit parameter cannot be greater than 15 in a 16 bit var"); - } - - if (assignBit > 31 && bitcount == BitCount.B32) { - throw new NotSupportedException("The assignBit parameter cannot be greater than 31 in a 32 bit var"); - } - - MemoryArea = memoryArea; - StringLength = 0; - BitCount = bitcount; - AssignedBitIndex = (int)assignBit; - - } - } } diff --git a/MewtocolNet/RegisterBuildInfo.cs b/MewtocolNet/RegisterBuildInfo.cs new file mode 100644 index 0000000..c53074a --- /dev/null +++ b/MewtocolNet/RegisterBuildInfo.cs @@ -0,0 +1,118 @@ +using MewtocolNet.Registers; +using System; +using System.Collections; +using System.Reflection; + +namespace MewtocolNet +{ + + internal struct RegisterBuildInfo { + + internal string name; + internal int memoryAddress; + internal int memorySizeBytes; + internal byte? specialAddress; + + internal RegisterType? registerType; + internal Type dotnetCastType; + internal Type collectionType; + + internal IRegister Build () { + + RegisterType regType = registerType ?? dotnetCastType.ToRegisterTypeDefault(); + + PlcVarType plcType = dotnetCastType.ToPlcVarType(); + Type registerClassType = plcType.GetDefaultPlcVarType(); + + if (regType.IsNumericDTDDT() && (dotnetCastType == typeof(bool) || dotnetCastType == typeof(BitArray))) { + + //------------------------------------------- + //as numeric register with boolean bit target + + var type = typeof(NumberRegister); + + var areaAddr = memoryAddress; + + //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, true, null }; + var instance = (IRegister)Activator.CreateInstance(type, flags, null, parameters, null); + + if (collectionType != null) + ((IRegisterInternal)instance).WithCollectionType(collectionType); + + return instance; + + } else if (regType.IsNumericDTDDT()) { + + //------------------------------------------- + //as numeric register + + var type = plcType.GetDefaultPlcVarType(); + + var areaAddr = memoryAddress; + + //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); + + if(collectionType != null) + ((IRegisterInternal)instance).WithCollectionType(collectionType); + + return instance; + + } + + if (regType.IsBoolean()) { + + //------------------------------------------- + //as boolean register + + var io = (IOType)(int)regType; + var spAddr = specialAddress; + var areaAddr = memoryAddress; + + //create a new bregister instance + var flags = BindingFlags.Public | BindingFlags.Instance; + var parameters = new object[] { io, spAddr.Value, areaAddr, name }; + var instance = (BoolRegister)Activator.CreateInstance(typeof(BoolRegister), flags, null, parameters, null); + + if (collectionType != null) + ((IRegisterInternal)instance).WithCollectionType(collectionType); + + return instance; + + } + + if(regType == RegisterType.DT_RANGE) { + + //------------------------------------------- + //as byte range register + + var type = plcType.GetDefaultPlcVarType(); + + //create a new bregister instance + var flags = BindingFlags.Public | BindingFlags.Instance; + //int _adress, int _reservedSize, string _name = null + var parameters = new object[] { memoryAddress, memorySizeBytes, name }; + var instance = (IRegister)Activator.CreateInstance(type, flags, null, parameters, null); + + if (collectionType != null) + ((IRegisterInternal)instance).WithCollectionType(collectionType); + + return instance; + + } + + throw new Exception("Failed to build register"); + + } + + } + +} diff --git a/MewtocolNet/RegisterBuilding/FinalizerExtensions.cs b/MewtocolNet/RegisterBuilding/FinalizerExtensions.cs index b42a30e..a06e77b 100644 --- a/MewtocolNet/RegisterBuilding/FinalizerExtensions.cs +++ b/MewtocolNet/RegisterBuilding/FinalizerExtensions.cs @@ -1,8 +1,10 @@ using MewtocolNet.Registers; using System; +using System.Linq; using System.Reflection; -namespace MewtocolNet.RegisterBuilding { +namespace MewtocolNet.RegisterBuilding +{ public static class FinalizerExtensions { @@ -29,7 +31,7 @@ namespace MewtocolNet.RegisterBuilding { step.dotnetVarType = typeof(bool); - } else if (isTypeNotDefined && step.RegType == RegisterType.DT_START) { + } else if (isTypeNotDefined && step.RegType == RegisterType.DT_RANGE) { step.dotnetVarType = typeof(string); @@ -37,58 +39,31 @@ namespace MewtocolNet.RegisterBuilding { if(step.plcVarType != null) { - step.dotnetVarType = step.plcVarType.Value.ToDotnetType(); + step.dotnetVarType = step.plcVarType.Value.GetDefaultDotnetType(); } - //as numeric register - if (step.RegType.IsNumericDTDDT()) { + var builtReg = new RegisterBuildInfo { - if(step.plcVarType == null && step.dotnetVarType != null) { + name = step.Name, + specialAddress = step.SpecialAddress, + memoryAddress = step.MemAddress, + registerType = step.RegType, + dotnetCastType = step.dotnetVarType, - step.plcVarType = step.dotnetVarType.ToPlcVarType(); + }.Build(); - } + step.AddToRegisterList(builtReg); - var type = step.plcVarType.Value.ToRegisterType(); + return builtReg; - var areaAddr = step.MemAddress; - var name = step.Name; + } - //create a new bregister instance - var flags = BindingFlags.Public | BindingFlags.Instance; + private static void AddToRegisterList (this RegisterBuilderStep step, IRegister 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); + if (step.forInterface == null) return; - 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"); + step.forInterface.AddRegister(instance); } diff --git a/MewtocolNet/RegisterBuilding/RegBuilder.cs b/MewtocolNet/RegisterBuilding/RegBuilder.cs index ce91a17..4ca8416 100644 --- a/MewtocolNet/RegisterBuilding/RegBuilder.cs +++ b/MewtocolNet/RegisterBuilding/RegBuilder.cs @@ -9,7 +9,9 @@ namespace MewtocolNet.RegisterBuilding { /// /// Contains useful tools for register creation /// - public static class RegBuilder { + public class RegBuilder { + + internal MewtocolInterface forInterface = null; //methods to test the input string on private static List> parseMethods = new List>() { @@ -19,7 +21,18 @@ namespace MewtocolNet.RegisterBuilding { }; - public static RegisterBuilderStep FromPlcRegName (string plcAddrName, string name = null) { + public static RegBuilder ForInterface (MewtocolInterface interf) { + + var rb = new RegBuilder(); + rb.forInterface = interf; + return rb; + + } + + public static RegBuilder Factory { get; private set; } = new RegBuilder(); + + + public RegisterBuilderStep FromPlcRegName (string plcAddrName, string name = null) { foreach (var method in parseMethods) { @@ -30,8 +43,8 @@ namespace MewtocolNet.RegisterBuilding { if (!string.IsNullOrEmpty(name)) res.stepData.Name = name; - res.stepData.OriginalInput = plcAddrName; - + res.stepData.OriginalInput = plcAddrName; + res.stepData.forInterface = forInterface; return res.stepData; } else if(res.state == ParseResultState.FailedHard) { diff --git a/MewtocolNet/RegisterBuilding/RegisterBuilderStep.cs b/MewtocolNet/RegisterBuilding/RegisterBuilderStep.cs index e1c2103..04883be 100644 --- a/MewtocolNet/RegisterBuilding/RegisterBuilderStep.cs +++ b/MewtocolNet/RegisterBuilding/RegisterBuilderStep.cs @@ -1,8 +1,11 @@ using System; namespace MewtocolNet.RegisterBuilding { + public class RegisterBuilderStep { + internal MewtocolInterface forInterface; + internal bool wasCasted = false; internal string OriginalInput; @@ -15,12 +18,12 @@ namespace MewtocolNet.RegisterBuilding { 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; + 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; } @@ -28,11 +31,11 @@ namespace MewtocolNet.RegisterBuilding { RegType = regType; MemAddress = memAddr; - SpecialAddress = specialAddr; + SpecialAddress = specialAddr; } - public RegisterBuilderStep AsPlcType (PlcVarType varType) { + public RegisterBuilderStep AsPlcType(PlcVarType varType) { dotnetVarType = null; plcVarType = varType; @@ -43,9 +46,9 @@ namespace MewtocolNet.RegisterBuilding { } - public RegisterBuilderStep AsType () { + public RegisterBuilderStep AsType() { - if(!typeof(T).IsAllowedPlcCastingType()) { + if (!typeof(T).IsAllowedPlcCastingType()) { throw new NotSupportedException($"The dotnet type {typeof(T)}, is not supported for PLC type casting"); @@ -60,7 +63,7 @@ namespace MewtocolNet.RegisterBuilding { } - internal RegisterBuilderStep AutoType () { + internal RegisterBuilderStep AutoType() { switch (RegType) { case RegisterType.X: @@ -74,7 +77,7 @@ namespace MewtocolNet.RegisterBuilding { case RegisterType.DDT: dotnetVarType = typeof(int); break; - case RegisterType.DT_START: + case RegisterType.DT_RANGE: dotnetVarType = typeof(string); break; } diff --git a/MewtocolNet/RegisterEnums.cs b/MewtocolNet/RegisterEnums.cs index 1195f35..e23e89f 100644 --- a/MewtocolNet/RegisterEnums.cs +++ b/MewtocolNet/RegisterEnums.cs @@ -1,4 +1,6 @@ -namespace MewtocolNet { +using System; + +namespace MewtocolNet { /// /// The register prefixed type @@ -26,9 +28,9 @@ /// DDT = 4, /// - /// Start area of a byte sequence longer than 2 words + /// Area of a byte sequence longer than 2 words /// - DT_START = 5, + DT_RANGE = 5, } diff --git a/MewtocolNet/Registers/BRegister.cs b/MewtocolNet/Registers/BoolRegister.cs similarity index 81% rename from MewtocolNet/Registers/BRegister.cs rename to MewtocolNet/Registers/BoolRegister.cs index 3e83adb..2ec09f4 100644 --- a/MewtocolNet/Registers/BRegister.cs +++ b/MewtocolNet/Registers/BoolRegister.cs @@ -1,13 +1,14 @@ using System; using System.ComponentModel; using System.Text; +using System.Threading.Tasks; namespace MewtocolNet.Registers { /// /// Defines a register containing a boolean /// - public class BRegister : IRegister, INotifyPropertyChanged { + public class BoolRegister : IRegister, IRegisterInternal, INotifyPropertyChanged { /// /// Gets called whenever the value was changed @@ -62,7 +63,7 @@ namespace MewtocolNet.Registers { /// The custom name /// /// - public BRegister(IOType _io, byte _spAddress = 0x0, int _areaAdress = 0, string _name = null) { + public BoolRegister(IOType _io, byte _spAddress = 0x0, int _areaAdress = 0, string _name = null) { if (_areaAdress < 0) throw new NotSupportedException("The area address cant be negative"); @@ -84,36 +85,33 @@ namespace MewtocolNet.Registers { } - internal BRegister WithCollectionType(Type colType) { - - collectionType = colType; - return this; - - } + public void WithCollectionType (Type colType) => collectionType = colType; public byte? GetSpecialAddress() => SpecialAddress; /// - /// Builds the register area name + /// Builds the register area name for the mewtocol protocol /// public string BuildMewtocolQuery() { - //build area code from register type - StringBuilder asciistring = new StringBuilder(RegisterType.ToString()); + //(R|X|Y)(area add [3] + special add [1]) + StringBuilder asciistring = new StringBuilder(); - string memPadded = MemoryAddress.ToString().PadLeft(4, '0'); + string prefix = RegisterType.ToString(); + string mem = MemoryAddress.ToString(); string sp = SpecialAddress.ToString("X1"); - asciistring.Append(memPadded); + asciistring.Append(prefix); + asciistring.Append(mem.PadLeft(3, '0')); asciistring.Append(sp); return asciistring.ToString(); } - internal void SetValueFromPLC(bool val) { + public void SetValueFromPLC(object val) { - lastValue = val; + lastValue = (bool)val; TriggerChangedEvnt(this); TriggerNotifyChange(); @@ -183,6 +181,19 @@ namespace MewtocolNet.Registers { } + public async Task ReadAsync (MewtocolInterface interf) { + + var read = await interf.ReadRawRegisterAsync(this); + return PlcValueParser.Parse(read); + + } + + public async Task WriteAsync (MewtocolInterface interf, object data) { + + return await interf.WriteRawRegisterAsync(this, PlcValueParser.Encode((bool)data)); + + } + } } diff --git a/MewtocolNet/Registers/BRegisterResult.cs b/MewtocolNet/Registers/BoolRegisterResult.cs similarity index 78% rename from MewtocolNet/Registers/BRegisterResult.cs rename to MewtocolNet/Registers/BoolRegisterResult.cs index 8a39277..4016a48 100644 --- a/MewtocolNet/Registers/BRegisterResult.cs +++ b/MewtocolNet/Registers/BoolRegisterResult.cs @@ -3,7 +3,7 @@ /// /// Result for a boolean register /// - public class BRegisterResult { + public class BoolRegisterResult { /// /// The command result @@ -13,7 +13,7 @@ /// /// The used register /// - public BRegister Register { get; set; } + public BoolRegister Register { get; set; } } diff --git a/MewtocolNet/Registers/SRegister.cs b/MewtocolNet/Registers/BytesRegister.cs similarity index 82% rename from MewtocolNet/Registers/SRegister.cs rename to MewtocolNet/Registers/BytesRegister.cs index 91b6ca4..8ac6240 100644 --- a/MewtocolNet/Registers/SRegister.cs +++ b/MewtocolNet/Registers/BytesRegister.cs @@ -1,13 +1,15 @@ using System; +using System.Collections.Generic; using System.ComponentModel; using System.Text; +using System.Threading.Tasks; namespace MewtocolNet.Registers { /// /// Defines a register containing a string /// - public class SRegister : IRegister { + public class BytesRegister : IRegister, IRegisterInternal { /// /// Gets called whenever the value was changed @@ -58,30 +60,25 @@ namespace MewtocolNet.Registers { /// /// Defines a register containing a string /// - public SRegister(int _adress, int _reservedStringSize, string _name = null) { + public BytesRegister(int _adress, int _reservedSize, string _name = null) { if (_adress > 99999) throw new NotSupportedException("Memory adresses cant be greater than 99999"); name = _name; memoryAdress = _adress; - ReservedSize = (short)_reservedStringSize; + ReservedSize = (short)_reservedSize; //calc mem length - var wordsize = (double)_reservedStringSize / 2; + var wordsize = (double)_reservedSize / 2; if (wordsize % 2 != 0) { wordsize++; } - RegisterType = RegisterType.DT_START; + RegisterType = RegisterType.DT_RANGE; memoryLength = (int)Math.Round(wordsize + 1); } - internal SRegister WithCollectionType (Type colType) { - - collectionType = colType; - return this; - - } + public void WithCollectionType(Type colType) => collectionType = colType; /// /// Builds the register identifier for the mewotocol protocol @@ -115,9 +112,9 @@ namespace MewtocolNet.Registers { public bool IsUsedBitwise() => false; - internal void SetValueFromPLC(string val) { + public void SetValueFromPLC(object val) { - lastValue = val; + lastValue = (string)val; TriggerChangedEvnt(this); TriggerNotifyChange(); @@ -146,6 +143,19 @@ namespace MewtocolNet.Registers { public string ToString(bool additional) => $"{GetRegisterPLCName()} - Value: {GetValueString()}"; + public async Task ReadAsync(MewtocolInterface interf) { + + var read = await interf.ReadRawRegisterAsync(this); + return PlcValueParser.Parse(read); + + } + + public async Task WriteAsync(MewtocolInterface interf, object data) { + + return await interf.WriteRawRegisterAsync(this, (byte[])data); + + } + } } diff --git a/MewtocolNet/Registers/SRegisterResult.cs b/MewtocolNet/Registers/BytesRegisterResult.cs similarity index 78% rename from MewtocolNet/Registers/SRegisterResult.cs rename to MewtocolNet/Registers/BytesRegisterResult.cs index 45129a6..314decf 100644 --- a/MewtocolNet/Registers/SRegisterResult.cs +++ b/MewtocolNet/Registers/BytesRegisterResult.cs @@ -3,7 +3,7 @@ /// /// The results of a string register operation /// - public class SRegisterResult { + public class BytesRegisterResult { /// /// The command result @@ -12,7 +12,7 @@ /// /// The register definition used /// - public SRegister Register { get; set; } + public BytesRegister Register { get; set; } } diff --git a/MewtocolNet/Registers/NRegister.cs b/MewtocolNet/Registers/NumberRegister.cs similarity index 90% rename from MewtocolNet/Registers/NRegister.cs rename to MewtocolNet/Registers/NumberRegister.cs index c36c0d4..b4f09c6 100644 --- a/MewtocolNet/Registers/NRegister.cs +++ b/MewtocolNet/Registers/NumberRegister.cs @@ -3,6 +3,7 @@ using System.Collections; using System.Collections.Generic; using System.ComponentModel; using System.Text; +using System.Threading.Tasks; namespace MewtocolNet.Registers { @@ -10,7 +11,7 @@ namespace MewtocolNet.Registers { /// Defines a register containing a number /// /// The type of the numeric value - public class NRegister : IRegister { + public class NumberRegister : IRegister, IRegisterInternal { /// /// Gets called whenever the value was changed @@ -65,7 +66,7 @@ namespace MewtocolNet.Registers { /// /// Memory start adress max 99999 /// Name of the register - public NRegister (int _adress, string _name = null) { + public NumberRegister (int _adress, string _name = null) { if (_adress > 99999) throw new NotSupportedException("Memory adresses cant be greater than 99999"); @@ -98,7 +99,7 @@ namespace MewtocolNet.Registers { } - public NRegister (int _adress, string _name = null, bool isBitwise = false, Type _enumType = null) { + public NumberRegister (int _adress, string _name = null, bool isBitwise = false, Type _enumType = null) { if (_adress > 99999) throw new NotSupportedException("Memory adresses cant be greater than 99999"); memoryAdress = _adress; @@ -132,14 +133,9 @@ namespace MewtocolNet.Registers { } - internal NRegister WithCollectionType(Type colType) { + public void WithCollectionType(Type colType) => collectionType = colType; - collectionType = colType; - return this; - - } - - internal void SetValueFromPLC(object val) { + public void SetValueFromPLC(object val) { lastValue = (T)val; TriggerChangedEvnt(this); @@ -214,7 +210,7 @@ namespace MewtocolNet.Registers { /// A bitarray public BitArray GetBitwise() { - if (this is NRegister shortReg) { + if (this is NumberRegister shortReg) { var bytes = BitConverter.GetBytes((short)Value); BitArray bitAr = new BitArray(bytes); @@ -222,7 +218,7 @@ namespace MewtocolNet.Registers { } - if (this is NRegister intReg) { + if (this is NumberRegister intReg) { var bytes = BitConverter.GetBytes((int)Value); BitArray bitAr = new BitArray(bytes); @@ -291,6 +287,19 @@ namespace MewtocolNet.Registers { public string ToString(bool additional) => $"{GetRegisterPLCName()} - Value: {GetValueString()}"; + public async Task ReadAsync(MewtocolInterface interf) { + + var read = await interf.ReadRawRegisterAsync(this); + return PlcValueParser.Parse(read); + + } + + public async Task WriteAsync(MewtocolInterface interf, object data) { + + return await interf.WriteRawRegisterAsync(this, PlcValueParser.Encode((T)data)); + + } + } } diff --git a/MewtocolNet/Registers/NRegisterResult.cs b/MewtocolNet/Registers/NumberRegisterResult.cs similarity index 88% rename from MewtocolNet/Registers/NRegisterResult.cs rename to MewtocolNet/Registers/NumberRegisterResult.cs index 367233a..04bdec3 100644 --- a/MewtocolNet/Registers/NRegisterResult.cs +++ b/MewtocolNet/Registers/NumberRegisterResult.cs @@ -4,7 +4,7 @@ /// Result for a read/write operation /// /// The type of the numeric value - public class NRegisterResult { + public class NumberRegisterResult { /// /// Command result @@ -14,7 +14,7 @@ /// /// The used register /// - public NRegister Register { get; set; } + public NumberRegister Register { get; set; } /// /// Trys to get the value of there is one diff --git a/MewtocolNet/TypeConversion/Conversions.cs b/MewtocolNet/TypeConversion/Conversions.cs new file mode 100644 index 0000000..db72369 --- /dev/null +++ b/MewtocolNet/TypeConversion/Conversions.cs @@ -0,0 +1,124 @@ +using MewtocolNet.Registers; +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Text; + +namespace MewtocolNet.TypeConversion { + + internal static class Conversions { + + internal static Dictionary dictPlcTypeToRegisterType = new Dictionary { + + { PlcVarType.BOOL, RegisterType.R }, + { PlcVarType.INT, RegisterType.DT }, + { PlcVarType.UINT, RegisterType.DT }, + { PlcVarType.DINT, RegisterType.DDT }, + { PlcVarType.UDINT, RegisterType.DDT }, + { PlcVarType.REAL, RegisterType.DDT }, + { PlcVarType.TIME, RegisterType.DDT }, + { PlcVarType.WORD, RegisterType.DT }, + { PlcVarType.DWORD, RegisterType.DDT }, + { PlcVarType.STRING, RegisterType.DT_RANGE }, + + }; + + internal static List items = new List { + + new PlcTypeConversion(RegisterType.R) { + HoldingRegisterType = typeof(BoolRegister), + PlcVarType = PlcVarType.BOOL, + FromRaw = bytes => { + + return (bool)(bytes[0] == 1); + }, + ToRaw = value => { + + return new byte[] { (byte)(value ? 1 : 0) }; + + }, + }, + new PlcTypeConversion(RegisterType.X) { + HoldingRegisterType = typeof(BoolRegister), + PlcVarType = PlcVarType.BOOL, + FromRaw = bytes => { + + return bytes[0] == 1; + }, + ToRaw = value => { + + return new byte[] { (byte)(value ? 1 : 0) }; + + }, + }, + new PlcTypeConversion(RegisterType.Y) { + HoldingRegisterType = typeof(BoolRegister), + PlcVarType = PlcVarType.BOOL, + FromRaw = bytes => { + + return bytes[0] == 1; + }, + ToRaw = value => { + + return new byte[] { (byte)(value ? 1 : 0) }; + + }, + }, + new PlcTypeConversion(RegisterType.DT) { + HoldingRegisterType = typeof(NumberRegister), + PlcVarType = PlcVarType.INT, + FromRaw = bytes => { + + return BitConverter.ToInt16(bytes, 0); + }, + ToRaw = value => { + + return BitConverter.GetBytes(value); + + }, + }, + new PlcTypeConversion(RegisterType.DT) { + HoldingRegisterType = typeof(NumberRegister), + PlcVarType = PlcVarType.UINT, + FromRaw = bytes => { + + return BitConverter.ToUInt16(bytes, 0); + }, + ToRaw = value => { + + return BitConverter.GetBytes(value); + + }, + }, + new PlcTypeConversion(RegisterType.DDT) { + HoldingRegisterType = typeof(NumberRegister), + PlcVarType = PlcVarType.DINT, + FromRaw = bytes => { + + return BitConverter.ToInt32(bytes, 0); + }, + ToRaw = value => { + + return BitConverter.GetBytes(value); + + }, + }, + new PlcTypeConversion(RegisterType.DDT) { + HoldingRegisterType = typeof(NumberRegister), + PlcVarType = PlcVarType.UDINT, + FromRaw = bytes => { + + return BitConverter.ToUInt32(bytes, 0); + }, + ToRaw = value => { + + return BitConverter.GetBytes(value); + + }, + }, + + }; + + } + +} diff --git a/MewtocolNet/TypeConversion/IPlcTypeConverter.cs b/MewtocolNet/TypeConversion/IPlcTypeConverter.cs new file mode 100644 index 0000000..0b381f8 --- /dev/null +++ b/MewtocolNet/TypeConversion/IPlcTypeConverter.cs @@ -0,0 +1,21 @@ +using System; + +namespace MewtocolNet { + + internal interface IPlcTypeConverter { + + object FromRawData(byte[] data); + + byte[] ToRawData(object value); + + Type GetDotnetType(); + + Type GetHoldingRegisterType(); + + RegisterType GetPlcRegisterType(); + + PlcVarType GetPlcVarType(); + + } + +} diff --git a/MewtocolNet/TypeConversion/PlcTypeConversion.cs b/MewtocolNet/TypeConversion/PlcTypeConversion.cs new file mode 100644 index 0000000..f50d0b5 --- /dev/null +++ b/MewtocolNet/TypeConversion/PlcTypeConversion.cs @@ -0,0 +1,42 @@ +using System; +using System.ComponentModel; + +namespace MewtocolNet { + + internal class PlcTypeConversion : IPlcTypeConverter { + + public Type MainType { get; private set; } + + public RegisterType PlcType { get; private set; } + + public PlcVarType PlcVarType { get; set; } + + public Type HoldingRegisterType { get; set; } + + public Func FromRaw { get; set; } + + public Func ToRaw { get; set; } + + public PlcTypeConversion(RegisterType plcType) { + + MainType = typeof(T); + PlcType = plcType; + + } + + public Type GetDotnetType() => MainType; + + public Type GetHoldingRegisterType() => HoldingRegisterType; + + public RegisterType GetPlcRegisterType() => PlcType; + + public PlcVarType GetPlcVarType() => PlcVarType; + + public object FromRawData(byte[] data) => FromRaw.Invoke(data); + + public byte[] ToRawData(object value) => ToRaw.Invoke((T)value); + + + } + +} diff --git a/MewtocolNet/TypeConversion/PlcValueParser.cs b/MewtocolNet/TypeConversion/PlcValueParser.cs new file mode 100644 index 0000000..05a34a1 --- /dev/null +++ b/MewtocolNet/TypeConversion/PlcValueParser.cs @@ -0,0 +1,55 @@ +using MewtocolNet.Exceptions; +using MewtocolNet.Registers; +using MewtocolNet.TypeConversion; +using System; +using System.Collections.Generic; +using System.Data; +using System.Linq; + +namespace MewtocolNet { + + internal static class PlcValueParser { + + private static List conversions => Conversions.items; + + public static T Parse(byte[] bytes) { + + var 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"); + + return (T)converter.FromRawData(bytes); + + } + + public static byte[] Encode (T value) { + + var 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"); + + return converter.ToRawData(value); + + } + + public static List GetAllowDotnetTypes () => conversions.Select(x => x.GetDotnetType()).ToList(); + + public static List GetAllowRegisterTypes () => conversions.Select(x => x.GetHoldingRegisterType()).ToList(); + + public static RegisterType? GetDefaultRegisterType (Type type) => + conversions.FirstOrDefault(x => x.GetDotnetType() == type)?.GetPlcRegisterType(); + + public static Type GetDefaultPlcVarType (this PlcVarType type) => + conversions.FirstOrDefault(x => x.GetPlcVarType() == type)?.GetHoldingRegisterType(); + + public static Type GetDefaultDotnetType (this PlcVarType type) => + conversions.FirstOrDefault(x => x.GetPlcVarType() == type)?.GetDotnetType(); + + public static PlcVarType? GetDefaultPlcVarType (this Type type) => + conversions.FirstOrDefault(x => x.GetDotnetType() == type)?.GetPlcVarType(); + + } + +} diff --git a/MewtocolNet/TypeConversion/PlcVarTypeConversions.cs b/MewtocolNet/TypeConversion/PlcVarTypeConversions.cs new file mode 100644 index 0000000..2ff6817 --- /dev/null +++ b/MewtocolNet/TypeConversion/PlcVarTypeConversions.cs @@ -0,0 +1,65 @@ +using MewtocolNet.Exceptions; +using MewtocolNet.Registers; +using MewtocolNet.TypeConversion; +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; + +namespace MewtocolNet { + + internal static class PlcVarTypeConversions { + + static List allowedCastingTypes = PlcValueParser.GetAllowDotnetTypes(); + + static List allowedGenericRegisters = PlcValueParser.GetAllowRegisterTypes(); + + internal static bool IsAllowedRegisterGenericType(this IRegister register) { + + return allowedGenericRegisters.Contains(register.GetType()); + + } + + internal static bool IsAllowedPlcCastingType() { + + return allowedCastingTypes.Contains(typeof(T)); + + } + + internal static bool IsAllowedPlcCastingType(this Type type) { + + return allowedCastingTypes.Contains(type); + + } + + internal static RegisterType ToRegisterTypeDefault(this Type type) { + + var found = PlcValueParser.GetDefaultRegisterType(type); + + if (found != null) { + + return found.Value; + + } + + throw new MewtocolException("No default register type found"); + + } + + internal static PlcVarType ToPlcVarType (this Type type) { + + var found = type.GetDefaultPlcVarType().Value; + + if (found != null) { + + return found; + + } + + throw new MewtocolException("No default plcvar type found"); + + } + + } + +} diff --git a/MewtocolTests/AutomatedPropertyRegisters.cs b/MewtocolTests/AutomatedPropertyRegisters.cs index cd46f3f..d0e4b1c 100644 --- a/MewtocolTests/AutomatedPropertyRegisters.cs +++ b/MewtocolTests/AutomatedPropertyRegisters.cs @@ -19,7 +19,7 @@ namespace MewtocolTests { //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, 100, spAdress: 0)] + [Register(IOType.R, memoryArea: 85, spAdress: 0)] public bool TestBool1 { get; private set; } //corresponds to a XD input of the PLC @@ -60,10 +60,10 @@ namespace MewtocolTests { 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, 9, BitCount.B16)] + [Register(1204, BitCount.B16, 9)] public bool BitValue { get; private set; } - [Register(1204, 5, BitCount.B16)] + [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) @@ -115,7 +115,7 @@ namespace MewtocolTests { var register = interf.GetRegister(nameof(TestRegisterCollection.TestBool1)); //test generic properties - TestBasicGeneration(register, nameof(TestRegisterCollection.TestBool1), false, 100, "R100"); + TestBasicGeneration(register, nameof(TestRegisterCollection.TestBool1), false, 85, "R85"); } @@ -208,8 +208,8 @@ namespace MewtocolTests { //test generic properties TestBasicGeneration(register, nameof(TestRegisterCollection.TestString2), null!, 7005, "DT7005"); - Assert.Equal(5, ((SRegister)register).ReservedSize); - Assert.Equal(4, ((SRegister)register).MemoryLength); + Assert.Equal(5, ((BytesRegister)register).ReservedSize); + Assert.Equal(4, ((BytesRegister)register).MemoryLength); } @@ -224,8 +224,8 @@ namespace MewtocolTests { //test generic properties TestBasicGeneration(register, "Auto_Bitwise_DT7010", (short)0, 7010, "DT7010"); - Assert.True(((NRegister)register).isUsedBitwise); - Assert.Equal(0, ((NRegister)register).MemoryLength); + Assert.True(((NumberRegister)register).isUsedBitwise); + Assert.Equal(0, ((NumberRegister)register).MemoryLength); } @@ -240,8 +240,8 @@ namespace MewtocolTests { //test generic properties TestBasicGeneration(register, "Auto_Bitwise_DDT8010", (int)0, 8010, "DDT8010"); - Assert.True(((NRegister)register).isUsedBitwise); - Assert.Equal(1, ((NRegister)register).MemoryLength); + Assert.True(((NumberRegister)register).isUsedBitwise); + Assert.Equal(1, ((NumberRegister)register).MemoryLength); } @@ -256,7 +256,7 @@ namespace MewtocolTests { //test generic properties TestBasicGeneration(register, "Auto_Bitwise_DT1204", (short)0, 1204, "DT1204"); - Assert.True(((NRegister)register).isUsedBitwise); + Assert.True(((NumberRegister)register).isUsedBitwise); } diff --git a/MewtocolTests/TestRegisterBuilder.cs b/MewtocolTests/TestRegisterBuilder.cs index d72671c..24a63f3 100644 --- a/MewtocolTests/TestRegisterBuilder.cs +++ b/MewtocolTests/TestRegisterBuilder.cs @@ -16,32 +16,32 @@ public class TestRegisterBuilder { this.output = output; } - [Fact(DisplayName = "Parsing as BRegister List (Phyiscal Outputs)")] + [Fact(DisplayName = "Parsing as Bool Register List (Phyiscal Outputs)")] public void TestParsingBRegisterY() { var tests = new Dictionary() { - {"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)}, + {"Y0", new BoolRegister(IOType.Y)}, + {"Y1", new BoolRegister(IOType.Y, 0x1)}, + {"Y2", new BoolRegister(IOType.Y, 0x2)}, + {"Y3", new BoolRegister(IOType.Y, 0x3)}, + {"Y4", new BoolRegister(IOType.Y, 0x4)}, + {"Y5", new BoolRegister(IOType.Y, 0x5)}, + {"Y6", new BoolRegister(IOType.Y, 0x6)}, + {"Y7", new BoolRegister(IOType.Y, 0x7)}, + {"Y8", new BoolRegister(IOType.Y, 0x8)}, + {"Y9", new BoolRegister(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)}, + {"YA", new BoolRegister(IOType.Y, 0xA)}, + {"YB", new BoolRegister(IOType.Y, 0xB)}, + {"YC", new BoolRegister(IOType.Y, 0xC)}, + {"YD", new BoolRegister(IOType.Y, 0xD)}, + {"YE", new BoolRegister(IOType.Y, 0xE)}, + {"YF", new BoolRegister(IOType.Y, 0xF)}, - {"Y1A", new BRegister(IOType.Y, 0xA, 1)}, - {"Y10B", new BRegister(IOType.Y, 0xB, 10)}, - {"Y109C", new BRegister(IOType.Y, 0xC, 109)}, + {"Y1A", new BoolRegister(IOType.Y, 0xA, 1)}, + {"Y10B", new BoolRegister(IOType.Y, 0xB, 10)}, + {"Y109C", new BoolRegister(IOType.Y, 0xC, 109)}, }; @@ -49,32 +49,32 @@ public class TestRegisterBuilder { } - [Fact(DisplayName = "Parsing as BRegister List (Phyiscal Inputs)")] + [Fact(DisplayName = "Parsing as Bool Register List (Phyiscal Inputs)")] public void TestParsingBRegisterX() { var tests = new Dictionary() { - {"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)}, + {"X0", new BoolRegister(IOType.X)}, + {"X1", new BoolRegister(IOType.X, 0x1)}, + {"X2", new BoolRegister(IOType.X, 0x2)}, + {"X3", new BoolRegister(IOType.X, 0x3)}, + {"X4", new BoolRegister(IOType.X, 0x4)}, + {"X5", new BoolRegister(IOType.X, 0x5)}, + {"X6", new BoolRegister(IOType.X, 0x6)}, + {"X7", new BoolRegister(IOType.X, 0x7)}, + {"X8", new BoolRegister(IOType.X, 0x8)}, + {"X9", new BoolRegister(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)}, + {"XA", new BoolRegister(IOType.X, 0xA)}, + {"XB", new BoolRegister(IOType.X, 0xB)}, + {"XC", new BoolRegister(IOType.X, 0xC)}, + {"XD", new BoolRegister(IOType.X, 0xD)}, + {"XE", new BoolRegister(IOType.X, 0xE)}, + {"XF", new BoolRegister(IOType.X, 0xF)}, - {"X1A", new BRegister(IOType.X, 0xA, 1)}, - {"X10B", new BRegister(IOType.X, 0xB, 10)}, - {"X109C", new BRegister(IOType.X, 0xC, 109)}, + {"X1A", new BoolRegister(IOType.X, 0xA, 1)}, + {"X10B", new BoolRegister(IOType.X, 0xB, 10)}, + {"X109C", new BoolRegister(IOType.X, 0xC, 109)}, }; @@ -82,35 +82,35 @@ public class TestRegisterBuilder { } - [Fact(DisplayName = "Parsing as BRegister List (Internal Relay)")] + [Fact(DisplayName = "Parsing as Bool Register List (Internal Relay)")] public void TestParsingBRegisterR() { var tests = new Dictionary() { - {"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)}, + {"R0", new BoolRegister(IOType.R)}, + {"R1", new BoolRegister(IOType.R, 0x1)}, + {"R2", new BoolRegister(IOType.R, 0x2)}, + {"R3", new BoolRegister(IOType.R, 0x3)}, + {"R4", new BoolRegister(IOType.R, 0x4)}, + {"R5", new BoolRegister(IOType.R, 0x5)}, + {"R6", new BoolRegister(IOType.R, 0x6)}, + {"R7", new BoolRegister(IOType.R, 0x7)}, + {"R8", new BoolRegister(IOType.R, 0x8)}, + {"R9", new BoolRegister(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)}, + {"RA", new BoolRegister(IOType.R, 0xA)}, + {"RB", new BoolRegister(IOType.R, 0xB)}, + {"RC", new BoolRegister(IOType.R, 0xC)}, + {"RD", new BoolRegister(IOType.R, 0xD)}, + {"RE", new BoolRegister(IOType.R, 0xE)}, + {"RF", new BoolRegister(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)}, + {"R1A", new BoolRegister(IOType.R, 0xA, 1)}, + {"R10B", new BoolRegister(IOType.R, 0xB, 10)}, + {"R109C", new BoolRegister(IOType.R, 0xC, 109)}, + {"R1000", new BoolRegister(IOType.R, 0x0, 100)}, + {"R511", new BoolRegister(IOType.R, 0x0, 511)}, + {"R511A", new BoolRegister(IOType.R, 0xA, 511)}, }; @@ -126,7 +126,7 @@ public class TestRegisterBuilder { output.WriteLine($"Expected: {item.Key}"); - var built = RegBuilder.FromPlcRegName(item.Key).AsPlcType(PlcVarType.BOOL).Build(); + var built = RegBuilder.Factory.FromPlcRegName(item.Key).AsPlcType(PlcVarType.BOOL).Build(); output.WriteLine($"{(built?.ToString(true) ?? "null")}\n"); Assert.Equivalent(item.Value, built); @@ -141,63 +141,75 @@ public class TestRegisterBuilder { } - [Fact(DisplayName = "Parsing as BRegister (Casted)")] + [Fact(DisplayName = "Parsing as Bool Register (Casted)")] public void TestRegisterBuildingBoolCasted () { - var expect = new BRegister(IOType.R, 0x1, 0); - var expect2 = new BRegister(IOType.Y, 0xA, 103); + var expect = new BoolRegister(IOType.R, 0x1, 0); + var expect2 = new BoolRegister(IOType.Y, 0xA, 103); - Assert.Equivalent(expect, RegBuilder.FromPlcRegName("R1").AsPlcType(PlcVarType.BOOL).Build()); - Assert.Equivalent(expect, RegBuilder.FromPlcRegName("R1").AsType().Build()); + Assert.Equivalent(expect, RegBuilder.Factory.FromPlcRegName("R1").AsPlcType(PlcVarType.BOOL).Build()); + Assert.Equivalent(expect, RegBuilder.Factory.FromPlcRegName("R1").AsType().Build()); - Assert.Equivalent(expect2, RegBuilder.FromPlcRegName("Y103A").AsPlcType(PlcVarType.BOOL).Build()); - Assert.Equivalent(expect2, RegBuilder.FromPlcRegName("Y103A").AsType().Build()); + Assert.Equivalent(expect2, RegBuilder.Factory.FromPlcRegName("Y103A").AsPlcType(PlcVarType.BOOL).Build()); + Assert.Equivalent(expect2, RegBuilder.Factory.FromPlcRegName("Y103A").AsType().Build()); } - [Fact(DisplayName = "Parsing as BRegister (Auto)")] + [Fact(DisplayName = "Parsing as Bool Register (Auto)")] public void TestRegisterBuildingBoolAuto () { - var expect = new BRegister(IOType.R, 0x1, 0); - var expect2 = new BRegister(IOType.Y, 0xA, 103); + var expect = new BoolRegister(IOType.R, 0x1, 0); + var expect2 = new BoolRegister(IOType.Y, 0xA, 103); - Assert.Equivalent(expect, RegBuilder.FromPlcRegName("R1").Build()); - Assert.Equivalent(expect, RegBuilder.FromPlcRegName("R1").Build()); + Assert.Equivalent(expect, RegBuilder.Factory.FromPlcRegName("R1").Build()); + Assert.Equivalent(expect, RegBuilder.Factory.FromPlcRegName("R1").Build()); - Assert.Equivalent(expect2, RegBuilder.FromPlcRegName("Y103A").Build()); - Assert.Equivalent(expect2, RegBuilder.FromPlcRegName("Y103A").Build()); + Assert.Equivalent(expect2, RegBuilder.Factory.FromPlcRegName("Y103A").Build()); + Assert.Equivalent(expect2, RegBuilder.Factory.FromPlcRegName("Y103A").Build()); } - [Fact(DisplayName = "Parsing as NRegister (Casted)")] + [Fact(DisplayName = "Parsing as Number Register (Casted)")] public void TestRegisterBuildingNumericCasted() { - var expect = new NRegister(303, null); - var expect2 = new NRegister(10002, null); - var expect3 = new NRegister(400, null); + 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); - Assert.Equivalent(expect, RegBuilder.FromPlcRegName("DT303").AsPlcType(PlcVarType.INT).Build()); - Assert.Equivalent(expect, RegBuilder.FromPlcRegName("DT303").AsType().Build()); + Assert.Equivalent(expect, RegBuilder.Factory.FromPlcRegName("DT303").AsPlcType(PlcVarType.INT).Build()); + Assert.Equivalent(expect, RegBuilder.Factory.FromPlcRegName("DT303").AsType().Build()); - Assert.Equivalent(expect2, RegBuilder.FromPlcRegName("DDT10002").AsPlcType(PlcVarType.DINT).Build()); - Assert.Equivalent(expect2, RegBuilder.FromPlcRegName("DDT10002").AsType().Build()); + Assert.Equivalent(expect2, RegBuilder.Factory.FromPlcRegName("DDT10002").AsPlcType(PlcVarType.DINT).Build()); + Assert.Equivalent(expect2, RegBuilder.Factory.FromPlcRegName("DDT10002").AsType().Build()); - Assert.Equivalent(expect3, RegBuilder.FromPlcRegName("DDT400").AsPlcType(PlcVarType.TIME).Build()); - Assert.Equivalent(expect3, RegBuilder.FromPlcRegName("DDT400").AsType().Build()); + Assert.Equivalent(expect3, RegBuilder.Factory.FromPlcRegName("DDT400").AsPlcType(PlcVarType.TIME).Build()); + Assert.Equivalent(expect3, RegBuilder.Factory.FromPlcRegName("DDT400").AsType().Build()); //Assert.Equivalent(expect4, RegBuilder.FromPlcRegName("DT103").AsType().Build()); } - [Fact(DisplayName = "Parsing as NRegister (Auto)")] + [Fact(DisplayName = "Parsing as Number Register (Auto)")] public void TestRegisterBuildingNumericAuto() { - var expect = new NRegister(303, null); - var expect2 = new NRegister(10002, null); + var expect = new NumberRegister(303, null); + var expect2 = new NumberRegister(10002, null); + + Assert.Equivalent(expect, RegBuilder.Factory.FromPlcRegName("DT303").Build()); + Assert.Equivalent(expect2, RegBuilder.Factory.FromPlcRegName("DDT10002").Build()); + + } + + [Fact(DisplayName = "Parsing as Bytes Register (Casted)")] + public void TestRegisterBuildingByteRangeCasted() { + + var expect = new BytesRegister(303, 5); + + + Assert.Equivalent(expect, RegBuilder.Factory.FromPlcRegName("DT303").AsPlcType(PlcVarType.INT).Build()); + Assert.Equivalent(expect, RegBuilder.Factory.FromPlcRegName("DT303").AsType().Build()); - Assert.Equivalent(expect, RegBuilder.FromPlcRegName("DT303").Build()); - Assert.Equivalent(expect2, RegBuilder.FromPlcRegName("DDT10002").Build()); } diff --git a/MewtocolTests/TestRegisterInterface.cs b/MewtocolTests/TestRegisterInterface.cs index bf11d1b..8a11726 100644 --- a/MewtocolTests/TestRegisterInterface.cs +++ b/MewtocolTests/TestRegisterInterface.cs @@ -17,12 +17,12 @@ namespace MewtocolTests { public void NumericRegisterMewtocolIdentifiers() { List registers = new List { - new NRegister(50, _name: null), - new NRegister(50, _name: null), - new NRegister(50, _name : null), - new NRegister(50, _name : null), - new NRegister(50, _name : null), - new NRegister(50, _name : null), + new NumberRegister(50, _name: null), + new NumberRegister(50, _name: null), + new NumberRegister(50, _name : null), + new NumberRegister(50, _name : null), + new NumberRegister(50, _name : null), + new NumberRegister(50, _name : null), }; List expectedIdents = new List { @@ -51,23 +51,23 @@ namespace MewtocolTests { List registers = new List { //numeric ones - new NRegister(50, _name: null), - new NRegister(60, _name : null), - new NRegister(70, _name : null), - new NRegister(80, _name : null), - new NRegister(90, _name : null), - new NRegister(100, _name : null), + new NumberRegister(50, _name: null), + new NumberRegister(60, _name : null), + new NumberRegister(70, _name : null), + new NumberRegister(80, _name : null), + new NumberRegister(90, _name : null), + new NumberRegister(100, _name : null), //boolean - new BRegister(IOType.R, 0, 100), - new BRegister(IOType.R, 0, 0), - new BRegister(IOType.X, 5), - new BRegister(IOType.X, 0xA), - new BRegister(IOType.X, 0xF, 109), - new BRegister(IOType.Y, 0xC, 75), + new BoolRegister(IOType.R, 0, 100), + new BoolRegister(IOType.R, 0, 0), + new BoolRegister(IOType.X, 5), + new BoolRegister(IOType.X, 0xA), + new BoolRegister(IOType.X, 0xF, 109), + new BoolRegister(IOType.Y, 0xC, 75), //string - new SRegister(999, 5), + new BytesRegister(999, 5), }; List expcectedIdents = new List { @@ -110,7 +110,7 @@ namespace MewtocolTests { var ex = Assert.Throws(() => { - new NRegister(100000, _name: null); + new NumberRegister(100000, _name: null); }); @@ -118,7 +118,7 @@ namespace MewtocolTests { var ex1 = Assert.Throws(() => { - new BRegister(IOType.R, _areaAdress: 512); + new BoolRegister(IOType.R, _areaAdress: 512); }); @@ -126,7 +126,7 @@ namespace MewtocolTests { var ex2 = Assert.Throws(() => { - new BRegister(IOType.X, _areaAdress: 110); + new BoolRegister(IOType.X, _areaAdress: 110); }); @@ -134,7 +134,7 @@ namespace MewtocolTests { var ex3 = Assert.Throws(() => { - new SRegister(100000, 5); + new BytesRegister(100000, 5); }); @@ -147,7 +147,7 @@ namespace MewtocolTests { var ex = Assert.Throws(() => { - new NRegister(100, _name: null); + new NumberRegister(100, _name: null); }); diff --git a/PLC_Test/test_c30_fpx_h.ini b/PLC_Test/test_c30_fpx_h.ini index e810e50..90aaa53 100644 Binary files a/PLC_Test/test_c30_fpx_h.ini and b/PLC_Test/test_c30_fpx_h.ini differ diff --git a/PLC_Test/test_c30_fpx_h.pro b/PLC_Test/test_c30_fpx_h.pro index fb08732..5b9447f 100644 Binary files a/PLC_Test/test_c30_fpx_h.pro and b/PLC_Test/test_c30_fpx_h.pro differ diff --git a/PLC_Test/test_c30_fpx_h.xml b/PLC_Test/test_c30_fpx_h.xml index 4109899..9a30f61 100644 --- a/PLC_Test/test_c30_fpx_h.xml +++ b/PLC_Test/test_c30_fpx_h.xml @@ -2,10 +2,20 @@ - + - + + + + + + + + + + +