patrick
2019-12-10 1c4426810c71eead57084be8a18ade8d314dd8c4
src/Bro.Device.AuboRobot/AuboRobotDriver.cs
@@ -10,6 +10,7 @@
using System.Net.Sockets;
using System.Threading;
using System.Threading.Tasks;
using static Bro.Common.Helper.EnumHelper;
namespace Bro.Device.AuboRobot
{
@@ -38,7 +39,7 @@
            if (string.IsNullOrWhiteSpace(IConfig.EndChar))
            {
                throw new ProcessException("协议文本的结束字符不可为空,请检查配置", null);
                throw new ProcessException("协议文本的结束字符不可为空,请检查配置");
            }
            client = new TcpClient();
@@ -46,6 +47,10 @@
            client.Client.Blocking = true;
            client.NoDelay = true;
            client.BeginConnect(IPAddress.Parse(IConfig.RobotIP), IConfig.RobotPort, OnConnect, null);
            replyHandleDict = new Dictionary<int, AutoResetEvent>();
            replyErrorCodeDict = new Dictionary<int, int>();
            taskHandleDict = new Dictionary<int, ManualResetEvent>();
        }
        protected override void Pause()
@@ -63,8 +68,7 @@
            //SendMsg(RobotMsgType.Send, 0, true, RobotMsgAction.IO, RobotMsgParas.Query, new List<string>());
            scanMsg = new RobotMsg();
            scanMsg.Action = RobotMsgAction.IO;
            scanMsg.Para1 = RobotMsgParas.Query;
            scanMsg.Action = RobotMsgAction.IOQuery;
            Task.Run(() =>
            {
@@ -74,6 +78,12 @@
        protected override void Stop()
        {
            replyHandleDict.Values.ToList().ForEach(h => h.Set());
            replyHandleDict.Clear();
            taskHandleDict.Values.ToList().ForEach(h => h.Set());
            taskHandleDict.Clear();
            if (client != null && client.Connected)
            {
                client.Close();
@@ -95,7 +105,8 @@
            }
            catch (Exception ex)
            {
                OnLog?.Invoke(DateTime.Now, this, ex.GetExceptionMessage());
                //OnLog?.Invoke(DateTime.Now, this, ex.GetExceptionMessage());
                LogAsync(DateTime.Now, "连接异常", ex.GetExceptionMessage());
                if (client != null && client.Connected)
                {
@@ -110,13 +121,12 @@
            try
            {
                int dataLength = stream.EndRead(ar);
                if (dataLength > 0)
                {
                    byte[] data = buffer.Take(dataLength).ToArray();
                    string dataStr = System.Text.Encoding.ASCII.GetString(data).Trim();
                    //OnLog?.BeginInvoke(DateTime.Now, this, $"{Name}接收数据:{dataStr}", null, null);
                    AnalyzeData(dataStr);
                    stream.BeginRead(buffer, 0, buffer.Length, OnDataReceived, null);
@@ -125,19 +135,21 @@
                {
                    if (!client.Connected)
                    {
                        OnLog?.Invoke(DateTime.Now, this, "返回空数据,连接中断");
                        //OnLog?.Invoke(DateTime.Now, this, "返回空数据,连接中断");
                        LogAsync(DateTime.Now, "连接中断", "返回空数据,连接中断");
                        client.BeginConnect(IPAddress.Parse(IConfig.RobotIP), IConfig.RobotPort, OnConnect, null);
                    }
                }
            }
            catch (Exception ex)
            {
                OnLog?.Invoke(DateTime.Now, this, $"{Name}数据接收异常:{ex.GetExceptionMessage()}");
                //OnLog?.Invoke(DateTime.Now, this, $"{Name}:{ex.GetExceptionMessage()}");
                LogAsync(DateTime.Now, "数据接收异常", ex.GetExceptionMessage());
            }
        }
        string msg = "";
        static object analyzeLock = new object();
        object analyzeLock = new object();
        private async void AnalyzeData(string data)
        {
            await Task.Run(() =>
@@ -168,41 +180,58 @@
            await Task.Run(() =>
            {
                Array.ForEach(datas, data =>
                 {
                     RobotMsg msg = RobotMsg.GetRobotMsg(data, IConfig.Seperator);
                {
                    RobotMsg msg = RobotMsg.GetRobotMsg(data, IConfig.Seperator);
                     if (msg.Type == RobotMsgType.Rec)
                     {
                         if (replyHandleDict.ContainsKey(msg.ID))
                         {
                             replyHandleList.Remove(msg.ID);
                    if (msg.Type == RobotMsgType.Rec)
                    {
                        replyErrorCodeDict[msg.ID] = msg.Para1;
                        if (replyHandleDict.ContainsKey(msg.ID))
                        {
                            replyHandleDict[msg.ID].Set();
                        }
                    }
                    else
                    {
                        if (msg.Action == RobotMsgAction.IOQuery)
                        {
                            newValues = new List<int>();
                             replyHandleDict[msg.ID].Set();
                             replyHandleDict.Remove(msg.ID);
                         }
                     }
                     else
                     {
                         canMonitor = true;
                            for (int i = msg.Para1.ToString().Length - 1; i >= 0; i--)
                            {
                                newValues.Add((msg.Para1 >> i) & 1);
                            }
                         if (msg.Action == RobotMsgAction.IO && msg.Para1 == RobotMsgParas.Query)
                         {
                             string resultStr = msg.Datas[0];
                             newValues = new List<int>();
                            MonitorHandle.Set();
                        }
                        else
                        {
                            canMonitor = true;
                            switch (msg.Action)
                            {
                                case RobotMsgAction.Move:
                                    CurrentPoint = msg.Point;
                                    break;
                                //case RobotMsgAction.Load:
                                //    //SlotIndex = msg.Para1;
                                //    break;
                                case RobotMsgAction.GetPosition:
                                    CurrentPoint = msg.Point;
                                    break;
                                default:
                                    break;
                            }
                             for (int i = resultStr.Length - 1; i >= 0; i--)
                             {
                                 newValues.Add(int.Parse(resultStr[i].ToString()));
                             }
                            if (taskHandleDict.ContainsKey(msg.ID))
                            {
                                taskHandleDict[msg.ID].Set();
                            }
                             MonitorHandle.Set();
                         }
                         else
                         {
                             OnMsgReceived?.BeginInvoke(DateTime.Now, this, msg, null, null);
                         }
                     }
                 });
                            LogAsync(DateTime.Now, "指令反馈", msg.GetDisplayText());
                            OnMsgReceived?.BeginInvoke(DateTime.Now, this, msg, null, null);
                        }
                    }
                });
            });
        }
@@ -220,24 +249,9 @@
            }
        }
        List<int> replyHandleList = new List<int>();
        Dictionary<int, AutoResetEvent> replyHandleDict = new Dictionary<int, AutoResetEvent>();
        public void SendMsg(RobotMsgAction action, RobotMsgParas para1, int para2, List<float> paras = null)
        {
            RobotMsg msg = new RobotMsg();
            msg.Type = RobotMsgType.Send;
            msg.ID = SID;
            msg.Action = action;
            msg.Para1 = para1;
            msg.Para2 = para2;
            msg.Datas = new List<string>((paras ?? new List<float>()).ConvertAll(i => i.ToString()));
            OnLog?.BeginInvoke(DateTime.Now, this, $"{Name}发送指令:{msg.GetDisplayText()}", null, null);
            SendMsg(msg, true);
        }
        Dictionary<int, int> replyErrorCodeDict = new Dictionary<int, int>();
        Dictionary<int, ManualResetEvent> taskHandleDict = new Dictionary<int, ManualResetEvent>();
        public void SendReplyMsg(int replyId)
        {
@@ -253,37 +267,183 @@
        object monitorLock = new object();
        public void SendMsg(RobotMsg msg, bool isWaitReply = true, bool isMonitorMsg = false)
        {
            replyErrorCodeDict[msg.ID] = 0;
            if (isWaitReply)
            {
                replyHandleList.Add(msg.ID);
                replyHandleDict[msg.ID] = new AutoResetEvent(false);
            }
            byte[] bytes = msg.GetMsgBytes(IConfig.Seperator, IConfig.EndChar);
            lock (monitorLock)
            byte[] bytes = msg.GetMsgBytes(IConfig.Seperator, IConfig.EndChar, out string dataStr);
            if (!isMonitorMsg)
            {
                if (!isMonitorMsg)
                {
                    canMonitor = false;
                }
                if (isMonitorMsg && !canMonitor)
                    return;
                //lock (this)
                {
                    stream.Write(bytes, 0, bytes.Length);
                }
                LogAsync(DateTime.Now, "指令发送", dataStr);
            }
            bool isNotTimeout = true;
            int reTryTime = IConfig.TimeoutRetryTimes;
            do
            {
                lock (monitorLock)
                {
                    if (!isMonitorMsg)
                    {
                        canMonitor = false;
                    }
                    if (isMonitorMsg && !canMonitor)
                        return;
                    stream.Write(bytes, 0, bytes.Length);
                    if (!isMonitorMsg)
                    {
                        LogAsync(DateTime.Now, "数据发送", BitConverter.ToString(bytes));
                    }
                }
                if (isWaitReply)
                {
                    int errorCode = replyErrorCodeDict[msg.ID];
                    if (errorCode != 0)
                    {
                        var desc = IConfig.RobotReplyWarnings.FirstOrDefault(u => u.WarningCode == errorCode);
                        throw new ProcessException($"{Name}{msg.ID}任务反馈异常{errorCode},异常描述:{(desc == null ? "无" : desc.WarningDescription)}");
                    }
                    isNotTimeout = replyHandleDict[msg.ID].WaitOne(IConfig.ReplyTimeout);
                    if (!isNotTimeout)
                    {
                        reTryTime--;
                    }
                }
            } while (reTryTime > 0 && !isNotTimeout);
            if (isWaitReply)
            {
                replyHandleDict[msg.ID].WaitOne(IConfig.ReplyTimeout);
                replyHandleDict.Remove(msg.ID);
            }
                if (replyHandleList.Contains(msg.ID))
            if (!isNotTimeout)
            {
                throw new ProcessException($"{Name}反馈数据超时\r\n" + msg.GetDisplayText());
            }
        }
        #region 执行结果属性
        public RobotPoint CurrentPoint { get; set; } = null;
        //public int SlotIndex { get; set; } = 0;
        #endregion
        public void Move(RobotPoint point, MoveType isAbs, bool isWaitFinished)
        {
            CurrentPoint = null;
            RobotMsg msg = new RobotMsg();
            msg.Type = RobotMsgType.Send;
            msg.ID = SID;
            msg.Action = RobotMsgAction.Move;
            msg.Para1 = (int)isAbs;
            msg.Point = point ?? new RobotPoint();
            SendMsg(msg, true);
            TaskTimeoutCheck(isWaitFinished, msg.ID, $"{Name}{(isAbs.GetEnumDescription())}至{point.GetDisplayText()}动作超时");
        }
        public void Load(RobotPoint point, TrayType trayType, bool isWaitFinished)
        {
            //SlotIndex = 0;
            RobotMsg msg = new RobotMsg();
            msg.Type = RobotMsgType.Send;
            msg.ID = SID;
            msg.Action = RobotMsgAction.Load;
            msg.Para1 = (int)trayType;
            msg.Point = point;
            SendMsg(msg, true);
            TaskTimeoutCheck(isWaitFinished, msg.ID, $"{Name}取{trayType.ToString()}{point.GetDisplayText()}动作超时");
            //if (isWaitFinished && SlotIndex <= 0)
            //{
            //    throw new ProcessException($"{Name}没有可用的空白格位,无法放置卷宗");
            //}
        }
        public void UnLoad(RobotPoint point, TrayType trayType, bool isWaitFinished)
        {
            RobotMsg msg = new RobotMsg();
            msg.Type = RobotMsgType.Send;
            msg.ID = SID;
            msg.Action = RobotMsgAction.Unload;
            msg.Para1 = (int)trayType;
            msg.Point = point;
            SendMsg(msg, true);
            TaskTimeoutCheck(isWaitFinished, msg.ID, $"{Name}卸{trayType.ToString()}{point.GetDisplayText()}动作超时");
        }
        public void GetPosition(bool isWaitFinished)
        {
            CurrentPoint = null;
            RobotMsg msg = new RobotMsg();
            msg.Type = RobotMsgType.Send;
            msg.ID = SID;
            msg.Action = RobotMsgAction.GetPosition;
            SendMsg(msg, true);
            TaskTimeoutCheck(isWaitFinished, msg.ID, $"{Name}获取当前坐标超时");
        }
        public void SetBasePoint()
        {
            RobotMsg msg = new RobotMsg();
            msg.Type = RobotMsgType.Send;
            msg.ID = SID;
            msg.Action = RobotMsgAction.BasePoint;
            SendMsg(msg, true);
        }
        public void SetIO(int outputIndex, bool isOn)
        {
            RobotMsg msg = new RobotMsg();
            msg.Type = RobotMsgType.Send;
            msg.ID = SID;
            msg.Action = RobotMsgAction.IOSet;
            msg.Para1 = outputIndex;
            msg.Para2 = isOn ? 1 : 0;
            SendMsg(msg, true);
        }
        private void TaskTimeoutCheck(bool isWaitFinished, int msgId, string errorMsg)
        {
            if (isWaitFinished)
            {
                taskHandleDict[msgId] = new ManualResetEvent(false);
                taskHandleDict[msgId].Reset();
                bool isNotTimeout = taskHandleDict[msgId].WaitOne((int)(IConfig.OperationTimeout * 60 * 1000));
                taskHandleDict.Remove(msgId);
                if (!isNotTimeout)
                {
                    throw new ProcessException("反馈数据超时\r\n" + msg.GetDisplayText(), null);
                    throw new ProcessException(errorMsg);
                }
            }
        }
@@ -295,14 +455,16 @@
        protected List<int> oldValues = new List<int>();
        List<int> newValues = new List<int>();
        public ManualResetEvent MonitorHandle { get; set; } = new ManualResetEvent(false);
        //public ManualResetEvent IOChangedHandle { get; set; } = new ManualResetEvent(true);
        public List<int> GetMonitorValues(int startAddress, int length)
        public List<int> GetIOValues()
        {
            MonitorHandle.Reset();
            scanMsg.ID = SID;
            SendMsg(scanMsg, true, true);
            MonitorHandle.WaitOne(IConfig.ReplyTimeout);
            var isNotTimeout = MonitorHandle.WaitOne(IConfig.ReplyTimeout * 3);
            if (!isNotTimeout)
                throw new ProcessException($"{Name}监听操作超时");
            return newValues;
        }
@@ -313,35 +475,51 @@
            {
                try
                {
                    List<int> newValues = GetMonitorValues(0, 0);
                    if (newValues == null || newValues.Count == 0)
                        continue;
                    if (oldValues.Count == 0)
                    if (IConfig.IsEnableMonitor)
                    {
                        oldValues = newValues.ConvertAll(s => -1).ToList();
                    }
                        List<int> newValues = GetIOValues();
                    if (oldValues.Count == newValues.Count)
                    {
                        var tempNew = new List<int>(newValues);
                        var tempOld = new List<int>(oldValues);
                        MonitorCheckAndInvoke(tempNew, tempOld);
                        if (newValues == null || newValues.Count == 0)
                            continue;
                        if (oldValues.Count == 0)
                        {
                            oldValues = newValues.ConvertAll(s => -1).ToList();
                        }
                        if (oldValues.Count == newValues.Count)
                        {
                            var tempNew = new List<int>(newValues);
                            var tempOld = new List<int>(oldValues);
                            MonitorCheckAndInvoke(tempNew, tempOld);
                        }
                        oldValues = new List<int>(newValues);
                    }
                    oldValues = new List<int>(newValues);
                    Thread.Sleep(IConfig.ScanInterval);
                }
                catch (Exception ex)
                {
                    OnLog?.Invoke(DateTime.Now, this, $"{Name}监听异常:{ex.GetExceptionMessage()}");
                    LogAsync(DateTime.Now, "监听异常", ex.GetExceptionMessage());
                }
            }
        }
        protected virtual void MonitorCheckAndInvoke(List<int> tempNew, List<int> tempOld)
        {
            IConfig.WarningSetCollection.ForEach(w =>
            {
                if (w.WarningIndex_Word < 0 || w.WarningIndex_Word >= tempNew.Count)
                    return;
                bool isOn = tempNew[w.WarningIndex_Word] == 1;
                if (w.CurrentStatus != isOn)
                {
                    w.CurrentStatus = isOn;
                    OnMonitorAlarm?.BeginInvoke(DateTime.Now, this, w, null, null);
                }
            });
            IConfig.MonitorSetCollection.ForEach(m =>
            {
                if (m.TriggerIndex < 0 || m.TriggerIndex >= tempNew.Count)
@@ -371,6 +549,11 @@
                }
            });
        }
        public virtual void ResetAlarm()
        {
            IConfig.WarningSetCollection.ForEach(u => u.CurrentStatus = !u.TriggerValue);
        }
        #endregion
    }
}