0,0 → 1,474 |
#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 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); |
} |