package com.mq.mylibrary.rfid.io.translate;

import com.fntech.RInt;
import com.mq.mylibrary.rfid.io.cmd.TXFRAME;
import com.mq.mylibrary.rfid.io.translate.frame.ApduFrame;
import com.mq.mylibrary.rfid.io.util.ByteUtils;

public class Fmcos {

	private final int APDU_RESP_OK = 0x9000;
	private final int FMRESP_ERROR = 0x6281;
	private final int FMRESP_FILE_ERROR = 0x6283;
	private final int FMRESP_KEY_ERROR0 = 0x63C0;
	private final int FMRESP_KEY_ERROR1 = 0x63CF;
	private final int FMRESP_STATUS_FLAG = 0x6400;
	private final int FMRESP_EEPROM_ERROR = 0x6581;
	private final int FMRESP_LEN_ERROR = 0x6700;
	private final int FMRESP_CLA_ERROR = 0x6900;
	private final int FMRESP_STATUS_ERROR = 0x6901;
	private final int FMRESP_CMD_ERROR = 0x6981;
	private final int FMRESP_SECURITY_ERROR = 0x6982;
	private final int FMRESP_KEYLOCK_ERROR = 0x6983;
	private final int FMRESP_CONDITION_ERROR = 0x6985;
	private final int FMRESP_NOSECURITYMSG_ERROR = 0x6987;
	private final int FMRESP_SECURITYMSG_ERROR = 0x6988;
	private final int FMRESP_DATAPARAM_ERROR = 0x6A80;
	private final int FMRESP_FUNC_ERROR = 0x6A81;
	private final int FMRESP_FILENOTFIND_ERROR = 0x6A82;
	private final int FMRESP_RECORDNOTFIND_ERROR = 0x6A83;
	private final int FMRESP_FILENOSPACE_ERROR = 0x6A84;
	private final int FMRESP_P1P2PARAM_ERROR = 0x6A86;
	private final int FMRESP_KEYNOTFIND_ERROR = 0x6A88;
	private final int FMRESP_OFFSET_ERROR = 0x6B00;
	private final int FMRESP_LE_ERROR0 = 0x6C00;
	private final int FMRESP_LE_ERROR1 = 0x6CFF;
	private final int FMRESP_CLA_INVALID = 0x6E00;
	private final int FMRESP_DATA_INVALID = 0x6F00;
	private final int FMRESP_MAC_ERROR = 0x9302;
	private final int FMRESP_APPLOCK_ERROR = 0x9303;
	private final int FMRESP_NOMONEY_ERROR = 0x9401;
	private final int FMRESP_NOKEY_ERROR = 0x9403;
	private final int FMRESP_NOUSEMAC_ERROR = 0x9406;

	// 记录偏移含义
	private byte FM_RECORD_CUR = (byte) 0x04;
	private byte FM_RECORD_FIRST = (byte) 0x00;
	private byte FM_RECORD_LAST = (byte) 0x01;
	private byte FM_RECORD_NEXT = (byte) 0x02;
	private byte FM_RECORD_PREV = (byte) 0x03;

	private String FMRESP_OK_MSG = "正确执行";
	private String FMRESP_ERROR_MSG = "回送的数据可能有错误";
	private String FMRESP_FILE_ERROR_MSG = "选择文件无效，文件或密钥校验错误";
	private String FMRESP_KEY_ERROR_MSG = "认证失败";
	private String FMRESP_STATUS_FLAG_MSG = "状态标志未改变";
	private String FMRESP_EEPROM_ERROR_MSG = "写EEPROM不成功";
	private String FMRESP_LEN_ERROR_MSG = "错误的长度";
	private String FMRESP_CLA_ERROR_MSG = "CLA与线路保护要求不匹配";
	private String FMRESP_STATUS_ERROR_MSG = "无效的状态";
	private String FMRESP_CMD_ERROR_MSG = "命令与文件结构不相容";
	private String FMRESP_SECURITY_ERROR_MSG = "不满足安全状态";
	private String FMRESP_KEYLOCK_ERROR_MSG = "密钥被锁死";
	private String FMRESP_CONDITION_ERROR_MSG = "使用条件不满足";
	private String FMRESP_NOSECURITYMSG_ERROR_MSG = "无安全报文";
	private String FMRESP_SECURITYMSG_ERROR_MSG = "安全报文数据项不正确";
	private String FMRESP_DATAPARAM_ERROR_MSG = "数据域参数错误";
	private String FMRESP_FUNC_ERROR_MSG = "功能不支持或卡无MF或卡片已锁定";
	private String FMRESP_FILENOTFIND_ERROR_MSG = "文件未找到";
	private String FMRESP_RECORDNOTFIND_ERROR_MSG = "记录未找到";
	private String FMRESP_FILENOSPACE_ERROR_MSG = "文件无足够空间";
	private String FMRESP_P1P2PARAM_ERROR_MSG = "参数P1P2错误";
	private String FMRESP_KEYNOTFIND_ERROR_MSG = "密钥未找到";
	private String FMRESP_OFFSET_ERROR_MSG = "在达到Le/Lc字节之前文件结束，偏移量错误";
	private String FMRESP_LE_ERROR_MSG = "Le错误";
	private String FMRESP_CLA_INVALID_MSG = "无效的CLA";
	private String FMRESP_DATA_INVALID_MSG = "数据无效";
	private String FMRESP_MAC_ERROR_MSG = "MAC错误";
	private String FMRESP_APPLOCK_ERROR_MSG = "应用已被锁定";
	private String FMRESP_NOMONEY_ERROR_MSG = "金额不足";
	private String FMRESP_NOKEY_ERROR_MSG = "密钥未找到";
	private String FMRESP_NOUSEMAC_ERROR_MSG = "所需的MAC不可用";

	private String FMRESP_UNKNOWN_ERROR_MSG = "未知错误";

	/*************************************************************************/
	public boolean is_status_word(byte sw1, byte sw2) {
		if (((sw1 & 0xF0) == 0x60) || ((sw1 & 0xF0) == 0x90)) {
			return true;
		}

		return false;
	}

	public static boolean is_des(byte mac_type) {
		return (mac_type == ISO1443Constant.FM_DES_8
				|| mac_type == ISO1443Constant.FM_DES_16
				|| mac_type == ISO1443Constant.FM_MACDES_8 || mac_type == ISO1443Constant.FM_MACDES_16);
	}

	public String fm_resp_errmsg(int error) {
		switch (error) {
		case APDU_RESP_OK:
			return FMRESP_OK_MSG;
		case FMRESP_ERROR:
			return FMRESP_ERROR_MSG;
		case FMRESP_FILE_ERROR:
			return FMRESP_FILE_ERROR_MSG;
		case FMRESP_STATUS_FLAG:
			return FMRESP_STATUS_FLAG_MSG;
		case FMRESP_EEPROM_ERROR:
			return FMRESP_EEPROM_ERROR_MSG;
		case FMRESP_LEN_ERROR:
			return FMRESP_LEN_ERROR_MSG;
		case FMRESP_CLA_ERROR:
			return FMRESP_CLA_ERROR_MSG;
		case FMRESP_STATUS_ERROR:
			return FMRESP_STATUS_ERROR_MSG;
		case FMRESP_CMD_ERROR:
			return FMRESP_CMD_ERROR_MSG;
		case FMRESP_SECURITY_ERROR:
			return FMRESP_SECURITY_ERROR_MSG;
		case FMRESP_KEYLOCK_ERROR:
			return FMRESP_KEYLOCK_ERROR_MSG;
		case FMRESP_CONDITION_ERROR:
			return FMRESP_CONDITION_ERROR_MSG;
		case FMRESP_NOSECURITYMSG_ERROR:
			return FMRESP_NOSECURITYMSG_ERROR_MSG;
		case FMRESP_SECURITYMSG_ERROR:
			return FMRESP_SECURITYMSG_ERROR_MSG;
		case FMRESP_DATAPARAM_ERROR:
			return FMRESP_DATAPARAM_ERROR_MSG;
		case FMRESP_FUNC_ERROR:
			return FMRESP_FUNC_ERROR_MSG;
		case FMRESP_FILENOTFIND_ERROR:
			return FMRESP_FILENOTFIND_ERROR_MSG;
		case FMRESP_RECORDNOTFIND_ERROR:
			return FMRESP_RECORDNOTFIND_ERROR_MSG;
		case FMRESP_FILENOSPACE_ERROR:
			return FMRESP_FILENOSPACE_ERROR_MSG;
		case FMRESP_P1P2PARAM_ERROR:
			return FMRESP_P1P2PARAM_ERROR_MSG;

		case FMRESP_KEYNOTFIND_ERROR:
			return FMRESP_KEYNOTFIND_ERROR_MSG;
		case FMRESP_OFFSET_ERROR:
			return FMRESP_OFFSET_ERROR_MSG;
		case FMRESP_CLA_INVALID:
			return FMRESP_CLA_INVALID_MSG;
		case FMRESP_DATA_INVALID:
			return FMRESP_DATA_INVALID_MSG;
		case FMRESP_MAC_ERROR:
			return FMRESP_MAC_ERROR_MSG;

		case FMRESP_APPLOCK_ERROR:
			return FMRESP_APPLOCK_ERROR_MSG;
		case FMRESP_NOMONEY_ERROR:
			return FMRESP_NOMONEY_ERROR_MSG;
		case FMRESP_NOKEY_ERROR:
			return FMRESP_NOKEY_ERROR_MSG;
		case FMRESP_NOUSEMAC_ERROR:
			return FMRESP_NOUSEMAC_ERROR_MSG;
		}

		if (error <= FMRESP_KEY_ERROR1 && error >= FMRESP_KEY_ERROR0) {
			return FMRESP_KEY_ERROR_MSG;
		} else if (error <= FMRESP_LE_ERROR1 && error >= FMRESP_LE_ERROR0) {
			return FMRESP_LE_ERROR_MSG;
		}

		return FMRESP_UNKNOWN_ERROR_MSG;
	}

	public static int fm_parse_frame_with_mac(TXFRAME frame, byte[] buf,
											  byte len, byte mac_type, byte[] mac_key) {
		int result = -1;
		byte[] data = new byte[TXFRAME.TX_BUF_LEN];
		byte data_len = 0;
		byte i = 0;

		if (Apdu.is_mac_none(mac_type))
			return TxApdu.tx_apdu_parse_frame(frame, buf, len);

		result = TxApdu.tx_apdu_parse_frame_status(frame);
		if (result != 0)
			return result;

		data_len = (byte) ((byte) frame.rx_len - 2);
		if (Apdu.is_mac(mac_type))
			data_len -= ISO1443Constant.ISO14443A_MAC_LEN;

		if (is_des(mac_type)) {
			for (i = 0; i < data_len / 8; i++) {
				Apdu.fm_des(ByteUtils.cutByte(frame.rx_data, i * 8), mac_key,
						(byte) Apdu.get_key_len(mac_type),
						ByteUtils.cutByte(data, i * 8));
			}

			len = data[0];
			// memcpy(buf, data[1], len);
			System.arraycopy(data, 1, buf, 0, len);
		} else {
			len = data_len;
			// memcpy(buf, frame.rx_data, len);
			System.arraycopy(frame.rx_data, 0, buf, 0, len);
		}

		return 0;
	}

	public static int fm_parse_frame_with_mac2(TXFRAME frame, byte[] buf,
                                               RInt len, byte mac_type, byte[] mac_key) {
		int result = -1;
		byte[] data = new byte[TXFRAME.TX_BUF_LEN];
		byte data_len = 0;
		byte i = 0;

		if (Apdu.is_mac_none(mac_type))
			return TxApdu.tx_apdu_parse_frame2(frame, buf, len);

		result = TxApdu.tx_apdu_parse_frame_status(frame);
		if (result != 0)
			return result;

		data_len = (byte) ((byte) frame.rx_len - 2);
		if (Apdu.is_mac(mac_type))
			data_len -= ISO1443Constant.ISO14443A_MAC_LEN;

		if (is_des(mac_type)) {
			for (i = 0; i < data_len / 8; i++) {
				Apdu.fm_des(ByteUtils.cutByte(frame.rx_data, i * 8), mac_key,
						(byte) Apdu.get_key_len(mac_type),
						ByteUtils.cutByte(data, i * 8));
			}

			len.len = data[0];
			// memcpy(buf, data[1], len);
			System.arraycopy(data, 1, buf, 0, len.len);
		} else {
			len.len = data_len;
			// memcpy(buf, frame.rx_data, len);
			System.arraycopy(frame.rx_data, 0, buf, 0, len.len);
		}

		return 0;
	}
	
	public int fm_parse_apdu_with_mac(ApduFrame aFrame, byte[] buf, byte len,
									  byte mac_type, byte[] mac_key) {
		int result = -1;
		byte[] data = new byte[TXFRAME.TX_BUF_LEN];
		byte data_len = 0;
		byte i = 0;

		if (Apdu.is_mac_none(mac_type))
			return Apdu.apdu_parse_data(aFrame, buf, len);

		result = Apdu.apdu_parse_status(aFrame);
		if (result != 0)
			return result;

		data_len = (byte) aFrame.Le;
		;
		if (Apdu.is_mac(mac_type))
			data_len -= ISO1443Constant.ISO14443A_MAC_LEN;

		if (is_des(mac_type)) {
			for (i = 0; i < data_len / 8; i++) {
				Apdu.fm_des(ByteUtils.cutByte(aFrame.DATA, i * 8), mac_key,
						(byte) Apdu.get_key_len(mac_type),
						ByteUtils.cutByte(data, i * 8));
			}

			len = data[0];
			// memcpy(buf, data[1], len);
			System.arraycopy(buf, 0, data, 1, len);
		} else {
			len = data_len;
			// memcpy(buf, aFrame.DATA, len);
			System.arraycopy(buf, 0, aFrame.DATA, 0, len);
		}

		return 0;
	}

	/*************************************************************************/
	public void fm_init_trans_cmd(ApduFrame aFrame, byte[] buf) {
		aFrame.CLA = buf[0];
		aFrame.INS = buf[1];
		aFrame.P1 = buf[2];
		aFrame.P2 = buf[3];
		switch (aFrame.INS) {
		case 0x0E:
			aFrame.Lc = 0x00;
			aFrame.Le = (byte) 0xFF;
			break;
		case 0x18:
			aFrame.Lc = (byte) 0xFF;
			aFrame.Le = (byte) 0xFF;
			break;
		case (byte) 0xC0:
		case (byte) 0x84:
		case (byte) 0xB0:
		case (byte) 0xB2:
			aFrame.Lc = (byte) 0xFF;
			aFrame.Le = buf[4];
			break;
		case (byte) 0xA4:
			aFrame.Lc = buf[4];
			// memcpy(aFrame.DATA, buf + 5, aFrame.Lc);
			System.arraycopy(aFrame.DATA, 0, buf, 5, aFrame.Lc);
			aFrame.Le = 0x00;
			break;
		case 0x70:
			aFrame.Lc = buf[4];
			// memcpy(aFrame.DATA, buf + 5, aFrame.Lc);
			System.arraycopy(aFrame.DATA, 0, buf, 5, aFrame.Lc);
			// req->Le = *(buf + 5 + req->Lc);
			aFrame.Le = 0x00;
			break;
		case (byte) 0xE0:
		case (byte) 0xD4:
		case (byte) 0xD6:
		case (byte) 0xDC:
		case (byte) 0xE2:
		case 0x1A:
		case (byte) 0xFA:
		case 0x72:
		default:
			aFrame.Lc = buf[4];
			// memcpy(aFrame.DATA, buf + 5, aFrame.Lc);
			System.arraycopy(aFrame.DATA, 0, buf, 5, aFrame.Lc);
			aFrame.Le = (byte) 0xFF;
			break;
		}
	}

	public void fm_init_get_reponse(ApduFrame aFrame, byte len) {
		aFrame.CLA = 0x00;
		aFrame.INS = (byte) 0xC0;
		aFrame.P1 = 0x00;
		aFrame.P2 = 0x00;
		aFrame.Lc = (byte) 0xFF;
		aFrame.Le = len;
	}

	public static void fm_init_erase_df(ApduFrame aFrame) {
		aFrame.CLA = (byte) 0x80;
		aFrame.INS = 0x0E;
		aFrame.P1 = 0x00;
		aFrame.P2 = 0x00;
		aFrame.Lc = 0x00;
		aFrame.Le = (byte) 0xFF;
	}

	public static void fm_make_erase_df(TXFRAME frame) {
		ApduFrame aFrame = new ApduFrame();

		fm_init_erase_df(aFrame);

		TxApdu.tx_apdu_to_frame(frame, aFrame);
	}

	public static void fm_init_create_file(ApduFrame aFrame, byte[] file_id,
			byte[] buf, byte len) {
		aFrame.CLA = (byte) 0x80;
		aFrame.INS = (byte) 0xE0;
		aFrame.P1 = file_id[0];// (byte) ((file_id>>8) & 0xFF);
		aFrame.P2 = file_id[1];// (byte) file_id;
		aFrame.Lc = len;
		// memcpy(aFrame.DATA, buf, len);
		System.arraycopy(buf, 0, aFrame.DATA, 0, len);
		aFrame.Le = (byte) 0xFF;
	}

	public static void fm_make_create_file(TXFRAME frame, byte[] file_id,
			byte[] buf, byte len) {
		ApduFrame aFrame = new ApduFrame();

		fm_init_create_file(aFrame, file_id, buf, len);

		TxApdu.tx_apdu_to_frame(frame, aFrame);
	}

	public static void fm_init_write_key(ApduFrame aFrame, byte type, byte id,
			byte[] buf, byte len, byte mac_type, byte[] mac_key,
			byte[] challenge) {
		byte key_len = 0;

		aFrame.CLA = (byte) 0x80;
		aFrame.INS = (byte) 0xD4;
		aFrame.P1 = type;
		aFrame.P2 = id;
		aFrame.Lc = len;
		// memcpy(aFrame.DATA, buf, len);
		System.arraycopy(aFrame.DATA, 0, buf, 0, len);
		aFrame.Le = (byte) 0xFF;

		if (Apdu.is_mac(mac_type)) {
			aFrame.CLA |= 0x04;
		}

		key_len = (byte) Apdu.get_key_len(mac_type);

		if (is_des(mac_type)) {
			Apdu.fm_make_des(aFrame, mac_key, key_len);
		}
		if (Apdu.is_mac(mac_type)) {
			Apdu.fm_make_mac(aFrame, challenge, mac_key, key_len);
		}
	}

	public static void fm_make_write_key(TXFRAME frame, byte type, byte id,
			byte[] buf, byte len, byte mac_type, byte[] mac_key,
			byte[] challenge) {
		ApduFrame aFrame = new ApduFrame();

		fm_init_write_key(aFrame, type, id, buf, len, mac_type, mac_key,
				challenge);

		TxApdu.tx_apdu_to_frame(frame, aFrame);
	}

	/*
	 * void fm_make_write_key1(TXFRAME *frame, unsigned char type, unsigned char
	 * id, KEYDATA1 *data) { req.CLA = 0x80; req.INS = 0xD4; req.P1 = type;
	 * req.P2 = id; req.Lc = len; memcpy(req.DATA, buf, len); }
	 */
	public static void fm_init_get_challenge(ApduFrame aFrame, byte len) {
		aFrame.CLA = 0x00;
		aFrame.INS = (byte) 0x84;
		aFrame.P1 = 0x00;
		aFrame.P2 = 0x00;
		aFrame.Lc = (byte) 0xFF;
		aFrame.Le = len;
	}

	public static void fm_make_get_challenge(TXFRAME frame, byte len) {
		ApduFrame aFrame = new ApduFrame();

		fm_init_get_challenge(aFrame, len);

		TxApdu.tx_apdu_to_frame(frame, aFrame);
	}

	public void fm_init_ext_authenticate_single(ApduFrame aFrame, byte key_id,
			byte[] challenge, byte len) {
		aFrame.CLA = 0x00;
		aFrame.INS = (byte) 0x82;
		aFrame.P1 = 0x00;
		aFrame.P2 = key_id;
		aFrame.Lc = len;
		// memcpy(aFrame.DATA, challenge, len);
		System.arraycopy(challenge, 0, aFrame.DATA, 0, len);
		aFrame.Le = (byte) 0xFF;
	}

	public void fm_make_ext_authenticate_single(TXFRAME frame, byte key_id,
			byte[] challenge, byte len) {
		ApduFrame aFrame = new ApduFrame();

		fm_init_ext_authenticate_single(aFrame, key_id, challenge, len);

		TxApdu.tx_apdu_to_frame(frame, aFrame);
	}

	static void fm_init_ext_authenticate(ApduFrame aFrame, byte key_id,
			byte[] key, byte len, byte[] challenge) {
		byte[] buf = new byte[ISO1443Constant.ISO14443A_KEY_LONG];

		aFrame.CLA = 0x00;
		aFrame.INS = (byte) 0x82;
		aFrame.P1 = 0x00;
		aFrame.P2 = key_id;
		aFrame.Lc = 0x08;
		aFrame.Le = (byte) 0xFF;

		Apdu.fm_des(challenge, key, len, buf);
		// memcpy(aFrame.DATA, buf, aFrame.Lc);
		System.arraycopy(buf, 0, aFrame.DATA, 0, aFrame.Lc);
	}

	public static void fm_make_ext_authenticate(TXFRAME frame, byte key_id,
			byte[] key, byte len, byte[] challenge) {
		ApduFrame aFrame = new ApduFrame();

		fm_init_ext_authenticate(aFrame, key_id, key, len, challenge);

		TxApdu.tx_apdu_to_frame(frame, aFrame);
	}

	public void fm_init_int_authenticate(ApduFrame aFrame, byte type,
			byte key_id, byte[] data, byte len) {
		byte[] buf = new byte[ISO1443Constant.ISO14443A_KEY_LONG];

		aFrame.CLA = 0x00;
		aFrame.INS = (byte) 0x88;
		aFrame.P1 = type;
		aFrame.P2 = key_id;
		aFrame.Lc = len;
		// memcpy(aFrame.DATA, data, len);
		System.arraycopy(aFrame.DATA, 0, data, 0, len);
		aFrame.Le = (byte) 0xFF;
	}

	public void fm_make_int_authenticate(TXFRAME frame, byte type, byte key_id,
			byte[] data, byte len) {
		ApduFrame aFrame = new ApduFrame();

		fm_init_int_authenticate(aFrame, type, key_id, data, len);

		TxApdu.tx_apdu_to_frame(frame, aFrame);
	}

	static void fm_init_select(ApduFrame aFrame, boolean file_id, byte[] file,
			byte file_len) {
		aFrame.CLA = 0x00;
		aFrame.INS = (byte) 0xA4;
		if (file_id)
			aFrame.P1 = 0x00;
		else
			aFrame.P1 = 0x04;
		aFrame.P2 = 0x00;
		aFrame.Lc = file_len;
		// memcpy(aFrame.DATA, file, file_len);
		System.arraycopy(file, 0, aFrame.DATA, 0, file_len);
		aFrame.Le = 0x00;
	}

	public static void fm_make_select(TXFRAME frame, boolean file_id,
			byte[] file, byte file_len) {
		ApduFrame aFrame = new ApduFrame();

		fm_init_select(aFrame, file_id, file, file_len);

		TxApdu.tx_apdu_to_frame(frame, aFrame);
	}

	public void fm_init_select_mf(ApduFrame aFrame) {
		byte[] file = { 0x3F, 0x00 };
		fm_init_select(aFrame, true, file, (byte) file.length);
	}

	public void fm_make_select_mf(TXFRAME frame) {
		byte[] file = { 0x3F, 0x00 };

		fm_make_select(frame, true, file, (byte) file.length);
	}

	public static void fm_init_read_binary(ApduFrame aFrame, byte file,
			byte offset, byte len, byte mac_type, byte[] mac_key,
			byte[] challenge) {
		byte mac_key_len = 0;

		aFrame.CLA = 0x00;
		aFrame.INS = (byte) 0xB0;
		if (file == 0x00) {
			if (offset < 0x8000) {
				aFrame.P1 = (byte) ((offset >> 8) & 0xFF);
				aFrame.P2 = offset;
			}
		} else if (file < 0x20) {
			aFrame.P1 = file;
			aFrame.P1 |= 0x80;
			aFrame.P2 = offset;
		}
		aFrame.Lc = (byte) 0xFF;
		aFrame.Le = len;

		if (Apdu.is_mac(mac_type)) {
			aFrame.CLA |= 0x04;
		}

		mac_key_len = (byte) Apdu.get_key_len(mac_type);

		/*
		 * if (is_des(mac_type)) { fm_make_des(&req, mac_key, key_len); }
		 */
		if (Apdu.is_mac(mac_type)) {
			Apdu.fm_make_mac(aFrame, challenge, mac_key, mac_key_len);
		}
	}

	public static void fm_make_read_binary(TXFRAME frame, byte file,
			short offset, byte len, byte mac_type, byte[] mac_key,
			byte[] challenge) {
		ApduFrame aFrame = new ApduFrame();

		fm_init_read_binary(aFrame, file, (byte) offset, len, mac_type,
				mac_key, challenge);

		TxApdu.tx_apdu_to_frame(frame, aFrame);
	}

	public static void fm_init_write_binary(ApduFrame aFrame, byte file,
			byte offset, byte[] buf, byte len, byte mac_type, byte[] mac_key,
			byte[] challenge) {
		byte mac_key_len = 0;

		aFrame.CLA = 0x00;
		aFrame.INS = (byte) 0xD6;
		if (file == 0x00) {
			if (offset < 0x8000) {
				aFrame.P1 = (byte) ((offset >> 8) & 0xFF);
				aFrame.P2 = offset;
			}
		} else if (file < 0x20) {
			aFrame.P1 = file;
			aFrame.P1 |= (byte) 0x80;
			aFrame.P2 = offset;
		}

		aFrame.Lc = len;
		// memcpy(aFrame.DATA, buf, len);
		System.arraycopy(buf, 0, aFrame.DATA, 0, len);
		aFrame.Le = (byte) 0xFF;

		if (Apdu.is_mac(mac_type)) {
			aFrame.CLA |= 0x04;
		}

		mac_key_len = (byte) Apdu.get_key_len(mac_type);

		if (is_des(mac_type)) {
			Apdu.fm_make_des(aFrame, mac_key, mac_key_len);
		}

		if (Apdu.is_mac(mac_type)) {
			Apdu.fm_make_mac(aFrame, challenge, mac_key, mac_key_len);
		}
	}

	public static void fm_make_write_binary(TXFRAME frame, byte file,
			short offset, byte[] buf, byte len, byte mac_type, byte[] mac_key,
			byte[] challenge) {
		ApduFrame aFrame = new ApduFrame();

		fm_init_write_binary(aFrame, file, (byte) offset, buf, len, mac_type,
				mac_key, challenge);

		TxApdu.tx_apdu_to_frame(frame, aFrame);
	}

	public static void fm_init_read_record(ApduFrame aFrame, byte file,
			byte record_index, byte record_id, byte mac_type, byte[] mac_key,
			byte[] challenge) {
		byte mac_key_len = 0;

		aFrame.CLA = 0x00;
		aFrame.INS = (byte) 0xB2;
		if (record_index == 0x00) {
			aFrame.P1 = record_id;
			aFrame.P2 = (byte) (file << 3);
		} else {
			aFrame.P1 = record_index;
			aFrame.P2 = (byte) (file << 3);
			aFrame.P2 |= 0x04;
		}
		aFrame.Lc = (byte) 0xFF;
		aFrame.Le = 0x00;

		if (Apdu.is_mac(mac_type)) {
			aFrame.CLA |= 0x04;
		}

		mac_key_len = (byte) Apdu.get_key_len(mac_type);

		if (Apdu.is_mac(mac_type)) {
			Apdu.fm_make_mac(aFrame, challenge, mac_key, mac_key_len);
		}
	}

	public static void fm_make_read_record(TXFRAME frame, byte file,
			byte record_index, byte record_id, byte mac_type, byte[] mac_key,
			byte[] challenge) {
		ApduFrame aFrame = new ApduFrame();

		fm_init_read_record(aFrame, file, record_index, record_id, mac_type,
				mac_key, challenge);

		TxApdu.tx_apdu_to_frame(frame, aFrame);
	}

	public static void fm_init_write_record(ApduFrame aFrame, byte file,
			byte record_index, byte record_pos, byte[] buf, byte len,
			byte mac_type, byte[] mac_key, byte[] challenge) {
		byte mac_key_len = 0;

		aFrame.CLA = 0x00;
		aFrame.INS = (byte) 0xDC;
		aFrame.P1 = record_index;
		aFrame.P2 = (byte) (file << 3);
		aFrame.P2 |= (record_pos & 0x07);
		aFrame.Lc = len;
		// memcpy(aFrame.DATA, buf, len);
		System.arraycopy(buf, 0, aFrame.DATA, 0, len);
		aFrame.Le = (byte) 0xFF;

		if (Apdu.is_mac(mac_type)) {
			aFrame.CLA |= 0x04;
		}

		mac_key_len = (byte) Apdu.get_key_len(mac_type);

		if (is_des(mac_type)) {
			Apdu.fm_make_des(aFrame, mac_key, mac_key_len);
		}

		if (Apdu.is_mac(mac_type)) {
			Apdu.fm_make_mac(aFrame, challenge, mac_key, mac_key_len);
		}
	}

	public static void fm_make_write_record(TXFRAME frame, byte file,
			byte record_index, byte record_pos, byte[] buf, byte len,
			byte mac_type, byte[] mac_key, byte[] challenge) {
		ApduFrame aFrame = new ApduFrame();

		fm_init_write_record(aFrame, file, record_index, record_pos, buf, len,
				mac_type, mac_key, challenge);

		TxApdu.tx_apdu_to_frame(frame, aFrame);
	}

	public static void fm_init_append_record(ApduFrame aFrame, byte file,
			byte[] buf, byte len, byte mac_type, byte[] mac_key,
			byte[] challenge) {
		byte mac_key_len = 0;

		aFrame.CLA = 0x00;
		aFrame.INS = (byte) 0xE2;
		aFrame.P1 = 0x00;
		aFrame.P2 = (byte) (file << 3);
		aFrame.P2 |= 0x04;
		aFrame.Lc = len;
		// memcpy(aFrame.DATA, buf, len);
		System.arraycopy(buf, 0, aFrame.DATA, 0, len);
		aFrame.Le = (byte) 0xFF;

		if (Apdu.is_mac(mac_type)) {
			aFrame.CLA |= 0x04;
		}

		mac_key_len = (byte) Apdu.get_key_len(mac_type);

		if (is_des(mac_type)) {
			Apdu.fm_make_des(aFrame, mac_key, mac_key_len);
		}

		if (Apdu.is_mac(mac_type)) {
			Apdu.fm_make_mac(aFrame, challenge, mac_key, mac_key_len);
		}
	}

	public static void fm_make_append_record(TXFRAME frame, byte file,
			byte[] buf, byte len, byte mac_type, byte[] mac_key,
			byte[] challenge) {
		ApduFrame aFrame = new ApduFrame();

		fm_init_append_record(aFrame, file, buf, len, mac_type, mac_key,
				challenge);

		TxApdu.tx_apdu_to_frame(frame, aFrame);
	}

	public static void fm_init_verify_pin(ApduFrame aFrame, byte key_id,
			byte[] key, byte len) {
		aFrame.CLA = 0x00;
		aFrame.INS = 0x20;
		aFrame.P1 = 0x00;
		aFrame.P2 = key_id;
		aFrame.Lc = len;
		// memcpy(aFrame.DATA, key, len);
		System.arraycopy(key, 0, aFrame.DATA, 0, len);
		aFrame.Le = (byte) 0xFF;
	}

	public static void fm_make_verify_pin(TXFRAME frame, byte key_id,
			byte[] key, byte len) {
		ApduFrame aFrame = new ApduFrame();

		fm_init_verify_pin(aFrame, key_id, key, len);

		TxApdu.tx_apdu_to_frame(frame, aFrame);
	}

	public void fm_make_lock_card(TXFRAME frame, byte[] key, byte len,
			byte[] challenge) {
		ApduFrame aFrame = new ApduFrame();

		aFrame.CLA = (byte) 0x84;
		aFrame.INS = 0x16;
		aFrame.P1 = 0x00;
		aFrame.P2 = 0x00;
		aFrame.Lc = (byte) 0xFF;
		aFrame.Le = (byte) 0xFF;

		Apdu.fm_make_mac(aFrame, challenge, key, len);
		TxApdu.tx_apdu_to_frame(frame, aFrame);
	}

	public void fm_init_app_unlock(ApduFrame aFrame, byte[] key, byte len,
			byte[] challenge) {
		aFrame.CLA = (byte) 0x84;
		aFrame.INS = 0x18;
		aFrame.P1 = 0x00;
		aFrame.P2 = 0x00;
		aFrame.Lc = (byte) 0xFF;
		aFrame.Le = (byte) 0xFF;

		Apdu.fm_make_mac(aFrame, challenge, key, len);
	}

	public void fm_make_app_unlock(TXFRAME frame, byte[] key, byte len,
			byte[] challenge) {
		ApduFrame aFrame = new ApduFrame();

		fm_init_app_unlock(aFrame, key, len, challenge);

		TxApdu.tx_apdu_to_frame(frame, aFrame);
	}

	void fm_init_app_lock(ApduFrame aFrame, byte[] key, byte len,
			byte[] challenge, boolean forever) {
		aFrame.CLA = (byte) 0x84;
		aFrame.INS = 0x1E;
		aFrame.P1 = 0x00;
		if (!forever)
			aFrame.P2 = 0x00;
		else
			aFrame.P2 = 0x01;
		aFrame.Lc = (byte) 0xFF;
		aFrame.Le = (byte) 0xFF;

		Apdu.fm_make_mac(aFrame, challenge, key, len);
	}

	public void fm_make_app_lock(TXFRAME frame, byte[] key, byte len,
			byte[] challenge, boolean forever) {
		ApduFrame aFrame = new ApduFrame();

		fm_init_app_lock(aFrame, key, len, challenge, forever);

		TxApdu.tx_apdu_to_frame(frame, aFrame);
	}

	public static void fm_make_unlock_pin(TXFRAME frame, byte key_id,
			byte[] key, byte len, byte[] unlock_key, byte unlock_key_len,
			byte[] challenge) {
		ApduFrame aFrame = new ApduFrame();
		byte[] buf = new byte[ISO1443Constant.ISO14443A_KEY_LONG];
		byte[] mac = new byte[ISO1443Constant.ISO14443A_MAC_LEN];
		byte[] init = new byte[ISO1443Constant.ISO14443A_CHALLENGE_SHORT];

		aFrame.CLA = (byte) 0x84;
		aFrame.INS = 0x24;
		aFrame.P1 = key_id;
		aFrame.P2 = 0x00;
		aFrame.Lc = len;
		// memcpy(aFrame.DATA, key, len);
		System.arraycopy(key, 0, aFrame.DATA, 0, len);
		aFrame.Le = (byte) 0xFF;

		Apdu.fm_make_des(aFrame, unlock_key, unlock_key_len);
		Apdu.fm_make_mac(aFrame, challenge, unlock_key, unlock_key_len);

		TxApdu.tx_apdu_to_frame(frame, aFrame);
	}

	public static void fm_make_reload_pin(TXFRAME frame, byte key_id,
			byte[] key, byte len, byte[] reload_key, byte reload_key_len) {
		ApduFrame aFrame = new ApduFrame();
		byte[] sk = new byte[ISO1443Constant.ISO14443A_KEY_LONG];
		int i = 0;
		byte[] mac = new byte[ISO1443Constant.ISO14443A_MAC_LEN];
		byte[] init = new byte[ISO1443Constant.ISO14443A_CHALLENGE_SHORT];

		aFrame.CLA = (byte) 0x80;
		aFrame.INS = 0x5E;
		aFrame.P1 = 0x00;
		aFrame.P2 = key_id;
		aFrame.Lc = len;
		// memcpy(aFrame.DATA, key, len);
		System.arraycopy(aFrame.DATA, 0, key, 0, len);
		aFrame.Le = (byte) 0xFF;

		// memcpy(sk, reload_key, reload_key_len);
		System.arraycopy(reload_key, 0, sk, 0, reload_key_len);
		for (i = 0; i < ISO1443Constant.ISO14443A_KEY_SHORT; i++) {
			sk[i] ^= sk[ISO1443Constant.ISO14443A_KEY_SHORT + i];
		}

		Apdu.fm_make_mac_base(aFrame.DATA, len, init, sk,
				ISO1443Constant.ISO14443A_KEY_SHORT, mac);
		aFrame.Lc += ISO1443Constant.ISO14443A_MAC_LEN;
		// memcpy(aFrame.DATA[aFrame.Lc - ISO1443Constant.ISO14443A_MAC_LEN],
		// mac, ISO1443Constant.ISO14443A_MAC_LEN);
		System.arraycopy(mac, 0, aFrame.DATA, aFrame.Lc
				- ISO1443Constant.ISO14443A_MAC_LEN,
				ISO1443Constant.ISO14443A_MAC_LEN);
		TxApdu.tx_apdu_to_frame(frame, aFrame);
	}

	public static void fm_make_change_pin(TXFRAME frame, byte key_id,
			byte[] old_key, byte old_len, byte[] new_key, byte new_len) {
		ApduFrame aFrame = new ApduFrame();

		aFrame.CLA = (byte) 0x80;
		aFrame.INS = 0x5E;
		aFrame.P1 = 0x01;
		aFrame.P2 = key_id;
		aFrame.Lc = (byte) (old_len + 1 + new_len);

		/*
		 * memcpy(aFrame.DATA, old_key, old_len); memset(aFrame.DATA + old_len,
		 * 0xFF, 1); memcpy(aFrame.DATA + old_len + 1, new_key, new_len);
		 */

		System.arraycopy(old_key, 0, aFrame.DATA, 0, old_len);
		// System.arraycopy(aFrame.DATA, old_len, 0xFF, 0, 1);
		aFrame.DATA[old_len] = (byte) 0xFF;
		System.arraycopy(new_key, 0, aFrame.DATA, old_len + 1, new_len);

		aFrame.Le = (byte) 0xFF;

		TxApdu.tx_apdu_to_frame(frame, aFrame);
	}

	public static void fm_make_init_load(TXFRAME frame, boolean bank,
			byte key_id, byte[] money, byte[] pos_id) {
		ApduFrame aFrame = new ApduFrame();

		aFrame.CLA = (byte) 0x80;
		aFrame.INS = 0x50;
		aFrame.P1 = 0x00;
		if (bank)
			aFrame.P2 = 0x01;
		else
			aFrame.P2 = 0x02;
		aFrame.Lc = 0x0B;
		/*
		 * memset(aFrame.DATA, key_id, 1); memcpy(aFrame.DATA + 1, money, 4);
		 * memcpy(aFrame.DATA + 1 + 4, pos_id, 6);
		 */
		aFrame.DATA[0] = key_id;
		System.arraycopy(money, 0, aFrame.DATA, 1, 4);
		System.arraycopy(pos_id, 0, aFrame.DATA, 1 + 4, 6);
		aFrame.Le = 0x10;

		TxApdu.tx_apdu_to_frame(frame, aFrame);
	}

	public static boolean fm_valid_init_load(boolean bank, byte[] key,
			byte key_len, byte[] money, byte[] pos_id, byte[] init_val,
			byte[] date, byte[] time, byte[] mac2) {
		byte[] buf = new byte[ISO1443Constant.ISO14443A_KEY_SHORT];
		byte[] sk = new byte[ISO1443Constant.ISO14443A_KEY_SHORT];
		byte[] src = new byte[15];
		byte[] init = new byte[ISO1443Constant.ISO14443A_KEY_SHORT];
		byte[] mac = new byte[ISO1443Constant.ISO14443A_MAC_LEN];
		byte[] src2 = new byte[18];

		/*
		 * memcpy(buf, Tools.cutByte(init_val , 8), 4); memcpy(buf + 4, init_val
		 * + 4, 2);
		 */
		System.arraycopy(init_val, 8, buf, 0, 4);
		System.arraycopy(init_val, 4, buf, 4, 2);
		buf[4 + 2] = (byte) 0x80;
		buf[4 + 2 + 1] = 0x00;

		Apdu.fm_des(buf, key, key_len, sk);

		/*
		 * memcpy(src, init_val, 4); memcpy(src + 4, money, 4);
		 */
		System.arraycopy(init_val, 0, src, 0, 4);
		System.arraycopy(money, 0, src, 4, 4);
		if (bank)
			src[4 + 4] = 0x01;
		else
			src[4 + 4] = 0x02;
		// memcpy(src + 4 + 4 + 1, pos_id, 6);
		System.arraycopy(pos_id, 0, src, 4 + 4 + 1, 6);

		Apdu.fm_make_mac_base(src, (byte) 15, init, sk,
				ISO1443Constant.ISO14443A_KEY_SHORT, mac);

		/*
		 * if (memcmp(mac, init_val + 12, ISO1443Constant.ISO14443A_MAC_LEN) !=
		 * 0) return false;
		 */
		for (int i = 0; i < ISO1443Constant.ISO14443A_MAC_LEN; i++) {
			if (mac[i] != init_val[i + 12]) {
				return false;
			}
		}
		// memcpy(src2, money, 4);
		System.arraycopy(money, 0, src2, 0, 4);
		if (bank)
			src2[4] = 0x01;
		else
			src2[4] = 0x02;
		/*
		 * memcpy(src2 + 4 + 1, pos_id, 6); memcpy(src2 + 4 + 1 + 6, date, 4);
		 * memcpy(src2 + 4 + 1 + 6 + 4, time, 3);
		 */
		System.arraycopy(pos_id, 0, src2, 4 + 1, 6);
		System.arraycopy(date, 0, src2, 4 + 1 + 6, 4);
		System.arraycopy(time, 0, src2, 4 + 1 + 6 + 4, 3);
		Apdu.fm_make_mac_base(src2, (byte) 18, init, sk,
				ISO1443Constant.ISO14443A_KEY_SHORT, mac2);

		return true;
	}

	public static void fm_make_credit_load(TXFRAME frame, byte[] date,
			byte[] time, byte[] mac) {
		ApduFrame aFrame = new ApduFrame();

		aFrame.CLA = (byte) 0x80;
		aFrame.INS = 0x52;
		aFrame.P1 = 0x00;
		aFrame.P2 = 0x00;
		aFrame.Lc = 0x0B;
		/*
		 * memcpy(aFrame.DATA, date, 4); memcpy(aFrame.DATA + 4, time, 3);
		 * memcpy(aFrame.DATA + 4 + 3, mac, 4);
		 */
		System.arraycopy(date, 0, aFrame.DATA, 0, 4);
		System.arraycopy(date, 0, aFrame.DATA, 4, 3);
		System.arraycopy(date, 0, aFrame.DATA, 4 + 3, 4);
		aFrame.Le = 0x04;

		TxApdu.tx_apdu_to_frame(frame, aFrame);
	}

	public static boolean fm_valid_credit_load(boolean bank, byte[] key,
			byte key_len, byte[] money, byte[] pos_id, byte[] init_val,
			byte[] date, byte[] time, byte[] tac) {
		byte[] init = new byte[ISO1443Constant.ISO14443A_CHALLENGE_SHORT];
		byte[] mac = new byte[ISO1443Constant.ISO14443A_MAC_LEN];
		// int old_money = 0;
		// int new_money = 0;
		byte[] p1 = new byte[4];
		byte[] p2 = new byte[4];
		byte[] src = new byte[24];
		byte[] sk = new byte[ISO1443Constant.ISO14443A_KEY_LONG];
		int i = 0;

		p1[0] = init_val[3];
		p1[1] = init_val[2];
		p1[2] = init_val[1];
		p1[3] = init_val[0];
		p2[0] = money[3];
		p2[1] = money[2];
		p2[2] = money[1];
		p2[3] = money[0];
		// new_money += old_money;
		// p2 = (unsigned char *)&new_money;
		src[0] = p2[3];
		src[1] = p2[2];
		src[2] = p2[1];
		src[3] = p2[0];

		/*
		 * memcpy(src + 4, init_val + 4, 2); memcpy(src + 4 + 2, money, 4);
		 */
		System.arraycopy(init_val, 4, src, 4, 2);
		System.arraycopy(money, 0, src, 4 + 2, 4);
		if (bank)
			src[4 + 2 + 4] = 0x01;
		else
			src[4 + 2 + 4] = 0x02;
		/*
		 * memcpy(src + 4 + 2 + 4 + 1, pos_id, 6); memcpy(src + 4 + 2 + 4 + 1 +
		 * 6, date, 4); memcpy(src + 4 + 2 + 4 + 1 + 6 + 4, time, 3);
		 */
		System.arraycopy(pos_id, 0, src, 4 + 2 + 4 + 1, 6);
		System.arraycopy(date, 0, src, 4 + 2 + 4 + 1 + 6, 4);
		System.arraycopy(time, 0, src, 4 + 2 + 4 + 1 + 6 + 4, 3);

		// memcpy(sk, key, key_len);
		System.arraycopy(key, 0, sk, 0, key_len);
		for (i = 0; i < ISO1443Constant.ISO14443A_KEY_SHORT; i++) {
			sk[i] ^= sk[ISO1443Constant.ISO14443A_KEY_SHORT + i];
		}

		Apdu.fm_make_mac_base(src, (byte) 24, init, sk,
				ISO1443Constant.ISO14443A_KEY_SHORT, mac);

		/*
		 * if (memcmp(mac, tac, ISO1443Constant.ISO14443A_MAC_LEN) != 0) return
		 * false;
		 */
		for (int k = 0; k < ISO1443Constant.ISO14443A_MAC_LEN; k++) {
			if (mac[k] != tac[k]) {
				return false;
			}
		}
		return true;
	}

	public static void fm_make_init_purchase(TXFRAME frame, boolean bank,
			byte key_id, byte[] money, byte[] pos_id) {
		// APDU_REQCMD req = {0};
		ApduFrame aFrame = new ApduFrame();
		aFrame.CLA = (byte) 0x80;
		aFrame.INS = 0x50;
		aFrame.P1 = 0x01;
		if (bank)
			aFrame.P2 = 0x01;
		else
			aFrame.P2 = 0x02;
		aFrame.Lc = 0x0B;
		/*
		 * memset(aFrame.DATA, key_id, 1); memcpy(aFrame.DATA + 1, money, 4);
		 * memcpy(aFrame.DATA + 1 + 4, pos_id, 6);
		 */
		//System.arraycopy(key_id, 0, aFrame.DATA, 0, 1);
		aFrame.DATA[0] = key_id;
		System.arraycopy(money, 0, aFrame.DATA, 1, 4);
		System.arraycopy(pos_id, 0, aFrame.DATA, 1 + 4, 6);
		aFrame.Le = 0x0F;

		TxApdu.tx_apdu_to_frame(frame, aFrame);
	}

	public static boolean fm_valid_init_purchase(boolean bank, byte[] key,
			byte key_len, byte[] money, byte[] pos_id, byte[] init_val,
			byte[] sn, byte[] date, byte[] time, byte[] mac1) {
		byte[] buf = new byte[ISO1443Constant.ISO14443A_KEY_SHORT];
		byte[] sk = new byte[ISO1443Constant.ISO14443A_KEY_SHORT];
		byte[] init = new byte[ISO1443Constant.ISO14443A_CHALLENGE_SHORT];
		byte[] src2 = new byte[18];

		/*
		 * memcpy(buf, init_val + 11, 4); memcpy(buf + 4, init_val + 4, 2);
		 * memcpy(buf + 4 + 2, sn + 2, 2);
		 */
		System.arraycopy(init_val, 11, buf, 0, 4);
		System.arraycopy(init_val, 4, buf, 4, 2);
		System.arraycopy(sn, 2, buf, 4 + 2, 2);
		Apdu.fm_des(buf, key, key_len, sk);

		// memcpy(src2, money, 4);
		System.arraycopy(money, 0, src2, 0, 4);
		if (bank)
			src2[4] = 0x05;
		else
			src2[4] = 0x06;
		/*
		 * memcpy(src2 + 4 + 1, pos_id, 6); memcpy(src2 + 4 + 1 + 6, date, 4);
		 * memcpy(src2 + 4 + 1 + 6 + 4, time, 3);
		 */
		System.arraycopy(pos_id, 0, src2, 4 + 1, 6);
		System.arraycopy(pos_id, 0, src2, 4 + 1 + 6, 4);
		System.arraycopy(pos_id, 0, src2, 4 + 1 + 6 + 4, 3);

		Apdu.fm_make_mac_base(src2, (byte) 18, init, sk,
				ISO1443Constant.ISO14443A_KEY_SHORT, mac1);

		return true;
	}

	public static void fm_make_debit_purchase(TXFRAME frame, byte[] sn,
			byte[] date, byte[] time, byte[] mac) {
		// APDU_REQCMD req = {0};
		ApduFrame aFrame = new ApduFrame();
		aFrame.CLA = (byte) 0x80;
		aFrame.INS = 0x54;
		aFrame.P1 = 0x01;
		aFrame.P2 = 0x00;
		aFrame.Lc = 0x0F;
		/*
		 * memcpy(aFrame.DATA, sn, 4); memcpy(aFrame.DATA + 4, date, 4);
		 * memcpy(aFrame.DATA + 4 + 4, time, 3); memcpy(aFrame.DATA + 4 + 4 + 3,
		 * mac, 4);
		 */
		System.arraycopy(sn, 0, aFrame.DATA, 0, 4);
		System.arraycopy(date, 0, aFrame.DATA, 4, 4);
		System.arraycopy(time, 0, aFrame.DATA, 4 + 4, 3);
		System.arraycopy(mac, 0, aFrame.DATA, 4 + 4 + 3, 4);
		aFrame.Le = 0x08;

		TxApdu.tx_apdu_to_frame(frame, aFrame);
	}

	public static boolean fm_valid_debit_purchase(boolean bank, byte[] key,
			byte key_len, byte[] money, byte[] pos_id, byte[] init_val,
			byte[] sn, byte[] date, byte[] time, byte[] tac) {
		byte[] init = new byte[ISO1443Constant.ISO14443A_CHALLENGE_SHORT];
		byte[] mac = new byte[ISO1443Constant.ISO14443A_MAC_LEN];
		byte[] src = new byte[22];
		byte[] sk = new byte[ISO1443Constant.ISO14443A_KEY_LONG];
		int i = 0;

		// memcpy(src, money, 4);
		System.arraycopy(money, 0, src, 0, 4);
		if (bank)
			src[4] = 0x05;
		else
			src[4] = 0x06;
		/*
		 * memcpy(src + 4 + 1, pos_id, 6); memcpy(src + 4 + 1 + 6, sn, 4);
		 * memcpy(src + 4 + 1 + 6 + 4, date, 4); memcpy(src + 4 + 1 + 6 + 4 + 4,
		 * time, 3);
		 */
		System.arraycopy(pos_id, 0, src, 4 + 1, 6);
		System.arraycopy(sn, 0, src, 4 + 1 + 6, 6);
		System.arraycopy(date, 0, src, 4 + 1 + 6 + 4, 6);
		System.arraycopy(time, 0, src, 4 + 1 + 6 + 4 + 4, 6);

		// memcpy(sk, key, key_len);
		System.arraycopy(key, 0, sk, 0, key_len);
		for (i = 0; i < ISO1443Constant.ISO14443A_KEY_SHORT; i++) {
			sk[i] ^= sk[ISO1443Constant.ISO14443A_KEY_SHORT + i];
		}

		Apdu.fm_make_mac_base(src, (byte) 22, init, sk,
				ISO1443Constant.ISO14443A_KEY_SHORT, mac);

		/*
		 * if (memcmp(mac, tac, ISO1443Constant.ISO14443A_MAC_LEN) != 0) return
		 * false;
		 */
		for (int k = 0; k <= ISO1443Constant.ISO14443A_MAC_LEN; k++) {
			if (mac[k] != tac[k]) {
				return false;
			}
		}
		return true;
	}

	void fm_make_init_capp_purchase(TXFRAME frame, byte key_id, byte[] money,
			byte[] pos_id) {
		ApduFrame aFrame = new ApduFrame();

		aFrame.CLA = (byte) 0x80;
		aFrame.INS = 0x50;
		aFrame.P1 = 0x03;
		aFrame.P2 = 0x02;
		aFrame.Lc = 0x0B;
		/*
		 * memset(aFrame.DATA, key_id, 1); memcpy(aFrame.DATA + 1, money, 4);
		 * memcpy(aFrame.DATA + 1 + 4, pos_id, 6);
		 */
		aFrame.DATA[0] = key_id;
		System.arraycopy(aFrame.DATA, 1, money, 0, 4);
		System.arraycopy(aFrame.DATA, 1 + 4, pos_id, 0, 6);
		aFrame.Le = 0x0F;

		TxApdu.tx_apdu_to_frame(frame, aFrame);
	}

	boolean fm_valid_init_capp_purchase(byte[] key, byte key_len, byte[] money,
			byte[] pos_id, byte[] init_val, byte[] sn, byte[] date,
			byte[] time, byte[] mac1) {
		byte[] buf = new byte[ISO1443Constant.ISO14443A_KEY_SHORT];
		byte[] sk = new byte[ISO1443Constant.ISO14443A_KEY_SHORT];
		byte[] init = new byte[ISO1443Constant.ISO14443A_CHALLENGE_SHORT];
		byte[] src2 = new byte[18];

		/*
		 * memcpy(buf, init_val + 11, 4); memcpy(buf + 4, init_val + 4, 2);
		 * memcpy(buf + 4 + 2, sn + 2, 2);
		 */
		System.arraycopy(buf, 0, ByteUtils.cutByte(init_val, 11), 0, 4);
		System.arraycopy(buf, 4, ByteUtils.cutByte(init_val, 4), 0, 2);
		System.arraycopy(buf, 4 + 2, ByteUtils.cutByte(init_val, 2), 0, 2);
		Apdu.fm_des(buf, key, key_len, sk);

		// memcpy(src2, money, 4);
		System.arraycopy(src2, 4, money, 0, 4);
		src2[4] = 0x09;
		/*
		 * memcpy(src2 + 4 + 1, pos_id, 6); memcpy(src2 + 4 + 1 + 6, date, 4);
		 * memcpy(src2 + 4 + 1 + 6 + 4, time, 3);
		 */
		System.arraycopy(src2, 4 + 1, pos_id, 0, 6);
		System.arraycopy(src2, 4 + 1 + 6, date, 0, 6);
		System.arraycopy(src2, 4 + 1 + 6 + 4, time, 0, 6);

		Apdu.fm_make_mac_base(src2, (byte) 18, init, sk,
				ISO1443Constant.ISO14443A_KEY_SHORT, mac1);

		return true;
	}

	public static void fm_make_debit_capp_purchase(TXFRAME frame, byte[] sn,
			byte[] date, byte[] time, byte[] mac) {
		ApduFrame aFrame = new ApduFrame();

		aFrame.CLA = (byte) 0x80;
		aFrame.INS = 0x54;
		aFrame.P1 = 0x01;
		aFrame.P2 = 0x00;
		aFrame.Lc = 0x0F;
		/*
		 * memcpy(aFrame.DATA, sn, 4); memcpy(aFrame.DATA + 4, date, 4);
		 * memcpy(aFrame.DATA + 4 + 4, time, 3); memcpy(aFrame.DATA + 4 + 4 + 3,
		 * mac, 4);
		 */
		System.arraycopy(sn, 0, aFrame.DATA, 0, 4);
		System.arraycopy(date, 0, aFrame.DATA, 4, 4);
		System.arraycopy(time, 0, aFrame.DATA, 4 + 4, 3);
		System.arraycopy(mac, 0, aFrame.DATA, 4 + 4 + 3, 4);
		aFrame.Le = 0x08;

		TxApdu.tx_apdu_to_frame(frame, aFrame);
	}

	boolean fm_valid_debit_capp_purchase(byte[] key, byte key_len,
			byte[] money, byte[] pos_id, byte[] init_val, byte[] sn,
			byte[] date, byte[] time, byte[] tac) {
		byte[] init = new byte[ISO1443Constant.ISO14443A_CHALLENGE_SHORT];
		byte[] mac = new byte[ISO1443Constant.ISO14443A_MAC_LEN];
		byte[] src = new byte[22];
		byte[] sk = new byte[ISO1443Constant.ISO14443A_KEY_LONG];
		int i = 0;

		// memcpy(src, money, 4);
		System.arraycopy(src, 0, money, 0, 4);
		src[4] = 0x09;
		/*
		 * memcpy(src + 4 + 1, pos_id, 6); memcpy(src + 4 + 1 + 6, sn, 4);
		 * memcpy(src + 4 + 1 + 6 + 4, date, 4); memcpy(src + 4 + 1 + 6 + 4 + 4,
		 * time, 3);
		 */
		System.arraycopy(src, 4 + 1, pos_id, 0, 6);
		System.arraycopy(src, 4 + 1 + 6, sn, 0, 4);
		System.arraycopy(src, 4 + 1 + 6 + 4, date, 0, 4);
		System.arraycopy(src, 4 + 1 + 6 + 4 + 4, time, 0, 3);

		// memcpy(sk, key, key_len);
		System.arraycopy(sk, 0, key, 0, key_len);
		for (i = 0; i < ISO1443Constant.ISO14443A_KEY_SHORT; i++) {
			sk[i] ^= sk[ISO1443Constant.ISO14443A_KEY_SHORT + i];
		}

		Apdu.fm_make_mac_base(src, (byte) 22, init, sk,
				ISO1443Constant.ISO14443A_KEY_SHORT, mac);

		/*
		 * if (memcmp(mac, tac, ISO1443Constant.ISO14443A_MAC_LEN) != 0) return
		 * false;
		 */
		for (int k = 0; k < ISO1443Constant.ISO14443A_MAC_LEN; k++) {
			if (mac[k] != tac[k]) {
				return false;
			}
		}

		return true;
	}

	void fm_make_update_capp_data_cache(TXFRAME frame, byte p1, byte p2,
			byte[] data, byte len) {
		ApduFrame aFrame = new ApduFrame();

		aFrame.CLA = (byte) 0x80;
		aFrame.INS = (byte) 0xDC;
		aFrame.P1 = p1;
		aFrame.P2 = p2;
		aFrame.Lc = len;
		// memcpy(aFrame.DATA, data, len);
		System.arraycopy(aFrame.DATA, 0, data, 0, len);
		aFrame.Le = (byte) 0xFF;

		TxApdu.tx_apdu_to_frame(frame, aFrame);
	}

	public static void fm_make_init_unload(TXFRAME frame, byte[] key_id,
			byte[] money, byte[] pos_id) {
		ApduFrame aFrame = new ApduFrame();

		aFrame.CLA = (byte) 0x80;
		aFrame.INS = 0x50;
		aFrame.P1 = 0x05;
		aFrame.P2 = 0x01;
		aFrame.Lc = 0x0B;
		/*
		 * memset(aFrame.DATA, key_id, 1); memcpy(aFrame.DATA + 1, money, 4);
		 * memcpy(aFrame.DATA + 1 + 4, pos_id, 6);
		 */
		System.arraycopy(key_id, 0, aFrame.DATA, 0, 1);
		System.arraycopy(money, 0, aFrame.DATA, 1, 4);
		System.arraycopy(pos_id, 0, aFrame.DATA, 1 + 4, 1);

		aFrame.Le = 0x10;

		TxApdu.tx_apdu_to_frame(frame, aFrame);
	}

	public static boolean fm_valid_init_unload(byte[] key, byte key_len,
			byte[] money, byte[] pos_id, byte[] init_val, byte[] date,
			byte[] time, byte[] mac2, byte[] sk) {
		byte[] buf = new byte[ISO1443Constant.ISO14443A_KEY_SHORT];
		byte[] src = new byte[15];
		byte[] init = new byte[ISO1443Constant.ISO14443A_CHALLENGE_SHORT];
		byte[] mac = new byte[ISO1443Constant.ISO14443A_MAC_LEN];
		byte[] src2 = new byte[18];

		/*
		 * memcpy(buf, init_val + 8, 4); memcpy(buf + 4, init_val + 4, 2);
		 */
		System.arraycopy(init_val, 8, buf, 0, 4);
		System.arraycopy(init_val, 4, buf, 0, 2);
		buf[4 + 2] = (byte) 0x80;
		buf[4 + 2 + 1] = 0x00;

		Apdu.fm_des(buf, key, key_len, sk);

		/*
		 * memcpy(src, init_val, 4); memcpy(src + 4, money, 4);
		 */
		System.arraycopy(init_val, 0, src, 0, 4);
		System.arraycopy(money, 0, src, 4, 4);
		src[4 + 4] = 0x03;
		// memcpy(src + 4 + 4 + 1, pos_id, 6);
		System.arraycopy(init_val, 0, src, 4 + 4 + 1, 6);
		Apdu.fm_make_mac_base(src, (byte) 15, init, sk,
				ISO1443Constant.ISO14443A_KEY_SHORT, mac);

		/*
		 * if (memcmp(mac, init_val + 12, ISO1443Constant.ISO14443A_MAC_LEN) !=
		 * 0) return false;
		 */
		for (int i = 0; i < ISO1443Constant.ISO14443A_MAC_LEN; i++) {
			if (mac[i] != init_val[i + 12]) {
				return false;
			}
		}
		// memcpy(src2, money, 4);
		System.arraycopy(money, 0, src2, 0, 4);
		src2[4] = 0x03;
		/*
		 * memcpy(src2 + 4 + 1, pos_id, 6); memcpy(src2 + 4 + 1 + 6, date, 4);
		 * memcpy(src2 + 4 + 1 + 6 + 4, time, 3);
		 */
		System.arraycopy(pos_id, 0, src2, 4 + 1, 6);
		System.arraycopy(date, 0, src2, 4 + 1 + 6, 4);
		System.arraycopy(time, 0, src2, 4 + 1 + 6 + 4, 3);
		Apdu.fm_make_mac_base(src2, (byte) 18, init, sk,
				ISO1443Constant.ISO14443A_KEY_SHORT, mac2);

		return true;
	}

	public static void fm_make_credit_unload(TXFRAME frame, byte[] date,
			byte[] time, byte[] mac) {
		ApduFrame aFrame = new ApduFrame();
		aFrame.CLA = (byte) 0x80;
		aFrame.INS = 0x54;
		aFrame.P1 = 0x03;
		aFrame.P2 = 0x00;
		aFrame.Lc = 0x0B;
		/*
		 * memcpy(aFrame.DATA, date, 4); memcpy(aFrame.DATA + 4, time, 3);
		 * memcpy(aFrame.DATA + 4 + 3, mac, 4);
		 */
		System.arraycopy(date, 0, aFrame.DATA, 0, 4);
		System.arraycopy(time, 0, aFrame.DATA, 4, 3);
		System.arraycopy(mac, 0, aFrame.DATA, 4 + 3, 4);
		aFrame.Le = 0x04;

		TxApdu.tx_apdu_to_frame(frame, aFrame);
	}

	public static boolean fm_valid_credit_unload(byte[] money, byte[] pos_id,
			byte[] init_val, byte[] date, byte[] time, byte[] sk, byte[] tac) {
		byte[] init = new byte[ISO1443Constant.ISO14443A_CHALLENGE_SHORT];
		byte[] mac = new byte[ISO1443Constant.ISO14443A_MAC_LEN];
		// int old_money = 0;
		// int new_money = 0;
		byte[] p1 = new byte[4];
		byte[] p2 = new byte[4];
		byte[] src = new byte[24];
		int i = 0;

		p1[0] = init_val[3];
		p1[1] = init_val[2];
		p1[2] = init_val[1];
		p1[3] = init_val[0];
		p2[0] = money[3];
		p2[1] = money[2];
		p2[2] = money[1];
		p2[3] = money[0];
		// new_money = old_money - new_money;
		// p2 = (unsigned char *)&new_money;
		src[0] = p2[3];
		src[1] = p2[2];
		src[2] = p2[1];
		src[3] = p2[0];

		/*
		 * memcpy(src + 4, init_val + 4, 2); memcpy(src + 4 + 2, money, 4);
		 */
		System.arraycopy(init_val, 4, src, 4, 2);
		System.arraycopy(money, 0, src, 4 + 2, 4);
		src[4 + 2 + 4] = 0x03;
		/*
		 * memcpy(src + 4 + 2 + 4 + 1, pos_id, 6); memcpy(src + 4 + 2 + 4 + 1 +
		 * 6, date, 4); memcpy(src + 4 + 2 + 4 + 1 + 6 + 4, time, 3);
		 */
		System.arraycopy(pos_id, 0, src, 4 + 2 + 4 + 1, 6);
		System.arraycopy(date, 0, src, 4 + 2 + 4 + 1 + 6, 4);
		System.arraycopy(time, 0, src, 4 + 2 + 4 + 1 + 6 + 4, 3);

		Apdu.fm_make_mac_base(src, (byte) 24, init, sk,
				ISO1443Constant.ISO14443A_KEY_SHORT, mac);

		/*
		 * if (memcmp(mac, tac, ISO1443Constant.ISO14443A_MAC_LEN) != 0) return
		 * false;
		 */
		for (int k = 0; k < ISO1443Constant.ISO14443A_MAC_LEN; k++) {
			if (mac[k] != tac[k]) {
				return false;
			}
		}
		return true;
	}

	public static void fm_make_init_cash_withdraw(TXFRAME frame, byte key_id,
			byte[] money, byte[] pos_id) {
		ApduFrame aFrame = new ApduFrame();

		aFrame.CLA = (byte) 0x80;
		aFrame.INS = 0x50;
		aFrame.P1 = 0x02;
		aFrame.P2 = 0x01;
		aFrame.Lc = 0x0B;
		/*
		 * memset(aFrame.DATA, key_id, 1); memcpy(aFrame.DATA + 1, money, 4);
		 * memcpy(aFrame.DATA + 1 + 4, pos_id, 6);
		 */
		aFrame.DATA[0] = key_id;
		System.arraycopy(money, 0, aFrame.DATA, 1, 4);
		System.arraycopy(pos_id, 0, aFrame.DATA, 1 + 4, 6);
		aFrame.Le = 0x0F;

		TxApdu.tx_apdu_to_frame(frame, aFrame);
	}

	public static boolean fm_valid_init_cash(byte[] key, byte key_len,
			byte[] money, byte[] pos_id, byte[] init_val, byte[] sn,
			byte[] date, byte[] time, byte[] mac1) {
		byte[] buf = new byte[ISO1443Constant.ISO14443A_KEY_SHORT];
		byte[] sk = new byte[ISO1443Constant.ISO14443A_KEY_SHORT];
		byte[] init = new byte[ISO1443Constant.ISO14443A_CHALLENGE_SHORT];
		byte[] src2 = new byte[18];

		/*
		 * memcpy(buf, init_val + 11, 4); memcpy(buf + 4, init_val + 4, 2);
		 * memcpy(buf + 4 + 2, sn + 2, 2);
		 */
		System.arraycopy(init_val, 11, buf, 0, 4);
		System.arraycopy(init_val, 4, buf, 4, 4);
		System.arraycopy(sn, 2, buf, 4 + 2, 4);
		Apdu.fm_des(buf, key, key_len, sk);

		// memcpy(src2, money, 4);
		System.arraycopy(money, 0, src2, 0, 4);
		src2[4] = 0x04;
		/*
		 * memcpy(src2 + 4 + 1, pos_id, 6); memcpy(src2 + 4 + 1 + 6, date, 4);
		 * memcpy(src2 + 4 + 1 + 6 + 4, time, 3);
		 */
		System.arraycopy(pos_id, 0, src2, 4 + 1, 6);
		System.arraycopy(date, 0, src2, 4 + 1 + 6, 4);
		System.arraycopy(time, 0, src2, 4 + 1 + 6 + 4, 3);
		Apdu.fm_make_mac_base(src2, (byte) 18, init, sk,
				ISO1443Constant.ISO14443A_KEY_SHORT, mac1);

		return true;
	}

	void fm_make_cash_withdraw(TXFRAME frame, byte[] sn, byte[] date,
			byte[] time, byte[] mac) {
		ApduFrame aFrame = new ApduFrame();

		aFrame.CLA = (byte) 0x80;
		aFrame.INS = 0x54;
		aFrame.P1 = 0x01;
		aFrame.P2 = 0x00;
		aFrame.Lc = 0x0F;
		// memcpy(aFrame.DATA, sn, 4);
		// memcpy(aFrame.DATA + 4, date, 4);
		// memcpy(aFrame.DATA + 4 + 4, time, 3);
		// memcpy(aFrame.DATA + 4 + 4 + 3, mac, 4);
		System.arraycopy(aFrame.DATA, 0, sn, 0, 4);
		System.arraycopy(aFrame.DATA, 4, date, 0, 4);
		System.arraycopy(aFrame.DATA, 4 + 4, time, 0, 3);
		System.arraycopy(aFrame.DATA, 4 + 4 + 3, mac, 0, 4);
		aFrame.Le = 0x08;

		TxApdu.tx_apdu_to_frame(frame, aFrame);
	}

	public static boolean fm_valid_cash_withdraw(byte[] key, byte key_len,
			byte[] money, byte[] pos_id, byte[] init_val, byte[] sn,
			byte[] date, byte[] time, byte[] tac) {
		byte[] init = new byte[ISO1443Constant.ISO14443A_CHALLENGE_SHORT];
		byte[] mac = new byte[ISO1443Constant.ISO14443A_MAC_LEN];
		byte[] src = new byte[22];
		byte[] sk = new byte[ISO1443Constant.ISO14443A_KEY_LONG];
		int i = 0;

		// memcpy(src, money, 4);
		System.arraycopy(money, 0, src, 0, 4);
		src[4] = 0x04;
		/*
		 * memcpy(src + 4 + 1, pos_id, 6); memcpy(src + 4 + 1 + 6, sn, 4);
		 * memcpy(src + 4 + 1 + 6 + 4, date, 4); memcpy(src + 4 + 1 + 6 + 4 + 4,
		 * time, 3);
		 */

		System.arraycopy(pos_id, 0, src, 4 + 1, 6);
		System.arraycopy(sn, 0, src, 4 + 1 + 6, 4);
		System.arraycopy(date, 0, src, 4 + 1 + 6 + 4, 4);
		System.arraycopy(time, 0, src, 4 + 1 + 6 + 4 + 4, 3);

		// memcpy(sk, key, key_len);
		System.arraycopy(key, 0, sk, 0, key_len);
		for (i = 0; i < ISO1443Constant.ISO14443A_KEY_SHORT; i++) {
			sk[i] ^= sk[ISO1443Constant.ISO14443A_KEY_SHORT + i];
		}

		Apdu.fm_make_mac_base(src, (byte) 22, init, sk,
				ISO1443Constant.ISO14443A_KEY_SHORT, mac);

		/*
		 * if (memcmp(mac, tac, ISO1443Constant.ISO14443A_MAC_LEN) != 0) return
		 * false;
		 */
		for (int k = 0; k < ISO1443Constant.ISO14443A_MAC_LEN; k++) {
			if (mac[k] != tac[k]) {
				return false;
			}
		}

		return true;
	}

	public static void fm_make_init_update_limit(TXFRAME frame, byte key_id,
			byte[] pos_id) {
		ApduFrame aFrame = new ApduFrame();

		aFrame.CLA = (byte) 0x80;
		aFrame.INS = 0x50;
		aFrame.P1 = 0x04;
		aFrame.P2 = 0x01;
		aFrame.Lc = 0x07;
		/*
		 * memset(aFrame.DATA, key_id, 1); memcpy(aFrame.DATA + 1, pos_id, 6);
		 */
		aFrame.DATA[0] = key_id;
		System.arraycopy(pos_id, 0, aFrame.DATA, 1, 6);

		aFrame.Le = 0x13;

		TxApdu.tx_apdu_to_frame(frame, aFrame);
	}

	public static boolean fm_valid_init_update_limit(byte[] key, byte key_len,
			byte[] pos_id, byte[] init_val, byte[] money, byte[] date,
			byte[] time, byte[] mac2) {
		byte[] buf = new byte[ISO1443Constant.ISO14443A_KEY_SHORT];
		byte[] sk = new byte[ISO1443Constant.ISO14443A_KEY_SHORT];
		byte[] src = new byte[14];
		byte[] init = new byte[ISO1443Constant.ISO14443A_CHALLENGE_SHORT];
		byte[] mac = new byte[ISO1443Constant.ISO14443A_MAC_LEN];
		byte[] src2 = new byte[17];

		/*
		 * memcpy(buf, init_val + 11, 4); memcpy(buf + 4, init_val + 4, 2);
		 */
		System.arraycopy(init_val, 11, buf, 0, 4);
		System.arraycopy(init_val, 4, buf, 4, 2);
		buf[4 + 2] = (byte) 0x80;
		buf[4 + 2 + 1] = 0x00;

		Apdu.fm_des(buf, key, key_len, sk);

		/*
		 * memcpy(src, init_val, 4); memcpy(src + 4, init_val + 6, 3);
		 */
		System.arraycopy(init_val, 0, src, 0, 4);
		System.arraycopy(init_val, 6, src, 4, 3);
		src[4 + 3] = 0x07;
		// memcpy(src + 4 + 3 + 1, pos_id, 6);
		System.arraycopy(pos_id, 0, src, 4 + 3 + 1, 6);
		Apdu.fm_make_mac_base(src, (byte) 14, init, sk,
				ISO1443Constant.ISO14443A_KEY_SHORT, mac);

		/*
		 * if (memcmp(mac, init_val + 15, ISO1443Constant.ISO14443A_MAC_LEN) !=
		 * 0) return false;
		 */
		for (int k = 0; k < ISO1443Constant.ISO14443A_MAC_LEN; k++) {
			if (mac[k] != init_val[k + 15]) {
				return false;
			}
		}
		// memcpy(src2, money, 3);
		System.arraycopy(money, 0, src2, 0, 3);
		src2[3] = 0x07;
		/*
		 * memcpy(src2 + 3 + 1, pos_id, 6); memcpy(src2 + 3 + 1 + 6, date, 4);
		 * memcpy(src2 + 3 + 1 + 6 + 4, time, 3);
		 */
		System.arraycopy(pos_id, 0, src2, 3 + 1, 6);
		System.arraycopy(date, 0, src2, 3 + 1 + 6, 4);
		System.arraycopy(time, 0, src2, 3 + 1 + 6 + 4, 3);

		Apdu.fm_make_mac_base(src2, (byte) 17, init, sk,
				ISO1443Constant.ISO14443A_KEY_SHORT, mac2);

		return true;
	}

	public static void fm_make_update_overdraw_limit(TXFRAME frame,
			byte[] money, byte[] date, byte[] time, byte[] mac) {
		ApduFrame aFrame = new ApduFrame();

		aFrame.CLA = (byte) 0x80;
		aFrame.INS = 0x58;
		aFrame.P1 = 0x00;
		aFrame.P2 = 0x00;
		aFrame.Lc = 0x0E;
		/*
		 * memcpy(aFrame.DATA, money, 3); memcpy(aFrame.DATA + 3, date, 4);
		 * memcpy(aFrame.DATA + 3 + 4, time, 3); memcpy(aFrame.DATA + 3 + 4 + 3,
		 * mac, 4);
		 */
		System.arraycopy(money, 0, aFrame.DATA, 0, 3);
		System.arraycopy(date, 0, aFrame.DATA, 3, 4);
		System.arraycopy(time, 0, aFrame.DATA, 3 + 4, 3);
		System.arraycopy(mac, 0, aFrame.DATA, 3 + 4 + 3, 4);
		aFrame.Le = 0x04;

		TxApdu.tx_apdu_to_frame(frame, aFrame);
	}

	public static boolean fm_valid_update_limit(byte[] key, byte key_len,
			byte[] pos_id, byte[] init_val, byte[] money, byte[] date,
			byte[] time, byte[] tac) {
		byte[] init = new byte[ISO1443Constant.ISO14443A_CHALLENGE_SHORT];
		byte[] mac = new byte[ISO1443Constant.ISO14443A_MAC_LEN];
		/*
		 * int old_money = 0; int new_money = 0; int old_over_money = 0;
		 */
		byte[] p1 = new byte[4];
		byte[] p2 = new byte[4];
		byte[] p3 = new byte[4];
		byte[] src = new byte[23];
		byte[] sk = new byte[ISO1443Constant.ISO14443A_KEY_LONG];
		int i = 0;

		p1[0] = init_val[3];
		p1[1] = init_val[2];
		p1[2] = init_val[1];
		p1[3] = init_val[0];

		p2[0] = money[2];
		p2[1] = money[1];
		p2[2] = money[0];

		p3[0] = init_val[4 + 2 + 2];
		p3[1] = init_val[4 + 2 + 1];
		p3[2] = init_val[4 + 2];

		// old_money -= old_over_money;
		// new_money += old_money;
		// p2 = (unsigned char *)&new_money;
		src[0] = p2[3];
		src[1] = p2[2];
		src[2] = p2[1];
		src[3] = p2[0];

		/*
		 * memcpy(src + 4, init_val + 4, 2); memcpy(src + 4 + 2, money, 3);
		 */
		System.arraycopy(init_val, 4, src, 4, 2);
		System.arraycopy(money, 0, src, 4 + 2, 3);
		src[4 + 2 + 3] = 0x07;
		/*
		 * memcpy(src + 4 + 2 + 3 + 1, pos_id, 6); memcpy(src + 4 + 2 + 3 + 1 +
		 * 6, date, 4); memcpy(src + 4 + 2 + 3 + 1 + 6 + 4, time, 3);
		 */
		System.arraycopy(pos_id, 0, src, 4 + 2 + 3 + 1, 6);
		System.arraycopy(date, 0, src, 4 + 2 + 3 + 1 + 6, 4);
		System.arraycopy(time, 0, src, 4 + 2 + 3 + 1 + 6 + 4, 3);

		// memcpy(sk, key, key_len);
		System.arraycopy(key, 0, sk, 0, key_len);
		for (i = 0; i < ISO1443Constant.ISO14443A_KEY_SHORT; i++) {
			sk[i] ^= sk[ISO1443Constant.ISO14443A_KEY_SHORT + i];
		}

		Apdu.fm_make_mac_base(src, (byte) 23, init, sk,
				ISO1443Constant.ISO14443A_KEY_SHORT, mac);

		/*
		 * if (memcmp(mac, tac, ISO1443Constant.ISO14443A_MAC_LEN) != 0) return
		 * false;
		 */
		for (int k = 0; k < ISO1443Constant.ISO14443A_MAC_LEN; k++) {
			if (mac[k] != tac[k]) {
				return false;
			}
		}
		return true;
	}

	void fm_make_get_transaction_prove(TXFRAME frame, byte type, byte[] sn) {
		ApduFrame aFrame = new ApduFrame();

		aFrame.CLA = (byte) 0x80;
		aFrame.INS = 0x5A;
		aFrame.P1 = 0x00;
		aFrame.P2 = type;
		aFrame.Lc = 0x02;
		// memcpy(aFrame.DATA, sn, 2);
		System.arraycopy(aFrame.DATA, 0, sn, 0, 2);
		aFrame.Le = 0x08;

		TxApdu.tx_apdu_to_frame(frame, aFrame);
	}

	public static void fm_make_get_balance(TXFRAME frame, boolean bank) {
		ApduFrame aFrame = new ApduFrame();
		aFrame.CLA = (byte) 0x80;
		aFrame.INS = 0x5C;
		aFrame.P1 = 0x00;
		if (bank)
			aFrame.P2 = 0x01;
		else
			aFrame.P2 = 0x02;
		aFrame.Lc = (byte) 0xFF;
		aFrame.Le = 0x04;

		TxApdu.tx_apdu_to_frame(frame, aFrame);
	}

	void fm_init_delivery_key(ApduFrame aFrame, byte use, byte id, byte[] data,
			byte len) {
		aFrame.CLA = (byte) 0x80;
		aFrame.INS = 0x1A;
		aFrame.P1 = use;
		aFrame.P2 = id;
		aFrame.Lc = len;
		// memcpy(aFrame.DATA, data, len);
		System.arraycopy(aFrame.DATA, 0, data, 0, len);
		aFrame.Le = (byte) 0xFF;
	}

	void fm_make_delivery_key(TXFRAME frame, byte use, byte id, byte[] data,
			byte len) {
		ApduFrame aFrame = new ApduFrame();

		fm_init_delivery_key(aFrame, use, id, data, len);

		TxApdu.tx_apdu_to_frame(frame, aFrame);
	}

	void fm_init_cipher_data(ApduFrame aFrame, byte mode, byte id, byte[] data,
			byte len) {
		aFrame.CLA = (byte) 0x80;
		aFrame.INS = (byte) 0xFA;
		aFrame.P1 = mode;
		aFrame.P2 = id;
		aFrame.Lc = len;
		// memcpy(aFrame.DATA, data, len);
		System.arraycopy(data, 0, aFrame.DATA, 0, len);
		aFrame.Le = (byte) 0xFF;
	}

	void fm_init_sam_for_purchase(ApduFrame aFrame, byte[] data, byte len) {
		aFrame.CLA = (byte) 0x80;
		aFrame.INS = 0x70;
		aFrame.P1 = 0x00;
		aFrame.P2 = 0x00;
		aFrame.Lc = len;
		// memcpy(aFrame.DATA, data, len);
		System.arraycopy(data, 0, aFrame.DATA, 0, len);
		aFrame.Le = 0x08;
	}

	void fm_init_credit_sam_for_purchase(ApduFrame aFrame, byte[] mac2) {
		aFrame.CLA = (byte) 0x80;
		aFrame.INS = 0x72;
		aFrame.P1 = 0x00;
		aFrame.P2 = 0x00;
		aFrame.Lc = 0x04;
		// memcpy(aFrame.DATA, mac2, aFrame.Lc);
		System.arraycopy(mac2, 0, aFrame.DATA, 0, aFrame.Lc);
		aFrame.Le = (byte) 0xFF;
	}
}
