using HslCommunication; 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正在离开" }; 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.TryGetValue(plcIpAddr, out var plcObj)) { data.PlcReadWrite = plcObj; } } } } 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.GetRouteConfig(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; //读取长度2,要求PLC有多出来一个byte地址 data.PlcSignalAddrLengthArray[infoIndex] = 2; } var jData = new JObject(); jData["库位号"] = data.routeConfig.LocationCode; jData["IP地址"] = data.routeConfig.PlcIpAddr; JDataList.Add(jData); } Task.Factory.StartNew(UserThread, TaskCreationOptions.LongRunning); 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 "SiemensS7Net_S200Smart": { var plc = new HslCommunication.Profinet.Siemens.SiemensS7Net(HslCommunication.Profinet.Siemens.SiemensPLCS.S200Smart, 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, 9600); plc.ConnectTimeOut = 1000; plc.ReceiveTimeOut = 1000; plc.ByteTransform.DataFormat = HslCommunication.Core.DataFormat.BADC; plc.SetPersistentConnection(); return plc; } case "OmronFinsUdp": { var plc = new HslCommunication.Profinet.Omron.OmronFinsUdp(plcIpAddr, 9600); plc.ReceiveTimeout = 1000; plc.ByteTransform.DataFormat = HslCommunication.Core.DataFormat.BADC; return plc; } case "AllenBradleyNet": { var plc = new HslCommunication.Profinet.AllenBradley.AllenBradleyNet(plcIpAddr); plc.ConnectTimeOut = 1000; plc.ReceiveTimeOut = 1000; plc.SetPersistentConnection(); return plc; } case "ModbusTcpNet": { var plc = new HslCommunication.ModBus.ModbusTcpNet(plcIpAddr); plc.ConnectTimeOut = 1000; plc.ReceiveTimeOut = 1000; plc.ByteTransform.DataFormat = HslCommunication.Core.DataFormat.BADC; plc.SetPersistentConnection(); return plc; } case "IOBoxNet": { var plc = new Profinet.IOBoxNet(plcIpAddr, 8898); return plc; } default: { var plc = new HslCommunication.Profinet.AllenBradley.AllenBradleyNet(plcIpAddr); plc.ConnectTimeOut = 1000; plc.ReceiveTimeOut = 1000; plc.SetPersistentConnection(); return plc; } } } private void PlcTaskProc() { var configList = ExcelConfig.Instance.RouteConfigList; var plcGroupList = configList .Where(d => d.PlcReadWrite != null) .GroupBy(d => d.PlcIpAddr); foreach (var item in plcGroupList) { var first = item.FirstOrDefault(d => !string.IsNullOrEmpty(d.PlcHeartbearAddr)); if (first == null) { continue; } //读取PLC心跳信号 var tempResult = first.PlcReadWrite.ReadBool(first.PlcHeartbearAddr); if (first.PlcConnected != tempResult.IsSuccess) { CLog.Instance.SystemLog.WriteInfo($"{first.LocationCode} {first.PlcIpAddr} PLC连接:{tempResult.IsSuccess.ToChineseString()} Code:{tempResult.ErrorCode} Message:{tempResult.Message}"); } foreach (var config in item) { config.PlcConnected = tempResult.IsSuccess; } } //for (int i = 0; i < configList.Count; i++) //{ // var routeConfig = configList[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); // //} // } //} } public List ReadPlcInfo() { //用于显示 var infoPlcList = ExcelConfig.Instance.InfoPlcList; //var RouteConfigList = ExcelConfig.Instance.RouteConfigList; Parallel.ForEach(infoPlcList, delegate (InfoPlc info, ParallelLoopState loopState) { try { 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支持 OperateResult result = null; switch (info.routeConfig.PlcReadWrite) { case HslCommunication.Profinet.AllenBradley.AllenBradleyNet plc: result = plc.Read(info.PlcSignalAddrArray); break; case HslCommunication.Profinet.Siemens.SiemensS7Net plc: result = plc.Read(info.PlcSignalAddrArray, info.PlcSignalAddrLengthArray); break; default: CLog.Instance.SystemLog.WriteInfo("PlcReadWrite转换失败"); return; } //批量读取 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 { switch (info.routeConfig.PlcReadWrite) { case HslCommunication.Profinet.AllenBradley.AllenBradleyNet plc: info.JData[colName] = plc.ByteTransform.TransBool(result.Content, i) ? "1" : "0"; break; case HslCommunication.Profinet.Siemens.SiemensS7Net plc: if (addr.Contains("DBW") || addr.Count(d => d == '.') == 1) { info.JData[colName] = plc.ByteTransform.TransInt16(result.Content, i * 2); } else { int bitIndex = int.Parse(addr.Last().ToString()); info.JData[colName] = result.Content[i * 2].GetBitVaule(bitIndex) ? "1" : "0"; } break; default: break; } } } info.LastUpdateTime = DateTime.Now; } info.JData["耗时"] = Math.Round((DateTime.Now - start).TotalMilliseconds); info.JData["消息"] = result.Message; } catch (Exception ex) { info.JData["消息"] = ex.Message; } }); for (int index = 0; index < infoPlcList.Count; index++) { var info = infoPlcList[index]; var jData = JDataList[index]; jData["更新时间"] = info.LastUpdateTime.ToString("G"); jData["消息"] = info.JData["消息"]; for (int i = 0; i < columnNameArray.Length; i++) { string colName = columnNameArray[i]; jData[colName] = info.JData[colName]; } jData["耗时(ms)"] = info.JData["耗时"]; //jData["有效"] = info.有效; } return JDataList.ToList(); } private void UserThread() { CLog.Instance.SystemLog.WriteDebug($"PlcControl已启动"); Thread.Sleep(2000); while (true) { try { PlcTaskProc(); } catch (Exception ex) { CLog.Instance.SystemLog.WriteException("PlcControl", ex); Thread.Sleep(5000); } Thread.Sleep(1000); } } } }