Rev 158 | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed
#include <xc.h>#include <string.h>#include <delays.h>#include "defines.h"#include "sensor_nfc_PN532.h"#include "base_I2C.h"static NFC_DATA *nfc_data_p;// Const value arrays for comparison usestatic const char pn532response_firmwarevers[] = {0x01, 0x00, 0x00, 0xFF, 0x06, 0xFA, 0xD5, 0x03};static const char pn532ack[] = {0x01, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00};void NFC_Init(NFC_DATA *data) {nfc_data_p = data;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)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 ACKchar NFC_Send_Command_Check_Ack(char *cmd, 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 fieldchar 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 fieldchar NFC_Poll_Targets(char number, 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)//char NFC_mifareclassic_IsFirstBlock(unsigned long uiBlock) {// // Test if we are in the small or big sectors// if (uiBlock < 128)// return ((uiBlock) % 4 == 0);// else// return ((uiBlock) % 16 == 0);//}//// Indicates whether the specified block number is the sector trailer//char NFC_mifareclassic_IsTrailerBlock(unsigned long uiBlock) {// // Test if we are in the small or big sectors// if (uiBlock < 128)// return ((uiBlock + 1) % 4 == 0);// else// return ((uiBlock + 1) % 16 == 0);//}//// Tries to authenticate a block of memory on a MIFARE card using the INDATAEXCHANGE command//char NFC_mifareclassic_AuthenticateBlock(char *uid, char uidLen, unsigned long blockNumber, char keyNumber, 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 value//// // Assemble frame data// nfc_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 (char i = 0; i < 6; i++) {// nfc_data_p->packetbuffer[4 + i] = keyData[i];// }// for (char i = 0; i < uidLen; i++) {// nfc_data_p->packetbuffer[10 + i] = uid[i];// }//// // Send frame and check for ACK// if (!NFC_Send_Command_Check_Ack(nfc_data_p->packetbuffer, 10 + uidLen))// return 0;//// // Read response from PN532// NFC_I2C_Read_Data(nfc_data_p->packetbuffer, 12);//// return 1;//}//// Tries to read an entire 16-byte data block at the specified block address//char NFC_mifareclassic_ReadDataBlock(char blockNumber, char *data) {// // Assemble frame data// nfc_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 ACK// if (!NFC_Send_Command_Check_Ack(nfc_data_p->packetbuffer, 4))// return 0;//// // Read reponse// NFC_I2C_Read_Data(nfc_data_p->packetbuffer, 26);//// // If byte 9 isnt 0x00 we probably have and error// if (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 response// for (char 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 address//char NFC_mifareclassic_WriteDataBlock(char blockNumber, char *data) {// // Assemble frame data// nfc_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 (char i = 0; i < 16; i++) { /* Data Payload */// nfc_data_p->packetbuffer[4 + i] = data[i];// }//// // Send frame and check for ACK// if (!NFC_Send_Command_Check_Ack(nfc_data_p->packetbuffer, 20))// return 0;//// // Read response// NFC_I2C_Read_Data(nfc_data_p->packetbuffer, 26);//// return 1;//}//// Formats a Mifare Classic card to store NDEF Records//char NFC_mifareclassic_FormatNDEF(void) {// char sectorbuffer1[16] = {0x14, 0x01, 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1};// char sectorbuffer2[16] = {0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1};// char sectorbuffer3[16] = {0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0x78, 0x77, 0x88, 0xC1, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};//// // Write blocks 1 and 2// if (!NFC_mifareclassic_WriteDataBlock(1, sectorbuffer1))// return 0;// if (!NFC_mifareclassic_WriteDataBlock(2, sectorbuffer2))// return 0;// // Write key A and access rights// if (!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 is// already formatted to work as an "NFC Forum Tag" and uses a MAD1// file system. You can use the NXP TagWriter app on Android to// properly format cards for this. *///char NFC_mifareclassic_WriteNDEFURI(char sectorNumber, 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 is// char len = strlen(url);//// char sectorbuffer1[16] = {0x00, 0x00, 0x03, len + 5, 0xD1, 0x01, len + 1, 0x55, uriIdentifier, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};// char sectorbuffer2[16] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};// char sectorbuffer3[16] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};// 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 number// if ((sectorNumber < 1) || (sectorNumber > 15))// return 0;//// // Make sure the URI payload is between 1 and 38 chars// if ((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 block// memcpy(sectorbuffer1 + 9, url, len);// sectorbuffer2[0] = 0xFE;// } else if ((len > 7) || (len <= 22)) {// // Url fits in two blocks// memcpy(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 block// memcpy(sectorbuffer1 + 9, url, 7);// memcpy(sectorbuffer2, url + 7, len - 7);// sectorbuffer3[0] = 0xFE;// } else {// // Url fits in three blocks// memcpy(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 card// if (!(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 signalchar NFC_I2C_Read_ACK() {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 readychar 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(char *buffer, char length) {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(char* cmd, char cmdlen) {char checksum;char buffer[PN532_PACKBUFFSIZ + 8];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 (char 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);}