PC/SC(Personal Computer/Smart Card)规范,PC/SC 规范作为读卡器和卡与计算机之间有一个标准接口,实现不同生产商的卡和读卡器之间的交互操作
Linux下运行的源码pcsc-lite 在http://pcsclite.alioth.debian.org/
其中有demo例程
1.建立资源管理器上下文
LONG SCardEstablishContext(DWORD dwScope, LPCVOID pvReserved1,LPCVOID pvReserved2, LPSCARDCONTEXT phContext);
说明:这必须是在PC / SC应用程序中调用的第一个 SCard函数,所有的应用进程都必须建立自己的上下文环境
参数:
dwScope: 输入类型:表示上下文建立的范围,建立本地连接或远程连接,目前支持 SCARD_SCOPE_SYSTEM(在系统域中完成设备数据库操作)
pvReserved1: 输入类型:保留,为NULL
pvReserved2: 输入类型:保留,为NULL
phContext: 输出类型:返回创建的资源管理器上下文
返回:
成功返回 SCARD_S_SUCCESS
失败返回其他值,定义在 pcsclite.h
//@code
SCARDCONTEXT hContext;
LONG rv;
rv = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, &posContext);
if(rv != SCARD_S_SUCCESS)
{
LOGE("SCardEstablishContext::failed!\n");
ret = ERROR_APP_CONTEXT;
return ret;
}
2.获取系统可用读卡器列表
LONG SCardListReaders(SCARDCONTEXT hContext, /*@unused@*/ LPCSTR mszGroups,LPSTR mszReaders, LPDWORD pcchReaders);
说明:
创建上下文后,就可在上下文中获取系统安装的可用的读卡器列表
参数:
hContext: 输入类型;ScardEstablishContext()建立的资源管理器上下文,不能为NULL
mszGroups: 输入类型;读卡器组名,为 NULL 时,表示列出所有读卡器。
mszReaders: 输出类型;系统中安装的读卡器的名字,各个名字之间用'\0'分隔,最后一个名字后面为两个连续的'\0'
pcchReaders: 输入输出类型;mszReaders 的长度
这个函数在使用时有多种用法,主要是为了给读卡器列表创建空间的方法不同
1).当mszReaders为 NULL 时,调用一次SCardListReaders会给pcchReaders输出mszReaders所需要的空间大小,然后自己malloc申请内存空间
2).当mszReaders为 NULL 且pcchReaders = SCARD_AUTOALLOCATE 时,SCardListReaders会自动申请内存,但是用完后必须要使用SCardFreeMemory(hContext, mszReaders);释放
3).当mszReaders 不为 NULL 时,需用pcchReaders传入其长度,SCardListReaders会在已申请的空间内存放读卡器列表
返回:
成功返回 SCARD_S_SUCCESS
失败返回其他值,定义在 pcsclite.h
这里对3种创建方法做一下代码示例:
//@code1
SCARDCONTEXT hContext;
LPSTR mszReaders;
DWORD dwReaders;
LONG rv;
...
rv = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, &hContext);
rv = SCardListReaders(hContext, NULL, NULL, &dwReaders);
mszReaders = malloc(sizeof(char)*dwReaders);
rv = SCardListReaders(hContext, NULL, mszReaders, &dwReaders);
...
free(mszReaders);
//@code2
SCARDCONTEXT hContext;
LPSTR mszReaders;
DWORD dwReaders;
LONG rv;
...
rv = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, &hContext);
dwReaders = SCARD_AUTOALLOCATE;
rv = SCardListReaders(hContext, NULL, mszReaders, &dwReaders);
...
rv = SCardFreeMemory(hContext, mszReaders);
//@code3
SCARDCONTEXT hContext;
LPSTR mszReaders[512];
DWORD dwReaders;
LONG rv;
...
rv = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, &hContext);
dwReaders = sizeof(mszReaders);
rv = SCardListReaders(hContext, NULL, mszReaders, &dwReaders);
...
下边是对读卡器名字的拾取代码
char name[128][3];
ptr = mszReaders;
int count = 0;
while ((*ptr != '\0') && (dwReaders > 0) && (count < 3))
{
strcpy(&name[0][count], ptr);
lens = strlen(&name[0][count]);
ptr += (lens + 1);
dwReaders -= (lens + 1);
count++;
LOGD("SCardListReaders::Reader Count %d Name:%s\n", count, &name[0][count]);
}
01-17 10:56:44.727: D/smartcardjni(2393): SCardListReaders::Reader Count 1 Name:ZNG Terminal2012-1402 00 00
01-17 10:56:44.727: D/smartcardjni(2393): SCardListReaders::Reader Count 2 Name:ZNG Terminal2012-1402 01 00
3.监测卡片插入
LONG SCardGetStatusChange(SCARDCONTEXT hContext, DWORD dwTimeout,SCARD_READERSTATE *rgReaderStates, DWORD cReaders);
说明:
阻塞监听卡插入或状态发生改变
参数:
hContext: 输入类型;ScardEstablishContext()建立的资源管理器上下文
dwTimeout: 输入类型;监听等待时间,0 或 INFINITE(0xFFFFFFFF)表示永久等待
rgReaderStates: 输入输出类型;SCARD_READERSTATE 结构体
cReaders: 输入类型;卡通道数
返回:
成功返回 SCARD_S_SUCCESS
失败返回其他值,定义在 pcsclite.h
typedef struct
{
const char *szReader; //读卡器名
void *pvUserData; //私有数据
DWORD dwCurrentState; //读卡器当前状态
DWORD dwEventState; //读卡器状态改变后的事件
DWORD cbAtr; //ATR长度
unsigned char rgbAtr[MAX_ATR_SIZE];//ATR
}
SCARD_READERSTATE, *LPSCARD_READERSTATE;
//@code
SCARDCONTEXT hContext;
SCARD_READERSTATE rgReaderStates[2];
LONG rv;
...
rv = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, &hContext);
...
rgReaderStates[0].szReader = "Reader X";
rgReaderStates[0].dwCurrentState = SCARD_STATE_UNAWARE;
rgReaderStates[1].szReader = "\\\\?PnP?\\Notification";
rgReaderStates[1].dwCurrentState = SCARD_STATE_UNAWARE;
...
rv = SCardGetStatusChange(hContext, INFINITE, rgReaderStates, 2);
printf("reader state: 0x%04X\n", rgReaderStates[0].dwEventState);
printf("reader state: 0x%04X\n", rgReaderStates[1].dwEventState);
if(rgReaderStates[0].dwEventState & SCARD_STATE_PRESENT)//卡片插入
{
}
if(rgReaderStates[0].dwEventState & SCARD_STATE_EMPTY)//卡片移除
{
}
//@endcode
4.连接读卡器
LONG SCardConnect(SCARDCONTEXT hContext, LPCSTR szReader,DWORD dwShareMode, DWORD dwPreferredProtocols, LPSCARDHANDLE phCard,LPDWORD pdwActiveProtocol);
说明:使用该接口后,读卡器上电读取ATR
参数:
hContext: 输入类型;ScardEstablishContext()建立的资源管理器上下文
szReader: 输入类型:要连接的读卡器名
dwShareMode: 输入类型:连接类型 SCARD_SHARE_SHARED 多个应用共享同一个智能卡
SCARD_SHARE_EXCLUSIVE 应用独占智能卡
SCARD_SHARE_DIRECT 私有类型,不允许其他应用访问
dwPreferredProtocols: 输入类型:使用的协议类型
SCARD_PROTOCOL_T0 T=0协议
SCARD_PROTOCOL_T1 T=1协议
SCARD_PROTOCOL_RAW 原始协议
phCard: 输出类型:卡的连接句柄
pdwActiveProtocol: 输出类型:实际使用的协议
SCARD_PROTOCOL_T0 Use the T=0 protocol.
SCARD_PROTOCOL_T1 Use the T=1 protocol.
返回:
成功返回 SCARD_S_SUCCESS
失败返回其他值,定义在 pcsclite.h
rv = SCardConnect(hContext, "Reader X", SCARD_SHARE_SHARED, SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1, &hCard, &dwActiveProtocol);
5.获取卡片状态和ATR
LONG SCardStatus(SCARDHANDLE hCard, LPSTR mszReaderName,LPDWORD pcchReaderLen, LPDWORD pdwState,LPDWORD pdwProtocol, LPBYTE pbAtr, LPDWORD pcbAtrLen);
说明:
参数:
hCard: 输入类型:SCardConnect()建立的卡连接句柄
mszReaderName: 输入输出类型:连接的读卡器名
pcchReaderLen: 输入输出类型:mszReaderName 的长度,使用方法同 SCardListReaders 中的 pcchReaders
pdwState: 输出类型:读卡器的当前状态
SCARD_UNKNOWN 0x0001 /**< Unknown state */
SCARD_ABSENT 0x0002 /**< Card is absent */
SCARD_PRESENT 0x0004 /**< Card is present */
SCARD_SWALLOWED 0x0008 /**< Card not powered */
SCARD_POWERED 0x0010 /**< Card is powered */
SCARD_NEGOTIABLE 0x0020 /**< Ready for PTS */
SCARD_SPECIFIC 0x0040 /**< PTS has been set */
pdwProtocol: 输出类型:读卡器当前协议类型
SCARD_PROTOCOL_T0 Use the T=0 protocol.
SCARD_PROTOCOL_T1 Use the T=1 protocol.
pbAtr: 输出类型:当前卡片的ATR
pcbAtrLen: 输入输出类型:pbAtr 的长度,使用方法同 SCardListReaders 中的 pcchReaders
返回:
成功返回 SCARD_S_SUCCESS
失败返回其他值,定义在 pcsclite.h
//@code
...
dwAtrLen = sizeof(pbAtr);
dwReaderLen = sizeof(pbReader);
rv = SCardStatus(posReaderList.readerList[using_reader_id].hCard, pbReader, &dwReaderLen, &dwState, &dwProt, pbAtr, &dwAtrLen);
if (rv != SCARD_S_SUCCESS)
{
LOGE("SCardStatus %s (0x%lX)\n" , pcsc_stringify_error(rv), rv);
ret = SCARD_STATUS_FALSE;
}
LOGD("pbReader: %s\n", pbReader);
LOGD("pbAtr: %s\n", pbAtr);
6.读卡器数据传输
LONG SCardTransmit(SCARDHANDLE hCard, const SCARD_IO_REQUEST *pioSendPci,LPCBYTE pbSendBuffer, DWORD cbSendLength, SCARD_IO_REQUEST *pioRecvPci, LPBYTE pbRecvBuffer,LPDWORD pcbRecvLength);
说明:从卡连接成功后就能进行APDU数据传输
参数:
hCard: 输入类型:SCardConnect()建立的卡连接句柄
pioSendPci: 输入输出类型:发送的指令协议头结构的指针,由 SCARD_IO_REQUEST 结构定义
pbSendBuffer: 输入类型:发送给卡的APDU指令
cbSendLength: 输入类型:APDU的长度
pioRecvPci: 输入输出类型:接收的指令协议头结构的指针,由 SCARD_IO_REQUEST 结构定义,如果不返回可设置为NULL
pbRecvBuffer: 输出类型:从卡返回的数据
pcbRecvLength: 输入输出类型:pbRecvBuffer 的实际大小
返回:
成功返回 SCARD_S_SUCCESS
失败返回其他值,定义在 pcsclite.h
typedef struct
{
unsigned long dwProtocol; /**< Protocol identifier */
unsigned long cbPciLength; /**< Protocol Control Inf Length */
}SCARD_IO_REQUEST, *PSCARD_IO_REQUEST, *LPSCARD_IO_REQUEST;
//@code
rv = SCardConnect(hContext, "Reader X", SCARD_SHARE_SHARED, SCARD_PROTOCOL_T0, &hCard, &dwActiveProtocol);
dwSendLength = sizeof(pbSendBuffer);
dwRecvLength = sizeof(pbRecvBuffer);
rv = SCardTransmit(hCard, SCARD_PCI_T0, pbSendBuffer, dwSendLength,&pioRecvPci, pbRecvBuffer, &dwRecvLength);
7.独占访问
这组操作一遍用于SCardTransmit() 前后,让传输操作更加安全可靠
LONG SCardBeginTransaction(SCARDHANDLE hCard);
说明:启动一个事务,阻止其它应用程序访问智能卡
参数:
hCard: 输入类型:SCardConnect()建立的卡连接句柄
LONG SCardEndTransaction(SCARDHANDLE hCard, DWORD dwDisposition);
说明:结束一个事务,允许其它引用程序访问智能卡
参数:
hCard: 输入类型:SCardConnect()建立的卡连接句柄
dwDisposition 输入类型:结束时对读卡器的操作
8.重新连接读卡器
LONG SCardReconnect(SCARDHANDLE hCard, DWORD dwShareMode,DWORD dwPreferredProtocols, DWORD dwInitialization, LPDWORD pdwActiveProtocol);
说明:将正在连接的读卡器重新连接,等于热复位
参数:
hCard: 输入类型:SCardConnect()建立的卡连接句柄
dwShareMode: 输入类型:连接类型 SCARD_SHARE_SHARED 多个应用共享同一个智能卡
SCARD_SHARE_EXCLUSIVE 应用独占智能卡
SCARD_SHARE_DIRECT 私有类型,不允许其他应用访问
dwPreferredProtocols: 输入类型:使用的协议类型
SCARD_PROTOCOL_T0 T=0协议
SCARD_PROTOCOL_T1 T=1协议
SCARD_PROTOCOL_RAW 原始协议
dwInitialization: 输入类型:读卡器指定的操作,常用作重启
SCARD_LEAVE_CARD - Do nothing.
SCARD_RESET_CARD - Reset the card (warm reset).
SCARD_UNPOWER_CARD - Power down the card (cold reset).
SCARD_EJECT_CARD - Eject the card.
pdwActiveProtocol: 输出类型:实际使用的协议
返回:
成功返回 SCARD_S_SUCCESS
失败返回其他值,定义在 pcsclite.h
9.断开读卡器
LONG SCardDisconnect(SCARDHANDLE hCard, DWORD dwDisposition);
说明:断开读卡器连接
参数:
hCard: 输入类型:SCardConnect()建立的卡连接句柄
dwDisposition 输入类型:断开连接时对读卡器的操作
SCARD_LEAVE_CARD 0x0000 /**< Do nothing on close */
SCARD_RESET_CARD 0x0001 /**< Reset on close */
SCARD_UNPOWER_CARD 0x0002 /**< Power down on close */
SCARD_EJECT_CARD 0x0003 /**< Eject on close */
返回:
成功返回 SCARD_S_SUCCESS
失败返回其他值,定义在 pcsclite.h
//@code
rv = SCardDisconnect(hCard, SCARD_UNPOWER_CARD);
10.释放上下文
LONG SCardReleaseContext(SCARDCONTEXT hContext);
说明:应用程序终止前,释放资源管理器上下文
参数:
hContext: 输入类型;ScardEstablishContext()建立的资源管理器上下文
返回:
成功返回 SCARD_S_SUCCESS
失败返回其他值,定义在 pcsclite.h
示例代码:
//***********************************
#define MAX_READER_COUNTS 3
typedef struct _strReaderListInfo
{
char reader[128];
int trans_begin;
SCARDHANDLE hCard;
DWORD dwActiveProtocol;
SCARD_IO_REQUEST pioSendPci;
SCARD_IO_REQUEST pioRecvPci;
}StrReaderListInfo, *pStrReaderListInfo;
typedef struct _strReaderList
{
int count;
StrReaderListInfo readerList[MAX_READER_COUNTS];
}StrReaderList, *pStrReaderList;
unsigned int posReaderId = 1; //readerid
StrReaderList posReaderList = {0};
SCARDCONTEXT posContext = 0;
DWORD posActiveProtocol[MAX_READER_COUNTS];
//上下文初始化
unsigned int Pcscd_Init()
{
LOGD("%s",__FUNCTION__);
unsigned int ret = ERROR_NONE;
LONG rv = 0;
unsigned int lens = 0;
DWORD dwReaders;
unsigned char reader_list_buf[512];
pStrReaderListInfo pStrInfo;
unsigned char *ptr = NULL;
unsigned int tryAgain = 0;
START:
if(posContext != 0)
{
LOGE("SCardEstablishContext::Context has already been created,Release!\n");
rv = SCardReleaseContext(hContext);
if(rv != SCARD_S_SUCCESS)
{
LOGE("SCardReleaseContext::failed!\n");
}
hContext = 0;
}
//建立上下文
memset(&posReaderList, 0, sizeof(StrReaderList));
rv = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, &posContext);
if(rv != SCARD_S_SUCCESS)
{
LOGE("SCardEstablishContext::failed!\n");
ret = ERROR_APP_CONTEXT;
return ret;
}
LOGD("SCardEstablishContext::success!\n");
//获取读卡器列表
dwReaders = sizeof(reader_list_buf);
rv = SCardListReaders(posContext, NULL, reader_list_buf, &dwReaders);
if(rv != SCARD_S_SUCCESS)
{
LOGE("SCardListReaders::native failed!(0x%x)\n",rv);
if(posContext != 0)
{
SCardReleaseContext(posContext);
posContext = 0;
}
if(rv == SCARD_E_NO_READERS_AVAILABLE)
{
ret = ERROR_APP_REBOOT_POS;
}
else
{
ret = ERROR_APP_LISTREADER;
}
return ret;
}
reader_list_buf[dwReaders] = 0x00;
reader_list_buf[dwReaders + 1] = 0x00;
posReaderList.count = 0;
ptr = reader_list_buf;
while ((*ptr != '\0') && (dwReaders > 0))
{
pStrInfo = &posReaderList.readerList[posReaderList.count];
strcpy(pStrInfo->reader, ptr);
lens = strlen(pStrInfo->reader);
ptr += (lens + 1);
dwReaders -= (lens + 1);
// pStrInfo->hCard = 0;
posReaderList.count++;
LOGD("SCardListReaders::Reader Count %d Name:%s\n", posReaderList.count, pStrInfo->reader);
if(posReaderList.count >= MAX_READER_COUNTS)
{
break;
}
}
if (posReaderList.count < 2)
{
LOGE("[%d]::reader count = %d!!!\n",__LINE__,posReaderList.count);
SCardStopDeamon(posContext);
sleep(3);
if(posContext != 0)
{
SCardReleaseContext(posContext);
posContext = 0;
}
if(tryAgain == 0)
{
ret = ERROR_NONE;
tryAgain = 1;
LOGE("init try again");
goto START;
}
else
{
ret = ERROR_APP_LISTREADER;
return ret;
}
}
LOGD("SCardListReaders::success!\r\n");
ret = ERROR_NONE;
return ret;
}
//释放上下文
unsigned int Pcscd_Release()
{
LOGD("%s",__FUNCTION__);
unsigned int ret = ERROR_NONE;
int rv;
pStrReaderListInfo pStrInfo;
if(posContext == 0)
{
LOGE("SCardReleaseContext::Context has not been created!\n");
ret = ERROR_NONE;
return ret;
}
memset(&posReaderList, 0, sizeof(StrReaderList));
rv = SCardReleaseContext(posContext);
if(rv != SCARD_S_SUCCESS)
{
LOGE("SCardReleaseContext::native failed!\n");
posContext = 0;
ret = ERROR_APP_CONTEXT;
return ret;
}
posContext = 0;
LOGD("SCardReleaseContext::success!\n");
ret = ERROR_NONE;
return ret;
}
//断开卡连接
int PBOC_DisConnect(unsigned int using_reader_id)
{
LOGD("%s(%d)",__FUNCTION__,using_reader_id);
LONG rv;
pStrReaderListInfo pStrInfo;
if(using_reader_id < 0 || using_reader_id >= posReaderList.count)
{
LOGE("[%d]reader id is wrong(%d)\n",__LINE__, using_reader_id);
// Nok_Reason = ErrorReason_PCSCD_READERS_ID;
return FALSE;
}
pStrInfo = &posReaderList.readerList[using_reader_id];
if(pStrInfo->trans_begin == 1)
{
rv = SCardEndTransaction(pStrInfo->hCard,SCARD_LEAVE_CARD);
if (rv != SCARD_S_SUCCESS)
{
if(rv == SCARD_E_NO_SERVICE || rv == SCARD_E_UNKNOWN_READER)
{
Reset_Reader();
}
LOGE("[%d]::SCardEndTransaction: %s (0x%lX)\n",__LINE__ ,pcsc_stringify_error(rv),rv);
}
pStrInfo->trans_begin = 0;
}
if(pStrInfo->hCard != 0)
{
rv = SCardDisconnect(pStrInfo->hCard,SCARD_UNPOWER_CARD);
if (rv != SCARD_S_SUCCESS)
{
if(rv == SCARD_E_NO_SERVICE || rv == SCARD_E_UNKNOWN_READER)
{
Reset_Reader();
}
LOGE("[%d]::SCardDisconnect: %s (0x%lX)\n",__LINE__ ,pcsc_stringify_error(rv),rv);
}
pStrInfo->hCard = 0;
}
return TRUE;
}
int PBOC_OpenCard(unsigned char* pAtr,unsigned int * pAtrlen)
{
int ret;
LOGD("%s",__FUNCTION__);
//检卡
DWORD dwReaderLen, dwState, dwProt, dwAtrLen;
BYTE pbAtr[MAX_ATR_SIZE] = "";
char pbReader[MAX_READERNAME] = "";
pStrReaderListInfo pStrInfo;
SCARD_READERSTATE rgReaderStates[1];
pStrInfo = &posReaderList.readerList[posReaderId];
dwAtrLen = sizeof(pbAtr);
dwReaderLen = sizeof(pbReader);
smart_card_type = 0;
rgReaderStates[0].szReader = posReaderList.readerList[posReaderId].reader;
rgReaderStates[0].dwCurrentState = SCARD_STATE_UNAWARE;
//检测是否有卡插入
ret = SCardGetStatusChange(posContext,INFINITE,rgReaderStates,1);
if (ret != SCARD_S_SUCCESS)
{
printf("SCardGetStatusChange err\r\n");
return -1;
}
LOGD("SCardGetStatusChange ok\r\n");
LOGD("rgReaderStates[0].dwEventState == %ld\r\n",rgReaderStates[0].dwEventState);
if(rgReaderStates[0].dwEventState & SCARD_STATE_PRESENT)//卡在
{
ret= SCardConnect(posContext, pStrInfo->reader, SCARD_SHARE_SHARED,
SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1, &pStrInfo->hCard, &posActiveProtocol[posReaderId]);
if (ret == SCARD_S_SUCCESS)
{
ret = SCardStatus(pStrInfo->hCard, pbReader, &dwReaderLen, &dwState, &dwProt,pbAtr, &dwAtrLen);
if (ret != SCARD_S_SUCCESS)
{
return -1;
}
MyPrintfBuff("CardAtr:",pbAtr, dwAtrLen);
//判断ATR是否是非接触卡
if((pbAtr[2] == 0x81 && pbAtr[3] == 0x01)||(pbAtr[2] == 0x11 && pbAtr[3] == 0x01) )
{
smart_card_type = 2;
}
//判断ATR 多张非接触卡
else if((pbAtr[1] == 0x70 && pbAtr[2] == 0x11) )
{
smart_card_type = 3;
}
//判断ATR是否是接触卡
else if(!((pbAtr[2] == 0x81 && pbAtr[3] == 0x01)||(pbAtr[2] == 0x11 && pbAtr[3] == 0x01) ||(pbAtr[1] == 0x60 && pbAtr[2] == 0x00)))
{
smart_card_type = 1;
}
else
{
smart_card_type = -1;
}
switch(posActiveProtocol[posReaderId])
{
case SCARD_PROTOCOL_T0:
pStrInfo->pioSendPci = *SCARD_PCI_T0;
LOGD("using T0");
break;
case SCARD_PROTOCOL_T1:
pStrInfo->pioSendPci = *SCARD_PCI_T1;
LOGD("using T1");
break;
default:
LOGE("Unknown protocol. No card present?\n");
}
MyMemcpy(pAtr,pbAtr, dwAtrLen);
*pAtrlen = dwAtrLen;
}
else
{
}
}
return smart_card_type;
}
//建立卡连接,并做好传输准备
int PBOC_Connect(int using_reader_id)
{
LOGD("%s(%d)",__FUNCTION__,using_reader_id);
LONG rv;
int ret = TRUE;
DWORD dwReaderLen, dwState, dwProt, dwAtrLen;
BYTE pbAtr[MAX_ATR_SIZE] = "";
char pbReader[MAX_READERNAME] = "";
pStrReaderListInfo pStrInfo;
unsigned int i;
unsigned int counts = 0;
if(using_reader_id < 0 || using_reader_id >= posReaderList.count)
{
LOGE("[%d]reader id is wrong(%d)\n",__LINE__, using_reader_id);
ret = FALSE;
// Nok_Reason = ErrorReason_PCSCD_READERS_ID;
goto ERROR;
}
pStrInfo = &posReaderList.readerList[using_reader_id];
/* connect to a reader (even without a card) */
LOGD("[%d]Using reader: %s\n",__LINE__, posReaderList.readerList[using_reader_id].reader);
while(1)
{
if(posReaderList.readerList[using_reader_id].hCard != 0)
{
LOGD("connected(%d)",(int)posActiveProtocol[using_reader_id]);
rv = SCARD_S_SUCCESS;
LOGD("SCardReconnect");
rv = SCardReconnect(posReaderList.readerList[using_reader_id].hCard, /*SCARD_SHARE_SHARED*/SCARD_SHARE_SHARED,
SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1,SCARD_RESET_CARD, (DWORD*)&posActiveProtocol);
}
else
{
LOGD("connect");
rv = SCardConnect(posContext, posReaderList.readerList[using_reader_id].reader, /*SCARD_SHARE_EXCLUSIVE*/SCARD_SHARE_SHARED,
SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1, &posReaderList.readerList[using_reader_id].hCard, &posActiveProtocol[using_reader_id]);
}
if (rv != SCARD_S_SUCCESS)
{
LOGE("SCardConnect %s (0x%lX)\n" , pcsc_stringify_error(rv), rv);
counts++;
if(rv == SCARD_E_SHARING_VIOLATION)
{
if(counts < 10)
{
usleep(500*1000);
LOGE("reader is busy,wait 500ms try again(%d)",counts);
continue;
}
}
else if(rv == SCARD_E_NO_SERVICE || rv == SCARD_E_UNKNOWN_READER)
{
Reset_Reader();
if(counts < 2)
{
LOGE("try again(%d)",counts);
continue;
}
}
ret = FALSE;
// Nok_Reason = ErrorReason_PCSCD_CONNECT_READERS;
goto ERROR_NOTHING;
}
else
{
break;
}
}
pStrInfo->dwActiveProtocol = posActiveProtocol[using_reader_id];
/* get card status */
dwAtrLen = sizeof(pbAtr);
dwReaderLen = sizeof(pbReader);
rv = SCardStatus(posReaderList.readerList[using_reader_id].hCard, pbReader, &dwReaderLen, &dwState, &dwProt,
pbAtr, &dwAtrLen);
if (rv != SCARD_S_SUCCESS)
{
LOGE("SCardStatus %s (0x%lX)\n" , pcsc_stringify_error(rv), rv);
ret = FALSE;
// Nok_Reason = ErrorReason_PCSCD_GET_READERS_STATUS;
goto ERROR;
}
LOGD(" State: 0x%04lX\n", dwState);
if (dwState & SCARD_ABSENT)
{
LOGE("No card inserted\n");
ret = FALSE;
// Nok_Reason = ErrorReason_PCSCD_NO_CARDS_INSIDE;
goto ERROR;
}
switch(posActiveProtocol[using_reader_id])
{
case SCARD_PROTOCOL_T0:
pStrInfo->pioSendPci = *SCARD_PCI_T0;
LOGD("using T0");
break;
case SCARD_PROTOCOL_T1:
pStrInfo->pioSendPci = *SCARD_PCI_T1;
LOGD("using T1");
break;
default:
LOGE("Unknown protocol. No card present?\n");
ret = FALSE;
// Nok_Reason = ErrorReason_PCSCD_NO_PROTOCOLS_SELECT;
goto ERROR;
}
rv = SCardBeginTransaction(posReaderList.readerList[using_reader_id].hCard);
if (rv != SCARD_S_SUCCESS)
{
if(rv == SCARD_E_NO_SERVICE || rv == SCARD_E_UNKNOWN_READER)
{
Reset_Reader();
}
LOGE("SCardBeginTransaction %s (0x%lX)\n" , pcsc_stringify_error(rv), rv);
ret = FALSE;
// Nok_Reason = ErrorReason_PCSCD_BEGIN_TRANSACTION;
goto ERROR;
}
pStrInfo->trans_begin = 1;
LOGD("SCardBeginTransaction::success!\n");
return ret;
ERROR:
rv = SCardDisconnect(posReaderList.readerList[using_reader_id].hCard,SCARD_UNPOWER_CARD);
if (rv != SCARD_S_SUCCESS)
{
if(rv == SCARD_E_NO_SERVICE || rv == SCARD_E_UNKNOWN_READER)
{
Reset_Reader();
}
LOGE("[%d]::SCardDisconnect: %s (0x%lX)\n",__LINE__ ,pcsc_stringify_error(rv),rv);
}
ERROR_NOTHING:
return ret;
}
//卡上电连接并获取ATR
int PBOC_PowerOn(int using_reader_id,unsigned char* pAtr,unsigned int * pAtrlen)
{
LOGD("%s",__FUNCTION__);
LONG rv;
int ret = TRUE;
DWORD dwReaderLen, dwState, dwProt, dwAtrLen;
BYTE pbAtr[MAX_ATR_SIZE] = "";
char pbReader[MAX_READERNAME] = "";
pStrReaderListInfo pStrInfo;
unsigned int i;
unsigned int counts = 0;
if(using_reader_id < 0 || using_reader_id >= posReaderList.count)
{
LOGE("[%d]reader id is wrong(%d)\n",__LINE__, using_reader_id);
ret = FALSE;
return ret;
}
pStrInfo = &posReaderList.readerList[using_reader_id];
/* connect to a reader (even without a card) */
LOGD("[%d]Using reader: %s\n",__LINE__, posReaderList.readerList[using_reader_id].reader);
while(1)
{
if(pStrInfo->hCard != 0)
{
LOGD("SCardConnect(%d)",(int)posActiveProtocol[using_reader_id]);
rv = SCARD_S_SUCCESS;
//LOGD("SCardReconnect");
//rv = SCardReconnect(pStrInfo->hCard, /*SCARD_SHARE_SHARED*/SCARD_SHARE_EXCLUSIVE, SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1,
// SCARD_RESET_CARD, &dwposActiveProtocol);
}
else
{
LOGD("SCardConnect");
rv = SCardConnect(posContext, pStrInfo->reader, /*SCARD_SHARE_SHARED*/SCARD_SHARE_SHARED,
SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1, &pStrInfo->hCard, &posActiveProtocol[using_reader_id]);
}
if (rv != SCARD_S_SUCCESS)
{
LOGE("SCardConnect %s (0x%lX)\n" , pcsc_stringify_error(rv), rv);
counts++;
if(rv == SCARD_E_SHARING_VIOLATION)
{
if(counts < 10)
{
usleep(500*1000);
LOGE("reader is busy,wait 500ms try again(%d)",counts);
continue;
}
}
else if(rv == SCARD_E_NO_SERVICE || rv == SCARD_E_UNKNOWN_READER)
{
usleep(2000*1000);
Pcscd_Init();
if(counts < 2)
{
LOGE("try again(%d)",counts);
continue;
}
}
ret = FALSE;
goto ERROR_NOTHING;
}
else
{
break;
}
}
pStrInfo->dwActiveProtocol = posActiveProtocol[using_reader_id];
/* get card status */
dwAtrLen = sizeof(pbAtr);
dwReaderLen = sizeof(pbReader);
//获取卡状态信息
rv = SCardStatus(pStrInfo->hCard, pbReader, &dwReaderLen, &dwState, &dwProt,
pbAtr, &dwAtrLen);
if (rv != SCARD_S_SUCCESS)
{
LOGE("SCardStatus %s (0x%lX)\n" , pcsc_stringify_error(rv), rv);
ret = FALSE;
goto ERROR;
}
LOGD(" State: 0x%04lX\n", dwState);
if (dwState & SCARD_ABSENT)
{
LOGE("No card inserted\n");
ret = FALSE;
goto ERROR;
}
switch(posActiveProtocol[using_reader_id])
{
case SCARD_PROTOCOL_T0:
pStrInfo->pioSendPci = *SCARD_PCI_T0;
LOGD("using T0");
break;
case SCARD_PROTOCOL_T1:
pStrInfo->pioSendPci = *SCARD_PCI_T1;
LOGD("using T1");
break;
default:
LOGE("Unknown protocol. No card present?\n");
ret = FALSE;
goto ERROR;
}
MyMemcpy(pbAtr,pAtr,dwAtrLen);
*pAtrlen = dwAtrLen;
//准备传输状态
rv = SCardBeginTransaction(pStrInfo->hCard);
if (rv != SCARD_S_SUCCESS)
{
if(rv == SCARD_E_NO_SERVICE || rv == SCARD_E_UNKNOWN_READER)
{
Reset_Reader();
}
LOGE("SCardBeginTransaction %s (0x%lX)\n" , pcsc_stringify_error(rv), rv);
ret = FALSE;
goto ERROR;
}
pStrInfo->trans_begin = 1;
LOGD("SCardBeginTransaction::success!\n");
return ret;
ERROR:
rv = SCardDisconnect(pStrInfo->hCard,SCARD_UNPOWER_CARD);
if (rv != SCARD_S_SUCCESS)
{
if(rv == SCARD_E_NO_SERVICE || rv == SCARD_E_UNKNOWN_READER)
{
Reset_Reader();
}
LOGE("[%d]::SCardDisconnect: %s (0x%lX)\n",__LINE__ ,pcsc_stringify_error(rv),rv);
}
ERROR_NOTHING:
return ret;
}
int PBOC_PowerOff(int using_reader_id)
{
LOGD("%s",__FUNCTION__);
LONG rv;
pStrReaderListInfo pStrInfo;
pStrInfo = &posReaderList.readerList[using_reader_id];
//结束传输
if(pStrInfo->trans_begin == 1)
{
rv = SCardEndTransaction(pStrInfo->hCard,SCARD_LEAVE_CARD);
if (rv != SCARD_S_SUCCESS)
{
if(rv == SCARD_E_NO_SERVICE || rv == SCARD_E_UNKNOWN_READER)
{
ResetReader();
}
LOGE("[%d]::SCardEndTransaction: %s (0x%lX)\n",__LINE__ ,pcsc_stringify_error(rv),rv);
}
pStrInfo->trans_begin = 0;
}
//断开连接
if(posReaderList.readerList[using_reader_id].hCard != 0)
{
LOGD("SCardDisconnect");
rv = SCardDisconnect(pStrInfo->hCard,SCARD_UNPOWER_CARD);
if (rv != SCARD_S_SUCCESS)
{
if(rv == SCARD_E_NO_SERVICE || rv == SCARD_E_UNKNOWN_READER)
{
Reset_Reader();
}
LOGE("[%d]::CloudPos_PowerOff: %s (0x%lX)\n",__LINE__ ,pcsc_stringify_error(rv),rv);
}
pStrInfo->hCard = 0;
}
return rv;
}
int PBOC_APDU_SendAPI(unsigned int using_reader_id,unsigned char * bSendBuffer,unsigned int send_length,unsigned char * bRecvBuffer,unsigned int *length)
{
LOGD("%s",__FUNCTION__);
LONG rv;
int ret = 0;
unsigned int i;
unsigned char temp[64] = {0};
//char debug_buffer[512] = {0};
pStrReaderListInfo pStrInfo;
if(using_reader_id < 0 || using_reader_id >= posReaderList.count)
{
LOGE("[%d]reader id is wrong(%d)\n",__LINE__, using_reader_id);
ret = FALSE;
goto SEND_ERROR;
}
#ifdef SE_KL81
if(send_length%64 == 54)
{
LOGI("fill 0xFFFF");
bSendBuffer[send_length] = 0xFF;
bSendBuffer[send_length+1] = 0xFF;
send_length += 2;
}
#endif
pStrInfo = &posReaderList.readerList[using_reader_id];
/* APDU select applet */
LOGD("[%d]::PBOC_APDU_SendAPI()::Dev send to card:\n",__LINE__);
if(send_length >= 256)
{
LOGD("send_length is bigger then print buffer length");
}
else
{
MyPrintfBuff("APDU_send:",bSendBuffer, send_length);
}
*length = MAX_BUFFER_SIZE_SZ;
MyMemset(bRecvBuffer,0x00,MAX_BUFFER_SIZE_SZ);
if(memcmp(&pStrInfo->pioSendPci,SCARD_PCI_T0,sizeof(pStrInfo->pioSendPci)) == 0)
{
LOGD("using T0");
}
else if(memcmp(&pStrInfo->pioSendPci,SCARD_PCI_T1,sizeof(pStrInfo->pioSendPci)) == 0)
{
LOGD("using T1");
}
else
{
LOGD("using None");
}
rv = SCardTransmit(pStrInfo->hCard, &pStrInfo->pioSendPci, bSendBuffer, (DWORD)send_length,
&pStrInfo->pioRecvPci, bRecvBuffer, (DWORD *)length);
if(rv != SCARD_S_SUCCESS)
{
if(rv == SCARD_E_NO_SERVICE || rv == SCARD_E_UNKNOWN_READER)
{
Reset_Reader();
}
MyMemset(bRecvBuffer,0x00,MAX_BUFFER_SIZE_SZ);
LOGE("SCardTransmit error,try again!(0x%08x)(%d)",(unsigned int)rv,*length);
snprintf(temp,sizeof(temp),"SCardTransmit error(0x%x)",(unsigned int)rv);
sleep(1);
*length = MAX_BUFFER_SIZE_SZ;
rv = SCardTransmit(pStrInfo->hCard, &pStrInfo->pioSendPci, bSendBuffer, (DWORD )send_length,
&pStrInfo->pioRecvPci, bRecvBuffer,(DWORD *) length);
if(rv != SCARD_S_SUCCESS)
{
if(rv == SCARD_E_NO_SERVICE || rv == SCARD_E_UNKNOWN_READER)
{
Reset_Reader();
}
LOGE("(rv = 0x%08x)",(unsigned int)rv);
snprintf(temp,sizeof(temp),"SCardTransmit error again(0x%x)",(unsigned int)rv);
ret = FALSE;
goto SEND_ERROR;
}
}
LOGD("[%d]::Card response to dev:\n",__LINE__);
if(*length >= 5120)
{
LOGD("length is bigger then print buffer length.");
}
else
{
MyPrintfBuff("APDU_Recv:",bRecvBuffer, *length);
}
if(*length > 54 && (*length+10)%64 == 2 && (bRecvBuffer[*length-2] == 0xFF && bRecvBuffer[*length-1] == 0xFF))
{
LOGD("clean FFFF");
(*length) -= 2;
}
PRASE_CARD_RETURN_STATUS:
if(bRecvBuffer[*length-2] == 0x61)
{
LOGD("[%d]::Dev 0x61 to card:\n",__LINE__);
memset(bSendBuffer,0x00,MAX_BUFFER_SIZE_SZ);
usleep(100*1000);
LOGD("[%d]::Card with the remaining returned to %02x%02x\n",__LINE__,bRecvBuffer[0],bRecvBuffer[1]);
send_length = 5;//00 C0 00 00 2A
memcpy(bSendBuffer, "\x00\xC0\x00\x00",send_length-1);
bSendBuffer[send_length-1] = bRecvBuffer[*length-1];
LOGD("[%d]::Dev send to card:\n",__LINE__);
MyMemset(bRecvBuffer,0x00,MAX_BUFFER_SIZE_SZ);
*length = MAX_BUFFER_SIZE_SZ;
rv = SCardTransmit(pStrInfo->hCard, &pStrInfo->pioSendPci, bSendBuffer, (DWORD )send_length,
&pStrInfo->pioRecvPci, bRecvBuffer, (DWORD *)length);
MyPrintfBuff("APDU_Recv:",bRecvBuffer, *length);
if(rv != SCARD_S_SUCCESS)
{
if(rv == SCARD_E_NO_SERVICE || rv == SCARD_E_UNKNOWN_READER)
{
Reset_Reader();
}
MyMemset(bRecvBuffer,0x00,MAX_BUFFER_SIZE_SZ);
LOGE("SCardTransmit error,try again!");
snprintf(temp,sizeof(temp),"SCardTransmit error(0x%x)",(unsigned int)rv);
*length = MAX_BUFFER_SIZE_SZ;
sleep(1);
rv = SCardTransmit(pStrInfo->hCard, &pStrInfo->pioSendPci, bSendBuffer, (DWORD )send_length,
&pStrInfo->pioRecvPci, bRecvBuffer, (DWORD *)length);
if(rv != SCARD_S_SUCCESS)
{
if(rv == SCARD_E_NO_SERVICE || rv == SCARD_E_UNKNOWN_READER)
{
Reset_Reader();
}
LOGE("SCardTransmit error!");
snprintf(temp,sizeof(temp),"SCardTransmit error again(0x%x)",(unsigned int)rv);
ret = FALSE;
goto SEND_ERROR;
}
}
LOGD("[%d]::Card response to dev:\n",__LINE__);
//memset(debug_buffer,0,sizeof(debug_buffer));
if(*length >= 5120)
{
LOGE("length is bigger then print buffer length");
}
else
{
// myAsciiToHex(bRecvBuffer, debug_buffer, *length);
MyPrintfBuff("APDU_Recv:",bRecvBuffer, *length);
}
if(*length > 54 && (*length+10)%64 == 2 && (bRecvBuffer[*length-2] == 0xFF && bRecvBuffer[*length-1] == 0xFF))
{
LOGD("clean FFFF");
(*length) -= 2;
}
}
else if(bRecvBuffer[*length-2] == 0x6C)
{
LOGD("[%d]::Dev 0x6C to card:\n",__LINE__);
bSendBuffer[send_length-1] = bRecvBuffer[*length-1];
MyMemset(bRecvBuffer,0x00,MAX_BUFFER_SIZE_SZ);
rv = SCardTransmit(pStrInfo->hCard, &pStrInfo->pioSendPci, bSendBuffer,(DWORD ) send_length,
&pStrInfo->pioRecvPci, bRecvBuffer, (DWORD *)length);
if(rv != SCARD_S_SUCCESS)
{
if(rv == SCARD_E_NO_SERVICE || rv == SCARD_E_UNKNOWN_READER)
{
Reset_Reader();
}
MyMemset(bRecvBuffer,0x00,MAX_BUFFER_SIZE_SZ);
LOGE("SCardTransmit error,try again!");
*length = MAX_BUFFER_SIZE_SZ;
sleep(1);
rv = SCardTransmit(pStrInfo->hCard, &pStrInfo->pioSendPci, bSendBuffer, (DWORD )send_length,
&pStrInfo->pioRecvPci, bRecvBuffer, (DWORD*)length);
if(rv != SCARD_S_SUCCESS)
{
if(rv == SCARD_E_NO_SERVICE || rv == SCARD_E_UNKNOWN_READER)
{
Reset_Reader();
}
// Nok_Reason = ErrorReason_PCSCD_TRANSMIT;
ret = FALSE;
goto SEND_ERROR;
}
}
if(*length > 54 && (*length+10)%64 == 2 && (bRecvBuffer[*length-2] == 0xFF && bRecvBuffer[*length-1] == 0xFF))
{
LOGD("clean FFFF");
(*length) -= 2;
}
goto PRASE_CARD_RETURN_STATUS;
}
else if((bRecvBuffer[*length-2] == 0x6A )&&( bRecvBuffer[*length-1] == 0x83))
{
LOGD("[%d]::Card response 6A83",__LINE__);
}
else if((bRecvBuffer[*length-2] != 0x90)||(bRecvBuffer[*length-1] != 0x00))
{
LOGE("Cards respont isn't 0x9000(0x%02X%02X)!\n",bRecvBuffer[*length-2],bRecvBuffer[*length-1]);
}
else
{
//LOGD("[%d]::Card response to dev:\n",__LINE__);
//memset(debug_buffer,0,sizeof(debug_buffer));
if(*length >= 5120)
{
LOGE("length is bigger then print buffer length");
}
else
{
//myAsciiToHex(bRecvBuffer, debug_buffer, *length);
//MyPrintfBuff("APDU_Recv:",bRecvBuffer, *length);
}
}
SEND_ERROR:
return ret;
}
//main.c
//使用test程序做PSAM卡和ICC卡通道通讯
ret = Pcscd_Init();
if(ret != 0)//读卡器未找到
{
return -1;
}
while(1)
{
printf("Please input command:\n");
printf("################################\n");
printf("'0' is select PSAM CARD\n");
printf("'1' is select ICC CARD\n");
printf("'quit' is return\n");
printf("'break' is go back\n");
printf("################################\n");
MyMemset(camd_buf,0,sizeof(camd_buf));
scanf("%s",camd_buf);
getchar();
if(MyMemcmp("0",camd_buf,MyStrlen("0")) == 0)
{
while(1)
{
printf("Please input APDU:\n");
MyMemset(camd_buf,0,sizeof(camd_buf));
scanf("%s",camd_buf);
getchar();
if(MyMemcmp("break",camd_buf,MyStrlen("break")) == 0)
break;
MyStrToHex((camd_buf),send_buf);
ret = CloudPos_SendToPcscd((unsigned char *)send_buf,0,recv_buf,&recv_len);
MyPrintfBuff("recv_buf::",recv_buf,recv_len);
}
}
else if(memcmp("1",camd_buf,MyStrlen("1")) == 0)
{
ret = PBOC_Connect(1);
if(ret == FALSE)
{
printf("Connect(1) error Please try again!\n");
}
else
{
printf("Connect(1) sucess\n");
while(1)
{
printf("Please input APDU:\n");
MyMemset(camd_buf,0,sizeof(camd_buf));
scanf("%s",camd_buf);
getchar();
if(MyMemcmp("break",camd_buf,MyStrlen("break")) == 0)
break;
send_len = MyStrToHex((camd_buf),send_buf);
ret = PBOC_APDU_SendAPI(1,send_buf,send_len,recv_buf,&recv_len);
MyPrintfBuff("recv_buf::",recv_buf,recv_len);
}
}
PBOC_DisConnect(1);
}
else if(MyMemcmp("quit",camd_buf,MyStrlen("quit")) == 0)
{
break;
}
}
Pcscd_Release();