| | |
| | | using System.Net.Sockets; |
| | | using System.Threading; |
| | | using System.Threading.Tasks; |
| | | using static Bro.Common.Helper.EnumHelper; |
| | | |
| | | namespace Bro.Device.AuboRobot |
| | | { |
| | |
| | | |
| | | if (string.IsNullOrWhiteSpace(IConfig.EndChar)) |
| | | { |
| | | throw new ProcessException("协议文本的结束字符不可为空,请检查配置", null); |
| | | throw new ProcessException("协议文本的结束字符不可为空,请检查配置"); |
| | | } |
| | | |
| | | client = new TcpClient(); |
| | |
| | | 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() |
| | |
| | | //Query Robot IOs |
| | | //SendMsg(RobotMsgType.Send, 0, true, RobotMsgAction.IO, RobotMsgParas.Query, new List<string>()); |
| | | |
| | | scanMsg = new RobotMsg(); |
| | | scanMsg.Action = RobotMsgAction.IO; |
| | | scanMsg.Para1 = RobotMsgParas.Query; |
| | | //scanMsg = new RobotMsg(); |
| | | //scanMsg.Action = RobotMsgAction.IO; |
| | | //scanMsg.Para1 = RobotMsgParas.Query; |
| | | |
| | | Task.Run(() => |
| | | { |
| | | Monitor(); |
| | | }); |
| | | //Task.Run(() => |
| | | //{ |
| | | // Monitor(); |
| | | //}); |
| | | } |
| | | |
| | | 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(); |
| | |
| | | #endregion |
| | | |
| | | TcpClient client = new TcpClient(); |
| | | NetworkStream stream = null; |
| | | byte[] buffer = new byte[1024]; |
| | | |
| | | private void OnConnect(IAsyncResult ar) |
| | |
| | | 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) |
| | | { |
| | |
| | | } |
| | | } |
| | | |
| | | private void OnDateReceived(IAsyncResult ar) |
| | | private void OnDataReceived(IAsyncResult ar) |
| | | { |
| | | try |
| | | { |
| | | int dataLength = client.GetStream().EndRead(ar); |
| | | |
| | | int dataLength = stream.EndRead(ar); |
| | | if (dataLength > 0) |
| | | { |
| | | 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); |
| | | stream.BeginRead(buffer, 0, buffer.Length, OnDataReceived, null); |
| | | } |
| | | else |
| | | { |
| | | 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(() => |
| | |
| | | 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); |
| | | } |
| | | } |
| | | }); |
| | | }); |
| | | } |
| | | |
| | |
| | | } |
| | | } |
| | | |
| | | 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())); |
| | | |
| | | SendMsg(msg, true); |
| | | } |
| | | Dictionary<int, int> replyErrorCodeDict = new Dictionary<int, int>(); |
| | | Dictionary<int, ManualResetEvent> taskHandleDict = new Dictionary<int, ManualResetEvent>(); |
| | | |
| | | public void SendReplyMsg(int replyId) |
| | | { |
| | |
| | | } |
| | | |
| | | 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); |
| | | |
| | | byte[] bytes = msg.GetMsgBytes(IConfig.Seperator, IConfig.EndChar, out string dataStr); |
| | | if (!isMonitorMsg) |
| | | { |
| | | canMonitor = false; |
| | | LogAsync(DateTime.Now, "指令发送", dataStr); |
| | | } |
| | | |
| | | if (isMonitorMsg && !canMonitor) |
| | | return; |
| | | |
| | | //lock (this) |
| | | bool isNotTimeout = true; |
| | | int reTryTime = IConfig.TimeoutRetryTimes; |
| | | do |
| | | { |
| | | client.GetStream().Write(bytes, 0, bytes.Length); |
| | | } |
| | | 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.RobotWarnings.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); |
| | | } |
| | | } |
| | | } |
| | |
| | | |
| | | protected List<int> oldValues = new List<int>(); |
| | | List<int> newValues = new List<int>(); |
| | | AutoResetEvent monitorHandle = new AutoResetEvent(false); |
| | | public List<int> GetMonitorValues(int startAddress, int length) |
| | | public ManualResetEvent MonitorHandle { get; set; } = new ManualResetEvent(false); |
| | | 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; |
| | | } |
| | |
| | | { |
| | | 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()); |
| | | } |
| | | } |
| | | } |