package com.co.lane.card.jni;
import java.util.Set;
import com.co.lane.util.ReflectUtil;
import com.co.lane.util.StringUtil;
import com.topsun.posclient.datamodel.VipUser;
/**
* 卡管理类提供对象写入和读取。<br>
* 可以指定对象的属性进行读写。<br>
*
* @author Xuyd
*
*/
public class RFCardManager {
/**
* 卡对象管理
*/
private static RFCardManager self = null;
/**
* 卡对象
*/
private static RFCard rfCard = null;
/**
* 传入对象
*/
private static ReflectUtil refectUtil = ReflectUtil.forClass(VipUser.class);
/**
* 块3的验证密码
*/
// public static final String initPassword = "ffffffffffff";
public static final String initPassword = "FAFAffffff00";
/**
* -0x10:PC与读写器通讯错误
*/
public static final String MSG_16 = "PC与读写器通讯错误";
/**
* -0x11:PC与读写器通讯错误
*/
public static final String MSG_17 = "通讯超时";
/**
* -0x20:PC与读写器通讯错误
*/
public static final String MSG_32 = "打开通信口失败";
/**
* -0x24:串口已被占用
*/
public static final String MSG_36 = "串口已被占用";
/**
* -0x30:地址格式错误
*/
public static final String MSG_48 = "地址格式错误";
/**
* -0x31:该块数据不是值格式
*/
public static final String MSG_49 = "该块数据不是值格式";
/**
* -0x32:长度错误
*/
public static final String MSG_50 = "长度错误";
/**
* -0x40:值操作失败
*/
public static final String MSG_64 = "值操作失败";
/**
* -0x50:长度错误
*/
public static final String MSG_80 = "卡中的值不够减";
static{
System.loadLibrary("RFCard");
}
/**
* private constructor
*/
private RFCardManager() {
rfCard = new RFCard();
}
/**
* signal mode
*
* @return
*/
public static RFCardManager getInstance() {
if (self == null) {
self = new RFCardManager();
}
return self;
}
/**
* 设置卡指定字段数据
*
* @param t 设置数据对象
* @see #writeCardData(T, String)
*
* @return
*/
public <T> void writeCardData(T t) {
this.writeCardData(t, null);
}
/**
* 设置卡指定字段数据
*
* @param t 设置数据对象
* @param k 读取的属性(字段名),如果为null或则空串则读取全部字段
* @see #writeCardData(T)
*
* @return
*/
public <T> void writeCardData(T t, String k) {
int sts = 0;
int cardmode = 1;
int loadmode = 0;
// 连接设备
int icdev = connect();
// 寻卡,失败就终止
long[] cardNo = new long[1];
sts = rfCard.rfCard(icdev, cardmode, cardNo);
if(sts != 0){
// rfCard.rfBeep(icdev, 10);
throw new RFCardException("寻卡失败!请重新放置卡");
}
// 获取存在于卡中的所有字段名
Set<String> keys = CardMemoryFactory.getMapCardMemory().keySet();
int section = 0;
int block = 0;
int bLength = 1;
int address = 0;
String strHex = null;
for (String key : keys) {
// 是否是指定读取对象的字段
if(!StringUtil.isEmpty(k)){
if(key != k){
continue;
}
}
// 获取卡地址
CardMemory cm = CardMemoryFactory.createMemoryLocation(key);
// 获取值
String data32 = StringUtil.toString(refectUtil.getGetMethodValue(t,
key));
section = cm.getSectionNo();
block = cm.getBlockNo();
bLength = cm.getBlockLength();
address = section * 4 + block;
// 不同扇区需再次验证(不考虑密码区当字段长度夸扇区的时候,事实上不会执行验证)
// 装载密码
sts = rfCard.rfLoadKeyHex(icdev, loadmode, section,RFCardManager.initPassword);
if(sts != 0){
// rfCard.rfBeep(icdev, 5);
// rfCard.rfBeep(icdev, 5);
throw new RFCardException("装载密码错误!");
}
// 验证
sts = rfCard.rfAuthentication(icdev, loadmode, section);
if(sts != 0){
// rfCard.rfBeep(icdev, 5);
// rfCard.rfBeep(icdev, 5);
throw new RFCardException("验证密码错误!");
}
// 写入数据
StringUtil.trace("写入" + key + "数据:" + data32);
// 分隔字符串成指定个数,不足返回空字符,保证每一块都被处理到<br>
// 比如name占3块,当前字符长度只占一块,但是2和3块还是要填充空<br>
// 否则在读取的时候,读3块就可能是发生不一致。<br>
String data = null;
String[] arrData = StringUtil.splitByBytelength(data32, bLength);
for (int i = 0; i < arrData.length; i++) {
data = arrData[i];
strHex = StringUtil.String2Hex(data);
sts = rfCard.rfWriteHex(icdev, address, strHex);
// 验证写入数据
sts = rfCard.rfCheckWritehex(icdev, cardNo[0], loadmode, address, strHex);
if (sts == 0) {
StringUtil.trace("写入地址" + address + "(第" + address / 4 + "扇区" + address % 4 + "块)数据:" + strHex);
} else {
// rfCard.rfBeep(icdev, 5);
StringUtil.trace("写入地址" + address + "数据失败!请重试,expection:" + strHex);
}
address++;
}
}
// rfCard.rfBeep(icdev, 20);
// 释放资源
disConnect(icdev);
}
/**
* 读取卡指定字段数据
*
* @param clazzT 读取的对象
* @param k 读取的属性(字段名),如果为null或则空串则读取全部字段
*
* @see #readCardData(Class, String)
* @return 取得的对象
*/
public <T> T readCardData(Class<T> clazzT) {
return readCardData(clazzT, null);
}
/**
* 读取卡指定数据
*
* @param clazzT 读取的对象
* @param k 读取的属性(字段名),如果为null或则空串则读取全部字段
*
* @see #readCardData(Class)
* @return 取得的对象
*/
public <T> T readCardData(Class<T> clazzT, String k) {
T t;
try {
t = clazzT.newInstance();
} catch (Exception e) {
e.printStackTrace();
throw new RFCardException(e.getMessage());
}
int sts = 0;
int cardmode = 1;
int loadmode = 0;
// 连接设备
int icdev = connect();
// 寻卡,失败就终止
long[] cardNo = new long[1];
sts = rfCard.rfCard(icdev, cardmode, cardNo);
if(sts != 0){
rfCard.rfBeep(icdev, 10);
throw new RFCardException("寻卡失败!请重新放置卡");
}
// 获取存在于卡中的所有字段名
Set<String> keys = CardMemoryFactory.getMapCardMemory().keySet();
int section = 0;
int block = 0;
int bLength = 1;
int address = 0;
String strHex = null;
for (String key : keys) {
// 是否是指定读取对象的字段
if(!StringUtil.isEmpty(k)){
if(key != k){
continue;
}
}
// 获取卡地址
CardMemory cm = CardMemoryFactory.createMemoryLocation(key);
section = cm.getSectionNo();
block = cm.getBlockNo();
bLength = cm.getBlockLength();
address = section * 4 + block;
// 装载密码
sts = rfCard.rfLoadKeyHex(icdev, loadmode, section,RFCardManager.initPassword);
if(sts != 0){
rfCard.rfBeep(icdev, 5);
rfCard.rfBeep(icdev, 5);
throw new RFCardException("装载密码错误!");
}
// 验证
sts = rfCard.rfAuthentication(icdev, loadmode, section);
if(sts != 0){
rfCard.rfBeep(icdev, 5);
rfCard.rfBeep(icdev, 5);
throw new RFCardException("验证密码错误!");
}
// 读取指定的所有块
// 比如名称是夸块的
String data32 = "";
String[] dataHex = new String[1];
for (int i = 0; i < bLength; i++) {
// 读取指定地址数据
// strHex = rfCard.rfReadHex(icdev, address);
sts = rfCard.rfReadByteHex(icdev, address, dataHex);
if(sts == 0){
strHex = dataHex[0];
StringUtil.trace("读取地址" + address + "(第" + address / 4 + "扇区" + address % 4 + "块)数据:" + strHex);
data32 += StringUtil.hex2String(strHex);
}else{
rfCard.rfBeep(icdev, 5);
StringUtil.trace("读取地址" + address + "(第" + address / 4 + "扇区" + address % 4 + "块)数据失败!");
}
address++;
}
StringUtil.trace("读取" + key + "数据:" + data32);
// 设置值
refectUtil.setSetMethodValue(t, key, data32);
}
rfCard.rfBeep(icdev, 20);
// 释放资源
disConnect(icdev);
return t;
}
/**
* 设备连接
*
* @return 设备标识号
*/
public int connect() {
// 当串口和USB都连接的时候,USB优先取得
// 想要串口可以连接,必须断开USB口。
int icdev = rfCard.rfInit(0, 115200);
return icdev;
}
/**
* 释放资源
*/
public void disConnect(int icdev) {
// 终止卡操作
rfCard.rfHalt(icdev);
// 释放端口
rfCard.rfExit(icdev);
}
}