mirror of
https://github.com/OpenLogics/MewtocolNet.git
synced 2025-12-06 03:01:24 +00:00
Add Dword / Word
This commit is contained in:
117
MewtocolNet/CustomTypes/DWord.cs
Normal file
117
MewtocolNet/CustomTypes/DWord.cs
Normal 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);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
7
MewtocolNet/CustomTypes/MewtocolExtensionType.cs
Normal file
7
MewtocolNet/CustomTypes/MewtocolExtensionType.cs
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
namespace MewtocolNet {
|
||||||
|
|
||||||
|
internal interface MewtocolExtensionTypeDT { }
|
||||||
|
|
||||||
|
internal interface MewtocolExtensionTypeDDT { }
|
||||||
|
|
||||||
|
}
|
||||||
117
MewtocolNet/CustomTypes/Word.cs
Normal file
117
MewtocolNet/CustomTypes/Word.cs
Normal 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);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
107
MewtocolNet/Registers/ArrayRegister.cs
Normal file
107
MewtocolNet/Registers/ArrayRegister.cs
Normal 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);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -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();
|
||||||
|
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|
||||||
|
|||||||
@@ -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;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -24,8 +24,6 @@ namespace MewtocolNet {
|
|||||||
|
|
||||||
// setters
|
// setters
|
||||||
|
|
||||||
void SetValueFromPLC(object value);
|
|
||||||
|
|
||||||
void ClearValue();
|
void ClearValue();
|
||||||
|
|
||||||
// Accessors
|
// Accessors
|
||||||
|
|||||||
@@ -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() {
|
||||||
|
|
||||||
@@ -108,7 +94,13 @@ namespace MewtocolNet.Registers {
|
|||||||
|
|
||||||
return $"{Value} [{((TimeSpan)Value).ToPlcTime()}]";
|
return $"{Value} [{((TimeSpan)Value).ToPlcTime()}]";
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (Value != null && typeof(T) == typeof(Word)) {
|
||||||
|
|
||||||
|
return $"{Value} [{((Word)Value).ToStringBitsPlc()}]";
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
if (Value != null && typeof(T).IsEnum) {
|
if (Value != null && typeof(T).IsEnum) {
|
||||||
|
|
||||||
@@ -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,30 +163,22 @@ 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);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
|
||||||
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,7 +17,9 @@ namespace MewtocolNet.UnderlyingRegisters {
|
|||||||
|
|
||||||
internal byte[] underlyingBytes = new byte[2];
|
internal byte[] underlyingBytes = new byte[2];
|
||||||
|
|
||||||
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);
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|
||||||
|
|||||||
@@ -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,22 +47,69 @@ namespace MewtocolNet.UnderlyingRegisters {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal bool LinkRegister (BaseRegister reg) {
|
internal void LinkRegisters (List<BaseRegister> 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<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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
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);
|
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()}");
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -29,6 +29,10 @@ namespace MewtocolNet.UnderlyingRegisters {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
public void SetUnderlyingBytes(BaseRegister reg, byte[] bytes) {
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte[] GetUnderlyingBytes(BaseRegister reg) {
|
public byte[] GetUnderlyingBytes(BaseRegister reg) {
|
||||||
|
|||||||
Reference in New Issue
Block a user