设备特性

RF系列非接触式IC卡读写器是深圳明华公司研制的非接触卡读写设备，它由主机、天线、串行接口等组成，通过RS232串行接口能实现同PC机的连接。随机提供的接口函数库可满足用户二次开发的需要；其完善、可靠的接口函数，支持访问射频卡的全部功能。目前该设备已广泛地应用于门禁、考勤及高速公路、油站、停车场、公交等收费系统中。

V3.0 以上的RF读写器比以往版本进行了如下增改：

l 八位数码管显示

l 显示方式可为日期、时间、整数、小数

l 提供384个字节的EEPROM供用户存贮一些数据信息

技术指标

l 支持Mifare标准

——发射频率：13.56MHz

——访问卡速率：106Kbit/s

l 接口功能：RS232串行接口，RS485接口

l 波特率：9600～115200bit/s ，自动侦测

l 工作电源：RF-25、RF-100分别是DC 5V±5%、DC 12V±5%

l 读写距离：RF-25、RF-100分别是25mm、100mm

l 最大功耗：RF-25 、RF-100分别是200mW、300mW

l 环境温度：0℃～50℃

l 相对湿度：30%～95%

l 重量：RF-25约 200克；RF-100约600克（不包括天线）


新增功能说明

如何使用演示软件

双击文件DemoRF.exe进入演示程序主菜单。主菜单包括设备操作、

密码设置、值操作、数据操作、读写测试、单步操作、其它操作、帮助以及退出系统。用户必须首先连接读写器，然后设置读写器类型和要操作的卡片类型，再开始其它的操作。

设置读写器类型

设置读写器类型。用户必须根据所使用的读写器类型进行设置，否则以后的操作会受到影响。有下面三个选择项：

1) RF-35

2) RF-25LT、RF-100LT

3) 华虹模块读写器(如RF-123)

错误的设置可能会导致以下问题：

a) 华虹模块和Mifare模块的读写器装载密码是不同的，如果设置错误，将会装载密码不成功。

b) RF35和华虹模块的读写器都只能装载一套密码，如果设置错误，则实际上只装载第三套密码，造成密码认证时认证错误。

设置卡片类型

设置要操作的卡片类型，包括M1卡、UltraLight卡、4K卡、ML卡和Token卡。


设备操作

端口设置

可选串口1～4，通讯速率为 9600～115200 BPS。

读写器在通讯成功后，如要更换串口或波特率，请先断开连接，然后选择新的串口和波特率再重新连接即可，如果连接失败，请关掉读写器电源再打开。

参考函数：

rf_init()

产品信息

包括软件版本号、硬件版本号和产品序列号。

进入系统后，自动显示演示软件版本号，并在连接成功后，读出硬件版本号和产品序列号。

参考函数：

rf_get_status()

rf_srd_snr()

蜂鸣器控制

读写器按输入值鸣响一段时间。

参考函数：

rf_beep()

读写器端口

RF读写器有5个I/O端口，可控制信号的输入/输出。

控制字低5位（D4D3D2D1D0）的每一位控制一个端口，高3位（D7D6D5）无效，对应端口位置如下所示（读写器的正面向前，天线接口在左边）：

D0 D1 D2 D3 D4

天线 ● ● ● ● ● ● ● ● ● ● 开关

参考函数：

rf_getport()

rf_setport()

显示方式控制

显示方式分为计算机控制和读写器控制两种。

由计算机控制时，控制数据中每个字节的最高位（D7）取值决定该位数字后的小数点是否显示。

由读写器控制时，显示模式又分为日期模式和时间模式。

日期显示格式为“年-月-日”，时间显示格式为“时-分-秒”。

数码管的显示亮度可调节，有效范围为0～15。

参考函数：

rf_ctl_mode()

rf_disp_mode()

rf_setbright()

备注操作

读写器提供384字节的EEPROM区，用户可写入任意数据。

参考函数：

rf_srd_eeprom()

rf_swr_eeprom()

参数设置

设置读写器和卡片通信的配置参数。

参考函数：

rf_clr_control_bit() rf_clr_control_bit

rf_clr_control_bit()

rf_config()


装载密码

该功能将密码写入读写器中。

M1卡

每个扇区有三套密码，每套密码包括A密码和B密码，可以从组合框中选择一种认证模式。

ML卡

每个有三套密码，每套密码包括A密码和B密码。

4K卡

有16个扇区的密码，每个扇区有三套密码，每套密码包括A密码和B密码。大于16扇区的密码必须重新装载，

然后调用rf_authentication_2()函数进行认证。

TOKEN卡

有三套密码，不分A密码和B密码。

参考函数：

rf_load_key()

rf_authentication_2()


数据操作

M1卡

每次读出4个扇区的内容，如有不能读出的块，则提示“部分扇区不能读取”，且相应扇区不显示任何内容；能读出的扇区，以十六进制显示卡中数据。

如果要修改卡片的数据，请先修改用户界面上的数据，然后按下<写入数据>，将用户输入的数据写入卡中。

ML卡

按下<读出数据>读出卡中所有单元的数据，如果要修改数据，直接在界面上修改，然后按下<写入数据>。

4K卡

前16个扇区的内容读取同M1卡。如果要读取的扇区的扇区号大于15，则单击‘其它扇区’按钮进入其它扇区数据界面。

选择要读写数据的扇区号，单击‘读数据’按钮读出数据，以十六进制显示卡中数据。

如果要修改卡片的数据，请先修改用户界面上的数据，然后按下<写入数据>，将用户输入的数据写入卡中。

ULTRALIGHT卡和 TOKEN卡

同ML卡。


值操作

M1卡

可进行读值、初始化值、减值、加值操作。

参考函数：

rf_initval()

rf_readval()

rf_increment()

rf_decrement()

ML卡

可进行读值、初始化值、减值操作。

参考函数：

rf_initval_ml()

rf_readval_ml()

rf_decrement_ml()

rf_decrement_transfer()


读写测试

将射频卡放在天线有效范围内，指定读/写地址，点击<开始操作>，系统对该卡进行连续的读/写操作，直至用户点取<终止操作>按钮为止。同时将每个操作步骤调用的函数、操作结果及读出/写入的数据显示在列表框中。


单步操作

单步操作演示了射频卡操作的整个流程，包括寻卡、防冲突、选卡、密码认证、读写数据、值操作等等。

在这里可以操作4k卡、UltraLigtht、筹码型卡等各种卡型。

操作说明：

注意：用户可以在编辑框中直接输入块地址。

1. 命令参数：可以设置寻卡模式、认证密码时采用的密码类型以及密码认证函数。当选择使用rf_authentication_2函数时，密码认证可以由用户设置采用0－15扇区的任何一个扇区的密码进行认证。

2. request： 根据命令参数中设置的寻卡模式进行寻卡

3. antioll： 防冲突

4. select： 选卡，根据防冲突时返回的卡片序列号选卡

5. Authen.：密码认证，根据命令参数中设置的密码类型进行卡片密码认证

6. loadkey：装载密码

7. Read： 读数据

8. Write： 写数据

9. Halt： 停机

10. Reset： 复位

11. Incr.： 增值，加指定的值到卡片的存储器。

12. Decr.： 减值，从卡片的存储器减去指定的值。

13. Restore：回传，将EEPROM中的内容传入卡的内部寄存器。

14. Transfer：传送，将寄存器的内容传送到EEPROM中

提示：

l UltraLight卡没有密码，所以不需要密码认证。

l Token卡只有一个密码，只要对其中一个块进行认证，就可以对其它的块操作。虽然筹码型卡不具有防冲突功能，但是寻卡后必须执行rf_anticoll()指令，取得卡片序列号。如果卡片序列号已知，则可省略。


其它操作说明

其它操作

其它操作中包括对SAM卡、CPU卡和双界面卡的操作。界面分为卡型设置、SAM卡（CPU卡、双界面卡接触界面）操作、双界面卡非接触界面操作、加密、解密、cos指令执行以及指令执行状态等等。首先，设置卡片类型。

SAM卡(CPU卡、双界面卡接触界面)操作

选择复位波特率，然后单击‘Reset’按钮对SAM卡(CPU卡、双界面卡接触界面)复位。

Reset

SAM卡(CPU卡、双界面卡接触界面)复位。

GetRamd

取随机数。

双界面卡操作

双界面卡非接触界面的指令操作流程：

寻卡（request）à防冲突（anticoll）à选卡（select）à ATS à PPS à HALT、RESET

按照操作流程依序单击相应按钮。其中，PPS为指令传输，参照 cos指令执行。

加、解密

密钥

用来加密或者解密的密钥。

数据

需要加密或者解密的数据。

结果

加密或者解密后的结果。

Cos指令执行、指令执行状态

在指令栏输入 要执行的cos指令，然后单击‘执行’按钮执行指令，指令执行状态在‘执行结果’列表中显示。可以单击‘清除’按钮清除指令编辑框和指令执行列表中的数据。


设备操作函数

rf_reset() rf_reset | rf_beep() | rf_get_status() | rf_srd_snr()
lib_ver() | rf_setbright() rf_setbright | rf_ctl_mode() | rf_disp_mode()
rf_disp8() | rf_disp() | rf_clr_control_bit() rf_clr_control_bit | rf_set_control_bit()
rf_getport() rf_getport | rf_setport() | rf_gettime() rf_gettime | rf_settime() rf_settime
rf_gettimehex() rf_gettimehex | rf_settimehex() | rf_srd_eeprom() rf_srd_eeprom | rf_swr_eeprom()
set_host_485() |  |  |

通用函数

rf_init() rf_init | rf_exit() | rf_card() | rf_config()
rf_request() | rf_anticoll() | rf_select() | rf_load_key()rf_load_key
rf_load_key_hex() | rf_halt()rf_halt | rf_read()rf_read | rf_read_hex()
rf_write() | rf_write_hex() | rf_encrypt() | rf_decrypt()

M1卡专用函数

rf_initval()rf_authentication | rf_changeb3() | rf_check_write() | rf_check_writehex()
rf_readval() | rf_increment() | rf_decrement() | rf_authentication()
rf_restore()rf_restore | rf_transfer()rf_transfer | rf_HL_read() | rf_HL_decrement()
rf_HL_readhex() rf_HL_readhex | rf_HL_write() rf_HL_write | rf_HL_writehex() | rf_HL_authentication()
rf_HL_initval() | rf_HL_increment() | rf_authentication_2() |

ML卡专用函数

rf_authentication_2() rf_authentication_2rf_decrement_ml | rf_initval_ml() rf_initval_ml | rf_readval_ml() rf_readval_ml | rf_decrement_ml()
rf_decrement_transfer() rf_decrement_transfer |  |  |

ULTRALIGHT卡专用函数

rf_get_snr

SAM卡专用函数

rf_sam_rst

rf_sam_trn

rf_sam_off

CPU卡专用函数

rf_cpu_rst

rf_cpu_trn

双界面卡专用函数

rf_pro_rst

rf_pro_trn

rf_pro_halt


设备操作函数

rf_reset() | rf_beep() | rf_get_status() | rf_srd_snr()
lib_ver() | rf_setbright() | rf_ctl_mode() | rf_disp_mode()
rf_disp8() | rf_disp() | rf_clr_control_bit() | rf_set_control_bit()
rf_getport() | rf_setport() | rf_gettime() | rf_settime()
rf_gettimehex() | rf_settimehex() | rf_srd_eeprom() | rf_swr_eeprom()
set_host_485() | Set_Reader_Mode() |  |


lib_ver

int lib_ver(unsinged char *buff);

功 能：读取软件版本号

参 数：buff：存放版本号的缓冲区，长度18字节(包括结束字符’\0’)。

返 回：成功则返回 0

例：unsigned char buff[18];

lib_ver(buff);

printf(“software version is %s”,buff);


rf_beep

int rf_beep(int icdev,unsigned int _Msec);

功 能：蜂鸣

参 数：icdev：通讯设备标识符

unsigned int _Msec：蜂鸣时间，单位是10毫秒

返 回：成功则返回 0

例：int st;

st=rf_beep(icdev,10); /*鸣叫100毫秒*/


rf_clr_control_bit

int rf_clr_control_bit(int icdev,unsigned char _b);

功 能：清除射频模块内控制寄存器中的一个二进制位

二进制位 | _b取值 | 作用
RF1 | 0x40 | 清除RF系统1（设置RF系统0）
RFPOWEROFF | 0x02 | 清除RF下电（设置RF上电）

参 数：icdev：通讯设备标识符

_b：要清除的位

返 回：成功则返回 0

例：st=rf_clr_control_bit(icdev,0x40);


rf_ctl_mode

int rf_ctl_mode(int icdev,unsigned char mode);

功 能：设置读写器数码管受控方式，关机后可保存设置值

参 数：icdev：通讯设备标识符

mode：受控方式

0——数码管显示受计算机控制

1——数码管显示受读写器控制（出厂设置）

显示模式由rf_disp_mode设置

返 回：成功则返回 0

例：st=rf_ctl_mode(icdev,0x01)


rf_disp

int rf_disp(int icdev,unsigned char pt_mode,unsigned short digit);

功 能：在读写器的数码管上显示数字（为低版本兼容函数，V3.0及以上版本不能使用）

参 数：icdev：通讯设备标识符

pt_mode：小数点显示模式

0——小数点熄灭

1——个位后的小数点位亮

2——十位后的小数点位亮

3——百位后的小数点位亮

4——千位后的小数点位亮

digit：要显示的数

返 回：成功则返回 0

例：int st;

st=rf_disp(icdev,0,1234); /*显示整数1234*/


rf_disp_mode

int rf_disp_mode(int icdev,unsigned char mode);

功 能：设置读写器数码管显示模式，关机后可保存设置值

参 数：icdev：通讯设备标识符

mode：显示模式

0——日期，格式为“年-月-日（yy-mm-dd）”，BCD码

1——时间，格式为“时-分-秒（hh-nn-ss）” ，BCD码

返 回：成功则返回 0

例：st=rf_disp_mode(icdev,0x01);//设为显示时间


rf_disp8

int rf_disp8(int icdev,int disp_len,unsigned char *disp_str);

功 能：在读写器数码管上显示数字

参 数：icdev：通讯设备标识符

disp_len：显示字符串的长度，最长为8

disp_str：要显示的数据

受读写器控制时，显示的日期/时间请参照rf_disp_mode()rf_disp_mode中定义的格式；

受计算机控制时，显示方式由显示数据决定；每个字节的最高位为1表示本位数后的小数点亮，为0表示小数点灭。

返 回：成功则返回 0

例：int st;

unsigned char *datebuff=“99-05-20”;

unsigned char *numbuff1={0x01,0x02,0x03,0x04,0x85,0x06,0x07,0x08};

unsigned char *numbuff2={0x88,0x87,0x86,0x85,0x84,0x83,0x82,0x81};

st=rf_ctl_mode(icdev,1); //显示受读写器控制

st=rf_disp_mode(icdev,0); //显示日期

st=rf_disp8(icdev,8,datebuff); //显示结果为“99-05-20”

st=rf_ctl_mode(icdev,0); //显示受计算机控制

st=rf_disp8(icdev,8,numbuff1); //显示结果为“1234.5678”

st=rf_disp8(icdev,8,numbuff2); //显示结果为“8.7.6.5.4.3.2.1.”


rf_get_status

int rf_get_status(int icdev,unsigned char *_Status);

功 能：取得读写器硬件版本号，如“mwrf100_v3.0”

参 数：icdev：通讯设备标识符

_Status：返回版本信息

返 回：成功则返回 0

例：int st;

unsigned char version[18];

st=rf_get_status(icdev,version);

if(st)

printf(“rf_get_status error”);

else

printf(“hardware version is %s”,version);


rf_getport

int rf_getport(int icdev,unsigned char *receive_data);

功 能：读取读写器端口输入的值

参 数：icdev：通讯设备标识符

receive_data：端口输入值，1个字节,低5位有效。

返 回：成功则返回 0

例：int st;

unsigned char rec_data[1];

st=rf_getport(icdev,rec_data);


rf_gettime

int rf_gettime(int icdev,unsigned char *time);

功 能：读取读写器日期、星期、时间

参 数：icdev：通讯设备标识符

time：返回数据，长度为7个字节，格式为“年、星期、月、日、时、分、秒”

返 回：成功则返回 0

例：int st;

unsigned char datetime[7];

st=rf_gettime(icdev,datetime);

//datetime为“0x99,0x04,0x05,0x20,0x13,0x30,0x10”，

//表示99年星期四5月20日13时30分10秒


rf_gettimehex

int rf_gettimehex(int icdev,char *time);

功 能：同rf_gettime()rf_gettime，用十六进制表示

参 数：icdev：通讯设备标识符

time：长度为14个字节,均为数字

返 回：成功则返回 0

例：int st;

unsigned char datetime[15];

st=rf_gettime(icdev,datetime);

//datetime为“99040520133010”，

//表示99年星期四5月20日13时30分10秒


rf_reset

int rf_reset(int icdev,unsigned int _Msec);

功 能：射频读写模块复位

参 数：icdev：通讯设备标识符

unsigned int _Msec：复位时间，0～500毫秒有效

返 回：成功则返回 0

例：int st;

st=rf_reset(icdev,60);


rf_set_control_bit

int rf_set_control_bit(int icdev,unsigned char _b);

功 能：设置射频模块控制寄存器中的一个二进制位

参 数：icdev：通讯设备标识符

_b：要设置的位，取值同rf_clr_control_bit()rf_clr_control_bit

返 回：成功则返回 0

例：st=rf_set_control_bit(icdev,0x40);


rf_setbright

int rf_setbright(int icdev,unsigned char bright);

功 能：设置数码管显示亮度

参 数：icdev：通讯设备标识符

bright：亮度值，0～15有效，0表示最暗，15表示最亮

返 回：成功则返回 0

例：st=rf_setbright(icdev,10);


rf_setport

int rf_setport(int icdev,unsigned char _Byte);

功 能：向读写器端口输出控制字，此信号可用于控制用户的外设。

参 数：icdev：通讯设备标识符

_Byte：控制字，该字节低5位每一位控制一个输出

返 回：成功则返回 0

例：st=rf_setport(icdev,0x13); //00010011


rf_settime

int rf_settime(int icdev,unsigned char *time);

功 能：设置读写器日期、星期、时间

参 数：icdev：通讯设备标识符

time：长度为7个字节，格式为“年、星期、月、日、时、分、秒”

返 回：成功则返回 0

例：int st;

unsigned char datetime[7]={0x99,0x04,0x05,0x20,0x13,0x30,0x10};

st=rf_settime(icdev,datetime);


rf_settimehex

int rf_settimehex(int icdev,char *time);

功 能：同rf_settime()rf_settime，用十六进制表示

参 数：icdev：通讯设备标识符

time：长度为14个字节,均为数字

返 回：成功则返回 0

例：int st;

unsigned char *datetime=“99040520133010”;

st=rf_settime(icdev,datetime);


rf_srd_eeprom

int rf_srd_eeprom(int icdev,int offset,int length,unsigned char *rec_buffer);

功 能：读取读写器备注信息

参 数：icdev：通讯设备标识符

offset：偏移地址（0～383）

length：读取信息长度（1～384）

rec_buffer：读取到的信息

返 回：成功则返回 0

例：int st;

unsigned char buffer[100];

st=rf_srd_eeprom(icdev,0,100,buffer);


rf_srd_snr

int rf_srd_snr(int icdev,int length,unsigned char *rec_buffer);

功 能：取得读写器产品序列号

参 数：icdev：通讯设备标识符

length：字符串长度，其值为16

red_buff：存放要读出的标识号字符串

返 回：成功则返回 0

例：

int st;

unsigned char buffer[17];

memset(buffer,0,17);

st=rf_srd_snr(icdev,16,buffer);

if(st)

printf(“rf_srd_snr error”);

else

printf(“The device serial number is :%s”,buffer);


rf_swr_eeprom

int rf_swr_eeprom(int icdev,int offset,int length,unsigned char* send_buffer);

功 能：向读写器备注区中写入信息

参 数：icdev：通讯设备标识符

offset：偏移地址（0～383）

length：读取信息长度（1～384）

rec_buffer：要写入的信息

返 回：成功则返回 0

例：st=rf_swr_eeprom(icdev,10,”mwrf v3.0”);


Void Set_Reader_Mode(unsigned char _Mode);

功 能：设置射频头类型

参 数：_Mode：射频头类型，0 Mifare模块, 1 华虹模块。

返 回：成功则返回 0

例：unsigned char _Mode;

Set_Reader_Mode(_Mode);


通用函数

rf_init() rf_init | rf_exit() | rf_card() | rf_config()
rf_request() | rf_anticoll() | rf_select() | rf_load_key()rf_load_key
rf_load_key_hex() | rf_halt()rf_halt | rf_read()rf_read | rf_read_hex()
rf_write() | rf_write_hex() | rf_encrypt() | rf_decrypt()


rf_anticoll

int rf_anticoll(int icdev,unsigned char _Bcnt,unsigned long *_Snr);

功 能：卡防冲突，返回卡的序列号

参 数：icdev：通讯设备标识符

_Bcn： 设为0

_Snr：返回的卡序列号地址

返 回：成功则返回 0

例：int st;

unsigned long snr;

st=rf_anticoll(icdev,0,&snr);

注：request指令之后应立即调用anticoll，除非卡的序列号已知。


rf_card

int rf_card(int icdev,unsigned char _Mode,unsigned long *_Snr);

功 能：寻卡，能返回在工作区域内某张卡的序列号

参 数：icdev：通讯设备标识符

_Mode：寻卡模式 mode_card

_Snr：返回的卡序列号

返 回：成功则返回 0

例：int st;

unsigned long snr;

st=rf_card(icdev,0,&snr);

注：选择IDLE模式，在对卡进行读写操作，执行rf_halt()rf_halt指令中止卡操作后，只有当该卡离开并再次进入操作区时，读写器才能够再次对它进行操作。


rf_config

int rf_config(int icdev,unsigned char _Mode,unsigned char _Baud);

功 能：设置射频模块的工作模式及卡与设备间的通讯速率

参 数：icdev：通讯设备标识符

_Mode：工作模式，MCM500模块和MCM200模块设0xC6，SB201模块设为0XD6，出厂时已设好，不需更改。

_Baud：卡与设备间的通讯速率，设为0x0E

返 回：成功则返回 0

注：如使用缺省值工作，则不必调用此函数。


rf_decrypt

int rf_decrypt(char *key,unsigned char *ptrSource,unsigned int msglen, char *ptrDest)

功 能：DES算法解密函数

参 数：key：密钥

ptrsource：要解密的密文

msglen：原文长度必需为8的倍数

ptrdest：解密后的原文

返 回：成功返回0

此函数不跟读写器通信，只在PC机运算。


rf_encrypt

int rf_encrypt(char *key,unsigned char *ptrSource, unsigned int msgLen,unsigned char *ptrDest)

功 能：DES算法加密函数

参 数：key：密钥

ptrSource：要加密码的原文

msglen：原文长度，必需为8的倍数

ptrDest：加密后的密文

返 回：成功返回0

例：char key[]=”12345678”;

unsigned char ptrsource[]=”abcdefghabcdefgh”;

unsigned char ptrdest[16];

st=ic_encrypt(dkey,ptrsource,16,ptrdest);

//将长度为16的“abcdefghabcdefgh”用密码“12345678”加密


rf_exit

int rf_exit(int icdev);

功 能：释放串口

参 数：icdev：通讯设备标识符

返 回：无

例：rf_exit(icdev);

注：在WIN32环境下icdev为串口的设备句柄，必须释放后才可以再次连接。


rf_halt

int rf_halt(int icdev)

功 能：中止对该卡操作

参 数：icdev：通讯设备标识符

返 回：成功则返回0

例：st=rf_halt(icdev);

说明：执行该命令后如果是ALL寻卡模式则必须重新寻卡才能够对该卡操作，如果是IDLE模式则必须把卡移开感应区再进来才能寻得这张卡。


rf_init

int rf_init(int port,long baud);

功 能：初始化串口

参 数：port：串口号，取值为0～3

baud：为通讯波特率9600～115200

返 回：成功则返回串口标识符>0，失败返回负值，见错误代码表

例：int icdev;

icdev=rf_init(0,9600);//初始化串口1，波特率9600

如果是WIN32程序则icdev为设备句柄，见下例：

HANDLE icdev;

icdev=rf_init(0,115200);

if(icdev<0)

MessageBox(“rf_init error”);


rf_load_key

int rf_load_key(int icdev,unsigned char _Mode,unsigned char _SecNr,unsigned char *_NKey);

功 能：将密码装入读写模块RAM中

参 数：icdev：通讯设备标识符

_Mode：装入密码模式，同密码验证模式 mode_auth

_SecNr：扇区号（M1卡：0～15； ML卡：0）

_Nkey：写入读写器中的卡密码

返 回：成功则返回 0

例：//key A and key B

unsigned char tk[6]={0xa0,0xa1,0xa2,0xa3,0xa4,0xa5};

/* 装入1扇区的0套A密码 */

if((rf_load_key(icdev,0,1,tk))!=0)

{

printf("Load key error!");

rf_exit(icdev)

exit(1);

}


rf_load_key_hex

int rf_load_key_hex(int icdev,unsigned char _Mode,unsigned char _SecNr,char *_NKey);

功 能：向读写器中装入十六进制密码

参 数：icdev：通讯设备标识符

_Mode：密码验证模式

_SecNr：扇区号（0～15）

_Nkey：写入读写器中的卡密码

返 回：成功则返回 0

例：/* 装入1扇区的A密码|0套 */

if((rf_load_key_Hex(icdev,0,1,"a0a1a2a3a4a5"))!=0)

{ printf("Load key error!");

rf_exit(icdev);

exit(1);

}


rf_read

int rf_read(int icdev,unsigned char _Adr,unsigned char *_Data);

功 能：读取卡中数据

对于M1卡，一次读一个块的数据，为16个字节；

对于ML卡，一次读出相同属性的两页（0和1，2和3，...），为8个字节

参 数：icdev：通讯设备标识符

_Adr：M1卡——块地址（0～63）；

ML卡——页地址（0～11）

_Data：读出数据

返 回：成功则返回 0

例：int st;

unsigned char data[16];

st=rf_read(icdev,4,data); //读M1卡块4的数据


rf_read_hex

int rf_read_hex(int icdev,usigned char _Adr,unsigned char *_Data);

功 能：同rf_read()rf_read

参 数：icdev：通讯设备标识符

_Adr：同rf_read

_Data：读出数据，数据以十六进制形式表示

返 回：成功则返回0；

例：int st;

unsigned char data[32];

st=rf_read_hex(icdev,2,data); // 读ML卡2页和3页的数据或M1卡的第二块数据。


rf_request

int rf_request(int icdev,unsigned char _Mode,unsigned int *TagType);

功 能：寻卡请求

参 数：icdev：通讯设备标识符

_Mode：寻卡模式 mode_card

Tagtype：卡类型值，0x0004为M1卡，0x0010为ML卡

返 回：成功则返回 0

例：#define IDLE 0x00

int st;

unsigned int *tagtype;

st=rf_request(icdev,IDLE,tagtype);


rf_select

int rf_select(int icdev,unsigned long _Snr,unsigned char *_Size);

功 能：从多个卡中选取一个给定序列号的卡

参 数：icdev：通讯设备标识符

_Snr：卡序列号

_Size：指向返回的卡容量的数据

返 回：成功则返回 0

例： int st,type;

unsigned char size;

unsigned long snr;

rf_request(icdev,0,&type);

rf_anticoll(icdev,0,&snr);

st=rf_select(icdev,snr,&size);


rf_write

int rf_write(int icdev,unsingned char _Adr,unsigned char *_Data);

功 能：向卡中写入数据

对于M1卡，一次必须写一个块，为16个字节；

对于ML卡，一次必须写一页，为4个字节

参 数：icdev：通讯设备标识符

_Adr：M1卡——块地址（1～63）；

ML卡——页地址（2～11）

_Data：要写入的数据

返 回：成功则返回0

例：int st;

unsigned char *data=”1234567890123456”;

st=rf_write(icdev,4,data);//写第四块


rf_write_hex

int rf_write_hex(int icdev,unsigned char _Adr,unsigned char *_Data)

功 能：同rf_write()rf_write

参 数：icdev：通讯设备标识符

_Adr：同rf_write

_Data：要写入的数据

返 回：成功则返回 0

例：int st;

unsigned char write_buf[33]=" ffffffffffffffffffffffffffffffff";

st=rf_write_hex(icdev,4,write_buf);


rf_authentication()

rf_authentication() | rf_changeb3() | rf_initval()
rf_readval() | rf_increment() | rf_decrement()
rf_restore()rf_restore | rf_transfer() | rf_HL_authentication()
rf_HL_read() | rf_HL_readhex() | rf_HL_write()
rf_HL_writehex() | rf_HL_initval() | rf_HL_increment()
rf_HL_decrement() | rf_check_write() | rf_check_writehex()
rf_authentication_2() |  |


rf_authentication

int rf_authentication(int icdev,unsigned char _Mode,unsigned char _SecNr);

功 能：验证某一扇区密码

参 数：icdev：通讯设备标识符

_Mode：密码验证模式 mode_auth

_SecNr：要验证密码的扇区号（0～15）

返 回：成功则返回 0

例：int st;

st=rf_authentication(icdev,0,0);

注：卡上每个扇区有A密码和B密码，可根据实际需要确定是否使用B密码，这由该扇区的存取控制位来决定。此外，读写器中可以存放三套密码，可用rf_load_key()rf_load_key来分别装入，只有装入后才能使用验证密码函数验证。此函数也可用于验证ML卡，扇区号为0。


int rf_authentication_2(int icdev,unsigned char _Mode, unsigned char KeyNr,

unsigned char Adr);

功 能：验证某一扇区密码

参 数：icdev：通讯设备标识符

_Mode：密码验证模式 mode_auth

_KeyNr：密码扇区号（0～15）

Adr: 要验证的块地址

返 回：成功则返回 0

例：int st;

st=rf_authentication_2(icdev,0,0，128);

注：卡上每个扇区有A密码和B密码，可根据实际需要确定是否使用B密码，这由该扇区的存取控制位来决定。可用 rf_load_key()rf_load_key来分别装入，只有装入后才能使用验证密码函数验证。主要用于验证扇区号大于15的扇区。


rf_changeb3

int rf_changeb3(int icdev,unsigned char _SecNr,unsigned char *_KeyA,unsigned char _B0,unsigned char _B1,unsigned char _B2,unsigned char _B3,unsigned char _Bk,unsigned char *_KeyB);

功 能：修改块3的数据

参 数：icdev：通讯设备标识符

_SecNr：扇区号（0～15）

_KeyA：密码A

_B0：块0控制字，低3位（D2D1D0）对应C10、C20、C30

_B1：块1控制字，低3位（D2D1D0）对应C11、C21、C31

_B2：块2控制字，低3位（D2D1D0）对应C12、C22、C32

_B3：块3控制字，低3位（D2D1D0）对应C13、C23、C33

_Bk：保留参数，取值为0

_KeyB：密码B

返 回：成功则返回 0

例：int st;

unsigned char keya；

unsigned char keyb；

memset(keya,0xff,6);

memset(keyb,0xff,6);

st=rf_changeb3(icdev,keya,0x00,0x00,0x00,0x01,0,keyb);


rf_check_write

int rf_check_write(int icdev,unsigned long Snr,unsigned char authmode,unsigned char Adr,unsigned char *_data);

功 能：检测指定数据是否与卡中数据一致

参 数：icdev：通讯设备标识符

Snr：卡序列号

authmode：上一次写操作时使用的密码验证模式 mode_auth

Adr：块地址（1～63）

_data：要检测的数据

返 回：成功则返回 0

例： unsigned long snr;

int st,icdev;

unsigned char databuf[16];

for(int i=0;i<16;i++)

data[i]=i;

rf_card(icdev,1,&snr);

rf_authentication(icdev,0,1);

rf_write(icdev,4,databuff); // 向块4写入数据

st=rf_check_write(icdev,snr,0,4,databuff); // 检测卡中数据是否为要写入的数据

if (!st)

{

printf(“Write bad”);

}


rf_check_writehex

int rf_check_writehex(int icdev,unsigned long Snr,unsigned char authmode,unsigned char Adr,unsigned char *_data);

功 能：功能同rf_check_write()rf_check_write，数据用十六进制表示

参 数：icdev：通讯设备标识符

Snr：卡序列号

authmode：上一次写操作时使用的密码验证模式

Adr：块地址（1～63）

_data：要检测的数据

返 回：成功则返回 0


rf_increment

int rf_decrement(int icdev,unsigned char _Adr,unsigned long _Value);

功 能：块减值

参 数：icdev：通讯设备标识符

_Adr：块地址1～63,4n+3除外

_Value：要减的值

返 回：成功则返回 0

例：int st;

unsigned long value;

value=10;

st=rf_decrement(icdev,1,value); /*将块1的值减少value*/


rf_HL_authentication

int rf_HL_authentication(int icdev,unsigned char reqmode,unsigned long snr,unsigned char authmode,unsigned char secnr);

功 能：高级验证（无需调用寻卡函数）

参 数：icdev：通讯设备标识符

reqmode：寻卡模式 mode_card1

snr：卡序列号（在寻卡模式为2时使用）

authmode：密码验证模式 mode_auth

secnr：扇区号（0～15）

返 回：成功则返回 0

例：st=rf_HL_authentication(icdev,0,snr,0,1);


rf_HL_decrement

int rf_HL_decrement(int icdev,unsigned char _Mode,unsigned char _SecNr,unsigned long _Value,unsigned long _Snr,unsigned long *_NValue, unsigned long *_NSnr);

功 能：高级减值操作

参 数：icdev：通讯设备标识符

_Mode：寻卡模式 mode_card1

_SecNr：扇区地址（0～15）

_Value：要减的值

_Snr：卡的序列号

_NValue：减后的值

unsigned long *_NSnr：返回卡的序列号地址

返 回：成功则返回 0

例： if((rf_HL_decrement(icdev,1,1,1L,snr,&Rvalue,&Rsnr))!=0)

{

printf("HL_decrement wrong");

continue;

}

printf("newValue=%lx\n",Rvalue);


rf_HL_increment

int rf_HL_increment(int icdev,unsigned char _Mode,unsigned char _SecNr,unsigned long _Value,unsigned long _Snr,unsigned long *_NValue,unsigned long *_NSnr);

功 能：高级增值操作

参 数：icdev：通讯设备标识符

_Mode：寻卡模式 mode_card1

_SecNr：扇区地址（0～15）

_Value：要加的值

_Snr：卡的序列号

_NValue：加后的值

_NSnr：返回卡的序列号地址

返 回：成功则返回 0

例： if((rf_HL_increment(icdev,1,1,1L,snr,&Rvalue,&Rsnr))!=0)

{

printf("HL_increment wrong");

continue;

}

printf("newValue=%lx\n",Rvalue);


rf_HL_initval

int rf_HL_initval(int icdev,unsigned char _Mode,unsigned char _SecNr,unsigned long _Value,unsigned long *_Snr);

功 能：高级初始化值（该函数操作时占用块1、2，故只能对扇区操作）

参 数：icdev：通讯设备标识符

_Mode：寻卡模式 mode_card1

_SecNr：扇区号（0～15）

_Value：初始值

_Snr：卡的序列号地址

返 回：成功则返回 0

例：if((rf_HL_initval(icdev,0x1,1,100L,&snr))!=0)

{

printf("init HLWvalue wrong");

}

printf("inval OK\n");

printf("snr=%lx\n",snr);


rf_HL_read

int rf_HL_read(int icdev,unsigned char _Mode,unsigned char _Adr,unsigned long _Snr,unsigned char *_Data, unsigned long *_NSnr);

功 能：高级读函数

参 数：icdev：通讯设备标识符

_Mode：寻卡模式 mode_card1

_Adr：块地址（0～63）

_Snr：卡的序列号

_Data：读出的数据

_NSnr：返回卡的序列号

返 回：成功则返回 0

例：if((rf_HL_read(icdev,1,5,snr,HLdata,&Rsnr))!=0)

{

printf("read HL Rvalue wrong");

}


rf_HL_readhex

int rf_HL_readhex(int icdev,unsigned char _Mode,unsigned char _Adr,unsigned long _Snr,unsigned char *_Data, unsigned long *_NSnr);

功 能：高级读函数，十六进制表示数据

参 数：icdev：通讯设备标识符

_Mode：寻卡模式 mode_card1

_Adr：块地址（0～63）

_Snr：卡的序列号

_Data：读出的数据，用十六进制表示

_NSnr：返回卡的序列号

返 回：成功则返回 0


rf_HL_write

int rf_HL_write(int icdev,unsigned char _Mode,unsigned char _Adr,unsigned long *_Snr,unsigned char *_Data);

功 能：高级写函数

参 数：icdev：通讯设备标识符

_Mode：寻卡模式 mode_card1

_Adr：块地址（1～63）

_Snr：卡的序列号地址

_Data：写入的数据

返 回：成功则返回 0

例：if((rf_HL_write(icdev,1,5,Snr,HLdata))!=0)

{

printf("read HL Rvalue wrong");

}


rf_HL_writehex

int rf_HL_writehex(int icdev,unsigned char _Mode,unsigned char _Adr,unsigned long *_Snr,unsigned char *_Data);

功 能：高级写函数，用十六进制表示数据

参 数：icdev：通讯设备标识符

_Mode：寻卡模式 mode_card1

_Adr：块地址（1～63）

_Snr：卡的序列号地址

_Data：写入的数据，用十六进制表示

返 回：成功则返回 0


rf_increment

int rf_increment(int icdev,unsigned char _Adr,unsigned long _Value);

功 能：块加值

参 数：icdev：通讯设备标识符

_Adr：块地址（1～63）

_Value：要增加的值

返 回：成功则返回 0；

例：int st;

unsigned long value;

value=10;

st=rf_increment(icdev,1,value); /*将块1的值增加value*/


rf_initval

int rf_initval(int icdev,unsigned char _Adr,unsigned long _Value);

功 能：初始化块值

参 数：icdev：通讯设备标识符

_Adr：块地址（1～63）

_Value：初始值

返 回：成功则返回 0

例：int st;

unsigned long value;

value=1000; /* 给value赋值*/

st=rf_initval(icdev,1,value); /*将块1的值初始化为1000*/

注：在进行值操作时，必须先执行初始化值函数，然后才可以读、减、加的操作。


rf_readval

rf_readval(int icdev,unsigned char _Adr,unsigned long *_Value);

功 能：读块值

参 数：icdev：通讯设备标识符

_Adr：块地址（1～63）

_Value：读出值的地址

返 回：成功则返回 0

例：int st;

unsigned long value;

st=rf_readval(icdev,1,&value); /*读出块1的值，放入value*/


rf_restore

int rf_restore(int icdev,unsigned char _Adr);

功 能：回传函数，将EEPROM中的内容传入卡的内部寄存器

参 数：icdev：通讯设备标识符

_Adr：要进行回传的块地址（1～63）

返 回：成功返回0

例：int st;

st=rf_restore(icdev,1);

注：用此函数将某一块中的数值传入内部寄存器，然后用rf_transfer()函数将寄存器中数据再传送到另一块中去，实现块与块之间数值传送。该函数只用于值块。


rf_transfer

int rf_transfer(int icdev,unsigned char _Adr);

功 能：传送，将寄存器的内容传送到EEPROM中

参 数：icdev：通讯设备标识符

_Adr：要传送的地址（1～63）

返 回：成功返回0

例：rf_restore(icdev,1);

rf_transfer(icdev,2);

上两行实现将块1的内容传送到块2。

注：见 rf_restore()rf_restore的说明。


rf_authentication_2

rf_decrement_ml

rf_decrement_transfer

rf_initval_ml

rf_readvl_ml


rf_authentication_2

int rf_authentication_2(int icdev,unsigned char _Mode,unsigned char KeyNr,unsigned char Adr);

功 能：ML卡验证密码

参 数：icdev：通讯设备标识符

_Mode：密码验证模式 mode_auth

KeyNr：=0

Adr：=0

返 回：成功则返回 0

例：int st;

st=rf_authentication_2(icdev,0,0,0); //验证0套A密码

注：也可以使用 rf_authenticatio( )函数认证ML卡，将扇区参数设为0即可。


rf_decrement_ml

int rf_decrement_ml(int icdev,unsigned int _Value);

功 能：ML卡减值操作（低版本兼容函数）

参 数：icdev：通讯设备标识符

_Value：要减的值

返 回：成功则返回 0

例：st=rf_decrement(icdev,10); /* 将ML卡钱包的值减少10 */


rf_decrement_transfer

int rf_decrement_transfer(int icdev,unsigned char Adr,unsigned long _Value);

功 能：ML卡减值操作

参 数：icdev：通讯设备标识符

Adr：=0

_Value：要减的值

返 回：成功则返回 0

例：st=rf_decrement_transfer(icdev,0,10);


rf_initval_ml

int rf_initval_ml(int icdev,unsigned int _Value);

功 能：ML卡初始化值

参 数：icdev：通讯设备标识符

_Value：初始值

返 回：成功则返回 0

例：int st;

value=1000;

st=rf_initval(icdev,value); /*将ML卡电子钱包赋初值1000*/

注：必须先初始化值，然后才可以执行减值操作。


rf_readvl_ml

int rf_readvl_ml(int icdev,unsigned int *_Value);

功 能：ML卡读值操作

参 数：icdev：通讯设备标识符

_Value：指向读出值的地址

返 回：成功则返回 0

例：int st;

unsigned int value;

st=rf_readvl_ml(icdev,&value); /*读出钱包的值*/


int rf_get_snr(HANDLE icdev,unsigned char *_Snr);

功 能：取卡片序列列号

参 数：icdev：通讯设备标识符

_Snr： 返回的卡片系列号

_Snr[0] 卡片序列号第0字节

. .

. .

_Snr[6] 卡片序列号第6字节

返 回：成功则返回 0

例：unsigned char _Snr[8];

memset(_Snr,0,8);

int st = rf_get_snr(icdev, _Snr);


int rf_sam_sel_rst(HANDLE icdev, unsigned char cardset, unsigned char baud, unsigned char *samack);

功 能：Sam卡复位

参 数：icdev：通讯设备标识符

cardset：卡座编号

0: PSAM_A/CPU大卡座, 1: PSAM_B, 3: PSAM_C, 4: PSAM_D

baud： 复位波特率

1:9600, 2:19200, 3:38400, 4:76800

samack：返回的复位应答信息

返 回：成功则返回 0

例： int st;

unsigned char samack[256];

memset(samack,0,256);

st=rf_sam_sel_rst(icdev,0, 1,samack);

相关函数：rf_sam_sel_trn()


int rf_sam_sel_trn(HANDLE icdev, unsigned char cardset, unsigned char *samblock,unsigned char *recv);

功 能：发送Sam卡指令

参 数：icdev：通讯设备标识符

cardset：卡座编号

0: PSAM_A/CPU大卡座, 1: PSAM_B, 3: PSAM_C, 4: PSAM_D

samblock：Sam卡指令

samblock[0] NAD(结点地址，一般为0)

samblock[1] pcb(协议控制字节，由卡片通讯协议决定)

samblock[2] len(指令信息长度)

samblock[3] 指令信息

. .

. .

samblock[len+3] 指令信息

recv：返回的指令应答信息

recv[0] NAD

recv[1] pcb

recv[2] len(应答信息长度)

recv[3] 应答信息

. .

. .

recv[len+3] 应答信息

返 回：成功则返回 0

例： int st;

int pcb=0;

unsigned char samblock[256];

unsigned char recv[256];

samblock[0]=0;

samblock[1]=pcb;

samblock[2]=7;

memcpy(&samblock[3],”\x80\xe0\x00\x01\x02\x3f\x00”,7);

memset(recv,0,256);

st=rf_sam_sel_trn(icdev,0,samblock,recv);

pcb = recv[1]^0x40;

相关函数：rf_sam_sel_rst()


int rf_sam_rst(HANDLE icdev, unsigned char baud, unsigned char *samack);

功 能：Sam卡复位

参 数：icdev：通讯设备标识符

baud： 复位波特率

1:9600, 2:19200, 3:38400, 4:76800 mode_auth

samack：返回的复位应答信息

返 回：成功则返回 0

例：int st;

unsigned char samack[256];

memset(samack,0,256);

st=rf_sam_rst(icdev,1,samack);

相关函数：rf_sam_trn(), rf_sam_off()


int rf_sam_trn rf_sam_trn(HANDLE icdev, unsigned char *samblock,unsigned char *recv);

int rf_sam_trn(HANDLE icdev, unsigned char *samblock,unsigned char *recv);

功 能：发送Sam卡指令

参 数：icdev：通讯设备标识符

samblock：Sam卡指令

samblock[0] NAD(结点地址，一般为0)

samblock[1] pcb(协议控制字节，由卡片通讯协议决定)

samblock[2] len(指令信息长度)

samblock[3] 指令信息

. .

. .

samblock[len+3] 指令信息

recv：返回的指令应答信息

recv[0] NAD

recv[1] pcb

recv[2] len(应答信息长度)

recv[3] 应答信息

. .

. .

recv[len+3] 应答信息

返 回：成功则返回 0

例：int st;

int pcb=0;

unsigned char samblock[256];

unsigned char recv[256];

samblock[0]=0;

samblock[1]=pcb;

samblock[2]=7;

memcpy(&samblock[3],”\x80\xe0\x00\x01\x02\x3f\x00”,7);

memset(recv,0,256);

st=rf_sam_trn(icdev,samblock,recv);

pcb = recv[1]^0x40;

相关函数：rf_sam_rst(), rf_sam_off()


int rf_sam_off(HANDLE icdev);

功 能：Sam卡下电

参 数：icdev：通讯设备标识符

返 回：成功则返回 0

例：int st;

st=rf_sam_off(icdev);

相关函数：rf_sam_rst(), rf_sam_trn()


int rf_cpu_rst(HANDLE icdev, unsigned char baud, unsigned char *cpuack);

功 能：Cpu卡复位、双界面卡接触界面复位

参 数：icdev：通讯设备标识符

baud： 复位波特率

1:9600, 2:19200, 3:38400, 4:76800 mode_auth

cpuack：返回的复位应答信息

返 回：成功则返回 0

例：int st;

unsigned char cpuack[256];

memset(cpuack,0,256);

st=rf_cpu_rst(icdev,1,cpuack);

相关函数：rf_cpu_trn()


int rf_cpu_trn(HANDLE icdev, unsigned char *cpublock,unsigned char *recv);

int rf_cpu_trn(HANDLE icdev, unsigned char *cpublock,

unsigned char *recv);

功 能：发送Cpu卡指令、双界面卡接触界面发送指令

参 数：icdev：通讯设备标识符

cpublock：发送信息

cpublock[0] NAD(结点地址，一般为0)

cpublock[1] pcb(协议控制字节，由卡片通讯协议决定)

cpublock[2] len(指令信息长度)

cpublock[3] 指令信息

. .

. .

cpublock[len+3] 指令信息

recv：返回的指令应答信息

recv[0] NAD

recv[1] pcb

recv[2] len(应答信息长度)

recv[3] 应答信息

. .

. .

recv[len+3] 应答信息

返 回：成功则返回 0

例：int st;

int pcb=0;

unsigned char cpublock[256];

unsigned char recv[256];

cpublock[0]=0;

cpublock[1]=pcb;

cpublock[2]=7;

memcpy(&cpublock[3],”\x80\xe0\x00\x01\x02\x3f\x00”,7);

memset(recv,0,256);

st=rf_cpu_trn(icdev,cpublock,recv);

pcb = recv[1]^0x40;

相关函数：rf_cpu_rst()


int rf_pro_rst(HANDLE icdev, unsigned char *_Data);

功 能：双界面卡非接触界面复位

参 数：icdev：通讯设备标识符

_Data：返回的复位应答信息

返 回：成功则返回 0

例：int st;

unsigned char _Data[256];

memset(_Data,0,256);

st=rf_pro_rst(icdev,_Data);

相关函数：rf_pro_trn(), rf_pro_halt()


int rf_pro_trn(HANDLE icdev, unsigned char *problock,unsigned char *recv);

int rf_pro_trn(HANDLE icdev, unsigned char *problock,

unsigned char *recv);

功 能：双界面卡非接触界面发送指令

参 数：icdev：通讯设备标识符

problock：发送信息

problock[0] NAD(结点地址，一般为0)

problock[1] CID(卡标识符)

problock[2] pcb(协议控制字节，由卡片通讯协议决定)

problock[3] len(指令信息长度)

problock[4] 指令信息

. .

. .

problock[len+4] 指令信息

recv：返回的指令应答信息

recv[0] NAD

recv[1] CID（用于访问指定的卡片，目前不支持）

recv[2] pcb(由卡片和读写器的通讯协议决定)

recv[3] len(应答信息长度)

recv[4] 应答信息

. .

. .

recv[len+4] 应答信息

返 回：成功则返回 0

例：int st;

unsigned char problock[256];

unsigned char recv[256];

problock[0]=0;

problock[1]=0;

problock[2]=0;

problock[3]=7;

memcpy(&problock[4],”\x80\xe0\x00\x01\x02\x3f\x00”,7);

memset(recv,0,256);

st=rf_pro_trn(icdev,problock,recv);

相关函数：rf_pro_rst(), rf_pro_halt()


int rf_pro_halt(HANDLE icdev);

功 能：将双界面卡非接触界面置于HALT状态

参 数：icdev：通讯设备标识符

返 回：成功则返回 0

例：int st;

st=rf_pro_halt(icdev);

相关函数：rf_pro_rst(), rf_pro_trn()


C语言接口函数库

我公司提供的C语言库函数共包括六种模式库，提供文件如下：

C.DOS\MWRF.H C语言库函数头文件

\MWRFT.LIB C微模式（TINY）函数库

\MWRFS.LIB C小模式（SMALL）函数库

\MWRFM.LIB C模式（MEDIUM）函数库

\MWRFC.LIB C紧凑模式（COMPACT）函数库

\MWRFL.LIB C大模式（LARGE）函数库

\MWRFH.LIB C巨模式（HUGE）函数库

C语言调用库函数的方法

（1）建立工程文件；

（2）在工程文件中加入所用模式的库；

（3）将头文件MWRF.H包含在程序中；

（4）在程序中调用库中函数。

注意事项

编译时应注意编译模式要与所选库的模式相同。

各种函数的使用方法请参见库函数详细说明 function_list。


Delphi调用16位或32位动态库的方法

16位与32位动态库调用方法相同。

语法：

[Public Private | protected] Function FunctionName([Var] [Arg1:DataType1;] [Arg2:DataType2;...]) [:ReturnDataType]; far;stdcall;external ‘libname’ [Name AliasName];

调用语句的语法包含下面部分：

关键字Public（可选），表示函数可以被程序代码中的任意部分访问。

关键字Private（可选），表示函数在声明类的单元（源代码）外不能访问。

关键字Protected（可选），表示保护函数，保护元素只能被当前类和它的子类访问。

关键字Function（必选），表示调用函数，函数有返回值。

FunctionName（必选），调用外部函数的名称，区分大小写。

关键字Var（可选），表示通过引用传递参数，函数参数可以用值传递，也可以通过引用传递。通过引用传递参数，它的值没被复制到存放函数例程参数的堆栈中，程序执行速度快。通过引用传值，将允许过程和函数改变参数的值。

ArgN:DataTypeN（可选），参数名以及参数类型，传递的参数类型可以是：Shorint，Smallint，Longint，Integer(16/32)，Single，Double，Extended，Currency，Date，Pchar，Object，Variant等。

ReturnType（可选），函数返回值的类型。

Stdcall（必选），表示传递约定，这样调用模块（应用程序），与被调用模块（DLL）就使用相同的参数约定。

关键字external（必选），声明访问外部函数。

Libname（必选），访问的DLL名称，16位Delphi中外部声明不带扩展名的库名。

Name ‘AliasName’（可选），Name指令可以为外部函数起别名，避免与系统例程和函数名称冲突。

外部程序调用的DLL函数，必须遵照下列规则：

（1）必须列在DLL的exports子句中。

（2）在Delphi3中，调用函数还需被声明为stdcall，来使用标准的WIN32参数传递技术。代替优化的register参数传递技术。

（3）在WIN32中，DLL可以使用全局数据，该数据将不会通过调用应用程序来分享，每当应用程序装载DLL时，它在自己的地址空间中存储着DLL的全部数据。

注：详细请参考MWRF\EXAMPLES目录下的使用范例。


FOXPRO FOR DOS接口函数库

提供库函数文件：FOXPRO.DOS\MWRF.PLB。

调用FOXPRO FOR DOS库函数的方法

执行语句“set libr to MWRF\FOXPRO.DOS\MWRF.PLB”，Foxpro将自动登录库“MWRF.PLB”中的函数。编译时，自动将“MWRF.PLB”链入。

注意事项

本库中的部分函数与C语言库的函数有差异，大致分为：函数名不同、参数不同、返回值不同。

（1）函数名不同

因FOXPRO FOR DOS函数名长度最大为10个字符，所以对于超长函数名有所修改。

（2）参数不同

对于读出性操作的函数，在C语言中需要用变参返回数据的函数，在本库中均去掉该参数，改为用返回值返回数据。

（3）返回值不同

按返回值类型分为返回字符串和返回整数两种。

对于返回字符串的函数，操作成功时返回：chr(0)+返回数据；操作失败时返回：以错误代码为ASCII码值的字符，即chr(错误代码 function_list_errcode)。

对于返回整数的函数，操作成功时返回整数值；失败时返回：chr(错误代码)。

例如：

FOXPRO FOR DOS | C语言
rf_get_sta(icdev) 功 能：读取版本号 参 数： icdev：设备描述符 返 回： 成功则返回chr(0)+读写器版本信息； 错误则返回chr(错误代码) 例：VERBUFF=rf_get_sta(icdev); if asc(substr(VERBUFF,1,1))<0 ?’Error.’ | int rf_get_status(int icdev, unsigned char *_Status); 功 能：取得读写器硬件版本号 参 数： icdev：通讯设备标识符 _Status：返回版本信息 返 回：成功则返回 0 例：int st; unsigned char *version; st=rf_get_status(icdev, version);

FOXPRO FOR DOS | C语言函数名 | 参数 | 返回值
设备操作函数 |  |  |
rf_reset | rf_reset() rf_reset |  |
rf_beep | rf_beep() rf_beep |  |
rf_get_sta | rf_get_status() rf_get_status | 少_Status | 成功：chr(0)+硬件版本信息 错误：chr(错误代码)
srd_snr | rf_srd_snr() rf_srd_snr | 少rec_buffer | 成功：chr(0)+产品序列号 错误：chr(错误代码)
lib_ver | lib_ver() lib_ver | 无参数 | 成功：chr(0)+软件版本信息 错误：chr(错误代码)
rf_bright | rf_setbright() rf_setbright |  |
rf_ctl_m | rf_ctl_mode() rf_ctl_mode |  |
rf_disp_m | rf_disp_mode() rf_disp_mode |  |
rf_disp8 | rf_disp8() rf_disp8 |  |
rf_disp | rf_disp() rf_disp |  |
rfx_clr_cb | rf_clr_control_bit() rf_clr_control_bit |  |
rfx_set_cb | rf_set_control_bit() rf_set_control_bit |  |
rf_getport | rf_getport() rf_getport | 少receive_data | 成功：chr(0)+端口输入值 错误：chr(错误代码)
rf_setport | rf_setport() rf_setport |  |
rf_gettime | rf_gettime() rf_gettime | 少time | 成功：chr(0)+日期时间 错误：chr(错误代码)
rf_settime | rf_settime() rf_settime |  |
rf_g_t_hex | rf_gettimehex() rf_gettimehex | 少time | 成功：chr(0)+日期时间 错误：chr(错误代码)
rf_s_t_hex | rf_settimehex() rf_settimehex |  |
srd_eeprom | rf_srd_eeprom() rf_srd_eeprom | 少rec_buffer | 成功：chr(0)+备注信息 错误：chr(错误代码)
swr_eeprom | rf_swr_eeprom() rf_swr_eeprom |  |
通用函数 |  |  |
rf_init | rf_init() rf_init |  |
rf_exit | rf_exit() rf_exit |  |
rf_card | rf_card() rf_card | 少_Snr | 成功：卡序列号 错误：错误代码（负数）
rf_config | rf_config() rf_config |  |
rf_request | rf_request()rf_request | 少TagType | 成功：卡类型值 错误：错误代码（负数）
rf_anti | rf_anticoll()rf_anticoll | 少_Snr | 成功：卡序列号 错误：错误代码（负数）
rf_select | rf_select()rf_select | 少_Size | 成功：卡容量 错误：错误代码（负数）
rf_ld_k | rf_load_key()rf_load_key |  |
rf_ld_kh | rf_load_key_hex()rf_load_key_hex |  |
rf_halt | rf_halt()rf_halt |  |
rf_read | rf_read()rf_read | 少_Data | 成功：chr(0)+读出数据 错误：chr(错误代码)
rf_rd_hex | rf_read_hex()rf_read_hex | 少_Data | 成功：chr(0)+读出数据 错误：chr(错误代码)
rf_write | rf_write()rf_write |  |
rf_w_hex | rf_write_hex()rf_write_hex |  |
rf_encrypt | rf_encrypt()rf_encrypt | 少ptrDest | 成功：chr(0)+加密后的数据 错误：chr(错误代码)
rf_decrypt | rf_decrypt() rf_decrypt | 少ptrDest | 成功：chr(0)+解密后的数据 错误：chr(错误代码)
Mifare 1卡 |  |  |
rf_auth | rf_authentication()rf_authentication |  |
rfx_chanb3 | rf_changeb3() rf_changeb3 |  |
rf_chk_wr | rf_check_write() rf_check_write |  |
rf_c_wrhex | rf_check_writehex() rf_check_writehex |  |
rf_ini_val | rf_initval()rf_initval |  |
rf_rd_val | rf_readval()rf_readval | 少_Value | 成功：读出值 错误：错误代码（负数）
rf_inc_val | rf_increment()rf_increment |  |
rf_dec_val | rf_decrement()rf_decrement |  |
rf_restore | rf_restore()rf_restore |  |
rf_tran | rf_transfer()rf_transfer |  |
rf_hl_auth | rf_HL_authentication() rf_HL_authentication
rf_hl_rd | rf_HL_read() rf_HL_read | 少_Data、_NSnr | 成功：chr(0)+读出数据 错误：chr(错误代码)
rf_hl_rhex | rf_HL_readhex() rf_HL_readhex | 少_Data、_NSnr | 成功：chr(0)+读出数据 错误：chr(错误代码)
rf_hl_wr | rf_HL_write() rf_HL_write |  |
rf_hl_whex | rf_HL_writehex() rf_HL_writehex |  |
rf_hl_ini | rf_HL_initval() rf_HL_initval |  |
rf_hl_inc | rf_HL_increment() rf_HL_increment | 少_NValu、_NSnr | 成功：卡序列号 错误：错误代码（负数）
rf_hl_dec | rf_HL_decrement() rf_HL_decrement | 少_NValu、_NSnr | 成功：卡序列号 错误：错误代码（负数）
Mifare Light卡 |  |  |
rf_auth_2 | rf_authentication_2() rf_authentication_2 |  |
rf_ini_ml | rf_initval_ml() rf_initval_ml |  |
rf_rd_ml | rf_readval_ml() rf_readval_ml | 少_Value | 成功：读出的值 错误：错误代码（负数）
rf_dec_ml | rf_decrement_ml() rf_decrement_ml |  |
rf_dectran | rf_decrement_transfer() rf_decrement_transfer |  |


PB调用32位动态库的方法

语法：

{ access } FUNCTION returndatatype name ([REF] datatype1 arg1， ...，{[REF] datatyn argn}) LIBRARY libname

部分描述：

access (仅仅能声明为本地函数) 有选择的声明访问级别。可以声明为PUBLIC、PRIVATE、PROTECTED三种访问级别，缺省级别是PUBLIC。

returndatatype 表示函数返回值的类型。

Name 调用的外部函数名称，区分大小写。

关键字ref（可选），表示通过引用传递参数。函数参数可以用值传递增，也可以通过引用传递。通过引用传递参数，就意味着它的值没被复制到存放函数例程参数的堆栈中，避免复制可以使程序执行速度加快。通过引用传值，这将允许过程和函数改变参数的值。

datatype argn（可选），参数类型以及参数名，表示要传递的参数。

LIBRARY libname 指定调用外部动态库的名称。

注：详细请参考MWRF\EXAMPLES目录下的使用范例。


VB调用16位或32位动态库的方法

16位与32位动态库调用方法相同。

语法：

[Public | Private] Declare Function name Lib "libname" [Alias "aliasname"] [([arglist])] [As type]

Declare 语句的语法包含下面部分：

Public （可选）用于声明在所有模块中的所有过程都可以使用的函数。

Private（可选），用于声明只能在包含该声明的模块中使用的函数。

Name（必选），任何合法的函数名。动态链接库的入口处（entry points）区分大小写。

Libname（必选），包含所声明的函数动态链接库名或代码资源名。

Alias（可选），表示将被调用的函数在动态链接库 (DLL) 中还有另外的名称。当外部函数名与某个函数重名时，就可以使用这个参数。当动态链接库的函数与同一范围内的公用变量、常数或任何其它过程的名称相同时，也可以使用 Alias。如果该动态链接库函数中的某个字符不符合动态链接库的命名约定时，也可以使用 Alias。

Aliasname（可选）动态链接库。如果首字符不是数字符号 (#)，则 aliasname 是动态链接库中该函数入口处的名称。如果首字符是 (#)，则随后的字符必须指定该函数入口处的顺序号。

Arglist（可选），代表调用该函数时需要传递参数的变量表。

Type（可选），Function返回值的数据类型；可以是 Byte、Boolean、Integer、Long、Currency、Single、Double、Decimal（目前尚不支持）、Date、String（只支持变长）或 Variant，用户定义类型，或对象类型。

arglist 参数的语法如下：

[Optional] [ByVal | ByRef] [ParamArray] varname[( )] [As type]

部分描述：

Optional（可选），表示参数不是必需的。如果使用该选项，则 arglist 中的后续参数都必需是可选的，而且必须都使用 Optional 关键字声明。如果使用了 ParamArray，则任何参数都不能使用 Optional。

ByVal（可选），表示该参数按值传递。

ByRef（可选），表示该参数按地址传递。

ParamArray（可选），只用于 arglist 的最后一个参数，表示最后参数是一个 Variant 元素的Optional 数组。使用 ParamArray 关键字可以提供任意数目的参数。ParamArray 关键字不能与 ByVal、ByRef或 Optional 一起使用。

Varname（必选），代表传给该函数参数的变量名；遵循标准的变量命名约定。

( ) 对数组变量是必需的。指明 varname 是一个数组。

type （可选），传递给函数参数的数据类型；可以是除Decimal以外的任何类型。

说明：

Function的数据类型决定其返回值的数据类型。可以在 arglist 之后使用 As 子句来指定函数返回值的数据类型。在 arglist 中，可以使用 As 子句来指定任何传给该函数参数的数据类型。不单可以指定为任何标准数据类型，还可以在 arglist 中指定 As Any 来禁止类型检查，从而允许将任意数据类型传递给该函数。

空圆括号表示该 Function 没有参数，且 Visual Basic 应确保不会传递任何参数。

注意：

（1）当所调用的外部函数需要一个值为 0 的字符串时，就要使用 vbNullString 常数。该常数与零长度字符串 ("")是不相同的。

（2）VB5调用32位动态库，对于ASCII码值大于128的读写操作，请参考Examples 中24系列的BYREF传递方式；16位动态库可以直接使用CHR函数转换。

（3）详细请参考MWRF\EXAMPLES目录下的使用范例。


VC调用16位或32位动态库的方法

（1）在.CPP中包含“MWRF**.H”头文件；

（2）在工程文件中加入MWRF**.LIB文件。


VFP调用16位动态库的方法

（1）函数Regfn()，Callfn()说明

VFP带有可由Foxtools.FLL调用的多种C语言函数的库程序。库中的两个函数RegFn（），CallFn（）允许FoxPro内部调用在Windows动态连接库中C语言函数。先用RegFn()存储一个DLL函数，然后用CallFn()按用户指定的参数调用函数。

登记DLL函数的RegFn()采用以下形式:

FnHandle=RegFn(FunctionName，ArgTypes，ReturnType[，DLLName])

返回值FnHandle是一个用在下面CallFn()中指定函数的数值。如果登记失败，RegFn()返回-1，而且会出现错误信息。可以多次登记一个函数。

FunctionName是一个包含要调用函数名字或在DLL中函数序号的字符串。

ArgTypes是一串字母代码，对应于DLL中函数中指定的每个参数的数据类型，例如，一个函数调用四种类型参数:整型、整型、字符串、浮点型，可以指定ArgTypes为"IICF"。在代码前放上@标志来指定可选择的参数。

ReturnType是函数的返回类型。

DLLName是一个可选参数，包含DLL名字及其路径名(可选)。如果使用序号调用一个函数，必须指定DLL名字。如果不提供DLL名，RegFn()将按顺序搜索被装入的所有DLL，接着是标准Microsoft Windows库函数。

用RegFn()登记一个函数后，可以用CallFn()调用它。

RetVal=CallFn(FnHandle，Args，…)

FnHandle是被登记函数的数值句柄，Args是参数表，相应于在RegFn()中定义的ArgTypes的数据类型和数值。RetVal是DLL函数的返回值，它带有开始在ReturnType参数中指定的数据类型。

（2）调用RegFn()和CallFn()的方法

VFP安装程序将FOXTOOLS.FLL放在Windows Foxpro主目录中，可用以下命令装入该库:

SET LIBRARY TO SYS(2004)+"FOXTOOLS.FLL" ADDITIVE.

SYS(2004)返回Windows FoxPro 主目录的名。ADDITIVE 表示保持打开上次所装入库。

可用下列命令取消FOXTOOLS.FLL:

RELEASE LIBRARY SYS(2004)+"FOXTOOLS.FLL"

（3）通过引用来传递参数

可以用@标志放在相应的RegFn() ArgType前，用引用方式传递参数给DLL函数。

注意：引用参数返回数据时，一定要先分配缓冲区大小。详细请参考MWRF\EXAMPLES目录下的使用范例


VFP调用32位动态库的方法

语法：

DECLARE [返回参数类型] 函数名 IN 动态库名 [AS 别名]

[参数类型1 [@] 参数1，参数类型2 [@] 参数类型2， ...]

返回参数类型：

类型 说明

SHORT 16-bit integer

INTEGER 32-bit integer

SINGLE 32-bit floating point

DOUBLE 64-bit floating point

STRING Character string

函数名：输入动态库提供的函数名。 注意：区分大小写，一定要严格遵循定义。

IN 动态库名：输入MWRF32.DLL.

AS 别名：取一个别名，不能使别名与其它函数名相同。可以省略

参数类型:

类型 说明

INTEGER 32-bit integer

SINGLE 32-bit floating point

DOUBLE 64-bit floating point

STRING Character string

可传送空字符(NULL)，VFP缺省用值传递，若要用地址传递，在参数前加@ 。

注：详细请参考MWRF\EXAMPLES目录下的使用范例


WINDOWS 16/32位动态库

我公司提供WINDOWS平台下的WINDOWS 16位动态库和WINDOWS 32动态库，文件名称如下：

MWRF16\MWRF16.DLL WINDOWS 16位动态库

\MWRF16.H 16位动态库的头文件

\MWRF16.LIB 16位动态库的输入库

MWRF32\MWRF32.DLL WINDOWS 32位动态库

\MWRF32.H 32位动态库的头文件

\MWRF32.LIB 32位动态库的输入库

调用WINDOWS动态库的方法

基于WINDOWS平台的各种开发工具调用动态库的方法各不相同，详见如何调用动态库 function_call。

WINDOWS 16位和32位动态库与C语言函数库格式基本相同，它们的区别如下：

函数库 | rf_init rf_init | 返回值icdev | 参数int
C语言库 | int rf_init( int port, long baud); baud 9600～115200 | int | int
16位库 | int rf_init( int port, long baud); baud 9600～115200 | int | int
32位库 | HANDLE rf_init( _int16 port, long baud); baud 9600～115200 | HANDLE | _int16


函数错误代码

函数错误代码（正值是卡返回的，负值是PC机返回的）

返回值 | 错误类型
0 | 正确
1 | 无卡
2 | CRC校验错
3 | 值溢出
4 | 未验证密码
5 | 奇偶校验错
6 | 通讯出错
8 | 错误的序列号
10 | 验证密码失败
11 | 接收的数据位错误
12 | 接收的数据字节错误
14 | Transfer错误
15 | 写失败
16 | 加值失败
17 | 减值失败
18 | 读失败
-0x10 | PC与读写器通讯错误
-0x11 | 通讯超时
-0x20 | 打开通信口失败
-0x24 | 串口已被占用
-0x30 | 地址格式错误
-0x31 | 该块数据不是值格式
-0x32 | 长度错误
-0x40 | 值操作失败
-0x50 | 卡中的值不够减


库函数介绍

我公司提供丰富的二次开发平台，包括以下几类函数库：

C语言接口函数库 func_intro_c

FOXPRO FOR DOS 接口函数库 func_intro_foxpro

WINDOWS 动态库 func_intro_win

UNIX、LINUX调用库函数方法

库函数使用方法参见库函数列表口库为例详细讲解其他类型的库函数请参考以上各库内容。

库函数调用方法参见 如何调用库函数 function_call。


库函数使用规则

（1）程序开始，调用rf_init()rf_init函数初始化串口。

（2）寻卡，调用rf_card()rf_card；

相当于连续调用三个函数：

rf_request()rf_request

rf_anticoll()rf_anticoll

rf_select()rf_select

注：调用高级函数对卡进行操作时，无需此步骤。

（3）对单个扇区操作，顺次执行A～D；

对多个扇区操作，循环执行A～E；

A、选定要操作的扇区；

B、装载密码，调用rf_load_key()rf_load_key；

C、验证密码，调用rf_authentication()rf_authentication；

D、进行操作，包括读写及值操作。

E、调用rf_halt()rf_halt。

（4）关闭串口，调用rf_exit()rf_exit。程序正常退出或因错误退出之前，要使用函数；否则再次执行初始化串口时将出错。


同UNIX下如何调用库函数


UNIX库函数说明

UNIX函数库与C库的格式基本相同，它们的区别如下：

（1） int rf_init(char *filename , long baud)

filename：初始化文件名，范例中为star500x;

baud： 通讯波特率。

FILE结构：

第一个字符为“#”，则此行为注释；

“PATH=”，有此行为无终端方式，读写器直接连接串口，其他行无效；

“SETAUX=”，设置终端方式，如显示等；

“INITAUX=”，开启辅口并初始化；

“CLOSEAUX=”，关闭辅口；

“WRITEAUX=”，写辅口的字头；

“AUXENDWRITE=”，结束写辅口；

“DISABLEKEYBOARD=”，键盘无效；

“ENABLEKEYBOARD=”，键盘有效。

注意事项：

1． 调用前包括函数的头文件（.h）。

2． 在UNIX下，如果使用终端，应先用ENABLE命令初始化该串口；如不使用终端，要用DISABLE命令置终端为不接收终端方式。

3． 编译时可使用命令：cc demorf.c mwrf30.a –o demorf

4． UNIX终端的设置：

通信设置（终端与UNIX系统）：XOFF选NO

辅口设置（终端与读写器）：XOFF选NO

5．如果以非终端方式运行，应确认用户登录的帐户是否具有读写串口的权限。


密码验证模式

对于M1卡的每个扇区，在读写器中只有一套密码(密码A和密码B)，动态库为了和RF-25兼容，仍对应三套密码（KEYSET0、KEYSET1、KEYSET2），每套密码包括A密码（KEYA）和B密码（KEYB），共六个密码，用0～2、4～6来表示这六个密码：

0——KEYSET0的KEYA`

1——KEYSET1的KEYA

2——KEYSET2的KEYA

4——KEYSET0的KEYB

5——KEYSET1的KEYB

6——KEYSET2的KEYB

注意：RF-35中只区分密码A或密码B, 0~2中任何一个值表示密码A，4～6中任何一个值表示密码B。


如何调用库函数

各开发工具调用WINDOWS动态库的方法如下：

Delphi调用16位或32位动态库 delphi

PB调用32位动态库 pb32

VB调用16位或32位动态库 vb

VC调用16位或32位动态库 vc

VFP调用16位动态库 vfp16

VFP调用32位动态库

vfp32

UNIX下如何调用库函数

LINUX下如何调用库函数

其他类型的库函数调用方法请参考相应的C语言 func_intro_c、FOXPRO FOR DOS func_intro_foxpro 静态库。


寻卡模式

寻卡模式分三种情况：IDLE模式、ALL模式及指定卡模式。

0——表示IDLE模式，一次只对一张卡操作；

1——表示ALL模式，一次可对多张卡操作；

2——表示指定卡模式，只对序列号等于snr的卡操作（高级函数才有）


RF-35和RF-25LT的函数级区别：

1. RF-25在很多函数中对于传入的块地址值或扇区号做了判断，例如扇区号必须大于等于0并且小于等于15，块地址必须大于等于0小于等于63。RF-35去掉了这些限制。

2． 由于RF-35增加了对双界面卡的支持，增加了rf_pro_rst、rf_pro_trn、rf_pro_halt、rf_cpu_rst、rf_cpu_trn等函数。

3． 由于RF-35增加了对UltraLight卡的支持，增加了读取卡片序列号的函数rf_get_snr, 该函数是UltraLight卡专用的。

4． 由于华虹模块的库和Mifare模块的库只是装载密码时传输密码不一样，所以增加了Set_Reader_Mode函数来设置装载密码时用的传输密码，这样就不需要两个版本的动态库了。

5． RF-35只能装载一套密码，而RF-25LT可以装载三套密码。RF-35中密码验证模式0、1或者2表示密码A，4、5或者6表示密码B。

6． RF-35的rf_check_write、rf_HL_read、rf_HL_read_hex、rf_HL_write、rf_HL_write_hex、rf_HL_decrement、rf_HL_increment、rf_HL_intival、rf_HL_authentication等高级函数由动态库实现，rf-25的高级函数由硬件底层完成。

7． RF-35目前不支持485接口通讯。

8． RF-35目前不支持多机。

除了以上的不同，RF-25和RF-35的函数基本相同，函数的调用也相同。


Mifare l卡特性简介

M1卡为8K位的非接触式IC卡。

电气特性

l 容量为8K位EEPrOM

l 分为16个扇区，每个扇区为4块，每块16个字节,以块为存取单位

l 每个扇区有独立的一组密码及访问控制

l 每张卡有唯一序列号，为32位

l 具有防冲突机制，支持多卡操作

l 无电源，自带天线，内含加密控制逻辑和通讯逻辑电路

l 工作温度：-20℃～50℃

l 工作频率：13.56MHZ

l 通信速率：106KBPS

l 读写距离：10mm以内（与读写器有关）

l 数据保存期为10年，可改写10万次，读不限次

存储结构

M1卡分为16个扇区，每个扇区4块（块0～3），共64块，按块号编址为0～63。第0扇区的块0（即绝对地址0块）用于存放厂商代码，已经固化，不可更改。其他各扇区的块0、块1、块2为数据块，用于存贮数据；块3为控制块，存放密码A、存取控制、密码B，其结构如下：

A0A1A2A3A4A5 FF 07 80 69 B0B1B2B3B4B5

密码A(6字节) 存取控制(4字节) 密码B(6字节)

控制属性

每个扇区的密码和存取控制都是独立的，可以根据实际需要设定各自的密码及存取控制。在存取控制中每个块都有相应的三个控制位,定义如下：

块0： C10 C20 C30

块1： C11 C21 C31

块2： C12 C22 C32

块3： C13 C23 C33

三个控制位以正和反两种形式存在于存取控制字节中，决定了该块的访问权限（如进行减值操作必须验证KEY A，进行加值操作必须验证KEY B，等等）。三个控制位在存取控制字节中的位置如下（字节9为备用字节，默认值为0x69）：

 | bit 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0
字节6 | C23_b | C22_b | C21_b | C20_b | C13_b | C12_b | C11_b | C10_b
字节7 | C13 | C12 | C11 | C10 | C33_b | C32_b | C31_b | C30_b
字节8 | C33 | C32 | C31 | C30 | C23 | C22 | C21 | C20

（注： _b表示取反）

其中，黑色区控制块3，蓝色区控制块2，绿色区控制块1，红色区控制块0。

数据块（块0、块1、块2）的存取控制如下：

控制位(X=0..2) |  |  | 访 问 条 件 （对块0、1、2）
C1X | C2X | C3X | Read | Write | Increment | Decrement transfer restore
0 | 0 | 0 | KeyA|B | KeyA|B | KeyA|B | KeyA|B
0 | 1 | 0 | KeyA|B | Never | Never | Never
1 | 0 | 0 | KeyA|B | KeyB | Never | Never
1 | 1 | 0 | KeyA|B | KeyB | KeyB | KeyA|B
0 | 0 | 1 | KeyA|B | Never | Never | KeyA|B
0 | 1 | 1 | KeyB | KeyB | Never | Never
1 | 0 | 1 | KeyB | Never | Never | Never
1 | 1 | 1 | Never | Never | Never | Never

（KeyA|B 表示密码A或密码B，Never表示任何条件下不能实现）

例如：当块0的存取控制位C10 C20 C30=100时，验证密码A或密码B正确后可读；验证密码B正确后可写；不能进行加值、减值操作。

控制块（块3）的存取控制与数据块（块0、1、2）不同，它的存取控制如下：

控制位 |  |  | 密码A |  | 存取控制 |  | 密码B
C13 | C23 | C33 | Read | Write | Read | Write | Read | Write
0 | 0 | 0 | Never | KeyA|B | KeyA|B | Never | KeyA|B | KeyA|B
0 | 1 | 0 | Never | Never | KeyA|B | Never | KeyA|B | Never
1 | 0 | 0 | Never | KeyB | KeyA|B | Never | Never | KeyB
1 | 1 | 0 | Never | Never | KeyA|B | Never | Never | Never
0 | 0 | 1 | Never | KeyA|B | KeyA|B | KeyA|B | KeyA|B | KeyA|B
0 | 1 | 1 | Never | KeyB | KeyA|B | KeyB | Never | KeyB
1 | 0 | 1 | Never | Never | KeyA|B | KeyB | Never | Never
1 | 1 | 1 | Never | Never | KeyA|B | Never | Never | Never

例如：当块3的存取控制位C13 C23 C33=100时，表示：

密码A： 不可读，验证KEYB正确后，可写（更改）。

存取控制：验证KEYA或KEYB正确后，可读不可写。

密码B： 不可读，验证KEYB正确后，可写。

工作原理

卡片的电气部分只由一个天线和 ASIC 组成。

天线：卡片的天线是只有几组绕线的线圈，很适于封装到 IS0 卡片中。

ASIC：卡片的 ASIC 由一个高速（106KB波特率）的 RF 接口，一个控制单元和一个8K位EEPROM组成。

读写器向 M1 卡发一组固定频率的电磁波，卡片内有一个 LC 串联谐振电路，其频率与讯写器发射的频率相同，在电磁波的激励下，LC 谐振电路产生共振，从而使电容内有了电荷，在这个电容的另一端，接有一个单向导通的电子泵，将电容内的电荷送到另一个电容内储存，当所积累的电荷达到 2V 时，此电容可做为电源为其它电路提供工作电压，将卡内数据发射出去或接取读写器的数据。


Mifare Light卡特性简介

ML卡是一种小容量卡，共384位，适合于一卡一用。

电气特性

l 容量为384位

l 16位的数值计算

l 128位的数据区（如果不用钱包文件可达192位）

l 用户可自定义控制权限

l 唯一的32位序列号

l 工作频率：13.56MHZ

l 通信速率：106KB波特率

l 防 冲 突：同一时间可处理多张卡

l 读写距离：在10cm以内（与天线有关）

l 卡内无需电源

存储结构

ML卡共384位，分为12页，每页为4个字节。存储结构如下：

页号 | 字节0 | 字节1 | 字节2 | 字节3 | 说明
0 | SerNr(0) | SerNr(1) | SerNr(2) | SerNr(3) | Block 0
1 | SerNr(4) | Size Code | Type(0) | Type(1) |
2 | Data(0) | Data(1) | Data(2) | Data(3) | Data1
3 | Data(4) | Data(5) | Data(6) | Data(7) |
4 | Value(0) | Value(1) | Value_b(0) | Value_b(1) | Value
5 | Value(0) | Value(1) | Value_b(0) | Value_b(1) |
6 | KeyA(0) | KeyA(1) | KeyA(2) | KeyA(3) | KeyA
7 | KeyA(4) | KeyA(5) | AC-A | AC-A_b |
8 | KeyB(0) | KeyB(1) | KeyB(2) | KeyB(3) | KeyB
9 | KeyB(4) | KeyB(5) | AC-B | AC-B_b |
A | Data(0) | Data(1) | Data(2) | Data(3) | Data2
B | Data(4) | Data(5) | Data(6) | Data(7) |

（注：_b表示取反）

（1）第0、1页存放着卡的序列号等信息，只可读。

（2）第2、3页及A、B两页数据块，可存贮一般的数据。

（3）第4、5页为数值块，可作为钱包使用，两字节的值以正和反两种形式存贮。只有减值操作，没有加值操作。如果不做钱包使用，则可以做为普通的数据块使用。

（4）第6、7、8、9页存储着密码A（6字节）、密码B（6字节）及存取控制。

（5）第7页的2字节、第9页的2字节为存储控制，存储控制以正和反的形式存两次。

Bit 7 | —
Bit 6 | —
Bit 5 | Data2—Write—Enable
Bit 4 | Data2—read—Enable
Bit 3 | Key+AC—Write—Enable
Bit 2 | Value—Write—Enable
Bit 1 | Data1—Write—Enable
Bit 0 | Data1—read—Enable

例如：AC-A的初始值为ff，即‘11111111’，即：

Data1：可读、可写；

Value：可写；

AC-A：可写；

Data2：可读、可写；

（6）一次写一页（4个字节），一次读两页（8个字节）。


Mifare UtraLight卡特性简介

UltraLight卡是一种512位非接触式IC卡。

电气特性

l 容量为512位，分为16页，每页4个字节

l 每页可编程锁定只读功能

l 32位用户可定义的一次性编程区域

l 384位用户读、写区域

l 数据可保留2年，可循环改写1000次

l 唯一的7字节序列号

l 工作频率：13.56MHZ

l 通信速率：106KB波特率

l 防 冲 突：同一时间可处理多张卡

l 读写距离：在100mm以内（与天线有关）

l 卡内无需电源

存储结构

UltraLight卡共512位，分为16页，每页为4个字节。存储结构如下：

页号 | 字节0 | 字节1 | 字节2 | 字节3 | 说明
0 | SN0 | SN1 | SN2 | BCC0 | Serial Number
1 | SN3 | SN4 | SN5 | SN6 | Serial Number
2 | BCC1 | 保留 | Lock0 | Lock1 | 保留/Lock
3 | OTP0 | OTP1 | OTP2 | OTP3 | OTP
4 | Data0 | Data1 | Data2 | Data3 | Data read/write
5 | Data4 | Data5 | Data6 | Data7 | Data read/write
6 | Data8 | Data9 | Data10 | Data11 | Data read/write
7 | Data12 | Data13 | Data14 | Data15 | Data read/write
8 | Data16 | Data17 | Data18 | Data19 | Data read/write
9 | Data20 | Data21 | Data22 | Data23 | Data read/write
10 | Data24 | Data25 | Data26 | Data27 | Data read/write
11 | Data28 | Data29 | Data30 | Data31 | Data read/write
12 | Data32 | Data33 | Data34 | Data35 | Data read/write
13 | Data36 | Data37 | Data38 | Data39 | Data read/write
14 | Data40 | Data41 | Data42 | Data43 | Data read/write
15 | Data44 | Data45 | Data46 | Data47 | Data read/write

（1） 第0、1页存放着卡的序列号等信息，只可读。依据ISO/IEC14443-3 校验位计算如下：

BCC0=CT⊕SN0⊕SN1⊕SN2

BCC1=SN3⊕SN4⊕SN5⊕SN6

（2） 第2页为LOCK BYTES, 设置字节2和字节3对应的位可以将从第3页到15页单独地锁定为只读区域。

Lock0

L

7

L

6

L

5

L

4

L

OTP

BL

15-10

BL

9-4

BL

OTP

Lock1

L

15

L

14

L

13

L

12

L

11

L

10

L

9

L

8

Lx 锁定X页为只读

BLX 锁定对应的Lx位

² 注意：一旦block-locking(BLX)位被设置为锁定配置，对应的内存区域将被冻结。如：BL15-10 设置为1，则L15到L10再也不能改变。Lock0和Lock1可以通过写命令来设置，写入的内容与当前内容进行位或操作得到新的内容，初始值为0。该过程是不可逆转的。如果有一个位被置为1，就再也不能置为0。

（3） 第3页为OTP，即一次性编程，初始值为0。可以通过写命令来改变它的值，写入的值和当前值进行位或操作得到新的值。这个过程是不可逆转的。如果一个位被置为1，将再也不能置回0。

注意：该内存区域可以用作最大值为32的一次性计数器。

（4） 第4到15页为用户读/写区域，初始值为0。

功能描述

UltraLight卡是一种单程票非接触式IC卡。

1、 卡片指令

reset--->request--->anticoll--->select--->read、write--->halt

2、 函数特别说明

UltraLight卡操作函数同Mifare One，有以下几点需要说明：

u 由于UltraLight卡的序列号为7个字节，所以防冲突函数不能够返回全部的卡片序列号，如要取得全部的卡片序列号请调用rf_get_snr函数，该函数为UltraLight卡专用函数。

u UltraLight卡没有密码，故不需要装载密码，也不存在认证指令。

u Rf_read函数返回16个字节的数据（即4个page），故用户给的缓冲区必须大于16个字节。

u Rf_write函数写入16个字节的数据，实际只有前面4个字节的数据写入指定的地址，其余字节可以补零。

u UltraLight卡不存在增值、减值指令。

u 不支持高级函数。


Mifare 4Kbyte IC卡特性简介

M1卡为4K字节的非接触式IC卡。

电气特性

l 容量为4K字节EEPrOM

l 分为40个扇区，其中32个扇区为4个块，8个扇区为16个块，每块16个字节,以块为存取单位

l 每个扇区有独立的一组密码及访问控制

l 每张卡有唯一序列号，为32位

l 具有防冲突机制，支持多卡操作

l 无电源，自带天线，内含加密控制逻辑和通讯逻辑电路

l 工作温度：-20℃～50℃

l 工作频率：13.56MHZ

l 通信速率：106KBPS

l 读写距离：10mm以内（与读写器有关）

l 数据保存期为10年，可改写10万次，读不限次

存储结构

Mifare 4KByte卡分为40个扇区，第0到31扇区每个扇区4块（块0～3），第32到39扇区每个扇区16块，共256个块。按块号编址为0～255。第0扇区的块0（即绝对地址0块）用于存放厂商代码，已经固化，不可更改。前32个扇区的块0、块1、块2为数据块，用于存贮数据；块3为控制块，存放密码A、存取控制、密码B。后8个扇区的块0到块14为数据块，块15为控制块。控制块的结构如下：

A0A1A2A3A4A5 FF 07 80 69 B0B1B2B3B4B5

密码A(6字节) 存取控制(4字节) 密码B(6字节)

控制属性

每个扇区的密码和存取控制都是独立的，可以根据实际需要设定各自的密码及存取控制。在存取控制中每个块都有相应的三个控制位,定义如下：

块0： C10 C20 C30

块1： C11 C21 C31

块2： C12 C22 C32

块3： C13 C23 C33

三个控制位以正和反两种形式存在于存取控制字节中，决定了该块的访问权限（如进行减值操作必须验证KEY A，进行加值操作必须验证KEY B，等等）。三个控制位在存取控制字节中的位置如下（字节9为备用字节，默认值为0x69）：

 | bit 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0
字节6 | C23_b | C22_b | C21_b | C20_b | C13_b | C12_b | C11_b | C10_b
字节7 | C13 | C12 | C11 | C10 | C33_b | C32_b | C31_b | C30_b
字节8 | C33 | C32 | C31 | C30 | C23 | C22 | C21 | C20

（注： _b表示取反）

其中，黑色区控制块3，蓝色区控制块2，绿色区控制块1，红色区控制块0。

数据块（块0、块1、块2）的存取控制如下：

控制位(X=0..2) |  |  | 访 问 条 件 （对块0、1、2）
C1X | C2X | C3X | Read | Write | Increment | Decrement transfer restore
0 | 0 | 0 | KeyA|B | KeyA|B | KeyA|B | KeyA|B
0 | 1 | 0 | KeyA|B | Never | Never | Never
1 | 0 | 0 | KeyA|B | KeyB | Never | Never
1 | 1 | 0 | KeyA|B | KeyB | KeyB | KeyA|B
0 | 0 | 1 | KeyA|B | Never | Never | KeyA|B
0 | 1 | 1 | KeyB | KeyB | Never | Never
1 | 0 | 1 | KeyB | Never | Never | Never
1 | 1 | 1 | Never | Never | Never | Never

（KeyA|B 表示密码A或密码B，Never表示任何条件下不能实现）

例如：当块0的存取控制位C10 C20 C30=100时，验证密码A或密码B正确后可读；验证密码B正确后可写；不能进行加值、减值操作。

控制块（块3）的存取控制与数据块（块0、1、2）不同，它的存取控制如下：

控制位 |  |  | 密码A |  | 存取控制 |  | 密码B
C13 | C23 | C33 | Read | Write | Read | Write | Read | Write
0 | 0 | 0 | Never | KeyA|B | KeyA|B | Never | KeyA|B | KeyA|B
0 | 1 | 0 | Never | Never | KeyA|B | Never | KeyA|B | Never
1 | 0 | 0 | Never | KeyB | KeyA|B | Never | Never | KeyB
1 | 1 | 0 | Never | Never | KeyA|B | Never | Never | Never
0 | 0 | 1 | Never | KeyA|B | KeyA|B | KeyA|B | KeyA|B | KeyA|B
0 | 1 | 1 | Never | KeyB | KeyA|B | KeyB | Never | KeyB
1 | 0 | 1 | Never | Never | KeyA|B | KeyB | Never | Never
1 | 1 | 1 | Never | Never | KeyA|B | Never | Never | Never

例如：当块3的存取控制位C13 C23 C33=100时，表示：

密码A： 不可读，验证KEYB正确后，可写（更改）。

存取控制：验证KEYA或KEYB正确后，可读不可写。

密码B： 不可读，验证KEYB正确后，可写。

工作原理

卡片的电气部分只由一个天线和 ASIC 组成。

天线：卡片的天线是只有几组绕线的线圈，很适于封装到 IS0 卡片中。

ASIC：卡片的 ASIC 由一个高速（106KB波特率）的 RF 接口，一个控制单元和一个8K位EEPROM组成。

读写器向 M1 卡发一组固定频率的电磁波，卡片内有一个 LC 串联谐振电路，其频率与讯写器发射的频率相同，在电磁波的激励下，LC 谐振电路产生共振，从而使电容内有了电荷，在这个电容的另一端，接有一个单向导通的电子泵，将电容内的电荷送到另一个电容内储存，当所积累的电荷达到 2V 时，此电容可做为电源为其它电路提供工作电压，将卡内数据发射出去或接取读写器的数据。

注意事项：

1) 由于明华公司rf-35读写器只能保存一套16个扇区的密码，所以扇区号大于15扇区的密码必须重新装载，同时调用认证函数rf_authentication_2( )。

例如：

int sector=16,mode=0;

HANDLE icdev;

Unsigned data[17];

rf_authentication_2(icdev, mode, sector%16, sector*4);

rf_read(icdev, sector*4, data);

2) 值操作中数据块的长度为4字节，存储结构如下：

字节号 | 0 1 2 3 | 4 5 6 7 | 8 9 10 11 | 12 | 13 | 14 | 15
描述 | Value | Value_b | Value | Addr | Addr_b | Addr | Addr_b

注（_b：表示取反）


（筹码型）非接触式IC卡性能介绍

一、主要指标

l 容量：不小于512位的EEPROM 存储单元

l 操作距离：不小于6cm

l 工作频率：13.56MHz

l 通讯波特率：106KB波特率

l 半双工通讯方式

l 无防冲突机制

l 可支持Mifare或上海地方三重防伪认证标准

l 灵活的读写权限控制

l 工作温度：－20℃～＋50℃

l 至少100,000次擦写循环

l 至少10年数据保存期

二、筹码的块分区和读写权限

筹码的通用存储器分3个区、16个Block，每个Block包括4个字节。存储结构如表1所示。

块号 | 说明
0 | 筹码标识（2字节客户代码、2字节厂商代码）
1 | 筹码序列号（4字节）
2 | 数据块
3 | 数据块
4 | 数据块
5 | 数据块
6 | 数据块
7 | 数据块
8 | 密码块（4字节）
9 | 数据块
10 | 数据块
11 | 数据块
12 | 数据块
13 | 数据块
14 | 数据块
15 | 数据块

筹码（Token卡）的读写权限如表1所示。

Block Number | 未认证 | 认证后
0~1 | 只可读 | 只可读
2~7 | 只可读 | 可读/可写
8~15 | 不可读/不可写 | 可读/可写

表 2

三、功能描述:

筹码型卡全兼容上海市地方标准《城市轨道交通单程票非接触式集成电路（IC）卡》，

适用于城市轨道交通单程票和各类计费和数据采集系统的应用。

1、卡片指令

i. reset--->request--->anticoll --->read--->halt

ii. ---> authertication--->read、write--->halt

2、特别说明

1) 由于筹码型卡只有一个密码，所以只需要对其中任意一个块认证通过后，即可对其它的块进行读写操作。

2) 装载密码时，由于筹码型卡的密码为4字节，所以后面两个字节必须补0。

3) 选中卡片后，如果执行认证、读操作和写操作的其中任一操作失败，则必须对卡片重新寻卡。

4) 筹码型卡无防冲突功能，调用该函数只是为了返回卡片序列号。如果同时有两张或两张以上卡片，则防冲突失败，不会有序列号返回。

5) 筹码型卡每个块只有4个字节。rf_write函数，写入16字节的数据，实际只有4个字节的数据写入到指定地址，其余的数据可以补0。Rf_read函数返回16字节的数据，即指定地址开始的4个块的数据。

6) 筹码型卡不存在增值和减值命令，所以增值和减值功能必须由写指令来实现。

7) 不支持高级函数。


常见问题

1． 初始化串口失败

可能是（1）串口资源已被占用，例如，程序出错退出时没有释放串口，然后再次初始化串口；同时打开两个程序使用同一个串口；该串口刚被DOS程序使用过。（2） 波特率不对，RF读写器采用自动侦测方式，如果要修改波特率只须断开连接然后重新初始化串口即可，如果不成功，请重新启动读写器。

2． 寻卡总是一次对，一次错。
采用ALL模式寻卡，结束时没有执行rf_halt（）。

3． RF读写器可以对ML操作吗？
对ML卡操作的读写函数和M1卡相同，M1卡的块地址对应ML卡的页地址，但另外提供了ML验证密码函数。

4． 用RF_WRITE()或RF_WRITE_HEX()写M1卡正确,但写ML卡总返回不正确
ML卡虽然只能一次写四个字节，但函数要求必须按M1卡的格式，定义为16字节的长度，不够以'FF'填充。

5． 对于RF-100读写器，只需要寻卡一次，就可以对不同的扇区进行操作，但RF-25读写器，每换一个扇区就必须重新寻卡一次。

6． M1和44R35的区别 M1卡的特性是KEYB可见时，核对无效。
当控制字节为默认值'FF 07 80 69'时，核对KEYB是无效的，改为'7F 07 88 69'时，可用KEYB。

7． 用DES加密后，解密的结果不对。
(1)将加密后的密文以BYTE用传地址方式传递。详见例程。
(2) 密文定义为全局变量，直接传递给解密函数解密。

8． 用PB、VB等编程时，出现"非法程序错误"
可能的原因有二：
(1) 字符串变量在预先分配空间，具体操作请参照例子。 在PB中，以DATA=SPACE（ ）的方式初始化； 在VB中以DIM DATA AS STRING*8方式定义 C中注意加结束符；
(2) 函数申明时请注意变量是用传值/传地址方式

9． RF-20时，因为用的是高级指令，所以只能用0套A密码验证，并不支持三套密码。

10． 高级指令是将低级指令的集成，它已经包括了寻卡、验证密码、及HALT过程。

11． RF-20开发板，无值操作（因为M1卡的数值为四个字节，而ML卡只有两个字节的值，所以M1、ML的值操作（加值、减值等）函数不同，而高级指令没有提供对ML卡的操作。

12． 如何修改密码？
修改密码可用RF_CHANGEB3修改块3的内容,同时也可以用RF_WRITE_HEX()函数来修改块3的内容,它的好处就是可以先写在别的数据块,看内容是否正确,然后才对块3操作，确保写入的内容正确。

13． 如果RF-25LT、RF100-LT接上电源后，数码显示全为8，而没有跳回时钟，那么表示在现有的电压下不能正常工作。

14． 用RF_DISP8时,若不想显示数据,则设0X0F;


int set_host_485(int icdev,unsigned char _Mode);

int set_host_485(unsigned char _Mode);

功 能：设置485或232通信方式

参 数：_Mode：通信方式，=0：RS232方式，=1：RS485方式。

返 回：成功则返回 0

例：设为RS485方式

int st;

unsigned char _Mode=1;

st=set_host_485(_Mode);

if(st)

printf(“set_host_485 error”);

else

printf(“set_host_485 ok.”)

注：如果要使用RS485通信方式，必须首先运行这个函数，否则通信失败。如果没有执行该函数，则使用方法232通讯。