using System; using Mesnac.Equips; using Mesnac.Equips.BaseInfo; using System.Runtime.InteropServices; namespace Mesnac.Equip.Siemens.S7.Default { /// /// 西门子S7-300PLC串口通讯设备类 /// public class Equip : BaseEquip { private bool _isOpen = false; //是否打开连接 private IntPtr equipHandle = new IntPtr(Marshal.SizeOf(typeof(int))); private IntPtr structToIntPtr(T s) { int nSizeOfT = Marshal.SizeOf(typeof(T)); int nSizeOfIntPtr = Marshal.SizeOf(typeof(IntPtr)); IntPtr Result = new IntPtr(); Result = Marshal.AllocHGlobal(nSizeOfT); Marshal.StructureToPtr(s, (IntPtr)((UInt32)Result), true); return Result; } private T IntPtrTostruct(IntPtr p) { return (T)Marshal.PtrToStructure(p, typeof(T)); } private int Swap(int a) { return (a >> 8 & 0xFF) + (a << 8 & 0xFF00); } public override bool Open() { lock (this) { if (this._isOpen == true) { return true; } this.State = false; //W95_S7.PLCConnParam adressType = new W95_S7.PLCConnParam(); byte c1 = 1; byte[,] p3 = { { 2, 0, 2, 0 }, { 3, 0, 2, 0 }, { 0, 0, 0, 0 } }; int Result = W95_S7.load_tool(c1, "S7ONLINE", p3); if ((Result != 0) && (Result != 39)) // 39已经初始化 { Console.WriteLine("PLC连接失败:" + this.GetErrInfo(Result)); this.State = false; return this.State; } else { this.State = true; this._isOpen = true; } return this.State; } } /// /// PLC数据读取方法 /// /// 要读取的块号 /// 要读取的起始字 /// 要读取的长度,最大255,超过255则不读取 /// /// public override bool Read(string block, int start, int len, out object[] buff) { lock (this) { buff = new object[len]; try { if (len > 256) { for (int i = 0; i < len; i++) { buff[i] = 0; } base.State = false; return false; } int maxOneLen = 100; //单次允许读取的最大长度,AB500限制为100个字 int count = len / maxOneLen; //要读取的次数 int mod = len % maxOneLen; //剩余的长度 bool flag = true; //保存读取标志 for (int i = 0; i < count; i++) { object[] _buff = new object[maxOneLen]; flag = this.ReadByLen(block, start + i * maxOneLen, maxOneLen, out _buff); if (flag == false) { base.State = flag; return false; } for (int k = i * maxOneLen; k < (i + 1) * maxOneLen; k++) { buff[k] = _buff[k - i * maxOneLen]; } } if (mod > 0) { object[] _buff = new object[mod]; flag = this.ReadByLen(block, start + count * maxOneLen, mod, out _buff); if (flag == false) { base.State = flag; return false; } for (int k = count * maxOneLen; k < count * maxOneLen + mod; k++) { buff[k] = _buff[k - count * maxOneLen]; } } base.State = flag; return flag; } catch (Exception ex) { //ICSharpCode.Core.LoggingService.Error(String.Format("读取PLC(AB500)设备失败-({0})!", ex.Message)); base.State = false; return false; } } } /// /// 单次读取最长100个字的方法 /// /// 块号 /// 起始字 /// 长度,最长不超过100 /// 数据缓冲区,存放读取的数据 /// 读取成功返回true,读取失败返回false private bool ReadByLen(string block, int start, int len, out object[] buff) { lock (this) { buff = new object[len]; if (!this.Open()) { return false; } int state = len; ushort[] _buff = new ushort[len]; int iblock = Convert.ToInt32(block); int iResult = W95_S7.db_read(iblock, start, ref state, _buff); if (iResult != 0) { Console.WriteLine("PLC读取失败:" + this.GetErrInfo(iResult)); this.State = false; return false; } else { this.State = true; } int iReadLen = len; if (iReadLen > state) { iReadLen = state; } for (int i = 0; i < iReadLen; i++) { int value = _buff[i]; if (value > ushort.MaxValue) { value = ushort.MaxValue - value; } buff[i] = Swap(value); } return true; } } private ushort ToValue(object obj, ushort defaultValue) { ushort result = 0; if (obj != null && obj != DBNull.Value && ushort.TryParse(obj.ToString(), out result)) { return result; } return defaultValue; } /// /// PLC数据写入方法 /// /// 要写入的块号 /// 起始字 /// 要写入PLC的数据 /// 写入成功返回true,失败返回false public override bool Write(int block, int start, object[] buff) { lock (this) { try { if (buff.Length > 256) { return false; } int len = buff.Length; int maxOneLen = 100; //单次允许读取的最大长度,AB500限制为100个字 int count = len / maxOneLen; //要读取的次数 int mod = len % maxOneLen; //剩余的长度 bool flag = true; //保存写入标志 for (int i = 0; i < count; i++) { object[] _buff = new object[maxOneLen]; for (int k = i * maxOneLen; k < (i + 1) * maxOneLen; k++) { _buff[k - i * maxOneLen] = buff[k]; } flag = this.WriteMax100(block, start + i * maxOneLen, _buff); if (flag == false) { return false; } } if (mod > 0) { object[] _buff = new object[mod]; for (int k = count * maxOneLen; k < count * maxOneLen + mod; k++) { _buff[k - count * maxOneLen] = buff[k]; } flag = this.WriteMax100(block, start + count * maxOneLen, _buff); } return flag; } catch (Exception ex) { //ICSharpCode.Core.LoggingService.Error(String.Format("写入PLC(AB500)设备失败-({0})!", ex.Message)); return false; } } } /// /// 单次写入最多100个字至PLC /// /// 要写入的块号 /// 要写入的起始字 /// 要写入的数据 /// 写入成功返回true,失败返回false private bool WriteMax100(int block, int start, object[] buff) { lock (this) { if (!this.Open()) { return false; } int state = buff.Length; ushort[] _buff = new ushort[buff.Length]; for (int i = 0; i < buff.Length; i++) { int value = 0; int.TryParse(buff[i].ToString(), out value); value = Swap(value); _buff[i] = (ushort)value; } int iblock = Convert.ToInt32(block); int iResult = W95_S7.db_write(iblock, start, ref state, _buff); if (iResult != 0) { Console.WriteLine("PLC【西门子S7-300】写入失败:" + this.GetErrInfo(iResult)); return false; } return true; } } public override void Close() { lock (this) { try { int result = W95_S7.unload_tool(); if (result != 0) { Console.WriteLine("PLC【西门子S7-300】关闭失败:" + this.GetErrInfo(result)); } else { this.State = false; this._isOpen = false; } } catch (Exception ex) { Console.WriteLine("PLC【西门子S7-300】关闭失败:" + ex.Message); } } } /// 根据错误代码返回错误信息 /// 例如int errCode=ActiveConn(1); sring errInfo = GetErrInfo(err); /// /// 错误码 /// 错误信息 public string GetErrInfo(int errCode) { switch (errCode) { case -1: return "User-Defined Error!"; //自定义错误,主要是参数传递错误! case 0x0000: return "Success"; case 0x0001: return "Load dll failed"; case 0x00E1: return "User max"; case 0x00E2: return "SCP entry"; case 0x00E7: return "SCP board open"; case 0x00E9: return "No Windows server"; case 0x00EA: return "Protect"; case 0x00CA: return "SCP no resources"; case 0x00CB: return "SCP configuration"; case 0x00CD: return "SCP illegal"; case 0x00CE: return "SCP incorrect parameter"; case 0x00CF: return "SCP open device"; case 0x00D0: return "SCP board"; case 0x00D1: return "SCP software"; case 0x00D2: return "SCP memory"; case 0x00D7: return "SCP no meas"; case 0x00D8: return "SCP user mem"; case 0x00DB: return "SCP timeout"; case 0x00F0: return "SCP db file does not exist"; case 0x00F1: return "SCP no global dos memory"; case 0x00F2: return "SCP send not successful"; case 0x00F3: return "SCP receive not successful"; case 0x00F4: return "SCP no device available"; case 0x00F5: return "SCP illegal subsystem"; case 0x00F6: return "SCP illegal opcode"; case 0x00F7: return "SCP buffer too short"; case 0x00F8: return "SCP buffer1 too short"; case 0x00F9: return "SCP illegal protocol sequence"; case 0x00FA: return "SCP illegal PDU arrived"; case 0x00FB: return "SCP request error"; case 0x00FC: return "SCP no license"; case 0x0101: return "Connection is not established / parameterized"; case 0x010a: return "Negative Acknowledgment received / timeout errors"; case 0x010c: return "Data not available or locked"; case 0x012A: return "No system memory left"; case 0x012E: return "Incorrect parameter"; case 0x0132: return "No storage space in the DPRAM"; case 0x0200: return "xx"; case 0x0201: return "Falsche Schnittstelle angegeben"; case 0x0202: return "Incorrect interface indicated"; case 0x0203: return "Toolbox already installed"; case 0x0204: return "Toolbox with other compounds already installed"; case 0x0205: return "Toolbox is not installed"; case 0x0206: return "Handle can not be set"; case 0x0207: return "Data segment can not be blocked"; case 0x0209: return "Erroneous data field"; case 0x0300: return "Timer init error"; case 0x0301: return "Com init error"; case 0x0302: return "Module is too small, DW does not exist"; case 0x0303: return "Block boundary erschritten, number correct"; case 0x0310: return "Could not find any hardware"; case 0x0311: return "Hardware defective"; case 0x0312: return "Incorrect configuration parameters"; case 0x0313: return "Incorrect baud rate/interrupt vector"; case 0x0314: return "HSA incorrectly parameterized"; case 0x0315: return "Address already assigned"; case 0x0316: return "Device already assigned"; case 0x0317: return "Interrupt not available"; case 0x0318: return "Interrupt occupied"; case 0x0319: return "SAP not occupied"; case 0x031A: return "Could not find any remote station"; case 0x031B: return "syni error"; case 0x031C: return "System error"; case 0x031D: return "Error in buffer size"; case 0x0320: return "DLL/VxD not found"; case 0x0321: return "DLL function error"; case 0x0330: return "Version conflict"; case 0x0331: return "Com config error"; case 0x0332: return "smc timeout"; case 0x0333: return "Com not configured"; case 0x0334: return "Com not available"; case 0x0335: return "Serial drive in use"; case 0x0336: return "No connection"; case 0x0337: return "Job rejected"; case 0x0380: return "Internal error"; case 0x0381: return "Device not in Registry"; case 0x0382: return "L2 driver not in Registry"; case 0x0384: return "L4 driver not in Registry"; case 0x03FF: return "System error"; case 0x4001: return "Connection is not known"; case 0x4002: return "Connection is not established"; case 0x4003: return "Connection is being established"; case 0x4004: return "Connection is collapsed"; case 0x0800: return "Toolbox occupied"; case 0x8001: return "in this mode is not allowed"; case 0x8101: return "Hardware error"; case 0x8103: return "Object Access not allowed"; case 0x8104: return "Context is not supported"; case 0x8105: return "ungtige Address"; case 0x8106: return "Type (data) is not supported"; case 0x8107: return "Type (data) is not consistent"; case 0x810A: return "Object does not exist"; case 0x8301: return "Memory on CPU is not sufficient"; case 0x8404: return "grave error"; case 0x8500: return "Incorrect PDU Size"; case 0x8702: return "Invalid address"; case 0xA0CE: return "User occupied"; case 0xA0CF: return "User does not pick up"; case 0xA0D4: return "Connection not available because modem prevents immediate redial (waiting time before repeat dial not kept to) "; case 0xA0D5: return "No dial tone"; case 0xD201: return "Syntax error module name"; case 0xD202: return "Syntax error function parameter"; case 0xD203: return "Syntax error Bausteshortyp"; case 0xD204: return "no memory module in eingeketteter"; case 0xD205: return "Object already exists"; case 0xD206: return "Object already exists"; case 0xD207: return "Module available in the EPROM"; case 0xD209: return "Module does not exist"; case 0xD20E: return "no module present"; case 0xD210: return "Block number is too big"; case 0xD241: return "Protection level of function is not sufficient"; case 0xD406: return "Information not available"; case 0xEF01: return "Wrong ID2"; case 0xFFFE: return "unknown error FFFE hex"; case 0xFFFF: return "Timeout error. Interface KVD"; default: return "Unkonw error"; } } } }