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";
}
}
}
}