using S7.Net; using S7.Net.Types; using System; using System.Collections.Generic; using System.Linq; using System.Reflection; using System.Runtime.InteropServices; using System.Text; using System.Threading; using System.Threading.Tasks; using System.Timers; namespace PLCS7 { public interface IPLCS7 { bool PLCConnect(); void PLCDisconnect(); bool WriteToPLC(object abstractPLCMsg, PLCDataType whoami); List ReadFromPLC(PLCDataType whichToRead, int index); } public enum PLCDataType { terminal, central, parkingSpace } public abstract class AbstractPLCLinker : IPLCS7 { protected const int mainBlockOffset = 52; protected const int parkingSpaceOffset = 18; /// /// PLC 连接状态flag /// public bool isConnected = false; /// /// plc中cpu类型 /// protected CpuType cpu; /// /// PLC的IP地址 /// protected string ip; /// /// PLC的端口号 /// protected Int16 rack; /// /// 工作站号 /// protected Int16 slot; /// /// 终端DB块iD /// protected int terminalDB; /// /// 中心DB块iD /// protected int centralDB; /// /// 车位DB块ID /// protected int parkingSpaceDB; /// /// 终端个数 /// protected int terminalCount; /// /// 停车位个数 /// protected int parkingSpaceCount; /// /// PLC S7连接对象 /// protected static Plc plc = null; public bool PLCConnect() { if (plc == null) { plc = new Plc(cpu, ip, rack, slot); } if (plc != null) { ErrorCode err = plc.Open(); if (err != ErrorCode.NoError) { Console.WriteLine("connection error"); isConnected = false; } else { Console.WriteLine("connected"); isConnected = true; } } else { isConnected = false; } return isConnected; } public void PLCDisconnect() { if (plc != null) { plc.Close(); } } public abstract List ReadFromPLC(PLCDataType whichToRead, int index); public abstract bool WriteToPLC(object abstractPLCMsg, PLCDataType whoami); } public class PLCLinker : AbstractPLCLinker { ///// ///// PLC刷新频率,来自于配置文件 ///// //private int PLC_refresh_interval; ///// ///// 无法获取配置文件时使用的PLC刷新频率 ///// //private const short PLC_TIME_SCALE = 200; //************************************** 方法区 ************************************* public void test() { Random rnd = new Random(); Task t = Task.Factory.StartNew(() => { while (true) { TerminalStru terminal1 = new TerminalStru(); terminal1 = (TerminalStru)ReadStruFromPLC(terminal1, 27, 0); Console.WriteLine(terminal1.ToString()); Thread.Sleep(200); terminal1.terminalStatus = (short)rnd.Next(1, 6); terminal1.licenseCodeA = rnd.Next(3000, 9999); terminal1.receiptNum = rnd.Next(3000, 9999); terminal1.licVerification = (short)rnd.Next(1, 555); WriteStruToPLC(terminal1, 27, 0); //List bList = Struct.ToBytes(terminal1).ToList(); //WriteMultipleBytes(27, bList, 0); ////203 chars //string str = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbccc"; ////pl.WriteMultipleBytes(1, (Encoding.ASCII.GetBytes(str)).ToList()); //byte[] bytes = pl.ReadMultipleBytes(27, 50).ToArray(); //string str2 = Encoding.ASCII.GetString(bytes); //Console.WriteLine(str2); //if (str == str2) //{ // Console.WriteLine("equals"); //} //else //{ // Console.WriteLine("error, unequal"); //} Thread.Sleep(2000); } }); t.Wait(); } /// /// PLCLinker构造函数 /// /// /// /// /// /// /// /// public PLCLinker(CpuType cpu, string ip, short rack, short slot, int terminalDB, int centralDB, int parkingSpaceDB, int terminalCount, int parkingSpaceCount) { this.cpu = cpu; this.ip = ip; this.rack = rack; this.slot = slot; this.terminalDB = terminalDB; this.centralDB = centralDB; this.parkingSpaceDB = parkingSpaceDB; this.terminalCount = terminalCount; this.parkingSpaceCount = parkingSpaceCount; isConnected = PLCConnect(); } /// /// 读取指定数据块中多个字节 /// /// /// /// /// private List ReadMultipleBytes(int db, int length, int startAddr = 0) { List resultBytes = new List(); int index = startAddr; int remains = length; while (remains > 0) { int maxToRead = Math.Min(remains, 200); try { byte[] temp = plc.ReadBytes(DataType.DataBlock, db, index, maxToRead); if (temp == null) return new List(); resultBytes.AddRange(temp); remains -= maxToRead; index += maxToRead; } catch { } } return resultBytes; } /// /// 写入指定数据块中多个字节 /// /// /// /// /// private ErrorCode WriteMultipleBytes(int db, List bytesToWrite, int startAddr = 0) { int index = startAddr; int remains = bytesToWrite.Count(); try { while (remains > 0) { int maxToWrite = Math.Min(remains, 200); ErrorCode ec = plc.WriteBytes(DataType.DataBlock, db, index, bytesToWrite.GetRange(index, maxToWrite).ToArray()); index += maxToWrite; remains -= maxToWrite; if (!ec.Equals(ErrorCode.NoError)) { return ec; } } } catch (Exception e) { Console.WriteLine(e.Message); } return ErrorCode.NoError; } /// /// 从PLC中读取结构体 /// /// /// /// /// private object ReadStruFromPLC(object obj, int db, int startAddr = 0) { Type structType = obj.GetType(); object returnedObj; try { //returnedObj = plc.ReadStruct(structType, db, startAddr); int numBytes = Struct.GetStructSize(structType); var resultBytes = plc.ReadBytes(DataType.DataBlock, db, startAddr, numBytes); returnedObj = Struct.FromBytes(structType, resultBytes); if (returnedObj != null) { return returnedObj; } } catch (Exception e) { Console.WriteLine(e.Message); } return null; //Console.WriteLine(ts.ToString()); } /// /// 向PLC中写入结构体 /// /// /// /// private ErrorCode WriteStruToPLC(object obj, int db, int startAddr = 0) { Console.WriteLine("write to PLC"); ErrorCode ec = ErrorCode.NoError; try { //ec = plc.WriteStruct(obj, 22, startAddr); List bList = Struct.ToBytes(obj).ToList(); ec = WriteMultipleBytes(db, bList, startAddr); } catch (Exception e) { Console.WriteLine(ec.ToString() + "," + e.Message); } return ec; } private short BytesRevert(short num) { byte[] temp = BitConverter.GetBytes(num); Array.Reverse(temp); return BitConverter.ToInt16(temp, 0); } private int BytesRevert(int num) { byte[] temp = BitConverter.GetBytes(num); Array.Reverse(temp); return BitConverter.ToInt32(temp, 0); } /// /// 读取PLC数据块 /// /// /// /// public override List ReadFromPLC(PLCDataType whichToRead, int index) { //更新设备状态 isConnected = plc.IsConnected; List result = new List(); if (isConnected) { switch (whichToRead) { case PLCDataType.central: object obj = ReadStruFromPLC(new MainBlockStru(), centralDB); if (obj != null) { result.Add(obj); } break; case PLCDataType.terminal: TerminalStru ts = new TerminalStru(); //index 在合理范围读取单一元素,否则全部读取 if (index > 0 && index < terminalCount) { obj = ReadStruFromPLC(ts, terminalDB, Struct.GetStructSize(ts.GetType()) * (index - 1)); if (obj != null) { result.Add(obj); } } else { for (int i = 0; i < terminalCount; i++) { obj = ReadStruFromPLC(ts, terminalDB, Struct.GetStructSize(ts.GetType()) * i); if (obj != null) { result.Add(obj); } } } break; case PLCDataType.parkingSpace: ParkingSpaceStru pss = new ParkingSpaceStru(); //index 在合理范围读取单一元素,否则全部读取 if (index > 0 && index < parkingSpaceCount) { obj = ReadStruFromPLC(pss, parkingSpaceDB, Struct.GetStructSize(pss.GetType()) * (index - 1)); if (obj != null) { result.Add(obj); } } else { for (int i = 0; i < parkingSpaceCount; i++) { obj = ReadStruFromPLC(pss, parkingSpaceDB, Struct.GetStructSize(pss.GetType()) * i); if (obj != null) { result.Add(obj); } } } break; default: Console.WriteLine("wrong type"); break; } } return result; } /// /// 写入PLC,其中可写入但不需写入字段请赋值为-1 /// /// /// /// public override bool WriteToPLC(object abstractPLCMsg, PLCDataType whoami) { //更新设备状态 isConnected = plc.IsConnected; if (abstractPLCMsg == null) return false; if (isConnected) { if (abstractPLCMsg.GetType().Equals(typeof(TerminalStru))) { TerminalStru ts = (TerminalStru)abstractPLCMsg; if (ts.terminalID <= 0 || ts.terminalID > terminalCount) { return false; } int offset = 42 * (ts.terminalID - 1); if (whoami.Equals(PLCDataType.central)) { if (ts.paymentStatus != (short)-1) { plc.WriteBytes(DataType.DataBlock, terminalDB, 28 + offset, BitConverter.GetBytes(BytesRevert(ts.paymentStatus))); } if (ts.licVerification != (short)-1) { plc.WriteBytes(DataType.DataBlock, terminalDB, 30 + offset, BitConverter.GetBytes(BytesRevert(ts.licVerification))); } if (ts.parkingFee != (short)-1) { plc.WriteBytes(DataType.DataBlock, terminalDB, 32 + offset, BitConverter.GetBytes(BytesRevert(ts.parkingFee))); } if (ts.userType != (short)-1) { plc.WriteBytes(DataType.DataBlock, terminalDB, 34 + offset, BitConverter.GetBytes(BytesRevert(ts.userType))); } } else if (whoami.Equals(PLCDataType.terminal)) { //if (ts.terminalStatus != (short)-1) { plc.WriteBytes(DataType.DataBlock, terminalDB, 2 + offset, BitConverter.GetBytes(BytesRevert(ts.terminalStatus))); } if (ts.btnStatus != (short)-1) { plc.WriteBytes(DataType.DataBlock, terminalDB, 4 + offset, BitConverter.GetBytes(BytesRevert(ts.btnStatus))); } if (ts.cmd != (short)-1) { plc.WriteBytes(DataType.DataBlock, terminalDB, 6 + offset, BitConverter.GetBytes(BytesRevert(ts.cmd))); } if (ts.licenseCodeA != -1) { plc.WriteBytes(DataType.DataBlock, terminalDB, 8 + offset, BitConverter.GetBytes(BytesRevert(ts.licenseCodeA))); } if (ts.licenseCodeB != -1) { plc.WriteBytes(DataType.DataBlock, terminalDB, 12 + offset, BitConverter.GetBytes(BytesRevert(ts.licenseCodeB))); } if (ts.licenseCodeC != -1) { plc.WriteBytes(DataType.DataBlock, terminalDB, 16 + offset, BitConverter.GetBytes(BytesRevert(ts.licenseCodeC))); } if (ts.licenseCodeD != -1) { plc.WriteBytes(DataType.DataBlock, terminalDB, 20 + offset, BitConverter.GetBytes(BytesRevert(ts.licenseCodeD))); } if (ts.receiptNum != -1) { plc.WriteBytes(DataType.DataBlock, terminalDB, 24 + offset, BitConverter.GetBytes(BytesRevert(ts.receiptNum))); } } } else if (abstractPLCMsg.GetType().Equals(typeof(MainBlockStru)) && whoami.Equals(PLCDataType.central)) { //只允许中控写入,且中控只允许写入号牌获取状态 MainBlockStru mbs = (MainBlockStru)abstractPLCMsg; byte[] temp = BitConverter.GetBytes(BytesRevert(mbs.licenseReceived)); ErrorCode ec = plc.WriteBytes(DataType.DataBlock, centralDB, mainBlockOffset, temp); if (!ec.Equals(ErrorCode.NoError)) { return false; } } else if (abstractPLCMsg.GetType().Equals(typeof(ParkingSpaceStru)) && whoami.Equals(PLCDataType.central)) { //只允许中控写入,中控只允许写车位状态 ParkingSpaceStru pss = (ParkingSpaceStru)abstractPLCMsg; int offset = 24 * (pss.parkingSpace - 1) + parkingSpaceOffset; byte[] temp = BitConverter.GetBytes(BytesRevert(pss.spaceStatus)); ErrorCode ec = plc.WriteBytes(DataType.DataBlock, parkingSpaceDB, offset, temp); if (!ec.Equals(ErrorCode.NoError)) { return false; } } else { return false; } } else { return false; } return true; } /// /// 根据地址偏移量写入PLC /// /// /// /// /// public bool WriteAccordingToOffset(PLCDataType whichToWrite, int offset, object value) { isConnected = plc.IsConnected; if (value == null) return false; if (isConnected) { ErrorCode ec = ErrorCode.NoError; switch (whichToWrite) { case PLCDataType.terminal: if (value.GetType().Equals(typeof(int))) { ec = plc.WriteBytes(DataType.DataBlock, terminalDB, offset, BitConverter.GetBytes(BytesRevert((int)value))); } else if (value.GetType().Equals(typeof(short))) { ec = plc.WriteBytes(DataType.DataBlock, terminalDB, offset, BitConverter.GetBytes(BytesRevert((short)value))); } if (ec.Equals(ErrorCode.NoError)) { return true; } else { return false; } break; case PLCDataType.central: if (value.GetType().Equals(typeof(int))) { ec = plc.WriteBytes(DataType.DataBlock, centralDB, offset, BitConverter.GetBytes(BytesRevert((int)value))); } else if (value.GetType().Equals(typeof(short))) { ec = plc.WriteBytes(DataType.DataBlock, centralDB, offset, BitConverter.GetBytes(BytesRevert((short)value))); } if (ec.Equals(ErrorCode.NoError)) { return true; } else { return false; } break; case PLCDataType.parkingSpace: if (value.GetType().Equals(typeof(int))) { ec = plc.WriteBytes(DataType.DataBlock, parkingSpaceDB, offset, BitConverter.GetBytes(BytesRevert((int)value))); } else if (value.GetType().Equals(typeof(short))) { ec = plc.WriteBytes(DataType.DataBlock, parkingSpaceDB, offset, BitConverter.GetBytes(BytesRevert((short)value))); } if (ec.Equals(ErrorCode.NoError)) { return true; } else { return false; } break; } } return false; } } }