diff --git a/MewtocolNet/CustomTypes/DWord.cs b/MewtocolNet/CustomTypes/DWord.cs new file mode 100644 index 0000000..2bef2bd --- /dev/null +++ b/MewtocolNet/CustomTypes/DWord.cs @@ -0,0 +1,117 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Drawing; +using System.Linq; +using System.Numerics; +using System.Runtime.InteropServices; +using System.Text; + +namespace MewtocolNet { + + /// + /// A DWord is a 16 bit value of 2 bytes + /// + public struct DWord : MewtocolExtensionTypeDDT { + + private int bitLength; + + internal uint value; + + public uint Value { + get => value; + set { + this.value = value; + } + } + + public DWord(uint bytes) { + value = bytes; + bitLength = Marshal.SizeOf(value) * 8; + } + public DWord(byte[] bytes) { + bytes = bytes.Take(4).ToArray(); + value = BitConverter.ToUInt32(bytes, 0); + bitLength = Marshal.SizeOf(value) * 8; + } + + //operations + + public static DWord operator -(DWord a, DWord b) => new DWord() { + value = (ushort)(a.value - b.value) + }; + + public static DWord operator +(DWord a, DWord b) => new DWord() { + value = (ushort)(a.value + b.value) + }; + + public static DWord operator *(DWord a, DWord b) => new DWord() { + value = (ushort)(a.value * b.value) + }; + + public static DWord operator /(DWord a, DWord b) => new DWord() { + value = (ushort)(a.value / b.value) + }; + + public static bool operator ==(DWord a, DWord b) => a.value == b.value; + + public static bool operator !=(DWord a, DWord b) => a.value != b.value; + + /// + /// Gets or sets the bit value at the given position + /// + public bool this[int bitIndex] { + get { + if (bitIndex > bitLength - 1) + throw new IndexOutOfRangeException($"The DWord bit index was out of range ({bitIndex}/{bitLength - 1})"); + + return (value & (1 << bitIndex)) != 0; + } + set { + if (bitIndex > bitLength - 1) + throw new IndexOutOfRangeException($"The DWord bit index was out of range ({bitIndex}/{bitLength - 1})"); + + int mask = 1 << bitIndex; + this.value = value ? this.value |= (uint)mask : this.value &= (uint)~mask; + } + } + + public void ClearBits () => this.value = 0; + + public override bool Equals(object obj) { + + if ((obj == null) || !this.GetType().Equals(obj.GetType())) { + return false; + } else { + return (DWord)obj == this; + } + + } + + public override int GetHashCode() => (int)value; + + public byte[] ToByteArray() => BitConverter.GetBytes(value); + + //string ops + + public override string ToString() => $"0x{value.ToString("X8")}"; + + public string ToStringBits () { + + return Convert.ToString(value, 2).PadLeft(bitLength, '0'); + + } + + public string ToStringBitsPlc () { + + var parts = Convert.ToString(value, 2) + .PadLeft(Marshal.SizeOf(value) * 8, '0') + .SplitInParts(4); + + return string.Join("_", parts); + + } + + } + +} diff --git a/MewtocolNet/CustomTypes/MewtocolExtensionType.cs b/MewtocolNet/CustomTypes/MewtocolExtensionType.cs new file mode 100644 index 0000000..85cb76c --- /dev/null +++ b/MewtocolNet/CustomTypes/MewtocolExtensionType.cs @@ -0,0 +1,7 @@ +namespace MewtocolNet { + + internal interface MewtocolExtensionTypeDT { } + + internal interface MewtocolExtensionTypeDDT { } + +} diff --git a/MewtocolNet/CustomTypes/Word.cs b/MewtocolNet/CustomTypes/Word.cs new file mode 100644 index 0000000..b544e51 --- /dev/null +++ b/MewtocolNet/CustomTypes/Word.cs @@ -0,0 +1,117 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Drawing; +using System.Linq; +using System.Numerics; +using System.Runtime.InteropServices; +using System.Text; + +namespace MewtocolNet { + + /// + /// A word is a 16 bit value of 2 bytes + /// + public struct Word : MewtocolExtensionTypeDT { + + private int bitLength; + + internal ushort value; + + public ushort Value { + get => value; + set { + this.value = value; + } + } + + public Word(ushort bytes) { + value = bytes; + bitLength = Marshal.SizeOf(value) * 8; + } + public Word(byte[] bytes) { + bytes = bytes.Take(2).ToArray(); + value = BitConverter.ToUInt16(bytes, 0); + bitLength = Marshal.SizeOf(value) * 8; + } + + //operations + + public static Word operator -(Word a, Word b) => new Word() { + value = (ushort)(a.value - b.value) + }; + + public static Word operator +(Word a, Word b) => new Word() { + value = (ushort)(a.value + b.value) + }; + + public static Word operator *(Word a, Word b) => new Word() { + value = (ushort)(a.value * b.value) + }; + + public static Word operator /(Word a, Word b) => new Word() { + value = (ushort)(a.value / b.value) + }; + + public static bool operator ==(Word a, Word b) => a.value == b.value; + + public static bool operator !=(Word a, Word b) => a.value != b.value; + + /// + /// Gets or sets the bit value at the given position + /// + public bool this[int bitIndex] { + get { + if (bitIndex > bitLength - 1) + throw new IndexOutOfRangeException($"The word bit index was out of range ({bitIndex}/{bitLength - 1})"); + + return (value & (1 << bitIndex)) != 0; + } + set { + if (bitIndex > bitLength - 1) + throw new IndexOutOfRangeException($"The word bit index was out of range ({bitIndex}/{bitLength - 1})"); + + int mask = 1 << bitIndex; + this.value = value ? this.value |= (ushort)mask : this.value &= (ushort)~mask; + } + } + + public void ClearBits () => this.value = 0; + + public override bool Equals(object obj) { + + if ((obj == null) || !this.GetType().Equals(obj.GetType())) { + return false; + } else { + return (Word)obj == this; + } + + } + + public override int GetHashCode() => (int)value; + + public byte[] ToByteArray() => BitConverter.GetBytes(value); + + //string ops + + public override string ToString() => $"0x{value.ToString("X4")}"; + + public string ToStringBits () { + + return Convert.ToString(value, 2).PadLeft(bitLength, '0'); + + } + + public string ToStringBitsPlc () { + + var parts = Convert.ToString(value, 2) + .PadLeft(Marshal.SizeOf(value) * 8, '0') + .SplitInParts(4); + + return string.Join("_", parts); + + } + + } + +} diff --git a/MewtocolNet/Helpers/MewtocolHelpers.cs b/MewtocolNet/Helpers/MewtocolHelpers.cs index 2191b05..493f44d 100644 --- a/MewtocolNet/Helpers/MewtocolHelpers.cs +++ b/MewtocolNet/Helpers/MewtocolHelpers.cs @@ -5,8 +5,10 @@ using System.Collections; using System.Collections.Generic; using System.Globalization; using System.Linq; +using System.Security.Cryptography; using System.Text; using System.Text.RegularExpressions; +using static MewtocolNet.RegisterBuilding.RBuild; namespace MewtocolNet { @@ -252,14 +254,18 @@ namespace MewtocolNet { } - internal static bool CompareIsDuplicateNonCast (this BaseRegister reg1, BaseRegister compare, bool ingnoreByteRegisters = true) { + internal static bool CompareIsDuplicateNonCast (this BaseRegister toInsert, BaseRegister compare, List allowOverlappingTypes) { - if (ingnoreByteRegisters && (compare.GetType() == typeof(BytesRegister) || reg1.GetType() == typeof(BytesRegister))) return false; + foreach (var type in allowOverlappingTypes) { - bool valCompare = reg1.GetType() != compare.GetType() && - reg1.MemoryAddress == compare.MemoryAddress && - reg1.GetRegisterAddressLen() == compare.GetRegisterAddressLen() && - reg1.GetSpecialAddress() == compare.GetSpecialAddress(); + if (toInsert.GetType() == type) return false; + + } + + bool valCompare = toInsert.GetType() != compare.GetType() && + toInsert.MemoryAddress == compare.MemoryAddress && + toInsert.GetRegisterAddressLen() == compare.GetRegisterAddressLen() && + toInsert.GetSpecialAddress() == compare.GetSpecialAddress(); return valCompare; diff --git a/MewtocolNet/MewtocolInterface.cs b/MewtocolNet/MewtocolInterface.cs index 147ee10..5abde05 100644 --- a/MewtocolNet/MewtocolInterface.cs +++ b/MewtocolNet/MewtocolInterface.cs @@ -156,10 +156,11 @@ namespace MewtocolNet { private void OnRegisterChanged(IRegister o) { - var asInternal = (IRegisterInternal)o; + var asInternal = (BaseRegister)o; Logger.Log($"{asInternal.GetMewName()} " + $"{(o.Name != null ? $"({o.Name}) " : "")}" + + $"{asInternal.underlyingSystemType} " + $"changed to \"{asInternal.GetValueString()}\"", LogLevel.Change, this); OnRegisterChangedUpdateProps((IRegisterInternal)o); diff --git a/MewtocolNet/MewtocolInterfaceRegisterHandling.cs b/MewtocolNet/MewtocolInterfaceRegisterHandling.cs index 1c80a4f..28dc91e 100644 --- a/MewtocolNet/MewtocolInterfaceRegisterHandling.cs +++ b/MewtocolNet/MewtocolInterfaceRegisterHandling.cs @@ -290,20 +290,7 @@ namespace MewtocolNet { internal void InsertRegistersToMemoryStack (List registers) { - //order by address - registers = registers.OrderBy(x => x.GetSpecialAddress()).ToList(); - registers = registers.OrderBy(x => x.MemoryAddress).ToList(); - - //link to memory manager - for (int i = 0, j = 0; i < registers.Count; i++) { - - BaseRegister reg = registers[i]; - reg.name = $"auto_prop_register_{j + 1}"; - - //link the memory area to the register - if (memoryManager.LinkRegister(reg)) j++; - - } + memoryManager.LinkRegisters(registers); } @@ -408,7 +395,7 @@ namespace MewtocolNet { } - internal void InvokeRegisterChanged(IRegister reg) { + internal void InvokeRegisterChanged(BaseRegister reg) { RegisterChanged?.Invoke(reg); diff --git a/MewtocolNet/RegisterBuilding/RBuild.cs b/MewtocolNet/RegisterBuilding/RBuild.cs index 7547560..28087e0 100644 --- a/MewtocolNet/RegisterBuilding/RBuild.cs +++ b/MewtocolNet/RegisterBuilding/RBuild.cs @@ -362,13 +362,14 @@ namespace MewtocolNet.RegisterBuilding { /// Boolean R/X/Y registers /// 16 bit signed integer /// 16 bit un-signed integer + /// 16 bit word (2 bytes) /// 32 bit signed integer /// 32 bit un-signed integer + /// 32 bit word (4 bytes) /// 32 bit floating point /// 32 bit time from interpreted as - /// 16 or 32 bit enums + /// 16 or 32 bit enums, also supports flags /// String of chars, the interface will automatically get the length - /// As an array of bits /// As an array of bytes /// /// @@ -611,7 +612,7 @@ namespace MewtocolNet.RegisterBuilding { var assembler = new RegisterAssembler(attachedPLC); var tempRegister = assembler.Assemble(reg.Data); - return await tempRegister.WriteToAnonymousAsync(value); + return await tempRegister.WriteAsync(value); } @@ -619,7 +620,7 @@ namespace MewtocolNet.RegisterBuilding { var assembler = new RegisterAssembler(attachedPLC); var tempRegister = assembler.Assemble(reg.Data); - return await tempRegister.WriteToAnonymousAsync(value); + return await tempRegister.WriteAsync(value); } @@ -627,7 +628,7 @@ namespace MewtocolNet.RegisterBuilding { var assembler = new RegisterAssembler(attachedPLC); var tempRegister = assembler.Assemble(reg.Data); - return await tempRegister.ReadFromAnonymousAsync(); + return await tempRegister.ReadAsync(); } @@ -635,7 +636,7 @@ namespace MewtocolNet.RegisterBuilding { var assembler = new RegisterAssembler(attachedPLC); var tempRegister = assembler.Assemble(reg.Data); - return (T)await tempRegister.ReadFromAnonymousAsync(); + return (T)await tempRegister.ReadAsync(); } diff --git a/MewtocolNet/RegisterBuilding/RegisterAssembler.cs b/MewtocolNet/RegisterBuilding/RegisterAssembler.cs index 86d8e4b..8accdce 100644 --- a/MewtocolNet/RegisterBuilding/RegisterAssembler.cs +++ b/MewtocolNet/RegisterBuilding/RegisterAssembler.cs @@ -3,6 +3,7 @@ using MewtocolNet.RegisterAttributes; using MewtocolNet.Registers; using System; using System.Collections.Generic; +using System.Data; using System.Reflection; using System.Runtime.InteropServices; using static MewtocolNet.RegisterBuilding.RBuild; @@ -49,9 +50,9 @@ namespace MewtocolNet.RegisterBuilding { //as numeric register with enum target var underlying = Enum.GetUnderlyingType(data.dotnetVarType); - var enuSize = Marshal.SizeOf(underlying); + int numericSize = Marshal.SizeOf(underlying); - if (enuSize > 4) + if (numericSize > 4) throw new NotSupportedException("Enums not based on 16 or 32 bit numbers are not supported"); var flags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance; @@ -61,6 +62,8 @@ namespace MewtocolNet.RegisterBuilding { var parameters = new object[] { data.memAddress, data.name }; var instance = (BaseRegister)constr.Invoke(parameters); + instance.RegisterType = numericSize > 2 ? RegisterType.DDT : RegisterType.DT; + generatedInstance = instance; } else if (registerClassType.IsGenericType) { @@ -74,23 +77,31 @@ namespace MewtocolNet.RegisterBuilding { //int _adress, Type _enumType = null, string _name = null var parameters = new object[] { data.memAddress, data.name }; var instance = (BaseRegister)Activator.CreateInstance(registerClassType, flags, null, parameters, null); - instance.pollLevel = data.pollLevel; + + int numericSize = 0; + bool isExtensionTypeDT = typeof(MewtocolExtensionTypeDT).IsAssignableFrom(data.dotnetVarType); + bool isExtensionTypeDDT = typeof(MewtocolExtensionTypeDDT).IsAssignableFrom(data.dotnetVarType); + + if (data.dotnetVarType.Namespace == "System") { + numericSize = Marshal.SizeOf(data.dotnetVarType); + } else if(isExtensionTypeDT) { + numericSize = 2; + } else if(isExtensionTypeDDT) { + numericSize = 4; + } else { + throw new NotSupportedException($"The type {data.dotnetVarType} is not supported for NumberRegisters"); + } + + instance.RegisterType = numericSize > 2 ? RegisterType.DDT : RegisterType.DT; + generatedInstance = instance; - } else if (registerClassType == typeof(BytesRegister) && data.byteSize != null) { + } else if (registerClassType == typeof(ArrayRegister) && data.byteSize != null) { //------------------------------------------- //as byte range register - BytesRegister instance = new BytesRegister(data.memAddress, (uint)data.byteSize, data.name); - generatedInstance = instance; - - } else if (registerClassType == typeof(BytesRegister) && data.bitSize != null) { - - //------------------------------------------- - //as bit range register - - BytesRegister instance = new BytesRegister(data.memAddress, (ushort)data.bitSize, data.name); + ArrayRegister instance = new ArrayRegister(data.memAddress, (uint)data.byteSize, data.name); generatedInstance = instance; } else if (registerClassType == typeof(StringRegister)) { @@ -125,8 +136,13 @@ namespace MewtocolNet.RegisterBuilding { if (collectionTarget != null) generatedInstance.WithRegisterCollection(collectionTarget); - generatedInstance.attachedInterface = onInterface; + if (data.boundProperty != null) + generatedInstance.WithBoundProperty(new RegisterPropTarget { + BoundProperty = data.boundProperty, + }); + generatedInstance.attachedInterface = onInterface; + generatedInstance.underlyingSystemType = data.dotnetVarType; generatedInstance.pollLevel = data.pollLevel; return generatedInstance; diff --git a/MewtocolNet/Registers/ArrayRegister.cs b/MewtocolNet/Registers/ArrayRegister.cs new file mode 100644 index 0000000..04facc4 --- /dev/null +++ b/MewtocolNet/Registers/ArrayRegister.cs @@ -0,0 +1,107 @@ +using MewtocolNet.Exceptions; +using System; +using System.Collections; +using System.Collections.Generic; +using System.ComponentModel; +using System.Text; +using System.Threading; +using System.Threading.Tasks; + +namespace MewtocolNet.Registers { + + /// + /// Defines a register containing a string + /// + public class ArrayRegister : BaseRegister { + + internal uint addressLength; + + /// + /// The rgisters memory length + /// + public uint AddressLength => addressLength; + + internal uint ReservedBytesSize { get; set; } + + internal ushort? ReservedBitSize { get; set; } + + [Obsolete("Creating registers directly is not supported use IPlc.Register instead")] + public ArrayRegister() => + throw new NotSupportedException("Direct register instancing is not supported, use the builder pattern"); + + internal ArrayRegister(uint _address, uint _reservedByteSize, string _name = null) { + + name = _name; + memoryAddress = _address; + ReservedBytesSize = _reservedByteSize; + + //calc mem length + //because one register is always 1 word (2 bytes) long, if the bytecount is uneven we get the trailing word too + var byteSize = ReservedBytesSize; + if (ReservedBytesSize % 2 != 0) byteSize++; + + RegisterType = RegisterType.DT_BYTE_RANGE; + addressLength = Math.Max((byteSize / 2), 1); + + CheckAddressOverflow(memoryAddress, addressLength); + + lastValue = null; + + } + + public override string GetValueString() { + + if (Value == null) return "null"; + + if(Value != null && Value is BitArray bitArr) { + + return bitArr.ToBitString(); + + } else { + + return ((byte[])Value).ToHexString("-"); + + } + + } + + /// + public override string BuildMewtocolQuery() { + + StringBuilder asciistring = new StringBuilder("D"); + + asciistring.Append(MemoryAddress.ToString().PadLeft(5, '0')); + asciistring.Append((MemoryAddress + AddressLength - 1).ToString().PadLeft(5, '0')); + + return asciistring.ToString(); + } + + /// + public override string GetRegisterString() => "DT"; + + /// + public override uint GetRegisterAddressLen() => AddressLength; + + /// + internal override void UpdateHoldingValue(object val) { + + bool changeTriggerBitArr = val is BitArray bitArr && + lastValue is BitArray bitArr2 && + (bitArr.ToBitString() != bitArr2.ToBitString()); + + bool changeTriggerGeneral = (lastValue?.ToString() != val?.ToString()); + + if (changeTriggerBitArr || changeTriggerGeneral) { + + lastValue = val; + + TriggerNotifyChange(); + attachedInterface.InvokeRegisterChanged(this); + + } + + } + + } + +} diff --git a/MewtocolNet/Registers/BaseRegister.cs b/MewtocolNet/Registers/BaseRegister.cs index ac36db9..853454a 100644 --- a/MewtocolNet/Registers/BaseRegister.cs +++ b/MewtocolNet/Registers/BaseRegister.cs @@ -19,8 +19,10 @@ namespace MewtocolNet.Registers { //links to internal RegisterCollection containedCollection; internal MewtocolInterface attachedInterface; - internal List boundToProps = new List(); + internal List boundProperties = new List(); + + internal Type underlyingSystemType; internal IMemoryArea underlyingMemory; internal object lastValue = null; internal string name; @@ -40,7 +42,7 @@ namespace MewtocolNet.Registers { public object Value => lastValue; /// - public RegisterType RegisterType { get; protected set; } + public RegisterType RegisterType { get; internal set; } /// public string Name => name; @@ -59,9 +61,9 @@ namespace MewtocolNet.Registers { #endregion - public virtual void ClearValue() => SetValueFromPLC(null); + public virtual void ClearValue() => UpdateHoldingValue(null); - public virtual void SetValueFromPLC(object val) { + internal virtual void UpdateHoldingValue(object val) { if(lastValue?.ToString() != val?.ToString()) { @@ -78,7 +80,14 @@ namespace MewtocolNet.Registers { internal void WithRegisterCollection (RegisterCollection collection) => containedCollection = collection; - internal void WithBoundProperty(RegisterPropTarget propInfo) => boundToProps.Add(propInfo); + internal void WithBoundProperty(RegisterPropTarget propInfo) => boundProperties.Add(propInfo); + + internal void WithBoundProperties(IEnumerable propInfos) { + + foreach (var item in propInfos) + boundProperties.Add(item); + + } #region Read / Write @@ -86,10 +95,6 @@ namespace MewtocolNet.Registers { public virtual Task WriteAsync(object data) => throw new NotImplementedException(); - internal virtual Task WriteToAnonymousAsync (object value) => throw new NotImplementedException(); - - internal virtual Task ReadFromAnonymousAsync () => throw new NotImplementedException(); - #endregion #region Default accessors @@ -147,18 +152,36 @@ namespace MewtocolNet.Registers { else successfulWrites++; } + internal virtual bool IsSameAddressAndType (BaseRegister toCompare) { + + return this.MemoryAddress == toCompare.MemoryAddress && + this.RegisterType == toCompare.RegisterType && + this.GetRegisterAddressLen() == toCompare.GetRegisterAddressLen() && + this.GetSpecialAddress() == toCompare.GetSpecialAddress(); + + } + + internal virtual bool IsSameAddress (BaseRegister toCompare) { + + return (this.MemoryAddress == toCompare.MemoryAddress) && + (this.GetRegisterAddressLen() == toCompare.GetRegisterAddressLen()) && + (this.GetSpecialAddress() == toCompare.GetSpecialAddress()); + + } + public override string ToString() { var sb = new StringBuilder(); sb.Append(GetMewName()); if(Name != null) sb.Append($" ({Name})"); + sb.Append($" [{this.GetType().Name}({underlyingSystemType.Name})]"); if (Value != null) sb.Append($" Val: {GetValueString()}"); return sb.ToString(); } - public virtual string ToString(bool additional) { + public virtual string ToString (bool additional) { if (!additional) return this.ToString(); @@ -166,16 +189,30 @@ namespace MewtocolNet.Registers { sb.AppendLine($"MewName: {GetMewName()}"); sb.AppendLine($"Name: {Name ?? "Not named"}"); sb.AppendLine($"Value: {GetValueString()}"); - sb.AppendLine($"Perf. Reads: {successfulReads}, Writes: {successfulWrites}"); sb.AppendLine($"Register Type: {RegisterType}"); sb.AppendLine($"Address: {GetRegisterWordRangeString()}"); - if(this is StringRegister sr) sb.AppendLine($"Reserved: {sr.ReservedSize}, Used: {sr.UsedSize}"); + + return sb.ToString(); + + } + + public virtual string Explain () { + + StringBuilder sb = new StringBuilder(); + sb.AppendLine($"MewName: {GetMewName()}"); + sb.AppendLine($"Name: {Name ?? "Not named"}"); + sb.AppendLine($"Value: {GetValueString()}"); + sb.AppendLine($"Perf. Reads: {successfulReads}, Writes: {successfulWrites}"); + sb.AppendLine($"Register Type: {RegisterType}"); + sb.AppendLine($"Underlying System Type: {underlyingSystemType}"); + sb.AppendLine($"Address: {GetRegisterWordRangeString()}"); + if (this is StringRegister sr) sb.AppendLine($"Reserved: {sr.ReservedSize}, Used: {sr.UsedSize}"); if (GetSpecialAddress() != null) sb.AppendLine($"SPAddress: {GetSpecialAddress():X1}"); if (GetType().IsGenericType) sb.AppendLine($"Type: NumberRegister<{GetType().GenericTypeArguments[0]}>"); else sb.AppendLine($"Type: {GetType()}"); - if(containedCollection != null) sb.AppendLine($"In collection: {containedCollection.GetType()}"); - if(boundToProps != null && boundToProps.Count != 0) - sb.AppendLine($"Bound props: {string.Join(",", boundToProps)}"); + if (containedCollection != null) sb.AppendLine($"In collection: {containedCollection.GetType()}"); + if (boundProperties != null && boundProperties.Count > 0) sb.AppendLine($"Bound props: {string.Join(", ", boundProperties)}"); + else sb.AppendLine("No bound properties"); return sb.ToString(); diff --git a/MewtocolNet/Registers/BoolRegister.cs b/MewtocolNet/Registers/BoolRegister.cs index ffd332e..80fa9ed 100644 --- a/MewtocolNet/Registers/BoolRegister.cs +++ b/MewtocolNet/Registers/BoolRegister.cs @@ -54,57 +54,6 @@ namespace MewtocolNet.Registers { } - #region Read / Write - - /// - public override async Task ReadAsync() { - - if (!attachedInterface.IsConnected) - throw MewtocolException.NotConnectedSend(); - - return null; - - } - - /// - public override async Task WriteAsync(object data) { - - if (!attachedInterface.IsConnected) - throw MewtocolException.NotConnectedSend(); - - return false; - - } - - internal override async Task WriteToAnonymousAsync (object value) { - - if (!attachedInterface.IsConnected) - throw MewtocolException.NotConnectedSend(); - - var station = attachedInterface.GetStationNumber(); - string reqStr = $"%{station}#WCS{BuildMewtocolQuery()}{((bool)value ? "1" : "0")}"; - var res = await attachedInterface.SendCommandAsync(reqStr); - - return res.Success; - - } - - internal override async Task ReadFromAnonymousAsync() { - - if (!attachedInterface.IsConnected) - throw MewtocolException.NotConnectedSend(); - - var station = attachedInterface.GetStationNumber(); - string requeststring = $"%{station}#RCS{BuildMewtocolQuery()}"; - var result = await attachedInterface.SendCommandAsync(requeststring); - if (!result.Success) return null; - - return result.Response.ParseRCSingleBit(); - - } - - #endregion - /// public override byte? GetSpecialAddress() => SpecialAddress; diff --git a/MewtocolNet/Registers/BytesRegister.cs b/MewtocolNet/Registers/BytesRegister.cs deleted file mode 100644 index bacd0b0..0000000 --- a/MewtocolNet/Registers/BytesRegister.cs +++ /dev/null @@ -1,203 +0,0 @@ -using MewtocolNet.Exceptions; -using System; -using System.Collections; -using System.Collections.Generic; -using System.ComponentModel; -using System.Text; -using System.Threading; -using System.Threading.Tasks; - -namespace MewtocolNet.Registers { - - /// - /// Defines a register containing a string - /// - public class BytesRegister : BaseRegister { - - internal uint addressLength; - /// - /// The rgisters memory length - /// - public uint AddressLength => addressLength; - - internal uint ReservedBytesSize { get; set; } - - internal ushort? ReservedBitSize { get; set; } - - [Obsolete("Creating registers directly is not supported use IPlc.Register instead")] - public BytesRegister() => - throw new NotSupportedException("Direct register instancing is not supported, use the builder pattern"); - - internal BytesRegister(uint _address, uint _reservedByteSize, string _name = null) { - - name = _name; - memoryAddress = _address; - ReservedBytesSize = _reservedByteSize; - - //calc mem length - //because one register is always 1 word (2 bytes) long, if the bytecount is uneven we get the trailing word too - var byteSize = ReservedBytesSize; - if (ReservedBytesSize % 2 != 0) byteSize++; - - RegisterType = RegisterType.DT_BYTE_RANGE; - addressLength = Math.Max((byteSize / 2), 1); - - CheckAddressOverflow(memoryAddress, addressLength); - - lastValue = null; - - } - - public BytesRegister(uint _address, ushort _reservedBitSize, string _name = null) { - - name = _name; - memoryAddress = _address; - ReservedBytesSize = (uint)Math.Max(1, _reservedBitSize / 8); - ReservedBitSize = _reservedBitSize; - - //calc mem length - //because one register is always 1 word (2 bytes) long, if the bytecount is uneven we get the trailing word too - var byteSize = ReservedBytesSize; - if (ReservedBytesSize % 2 != 0) byteSize++; - - RegisterType = RegisterType.DT_BYTE_RANGE; - addressLength = Math.Max((byteSize / 2), 1); - - CheckAddressOverflow(memoryAddress, addressLength); - - lastValue = null; - - } - - public override string GetValueString() { - - if (Value == null) return "null"; - - if(Value != null && Value is BitArray bitArr) { - - return bitArr.ToBitString(); - - } else { - - return ((byte[])Value).ToHexString("-"); - - } - - } - - /// - public override string BuildMewtocolQuery() { - - StringBuilder asciistring = new StringBuilder("D"); - - asciistring.Append(MemoryAddress.ToString().PadLeft(5, '0')); - asciistring.Append((MemoryAddress + AddressLength - 1).ToString().PadLeft(5, '0')); - - return asciistring.ToString(); - } - - /// - public override void SetValueFromPLC (object val) { - - bool changeTriggerBitArr = val is BitArray bitArr && - lastValue is BitArray bitArr2 && - (bitArr.ToBitString() != bitArr2.ToBitString()); - - bool changeTriggerGeneral = (lastValue?.ToString() != val?.ToString()); - - if (changeTriggerBitArr || changeTriggerGeneral) { - - lastValue = val; - - TriggerNotifyChange(); - attachedInterface.InvokeRegisterChanged(this); - - } - - } - - /// - public override string GetRegisterString() => "DT"; - - /// - public override uint GetRegisterAddressLen() => AddressLength; - - /// - public override async Task ReadAsync() { - - if (!attachedInterface.IsConnected) - throw MewtocolException.NotConnectedSend(); - - var res = await underlyingMemory.ReadRegisterAsync(this); - if (!res) return null; - - var bytes = underlyingMemory.GetUnderlyingBytes(this); - - return SetValueFromBytes(bytes); - - } - - /// - public override async Task WriteAsync(object data) { - - if (!attachedInterface.IsConnected) - throw MewtocolException.NotConnectedSend(); - - byte[] encoded; - - if (ReservedBitSize != null) { - encoded = PlcValueParser.Encode(this, (BitArray)data); - } else { - encoded = PlcValueParser.Encode(this, (byte[])data); - } - - var res = await underlyingMemory.WriteRegisterAsync(this, encoded); - if (res) { - AddSuccessWrite(); - SetValueFromPLC(data); - } - - return res; - - } - - internal override object SetValueFromBytes(byte[] bytes) { - - AddSuccessRead(); - - object parsed; - if (ReservedBitSize != null) { - parsed = PlcValueParser.Parse(this, bytes); - } else { - parsed = PlcValueParser.Parse(this, bytes); - } - - SetValueFromPLC(parsed); - return parsed; - - } - - internal override async Task WriteToAnonymousAsync(object value) { - - if (!attachedInterface.IsConnected) - throw MewtocolException.NotConnectedSend(); - - return await attachedInterface.WriteByteRange((int)MemoryAddress, (byte[])value); - - } - - internal override async Task ReadFromAnonymousAsync() { - - if (!attachedInterface.IsConnected) - throw MewtocolException.NotConnectedSend(); - - var res = await attachedInterface.ReadByteRangeNonBlocking((int)MemoryAddress, (int)GetRegisterAddressLen() * 2, false); - if (res == null) return null; - - return res; - - } - - } - -} diff --git a/MewtocolNet/Registers/Interfaces/IRegisterInternal.cs b/MewtocolNet/Registers/Interfaces/IRegisterInternal.cs index 3b87415..911cf44 100644 --- a/MewtocolNet/Registers/Interfaces/IRegisterInternal.cs +++ b/MewtocolNet/Registers/Interfaces/IRegisterInternal.cs @@ -24,8 +24,6 @@ namespace MewtocolNet { // setters - void SetValueFromPLC(object value); - void ClearValue(); // Accessors diff --git a/MewtocolNet/Registers/NumberRegister.cs b/MewtocolNet/Registers/NumberRegister.cs index 8b9474c..924ce39 100644 --- a/MewtocolNet/Registers/NumberRegister.cs +++ b/MewtocolNet/Registers/NumberRegister.cs @@ -4,6 +4,7 @@ using System; using System.Collections; using System.Collections.Generic; using System.ComponentModel; +using System.Linq; using System.Runtime.InteropServices; using System.Text; using System.Threading.Tasks; @@ -62,21 +63,6 @@ namespace MewtocolNet.Registers { } - /// - public override void SetValueFromPLC(object val) { - - if (lastValue?.ToString() != val?.ToString()) { - - if (val != null) lastValue = (T)val; - else lastValue = null; - - TriggerNotifyChange(); - attachedInterface.InvokeRegisterChanged(this); - - } - - } - /// public override string BuildMewtocolQuery() { @@ -108,7 +94,13 @@ namespace MewtocolNet.Registers { return $"{Value} [{((TimeSpan)Value).ToPlcTime()}]"; - } + } + + if (Value != null && typeof(T) == typeof(Word)) { + + return $"{Value} [{((Word)Value).ToStringBitsPlc()}]"; + + } if (Value != null && typeof(T).IsEnum) { @@ -126,36 +118,43 @@ namespace MewtocolNet.Registers { /// public override uint GetRegisterAddressLen() => (uint)(RegisterType == RegisterType.DT ? 1 : 2); + /// + public override async Task WriteAsync (object value) { + + if (!attachedInterface.IsConnected) + throw MewtocolException.NotConnectedSend(); + + var encoded = PlcValueParser.Encode(this, (T)value); + var res = await attachedInterface.WriteByteRange((int)MemoryAddress, encoded); + + if(res) { + + //find the underlying memory + var matchingReg = attachedInterface.memoryManager.GetAllRegisters() + .FirstOrDefault(x => x.IsSameAddressAndType(this)); + + if (matchingReg != null) + matchingReg.underlyingMemory.SetUnderlyingBytes(matchingReg, encoded); + + AddSuccessWrite(); + UpdateHoldingValue(value); + + } + + return res; + + } + /// public override async Task ReadAsync() { if (!attachedInterface.IsConnected) throw MewtocolException.NotConnectedSend(); - var res = await underlyingMemory.ReadRegisterAsync(this); - if (!res) return null; + var res = await attachedInterface.ReadByteRangeNonBlocking((int)MemoryAddress, (int)GetRegisterAddressLen() * 2, false); + if (res == null) return null; - var bytes = underlyingMemory.GetUnderlyingBytes(this); - - return SetValueFromBytes(bytes); - - } - - /// - public override async Task WriteAsync(object data) { - - if (!attachedInterface.IsConnected) - throw MewtocolException.NotConnectedSend(); - - var encoded = PlcValueParser.Encode(this, (T)data); - var res = await underlyingMemory.WriteRegisterAsync(this, encoded); - - if (res) { - AddSuccessWrite(); - SetValueFromPLC(data); - } - - return res; + return SetValueFromBytes(res); } @@ -164,30 +163,22 @@ namespace MewtocolNet.Registers { AddSuccessRead(); var parsed = PlcValueParser.Parse(this, bytes); - SetValueFromPLC(parsed); + UpdateHoldingValue(parsed); return parsed; } - internal override async Task WriteToAnonymousAsync (object value) { + internal override void UpdateHoldingValue(object val) { - if (!attachedInterface.IsConnected) - throw MewtocolException.NotConnectedSend(); + if (lastValue?.ToString() != val?.ToString()) { - var encoded = PlcValueParser.Encode(this, (T)value); - return await attachedInterface.WriteByteRange((int)MemoryAddress, encoded); + if (val != null) lastValue = (T)val; + else lastValue = null; - } + TriggerNotifyChange(); + attachedInterface.InvokeRegisterChanged(this); - internal override async Task ReadFromAnonymousAsync () { - - if (!attachedInterface.IsConnected) - throw MewtocolException.NotConnectedSend(); - - var res = await attachedInterface.ReadByteRangeNonBlocking((int)MemoryAddress, (int)GetRegisterAddressLen() * 2, false); - if (res == null) return null; - - return PlcValueParser.Parse(this, res); + } } diff --git a/MewtocolNet/Registers/StringRegister.cs b/MewtocolNet/Registers/StringRegister.cs index 7dbee77..1531d0e 100644 --- a/MewtocolNet/Registers/StringRegister.cs +++ b/MewtocolNet/Registers/StringRegister.cs @@ -51,21 +51,7 @@ namespace MewtocolNet.Registers { } /// - public override string GetValueString() => $"'{Value}'"; - - /// - public override void SetValueFromPLC (object val) { - - if (val == null || !val.Equals(lastValue)) { - - lastValue = (string)val; - - TriggerNotifyChange(); - attachedInterface.InvokeRegisterChanged(this); - - } - - } + public override string GetValueString() => Value == null ? "null" : $"'{Value}'"; /// public override string GetRegisterString() => "DT"; @@ -97,76 +83,17 @@ namespace MewtocolNet.Registers { } /// - public override async Task ReadAsync() { + internal override void UpdateHoldingValue(object val) { - if (!attachedInterface.IsConnected) - throw MewtocolException.NotConnectedSend(); + if ((val == null && lastValue != null) || val != lastValue) { - if (!isCalibratedFromPlc) await CalibrateFromPLC(); + lastValue = val; - var res = await underlyingMemory.ReadRegisterAsync(this); - if (!res) return null; + TriggerNotifyChange(); + attachedInterface.InvokeRegisterChanged(this); - var bytes = underlyingMemory.GetUnderlyingBytes(this); - - return SetValueFromBytes(bytes); - - } - - /// - public override async Task WriteAsync(object data) { - - if (!attachedInterface.IsConnected) - throw MewtocolException.NotConnectedSend(); - - if (!isCalibratedFromPlc) await CalibrateFromPLC(); - - var encoded = PlcValueParser.Encode(this, (string)data); - var res = await underlyingMemory.WriteRegisterAsync(this, encoded); - - if (res) { - AddSuccessWrite(); - SetValueFromPLC(data); } - return res; - - } - - internal override object SetValueFromBytes(byte[] bytes) { - - AddSuccessRead(); - - var parsed = PlcValueParser.Parse(this, bytes); - SetValueFromPLC(parsed); - return parsed; - - } - - internal override async Task WriteToAnonymousAsync(object value) { - - if (!attachedInterface.IsConnected) - throw MewtocolException.NotConnectedSend(); - - if (!isCalibratedFromPlc) await CalibrateFromPLC(); - - var encoded = PlcValueParser.Encode(this, (string)value); - return await attachedInterface.WriteByteRange((int)MemoryAddress, encoded); - - } - - internal override async Task ReadFromAnonymousAsync() { - - if (!attachedInterface.IsConnected) - throw MewtocolException.NotConnectedSend(); - - if (!isCalibratedFromPlc) await CalibrateFromPLC(); - - var res = await attachedInterface.ReadByteRangeNonBlocking((int)MemoryAddress, (int)GetRegisterAddressLen() * 2); - if (res == null) return null; - - return PlcValueParser.Parse(this, res); - } } diff --git a/MewtocolNet/TypeConversion/Conversions.cs b/MewtocolNet/TypeConversion/Conversions.cs index bf35b52..1cc228a 100644 --- a/MewtocolNet/TypeConversion/Conversions.cs +++ b/MewtocolNet/TypeConversion/Conversions.cs @@ -72,12 +72,12 @@ namespace MewtocolNet.TypeConversion { ToRaw = (reg, value) => BitConverter.GetBytes(value), }, - //default ushort DT conversion - new PlcTypeConversion(RegisterType.DT) { - HoldingRegisterType = typeof(NumberRegister), + //default Word DT conversion + new PlcTypeConversion(RegisterType.DT) { + HoldingRegisterType = typeof(NumberRegister), PlcVarType = PlcVarType.WORD, - FromRaw = (reg, bytes) => BitConverter.ToUInt16(bytes, 0), - ToRaw = (reg, value) => BitConverter.GetBytes(value), + FromRaw = (reg, bytes) => new Word(bytes), + ToRaw = (reg, value) => value.ToByteArray(), }, //default int DDT conversion @@ -96,12 +96,12 @@ namespace MewtocolNet.TypeConversion { ToRaw = (reg, value) => BitConverter.GetBytes(value), }, - //default uint DDT conversion - new PlcTypeConversion(RegisterType.DDT) { - HoldingRegisterType = typeof(NumberRegister), + //default DWord DDT conversion + new PlcTypeConversion(RegisterType.DDT) { + HoldingRegisterType = typeof(NumberRegister), PlcVarType = PlcVarType.DWORD, - FromRaw = (reg, bytes) => BitConverter.ToUInt32(bytes, 0), - ToRaw = (reg, value) => BitConverter.GetBytes(value), + FromRaw = (reg, bytes) => new DWord(bytes), + ToRaw = (reg, value) => value.ToByteArray(), }, //default float DDT conversion @@ -134,7 +134,7 @@ namespace MewtocolNet.TypeConversion { //default byte array DT Range conversion, direct pass through new PlcTypeConversion(RegisterType.DT_BYTE_RANGE) { - HoldingRegisterType = typeof(BytesRegister), + HoldingRegisterType = typeof(ArrayRegister), FromRaw = (reg, bytes) => bytes, ToRaw = (reg, value) => value, }, @@ -182,37 +182,6 @@ namespace MewtocolNet.TypeConversion { }, }, - //default bit array <=> byte array conversion - new PlcTypeConversion(RegisterType.DT_BYTE_RANGE) { - HoldingRegisterType = typeof(BytesRegister), - FromRaw = (reg, bytes) => { - - var byteReg = (BytesRegister)reg; - - BitArray bitAr = new BitArray(bytes); - bitAr.Length = (int)byteReg.ReservedBitSize; - - return bitAr; - - }, - ToRaw = (reg, value) => { - - byte[] ret = new byte[(value.Length - 1) / 8 + 1]; - value.CopyTo(ret, 0); - - if(ret.Length % 2 != 0) { - - var lst = ret.ToList(); - lst.Add(0); - ret = lst.ToArray(); - - } - - return ret; - - }, - }, - }; } diff --git a/MewtocolNet/UnderlyingRegisters/DTArea.cs b/MewtocolNet/UnderlyingRegisters/DTArea.cs index e0a6005..adf4a0b 100644 --- a/MewtocolNet/UnderlyingRegisters/DTArea.cs +++ b/MewtocolNet/UnderlyingRegisters/DTArea.cs @@ -17,7 +17,9 @@ namespace MewtocolNet.UnderlyingRegisters { internal byte[] underlyingBytes = new byte[2]; - internal List linkedRegisters = new List(); + internal List linkedRegisters = new List(); + + internal Dictionary> crossRegisterBindings = new Dictionary>(); public ulong AddressStart => addressStart; public ulong AddressEnd => addressEnd; @@ -40,7 +42,7 @@ namespace MewtocolNet.UnderlyingRegisters { //copy old bytes to new array var offset = (int)(oldFrom - addFrom) * 2; - oldUnderlying.CopyTo(oldUnderlying, offset); + oldUnderlying.CopyTo(underlyingBytes, offset); addressStart = addFrom; addressEnd = addTo; @@ -61,18 +63,6 @@ namespace MewtocolNet.UnderlyingRegisters { } - public async Task ReadRegisterAsync (BaseRegister reg) { - - return await RequestByteReadAsync(reg.MemoryAddress, reg.MemoryAddress + reg.GetRegisterAddressLen() - 1); - - } - - public async Task WriteRegisterAsync (BaseRegister reg, byte[] bytes) { - - return await RequestByteWriteAsync(reg.MemoryAddress, bytes); - - } - internal async Task RequestByteReadAsync (ulong addStart, ulong addEnd) { await CheckDynamicallySizedRegistersAsync(); @@ -93,24 +83,6 @@ namespace MewtocolNet.UnderlyingRegisters { } - internal async Task RequestByteWriteAsync(ulong addStart, byte[] bytes) { - - var station = mewInterface.GetStationNumber(); - var addEnd = addStart + ((ulong)bytes.Length / 2) - 1; - - string requeststring = $"%{station}#WD{GetMewtocolIdent(addStart, addEnd)}{bytes.ToHexString()}"; - var result = await mewInterface.SendCommandAsync(requeststring); - - if (result.Success) { - - SetUnderlyingBytes(bytes, addStart); - - } - - return result.Success; - - } - public byte[] GetUnderlyingBytes(BaseRegister reg) { int byteLen = (int)(reg.GetRegisterAddressLen() * 2); diff --git a/MewtocolNet/UnderlyingRegisters/IMemoryArea.cs b/MewtocolNet/UnderlyingRegisters/IMemoryArea.cs index 9deb19b..5dc8161 100644 --- a/MewtocolNet/UnderlyingRegisters/IMemoryArea.cs +++ b/MewtocolNet/UnderlyingRegisters/IMemoryArea.cs @@ -7,9 +7,7 @@ namespace MewtocolNet.UnderlyingRegisters { byte[] GetUnderlyingBytes(BaseRegister reg); - Task ReadRegisterAsync(BaseRegister reg); - - Task WriteRegisterAsync(BaseRegister reg, byte[] bytes); + void SetUnderlyingBytes(BaseRegister reg, byte[] bytes); void UpdateAreaRegisterValues(); diff --git a/MewtocolNet/UnderlyingRegisters/MemoryAreaManager.cs b/MewtocolNet/UnderlyingRegisters/MemoryAreaManager.cs index 1216f34..ab7edcf 100644 --- a/MewtocolNet/UnderlyingRegisters/MemoryAreaManager.cs +++ b/MewtocolNet/UnderlyingRegisters/MemoryAreaManager.cs @@ -1,9 +1,12 @@ -using MewtocolNet.Registers; +using MewtocolNet.Helpers; +using MewtocolNet.Registers; using MewtocolNet.SetupClasses; using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; +using System.Reflection; +using System.Security.Cryptography; using System.Text; using System.Threading.Tasks; @@ -44,22 +47,69 @@ namespace MewtocolNet.UnderlyingRegisters { } - internal bool LinkRegister (BaseRegister reg) { + internal void LinkRegisters (List registers = null) { - TestPollLevelExistence(reg); + //for self calling + if (registers == null) registers = GetAllRegisters().ToList(); + + //pre combine + var groupedByAdd = registers + .GroupBy(x => new { + x.MemoryAddress, + len = x.GetRegisterAddressLen(), + spadd = x.GetSpecialAddress(), + }); + + var filteredRegisters = new List(); + var propertyLookupTable = new Dictionary(); + + foreach (var addressGroup in groupedByAdd) { + + var ordered = addressGroup.OrderBy(x => x.pollLevel); + var highestPollLevel = ordered.Max(x => x.pollLevel); + + var distinctByUnderlyingType = + ordered.GroupBy(x => x.underlyingSystemType).ToList(); + + foreach (var underlyingTypeGroup in distinctByUnderlyingType) { + + foreach (var register in underlyingTypeGroup) { + + register.pollLevel = highestPollLevel; + + var alreadyAdded = filteredRegisters + .FirstOrDefault(x => x.underlyingSystemType == register.underlyingSystemType); + + if(alreadyAdded == null) { + filteredRegisters.Add(register); + } else { + alreadyAdded.WithBoundProperties(register.boundProperties); + } + + } + + } - switch (reg.RegisterType) { - case RegisterType.X: - case RegisterType.Y: - case RegisterType.R: - return AddWRArea(reg); - case RegisterType.DT: - case RegisterType.DDT: - case RegisterType.DT_BYTE_RANGE: - return AddDTArea(reg); } - return false; + foreach (var reg in filteredRegisters) { + + TestPollLevelExistence(reg); + + switch (reg.RegisterType) { + case RegisterType.X: + case RegisterType.Y: + case RegisterType.R: + AddToWRArea(reg); + break; + case RegisterType.DT: + case RegisterType.DDT: + case RegisterType.DT_BYTE_RANGE: + AddToDTArea(reg); + break; + } + + } } @@ -88,7 +138,7 @@ namespace MewtocolNet.UnderlyingRegisters { } - private bool AddWRArea (BaseRegister insertReg) { + private bool AddToWRArea (BaseRegister insertReg) { var pollLevelFound = pollLevels.FirstOrDefault(x => x.level == insertReg.pollLevel); @@ -115,9 +165,6 @@ namespace MewtocolNet.UnderlyingRegisters { if(existingLinkedRegister != null) { - foreach (var prop in insertReg.boundToProps) - existingLinkedRegister.WithBoundProperty(prop); - return false; } else { @@ -147,7 +194,7 @@ namespace MewtocolNet.UnderlyingRegisters { } - private bool AddDTArea (BaseRegister insertReg) { + private void AddToDTArea (BaseRegister insertReg) { uint regInsAddStart = insertReg.MemoryAddress; uint regInsAddEnd = insertReg.MemoryAddress + insertReg.GetRegisterAddressLen() - 1; @@ -159,26 +206,13 @@ namespace MewtocolNet.UnderlyingRegisters { foreach (var dtArea in dataAreas) { - bool matchingAddress = regInsAddStart >= dtArea.AddressStart && - regInsAddEnd <= dtArea.addressEnd; + bool addressInsideArea = regInsAddStart >= dtArea.AddressStart && + regInsAddEnd <= dtArea.AddressEnd; - //found matching - if (matchingAddress) { - - //check if the area has registers linked that are overlapping (not matching) - var foundDupe = dtArea.linkedRegisters - .FirstOrDefault(x => x.CompareIsDuplicateNonCast(insertReg, allowByteRegDupes)); - - if (foundDupe != null) { - throw new NotSupportedException( - message: $"Can't have registers of different types at the same referenced plc address: " + - $"{insertReg.PLCAddressName} ({insertReg.GetType()}) <=> " + - $"{foundDupe.PLCAddressName} ({foundDupe.GetType()})" - ); - } + if (addressInsideArea) { + //found an area that is already existing where the register can fit into targetArea = dtArea; - break; } @@ -208,7 +242,6 @@ namespace MewtocolNet.UnderlyingRegisters { //expand the boundaries for the area to include the new adjacent area dtArea.BoundaryUdpdate(addrFrom: regInsAddStart); - targetArea = dtArea; break; @@ -218,6 +251,7 @@ namespace MewtocolNet.UnderlyingRegisters { } + //create a new area if (targetArea == null) { targetArea = new DTArea(mewInterface) { @@ -227,45 +261,27 @@ namespace MewtocolNet.UnderlyingRegisters { }; targetArea.BoundaryUdpdate(); - dataAreas.Add(targetArea); } insertReg.underlyingMemory = targetArea; - var existingLinkedRegister = targetArea.linkedRegisters - .FirstOrDefault(x => x.CompareIsDuplicate(insertReg)); - - if (existingLinkedRegister != null) { - - foreach (var prop in insertReg.boundToProps) - existingLinkedRegister.WithBoundProperty(prop); - - return false; - - } else { - - targetArea.linkedRegisters.Add(insertReg); - return true; - + if (insertReg.name == null) { + insertReg.name = $"auto_{Guid.NewGuid().ToString("N")}"; } - + + Console.WriteLine($"Adding linked register: {insertReg}"); + targetArea.linkedRegisters.Add(insertReg); + return; + } internal void MergeAndSizeDataAreas () { //merge gaps that the algorithm didn't catch be rerunning the register attachment - foreach (var pLevel in pollLevels) { - - var allDataAreaRegisters = pLevel.dataAreas.SelectMany(x => x.linkedRegisters).ToList(); - var dataAreas = new List(allDataAreaRegisters.Capacity); - - foreach (var reg in allDataAreaRegisters) - AddDTArea(reg); - - } + LinkRegisters(); } @@ -309,7 +325,7 @@ namespace MewtocolNet.UnderlyingRegisters { } //update registers in poll level - foreach (var dtArea in pollLevel.dataAreas) { + foreach (var dtArea in pollLevel.dataAreas.ToArray()) { //set the whole memory area at once await dtArea.RequestByteReadAsync(dtArea.AddressStart, dtArea.AddressEnd); @@ -346,7 +362,7 @@ namespace MewtocolNet.UnderlyingRegisters { sb.AppendLine($"Optimization distance: {maxOptimizationDistance}"); sb.AppendLine(); - sb.AppendLine($"---- DT Area ----"); + sb.AppendLine($"---- DT Areas: ----"); foreach (var area in pollLevel.dataAreas) { @@ -358,7 +374,7 @@ namespace MewtocolNet.UnderlyingRegisters { foreach (var reg in area.linkedRegisters) { - sb.AppendLine($"{reg.ToString(true)}"); + sb.AppendLine($"{reg.Explain()}"); } @@ -372,7 +388,7 @@ namespace MewtocolNet.UnderlyingRegisters { foreach (var reg in area.linkedRegisters) { - sb.AppendLine($"{reg.ToString(true)}"); + sb.AppendLine($"{reg.Explain()}"); } @@ -386,7 +402,7 @@ namespace MewtocolNet.UnderlyingRegisters { foreach (var reg in area.linkedRegisters) { - sb.AppendLine($"{reg.ToString(true)}"); + sb.AppendLine($"{reg.Explain()}"); } @@ -400,7 +416,7 @@ namespace MewtocolNet.UnderlyingRegisters { foreach (var reg in area.linkedRegisters) { - sb.AppendLine($"{reg.ToString(true)}"); + sb.AppendLine($"{reg.Explain()}"); } diff --git a/MewtocolNet/UnderlyingRegisters/WRArea.cs b/MewtocolNet/UnderlyingRegisters/WRArea.cs index c2f7a9b..409fc8d 100644 --- a/MewtocolNet/UnderlyingRegisters/WRArea.cs +++ b/MewtocolNet/UnderlyingRegisters/WRArea.cs @@ -29,6 +29,10 @@ namespace MewtocolNet.UnderlyingRegisters { + } + public void SetUnderlyingBytes(BaseRegister reg, byte[] bytes) { + + } public byte[] GetUnderlyingBytes(BaseRegister reg) {