You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

536 lines
26 KiB
C#

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

/**********************************************************************************
* Class for Communicate to PLC with Prodave
* Create by J0YANG
* Last Modify Date:2009-08-11
* ********************************************************************************/
/****************************与PLC通讯应用实例****************************************
为保证数据的一致性,可以使用一个定时器,触发时间设为PLC扫描周期,在其触发事件中,把需要用到的PLC变量
一次性读取.建立与PLC的连接,示例如下
PLCConnParam[] Conn=new PLCConnParam[2]; //MPI网中有2个PLC,地址分别为2,3
Conn[0] .Addres=2; Conn[0].Slot=2; Conn[0].Rack=0;
Conn[1] .Addres=3; Conn[1].Slot=2; Conn[1].Rack=0;
errCode= DCProdave.Open(1,Conn); //建立连接
errCode= DCProdave.ActiveConn(1); //激活第一个连接
errCode= DCProdave.GetDBByteData(2, 0, 6, buf, 0); //DB2.DBW0--DBW5 共6个字节的变量,从buf的0位存储
if(errCode!=0){//DCLog.Write(DCProdave.GetErrInfo(errCode),"log.txt");}//如果返回值不=0,则将错误写入日志
* *********************************************************************************/
using System;
using System.Text;
using System.Collections;
using System.Collections.Generic;
using System.Runtime.InteropServices; //DllImport需要用到的库
namespace DCProdaveCS
{
#region 定义结构体[连接PLC所需参数]
public struct PLCConnParam
{
public byte Addres; // 定义CPU的MPI/DP地址
//public byte SegmentId; // 保留为0
public byte Rack; // 定义CPU的机架号
public byte Slot; // 定义CPU的槽号
}
#endregion
#region 定义枚举类型[PLC的存储区域编号]
public enum PLCBlockType
{
I = 1, //Input bytes
Q = 2, //Output bytes
M = 3, //Flag bytes
T = 4, //Timer words
Z = 5, //Counter words
D = 6, //Data from DB
}
#endregion
public class DCProdave
{
/// <summary>静态构造函数
/// 在创建第一个实例或引用任何静态成员,函数之前,将自动调用静态构造函数来初始化类
/// </summary>
static DCProdave(){ }
#region 导入w95_s7.dll中的通讯函数
/// <summary>与PLC建立连接,该函数必须在其他所有函数调用之前被调用
/// 在一个MPI网络中若有多个CPU时可指定多个连接列。最后一列的所有参数须置0以标志参数列结束。
/// e.g.一个MPI网中有两个CPU,他们的MPI地址分别为2和3槽号均为2机架号均为0则可按如下方式调用:
/// byte[,] btr={{2,0,2,0},{3,0,2,0},{0,0,0,0}}; int err=load_tool(1, "s7online",btr);
/// </summary>
/// <param name="nr">连接数,在DOS,WIN3.1最多可以有4个,在WIN95以上最多可以有16个</param>
/// <param name="device">与PLC通讯的设备名称,一般为S7ONLINE</param>
/// <param name="adr_table">参数列表,4个值分别为MPI/DP地址,保留值=0,槽号,机架号</param>
/// <returns>0正常返回,非0为错误号</returns>
[DllImport("w95_s7.dll")]
private extern static int load_tool(byte nr, string device, byte[,] adr_table);
/// <summary>断开与PLC的连接,必须退出数采软件之前调用,否则PLC的连接一直被占用,影响下次连接
/// </summary>
/// <returns>0正常返回,非0为错误号</returns>
[DllImport("w95_s7.dll")]
private extern static int unload_tool();
/// <summary>激活与MPI网中的哪个CPU通讯,load_tool后默认激活第一个CPU连接
/// 其参数与load_tool中参数adr_table所传递的连接参数顺序对应譬如byte[,] btr={{2,0,2,0},{3,0,2,0},{0,0,0,0}}
/// new_ss(1)则激活第1个连接即与MPI地址为2的PLC通讯,类似的new_ss(2)则激活与MPI地址为3的PLC通讯,
/// </summary>
/// <param name="no">连接号,对应于参数adr_table所传递的连接参数顺序</param>
/// <returns>0正常返回,非0为错误号,若激活的连接在MPI网中没有则返回错误号517</returns>
[DllImport("w95_s7.dll")]
private extern static int new_ss(byte no);
/// <summary>从DB中读取BYTE数组(长度是WORD倍数,即双BYTE)
/// </summary>
/// <param name="dbno">DB块号</param>
/// <param name="dwno">DBW起始编号,=0表示DBW0,=1表示DBW2,跨度为WORD</param>
/// <param name="anzahl">读取的WORD长度(1个WORD==2个BYTE)</param>
/// <param name="buffer">返回值,BYTE型buffer</param>
/// <returns>0正常返回,非0为错误号</returns>
[DllImport("w95_s7.dll")]
private extern static int db_read(int dbno, int dwno, ref int anzahl, byte[] buffer);
/// <summary>从DB中读取INT数据(DBW:INT16 或者 DBD:INT32),最多4个字节的整数
/// </summary>
/// <param name="dbno">DB块号</param>
/// <param name="dwno">DBW起始编号,0表示DBW0,1表示DBW2,跨度为WORD</param>
/// <param name="anzahl">读取的WORD长度(1个WORD==2个BYTE) 2:DBW , 4:DBD</param>
/// <param name="buffer">返回值,int型整数(十进制)</param>
/// <returns>0正常返回,非0为错误号</returns>
[DllImport("w95_s7.dll")]
private extern static int db_read(int dbno, int dwno, ref int anzahl, ref int buffer);
/// <summary>从DB中读取BYTE数组(字节数可以是任意长度的)
/// </summary>
/// <param name="blockno">DB块号</param>
/// <param name="no">DBB起始编号,0表示DBB0,1表示DBB1,跨度为BYTE</param>
/// <param name="amount">读取的BYTE长度(任意长度,可以为奇数)</param>
/// <param name="buffer">返回值,BYTE型buffer</param>
/// <returns>0正常返回,非0为错误号</returns>
[DllImport("w95_s7.dll")]
private extern static int d_field_read(int blockno, int no, int amount, byte[] buffer);
/// <summary>测试DB块的状态 0:存在 !0:不存在
/// </summary>
/// <param name="buffer">buffer[123]!=0表明存在DB123</param>
/// <returns>0正常返回,非0为错误号</returns>
[DllImport("w95_s7.dll")]
private extern static int db_buch(ushort[] buffer);
/// <summary>读取PLC中的M字节数据
/// </summary>
/// <param name="no">指定M字节号譬如要读取MB10的值则指定no等于10</param>
/// <param name="anzahl">指定读取的字节数譬如需要读取MB10至MB14之间的值则可指定为5</param>
/// <param name="buffer">返回获取的值这是一个十进制的值如果需要获取某一个M位的状态需要把它转换成二进制</param>
/// <returns>0正常返回,非0为错误号</returns>
[DllImport("w95_s7.dll")]
private extern static int m_field_read(int no, int anzahl, byte[] buffer);
/// <summary>获取MB变量的位状态值
/// </summary>
/// <param name="mbno"> 指定M字节号</param>
/// <param name="bitno"> 指定位号范围为0-7,返回值</param>
/// <param name="retwert"> 大于0表示该位为1=0表示该位为0</param>
/// <returns>0正常返回,非0为错误号</returns>
[DllImport("w95_s7.dll")]
private extern static int mb_bittest(int mbno, int bitno, ref byte retwert);
/// <summary>读取Output值
/// </summary>
/// <param name="no">QB号</param>
/// <param name="anzahl">读出多少个QB字节</param>
/// <param name="buffer">返回读出的值,十进制</param>
/// <returns></returns>
[DllImport("w95_s7.dll")]
private extern static int a_field_read(int no, int anzahl, byte[] buffer);
/// <summary>读取Input的值
/// </summary>
/// <param name="no">IB号</param>
/// <param name="anzahl">读出多少个IB字节</param>
/// <param name="buffer">返回读出的值,十进制</param>
/// <returns>0正常返回,非0为错误号</returns>
[DllImport("w95_s7.dll")]
private extern static int e_field_read(int no, int anzahl, byte[] buffer);
/// <summary> 获取PLC的运行状态
/// </summary>
/// <param name="buffer">返回0或者1 0表示Run;1表示Stop或者Restart</param>
/// <returns>0正常返回,非0为错误号</returns>
[DllImport("w95_s7.dll")]
private extern static int ag_zustand(ref byte buffer);
#region 往PLC写入数据,在数采系统中不允许的函数
//复位MB变量的位状态,指定M字节号,指定位号范围为0-7
//[DllImport("w95_s7.dll")] private extern static int mb_resetbit(short mbno, short bitno);
//置位MB变量的位状态,指定M字节号,指定位号范围为0-7
//[DllImport("w95_s7.dll")] private extern static int mb_setbit(short mbno, short bitno);
// 写入Output值,no为QB号,anzahl为有多少个QB字节需要写入,buffer为指定写入的值
//[DllImport("w95_s7.dll")] private extern static int a_field_write(int no, int anzahl, byte[] buffer);
/// <summary>向DB中写入数据
/// </summary>
/// <param name="dbno">指定DB块号</param>
/// <param name="dwno">指定写入的起始字序号,=0表示DBW0,=1表示DBW2</param>
/// <param name="anzahl">指定写入的对象有多少个字</param>
/// <param name="buffer">写入值</param>
/// <returns>0正常返回,非0为错误号</returns>
//[DllImport("w95_s7.dll")] private extern static int db_write(int dbno, int dwno, ref int anzahl, ref long buffer);
/// <summary>向PLC中的M字节写入值
/// </summary>
/// <param name="no">指定M字节号比如要读取MB10的值则指定no等于10</param>
/// <param name="anzahl">指定写入的字节数</param>
/// <param name="buffer">向PLC中写入的值,十进制数据</param>
/// <returns>0正常返回,非0为错误号</returns>
//[DllImport("w95_s7.dll")] private extern static int m_field_write(short no, short anzahl, ref long buffer);
#endregion
#endregion
#region 自定义与PLC的通讯函数,在w95_s7.dll的基础上进行封装
/// <summary>建立连接,同一个连接只容许调用一次
/// </summary>
/// <param name="connNo">连接号connNo为1-4</param>
/// <param name="connParam">连接参数,PLCConnParam定义的参数结构体</param>
/// <returns>返回10进制错误号0表示没有错误</returns>
public static int Open(byte connNo, PLCConnParam[] connParam)
{
int PLCCPUCnt = connParam.Length;
if (PLCCPUCnt <= 0) //传递参数不正确
{
return -1;
}
byte[,] btr = new byte[PLCCPUCnt + 1, 4]; //多分配1个,用于存放0作为连接结束标记
//转换连接表
for (int i = 0; i < connParam.Length; i++)
{
btr[i, 0] = connParam[i].Addres;
btr[i, 1] = 0;
btr[i, 2] = connParam[i].Slot;
btr[i, 3] = connParam[i].Rack;
}
btr[connParam.Length, 0] = 0;
btr[connParam.Length, 1] = 0;
btr[connParam.Length, 2] = 0;
btr[connParam.Length, 3] = 0;
//调用初始化函数,打开连接
int errCode = load_tool(connNo, "S7ONLINE", btr);
return errCode;
}
/// <summary>断开与PLC的连接,必须退出数采软件之前调用,否则PLC的连接一直被占用,影响下次连接
/// </summary>
/// <returns></returns>
public static int Close()
{
return unload_tool();
}
/// <summary>激活连接,设定与MPI网中的哪一个CPU通讯
/// </summary>
/// <param name="connNO">与load_tool中的参数adr_table所传递的连接参数顺序对应</param>
/// <returns>若激活的连接在MPI网中没有则返回错误号517</returns>
public static int ActiveConn(int connNO)
{
return new_ss((byte)connNO);
}
/// <summary>从DB块中读取整型数据
/// 要读取DB2.DBW6,则DB块号为2,DBB号为6,字节长度为2
/// 要读取DB2.DBD6,则DB块号为2,DBB号为6,字节长度为4
/// </summary>
/// <param name="DBBlockNO">DB块号,如:DB2</param>
/// <param name="DBBNO">DBB的起始字节号,如DBW2则从2开始读,由于是WORD(2个BYTE),DBB号必须为偶数</param>
/// <param name="DBByteAmount">要读取的BYTE数,必须是偶数(这里只能是2和4,在PLC中只有DBW,DBD两种整数)</param>
/// <param name="buffer">INT32型缓存区,存储读取的十进制数据</param>
/// <returns>返回值 0:成功 非0:错误代码</returns>
public static int GetDBInt32Data(int DBBlockNO, int DBBNO, int DBByteAmount, ref int buffer)
{
int DBWNO = DBBNO / 2;
int DBWordAmount = DBByteAmount / 2;
int errCode = db_read(DBBlockNO, DBWNO, ref DBWordAmount, ref buffer);
byte[] bbuf = new byte[4];
GetByteFromInt32(buffer, bbuf, true);
buffer = bbuf[0] * 0x1000000 + bbuf[1] * 0x10000 + bbuf[2] * 0x100 + bbuf[3];
return errCode;
}
/// <summary>读取DB块的WORD数据
/// </summary>
/// <param name="DBBlockNO">DB块号,如:DB2</param>
/// <param name="DBWNO">DBW的起始字节号,如DBW2则从2开始读,由于是WORD(2个BYTE),DBW号必须为偶数</param>
/// <param name="DBWordAmount">要读取的WORD数,如从DBW2--DBW5,共2个WORD(4个BYTE)</param>
/// <param name="buffer">BYTE型缓存区,存储读取的数据</param>
/// <returns>返回值 0:成功 非0:错误代码</returns>
public static int GetDBWordData(int DBBlockNO , int DBWNO , int DBWordAmount , byte[] buffer)
{
return db_read(DBBlockNO, DBWNO, ref DBWordAmount, buffer);
}
/// <summary>读取DB块的BYTE数据
/// </summary>
/// <param name="DBBlockNO">DB块号,如:DB2</param>
/// <param name="DBBNO">DB数据的起始字节,如DBB2则从2开始读</param>
/// <param name="DBByteAmount">要读取的字节数,如从DBB2--DBB5,共4个字节</param>
/// <param name="buffer">BYTE型缓存区,存储读取的数据</param>
/// <param name="StartIndex">数据缓存区的起始位置</param>
/// <returns>返回值 0:成功 非0:错误代码</returns>
public static int GetDBByteData(int DBBlockNO, int DBBNO, int DBByteAmount, byte[] buffer, int StartIndex)
{
byte[] bBufTemp = new byte[DBByteAmount];
int errCode=d_field_read(DBBlockNO, DBBNO, DBByteAmount, bBufTemp);
for(int i=0;i<DBByteAmount;i++)
{
buffer[i+StartIndex] = bBufTemp[i] ;
}
return errCode;
}
/// <summary>从M区读取位状态数据
/// </summary>
/// <param name="MBlockNO">M区号,如M10</param>
/// <param name="MBitNO">要读取的位号,如M10.2则位号为2</param>
/// <param name="MBitState">位状态, 0:false,1:true</param>
/// <returns>0正常,非0为错误号</returns>
public static int GetMBitData(int MBlockNO, int MBitNO,ref bool MBitState)
{
int errCode;
if (MBlockNO >= 0 && MBitNO >= 0 && MBitNO <=7 )
{
byte rtn = 0;
errCode = mb_bittest(MBlockNO, MBitNO, ref rtn);
MBitState = (rtn == 0) ? false : true;
return errCode;
}
else
{
return -1; //越界,超出8个字节
}
}
/// <summary>从M,I,Q区中读取字节数组
/// </summary>
/// <param name="blockType">Block类别,在枚举PLCBlockType中定义,如要读取M区的值,则blockType=PLCBlockType.M</param>
/// <param name="BlockNO">区号,如IB10,MB10...</param>
/// <param name="ByteAmount">要读取的字节数量,如IB10--IB14共5个字节</param>
/// <param name="bbuf">byte[]类型的buffer</param>
/// <param name="StartIndex">byte[]存储的起始位置</param>
/// <returns>0正常返回,非0为错误号</returns>
public static int GetMIQByteData(PLCBlockType blockType, int BlockNO, int ByteAmount, byte[] bbuf, int StartIndex)
{
int errCode = 0;
byte[] bBufTemp = new byte[ByteAmount]; //局部变量,不用担心内存释放的问题. C++程序员看到"new"估计很谨慎.
switch (blockType) //根据块类别,调用相应的块读取函数.
{
case PLCBlockType.M: errCode = m_field_read(BlockNO, ByteAmount, bBufTemp); break;
case PLCBlockType.I : errCode = e_field_read(BlockNO, ByteAmount, bBufTemp); break;
case PLCBlockType.Q: errCode = a_field_read(BlockNO, ByteAmount, bBufTemp); break;
}
for (int i = 0; i < ByteAmount; i++) //由于C#中对指针有所限制,从数组指定的起始位置,逐个赋值.
{
bbuf[i + StartIndex] = bBufTemp[i];
}
return errCode;
}
/// <summary>从long型数据中提取byte字节数组
/// </summary>
/// <param name="lbuf">源数据(long型)</param>
/// <param name="bbuf">字节数组,存放提取的Byte数据</param>
/// <param name="startIndex">起始位置</param>
/// <param name="ByteAmount">提取的字节数</param>
/// <param name="isBigEndian">long型源数据是否高位优先,如果不是,则进行反向提取</param>
public static void GetByteFromInt32(int ibuf, byte[] bbuf , bool isBigEndian)
{
if (isBigEndian) //高位优先,则反向提取.
{
for (int i = 0; i <=3; i++) //Int32只有4个字节
{
bbuf[i] = (byte)(ibuf & 0x000000ff); //取低位字节
ibuf >>= 8; //右移8位
}
}
else //低位优先,按顺序提取.
{
for (int i = 3; i >= 0; i--)
{
bbuf[i] = (byte)(ibuf & 0x000000ff);
ibuf >>= 8;
}
}
}
/// <summary>从Byte数据中取得所有bit的值(1Byte=8Bit , false:0 , true:1)
/// </summary>
/// <param name="byteData">源数据(Byte型),其中的8个bit位,从右到左0--7编号</param>
/// <param name="bitArray">bit数组,存放Byte中的8个bit的值,0:false, 1:true</param>
/// <param name="startIndex">在bit数组中存放的起始位置</param>
public static void GetBitFromByte(byte byteData, bool[] bitArray, int startIndex)
{
byte[] byteArray = new byte[1];
byteArray[0] = byteData;
System.Collections.BitArray BA = new System.Collections.BitArray(byteArray);
for (int i = 0; i <= 7; i++) //依次取8个位,逐个赋值
{
bitArray[startIndex + i] = BA.Get(i);
}
}
/// <summary>从Byte数据中取得某一位bit的值(false:0 , true:1)
/// </summary>
/// <param name="byteData">源数据(Byte型),其中的8个bit位,从右到左0--7编号</param>
/// <param name="bitNo">bit位编号,从右到左以0--7编号</param>
/// <param name="bitData">bit值,以bool型返回,false:0 , true:1</param>
public static void GetBitFromByte(byte byteData, int bitNo, ref bool bitData)
{
if (bitNo >= 0 && bitNo <= 7) //位号必须在0~7之间
{
byte[] byteArray = new byte[1];
byteArray[0] = byteData;
System.Collections.BitArray BA = new System.Collections.BitArray(byteArray);
bitData = BA.Get(bitNo);
}
}
/// <summary>根据错误代码返回错误信息
/// 例如int errCode=ActiveConn(1); sring errInfo = GetErrInfo(err);
/// </summary>
/// <param name="errCode">错误码</param>
/// <returns>错误信息</returns>
public static 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";
}
}
#endregion
}
}