diff --git a/MewtocolNet/MewtocolInterfaceRegisterHandling.cs b/MewtocolNet/MewtocolInterfaceRegisterHandling.cs
index 17d962b..27be26b 100644
--- a/MewtocolNet/MewtocolInterfaceRegisterHandling.cs
+++ b/MewtocolNet/MewtocolInterfaceRegisterHandling.cs
@@ -393,7 +393,7 @@ namespace MewtocolNet {
Register = reg,
PreviousValue = preValue,
PreviousValueString = preValueString,
- Value = reg.Value,
+ Value = reg.ValueObj,
});
}
diff --git a/MewtocolNet/MewtocolInterfaceRequests.cs b/MewtocolNet/MewtocolInterfaceRequests.cs
index 7b6c6f2..51769a2 100644
--- a/MewtocolNet/MewtocolInterfaceRequests.cs
+++ b/MewtocolNet/MewtocolInterfaceRequests.cs
@@ -108,6 +108,9 @@ namespace MewtocolNet {
///
public async Task WriteByteRange(int start, byte[] byteArr) {
+ if (byteArr == null)
+ throw new ArgumentNullException(nameof(byteArr));
+
string byteString = byteArr.ToHexString();
var wordLength = byteArr.Length / 2;
diff --git a/MewtocolNet/RegisterAttributes/RegisterCollection.cs b/MewtocolNet/RegisterAttributes/RegisterCollection.cs
index 5217e8a..b05bc5a 100644
--- a/MewtocolNet/RegisterAttributes/RegisterCollection.cs
+++ b/MewtocolNet/RegisterAttributes/RegisterCollection.cs
@@ -37,7 +37,7 @@ namespace MewtocolNet.RegisterAttributes {
if (value is IRegister reg) {
- privateField = (T)reg.Value;
+ privateField = (T)reg.ValueObj;
return;
}
diff --git a/MewtocolNet/RegisterBuilding/RBuildAnon.cs b/MewtocolNet/RegisterBuilding/RBuildAnon.cs
index 40ab58f..2c0198c 100644
--- a/MewtocolNet/RegisterBuilding/RBuildAnon.cs
+++ b/MewtocolNet/RegisterBuilding/RBuildAnon.cs
@@ -1,4 +1,5 @@
-using MewtocolNet.Registers;
+using System;
+using MewtocolNet.Registers;
using System.Threading.Tasks;
namespace MewtocolNet.RegisterBuilding {
@@ -33,16 +34,18 @@ namespace MewtocolNet.RegisterBuilding {
/// True if success
public async Task WriteToAsync(T value) {
- try {
+ throw new NotImplementedException();
- var tempRegister = AssembleTemporaryRegister();
- return await tempRegister.WriteAsync(value);
+ //try {
- } catch {
+ // var tempRegister = AssembleTemporaryRegister();
+ // return await tempRegister.WriteAsync(value);
- throw;
+ //} catch {
- }
+ // throw;
+
+ //}
}
@@ -52,16 +55,18 @@ namespace MewtocolNet.RegisterBuilding {
/// The value read or null if failed
public async Task ReadFromAsync() {
- try {
+ throw new NotImplementedException();
- var tempRegister = AssembleTemporaryRegister();
- return (T)await tempRegister.ReadAsync();
+ //try {
- } catch {
+ // var tempRegister = AssembleTemporaryRegister();
+ // return (T)await tempRegister.ReadAsync();
- throw;
+ //} catch {
- }
+ // throw;
+
+ //}
}
diff --git a/MewtocolNet/RegisterBuilding/RBuildBase.cs b/MewtocolNet/RegisterBuilding/RBuildBase.cs
index 97d6ca2..f0d6641 100644
--- a/MewtocolNet/RegisterBuilding/RBuildBase.cs
+++ b/MewtocolNet/RegisterBuilding/RBuildBase.cs
@@ -16,7 +16,7 @@ namespace MewtocolNet.RegisterBuilding {
internal RBuildBase(MewtocolInterface plc) => attachedPLC = plc;
- internal List unfinishedList = new List();
+ internal List unfinishedList = new List();
#region Parser stage
@@ -50,7 +50,7 @@ namespace MewtocolNet.RegisterBuilding {
internal string hardFailReason;
- internal StepData stepData;
+ internal BaseStepData stepData;
}
@@ -277,9 +277,7 @@ namespace MewtocolNet.RegisterBuilding {
res.stepData.originalParseStr = plcAddrName;
res.stepData.buildSource = RegisterBuildSource.Manual;
- unfinishedList.Add(res.stepData);
-
- return res.stepData;
+ return new StepData().Map(res.stepData);
} else if (res.state == ParseResultState.FailedHard) {
@@ -305,7 +303,7 @@ namespace MewtocolNet.RegisterBuilding {
///
///
///
- public TypedRegister AsType() {
+ internal TypedRegister AsType() {
if (!typeof(T).IsAllowedPlcCastingType()) {
@@ -326,7 +324,7 @@ namespace MewtocolNet.RegisterBuilding {
///
///
///
- public TypedRegister AsType(Type type) {
+ internal TypedRegister AsType(Type type) {
//was ranged syntax array build
if (Data.wasAddressStringRangeBased && type.IsArray && type.GetArrayRank() == 1) {
@@ -395,7 +393,7 @@ namespace MewtocolNet.RegisterBuilding {
///
/// Sets the register type as a predefined
///
- public TypedRegister AsType(PlcVarType type) {
+ internal TypedRegister AsType(PlcVarType type) {
Data.dotnetVarType = type.GetDefaultDotnetType();
@@ -420,7 +418,7 @@ namespace MewtocolNet.RegisterBuilding {
/// - DWORD32 bit double word interpreted as
///
///
- public TypedRegister AsType(string type) {
+ internal TypedRegister AsType(string type) {
var regexString = new Regex(@"^STRING *\[(?[0-9]*)\]$", RegexOptions.IgnoreCase);
var regexArray = new Regex(@"^ARRAY *\[(?[0-9]*)..(?[0-9]*)(?:\,(?[0-9]*)..(?[0-9]*))?(?:\,(?[0-9]*)..(?[0-9]*))?\] *OF {1,}(?.*)$", RegexOptions.IgnoreCase);
@@ -520,7 +518,7 @@ namespace MewtocolNet.RegisterBuilding {
/// ARRAY [0..2, 0..3, 0..4] OF INT = AsTypeArray<short[,,]>(3,4,5)
/// ARRAY [5..6, 0..2] OF DWORD = AsTypeArray<DWord[,]>(2, 3)
///
- public TypedRegister AsTypeArray(params int[] indicies) {
+ internal TypedRegister AsTypeArray(params int[] indicies) {
if (!typeof(T).IsArray)
throw new NotSupportedException($"The type {typeof(T)} was no array");
diff --git a/MewtocolNet/RegisterBuilding/RBuildMult.cs b/MewtocolNet/RegisterBuilding/RBuildMult.cs
index 84613ba..311c1d9 100644
--- a/MewtocolNet/RegisterBuilding/RBuildMult.cs
+++ b/MewtocolNet/RegisterBuilding/RBuildMult.cs
@@ -15,6 +15,8 @@ namespace MewtocolNet.RegisterBuilding {
#region String parse stage
+ //at runtime constructor
+
///
/// Starts the register builder for a new mewtocol address
/// Examples:
@@ -26,6 +28,8 @@ namespace MewtocolNet.RegisterBuilding {
var data = ParseAddress(plcAddrName, name);
+ unfinishedList.Add(data);
+
return new SAddress {
Data = data,
builder = this,
@@ -33,6 +37,68 @@ namespace MewtocolNet.RegisterBuilding {
}
+ //struct constructor
+
+ public SAddressStruct Address(string plcAddrName, string name = null) where T : struct {
+
+ var data = ParseAddress(plcAddrName, name);
+
+ data.dotnetVarType = typeof(T);
+
+ unfinishedList.Add(data);
+
+ return new SAddressStruct(data) {
+ builder = this,
+ };
+
+ }
+
+ public SAddressString AddressString(string plcAddrName, int sizeHint, string name = null) where T : class {
+
+ var data = ParseAddress(plcAddrName, name);
+
+ data.dotnetVarType = typeof(T);
+
+ unfinishedList.Add(data);
+
+ if (typeof(T).IsArray) {
+
+ return new SAddressString(data, true) {
+ Data = data,
+ builder = this,
+ };
+
+ }
+
+ return new SAddressString(data) {
+ builder = this,
+ };
+
+ }
+
+ public SAddressArray AddressArray(string plcAddrName, string name = null) where T : class {
+
+ var data = ParseAddress(plcAddrName, name);
+
+ data.dotnetVarType = typeof(T);
+
+ unfinishedList.Add(data);
+
+ if (typeof(T).IsArray) {
+
+ return new SAddressArray(data, true) {
+ Data = data,
+ builder = this,
+ };
+
+ }
+
+ return new SAddressArray(data) {
+ builder = this,
+ };
+
+ }
+
//internal use only, adds a type definition (for use when building from attibute)
internal SAddress AddressFromAttribute(string plcAddrName, string typeDef, RegisterCollection regCol, PropertyInfo prop, uint? bytesizeHint = null) {
@@ -52,6 +118,7 @@ namespace MewtocolNet.RegisterBuilding {
#region Typing stage
+ //non generic
public new class SAddress : RBuildBase.SAddress {
public new TypedRegister AsType() => new TypedRegister().Map(base.AsType());
@@ -64,9 +131,95 @@ namespace MewtocolNet.RegisterBuilding {
public new TypedRegister AsTypeArray(params int[] indicies) => new TypedRegister().Map(base.AsTypeArray(indicies));
+ }
+
+ //structs
+ public class SAddressStruct : RBuildBase.SAddress where T : struct {
+
+ internal SAddressStruct(StepData data) {
+
+ this.Data = data;
+
+ this.Map(AsType(typeof(T)));
+
+ }
+
+ internal SAddressStruct(StepData data, bool arrayed) {
+
+ this.Data = data;
+
+ }
+
+ ///
+ /// Outputs the generated
+ ///
+ public void Out(Action> registerOut) {
+
+ Data.registerOut = new Action
public void Out(Action registerOut) {
- Data.registerOut = registerOut;
+ Data.registerOut = (Action)registerOut;
}
@@ -103,7 +256,7 @@ namespace MewtocolNet.RegisterBuilding {
///
public void Out(Action registerOut) {
- Data.registerOut = registerOut;
+ Data.registerOut = (Action)registerOut;
}
@@ -118,7 +271,7 @@ namespace MewtocolNet.RegisterBuilding {
///
public void Out(Action registerOut) {
- Data.registerOut = registerOut;
+ Data.registerOut = (Action)registerOut;
}
diff --git a/MewtocolNet/RegisterBuilding/RegisterAssembler.cs b/MewtocolNet/RegisterBuilding/RegisterAssembler.cs
index 0f101fb..c70dbe3 100644
--- a/MewtocolNet/RegisterBuilding/RegisterAssembler.cs
+++ b/MewtocolNet/RegisterBuilding/RegisterAssembler.cs
@@ -28,7 +28,8 @@ namespace MewtocolNet.RegisterBuilding {
var generatedInstance = Assemble(data);
generatedInstance.autoGenerated = flagAutoGenerated;
- data.registerOut?.Invoke(generatedInstance);
+
+ data?.InvokeBuilt(generatedInstance);
generatedInstances.Add(generatedInstance);
@@ -38,7 +39,7 @@ namespace MewtocolNet.RegisterBuilding {
}
- internal Register Assemble(StepData data) {
+ internal Register Assemble(BaseStepData data) {
Register generatedInstance = null;
@@ -114,7 +115,7 @@ namespace MewtocolNet.RegisterBuilding {
var flags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance;
- Type paramedClass = typeof(SingleRegister<>).MakeGenericType(data.dotnetVarType);
+ Type paramedClass = typeof(StructRegister<>).MakeGenericType(data.dotnetVarType);
ConstructorInfo constr = paramedClass.GetConstructor(flags, null, new Type[] {
typeof(uint), typeof(uint) ,typeof(string)
}, null);
diff --git a/MewtocolNet/RegisterBuilding/StepData.cs b/MewtocolNet/RegisterBuilding/StepData.cs
index 2b44007..35ee44b 100644
--- a/MewtocolNet/RegisterBuilding/StepData.cs
+++ b/MewtocolNet/RegisterBuilding/StepData.cs
@@ -6,10 +6,9 @@ using System.Reflection;
namespace MewtocolNet.RegisterBuilding {
- internal class StepData {
+ internal class BaseStepData {
- //for referencing the output at builder level
- internal Action registerOut;
+ internal Action registerOut;
internal RegisterBuildSource buildSource = RegisterBuildSource.Anonymous;
@@ -34,6 +33,40 @@ namespace MewtocolNet.RegisterBuilding {
internal string typeDef;
+ internal void InvokeBuilt(Register reg) {
+
+ registerOut.Invoke(reg);
+
+ //var selftype = this.GetType();
+
+ //if ((selftype.IsGenericType && selftype.GetGenericTypeDefinition() == typeof(StepData<>))) {
+
+ // var field = selftype.GetField("registerOut", BindingFlags.NonPublic | BindingFlags.Instance);
+
+ // var generic = typeof(IRegister<>).MakeGenericType()
+
+ // var action = Action.CreateDelegate(typeof(IRegister));
+
+ // field.SetValue(this,);
+
+ //}
+
+ }
+
+ }
+
+ internal class StepData : BaseStepData {
+
+ //for referencing the output at builder level
+ //internal Action> registerOut;
+
+ }
+
+ internal class StepData : BaseStepData {
+
+ //for referencing the output at builder level
+ //internal Action registerOut;
+
}
}
diff --git a/MewtocolNet/Registers/ArrayRegister.cs b/MewtocolNet/Registers/ArrayRegister.cs
index 085f0ec..7413841 100644
--- a/MewtocolNet/Registers/ArrayRegister.cs
+++ b/MewtocolNet/Registers/ArrayRegister.cs
@@ -10,7 +10,7 @@ namespace MewtocolNet.Registers {
///
/// Defines a register containing a string
///
- public class ArrayRegister : Register {
+ public class ArrayRegister : Register, IArrayRegister {
internal int[] indices;
@@ -21,6 +21,8 @@ namespace MewtocolNet.Registers {
///
public uint AddressLength => addressLength;
+ public T[] Value => (T[])ValueObj;
+
[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");
@@ -47,16 +49,16 @@ namespace MewtocolNet.Registers {
public override string GetValueString() {
- if (Value == null) return "null";
+ if (ValueObj == null) return "null";
if(typeof(T) == typeof(byte[])) {
- return ((byte[])Value).ToHexString("-");
+ return ((byte[])ValueObj).ToHexString("-");
}
StringBuilder sb = new StringBuilder();
- var valueIenum = (IEnumerable)Value;
+ var valueIenum = (IEnumerable)ValueObj;
foreach (var el in valueIenum) {
@@ -64,7 +66,7 @@ namespace MewtocolNet.Registers {
}
- return ArrayToString((Array)Value);
+ return ArrayToString((Array)ValueObj);
}
@@ -75,9 +77,9 @@ namespace MewtocolNet.Registers {
public override uint GetRegisterAddressLen() => AddressLength;
///
- public override async Task WriteAsync(object value) {
+ public async Task WriteAsync(T value) {
- var encoded = PlcValueParser.Encode(this, (T)value);
+ var encoded = PlcValueParser.EncodeArray(this, value);
var res = await attachedInterface.WriteByteRange((int)MemoryAddress, encoded);
if (res) {
@@ -99,18 +101,18 @@ namespace MewtocolNet.Registers {
}
///
- public override async Task ReadAsync() {
+ async Task IArrayRegister.ReadAsync() {
var res = await attachedInterface.ReadByteRangeNonBlocking((int)MemoryAddress, (int)GetRegisterAddressLen() * 2);
- if (res == null) return null;
+ if (res == null) throw new Exception();
- //var matchingReg = attachedInterface.memoryManager.GetAllRegisters()
- //.FirstOrDefault(x => x.IsSameAddressAndType(this));
+ var matchingReg = attachedInterface.memoryManager.GetAllRegisters()
+ .FirstOrDefault(x => x.IsSameAddressAndType(this));
- //if (matchingReg != null)
- // matchingReg.underlyingMemory.SetUnderlyingBytes(matchingReg, res);
+ if (matchingReg != null)
+ matchingReg.underlyingMemory.SetUnderlyingBytes(matchingReg, res);
- return SetValueFromBytes(res);
+ return (T[])SetValueFromBytes(res);
}
diff --git a/MewtocolNet/Registers/Base/IArrayRegister.cs b/MewtocolNet/Registers/Base/IArrayRegister.cs
new file mode 100644
index 0000000..7cdb364
--- /dev/null
+++ b/MewtocolNet/Registers/Base/IArrayRegister.cs
@@ -0,0 +1,26 @@
+using System.Threading.Tasks;
+
+namespace MewtocolNet.Registers {
+
+ public interface IArrayRegister : IRegister {
+
+ ///
+ /// The current value of the register
+ ///
+ T[] Value { get; }
+
+ ///
+ /// Reads the register value async from the plc
+ ///
+ /// The register value
+ Task ReadAsync();
+
+ ///
+ /// Writes the register content async to the plc
+ ///
+ /// True if successfully set
+ Task WriteAsync(T data);
+
+ }
+
+}
diff --git a/MewtocolNet/Registers/Base/IRegister.cs b/MewtocolNet/Registers/Base/IRegister.cs
index fbadb7c..ebecb81 100644
--- a/MewtocolNet/Registers/Base/IRegister.cs
+++ b/MewtocolNet/Registers/Base/IRegister.cs
@@ -32,7 +32,7 @@ namespace MewtocolNet.Registers {
///
/// The current value of the register
///
- object Value { get; }
+ object ValueObj { get; }
///
/// The plc memory address of the register
@@ -55,18 +55,6 @@ namespace MewtocolNet.Registers {
///
string ToString(bool detailed);
- ///
- /// Reads the register value async from the plc
- ///
- /// The register value
- Task ReadAsync();
-
- ///
- /// Writes the register content async to the plc
- ///
- /// True if successfully set
- Task WriteAsync(object data);
-
}
}
diff --git a/MewtocolNet/Registers/Base/IRegisterT.cs b/MewtocolNet/Registers/Base/IRegisterT.cs
new file mode 100644
index 0000000..6ffa350
--- /dev/null
+++ b/MewtocolNet/Registers/Base/IRegisterT.cs
@@ -0,0 +1,31 @@
+using System;
+using System.Threading.Tasks;
+using MewtocolNet.Events;
+
+namespace MewtocolNet.Registers {
+
+ ///
+ /// An interface for all register types
+ ///
+ public interface IRegister : IRegister where T : struct {
+
+ ///
+ /// The current value of the register
+ ///
+ T? Value { get; }
+
+ ///
+ /// Reads the register value async from the plc
+ ///
+ /// The register value
+ Task ReadAsync();
+
+ ///
+ /// Writes the register content async to the plc
+ ///
+ /// True if successfully set
+ Task WriteAsync(T data);
+
+ }
+
+}
diff --git a/MewtocolNet/Registers/Base/IStringRegister.cs b/MewtocolNet/Registers/Base/IStringRegister.cs
new file mode 100644
index 0000000..48da7a9
--- /dev/null
+++ b/MewtocolNet/Registers/Base/IStringRegister.cs
@@ -0,0 +1,25 @@
+using System.Threading.Tasks;
+
+namespace MewtocolNet.Registers {
+ public interface IStringRegister : IRegister where T : class {
+
+ ///
+ /// The current value of the register
+ ///
+ T Value { get; }
+
+ ///
+ /// Reads the register value async from the plc
+ ///
+ /// The register value
+ Task ReadAsync();
+
+ ///
+ /// Writes the register content async to the plc
+ ///
+ /// True if successfully set
+ Task WriteAsync(T data);
+
+ }
+
+}
diff --git a/MewtocolNet/Registers/Base/Register.cs b/MewtocolNet/Registers/Base/Register.cs
index 8d57d68..6ca98de 100644
--- a/MewtocolNet/Registers/Base/Register.cs
+++ b/MewtocolNet/Registers/Base/Register.cs
@@ -44,7 +44,7 @@ namespace MewtocolNet.Registers {
public MewtocolInterface AttachedInterface => attachedInterface;
///
- public object Value => lastValue;
+ public object ValueObj => lastValue;
///
public RegisterType RegisterType { get; internal set; }
@@ -62,7 +62,7 @@ namespace MewtocolNet.Registers {
public event PropertyChangedEventHandler PropertyChanged;
- public void TriggerNotifyChange() => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Value)));
+ public void TriggerNotifyChange() => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(ValueObj)));
#endregion
@@ -97,23 +97,13 @@ namespace MewtocolNet.Registers {
}
- #region Read / Write
-
- public virtual Task ReadAsync() => throw new NotImplementedException();
-
- public virtual Task WriteAsync(object data) => throw new NotImplementedException();
-
- internal virtual Task UpdateDynamicSize () => throw new NotImplementedException();
-
- #endregion
-
#region Default accessors
public virtual byte? GetSpecialAddress() => null;
- public virtual string GetValueString() => Value?.ToString() ?? "null";
+ public virtual string GetValueString() => ValueObj?.ToString() ?? "null";
- public virtual string GetAsPLC() => Value?.ToString() ?? "null";
+ public virtual string GetAsPLC() => ValueObj?.ToString() ?? "null";
public virtual string GetRegisterString() => RegisterType == RegisterType.DT_BYTE_RANGE ? "DT" : RegisterType.ToString();
@@ -202,7 +192,7 @@ namespace MewtocolNet.Registers {
sb.Append(GetMewName());
if (Name != null) sb.Append($" ({Name})");
sb.Append($" [{this.GetType().Name}({underlyingSystemType.Name})]");
- if (Value != null) sb.Append($" Val: {GetValueString()}");
+ if (ValueObj != null) sb.Append($" Val: {GetValueString()}");
return sb.ToString();
@@ -235,7 +225,7 @@ namespace MewtocolNet.Registers {
sb.Append($"Name: {Name ?? "Not named"}\n");
- if (Value != null)
+ if (ValueObj != null)
sb.Append($"Value: {GetValueString()}\n");
sb.Append($"Reads: {successfulReads}, Writes: {successfulWrites}\n");
diff --git a/MewtocolNet/Registers/SingleRegister.cs b/MewtocolNet/Registers/StructRegister.cs
similarity index 75%
rename from MewtocolNet/Registers/SingleRegister.cs
rename to MewtocolNet/Registers/StructRegister.cs
index cca4ca4..a4296f9 100644
--- a/MewtocolNet/Registers/SingleRegister.cs
+++ b/MewtocolNet/Registers/StructRegister.cs
@@ -14,7 +14,7 @@ namespace MewtocolNet.Registers {
/// Defines a register containing a number
///
/// The type of the numeric value
- public class SingleRegister : Register {
+ public class StructRegister : Register, IRegister where T : struct {
internal uint byteLength;
@@ -25,11 +25,13 @@ namespace MewtocolNet.Registers {
///
public uint AddressLength => addressLength;
+ public T? Value => (T?)ValueObj;
+
[Obsolete("Creating registers directly is not supported use IPlc.Register instead")]
- public SingleRegister() =>
+ public StructRegister() =>
throw new NotSupportedException("Direct register instancing is not supported, use the builder pattern");
- internal SingleRegister(uint _address, uint _reservedByteSize, string _name = null) {
+ internal StructRegister(uint _address, uint _reservedByteSize, string _name = null) {
memoryAddress = _address;
name = _name;
@@ -56,33 +58,33 @@ namespace MewtocolNet.Registers {
///
public override string GetAsPLC() {
- if (typeof(T) == typeof(TimeSpan)) return ((TimeSpan)Value).ToPlcTime();
+ if (typeof(T) == typeof(TimeSpan)) return ((TimeSpan)(object)ValueObj).ToPlcTime();
- return Value.ToString();
+ return ValueObj.ToString();
}
///
public override string GetValueString() {
- if (Value != null && typeof(T) == typeof(TimeSpan)) return $"{Value} [{((TimeSpan)Value).ToPlcTime()}]";
+ if (ValueObj != null && typeof(T) == typeof(TimeSpan)) return $"{ValueObj} [{((TimeSpan)(object)ValueObj).ToPlcTime()}]";
- if (Value != null && typeof(T) == typeof(Word)) return $"{Value} [{((Word)Value).ToStringBitsPlc()}]";
+ if (ValueObj != null && typeof(T) == typeof(Word)) return $"{ValueObj} [{((Word)(object)ValueObj).ToStringBitsPlc()}]";
- if (Value != null && typeof(T) == typeof(DWord)) return $"{Value} [{((DWord)Value).ToStringBitsPlc()}]";
+ if (ValueObj != null && typeof(T) == typeof(DWord)) return $"{ValueObj} [{((DWord)(object)ValueObj).ToStringBitsPlc()}]";
var hasFlags = typeof(T).GetCustomAttribute() != null;
- if (Value != null && typeof(T).IsEnum && !hasFlags) {
+ if (ValueObj != null && typeof(T).IsEnum && !hasFlags) {
var underlying = Enum.GetUnderlyingType(typeof(T));
- object val = Convert.ChangeType(Value, underlying);
- return $"{Value} [{val}]";
+ object val = Convert.ChangeType(ValueObj, underlying);
+ return $"{ValueObj} [{val}]";
}
- if (Value != null && typeof(T).IsEnum && hasFlags) return $"{Value}";
+ if (ValueObj != null && typeof(T).IsEnum && hasFlags) return $"{ValueObj}";
- return Value?.ToString() ?? "null";
+ return ValueObj?.ToString() ?? "null";
}
@@ -90,7 +92,7 @@ namespace MewtocolNet.Registers {
public override uint GetRegisterAddressLen() => AddressLength;
///
- public override async Task WriteAsync(object value) {
+ public async Task WriteAsync(T value) {
var encoded = PlcValueParser.Encode(this, (T)value);
var res = await attachedInterface.WriteByteRange((int)MemoryAddress, encoded);
@@ -114,25 +116,27 @@ namespace MewtocolNet.Registers {
}
///
- public override async Task ReadAsync() {
+ public async Task ReadAsync() {
var res = await attachedInterface.ReadByteRangeNonBlocking((int)MemoryAddress, (int)GetRegisterAddressLen() * 2);
- if (res == null) return null;
+ if (res == null) return (T?)(object)null;
var matchingReg = attachedInterface.memoryManager.GetAllRegisters()
.FirstOrDefault(x => x.IsSameAddressAndType(this));
if (matchingReg != null) {
- if (matchingReg is SingleRegister sreg && this is SingleRegister selfSreg) {
- sreg.addressLength = selfSreg.addressLength;
- }
+ //if (matchingReg is StructRegister sreg && this.GetType() == typeof(StructRegister)) {
+
+ // sreg.addressLength = selfSreg.addressLength;
+
+ //}
matchingReg.underlyingMemory.SetUnderlyingBytes(matchingReg, res);
}
- return SetValueFromBytes(res);
+ return (T)SetValueFromBytes(res);
}
diff --git a/MewtocolNet/TypeConversion/Conversions.cs b/MewtocolNet/TypeConversion/Conversions.cs
index 788ef55..1788939 100644
--- a/MewtocolNet/TypeConversion/Conversions.cs
+++ b/MewtocolNet/TypeConversion/Conversions.cs
@@ -54,7 +54,7 @@ namespace MewtocolNet.TypeConversion {
//default short DT conversion
new PlcTypeConversion(RegisterType.DT) {
- HoldingRegisterType = typeof(SingleRegister),
+ HoldingRegisterType = typeof(StructRegister),
PlcVarType = PlcVarType.INT,
FromRaw = (reg, bytes) => BitConverter.ToInt16(bytes, 0),
ToRaw = (reg, value) => BitConverter.GetBytes(value),
@@ -62,7 +62,7 @@ namespace MewtocolNet.TypeConversion {
//default ushort DT conversion
new PlcTypeConversion(RegisterType.DT) {
- HoldingRegisterType = typeof(SingleRegister),
+ HoldingRegisterType = typeof(StructRegister),
PlcVarType = PlcVarType.UINT,
FromRaw = (reg, bytes) => BitConverter.ToUInt16(bytes, 0),
ToRaw = (reg, value) => BitConverter.GetBytes(value),
@@ -70,7 +70,7 @@ namespace MewtocolNet.TypeConversion {
//default Word DT conversion
new PlcTypeConversion(RegisterType.DT) {
- HoldingRegisterType = typeof(SingleRegister),
+ HoldingRegisterType = typeof(StructRegister),
PlcVarType = PlcVarType.WORD,
FromRaw = (reg, bytes) => new Word(bytes),
ToRaw = (reg, value) => value.ToByteArray(),
@@ -78,7 +78,7 @@ namespace MewtocolNet.TypeConversion {
//default int DDT conversion
new PlcTypeConversion(RegisterType.DDT) {
- HoldingRegisterType = typeof(SingleRegister),
+ HoldingRegisterType = typeof(StructRegister),
PlcVarType = PlcVarType.DINT,
FromRaw = (reg, bytes) => BitConverter.ToInt32(bytes, 0),
ToRaw = (reg, value) => BitConverter.GetBytes(value),
@@ -86,7 +86,7 @@ namespace MewtocolNet.TypeConversion {
//default uint DDT conversion
new PlcTypeConversion(RegisterType.DDT) {
- HoldingRegisterType = typeof(SingleRegister),
+ HoldingRegisterType = typeof(StructRegister),
PlcVarType = PlcVarType.UDINT,
FromRaw = (reg, bytes) => BitConverter.ToUInt32(bytes, 0),
ToRaw = (reg, value) => BitConverter.GetBytes(value),
@@ -94,7 +94,7 @@ namespace MewtocolNet.TypeConversion {
//default DWord DDT conversion
new PlcTypeConversion(RegisterType.DDT) {
- HoldingRegisterType = typeof(SingleRegister),
+ HoldingRegisterType = typeof(StructRegister),
PlcVarType = PlcVarType.DWORD,
FromRaw = (reg, bytes) => new DWord(bytes),
ToRaw = (reg, value) => value.ToByteArray(),
@@ -102,7 +102,7 @@ namespace MewtocolNet.TypeConversion {
//default float DDT conversion
new PlcTypeConversion(RegisterType.DDT) {
- HoldingRegisterType = typeof(SingleRegister),
+ HoldingRegisterType = typeof(StructRegister),
PlcVarType = PlcVarType.REAL,
FromRaw = (reg, bytes) => BitConverter.ToSingle(bytes, 0),
ToRaw = (reg, value) => BitConverter.GetBytes(value),
@@ -110,7 +110,7 @@ namespace MewtocolNet.TypeConversion {
//default TimeSpan DDT conversion
new PlcTypeConversion(RegisterType.DDT) {
- HoldingRegisterType = typeof(SingleRegister),
+ HoldingRegisterType = typeof(StructRegister),
PlcVarType = PlcVarType.TIME,
FromRaw = (reg, bytes) => {
@@ -130,48 +130,48 @@ namespace MewtocolNet.TypeConversion {
//default string DT Range conversion Example bytes: (04 00 03 00 XX XX XX)
//first 4 bytes are reserved size (2 bytes) and used size (2 bytes)
//the remaining bytes are the ascii bytes for the string
- new PlcTypeConversion(RegisterType.DT_BYTE_RANGE) {
- HoldingRegisterType = typeof(SingleRegister),
- PlcVarType = PlcVarType.STRING,
- FromRaw = (reg, bytes) => {
+ //new PlcTypeConversion(RegisterType.DT_BYTE_RANGE) {
+ // HoldingRegisterType = typeof(StructRegister),
+ // PlcVarType = PlcVarType.STRING,
+ // FromRaw = (reg, bytes) => {
- if(bytes.Length == 4) return string.Empty;
+ // if(bytes.Length == 4) return string.Empty;
- if(bytes == null || bytes.Length < 4) {
+ // if(bytes == null || bytes.Length < 4) {
- throw new Exception("Failed to convert string bytes, response not long enough");
+ // throw new Exception("Failed to convert string bytes, response not long enough");
- }
+ // }
- //get actual showed size
- short actualLen = BitConverter.ToInt16(bytes, 2);
+ // //get actual showed size
+ // short actualLen = BitConverter.ToInt16(bytes, 2);
- //skip 4 bytes because they only describe the length
- string gotVal = Encoding.UTF8.GetString(bytes.Skip(4).Take(actualLen).ToArray());
+ // //skip 4 bytes because they only describe the length
+ // string gotVal = Encoding.UTF8.GetString(bytes.Skip(4).Take(actualLen).ToArray());
- return gotVal;
+ // return gotVal;
- },
- ToRaw = (reg, value) => {
+ // },
+ // ToRaw = (reg, value) => {
- int padLen = value.Length;
- if(value.Length % 2 != 0) padLen++;
+ // int padLen = value.Length;
+ // if(value.Length % 2 != 0) padLen++;
- var strBytes = Encoding.UTF8.GetBytes(value.PadRight(padLen, '\0'));
+ // var strBytes = Encoding.UTF8.GetBytes(value.PadRight(padLen, '\0'));
- List finalBytes = new List();
+ // List finalBytes = new List();
- short reserved = (short)(reg.GetRegisterAddressLen() * 2 - 4);
- short used = (short)value.Length;
+ // short reserved = (short)(reg.GetRegisterAddressLen() * 2 - 4);
+ // short used = (short)value.Length;
- finalBytes.AddRange(BitConverter.GetBytes(reserved));
- finalBytes.AddRange(BitConverter.GetBytes(used));
- finalBytes.AddRange(strBytes);
+ // finalBytes.AddRange(BitConverter.GetBytes(reserved));
+ // finalBytes.AddRange(BitConverter.GetBytes(used));
+ // finalBytes.AddRange(strBytes);
- return finalBytes.ToArray();
+ // return finalBytes.ToArray();
- },
- },
+ // },
+ //},
};
diff --git a/MewtocolNet/TypeConversion/PlcValueParser.cs b/MewtocolNet/TypeConversion/PlcValueParser.cs
index f731f91..f2dad34 100644
--- a/MewtocolNet/TypeConversion/PlcValueParser.cs
+++ b/MewtocolNet/TypeConversion/PlcValueParser.cs
@@ -1,6 +1,7 @@
using MewtocolNet.Registers;
using MewtocolNet.TypeConversion;
using System;
+using System.Collections;
using System.Collections.Generic;
using System.Linq;
@@ -29,7 +30,7 @@ namespace MewtocolNet {
converter = conversions.FirstOrDefault(x => x.GetDotnetType() == underlyingType);
if (converter == null)
- throw new Exception($"A converter for the dotnet type {underlyingType} doesn't exist");
+ throw new Exception($"A converter for the type {underlyingType} doesn't exist");
return (T)converter.FromRawData(register, bytes);
@@ -37,6 +38,9 @@ namespace MewtocolNet {
internal static T ParseArray (Register register, int[] indices, byte[] bytes) {
+ //if byte array directly return the bytes
+ if (typeof(T) == typeof(byte[])) return (T)(object)bytes;
+
IPlcTypeConverter converter;
Type underlyingElementType;
@@ -54,19 +58,18 @@ namespace MewtocolNet {
converter = conversions.FirstOrDefault(x => x.GetDotnetType() == underlyingElementType);
if (converter == null)
- throw new Exception($"A converter for the dotnet type {underlyingElementType} doesn't exist");
+ throw new Exception($"A converter for the type {underlyingElementType} doesn't exist");
//parse the array from one to n dimensions
var outArray = Array.CreateInstance(underlyingElementType, indices);
- if(outArray.GetType() == typeof(byte[])) {
-
- Console.WriteLine();
-
+ int sizePerItem = 0;
+ if(underlyingElementType == typeof(string)) {
+ throw new NotImplementedException();
+ } else {
+ sizePerItem = underlyingElementType.DetermineTypeByteIntialSize();
}
- int sizePerItem = underlyingElementType.DetermineTypeByteIntialSize();
-
var iterateItems = indices.Aggregate((a, x) => a * x);
var indexer = new int[indices.Length];
for (int i = 0; i < iterateItems; i++) {
@@ -92,44 +95,6 @@ namespace MewtocolNet {
}
- static void ConvertFlatArrayToDim (
- IPlcTypeConverter converter,
- Register register,
- byte[] source,
- Array target,
- int sizePerVal,
- int[] dims,
- int currentIndex,
- int currentArrayIndex
- ) {
-
- if (currentIndex == dims.Length - 1) {
-
- for (int i = 0; i < dims[currentIndex]; i++) {
-
- byte[] rawDataItem = source.Skip(currentArrayIndex).Take(sizePerVal).ToArray();
- var value = converter.FromRawData(register, rawDataItem);
-
- target.SetValue(value, i);
- currentArrayIndex += sizePerVal;
-
- }
-
- } else {
-
- for (int i = 0; i < dims[currentIndex]; i++) {
-
- Array innerArray = (Array)target.GetValue(i);
- ConvertFlatArrayToDim(converter, register, source, innerArray, sizePerVal, dims, currentIndex + 1, currentArrayIndex);
- currentArrayIndex += innerArray.Length * sizePerVal;
-
- }
-
- }
-
- }
-
-
internal static byte[] Encode(Register register, T value) {
IPlcTypeConverter converter;
@@ -155,10 +120,53 @@ namespace MewtocolNet {
}
- //internal static byte[] EncodeArray (IRegister register, T value) {
+ internal static byte[] EncodeArray(Register register, T value) {
+ //if byte array directly return the bytes
+ if (typeof(T) == typeof(byte[])) return (byte[])(object)value;
- //}
+ IPlcTypeConverter converter;
+ Type underlyingElementType;
+
+ //special case for enums
+ if (typeof(T).IsEnum) {
+
+ underlyingElementType = typeof(T).GetElementType().GetEnumUnderlyingType();
+
+ } else {
+
+ underlyingElementType = typeof(T).GetElementType();
+
+ }
+
+ converter = conversions.FirstOrDefault(x => x.GetDotnetType() == underlyingElementType);
+
+ if (converter == null)
+ throw new Exception($"A converter for the type {underlyingElementType} doesn't exist");
+
+ int sizePerItem = 0;
+ if (underlyingElementType == typeof(string)) {
+ throw new NotImplementedException();
+ } else {
+ sizePerItem = underlyingElementType.DetermineTypeByteIntialSize();
+ }
+
+ byte[] encodedData = new byte[((ICollection)value).Count * sizePerItem];
+
+ int i = 0;
+ foreach (object item in (IEnumerable)value) {
+
+ var encoded = converter.ToRawData(register, item);
+
+ encoded.CopyTo(encodedData, i);
+
+ i += sizePerItem;
+
+ }
+
+ return encodedData;
+
+ }
public static List GetAllowDotnetTypes() => conversions.Select(x => x.GetDotnetType()).ToList();