using 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; using System.Net; using System.Net.Sockets; using System.Threading; using System.Threading.Tasks; namespace Bro.Device.AuboRobot { [Device("AuboRobot", "奥博机器人", EnumHelper.DeviceAttributeType.Device)] public class AuboRobotDriver : DeviceBase, IMonitor { public Action OnMsgReceived { get; set; } AuboRobotInitialConfig IConfig { get => InitialConfig as AuboRobotInitialConfig; } #region DeviceBase protected override void DeviceRun(IOperationConfig config) { } protected override void DeviceSet(IDeviceConfig config) { } protected override void Init() { if (string.IsNullOrWhiteSpace(IConfig.EndChar)) { throw new ProcessException("协议文本的结束字符不可为空,请检查配置", null); } client = new TcpClient(); client.SendBufferSize = client.ReceiveBufferSize = 0; client.Client.Blocking = true; client.NoDelay = true; client.BeginConnect(IPAddress.Parse(IConfig.RobotIP), IConfig.RobotPort, OnConnect, null); } protected override void Pause() { } protected override void Resume() { } RobotMsg scanMsg = new RobotMsg(); protected override void Start() { //Query Robot IOs //SendMsg(RobotMsgType.Send, 0, true, RobotMsgAction.IO, RobotMsgParas.Query, new List()); scanMsg = new RobotMsg(); scanMsg.Action = RobotMsgAction.IO; scanMsg.Para1 = RobotMsgParas.Query; Task.Run(() => { Monitor(); }); } protected override void Stop() { client.Close(); } #endregion TcpClient client = new TcpClient(); byte[] buffer = new byte[1024]; private void OnConnect(IAsyncResult ar) { try { client.EndConnect(ar); client.GetStream().BeginRead(buffer, 0, buffer.Length, OnDateReceived, null); } catch (Exception ex) { OnLog?.Invoke(DateTime.Now, this, ex.GetExceptionMessage()); client.BeginConnect(IPAddress.Parse(IConfig.RobotIP), IConfig.RobotPort, OnConnect, null); } } private void OnDateReceived(IAsyncResult ar) { int dataLength = client.GetStream().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); } else { if (!client.Connected) { OnLog?.Invoke(DateTime.Now, this, "返回空数据,连接中断"); client.BeginConnect(IPAddress.Parse(IConfig.RobotIP), IConfig.RobotPort, OnConnect, null); } } } string msg = ""; static object analyzeLock = new object(); private async void AnalyzeData(string data) { await Task.Run(() => { lock (analyzeLock) { msg += data; var datas = msg.Split(new string[] { IConfig.EndChar }, StringSplitOptions.RemoveEmptyEntries); if (msg.EndsWith(IConfig.EndChar)) { msg = ""; } else { msg = datas[datas.Length - 1]; datas = datas.Take(datas.Length - 1).ToArray(); } AnalyzeDataList(datas); } }); } private async void AnalyzeDataList(string[] datas) { await Task.Run(() => { Array.ForEach(datas, data => { RobotMsg msg = RobotMsg.GetRobotMsg(data, IConfig.Seperator); if (msg.Type == RobotMsgType.Rec) { if (replyHandleDict.ContainsKey(msg.ID)) { replyHandleList.Remove(msg.ID); replyHandleDict[msg.ID].Set(); replyHandleDict.Remove(msg.ID); } } else { canMonitor = true; if (msg.Action == RobotMsgAction.IO && msg.Para1 == RobotMsgParas.Query) { string resultStr = msg.Datas[0]; newValues = new List(); for (int i = resultStr.Length - 1; i >= 0; i--) { newValues.Add(resultStr[i]); } monitorHandle.Set(); } else { OnMsgReceived?.BeginInvoke(DateTime.Now, this, msg, null, null); } } }); }); } int sid = 1; int SID { get { if (sid > 99) { sid = 1; } return sid++; } } List replyHandleList = new List(); Dictionary replyHandleDict = new Dictionary(); public void SendMsg(RobotMsgAction action, RobotMsgParas para1, int para2, List 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((paras ?? new List()).ConvertAll(i => i.ToString())); SendMsg(msg, true); } public void SendReplyMsg(int replyId) { RobotMsg msg = new RobotMsg(); msg.Type = RobotMsgType.Rec; msg.ID = replyId; SendMsg(msg, false); } bool canMonitor = true; public void SendMsg(RobotMsg msg, bool isWaitReply = true, bool isMonitorMsg = false) { if (isWaitReply) { replyHandleList.Add(msg.ID); replyHandleDict[msg.ID] = new AutoResetEvent(false); } byte[] bytes = msg.GetMsgBytes(IConfig.Seperator, IConfig.EndChar); if (!isMonitorMsg) { canMonitor = false; } if (isMonitorMsg && !canMonitor) return; lock (this) { client.GetStream().Write(bytes, 0, bytes.Length); if (isWaitReply) { replyHandleDict[msg.ID].WaitOne(IConfig.ReplyTimeout); if (replyHandleList.Contains(msg.ID)) { throw new ProcessException("反馈数据超时\r\n" + msg.GetDisplayText(), null); } } } } #region IMonitor public event OnMonitorInvokeDelegate OnMonitorInvoke; public event OnMonitorAlarmDelegate OnMonitorAlarm; protected List oldValues = new List(); List newValues = new List(); AutoResetEvent monitorHandle = new AutoResetEvent(false); public List GetMonitorValues(int startAddress, int length) { SendMsg(scanMsg, true, true); monitorHandle.WaitOne(); return newValues; } public virtual void Monitor() { while (CurrentState != EnumHelper.DeviceState.DSClose && CurrentState != EnumHelper.DeviceState.DSExcept) { try { List newValues = GetMonitorValues(0, 0); if (newValues == null || newValues.Count == 0) continue; if (oldValues.Count == newValues.Count) { var tempNew = new List(newValues); var tempOld = new List(oldValues); MonitorCheckAndInvoke(tempNew, tempOld); } oldValues = new List(newValues); Thread.Sleep(IConfig.ScanInterval); } catch (Exception ex) { OnLog?.Invoke(DateTime.Now, this, $"{Name}监听异常:{ex.GetExceptionMessage()}"); } } } protected virtual void MonitorCheckAndInvoke(List tempNew, List tempOld) { IConfig.MonitorSetCollection.ForEach(m => { 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); } } }); } #endregion } }