From 7ad440c9e5774ce1bac471908d73b2334bff06f2 Mon Sep 17 00:00:00 2001 From: parallelbgls Date: Mon, 25 Dec 2017 17:16:46 +0800 Subject: [PATCH] 2017-12-25 update 1 Serial Port Multistation fix --- .../Modbus.Net.PersistedTests.csproj | 18 +++ .../Modbus.Net.PersistedTests/Program.cs | 147 ++++++++++++++++++ Modbus.Net/Modbus.Net.sln | 7 + Modbus.Net/Modbus.Net/BaseConnector.cs | 2 +- Modbus.Net/Modbus.Net/BaseController.cs | 26 ++-- Modbus.Net/Modbus.Net/ComConnector.cs | 143 +++++++++-------- Modbus.Net/Modbus.Net/FifoController.cs | 19 +-- Modbus.Net/Modbus.Net/MatchController.cs | 19 +-- Modbus.Net/Modbus.Net/TaskManager.cs | 27 ++-- 9 files changed, 291 insertions(+), 117 deletions(-) create mode 100644 Modbus.Net/Modbus.Net.PersistedTests/Modbus.Net.PersistedTests.csproj create mode 100644 Modbus.Net/Modbus.Net.PersistedTests/Program.cs diff --git a/Modbus.Net/Modbus.Net.PersistedTests/Modbus.Net.PersistedTests.csproj b/Modbus.Net/Modbus.Net.PersistedTests/Modbus.Net.PersistedTests.csproj new file mode 100644 index 0000000..6e5b5b1 --- /dev/null +++ b/Modbus.Net/Modbus.Net.PersistedTests/Modbus.Net.PersistedTests.csproj @@ -0,0 +1,18 @@ + + + + Exe + net45; netcoreapp2.0 + + + + + + + + + + + + + diff --git a/Modbus.Net/Modbus.Net.PersistedTests/Program.cs b/Modbus.Net/Modbus.Net.PersistedTests/Program.cs new file mode 100644 index 0000000..9157bce --- /dev/null +++ b/Modbus.Net/Modbus.Net.PersistedTests/Program.cs @@ -0,0 +1,147 @@ +using System; +using System.Collections.Generic; +using System.Threading; +using Modbus.Net.Modbus; +using Serilog; + +namespace Modbus.Net.PersistedTests +{ + class Program + { + static void Main(string[] args) + { + Log.Logger = new LoggerConfiguration().MinimumLevel.Verbose().WriteTo.Console().CreateLogger(); + + IMachineProperty machine = new ModbusMachine(1, ModbusType.Rtu, "COM1", + new List() + { + new AddressUnit() + { + Id = "1", + Area = "4X", + Address = 1, + Name = "test 1", + DataType = typeof(ushort) + }, + new AddressUnit() + { + Id = "2", + Area = "4X", + Address = 2, + Name = "test 2", + DataType = typeof(ushort) + }, + new AddressUnit() + { + Id = "3", + Area = "4X", + Address = 3, + Name = "test 3", + DataType = typeof(ushort) + }, + }, true, 2, 1); + IMachineProperty machine2 = new ModbusMachine(2, ModbusType.Rtu, "COM1", + new List() + { + new AddressUnit() + { + Id = "1", + Area = "4X", + Address = 11, + Name = "test 1", + DataType = typeof(ushort) + }, + new AddressUnit() + { + Id = "2", + Area = "4X", + Address = 12, + Name = "test 2", + DataType = typeof(ushort) + }, + new AddressUnit() + { + Id = "3", + Area = "4X", + Address = 13, + Name = "test 3", + DataType = typeof(ushort) + }, + }, true, 3, 1); + IMachineProperty machine3 = new ModbusMachine(3, ModbusType.Rtu, "COM1", + new List() + { + new AddressUnit() + { + Id = "1", + Area = "4X", + Address = 21, + Name = "test 1", + DataType = typeof(ushort) + }, + new AddressUnit() + { + Id = "2", + Area = "4X", + Address = 22, + Name = "test 2", + DataType = typeof(ushort) + }, + new AddressUnit() + { + Id = "3", + Area = "4X", + Address = 23, + Name = "test 3", + DataType = typeof(ushort) + }, + }, true, 4, 1); + + TaskManager manager = new TaskManager(20, true); + manager.AddMachines(new List>{machine, machine2, machine3}); + Random r = new Random(); + manager.InvokeTimerAll(new TaskItemSetData(()=>new Dictionary + { + { + "4X 1.0", r.Next()%65536 + }, + { + "4X 2.0", r.Next()%65536 + }, + { + "4X 3.0", r.Next()%65536 + }, + { + "4X 11.0", r.Next()%65536 + }, + { + "4X 12.0", r.Next()%65536 + }, + { + "4X 13.0", r.Next()%65536 + }, + { + "4X 21.0", r.Next()%65536 + }, + { + "4X 22.0", r.Next()%65536 + }, + { + "4X 23.0", r.Next()%65536 + }, + }, MachineSetDataType.Address, 10000, 10000)); + Thread.Sleep(5000); + manager.InvokeTimerAll(new TaskItemGetData(data => + { + foreach (var dataInner in data.ReturnValues) + { + Console.WriteLine(dataInner.Key + " " + dataInner.Value.PlcValue); + } + + }, MachineGetDataType.Address, 10000, 10000)); + + Console.Read(); + Console.Read(); + } + } +} diff --git a/Modbus.Net/Modbus.Net.sln b/Modbus.Net/Modbus.Net.sln index 94c1d72..4eac7b8 100644 --- a/Modbus.Net/Modbus.Net.sln +++ b/Modbus.Net/Modbus.Net.sln @@ -30,6 +30,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CrossLamp", "..\Samples\Cro EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AnyType", "..\Samples\AnyType\AnyType.csproj", "{25FABD48-D82E-4E08-91A4-46F7057EC954}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Modbus.Net.PersistedTests", "Modbus.Net.PersistedTests\Modbus.Net.PersistedTests.csproj", "{5BFCA3D4-D809-485E-B69C-6F80A6A917D4}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -72,6 +74,10 @@ Global {25FABD48-D82E-4E08-91A4-46F7057EC954}.Debug|Any CPU.Build.0 = Debug|Any CPU {25FABD48-D82E-4E08-91A4-46F7057EC954}.Release|Any CPU.ActiveCfg = Release|Any CPU {25FABD48-D82E-4E08-91A4-46F7057EC954}.Release|Any CPU.Build.0 = Release|Any CPU + {5BFCA3D4-D809-485E-B69C-6F80A6A917D4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {5BFCA3D4-D809-485E-B69C-6F80A6A917D4}.Debug|Any CPU.Build.0 = Debug|Any CPU + {5BFCA3D4-D809-485E-B69C-6F80A6A917D4}.Release|Any CPU.ActiveCfg = Release|Any CPU + {5BFCA3D4-D809-485E-B69C-6F80A6A917D4}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -82,6 +88,7 @@ Global {2D939825-8459-438A-AC82-4C67A73E373E} = {145DA93A-6768-4D98-8512-AB22339933F7} {41F40C27-AB1A-4153-BBAD-BFC7BD57B380} = {145DA93A-6768-4D98-8512-AB22339933F7} {25FABD48-D82E-4E08-91A4-46F7057EC954} = {145DA93A-6768-4D98-8512-AB22339933F7} + {5BFCA3D4-D809-485E-B69C-6F80A6A917D4} = {D8DD32FC-CF39-4A1A-8FBF-9E82C5278C34} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {AF00D64E-3C70-474A-8A81-E9E48017C4B5} diff --git a/Modbus.Net/Modbus.Net/BaseConnector.cs b/Modbus.Net/Modbus.Net/BaseConnector.cs index de185da..85c5792 100644 --- a/Modbus.Net/Modbus.Net/BaseConnector.cs +++ b/Modbus.Net/Modbus.Net/BaseConnector.cs @@ -30,7 +30,7 @@ namespace Modbus.Net /// /// 传输控制器 /// - protected IController Controller { get; set; } + protected virtual IController Controller { get; set; } /// /// 标识Connector的连接关键字 diff --git a/Modbus.Net/Modbus.Net/BaseController.cs b/Modbus.Net/Modbus.Net/BaseController.cs index 9547bcd..4eb02e6 100644 --- a/Modbus.Net/Modbus.Net/BaseController.cs +++ b/Modbus.Net/Modbus.Net/BaseController.cs @@ -30,7 +30,7 @@ namespace Modbus.Net WaitingMessages = new List(); } - /// + /// public MessageWaitingDef AddMessage(byte[] sendMessage) { var def = new MessageWaitingDef @@ -40,8 +40,11 @@ namespace Modbus.Net SendMutex = new AutoResetEvent(false), ReceiveMutex = new AutoResetEvent(false) }; - AddMessageToList(def); - return def; + if (AddMessageToList(def)) + { + return def; + } + return null; } /// @@ -49,10 +52,10 @@ namespace Modbus.Net /// protected abstract void SendingMessageControlInner(); - /// + /// public abstract void SendStop(); - /// + /// public void SendStart() { if (SendingThread == null) @@ -61,7 +64,7 @@ namespace Modbus.Net } } - /// + /// public void Clear() { lock (WaitingMessages) @@ -74,11 +77,16 @@ namespace Modbus.Net /// Ϣӵ /// /// ҪӵϢϢ - protected virtual void AddMessageToList(MessageWaitingDef def) + protected virtual bool AddMessageToList(MessageWaitingDef def) { lock (WaitingMessages) { - WaitingMessages.Add(def); + if (WaitingMessages.FirstOrDefault(p => p.Key == def.Key) == null) + { + WaitingMessages.Add(def); + return true; + } + return false; } } @@ -89,7 +97,7 @@ namespace Modbus.Net /// Ϣļؼ protected abstract string GetKeyFromMessage(byte[] message); - /// + /// public bool ConfirmMessage(byte[] receiveMessage) { var def = GetMessageFromWaitingList(receiveMessage); diff --git a/Modbus.Net/Modbus.Net/ComConnector.cs b/Modbus.Net/Modbus.Net/ComConnector.cs index cb998ae..1f35cc2 100644 --- a/Modbus.Net/Modbus.Net/ComConnector.cs +++ b/Modbus.Net/Modbus.Net/ComConnector.cs @@ -108,6 +108,28 @@ namespace Modbus.Net private static Dictionary Connectors { get; } = new Dictionary() ; + private static Dictionary Controllers { get; } = new Dictionary() + ; + + /// + protected override IController Controller { + get + { + if (Controllers.ContainsKey(_com)) + { + return Controllers[_com]; + } + return null; + } + set + { + if (!Controllers.ContainsKey(_com)) + { + Controllers.Add(_com, value); + } + } + } + /// /// 连接中的连接器 /// @@ -272,9 +294,7 @@ namespace Modbus.Net #region 发送接收数据 - /// - /// 是否正在连接 - /// + /// public override bool IsConnected { get @@ -293,31 +313,33 @@ namespace Modbus.Net { try { - if (!Connectors.ContainsKey(_com)) + lock (Connectors) { - Connectors.Add(_com, new SerialPortLock + if (!Connectors.ContainsKey(_com)) { - PortName = _com, - BaudRate = _baudRate, - Parity = _parity, - StopBits = _stopBits, - DataBits = _dataBits, - ReadTimeout = _timeoutTime - }); - } - if (!Linkers.ContainsKey(_slave)) - { - Linkers.Add(_slave, _com); - } - if (!SerialPort.IsOpen) - { - lock (SerialPort) + Connectors.Add(_com, new SerialPortLock + { + PortName = _com, + BaudRate = _baudRate, + Parity = _parity, + StopBits = _stopBits, + DataBits = _dataBits, + ReadTimeout = _timeoutTime + }); + } + if (!Linkers.ContainsKey(_slave)) { - SerialPort.Open(); - ReceiveMsgThreadStart(); + Linkers.Add(_slave, _com); + } + if (!SerialPort.IsOpen) + { + lock (SerialPort) + { + SerialPort.Open(); + ReceiveMsgThreadStart(); + } } } - Controller.SendStart(); Log.Information("Com client {ConnectionToken} connect success", ConnectionToken); @@ -331,19 +353,13 @@ namespace Modbus.Net } } - /// - /// 连接串口 - /// - /// 是否连接成功 + /// public override Task ConnectAsync() { return Task.FromResult(Connect()); } - /// - /// 断开串口 - /// - /// 是否断开成功 + /// public override bool Disconnect() { if (Linkers.ContainsKey(_slave) && Connectors.ContainsKey(_com)) @@ -415,15 +431,11 @@ namespace Modbus.Net return AsyncHelper.RunSync(() => SendMsgAsync(message)); } - /// - /// 发送数据,需要返回 - /// - /// 发送的数据 - /// 是否发送成功 + /// public override async Task SendMsgAsync(byte[] message) { CheckOpen(); - var task = SendMsgInner(message).WithCancellation(new CancellationTokenSource(10000).Token); + var task = SendMsgInner(message).WithCancellation(new CancellationTokenSource(100000).Token); var ans = await task; if (task.IsCanceled) { @@ -434,38 +446,35 @@ namespace Modbus.Net } private async Task SendMsgInner(byte[] message) - { - var messageSendingdef = Controller.AddMessage(message); - messageSendingdef.SendMutex.WaitOne(); - await SendMsgWithoutConfirm(message); - messageSendingdef.ReceiveMutex.WaitOne(); - return messageSendingdef; - } - - /// - /// 发送数据,不确认 - /// - /// 需要发送的数据 - protected override async Task SendMsgWithoutConfirm(byte[] message) { using (await SerialPort.Lock.LockAsync()) { - try - { - Log.Verbose("Com client {ConnectionToken} send msg length: {Length}", ConnectionToken, - message.Length); - Log.Verbose( - $"Com client {ConnectionToken} send msg: {String.Concat(message.Select(p => " " + p.ToString("X2")))}"); - await Task.Run(()=>SerialPort.Write(message, 0, message.Length)); - } - catch (Exception err) - { - Log.Error(err, "Com client {ConnectionToken} send msg error", ConnectionToken); - } - RefreshSendCount(); + var messageSendingdef = Controller.AddMessage(message); + messageSendingdef.SendMutex.WaitOne(); + await SendMsgWithoutConfirm(message); + messageSendingdef.ReceiveMutex.WaitOne(); + return messageSendingdef; } } + /// + protected override async Task SendMsgWithoutConfirm(byte[] message) + { + try + { + Log.Verbose("Com client {ConnectionToken} send msg length: {Length}", ConnectionToken, + message.Length); + Log.Verbose( + $"Com client {ConnectionToken} send msg: {String.Concat(message.Select(p => " " + p.ToString("X2")))}"); + await Task.Run(() => SerialPort.Write(message, 0, message.Length)); + } + catch (Exception err) + { + Log.Error(err, "Com client {ConnectionToken} send msg error", ConnectionToken); + } + RefreshSendCount(); + } + /// protected override void ReceiveMsgThreadStart() { @@ -497,8 +506,9 @@ namespace Modbus.Net { //主动传输事件 } - } - RefreshReceiveCount(); + + RefreshReceiveCount(); + } Thread.Sleep(500); } @@ -515,9 +525,8 @@ namespace Modbus.Net { CheckOpen(); - byte[] data; Thread.Sleep(100); - var i = ReadComm(out data, 10, 5000, 1000); + var i = ReadComm(out var data, 10, 5000, 1000); if (i > 0) { var returndata = new byte[i]; diff --git a/Modbus.Net/Modbus.Net/FifoController.cs b/Modbus.Net/Modbus.Net/FifoController.cs index bb1296e..bb4c99d 100644 --- a/Modbus.Net/Modbus.Net/FifoController.cs +++ b/Modbus.Net/Modbus.Net/FifoController.cs @@ -31,7 +31,7 @@ namespace Modbus.Net AcquireTime = acquireTime; } - /// + /// protected override void SendingMessageControlInner() { try @@ -54,14 +54,9 @@ namespace Modbus.Net if (_currentSendingPos != null) { _currentSendingPos.SendMutex.Set(); - if (WaitingMessages.Count <= 1) - { - _currentSendingPos = null; - } - else - { - _currentSendingPos = WaitingMessages[WaitingMessages.IndexOf(_currentSendingPos) + 1]; - } + _currentSendingPos = WaitingMessages.Count <= 1 + ? null + : WaitingMessages[WaitingMessages.IndexOf(_currentSendingPos) + 1]; } } } @@ -77,19 +72,19 @@ namespace Modbus.Net } - /// + /// public override void SendStop() { _taskCancel = true; } - /// + /// protected override string GetKeyFromMessage(byte[] message) { return null; } - /// + /// protected override MessageWaitingDef GetMessageFromWaitingList(byte[] receiveMessage) { return WaitingMessages.FirstOrDefault(); diff --git a/Modbus.Net/Modbus.Net/MatchController.cs b/Modbus.Net/Modbus.Net/MatchController.cs index 48f7e02..8fed36a 100644 --- a/Modbus.Net/Modbus.Net/MatchController.cs +++ b/Modbus.Net/Modbus.Net/MatchController.cs @@ -38,7 +38,7 @@ namespace Modbus.Net AcquireTime = acquireTime; } - /// + /// protected override void SendingMessageControlInner() { try @@ -61,14 +61,9 @@ namespace Modbus.Net if (_currentSendingPos != null) { _currentSendingPos.SendMutex.Set(); - if (WaitingMessages.Count <= 1) - { - _currentSendingPos = null; - } - else - { - _currentSendingPos = WaitingMessages[WaitingMessages.IndexOf(_currentSendingPos) + 1]; - } + _currentSendingPos = WaitingMessages.Count <= 1 + ? null + : WaitingMessages[WaitingMessages.IndexOf(_currentSendingPos) + 1]; } } } @@ -84,13 +79,13 @@ namespace Modbus.Net } - /// + /// public override void SendStop() { _taskCancel = false; } - /// + /// protected override string GetKeyFromMessage(byte[] message) { string ans = ""; @@ -106,7 +101,7 @@ namespace Modbus.Net return ans; } - /// + /// protected override MessageWaitingDef GetMessageFromWaitingList(byte[] receiveMessage) { var returnKey = GetKeyFromMessage(receiveMessage); diff --git a/Modbus.Net/Modbus.Net/TaskManager.cs b/Modbus.Net/Modbus.Net/TaskManager.cs index d47a530..ef0c7cf 100644 --- a/Modbus.Net/Modbus.Net/TaskManager.cs +++ b/Modbus.Net/Modbus.Net/TaskManager.cs @@ -691,7 +691,7 @@ namespace Modbus.Net /// 多台设备 public void AddMachines(IEnumerable machines) { - base.AddMachines(machines); + base.AddMachines(machines); } /// @@ -699,9 +699,9 @@ namespace Modbus.Net /// /// 设备Id /// 获取的设备 - public BaseMachine GetMachineById(string id) + public new BaseMachine GetMachineById(string id) { - return base.GetMachineById(id) as BaseMachine; + return base.GetMachineById(id) as BaseMachine; } /// @@ -709,9 +709,9 @@ namespace Modbus.Net /// /// 通讯标志 /// 获取的设备 - public BaseMachine GetMachineByConnectionToken(string connectionToken) + public new BaseMachine GetMachineByConnectionToken(string connectionToken) { - return base.GetMachineByConnectionToken(connectionToken) as BaseMachine; + return base.GetMachineByConnectionToken(connectionToken) as BaseMachine; } } @@ -808,8 +808,7 @@ namespace Modbus.Net /// 添加一台设备 /// /// 设备 - public void AddMachine(BaseMachine machine) - where TUnitKey : IEquatable + public void AddMachine(IMachineProperty machine) { machine.KeepConnect = KeepConnect; lock (_machines) @@ -822,7 +821,7 @@ namespace Modbus.Net /// 添加多台设备 /// /// 设备的列表 - public void AddMachines(IEnumerable> machines) + public void AddMachines(IEnumerable> machines) where TUnitKey : IEquatable { foreach (var machine in machines) @@ -832,11 +831,9 @@ namespace Modbus.Net /// /// 通过Id获取设备 /// - /// 设备地址Id的类型 /// 设备的Id /// 获取设备 - public BaseMachine GetMachineById(TMachineKey id) - where TUnitKey : IEquatable + public IMachineProperty GetMachineById(TMachineKey id) { try { @@ -845,7 +842,7 @@ namespace Modbus.Net { machine = _machines.SingleOrDefault(p => p.Machine.Id.Equals(id)); } - return machine?.Machine as BaseMachine; + return machine?.Machine; } catch (Exception e) { @@ -857,11 +854,9 @@ namespace Modbus.Net /// /// 通过通讯标志获取设备 /// - /// 设备地址Id的类型 /// 通讯标志 /// 获取的数据 - public BaseMachine GetMachineByConnectionToken(string connectionToken) - where TUnitKey : IEquatable + public IMachineProperty GetMachineByConnectionToken(string connectionToken) { try { @@ -870,7 +865,7 @@ namespace Modbus.Net { machine = _machines.SingleOrDefault(p => p.Machine.ConnectionToken == connectionToken && p.Machine.IsConnected); } - return machine?.Machine as BaseMachine; + return machine?.Machine; } catch (Exception e) {