Rev 154 | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed
#include "defines.h"#include "nfc_PN532.h"#include "i2c.h"#include <string.h>#include <delays.h>static NFC_DATA nfc_data;static NFC_DATA *nfc_data_p = &nfc_data;// Const value arrays for comparison usestatic char pn532response_firmwarevers[] = {0x01, 0x00, 0x00, 0xFF, 0x06, 0xFA, 0xD5, 0x03};static char pn532ack[] = {0x01, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00};void NFC_Init() {NFC_IRQ_TRIS = 1; // IRQ Pin is RC5/* NFC reset is disabled due to lack of pins */// NFC_RESET_TRIS = 0; // Reset Pin is RC2//// // Reset the PN532// NFC_RESET_LAT = 1;// NFC_RESET_LAT = 0;// Delay10TCYx(1);// NFC_RESET_LAT = 1;}// Configures the SAM (Secure Access Module)unsigned char NFC_SAMConfig() {nfc_data_p->packetbuffer[0] = PN532_COMMAND_SAMCONFIGURATION;nfc_data_p->packetbuffer[1] = 0x01; // Normal modenfc_data_p->packetbuffer[2] = 0x14; // Timeout 50ms * 20 = 1snfc_data_p->packetbuffer[3] = 0x01; // Use IRQ pinif (!NFC_Send_Command_Check_Ack(nfc_data_p->packetbuffer, 4))return 0;NFC_I2C_Read_Data(nfc_data_p->packetbuffer, 8);return (nfc_data_p->packetbuffer[7] == 0x15);}// Checks the firmware version of the PN5xx chipNFC_FIRMWARE_VERSION NFC_Get_Firmware_Version(void) {NFC_FIRMWARE_VERSION response = {0, 0, 0, 0};// Create and send commandnfc_data_p->packetbuffer[0] = PN532_COMMAND_GETFIRMWAREVERSION;if (!NFC_Send_Command_Check_Ack(nfc_data_p->packetbuffer, 1))return response;// Read back data from the PN532NFC_I2C_Read_Data(nfc_data_p->packetbuffer, 12);// Compare and check returned valuesif (strncmp((char *) nfc_data_p->packetbuffer, (char *) pn532response_firmwarevers, 8) != 0)return response;// Save and return inforesponse.IC = nfc_data_p->packetbuffer[8];response.Ver = nfc_data_p->packetbuffer[9];response.Rev = nfc_data_p->packetbuffer[10];response.Support = nfc_data_p->packetbuffer[11];return response;}// Sends a command and waits a specified period for the ACKunsigned char NFC_Send_Command_Check_Ack(unsigned char *cmd, unsigned char cmdlen) {unsigned int timer = 0;// Write the commandNFC_I2C_Write_Cmd(cmd, cmdlen);// Wait for chip to be readywhile (NFC_I2C_Read_Status() != PN532_I2C_READY) {if (PN532_TIMEOUT != 0) {timer += 1;if (timer > PN532_TIMEOUT)return 0;}Delay10TCYx(1);}// Check ACKif (!NFC_I2C_Read_ACK()) {return 0;}return 1;}// Passive polling, waits for an ISO14443A target to enter the fieldunsigned char NFC_Read_Passive_Target_ID(NFC_TargetDataMiFare *cardData) {nfc_data_p->packetbuffer[0] = PN532_COMMAND_INLISTPASSIVETARGET;nfc_data_p->packetbuffer[1] = 2; // Max 2 cards at oncenfc_data_p->packetbuffer[2] = PN532_MIFARE_ISO14443A; // Mifare onlyif (!NFC_Send_Command_Check_Ack(nfc_data_p->packetbuffer, 3))return 0;// Wait for IRQ linewhile (NFC_I2C_Read_Status() != PN532_I2C_READY);NFC_I2C_Read_Data(nfc_data_p->packetbuffer, 35);/* InListPassiveTarget response should be in the following format:* Byte Description* ---------- ------------------* b0 Data ACK* b1..7 Frame header and preamble* b8 Tags found* b9..N NFC_TargetDataMiFare[2]* bN+1..N+2 Checksum + postamble*/// Check # of tags foundif (!nfc_data_p->packetbuffer[8])return 0;// Save data from first cardif (nfc_data_p->packetbuffer[13] == 4) {memcpy((char *)&cardData[0], (const char *)&nfc_data_p->packetbuffer[9], 9);} else {memcpy((char *)&cardData[0], (const char *)&nfc_data_p->packetbuffer[9], 12);}// Save data from second cardif (nfc_data_p->packetbuffer[8] == 2) {// Offset will vary depending on length of first cardif (nfc_data_p->packetbuffer[13] == 4) {if (nfc_data_p->packetbuffer[22] == 4) {memcpy((char *)&cardData[1], (const char *)&nfc_data_p->packetbuffer[18], 9);} else {memcpy((char *)&cardData[1], (const char *)&nfc_data_p->packetbuffer[18], 12);}} else { // Length of first UID is 7if (nfc_data_p->packetbuffer[25] == 4) {memcpy((char *)&cardData[1], (const char *)&nfc_data_p->packetbuffer[21], 9);} else {memcpy((char *)&cardData[1], (const char *)&nfc_data_p->packetbuffer[21], 12);}}}// Return the number of cards detectedreturn nfc_data_p->packetbuffer[8];}// Active polling, returns number of cards in the fieldunsigned char NFC_Poll_Targets(unsigned char number, unsigned char period, NFC_TargetDataMiFare *cardData) {nfc_data_p->packetbuffer[0] = PN532_COMMAND_INAUTOPOLL;nfc_data_p->packetbuffer[1] = number; // Number of pollingnfc_data_p->packetbuffer[2] = period; // Polling period in units of 150msnfc_data_p->packetbuffer[3] = 0x10; // Check for Mifare cards onlyif (!NFC_Send_Command_Check_Ack(nfc_data_p->packetbuffer, 4))return 0;// Wait for IRQ linewhile (NFC_I2C_Read_Status() != PN532_I2C_READY);NFC_I2C_Read_Data(nfc_data_p->packetbuffer, 37);/* InAutoPoll response should be in the following format:* Byte Description* ---------- ------------------* b0 Data ACK* b1..7 Frame header and preamble* b6 Tags found* b7 Polled target type (should be 0x10 Mifare)* b8 TargetData length (1/2)* b9..N NFC_TargetDataMiFare[1/2]* bN+1..N+2 Checksum + postamble*/// Check # of tags foundif (!nfc_data_p->packetbuffer[8])return 0;// Save data from first cardif (nfc_data_p->packetbuffer[15] == 4) {memcpy((char *)&cardData[0], (const char *)&nfc_data_p->packetbuffer[11], 9);} else {memcpy((char *)&cardData[0], (const char *)&nfc_data_p->packetbuffer[11], 12);}// Save data from second cardif (nfc_data_p->packetbuffer[8] == 2) {// Offset will vary depending on length of first cardif (nfc_data_p->packetbuffer[15] == 4) {if (nfc_data_p->packetbuffer[26] == 4) {memcpy((char *)&cardData[1], (const char *)&nfc_data_p->packetbuffer[22], 9);} else {memcpy((char *)&cardData[1], (const char *)&nfc_data_p->packetbuffer[22], 12);}} else {if (nfc_data_p->packetbuffer[29] == 4) {memcpy((char *)&cardData[1], (const char *)&nfc_data_p->packetbuffer[25], 9);} else {memcpy((char *)&cardData[1], (const char *)&nfc_data_p->packetbuffer[25], 12);}}}// Return the number of cards detectedreturn nfc_data_p->packetbuffer[8];}// Indicates whether the specified block number is the first block// in the sector (block 0 relative to the current sector)unsigned char NFC_mifareclassic_IsFirstBlock(unsigned long uiBlock) {// Test if we are in the small or big sectorsif (uiBlock < 128)return ((uiBlock) % 4 == 0);elsereturn ((uiBlock) % 16 == 0);}// Indicates whether the specified block number is the sector trailerunsigned char NFC_mifareclassic_IsTrailerBlock(unsigned long uiBlock) {// Test if we are in the small or big sectorsif (uiBlock < 128)return ((uiBlock + 1) % 4 == 0);elsereturn ((uiBlock + 1) % 16 == 0);}// Tries to authenticate a block of memory on a MIFARE card using the INDATAEXCHANGE commandunsigned char NFC_mifareclassic_AuthenticateBlock(unsigned char *uid, unsigned char uidLen, unsigned long blockNumber, unsigned char keyNumber, unsigned char *keyData) {// See section 7.3.8 of the PN532 User Manual// blockNumber = The block number to authenticate. (0..63 for 1KB cards, and 0..255 for 4KB cards)\// keyNumber = Which key type to use during authentication (0 = MIFARE_CMD_AUTH_A, 1 = MIFARE_CMD_AUTH_B)// keyData = Pointer to a byte array containing the 6 byte key valueunsigned char i;// Assemble frame datanfc_data_p->packetbuffer[0] = PN532_COMMAND_INDATAEXCHANGE; /* Data Exchange Header */nfc_data_p->packetbuffer[1] = 1; /* Max card numbers */nfc_data_p->packetbuffer[2] = (keyNumber) ? MIFARE_CMD_AUTH_A : MIFARE_CMD_AUTH_B;nfc_data_p->packetbuffer[3] = blockNumber; /* Block Number (1K = 0..63, 4K = 0..255 */for (i = 0; i < 6; i++) {nfc_data_p->packetbuffer[4 + i] = keyData[i];}for (i = 0; i < uidLen; i++) {nfc_data_p->packetbuffer[10 + i] = uid[i];}// Send frame and check for ACKif (!NFC_Send_Command_Check_Ack(nfc_data_p->packetbuffer, 10 + uidLen))return 0;// Read response from PN532NFC_I2C_Read_Data(nfc_data_p->packetbuffer, 12);return 1;}// Tries to read an entire 16-byte data block at the specified block addressunsigned char NFC_mifareclassic_ReadDataBlock(unsigned char blockNumber, unsigned char *data) {unsigned char i;// Assemble frame datanfc_data_p->packetbuffer[0] = PN532_COMMAND_INDATAEXCHANGE;nfc_data_p->packetbuffer[1] = 1; /* Card number */nfc_data_p->packetbuffer[2] = MIFARE_CMD_READ; /* Mifare Read command = 0x30 */nfc_data_p->packetbuffer[3] = blockNumber; /* Block Number (0..63 for 1K, 0..255 for 4K) */// Send frame and check for ACKif (!NFC_Send_Command_Check_Ack(nfc_data_p->packetbuffer, 4))return 0;// Read reponseNFC_I2C_Read_Data(nfc_data_p->packetbuffer, 26);// If byte 9 isnt 0x00 we probably have and errorif (nfc_data_p->packetbuffer[8] != 0x00) {return 0;}// Copy the 16 data bytes into the data buffer// Block contents starts at byte 10 of a valid responsefor (i = 0; i < 16; i++) {data[i] = nfc_data_p->packetbuffer[9 + i];}return 1;}// Tries to write an entire 16-byte data block at the specified block addressunsigned char NFC_mifareclassic_WriteDataBlock(unsigned char blockNumber, unsigned char *data) {unsigned char i;// Assemble frame datanfc_data_p->packetbuffer[0] = PN532_COMMAND_INDATAEXCHANGE;nfc_data_p->packetbuffer[1] = 1; /* Card number */nfc_data_p->packetbuffer[2] = MIFARE_CMD_WRITE; /* Mifare Write command = 0xA0 */nfc_data_p->packetbuffer[3] = blockNumber; /* Block Number (0..63 for 1K, 0..255 for 4K) */for (i = 0; i < 16; i++) { /* Data Payload */nfc_data_p->packetbuffer[4 + i] = data[i];}// Send frame and check for ACKif (!NFC_Send_Command_Check_Ack(nfc_data_p->packetbuffer, 20))return 0;// Read responseNFC_I2C_Read_Data(nfc_data_p->packetbuffer, 26);return 1;}// Formats a Mifare Classic card to store NDEF Recordsunsigned char NFC_mifareclassic_FormatNDEF(void) {unsigned char sectorbuffer1[16] = {0x14, 0x01, 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1};unsigned char sectorbuffer2[16] = {0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1};unsigned char sectorbuffer3[16] = {0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0x78, 0x77, 0x88, 0xC1, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};// Write blocks 1 and 2if (!NFC_mifareclassic_WriteDataBlock(1, sectorbuffer1))return 0;if (!NFC_mifareclassic_WriteDataBlock(2, sectorbuffer2))return 0;// Write key A and access rightsif (!NFC_mifareclassic_WriteDataBlock(3, sectorbuffer3))return 0;return 1;}// Writes an NDEF URI Record to the specified sector (1..15)/* Note that this function assumes that the Mifare Classic card isalready formatted to work as an "NFC Forum Tag" and uses a MAD1file system. You can use the NXP TagWriter app on Android toproperly format cards for this. */unsigned char NFC_mifareclassic_WriteNDEFURI(unsigned char sectorNumber, unsigned char uriIdentifier, const char * url) {// uriIdentifier = The uri identifier code (0 = none, 0x01 = "http://www.", etc.)// url = The uri text to write (max 38 characters)// Figure out how long the string isunsigned char len = strlen(url);unsigned char sectorbuffer1[16] = {0x00, 0x00, 0x03, len + 5, 0xD1, 0x01, len + 1, 0x55, uriIdentifier, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};unsigned char sectorbuffer2[16] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};unsigned char sectorbuffer3[16] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};unsigned char sectorbuffer4[16] = {0xD3, 0xF7, 0xD3, 0xF7, 0xD3, 0xF7, 0x7F, 0x07, 0x88, 0x40, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};// Make sure we're within a 1K limit for the sector numberif ((sectorNumber < 1) || (sectorNumber > 15))return 0;// Make sure the URI payload is between 1 and 38 charsif ((len < 1) || (len > 38))return 0;if (len <= 6) {// Unlikely we'll get a url this short, but why not ...memcpy(sectorbuffer1 + 9, url, len);sectorbuffer1[len + 9] = 0xFE;} else if (len == 7) {// 0xFE needs to be wrapped around to next blockmemcpy(sectorbuffer1 + 9, url, len);sectorbuffer2[0] = 0xFE;} else if ((len > 7) || (len <= 22)) {// Url fits in two blocksmemcpy(sectorbuffer1 + 9, url, 7);memcpy(sectorbuffer2, url + 7, len - 7);sectorbuffer2[len - 7] = 0xFE;} else if (len == 23) {// 0xFE needs to be wrapped around to final blockmemcpy(sectorbuffer1 + 9, url, 7);memcpy(sectorbuffer2, url + 7, len - 7);sectorbuffer3[0] = 0xFE;} else {// Url fits in three blocksmemcpy(sectorbuffer1 + 9, url, 7);memcpy(sectorbuffer2, url + 7, 16);memcpy(sectorbuffer3, url + 23, len - 24);sectorbuffer3[len - 22] = 0xFE;}// Now write all three blocks back to the cardif (!(NFC_mifareclassic_WriteDataBlock(sectorNumber * 4, sectorbuffer1)))return 0;if (!(NFC_mifareclassic_WriteDataBlock((sectorNumber * 4) + 1, sectorbuffer2)))return 0;if (!(NFC_mifareclassic_WriteDataBlock((sectorNumber * 4) + 2, sectorbuffer3)))return 0;if (!(NFC_mifareclassic_WriteDataBlock((sectorNumber * 4) + 3, sectorbuffer4)))return 0;return 1;}// Reads and checks for the ACK signalunsigned char NFC_I2C_Read_ACK() {unsigned char buffer[7];// Check ACKNFC_I2C_Read_Data(buffer, 6);// Return if the 7 bytes matches the ACK patternreturn (strncmp((char *) buffer, (char *) pn532ack, 7) == 0);}// Checks the IRQ pin to know if the PN532 is readyunsigned char NFC_I2C_Read_Status() {if (NFC_IRQ_PORT == 1) {return PN532_I2C_BUSY;} else {return PN532_I2C_READY;}}// Reads n bytes of data from the PN532 via I2Cvoid NFC_I2C_Read_Data(unsigned char *buffer, unsigned char length) {unsigned char result;// Wait for IRQ to go lowwhile (NFC_I2C_Read_Status() != PN532_I2C_READY);// Read bytes from PN532 into bufferI2C_Master_Recv(PN532_I2C_ADDRESS, length + 2);result = I2C_Get_Status();while (!result) {result = I2C_Get_Status();}I2C_Read_Buffer((char *) buffer);/* Remaining packet byte layout is as follows:Byte Description----- ----------------------* 0 Data ready ACK* 1 Preamble (0x00)* 2-3 Start code (0x00,0xFF)* 4 Length (TFI to N)* 5 Length Checksum (Length + LCS = 0x00)* 6 TFI (Frame identifier)* 0xD4 - Host to PN532* 0xD5 - PN532 to Host* 7-N Data (Length - 1 bytes)* N+1 Data checksum (TFI + Data~N + DCS = 0x00)* N+2 Postamble (0x00) */}// Writes a command to the PN532, automatically inserting the preamble and required frame details (checksum, len, etc.)void NFC_I2C_Write_Cmd(unsigned char* cmd, unsigned char cmdlen) {int i;unsigned char checksum;unsigned char buffer[PN532_PACKBUFFSIZ + 8];unsigned char buffer_ind = 6;cmdlen++;checksum = PN532_PREAMBLE + PN532_PREAMBLE + PN532_STARTCODE2 + PN532_HOSTTOPN532;// Fill out required frame fieldsbuffer[0] = PN532_PREAMBLE;buffer[1] = PN532_PREAMBLE;buffer[2] = PN532_STARTCODE2;buffer[3] = cmdlen;buffer[4] = ~cmdlen + 1;buffer[5] = PN532_HOSTTOPN532;// Copy cmd to be sentfor (i = 0; i < cmdlen - 1; i++) {checksum += cmd[i];buffer[buffer_ind] = cmd[i];buffer_ind++;}buffer[buffer_ind] = ~checksum;buffer_ind++;buffer[buffer_ind] = PN532_POSTAMBLE;buffer_ind++;I2C_Master_Send(PN532_I2C_ADDRESS, buffer_ind, buffer);}