From b0a4c47dd74bc41c5df3bab6ddd8de7bcc6a52b0 Mon Sep 17 00:00:00 2001 From: patrick <patrick.xu@broconcentric.com> Date: 星期五, 06 十二月 2019 18:35:42 +0800 Subject: [PATCH] 1. 重新整理项目,按照A034模式,将设备异步操作修改为类同步操作。使用任务队列来存储和分配任务。 --- src/Bro.Device.SeerAGV/SeerAGVDriver.cs | 210 +++++++++++++++++++++++++++++++++++++++++++++++++--- 1 files changed, 198 insertions(+), 12 deletions(-) diff --git a/src/Bro.Device.SeerAGV/SeerAGVDriver.cs b/src/Bro.Device.SeerAGV/SeerAGVDriver.cs index fdb4428..bb05aee 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 { @@ -38,6 +41,15 @@ { 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(ref TcpClient client, int port) @@ -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,10 +95,18 @@ protected override void Stop() { + 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.Close(); client_Guide = null; } @@ -124,6 +154,8 @@ } } + 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; public AGVTaskStatus TaskStatus { @@ -136,28 +168,65 @@ 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) { + _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) { - OnLog?.Invoke(DateTime.Now, this, $"{Name}鐩戝惉寮傚父锛歿ex.GetExceptionMessage()}"); + LogAsync(DateTime.Now, "鐩戝惉寮傚父", ex.GetExceptionMessage()); } } } @@ -174,7 +243,7 @@ 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) { @@ -182,7 +251,7 @@ SeerMessage recMsg = SeerMessage.GetSeerMessage(rec); if (recMsg.TypeCode != (10000 + msg.TypeCode) || recMsg.SeqNum != msg.SeqNum) { - throw new ProcessException("鍙嶉淇℃伅鍜屽彂閫佷俊鎭笉涓�鑷�", null); + throw new ProcessException("鍙嶉淇℃伅鍜屽彂閫佷俊鎭笉涓�鑷�"); } if (recMsg.JValues.ContainsKey("ret_code")) @@ -190,7 +259,7 @@ int retCode = recMsg.JValues.Value<int>("ret_code"); if (retCode != 0) { - throw new ProcessException($"鍙嶉淇℃伅寮傚父,寮傚父鐮�:{retCode}", null); + throw new ProcessException($"鍙嶉淇℃伅寮傚父,寮傚父鐮�:{retCode}"); } } @@ -202,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); @@ -227,9 +296,35 @@ { 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; @@ -249,11 +344,102 @@ SendMsg(client_Guide, IConfig.GuidePort, msg); } - public void TaskOrder(string dest) + 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()}"); + } + } + } + #endregion } } -- Gitblit v1.8.0