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<DateTime, AuboRobotDriver, RobotMsg> 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()
|
{
|
oldValues = new List<int>();
|
|
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<string>());
|
|
scanMsg = new RobotMsg();
|
scanMsg.Action = RobotMsgAction.IO;
|
scanMsg.Para1 = RobotMsgParas.Query;
|
|
Task.Run(() =>
|
{
|
Monitor();
|
});
|
}
|
|
protected override void Stop()
|
{
|
if (client != null && client.Connected)
|
{
|
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());
|
|
if (client != null && client.Connected)
|
{
|
client.Close();
|
}
|
client.BeginConnect(IPAddress.Parse(IConfig.RobotIP), IConfig.RobotPort, OnConnect, null);
|
}
|
}
|
|
private void OnDateReceived(IAsyncResult ar)
|
{
|
try
|
{
|
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);
|
}
|
}
|
}
|
catch (Exception ex)
|
{
|
OnLog?.Invoke(DateTime.Now, this, $"{Name}数据接收异常:{ex.GetExceptionMessage()}");
|
}
|
}
|
|
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<int>();
|
|
for (int i = resultStr.Length - 1; i >= 0; i--)
|
{
|
newValues.Add(int.Parse(resultStr[i].ToString()));
|
}
|
|
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<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);
|
}
|
|
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<int> oldValues = new List<int>();
|
List<int> newValues = new List<int>();
|
AutoResetEvent monitorHandle = new AutoResetEvent(false);
|
public List<int> GetMonitorValues(int startAddress, int length)
|
{
|
scanMsg.ID = SID;
|
SendMsg(scanMsg, true, true);
|
monitorHandle.WaitOne(IConfig.ReplyTimeout);
|
|
return newValues;
|
}
|
|
public virtual void Monitor()
|
{
|
while (CurrentState != EnumHelper.DeviceState.DSClose && CurrentState != EnumHelper.DeviceState.DSExcept)
|
{
|
try
|
{
|
List<int> newValues = GetMonitorValues(0, 0);
|
|
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)
|
{
|
OnLog?.Invoke(DateTime.Now, this, $"{Name}监听异常:{ex.GetExceptionMessage()}");
|
}
|
}
|
}
|
|
protected virtual void MonitorCheckAndInvoke(List<int> tempNew, List<int> tempOld)
|
{
|
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);
|
}
|
}
|
});
|
}
|
#endregion
|
}
|
}
|