From 1c4426810c71eead57084be8a18ade8d314dd8c4 Mon Sep 17 00:00:00 2001 From: patrick <patrick.xu@broconcentric.com> Date: 星期二, 10 十二月 2019 14:24:31 +0800 Subject: [PATCH] 1. 重构项目 --- src/Bro.Device.SeerAGV/SeerAGVDriver.cs | 278 ++++++++++++++++++++++++++++++++++++++++++++++++++----- 1 files changed, 250 insertions(+), 28 deletions(-) diff --git a/src/Bro.Device.SeerAGV/SeerAGVDriver.cs b/src/Bro.Device.SeerAGV/SeerAGVDriver.cs index e64d17c..7726e0e 100644 --- a/src/Bro.Device.SeerAGV/SeerAGVDriver.cs +++ b/src/Bro.Device.SeerAGV/SeerAGVDriver.cs @@ -1,24 +1,27 @@ 锘縰sing Bro.Common.Base; using Bro.Common.Helper; using Bro.Common.Interface; +using Bro.Common.Model; +using Bro.Common.Model.Interface; using Newtonsoft.Json; +using Newtonsoft.Json.Linq; using System; using System.Collections.Generic; using System.Linq; using System.Net; using System.Net.Sockets; -using System.Runtime.InteropServices; -using System.Text; using System.Threading; using System.Threading.Tasks; namespace Bro.Device.SeerAGV { [Device("SeerAGV", "SeerAGV", EnumHelper.DeviceAttributeType.Device)] - public class SeerAGVDriver : DeviceBase + public class SeerAGVDriver : DeviceBase, IMonitor { public Action<SeerAGVDriver, string> OnAGVPositoinChanged; public Action<SeerAGVDriver, AGVTaskStatus> OnAGVTaskStatusChanged; + public Action<SeerAGVDriver, float, float> OnAGVBatteryLvlChanged; + public Action<SeerAGVDriver, IODefinition> OnAGVIOChanged; SeerAGVInitialConfig IConfig { @@ -36,13 +39,22 @@ protected override void Init() { - InitialTcpClient(client_State, IConfig.StatusPort); - InitialTcpClient(client_Guide, IConfig.GuidePort); + InitialTcpClient(ref client_State, IConfig.StatusPort); + InitialTcpClient(ref client_Guide, IConfig.GuidePort); + + StateHandle = new ManualResetEvent(false); + PositionHandle = new ManualResetEvent(false); + BatteryHandle = new ManualResetEvent(false); + IOHandle = new ManualResetEvent(false); + + _taskDoneHandle = new ManualResetEvent(false); + _monitorLock = new ManualResetEvent(true); + _isTaskRunning = false; } - private void InitialTcpClient(TcpClient client, int port) + private void InitialTcpClient(ref TcpClient client, int port) { - if (client == null || !client_State.Connected) + if (client == null || !client.Connected) { client = new TcpClient(); client.SendBufferSize = client.ReceiveBufferSize = 0; @@ -64,6 +76,16 @@ { msg_Position = new SeerMessage((int)AGVCode.QueryPosition, SID); msg_GuideStatus = new SeerMessage((int)AGVCode.QueryTaskStatus, SID, IConfig.IsSimpleMonitor ? JsonConvert.SerializeObject(new { simple = true }) : ""); + msg_Battery = new SeerMessage((int)AGVCode.QueryBattery, SID, IConfig.IsSimpleMonitor ? JsonConvert.SerializeObject(new { simple = true }) : ""); + msg_IO = new SeerMessage((int)AGVCode.QueryIO, SID); + + _taskDoneHandle.Reset(); + _monitorLock.Set(); + + Task.Run(() => + { + Monitor(); + }); Task.Run(() => { @@ -73,7 +95,26 @@ protected override void Stop() { - throw new NotImplementedException(); + StateHandle.Set(); + PositionHandle.Set(); + BatteryHandle.Set(); + IOHandle.Set(); + + _taskDoneHandle.Set(); + _monitorLock.Set(); + + if (client_Guide != null && client_Guide.Connected) + { + CancelTask(); + client_Guide.Close(); + client_Guide = null; + } + + if (client_State != null && client_State.Connected) + { + client_State.Close(); + client_State = null; + } } #endregion @@ -96,7 +137,7 @@ byte[] buffer = new byte[1024]; string currentPosition = ""; - string CurrentPosition + public string CurrentPosition { get => currentPosition; set @@ -105,13 +146,18 @@ { currentPosition = value; - OnAGVPositoinChanged?.Invoke(this, currentPosition); + if (!string.IsNullOrWhiteSpace(currentPosition)) + { + OnAGVPositoinChanged?.Invoke(this, currentPosition); + } } } } + List<AGVTaskStatus> _taskRunningStates = new List<AGVTaskStatus>() { AGVTaskStatus.Running, AGVTaskStatus.Waiting, AGVTaskStatus.Suspended }; + List<AGVTaskStatus> _taskDoneStates = new List<AGVTaskStatus>() { AGVTaskStatus.Cancelled, AGVTaskStatus.Completed, AGVTaskStatus.Failed }; AGVTaskStatus taskStatus = AGVTaskStatus.None; - AGVTaskStatus TaskStatus + public AGVTaskStatus TaskStatus { get => taskStatus; set @@ -119,21 +165,69 @@ if (taskStatus != value) { taskStatus = value; - OnAGVTaskStatusChanged?.Invoke(this, taskStatus); + + if (taskStatus != AGVTaskStatus.None) + { + if (_isTaskRunning && _taskDoneStates.Contains(taskStatus)) + { + _taskDoneHandle.Set(); + _isTaskRunning = false; + } + + OnAGVTaskStatusChanged?.Invoke(this, taskStatus); + } } } } + float batteryLvl = 0; + public float BatteryLvl + { + get => batteryLvl; + set + { + if (batteryLvl != value) + { + float pre = batteryLvl; + batteryLvl = value; + OnAGVBatteryLvlChanged?.Invoke(this, pre, batteryLvl); + } + } + } + + public string LastStation { get; set; } + public string Destination { get; set; } = ""; + SeerMessage msg_Position = new SeerMessage(); SeerMessage msg_GuideStatus = new SeerMessage(); + SeerMessage msg_Battery = new SeerMessage(); + SeerMessage msg_IO = new SeerMessage(); + + public ManualResetEvent StateHandle { get; set; } = new ManualResetEvent(false); + public ManualResetEvent PositionHandle { get; set; } = new ManualResetEvent(false); + public ManualResetEvent BatteryHandle { get; set; } = new ManualResetEvent(false); + public ManualResetEvent IOHandle { get; set; } = new ManualResetEvent(false); + private void MonitorAGV() { while (CurrentState != EnumHelper.DeviceState.DSClose && CurrentState != EnumHelper.DeviceState.DSExcept) { - SendMsg(client_State, IConfig.StatusPort, msg_Position); - Thread.Sleep(IConfig.ScanInterval); - SendMsg(client_State, IConfig.StatusPort, msg_GuideStatus); - Thread.Sleep(IConfig.ScanInterval); + _monitorLock.WaitOne(); + try + { + SendMsg(client_State, IConfig.StatusPort, msg_Position); + Thread.Sleep(IConfig.ScanInterval); + SendMsg(client_State, IConfig.StatusPort, msg_GuideStatus); + Thread.Sleep(IConfig.ScanInterval); + SendMsg(client_State, IConfig.StatusPort, msg_Battery); + Thread.Sleep(IConfig.ScanInterval); + SendMsg(client_State, IConfig.StatusPort, msg_IO); + Thread.Sleep(IConfig.ScanInterval); + } + catch (Exception ex) + { + LogAsync(DateTime.Now, "鐩戝惉寮傚父", ex.GetExceptionMessage()); + } } } @@ -145,20 +239,19 @@ { try { - InitialTcpClient(client, port); + InitialTcpClient(ref client, port); var stream = client.GetStream(); stream.Write(msg.Frame, 0, msg.Frame.Length); - + stream.Flush(); int recSize = stream.Read(buffer, 0, buffer.Length); if (recSize > 0) { byte[] rec = buffer.Take(recSize).ToArray(); SeerMessage recMsg = SeerMessage.GetSeerMessage(rec); - - if (recMsg.TypeCode != msg.TypeCode || recMsg.SeqNum != msg.SeqNum) + if (recMsg.TypeCode != (10000 + msg.TypeCode) || recMsg.SeqNum != msg.SeqNum) { - throw new ProcessException("鍙嶉淇℃伅鍜屽彂閫佷俊鎭笉涓�鑷�", null); + throw new ProcessException("鍙嶉淇℃伅鍜屽彂閫佷俊鎭笉涓�鑷�"); } if (recMsg.JValues.ContainsKey("ret_code")) @@ -166,7 +259,7 @@ int retCode = recMsg.JValues.Value<int>("ret_code"); if (retCode != 0) { - throw new ProcessException($"鍙嶉淇℃伅寮傚父,寮傚父鐮�:{retCode}", null); + throw new ProcessException($"鍙嶉淇℃伅寮傚父,寮傚父鐮�:{retCode}"); } } @@ -178,18 +271,18 @@ catch (SocketException ex) { repeatTime--; - new ProcessException("AGV缃戠粶閫氫俊寮傚父", ex); + new ProcessException("AGV缃戠粶閫氫俊寮傚父", ExceptionLevel.Warning, ex); if (repeatTime <= 0) { - throw new ProcessException("AGV缃戠粶閫氫俊澶辫触", ex); + throw new ProcessException("AGV缃戠粶閫氫俊澶辫触", ExceptionLevel.Warning, ex); } Thread.Sleep(IConfig.ScanInterval); } catch (Exception ex) { - throw new ProcessException("AGV淇℃伅鍙戦�佸紓甯�", ex); + throw new ProcessException("AGV淇℃伅鍙戦�佸紓甯�", ExceptionLevel.Warning, ex); } } while (repeatTime > 0); @@ -199,13 +292,39 @@ { await Task.Run(() => { - switch (recMsg.TypeCode) + switch (recMsg.TypeCode - 10000) { case (int)AGVCode.QueryPosition: CurrentPosition = recMsg.JValues.Value<string>("current_station"); + LastStation = recMsg.JValues.Value<string>("last_station"); + + PositionHandle.Set(); break; case (int)AGVCode.QueryTaskStatus: TaskStatus = (AGVTaskStatus)recMsg.JValues.Value<int>("task_status"); + + StateHandle.Set(); + break; + case (int)AGVCode.QueryBattery: + BatteryLvl = recMsg.JValues.Value<float>("battery_level"); + + BatteryHandle.Set(); + break; + case (int)AGVCode.QueryIO: + //recMsg.JValues.Value<JArray>("DI").ToList().ForEach(j => + //{ + // var ioDefinition = IConfig.IOCollection.FirstOrDefault(i => i.IOIndex == j.Value<int>("id")); + + // if (ioDefinition != null && j.Value<bool>("status") != ioDefinition.CurrentValue) + // { + // ioDefinition.CurrentValue = j.Value<bool>("status"); + // OnAGVIOChanged?.Invoke(this, ioDefinition); + // } + //}); + + //楂樼數骞� 1 浣庣數骞� 0 + _ioDict = recMsg.JValues.Value<JArray>("DI").ToDictionary(u => u.Value<int>("id"), u => u.Value<bool>("status") ? 1 : 0); + IOHandle.Set(); break; default: break; @@ -219,10 +338,113 @@ SendMsg(client_Guide, IConfig.GuidePort, msg); } - public void TaskOrder(string dest) + public void PauseTask() { - SeerMessage msg = new SeerMessage((int)AGVCode.TaskOrder, SID, JsonConvert.SerializeObject(new { id = dest })); + SeerMessage msg = new SeerMessage((int)AGVCode.PauseTask, SID); SendMsg(client_Guide, IConfig.GuidePort, msg); } + + ManualResetEvent _taskDoneHandle = new ManualResetEvent(false); + ManualResetEvent _monitorLock = new ManualResetEvent(true); + bool _isTaskRunning = false; + public void TaskOrder(string dest, bool isWaitFinished) + { + _monitorLock.Reset(); + Thread.Sleep(IConfig.ScanInterval); + + CurrentPosition = ""; + Destination = dest; + TaskStatus = AGVTaskStatus.None; + + SeerMessage msg = new SeerMessage((int)AGVCode.TaskOrder, SID, JsonConvert.SerializeObject(new { id = dest })); + //OnLog?.BeginInvoke(DateTime.Now, this, $"{Name}琛岄┒鍚� {dest}", null, null); + LogAsync(DateTime.Now, "", $"{Name}琛岄┒鍚� {dest}"); + + SendMsg(client_Guide, IConfig.GuidePort, msg); + //Thread.Sleep(IConfig.ScanInterval); + _monitorLock.Set(); + + if (isWaitFinished) + { + _isTaskRunning = true; + _taskDoneHandle.Reset(); + bool isNotTimeout = _taskDoneHandle.WaitOne((int)(IConfig.OperationTimeout * 60 * 1000)); + if (!isNotTimeout) + { + throw new ProcessException($"{Name}鎵ц鍘诲線{dest}鍔ㄤ綔瓒呮椂"); + } + + if (TaskStatus == AGVTaskStatus.Failed) + { + throw new ProcessException($"{Name}鎵ц鍘诲線{dest}鍔ㄤ綔澶辫触"); + } + else if (TaskStatus == AGVTaskStatus.Cancelled) + { + //OnLog?.Invoke(DateTime.Now, this, $"{Name}鎵ц鍘诲線{dest}鍔ㄤ綔鍙栨秷"); + LogAsync(DateTime.Now, "", $"{Name}鎵ц鍘诲線{dest}鍔ㄤ綔鍙栨秷"); + } + } + } + + #region IMonitor + public event OnMonitorInvokeDelegate OnMonitorInvoke; + public event OnMonitorAlarmDelegate OnMonitorAlarm; + + Dictionary<int, int> _ioDict = new Dictionary<int, int>(); + public void Monitor() + { + while (CurrentState != EnumHelper.DeviceState.DSClose && CurrentState != EnumHelper.DeviceState.DSExcept) + { + try + { + IOHandle.Reset(); + + var isNotTimeout = IOHandle.WaitOne(IConfig.ScanInterval * 3); + + if (!isNotTimeout) + throw new ProcessException($"{Name}鐩戝惉瓒呮椂"); + + IConfig.MonitorSetCollection.ForEach(m => + { + if (_ioDict.ContainsKey(m.TriggerIndex)) + { + if ((m.TriggerValue == _ioDict[m.TriggerIndex] || m.TriggerIndex == -999) && _ioDict[m.TriggerIndex] != m.CurrentValue) + { + if (m.OpConfig == null) + { + m.OpConfig = new OperationConfigBase(); + } + + m.OpConfig.InputPara = m.InputDataIndex.ConvertAll(index => + { + if (_ioDict.ContainsKey(index)) + { + return _ioDict[index]; + } + else + { + return -1; + } + }).ToList(); + + OnMonitorInvoke?.BeginInvoke(DateTime.Now, this, m, null, null); + } + + m.CurrentValue = _ioDict[m.TriggerIndex]; + } + }); + } + catch (Exception ex) + { + OnLog?.Invoke(DateTime.Now, this, $"{Name}鐩戝惉寮傚父:{ex.GetExceptionMessage()}"); + } + } + } + + public virtual void ResetAlarm() + { + IConfig.WarningSetCollection.ForEach(u => u.CurrentStatus = !u.TriggerValue); + } + #endregion } } -- Gitblit v1.8.0