/* Public platform independent Near Field Communication (NFC) library Copyright (C) 2009, Roel Verdult This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include #include #include "acr122.h" #include "bitutils.h" #define SCARD_OPERATION_SUCCESS 0x61 #define SCARD_OPERATION_ERROR 0x63 #define FIRMWARE_TEXT "ACR122U10" // ACR122U101(ACS), ACR122U102(Tikitag) #define ACR122_WRAP_LEN 5 #define ACR122_COMMAND_LEN 266 #define ACR122_RESPONSE_LEN 268 #define MAX_READERS 16 static SCARDCONTEXT hCtx = null; static byte abtTxBuf[ACR122_WRAP_LEN+ACR122_COMMAND_LEN] = { 0xFF, 0x00, 0x00, 0x00 }; static byte abtRxCmd[5] = { 0xFF,0xC0,0x00,0x00 }; static byte uiRxCmdLen = sizeof(abtRxCmd); static byte abtRxBuf[ACR122_RESPONSE_LEN]; static ulong ulRxBufLen; static byte abtGetFw[5] = { 0xFF,0x00,0x48,0x00,0x00 }; static byte abtLed[9] = { 0xFF,0x00,0x40,0x05,0x04,0x00,0x00,0x00,0x00 }; dev_id acr122_connect(const ui32 uiDeviceIndex) { SCARDHANDLE hCard = null; char* pacReaders[MAX_READERS]; char acList[256+64*MAX_READERS]; ulong ulListLen = sizeof(acList); ulong ulActiveProtocol = 0; ui32 uiPos; ui32 uiReaderCount; ui32 uiReader; ui32 uiReaderIndex; // Clear the reader list memset(acList,0x00,ulListLen); // Test if context succeeded if (SCardEstablishContext(SCARD_SCOPE_USER,null,null,&hCtx) != SCARD_S_SUCCESS) return INVALID_DEVICE_ID; // Retrieve the string array of all available pcsc readers if (SCardListReaders(hCtx,null,acList,(void*)&ulListLen) != SCARD_S_SUCCESS) return INVALID_DEVICE_ID; pacReaders[0] = acList; uiReaderCount = 1; for (uiPos=0; uiPos ACR122_COMMAND_LEN) return false; // Store the length of the command we are going to send abtTxBuf[4] = uiTxLen; #ifdef _LIBNFC_VERBOSE_ printf("Tx: "); print_hex(pbtTx,uiTxLen); #endif // Prepare and transmit the send buffer memcpy(abtTxBuf+5,pbtTx,uiTxLen); ulRxBufLen = sizeof(abtRxBuf); if (SCardTransmit((SCARDHANDLE)di,SCARD_PCI_T0,abtTxBuf,uiTxLen+5,null,abtRxBuf,(void*)&ulRxBufLen) != SCARD_S_SUCCESS) return false; // Make sure we received the byte-count we expected if (ulRxBufLen != 2) return false; // Check if the operation was successful, so an answer is available if (*abtRxBuf == SCARD_OPERATION_ERROR) return false; // Retrieve the response bytes abtRxCmd[4] = abtRxBuf[1]; ulRxBufLen = sizeof(abtRxBuf); if (SCardTransmit((SCARDHANDLE)di,SCARD_PCI_T0,abtRxCmd,uiRxCmdLen,null,abtRxBuf,(void*)&ulRxBufLen) != SCARD_S_SUCCESS) return false; // When the answer should be ignored, just return true if (pbtRx == null || puiRxLen == null) return true; // Make sure we have an emulated answer that fits the return buffer if (ulRxBufLen < 4 || (ulRxBufLen-4) > *puiRxLen) return false; // Wipe out the 4 APDU emulation bytes: D5 4B .. .. .. 90 00 *puiRxLen = ulRxBufLen-4; memcpy(pbtRx,abtRxBuf+2,*puiRxLen); #ifdef _LIBNFC_VERBOSE_ printf("Rx: "); print_hex(pbtRx,*puiRxLen); #endif // Transmission went successful return true; } char* acr122_firmware(const dev_id di) { static char abtFw[11]; ulong ulFwLen = sizeof(abtFw); memset(abtFw,0x00,ulFwLen); SCardTransmit((SCARDHANDLE)di,SCARD_PCI_T0,abtGetFw,sizeof(abtGetFw),null,(byte*)abtFw,(void*)&ulFwLen); return abtFw; } bool acr122_led_red(const dev_id di, bool bOn) { byte abtBuf[2]; ulong ulBufLen = sizeof(abtBuf); return (SCardTransmit((SCARDHANDLE)di,SCARD_PCI_T0,abtLed,sizeof(abtLed),null,(byte*)abtBuf,(void*)&ulBufLen) == SCARD_S_SUCCESS); }