mirror of
https://github.com/OpenLogics/MewtocolNet.git
synced 2025-12-06 03:01:24 +00:00
Array support first addition
This commit is contained in:
@@ -2,7 +2,7 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
||||||
namespace MewtocolNet.DocAttributes {
|
namespace MewtocolNet.Documentation {
|
||||||
|
|
||||||
[AttributeUsage(AttributeTargets.Field, AllowMultiple = false, Inherited = false)]
|
[AttributeUsage(AttributeTargets.Field, AllowMultiple = false, Inherited = false)]
|
||||||
internal class PlcCodeTestedAttribute : Attribute {
|
internal class PlcCodeTestedAttribute : Attribute {
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
||||||
namespace MewtocolNet.DocAttributes {
|
namespace MewtocolNet.Documentation {
|
||||||
|
|
||||||
[AttributeUsage(AttributeTargets.Field, AllowMultiple = false, Inherited = false)]
|
[AttributeUsage(AttributeTargets.Field, AllowMultiple = false, Inherited = false)]
|
||||||
internal class PlcEXRTAttribute : Attribute {
|
internal class PlcEXRTAttribute : Attribute {
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
||||||
namespace MewtocolNet.DocAttributes {
|
namespace MewtocolNet.Documentation {
|
||||||
|
|
||||||
[AttributeUsage(AttributeTargets.Field, AllowMultiple = false, Inherited = false)]
|
[AttributeUsage(AttributeTargets.Field, AllowMultiple = false, Inherited = false)]
|
||||||
internal class PlcLegacyAttribute : Attribute {
|
internal class PlcLegacyAttribute : Attribute {
|
||||||
75
MewtocolNet/Documentation/docs.xml
Normal file
75
MewtocolNet/Documentation/docs.xml
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8" ?>
|
||||||
|
<extradoc>
|
||||||
|
<class name="support-conv-types">
|
||||||
|
<list type="bullet">
|
||||||
|
<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="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="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="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, also supports flags</description>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<term>
|
||||||
|
<see cref="string"/>
|
||||||
|
</term>
|
||||||
|
<description>String of chars, the interface will automatically get the length</description>
|
||||||
|
</item>
|
||||||
|
</list>
|
||||||
|
</class>
|
||||||
|
</extradoc>
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
using MewtocolNet.DocAttributes;
|
using MewtocolNet.Documentation;
|
||||||
using MewtocolNet.Registers;
|
using MewtocolNet.Registers;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections;
|
using System.Collections;
|
||||||
|
|||||||
@@ -125,7 +125,7 @@ namespace MewtocolNet {
|
|||||||
/// </example>
|
/// </example>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
||||||
public int MaxOptimizationDistance { get; set; } = 8;
|
public int MaxOptimizationDistance { get; set; } = 4;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The max number of registers per request group
|
/// The max number of registers per request group
|
||||||
|
|||||||
@@ -158,10 +158,15 @@ namespace MewtocolNet {
|
|||||||
|
|
||||||
var asInternal = (BaseRegister)o;
|
var asInternal = (BaseRegister)o;
|
||||||
|
|
||||||
Logger.Log($"{asInternal.GetMewName()} " +
|
var sb = new StringBuilder();
|
||||||
$"{(o.Name != null ? $"({o.Name}) " : "")}" +
|
sb.Append(asInternal.GetMewName());
|
||||||
$"{asInternal.underlyingSystemType} " +
|
if(asInternal.Name != null) {
|
||||||
$"changed to \"{asInternal.GetValueString()}\"", LogLevel.Change, this);
|
sb.Append(asInternal.autoGenerated ? $" (Auto)" : $" ({o.Name})");
|
||||||
|
}
|
||||||
|
sb.Append($" {asInternal.underlyingSystemType.Name}");
|
||||||
|
sb.Append($" changed to \"{asInternal.GetValueString()}\"");
|
||||||
|
|
||||||
|
Logger.Log(sb.ToString(), LogLevel.Change, this);
|
||||||
|
|
||||||
OnRegisterChangedUpdateProps((IRegisterInternal)o);
|
OnRegisterChangedUpdateProps((IRegisterInternal)o);
|
||||||
|
|
||||||
|
|||||||
@@ -190,7 +190,7 @@ namespace MewtocolNet {
|
|||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Register Colleciton adding
|
#region Register Collection adding
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Adds the given register collection and all its registers with attributes to the register list
|
/// Adds the given register collection and all its registers with attributes to the register list
|
||||||
@@ -219,18 +219,14 @@ namespace MewtocolNet {
|
|||||||
|
|
||||||
var pollFreqAttr = (PollLevelAttribute)attributes.FirstOrDefault(x => x.GetType() == typeof(PollLevelAttribute));
|
var pollFreqAttr = (PollLevelAttribute)attributes.FirstOrDefault(x => x.GetType() == typeof(PollLevelAttribute));
|
||||||
|
|
||||||
if (!prop.PropertyType.IsAllowedPlcCastingType()) {
|
|
||||||
throw new MewtocolException($"The register attribute property type is not allowed ({prop.PropertyType})");
|
|
||||||
}
|
|
||||||
|
|
||||||
var dotnetType = prop.PropertyType;
|
var dotnetType = prop.PropertyType;
|
||||||
int pollLevel = 1;
|
int pollLevel = 1;
|
||||||
|
|
||||||
if (pollFreqAttr != null) pollLevel = pollFreqAttr.pollLevel;
|
if (pollFreqAttr != null) pollLevel = pollFreqAttr.pollLevel;
|
||||||
|
|
||||||
//add builder item
|
//add builder item
|
||||||
regBuild
|
var stp1 = regBuild
|
||||||
.Address(cAttribute.MewAddress)
|
.AddressFromAttribute(cAttribute.MewAddress, cAttribute.TypeDef)
|
||||||
.AsType(dotnetType.IsEnum ? dotnetType.UnderlyingSystemType : dotnetType)
|
.AsType(dotnetType.IsEnum ? dotnetType.UnderlyingSystemType : dotnetType)
|
||||||
.PollLevel(pollLevel)
|
.PollLevel(pollLevel)
|
||||||
.RegCollection(collection)
|
.RegCollection(collection)
|
||||||
@@ -255,7 +251,7 @@ namespace MewtocolNet {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var assembler = new RegisterAssembler(this);
|
var assembler = new RegisterAssembler(this);
|
||||||
var registers = assembler.AssembleAll(regBuild);
|
var registers = assembler.AssembleAll(regBuild, true);
|
||||||
AddRegisters(registers.ToArray());
|
AddRegisters(registers.ToArray());
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -290,7 +286,7 @@ namespace MewtocolNet {
|
|||||||
|
|
||||||
internal void InsertRegistersToMemoryStack (List<BaseRegister> registers) {
|
internal void InsertRegistersToMemoryStack (List<BaseRegister> registers) {
|
||||||
|
|
||||||
memoryManager.LinkRegisters(registers);
|
memoryManager.LinkAndMergeRegisters(registers);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using MewtocolNet.DocAttributes;
|
using MewtocolNet.Documentation;
|
||||||
|
|
||||||
namespace MewtocolNet {
|
namespace MewtocolNet {
|
||||||
|
|
||||||
|
|||||||
11
MewtocolNet/PublicEnums/RegisterBuildSource.cs
Normal file
11
MewtocolNet/PublicEnums/RegisterBuildSource.cs
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace MewtocolNet.PublicEnums {
|
||||||
|
public enum RegisterBuildSource {
|
||||||
|
Anonymous,
|
||||||
|
Manual,
|
||||||
|
Attribute,
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -9,13 +9,19 @@ namespace MewtocolNet.RegisterAttributes {
|
|||||||
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]
|
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]
|
||||||
public class RegisterAttribute : Attribute {
|
public class RegisterAttribute : Attribute {
|
||||||
|
|
||||||
internal int AssignedBitIndex = -1;
|
|
||||||
|
|
||||||
internal string MewAddress = null;
|
internal string MewAddress = null;
|
||||||
|
internal string TypeDef = null;
|
||||||
|
|
||||||
public RegisterAttribute(string mewAddress) {
|
/// <summary>
|
||||||
|
/// Builds automatic data transfer between the property below this and
|
||||||
|
/// the plc register
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="mewAddress">The FP-Address (DT, DDT, R, X, Y..)</param>
|
||||||
|
/// <param name="plcTypeDef">The type definition from the PLC (STRING[n], ARRAY [0..2] OF ...)</param>
|
||||||
|
public RegisterAttribute(string mewAddress, string plcTypeDef = null) {
|
||||||
|
|
||||||
MewAddress = mewAddress;
|
MewAddress = mewAddress;
|
||||||
|
TypeDef = plcTypeDef;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,16 +1,20 @@
|
|||||||
using MewtocolNet.RegisterAttributes;
|
using MewtocolNet.PublicEnums;
|
||||||
|
using MewtocolNet.RegisterAttributes;
|
||||||
using MewtocolNet.UnderlyingRegisters;
|
using MewtocolNet.UnderlyingRegisters;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections;
|
using System.Collections;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Data;
|
||||||
using System.Data.Common;
|
using System.Data.Common;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Xml.Linq;
|
using System.Xml.Linq;
|
||||||
|
using static MewtocolNet.RegisterBuilding.RBuild;
|
||||||
|
|
||||||
namespace MewtocolNet.RegisterBuilding {
|
namespace MewtocolNet.RegisterBuilding {
|
||||||
|
|
||||||
@@ -63,6 +67,9 @@ namespace MewtocolNet.RegisterBuilding {
|
|||||||
|
|
||||||
internal class SData {
|
internal class SData {
|
||||||
|
|
||||||
|
internal RegisterBuildSource buildSource = RegisterBuildSource.Anonymous;
|
||||||
|
|
||||||
|
internal bool wasAddressStringRangeBased;
|
||||||
internal string originalParseStr;
|
internal string originalParseStr;
|
||||||
internal string name;
|
internal string name;
|
||||||
internal RegisterType regType;
|
internal RegisterType regType;
|
||||||
@@ -77,9 +84,12 @@ namespace MewtocolNet.RegisterBuilding {
|
|||||||
|
|
||||||
internal int pollLevel = 1;
|
internal int pollLevel = 1;
|
||||||
|
|
||||||
|
//only for building from attributes
|
||||||
internal RegisterCollection regCollection;
|
internal RegisterCollection regCollection;
|
||||||
internal PropertyInfo boundProperty;
|
internal PropertyInfo boundProperty;
|
||||||
|
|
||||||
|
internal string typeDef;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public class SBase {
|
public class SBase {
|
||||||
@@ -304,6 +314,7 @@ namespace MewtocolNet.RegisterBuilding {
|
|||||||
state = ParseResultState.Success,
|
state = ParseResultState.Success,
|
||||||
stepData = new SData {
|
stepData = new SData {
|
||||||
regType = RegisterType.DT_BYTE_RANGE,
|
regType = RegisterType.DT_BYTE_RANGE,
|
||||||
|
wasAddressStringRangeBased = true,
|
||||||
dotnetVarType = typeof(byte[]),
|
dotnetVarType = typeof(byte[]),
|
||||||
memAddress = addresses[0],
|
memAddress = addresses[0],
|
||||||
byteSize = (addresses[1] - addresses[0] + 1) * 2
|
byteSize = (addresses[1] - addresses[0] + 1) * 2
|
||||||
@@ -330,6 +341,7 @@ namespace MewtocolNet.RegisterBuilding {
|
|||||||
if (!string.IsNullOrEmpty(name)) res.stepData.name = name;
|
if (!string.IsNullOrEmpty(name)) res.stepData.name = name;
|
||||||
|
|
||||||
res.stepData.originalParseStr = plcAddrName;
|
res.stepData.originalParseStr = plcAddrName;
|
||||||
|
res.stepData.buildSource = RegisterBuildSource.Manual;
|
||||||
|
|
||||||
unfinishedList.Add(res.stepData);
|
unfinishedList.Add(res.stepData);
|
||||||
|
|
||||||
@@ -350,6 +362,16 @@ namespace MewtocolNet.RegisterBuilding {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//internal use only, adds a type definition (for use when building from attibute)
|
||||||
|
internal SAddress AddressFromAttribute (string plcAddrName, string typeDef) {
|
||||||
|
|
||||||
|
var built = Address(plcAddrName);
|
||||||
|
built.Data.typeDef = typeDef;
|
||||||
|
built.Data.buildSource = RegisterBuildSource.Attribute;
|
||||||
|
return built;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Type determination stage
|
#region Type determination stage
|
||||||
@@ -358,21 +380,10 @@ namespace MewtocolNet.RegisterBuilding {
|
|||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Sets the register as a dotnet <see cref="System"/> type for direct conversion
|
/// Sets the register as a dotnet <see cref="System"/> type for direct conversion
|
||||||
/// <list type="bullet">
|
|
||||||
/// <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="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="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="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, 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="byte[]"/></term><description>As an array of bytes</description></item>
|
|
||||||
/// </list>
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
/// <typeparam name="T">
|
||||||
|
/// <include file="../Documentation/docs.xml" path='extradoc/class[@name="support-conv-types"]/*' />
|
||||||
|
/// </typeparam>
|
||||||
public TempRegister<T> AsType<T> () {
|
public TempRegister<T> AsType<T> () {
|
||||||
|
|
||||||
if (!typeof(T).IsAllowedPlcCastingType()) {
|
if (!typeof(T).IsAllowedPlcCastingType()) {
|
||||||
@@ -387,9 +398,77 @@ namespace MewtocolNet.RegisterBuilding {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
///<inheritdoc cref="AsType{T}()"/>
|
/// <summary>
|
||||||
|
/// Sets the register as a dotnet <see cref="System"/> type for direct conversion
|
||||||
|
/// <include file="../Documentation/docs.xml" path='extradoc/class[@name="support-conv-types"]/*' />
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="type">
|
||||||
|
/// <include file="../Documentation/docs.xml" path='extradoc/class[@name="support-conv-types"]/*' />
|
||||||
|
/// </param>
|
||||||
public TempRegister AsType (Type type) {
|
public TempRegister AsType (Type type) {
|
||||||
|
|
||||||
|
//was ranged syntax array build
|
||||||
|
if (Data.wasAddressStringRangeBased && type.IsArray && type.GetArrayRank() == 1) {
|
||||||
|
|
||||||
|
//invoke generic AsTypeArray
|
||||||
|
MethodInfo method = typeof(SAddress).GetMethod(nameof(AsTypeArray));
|
||||||
|
MethodInfo generic = method.MakeGenericMethod(type);
|
||||||
|
|
||||||
|
var elementType = type.GetElementType();
|
||||||
|
|
||||||
|
if (!elementType.IsAllowedPlcCastingType()) {
|
||||||
|
|
||||||
|
throw new NotSupportedException($"The dotnet type {elementType}, is not supported for PLC type casting");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isExtensionTypeDT = typeof(MewtocolExtensionTypeDT).IsAssignableFrom(elementType);
|
||||||
|
bool isExtensionTypeDDT = typeof(MewtocolExtensionTypeDDT).IsAssignableFrom(elementType);
|
||||||
|
|
||||||
|
int byteSizePerItem = 0;
|
||||||
|
if(elementType.Namespace.StartsWith("System")) {
|
||||||
|
byteSizePerItem = Marshal.SizeOf(elementType);
|
||||||
|
} else if (isExtensionTypeDT) {
|
||||||
|
byteSizePerItem = 2;
|
||||||
|
} else if (isExtensionTypeDDT) {
|
||||||
|
byteSizePerItem = 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
//check if it fits without remainder
|
||||||
|
if(Data.byteSize % byteSizePerItem != 0) {
|
||||||
|
throw new NotSupportedException($"The array element type {elementType} doesn't fit into the adress range");
|
||||||
|
}
|
||||||
|
|
||||||
|
return (TempRegister)generic.Invoke(this, new object[] {
|
||||||
|
//element count
|
||||||
|
new int[] { (int)((Data.byteSize / byteSizePerItem) / 2) }
|
||||||
|
});
|
||||||
|
|
||||||
|
} else if(Data.wasAddressStringRangeBased) {
|
||||||
|
|
||||||
|
throw new NotSupportedException("DT range building is only allowed for 1 dimensional arrays");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//for internal only, relay to AsType from string
|
||||||
|
if (Data.buildSource == RegisterBuildSource.Attribute) {
|
||||||
|
|
||||||
|
if ((type.IsArray || type == typeof(string)) && Data.typeDef != null) {
|
||||||
|
|
||||||
|
return AsType(Data.typeDef);
|
||||||
|
|
||||||
|
} else if ((type.IsArray || type == typeof(string)) && Data.typeDef == null) {
|
||||||
|
|
||||||
|
throw new NotSupportedException("Typedef parameter is needed for array or string types");
|
||||||
|
|
||||||
|
} else if (Data.typeDef != null) {
|
||||||
|
|
||||||
|
throw new NotSupportedException("Can't use the typedef parameter on non array or string types");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
if (!type.IsAllowedPlcCastingType()) {
|
if (!type.IsAllowedPlcCastingType()) {
|
||||||
|
|
||||||
throw new NotSupportedException($"The dotnet type {type}, is not supported for PLC type casting");
|
throw new NotSupportedException($"The dotnet type {type}, is not supported for PLC type casting");
|
||||||
@@ -430,7 +509,7 @@ namespace MewtocolNet.RegisterBuilding {
|
|||||||
/// <item><term>DWORD</term><description>32 bit double word interpreted as <see cref="uint"/></description></item>
|
/// <item><term>DWORD</term><description>32 bit double word interpreted as <see cref="uint"/></description></item>
|
||||||
/// </list>
|
/// </list>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public TempRegister AsType(string type) {
|
public TempRegister AsType (string type) {
|
||||||
|
|
||||||
var stringMatch = Regex.Match(type, @"STRING *\[(?<len>[0-9]*)\]", RegexOptions.IgnoreCase);
|
var stringMatch = Regex.Match(type, @"STRING *\[(?<len>[0-9]*)\]", RegexOptions.IgnoreCase);
|
||||||
var arrayMatch = Regex.Match(type, @"ARRAY *\[(?<S1>[0-9]*)..(?<E1>[0-9]*)(?:\,(?<S2>[0-9]*)..(?<E2>[0-9]*))?(?:\,(?<S3>[0-9]*)..(?<E3>[0-9]*))?\] *OF {1,}(?<t>.*)", RegexOptions.IgnoreCase);
|
var arrayMatch = Regex.Match(type, @"ARRAY *\[(?<S1>[0-9]*)..(?<E1>[0-9]*)(?:\,(?<S2>[0-9]*)..(?<E2>[0-9]*))?(?:\,(?<S3>[0-9]*)..(?<E3>[0-9]*))?\] *OF {1,}(?<t>.*)", RegexOptions.IgnoreCase);
|
||||||
@@ -446,11 +525,46 @@ namespace MewtocolNet.RegisterBuilding {
|
|||||||
|
|
||||||
} else if (arrayMatch.Success) {
|
} else if (arrayMatch.Success) {
|
||||||
|
|
||||||
throw new NotSupportedException("Arrays are currently not supported");
|
//invoke generic AsTypeArray
|
||||||
|
|
||||||
|
string arrTypeString = arrayMatch.Groups["t"].Value;
|
||||||
|
|
||||||
|
if (Enum.TryParse<PlcVarType>(arrTypeString, out var parsedArrType)) {
|
||||||
|
|
||||||
|
var dotnetArrType = parsedArrType.GetDefaultDotnetType();
|
||||||
|
var indices = new List<int>();
|
||||||
|
|
||||||
|
for (int i = 1; i < 4; i++) {
|
||||||
|
|
||||||
|
var arrStart = arrayMatch.Groups[$"S{i}"]?.Value;
|
||||||
|
var arrEnd = arrayMatch.Groups[$"E{i}"]?.Value;
|
||||||
|
if (string.IsNullOrEmpty(arrStart) || string.IsNullOrEmpty(arrEnd)) break;
|
||||||
|
|
||||||
|
var arrStartInt = int.Parse(arrStart);
|
||||||
|
var arrEndInt = int.Parse(arrEnd);
|
||||||
|
|
||||||
|
indices.Add(arrEndInt - arrStartInt + 1);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
var arr = Array.CreateInstance(dotnetArrType, indices.ToArray());
|
||||||
|
var arrType = arr.GetType();
|
||||||
|
|
||||||
|
MethodInfo method = typeof(SAddress).GetMethod(nameof(AsTypeArray));
|
||||||
|
MethodInfo generic = method.MakeGenericMethod(arrType);
|
||||||
|
|
||||||
|
return (TempRegister)generic.Invoke(this, new object[] {
|
||||||
|
indices.ToArray()
|
||||||
|
});
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
throw new NotSupportedException($"The FP type '{arrTypeString}' was not recognized");
|
||||||
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
throw new NotSupportedException($"The mewtocol type '{type}' was not recognized");
|
throw new NotSupportedException($"The FP type '{type}' was not recognized");
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -459,38 +573,41 @@ namespace MewtocolNet.RegisterBuilding {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the data DT area as a <see cref="byte[]"/>
|
/// Sets the register as a (multidimensional) array targeting a PLC array
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="byteLength">Bytes to assign</param>
|
/// <typeparam name="T">
|
||||||
public TempRegister AsBytes (uint byteLength) {
|
/// <include file="../Documentation/docs.xml" path='extradoc/class[@name="support-conv-types"]/*' />
|
||||||
|
/// </typeparam>
|
||||||
|
/// <param name="indicies">
|
||||||
|
/// Indicies for multi dimensional arrays, for normal arrays just one INT
|
||||||
|
/// </param>
|
||||||
|
/// <example>
|
||||||
|
/// <b>One dimensional arrays:</b><br/>
|
||||||
|
/// ARRAY [0..2] OF INT = <c>AsTypeArray<short[]>(3)</c><br/>
|
||||||
|
/// ARRAY [5..6] OF DWORD = <c>AsTypeArray<DWord[]>(2)</c><br/>
|
||||||
|
/// <br/>
|
||||||
|
/// <b>Multi dimensional arrays:</b><br/>
|
||||||
|
/// ARRAY [0..2, 0..3, 0..4] OF INT = <c>AsTypeArray<short[,,]>(3,4,5)</c><br/>
|
||||||
|
/// ARRAY [5..6, 0..2] OF DWORD = <c>AsTypeArray<DWord[,]>(2, 3)</c><br/>
|
||||||
|
/// </example>
|
||||||
|
public TempRegister AsTypeArray<T> (params int[] indicies) {
|
||||||
|
|
||||||
if (Data.regType != RegisterType.DT) {
|
if (!typeof(T).IsArray)
|
||||||
|
throw new NotSupportedException($"The type {typeof(T)} was no array");
|
||||||
|
|
||||||
throw new NotSupportedException($"Cant use the {nameof(AsBytes)} converter on a non {nameof(RegisterType.DT)} register");
|
var arrRank = typeof(T).GetArrayRank();
|
||||||
|
var elBaseType = typeof(T).GetElementType();
|
||||||
|
|
||||||
}
|
if (arrRank > 3)
|
||||||
|
throw new NotSupportedException($"4+ dimensional arrays are not supported");
|
||||||
|
|
||||||
Data.byteSize = byteLength;
|
if (!elBaseType.IsAllowedPlcCastingType())
|
||||||
Data.dotnetVarType = typeof(byte[]);
|
throw new NotSupportedException($"The dotnet type {typeof(T)}, is not supported for PLC array type casting");
|
||||||
|
|
||||||
return new TempRegister(Data, builder);
|
if (arrRank != indicies.Length)
|
||||||
|
throw new NotSupportedException($"All dimensional array indicies must be set");
|
||||||
|
|
||||||
}
|
Data.dotnetVarType = typeof(T);
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the data DT area as a <see cref="BitArray"/>
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="bitCount">Number of bits to read</param>
|
|
||||||
public TempRegister AsBits (ushort bitCount = 16) {
|
|
||||||
|
|
||||||
if (Data.regType != RegisterType.DT) {
|
|
||||||
|
|
||||||
throw new NotSupportedException($"Cant use the {nameof(AsBits)} converter on a non {nameof(RegisterType.DT)} register");
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
Data.bitSize = bitCount;
|
|
||||||
Data.dotnetVarType = typeof(BitArray);
|
|
||||||
|
|
||||||
return new TempRegister(Data, builder);
|
return new TempRegister(Data, builder);
|
||||||
|
|
||||||
|
|||||||
@@ -21,14 +21,14 @@ namespace MewtocolNet.RegisterBuilding {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal List<BaseRegister> AssembleAll (RBuild rBuildData) {
|
internal List<BaseRegister> AssembleAll (RBuild rBuildData, bool flagAutoGenerated = false) {
|
||||||
|
|
||||||
List<BaseRegister> generatedInstances = new List<BaseRegister>();
|
List<BaseRegister> generatedInstances = new List<BaseRegister>();
|
||||||
|
|
||||||
foreach (var data in rBuildData.unfinishedList) {
|
foreach (var data in rBuildData.unfinishedList) {
|
||||||
|
|
||||||
var generatedInstance = Assemble(data);
|
var generatedInstance = Assemble(data);
|
||||||
|
generatedInstance.autoGenerated = flagAutoGenerated;
|
||||||
generatedInstances.Add(generatedInstance);
|
generatedInstances.Add(generatedInstance);
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -44,6 +44,13 @@ namespace MewtocolNet.RegisterBuilding {
|
|||||||
|
|
||||||
BaseRegister generatedInstance = null;
|
BaseRegister generatedInstance = null;
|
||||||
|
|
||||||
|
if(data.dotnetVarType.IsArray) {
|
||||||
|
|
||||||
|
Console.WriteLine();
|
||||||
|
return new ArrayRegister(0, 0);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
if (data.dotnetVarType.IsEnum) {
|
if (data.dotnetVarType.IsEnum) {
|
||||||
|
|
||||||
//-------------------------------------------
|
//-------------------------------------------
|
||||||
|
|||||||
@@ -24,6 +24,8 @@ namespace MewtocolNet.Registers {
|
|||||||
|
|
||||||
internal Type underlyingSystemType;
|
internal Type underlyingSystemType;
|
||||||
internal IMemoryArea underlyingMemory;
|
internal IMemoryArea underlyingMemory;
|
||||||
|
internal bool autoGenerated;
|
||||||
|
|
||||||
internal object lastValue = null;
|
internal object lastValue = null;
|
||||||
internal string name;
|
internal string name;
|
||||||
internal uint memoryAddress;
|
internal uint memoryAddress;
|
||||||
@@ -128,6 +130,8 @@ namespace MewtocolNet.Registers {
|
|||||||
|
|
||||||
public virtual uint GetRegisterAddressLen() => throw new NotImplementedException();
|
public virtual uint GetRegisterAddressLen() => throw new NotImplementedException();
|
||||||
|
|
||||||
|
public virtual uint GetRegisterAddressEnd() => MemoryAddress + GetRegisterAddressLen() - 1;
|
||||||
|
|
||||||
public string GetRegisterWordRangeString() => $"{GetMewName()} - {MemoryAddress + GetRegisterAddressLen() - 1}";
|
public string GetRegisterWordRangeString() => $"{GetMewName()} - {MemoryAddress + GetRegisterAddressLen() - 1}";
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
@@ -156,6 +160,7 @@ namespace MewtocolNet.Registers {
|
|||||||
|
|
||||||
return this.MemoryAddress == toCompare.MemoryAddress &&
|
return this.MemoryAddress == toCompare.MemoryAddress &&
|
||||||
this.RegisterType == toCompare.RegisterType &&
|
this.RegisterType == toCompare.RegisterType &&
|
||||||
|
this.underlyingSystemType == toCompare.underlyingSystemType &&
|
||||||
this.GetRegisterAddressLen() == toCompare.GetRegisterAddressLen() &&
|
this.GetRegisterAddressLen() == toCompare.GetRegisterAddressLen() &&
|
||||||
this.GetSpecialAddress() == toCompare.GetSpecialAddress();
|
this.GetSpecialAddress() == toCompare.GetSpecialAddress();
|
||||||
|
|
||||||
@@ -199,20 +204,34 @@ namespace MewtocolNet.Registers {
|
|||||||
public virtual string Explain () {
|
public virtual string Explain () {
|
||||||
|
|
||||||
StringBuilder sb = new StringBuilder();
|
StringBuilder sb = new StringBuilder();
|
||||||
sb.AppendLine($"MewName: {GetMewName()}");
|
sb.Append($"Address: {GetRegisterWordRangeString()}\n");
|
||||||
sb.AppendLine($"Name: {Name ?? "Not named"}");
|
|
||||||
sb.AppendLine($"Value: {GetValueString()}");
|
if (GetType().IsGenericType)
|
||||||
sb.AppendLine($"Perf. Reads: {successfulReads}, Writes: {successfulWrites}");
|
sb.Append($"Type: {RegisterType}, NumberRegister<{GetType().GenericTypeArguments[0]}>\n");
|
||||||
sb.AppendLine($"Register Type: {RegisterType}");
|
else
|
||||||
sb.AppendLine($"Underlying System Type: {underlyingSystemType}");
|
sb.AppendLine($"Type: {RegisterType}, {GetType().Name}\n");
|
||||||
sb.AppendLine($"Address: {GetRegisterWordRangeString()}");
|
|
||||||
if (this is StringRegister sr) sb.AppendLine($"Reserved: {sr.ReservedSize}, Used: {sr.UsedSize}");
|
sb.Append($"Name: {Name ?? "Not named"}\n");
|
||||||
if (GetSpecialAddress() != null) sb.AppendLine($"SPAddress: {GetSpecialAddress():X1}");
|
|
||||||
if (GetType().IsGenericType) sb.AppendLine($"Type: NumberRegister<{GetType().GenericTypeArguments[0]}>");
|
if(Value != null)
|
||||||
else sb.AppendLine($"Type: {GetType()}");
|
sb.Append($"Value: {GetValueString()}\n");
|
||||||
if (containedCollection != null) sb.AppendLine($"In collection: {containedCollection.GetType()}");
|
|
||||||
if (boundProperties != null && boundProperties.Count > 0) sb.AppendLine($"Bound props: {string.Join(", ", boundProperties)}");
|
sb.Append($"Reads: {successfulReads}, Writes: {successfulWrites}\n");
|
||||||
else sb.AppendLine("No bound properties");
|
sb.Append($"Underlying System Type: {underlyingSystemType}\n");
|
||||||
|
|
||||||
|
if (this is StringRegister sr)
|
||||||
|
sb.Append($"Reserved: {sr.ReservedSize}, Used: {sr.UsedSize}\n");
|
||||||
|
|
||||||
|
if (GetSpecialAddress() != null)
|
||||||
|
sb.Append($"SPAddress: {GetSpecialAddress():X1}\n");
|
||||||
|
|
||||||
|
if (containedCollection != null)
|
||||||
|
sb.Append($"In collection: {containedCollection.GetType()}\n");
|
||||||
|
|
||||||
|
if (boundProperties != null && boundProperties.Count > 0)
|
||||||
|
sb.Append($"Bound props: \n\t{string.Join(",\n\t", boundProperties)}");
|
||||||
|
else
|
||||||
|
sb.Append("No bound properties");
|
||||||
|
|
||||||
return sb.ToString();
|
return sb.ToString();
|
||||||
|
|
||||||
|
|||||||
@@ -154,6 +154,12 @@ namespace MewtocolNet.Registers {
|
|||||||
var res = await attachedInterface.ReadByteRangeNonBlocking((int)MemoryAddress, (int)GetRegisterAddressLen() * 2, false);
|
var res = await attachedInterface.ReadByteRangeNonBlocking((int)MemoryAddress, (int)GetRegisterAddressLen() * 2, false);
|
||||||
if (res == null) return null;
|
if (res == null) return null;
|
||||||
|
|
||||||
|
var matchingReg = attachedInterface.memoryManager.GetAllRegisters()
|
||||||
|
.FirstOrDefault(x => x.IsSameAddressAndType(this));
|
||||||
|
|
||||||
|
if (matchingReg != null)
|
||||||
|
matchingReg.underlyingMemory.SetUnderlyingBytes(matchingReg, res);
|
||||||
|
|
||||||
return SetValueFromBytes(res);
|
return SetValueFromBytes(res);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,9 +17,10 @@ namespace MewtocolNet.UnderlyingRegisters {
|
|||||||
|
|
||||||
internal byte[] underlyingBytes = new byte[2];
|
internal byte[] underlyingBytes = new byte[2];
|
||||||
|
|
||||||
internal List<BaseRegister> linkedRegisters = new List<BaseRegister>();
|
/// <summary>
|
||||||
|
/// List of register link groups that are managed in this memory area
|
||||||
internal Dictionary<BaseRegister, List<BaseRegister>> crossRegisterBindings = new Dictionary<BaseRegister, List<BaseRegister>>();
|
/// </summary>
|
||||||
|
internal List<LinkedRegisterGroup> managedRegisters = new List<LinkedRegisterGroup>();
|
||||||
|
|
||||||
public ulong AddressStart => addressStart;
|
public ulong AddressStart => addressStart;
|
||||||
public ulong AddressEnd => addressEnd;
|
public ulong AddressEnd => addressEnd;
|
||||||
@@ -51,7 +52,7 @@ namespace MewtocolNet.UnderlyingRegisters {
|
|||||||
|
|
||||||
public void UpdateAreaRegisterValues() {
|
public void UpdateAreaRegisterValues() {
|
||||||
|
|
||||||
foreach (var register in this.linkedRegisters) {
|
foreach (var register in this.managedRegisters.SelectMany(x => x.Linked)) {
|
||||||
|
|
||||||
var regStart = register.MemoryAddress;
|
var regStart = register.MemoryAddress;
|
||||||
var addLen = (int)register.GetRegisterAddressLen();
|
var addLen = (int)register.GetRegisterAddressLen();
|
||||||
@@ -120,7 +121,8 @@ namespace MewtocolNet.UnderlyingRegisters {
|
|||||||
private async Task CheckDynamicallySizedRegistersAsync () {
|
private async Task CheckDynamicallySizedRegistersAsync () {
|
||||||
|
|
||||||
//calibrating at runtime sized registers
|
//calibrating at runtime sized registers
|
||||||
var uncalibratedStringRegisters = linkedRegisters
|
var uncalibratedStringRegisters = managedRegisters
|
||||||
|
.SelectMany(x => x.Linked)
|
||||||
.Where(x => x is StringRegister sreg && !sreg.isCalibratedFromPlc)
|
.Where(x => x is StringRegister sreg && !sreg.isCalibratedFromPlc)
|
||||||
.Cast<StringRegister>()
|
.Cast<StringRegister>()
|
||||||
.ToList();
|
.ToList();
|
||||||
@@ -129,7 +131,7 @@ namespace MewtocolNet.UnderlyingRegisters {
|
|||||||
await register.CalibrateFromPLC();
|
await register.CalibrateFromPLC();
|
||||||
|
|
||||||
if (uncalibratedStringRegisters.Count > 0)
|
if (uncalibratedStringRegisters.Count > 0)
|
||||||
mewInterface.memoryManager.MergeAndSizeDataAreas();
|
mewInterface.memoryManager.LinkAndMergeRegisters();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
18
MewtocolNet/UnderlyingRegisters/LinkedRegisterGroup.cs
Normal file
18
MewtocolNet/UnderlyingRegisters/LinkedRegisterGroup.cs
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
using MewtocolNet.Registers;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace MewtocolNet.UnderlyingRegisters {
|
||||||
|
|
||||||
|
internal class LinkedRegisterGroup {
|
||||||
|
|
||||||
|
internal uint AddressStart;
|
||||||
|
|
||||||
|
internal uint AddressEnd;
|
||||||
|
|
||||||
|
internal List<BaseRegister> Linked = new List<BaseRegister>();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -47,12 +47,12 @@ namespace MewtocolNet.UnderlyingRegisters {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void LinkRegisters (List<BaseRegister> registers = null) {
|
internal void LinkAndMergeRegisters (List<BaseRegister> registers = null) {
|
||||||
|
|
||||||
//for self calling
|
//for self calling
|
||||||
if (registers == null) registers = GetAllRegisters().ToList();
|
if (registers == null) registers = GetAllRegisters().ToList();
|
||||||
|
|
||||||
//pre combine
|
//pre combine per address
|
||||||
var groupedByAdd = registers
|
var groupedByAdd = registers
|
||||||
.GroupBy(x => new {
|
.GroupBy(x => new {
|
||||||
x.MemoryAddress,
|
x.MemoryAddress,
|
||||||
@@ -60,39 +60,20 @@ namespace MewtocolNet.UnderlyingRegisters {
|
|||||||
spadd = x.GetSpecialAddress(),
|
spadd = x.GetSpecialAddress(),
|
||||||
});
|
});
|
||||||
|
|
||||||
var filteredRegisters = new List<BaseRegister>();
|
//poll level merging
|
||||||
var propertyLookupTable = new Dictionary<PropertyInfo, BaseRegister>();
|
|
||||||
|
|
||||||
foreach (var addressGroup in groupedByAdd) {
|
foreach (var addressGroup in groupedByAdd) {
|
||||||
|
|
||||||
var ordered = addressGroup.OrderBy(x => x.pollLevel);
|
//determine highest poll level for same addresses
|
||||||
var highestPollLevel = ordered.Max(x => x.pollLevel);
|
var highestPollLevel = addressGroup.Max(x => x.pollLevel);
|
||||||
|
|
||||||
var distinctByUnderlyingType =
|
//apply poll level to all registers in same group
|
||||||
ordered.GroupBy(x => x.underlyingSystemType).ToList();
|
foreach (var reg in addressGroup)
|
||||||
|
reg.pollLevel = highestPollLevel;
|
||||||
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) {
|
//insert into area
|
||||||
|
foreach (var reg in registers) {
|
||||||
|
|
||||||
TestPollLevelExistence(reg);
|
TestPollLevelExistence(reg);
|
||||||
|
|
||||||
@@ -111,6 +92,18 @@ namespace MewtocolNet.UnderlyingRegisters {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//order
|
||||||
|
|
||||||
|
foreach (var lvl in pollLevels) {
|
||||||
|
|
||||||
|
foreach (var area in lvl.dataAreas) {
|
||||||
|
|
||||||
|
area.managedRegisters = area.managedRegisters.OrderBy(x => x.AddressStart).ToList();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void TestPollLevelExistence (BaseRegister reg) {
|
private void TestPollLevelExistence (BaseRegister reg) {
|
||||||
@@ -271,17 +264,27 @@ namespace MewtocolNet.UnderlyingRegisters {
|
|||||||
insertReg.name = $"auto_{Guid.NewGuid().ToString("N")}";
|
insertReg.name = $"auto_{Guid.NewGuid().ToString("N")}";
|
||||||
}
|
}
|
||||||
|
|
||||||
Console.WriteLine($"Adding linked register: {insertReg}");
|
var existinglinkedGroup = targetArea.managedRegisters
|
||||||
targetArea.linkedRegisters.Add(insertReg);
|
.FirstOrDefault(x => x.AddressStart == insertReg.MemoryAddress &&
|
||||||
return;
|
x.AddressEnd == insertReg.GetRegisterAddressEnd());
|
||||||
|
|
||||||
}
|
if (existinglinkedGroup == null) {
|
||||||
|
// make a new linked group
|
||||||
|
existinglinkedGroup = new LinkedRegisterGroup {
|
||||||
|
AddressStart = insertReg.MemoryAddress,
|
||||||
|
AddressEnd = insertReg.GetRegisterAddressEnd(),
|
||||||
|
};
|
||||||
|
targetArea.managedRegisters.Add(existinglinkedGroup);
|
||||||
|
}
|
||||||
|
|
||||||
internal void MergeAndSizeDataAreas () {
|
//check if the linked group has duplicate type registers
|
||||||
|
|
||||||
//merge gaps that the algorithm didn't catch be rerunning the register attachment
|
var dupedTypeReg = existinglinkedGroup.Linked.FirstOrDefault(x => x.IsSameAddressAndType(insertReg));
|
||||||
|
if (dupedTypeReg != null) {
|
||||||
LinkRegisters();
|
dupedTypeReg.WithBoundProperties(insertReg.boundProperties);
|
||||||
|
} else {
|
||||||
|
existinglinkedGroup.Linked.Add(insertReg);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -350,75 +353,67 @@ namespace MewtocolNet.UnderlyingRegisters {
|
|||||||
|
|
||||||
foreach (var pollLevel in pollLevels) {
|
foreach (var pollLevel in pollLevels) {
|
||||||
|
|
||||||
sb.AppendLine($"==== Poll lvl {pollLevel.level} ====");
|
sb.AppendLine($"\n> ==== Poll lvl {pollLevel.level} ====");
|
||||||
|
|
||||||
sb.AppendLine();
|
sb.AppendLine();
|
||||||
if (pollLevelConfigs[pollLevel.level].delay != null) {
|
if (pollLevelConfigs[pollLevel.level].delay != null) {
|
||||||
sb.AppendLine($"Poll each {pollLevelConfigs[pollLevel.level].delay?.TotalMilliseconds}ms");
|
sb.AppendLine($"> Poll each {pollLevelConfigs[pollLevel.level].delay?.TotalMilliseconds}ms");
|
||||||
} else {
|
} else {
|
||||||
sb.AppendLine($"Poll every {pollLevelConfigs[pollLevel.level].skipNth} iterations");
|
sb.AppendLine($"> Poll every {pollLevelConfigs[pollLevel.level].skipNth} iterations");
|
||||||
}
|
}
|
||||||
sb.AppendLine($"Level read time: {pollLevel.lastReadTimeMs}ms");
|
sb.AppendLine($"> Level read time: {pollLevel.lastReadTimeMs}ms");
|
||||||
sb.AppendLine($"Optimization distance: {maxOptimizationDistance}");
|
sb.AppendLine($"> Optimization distance: {maxOptimizationDistance}");
|
||||||
sb.AppendLine();
|
sb.AppendLine();
|
||||||
|
|
||||||
sb.AppendLine($"---- DT Areas: ----");
|
|
||||||
|
|
||||||
foreach (var area in pollLevel.dataAreas) {
|
foreach (var area in pollLevel.dataAreas) {
|
||||||
|
|
||||||
|
var areaHeader = $"AREA => {area} = {area.underlyingBytes.Length} bytes";
|
||||||
|
sb.AppendLine($"* {new string('-', areaHeader.Length)}*");
|
||||||
|
sb.AppendLine($"* {areaHeader}");
|
||||||
|
sb.AppendLine($"* {new string('-', areaHeader.Length)}*");
|
||||||
|
sb.AppendLine("*");
|
||||||
|
sb.AppendLine($"* {(string.Join("\n* ", area.underlyingBytes.ToHexString(" ").SplitInParts(3 * 8)))}");
|
||||||
|
sb.AppendLine("*");
|
||||||
|
|
||||||
|
int seperatorLen = 50;
|
||||||
|
|
||||||
|
LinkedRegisterGroup prevGroup = null;
|
||||||
|
|
||||||
|
foreach (var linkedG in area.managedRegisters) {
|
||||||
|
|
||||||
|
if (prevGroup != null && (linkedG.AddressStart - prevGroup.AddressEnd - 1 > 0)) {
|
||||||
|
|
||||||
|
var dist = linkedG.AddressStart - prevGroup.AddressEnd - 1;
|
||||||
|
|
||||||
|
sb.AppendLine($"* {new string('=', seperatorLen + 3)}");
|
||||||
|
sb.AppendLine($"* Byte spacer: {dist} Words");
|
||||||
|
sb.AppendLine($"* {new string('=', seperatorLen + 3)}");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
sb.AppendLine($"* {new string('_', seperatorLen + 3)}");
|
||||||
|
sb.AppendLine($"* || Linked group {linkedG.AddressStart} - {linkedG.AddressEnd}");
|
||||||
|
sb.AppendLine($"* || {new string('=', seperatorLen)}");
|
||||||
|
|
||||||
|
foreach (var reg in linkedG.Linked) {
|
||||||
|
|
||||||
|
string explained = reg.Explain();
|
||||||
|
|
||||||
|
sb.AppendLine($"* || {explained.Replace("\n", "\n* || ")}");
|
||||||
|
|
||||||
|
if (linkedG.Linked.Count > 1) {
|
||||||
|
sb.AppendLine($"* || {new string('-', seperatorLen)}");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
sb.AppendLine($"* {new string('=', seperatorLen + 3)}");
|
||||||
|
|
||||||
|
prevGroup = linkedG;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
sb.AppendLine();
|
sb.AppendLine();
|
||||||
sb.AppendLine($"=> {area} = {area.underlyingBytes.Length} bytes");
|
|
||||||
sb.AppendLine();
|
|
||||||
sb.AppendLine(string.Join("\n", area.underlyingBytes.ToHexString(" ").SplitInParts(3 * 8)));
|
|
||||||
sb.AppendLine();
|
|
||||||
|
|
||||||
foreach (var reg in area.linkedRegisters) {
|
|
||||||
|
|
||||||
sb.AppendLine($"{reg.Explain()}");
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
sb.AppendLine($"---- WR X Area ----");
|
|
||||||
|
|
||||||
foreach (var area in pollLevel.externalRelayInAreas) {
|
|
||||||
|
|
||||||
sb.AppendLine(area.ToString());
|
|
||||||
|
|
||||||
foreach (var reg in area.linkedRegisters) {
|
|
||||||
|
|
||||||
sb.AppendLine($"{reg.Explain()}");
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
sb.AppendLine($"---- WR Y Area ---");
|
|
||||||
|
|
||||||
foreach (var area in pollLevel.externalRelayOutAreas) {
|
|
||||||
|
|
||||||
sb.AppendLine(area.ToString());
|
|
||||||
|
|
||||||
foreach (var reg in area.linkedRegisters) {
|
|
||||||
|
|
||||||
sb.AppendLine($"{reg.Explain()}");
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
sb.AppendLine($"---- WR R Area ----");
|
|
||||||
|
|
||||||
foreach (var area in pollLevel.internalRelayAreas) {
|
|
||||||
|
|
||||||
sb.AppendLine(area.ToString());
|
|
||||||
|
|
||||||
foreach (var reg in area.linkedRegisters) {
|
|
||||||
|
|
||||||
sb.AppendLine($"{reg.Explain()}");
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -434,7 +429,8 @@ namespace MewtocolNet.UnderlyingRegisters {
|
|||||||
|
|
||||||
foreach (var lvl in pollLevels) {
|
foreach (var lvl in pollLevels) {
|
||||||
|
|
||||||
registers.AddRange(lvl.dataAreas.SelectMany(x => x.linkedRegisters));
|
registers.AddRange(lvl.dataAreas.SelectMany(x => x.managedRegisters).SelectMany(x => x.Linked));
|
||||||
|
|
||||||
registers.AddRange(lvl.internalRelayAreas.SelectMany(x => x.linkedRegisters));
|
registers.AddRange(lvl.internalRelayAreas.SelectMany(x => x.linkedRegisters));
|
||||||
registers.AddRange(lvl.externalRelayInAreas.SelectMany(x => x.linkedRegisters));
|
registers.AddRange(lvl.externalRelayInAreas.SelectMany(x => x.linkedRegisters));
|
||||||
registers.AddRange(lvl.externalRelayOutAreas.SelectMany(x => x.linkedRegisters));
|
registers.AddRange(lvl.externalRelayOutAreas.SelectMany(x => x.linkedRegisters));
|
||||||
|
|||||||
Reference in New Issue
Block a user