Go to most recent revision | Blame | Last modification | View Log | RSS feed
#include <xc.h>
#include <string.h>
#include <delays.h>
#include "defines.h"
#include "nfc_PN532.h"
#include "i2c.h"
static NFC_DATA *nfc_data_p;
// Const value arrays for comparison use
static 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 mode
nfc_data_p->packetbuffer[2] = 0x14; // Timeout 50ms * 20 = 1s
nfc_data_p->packetbuffer[3] = 0x01; // Use IRQ pin
if (!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 chip
NFC_FIRMWARE_VERSION NFC_Get_Firmware_Version(void) {
NFC_FIRMWARE_VERSION response = {0, 0, 0, 0};
// Create and send command
nfc_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 PN532
NFC_I2C_Read_Data(nfc_data_p->packetbuffer, 12);
// Compare and check returned values
if (strncmp((char *) nfc_data_p->packetbuffer, (char *) pn532response_firmwarevers, 8) != 0)
return response;
// Save and return info
response.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 ACK
char NFC_Send_Command_Check_Ack(char *cmd, char cmdlen) {
unsigned int timer = 0;
// Write the command
NFC_I2C_Write_Cmd(cmd, cmdlen);
// Wait for chip to be ready
while (NFC_I2C_Read_Status() != PN532_I2C_READY) {
if (PN532_TIMEOUT != 0) {
timer += 1;
if (timer > PN532_TIMEOUT)
return 0;
}
Delay10TCYx(1);
}
// Check ACK
if (!NFC_I2C_Read_ACK()) {
return 0;
}
return 1;
}
// Passive polling, waits for an ISO14443A target to enter the field
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 once
nfc_data_p->packetbuffer[2] = PN532_MIFARE_ISO14443A; // Mifare only
if (!NFC_Send_Command_Check_Ack(nfc_data_p->packetbuffer, 3))
return 0;
// Wait for IRQ line
while (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 found
if (!nfc_data_p->packetbuffer[8])
return 0;
// Save data from first card
if (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 card
if (nfc_data_p->packetbuffer[8] == 2) {
// Offset will vary depending on length of first card
if (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 7
if (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 detected
return nfc_data_p->packetbuffer[8];
}
// Active polling, returns number of cards in the field
char 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 polling
nfc_data_p->packetbuffer[2] = period; // Polling period in units of 150ms
nfc_data_p->packetbuffer[3] = 0x10; // Check for Mifare cards only
if (!NFC_Send_Command_Check_Ack(nfc_data_p->packetbuffer, 4))
return 0;
// Wait for IRQ line
while (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 found
if (!nfc_data_p->packetbuffer[8])
return 0;
// Save data from first card
if (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 card
if (nfc_data_p->packetbuffer[8] == 2) {
// Offset will vary depending on length of first card
if (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 detected
return 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 signal
char NFC_I2C_Read_ACK() {
char buffer[7];
// Check ACK
NFC_I2C_Read_Data(buffer, 6);
// Return if the 7 bytes matches the ACK pattern
return (strncmp((char *) buffer, (char *) pn532ack, 7) == 0);
}
// Checks the IRQ pin to know if the PN532 is ready
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 I2C
void NFC_I2C_Read_Data(char *buffer, char length) {
char result;
// Wait for IRQ to go low
while (NFC_I2C_Read_Status() != PN532_I2C_READY);
// Read bytes from PN532 into buffer
I2C_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 fields
buffer[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 sent
for (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);
}