using DbCommon.BusinessCore.BaseCore; using DbCommon.Enties.DbModels; using Mapster; using ProjectManagementSystem.Common.Config; using ProjectManagementSystem.Common.Extenions; using ProjectManagementSystem.Common.Logger; using ProjectManagementSystem.Device.Command; using ProjectManagementSystem.Device.CommandCallback; using ProjectManagementSystem.Device.Core; using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; namespace ProjectManagementSystem.Common.Core { public class DeviceControl { private static DeviceControl m_instance; private CommandRoller commandRollerQuery = new CommandRoller(); public CasunCommunication Communication { get; private set; } public static DeviceControl Instance { get { if (m_instance == null) { m_instance = new DeviceControl(); if (!m_instance.Initialize()) { m_instance = null; } } return m_instance; } } private DeviceControl() { } private bool Initialize() { string ipAddress = Function.AppSetting.TryGetValue("ListenIp"); int port = Function.AppSetting.TryGetValue("ListenPort"); string comPortName = Function.AppSetting.TryGetValue("ComPortName"); Communication = new CasunCommunication(); Communication.OnInfoRoller += Communication_OnInfoRoller; Communication.OnInfoIO += Communication_OnInfoIO; Communication.OnInfoBox += Communication_OnInfoBox; Communication.OnInfoBoxRelease += Communication_OnInfoBoxRelease; Communication.OnInfoAgv += Communication_OnInfoAgv; if (!string.IsNullOrEmpty(ipAddress)) { var tcp = new CommunicationTcp(ipAddress, port); tcp.OnLogMsg += LogMsg; tcp.DataReceived += (addr, data) => Communication.Handling(addr, data); tcp.Start(); if (tcp.IsStart) { Communication.Communications.Add(tcp); } else { return false; } var udp = new CommunicationUdp(ipAddress, port); udp.OnLogMsg += LogMsg; udp.DataReceived += (addr, data) => Communication.Handling(addr, data); udp.Start(); if (udp.IsStart) { Communication.Communications.Add(udp); } else { return false; } } if (!string.IsNullOrEmpty(comPortName)) { var com = new CommunicationCom(comPortName, 9600); com.OnLogMsg += LogMsg; com.DataReceived += (addr, data) => Communication.Handling(addr, data); com.Start(); if (com.IsStart) { Communication.Communications.Add(com); } else { return false; } } var vcu = CommunicationVcu.Instance; vcu.OnLogMsg += LogMsg; vcu.DataReceived += (addr, data) => Communication.Handling(addr, data); Communication.Communications.Add(vcu); CLog.Instance.SystemLog.WriteDebug($"DeviceControl已启动"); return true; } private void Communication_OnInfoAgv(InfoAgv info) { CLog.Instance.GetAgvLog(info.AgvId).WriteDebug($"{info.AgvId}# M:{info.Mark} R:{info.Route} S:0x{info.Status:X2}({info.StatusEnum}) A:0x{info.Alarm:X2}({info.AlarmText})"); } private void Communication_OnInfoBoxRelease(InfoBoxRelease info) { if (info.BoxReleaseLightOn) { CLog.Instance.SystemLog.WriteInfo($"放行盒已亮灯,地标{info.Mark} 路线{info.Route} AGV{info.AgvId}"); } if (info.BoxReleaseAgv) { CLog.Instance.SystemLog.WriteInfo($"放行盒已放行,地标{info.Mark} 路线{info.Route} AGV{info.AgvId}"); } } private void Communication_OnInfoBox(InfoBox info) { if (info.BoxCalled || info.BoxCancelCall) { CLog.Instance.SystemLog.WriteInfo($"线路{info.Route} 叫料{info.BoxCalled} 叫料取消{info.BoxCancelCall}"); //RouteCalled.Instance.Call(info.Adapt()); } } private void Communication_OnInfoIO(InfoIO info) { } private void Communication_OnInfoRoller(InfoRoller info) { } private void LogMsg(string obj, Exception ex) { if (ex == null) { CLog.Instance.DeviceLog.WriteDebug(obj); } else { CLog.Instance.DeviceLog.WriteException("DeviceControl", obj, ex); } } #region IO透传功能 private int GetIOAddressIndex(string address) { //解析地址,格式Y1-Y8(输出信号) var invalidValue = -1; if (string.IsNullOrEmpty(address)) return invalidValue; if (!int.TryParse(address.Substring(1), out int index)) { return invalidValue; } index--; if (index < 0) { return invalidValue; } return index; } public bool CheckInputIO(int id, string[] addressArray, bool[] bitArray, out string msg) { msg = null; for (int i = 0; i < addressArray.Length; i++) { string plcAddr = addressArray[i]; bool plcValue = bitArray[i]; var result2 = GetInputIO(id, addressArray[i]); if (result2.Item1 == false || result2.Item2 != plcValue) { msg = $"等待信号({plcAddr}={plcValue})"; return false; } } return true; } public bool CheckOutputIO(int id, string[] addressArray, bool[] bitArray, out string msg) { msg = null; for (int i = 0; i < addressArray.Length; i++) { string plcAddr = addressArray[i]; bool plcValue = bitArray[i]; var result = GetOutputIO(id, addressArray[i]); if (result.Item1 == false || result.Item2 != plcValue) { msg = $"写入失败({plcAddr}写入{plcValue})"; return false; } } return true; } public Tuple GetInputIO(int id, string address) { int index = GetIOAddressIndex(address); if (index < 0) return new Tuple(false, false); if (!Communication.InfoIODictionary.TryGetValue(id, out var info)) { return new Tuple(false, false); } if (!info.DataValid) return new Tuple(false, false); bool bitTrue = (info.Input & (0x01 << index)) > 0; return new Tuple(true, bitTrue); } public Tuple GetOutputIO(int id, string address) { int index = GetIOAddressIndex(address); if (index < 0) return new Tuple(false, false); if (!Communication.InfoIODictionary.TryGetValue(id, out var info)) { return new Tuple(false, false); } if (!info.DataValid) return new Tuple(false, false); bool bitTrue = (info.Output & (0x01 << index)) > 0; return new Tuple(true, bitTrue); } public void SetOutputIO(int id, string address, bool bit) { SetOutputIO(id, new string[] { address }, new bool[] { bit }); } public void SetOutputIO(int id, string[] addressArray, bool[] bitArray) { if (addressArray == null || addressArray.Length == 0) return; if (bitArray == null || bitArray.Length == 0) return; int[] indexArray = new int[addressArray.Length]; for (int i = 0; i < addressArray.Length; i++) { string address = addressArray[i]; indexArray[i] = GetIOAddressIndex(address); } SetOutputIO(id, indexArray, bitArray); } public bool SetOutputIO_ThenCheck(int id, string[] addressArray, bool[] bitArray, out string msg) { msg = null; SetOutputIO(id, addressArray, bitArray); for (int i = 0; i < 50; i++) { if (CheckOutputIO(id, addressArray, bitArray, out msg)) { return true; } Thread.Sleep(20); } return false; } public void SetOutputIO(int id, int[] indexArray, bool[] bitArray) { if (!Communication.InfoIODictionary.TryGetValue(id, out var info)) { return; } if (!info.DataValid) return; ushort newOutput = info.Output; for (int i = 0; i < indexArray.Length; i++) { int index = indexArray[i]; if (index < 0) { return; } bool bit = bitArray[i]; if (bit) { newOutput = (ushort)(newOutput | (0x01 << index)); } else { newOutput = (ushort)(newOutput & (ushort.MaxValue - (1 << index))); } } SetOutputIO(id, newOutput); } public void SetOutputIO(int id, ushort output) { var data = new CommandIO(); data.TargetID = (byte)id; data.Output = output; SendCommand(data, id, Communication.InfoIODictionary); } public void SetOutputIOClear(int id) { if (Communication.InfoIODictionary.TryGetValue(id, out var info) && info.Output != 0) { SetOutputIO(id, 0); CLog.Instance.SystemLog.WriteInfo($"对接盒ID{id},清零输出"); Thread.Sleep(100); } } #endregion #region 滚筒台对接 public void RollerOperate(int id, ushort code) { var data = new CommandRoller(); data.TargetID = (byte)id; data.ActionCode = code; SendCommand(data, id, Communication.InfoRollerDictionary); } public void RollerOperateClear(int id) { var data = new CommandRoller(); data.TargetID = (byte)id; data.Operate = 0; data.ActionCode = 0; SendCommand(data, id, Communication.InfoRollerDictionary); } public void RollerActionClear(int id) { var data = new CommandRoller(); data.TargetID = (byte)id; data.ActionCode = 0; SendCommand(data, id, Communication.InfoRollerDictionary); } public void RollerQuery(int id) { commandRollerQuery.Function = 0x21; commandRollerQuery.TargetID = (byte)id; SendCommand(commandRollerQuery, id, Communication.InfoRollerDictionary); } public void RollerQuery() { var configList = ExcelConfig.Instance.RouteConfigList; for (int i = 0; i < configList.Count; i++) { var config = configList[i]; if (config.RollerID > 0) { RollerQuery(config.RollerID); } } } #endregion #region 华星滚筒 public void RollerHxOperate(int id, ushort code) { var data = new CommandRollerHx(); data.TargetID = (byte)id; data.Function = 0x51; data.ActionCode = (byte)code; SendCommand(data, id, Communication.InfoRollerHxDictionary); } public void RollerHxQuery(int id) { var data = new CommandRollerHx(); data.TargetID = (byte)id; data.Function = 0x53; SendCommand(data, id, Communication.InfoRollerHxDictionary); } #endregion #region 报警灯功能 public void SetAlarmLight(int id, int lightType) { var data = new CommandAlarmLight(); data.DeviceId = (byte)id; data.LightType = (byte)lightType; SendCommand(data, id, Communication.InfoAlarmLightDictionary); } #endregion #region 叫料盒功能 public void CallBoxQuery(int route) { var data = new CommandBox(); data.Route = route; data.Function = 0x40; SendCommand(data, route, Communication.InfoBoxDictionary); } public void CallBoxLightOff(int route) { var data = new CommandBox(); data.Route = route; data.Function = 0x45; SendCommand(data, route, Communication.InfoBoxDictionary); } #endregion #region 放行盒功能 public void ReleaseBoxLightOn(int mark, int route = 0, int agvId = 0) { var data = new CommandBox(); data.Mark = mark; data.Route = route; data.AgvId = (byte)agvId; data.Function = 0x35; SendCommand(data, mark, Communication.InfoBoxReleaseDictionary); } public void ReleaseBoxLightOff(int mark, int route = 0, int agvId = 0) { var data = new CommandBox(); data.Mark = mark; data.Route = route; data.AgvId = (byte)agvId; data.Function = 0x38; SendCommand(data, mark, Communication.InfoBoxReleaseDictionary); } #endregion #region 有轨AGV public void ReleaseAgvOnStop(int mark, int route, int agvId) { var data = new CommandBox(); data.Mark = mark; data.Route = route; data.AgvId = (byte)agvId; data.Function = 0x37; SendCommand(data, agvId, Communication.InfoAgvDictionary); } public void ReleaseAgvOnStop(int mark, int route, int targetMark, int agvId) { var data = new CommandBoxRelease(); data.Mark = mark; data.Spare = targetMark; data.Route = route; data.AgvId = (byte)agvId; data.Function = 0x37; SendCommand(data, agvId, Communication.InfoAgvDictionary); } public void ReleaseAgvOnStandby(int mark, int route, int agvId) { var data = new CommandBox(); data.Mark = mark; data.Route = route; data.AgvId = (byte)agvId; data.Function = 0x31; SendCommand(data, agvId, Communication.InfoAgvDictionary); } public void RailAgv_Query1061(int agvId = 0) { var data = new Command1061(); SendCommand(data, agvId, Communication.InfoAgvDictionary); } public void RailAgv_Query1063(int fps, int agvId = 0) { var data = new Command1063(); data.FPS = fps; SendCommand(data, agvId, Communication.InfoAgvDictionary); } public void RailAgv_Query() { for (int i = 1; i <= 3; i++) { RailAgv_Query1063(i); Thread.Sleep(100); } } public void RailAgv_StartButton(int agvId) { RailAgv_Control1071(agvId, 0, 0); } public void RailAgv_StopButton(int agvId) { RailAgv_Control1071(agvId, 1, 0); } public void RailAgv_Control1071(int agvId, int iOperation = 0, int iSpeed = 0) { var data = new Command1071(); data.Function = 0x71; data.Operation = (byte)iOperation; data.Speed = (byte)iSpeed; data.AgvId = (byte)agvId; SendCommand(data, agvId, Communication.InfoAgvDictionary); } /// /// 改变AGV速度 /// /// AGV编号 /// AGV速度,单位:m/min public void RailAgv_SpeedChange(int agvId, decimal speed) { var data = new CommandBox(); data.Spare = (int)Math.Round(speed * 100); data.AgvId = (byte)agvId; data.Function = 0x47; SendCommand(data, agvId, Communication.InfoAgvDictionary); } public void RailAgv_ReleaseAlarm(int agvId, int alarmSec) { var data = new CommandBox(); data.Spare = alarmSec; data.AgvId = (byte)agvId; data.Function = 0x49; SendCommand(data, agvId, Communication.InfoAgvDictionary); } #endregion /// /// 根据设备ID查找设备终结点,并向指定终结点发送指令 /// /// /// /// /// /// public void SendCommand(IDeviceCommand cmd, TKey deviceId, IDictionary infoDict) where TKey : struct where TValue : BaseInfo { string ipAddress = infoDict.TryGetValue(deviceId, out var info) ? info.RemoteEndPoint : null; var data = cmd.Serialization(); Communication.SendCommand(data, ipAddress); } } }