using Bro.Common.Base; using Bro.Common.Helper; using Bro.Common.Interface; using Bro.Common.Model; using Bro.Common.Model.Interface; using Newtonsoft.Json; using Newtonsoft.Json.Linq; 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.SeerAGV { [Device("SeerAGV", "SeerAGV", EnumHelper.DeviceAttributeType.Device)] public class SeerAGVDriver : DeviceBase, IMonitor { public Action OnAGVPositoinChanged; public Action OnAGVTaskStatusChanged; public Action OnAGVBatteryLvlChanged; public Action OnAGVIOChanged; SeerAGVInitialConfig IConfig { get => InitialConfig as SeerAGVInitialConfig; } #region DeviceBase protected override void DeviceRun(IOperationConfig config) { } protected override void DeviceSet(IDeviceConfig config) { } protected override void Init() { InitialTcpClient(ref client_State, IConfig.StatusPort); InitialTcpClient(ref client_Guide, IConfig.GuidePort); StateHandle = new ManualResetEvent(false); PositionHandle = new ManualResetEvent(false); BatteryHandle = new ManualResetEvent(false); IOHandle = new ManualResetEvent(false); _taskDoneHandle = new ManualResetEvent(false); _monitorLock = new ManualResetEvent(true); _isTaskRunning = false; } private void InitialTcpClient(ref TcpClient client, int port) { if (client == null || !client.Connected) { client = new TcpClient(); client.SendBufferSize = client.ReceiveBufferSize = 0; client.Client.Blocking = true; client.NoDelay = true; client.Connect(IPAddress.Parse(IConfig.AGVIP), port); } } protected override void Pause() { } protected override void Resume() { } protected override void Start() { msg_Position = new SeerMessage((int)AGVCode.QueryPosition, SID); msg_GuideStatus = new SeerMessage((int)AGVCode.QueryTaskStatus, SID, IConfig.IsSimpleMonitor ? JsonConvert.SerializeObject(new { simple = true }) : ""); msg_Battery = new SeerMessage((int)AGVCode.QueryBattery, SID, IConfig.IsSimpleMonitor ? JsonConvert.SerializeObject(new { simple = true }) : ""); msg_IO = new SeerMessage((int)AGVCode.QueryIO, SID); _taskDoneHandle.Reset(); _monitorLock.Set(); Task.Run(() => { Monitor(); }); Task.Run(() => { MonitorAGV(); }); } protected override void Stop() { StateHandle.Set(); PositionHandle.Set(); BatteryHandle.Set(); IOHandle.Set(); _taskDoneHandle.Set(); _monitorLock.Set(); if (client_Guide != null && client_Guide.Connected) { CancelTask(); client_Guide.Close(); client_Guide = null; } if (client_State != null && client_State.Connected) { client_State.Close(); client_State = null; } } #endregion int sid = 1; int SID { get { if (sid > 65535) { sid = 1; } return sid++; } } TcpClient client_State = new TcpClient(); TcpClient client_Guide = new TcpClient(); byte[] buffer = new byte[1024]; string currentPosition = ""; public string CurrentPosition { get => currentPosition; set { if (currentPosition != value) { currentPosition = value; if (!string.IsNullOrWhiteSpace(currentPosition)) { OnAGVPositoinChanged?.Invoke(this, currentPosition); } } } } List _taskRunningStates = new List() { AGVTaskStatus.Running, AGVTaskStatus.Waiting, AGVTaskStatus.Suspended }; List _taskDoneStates = new List() { AGVTaskStatus.Cancelled, AGVTaskStatus.Completed, AGVTaskStatus.Failed }; AGVTaskStatus taskStatus = AGVTaskStatus.None; public AGVTaskStatus TaskStatus { get => taskStatus; set { if (taskStatus != value) { taskStatus = value; if (taskStatus != AGVTaskStatus.None) { if (_isTaskRunning && _taskDoneStates.Contains(taskStatus)) { _taskDoneHandle.Set(); _isTaskRunning = false; } OnAGVTaskStatusChanged?.Invoke(this, taskStatus); } } } } float batteryLvl = 0; public float BatteryLvl { get => batteryLvl; set { if (batteryLvl != value) { float pre = batteryLvl; batteryLvl = value; OnAGVBatteryLvlChanged?.Invoke(this, pre, batteryLvl); } } } public string LastStation { get; set; } public string Destination { get; set; } = ""; SeerMessage msg_Position = new SeerMessage(); SeerMessage msg_GuideStatus = new SeerMessage(); SeerMessage msg_Battery = new SeerMessage(); SeerMessage msg_IO = new SeerMessage(); public ManualResetEvent StateHandle { get; set; } = new ManualResetEvent(false); public ManualResetEvent PositionHandle { get; set; } = new ManualResetEvent(false); public ManualResetEvent BatteryHandle { get; set; } = new ManualResetEvent(false); public ManualResetEvent IOHandle { get; set; } = new ManualResetEvent(false); private void MonitorAGV() { while (CurrentState != EnumHelper.DeviceState.DSClose && CurrentState != EnumHelper.DeviceState.DSExcept) { _monitorLock.WaitOne(); try { SendMsg(client_State, IConfig.StatusPort, msg_Position); Thread.Sleep(IConfig.ScanInterval); SendMsg(client_State, IConfig.StatusPort, msg_GuideStatus); Thread.Sleep(IConfig.ScanInterval); SendMsg(client_State, IConfig.StatusPort, msg_Battery); Thread.Sleep(IConfig.ScanInterval); SendMsg(client_State, IConfig.StatusPort, msg_IO); Thread.Sleep(IConfig.ScanInterval); } catch (Exception ex) { LogAsync(DateTime.Now, "监听异常", ex.GetExceptionMessage()); } } } private void SendMsg(TcpClient client, int port, SeerMessage msg) { int repeatTime = 5; do { try { InitialTcpClient(ref client, port); var stream = client.GetStream(); stream.Write(msg.Frame, 0, msg.Frame.Length); stream.Flush(); int recSize = stream.Read(buffer, 0, buffer.Length); if (recSize > 0) { byte[] rec = buffer.Take(recSize).ToArray(); SeerMessage recMsg = SeerMessage.GetSeerMessage(rec); if (recMsg.TypeCode != (10000 + msg.TypeCode) || recMsg.SeqNum != msg.SeqNum) { throw new ProcessException("反馈信息和发送信息不一致"); } if (recMsg.JValues.ContainsKey("ret_code")) { int retCode = recMsg.JValues.Value("ret_code"); if (retCode != 0) { throw new ProcessException($"反馈信息异常,异常码:{retCode}"); } } AnalyzeSeerMsg(recMsg); } repeatTime = 0; } catch (SocketException ex) { repeatTime--; new ProcessException("AGV网络通信异常", ExceptionLevel.Warning, ex); if (repeatTime <= 0) { throw new ProcessException("AGV网络通信失败", ExceptionLevel.Warning, ex); } Thread.Sleep(IConfig.ScanInterval); } catch (Exception ex) { throw new ProcessException("AGV信息发送异常", ExceptionLevel.Warning, ex); } } while (repeatTime > 0); } private async void AnalyzeSeerMsg(SeerMessage recMsg) { await Task.Run(() => { switch (recMsg.TypeCode - 10000) { case (int)AGVCode.QueryPosition: CurrentPosition = recMsg.JValues.Value("current_station"); LastStation = recMsg.JValues.Value("last_station"); PositionHandle.Set(); break; case (int)AGVCode.QueryTaskStatus: TaskStatus = (AGVTaskStatus)recMsg.JValues.Value("task_status"); StateHandle.Set(); break; case (int)AGVCode.QueryBattery: BatteryLvl = recMsg.JValues.Value("battery_level"); BatteryHandle.Set(); break; case (int)AGVCode.QueryIO: //recMsg.JValues.Value("DI").ToList().ForEach(j => //{ // var ioDefinition = IConfig.IOCollection.FirstOrDefault(i => i.IOIndex == j.Value("id")); // if (ioDefinition != null && j.Value("status") != ioDefinition.CurrentValue) // { // ioDefinition.CurrentValue = j.Value("status"); // OnAGVIOChanged?.Invoke(this, ioDefinition); // } //}); //高电平 1 低电平 0 _ioDict = recMsg.JValues.Value("DI").ToDictionary(u => u.Value("id"), u => u.Value("status") ? 1 : 0); IOHandle.Set(); break; default: break; } }); } public void CancelTask() { SeerMessage msg = new SeerMessage((int)AGVCode.CancelTask, SID); SendMsg(client_Guide, IConfig.GuidePort, msg); } public void PauseTask() { SeerMessage msg = new SeerMessage((int)AGVCode.PauseTask, SID); SendMsg(client_Guide, IConfig.GuidePort, msg); } ManualResetEvent _taskDoneHandle = new ManualResetEvent(false); ManualResetEvent _monitorLock = new ManualResetEvent(true); bool _isTaskRunning = false; public void TaskOrder(string dest, bool isWaitFinished) { _monitorLock.Reset(); Thread.Sleep(IConfig.ScanInterval); CurrentPosition = ""; Destination = dest; TaskStatus = AGVTaskStatus.None; SeerMessage msg = new SeerMessage((int)AGVCode.TaskOrder, SID, JsonConvert.SerializeObject(new { id = dest })); //OnLog?.BeginInvoke(DateTime.Now, this, $"{Name}行驶向 {dest}", null, null); LogAsync(DateTime.Now, "", $"{Name}行驶向 {dest}"); SendMsg(client_Guide, IConfig.GuidePort, msg); //Thread.Sleep(IConfig.ScanInterval); _monitorLock.Set(); if (isWaitFinished) { _isTaskRunning = true; _taskDoneHandle.Reset(); bool isNotTimeout = _taskDoneHandle.WaitOne((int)(IConfig.OperationTimeout * 60 * 1000)); if (!isNotTimeout) { throw new ProcessException($"{Name}执行去往{dest}动作超时"); } if (TaskStatus == AGVTaskStatus.Failed) { throw new ProcessException($"{Name}执行去往{dest}动作失败"); } else if (TaskStatus == AGVTaskStatus.Cancelled) { //OnLog?.Invoke(DateTime.Now, this, $"{Name}执行去往{dest}动作取消"); LogAsync(DateTime.Now, "", $"{Name}执行去往{dest}动作取消"); } } } #region IMonitor public event OnMonitorInvokeDelegate OnMonitorInvoke; public event OnMonitorAlarmDelegate OnMonitorAlarm; Dictionary _ioDict = new Dictionary(); public void Monitor() { while (CurrentState != EnumHelper.DeviceState.DSClose && CurrentState != EnumHelper.DeviceState.DSExcept) { try { IOHandle.Reset(); var isNotTimeout = IOHandle.WaitOne(IConfig.ScanInterval * 3); if (!isNotTimeout) throw new ProcessException($"{Name}监听超时"); IConfig.MonitorSetCollection.ForEach(m => { if (_ioDict.ContainsKey(m.TriggerIndex)) { if ((m.TriggerValue == _ioDict[m.TriggerIndex] || m.TriggerIndex == -999) && _ioDict[m.TriggerIndex] != m.CurrentValue) { if (m.OpConfig == null) { m.OpConfig = new OperationConfigBase(); } m.OpConfig.InputPara = m.InputDataIndex.ConvertAll(index => { if (_ioDict.ContainsKey(index)) { return _ioDict[index]; } else { return -1; } }).ToList(); OnMonitorInvoke?.BeginInvoke(DateTime.Now, this, m, null, null); } m.CurrentValue = _ioDict[m.TriggerIndex]; } }); } catch (Exception ex) { OnLog?.Invoke(DateTime.Now, this, $"{Name}监听异常:{ex.GetExceptionMessage()}"); } } } public virtual void ResetAlarm() { IConfig.WarningSetCollection.ForEach(u => u.CurrentStatus = !u.TriggerValue); } #endregion } }