diff --git a/Modbus.Net/Modbus.Net.OPC/AddressFormaterOpc.cs b/Modbus.Net/Modbus.Net.OPC/AddressFormaterOpc.cs index d4b4ca6..a880837 100644 --- a/Modbus.Net/Modbus.Net.OPC/AddressFormaterOpc.cs +++ b/Modbus.Net/Modbus.Net.OPC/AddressFormaterOpc.cs @@ -26,7 +26,7 @@ namespace Modbus.Net.OPC protected Func, AddressUnit, string[]> TagGeter { get; set; } - protected char Seperator { get; set; } + public char Seperator { get; protected set; } public override string FormatAddress(string area, int address) { diff --git a/Modbus.Net/Modbus.Net.OPC/ClientExtend.cs b/Modbus.Net/Modbus.Net.OPC/ClientExtend.cs index dc363db..d60b351 100644 --- a/Modbus.Net/Modbus.Net.OPC/ClientExtend.cs +++ b/Modbus.Net/Modbus.Net.OPC/ClientExtend.cs @@ -24,6 +24,8 @@ namespace Modbus.Net.OPC Task FindNodeAsync(string tag); Task> ExploreFolderAsync(string tag); + + Node RootNodeBase { get; } } public class MyDaClient : DaClient, IClientExtend @@ -31,6 +33,8 @@ namespace Modbus.Net.OPC public MyDaClient(Uri serverUrl) : base(serverUrl) { } + + public Node RootNodeBase => RootNode; } public class MyUaClient : UaClient, IClientExtend @@ -38,5 +42,7 @@ namespace Modbus.Net.OPC public MyUaClient(Uri serverUrl) : base(serverUrl) { } + + public Node RootNodeBase => RootNode; } } \ 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 2e7b069..802097b 100644 --- a/Modbus.Net/Modbus.Net.OPC/FBox/FBoxOpcDaManchine.cs +++ b/Modbus.Net/Modbus.Net.OPC/FBox/FBoxOpcDaManchine.cs @@ -6,14 +6,14 @@ 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; @@ -22,7 +22,7 @@ namespace Modbus.Net.OPC.FBox (machine, unit) => new string[] { - "他人分享", ((FBoxOpcDaMachine) machine).LinkerName, ((FBoxOpcDaMachine) machine).LocalSequence, + "(.*)", ((FBoxOpcDaMachine) machine).LinkerName, ((FBoxOpcDaMachine) machine).LocalSequence, unit.Name }, this, '.'); } diff --git a/Modbus.Net/Modbus.Net.OPC/OpcConnector.cs b/Modbus.Net/Modbus.Net.OPC/OpcConnector.cs index b5fd889..69cf2f6 100644 --- a/Modbus.Net/Modbus.Net.OPC/OpcConnector.cs +++ b/Modbus.Net/Modbus.Net.OPC/OpcConnector.cs @@ -54,6 +54,29 @@ namespace Modbus.Net.OPC return AsyncHelper.RunSync(() => SendMsgAsync(message)); } + private string[] SplitTag(string tag, char split) + { + var tagSplitList = tag.Split(split).ToList(); + for (int i = 0; i < tagSplitList.Count; i++) + { + if (tagSplitList[i].Contains("(")) + { + for (int j = i; j < tagSplitList.Count; j++) + { + if (tagSplitList[j].Contains(")")) + { + for (int k = i + 1; k <= j; k++) + { + tagSplitList[i] += split + tagSplitList[i + 1]; + tagSplitList.RemoveAt(i + 1); + } + } + } + } + } + return tagSplitList.ToArray(); + } + public override async Task SendMsgAsync(byte[] message) { try @@ -62,12 +85,15 @@ namespace Modbus.Net.OPC var protocal = BigEndianValueHelper.Instance.GetByte(message, ref pos); if (protocal == 0) { - var tagBytes = new byte[message.Length - 1]; + 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 = tag.Split('/'); - var rootDirectory = await Client.ExploreFolderAsync("/"); - var answerTag = await SearchTag(tagSplit, 0, rootDirectory); + var tagSplit = SplitTag(tag, split[0]); + var rootDirectory = await Client.ExploreFolderAsync(""); + var answerTag = await SearchTag(tagSplit, split[0], 0, rootDirectory); if (answerTag != null) { var result = await Client.ReadAsync(answerTag); @@ -98,38 +124,68 @@ namespace Modbus.Net.OPC 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 typeBytes = new byte[index2 - index - 4]; - Array.Copy(message, index + 4, typeBytes, 0, typeBytes.Length); + 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 - index2 - 4]; - Array.Copy(message, index2 + 4, valueBytes, 0, valueBytes.Length); + 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); - await Client.WriteAsync(tag, value); - return new byte[] { 1 }; + + var rootDirectory = await Client.ExploreFolderAsync(""); + var tagSplit = SplitTag(tag, split[0]); + var answerTag = await SearchTag(tagSplit, split[0], 0, rootDirectory); + if (answerTag != null) + { + try + { + await Client.WriteAsync(answerTag, value); + } + catch (Exception e) + { + AddInfo("opc write exception:" + e.Message); + return new byte[] { 0 }; + } + return new byte[] {1}; + } + return new byte[] {0}; } } catch (Exception e) { - //AddInfo("opc client exception:" + e); + AddInfo("opc client exception:" + e.Message); return Encoding.ASCII.GetBytes("NoData"); - //return null; } } - private async Task SearchTag(string[] tags, int deep, IEnumerable nodes) + private async Task SearchTag(string[] tags, char split, int deep, IEnumerable nodes) { foreach (var node in nodes) { - var currentTag = node.Tag.Substring(node.Tag.LastIndexOf('/')); + var currentTag = node.Tag.Substring(node.Tag.LastIndexOf(split) + 1); if (Regex.IsMatch(currentTag, tags[deep])) { - if (deep == tags.Length) return currentTag; + if (deep == tags.Length - 1) return node.Tag; var subDirectories = await Client.ExploreFolderAsync(node.Tag); - var answerTag = await SearchTag(tags, deep + 1, subDirectories); + var answerTag = await SearchTag(tags, split, deep + 1, subDirectories); if (answerTag != null) return answerTag; } } diff --git a/Modbus.Net/Modbus.Net.OPC/OpcDaMachine.cs b/Modbus.Net/Modbus.Net.OPC/OpcDaMachine.cs index 8e02851..ef5eeec 100644 --- a/Modbus.Net/Modbus.Net.OPC/OpcDaMachine.cs +++ b/Modbus.Net/Modbus.Net.OPC/OpcDaMachine.cs @@ -6,9 +6,11 @@ namespace Modbus.Net.OPC public class OpcDaMachine : OpcMachine where TKey : IEquatable where TUnitKey : IEquatable { public OpcDaMachine(string connectionString, IEnumerable> getAddresses, bool keepConnect) - : base(connectionString, getAddresses, keepConnect) + : base(getAddresses, keepConnect) { BaseUtility = new OpcDaUtility(connectionString); + ((OpcUtility) BaseUtility).GetSeperator += + () => ((AddressFormaterOpc) AddressFormater).Seperator; } public OpcDaMachine(string connectionString, IEnumerable> getAddresses) @@ -20,9 +22,11 @@ namespace Modbus.Net.OPC public class OpcDaMachine : OpcMachine { public OpcDaMachine(string connectionString, IEnumerable getAddresses, bool keepConnect) - : base(connectionString, getAddresses, keepConnect) + : base(getAddresses, keepConnect) { BaseUtility = new OpcDaUtility(connectionString); + ((OpcUtility)BaseUtility).GetSeperator += + () => ((AddressFormaterOpc)AddressFormater).Seperator; } public OpcDaMachine(string connectionString, IEnumerable getAddresses) diff --git a/Modbus.Net/Modbus.Net.OPC/OpcMachine.cs b/Modbus.Net/Modbus.Net.OPC/OpcMachine.cs index f8f1322..034508b 100644 --- a/Modbus.Net/Modbus.Net.OPC/OpcMachine.cs +++ b/Modbus.Net/Modbus.Net.OPC/OpcMachine.cs @@ -12,7 +12,7 @@ namespace Modbus.Net.OPC public abstract class OpcMachine : BaseMachine where TKey : IEquatable where TUnitKey : IEquatable { - public OpcMachine(string connectionString, IEnumerable> getAddresses, bool keepConnect) + protected OpcMachine(IEnumerable> getAddresses, bool keepConnect) : base(getAddresses, keepConnect) { AddressCombiner = new AddressCombinerSingle(); @@ -25,7 +25,7 @@ namespace Modbus.Net.OPC /// public abstract class OpcMachine : BaseMachine { - public OpcMachine(string connectionString, IEnumerable getAddresses, bool keepConnect) + protected OpcMachine(IEnumerable getAddresses, bool keepConnect) : base(getAddresses, keepConnect) { AddressCombiner = new AddressCombinerSingle(); diff --git a/Modbus.Net/Modbus.Net.OPC/OpcProtocal.cs b/Modbus.Net/Modbus.Net.OPC/OpcProtocal.cs index 587b1d2..5a3025a 100644 --- a/Modbus.Net/Modbus.Net.OPC/OpcProtocal.cs +++ b/Modbus.Net/Modbus.Net.OPC/OpcProtocal.cs @@ -16,12 +16,14 @@ namespace Modbus.Net.OPC public class ReadRequestOpcInputStruct : IInputStruct { - public ReadRequestOpcInputStruct(string tag) + public ReadRequestOpcInputStruct(string tag, string split) { Tag = tag; + Split = split; } public string Tag { get; } + public string Split { get; } } public class ReadRequestOpcOutputStruct : IOutputStruct @@ -39,7 +41,7 @@ namespace Modbus.Net.OPC public override byte[] Format(IInputStruct message) { var r_message = (ReadRequestOpcInputStruct) message; - return Format((byte) 0x00, Encoding.UTF8.GetBytes(r_message.Tag)); + return Format((byte) 0x00, Encoding.UTF8.GetBytes(r_message.Tag), 0x00ffff00, Encoding.UTF8.GetBytes(r_message.Split)); } public override IOutputStruct Unformat(byte[] messageBytes, ref int pos) @@ -54,13 +56,15 @@ namespace Modbus.Net.OPC public class WriteRequestOpcInputStruct : IInputStruct { - public WriteRequestOpcInputStruct(string tag, object setValue) + public WriteRequestOpcInputStruct(string tag, string split, object setValue) { Tag = tag; + Split = split; SetValue = setValue; } public string Tag { get; } + public string Split { get; } public object SetValue { get; } } @@ -81,7 +85,8 @@ namespace Modbus.Net.OPC var r_message = (WriteRequestOpcInputStruct) message; var tag = Encoding.UTF8.GetBytes(r_message.Tag); var fullName = Encoding.UTF8.GetBytes(r_message.SetValue.GetType().FullName); - return Format((byte) 0x01, tag, 0x00ffff00, fullName, 0x00ffff00, r_message.SetValue); + var split = Encoding.UTF8.GetBytes(r_message.Split); + return Format((byte) 0x01, tag, 0x00ffff00, split, 0x00ffff00, fullName, 0x00ffff00, r_message.SetValue); } public override IOutputStruct Unformat(byte[] messageBytes, ref int pos) diff --git a/Modbus.Net/Modbus.Net.OPC/OpcUaMachine.cs b/Modbus.Net/Modbus.Net.OPC/OpcUaMachine.cs index 4a1e480..92b00dd 100644 --- a/Modbus.Net/Modbus.Net.OPC/OpcUaMachine.cs +++ b/Modbus.Net/Modbus.Net.OPC/OpcUaMachine.cs @@ -9,9 +9,11 @@ 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) + : base(getAddresses, keepConnect) { BaseUtility = new OpcUaUtility(connectionString); + ((OpcUtility)BaseUtility).GetSeperator += + () => ((AddressFormaterOpc)AddressFormater).Seperator; } public OpcUaMachine(string connectionString, IEnumerable> getAddresses) @@ -23,9 +25,11 @@ namespace Modbus.Net.OPC public class OpcUaMachine : OpcMachine { public OpcUaMachine(string connectionString, IEnumerable getAddresses, bool keepConnect) - : base(connectionString, getAddresses, keepConnect) + : base(getAddresses, keepConnect) { BaseUtility = new OpcUaUtility(connectionString); + ((OpcUtility)BaseUtility).GetSeperator += + () => ((AddressFormaterOpc)AddressFormater).Seperator; } public OpcUaMachine(string connectionString, IEnumerable getAddresses) diff --git a/Modbus.Net/Modbus.Net.OPC/OpcUtility.cs b/Modbus.Net/Modbus.Net.OPC/OpcUtility.cs index 77978c8..0cd1d63 100644 --- a/Modbus.Net/Modbus.Net.OPC/OpcUtility.cs +++ b/Modbus.Net/Modbus.Net.OPC/OpcUtility.cs @@ -7,13 +7,17 @@ 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 delegate char GetSeperatorDelegate(); + + public event GetSeperatorDelegate GetSeperator; + public override Endian Endian => Endian.BigEndianLsb; public override void SetConnectionType(int connectionType) @@ -25,7 +29,8 @@ namespace Modbus.Net.OPC { try { - var readRequestOpcInputStruct = new ReadRequestOpcInputStruct(startAddress); + var split = GetSeperator?.Invoke() ?? '/'; + var readRequestOpcInputStruct = new ReadRequestOpcInputStruct(startAddress, split.ToString()); var readRequestOpcOutputStruct = await Wrapper.SendReceiveAsync(Wrapper[typeof(ReadRequestOpcProtocal)], readRequestOpcInputStruct) as @@ -42,7 +47,8 @@ namespace Modbus.Net.OPC { try { - var writeRequestOpcInputStruct = new WriteRequestOpcInputStruct(startAddress, setContents[0]); + var split = GetSeperator?.Invoke() ?? '/'; + var writeRequestOpcInputStruct = new WriteRequestOpcInputStruct(startAddress, split.ToString(), setContents[0]); var writeRequestOpcOutputStruct = await Wrapper.SendReceiveAsync(Wrapper[typeof(WriteRequestOpcProtocal)], writeRequestOpcInputStruct) diff --git a/Tests/Modbus.Net.Tests/Modbus.Net.Tests.csproj b/Tests/Modbus.Net.Tests/Modbus.Net.Tests.csproj index 8a9c4e2..41c27bb 100644 --- a/Tests/Modbus.Net.Tests/Modbus.Net.Tests.csproj +++ b/Tests/Modbus.Net.Tests/Modbus.Net.Tests.csproj @@ -56,6 +56,7 @@ + diff --git a/Tests/Modbus.Net.Tests/OpcTest.cs b/Tests/Modbus.Net.Tests/OpcTest.cs new file mode 100644 index 0000000..d60c345 --- /dev/null +++ b/Tests/Modbus.Net.Tests/OpcTest.cs @@ -0,0 +1,100 @@ +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Modbus.Net.OPC; +using Modbus.Net.OPC.FBox; + +namespace Modbus.Net.Tests +{ + [TestClass] + public class OpcTest + { + private BaseMachine _opcMachine; + + [TestInitialize] + public void Init() + { + _opcMachine = new FBoxOpcDaMachine("1","德联科技测试", null, true); + } + + [TestMethod] + public async Task OpcSingle() + { + _opcMachine.GetAddresses = new List + { + new AddressUnit() + { + Id = "1", + Name = "蒸汽压力下限", + Area = "0", + Address = 1, + DataType = typeof(ushort) + } + }; + var ans = await _opcMachine.GetDatasAsync(MachineGetDataType.Id); + Assert.AreEqual(ans["1"].PlcValue, 525); + } + + [TestMethod] + public async Task OpcMultiple() + { + _opcMachine.GetAddresses = new List + { + new AddressUnit() + { + Id = "1", + Name = "蒸汽压力下限", + Area = "0", + Address = 1, + DataType = typeof(ushort) + }, + new AddressUnit() + { + Id = "2", + Name = "蒸汽压力目标", + Area = "0", + Address = 2, + DataType = typeof(ushort) + }, + new AddressUnit() + { + Id = "3", + Name = "蒸汽压力上限", + Area = "0", + Address = 3, + DataType = typeof(ushort) + } + }; + var ans = await _opcMachine.GetDatasAsync(MachineGetDataType.Id); + Assert.AreEqual(ans["1"].PlcValue, 525); + Assert.AreEqual(ans["2"].PlcValue, 600); + Assert.AreEqual(ans["3"].PlcValue, 650); + } + + [TestMethod] + public async Task OpcWrite() + { + _opcMachine.GetAddresses = new List + { + new AddressUnit() + { + Id = "1", + Name = "蒸汽压力下限", + Area = "0", + Address = 1, + DataType = typeof(ushort) + } + }; + var success = await _opcMachine.SetDatasAsync(MachineSetDataType.Id, new Dictionary + { + { + "1", 525 + } + }); + Assert.AreEqual(success, true); + var ans = await _opcMachine.GetDatasAsync(MachineGetDataType.Id); + Assert.AreEqual(ans["1"].PlcValue, 525); + } + } +}