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