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.AuboRobot/AuboRobotDriver.cs | 464 ++++++++++++++++++++++++++++++++++++++++++++++++++------- 1 files changed, 401 insertions(+), 63 deletions(-) diff --git a/src/Bro.Device.AuboRobot/AuboRobotDriver.cs b/src/Bro.Device.AuboRobot/AuboRobotDriver.cs index 26e7324..54a3600 100644 --- a/src/Bro.Device.AuboRobot/AuboRobotDriver.cs +++ b/src/Bro.Device.AuboRobot/AuboRobotDriver.cs @@ -1,6 +1,8 @@ 锘縰sing Bro.Common.Base; using Bro.Common.Helper; using Bro.Common.Interface; +using Bro.Common.Model; +using Bro.Common.Model.Interface; using System; using System.Collections.Generic; using System.Linq; @@ -8,13 +10,14 @@ using System.Net.Sockets; using System.Threading; using System.Threading.Tasks; +using static Bro.Common.Helper.EnumHelper; namespace Bro.Device.AuboRobot { [Device("AuboRobot", "濂ュ崥鏈哄櫒浜�", EnumHelper.DeviceAttributeType.Device)] - public class AuboRobotDriver : DeviceBase + public class AuboRobotDriver : DeviceBase, IMonitor { - public Action<RobotMsg> OnMsgReceived { get; set; } + public Action<DateTime, AuboRobotDriver, RobotMsg> OnMsgReceived { get; set; } AuboRobotInitialConfig IConfig { @@ -32,9 +35,11 @@ protected override void Init() { + oldValues = new List<int>(); + if (string.IsNullOrWhiteSpace(IConfig.EndChar)) { - throw new ProcessException("鍗忚鏂囨湰鐨勭粨鏉熷瓧绗︿笉鍙负绌猴紝璇锋鏌ラ厤缃�", null); + throw new ProcessException("鍗忚鏂囨湰鐨勭粨鏉熷瓧绗︿笉鍙负绌猴紝璇锋鏌ラ厤缃�"); } client = new TcpClient(); @@ -42,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() @@ -52,19 +61,38 @@ { } + RobotMsg scanMsg = new RobotMsg(); protected override void Start() { //Query Robot IOs //SendMsg(RobotMsgType.Send, 0, true, RobotMsgAction.IO, RobotMsgParas.Query, new List<string>()); + + scanMsg = new RobotMsg(); + scanMsg.Action = RobotMsgAction.IOQuery; + + Task.Run(() => + { + Monitor(); + }); } protected override void Stop() { - client.Close(); + 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(); + } } #endregion TcpClient client = new TcpClient(); + NetworkStream stream = null; byte[] buffer = new byte[1024]; private void OnConnect(IAsyncResult ar) @@ -72,41 +100,56 @@ try { client.EndConnect(ar); - client.GetStream().BeginRead(buffer, 0, buffer.Length, OnDateReceived, null); + stream = client.GetStream(); + stream.BeginRead(buffer, 0, buffer.Length, OnDataReceived, null); } 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) + { + client.Close(); + } client.BeginConnect(IPAddress.Parse(IConfig.RobotIP), IConfig.RobotPort, OnConnect, null); } } - private void OnDateReceived(IAsyncResult ar) + private void OnDataReceived(IAsyncResult ar) { - int dataLength = client.GetStream().EndRead(ar); - - if (dataLength > 0) + try { - byte[] data = buffer.Take(dataLength).ToArray(); - - string dataStr = System.Text.Encoding.ASCII.GetString(data).Trim(); - AnalyzeData(dataStr); - - client.GetStream().BeginRead(buffer, 0, buffer.Length, OnDateReceived, null); - } - else - { - if (!client.Connected) + int dataLength = stream.EndRead(ar); + if (dataLength > 0) { - OnLog?.Invoke(DateTime.Now, this, "杩斿洖绌烘暟鎹紝杩炴帴涓柇"); - client.BeginConnect(IPAddress.Parse(IConfig.RobotIP), IConfig.RobotPort, OnConnect, null); + byte[] data = buffer.Take(dataLength).ToArray(); + + string dataStr = System.Text.Encoding.ASCII.GetString(data).Trim(); + + AnalyzeData(dataStr); + + stream.BeginRead(buffer, 0, buffer.Length, OnDataReceived, null); } + else + { + if (!client.Connected) + { + //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()}"); + 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(() => @@ -137,25 +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 - { - SendMsg(RobotMsgType.Rec, msg.ID, false); - OnMsgReceived?.Invoke(msg); - } - }); + for (int i = msg.Para1.ToString().Length - 1; i >= 0; i--) + { + newValues.Add((msg.Para1 >> i) & 1); + } + + 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; + } + + if (taskHandleDict.ContainsKey(msg.ID)) + { + taskHandleDict[msg.ID].Set(); + } + + LogAsync(DateTime.Now, "鎸囦护鍙嶉", msg.GetDisplayText()); + OnMsgReceived?.BeginInvoke(DateTime.Now, this, msg, null, null); + } + } + }); }); } @@ -164,7 +240,7 @@ { get { - if (sid > 999) + if (sid > 99) { sid = 1; } @@ -173,49 +249,311 @@ } } - List<int> replyHandleList = new List<int>(); Dictionary<int, AutoResetEvent> replyHandleDict = new Dictionary<int, AutoResetEvent>(); + Dictionary<int, int> replyErrorCodeDict = new Dictionary<int, int>(); + Dictionary<int, ManualResetEvent> taskHandleDict = new Dictionary<int, ManualResetEvent>(); - public void SendMsg(RobotMsgType type, int replyId, bool isWaitReply = true, RobotMsgAction action = RobotMsgAction.Move, RobotMsgParas para1 = RobotMsgParas.None, List<string> paras = null) + public void SendReplyMsg(int replyId) { RobotMsg msg = new RobotMsg(); - msg.Type = type; - if (msg.Type == RobotMsgType.Send) - { - msg.ID = SID; - } - else - { - msg.ID = replyId; - } + msg.Type = RobotMsgType.Rec; + msg.ID = replyId; - msg.Para1 = para1; - msg.Paras = new List<string>(paras ?? new List<string>()); - - SendMsg(msg, isWaitReply); + SendMsg(msg, false); } - public void SendMsg(RobotMsg msg, bool isWaitReply = true) + bool canMonitor = true; + 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); - client.GetStream().Write(bytes, 0, bytes.Length); + byte[] bytes = msg.GetMsgBytes(IConfig.Seperator, IConfig.EndChar, out string dataStr); + if (!isMonitorMsg) + { + 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); } } } + + #region IMonitor + public event OnMonitorInvokeDelegate OnMonitorInvoke; + public event OnMonitorAlarmDelegate OnMonitorAlarm; + + protected List<int> oldValues = new List<int>(); + List<int> newValues = new List<int>(); + public ManualResetEvent MonitorHandle { get; set; } = new ManualResetEvent(false); + public List<int> GetIOValues() + { + MonitorHandle.Reset(); + scanMsg.ID = SID; + SendMsg(scanMsg, true, true); + + var isNotTimeout = MonitorHandle.WaitOne(IConfig.ReplyTimeout * 3); + + if (!isNotTimeout) + throw new ProcessException($"{Name}鐩戝惉鎿嶄綔瓒呮椂"); + + return newValues; + } + + public virtual void Monitor() + { + while (CurrentState != EnumHelper.DeviceState.DSClose && CurrentState != EnumHelper.DeviceState.DSExcept) + { + try + { + if (IConfig.IsEnableMonitor) + { + List<int> newValues = GetIOValues(); + + 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); + } + + Thread.Sleep(IConfig.ScanInterval); + } + catch (Exception ex) + { + 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) + { + return; + } + + int newValue = tempNew[m.TriggerIndex]; + int oldValue = tempOld[m.TriggerIndex]; + + if (newValue != oldValue) + { + if (m.TriggerValue == -999 || newValue == m.TriggerValue) + { + if (m.OpConfig == null) + { + m.OpConfig = new OperationConfigBase(); + } + + m.OpConfig.InputPara = m.InputDataIndex.ConvertAll(index => + { + return tempNew[index]; + }).ToList(); + + OnMonitorInvoke?.BeginInvoke(DateTime.Now, this, m, null, null); + } + } + }); + } + + public virtual void ResetAlarm() + { + IConfig.WarningSetCollection.ForEach(u => u.CurrentStatus = !u.TriggerValue); + } + #endregion } } -- Gitblit v1.8.0