分类: 嵌入式
2013-01-17 17:27:55
/* * 摘要:PBOC2.0 Level 1 测试程序 * 分为二部分:电气测试、协议测试 * Created on: 2013-1-10 * Author: lzy */ #include "Common.h" #include "AU9540.h" #include "lib.h" #define TIME_Level1 7 /* 电气循环测试时间间隔*/ #define TIME 1 /* 协议循环测试时间间隔*/ #define APDU_DEBUG 1 static FILE *g_LogoFd; #define LOGO_PRINT(fmt,args...) PR_DEBUG(fmt,##args) /*fprintf(g_LogoFd, fmt,##args)*/ /** * 功 能:打开AU9540模块,和LCD * 入口参数: * 出口参数: * 返回值:0 成功 * 开发人员:Lzy 2013-1-12 * 修改记录: */ LONG DevOpen(void) { LONG ret; gpio_dev_open(); hapi_set_dir(8, 5, 0); hapi_set_dir(4, 0, 1); hapi_gpio_write(4, 0, 1); ret = fb_init(); /* 打开LCD */ EXAM_ASSERT(ret, "LCD Open fail ErrNO=%d\n", ret); ret = OpenAU9540(); EXAM_ASSERT(ret, "Open Init AU9540 ErrNO=%d\n", ret); F1850_init(); LcdBlackCol(1); #if 0 g_LogoFd = fopen("logo.txt", "w+"); time_t timep; time(&timep); LOGO_PRINT("\n%s\n",ctime(&timep)) #endif return ret; } /** * 功 能:电气测试菜单 * 入口参数:i 复位次数 * 出口参数: * 返回值: * 开发人员:Lzy 2013-1-12 * 修改记录 */ LONG MenuElectTest(void) { LONG ret = 0; ST_Cls(); ST_Display(1, "终端Level_1电特性测试"); ST_Display(2, " 1 单次触发模式"); ST_Display(3, " 2 循环触发模式"); ST_Display(4, " 3 返回"); return ret; } LONG MenuMain(void) { ST_Cls(); ST_Display(1, " 终端 Level 1 测试"); ST_Display(2, " 1 电特性测试"); ST_Display(3, " 2 协议测试"); ST_Display(4, " 3 与PC机连接"); } /**************************电特性测试******************************/ /** * 函数功能:发送命令至IC卡 * 入口参数: * unsigned char *pszCmd --> 命令 * unsigned char ucLgcmd --> 命令长度 * 出口参数: * unsigned char *szRep --> 返回报文 * unsigned char ucLgRep --> 响应数据长度 * 返 回:0-->成功 或返回错误码 * * 开发人员: * 修改记录:Lzy 2012-11-27 */ int SendCmd(unsigned char *pszCmd, unsigned int ucLgcmd, unsigned char *szRep, unsigned int *ucLgRep) { int i, iOffset = 0, ret; unsigned int rtn; #if APDU_DEBUG /* 打印C-APDU 与log信息保存 */ LOGO_PRINT("\nC_APDU ==>[len:%d] ", ucLgcmd); for (i = 0; i < ucLgcmd; i++) LOGO_PRINT( "%02X ", pszCmd[i]); #endif ret = SendAPDUCommand(pszCmd, ucLgcmd, szRep, &rtn); /* 命令发送与接收 */ if (ret == 0) { #if APDU_DEBUG /* 打印R-APDU */ *ucLgRep = rtn; if (*szRep != 0x61 && *szRep != 0x6c) { LOGO_PRINT( "\nR_APDU <==[len:%d] ", *ucLgRep); for (i = 0; i < *ucLgRep; i++) LOGO_PRINT("%02X ", szRep[i]); LOGO_PRINT( "\n"); } #endif } return ret; } /** * 功 能: 文件选择命令 * 输入参数: char *file_id : 文件名称 * int filelen :文件长度 * 输出参数:unsigned char *recvbuf : 接收字符串 * 返 回: 0--成功; <0: 失败 * 开发人员: yangxh * 修改记录: Lzy 2012-11-27 */ int IC_CMD_Select(unsigned char *file_id, int filelen, unsigned char *recvbuf) { unsigned int recvlen = 0; unsigned char SendCommand[128], *ptr; unsigned int sendlen; int ret, i; /* * 00 A4 发送选择命令 * P1=0x04表示选择DF,这里数据域为DF的文件名 * P2=0x00表示选择满足条件的第一个或者是仅有的一个文件; */ memset((char *) SendCommand, 0x00, sizeof(SendCommand)); sprintf((char *) SendCommand, "%c%c%c%c%c", 0x00, 0xA4, 0x04, 0x00, filelen); memcpy(SendCommand + 5, file_id, filelen); sendlen = filelen + 5; SendCommand[sendlen] = 0; sendlen++; ret = SendCmd(SendCommand, sendlen, recvbuf, &recvlen); if (ret != 0) { ST_Display(4, " R-APDU[错误]"); PR_ERR("PbocICSelect fail"); // return -1; } else { ST_Display(3, " C-APDU[发送]"); ST_Display(4, " R-APDU[正确]"); } return 0; } /** * 功 能: 电气测试 命令发送流程 * 输入参数: 无 * 输出参数: * 返 回: 0--成功; <0: 失败 * 开发人员: yangxh * 修改记录: Lzy 2012-11-27 */ int Pb_SelectPSE(void) { char chPSE[0x80]; unsigned char recvbuf[256]; INT sfi, ret, i, j; memset(recvbuf, '\0', 256); memset(chPSE, '\0', 50); memcpy(chPSE, "1PAY.SYS.DDF01", 14); sfi = IC_CMD_Select(chPSE, strlen(chPSE), recvbuf); if (sfi < 0) { PR_ERR("PSE 出错\n "); return -1; } memset(recvbuf, 0x00, sizeof(recvbuf)); bzero(chPSE, sizeof(chPSE)); for (j = 1; j < 64; j++) { ST_Disp(1, 16, "%d", j); for (i = 0; i < 0x80; i++) chPSE[i] = i; IC_CMD_Select(chPSE, 0x80, recvbuf); } return ret; } /** * 功 能:电气特性测试 * 入口参娄: * 出口参数: * 返回值: * 开发人员: * 修改记录: */ LONG ElectricalTest(void) { LONG ret; INT iKey, i = 1, rtn = 0, flag; UCHAR cRecvbuf[256], Buf[50] = "ATR:"; while (1) { MenuElectTest(); iKey = ST_GetkeyMs(0) - '0'; /*库文件返回的 'BCD'*/ if (iKey == 3) break; else if (iKey == 1) flag = 0; else if (iKey == 2) flag = 1; else continue; ST_Cls(); do { if (0 == flag) ST_Display(1, " 单次触发模式"); else ST_Display(1, " 循环触发模式%d", flag++); bzero(cRecvbuf, sizeof(cRecvbuf)); ret = MSG_PC_to_RDR_IccPowerOn(cRecvbuf, &rtn); /* 冷复位 */ if (ret) { bzero(cRecvbuf, sizeof(cRecvbuf)); ret = MSG_PC_to_RDR_IccPowerOff(cRecvbuf, &rtn); PR_ERR( "卡已下电"); } else { /* 打印至屏幕*/ ST_Display(2, " "); for (i = 0; i < rtn && i < 7; i++) /* 由于屏幕的关第不能全部显示 */ sprintf(&Buf[4 + i * 3], "%02X ", cRecvbuf[i + 10]); ST_Displays(2, 0, Buf); PR_DEBUG("\nATR=[len:%d] ", rtn-11); /* 这里数据长度减去11才是ATR长度*/ for (i = 10; i < rtn - 1; i++) PR_DEBUG("%02X ", cRecvbuf[i]); PR_DEBUG("\n"); Pb_SelectPSE(); ret = MSG_PC_to_RDR_IccPowerOff(); EXAM_ASSERT(ret, "卡下电失败"); } S_Delay(TIME_Level1); } while (flag); } return ret; } /***************************************************************/ /*********************************协议测试***********************/ typedef struct { unsigned char data[261]; // ‘CLA INS P1 P2 [Lc + Lc data] [Le]’ for command or unsigned int length; // ‘[Le data] SW1 SW2’ for response ( max = 256+2 ) } T_APDU; #define TypeAPDU R_Apdu.data[3] #define LC R_Apdu.data[4] #define LE R_Apdu.data[5] #define OK 0 // Proprietary card activation and APDU Command/Response functions char PBOC_PowerOn(void) { LONG ret; INT iKey, i = 1, rtn = 0, flag; UCHAR cRecvbuf[256]; bzero(cRecvbuf, sizeof(cRecvbuf)); ret = MSG_PC_to_RDR_IccPowerOn(cRecvbuf, &rtn); /* 冷复位 */ if (ret) /*上电未成功,需要发送下电命令*/ { bzero(cRecvbuf, sizeof(cRecvbuf)); ret = MSG_PC_to_RDR_IccPowerOff(); /*下电*/ PR_DEBUG("已下电\n"); return -1; } /* 这里数据长度减去11才是ATR长度*/ if ((rtn - 11) == cRecvbuf[1] && 0x80 == cRecvbuf[0]) { PR_DEBUG("\nATR=[len:%d] ", rtn-11); for (i = 10; i < rtn - 1; i++) PR_DEBUG("%02X ", cRecvbuf[i]); PR_DEBUG("\n"); } else { PR_ERR("Read ATR fail\n"); return -1; } return ret; } char PBOC_apdu(T_APDU *C_Apdu, T_APDU *R_Apdu) { char ret; ret = SendCmd(C_Apdu->data, C_Apdu->length, R_Apdu->data, &(R_Apdu->length)); if (ret) PR_ERR("SendCmd error!"); return ret; } const unsigned char selectVisaCredit[] = { 0x00, 0xA4, 0x04, 0x00, 7, 0xA0, 0, 0, 0, 3, 0x10, 0x10, 0 }; T_APDU C_Apdu, R_Apdu; // C_Apdu sent to the Card, R_Apdu received from the Card char ComputeLrc(int ln, unsigned char *p) { char lrc; int i; lrc = 0; i = 0; while (i < ln) lrc ^= p[i++]; return (lrc); } static void InitSelectVisa(T_APDU *apdu) { memcpy(apdu->data, selectVisaCredit, 13); apdu->length = 13; } void MenuMainTestVisa(void) { ST_Cls(); ST_Display(1, "终端Level_1协议测试"); ST_Display(2, " 1 单次触发模式"); ST_Display(3, " 2 循环触发模式"); ST_Display(4, " 3 返回"); } void MenuTestVisa(void) { ST_Cls(); ST_Display(1, "终端Level_1协议测试"); ST_Display(3, " 正在进行协议测试"); } /* Main function */ int TestVisa(void) { unsigned char RetCode, profil; unsigned short DataInSize; unsigned char *ptr, Historical[15]; RetCode = PBOC_PowerOn(); if (RetCode == OK) { InitSelectVisa(&C_Apdu); // First APDU Command = Select Visa Credit while (1) { RetCode = PBOC_apdu(&C_Apdu, &R_Apdu); // Proprietary Command/Response function if ((RetCode != OK) || !memcmp(&R_Apdu.data[R_Apdu.length - 2], "\x6A" "\x82", 2)) break; // Building new APDU command if (R_Apdu.length < 8) // Not enough data to create new command InitSelectVisa(&C_Apdu); // -> default APDU Command = Select PSE else { // R-APDU : R_Apdu.data -> CLA/INS/P1/Type APDU/Lc/Le/[data]/Me1/Me2 memcpy(C_Apdu.data, R_Apdu.data, 3); // CLA/INS/P1 C_Apdu.length = 4; ptr = C_Apdu.data + 4; if ((TypeAPDU> 2) && LC) // Case 3 or 4 : Lc field is present { DataInSize = LC; C_Apdu.length += (1+DataInSize); *ptr++ = DataInSize; profil = 0; while(DataInSize--)/* Building data string*/ *ptr++ = profil++; // -> Lc data = 0,1,2...,Lc-1 } if ((TypeAPDU== 2) || (TypeAPDU == 4) ) // Le is present { C_Apdu.length++; *ptr++ = LE; } } C_Apdu.data[3] = ComputeLrc(R_Apdu.length, R_Apdu.data); // P2 } MSG_PC_to_RDR_IccPowerOff(); } S_Delay(TIME); return (RetCode); } /** * 功 能:协议测试入口 */ void AgreementTest(void) { INT iKey = 0; while (1) { MenuMainTestVisa(); iKey = ST_GetkeyMs(0) - '0'; /*库文件返回的 'BCD'*/ if (iKey == 3) break; MenuTestVisa(); if (iKey == 1) TestVisa(); else if (iKey == 2) { while (1) TestVisa(); } } } void ConectPC(void) { ST_Cls(); hapi_gpio_write(4, 0, 0); ST_Display(2, " 已连接PC机"); while (1) ; } int main(void) { INT iKey = 0; DevOpen(); ST_Cls(); while (InitAU9540()) /* 检查卡状态*/ ST_Display(2, " 亲,没插卡"); while (1) { MenuMain(); iKey = ST_GetkeyMs(0) - '0'; /*库文件返回的 'BCD'*/ switch (iKey) { case 1: CMD_SET_PCSC_EMV_SPEED(3); // 2 默认 3 低速 ElectricalTest(); break; case 2: CMD_SET_PCSC_EMV_SPEED(2); AgreementTest(); break; case 3: ConectPC(); break; default: break; } } return 0; }项目源码:loopback.rar