mirror of
https://github.com/OpenLogics/MewtocolNet.git
synced 2025-12-06 03:01:24 +00:00
Restricted register generics
This commit is contained in:
@@ -393,7 +393,7 @@ namespace MewtocolNet {
|
|||||||
Register = reg,
|
Register = reg,
|
||||||
PreviousValue = preValue,
|
PreviousValue = preValue,
|
||||||
PreviousValueString = preValueString,
|
PreviousValueString = preValueString,
|
||||||
Value = reg.Value,
|
Value = reg.ValueObj,
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -108,6 +108,9 @@ namespace MewtocolNet {
|
|||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public async Task<bool> WriteByteRange(int start, byte[] byteArr) {
|
public async Task<bool> WriteByteRange(int start, byte[] byteArr) {
|
||||||
|
|
||||||
|
if (byteArr == null)
|
||||||
|
throw new ArgumentNullException(nameof(byteArr));
|
||||||
|
|
||||||
string byteString = byteArr.ToHexString();
|
string byteString = byteArr.ToHexString();
|
||||||
|
|
||||||
var wordLength = byteArr.Length / 2;
|
var wordLength = byteArr.Length / 2;
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ namespace MewtocolNet.RegisterAttributes {
|
|||||||
|
|
||||||
if (value is IRegister reg) {
|
if (value is IRegister reg) {
|
||||||
|
|
||||||
privateField = (T)reg.Value;
|
privateField = (T)reg.ValueObj;
|
||||||
return;
|
return;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using MewtocolNet.Registers;
|
using System;
|
||||||
|
using MewtocolNet.Registers;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace MewtocolNet.RegisterBuilding {
|
namespace MewtocolNet.RegisterBuilding {
|
||||||
@@ -33,16 +34,18 @@ namespace MewtocolNet.RegisterBuilding {
|
|||||||
/// <returns>True if success</returns>
|
/// <returns>True if success</returns>
|
||||||
public async Task<bool> WriteToAsync<T>(T value) {
|
public async Task<bool> WriteToAsync<T>(T value) {
|
||||||
|
|
||||||
try {
|
throw new NotImplementedException();
|
||||||
|
|
||||||
var tempRegister = AssembleTemporaryRegister<T>();
|
//try {
|
||||||
return await tempRegister.WriteAsync(value);
|
|
||||||
|
|
||||||
} catch {
|
// var tempRegister = AssembleTemporaryRegister<T>();
|
||||||
|
// return await tempRegister.WriteAsync(value);
|
||||||
|
|
||||||
throw;
|
//} catch {
|
||||||
|
|
||||||
}
|
// throw;
|
||||||
|
|
||||||
|
//}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -52,16 +55,18 @@ namespace MewtocolNet.RegisterBuilding {
|
|||||||
/// <returns>The value read or null if failed</returns>
|
/// <returns>The value read or null if failed</returns>
|
||||||
public async Task<T> ReadFromAsync<T>() {
|
public async Task<T> ReadFromAsync<T>() {
|
||||||
|
|
||||||
try {
|
throw new NotImplementedException();
|
||||||
|
|
||||||
var tempRegister = AssembleTemporaryRegister<T>();
|
//try {
|
||||||
return (T)await tempRegister.ReadAsync();
|
|
||||||
|
|
||||||
} catch {
|
// var tempRegister = AssembleTemporaryRegister<T>();
|
||||||
|
// return (T)await tempRegister.ReadAsync();
|
||||||
|
|
||||||
throw;
|
//} catch {
|
||||||
|
|
||||||
}
|
// throw;
|
||||||
|
|
||||||
|
//}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ namespace MewtocolNet.RegisterBuilding {
|
|||||||
|
|
||||||
internal RBuildBase(MewtocolInterface plc) => attachedPLC = plc;
|
internal RBuildBase(MewtocolInterface plc) => attachedPLC = plc;
|
||||||
|
|
||||||
internal List<StepData> unfinishedList = new List<StepData>();
|
internal List<BaseStepData> unfinishedList = new List<BaseStepData>();
|
||||||
|
|
||||||
#region Parser stage
|
#region Parser stage
|
||||||
|
|
||||||
@@ -50,7 +50,7 @@ namespace MewtocolNet.RegisterBuilding {
|
|||||||
|
|
||||||
internal string hardFailReason;
|
internal string hardFailReason;
|
||||||
|
|
||||||
internal StepData stepData;
|
internal BaseStepData stepData;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -277,9 +277,7 @@ namespace MewtocolNet.RegisterBuilding {
|
|||||||
res.stepData.originalParseStr = plcAddrName;
|
res.stepData.originalParseStr = plcAddrName;
|
||||||
res.stepData.buildSource = RegisterBuildSource.Manual;
|
res.stepData.buildSource = RegisterBuildSource.Manual;
|
||||||
|
|
||||||
unfinishedList.Add(res.stepData);
|
return new StepData().Map(res.stepData);
|
||||||
|
|
||||||
return res.stepData;
|
|
||||||
|
|
||||||
} else if (res.state == ParseResultState.FailedHard) {
|
} else if (res.state == ParseResultState.FailedHard) {
|
||||||
|
|
||||||
@@ -305,7 +303,7 @@ namespace MewtocolNet.RegisterBuilding {
|
|||||||
/// <typeparam name="T">
|
/// <typeparam name="T">
|
||||||
/// <include file="../Documentation/docs.xml" path='extradoc/class[@name="support-conv-types"]/*' />
|
/// <include file="../Documentation/docs.xml" path='extradoc/class[@name="support-conv-types"]/*' />
|
||||||
/// </typeparam>
|
/// </typeparam>
|
||||||
public TypedRegister AsType<T>() {
|
internal TypedRegister AsType<T>() {
|
||||||
|
|
||||||
if (!typeof(T).IsAllowedPlcCastingType()) {
|
if (!typeof(T).IsAllowedPlcCastingType()) {
|
||||||
|
|
||||||
@@ -326,7 +324,7 @@ namespace MewtocolNet.RegisterBuilding {
|
|||||||
/// <param name="type">
|
/// <param name="type">
|
||||||
/// <include file="../Documentation/docs.xml" path='extradoc/class[@name="support-conv-types"]/*' />
|
/// <include file="../Documentation/docs.xml" path='extradoc/class[@name="support-conv-types"]/*' />
|
||||||
/// </param>
|
/// </param>
|
||||||
public TypedRegister AsType(Type type) {
|
internal TypedRegister AsType(Type type) {
|
||||||
|
|
||||||
//was ranged syntax array build
|
//was ranged syntax array build
|
||||||
if (Data.wasAddressStringRangeBased && type.IsArray && type.GetArrayRank() == 1) {
|
if (Data.wasAddressStringRangeBased && type.IsArray && type.GetArrayRank() == 1) {
|
||||||
@@ -395,7 +393,7 @@ namespace MewtocolNet.RegisterBuilding {
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Sets the register type as a predefined <see cref="PlcVarType"/>
|
/// Sets the register type as a predefined <see cref="PlcVarType"/>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public TypedRegister AsType(PlcVarType type) {
|
internal TypedRegister AsType(PlcVarType type) {
|
||||||
|
|
||||||
Data.dotnetVarType = type.GetDefaultDotnetType();
|
Data.dotnetVarType = type.GetDefaultDotnetType();
|
||||||
|
|
||||||
@@ -420,7 +418,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 TypedRegister AsType(string type) {
|
internal TypedRegister AsType(string type) {
|
||||||
|
|
||||||
var regexString = new Regex(@"^STRING *\[(?<len>[0-9]*)\]$", RegexOptions.IgnoreCase);
|
var regexString = new Regex(@"^STRING *\[(?<len>[0-9]*)\]$", RegexOptions.IgnoreCase);
|
||||||
var regexArray = new Regex(@"^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 regexArray = new Regex(@"^ARRAY *\[(?<S1>[0-9]*)..(?<E1>[0-9]*)(?:\,(?<S2>[0-9]*)..(?<E2>[0-9]*))?(?:\,(?<S3>[0-9]*)..(?<E3>[0-9]*))?\] *OF {1,}(?<t>.*)$", RegexOptions.IgnoreCase);
|
||||||
@@ -520,7 +518,7 @@ namespace MewtocolNet.RegisterBuilding {
|
|||||||
/// ARRAY [0..2, 0..3, 0..4] OF INT = <c>AsTypeArray<short[,,]>(3,4,5)</c><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/>
|
/// ARRAY [5..6, 0..2] OF DWORD = <c>AsTypeArray<DWord[,]>(2, 3)</c><br/>
|
||||||
/// </example>
|
/// </example>
|
||||||
public TypedRegister AsTypeArray<T>(params int[] indicies) {
|
internal TypedRegister AsTypeArray<T>(params int[] indicies) {
|
||||||
|
|
||||||
if (!typeof(T).IsArray)
|
if (!typeof(T).IsArray)
|
||||||
throw new NotSupportedException($"The type {typeof(T)} was no array");
|
throw new NotSupportedException($"The type {typeof(T)} was no array");
|
||||||
|
|||||||
@@ -15,6 +15,8 @@ namespace MewtocolNet.RegisterBuilding {
|
|||||||
|
|
||||||
#region String parse stage
|
#region String parse stage
|
||||||
|
|
||||||
|
//at runtime constructor
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Starts the register builder for a new mewtocol address <br/>
|
/// Starts the register builder for a new mewtocol address <br/>
|
||||||
/// Examples:
|
/// Examples:
|
||||||
@@ -26,6 +28,8 @@ namespace MewtocolNet.RegisterBuilding {
|
|||||||
|
|
||||||
var data = ParseAddress(plcAddrName, name);
|
var data = ParseAddress(plcAddrName, name);
|
||||||
|
|
||||||
|
unfinishedList.Add(data);
|
||||||
|
|
||||||
return new SAddress {
|
return new SAddress {
|
||||||
Data = data,
|
Data = data,
|
||||||
builder = this,
|
builder = this,
|
||||||
@@ -33,6 +37,68 @@ namespace MewtocolNet.RegisterBuilding {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//struct constructor
|
||||||
|
|
||||||
|
public SAddressStruct<T> Address<T>(string plcAddrName, string name = null) where T : struct {
|
||||||
|
|
||||||
|
var data = ParseAddress(plcAddrName, name);
|
||||||
|
|
||||||
|
data.dotnetVarType = typeof(T);
|
||||||
|
|
||||||
|
unfinishedList.Add(data);
|
||||||
|
|
||||||
|
return new SAddressStruct<T>(data) {
|
||||||
|
builder = this,
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public SAddressString<T> AddressString<T>(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<T>(data, true) {
|
||||||
|
Data = data,
|
||||||
|
builder = this,
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return new SAddressString<T>(data) {
|
||||||
|
builder = this,
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public SAddressArray<T> AddressArray<T>(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<T>(data, true) {
|
||||||
|
Data = data,
|
||||||
|
builder = this,
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return new SAddressArray<T>(data) {
|
||||||
|
builder = this,
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
//internal use only, adds a type definition (for use when building from attibute)
|
//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) {
|
internal SAddress AddressFromAttribute(string plcAddrName, string typeDef, RegisterCollection regCol, PropertyInfo prop, uint? bytesizeHint = null) {
|
||||||
|
|
||||||
@@ -52,6 +118,7 @@ namespace MewtocolNet.RegisterBuilding {
|
|||||||
|
|
||||||
#region Typing stage
|
#region Typing stage
|
||||||
|
|
||||||
|
//non generic
|
||||||
public new class SAddress : RBuildBase.SAddress {
|
public new class SAddress : RBuildBase.SAddress {
|
||||||
|
|
||||||
public new TypedRegister AsType<T>() => new TypedRegister().Map(base.AsType<T>());
|
public new TypedRegister AsType<T>() => new TypedRegister().Map(base.AsType<T>());
|
||||||
@@ -64,9 +131,95 @@ namespace MewtocolNet.RegisterBuilding {
|
|||||||
|
|
||||||
public new TypedRegister AsTypeArray<T>(params int[] indicies) => new TypedRegister().Map(base.AsTypeArray<T>(indicies));
|
public new TypedRegister AsTypeArray<T>(params int[] indicies) => new TypedRegister().Map(base.AsTypeArray<T>(indicies));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//structs
|
||||||
|
public class SAddressStruct<T> : 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;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Outputs the generated <see cref="IRegister"/>
|
||||||
|
/// </summary>
|
||||||
|
public void Out(Action<IRegister<T>> registerOut) {
|
||||||
|
|
||||||
|
Data.registerOut = new Action<object>(o => registerOut((IRegister<T>)o));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//strings
|
||||||
|
public class SAddressString<T> : RBuildBase.SAddress where T : class {
|
||||||
|
|
||||||
|
internal SAddressString(StepData data) {
|
||||||
|
|
||||||
|
this.Data = data;
|
||||||
|
|
||||||
|
this.Map(AsType(typeof(T)));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
internal SAddressString(StepData data, bool arrayed) {
|
||||||
|
|
||||||
|
this.Data = data;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Outputs the generated <see cref="IRegister"/>
|
||||||
|
/// </summary>
|
||||||
|
public void Out(Action<IStringRegister<T>> registerOut) {
|
||||||
|
|
||||||
|
Data.registerOut = new Action<object>(o => registerOut((IStringRegister<T>)o));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//arrays
|
||||||
|
public class SAddressArray<T> : RBuildBase.SAddress {
|
||||||
|
|
||||||
|
internal SAddressArray(StepData data) {
|
||||||
|
|
||||||
|
this.Data = data;
|
||||||
|
|
||||||
|
this.Map(AsType(typeof(T)));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
internal SAddressArray(StepData data, bool arrayed) {
|
||||||
|
|
||||||
|
this.Data = data;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public TypedRegister Indicies(params int[] indicies) => new TypedRegister().Map(base.AsTypeArray<T>(indicies));
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Outputs the generated <see cref="IRegister"/>
|
||||||
|
/// </summary>
|
||||||
|
public void Out(Action<IArrayRegister<T>> registerOut) {
|
||||||
|
|
||||||
|
Data.registerOut = new Action<object>(o => registerOut((IArrayRegister<T>)o));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Typing size hint
|
#region Typing size hint
|
||||||
@@ -83,7 +236,7 @@ namespace MewtocolNet.RegisterBuilding {
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public void Out(Action<IRegister> registerOut) {
|
public void Out(Action<IRegister> registerOut) {
|
||||||
|
|
||||||
Data.registerOut = registerOut;
|
Data.registerOut = (Action<object>)registerOut;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -103,7 +256,7 @@ namespace MewtocolNet.RegisterBuilding {
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public void Out(Action<IRegister> registerOut) {
|
public void Out(Action<IRegister> registerOut) {
|
||||||
|
|
||||||
Data.registerOut = registerOut;
|
Data.registerOut = (Action<object>)registerOut;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -118,7 +271,7 @@ namespace MewtocolNet.RegisterBuilding {
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public void Out(Action<IRegister> registerOut) {
|
public void Out(Action<IRegister> registerOut) {
|
||||||
|
|
||||||
Data.registerOut = registerOut;
|
Data.registerOut = (Action<object>)registerOut;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -28,7 +28,8 @@ namespace MewtocolNet.RegisterBuilding {
|
|||||||
var generatedInstance = Assemble(data);
|
var generatedInstance = Assemble(data);
|
||||||
|
|
||||||
generatedInstance.autoGenerated = flagAutoGenerated;
|
generatedInstance.autoGenerated = flagAutoGenerated;
|
||||||
data.registerOut?.Invoke(generatedInstance);
|
|
||||||
|
data?.InvokeBuilt(generatedInstance);
|
||||||
|
|
||||||
generatedInstances.Add(generatedInstance);
|
generatedInstances.Add(generatedInstance);
|
||||||
|
|
||||||
@@ -38,7 +39,7 @@ namespace MewtocolNet.RegisterBuilding {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal Register Assemble(StepData data) {
|
internal Register Assemble(BaseStepData data) {
|
||||||
|
|
||||||
Register generatedInstance = null;
|
Register generatedInstance = null;
|
||||||
|
|
||||||
@@ -114,7 +115,7 @@ namespace MewtocolNet.RegisterBuilding {
|
|||||||
|
|
||||||
var flags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance;
|
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[] {
|
ConstructorInfo constr = paramedClass.GetConstructor(flags, null, new Type[] {
|
||||||
typeof(uint), typeof(uint) ,typeof(string)
|
typeof(uint), typeof(uint) ,typeof(string)
|
||||||
}, null);
|
}, null);
|
||||||
|
|||||||
@@ -6,10 +6,9 @@ using System.Reflection;
|
|||||||
|
|
||||||
namespace MewtocolNet.RegisterBuilding {
|
namespace MewtocolNet.RegisterBuilding {
|
||||||
|
|
||||||
internal class StepData {
|
internal class BaseStepData {
|
||||||
|
|
||||||
//for referencing the output at builder level
|
internal Action<object> registerOut;
|
||||||
internal Action<IRegister> registerOut;
|
|
||||||
|
|
||||||
internal RegisterBuildSource buildSource = RegisterBuildSource.Anonymous;
|
internal RegisterBuildSource buildSource = RegisterBuildSource.Anonymous;
|
||||||
|
|
||||||
@@ -34,6 +33,40 @@ namespace MewtocolNet.RegisterBuilding {
|
|||||||
|
|
||||||
internal string typeDef;
|
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<T>));
|
||||||
|
|
||||||
|
// field.SetValue(this,);
|
||||||
|
|
||||||
|
//}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class StepData<T> : BaseStepData {
|
||||||
|
|
||||||
|
//for referencing the output at builder level
|
||||||
|
//internal Action<IRegister<T>> registerOut;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class StepData : BaseStepData {
|
||||||
|
|
||||||
|
//for referencing the output at builder level
|
||||||
|
//internal Action<IRegister> registerOut;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ namespace MewtocolNet.Registers {
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Defines a register containing a string
|
/// Defines a register containing a string
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class ArrayRegister<T> : Register {
|
public class ArrayRegister<T> : Register, IArrayRegister<T> {
|
||||||
|
|
||||||
internal int[] indices;
|
internal int[] indices;
|
||||||
|
|
||||||
@@ -21,6 +21,8 @@ namespace MewtocolNet.Registers {
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public uint AddressLength => addressLength;
|
public uint AddressLength => addressLength;
|
||||||
|
|
||||||
|
public T[] Value => (T[])ValueObj;
|
||||||
|
|
||||||
[Obsolete("Creating registers directly is not supported use IPlc.Register instead")]
|
[Obsolete("Creating registers directly is not supported use IPlc.Register instead")]
|
||||||
public ArrayRegister() =>
|
public ArrayRegister() =>
|
||||||
throw new NotSupportedException("Direct register instancing is not supported, use the builder pattern");
|
throw new NotSupportedException("Direct register instancing is not supported, use the builder pattern");
|
||||||
@@ -47,16 +49,16 @@ namespace MewtocolNet.Registers {
|
|||||||
|
|
||||||
public override string GetValueString() {
|
public override string GetValueString() {
|
||||||
|
|
||||||
if (Value == null) return "null";
|
if (ValueObj == null) return "null";
|
||||||
|
|
||||||
if(typeof(T) == typeof(byte[])) {
|
if(typeof(T) == typeof(byte[])) {
|
||||||
|
|
||||||
return ((byte[])Value).ToHexString("-");
|
return ((byte[])ValueObj).ToHexString("-");
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
StringBuilder sb = new StringBuilder();
|
StringBuilder sb = new StringBuilder();
|
||||||
var valueIenum = (IEnumerable)Value;
|
var valueIenum = (IEnumerable)ValueObj;
|
||||||
|
|
||||||
foreach (var el in valueIenum) {
|
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 uint GetRegisterAddressLen() => AddressLength;
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public override async Task<bool> WriteAsync(object value) {
|
public async Task<bool> WriteAsync(T value) {
|
||||||
|
|
||||||
var encoded = PlcValueParser.Encode(this, (T)value);
|
var encoded = PlcValueParser.EncodeArray(this, value);
|
||||||
var res = await attachedInterface.WriteByteRange((int)MemoryAddress, encoded);
|
var res = await attachedInterface.WriteByteRange((int)MemoryAddress, encoded);
|
||||||
|
|
||||||
if (res) {
|
if (res) {
|
||||||
@@ -99,18 +101,18 @@ namespace MewtocolNet.Registers {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public override async Task<object> ReadAsync() {
|
async Task<T[]> IArrayRegister<T>.ReadAsync() {
|
||||||
|
|
||||||
var res = await attachedInterface.ReadByteRangeNonBlocking((int)MemoryAddress, (int)GetRegisterAddressLen() * 2);
|
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()
|
var matchingReg = attachedInterface.memoryManager.GetAllRegisters()
|
||||||
//.FirstOrDefault(x => x.IsSameAddressAndType(this));
|
.FirstOrDefault(x => x.IsSameAddressAndType(this));
|
||||||
|
|
||||||
//if (matchingReg != null)
|
if (matchingReg != null)
|
||||||
// matchingReg.underlyingMemory.SetUnderlyingBytes(matchingReg, res);
|
matchingReg.underlyingMemory.SetUnderlyingBytes(matchingReg, res);
|
||||||
|
|
||||||
return SetValueFromBytes(res);
|
return (T[])SetValueFromBytes(res);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
26
MewtocolNet/Registers/Base/IArrayRegister.cs
Normal file
26
MewtocolNet/Registers/Base/IArrayRegister.cs
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace MewtocolNet.Registers {
|
||||||
|
|
||||||
|
public interface IArrayRegister<T> : IRegister {
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The current value of the register
|
||||||
|
/// </summary>
|
||||||
|
T[] Value { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Reads the register value async from the plc
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>The register value</returns>
|
||||||
|
Task<T[]> ReadAsync();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes the register content async to the plc
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>True if successfully set</returns>
|
||||||
|
Task<bool> WriteAsync(T data);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -32,7 +32,7 @@ namespace MewtocolNet.Registers {
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// The current value of the register
|
/// The current value of the register
|
||||||
/// </summary>
|
/// </summary>
|
||||||
object Value { get; }
|
object ValueObj { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The plc memory address of the register
|
/// The plc memory address of the register
|
||||||
@@ -55,18 +55,6 @@ namespace MewtocolNet.Registers {
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
string ToString(bool detailed);
|
string ToString(bool detailed);
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Reads the register value async from the plc
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>The register value</returns>
|
|
||||||
Task<object> ReadAsync();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Writes the register content async to the plc
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>True if successfully set</returns>
|
|
||||||
Task<bool> WriteAsync(object data);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
31
MewtocolNet/Registers/Base/IRegisterT.cs
Normal file
31
MewtocolNet/Registers/Base/IRegisterT.cs
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
using System;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using MewtocolNet.Events;
|
||||||
|
|
||||||
|
namespace MewtocolNet.Registers {
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// An interface for all register types
|
||||||
|
/// </summary>
|
||||||
|
public interface IRegister<T> : IRegister where T : struct {
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The current value of the register
|
||||||
|
/// </summary>
|
||||||
|
T? Value { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Reads the register value async from the plc
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>The register value</returns>
|
||||||
|
Task<T?> ReadAsync();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes the register content async to the plc
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>True if successfully set</returns>
|
||||||
|
Task<bool> WriteAsync(T data);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
25
MewtocolNet/Registers/Base/IStringRegister.cs
Normal file
25
MewtocolNet/Registers/Base/IStringRegister.cs
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace MewtocolNet.Registers {
|
||||||
|
public interface IStringRegister<T> : IRegister where T : class {
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The current value of the register
|
||||||
|
/// </summary>
|
||||||
|
T Value { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Reads the register value async from the plc
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>The register value</returns>
|
||||||
|
Task<T> ReadAsync();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes the register content async to the plc
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>True if successfully set</returns>
|
||||||
|
Task<bool> WriteAsync(T data);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -44,7 +44,7 @@ namespace MewtocolNet.Registers {
|
|||||||
public MewtocolInterface AttachedInterface => attachedInterface;
|
public MewtocolInterface AttachedInterface => attachedInterface;
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public object Value => lastValue;
|
public object ValueObj => lastValue;
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public RegisterType RegisterType { get; internal set; }
|
public RegisterType RegisterType { get; internal set; }
|
||||||
@@ -62,7 +62,7 @@ namespace MewtocolNet.Registers {
|
|||||||
|
|
||||||
public event PropertyChangedEventHandler PropertyChanged;
|
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
|
#endregion
|
||||||
|
|
||||||
@@ -97,23 +97,13 @@ namespace MewtocolNet.Registers {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#region Read / Write
|
|
||||||
|
|
||||||
public virtual Task<object> ReadAsync() => throw new NotImplementedException();
|
|
||||||
|
|
||||||
public virtual Task<bool> WriteAsync(object data) => throw new NotImplementedException();
|
|
||||||
|
|
||||||
internal virtual Task UpdateDynamicSize () => throw new NotImplementedException();
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Default accessors
|
#region Default accessors
|
||||||
|
|
||||||
public virtual byte? GetSpecialAddress() => null;
|
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();
|
public virtual string GetRegisterString() => RegisterType == RegisterType.DT_BYTE_RANGE ? "DT" : RegisterType.ToString();
|
||||||
|
|
||||||
@@ -202,7 +192,7 @@ namespace MewtocolNet.Registers {
|
|||||||
sb.Append(GetMewName());
|
sb.Append(GetMewName());
|
||||||
if (Name != null) sb.Append($" ({Name})");
|
if (Name != null) sb.Append($" ({Name})");
|
||||||
sb.Append($" [{this.GetType().Name}({underlyingSystemType.Name})]");
|
sb.Append($" [{this.GetType().Name}({underlyingSystemType.Name})]");
|
||||||
if (Value != null) sb.Append($" Val: {GetValueString()}");
|
if (ValueObj != null) sb.Append($" Val: {GetValueString()}");
|
||||||
|
|
||||||
return sb.ToString();
|
return sb.ToString();
|
||||||
|
|
||||||
@@ -235,7 +225,7 @@ namespace MewtocolNet.Registers {
|
|||||||
|
|
||||||
sb.Append($"Name: {Name ?? "Not named"}\n");
|
sb.Append($"Name: {Name ?? "Not named"}\n");
|
||||||
|
|
||||||
if (Value != null)
|
if (ValueObj != null)
|
||||||
sb.Append($"Value: {GetValueString()}\n");
|
sb.Append($"Value: {GetValueString()}\n");
|
||||||
|
|
||||||
sb.Append($"Reads: {successfulReads}, Writes: {successfulWrites}\n");
|
sb.Append($"Reads: {successfulReads}, Writes: {successfulWrites}\n");
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ namespace MewtocolNet.Registers {
|
|||||||
/// Defines a register containing a number
|
/// Defines a register containing a number
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <typeparam name="T">The type of the numeric value</typeparam>
|
/// <typeparam name="T">The type of the numeric value</typeparam>
|
||||||
public class SingleRegister<T> : Register {
|
public class StructRegister<T> : Register, IRegister<T> where T : struct {
|
||||||
|
|
||||||
internal uint byteLength;
|
internal uint byteLength;
|
||||||
|
|
||||||
@@ -25,11 +25,13 @@ namespace MewtocolNet.Registers {
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public uint AddressLength => addressLength;
|
public uint AddressLength => addressLength;
|
||||||
|
|
||||||
|
public T? Value => (T?)ValueObj;
|
||||||
|
|
||||||
[Obsolete("Creating registers directly is not supported use IPlc.Register instead")]
|
[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");
|
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;
|
memoryAddress = _address;
|
||||||
name = _name;
|
name = _name;
|
||||||
@@ -56,33 +58,33 @@ namespace MewtocolNet.Registers {
|
|||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public override string GetAsPLC() {
|
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();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public override string GetValueString() {
|
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<FlagsAttribute>() != null;
|
var hasFlags = typeof(T).GetCustomAttribute<FlagsAttribute>() != null;
|
||||||
|
|
||||||
if (Value != null && typeof(T).IsEnum && !hasFlags) {
|
if (ValueObj != null && typeof(T).IsEnum && !hasFlags) {
|
||||||
|
|
||||||
var underlying = Enum.GetUnderlyingType(typeof(T));
|
var underlying = Enum.GetUnderlyingType(typeof(T));
|
||||||
object val = Convert.ChangeType(Value, underlying);
|
object val = Convert.ChangeType(ValueObj, underlying);
|
||||||
return $"{Value} [{val}]";
|
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 uint GetRegisterAddressLen() => AddressLength;
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public override async Task<bool> WriteAsync(object value) {
|
public async Task<bool> WriteAsync(T value) {
|
||||||
|
|
||||||
var encoded = PlcValueParser.Encode(this, (T)value);
|
var encoded = PlcValueParser.Encode(this, (T)value);
|
||||||
var res = await attachedInterface.WriteByteRange((int)MemoryAddress, encoded);
|
var res = await attachedInterface.WriteByteRange((int)MemoryAddress, encoded);
|
||||||
@@ -114,25 +116,27 @@ namespace MewtocolNet.Registers {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public override async Task<object> ReadAsync() {
|
public async Task<T?> ReadAsync() {
|
||||||
|
|
||||||
var res = await attachedInterface.ReadByteRangeNonBlocking((int)MemoryAddress, (int)GetRegisterAddressLen() * 2);
|
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()
|
var matchingReg = attachedInterface.memoryManager.GetAllRegisters()
|
||||||
.FirstOrDefault(x => x.IsSameAddressAndType(this));
|
.FirstOrDefault(x => x.IsSameAddressAndType(this));
|
||||||
|
|
||||||
if (matchingReg != null) {
|
if (matchingReg != null) {
|
||||||
|
|
||||||
if (matchingReg is SingleRegister<string> sreg && this is SingleRegister<string> selfSreg) {
|
//if (matchingReg is StructRegister<string> sreg && this.GetType() == typeof(StructRegister<string>)) {
|
||||||
sreg.addressLength = selfSreg.addressLength;
|
|
||||||
}
|
// sreg.addressLength = selfSreg.addressLength;
|
||||||
|
|
||||||
|
//}
|
||||||
|
|
||||||
matchingReg.underlyingMemory.SetUnderlyingBytes(matchingReg, res);
|
matchingReg.underlyingMemory.SetUnderlyingBytes(matchingReg, res);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return SetValueFromBytes(res);
|
return (T)SetValueFromBytes(res);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -54,7 +54,7 @@ namespace MewtocolNet.TypeConversion {
|
|||||||
|
|
||||||
//default short DT conversion
|
//default short DT conversion
|
||||||
new PlcTypeConversion<short>(RegisterType.DT) {
|
new PlcTypeConversion<short>(RegisterType.DT) {
|
||||||
HoldingRegisterType = typeof(SingleRegister<short>),
|
HoldingRegisterType = typeof(StructRegister<short>),
|
||||||
PlcVarType = PlcVarType.INT,
|
PlcVarType = PlcVarType.INT,
|
||||||
FromRaw = (reg, bytes) => BitConverter.ToInt16(bytes, 0),
|
FromRaw = (reg, bytes) => BitConverter.ToInt16(bytes, 0),
|
||||||
ToRaw = (reg, value) => BitConverter.GetBytes(value),
|
ToRaw = (reg, value) => BitConverter.GetBytes(value),
|
||||||
@@ -62,7 +62,7 @@ namespace MewtocolNet.TypeConversion {
|
|||||||
|
|
||||||
//default ushort DT conversion
|
//default ushort DT conversion
|
||||||
new PlcTypeConversion<ushort>(RegisterType.DT) {
|
new PlcTypeConversion<ushort>(RegisterType.DT) {
|
||||||
HoldingRegisterType = typeof(SingleRegister<ushort>),
|
HoldingRegisterType = typeof(StructRegister<ushort>),
|
||||||
PlcVarType = PlcVarType.UINT,
|
PlcVarType = PlcVarType.UINT,
|
||||||
FromRaw = (reg, bytes) => BitConverter.ToUInt16(bytes, 0),
|
FromRaw = (reg, bytes) => BitConverter.ToUInt16(bytes, 0),
|
||||||
ToRaw = (reg, value) => BitConverter.GetBytes(value),
|
ToRaw = (reg, value) => BitConverter.GetBytes(value),
|
||||||
@@ -70,7 +70,7 @@ namespace MewtocolNet.TypeConversion {
|
|||||||
|
|
||||||
//default Word DT conversion
|
//default Word DT conversion
|
||||||
new PlcTypeConversion<Word>(RegisterType.DT) {
|
new PlcTypeConversion<Word>(RegisterType.DT) {
|
||||||
HoldingRegisterType = typeof(SingleRegister<Word>),
|
HoldingRegisterType = typeof(StructRegister<Word>),
|
||||||
PlcVarType = PlcVarType.WORD,
|
PlcVarType = PlcVarType.WORD,
|
||||||
FromRaw = (reg, bytes) => new Word(bytes),
|
FromRaw = (reg, bytes) => new Word(bytes),
|
||||||
ToRaw = (reg, value) => value.ToByteArray(),
|
ToRaw = (reg, value) => value.ToByteArray(),
|
||||||
@@ -78,7 +78,7 @@ namespace MewtocolNet.TypeConversion {
|
|||||||
|
|
||||||
//default int DDT conversion
|
//default int DDT conversion
|
||||||
new PlcTypeConversion<int>(RegisterType.DDT) {
|
new PlcTypeConversion<int>(RegisterType.DDT) {
|
||||||
HoldingRegisterType = typeof(SingleRegister<int>),
|
HoldingRegisterType = typeof(StructRegister<int>),
|
||||||
PlcVarType = PlcVarType.DINT,
|
PlcVarType = PlcVarType.DINT,
|
||||||
FromRaw = (reg, bytes) => BitConverter.ToInt32(bytes, 0),
|
FromRaw = (reg, bytes) => BitConverter.ToInt32(bytes, 0),
|
||||||
ToRaw = (reg, value) => BitConverter.GetBytes(value),
|
ToRaw = (reg, value) => BitConverter.GetBytes(value),
|
||||||
@@ -86,7 +86,7 @@ namespace MewtocolNet.TypeConversion {
|
|||||||
|
|
||||||
//default uint DDT conversion
|
//default uint DDT conversion
|
||||||
new PlcTypeConversion<uint>(RegisterType.DDT) {
|
new PlcTypeConversion<uint>(RegisterType.DDT) {
|
||||||
HoldingRegisterType = typeof(SingleRegister<uint>),
|
HoldingRegisterType = typeof(StructRegister<uint>),
|
||||||
PlcVarType = PlcVarType.UDINT,
|
PlcVarType = PlcVarType.UDINT,
|
||||||
FromRaw = (reg, bytes) => BitConverter.ToUInt32(bytes, 0),
|
FromRaw = (reg, bytes) => BitConverter.ToUInt32(bytes, 0),
|
||||||
ToRaw = (reg, value) => BitConverter.GetBytes(value),
|
ToRaw = (reg, value) => BitConverter.GetBytes(value),
|
||||||
@@ -94,7 +94,7 @@ namespace MewtocolNet.TypeConversion {
|
|||||||
|
|
||||||
//default DWord DDT conversion
|
//default DWord DDT conversion
|
||||||
new PlcTypeConversion<DWord>(RegisterType.DDT) {
|
new PlcTypeConversion<DWord>(RegisterType.DDT) {
|
||||||
HoldingRegisterType = typeof(SingleRegister<DWord>),
|
HoldingRegisterType = typeof(StructRegister<DWord>),
|
||||||
PlcVarType = PlcVarType.DWORD,
|
PlcVarType = PlcVarType.DWORD,
|
||||||
FromRaw = (reg, bytes) => new DWord(bytes),
|
FromRaw = (reg, bytes) => new DWord(bytes),
|
||||||
ToRaw = (reg, value) => value.ToByteArray(),
|
ToRaw = (reg, value) => value.ToByteArray(),
|
||||||
@@ -102,7 +102,7 @@ namespace MewtocolNet.TypeConversion {
|
|||||||
|
|
||||||
//default float DDT conversion
|
//default float DDT conversion
|
||||||
new PlcTypeConversion<float>(RegisterType.DDT) {
|
new PlcTypeConversion<float>(RegisterType.DDT) {
|
||||||
HoldingRegisterType = typeof(SingleRegister<float>),
|
HoldingRegisterType = typeof(StructRegister<float>),
|
||||||
PlcVarType = PlcVarType.REAL,
|
PlcVarType = PlcVarType.REAL,
|
||||||
FromRaw = (reg, bytes) => BitConverter.ToSingle(bytes, 0),
|
FromRaw = (reg, bytes) => BitConverter.ToSingle(bytes, 0),
|
||||||
ToRaw = (reg, value) => BitConverter.GetBytes(value),
|
ToRaw = (reg, value) => BitConverter.GetBytes(value),
|
||||||
@@ -110,7 +110,7 @@ namespace MewtocolNet.TypeConversion {
|
|||||||
|
|
||||||
//default TimeSpan DDT conversion
|
//default TimeSpan DDT conversion
|
||||||
new PlcTypeConversion<TimeSpan>(RegisterType.DDT) {
|
new PlcTypeConversion<TimeSpan>(RegisterType.DDT) {
|
||||||
HoldingRegisterType = typeof(SingleRegister<TimeSpan>),
|
HoldingRegisterType = typeof(StructRegister<TimeSpan>),
|
||||||
PlcVarType = PlcVarType.TIME,
|
PlcVarType = PlcVarType.TIME,
|
||||||
FromRaw = (reg, bytes) => {
|
FromRaw = (reg, bytes) => {
|
||||||
|
|
||||||
@@ -130,48 +130,48 @@ namespace MewtocolNet.TypeConversion {
|
|||||||
//default string DT Range conversion Example bytes: (04 00 03 00 XX XX XX)
|
//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)
|
//first 4 bytes are reserved size (2 bytes) and used size (2 bytes)
|
||||||
//the remaining bytes are the ascii bytes for the string
|
//the remaining bytes are the ascii bytes for the string
|
||||||
new PlcTypeConversion<string>(RegisterType.DT_BYTE_RANGE) {
|
//new PlcTypeConversion<string>(RegisterType.DT_BYTE_RANGE) {
|
||||||
HoldingRegisterType = typeof(SingleRegister<string>),
|
// HoldingRegisterType = typeof(StructRegister<string>),
|
||||||
PlcVarType = PlcVarType.STRING,
|
// PlcVarType = PlcVarType.STRING,
|
||||||
FromRaw = (reg, bytes) => {
|
// 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
|
// //get actual showed size
|
||||||
short actualLen = BitConverter.ToInt16(bytes, 2);
|
// short actualLen = BitConverter.ToInt16(bytes, 2);
|
||||||
|
|
||||||
//skip 4 bytes because they only describe the length
|
// //skip 4 bytes because they only describe the length
|
||||||
string gotVal = Encoding.UTF8.GetString(bytes.Skip(4).Take(actualLen).ToArray());
|
// 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;
|
// int padLen = value.Length;
|
||||||
if(value.Length % 2 != 0) padLen++;
|
// 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<byte> finalBytes = new List<byte>();
|
// List<byte> finalBytes = new List<byte>();
|
||||||
|
|
||||||
short reserved = (short)(reg.GetRegisterAddressLen() * 2 - 4);
|
// short reserved = (short)(reg.GetRegisterAddressLen() * 2 - 4);
|
||||||
short used = (short)value.Length;
|
// short used = (short)value.Length;
|
||||||
|
|
||||||
finalBytes.AddRange(BitConverter.GetBytes(reserved));
|
// finalBytes.AddRange(BitConverter.GetBytes(reserved));
|
||||||
finalBytes.AddRange(BitConverter.GetBytes(used));
|
// finalBytes.AddRange(BitConverter.GetBytes(used));
|
||||||
finalBytes.AddRange(strBytes);
|
// finalBytes.AddRange(strBytes);
|
||||||
|
|
||||||
return finalBytes.ToArray();
|
// return finalBytes.ToArray();
|
||||||
|
|
||||||
},
|
// },
|
||||||
},
|
//},
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
using MewtocolNet.Registers;
|
using MewtocolNet.Registers;
|
||||||
using MewtocolNet.TypeConversion;
|
using MewtocolNet.TypeConversion;
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
|
||||||
@@ -29,7 +30,7 @@ namespace MewtocolNet {
|
|||||||
converter = conversions.FirstOrDefault(x => x.GetDotnetType() == underlyingType);
|
converter = conversions.FirstOrDefault(x => x.GetDotnetType() == underlyingType);
|
||||||
|
|
||||||
if (converter == null)
|
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);
|
return (T)converter.FromRawData(register, bytes);
|
||||||
|
|
||||||
@@ -37,6 +38,9 @@ namespace MewtocolNet {
|
|||||||
|
|
||||||
internal static T ParseArray <T>(Register register, int[] indices, byte[] bytes) {
|
internal static T ParseArray <T>(Register register, int[] indices, byte[] bytes) {
|
||||||
|
|
||||||
|
//if byte array directly return the bytes
|
||||||
|
if (typeof(T) == typeof(byte[])) return (T)(object)bytes;
|
||||||
|
|
||||||
IPlcTypeConverter converter;
|
IPlcTypeConverter converter;
|
||||||
Type underlyingElementType;
|
Type underlyingElementType;
|
||||||
|
|
||||||
@@ -54,19 +58,18 @@ namespace MewtocolNet {
|
|||||||
converter = conversions.FirstOrDefault(x => x.GetDotnetType() == underlyingElementType);
|
converter = conversions.FirstOrDefault(x => x.GetDotnetType() == underlyingElementType);
|
||||||
|
|
||||||
if (converter == null)
|
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
|
//parse the array from one to n dimensions
|
||||||
var outArray = Array.CreateInstance(underlyingElementType, indices);
|
var outArray = Array.CreateInstance(underlyingElementType, indices);
|
||||||
|
|
||||||
if(outArray.GetType() == typeof(byte[])) {
|
int sizePerItem = 0;
|
||||||
|
if(underlyingElementType == typeof(string)) {
|
||||||
Console.WriteLine();
|
throw new NotImplementedException();
|
||||||
|
} else {
|
||||||
|
sizePerItem = underlyingElementType.DetermineTypeByteIntialSize();
|
||||||
}
|
}
|
||||||
|
|
||||||
int sizePerItem = underlyingElementType.DetermineTypeByteIntialSize();
|
|
||||||
|
|
||||||
var iterateItems = indices.Aggregate((a, x) => a * x);
|
var iterateItems = indices.Aggregate((a, x) => a * x);
|
||||||
var indexer = new int[indices.Length];
|
var indexer = new int[indices.Length];
|
||||||
for (int i = 0; i < iterateItems; i++) {
|
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<T>(Register register, T value) {
|
internal static byte[] Encode<T>(Register register, T value) {
|
||||||
|
|
||||||
IPlcTypeConverter converter;
|
IPlcTypeConverter converter;
|
||||||
@@ -155,10 +120,53 @@ namespace MewtocolNet {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//internal static byte[] EncodeArray (IRegister register, T value) {
|
internal static byte[] EncodeArray<T>(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<Type> GetAllowDotnetTypes() => conversions.Select(x => x.GetDotnetType()).ToList();
|
public static List<Type> GetAllowDotnetTypes() => conversions.Select(x => x.GetDotnetType()).ToList();
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user