diff --git a/Modbus.Net/Modbus.Net.OPC/AddressFormaterOpc.cs b/Modbus.Net/Modbus.Net.OPC/AddressFormaterOpc.cs index ea16eb8..d4b4ca6 100644 --- a/Modbus.Net/Modbus.Net.OPC/AddressFormaterOpc.cs +++ b/Modbus.Net/Modbus.Net.OPC/AddressFormaterOpc.cs @@ -6,7 +6,7 @@ namespace Modbus.Net.OPC /// /// Opc地址编码器 /// - public class AddressFormaterOpc : AddressFormater + public class AddressFormaterOpc : AddressFormater where TMachineKey : IEquatable where TUnitKey : IEquatable { /// /// 协议构造器 @@ -14,7 +14,7 @@ namespace Modbus.Net.OPC /// 如何通过BaseMachine和AddressUnit构造Opc的标签 /// 调用这个编码器的设备 /// 每两个标签之间用什么符号隔开,默认为/ - public AddressFormaterOpc(Func tagGeter, BaseMachine machine, + public AddressFormaterOpc(Func, AddressUnit, string[]> tagGeter, BaseMachine machine, char seperator = '/') { Machine = machine; @@ -22,9 +22,9 @@ namespace Modbus.Net.OPC Seperator = seperator; } - public BaseMachine Machine { get; set; } + public BaseMachine Machine { get; set; } - protected Func TagGeter { get; set; } + protected Func, AddressUnit, string[]> TagGeter { get; set; } protected char Seperator { get; set; } diff --git a/Modbus.Net/Modbus.Net.OPC/ClientExtend.cs b/Modbus.Net/Modbus.Net.OPC/ClientExtend.cs new file mode 100644 index 0000000..dc363db --- /dev/null +++ b/Modbus.Net/Modbus.Net.OPC/ClientExtend.cs @@ -0,0 +1,42 @@ +using System; +using System.Threading.Tasks; +using Hylasoft.Opc.Common; +using Hylasoft.Opc.Da; +using Opc; +using Opc.Da; +using System.Collections.Generic; +using Hylasoft.Opc.Ua; + +namespace Modbus.Net.OPC +{ + public interface IClientExtend : IDisposable + { + void Connect(); + + T Read(string tag); + + void Write(string tag, T item); + + Task ReadAsync(string tag); + + Task WriteAsync(string tag, T item); + + Task FindNodeAsync(string tag); + + Task> ExploreFolderAsync(string tag); + } + + public class MyDaClient : DaClient, IClientExtend + { + public MyDaClient(Uri serverUrl) : base(serverUrl) + { + } + } + + public class MyUaClient : UaClient, IClientExtend + { + public MyUaClient(Uri serverUrl) : base(serverUrl) + { + } + } +} \ No newline at end of file diff --git a/Modbus.Net/Modbus.Net.OPC/DaClientExtend.cs b/Modbus.Net/Modbus.Net.OPC/DaClientExtend.cs deleted file mode 100644 index f5c196a..0000000 --- a/Modbus.Net/Modbus.Net.OPC/DaClientExtend.cs +++ /dev/null @@ -1,64 +0,0 @@ -using System; -using System.Threading.Tasks; -using Hylasoft.Opc.Common; -using Hylasoft.Opc.Da; -using Opc; -using Opc.Da; - -namespace Modbus.Net.OPC -{ - /// - /// Read value full result - /// - public class OpcValueResult - { - public object Value { get; set; } - public DateTime Timestamp { get; set; } - public bool QualityGood { get; set; } - } - - public class MyDaClient : DaClient - { - public MyDaClient(Uri serverUrl) : base(serverUrl) - { - } - - /// - /// Write a value on the specified opc tag - /// - /// - /// The fully-qualified identifier of the tag. You can specify a subfolder by using a comma delimited name. - /// E.g: the tag `foo.bar` writes on the tag `bar` on the folder `foo` - /// - public OpcValueResult Read(string tag) - { - var item = new Item {ItemName = tag}; - var result = Server.Read(new[] {item})[0]; - CheckResult(result, tag); - return new OpcValueResult - { - Value = result.Value, - Timestamp = result.Timestamp, - QualityGood = result.Quality == Quality.Good - }; - } - - /// - /// Read a tag asynchronusly - /// - public Task ReadAsync(string tag) - { - return Task.Run(() => Read(tag)); - } - - private static void CheckResult(IResult result, string tag) - { - if (result == null) - throw new OpcException("The server replied with an empty response"); - if (result.ResultID.ToString() != "S_OK") - throw new OpcException( - string.Format("Invalid response from the server. (Response Status: {0}, Opc Tag: {1})", - result.ResultID, tag)); - } - } -} \ No newline at end of file diff --git a/Modbus.Net/Modbus.Net.OPC/FBox/FBoxOpcDaManchine.cs b/Modbus.Net/Modbus.Net.OPC/FBox/FBoxOpcDaManchine.cs index 06b2d51..2e7b069 100644 --- a/Modbus.Net/Modbus.Net.OPC/FBox/FBoxOpcDaManchine.cs +++ b/Modbus.Net/Modbus.Net.OPC/FBox/FBoxOpcDaManchine.cs @@ -6,19 +6,19 @@ using System.Threading.Tasks; namespace Modbus.Net.OPC.FBox { - public class FBoxOpcDaMachine : OpcDaMachine + public class FBoxOpcDaMachine : OpcDaMachine { public string LocalSequence { get; set; } public string LinkerName { get; set; } public FBoxOpcDaMachine(string localSequence, string linkerName, - IEnumerable getAddresses, bool keepConnect) : base(ConfigurationManager.FBoxOpcDaHost, getAddresses, keepConnect) + IEnumerable> getAddresses, bool keepConnect) : base(ConfigurationManager.FBoxOpcDaHost, getAddresses, keepConnect) { LocalSequence = localSequence; LinkerName = linkerName; AddressFormater = - new AddressFormaterOpc( + new AddressFormaterOpc( (machine, unit) => new string[] { diff --git a/Modbus.Net/Modbus.Net.OPC/Modbus.Net.OPC.csproj b/Modbus.Net/Modbus.Net.OPC/Modbus.Net.OPC.csproj index 71afb08..48124b1 100644 --- a/Modbus.Net/Modbus.Net.OPC/Modbus.Net.OPC.csproj +++ b/Modbus.Net/Modbus.Net.OPC/Modbus.Net.OPC.csproj @@ -31,33 +31,26 @@ 4 - - ..\packages\H.Opc.0.7.0\lib\h-opc.dll - True + + ..\packages\H.Opc.0.8.1\lib\h-opc.dll - ..\packages\H.Opc.0.7.0\lib\Opc.Ua.Client.dll - True + ..\packages\H.Opc.0.8.1\lib\Opc.Ua.Client.dll - ..\packages\H.Opc.0.7.0\lib\Opc.Ua.Configuration.dll - True + ..\packages\H.Opc.0.8.1\lib\Opc.Ua.Configuration.dll - ..\packages\H.Opc.0.7.0\lib\Opc.Ua.Core.dll - True + ..\packages\H.Opc.0.8.1\lib\Opc.Ua.Core.dll - ..\packages\H.Opc.0.7.0\lib\OpcComRcw.dll - True + ..\packages\H.Opc.0.8.1\lib\OpcComRcw.dll - ..\packages\H.Opc.0.7.0\lib\OpcNetApi.dll - True + ..\packages\H.Opc.0.8.1\lib\OpcNetApi.dll - ..\packages\H.Opc.0.7.0\lib\OpcNetApi.Com.dll - True + ..\packages\H.Opc.0.8.1\lib\OpcNetApi.Com.dll @@ -71,14 +64,22 @@ - + + + + + + + + + diff --git a/Modbus.Net/Modbus.Net.OPC/Modbus.Net.OPC.nuspec b/Modbus.Net/Modbus.Net.OPC/Modbus.Net.OPC.nuspec index 73dfd19..e8e8965 100644 --- a/Modbus.Net/Modbus.Net.OPC/Modbus.Net.OPC.nuspec +++ b/Modbus.Net/Modbus.Net.OPC/Modbus.Net.OPC.nuspec @@ -2,7 +2,7 @@ Modbus.Net.OPC - 1.2.3 + 1.2.4 Modbus.Net.OPC Chris L.(Luo Sheng) Hangzhou Delian IoT Science Technology Co.,Ltd. @@ -14,7 +14,7 @@ hardware communicate protocal OPC DA Delian - + diff --git a/Modbus.Net/Modbus.Net.OPC/OpcConnector.cs b/Modbus.Net/Modbus.Net.OPC/OpcConnector.cs new file mode 100644 index 0000000..b5fd889 --- /dev/null +++ b/Modbus.Net/Modbus.Net.OPC/OpcConnector.cs @@ -0,0 +1,167 @@ +using Hylasoft.Opc.Common; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Text.RegularExpressions; +using System.Threading.Tasks; + +namespace Modbus.Net.OPC +{ + public abstract class OpcConnector : BaseConnector + { + protected IClientExtend Client; + + protected bool _connect; + public override string ConnectionToken { get; } + public override bool IsConnected => _connect; + + protected OpcConnector(string host) + { + ConnectionToken = host; + } + + public override bool Disconnect() + { + try + { + Client?.Dispose(); + Client = null; + _connect = false; + AddInfo("client disconnected successfully."); + return true; + } + catch (Exception ex) + { + AddInfo("client disconnected exception: " + ex.Message); + _connect = false; + return false; + } + } + + public override bool SendMsgWithoutReturn(byte[] message) + { + throw new NotImplementedException(); + } + + public override Task SendMsgWithoutReturnAsync(byte[] message) + { + throw new NotImplementedException(); + } + + public override byte[] SendMsg(byte[] message) + { + return AsyncHelper.RunSync(() => SendMsgAsync(message)); + } + + public override async Task SendMsgAsync(byte[] message) + { + try + { + var pos = 0; + var protocal = BigEndianValueHelper.Instance.GetByte(message, ref pos); + if (protocal == 0) + { + var tagBytes = new byte[message.Length - 1]; + Array.Copy(message, 1, tagBytes, 0, tagBytes.Length); + var tag = Encoding.UTF8.GetString(tagBytes); + var tagSplit = tag.Split('/'); + var rootDirectory = await Client.ExploreFolderAsync("/"); + var answerTag = await SearchTag(tagSplit, 0, rootDirectory); + if (answerTag != null) + { + var result = await Client.ReadAsync(answerTag); + return BigEndianValueHelper.Instance.GetBytes(result, result.GetType()); + } + return 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 tagBytes = new byte[index - 1]; + Array.Copy(message, 1, tagBytes, 0, tagBytes.Length); + var tag = Encoding.UTF8.GetString(tagBytes); + var typeBytes = new byte[index2 - index - 4]; + Array.Copy(message, index + 4, typeBytes, 0, typeBytes.Length); + var type = Type.GetType(Encoding.UTF8.GetString(typeBytes)); + var valueBytes = new byte[message.Length - index2 - 4]; + Array.Copy(message, index2 + 4, valueBytes, 0, valueBytes.Length); + int mainpos = 0, subpos = 0; + var value = BigEndianValueHelper.Instance.GetValue(valueBytes, ref mainpos, ref subpos, type); + await Client.WriteAsync(tag, value); + return new byte[] { 1 }; + } + } + catch (Exception e) + { + //AddInfo("opc client exception:" + e); + return Encoding.ASCII.GetBytes("NoData"); + //return null; + } + } + + private async Task SearchTag(string[] tags, int deep, IEnumerable nodes) + { + foreach (var node in nodes) + { + var currentTag = node.Tag.Substring(node.Tag.LastIndexOf('/')); + if (Regex.IsMatch(currentTag, tags[deep])) + { + if (deep == tags.Length) return currentTag; + var subDirectories = await Client.ExploreFolderAsync(node.Tag); + var answerTag = await SearchTag(tags, deep + 1, subDirectories); + if (answerTag != null) return answerTag; + } + } + return null; + } + + protected void AddInfo(string message) + { + Console.WriteLine(message); + } + + public override bool Connect() + { + try + { + Client.Connect(); + _connect = true; + AddInfo("client connected."); + return true; + } + catch (Exception ex) + { + AddInfo("client connected exception: " + ex.Message); + AddInfo("connect failed."); + _connect = false; + return false; + } + } + + public override Task ConnectAsync() + { + return Task.FromResult(Connect()); + } + } +} diff --git a/Modbus.Net/Modbus.Net.OPC/OpcDaConnector.cs b/Modbus.Net/Modbus.Net.OPC/OpcDaConnector.cs index 9538441..1beddcb 100644 --- a/Modbus.Net/Modbus.Net.OPC/OpcDaConnector.cs +++ b/Modbus.Net/Modbus.Net.OPC/OpcDaConnector.cs @@ -1,6 +1,8 @@ -using System; +using Hylasoft.Opc.Common; +using System; using System.Collections.Generic; using System.Text; +using System.Text.RegularExpressions; using System.Threading.Tasks; namespace Modbus.Net.OPC @@ -8,21 +10,15 @@ namespace Modbus.Net.OPC /// /// OpcDa协议连接实现 /// - public class OpcDaConnector : BaseConnector + public class OpcDaConnector : OpcConnector { protected static Dictionary _instances = new Dictionary(); - protected bool _connect; - protected MyDaClient _daClient; - - protected OpcDaConnector(string host) + protected OpcDaConnector(string host) : base(host) { - ConnectionToken = host; + Client = new MyDaClient(new Uri(ConnectionToken)); } - public override string ConnectionToken { get; } - public override bool IsConnected => _connect; - public static OpcDaConnector Instance(string host) { if (!_instances.ContainsKey(host)) @@ -32,130 +28,5 @@ namespace Modbus.Net.OPC } return _instances[host]; } - - public override bool Connect() - { - try - { - _daClient = new MyDaClient(new Uri(ConnectionToken)); - _daClient.Connect(); - _connect = true; - AddInfo("client connected."); - return true; - } - catch (Exception ex) - { - AddInfo("client connected exception: " + ex.Message); - AddInfo("connect failed."); - _connect = false; - return false; - } - } - - public override Task ConnectAsync() - { - return Task.FromResult(Connect()); - } - - public override bool Disconnect() - { - try - { - _daClient?.Dispose(); - _daClient = null; - _connect = false; - AddInfo("client disconnected successfully."); - return true; - } - catch (Exception ex) - { - AddInfo("client disconnected exception: " + ex.Message); - _connect = false; - return false; - } - } - - public override bool SendMsgWithoutReturn(byte[] message) - { - throw new NotImplementedException(); - } - - public override Task SendMsgWithoutReturnAsync(byte[] message) - { - throw new NotImplementedException(); - } - - public override byte[] SendMsg(byte[] message) - { - return AsyncHelper.RunSync(() => SendMsgAsync(message)); - } - - public override async Task SendMsgAsync(byte[] message) - { - try - { - var pos = 0; - var protocal = BigEndianValueHelper.Instance.GetByte(message, ref pos); - if (protocal == 0) - { - var tagBytes = new byte[message.Length - 1]; - Array.Copy(message, 1, tagBytes, 0, tagBytes.Length); - var tag = Encoding.UTF8.GetString(tagBytes); - var result = await _daClient.ReadAsync(tag); - if (result.QualityGood) - { - return BigEndianValueHelper.Instance.GetBytes(result.Value, result.Value.GetType()); - } - return 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 tagBytes = new byte[index - 1]; - Array.Copy(message, 1, tagBytes, 0, tagBytes.Length); - var tag = Encoding.UTF8.GetString(tagBytes); - var typeBytes = new byte[index2 - index - 4]; - Array.Copy(message, index + 4, typeBytes, 0, typeBytes.Length); - var type = Type.GetType(Encoding.UTF8.GetString(typeBytes)); - var valueBytes = new byte[message.Length - index2 - 4]; - Array.Copy(message, index2 + 4, valueBytes, 0, valueBytes.Length); - int mainpos = 0, subpos = 0; - var value = BigEndianValueHelper.Instance.GetValue(valueBytes, ref mainpos, ref subpos, type); - await _daClient.WriteAsync(tag, value); - return new byte[] {1}; - } - } - catch (Exception e) - { - //AddInfo("opc client exception:" + e); - return Encoding.ASCII.GetBytes("NoData"); - //return null; - } - } - - private void AddInfo(string message) - { - Console.WriteLine(message); - } } } \ No newline at end of file diff --git a/Modbus.Net/Modbus.Net.OPC/OpcDaMachine.cs b/Modbus.Net/Modbus.Net.OPC/OpcDaMachine.cs index 0fc3694..8e02851 100644 --- a/Modbus.Net/Modbus.Net.OPC/OpcDaMachine.cs +++ b/Modbus.Net/Modbus.Net.OPC/OpcDaMachine.cs @@ -3,18 +3,12 @@ using System.Collections.Generic; namespace Modbus.Net.OPC { - /// - /// OpcDa设备 - /// - public class OpcDaMachine : BaseMachine where TKey : IEquatable - where TUnitKey : IEquatable + public class OpcDaMachine : OpcMachine where TKey : IEquatable where TUnitKey : IEquatable { public OpcDaMachine(string connectionString, IEnumerable> getAddresses, bool keepConnect) - : base(getAddresses, keepConnect) + : base(connectionString, getAddresses, keepConnect) { BaseUtility = new OpcDaUtility(connectionString); - AddressCombiner = new AddressCombinerSingle(); - AddressCombinerSet = new AddressCombinerSingle(); } public OpcDaMachine(string connectionString, IEnumerable> getAddresses) @@ -23,17 +17,12 @@ namespace Modbus.Net.OPC } } - /// - /// OpcDa设备 - /// - public class OpcDaMachine : BaseMachine + public class OpcDaMachine : OpcMachine { - public OpcDaMachine(string connectionString, IEnumerable getAddresses, bool keepConnect) - : base(getAddresses, keepConnect) + public OpcDaMachine(string connectionString, IEnumerable getAddresses, bool keepConnect) + : base(connectionString, getAddresses, keepConnect) { BaseUtility = new OpcDaUtility(connectionString); - AddressCombiner = new AddressCombinerSingle(); - AddressCombinerSet = new AddressCombinerSingle(); } public OpcDaMachine(string connectionString, IEnumerable getAddresses) diff --git a/Modbus.Net/Modbus.Net.OPC/OpcDaUtility.cs b/Modbus.Net/Modbus.Net.OPC/OpcDaUtility.cs index 8376dc7..f59ee5c 100644 --- a/Modbus.Net/Modbus.Net.OPC/OpcDaUtility.cs +++ b/Modbus.Net/Modbus.Net.OPC/OpcDaUtility.cs @@ -6,53 +6,11 @@ namespace Modbus.Net.OPC /// /// Opc Da协议Api入口 /// - public class OpcDaUtility : BaseUtility + public class OpcDaUtility : OpcUtility { - public OpcDaUtility(string connectionString) : base(0, 0) + public OpcDaUtility(string connectionString) : base(connectionString) { - ConnectionString = connectionString; - AddressTranslator = new AddressTranslatorOpc(); Wrapper = new OpcDaProtocal(ConnectionString); } - - public override Endian Endian => Endian.BigEndianLsb; - - public override void SetConnectionType(int connectionType) - { - } - - public override async Task GetDatasAsync(string startAddress, int getByteCount) - { - try - { - var readRequestOpcInputStruct = new ReadRequestOpcInputStruct(startAddress); - var readRequestOpcOutputStruct = - await - Wrapper.SendReceiveAsync(Wrapper[typeof (ReadRequestOpcProtocal)], readRequestOpcInputStruct) as - ReadRequestOpcOutputStruct; - return readRequestOpcOutputStruct?.GetValue; - } - catch (Exception) - { - return null; - } - } - - public override async Task SetDatasAsync(string startAddress, object[] setContents) - { - try - { - var writeRequestOpcInputStruct = new WriteRequestOpcInputStruct(startAddress, setContents[0]); - var writeRequestOpcOutputStruct = - await - Wrapper.SendReceiveAsync(Wrapper[typeof (WriteRequestOpcProtocal)], writeRequestOpcInputStruct) - as WriteRequestOpcOutputStruct; - return writeRequestOpcOutputStruct?.WriteResult == true; - } - catch (Exception e) - { - return false; - } - } } } \ No newline at end of file diff --git a/Modbus.Net/Modbus.Net.OPC/OpcMachine.cs b/Modbus.Net/Modbus.Net.OPC/OpcMachine.cs new file mode 100644 index 0000000..f8f1322 --- /dev/null +++ b/Modbus.Net/Modbus.Net.OPC/OpcMachine.cs @@ -0,0 +1,35 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Modbus.Net.OPC +{ + /// + /// OpcDa设备 + /// + public abstract class OpcMachine : BaseMachine where TKey : IEquatable + where TUnitKey : IEquatable + { + public OpcMachine(string connectionString, IEnumerable> getAddresses, bool keepConnect) + : base(getAddresses, keepConnect) + { + AddressCombiner = new AddressCombinerSingle(); + AddressCombinerSet = new AddressCombinerSingle(); + } + } + + /// + /// OpcDa设备 + /// + public abstract class OpcMachine : BaseMachine + { + public OpcMachine(string connectionString, IEnumerable getAddresses, bool keepConnect) + : base(getAddresses, keepConnect) + { + AddressCombiner = new AddressCombinerSingle(); + AddressCombinerSet = new AddressCombinerSingle(); + } + } +} diff --git a/Modbus.Net/Modbus.Net.OPC/OpcUaConnector.cs b/Modbus.Net/Modbus.Net.OPC/OpcUaConnector.cs new file mode 100644 index 0000000..8636986 --- /dev/null +++ b/Modbus.Net/Modbus.Net.OPC/OpcUaConnector.cs @@ -0,0 +1,34 @@ +using Hylasoft.Opc.Common; +using Hylasoft.Opc.Ua; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Text.RegularExpressions; +using System.Threading.Tasks; + +namespace Modbus.Net.OPC +{ + /// + /// OpcDa协议连接实现 + /// + public class OpcUaConnector : OpcConnector + { + protected static Dictionary _instances = new Dictionary(); + + protected OpcUaConnector(string host) : base(host) + { + Client = new MyUaClient(new Uri(ConnectionToken)); + } + + public static OpcUaConnector Instance(string host) + { + if (!_instances.ContainsKey(host)) + { + var connector = new OpcUaConnector(host); + _instances.Add(host, connector); + } + return _instances[host]; + } + } +} diff --git a/Modbus.Net/Modbus.Net.OPC/OpcUaMachine.cs b/Modbus.Net/Modbus.Net.OPC/OpcUaMachine.cs new file mode 100644 index 0000000..4a1e480 --- /dev/null +++ b/Modbus.Net/Modbus.Net.OPC/OpcUaMachine.cs @@ -0,0 +1,36 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Modbus.Net.OPC +{ + public class OpcUaMachine : OpcMachine where TKey : IEquatable where TUnitKey : IEquatable + { + public OpcUaMachine(string connectionString, IEnumerable> getAddresses, bool keepConnect) + : base(connectionString, getAddresses, keepConnect) + { + BaseUtility = new OpcUaUtility(connectionString); + } + + public OpcUaMachine(string connectionString, IEnumerable> getAddresses) + : this(connectionString, getAddresses, false) + { + } + } + + public class OpcUaMachine : OpcMachine + { + public OpcUaMachine(string connectionString, IEnumerable getAddresses, bool keepConnect) + : base(connectionString, getAddresses, keepConnect) + { + BaseUtility = new OpcUaUtility(connectionString); + } + + public OpcUaMachine(string connectionString, IEnumerable getAddresses) + : this(connectionString, getAddresses, false) + { + } + } +} diff --git a/Modbus.Net/Modbus.Net.OPC/OpcUaProtocal.cs b/Modbus.Net/Modbus.Net.OPC/OpcUaProtocal.cs new file mode 100644 index 0000000..762d487 --- /dev/null +++ b/Modbus.Net/Modbus.Net.OPC/OpcUaProtocal.cs @@ -0,0 +1,36 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Modbus.Net.OPC +{ + /// + /// OpcUa协议 + /// + public class OpcUaProtocal : OpcProtocal + { + private readonly string _host; + private int _connectTryCount; + + public OpcUaProtocal(string host) + { + _host = host; + } + + public override bool Connect() + { + return AsyncHelper.RunSync(ConnectAsync); + } + + public override async Task ConnectAsync() + { + _connectTryCount++; + ProtocalLinker = new OpcUaProtocalLinker(_host); + if (!await ProtocalLinker.ConnectAsync()) return false; + _connectTryCount = 0; + return true; + } + } +} diff --git a/Modbus.Net/Modbus.Net.OPC/OpcUaProtocalLinker.cs b/Modbus.Net/Modbus.Net.OPC/OpcUaProtocalLinker.cs new file mode 100644 index 0000000..46673ee --- /dev/null +++ b/Modbus.Net/Modbus.Net.OPC/OpcUaProtocalLinker.cs @@ -0,0 +1,32 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Modbus.Net.OPC +{ + /// + /// Opc Da协议连接器 + /// + public class OpcUaProtocalLinker : ProtocalLinker + { + public OpcUaProtocalLinker() : this(ConfigurationManager.OpcUaHost) + { + } + + public OpcUaProtocalLinker(string host) + { + 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/OpcUaUtility.cs b/Modbus.Net/Modbus.Net.OPC/OpcUaUtility.cs new file mode 100644 index 0000000..6502f2a --- /dev/null +++ b/Modbus.Net/Modbus.Net.OPC/OpcUaUtility.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Modbus.Net.OPC +{ + /// + /// Opc Da协议Api入口 + /// + public class OpcUaUtility : OpcUtility + { + public OpcUaUtility(string connectionString) : base(connectionString) + { + Wrapper = new OpcUaProtocal(ConnectionString); + } + } +} diff --git a/Modbus.Net/Modbus.Net.OPC/OpcUtility.cs b/Modbus.Net/Modbus.Net.OPC/OpcUtility.cs new file mode 100644 index 0000000..77978c8 --- /dev/null +++ b/Modbus.Net/Modbus.Net.OPC/OpcUtility.cs @@ -0,0 +1,58 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Modbus.Net.OPC +{ + public abstract class OpcUtility : BaseUtility + { + protected OpcUtility(string connectionString) : base(0, 0) + { + ConnectionString = connectionString; + AddressTranslator = new AddressTranslatorOpc(); + } + + public override Endian Endian => Endian.BigEndianLsb; + + public override void SetConnectionType(int connectionType) + { + throw new NotImplementedException(); + } + + public override async Task GetDatasAsync(string startAddress, int getByteCount) + { + try + { + var readRequestOpcInputStruct = new ReadRequestOpcInputStruct(startAddress); + var readRequestOpcOutputStruct = + await + Wrapper.SendReceiveAsync(Wrapper[typeof(ReadRequestOpcProtocal)], readRequestOpcInputStruct) as + ReadRequestOpcOutputStruct; + return readRequestOpcOutputStruct?.GetValue; + } + catch (Exception) + { + return null; + } + } + + public override async Task SetDatasAsync(string startAddress, object[] setContents) + { + try + { + var writeRequestOpcInputStruct = new WriteRequestOpcInputStruct(startAddress, setContents[0]); + var writeRequestOpcOutputStruct = + await + Wrapper.SendReceiveAsync(Wrapper[typeof(WriteRequestOpcProtocal)], writeRequestOpcInputStruct) + as WriteRequestOpcOutputStruct; + return writeRequestOpcOutputStruct?.WriteResult == true; + } + catch (Exception e) + { + return false; + } + } + } +} diff --git a/Modbus.Net/Modbus.Net.OPC/Properties/AssemblyInfo.cs b/Modbus.Net/Modbus.Net.OPC/Properties/AssemblyInfo.cs index 62e97ac..4045f29 100644 --- a/Modbus.Net/Modbus.Net.OPC/Properties/AssemblyInfo.cs +++ b/Modbus.Net/Modbus.Net.OPC/Properties/AssemblyInfo.cs @@ -32,5 +32,5 @@ using System.Runtime.InteropServices; //可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值, // 方法是按如下所示使用“*”: : // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.2.3")] -[assembly: AssemblyFileVersion("1.2.3")] +[assembly: AssemblyVersion("1.2.4")] +[assembly: AssemblyFileVersion("1.2.4")] diff --git a/Modbus.Net/Modbus.Net.OPC/packages.config b/Modbus.Net/Modbus.Net.OPC/packages.config index 9a214f5..1b83f0e 100644 --- a/Modbus.Net/Modbus.Net.OPC/packages.config +++ b/Modbus.Net/Modbus.Net.OPC/packages.config @@ -1,4 +1,4 @@  - + \ No newline at end of file diff --git a/Modbus.Net/Modbus.Net/ConfigurationManager.Designer.cs b/Modbus.Net/Modbus.Net/ConfigurationManager.Designer.cs index 4a2b49b..a465d48 100644 --- a/Modbus.Net/Modbus.Net/ConfigurationManager.Designer.cs +++ b/Modbus.Net/Modbus.Net/ConfigurationManager.Designer.cs @@ -114,6 +114,15 @@ namespace Modbus.Net { } } + /// + /// 查找类似 opc.tcp://localhost/... 的本地化字符串。 + /// + public static string OpcUaHost { + get { + return ResourceManager.GetString("OpcUaHost", resourceCulture); + } + } + /// /// 查找类似 102 的本地化字符串。 /// diff --git a/Modbus.Net/Modbus.Net/ConfigurationManager.resx b/Modbus.Net/Modbus.Net/ConfigurationManager.resx index ea86858..192a30e 100644 --- a/Modbus.Net/Modbus.Net/ConfigurationManager.resx +++ b/Modbus.Net/Modbus.Net/ConfigurationManager.resx @@ -135,6 +135,9 @@ opcda://localhost/... + + opc.tcp://localhost/... + 102 diff --git a/Modbus.Net/Modbus.Net/TaskManager.cs b/Modbus.Net/Modbus.Net/TaskManager.cs index 62acb5e..33a1d03 100644 --- a/Modbus.Net/Modbus.Net/TaskManager.cs +++ b/Modbus.Net/Modbus.Net/TaskManager.cs @@ -230,22 +230,7 @@ namespace Modbus.Net { try { - //调试代码,调试时取消下面一下代码的注释,会同步调用获取数据。 - //var ans = machine.GetDatas(); - //设置Cancellation Token - var cts = new CancellationTokenSource(); - //超时后取消任务 - cts.CancelAfter(TimeSpan.FromSeconds(GetCycle)); - //读取数据 - var ans = await machine.GetDatasAsync(GetDataType).WithCancellation(cts.Token); - if (!machine.IsConnected) - { - MoveMachineToUnlinked(machine.Id); - } - else - { - MoveMachineToLinked(machine.Id); - } + var ans = await GetValue(machine); ReturnValues?.Invoke(new TaskReturnDef { MachineId = machine.Id, @@ -790,22 +775,7 @@ namespace Modbus.Net { try { - //调试代码,调试时取消下面一下代码的注释,会同步调用获取数据。 - //var ans = machine.GetDatas(); - //设置Cancellation Token - var cts = new CancellationTokenSource(); - //超时后取消任务 - cts.CancelAfter(TimeSpan.FromSeconds(_getCycle)); - //读取数据 - var ans = await machine.GetDatasAsync(GetDataType).WithCancellation(cts.Token); - if (!machine.IsConnected) - { - MoveMachineToUnlinked(machine.Id); - } - else - { - MoveMachineToLinked(machine.Id); - } + var ans = await GetValue(machine); ReturnValues?.Invoke(new TaskReturnDef { MachineId = machine.Id, @@ -825,5 +795,26 @@ namespace Modbus.Net }); } } + + protected async Task> GetValue(IMachineProperty machine) + { + //调试代码,调试时取消下面一下代码的注释,会同步调用获取数据。 + //var ans = machine.GetDatas(); + //设置Cancellation Token + var cts = new CancellationTokenSource(); + //超时后取消任务 + cts.CancelAfter(TimeSpan.FromSeconds(_getCycle)); + //读取数据 + var ans = await machine.GetDatasAsync(GetDataType).WithCancellation(cts.Token); + if (!machine.IsConnected) + { + MoveMachineToUnlinked(machine.Id); + } + else + { + MoveMachineToLinked(machine.Id); + } + return ans; + } } } \ No newline at end of file