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