Add Dword / Word

This commit is contained in:
Felix Weiß
2023-07-14 00:33:42 +02:00
parent daecd73a6d
commit 32c20e7360
20 changed files with 609 additions and 592 deletions

View File

@@ -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 {
/// <summary>
/// A DWord is a 16 bit value of 2 bytes
/// </summary>
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;
/// <summary>
/// Gets or sets the bit value at the given position
/// </summary>
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);
}
}
}

View File

@@ -0,0 +1,7 @@
namespace MewtocolNet {
internal interface MewtocolExtensionTypeDT { }
internal interface MewtocolExtensionTypeDDT { }
}

View File

@@ -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 {
/// <summary>
/// A word is a 16 bit value of 2 bytes
/// </summary>
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;
/// <summary>
/// Gets or sets the bit value at the given position
/// </summary>
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);
}
}
}

View File

@@ -5,8 +5,10 @@ using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using System.Globalization; using System.Globalization;
using System.Linq; using System.Linq;
using System.Security.Cryptography;
using System.Text; using System.Text;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using static MewtocolNet.RegisterBuilding.RBuild;
namespace MewtocolNet { 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<Type> allowOverlappingTypes) {
if (ingnoreByteRegisters && (compare.GetType() == typeof(BytesRegister) || reg1.GetType() == typeof(BytesRegister))) return false; foreach (var type in allowOverlappingTypes) {
bool valCompare = reg1.GetType() != compare.GetType() && if (toInsert.GetType() == type) return false;
reg1.MemoryAddress == compare.MemoryAddress &&
reg1.GetRegisterAddressLen() == compare.GetRegisterAddressLen() && }
reg1.GetSpecialAddress() == compare.GetSpecialAddress();
bool valCompare = toInsert.GetType() != compare.GetType() &&
toInsert.MemoryAddress == compare.MemoryAddress &&
toInsert.GetRegisterAddressLen() == compare.GetRegisterAddressLen() &&
toInsert.GetSpecialAddress() == compare.GetSpecialAddress();
return valCompare; return valCompare;

View File

@@ -156,10 +156,11 @@ namespace MewtocolNet {
private void OnRegisterChanged(IRegister o) { private void OnRegisterChanged(IRegister o) {
var asInternal = (IRegisterInternal)o; var asInternal = (BaseRegister)o;
Logger.Log($"{asInternal.GetMewName()} " + Logger.Log($"{asInternal.GetMewName()} " +
$"{(o.Name != null ? $"({o.Name}) " : "")}" + $"{(o.Name != null ? $"({o.Name}) " : "")}" +
$"{asInternal.underlyingSystemType} " +
$"changed to \"{asInternal.GetValueString()}\"", LogLevel.Change, this); $"changed to \"{asInternal.GetValueString()}\"", LogLevel.Change, this);
OnRegisterChangedUpdateProps((IRegisterInternal)o); OnRegisterChangedUpdateProps((IRegisterInternal)o);

View File

@@ -290,20 +290,7 @@ namespace MewtocolNet {
internal void InsertRegistersToMemoryStack (List<BaseRegister> registers) { internal void InsertRegistersToMemoryStack (List<BaseRegister> registers) {
//order by address memoryManager.LinkRegisters(registers);
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++;
}
} }
@@ -408,7 +395,7 @@ namespace MewtocolNet {
} }
internal void InvokeRegisterChanged(IRegister reg) { internal void InvokeRegisterChanged(BaseRegister reg) {
RegisterChanged?.Invoke(reg); RegisterChanged?.Invoke(reg);

View File

@@ -362,13 +362,14 @@ namespace MewtocolNet.RegisterBuilding {
/// <item><term><see cref="bool"/></term><description>Boolean R/X/Y registers</description></item> /// <item><term><see cref="bool"/></term><description>Boolean R/X/Y registers</description></item>
/// <item><term><see cref="short"/></term><description>16 bit signed integer</description></item> /// <item><term><see cref="short"/></term><description>16 bit signed integer</description></item>
/// <item><term><see cref="ushort"/></term><description>16 bit un-signed integer</description></item> /// <item><term><see cref="ushort"/></term><description>16 bit un-signed integer</description></item>
/// <item><term><see cref="Word"/></term><description>16 bit word (2 bytes)</description></item>
/// <item><term><see cref="int"/></term><description>32 bit signed integer</description></item> /// <item><term><see cref="int"/></term><description>32 bit signed integer</description></item>
/// <item><term><see cref="uint"/></term><description>32 bit un-signed integer</description></item> /// <item><term><see cref="uint"/></term><description>32 bit un-signed integer</description></item>
/// <item><term><see cref="DWord"/></term><description>32 bit word (4 bytes)</description></item>
/// <item><term><see cref="float"/></term><description>32 bit floating point</description></item> /// <item><term><see cref="float"/></term><description>32 bit floating point</description></item>
/// <item><term><see cref="TimeSpan"/></term><description>32 bit time from <see cref="PlcVarType.TIME"/> interpreted as <see cref="TimeSpan"/></description></item> /// <item><term><see cref="TimeSpan"/></term><description>32 bit time from <see cref="PlcVarType.TIME"/> interpreted as <see cref="TimeSpan"/></description></item>
/// <item><term><see cref="Enum"/></term><description>16 or 32 bit enums</description></item> /// <item><term><see cref="Enum"/></term><description>16 or 32 bit enums, also supports flags</description></item>
/// <item><term><see cref="string"/></term><description>String of chars, the interface will automatically get the length</description></item> /// <item><term><see cref="string"/></term><description>String of chars, the interface will automatically get the length</description></item>
/// <item><term><see cref="BitArray"/></term><description>As an array of bits</description></item>
/// <item><term><see cref="byte[]"/></term><description>As an array of bytes</description></item> /// <item><term><see cref="byte[]"/></term><description>As an array of bytes</description></item>
/// </list> /// </list>
/// </summary> /// </summary>
@@ -611,7 +612,7 @@ namespace MewtocolNet.RegisterBuilding {
var assembler = new RegisterAssembler(attachedPLC); var assembler = new RegisterAssembler(attachedPLC);
var tempRegister = assembler.Assemble(reg.Data); 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 assembler = new RegisterAssembler(attachedPLC);
var tempRegister = assembler.Assemble(reg.Data); 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 assembler = new RegisterAssembler(attachedPLC);
var tempRegister = assembler.Assemble(reg.Data); 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 assembler = new RegisterAssembler(attachedPLC);
var tempRegister = assembler.Assemble(reg.Data); var tempRegister = assembler.Assemble(reg.Data);
return (T)await tempRegister.ReadFromAnonymousAsync(); return (T)await tempRegister.ReadAsync();
} }

View File

@@ -3,6 +3,7 @@ using MewtocolNet.RegisterAttributes;
using MewtocolNet.Registers; using MewtocolNet.Registers;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Data;
using System.Reflection; using System.Reflection;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using static MewtocolNet.RegisterBuilding.RBuild; using static MewtocolNet.RegisterBuilding.RBuild;
@@ -49,9 +50,9 @@ namespace MewtocolNet.RegisterBuilding {
//as numeric register with enum target //as numeric register with enum target
var underlying = Enum.GetUnderlyingType(data.dotnetVarType); 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"); throw new NotSupportedException("Enums not based on 16 or 32 bit numbers are not supported");
var flags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance; var flags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance;
@@ -61,6 +62,8 @@ namespace MewtocolNet.RegisterBuilding {
var parameters = new object[] { data.memAddress, data.name }; var parameters = new object[] { data.memAddress, data.name };
var instance = (BaseRegister)constr.Invoke(parameters); var instance = (BaseRegister)constr.Invoke(parameters);
instance.RegisterType = numericSize > 2 ? RegisterType.DDT : RegisterType.DT;
generatedInstance = instance; generatedInstance = instance;
} else if (registerClassType.IsGenericType) { } else if (registerClassType.IsGenericType) {
@@ -74,23 +77,31 @@ namespace MewtocolNet.RegisterBuilding {
//int _adress, Type _enumType = null, string _name = null //int _adress, Type _enumType = null, string _name = null
var parameters = new object[] { data.memAddress, data.name }; var parameters = new object[] { data.memAddress, data.name };
var instance = (BaseRegister)Activator.CreateInstance(registerClassType, flags, null, parameters, null); 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; generatedInstance = instance;
} else if (registerClassType == typeof(BytesRegister) && data.byteSize != null) { } else if (registerClassType == typeof(ArrayRegister) && data.byteSize != null) {
//------------------------------------------- //-------------------------------------------
//as byte range register //as byte range register
BytesRegister instance = new BytesRegister(data.memAddress, (uint)data.byteSize, data.name); ArrayRegister instance = new ArrayRegister(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);
generatedInstance = instance; generatedInstance = instance;
} else if (registerClassType == typeof(StringRegister)) { } else if (registerClassType == typeof(StringRegister)) {
@@ -125,8 +136,13 @@ namespace MewtocolNet.RegisterBuilding {
if (collectionTarget != null) if (collectionTarget != null)
generatedInstance.WithRegisterCollection(collectionTarget); 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; generatedInstance.pollLevel = data.pollLevel;
return generatedInstance; return generatedInstance;

View File

@@ -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 {
/// <summary>
/// Defines a register containing a string
/// </summary>
public class ArrayRegister : BaseRegister {
internal uint addressLength;
/// <summary>
/// The rgisters memory length
/// </summary>
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("-");
}
}
/// <inheritdoc/>
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();
}
/// <inheritdoc/>
public override string GetRegisterString() => "DT";
/// <inheritdoc/>
public override uint GetRegisterAddressLen() => AddressLength;
/// <inheritdoc/>
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);
}
}
}
}

View File

@@ -19,8 +19,10 @@ namespace MewtocolNet.Registers {
//links to //links to
internal RegisterCollection containedCollection; internal RegisterCollection containedCollection;
internal MewtocolInterface attachedInterface; internal MewtocolInterface attachedInterface;
internal List<RegisterPropTarget> boundToProps = new List<RegisterPropTarget>();
internal List<RegisterPropTarget> boundProperties = new List<RegisterPropTarget>();
internal Type underlyingSystemType;
internal IMemoryArea underlyingMemory; internal IMemoryArea underlyingMemory;
internal object lastValue = null; internal object lastValue = null;
internal string name; internal string name;
@@ -40,7 +42,7 @@ namespace MewtocolNet.Registers {
public object Value => lastValue; public object Value => lastValue;
/// <inheritdoc/> /// <inheritdoc/>
public RegisterType RegisterType { get; protected set; } public RegisterType RegisterType { get; internal set; }
/// <inheritdoc/> /// <inheritdoc/>
public string Name => name; public string Name => name;
@@ -59,9 +61,9 @@ namespace MewtocolNet.Registers {
#endregion #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()) { if(lastValue?.ToString() != val?.ToString()) {
@@ -78,7 +80,14 @@ namespace MewtocolNet.Registers {
internal void WithRegisterCollection (RegisterCollection collection) => containedCollection = collection; 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<RegisterPropTarget> propInfos) {
foreach (var item in propInfos)
boundProperties.Add(item);
}
#region Read / Write #region Read / Write
@@ -86,10 +95,6 @@ namespace MewtocolNet.Registers {
public virtual Task<bool> WriteAsync(object data) => throw new NotImplementedException(); public virtual Task<bool> WriteAsync(object data) => throw new NotImplementedException();
internal virtual Task<bool> WriteToAnonymousAsync (object value) => throw new NotImplementedException();
internal virtual Task<object> ReadFromAnonymousAsync () => throw new NotImplementedException();
#endregion #endregion
#region Default accessors #region Default accessors
@@ -147,18 +152,36 @@ namespace MewtocolNet.Registers {
else successfulWrites++; 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() { public override string ToString() {
var sb = new StringBuilder(); var sb = new StringBuilder();
sb.Append(GetMewName()); sb.Append(GetMewName());
if(Name != null) sb.Append($" ({Name})"); if(Name != null) sb.Append($" ({Name})");
sb.Append($" [{this.GetType().Name}({underlyingSystemType.Name})]");
if (Value != null) sb.Append($" Val: {GetValueString()}"); if (Value != null) sb.Append($" Val: {GetValueString()}");
return sb.ToString(); return sb.ToString();
} }
public virtual string ToString(bool additional) { public virtual string ToString (bool additional) {
if (!additional) return this.ToString(); if (!additional) return this.ToString();
@@ -166,16 +189,30 @@ namespace MewtocolNet.Registers {
sb.AppendLine($"MewName: {GetMewName()}"); sb.AppendLine($"MewName: {GetMewName()}");
sb.AppendLine($"Name: {Name ?? "Not named"}"); sb.AppendLine($"Name: {Name ?? "Not named"}");
sb.AppendLine($"Value: {GetValueString()}"); sb.AppendLine($"Value: {GetValueString()}");
sb.AppendLine($"Perf. Reads: {successfulReads}, Writes: {successfulWrites}");
sb.AppendLine($"Register Type: {RegisterType}"); sb.AppendLine($"Register Type: {RegisterType}");
sb.AppendLine($"Address: {GetRegisterWordRangeString()}"); 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 (GetSpecialAddress() != null) sb.AppendLine($"SPAddress: {GetSpecialAddress():X1}");
if (GetType().IsGenericType) sb.AppendLine($"Type: NumberRegister<{GetType().GenericTypeArguments[0]}>"); if (GetType().IsGenericType) sb.AppendLine($"Type: NumberRegister<{GetType().GenericTypeArguments[0]}>");
else sb.AppendLine($"Type: {GetType()}"); else sb.AppendLine($"Type: {GetType()}");
if(containedCollection != null) sb.AppendLine($"In collection: {containedCollection.GetType()}"); if (containedCollection != null) sb.AppendLine($"In collection: {containedCollection.GetType()}");
if(boundToProps != null && boundToProps.Count != 0) if (boundProperties != null && boundProperties.Count > 0) sb.AppendLine($"Bound props: {string.Join(", ", boundProperties)}");
sb.AppendLine($"Bound props: {string.Join(",", boundToProps)}"); else sb.AppendLine("No bound properties");
return sb.ToString(); return sb.ToString();

View File

@@ -54,57 +54,6 @@ namespace MewtocolNet.Registers {
} }
#region Read / Write
/// <inheritdoc/>
public override async Task<object> ReadAsync() {
if (!attachedInterface.IsConnected)
throw MewtocolException.NotConnectedSend();
return null;
}
/// <inheritdoc/>
public override async Task<bool> WriteAsync(object data) {
if (!attachedInterface.IsConnected)
throw MewtocolException.NotConnectedSend();
return false;
}
internal override async Task<bool> 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<object> 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
/// <inheritdoc/> /// <inheritdoc/>
public override byte? GetSpecialAddress() => SpecialAddress; public override byte? GetSpecialAddress() => SpecialAddress;

View File

@@ -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 {
/// <summary>
/// Defines a register containing a string
/// </summary>
public class BytesRegister : BaseRegister {
internal uint addressLength;
/// <summary>
/// The rgisters memory length
/// </summary>
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("-");
}
}
/// <inheritdoc/>
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();
}
/// <inheritdoc/>
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);
}
}
/// <inheritdoc/>
public override string GetRegisterString() => "DT";
/// <inheritdoc/>
public override uint GetRegisterAddressLen() => AddressLength;
/// <inheritdoc/>
public override async Task<object> 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);
}
/// <inheritdoc/>
public override async Task<bool> 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<BitArray>(this, bytes);
} else {
parsed = PlcValueParser.Parse<byte[]>(this, bytes);
}
SetValueFromPLC(parsed);
return parsed;
}
internal override async Task<bool> WriteToAnonymousAsync(object value) {
if (!attachedInterface.IsConnected)
throw MewtocolException.NotConnectedSend();
return await attachedInterface.WriteByteRange((int)MemoryAddress, (byte[])value);
}
internal override async Task<object> 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;
}
}
}

View File

@@ -24,8 +24,6 @@ namespace MewtocolNet {
// setters // setters
void SetValueFromPLC(object value);
void ClearValue(); void ClearValue();
// Accessors // Accessors

View File

@@ -4,6 +4,7 @@ using System;
using System.Collections; using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using System.ComponentModel; using System.ComponentModel;
using System.Linq;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
@@ -62,21 +63,6 @@ namespace MewtocolNet.Registers {
} }
/// <inheritdoc/>
public override void SetValueFromPLC(object val) {
if (lastValue?.ToString() != val?.ToString()) {
if (val != null) lastValue = (T)val;
else lastValue = null;
TriggerNotifyChange();
attachedInterface.InvokeRegisterChanged(this);
}
}
/// <inheritdoc/> /// <inheritdoc/>
public override string BuildMewtocolQuery() { public override string BuildMewtocolQuery() {
@@ -110,6 +96,12 @@ namespace MewtocolNet.Registers {
} }
if (Value != null && typeof(T) == typeof(Word)) {
return $"{Value} [{((Word)Value).ToStringBitsPlc()}]";
}
if (Value != null && typeof(T).IsEnum) { if (Value != null && typeof(T).IsEnum) {
var underlying = Enum.GetUnderlyingType(typeof(T)); var underlying = Enum.GetUnderlyingType(typeof(T));
@@ -126,36 +118,43 @@ namespace MewtocolNet.Registers {
/// <inheritdoc/> /// <inheritdoc/>
public override uint GetRegisterAddressLen() => (uint)(RegisterType == RegisterType.DT ? 1 : 2); public override uint GetRegisterAddressLen() => (uint)(RegisterType == RegisterType.DT ? 1 : 2);
/// <inheritdoc/>
public override async Task<bool> 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;
}
/// <inheritdoc/> /// <inheritdoc/>
public override async Task<object> ReadAsync() { public override async Task<object> ReadAsync() {
if (!attachedInterface.IsConnected) if (!attachedInterface.IsConnected)
throw MewtocolException.NotConnectedSend(); throw MewtocolException.NotConnectedSend();
var res = await underlyingMemory.ReadRegisterAsync(this); var res = await attachedInterface.ReadByteRangeNonBlocking((int)MemoryAddress, (int)GetRegisterAddressLen() * 2, false);
if (!res) return null; if (res == null) return null;
var bytes = underlyingMemory.GetUnderlyingBytes(this); return SetValueFromBytes(res);
return SetValueFromBytes(bytes);
}
/// <inheritdoc/>
public override async Task<bool> 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;
} }
@@ -164,31 +163,23 @@ namespace MewtocolNet.Registers {
AddSuccessRead(); AddSuccessRead();
var parsed = PlcValueParser.Parse<T>(this, bytes); var parsed = PlcValueParser.Parse<T>(this, bytes);
SetValueFromPLC(parsed); UpdateHoldingValue(parsed);
return parsed; return parsed;
} }
internal override async Task<bool> WriteToAnonymousAsync (object value) { internal override void UpdateHoldingValue(object val) {
if (!attachedInterface.IsConnected) if (lastValue?.ToString() != val?.ToString()) {
throw MewtocolException.NotConnectedSend();
var encoded = PlcValueParser.Encode(this, (T)value); if (val != null) lastValue = (T)val;
return await attachedInterface.WriteByteRange((int)MemoryAddress, encoded); else lastValue = null;
TriggerNotifyChange();
attachedInterface.InvokeRegisterChanged(this);
} }
internal override async Task<object> 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<T>(this, res);
} }
} }

View File

@@ -51,21 +51,7 @@ namespace MewtocolNet.Registers {
} }
/// <inheritdoc/> /// <inheritdoc/>
public override string GetValueString() => $"'{Value}'"; public override string GetValueString() => Value == null ? "null" : $"'{Value}'";
/// <inheritdoc/>
public override void SetValueFromPLC (object val) {
if (val == null || !val.Equals(lastValue)) {
lastValue = (string)val;
TriggerNotifyChange();
attachedInterface.InvokeRegisterChanged(this);
}
}
/// <inheritdoc/> /// <inheritdoc/>
public override string GetRegisterString() => "DT"; public override string GetRegisterString() => "DT";
@@ -97,76 +83,17 @@ namespace MewtocolNet.Registers {
} }
/// <inheritdoc/> /// <inheritdoc/>
public override async Task<object> ReadAsync() { internal override void UpdateHoldingValue(object val) {
if (!attachedInterface.IsConnected) if ((val == null && lastValue != null) || val != lastValue) {
throw MewtocolException.NotConnectedSend();
if (!isCalibratedFromPlc) await CalibrateFromPLC(); lastValue = val;
var res = await underlyingMemory.ReadRegisterAsync(this); TriggerNotifyChange();
if (!res) return null; attachedInterface.InvokeRegisterChanged(this);
var bytes = underlyingMemory.GetUnderlyingBytes(this);
return SetValueFromBytes(bytes);
} }
/// <inheritdoc/>
public override async Task<bool> 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<string>(this, bytes);
SetValueFromPLC(parsed);
return parsed;
}
internal override async Task<bool> 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<object> 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<string>(this, res);
} }
} }

View File

@@ -72,12 +72,12 @@ namespace MewtocolNet.TypeConversion {
ToRaw = (reg, value) => BitConverter.GetBytes(value), ToRaw = (reg, value) => BitConverter.GetBytes(value),
}, },
//default ushort DT conversion //default Word DT conversion
new PlcTypeConversion<ushort>(RegisterType.DT) { new PlcTypeConversion<Word>(RegisterType.DT) {
HoldingRegisterType = typeof(NumberRegister<ushort>), HoldingRegisterType = typeof(NumberRegister<Word>),
PlcVarType = PlcVarType.WORD, PlcVarType = PlcVarType.WORD,
FromRaw = (reg, bytes) => BitConverter.ToUInt16(bytes, 0), FromRaw = (reg, bytes) => new Word(bytes),
ToRaw = (reg, value) => BitConverter.GetBytes(value), ToRaw = (reg, value) => value.ToByteArray(),
}, },
//default int DDT conversion //default int DDT conversion
@@ -96,12 +96,12 @@ namespace MewtocolNet.TypeConversion {
ToRaw = (reg, value) => BitConverter.GetBytes(value), ToRaw = (reg, value) => BitConverter.GetBytes(value),
}, },
//default uint DDT conversion //default DWord DDT conversion
new PlcTypeConversion<uint>(RegisterType.DDT) { new PlcTypeConversion<DWord>(RegisterType.DDT) {
HoldingRegisterType = typeof(NumberRegister<uint>), HoldingRegisterType = typeof(NumberRegister<DWord>),
PlcVarType = PlcVarType.DWORD, PlcVarType = PlcVarType.DWORD,
FromRaw = (reg, bytes) => BitConverter.ToUInt32(bytes, 0), FromRaw = (reg, bytes) => new DWord(bytes),
ToRaw = (reg, value) => BitConverter.GetBytes(value), ToRaw = (reg, value) => value.ToByteArray(),
}, },
//default float DDT conversion //default float DDT conversion
@@ -134,7 +134,7 @@ namespace MewtocolNet.TypeConversion {
//default byte array DT Range conversion, direct pass through //default byte array DT Range conversion, direct pass through
new PlcTypeConversion<byte[]>(RegisterType.DT_BYTE_RANGE) { new PlcTypeConversion<byte[]>(RegisterType.DT_BYTE_RANGE) {
HoldingRegisterType = typeof(BytesRegister), HoldingRegisterType = typeof(ArrayRegister),
FromRaw = (reg, bytes) => bytes, FromRaw = (reg, bytes) => bytes,
ToRaw = (reg, value) => value, ToRaw = (reg, value) => value,
}, },
@@ -182,37 +182,6 @@ namespace MewtocolNet.TypeConversion {
}, },
}, },
//default bit array <=> byte array conversion
new PlcTypeConversion<BitArray>(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;
},
},
}; };
} }

View File

@@ -19,6 +19,8 @@ namespace MewtocolNet.UnderlyingRegisters {
internal List<BaseRegister> linkedRegisters = new List<BaseRegister>(); internal List<BaseRegister> linkedRegisters = new List<BaseRegister>();
internal Dictionary<BaseRegister, List<BaseRegister>> crossRegisterBindings = new Dictionary<BaseRegister, List<BaseRegister>>();
public ulong AddressStart => addressStart; public ulong AddressStart => addressStart;
public ulong AddressEnd => addressEnd; public ulong AddressEnd => addressEnd;
@@ -40,7 +42,7 @@ namespace MewtocolNet.UnderlyingRegisters {
//copy old bytes to new array //copy old bytes to new array
var offset = (int)(oldFrom - addFrom) * 2; var offset = (int)(oldFrom - addFrom) * 2;
oldUnderlying.CopyTo(oldUnderlying, offset); oldUnderlying.CopyTo(underlyingBytes, offset);
addressStart = addFrom; addressStart = addFrom;
addressEnd = addTo; addressEnd = addTo;
@@ -61,18 +63,6 @@ namespace MewtocolNet.UnderlyingRegisters {
} }
public async Task<bool> ReadRegisterAsync (BaseRegister reg) {
return await RequestByteReadAsync(reg.MemoryAddress, reg.MemoryAddress + reg.GetRegisterAddressLen() - 1);
}
public async Task<bool> WriteRegisterAsync (BaseRegister reg, byte[] bytes) {
return await RequestByteWriteAsync(reg.MemoryAddress, bytes);
}
internal async Task<bool> RequestByteReadAsync (ulong addStart, ulong addEnd) { internal async Task<bool> RequestByteReadAsync (ulong addStart, ulong addEnd) {
await CheckDynamicallySizedRegistersAsync(); await CheckDynamicallySizedRegistersAsync();
@@ -93,24 +83,6 @@ namespace MewtocolNet.UnderlyingRegisters {
} }
internal async Task<bool> 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) { public byte[] GetUnderlyingBytes(BaseRegister reg) {
int byteLen = (int)(reg.GetRegisterAddressLen() * 2); int byteLen = (int)(reg.GetRegisterAddressLen() * 2);

View File

@@ -7,9 +7,7 @@ namespace MewtocolNet.UnderlyingRegisters {
byte[] GetUnderlyingBytes(BaseRegister reg); byte[] GetUnderlyingBytes(BaseRegister reg);
Task<bool> ReadRegisterAsync(BaseRegister reg); void SetUnderlyingBytes(BaseRegister reg, byte[] bytes);
Task<bool> WriteRegisterAsync(BaseRegister reg, byte[] bytes);
void UpdateAreaRegisterValues(); void UpdateAreaRegisterValues();

View File

@@ -1,9 +1,12 @@
using MewtocolNet.Registers; using MewtocolNet.Helpers;
using MewtocolNet.Registers;
using MewtocolNet.SetupClasses; using MewtocolNet.SetupClasses;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.Linq; using System.Linq;
using System.Reflection;
using System.Security.Cryptography;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
@@ -44,7 +47,52 @@ namespace MewtocolNet.UnderlyingRegisters {
} }
internal bool LinkRegister (BaseRegister reg) { internal void LinkRegisters (List<BaseRegister> registers = null) {
//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<BaseRegister>();
var propertyLookupTable = new Dictionary<PropertyInfo, BaseRegister>();
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);
}
}
}
}
foreach (var reg in filteredRegisters) {
TestPollLevelExistence(reg); TestPollLevelExistence(reg);
@@ -52,14 +100,16 @@ namespace MewtocolNet.UnderlyingRegisters {
case RegisterType.X: case RegisterType.X:
case RegisterType.Y: case RegisterType.Y:
case RegisterType.R: case RegisterType.R:
return AddWRArea(reg); AddToWRArea(reg);
break;
case RegisterType.DT: case RegisterType.DT:
case RegisterType.DDT: case RegisterType.DDT:
case RegisterType.DT_BYTE_RANGE: case RegisterType.DT_BYTE_RANGE:
return AddDTArea(reg); AddToDTArea(reg);
break;
} }
return false; }
} }
@@ -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); var pollLevelFound = pollLevels.FirstOrDefault(x => x.level == insertReg.pollLevel);
@@ -115,9 +165,6 @@ namespace MewtocolNet.UnderlyingRegisters {
if(existingLinkedRegister != null) { if(existingLinkedRegister != null) {
foreach (var prop in insertReg.boundToProps)
existingLinkedRegister.WithBoundProperty(prop);
return false; return false;
} else { } else {
@@ -147,7 +194,7 @@ namespace MewtocolNet.UnderlyingRegisters {
} }
private bool AddDTArea (BaseRegister insertReg) { private void AddToDTArea (BaseRegister insertReg) {
uint regInsAddStart = insertReg.MemoryAddress; uint regInsAddStart = insertReg.MemoryAddress;
uint regInsAddEnd = insertReg.MemoryAddress + insertReg.GetRegisterAddressLen() - 1; uint regInsAddEnd = insertReg.MemoryAddress + insertReg.GetRegisterAddressLen() - 1;
@@ -159,26 +206,13 @@ namespace MewtocolNet.UnderlyingRegisters {
foreach (var dtArea in dataAreas) { foreach (var dtArea in dataAreas) {
bool matchingAddress = regInsAddStart >= dtArea.AddressStart && bool addressInsideArea = regInsAddStart >= dtArea.AddressStart &&
regInsAddEnd <= dtArea.addressEnd; regInsAddEnd <= dtArea.AddressEnd;
//found matching if (addressInsideArea) {
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()})"
);
}
//found an area that is already existing where the register can fit into
targetArea = dtArea; targetArea = dtArea;
break; break;
} }
@@ -208,7 +242,6 @@ namespace MewtocolNet.UnderlyingRegisters {
//expand the boundaries for the area to include the new adjacent area //expand the boundaries for the area to include the new adjacent area
dtArea.BoundaryUdpdate(addrFrom: regInsAddStart); dtArea.BoundaryUdpdate(addrFrom: regInsAddStart);
targetArea = dtArea; targetArea = dtArea;
break; break;
@@ -218,6 +251,7 @@ namespace MewtocolNet.UnderlyingRegisters {
} }
//create a new area
if (targetArea == null) { if (targetArea == null) {
targetArea = new DTArea(mewInterface) { targetArea = new DTArea(mewInterface) {
@@ -227,45 +261,27 @@ namespace MewtocolNet.UnderlyingRegisters {
}; };
targetArea.BoundaryUdpdate(); targetArea.BoundaryUdpdate();
dataAreas.Add(targetArea); dataAreas.Add(targetArea);
} }
insertReg.underlyingMemory = targetArea; insertReg.underlyingMemory = targetArea;
var existingLinkedRegister = targetArea.linkedRegisters if (insertReg.name == null) {
.FirstOrDefault(x => x.CompareIsDuplicate(insertReg)); insertReg.name = $"auto_{Guid.NewGuid().ToString("N")}";
if (existingLinkedRegister != null) {
foreach (var prop in insertReg.boundToProps)
existingLinkedRegister.WithBoundProperty(prop);
return false;
} else {
targetArea.linkedRegisters.Add(insertReg);
return true;
} }
Console.WriteLine($"Adding linked register: {insertReg}");
targetArea.linkedRegisters.Add(insertReg);
return;
} }
internal void MergeAndSizeDataAreas () { internal void MergeAndSizeDataAreas () {
//merge gaps that the algorithm didn't catch be rerunning the register attachment //merge gaps that the algorithm didn't catch be rerunning the register attachment
foreach (var pLevel in pollLevels) { LinkRegisters();
var allDataAreaRegisters = pLevel.dataAreas.SelectMany(x => x.linkedRegisters).ToList();
var dataAreas = new List<DTArea>(allDataAreaRegisters.Capacity);
foreach (var reg in allDataAreaRegisters)
AddDTArea(reg);
}
} }
@@ -309,7 +325,7 @@ namespace MewtocolNet.UnderlyingRegisters {
} }
//update registers in poll level //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 //set the whole memory area at once
await dtArea.RequestByteReadAsync(dtArea.AddressStart, dtArea.AddressEnd); await dtArea.RequestByteReadAsync(dtArea.AddressStart, dtArea.AddressEnd);
@@ -346,7 +362,7 @@ namespace MewtocolNet.UnderlyingRegisters {
sb.AppendLine($"Optimization distance: {maxOptimizationDistance}"); sb.AppendLine($"Optimization distance: {maxOptimizationDistance}");
sb.AppendLine(); sb.AppendLine();
sb.AppendLine($"---- DT Area ----"); sb.AppendLine($"---- DT Areas: ----");
foreach (var area in pollLevel.dataAreas) { foreach (var area in pollLevel.dataAreas) {
@@ -358,7 +374,7 @@ namespace MewtocolNet.UnderlyingRegisters {
foreach (var reg in area.linkedRegisters) { 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) { 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) { 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) { foreach (var reg in area.linkedRegisters) {
sb.AppendLine($"{reg.ToString(true)}"); sb.AppendLine($"{reg.Explain()}");
} }

View File

@@ -29,6 +29,10 @@ namespace MewtocolNet.UnderlyingRegisters {
}
public void SetUnderlyingBytes(BaseRegister reg, byte[] bytes) {
} }
public byte[] GetUnderlyingBytes(BaseRegister reg) { public byte[] GetUnderlyingBytes(BaseRegister reg) {