T5557卡是美国Atmel公司生产的多功能非接触式射频卡芯片,属于125KHz的低频卡,在国内有广大的应用市场。该芯片共有330bit(比特)的EPROM(分布为10个区块, 每个区块33bit)。0页的块0是被保留用于设置T5557操作模式的参数配置块。第0页第7块可以作用户数据块使用,也可以作为保护全部数据的密码(假如在配置块中启用密码功能的话),防止非法改写数据。 第1页的1、2块保存了出厂商信息及唯一出厂ID,只能读取不可更改,T5567、T5577是T5557的升级版。
本示例使用的发卡器:T5557 T5567 T5577低频RFID读写器 EM4100 HID卡复制器 酒店门卡-淘宝网 (taobao.com)
import com.sun.jna.Library ;
import com.sun.jna.Native;
import com.sun.jna.WString;
interface CLibrary extends Library {
//DLL绝对路径的地址获取,注意要去空格
String filePath = CLibrary.class.getResource("").getPath().replaceFirst("/","").replaceAll("%20"," ")+"OUR_IDR";
CLibrary sdtapi = (CLibrary) Native.loadLibrary(filePath, CLibrary.class);
//动态链接库中的方法
byte idr_beep(int xms); //让设备发出声音
byte pcdgetdevicenumber(byte[] devicenumber); //读取设备编号
String pcdgetdevicenumber_str(); //读取设备编号,输出字符串
byte idr_read(byte[] mypiccserial ); //轻松读ID卡,只要卡在感应区,每次执行此方法都可以读到卡号
byte hid_read(byte[] mypiccserial ); //轻松读ID卡,只要卡在感应区,每次执行此方法都可以读到卡号
String idr_read_8h10d_str(); //读ID卡,输出十位十进制卡号
byte t5557_read(byte ctrlword, byte[] mypiccserial,byte[] oldkey,byte[] blockflag,byte[] blockdata); //读t5557卡,
byte t5557_write(byte ctrlword, byte[] mypiccserial,byte[] oldkey,byte[] blockflag,byte[] blockdata); //写t5557卡,
byte t5557_init(byte ctrlword, byte[] mypiccserial,byte[] oldkey,byte[] configdata,byte[] newkey); //写t5557卡配置值
byte t5557_changekey(byte ctrlword, byte[] mypiccserial,byte[] oldkey,byte[] newkey); //修改t5557卡密钥
}
public class IDReader {
public static final byte NEEDSERIAL=1; //只对指定UID列号的卡操作
public static final byte NEEDKEY=2; //需要用密码认证卡
public static final byte LOCKBIT=4; //锁定配置块或数据块,仅对 t5557_init,t5557_write ,t5557_changekey函数有效
public static final byte KEYENABLE=8; //启用本卡的密码功能
public static final byte RESETCARD=16; //操作成功后重启卡片
public static void main(String[] args) {
System.setProperty("jna.encoding", "GBK");
String filePath = CLibrary.class.getResource("").getPath().replaceFirst("/", "").replaceAll("%20", " ") + "OUR_IDR.DLL";
System.out.println("本示例引用的DLL文件:" + filePath);
if (args.length == 0) {
System.out.println("\n请先输入运行参数!");
System.out.println("\n参数 0:驱动读卡器嘀一声");
System.out.println("\n参数 1:读取设备编号");
System.out.println("\n参数 2:读取设备编号,输出字符串");
System.out.println("\n参数 3:轻松读ID卡");
System.out.println("\n参数 4:轻松读HID卡");
System.out.println("\n参数 5:轻松读ID卡,输出十位十进制卡号");
System.out.println("\n参数 6:读T5557卡");
System.out.println("\n参数 7:写T5557卡");
System.out.println("\n参数 8:写T5557卡配置值");
System.out.println("\n参数 9:修改T5557卡密钥");
return;
}
//Java中只能使用string1.equals(string2)的方式来比较字符串
if (args[0].equals("0")) { //驱动读卡器发嘀一声
System.out.print("\n0-驱动读卡器嘀一声\n");
CLibrary.sdtapi.idr_beep(50);
System.out.print("结果:如果能听到读卡器嘀一声表示成功,否则请检查读卡器是否已连上线!\n\n");
} else if (args[0].equals("1")) //读取设备编号,可做为软件加密狗用,也可以根据此编号在公司网站上查询保修期限
{
int status; //存放返回值
byte[] devicenumber = new byte[4]; //4字节设备编号
System.out.print("\n1-读取设备编号\n");
status = (int) (CLibrary.sdtapi.pcdgetdevicenumber(devicenumber) & 0xff);//& 0xff用于转为无符号行数据
System.out.print("结果:");
if (status == 0) {
CLibrary.sdtapi.idr_beep(38);
System.out.print("读取成功!设备编号为:" + (devicenumber[0] & 0xff) + "-" + (devicenumber[1] & 0xff) + "-" + (devicenumber[2] & 0xff) + "-" + (devicenumber[3] & 0xff));
} else {
PrintErrInf(status); //错误代码提示
}
}else if (args[0].equals("2")) //读取设备编号,直接输出字符串
{
System.out.print("\n2-读取设备编号\n");
String statustr = CLibrary.sdtapi.pcdgetdevicenumber_str().trim(); //设备编号
if(statustr.length()==10) {
CLibrary.sdtapi.idr_beep(38);
System.out.print("读取成功!设备编号为:" + statustr + "\n");
}else{
PrintErrStr(statustr); //错误字符串代码提示
}
}else if (args[0].equals("3")) //轻松读ID卡
{
int status; //存放返回值
byte[] mypiccserial = new byte[5]; //5字节卡序列号
System.out.print("\n3-轻松读卡\n");
status = (int) (CLibrary.sdtapi.idr_read(mypiccserial ) & 0xff); //只要卡在感应区,每次执行此方法都可以读到卡号
System.out.print("结果:");
if (status == 0) {
CLibrary.sdtapi.idr_beep(38);
String serialnumber = "";
for (int i = 0; i < 5; i++) {
String bytestr = "00" + Integer.toHexString(mypiccserial[i] & 0xff);
serialnumber = serialnumber + bytestr.substring(bytestr.length() - 2, bytestr.length());
}
System.out.print("读取成功!16进制卡序列号为:" + serialnumber+"\n");
long cardnum;
cardnum=mypiccserial[4] & 0xff;
cardnum=cardnum+(mypiccserial[3] & 0xff) *256;
cardnum=cardnum+(mypiccserial[2] & 0xff) *65536;
cardnum=cardnum+(mypiccserial[1] & 0xff) *16777216;
long cardno10 = 0;
for (int j=28; j>=0; j-=4) {
cardno10 = cardno10<<4 | (cardnum>>>j & 0xF);
}
System.out.print("换算成10进制卡号:"+String.format("%010d", cardno10)+"\n");
} else {
PrintErrInf(status); //错误代码提示
}
}else if (args[0].equals("4")) //轻松读HID卡
{
int status; //存放返回值
byte[] mypiccserial = new byte[7]; //7字节卡序列号
System.out.print("\n4-轻松读HID卡\n");
status = (int) (CLibrary.sdtapi.hid_read(mypiccserial ) & 0xff);
System.out.print("结果:");
if (status == 0) {
CLibrary.sdtapi.idr_beep(38);
String serialnumber = "";
for (int i = 0; i < 7; i++) {
String bytestr = "00" + Integer.toHexString(mypiccserial[i] & 0xff);
serialnumber = serialnumber + bytestr.substring(bytestr.length() - 2, bytestr.length());
}
System.out.print("读取成功!16进制卡序列号为:" + serialnumber+"\n");
long cardnum;
cardnum=mypiccserial[6] & 0xff;
cardnum=cardnum+(mypiccserial[5] & 0xff) *256;
cardnum=cardnum+(mypiccserial[4] & 0xff) *65536;
cardnum=cardnum+(mypiccserial[3] & 0xff) *16777216;
long cardno10 = 0;
for (int j=28; j>=0; j-=4) {
cardno10 = cardno10<<4 | (cardnum>>>j & 0xF);
}
System.out.print("换算成8H10D卡号:"+String.format("%010d", cardno10)+"\n");
} else {
PrintErrInf(status); //错误代码提示
}
}else if (args[0].equals("5")) //读ID卡,输出十位十进制卡号
{
System.out.print("\n5-读10进制ID卡号\n");
String statustr = CLibrary.sdtapi.idr_read_8h10d_str().trim(); //只要卡在感应区,每次执行此方法都可以读到卡号
if(statustr.length()==10) {
CLibrary.sdtapi.idr_beep(38);
System.out.print("读卡成功!8H10D卡号为:" + statustr + "\n");
}else{
PrintErrStr(statustr); //错误字符串代码提示
}
}else if (args[0].equals("6")) //读T5557卡
{
System.out.print("\n6-读t5557卡\n");
byte status; //存放返回值
byte myctrlword=0; //控制字
byte[] oldpicckey=new byte[4]; //认证密钥
byte[] mypiccserial=new byte[6]; //卡UID序列号
byte[] mypiccdata=new byte[100]; //读卡数据缓冲:卡无线转输分频比、卡内容长度(字节数),及最多返回12个块的数据
byte[] mypiccblockflag=new byte[2]; //指定本次操作的块
boolean withkey=false; //是否要认证卡密钥
boolean thiscarduit =false; //是否只操作指定UID序号的卡
if (withkey){ //本次操作需要密码验证,将认证密钥加入oldpicckey
myctrlword=(byte)(myctrlword+NEEDKEY);
String Keyhexstr="12345678"; //认证密钥
for(int i=0;i<4;i++){
oldpicckey[i]=(byte)Integer.parseInt(Keyhexstr.substring(i*2,(i+1)*2),16);
}
}
if(thiscarduit){ //本次只操作指定UID号的卡,mypiccserial
myctrlword=(byte)(myctrlword+NEEDSERIAL);
String Uidhexstr="000000000000"; //卡片uid
for(int i=0;i<6;i++){
mypiccserial[i]=(byte)Integer.parseInt(Uidhexstr.substring(i*2,(i+1)*2),16);
}
}
String Seleblockstr0="11111111"; //第0页每块选取状态,从左到右依次表示第7、6、5、4、3、2、1、0块是否要操作,取1表示该块要读,取0表示该块不读,如要读0、1、3 块取值为 00001011,读第0页全部块为 11111111
String Seleblockstr1="11110"; //第1页每块选取状态,从左到右依次表示第3、2、1、0块是否要操作,取1表示该块要读,取0表示该块不读,该页总计4块,最右边表示页选取值0
mypiccblockflag[0]=(byte)Integer.parseInt(Seleblockstr0,2);
mypiccblockflag[1]=(byte)Integer.parseInt(Seleblockstr1,2);
status = CLibrary.sdtapi.t5557_read(myctrlword,mypiccserial,oldpicckey,mypiccblockflag,mypiccdata);
if(status == 0) {
CLibrary.sdtapi.idr_beep(38);
String cardnohex="";
for (int i=0;i<6;i++){
String bytestr = "00" + Integer.toHexString(mypiccserial[i] & 0xff);
cardnohex = cardnohex + bytestr.substring(bytestr.length() - 2, bytestr.length()) ;
}
System.out.print("读卡成功,16进制卡序列号:"+cardnohex+"\n");
System.out.print("卡无线转输分频比:"+Integer.toString(mypiccdata[0])+"\n");
if(mypiccdata[1]>0) {
String blockdata = "块内数据:";
for (int i = 0; i < mypiccdata[1]; i++) {
String bytestr = "00" + Integer.toHexString(mypiccdata[2 + i] & 0xff);
blockdata = blockdata + bytestr.substring(bytestr.length() - 2, bytestr.length()) + " ";
}
System.out.print(blockdata+"\n");
}
}else {
PrintErrInf(status); //错误代码提示
}
}else if (args[0].equals("7")) //写T5557卡
{
System.out.print("\n7-写t5557卡块\n");
byte status; //存放返回值
byte myctrlword=0; //控制字
byte[] oldpicckey=new byte[4]; //认证密钥
byte[] mypiccserial=new byte[6]; //卡UID序列号
byte[] mypiccdata=new byte[50]; //读卡数据缓冲:卡无线转输分频比、卡内容长度(字节数),及最多返回12个块的数据
byte[] mypiccblockflag=new byte[2]; //指定本次操作的块
boolean withkey=false; //是否要认证卡密钥
boolean thiscarduit =false; //是否只操作指定UID序号的卡
if (withkey){ //本次操作需要密码验证,将认证密钥加入oldpicckey
myctrlword=(byte)(myctrlword+NEEDKEY);
String Keyhexstr="12345678"; //认证密钥
for(int i=0;i<4;i++){
oldpicckey[i]=(byte)Integer.parseInt(Keyhexstr.substring(i*2,(i+1)*2),16);
}
}
if(thiscarduit){ //本次只操作指定UID号的卡,mypiccserial
myctrlword=(byte)(myctrlword+NEEDSERIAL);
String Uidhexstr="000000000000"; //卡片uid
for(int i=0;i<6;i++){
mypiccserial[i]=(byte)Integer.parseInt(Uidhexstr.substring(i*2,(i+1)*2),16);
}
}
String Seleblockstr0="11111110"; //第0页每块选取状态,从左到右依次表示第7、6、5、4、3、2、1、0块是否要操作,取1表示该块要写,取0表示该块不写,如要写1、3 块取值为 00001010,第0块是配置块不能用此功能写入,如开启了密码功能,第7块为密码块也不能用此功能写
String Seleblockstr1="00000"; //第1页每块选取状态,此页只读不可写,
mypiccblockflag[0]=(byte)Integer.parseInt(Seleblockstr0,2);
mypiccblockflag[1]=(byte)Integer.parseInt(Seleblockstr1,2);
String writedatahex="11111111222222223333333344444444555555556666666677777777"; //写入的数据,实际写入数据的块 由mypiccblockflag值决定
for (int i=0;i<28;i++){
mypiccdata[i]=(byte)Integer.parseInt(writedatahex.substring(i*2,(i+1)*2),16);
}
status = CLibrary.sdtapi.t5557_write(myctrlword,mypiccserial,oldpicckey,mypiccblockflag,mypiccdata);
if(status == 0) {
CLibrary.sdtapi.idr_beep(38);
String cardnohex = "";
for (int i = 0; i < 6; i++) {
String bytestr = "00" + Integer.toHexString(mypiccserial[i] & 0xff);
cardnohex = cardnohex + bytestr.substring(bytestr.length() - 2, bytestr.length());
}
System.out.print("写卡成功,16进制卡序列号:" + cardnohex + "\n");
}else {
PrintErrInf(status); //错误代码提示
}
}else if (args[0].equals("8")) //写T5557卡配置块
{
System.out.print("\n8-写t5557卡配置块\n");
byte status; //存放返回值
byte myctrlword=0; //控制字
byte[] oldpicckey=new byte[4]; //认证密钥
byte[] newpicckey=new byte[4]; //卡片新密钥
byte[] mypiccserial=new byte[6]; //卡UID序列号
byte[] configdata=new byte[4]; //配置值
boolean withkey=false; //是否要认证卡密钥
boolean newkeyEn=false; //是否要开启卡片密钥功能
if (withkey){ //本次操作需要密码验证,将认证密钥加入oldpicckey
myctrlword=(byte)(myctrlword+NEEDKEY);
String oldKeyhexstr="12345678"; //认证密钥
for(int i=0;i<4;i++){
oldpicckey[i]=(byte)Integer.parseInt(oldKeyhexstr.substring(i*2,(i+1)*2),16);
}
}
String configdatahex="00088028"; //卡片出厂默认配置值,不同功能配置值不一样,请查询相关资料
if (newkeyEn){ //卡片启用密钥保护功能
myctrlword=(byte)(myctrlword+KEYENABLE);
configdatahex="00088038"; //开启密钥配置值,不同功能配置值不一样,请查询相关资料
String newKeyhexstr="12345678"; //新密钥
for(int i=0;i<4;i++){
newpicckey[i]=(byte)Integer.parseInt(newKeyhexstr.substring(i*2,(i+1)*2),16);
}
}
for (int i=0;i<4;i++){
configdata[i]=(byte)Integer.parseInt(configdatahex.substring(i*2,(i+1)*2),16);
}
status = CLibrary.sdtapi.t5557_init(myctrlword,mypiccserial,oldpicckey,configdata,newpicckey);
if(status == 0) {
CLibrary.sdtapi.idr_beep(38);
String cardnohex = "";
for (int i = 0; i < 6; i++) {
String bytestr = "00" + Integer.toHexString(mypiccserial[i] & 0xff);
cardnohex = cardnohex + bytestr.substring(bytestr.length() - 2, bytestr.length());
}
System.out.print("写配置块成功,16进制卡序列号:" + cardnohex + "\n");
}else {
PrintErrInf(status); //错误代码提示
}
}else if (args[0].equals("9")) //修改T5557卡密钥
{
System.out.print("\n9-修改T5557卡密钥\n");
byte status; //存放返回值
byte myctrlword=0; //控制字
byte[] oldpicckey=new byte[4]; //认证密钥
byte[] newpicckey=new byte[4]; //卡片新密钥
byte[] mypiccserial=new byte[6]; //卡UID序列号
boolean withkey=true; //是否要认证卡密钥
boolean thiscarduit =false; //是否只操作指定卡号的卡
if (withkey){ //本次操作需要密码验证,将认证密钥加入oldpicckey
myctrlword=(byte)(myctrlword+NEEDKEY);
String oldKeyhexstr="12345678"; //认证密钥
for(int i=0;i<4;i++){
oldpicckey[i]=(byte)Integer.parseInt(oldKeyhexstr.substring(i*2,(i+1)*2),16);
}
}
if(thiscarduit){ //本次只操作指定UID号的卡,mypiccserial
myctrlword=(byte)(myctrlword+NEEDSERIAL);
String Uidhexstr="000000000000"; //卡片uid
for(int i=0;i<6;i++){
mypiccserial[i]=(byte)Integer.parseInt(Uidhexstr.substring(i*2,(i+1)*2),16);
}
}
String newKeyhexstr="12345678"; //新密钥
for(int i=0;i<4;i++){
newpicckey[i]=(byte)Integer.parseInt(newKeyhexstr.substring(i*2,(i+1)*2),16);
}
status = CLibrary.sdtapi.t5557_changekey(myctrlword,mypiccserial,oldpicckey,newpicckey);
if(status == 0) {
CLibrary.sdtapi.idr_beep(38);
String cardnohex = "";
for (int i = 0; i < 6; i++) {
String bytestr = "00" + Integer.toHexString(mypiccserial[i] & 0xff);
cardnohex = cardnohex + bytestr.substring(bytestr.length() - 2, bytestr.length());
}
System.out.print("修改卡密钥成功,16进制卡序列号:" + cardnohex + "\n");
}else {
PrintErrInf(status); //错误代码提示
}
}
}
//----------------------------------------------------------------------------------错误字符串代码提示
static void PrintErrStr(String Errstr){
if(Errstr.equals("ER08")){
System.out.print("错误代码:ER08,未寻到卡,请重新拿开卡后再放到感应区!\n");
} else if(Errstr.equals("ER22")){
System.out.print("错误代码:ER22,动态库或驱动程序异常!\n");
} else if(Errstr.equals("ER23")){
System.out.print("错误代码:ER23,驱动程序错误或尚未安装!\n");
} else if(Errstr.equals("ER24")){
System.out.print("错误代码:ER24,操作超时,一般是动态库没有反映!\n");
}else {
System.out.print("错误代码:"+Errstr);
}
}
//----------------------------------------------------------------------------------错误代码提示
static void PrintErrInf(int errcode) {
switch(errcode){
case 1:
System.out.print("错误代码:1,写入配置的值不正确,请重新写入!\n");
break;
case 2:
System.out.print("错误代码:2,本卡尚未开启密码功能,函数myctrlword中无需加入NEEDKEY!\n");
break;
case 3:
System.out.print("错误代码:3,需要密码才能读卡,函数myctrlword要加入NEEDKEY!\n");
break;
case 5:
System.out.print("错误代码:5,密码错误!\n");
break;
case 8:
System.out.print("错误代码:8,未寻到卡,请重新拿开卡后再放到感应区!\n");
break;
case 21:
System.out.print("错误代码:21,没有动态库!\n");
break;
case 22:
System.out.print("错误代码:22,动态库或驱动程序异常!\n");
break;
case 23:
System.out.print("错误代码:23,驱动程序错误或尚未安装!\n");
break;
case 24:
System.out.print("错误代码:24,操作超时,一般是动态库没有反映!\n");
break;
case 25:
System.out.print("错误代码:25,发送字数不够!\n");
break;
case 26:
System.out.print("错误代码:26,发送的CRC错!\n");
break;
case 27:
System.out.print("错误代码:27,接收的字数不够!\n");
break;
case 28:
System.out.print("错误代码:28,接收的CRC错!\n");
break;
default:
System.out.print("未知错误,错误代码:"+Integer.toString(errcode)+"\n");
break;
}
}
}