using Newtonsoft.Json.Linq; using ProjectManagementSystem.Common.Config; using ProjectManagementSystem.Common.Extenions; using ProjectManagementSystem.Common.Logger; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; namespace ProjectManagementSystem.Common.Core { public class PlcControl { private static PlcControl m_instance; private Dictionary m_plcDict = new Dictionary(); public List JDataList { get; set; } = new List(); private string[] columnNameArray = new string[] { "PLC允许进入" , "PLC放行" , "PLC返修" , "AGV请求进入", "AGV正在进入", "AGV到位", "AGV正在离开" }; private string[] signalMonitorColumnNameArray = new string[] { "PLC呼叫满盘", "PLC转运空盘" }; public static PlcControl Instance { get { if (m_instance == null) { m_instance = new PlcControl(); if (!m_instance.Initialize()) { m_instance = null; } } return m_instance; } } private PlcControl() { } private bool Initialize() { var dataList = ExcelConfig.Instance.RouteConfigList; for (int i = 0; i < dataList.Count; i++) { var data = dataList[i]; string plcIpAddr = data.PlcIpAddr; if (!string.IsNullOrEmpty(plcIpAddr)) { bool selfPlcReadWrite = data.LocationCode.GetLocationMember("独立通讯(PLC)").ToValue(); if (selfPlcReadWrite) { //每个库位独立的PLC通讯对象 var plc = GetReadWriteNet(data); data.PlcReadWrite = plc; } else { //库位相同IP共用PLC通讯对象 if (!m_plcDict.ContainsKey(plcIpAddr)) { var plc = GetReadWriteNet(data); m_plcDict.Add(plcIpAddr, plc); } if (m_plcDict.ContainsKey(plcIpAddr)) { data.PlcReadWrite = m_plcDict[plcIpAddr]; } } } } columnNameArray = Function.AppSetting.TryGetValue("PlcSignalColumnName").ToValueArray(); var dataList2 = ExcelConfig.Instance.InfoPlcList; for (int i = 0; i < dataList2.Count; i++) { var data = dataList2[i]; data.routeConfig = ExcelConfig.Instance.RouteConfigList.FirstOrDefault(d => d.LocationCode == data.库位号); data.JData = new JObject(); string defaultAddr = data.routeConfig.PlcHeartbearAddr; data.PlcSignalAddrArray = new string[columnNameArray.Length]; data.PlcSignalAddrLengthArray = new ushort[columnNameArray.Length]; for (int infoIndex = 0; infoIndex < columnNameArray.Length; infoIndex++) { string info = columnNameArray[infoIndex]; string plcRealAddr = data.routeConfig.LocationCode.GetLocationMember(info); data.PlcSignalAddrArray[infoIndex] = string.IsNullOrEmpty(plcRealAddr) ? defaultAddr : plcRealAddr; data.PlcSignalAddrLengthArray[infoIndex] = 1; } var jData = new JObject(); jData["库位号"] = data.routeConfig.LocationCode; jData["IP地址"] = data.routeConfig.PlcIpAddr; JDataList.Add(jData); } Task.Factory.StartNew(UserThread); return true; } /// /// 获取创建的PLC通讯对象 /// /// /// private HslCommunication.Core.IReadWriteNet GetReadWriteNet(RouteConfig data) { string plcIpAddr = data.PlcIpAddr; var plcProtocol = data.LocationCode.GetLocationMember("通讯协议(PLC)"); switch (plcProtocol) { case "SiemensS7Net": { var plc = new HslCommunication.Profinet.Siemens.SiemensS7Net(HslCommunication.Profinet.Siemens.SiemensPLCS.S1500, plcIpAddr); plc.ConnectTimeOut = 1000; plc.ReceiveTimeOut = 1000; plc.SetPersistentConnection(); return plc; } case "MelsecMcNet": { var plc = new HslCommunication.Profinet.Melsec.MelsecMcNet(plcIpAddr, 5000); plc.ConnectTimeOut = 1000; plc.ReceiveTimeOut = 1000; plc.SetPersistentConnection(); return plc; } case "OmronFinsNet": { var plc = new HslCommunication.Profinet.Omron.OmronFinsNet(plcIpAddr, 5000); plc.ConnectTimeOut = 1000; plc.ReceiveTimeOut = 1000; plc.SetPersistentConnection(); return plc; } case "AllenBradleyNet": { var plc = new HslCommunication.Profinet.AllenBradley.AllenBradleyNet(plcIpAddr); plc.ConnectTimeOut = 1000; plc.ReceiveTimeOut = 1000; plc.SetPersistentConnection(); return plc; } case "ModbusRtuOverTcp": { var plc = new HslCommunication.ModBus.ModbusRtuOverTcp(plcIpAddr); plc.ConnectTimeOut = 1000; plc.ReceiveTimeOut = 1000; plc.SetPersistentConnection(); return plc; } default: { var plc = new HslCommunication.Profinet.AllenBradley.AllenBradleyNet(plcIpAddr); plc.ConnectTimeOut = 1000; plc.ReceiveTimeOut = 1000; plc.SetPersistentConnection(); return plc; } } } private void Clear(RouteConfig routeConfig) { var plcBehaviorList = ExcelConfig.Instance.PlcBehaviorList .Where(d => !string.IsNullOrEmpty(d.Remark) && d.Remark.Contains("初始化")); if (plcBehaviorList == null || plcBehaviorList.Count() == 0) { //string strLog = $"{routeConfig.LocationCode} IP地址:{routeConfig.PlcIpAddr},无需清零地址"; //CLog.Instance.SystemLog.WriteInfo(strLog); return; } foreach (var item in plcBehaviorList) { foreach (string addrDesc in item.DbAddressWrite) { string addr = routeConfig.LocationCode.GetPlcTaskAddr(addrDesc); if (string.IsNullOrEmpty(addr)) continue; int id = routeConfig.IOTransID; if(id > 0) { var readResult2 = DeviceControl.Instance.GetOutputIO(id, addr); if (readResult2.Item1 && readResult2.Item2) { DeviceControl.Instance.SetOutputIO(id, addr, false); string strLog = $"{routeConfig.LocationCode},IO对接盒ID{id},清零:{addr} ({addrDesc})"; CLog.Instance.SystemLog.WriteInfo(strLog); Thread.Sleep(50); } } var plc = routeConfig.PlcReadWrite; if (plc != null && routeConfig.PlcConnected) { var readResult = plc.ReadBool(addr); if (!readResult.IsSuccess || (readResult.IsSuccess && readResult.Content != false)) { var result = plc.Write(addr, false); string strLog = $"{routeConfig.LocationCode},{routeConfig.PlcIpAddr},清零:{addr} ({addrDesc}),写入{result.IsSuccess.ToChineseString()}"; CLog.Instance.SystemLog.WriteInfo(strLog); } } } } } private void PlcTaskProc() { var RouteConfigList = ExcelConfig.Instance.RouteConfigList; for (int i = 0; i < RouteConfigList.Count; i++) { var routeConfig = RouteConfigList[i]; if (!string.IsNullOrEmpty(routeConfig.PlcHeartbearAddr) && routeConfig.PlcReadWrite != null) { //读取PLC心跳信号 var tempResult = routeConfig.PlcReadWrite.ReadBool(routeConfig.PlcHeartbearAddr); if (routeConfig.PlcConnected != tempResult.IsSuccess) { CLog.Instance.SystemLog.WriteInfo($"{routeConfig.LocationCode} {routeConfig.PlcIpAddr} PLC连接:{tempResult.IsSuccess.ToChineseString()}"); } routeConfig.PlcConnected = tempResult.IsSuccess; //回写PLC心跳信号 if (tempResult.IsSuccess && !string.IsNullOrEmpty(routeConfig.PlcHeartbearAddr_AGV)) { routeConfig.PlcReadWrite.Write(routeConfig.PlcHeartbearAddr_AGV, tempResult.Content); } } } } private void PlcMonitorProc() { var RouteConfigList = ExcelConfig.Instance.RouteConfigList; for (int i = 0; i < RouteConfigList.Count; i++) { var routeConfig = RouteConfigList[i]; if (routeConfig.PlcConnected) { //监控PLC信号 for (int idx = 0; idx < signalMonitorColumnNameArray.Length; idx++) { string colName = signalMonitorColumnNameArray[idx]; var signalAddr = routeConfig.LocationCode.GetLocationMember(colName); if (!string.IsNullOrEmpty(signalAddr)) { var readResult = routeConfig.PlcReadWrite.ReadBool(signalAddr); var signalValue = readResult.IsSuccess ? readResult.Content.ToString() : "读取失败"; if (signalValue != routeConfig.JData[colName]?.ToString()) { CLog.Instance.SystemLog.WriteInfo($"{routeConfig.LocationCode} {routeConfig.PlcIpAddr} {colName}信号:{signalAddr}={signalValue}"); } routeConfig.JData[colName] = signalValue; } } } } } private void PlcClearProc() { var RouteConfigList = ExcelConfig.Instance.RouteConfigList; for (int i = 0; i < RouteConfigList.Count; i++) { var routeConfig = RouteConfigList[i]; if (routeConfig.PlcIsNeedClear) { Clear(routeConfig); } } } public List ReadPlcInfo() { //用于显示 var infoPlcList = ExcelConfig.Instance.InfoPlcList; //var RouteConfigList = ExcelConfig.Instance.RouteConfigList; Parallel.ForEach(infoPlcList, delegate (InfoPlc info, ParallelLoopState loopState) { try { if (info.routeConfig.PlcConnected) { DateTime start = DateTime.Now; //单个读取信号 for (int i = 0; i < columnNameArray.Length; i++) { string colName = columnNameArray[i]; string addr = info.routeConfig.LocationCode.GetLocationMember(colName); if (!string.IsNullOrEmpty(addr)) { var result = info.routeConfig.PlcReadWrite.ReadBool(addr); if (result.IsSuccess) { info.JData[colName] = result.Content; } else { info.JData[colName] = null; } } else { info.JData[colName] = null; } } info.LastUpdateTime = DateTime.Now; //////离散地址批量读取,部分plc支持 ////var plc = info.routeConfig.PlcReadWrite as HslCommunication.Profinet.AllenBradley.AllenBradleyNet; //var plc = info.routeConfig.PlcReadWrite as HslCommunication.Profinet.Siemens.SiemensS7Net; //if (plc == null) //{ // CLog.Instance.SystemLog.WriteInfo("PlcReadWrite转换失败"); // return; //} ////批量读取 //var result = plc.Read(info.PlcSignalAddrArray, info.PlcSignalAddrLengthArray); //if (result.IsSuccess) //{ // for (int i = 0; i < columnNameArray.Length; i++) // { // string colName = columnNameArray[i]; // string addr = info.routeConfig.LocationCode.GetLocationMember(colName); // if (string.IsNullOrEmpty(addr)) // { // info.JData[colName] = null; // } // else // { // //info.JData[colName] = plc.ByteTransform.TransBool(result.Content, i); // int bitIndex = int.Parse(addr.Last().ToString()); // info.JData[colName] = result.Content[i].GetBitVaule(bitIndex); // } // } // info.LastUpdateTime = DateTime.Now; //} info.JData["耗时"] = Math.Round((DateTime.Now - start).TotalMilliseconds); } } catch { } }); for (int index = 0; index < infoPlcList.Count; index++) { var info = infoPlcList[index]; var jData = JDataList[index]; for (int i = 0; i < columnNameArray.Length; i++) { string colName = columnNameArray[i]; jData[colName] = info.JData[colName]; } jData["耗时(ms)"] = info.JData["耗时"]; jData["LastUpdateTime"] = info.LastUpdateTime; jData["有效"] = info.有效; } return JDataList.ToList(); } private void UserThread() { CLog.Instance.SystemLog.WriteDebug($"PlcControl已启动"); Thread.Sleep(2000); uint counter = 0; while (true) { try { PlcTaskProc(); PlcMonitorProc(); if (counter % 10 == 0) { PlcClearProc(); } } catch (Exception ex) { CLog.Instance.SystemLog.WriteException("PlcControl", ex); Thread.Sleep(5000); } counter++; Thread.Sleep(1000); } } } }