using Hh.Mes.POJO.BllModel; using Hh.Mes.POJO.Entity; using HHECS.Model.PLCHelper.Interfaces; using HHECS.Model.PLCHelper.PLCComponent; using HHECS.Model.PLCHelper.PLCComponent.Sharp7Component; using Sharp7; using System; using System.Collections.Generic; using System.Linq; using System.Threading; using SiemensPLCType = HHECS.Model.PLCHelper.PLCComponent.Sharp7Component.SiemensPLCType; namespace HHECS.Model.PLCHelper.Implement { /// <summary> /// 封装高性能Snap7,提供多PLC支持,提供线程安全,无需安装多余组件 /// 使用此类,请先行构造S7PLCHelpers /// </summary> public class S7Implement : IPLC { /// <summary> /// 连接配置 /// </summary> public List<S7PLCHelper> S7PLCHelpers { get; set; } = new List<S7PLCHelper>(); public string IP { get => throw new NotImplementedException(); set => throw new NotImplementedException(); } public PLCComponent.PLCType PLCType { get => throw new NotImplementedException(); set => throw new NotImplementedException(); } public string Name { get => throw new NotImplementedException(); set => throw new NotImplementedException(); } private List<LockInt> _lockIds = new List<LockInt>(); private Dictionary<string, AutoResetEvent> _lockEvent = new Dictionary<string, AutoResetEvent>(); /// <summary> /// 获取锁 /// </summary> private void GetLock(string key) { if (Interlocked.Increment(ref _lockIds.First(t => t.Key == key).I) == 1) { //如果是第一次进入 return; } else { _lockEvent.First(t => t.Key == key).Value.WaitOne(); } } /// <summary> /// 重置锁 /// </summary> private void ResetLock(string key) { _lockEvent.First(t => t.Key == key).Value.Set(); } /// <summary> /// 连接方法,使用此方法之前请先构造S7PLCHelpers /// </summary> /// <returns></returns> public BllResult Connect() { if (S7PLCHelpers.Count() == 0) { return BllResultFactory.Error($"未配置PLC参数"); } int i = 0; foreach (var item in S7PLCHelpers) { S7Client s7Client = new S7Client(); switch (Enum.Parse(typeof(SiemensPLCType), item.PLCType)) { case SiemensPLCType.S7_300: i = s7Client.ConnectTo(item.PLCIP, 0, 1); break; case SiemensPLCType.S7_400: i = s7Client.ConnectTo(item.PLCIP, item.Rack, item.Slot); break; case SiemensPLCType.S7_1200: i = s7Client.ConnectTo(item.PLCIP, 0, 1); break; case SiemensPLCType.S7_1500: i = s7Client.ConnectTo(item.PLCIP, 0, 1); break; default: return BllResultFactory.Error($"无法识别{item.PLCType}"); } if (i != 0) { return BllResultFactory.Error(s7Client.ErrorText(i)); } if (!_lockIds.Exists(t => t.Key == item.PLCIP)) { _lockIds.Add(new LockInt() { Key = item.PLCIP }); } if (!_lockEvent.TryGetValue(item.PLCIP, out AutoResetEvent e)) { _lockEvent.Add(item.PLCIP, new AutoResetEvent(false)); } item.S7Client = s7Client; } return BllResultFactory.Success(); } /// <summary> /// 断开连接,安全做法是先停止控制循环,然后调用 /// </summary> /// <returns></returns> public BllResult DisConnect() { if (S7PLCHelpers.Count() == 0) { return BllResultFactory.Error($"未配置PLC参数"); } foreach (var item in S7PLCHelpers) { item.S7Client?.Disconnect(); } //重置所有锁 _lockIds.ForEach(t => t.I = 0); return BllResultFactory.Success(); } public BllResult Connect(string ip) { if (S7PLCHelpers.Count() == 0) { return BllResultFactory.Error($"未配置PLC参数"); } var item = S7PLCHelpers.Find(t => t.PLCIP == ip); if (item == null) { return BllResultFactory.Error($"未找到IP为{ip}的PLC"); } int i = 0; S7Client s7Client = new S7Client(); switch (Enum.Parse(typeof(SiemensPLCType), item.PLCType)) { case SiemensPLCType.S7_300: i = s7Client.ConnectTo(item.PLCIP, 0, 1); break; case SiemensPLCType.S7_400: i = s7Client.ConnectTo(item.PLCIP, item.Rack, item.Slot); break; case SiemensPLCType.S7_1200: i = s7Client.ConnectTo(item.PLCIP, 0, 1); break; case SiemensPLCType.S7_1500: i = s7Client.ConnectTo(item.PLCIP, 0, 1); break; default: return BllResultFactory.Error($"无法识别{item.PLCType}"); } if (i != 0) { return BllResultFactory.Error(s7Client.ErrorText(i)); } if (!_lockIds.Exists(t => t.Key == item.PLCIP)) { _lockIds.Add(new LockInt() { Key = item.PLCIP }); } if (!_lockEvent.TryGetValue(item.PLCIP, out AutoResetEvent e)) { _lockEvent.Add(item.PLCIP, new AutoResetEvent(false)); } item.S7Client = s7Client; return BllResultFactory.Success(); } public BllResult DisConnect(string ip) { if (S7PLCHelpers.Count() == 0) { return BllResultFactory.Error($"未配置PLC参数"); } var item = S7PLCHelpers.Find(t => t.PLCIP == ip); if (item == null) { return BllResultFactory.Error($"未找到IP为{ip}的PLC"); } item.S7Client?.Disconnect(); //解锁 var temp = _lockIds.Find(t => t.Key == item.PLCIP); if (temp != null) { temp.I = 0; } return BllResultFactory.Success(); } public BllResult GetConnectStatus() { if (S7PLCHelpers.Count() == 0) { return BllResultFactory.Error($"未配置PLC参数"); } foreach (var item in S7PLCHelpers) { if (item.S7Client?.Connected != true) { return BllResultFactory.Error($"存在IP为{item.PLCIP}的PLC未连接"); } } return BllResultFactory.Success(); } public BllResult GetConnectStatus(string plcIp) { var temp = S7PLCHelpers.FirstOrDefault(t => t.PLCIP == plcIp); if (temp == null) { return BllResultFactory.Error($"未找到指定IP{plcIp}的PLC"); } else { if (temp.S7Client?.Connected == true) { return BllResultFactory.Success(); } else { return BllResultFactory.Error($"IP为{plcIp}的PLC未连接"); } } } public BllResult Read(base_equipment_prop equipmentProp) { //确定属性中对应的PLC是否存在连接 return Reads(new List<base_equipment_prop>() { equipmentProp }); } public BllResult Reads(List<base_equipment_prop> equipmentProps) { if (equipmentProps == null || equipmentProps.Count() == 0) { return BllResultFactory.Error($"未传递属性"); } //选取设备类 var ips = equipmentProps.Select(t => t.Equipment).Select(t => t.ip).Distinct().ToList(); //设备类是否对应PLC配置IP foreach (var item in ips) { var temp = S7PLCHelpers.FirstOrDefault(t => t.PLCIP == item); //确定属性中对应的PLC是否存在连接 if (temp.S7Client == null || !temp.S7Client.Connected) { return BllResultFactory.Error($"存在IP为{item}的PLC未连接"); } } try { foreach (var item in ips) { //缓存 List<byte[]> list = new List<byte[]>(); var props = equipmentProps.Where(t => t.Equipment.ip == item).ToList(); var client = S7PLCHelpers.FirstOrDefault(t => t.PLCIP == item).S7Client; S7MultiVar s7MultiVar = new S7MultiVar(client); int count = 10; int i = 0; while (true) { var tempProps = props.Skip(i).Take(count); i += count; if (tempProps.Count() == 0) { break; } //添加dataitem foreach (var prop in tempProps) { var result = S7PLCHelper.AddressAnalyze(prop.address); if (!result.Success) { return BllResultFactory.Error($"地址解析错误,属性明细Id:{prop.id},详情:{result.Msg}"); } var tran = result.Data; var temp = new byte[256]; if (s7MultiVar.Add(tran.Area, tran.DataType, tran.DataNumber, tran.DataOffset, tran.DataAmount, ref temp) == false) { return BllResultFactory.Error("添加地址失败"); } list.Add(temp); } GetLock(item); int flag = s7MultiVar.Read(); ResetLock(item); if (flag != 0) { return BllResultFactory.Error($"读取错误:{client.ErrorText(flag)}"); } var tempp = s7MultiVar.Results.ToList().Where(t => t != 0).ToList(); if (tempp.Count > 0) { return BllResultFactory.Error($"存在读取错误:{client.ErrorText(tempp[0])}"); } s7MultiVar.Clear(); }; //转换读取后的值 Console.WriteLine(DateTime.Now); for (int g = 0; g < props.Count; g++) { if (!Enum.TryParse<PLCDataType>(props[g].EquipmentTypePropTemplate.dataType, out PLCDataType dataType)) { return BllResultFactory.Error($"未识别的数据类型{props[g].EquipmentTypePropTemplate.dataType}"); } var result = S7PLCHelper.TransferBufferToString(dataType, list[g]); if (result.Success) { props[g].value = result.Data; Console.WriteLine(props[g].EquipmentTypePropTemplate.code + ":" + props[g].value); } else { return BllResultFactory.Error($"读取数据出错:{result.Msg}"); } } s7MultiVar.Clear(); Console.WriteLine(""); } } catch (Exception ex) { return BllResultFactory.Error($"读取出现异常:" + ex.ToString()); } return BllResultFactory.Success(); } public BllResult Write(base_equipment_prop equipmentProp) { return Writes(new List<base_equipment_prop>() { equipmentProp }); } public BllResult Writes(List<base_equipment_prop> equipmentProps) { if (equipmentProps == null || equipmentProps.Count() == 0) { return BllResultFactory.Error($"未传递属性"); } var ips = equipmentProps.Select(t => t.Equipment).Select(t => t.ip).Distinct().ToList(); foreach (var item in ips) { var temp = S7PLCHelpers.FirstOrDefault(t => t.PLCIP == item); //确定属性中对应的PLC是否存在连接 if (!temp.S7Client.Connected) { return BllResultFactory.Error($"存在IP为{item}的PLC未连接"); } } try { foreach (var item in ips) { var props = equipmentProps.Where(t => t.Equipment.ip == item).ToList(); var client = S7PLCHelpers.FirstOrDefault(t => t.PLCIP == item).S7Client; S7MultiVar s7MultiVar = new S7MultiVar(client); int count = 20; int i = 0; while (true) { var tempProps = props.Skip(i).Take(count); i += count; if (tempProps.Count() == 0) { break; } //添加dataitem foreach (var prop in tempProps) { var result = S7PLCHelper.AddressAnalyze(prop.address); if (!result.Success) { return BllResultFactory.Error($"地址解析错误,属性明细Id:{prop.id},详情:{result.Msg}"); } var tran = result.Data; if (!Enum.TryParse<PLCDataType>(prop.EquipmentTypePropTemplate.dataType, out PLCDataType dataType)) { return BllResultFactory.Error($"未识别的数据类型{prop.EquipmentTypePropTemplate.dataType}"); } var temp = S7PLCHelper.TransferStringToBuffer(dataType, prop.value.PadRight(20, ' ')); if (!temp.Success) { return BllResultFactory.Error($"转换数据出错:{temp.Msg}"); } var tempBytes = temp.Data; if (s7MultiVar.Add(tran.Area, tran.DataType, tran.DataNumber, tran.DataOffset, tran.DataAmount, ref tempBytes) == false) { return BllResultFactory.Error("添加地址失败"); } } GetLock(item); int flag = s7MultiVar.Write(); ResetLock(item); if (flag != 0) { return BllResultFactory.Error($"写入错误:{client.ErrorText(flag)}"); } var tempp = s7MultiVar.Results.ToList().Where(t => t != 0).ToList(); if (tempp.Count > 0) { return BllResultFactory.Error($"存在写入错误:{client.ErrorText(tempp[0])}"); } s7MultiVar.Clear(); }; } } catch (Exception ex) { return BllResultFactory.Error($"写入出现异常:{ex.ToString() }"); } return BllResultFactory.Success(); } } }