patrick
2019-12-10 1c4426810c71eead57084be8a18ade8d314dd8c4
src/Bro.Device.SeerAGV/SeerAGVDriver.cs
@@ -1,25 +1,27 @@
using 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
        {
@@ -39,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)
@@ -66,6 +77,15 @@
            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(() =>
            {
@@ -75,6 +95,14 @@
        protected override void Stop()
        {
            StateHandle.Set();
            PositionHandle.Set();
            BatteryHandle.Set();
            IOHandle.Set();
            _taskDoneHandle.Set();
            _monitorLock.Set();
            if (client_Guide != null && client_Guide.Connected)
            {
                CancelTask();
@@ -126,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
        {
@@ -138,6 +168,12 @@
                    if (taskStatus != AGVTaskStatus.None)
                    {
                        if (_isTaskRunning && _taskDoneStates.Contains(taskStatus))
                        {
                            _taskDoneHandle.Set();
                            _isTaskRunning = false;
                        }
                        OnAGVTaskStatusChanged?.Invoke(this, taskStatus);
                    }
                }
@@ -159,13 +195,24 @@
            }
        }
        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);
@@ -174,10 +221,12 @@
                    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());
                }
            }
        }
@@ -194,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)
                    {
@@ -202,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"))
@@ -210,7 +259,7 @@
                            int retCode = recMsg.JValues.Value<int>("ret_code");
                            if (retCode != 0)
                            {
                                throw new ProcessException($"反馈信息异常,异常码:{retCode}", null);
                                throw new ProcessException($"反馈信息异常,异常码:{retCode}");
                            }
                        }
@@ -222,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);
@@ -247,12 +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;
@@ -272,13 +344,107 @@
            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)
        {
            CurrentPosition = "";
            SeerMessage msg = new SeerMessage((int)AGVCode.TaskOrder, SID, JsonConvert.SerializeObject(new { id = dest }));
            _monitorLock.Reset();
            Thread.Sleep(IConfig.ScanInterval);
            OnLog?.BeginInvoke(DateTime.Now, this, $"{Name}行驶向 {dest}", null, null);
            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
    }
}