using HH.WCS.Mobox3.AnGang.api; using Newtonsoft.Json.Linq; using S7.Net; using S7.Net.Types; using System; using System.Collections; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Web.Services.Description; namespace HH.WCS.Mobox3.AnGang.device { /// /// 西门子plc /// public class S7Helper { public static Dictionary ip_Plc = new Dictionary();//内存,连接上的PLC通讯对象 public S7Helper(string ip, short rack, short slot) { Init(new S7ConfigModel() { Ip = ip, Rack = rack, Slot = slot, CpuType = CpuType.S71500 }); } /// /// S7启动初始化 /// public static void Init(S7ConfigModel s7ConfigInfo) { //配置文件读取所有的plc进行初始化 try { if (s7ConfigInfo == null) { //读取配置信息失败 return; } var plc = new Plc(s7ConfigInfo.CpuType, s7ConfigInfo.Ip, s7ConfigInfo.Rack, s7ConfigInfo.Slot); ip_Plc.Add(s7ConfigInfo.Ip, plc); Link(plc); } catch (Exception ex) { LogHelper.Info($"{ex.Message}\r\n{ex.StackTrace}"); } } /// /// 重连 /// public static void RestLink() { if (ip_Plc.Count>0) { foreach (var item in ip_Plc) { if(!item.Value.IsConnected) { Link(item.Value); } } } } /// /// 连接PLC /// /// private static void Link(Plc plc) { try { plc.Close(); plc.Open(); if (plc.IsConnected) { LogHelper.Info($"连接上{plc.IP}");//连接上 } else { LogHelper.Info($"没连上{plc.IP}");//没连上 } } catch (Exception ex) { LogHelper.Info($"{ex.Message}\r\n{ex.StackTrace}"); } } /// /// 批量读取或单独读取DB块数据(8位byte),并转换成字符串形式 /// /// plc设备通讯地址 /// DB块号 /// 起始byte地址,最小值0,1=8位=1个Block /// 读取的个数,1个=8位十六进制数 /// public static string ReadString(string deviceIp, int dbNo, int startByteAdr, int count) { string result = ""; try { var plc = GetPlc(deviceIp); if (plc != null) { if (plc.IsConnected) { var data = plc.ReadBytes(DataType.DataBlock, dbNo, startByteAdr, count); result = System.Text.Encoding.UTF8.GetString(data).TrimEnd('\0').TrimEnd('\n').TrimEnd('\r'); ;//此方法可以把byte数组转换成字符串,但是会造成\0\u结束符不显示,需要下位机正确的数据 if (result == string.Empty) { Link(plc);//设备发送的数据为空,重连 } } else { Link(plc);//设备未连接,重连 } } else { LogHelper.Info($"不存在的设备。配置文件中是否包含其设备。");//不存在的设备。配置文件中是否包含其设备。 } } catch (Exception ex) { LogHelper.Info($"{ex.Message}\r\n{ex.StackTrace}"); } return result; } /// /// 批量写入或单独写入DB块数据(8位byte),以字符串转换byte形式写入 /// /// plc设备通讯地址 /// DB块号 /// 起始byte地址,最小值0,1=8位=1个Block /// 要写入的数据 /// public static bool WriteString(string deviceIp, int dbNo, int startByteAdr, string data) { var result = false; try { var plc = GetPlc(deviceIp); if (plc != null) { if (plc.IsConnected) { byte[] bytes = System.Text.Encoding.UTF8.GetBytes(data); plc.WriteBytes(DataType.DataBlock, dbNo, startByteAdr, bytes); if (!result) { //写完再读一次确认 var readData = ReadString(deviceIp, dbNo, startByteAdr, data.Length); result = readData == data; } } else { Link(plc);//设备未连接,重连 } } else { //不存在的设备。配置文件中是否包含其设备。 } } catch (Exception ex) { LogHelper.Info($"{ex.Message}\r\n{ex.StackTrace}"); } return result; } /// /// 批量读取或单独读取DB块数据(8位byte) /// /// plc设备通讯地址 /// DB块号 /// 起始byte地址,最小值0,1=8位=1个Block /// 读取的个数,1个=8位十六进制数 /// public static byte[] ReadBytes(string deviceIp, int dbNo, int startByteAdr, int count) { byte[] result = null; try { var plc = GetPlc(deviceIp); if (plc != null) { if (plc.IsConnected) { result = plc.ReadBytes(DataType.DataBlock, dbNo, startByteAdr, count); if (result.Length == 0) { Link(plc);//设备发送的数据为空,重连 } } else { Link(plc);//设备未连接,重连 } } else { LogHelper.Info($"不存在的设备。配置文件中是否包含其设备。");//不存在的设备。配置文件中是否包含其设备。 } } catch (Exception ex) { LogHelper.Info($"{ex.Message}\r\n{ex.StackTrace}"); } return result; } /// /// 批量写入或单独写入DB块数据(8位byte) /// /// plc设备通讯地址 /// DB块号 /// 起始byte地址,最小值0,1=8位=1个Block /// 要写入的数据 /// public static bool WriteBytes(string deviceIp, int dbNo, int startByteAdr, byte[] data) { var result = false; try { var plc = GetPlc(deviceIp); if (plc != null) { if (plc.IsConnected) { plc.WriteBytes(DataType.DataBlock, dbNo, startByteAdr, data); if (!result) { //写完再读一次确认 var readData = ReadBytes(deviceIp, dbNo, startByteAdr, data.Length); result = readData.SequenceEqual(data); } } else { Link(plc);//设备未连接,重连 } } else { LogHelper.Info($"不存在的设备。配置文件中是否包含其设备。");//不存在的设备。配置文件中是否包含其设备。 } } catch (Exception ex) { LogHelper.Info($"{ex.Message}\r\n{ex.StackTrace}"); } return result; } /// /// 批量读取或单独读取DB块数据(1位bit) /// /// plc设备通讯地址 /// DB块号 /// 起始byte地址,最小值0,1=8位=1个Block /// 要读取多少位 /// 从第几位开始读取 /// public static BitArray ReadBits(string deviceIp, int dbNo, int startByteAdr, int count, byte bitAdr = 0) { BitArray result = null; try { var plc = GetPlc(deviceIp); if (plc != null) { if (plc.IsConnected) { var data = plc.Read(DataType.DataBlock, dbNo, startByteAdr, VarType.Bit, count, bitAdr); if (count == 1) { result = new BitArray(new bool[] { (bool)data }); } else { result = (BitArray)data; } if (result.Length == 0) { Link(plc);//设备发送的数据为空,重连 } } else { Link(plc);//设备未连接,重连 } } else { LogHelper.Info($"不存在的设备。配置文件中是否包含其设备。");//不存在的设备。配置文件中是否包含其设备。 } } catch (Exception ex) { LogHelper.Info($"{ex.Message}\r\n{ex.StackTrace}"); } return result; } /// /// 批量写入或单独写入DB块数据(1位bit) /// /// plc设备通讯地址 /// DB块号 /// 起始byte地址,最小值0,1=8位=1个Block /// 起始bit地址,从第几位开始写k /// 要写入的数据 /// public static bool WriteBits(string deviceIp, int dbNo, int startByteAdr, byte biteAdr, BitArray bitValue) { var result = false; try { var plc = GetPlc(deviceIp); if (plc != null) { if (plc.IsConnected) { for (int i = 0; i < bitValue.Length; i++) { plc.WriteBit(DataType.DataBlock, dbNo, startByteAdr, biteAdr + i, bitValue[i]); } if (!result) { //写完再读一次确认 var readData = ReadBits(deviceIp, dbNo, startByteAdr, bitValue.Length, biteAdr); result = CompareBitArray(readData, bitValue); } } else { Link(plc);//设备未连接,重连 } } else { LogHelper.Info($"不存在的设备。配置文件中是否包含其设备。");//不存在的设备。配置文件中是否包含其设备。 } } catch (Exception ex) { LogHelper.Info($"{ex.Message}\r\n{ex.StackTrace}"); } return result; } /// /// 获取PLC读写对象 /// /// /// private static Plc GetPlc(string plc) { if (ip_Plc.ContainsKey(plc)) { return ip_Plc[plc]; } else { return null; } } /// /// 比较两个二进制的数值是否相同 /// /// /// /// private static bool CompareBitArray(BitArray b1, BitArray b2) { bool result = true; b1.Xor(b2).Not();//异或操作 然后 非操作 foreach (var item in b1) { if (!(bool)item) { result = false; break; } } return result; } /// /// 通过S7协议连接下位机时需要的model,应该放在model层,这里我懒了 /// public class S7ConfigModel { public CpuType CpuType { set; get; }//协议类型 public string Ip { set; get; }//IP地址 public short Rack { set; get; }//架子号 public short Slot { set; get; }//插槽号 } } }