diff --git a/MewTerminal/Commands/OnlineCommands/OnlineCommand.cs b/MewTerminal/Commands/OnlineCommands/OnlineCommand.cs
index 4f60c8f..6f45eaf 100644
--- a/MewTerminal/Commands/OnlineCommands/OnlineCommand.cs
+++ b/MewTerminal/Commands/OnlineCommands/OnlineCommand.cs
@@ -25,7 +25,7 @@ internal class OnlineCommand : CommandLineExcecuteable {
string ip = split[0];
int port = int.Parse(split[1]);
- using (var plc = Mewtocol.Ethernet(ip, port)) {
+ using (var plc = Mewtocol.Ethernet(ip, port).Build()) {
await AfterSetup(plc);
diff --git a/MewTerminal/Commands/ScanCommand.cs b/MewTerminal/Commands/ScanCommand.cs
index d197c68..f2e2809 100644
--- a/MewTerminal/Commands/ScanCommand.cs
+++ b/MewTerminal/Commands/ScanCommand.cs
@@ -45,7 +45,7 @@ internal class ScanCommand : CommandLineExcecuteable {
ctx.Status($"Getting cassette PLC {item.Cassette.IPAddress}:{item.Cassette.Port}")
.Spinner(Spinner.Known.Dots);
- var dev = Mewtocol.Ethernet(item.Cassette.IPAddress, item.Cassette.Port);
+ var dev = Mewtocol.Ethernet(item.Cassette.IPAddress, item.Cassette.Port).Build();
dev.ConnectTimeout = 1000;
await dev.ConnectAsync();
item.PLCInf = dev.PlcInfo;
diff --git a/MewTerminal/Program.cs b/MewTerminal/Program.cs
index f12e52a..143ec4d 100644
--- a/MewTerminal/Program.cs
+++ b/MewTerminal/Program.cs
@@ -1,6 +1,7 @@
using CommandLine;
using CommandLine.Text;
using MewTerminal.Commands;
+using MewTerminal.Commands.OnlineCommands;
using MewtocolNet.Logging;
using Spectre.Console;
using System.Globalization;
diff --git a/MewtocolNet/Helpers/MewtocolHelpers.cs b/MewtocolNet/Helpers/MewtocolHelpers.cs
index 6a144c9..f27f1ff 100644
--- a/MewtocolNet/Helpers/MewtocolHelpers.cs
+++ b/MewtocolNet/Helpers/MewtocolHelpers.cs
@@ -1,4 +1,5 @@
using MewtocolNet.DocAttributes;
+using MewtocolNet.Registers;
using System;
using System.Collections;
using System.Collections.Generic;
@@ -118,7 +119,9 @@ namespace MewtocolNet {
/// A or null of failed
internal static byte[] ParseDTRawStringAsBytes (this string _onString) {
- var res = new Regex(@"\%([0-9]{2})\$RD(?.*)(?..)..").Match(_onString);
+ _onString = _onString.Replace("\r", "");
+
+ var res = new Regex(@"\%([0-9]{2})\$RD(?.*)(?..)").Match(_onString);
if (res.Success) {
string val = res.Groups["data"].Value;
@@ -248,6 +251,16 @@ namespace MewtocolNet {
}
+ internal static bool CompareIsDuplicateNonCast (this BaseRegister reg1, BaseRegister compare) {
+
+ bool valCompare = reg1.GetType() != compare.GetType() &&
+ reg1.MemoryAddress == compare.MemoryAddress &&
+ reg1.GetSpecialAddress() == compare.GetSpecialAddress();
+
+ return valCompare;
+
+ }
+
internal static bool CompareIsNameDuplicate(this IRegisterInternal reg1, IRegisterInternal compare) {
return ( reg1.Name != null || compare.Name != null) && reg1.Name == compare.Name;
diff --git a/MewtocolNet/IPlc.cs b/MewtocolNet/IPlc.cs
index b92a434..cfa3fcb 100644
--- a/MewtocolNet/IPlc.cs
+++ b/MewtocolNet/IPlc.cs
@@ -124,6 +124,11 @@ namespace MewtocolNet {
///
IEnumerable GetAllRegisters();
+ ///
+ /// Explains the register internal layout at this moment in time
+ ///
+ string Explain();
+
}
}
diff --git a/MewtocolNet/IPlcEthernet.cs b/MewtocolNet/IPlcEthernet.cs
index dd95ddf..0fa9ec4 100644
--- a/MewtocolNet/IPlcEthernet.cs
+++ b/MewtocolNet/IPlcEthernet.cs
@@ -38,18 +38,6 @@ namespace MewtocolNet {
/// Station Number of the PLC
void ConfigureConnection(string _ip, int _port = 9094, int _station = 1);
- ///
- /// Attaches a poller to the interface
- ///
- IPlcEthernet WithPoller();
-
- ///
- /// Attaches a register collection object to
- /// the interface that can be updated automatically.
- ///
- /// The type of the collection base class
- IPlcEthernet AddRegisterCollection(RegisterCollection collection);
-
}
}
diff --git a/MewtocolNet/IPlcSerial.cs b/MewtocolNet/IPlcSerial.cs
index 609bf40..760a9fa 100644
--- a/MewtocolNet/IPlcSerial.cs
+++ b/MewtocolNet/IPlcSerial.cs
@@ -58,18 +58,6 @@ namespace MewtocolNet {
///
Task ConnectAsync(Action onTryingConfig);
- ///
- /// Attaches a poller to the interface
- ///
- IPlcSerial WithPoller();
-
- ///
- /// Attaches a register collection object to
- /// the interface that can be updated automatically.
- ///
- /// The type of the collection base class
- IPlcSerial AddRegisterCollection(RegisterCollection collection);
-
}
}
diff --git a/MewtocolNet/Mewtocol.cs b/MewtocolNet/Mewtocol.cs
index ca88908..f9d34c1 100644
--- a/MewtocolNet/Mewtocol.cs
+++ b/MewtocolNet/Mewtocol.cs
@@ -1,6 +1,8 @@
using MewtocolNet.Exceptions;
+using MewtocolNet.RegisterAttributes;
using System;
using System.Collections.Generic;
+using System.Collections.ObjectModel;
using System.IO.Ports;
using System.Linq;
using System.Net;
@@ -20,11 +22,13 @@ namespace MewtocolNet {
///
/// Plc station number
///
- public static IPlcEthernet Ethernet (string ip, int port = 9094, int station = 1) {
+ public static PostInit Ethernet (string ip, int port = 9094, int station = 1) {
var instance = new MewtocolInterfaceTcp();
instance.ConfigureConnection(ip, port, station);
- return instance;
+ return new PostInit {
+ intf = instance
+ };
}
@@ -35,11 +39,13 @@ namespace MewtocolNet {
///
/// Plc station number
///
- public static IPlcEthernet Ethernet(IPAddress ip, int port = 9094, int station = 1) {
+ public static PostInit Ethernet(IPAddress ip, int port = 9094, int station = 1) {
var instance = new MewtocolInterfaceTcp();
instance.ConfigureConnection(ip, port, station);
- return instance;
+ return new PostInit {
+ intf = instance
+ };
}
@@ -53,13 +59,15 @@ namespace MewtocolNet {
///
///
///
- public static IPlcSerial Serial (string portName, BaudRate baudRate = BaudRate._19200, DataBits dataBits = DataBits.Eight, Parity parity = Parity.Odd, StopBits stopBits = StopBits.One, int station = 1) {
+ public static PostInit Serial (string portName, BaudRate baudRate = BaudRate._19200, DataBits dataBits = DataBits.Eight, Parity parity = Parity.Odd, StopBits stopBits = StopBits.One, int station = 1) {
TestPortName(portName);
var instance = new MewtocolInterfaceSerial();
instance.ConfigureConnection(portName, (int)baudRate, (int)dataBits, parity, stopBits, station);
- return instance;
+ return new PostInit {
+ intf = instance
+ };
}
@@ -69,14 +77,16 @@ namespace MewtocolNet {
///
///
///
- public static IPlcSerial SerialAuto (string portName, int station = 1) {
+ public static PostInit SerialAuto (string portName, int station = 1) {
TestPortName(portName);
var instance = new MewtocolInterfaceSerial();
instance.ConfigureConnection(portName, station);
instance.ConfigureConnectionAuto();
- return instance;
+ return new PostInit {
+ intf = instance
+ };
}
@@ -89,6 +99,112 @@ namespace MewtocolNet {
}
+ public class MemoryManagerSettings {
+
+ ///
+ ///
+ /// This feature can improve read write times by a big margin but also
+ /// block outgoing messages inbetween polling cycles more frequently
+ ///
+ /// The max distance of the gap between registers (if there is a gap between
+ /// adjacent registers) to merge them into one request
+ /// Example:
+ ///
+ /// We have a register at DT100 (1 word long) and a
+ /// register at DT101 (1 word long)
+ /// - If the max distance is 0 it will not merge them into one request
+ /// - If the max distance is 1 it will merge them into one request
+ /// - If the max distance is 2 and the next register is at DT102 it will also merge them and ignore the spacer byte in the response
+ ///
+ ///
+
+ public int MaxOptimizationDistance { get; set; } = 8;
+
+ ///
+ /// The max number of registers per request group
+ ///
+ public int MaxRegistersPerGroup { get; set; } = -1;
+
+ }
+
+ public class PostInit {
+
+ internal T intf;
+
+ ///
+ /// Attaches a auto poller to the interface that reads all registers
+ /// cyclic
+ ///
+ ///
+ public PostInit WithPoller() {
+
+ if (intf is MewtocolInterface imew) {
+ imew.usePoller = true;
+ }
+
+ return this;
+
+ }
+
+ ///
+ /// General setting for the memory manager
+ ///
+ public PostInit WithMemoryManagerSettings (Action settings) {
+
+ var res = new MemoryManagerSettings();
+ settings.Invoke(res);
+
+ if (res.MaxOptimizationDistance < 0)
+ throw new NotSupportedException($"A value lower than 0 is not allowed for " +
+ $"{nameof(MemoryManagerSettings.MaxOptimizationDistance)}");
+
+ if (intf is MewtocolInterface imew) {
+
+ imew.memoryManager.maxOptimizationDistance = res.MaxOptimizationDistance;
+ imew.memoryManager.maxRegistersPerGroup = res.MaxRegistersPerGroup;
+
+ }
+
+ return this;
+
+ }
+
+ ///
+ /// A builder for attaching register collections
+ ///
+ public EndInit WithRegisterCollections(Action collector) {
+
+ var res = new RegisterCollectionCollector();
+ collector.Invoke(res);
+
+ if (intf is MewtocolInterface imew) {
+ imew.WithRegisterCollections(res.collections);
+ }
+
+ return new EndInit {
+ postInit = this
+ };
+
+ }
+
+ ///
+ /// Builds and returns the final plc interface
+ ///
+ public T Build() => intf;
+
+ }
+
+ public class EndInit {
+
+ internal PostInit postInit;
+
+ ///
+ /// Builds and returns the final plc interface
+ ///
+ public T Build() => postInit.intf;
+
+ }
+
}
}
diff --git a/MewtocolNet/MewtocolInterface.cs b/MewtocolNet/MewtocolInterface.cs
index a1ac273..0aa006f 100644
--- a/MewtocolNet/MewtocolInterface.cs
+++ b/MewtocolNet/MewtocolInterface.cs
@@ -11,10 +11,11 @@ using System.Runtime.CompilerServices;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
+using MewtocolNet.UnderlyingRegisters;
namespace MewtocolNet {
- public partial class MewtocolInterface : IPlc, INotifyPropertyChanged, IDisposable {
+ public abstract partial class MewtocolInterface : IPlc, INotifyPropertyChanged, IDisposable {
#region Private fields
@@ -49,6 +50,7 @@ namespace MewtocolNet {
internal volatile bool pollerTaskStopped = true;
internal volatile bool pollerFirstCycle;
internal bool usePoller = false;
+ internal MemoryAreaManager memoryManager;
internal List RegistersUnderlying { get; private set; } = new List();
internal IEnumerable RegistersInternal => RegistersUnderlying.Cast();
@@ -142,6 +144,8 @@ namespace MewtocolNet {
private protected MewtocolInterface () {
+ memoryManager = new MemoryAreaManager(this);
+
Connected += MewtocolInterface_Connected;
RegisterChanged += OnRegisterChanged;
@@ -164,6 +168,8 @@ namespace MewtocolNet {
$"{(o.Name != null ? $"({o.Name}) " : "")}" +
$"changed to \"{asInternal.GetValueString()}\"", LogLevel.Change, this);
+ OnRegisterChangedUpdateProps((IRegisterInternal)o);
+
}
///
@@ -352,8 +358,9 @@ namespace MewtocolNet {
}
//request next frame
- var writeBuffer = Encoding.UTF8.GetBytes("%01**&\r");
+ var writeBuffer = Encoding.UTF8.GetBytes($"%{GetStationNumber()}**&\r");
await stream.WriteAsync(writeBuffer, 0, writeBuffer.Length);
+ Logger.Log($">> Requested next frame", LogLevel.Critical, this);
wasMultiFramedResponse = true;
}
@@ -521,6 +528,8 @@ namespace MewtocolNet {
#endregion
+ public string Explain() => memoryManager.ExplainLayout();
+
}
}
diff --git a/MewtocolNet/MewtocolInterfaceRegisterHandling.cs b/MewtocolNet/MewtocolInterfaceRegisterHandling.cs
index 8c188bf..fa19a1b 100644
--- a/MewtocolNet/MewtocolInterfaceRegisterHandling.cs
+++ b/MewtocolNet/MewtocolInterfaceRegisterHandling.cs
@@ -3,9 +3,11 @@ using MewtocolNet.Logging;
using MewtocolNet.RegisterAttributes;
using MewtocolNet.RegisterBuilding;
using MewtocolNet.Registers;
+using MewtocolNet.UnderlyingRegisters;
using System;
using System.Collections;
using System.Collections.Generic;
+using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
@@ -18,7 +20,7 @@ namespace MewtocolNet {
///
/// The PLC com interface class
///
- public partial class MewtocolInterface {
+ public abstract partial class MewtocolInterface {
internal Task pollCycleTask;
@@ -30,14 +32,16 @@ namespace MewtocolNet {
///
/// Current poller cycle duration
///
- public int PollerCycleDurationMs {
- get => pollerCycleDurationMs;
+ public int PollerCycleDurationMs {
+ get => pollerCycleDurationMs;
private set {
pollerCycleDurationMs = value;
OnPropChange();
}
}
+ private List registerCollections = new List();
+
#region Register Polling
///
@@ -70,7 +74,7 @@ namespace MewtocolNet {
/// useful if you want to use a custom update frequency
///
/// The number of inidvidual mewtocol commands sent
- public async Task RunPollerCylceManual () {
+ public async Task RunPollerCylceManual() {
if (!pollerTaskStopped)
throw new NotSupportedException($"The poller is already running, " +
@@ -86,7 +90,7 @@ namespace MewtocolNet {
}
//polls all registers one by one (slow)
- internal async Task Poll () {
+ internal async Task Poll() {
Logger.Log("Poller is attaching", LogLevel.Info, this);
@@ -111,13 +115,15 @@ namespace MewtocolNet {
}
- private async Task OnMultiFrameCycle () {
+ private async Task OnMultiFrameCycle() {
var sw = Stopwatch.StartNew();
- await UpdateRCPRegisters();
+ //await UpdateRCPRegisters();
- await UpdateDTRegisters();
+ //await UpdateDTRegisters();
+
+ await memoryManager.PollAllAreasAsync();
await GetPLCInfoAsync();
@@ -130,7 +136,7 @@ namespace MewtocolNet {
#region Smart register polling methods
- private async Task UpdateRCPRegisters () {
+ private async Task UpdateRCPRegisters() {
//build booleans
var rcpList = RegistersUnderlying.Where(x => x.GetType() == typeof(BoolRegister))
@@ -145,7 +151,7 @@ namespace MewtocolNet {
int toReadRegistersCount = 8;
- if(i == rcpFrameCount - 1) toReadRegistersCount = rcpLastFrameRemainder;
+ if (i == rcpFrameCount - 1) toReadRegistersCount = rcpLastFrameRemainder;
var rcpString = new StringBuilder($"%{GetStationNumber()}#RCP{toReadRegistersCount}");
@@ -166,23 +172,23 @@ namespace MewtocolNet {
var register = rcpList[i + k];
- if((bool)register.Value != resultBitArray[k]) {
+ if ((bool)register.Value != resultBitArray[k]) {
register.SetValueFromPLC(resultBitArray[k]);
}
}
-
+
}
}
- private async Task UpdateDTRegisters () {
+ private async Task UpdateDTRegisters() {
foreach (var reg in RegistersUnderlying) {
var type = reg.GetType();
- if(reg.RegisterType.IsNumericDTDDT() || reg.RegisterType == RegisterType.DT_BYTE_RANGE) {
+ if (reg.RegisterType.IsNumericDTDDT() || reg.RegisterType == RegisterType.DT_BYTE_RANGE) {
var lastVal = reg.Value;
var rwReg = (IRegisterInternal)reg;
@@ -203,144 +209,81 @@ namespace MewtocolNet {
#region Register Colleciton adding
- internal MewtocolInterface WithRegisterCollection (RegisterCollection collection) {
+ ///
+ /// Adds the given register collection and all its registers with attributes to the register list
+ ///
+ internal void WithRegisterCollections(List collections) {
- collection.PLCInterface = this;
+ if (registerCollections.Count != 0)
+ throw new NotSupportedException("Register collections can only be build once");
- var props = collection.GetType().GetProperties();
+ List buildInfos = new List();
- foreach (var prop in props) {
+ foreach (var collection in collections) {
- var attributes = prop.GetCustomAttributes(true);
+ collection.PLCInterface = this;
- string propName = prop.Name;
- foreach (var attr in attributes) {
+ var props = collection.GetType().GetProperties();
- if (attr is RegisterAttribute cAttribute) {
+ foreach (var prop in props) {
+
+ var attributes = prop.GetCustomAttributes(true);
+
+ string propName = prop.Name;
+ foreach (var attr in attributes) {
+
+ if (attr is RegisterAttribute cAttribute) {
+
+ if (!prop.PropertyType.IsAllowedPlcCastingType()) {
+ throw new MewtocolException($"The register attribute property type is not allowed ({prop.PropertyType})");
+ }
+
+ var dotnetType = prop.PropertyType;
+
+ buildInfos.Add(new RegisterBuildInfo {
+ mewAddress = cAttribute.MewAddress,
+ dotnetCastType = dotnetType.IsEnum ? dotnetType.UnderlyingSystemType : dotnetType,
+ collectionTarget = collection,
+ boundPropTarget = prop,
+ });
- if(!prop.PropertyType.IsAllowedPlcCastingType()) {
- throw new MewtocolException($"The register attribute property type is not allowed ({prop.PropertyType})");
}
- var dotnetType = prop.PropertyType;
-
- AddRegister(new RegisterBuildInfo {
- mewAddress = cAttribute.MewAddress,
- memoryAddress = cAttribute.MemoryArea,
- specialAddress = cAttribute.SpecialAddress,
- memorySizeBytes = cAttribute.ByteLength,
- registerType = cAttribute.RegisterType,
- dotnetCastType = dotnetType.IsEnum ? dotnetType.UnderlyingSystemType : dotnetType,
- collectionType = collection.GetType(),
- name = prop.Name,
- });
-
}
}
+ if (collection != null) {
+ registerCollections.Add(collection);
+ collection.OnInterfaceLinked(this);
+ }
+
+ Connected += (i) => {
+ if (collection != null)
+ collection.OnInterfaceLinkedAndOnline(this);
+ };
+
}
- RegisterChanged += (reg) => {
+ AddRegisters(buildInfos);
- //register is used bitwise
- if (reg.GetType() == typeof(BytesRegister)) {
+ }
- for (int i = 0; i < props.Length; i++) {
+ ///
+ /// Writes back the values changes of the underlying registers to the corrosponding property
+ ///
+ private void OnRegisterChangedUpdateProps(IRegisterInternal reg) {
- var prop = props[i];
- var bitWiseFound = prop.GetCustomAttributes(true)
- .FirstOrDefault(y => y.GetType() == typeof(RegisterAttribute) && ((RegisterAttribute)y).MemoryArea == reg.MemoryAddress);
+ var collection = reg.ContainedCollection;
+ if (collection == null) return;
- if (bitWiseFound != null) {
+ var props = collection.GetType().GetProperties();
- var casted = (RegisterAttribute)bitWiseFound;
- var bitIndex = casted.AssignedBitIndex;
+ //set the specific bit array if needed
+ //prop.SetValue(collection, bitAr);
+ //collection.TriggerPropertyChanged(prop.Name);
- BitArray bitAr = null;
- if (reg is NumberRegister reg16) {
- var bytes = BitConverter.GetBytes((short)reg16.Value);
- bitAr = new BitArray(bytes);
- } else if (reg is NumberRegister reg32) {
- var bytes = BitConverter.GetBytes((int)reg32.Value);
- bitAr = new BitArray(bytes);
- }
-
- if (bitAr != null && bitIndex < bitAr.Length && bitIndex >= 0) {
-
- //set the specific bit index if needed
- prop.SetValue(collection, bitAr[bitIndex]);
- collection.TriggerPropertyChanged(prop.Name);
-
- } else if (bitAr != null) {
-
- //set the specific bit array if needed
- prop.SetValue(collection, bitAr);
- collection.TriggerPropertyChanged(prop.Name);
-
- }
-
- }
-
- }
-
- }
-
- //updating normal properties
- var foundToUpdate = props.FirstOrDefault(x => x.Name == reg.Name);
-
- if (foundToUpdate != null) {
-
- var foundAttributes = foundToUpdate.GetCustomAttributes(true);
- var foundAttr = foundAttributes.FirstOrDefault(x => x.GetType() == typeof(RegisterAttribute));
-
- if (foundAttr == null)
- return;
-
- var registerAttr = (RegisterAttribute)foundAttr;
-
- //check if bit parse mode
- if (registerAttr.AssignedBitIndex == -1) {
-
- HashSet NumericTypes = new HashSet {
- typeof(bool),
- typeof(short),
- typeof(ushort),
- typeof(int),
- typeof(uint),
- typeof(float),
- typeof(TimeSpan),
- typeof(string)
- };
-
- var regValue = ((IRegister)reg).Value;
-
- if (NumericTypes.Any(x => foundToUpdate.PropertyType == x)) {
- foundToUpdate.SetValue(collection, regValue);
- }
-
- if (foundToUpdate.PropertyType.IsEnum) {
- foundToUpdate.SetValue(collection, regValue);
- }
-
- }
-
- collection.TriggerPropertyChanged(foundToUpdate.Name);
-
- }
-
- };
-
- if (collection != null)
- collection.OnInterfaceLinked(this);
-
- Connected += (i) => {
- if (collection != null)
- collection.OnInterfaceLinkedAndOnline(this);
- };
-
- return this;
}
@@ -349,10 +292,10 @@ namespace MewtocolNet {
#region Register Adding
///
- public void AddRegister(IRegister register) => AddRegister(register as BaseRegister);
+ public void AddRegister (IRegister register) => AddRegister(register as BaseRegister);
///
- public void AddRegister(BaseRegister register) {
+ public void AddRegister (BaseRegister register) {
if (CheckDuplicateRegister(register))
throw MewtocolException.DupeRegister(register);
@@ -368,28 +311,56 @@ namespace MewtocolNet {
}
- internal void AddRegister (RegisterBuildInfo buildInfo) {
+ // Used for internal property based register building
+ internal void AddRegisters (List buildInfos) {
- var builtRegister = buildInfo.Build();
+ //build all from attribute
+ List registers = new List();
- //is bitwise and the register list already contains that area register
- if(builtRegister.GetType() == typeof(BytesRegister) && CheckDuplicateRegister(builtRegister, out var existing)) {
+ foreach (var buildInfo in buildInfos) {
- return;
+ var builtRegister = buildInfo.BuildForCollectionAttribute();
+
+ int? linkLen = null;
+
+ if(builtRegister is BytesRegister bReg) {
+
+ linkLen = (int?)bReg.ReservedBytesSize ?? bReg.ReservedBitSize;
+
+ }
+
+ //attach the property and collection
+ builtRegister.WithBoundProperty(new RegisterPropTarget {
+ BoundProperty = buildInfo.boundPropTarget,
+ LinkLength = linkLen,
+ });
+
+ builtRegister.WithRegisterCollection(buildInfo.collectionTarget);
+
+ builtRegister.attachedInterface = this;
+ registers.Add(builtRegister);
}
- if (CheckDuplicateRegister(builtRegister))
- throw MewtocolException.DupeRegister(builtRegister);
+ //order by address
+ registers = registers.OrderBy(x => x.GetSpecialAddress()).ToList();
+ registers = registers.OrderBy(x => x.MemoryAddress).ToList();
- if(CheckDuplicateNameRegister(builtRegister))
- throw MewtocolException.DupeNameRegister(builtRegister);
+ //link to memory manager
+ for (int i = 0, j = 0; i < registers.Count; i++) {
- if (CheckOverlappingRegister(builtRegister, out var regB))
- throw MewtocolException.OverlappingRegister(builtRegister, regB);
+ BaseRegister reg = registers[i];
+ reg.name = $"auto_prop_register_{j + 1}";
- builtRegister.attachedInterface = this;
- RegistersUnderlying.Add(builtRegister);
+ //link the memory area to the register
+ if (memoryManager.LinkRegister(reg)) {
+
+ RegistersUnderlying.Add(reg);
+ j++;
+
+ }
+
+ }
}
@@ -480,7 +451,6 @@ namespace MewtocolNet {
}
-
internal void PropertyRegisterWasSet(string propName, object value) {
_ = SetRegisterAsync(GetRegister(propName), value);
diff --git a/MewtocolNet/MewtocolInterfaceRequests.cs b/MewtocolNet/MewtocolInterfaceRequests.cs
index 6e3f7d7..7dadf6a 100644
--- a/MewtocolNet/MewtocolInterfaceRequests.cs
+++ b/MewtocolNet/MewtocolInterfaceRequests.cs
@@ -12,7 +12,7 @@ using System.Threading.Tasks;
namespace MewtocolNet {
- public partial class MewtocolInterface {
+ public abstract partial class MewtocolInterface {
#region PLC info getters
diff --git a/MewtocolNet/MewtocolInterfaceSerial.cs b/MewtocolNet/MewtocolInterfaceSerial.cs
index 62abbc8..008d385 100644
--- a/MewtocolNet/MewtocolInterfaceSerial.cs
+++ b/MewtocolNet/MewtocolInterfaceSerial.cs
@@ -14,7 +14,7 @@ using MewtocolNet.RegisterAttributes;
namespace MewtocolNet {
- public class MewtocolInterfaceSerial : MewtocolInterface, IPlcSerial {
+ public sealed class MewtocolInterfaceSerial : MewtocolInterface, IPlcSerial {
private bool autoSerial;
@@ -50,13 +50,6 @@ namespace MewtocolNet {
}
- public IPlcSerial AddRegisterCollection (RegisterCollection collection) {
-
- WithRegisterCollection(collection);
- return this;
-
- }
-
///
public override string GetConnectionInfo() {
diff --git a/MewtocolNet/MewtocolInterfaceTcp.cs b/MewtocolNet/MewtocolInterfaceTcp.cs
index f90181b..c047f11 100644
--- a/MewtocolNet/MewtocolInterfaceTcp.cs
+++ b/MewtocolNet/MewtocolInterfaceTcp.cs
@@ -11,7 +11,7 @@ namespace MewtocolNet {
///
/// The PLC com interface class
///
- public class MewtocolInterfaceTcp : MewtocolInterface, IPlcEthernet {
+ public sealed class MewtocolInterfaceTcp : MewtocolInterface, IPlcEthernet {
//TCP
internal TcpClient client;
@@ -29,22 +29,6 @@ namespace MewtocolNet {
internal MewtocolInterfaceTcp () : base() { }
- ///
- public IPlcEthernet WithPoller () {
-
- usePoller = true;
- return this;
-
- }
-
- ///
- public IPlcEthernet AddRegisterCollection (RegisterCollection collection) {
-
- WithRegisterCollection(collection);
- return this;
-
- }
-
#region TCP connection state handling
///
diff --git a/MewtocolNet/RegisterAttributes/PollFrequencyAttribute.cs b/MewtocolNet/RegisterAttributes/PollFrequencyAttribute.cs
new file mode 100644
index 0000000..981e3ee
--- /dev/null
+++ b/MewtocolNet/RegisterAttributes/PollFrequencyAttribute.cs
@@ -0,0 +1,20 @@
+using System;
+
+namespace MewtocolNet.RegisterAttributes {
+ ///
+ /// Defines the behavior of a register property
+ ///
+ [AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]
+ public class PollFrequencyAttribute : Attribute {
+
+ internal int skipEachCycle;
+
+ public PollFrequencyAttribute(int eachCycleN) {
+
+ skipEachCycle = eachCycleN;
+
+ }
+
+ }
+
+}
diff --git a/MewtocolNet/RegisterAttributes/RegisterAttribute.cs b/MewtocolNet/RegisterAttributes/RegisterAttribute.cs
index a08b29a..5546f82 100644
--- a/MewtocolNet/RegisterAttributes/RegisterAttribute.cs
+++ b/MewtocolNet/RegisterAttributes/RegisterAttribute.cs
@@ -9,13 +9,6 @@ namespace MewtocolNet.RegisterAttributes {
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]
public class RegisterAttribute : Attribute {
- internal RegisterType? RegisterType;
-
- internal uint MemoryArea = 0;
- internal uint ByteLength = 2;
- internal byte SpecialAddress = 0x0;
-
- internal BitCount BitCount;
internal int AssignedBitIndex = -1;
internal string MewAddress = null;
@@ -26,65 +19,6 @@ namespace MewtocolNet.RegisterAttributes {
}
- ///
- /// Attribute for string type or numeric registers
- ///
- /// The area in the plcs memory
- public RegisterAttribute(uint memoryArea) {
-
- MemoryArea = memoryArea;
-
- }
-
- public RegisterAttribute(uint memoryArea, uint byteLength) {
-
- MemoryArea = memoryArea;
- ByteLength = byteLength;
-
- }
-
- public RegisterAttribute(uint memoryArea, BitCount bitCount) {
-
- MemoryArea = memoryArea;
- BitCount = bitCount;
- AssignedBitIndex = 0;
-
- RegisterType = BitCount == BitCount.B16 ? MewtocolNet.RegisterType.DT : MewtocolNet.RegisterType.DDT;
-
- }
-
- public RegisterAttribute(uint memoryArea, BitCount bitCount, int bitIndex) {
-
- MemoryArea = memoryArea;
- BitCount = bitCount;
- AssignedBitIndex = bitIndex;
-
- RegisterType = BitCount == BitCount.B16 ? MewtocolNet.RegisterType.DT : MewtocolNet.RegisterType.DDT;
-
- }
-
- ///
- /// Attribute for boolean registers
- ///
- public RegisterAttribute(IOType type, byte spAdress = 0x0) {
-
- MemoryArea = 0;
- RegisterType = (RegisterType)(int)type;
- SpecialAddress = spAdress;
-
- }
-
- ///
- /// Attribute for boolean registers
- ///
- public RegisterAttribute(IOType type, uint memoryArea, byte spAdress = 0x0) {
-
- MemoryArea = memoryArea;
- RegisterType = (RegisterType)(int)type;
- SpecialAddress = spAdress;
-
- }
-
}
}
diff --git a/MewtocolNet/RegisterAttributes/RegisterCollectionCollector.cs b/MewtocolNet/RegisterAttributes/RegisterCollectionCollector.cs
new file mode 100644
index 0000000..e7ce46e
--- /dev/null
+++ b/MewtocolNet/RegisterAttributes/RegisterCollectionCollector.cs
@@ -0,0 +1,31 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace MewtocolNet.RegisterAttributes {
+
+ public class RegisterCollectionCollector {
+
+ internal List collections = new List();
+
+ public RegisterCollectionCollector AddCollection (RegisterCollection collection) {
+
+ collections.Add(collection);
+
+ return this;
+
+ }
+
+ public RegisterCollectionCollector AddCollection () where T : RegisterCollection {
+
+ var instance = (RegisterCollection)Activator.CreateInstance(typeof(T));
+
+ collections.Add(instance);
+
+ return this;
+
+ }
+
+ }
+
+}
diff --git a/MewtocolNet/RegisterAttributes/RegisterPropTarget.cs b/MewtocolNet/RegisterAttributes/RegisterPropTarget.cs
new file mode 100644
index 0000000..4468440
--- /dev/null
+++ b/MewtocolNet/RegisterAttributes/RegisterPropTarget.cs
@@ -0,0 +1,26 @@
+using System.Reflection;
+using System.Text;
+
+namespace MewtocolNet.RegisterAttributes {
+
+ internal class RegisterPropTarget {
+
+ //propinfo of the bound property
+ internal PropertyInfo BoundProperty;
+
+ //general number of bits or bytes to read back to the prop
+ internal int? LinkLength;
+
+ public override string ToString() {
+
+ var sb = new StringBuilder();
+ sb.Append($"{BoundProperty}");
+ if(LinkLength != null) sb.Append($" -Len: {LinkLength}");
+
+ return sb.ToString();
+
+ }
+
+ }
+
+}
diff --git a/MewtocolNet/RegisterBuilding/RegisterBuildInfo.cs b/MewtocolNet/RegisterBuilding/RegisterBuildInfo.cs
index e6b8de3..bfd9ad5 100644
--- a/MewtocolNet/RegisterBuilding/RegisterBuildInfo.cs
+++ b/MewtocolNet/RegisterBuilding/RegisterBuildInfo.cs
@@ -1,4 +1,5 @@
using MewtocolNet.Exceptions;
+using MewtocolNet.RegisterAttributes;
using MewtocolNet.Registers;
using System;
using System.Collections;
@@ -20,14 +21,20 @@ namespace MewtocolNet.RegisterBuilding {
internal byte? specialAddress;
internal RegisterType? registerType;
+
internal Type dotnetCastType;
- internal Type collectionType;
+
+ internal RegisterCollection collectionTarget;
+ internal PropertyInfo boundPropTarget;
+
+ internal BaseRegister BuildForCollectionAttribute () {
+
+ return (BaseRegister)RegBuilder.Factory.FromPlcRegName(mewAddress, name).AsType(dotnetCastType).Build();
+
+ }
internal BaseRegister Build () {
- //Has mew address use this before the default checks
- if (mewAddress != null) return BuildFromMewAddress();
-
//parse enums
if (dotnetCastType.IsEnum) {
@@ -46,8 +53,8 @@ namespace MewtocolNet.RegisterBuilding {
var parameters = new object[] { memoryAddress, name };
var instance = (BaseRegister)constr.Invoke(parameters);
- if (collectionType != null)
- instance.WithCollectionType(collectionType);
+ if (collectionTarget != null)
+ instance.WithRegisterCollection(collectionTarget);
return instance;
@@ -56,22 +63,18 @@ namespace MewtocolNet.RegisterBuilding {
//parse all others where the type is known
RegisterType regType = registerType ?? dotnetCastType.ToRegisterTypeDefault();
Type registerClassType = dotnetCastType.GetDefaultRegisterHoldingType();
- bool isBytesRegister = !registerClassType.IsGenericType && registerClassType == typeof(BytesRegister);
+
+ bool isBoolRegister = regType.IsBoolean();
+
+ bool isBytesArrRegister = !registerClassType.IsGenericType && registerClassType == typeof(BytesRegister) && dotnetCastType == typeof(byte[]);
+
+ bool isBytesBitsRegister = !registerClassType.IsGenericType && registerClassType == typeof(BytesRegister) && dotnetCastType == typeof(BitArray);
+
bool isStringRegister = !registerClassType.IsGenericType && registerClassType == typeof(StringRegister);
- if (regType.IsNumericDTDDT() && (dotnetCastType == typeof(bool))) {
+ bool isNormalNumericResiter = regType.IsNumericDTDDT() && !isBytesArrRegister && !isBytesBitsRegister && !isStringRegister;
- //-------------------------------------------
- //as numeric register with boolean bit target
- //create a new bregister instance
- var instance = new BytesRegister(memoryAddress, memorySizeBytes.Value, name);
-
- if (collectionType != null)
- instance.WithCollectionType(collectionType);
-
- return instance;
-
- } else if (regType.IsNumericDTDDT() && !isBytesRegister && !isStringRegister) {
+ if (isNormalNumericResiter) {
//-------------------------------------------
//as numeric register
@@ -83,28 +86,43 @@ namespace MewtocolNet.RegisterBuilding {
var parameters = new object[] { memoryAddress, name };
var instance = (BaseRegister)Activator.CreateInstance(registerClassType, flags, null, parameters, null);
- if(collectionType != null)
- instance.WithCollectionType(collectionType);
+ if(collectionTarget != null)
+ instance.WithRegisterCollection(collectionTarget);
return instance;
}
- if(isBytesRegister) {
+ if(isBytesArrRegister) {
//-------------------------------------------
//as byte range register
+ BytesRegister instance = new BytesRegister(memoryAddress, memorySizeBytes.Value, name);
+ instance.ReservedBytesSize = (ushort)memorySizeBytes.Value;
+
+ if (collectionTarget != null)
+ instance.WithRegisterCollection(collectionTarget);
+
+ return instance;
+
+ }
+
+ if(isBytesBitsRegister) {
+
+ //-------------------------------------------
+ //as bit range register
+
BytesRegister instance;
- if(memorySizeBits != null) {
+ if (memorySizeBits != null) {
instance = new BytesRegister(memoryAddress, memorySizeBits.Value, name);
} else {
- instance = new BytesRegister(memoryAddress, memorySizeBytes.Value, name);
+ instance = new BytesRegister(memoryAddress, 16, name);
}
- if (collectionType != null)
- instance.WithCollectionType(collectionType);
+ if (collectionTarget != null)
+ instance.WithRegisterCollection(collectionTarget);
return instance;
@@ -116,14 +134,14 @@ namespace MewtocolNet.RegisterBuilding {
//as byte range register
var instance = (BaseRegister)new StringRegister(memoryAddress, name);
- if (collectionType != null)
- instance.WithCollectionType(collectionType);
+ if (collectionTarget != null)
+ instance.WithRegisterCollection(collectionTarget);
return instance;
}
- if (regType.IsBoolean()) {
+ if (isBoolRegister) {
//-------------------------------------------
//as boolean register
@@ -134,8 +152,8 @@ namespace MewtocolNet.RegisterBuilding {
var instance = new BoolRegister(io, spAddr.Value, areaAddr, name);
- if (collectionType != null)
- ((IRegisterInternal)instance).WithCollectionType(collectionType);
+ if (collectionTarget != null)
+ instance.WithRegisterCollection(collectionTarget);
return instance;
@@ -145,12 +163,6 @@ namespace MewtocolNet.RegisterBuilding {
}
- private BaseRegister BuildFromMewAddress () {
-
- return (BaseRegister)RegBuilder.Factory.FromPlcRegName(mewAddress, name).AsType(dotnetCastType).Build();
-
- }
-
}
}
diff --git a/MewtocolNet/Registers/BaseRegister.cs b/MewtocolNet/Registers/BaseRegister.cs
index ac3f8d5..8388d95 100644
--- a/MewtocolNet/Registers/BaseRegister.cs
+++ b/MewtocolNet/Registers/BaseRegister.cs
@@ -1,5 +1,9 @@
-using System;
+using MewtocolNet.RegisterAttributes;
+using MewtocolNet.UnderlyingRegisters;
+using System;
+using System.Collections.Generic;
using System.ComponentModel;
+using System.Reflection;
using System.Text;
using System.Threading.Tasks;
@@ -12,12 +16,19 @@ namespace MewtocolNet.Registers {
///
public event Action