using Bro.Common.Base; using Bro.Common.Helper; using Bro.Common.Interface; using Newtonsoft.Json; using System; using System.Collections.Generic; using System.Linq; using System.Net; using System.Net.Sockets; using System.Runtime.InteropServices; using System.Text; using System.Threading; using System.Threading.Tasks; namespace Bro.Device.SeerAGV { [Device("SeerAGV", "SeerAGV", EnumHelper.DeviceAttributeType.Device)] public class SeerAGVDriver : DeviceBase { public Action OnAGVPositoinChanged; public Action OnAGVTaskStatusChanged; public Action OnAGVBatteryLvlChanged; 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); } 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 }) : ""); Task.Run(() => { MonitorAGV(); }); } protected override void Stop() { 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); } } } } AGVTaskStatus taskStatus = AGVTaskStatus.None; public AGVTaskStatus TaskStatus { get => taskStatus; set { if (taskStatus != value) { taskStatus = value; if (taskStatus != AGVTaskStatus.None) { OnAGVTaskStatusChanged?.Invoke(this, taskStatus); } } } } float batteryLvl = 0; public float BatteryLvl { get => batteryLvl; set { if (batteryLvl != value) { batteryLvl = value; OnAGVBatteryLvlChanged?.Invoke(this, batteryLvl); } } } SeerMessage msg_Position = new SeerMessage(); SeerMessage msg_GuideStatus = new SeerMessage(); SeerMessage msg_Battery = new SeerMessage(); private void MonitorAGV() { while (CurrentState != EnumHelper.DeviceState.DSClose && CurrentState != EnumHelper.DeviceState.DSExcept) { 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); } catch (Exception ex) { OnLog?.Invoke(DateTime.Now, this, $"{Name}监听异常:{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); 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("反馈信息和发送信息不一致", null); } if (recMsg.JValues.ContainsKey("ret_code")) { int retCode = recMsg.JValues.Value("ret_code"); if (retCode != 0) { throw new ProcessException($"反馈信息异常,异常码:{retCode}", null); } } AnalyzeSeerMsg(recMsg); } repeatTime = 0; } catch (SocketException ex) { repeatTime--; new ProcessException("AGV网络通信异常", ex); if (repeatTime <= 0) { throw new ProcessException("AGV网络通信失败", ex); } Thread.Sleep(IConfig.ScanInterval); } catch (Exception ex) { throw new ProcessException("AGV信息发送异常", 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"); break; case (int)AGVCode.QueryTaskStatus: TaskStatus = (AGVTaskStatus)recMsg.JValues.Value("task_status"); break; case (int)AGVCode.QueryBattery: BatteryLvl = recMsg.JValues.Value("battery_level"); 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); } public void TaskOrder(string dest) { CurrentPosition = ""; SeerMessage msg = new SeerMessage((int)AGVCode.TaskOrder, SID, JsonConvert.SerializeObject(new { id = dest })); SendMsg(client_Guide, IConfig.GuidePort, msg); } } }