From 5b3854748ca8a0107451630590de23f1f6fb8087 Mon Sep 17 00:00:00 2001 From: parallelbgls Date: Wed, 3 May 2017 17:08:50 +0800 Subject: [PATCH] 2017-05-03 update 1 Base Connector Template (Not Test) --- Modbus.Net/Modbus.Net.OPC/ClientExtend.cs | 14 ++ Modbus.Net/Modbus.Net.OPC/OpcConnector.cs | 114 ++++++-------- .../Modbus.Net.OPC/OpcDaProtocalLinker.cs | 11 +- Modbus.Net/Modbus.Net.OPC/OpcProtocal.cs | 44 +++--- .../Modbus.Net.OPC/OpcProtocalLinker.cs | 24 +++ .../Modbus.Net.OPC/OpcUaProtocalLinker.cs | 11 +- Modbus.Net/Modbus.Net.OPC/OpcUtility.cs | 6 +- Modbus.Net/src/Base.Common/BaseMachine.cs | 45 ++---- Modbus.Net/src/Base.Common/BaseProtocal.cs | 139 ++++++++++-------- Modbus.Net/src/Base.Common/BaseUtility.cs | 121 ++++++++++++++- .../src/Base.Common/IProtocalFormatting.cs | 23 ++- Modbus.Net/src/Base.Common/ProtocalLinker.cs | 99 ++++++++++--- Modbus.Net/src/Base.Common/ProtocalUnit.cs | 16 +- .../TripleAdd/Controllers/HomeController.cs | 4 +- Tests/Modbus.Net.Tests/MachineMethodTest.cs | 4 +- 15 files changed, 437 insertions(+), 238 deletions(-) create mode 100644 Modbus.Net/Modbus.Net.OPC/OpcProtocalLinker.cs diff --git a/Modbus.Net/Modbus.Net.OPC/ClientExtend.cs b/Modbus.Net/Modbus.Net.OPC/ClientExtend.cs index d60b351..7539f34 100644 --- a/Modbus.Net/Modbus.Net.OPC/ClientExtend.cs +++ b/Modbus.Net/Modbus.Net.OPC/ClientExtend.cs @@ -45,4 +45,18 @@ namespace Modbus.Net.OPC public Node RootNodeBase => RootNode; } + + public class OpcParamIn + { + public bool IsRead { get; set; } + public string Tag { get; set; } + public char Split { get; set; } + public object SetValue { get; set; } + } + + public class OpcParamOut + { + public bool Success { get; set; } + public byte[] Value { get; set; } + } } \ No newline at end of file diff --git a/Modbus.Net/Modbus.Net.OPC/OpcConnector.cs b/Modbus.Net/Modbus.Net.OPC/OpcConnector.cs index d78d95e..8c4eb6f 100644 --- a/Modbus.Net/Modbus.Net.OPC/OpcConnector.cs +++ b/Modbus.Net/Modbus.Net.OPC/OpcConnector.cs @@ -8,7 +8,7 @@ using System.Threading.Tasks; namespace Modbus.Net.OPC { - public abstract class OpcConnector : BaseConnector + public abstract class OpcConnector : BaseConnector { protected IClientExtend Client; @@ -39,17 +39,17 @@ namespace Modbus.Net.OPC } } - public override bool SendMsgWithoutReturn(byte[] message) + public override bool SendMsgWithoutReturn(OpcParamIn message) { throw new NotImplementedException(); } - public override Task SendMsgWithoutReturnAsync(byte[] message) + public override Task SendMsgWithoutReturnAsync(OpcParamIn message) { throw new NotImplementedException(); } - public override byte[] SendMsg(byte[] message) + public override OpcParamOut SendMsg(OpcParamIn message) { return AsyncHelper.RunSync(() => SendMsgAsync(message)); } @@ -88,82 +88,41 @@ namespace Modbus.Net.OPC return tagSplitList.ToArray(); } - public override async Task SendMsgAsync(byte[] message) + public override async Task SendMsgAsync(OpcParamIn message) { try { - var pos = 0; - var protocal = BigEndianValueHelper.Instance.GetByte(message, ref pos); - if (protocal == 0) + if (message.IsRead) { - var tagBytes = new byte[message.Length - 6]; - Array.Copy(message, 1, tagBytes, 0, tagBytes.Length); - pos += tagBytes.Length; - pos += 4; - var split = Encoding.UTF8.GetString(new[] { message[pos] }); - var tag = Encoding.UTF8.GetString(tagBytes); - var tagSplit = SplitTag(tag, split[0]); + var split = message.Split; + var tag = message.Tag; + var tagSplit = SplitTag(tag, split); var rootDirectory = await Client.ExploreFolderAsync(""); - var answerTag = await SearchTag(tagSplit, split[0], 0, rootDirectory); + var answerTag = await SearchTag(tagSplit, split, 0, rootDirectory); if (answerTag != null) { var result = await Client.ReadAsync(answerTag); - return BigEndianValueHelper.Instance.GetBytes(result, result.GetType()); + return new OpcParamOut + { + Success = true, + Value = BigEndianValueHelper.Instance.GetBytes(result, result.GetType()) + }; } - return Encoding.ASCII.GetBytes("NoData"); + return new OpcParamOut() + { + Success = false, + Value = Encoding.ASCII.GetBytes("NoData") + }; } else { - var index = 0; - for (var i = 1; i < message.Length - 3; i++) - { - if (message[i] == 0x00 && message[i + 1] == 0xff && message[i + 2] == 0xff && - message[i + 3] == 0x00) - { - index = i; - break; - } - } - - var index2 = 0; - for (var i = index + 4; i < message.Length - 3; i++) - { - if (message[i] == 0x00 && message[i + 1] == 0xff && message[i + 2] == 0xff && - message[i + 3] == 0x00) - { - index2 = i; - break; - } - } - - var index3 = 0; - for (var i = index2 + 4; i < message.Length - 3; i++) - { - if (message[i] == 0x00 && message[i + 1] == 0xff && message[i + 2] == 0xff && - message[i + 3] == 0x00) - { - index3 = i; - break; - } - } - - var tagBytes = new byte[index - 1]; - Array.Copy(message, 1, tagBytes, 0, tagBytes.Length); - var tag = Encoding.UTF8.GetString(tagBytes); - var splitBytes = new byte[index2 - index - 4]; - Array.Copy(message, index + 4, splitBytes, 0, splitBytes.Length); - var split = Encoding.UTF8.GetString(splitBytes); - var typeBytes = new byte[index3 - index2 - 4]; - Array.Copy(message, index2 + 4, typeBytes, 0, typeBytes.Length); - var type = Type.GetType(Encoding.UTF8.GetString(typeBytes)); - var valueBytes = new byte[message.Length - index3 - 4]; - Array.Copy(message, index3 + 4, valueBytes, 0, valueBytes.Length); - int mainpos = 0, subpos = 0; - var value = BigEndianValueHelper.Instance.GetValue(valueBytes, ref mainpos, ref subpos, type); + var tag = message.Tag; + var split = message.Split; + var value = message.SetValue; var rootDirectory = await Client.ExploreFolderAsync(""); - var tagSplit = SplitTag(tag, split[0]); - var answerTag = await SearchTag(tagSplit, split[0], 0, rootDirectory); + var tagSplit = SplitTag(tag, split); + var answerTag = await SearchTag(tagSplit, split, 0, rootDirectory); if (answerTag != null) { try @@ -173,17 +132,30 @@ namespace Modbus.Net.OPC catch (Exception e) { AddInfo("opc write exception:" + e.Message); - return new byte[] { 0 }; - } - return new byte[] {1}; + return new OpcParamOut() + { + Success = false + }; + } + return new OpcParamOut() + { + Success = true + }; } - return new byte[] {0}; + return new OpcParamOut() + { + Success = false + }; } } catch (Exception e) { AddInfo("opc client exception:" + e.Message); - return Encoding.ASCII.GetBytes("NoData"); + return new OpcParamOut() + { + Success = false, + Value = Encoding.ASCII.GetBytes("NoData") + }; } } diff --git a/Modbus.Net/Modbus.Net.OPC/OpcDaProtocalLinker.cs b/Modbus.Net/Modbus.Net.OPC/OpcDaProtocalLinker.cs index 11ec17d..2307645 100644 --- a/Modbus.Net/Modbus.Net.OPC/OpcDaProtocalLinker.cs +++ b/Modbus.Net/Modbus.Net.OPC/OpcDaProtocalLinker.cs @@ -5,7 +5,7 @@ namespace Modbus.Net.OPC /// /// Opc Da协议连接器 /// - public class OpcDaProtocalLinker : ProtocalLinker + public class OpcDaProtocalLinker : OpcProtocalLinker { public OpcDaProtocalLinker() : this(ConfigurationManager.OpcDaHost) { @@ -15,14 +15,5 @@ namespace Modbus.Net.OPC { BaseConnector = OpcDaConnector.Instance(host); } - - public override bool? CheckRight(byte[] content) - { - if (content != null && content.Length == 6 && Encoding.ASCII.GetString(content) == "NoData") - { - return null; - } - return base.CheckRight(content); - } } } \ No newline at end of file diff --git a/Modbus.Net/Modbus.Net.OPC/OpcProtocal.cs b/Modbus.Net/Modbus.Net.OPC/OpcProtocal.cs index 5a3025a..119b088 100644 --- a/Modbus.Net/Modbus.Net.OPC/OpcProtocal.cs +++ b/Modbus.Net/Modbus.Net.OPC/OpcProtocal.cs @@ -5,7 +5,7 @@ namespace Modbus.Net.OPC /// /// Opc协议 /// - public abstract class OpcProtocal : BaseProtocal + public abstract class OpcProtocal : BaseProtocal> { protected OpcProtocal() : base(0, 0, Endian.BigEndianLsb) { @@ -16,14 +16,14 @@ namespace Modbus.Net.OPC public class ReadRequestOpcInputStruct : IInputStruct { - public ReadRequestOpcInputStruct(string tag, string split) + public ReadRequestOpcInputStruct(string tag, char split) { Tag = tag; Split = split; } public string Tag { get; } - public string Split { get; } + public char Split { get; } } public class ReadRequestOpcOutputStruct : IOutputStruct @@ -36,17 +36,22 @@ namespace Modbus.Net.OPC public byte[] GetValue { get; private set; } } - public class ReadRequestOpcProtocal : ProtocalUnit, ISpecialProtocalUnit + public class ReadRequestOpcProtocal : ProtocalUnit, ISpecialProtocalUnit { - public override byte[] Format(IInputStruct message) + public override OpcParamIn Format(IInputStruct message) { var r_message = (ReadRequestOpcInputStruct) message; - return Format((byte) 0x00, Encoding.UTF8.GetBytes(r_message.Tag), 0x00ffff00, Encoding.UTF8.GetBytes(r_message.Split)); + return new OpcParamIn() + { + IsRead = true, + Tag = r_message.Tag, + Split = r_message.Split + }; } - public override IOutputStruct Unformat(byte[] messageBytes, ref int pos) + public override IOutputStruct Unformat(OpcParamOut messageBytes, ref int pos) { - return new ReadRequestOpcOutputStruct(messageBytes); + return new ReadRequestOpcOutputStruct(messageBytes.Value); } } @@ -56,7 +61,7 @@ namespace Modbus.Net.OPC public class WriteRequestOpcInputStruct : IInputStruct { - public WriteRequestOpcInputStruct(string tag, string split, object setValue) + public WriteRequestOpcInputStruct(string tag, char split, object setValue) { Tag = tag; Split = split; @@ -64,7 +69,7 @@ namespace Modbus.Net.OPC } public string Tag { get; } - public string Split { get; } + public char Split { get; } public object SetValue { get; } } @@ -78,20 +83,23 @@ namespace Modbus.Net.OPC public bool WriteResult { get; private set; } } - public class WriteRequestOpcProtocal : ProtocalUnit, ISpecialProtocalUnit + public class WriteRequestOpcProtocal : ProtocalUnit, ISpecialProtocalUnit { - public override byte[] Format(IInputStruct message) + public override OpcParamIn Format(IInputStruct message) { var r_message = (WriteRequestOpcInputStruct) message; - var tag = Encoding.UTF8.GetBytes(r_message.Tag); - var fullName = Encoding.UTF8.GetBytes(r_message.SetValue.GetType().FullName); - var split = Encoding.UTF8.GetBytes(r_message.Split); - return Format((byte) 0x01, tag, 0x00ffff00, split, 0x00ffff00, fullName, 0x00ffff00, r_message.SetValue); + return new OpcParamIn() + { + IsRead = false, + Tag = r_message.Tag, + Split = r_message.Split, + SetValue = r_message.SetValue + }; } - public override IOutputStruct Unformat(byte[] messageBytes, ref int pos) + public override IOutputStruct Unformat(OpcParamOut messageBytes, ref int pos) { - var ansByte = BigEndianValueHelper.Instance.GetByte(messageBytes, ref pos); + var ansByte = BigEndianValueHelper.Instance.GetByte(messageBytes.Value, ref pos); var ans = ansByte != 0; return new WriteRequestOpcOutputStruct(ans); } diff --git a/Modbus.Net/Modbus.Net.OPC/OpcProtocalLinker.cs b/Modbus.Net/Modbus.Net.OPC/OpcProtocalLinker.cs new file mode 100644 index 0000000..352e534 --- /dev/null +++ b/Modbus.Net/Modbus.Net.OPC/OpcProtocalLinker.cs @@ -0,0 +1,24 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Modbus.Net.OPC +{ + /// + /// Opc协议连接器 + /// + public abstract class OpcProtocalLinker : ProtocalLinker + { + public override bool? CheckRight(OpcParamOut content) + { + if (content == null || !content.Success) return false; + if (content.Value.Length == 6 && Encoding.ASCII.GetString(content.Value) == "NoData") + { + return null; + } + return base.CheckRight(content); + } + } +} diff --git a/Modbus.Net/Modbus.Net.OPC/OpcUaProtocalLinker.cs b/Modbus.Net/Modbus.Net.OPC/OpcUaProtocalLinker.cs index 46673ee..dd090e5 100644 --- a/Modbus.Net/Modbus.Net.OPC/OpcUaProtocalLinker.cs +++ b/Modbus.Net/Modbus.Net.OPC/OpcUaProtocalLinker.cs @@ -9,7 +9,7 @@ namespace Modbus.Net.OPC /// /// Opc Da协议连接器 /// - public class OpcUaProtocalLinker : ProtocalLinker + public class OpcUaProtocalLinker : OpcProtocalLinker { public OpcUaProtocalLinker() : this(ConfigurationManager.OpcUaHost) { @@ -19,14 +19,5 @@ namespace Modbus.Net.OPC { BaseConnector = OpcUaConnector.Instance(host); } - - public override bool? CheckRight(byte[] content) - { - if (content != null && content.Length == 6 && Encoding.ASCII.GetString(content) == "NoData") - { - return null; - } - return base.CheckRight(content); - } } } diff --git a/Modbus.Net/Modbus.Net.OPC/OpcUtility.cs b/Modbus.Net/Modbus.Net.OPC/OpcUtility.cs index 18e3fa3..137637b 100644 --- a/Modbus.Net/Modbus.Net.OPC/OpcUtility.cs +++ b/Modbus.Net/Modbus.Net.OPC/OpcUtility.cs @@ -6,7 +6,7 @@ using System.Threading.Tasks; namespace Modbus.Net.OPC { - public abstract class OpcUtility : BaseUtility + public abstract class OpcUtility : BaseUtility { protected OpcUtility(string connectionString) : base(0, 0) { @@ -30,7 +30,7 @@ namespace Modbus.Net.OPC try { var split = GetSeperator?.Invoke() ?? '/'; - var readRequestOpcInputStruct = new ReadRequestOpcInputStruct(startAddress, split.ToString()); + var readRequestOpcInputStruct = new ReadRequestOpcInputStruct(startAddress, split); var readRequestOpcOutputStruct = await Wrapper.SendReceiveAsync(Wrapper[typeof(ReadRequestOpcProtocal)], readRequestOpcInputStruct); @@ -47,7 +47,7 @@ namespace Modbus.Net.OPC try { var split = GetSeperator?.Invoke() ?? '/'; - var writeRequestOpcInputStruct = new WriteRequestOpcInputStruct(startAddress, split.ToString(), setContents[0]); + var writeRequestOpcInputStruct = new WriteRequestOpcInputStruct(startAddress, split, setContents[0]); var writeRequestOpcOutputStruct = await Wrapper.SendReceiveAsync(Wrapper[typeof(WriteRequestOpcProtocal)], writeRequestOpcInputStruct); diff --git a/Modbus.Net/src/Base.Common/BaseMachine.cs b/Modbus.Net/src/Base.Common/BaseMachine.cs index b367f3a..10f8bdc 100644 --- a/Modbus.Net/src/Base.Common/BaseMachine.cs +++ b/Modbus.Net/src/Base.Common/BaseMachine.cs @@ -200,7 +200,7 @@ namespace Modbus.Net /// /// 设备的连接器 /// - protected BaseUtility BaseUtility { get; set; } + public IUtilityProperty BaseUtility { get; protected set; } /// /// 设备的Id @@ -254,7 +254,7 @@ namespace Modbus.Net //获取数据 var datas = await - BaseUtility.GetDatasAsync( + BaseUtility.InvokeUtilityMethod>("GetDatasAsync", AddressFormater.FormatAddress(communicateAddress.Area, communicateAddress.Address, communicateAddress.SubAddress), (int) @@ -454,7 +454,7 @@ namespace Modbus.Net var addressStart = AddressFormater.FormatAddress(communicateAddress.Area, communicateAddress.Address); - var datasReturn = await BaseUtility.GetDatasAsync( + var datasReturn = await BaseUtility.InvokeUtilityMethod>("GetDatasAsync", AddressFormater.FormatAddress(communicateAddress.Area, communicateAddress.Address, 0), (int) Math.Ceiling(communicateAddress.GetCount* @@ -544,7 +544,7 @@ namespace Modbus.Net } //写入数据 await - BaseUtility.SetDatasAsync(addressStart, + BaseUtility.InvokeUtilityMethod>("SetDatasAsync",addressStart, valueHelper.ByteArrayToObjectArray(datas, new KeyValuePair(communicateAddress.DataType, communicateAddress.GetCount))); } @@ -580,27 +580,6 @@ namespace Modbus.Net } } - /// - /// 调用Utility中的方法 - /// - /// Utility实现的接口名称 - /// 返回值的类型 - /// 方法的名称 - /// 方法的参数 - /// - public TReturnType InvokeUtilityMethod(string methodName, - params object[] parameters) where TUtilityMethod : IUtilityMethod - { - if (BaseUtility is TUtilityMethod) - { - Type t = typeof(TUtilityMethod); - object returnValue = t.GetRuntimeMethod(methodName, parameters.Select(p => p.GetType()).ToArray()) - .Invoke(BaseUtility, parameters); - return (TReturnType) returnValue; - } - throw new InvalidCastException($"Utility未实现{typeof(TUtilityMethod).Name}的接口"); - } - /// /// 调用Machine中的方法 /// @@ -865,6 +844,11 @@ namespace Modbus.Net /// bool KeepConnect { get; set; } + /// + /// 设备的连接器 + /// + IUtilityProperty BaseUtility { get; } + /// /// 调用Machine中的方法 /// @@ -877,15 +861,10 @@ namespace Modbus.Net params object[] parameters) where TMachineMethod : IMachineMethod; /// - /// 调用Utility中的方法 + /// 连接设备 /// - /// Utility实现的接口名称 - /// 返回值的类型 - /// 方法的名称 - /// 方法的参数 - /// - TReturnType InvokeUtilityMethod(string methodName, - params object[] parameters) where TUtilityMethod : IUtilityMethod; + /// 是否连接成功 + bool Connect(); /// /// 连接设备 diff --git a/Modbus.Net/src/Base.Common/BaseProtocal.cs b/Modbus.Net/src/Base.Common/BaseProtocal.cs index 4b473bc..1d7101d 100644 --- a/Modbus.Net/src/Base.Common/BaseProtocal.cs +++ b/Modbus.Net/src/Base.Common/BaseProtocal.cs @@ -8,66 +8,18 @@ namespace Modbus.Net /// /// 基本协议 /// - public abstract class BaseProtocal + public abstract class BaseProtocal : BaseProtocal { - /// - /// 构造器 - /// - protected BaseProtocal(byte slaveAddress, byte masterAddress, Endian endian) - { - Endian = endian; - Protocals = new Dictionary(); - SlaveAddress = slaveAddress; - MasterAddress = masterAddress; - } - - protected Endian Endian { get; set; } - - public byte SlaveAddress { get; set; } - public byte MasterAddress { get; set; } - /// /// 协议的连接器 /// - public ProtocalLinker ProtocalLinker { get; protected set; } + public new ProtocalLinker ProtocalLinker { get; set; } /// - /// 协议索引器,这是一个懒加载协议,当字典中不存在协议时自动加载协议,否则调用已经加载的协议 + /// 构造器 /// - /// 协议的类的GetType - /// 协议的实例 - public ProtocalUnit this[Type type] + protected BaseProtocal(byte slaveAddress, byte masterAddress, Endian endian) : base(slaveAddress, masterAddress, endian) { - get - { - var protocalName = type.FullName; - if (Protocals.ContainsKey(protocalName)) - { - return Protocals[protocalName]; - } - //自动寻找存在的协议并将其加载 - var protocalUnit = - Activator.CreateInstance(type.GetTypeInfo().Assembly.GetType(protocalName)) as ProtocalUnit; - if (protocalUnit == null) throw new InvalidCastException("没有相应的协议内容"); - protocalUnit.Endian = Endian; - Register(protocalUnit); - return Protocals[protocalName]; - } - } - - /// - /// 协议集合 - /// - protected Dictionary Protocals { get; } - - /// - /// 注册一个协议 - /// - /// 需要注册的协议 - protected void Register(ProtocalUnit linkProtocal) - { - if (linkProtocal == null) return; - Protocals.Add(linkProtocal.GetType().FullName, linkProtocal); } /// @@ -85,7 +37,7 @@ namespace Modbus.Net /// /// 写入的内容,使用对象数组描述 /// 从设备获取的字节流 - public virtual async Task SendReceiveAsync(params object[] content) + public override async Task SendReceiveAsync(params object[] content) { if (ProtocalLinker == null || !ProtocalLinker.IsConnected) { @@ -97,6 +49,72 @@ namespace Modbus.Net } return null; } + } + + /// + /// 基本协议 + /// + public abstract class BaseProtocal where TProtocalUnit : ProtocalUnit + { + /// + /// 构造器 + /// + protected BaseProtocal(byte slaveAddress, byte masterAddress, Endian endian) + { + Endian = endian; + Protocals = new Dictionary(); + SlaveAddress = slaveAddress; + MasterAddress = masterAddress; + } + + protected Endian Endian { get; set; } + + public byte SlaveAddress { get; set; } + public byte MasterAddress { get; set; } + + /// + /// 协议的连接器 + /// + public ProtocalLinker ProtocalLinker { get; protected set; } + + /// + /// 协议索引器,这是一个懒加载协议,当字典中不存在协议时自动加载协议,否则调用已经加载的协议 + /// + /// 协议的类的GetType + /// 协议的实例 + public TProtocalUnit this[Type type] + { + get + { + var protocalName = type.FullName; + if (Protocals.ContainsKey(protocalName)) + { + return Protocals[protocalName]; + } + //自动寻找存在的协议并将其加载 + var protocalUnit = + Activator.CreateInstance(type.GetTypeInfo().Assembly.GetType(protocalName)) as TProtocalUnit; + if (protocalUnit == null) throw new InvalidCastException("没有相应的协议内容"); + protocalUnit.Endian = Endian; + Register(protocalUnit); + return Protocals[protocalName]; + } + } + + /// + /// 协议集合 + /// + protected Dictionary Protocals { get; } + + /// + /// 注册一个协议 + /// + /// 需要注册的协议 + protected void Register(TProtocalUnit linkProtocal) + { + if (linkProtocal == null) return; + Protocals.Add(linkProtocal.GetType().FullName, linkProtocal); + } /// /// 发送协议,通过传入需要使用的协议内容和输入结构 @@ -104,7 +122,7 @@ namespace Modbus.Net /// 协议的实例 /// 输入信息的结构化描述 /// 输出信息的结构化描述 - public virtual IOutputStruct SendReceive(ProtocalUnit unit, IInputStruct content) + public virtual IOutputStruct SendReceive(TProtocalUnit unit, IInputStruct content) { return AsyncHelper.RunSync(() => SendReceiveAsync(unit, content)); } @@ -116,7 +134,7 @@ namespace Modbus.Net /// 输入信息的结构化描述 /// 输出信息的结构化描述 /// IOutputStruct的具体类型 - public virtual T SendReceive(ProtocalUnit unit, IInputStruct content) where T : class, IOutputStruct + public virtual T SendReceive(TProtocalUnit unit, IInputStruct content) where T : class, IOutputStruct { return AsyncHelper.RunSync(() => SendReceiveAsync(unit, content)); } @@ -127,7 +145,7 @@ namespace Modbus.Net /// 协议的实例 /// 输入信息的结构化描述 /// 输出信息的结构化描述 - public virtual async Task SendReceiveAsync(ProtocalUnit unit, IInputStruct content) + public virtual async Task SendReceiveAsync(TProtocalUnit unit, IInputStruct content) { return await SendReceiveAsync(unit, content); } @@ -139,13 +157,13 @@ namespace Modbus.Net /// 输入信息的结构化描述 /// 输出信息的结构化描述 /// IOutputStruct的具体类型 - public virtual async Task SendReceiveAsync(ProtocalUnit unit, IInputStruct content) where T : class, IOutputStruct + public virtual async Task SendReceiveAsync(TProtocalUnit unit, IInputStruct content) where T : class, IOutputStruct { var t = 0; var formatContent = unit.Format(content); if (formatContent != null) { - byte[] receiveContent; + TParamOut receiveContent; //如果为特别处理协议的话,跳过协议扩展收缩 if (unit is ISpecialProtocalUnit) { @@ -163,6 +181,11 @@ namespace Modbus.Net return null; } + public virtual async Task SendReceiveAsync(params object[] content) + { + throw new NotImplementedException(); + } + /// /// 协议连接开始 /// diff --git a/Modbus.Net/src/Base.Common/BaseUtility.cs b/Modbus.Net/src/Base.Common/BaseUtility.cs index a88228e..085ed67 100644 --- a/Modbus.Net/src/Base.Common/BaseUtility.cs +++ b/Modbus.Net/src/Base.Common/BaseUtility.cs @@ -1,28 +1,59 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Reflection; using System.Threading.Tasks; +/// +/// 端格式 +/// public enum Endian { + /// + /// 小端 + /// LittleEndianLsb, + /// + /// 大端-小端位 + /// BigEndianLsb, + /// + /// 大端-大端位 + /// BigEndianMsb } namespace Modbus.Net { - + /// + /// 基础Api入口 + /// + public abstract class BaseUtility : BaseUtility + { + /// + /// 构造器 + /// + protected BaseUtility(byte slaveAddress, byte masterAddress) : base(slaveAddress, masterAddress) + { + + } + + /// + /// 协议收发主体 + /// + protected new BaseProtocal Wrapper; + + } /// /// 基础Api入口 /// - public abstract class BaseUtility : IUtilityData + public abstract class BaseUtility : IUtilityProperty, IUtilityData { /// /// 协议收发主体 /// - protected BaseProtocal Wrapper; + protected BaseProtocal> Wrapper; /// /// 构造器 @@ -34,9 +65,18 @@ namespace Modbus.Net AddressTranslator = new AddressTranslatorBase(); } + /// + /// 连接字符串 + /// protected string ConnectionString { get; set; } + /// + /// 从站号 + /// public byte SlaveAddress { get; set; } + /// + /// 主站号 + /// public byte MasterAddress { get; set; } /// @@ -241,5 +281,80 @@ namespace Modbus.Net { return Wrapper.Disconnect(); } + + /// + /// 调用Utility中的方法 + /// + /// Utility实现的接口名称 + /// 返回值的类型 + /// 方法的名称 + /// 方法的参数 + /// + public TReturnType InvokeUtilityMethod(string methodName, + params object[] parameters) where TUtilityMethod : IUtilityMethod + { + if (this is TUtilityMethod) + { + Type t = typeof(TUtilityMethod); + object returnValue = t.GetRuntimeMethod(methodName, parameters.Select(p => p.GetType()).ToArray()) + .Invoke(this, parameters); + return (TReturnType)returnValue; + } + throw new InvalidCastException($"Utility未实现{typeof(TUtilityMethod).Name}的接口"); + } + } + + /// + /// Api入口的抽象 + /// + public interface IUtilityProperty + { + /// + /// 协议是否遵循小端格式 + /// + Endian Endian { get; } + + /// + /// 设备是否已经连接 + /// + bool IsConnected { get; } + /// + /// 标识设备的连接关键字 + /// + string ConnectionToken { get; } + + /// + /// 地址翻译器 + /// + AddressTranslator AddressTranslator { get; set; } + + /// + /// 连接设备 + /// + /// 设备是否连接成功 + bool Connect(); + + /// + /// 连接设备 + /// + /// 设备是否连接成功 + Task ConnectAsync(); + + /// + /// 断开设备 + /// + /// 设备是否断开成功 + bool Disconnect(); + + /// + /// 调用Utility中的方法 + /// + /// Utility实现的接口名称 + /// 返回值的类型 + /// 方法的名称 + /// 方法的参数 + /// + TReturnType InvokeUtilityMethod(string methodName, + params object[] parameters) where TUtilityMethod : IUtilityMethod; } } \ No newline at end of file diff --git a/Modbus.Net/src/Base.Common/IProtocalFormatting.cs b/Modbus.Net/src/Base.Common/IProtocalFormatting.cs index eca6262..0fcad73 100644 --- a/Modbus.Net/src/Base.Common/IProtocalFormatting.cs +++ b/Modbus.Net/src/Base.Common/IProtocalFormatting.cs @@ -3,14 +3,22 @@ /// /// 协议转换的接口 /// - public interface IProtocalFormatting + public interface IProtocalFormatting : IProtocalFormatting + { + + } + + /// + /// 协议转换的接口 + /// + public interface IProtocalFormatting { /// /// 从输入结构格式化 /// /// 结构化的输入数据 /// 格式化后的字节流 - byte[] Format(IInputStruct message); + TParamIn Format(IInputStruct message); /// /// 从对象的参数数组格式化 @@ -25,6 +33,15 @@ /// 返回数据的字节流 /// 转换标记位 /// 结构化的输出数据 - IOutputStruct Unformat(byte[] messageBytes, ref int pos); + IOutputStruct Unformat(TParamOut messageBytes, ref int pos); + + /// + /// 把仪器返回的内容填充到输出结构中 + /// + /// 返回数据的字节流 + /// 转换标记位 + /// IOutputStruct的具体类型 + /// 结构化的输出数据 + T Unformat(TParamOut messageBytes, ref int pos) where T : class, IOutputStruct; } } \ No newline at end of file diff --git a/Modbus.Net/src/Base.Common/ProtocalLinker.cs b/Modbus.Net/src/Base.Common/ProtocalLinker.cs index 5a244b0..1ca94be 100644 --- a/Modbus.Net/src/Base.Common/ProtocalLinker.cs +++ b/Modbus.Net/src/Base.Common/ProtocalLinker.cs @@ -7,9 +7,72 @@ namespace Modbus.Net /// /// 基本的协议连接器 /// - public abstract class ProtocalLinker + public abstract class ProtocalLinker : ProtocalLinker { - protected BaseConnector BaseConnector; + protected new BaseConnector BaseConnector; + + /// + /// 发送并接收数据 + /// + /// 发送协议的内容 + /// 接收协议的内容 + public override async Task SendReceiveAsync(byte[] content) + { + var extBytes = BytesExtend(content); + var receiveBytes = await SendReceiveWithoutExtAndDecAsync(extBytes); + return receiveBytes == null ? null : receiveBytes.Length == 0 ? receiveBytes : BytesDecact(receiveBytes); + } + + /// + /// 发送并接收数据,不进行协议扩展和收缩,用于特殊协议 + /// + /// 发送协议的内容 + /// 接收协议的内容 + public override async Task SendReceiveWithoutExtAndDecAsync(byte[] content) + { + //发送数据 + var receiveBytes = await BaseConnector.SendMsgAsync(content); + //容错处理 + var checkRight = CheckRight(receiveBytes); + return checkRight == null ? new byte[0] : (!checkRight.Value ? null : receiveBytes); + //返回字符 + } + + /// + /// 协议内容扩展,发送时根据需要扩展 + /// + /// 扩展前的基本协议内容 + /// 扩展后的协议内容 + public override byte[] BytesExtend(byte[] content) + { + //自动查找相应的协议放缩类,命令规则为——当前的实际类名(注意是继承后的)+"BytesExtend"。 + var bytesExtend = + Activator.CreateInstance(GetType().GetTypeInfo().Assembly.GetType(GetType().FullName + "BytesExtend")) as + IProtocalLinkerBytesExtend; + return bytesExtend?.BytesExtend(content); + } + + /// + /// 协议内容缩减,接收时根据需要缩减 + /// + /// 缩减前的完整协议内容 + /// 缩减后的协议内容 + public override byte[] BytesDecact(byte[] content) + { + //自动查找相应的协议放缩类,命令规则为——当前的实际类名(注意是继承后的)+"BytesExtend"。 + var bytesExtend = + Activator.CreateInstance(GetType().GetTypeInfo().Assembly.GetType(GetType().FullName + "BytesExtend")) as + IProtocalLinkerBytesExtend; + return bytesExtend?.BytesDecact(content); + } + } + + /// + /// 基本的协议连接器 + /// + public abstract class ProtocalLinker + { + protected BaseConnector BaseConnector; public string ConnectionToken => BaseConnector.ConnectionToken; @@ -50,7 +113,7 @@ namespace Modbus.Net /// /// 发送协议的内容 /// 接收协议的内容 - public virtual byte[] SendReceive(byte[] content) + public virtual TParamOut SendReceive(TParamIn content) { return AsyncHelper.RunSync(() => SendReceiveAsync(content)); } @@ -60,11 +123,12 @@ namespace Modbus.Net /// /// 发送协议的内容 /// 接收协议的内容 - public virtual async Task SendReceiveAsync(byte[] content) + public virtual async Task SendReceiveAsync(TParamIn content) { var extBytes = BytesExtend(content); var receiveBytes = await SendReceiveWithoutExtAndDecAsync(extBytes); - return receiveBytes == null ? null : receiveBytes.Length == 0 ? receiveBytes : BytesDecact(receiveBytes); + if (receiveBytes != null) return receiveBytes; + throw new NullReferenceException(); } /// @@ -72,7 +136,7 @@ namespace Modbus.Net /// /// 发送协议的内容 /// 接收协议的内容 - public virtual byte[] SendReceiveWithoutExtAndDec(byte[] content) + public virtual TParamOut SendReceiveWithoutExtAndDec(TParamIn content) { return AsyncHelper.RunSync(() => SendReceiveWithoutExtAndDecAsync(content)); } @@ -82,14 +146,15 @@ namespace Modbus.Net /// /// 发送协议的内容 /// 接收协议的内容 - public virtual async Task SendReceiveWithoutExtAndDecAsync(byte[] content) + public virtual async Task SendReceiveWithoutExtAndDecAsync(TParamIn content) { //发送数据 var receiveBytes = await BaseConnector.SendMsgAsync(content); //容错处理 var checkRight = CheckRight(receiveBytes); - return checkRight == null ? new byte[0] : (!checkRight.Value ? null : receiveBytes); //返回字符 + if (checkRight == true) return receiveBytes; + throw new NullReferenceException(); } /// @@ -97,7 +162,7 @@ namespace Modbus.Net /// /// 接收协议的内容 /// 协议是否是正确的 - public virtual bool? CheckRight(byte[] content) + public virtual bool? CheckRight(TParamOut content) { if (content != null) return true; Disconnect(); @@ -109,13 +174,9 @@ namespace Modbus.Net /// /// 扩展前的基本协议内容 /// 扩展后的协议内容 - public byte[] BytesExtend(byte[] content) + public virtual TParamIn BytesExtend(TParamIn content) { - //自动查找相应的协议放缩类,命令规则为——当前的实际类名(注意是继承后的)+"BytesExtend"。 - var bytesExtend = - Activator.CreateInstance(GetType().GetTypeInfo().Assembly.GetType(GetType().FullName + "BytesExtend")) as - IProtocalLinkerBytesExtend; - return bytesExtend?.BytesExtend(content); + throw new NotImplementedException(); } /// @@ -123,13 +184,9 @@ namespace Modbus.Net /// /// 缩减前的完整协议内容 /// 缩减后的协议内容 - public byte[] BytesDecact(byte[] content) + public virtual TParamOut BytesDecact(TParamOut content) { - //自动查找相应的协议放缩类,命令规则为——当前的实际类名(注意是继承后的)+"BytesExtend"。 - var bytesExtend = - Activator.CreateInstance(GetType().GetTypeInfo().Assembly.GetType(GetType().FullName + "BytesExtend")) as - IProtocalLinkerBytesExtend; - return bytesExtend?.BytesDecact(content); + throw new NotImplementedException(); } } } \ No newline at end of file diff --git a/Modbus.Net/src/Base.Common/ProtocalUnit.cs b/Modbus.Net/src/Base.Common/ProtocalUnit.cs index 46aff85..33b7506 100644 --- a/Modbus.Net/src/Base.Common/ProtocalUnit.cs +++ b/Modbus.Net/src/Base.Common/ProtocalUnit.cs @@ -5,7 +5,15 @@ namespace Modbus.Net /// /// 协议单元 /// - public abstract class ProtocalUnit : IProtocalFormatting + public abstract class ProtocalUnit : ProtocalUnit + { + + } + + /// + /// 协议单元 + /// + public abstract class ProtocalUnit : IProtocalFormatting { /// /// 是否为小端格式 @@ -17,7 +25,7 @@ namespace Modbus.Net /// s /// 结构化的输入数据 /// 格式化后的字节流 - public abstract byte[] Format(IInputStruct message); + public abstract TParamIn Format(IInputStruct message); /// /// 从对象的参数数组格式化 @@ -35,7 +43,7 @@ namespace Modbus.Net /// 返回数据的字节流 /// 转换标记位 /// 结构化的输出数据 - public abstract IOutputStruct Unformat(byte[] messageBytes, ref int pos); + public abstract IOutputStruct Unformat(TParamOut messageBytes, ref int pos); /// /// 把仪器返回的内容填充到输出结构中 @@ -44,7 +52,7 @@ namespace Modbus.Net /// 转换标记位 /// IOutputStruct的具体类型 /// 结构化的输出数据 - public T Unformat(byte[] messageBytes, ref int pos) where T : class, IOutputStruct + public T Unformat(TParamOut messageBytes, ref int pos) where T : class, IOutputStruct { return Unformat(messageBytes, ref pos) as T; } diff --git a/Samples/TripleAdd/Controllers/HomeController.cs b/Samples/TripleAdd/Controllers/HomeController.cs index fe8fd5d..3f7d401 100644 --- a/Samples/TripleAdd/Controllers/HomeController.cs +++ b/Samples/TripleAdd/Controllers/HomeController.cs @@ -58,8 +58,8 @@ namespace TripleAdd.Controllers new AddressUnit() {Id = "3", Area = "4X", Address = 3, CommunicationTag = "Add3", DataType = typeof(ushort), Zoom = 1, DecimalPos = 0}, new AddressUnit() {Id = "4", Area = "4X", Address = 4, CommunicationTag = "Ans", DataType = typeof(ushort), Zoom = 1, DecimalPos = 0}, }, 2, 0); - machine.AddressCombiner = new AddressCombinerContinus(machine.AddressTranslator); - machine.AddressCombinerSet = new AddressCombinerContinus(machine.AddressTranslator); + machine.AddressCombiner = new AddressCombinerContinus(machine.AddressTranslator, 100000); + machine.AddressCombinerSet = new AddressCombinerContinus(machine.AddressTranslator, 100000); } var resultFormat = (await machine.GetDatasAsync(MachineGetDataType.CommunicationTag)).MapGetValuesToSetValues(); return SetValue(new ushort[4] { (ushort)resultFormat["Add1"], (ushort)resultFormat["Add2"], (ushort)resultFormat["Add3"], (ushort)resultFormat["Ans"] }); diff --git a/Tests/Modbus.Net.Tests/MachineMethodTest.cs b/Tests/Modbus.Net.Tests/MachineMethodTest.cs index be08009..e6d980a 100644 --- a/Tests/Modbus.Net.Tests/MachineMethodTest.cs +++ b/Tests/Modbus.Net.Tests/MachineMethodTest.cs @@ -25,9 +25,9 @@ namespace Modbus.Net.Tests public async Task InvokeUtility() { BaseMachine baseMachine = new ModbusMachine(ModbusType.Tcp, "192.168.3.12", null, true, 2, 0); - var success = await baseMachine.InvokeUtilityMethod>("SetTimeAsync", DateTime.Now); + var success = await baseMachine.BaseUtility.InvokeUtilityMethod>("SetTimeAsync", DateTime.Now); Assert.AreEqual(success, true); - var time = await baseMachine.InvokeUtilityMethod>("GetTimeAsync"); + var time = await baseMachine.BaseUtility.InvokeUtilityMethod>("GetTimeAsync"); Assert.AreEqual((time.ToUniversalTime() - DateTime.Now.ToUniversalTime()).Seconds < 10, true); }