pn532_error_t pn532_mifareclassic_WaitForPassiveTarget (byte_t * pbtCUID, size_t * szCUIDLen) { byte_t abtResponse[PN532_RESPONSELEN_INLISTPASSIVETARGET]; pn532_error_t error; size_t szLen; #ifdef PN532_DEBUGMODE PN532_DEBUG("Waiting for an ISO14443A Card%s", CFG_PRINTF_NEWLINE); #endif /* Try to initialise a single ISO14443A tag at 106KBPS */ /* Note: To wait for a card with a known UID, append the four byte */ /* UID to the end of the command. */ byte_t abtCommand[] = { PN532_COMMAND_INLISTPASSIVETARGET, 0x01, PN532_MODULATION_ISO14443A_106KBPS}; error = pn532Write(abtCommand, sizeof(abtCommand)); if (error) return error; /* Wait until we get a valid response or a timeout */ do { systickDelay(25); error = pn532Read(abtResponse, &szLen); } while (error == PN532_ERROR_RESPONSEBUFFEREMPTY); if (error) return error; /* Check SENSE_RES to make sure this is a Mifare Classic card */ /* Classic 1K = 00 04 */ /* Classic 4K = 00 02 */ /* Classic Emulated = 00 08 */ if ((abtResponse[10] == 0x02) || (abtResponse[10] == 0x04) || (abtResponse[10] == 0x08)) { /* Card appears to be Mifare Classic */ *szCUIDLen = abtResponse[12]; uint8_t i; for (i=0; i < *szCUIDLen; i++) { pbtCUID[i] = abtResponse[13+i]; } #ifdef PN532_DEBUGMODE PN532_DEBUG("Card Found: %s", CFG_PRINTF_NEWLINE); PN532_DEBUG(" ATQA: "); pn532PrintHex(abtResponse+9, 2); PN532_DEBUG(" SAK: %02x%s", abtResponse[11], CFG_PRINTF_NEWLINE); PN532_DEBUG(" UID: "); pn532PrintHex(pbtCUID, *szCUIDLen); #endif } else { /* Card is ISO14443A but doesn't appear to be Mifare Classic */ /* Mifare Ultralight = 0x0044 */ /* Mifare DESFire = 0x0344 */ /* Innovision Jewel = 0x0C00 */ #ifdef PN532_DEBUGMODE PN532_DEBUG("Wrong Card Type (Expected ATQA 00 02, 00 04 or 00 08) %s%s", CFG_PRINTF_NEWLINE, CFG_PRINTF_NEWLINE); PN532_DEBUG(" ATQA : "); pn532PrintHex(abtResponse+9, 2); PN532_DEBUG(" SAK : %02x%s", abtResponse[11], CFG_PRINTF_NEWLINE); PN532_DEBUG(" UID Length : %d%s", abtResponse[12], CFG_PRINTF_NEWLINE); PN532_DEBUG(" UID : "); size_t pos; for (pos=0; pos < abtResponse[12]; pos++) { printf("%02x ", abtResponse[13 + pos]); } printf("%s%s", CFG_PRINTF_NEWLINE, CFG_PRINTF_NEWLINE); #endif return PN532_ERROR_WRONGCARDTYPE; } return PN532_ERROR_NONE; }
pn532_error_t pn532_mifareclassic_AuthenticateBlock (byte_t * pbtCUID, size_t szCUIDLen, uint32_t uiBlockNumber, uint8_t uiKeyType, byte_t * pbtKeys) { pn532_error_t error; byte_t abtCommand[17]; byte_t abtResponse[PN532_RESPONSELEN_INDATAEXCHANGE]; size_t szLen; #ifdef PN532_DEBUGMODE PN532_DEBUG("Trying to authenticate card "); pn532PrintHex(pbtCUID, szCUIDLen); #endif /* Prepare the authentication command */ abtCommand[0] = PN532_COMMAND_INDATAEXCHANGE; /* Data Exchange Header */ abtCommand[1] = 1; /* Max card numbers */ abtCommand[2] = (uiKeyType) ? PN532_MIFARE_CMD_AUTH_A : PN532_MIFARE_CMD_AUTH_B; abtCommand[3] = uiBlockNumber; /* Block Number (1K = 0..63, 4K = 0..255 */ memcpy (abtCommand+4, pbtKeys, 6); uint8_t i; for (i = 0; i < szCUIDLen; i++) { abtCommand[10+i] = pbtCUID[i]; /* 4 byte card ID */ } /* Send the command */ error = pn532Write(abtCommand, 10+szCUIDLen); if (error) { /* Problem with the serial bus, etc. */ #ifdef PN532_DEBUGMODE PN532_DEBUG("Authentification failed%s", CFG_PRINTF_NEWLINE); #endif return error; } /* Read the authentication response */ memset(abtResponse, 0, PN532_RESPONSELEN_INDATAEXCHANGE); do { systickDelay(25); error = pn532Read(abtResponse, &szLen); } while (error == PN532_ERROR_RESPONSEBUFFEREMPTY); if (error) { #ifdef PN532_DEBUGMODE PN532_DEBUG("Authentification failed%s", CFG_PRINTF_NEWLINE); #endif return error; } // ToDo: How to check if authentification really worked (bad key, etc.)? /* Output the authentification data */ #ifdef PN532_DEBUGMODE PN532_DEBUG("Authenticated block %d %s", uiBlockNumber, CFG_PRINTF_NEWLINE); #endif // Return OK signal return PN532_ERROR_NONE; }
pn532_error_t pn532_bus_ReadResponse(byte_t * pbtResponse, size_t * pszRxLen) { uint8_t i; pn532_pcb_t *pn532 = pn532GetPCB(); // Check if we're busy if (pn532->state == PN532_STATE_BUSY) { return PN532_ERROR_BUSY; } // Flag the stack as busy pn532->state = PN532_STATE_BUSY; // Reset the app error flag pn532->appError = PN532_APPERROR_NONE; for ( i = 0; i < I2C_BUFSIZE; i++ ) { I2CMasterBuffer[i] = 0x00; } I2CWriteLength = 0; I2CReadLength = I2C_BUFSIZE; I2CMasterBuffer[0] = PN532_I2C_ADDRESS | PN532_I2C_READBIT; i2cEngine(); // Use the full I2C buffer size for now (until we're sure we have a good frame) *pszRxLen = I2C_BUFSIZE - 1; // Display the raw response data for debugging if requested #ifdef PN532_DEBUGMODE PN532_DEBUG("Received (%02d): ", I2C_BUFSIZE-1); pn532PrintHex(I2CSlaveBuffer+1, I2C_BUFSIZE-1); #endif // Check the frame type if ((0x01 == I2CSlaveBuffer[4]) && (0xff == I2CSlaveBuffer[5])) { // Error frame #ifdef PN532_DEBUGMODE PN532_DEBUG("Application level error (0x%02x)%s", I2CSlaveBuffer[6], CFG_PRINTF_NEWLINE); #endif // Set application error message ID pn532->appError = I2CSlaveBuffer[6]; pn532->state = PN532_STATE_READY; return PN532_ERROR_APPLEVELERROR; } else if ((0xff == I2CSlaveBuffer[4]) && (0xff == I2CSlaveBuffer[5])) { // Extended frame #ifdef PN532_DEBUGMODE PN532_DEBUG("Extended frames currently unsupported%s", CFG_PRINTF_NEWLINE); #endif pn532->state = PN532_STATE_READY; return PN532_ERROR_EXTENDEDFRAME; } else { // Normal frame if (256 != ((I2CSlaveBuffer[4]) + (I2CSlaveBuffer[5]))) { // TODO: Retry #ifdef PN532_DEBUGMODE PN532_DEBUG("Length checksum mismatch%s", CFG_PRINTF_NEWLINE); #endif pn532->state = PN532_STATE_READY; return PN532_ERROR_LENCHECKSUMMISMATCH; } } // Figure out how large the response really is // Response Frame Len = pbtResponse[4] + 7 (00 00 FF LEN LCS TFI [DATA] DCS) *pszRxLen = (I2CSlaveBuffer[4]) + 7; // TODO: Find a solution for this horribly ugly Mifare Classic block write hack! // Some responses to command 0x40 report the incorrect len, and don't take into // account the 16 byte payload when working with Mifare Classic sectors. // The response frame indicates len 10 (0x0A) in I2CSlaveBuffer[4] but it should be // 10+16 = 26 (0x1A) if ((*pszRxLen == 10) && (I2CSlaveBuffer[7] == 0x41) && (I2CSlaveBuffer[26] != 0x00)) { // For some reason, the PN532 reports len 10 for responses to // command 0x40 which includes the command data but does not // take into account the response/payload data in the len byte *pszRxLen+=16; } // Fill the response buffer // memcpy(pbtResponse, I2CSlaveBuffer+1, *pszRxLen); for ( i = 0; i < *pszRxLen; i++ ) { pbtResponse[i] = I2CSlaveBuffer[i+1]; } pn532->state = PN532_STATE_READY; return PN532_ERROR_NONE; }
pn532_error_t pn532_bus_SendCommand(const byte_t * pbtData, const size_t szData) { pn532_error_t error = PN532_ERROR_NONE; byte_t abtFrame[PN532_BUFFER_LEN] = { 0x00, 0x00, 0xff }; size_t szFrame = 0; pn532_pcb_t *pn532 = pn532GetPCB(); uint32_t i; // Check if we're busy if (pn532->state == PN532_STATE_BUSY) { return PN532_ERROR_BUSY; } // Flag the stack as busy pn532->state = PN532_STATE_BUSY; // -------------------------------------------------------------------- // Send the command frame // -------------------------------------------------------------------- // Build the frame pn532_bus_i2c_BuildFrame (abtFrame, &szFrame, pbtData, szData); // Keep track of the last command that was sent pn532->lastCommand = pbtData[0]; // Output the frame data for debugging if requested #ifdef PN532_DEBUGMODE PN532_DEBUG("Sending (%02d): ", szFrame); pn532PrintHex(abtFrame, szFrame); #endif // Send data to the PN532 error = pn532_bus_i2c_WriteData(abtFrame, szFrame); if (error == PN532_ERROR_I2C_NACK) { // Most likely error is PN532_ERROR_I2C_NACK // meaning no I2C ACK received from the PN532 #ifdef PN532_DEBUGMODE PN532_DEBUG ("No ACK received on I2C bus%s", CFG_PRINTF_NEWLINE); #endif pn532->state = PN532_STATE_READY; return error; } // -------------------------------------------------------------------- // Wait for the IRQ/Ready flag // -------------------------------------------------------------------- if (!(pn532_bus_i2c_WaitForReady(PN532_I2C_TIMEOUT))) { pn532->state = PN532_STATE_READY; #ifdef PN532_DEBUGMODE PN532_DEBUG ("Timed out waiting for IRQ/Ready%s", CFG_PRINTF_NEWLINE); #endif return PN532_ERROR_READYSTATUSTIMEOUT; } // -------------------------------------------------------------------- // Read the ACK frame // -------------------------------------------------------------------- I2CWriteLength = 0; I2CReadLength = 7; // ACK + Ready bit = 7 I2CMasterBuffer[0] = PN532_I2C_ADDRESS | PN532_I2C_READBIT; i2cEngine(); // Make sure the received ACK matches the prototype do { const byte_t abtAck[6] = { 0x00, 0x00, 0xff, 0x00, 0xff, 0x00 }; byte_t abtRxBuf[6]; // memcpy(abtRxBuf, I2CSlaveBuffer+1, 6); for ( i = 0; i < 6; i++ ) { abtRxBuf[i] = I2CSlaveBuffer[i+1]; } if (0 != (memcmp (abtRxBuf, abtAck, 6))) { #ifdef PN532_DEBUGMODE PN532_DEBUG ("Invalid ACK: "); pn532PrintHex(abtRxBuf, 6); PN532_DEBUG("%s", CFG_PRINTF_NEWLINE); #endif pn532->state = PN532_STATE_READY; return PN532_ERROR_INVALIDACK; } // -------------------------------------------------------------------- // Wait for the post-ACK IRQ/Ready flag // -------------------------------------------------------------------- if (!(pn532_bus_i2c_WaitForReady(PN532_I2C_TIMEOUT))) { pn532->state = PN532_STATE_READY; #ifdef PN532_DEBUGMODE PN532_DEBUG ("Timed out waiting for IRQ/Ready%s", CFG_PRINTF_NEWLINE); #endif return PN532_ERROR_READYSTATUSTIMEOUT; } } while(0); pn532->state = PN532_STATE_READY; return PN532_ERROR_NONE; }
int main (void) { #ifdef CFG_INTERFACE //#error "CFG_INTERFACE must be disabled in projectconfig.h for this demo" #endif #if !defined CFG_PRINTF_USBCDC #error "CFG_PRINTF_USBCDC must be enabled in projectconfig.h for this demo" #endif // Configure cpu and mandatory peripherals systemInit(); // Wait a bit for someone to open the USB connection for printf systickDelay(5000); // Initialise the PN532 pn532Init(); pn532_error_t error; byte_t response[64]; size_t responseLen; // Setup command to initialise a single ISO14443A target at 106kbps (Mifare Classic, Ultralight, etc.) byte_t abtCommand[] = { PN532_COMMAND_INLISTPASSIVETARGET, 0x01, PN532_MODULATION_ISO14443A_106KBPS }; while (1) { printf("%s", CFG_PRINTF_NEWLINE); printf("Waiting for an ISO14443A card (Mifare Classic, etc.)%s", CFG_PRINTF_NEWLINE); // Send the command (and handle the most common errors) error = pn532Write(abtCommand, sizeof(abtCommand)); if (error) { // Something went wrong sending the command (probably the bus selection or wiring) switch(error) { case (PN532_ERROR_NOACK): case (PN532_ERROR_INVALIDACK): // No ACK response frame received from the PN532 printf("Ooops ... No valid ACK frame received!%s", CFG_PRINTF_NEWLINE); break; case (PN532_ERROR_I2C_NACK): // No ACK bit received to I2C start ... not same as PN532 ACK frame (bus pins not set correctly?) printf("Ooops ... No I2C ACK received! Are the bus select pins sets to I2C?%s", CFG_PRINTF_NEWLINE); break; case (PN532_ERROR_READYSTATUSTIMEOUT): // Timed out waiting for the ready bit to clear ... this can be intentional, though, in the // case of PN532_COMMAND_INLISTPASSIVETARGET since it will only clear when a card // enters the magnetic field! Handle with caution because it isn't always an error // Note: Only valid for I2C and SPI printf("Timed out waiting for Ready/IRQ%s", CFG_PRINTF_NEWLINE); break; default: printf("Ooops ... something went wrong! [PN532 Error Code: 0x%02X]%s", error, CFG_PRINTF_NEWLINE); break; } } else { // Commmand seems to have gone through ... do { // Keep reading until we get a response or an unexpected error condition error = pn532Read(response, &responseLen); systickDelay(25); } while (error == PN532_ERROR_RESPONSEBUFFEREMPTY); printf("%s", CFG_PRINTF_NEWLINE); printf("%-12s: ", "Received"); pn532PrintHex(response, responseLen); // Try to handle some potential frame errors // Unhandled errors are caught further down switch (error) { case (PN532_ERROR_PREAMBLEMISMATCH): // Frame should start with 0x00 0x00 0xFF! printf("Response frame doesn't start with expected preamble (00 00 FF)%s", CFG_PRINTF_NEWLINE); break; case (PN532_ERROR_APPLEVELERROR): printf("Application level error reported by PN532%s", CFG_PRINTF_NEWLINE); break; case (PN532_ERROR_LENCHECKSUMMISMATCH): printf("Frame length check/checksum mismatch%s", CFG_PRINTF_NEWLINE); break; default: // Other errors handled below break; } // Print the card details if possible if (!error) { /* Response for ISO14443A 106KBPS (Mifare Classic, etc.) See UM0701-02 section 7.3.5 for more information byte Description ------------- ------------------------------------------ b7 Tags Found b8 Tag Number (only one used in this example) b9..10 SENS_RES b11 SEL_RES b12 NFCID Length b13..NFCIDLen NFCID SENS_RES SEL_RES Manufacturer/Card Type NFCID Len -------- ------- ----------------------- --------- 00 04 08 NXP Mifare Classic 1K 4 bytes */ printf("%-12s: %d %s", "Tags Found", response[7], CFG_PRINTF_NEWLINE); printf("%-12s: %02X %02X %s", "SENS_RES", response[9], response[10], CFG_PRINTF_NEWLINE); printf("%-12s: %02X %s", "SEL_RES", response[11], CFG_PRINTF_NEWLINE); printf("%-12s: ", "NFCID"); size_t pos; for (pos=0; pos < response[12]; pos++) { printf("%02x ", response[13 + pos]); } printf(CFG_PRINTF_NEWLINE); if ((response[9] == 0x00) && (response[10] == 0x04) && (response[11] == 0x08)) { printf("Seems to be a Mifare Classic 1K Card%s", CFG_PRINTF_NEWLINE); } } else { // Oops .... something bad happened. Check 'error' printf("Ooops! Error %02X %s", error, CFG_PRINTF_NEWLINE); } } // Wait at least one second before trying again systickDelay(1000); } }
pn532_error_t pn532_bus_ReadResponse(byte_t * pbtResponse, size_t * pszRxLen) { pn532_pcb_t *pn532 = pn532GetPCB(); // Check if we're busy if (pn532->state == PN532_STATE_BUSY) { return PN532_ERROR_BUSY; } // Flag the stack as busy pn532->state = PN532_STATE_BUSY; // Reset the app error flag pn532->appError = PN532_APPERROR_NONE; // Read response from uart if (!uartRxBufferReadArray(pbtResponse, pszRxLen)) { pn532->state = PN532_STATE_READY; return PN532_ERROR_RESPONSEBUFFEREMPTY; } // Display the raw response data for debugging if requested #ifdef PN532_DEBUGMODE PN532_DEBUG("Received (%02d): ", *pszRxLen); pn532PrintHex(pbtResponse, *pszRxLen); #endif // Check preamble const byte_t pn53x_preamble[3] = { 0x00, 0x00, 0xff }; if (0 != (memcmp (pbtResponse, pn53x_preamble, 3))) { #ifdef PN532_DEBUGMODE PN532_DEBUG("Frame preamble + start code mismatch%s", CFG_PRINTF_NEWLINE); #endif pn532->state = PN532_STATE_READY; return PN532_ERROR_PREAMBLEMISMATCH; } // Check the frame type if ((0x01 == pbtResponse[3]) && (0xff == pbtResponse[4])) { // Error frame #ifdef PN532_DEBUGMODE PN532_DEBUG("Application level error (0x%02x)%s", pbtResponse[5], CFG_PRINTF_NEWLINE); #endif // Set application error message ID pn532->appError = pbtResponse[5]; pn532->state = PN532_STATE_READY; return PN532_ERROR_APPLEVELERROR; } else if ((0xff == pbtResponse[3]) && (0xff == pbtResponse[4])) { // Extended frame #ifdef PN532_DEBUGMODE PN532_DEBUG("Extended frames currently unsupported%s", CFG_PRINTF_NEWLINE); #endif pn532->state = PN532_STATE_READY; return PN532_ERROR_EXTENDEDFRAME; } else { // Normal frame if (256 != (pbtResponse[3] + pbtResponse[4])) { // TODO: Retry #ifdef PN532_DEBUGMODE PN532_DEBUG("Length checksum mismatch%s", CFG_PRINTF_NEWLINE); #endif pn532->state = PN532_STATE_READY; return PN532_ERROR_LENCHECKSUMMISMATCH; } // size_t szPayloadLen = abtRx[3] - 2; } pn532->state = PN532_STATE_READY; return PN532_ERROR_NONE; }
pn532_error_t pn532_bus_SendCommand(const byte_t * pbtData, const size_t szData) { pn532_pcb_t *pn532 = pn532GetPCB(); // Check if we're busy if (pn532->state == PN532_STATE_BUSY) { return PN532_ERROR_BUSY; } // Flag the stack as busy pn532->state = PN532_STATE_BUSY; // Every packet must start with "00 00 ff" byte_t abtFrame[PN532_BUFFER_LEN] = { 0x00, 0x00, 0xff }; size_t szFrame = 0; // Build the frame pn532_bus_BuildFrame (abtFrame, &szFrame, pbtData, szData); // Keep track of the last command that was sent pn532->lastCommand = pbtData[0]; // Output the frame data for debugging if requested #ifdef PN532_DEBUGMODE PN532_DEBUG("Sending (%02d): ", szFrame); pn532PrintHex(abtFrame, szFrame); #endif // Send data to the PN532 uartSend (abtFrame, szFrame); // Wait for ACK byte_t abtRxBuf[6]; uart_pcb_t *uart = uartGetPCB(); delay(10); // FIXME: How long should we wait for ACK? if (uart->rxfifo.len < 6) { // Unable to read ACK #ifdef PN532_DEBUGMODE PN532_DEBUG ("Unable to read ACK%s", CFG_PRINTF_NEWLINE); #endif pn532->state = PN532_STATE_READY; return PN532_ERROR_NOACK; } // Read ACK ... this will also remove it from the buffer const byte_t abtAck[6] = { 0x00, 0x00, 0xff, 0x00, 0xff, 0x00 }; abtRxBuf[0] = uartRxBufferRead(); abtRxBuf[1] = uartRxBufferRead(); abtRxBuf[2] = uartRxBufferRead(); abtRxBuf[3] = uartRxBufferRead(); abtRxBuf[4] = uartRxBufferRead(); abtRxBuf[5] = uartRxBufferRead(); // Make sure the received ACK matches the prototype if (0 != (memcmp (abtRxBuf, abtAck, 6))) { #ifdef PN532_DEBUGMODE PN532_DEBUG ("Invalid ACK: "); pn532PrintHex(abtRxBuf, 6); PN532_DEBUG("%s", CFG_PRINTF_NEWLINE); #endif pn532->state = PN532_STATE_READY; return PN532_ERROR_INVALIDACK; } pn532->state = PN532_STATE_READY; return PN532_ERROR_NONE; }