Now with more examples!
This commit is contained in:
parent
3dab651676
commit
18d7144b47
8 changed files with 1470 additions and 60 deletions
744
PN532.cpp
744
PN532.cpp
|
|
@ -1,13 +1,53 @@
|
|||
#include "PN532.h"
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@file PN532.cpp
|
||||
@author Adafruit Industries
|
||||
@license BSD (see license.txt)
|
||||
|
||||
SPI Driver for NXP's PN532 NFC/13.56MHz RFID Transceiver
|
||||
|
||||
@section HISTORY
|
||||
|
||||
//#define PN532DEBUG 1
|
||||
v1.2 - Added writeGPIO()
|
||||
- Added readGPIO()
|
||||
|
||||
v1.1 - Changed readPassiveTargetID() to handle multiple UID sizes
|
||||
- Added the following helper functions for text display
|
||||
static void PrintHex(const byte * data, const uint32_t numBytes)
|
||||
static void PrintHexChar(const byte * pbtData, const uint32_t numBytes)
|
||||
- Added the following Mifare Classic functions:
|
||||
bool mifareclassic_IsFirstBlock (uint32_t uiBlock)
|
||||
bool mifareclassic_IsTrailerBlock (uint32_t uiBlock)
|
||||
uint8_t mifareclassic_AuthenticateBlock (uint8_t * uid, uint8_t uidLen, uint32_t blockNumber, uint8_t keyNumber, uint8_t * keyData)
|
||||
uint8_t mifareclassic_ReadDataBlock (uint8_t blockNumber, uint8_t * data)
|
||||
uint8_t mifareclassic_WriteDataBlock (uint8_t blockNumber, uint8_t * data)
|
||||
- Added the following Mifare Ultalight functions:
|
||||
uint8_t mifareultralight_ReadPage (uint8_t page, uint8_t * buffer)
|
||||
*/
|
||||
/**************************************************************************/
|
||||
#include <WProgram.h>
|
||||
#include "PN532.h"
|
||||
|
||||
byte pn532ack[] = {0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00};
|
||||
byte pn532response_firmwarevers[] = {0x00, 0xFF, 0x06, 0xFA, 0xD5, 0x03};
|
||||
|
||||
// Uncomment these lines to enable debug output for PN532(SPI) and/or MIFARE related code
|
||||
// #define PN532DEBUG
|
||||
// #define MIFAREDEBUG
|
||||
|
||||
#define PN532_PACKBUFFSIZ 64
|
||||
byte pn532_packetbuffer[PN532_PACKBUFFSIZ];
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Instantiates a new PN532 class
|
||||
|
||||
@param clk SPI clock pin (SCK)
|
||||
@param miso SPI MISO pin
|
||||
@param mosi SPI MOSI pin
|
||||
@param ss SPI chip select pin (CS/SSEL)
|
||||
*/
|
||||
/**************************************************************************/
|
||||
PN532::PN532(uint8_t clk, uint8_t miso, uint8_t mosi, uint8_t ss) {
|
||||
_clk = clk;
|
||||
_miso = miso;
|
||||
|
|
@ -20,28 +60,103 @@ PN532::PN532(uint8_t clk, uint8_t miso, uint8_t mosi, uint8_t ss) {
|
|||
pinMode(_miso, INPUT);
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Setups the HW
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void PN532::begin() {
|
||||
digitalWrite(_ss, LOW);
|
||||
|
||||
delay(1000);
|
||||
|
||||
// not exactly sure why but we have to send a dummy command to get synced up
|
||||
pn532_packetbuffer[0] = PN532_FIRMWAREVERSION;
|
||||
pn532_packetbuffer[0] = PN532_COMMAND_GETFIRMWAREVERSION;
|
||||
sendCommandCheckAck(pn532_packetbuffer, 1);
|
||||
|
||||
// ignore response!
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Prints a hexadecimal value in plain characters
|
||||
|
||||
@param data Pointer to the byte data
|
||||
@param numBytes Data length in bytes
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void PN532::PrintHex(const byte * data, const uint32_t numBytes)
|
||||
{
|
||||
uint32_t szPos;
|
||||
for (szPos=0; szPos < numBytes; szPos++)
|
||||
{
|
||||
Serial.print("0x");
|
||||
// Append leading 0 for small values
|
||||
if (data[szPos] <= 0xF)
|
||||
Serial.print("0");
|
||||
Serial.print(data[szPos], HEX);
|
||||
if ((numBytes > 1) && (szPos != numBytes - 1))
|
||||
{
|
||||
Serial.print(" ");
|
||||
}
|
||||
}
|
||||
Serial.println("");
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Prints a hexadecimal value in plain characters, along with
|
||||
the char equivalents in the following format
|
||||
|
||||
00 00 00 00 00 00 ......
|
||||
|
||||
@param data Pointer to the byte data
|
||||
@param numBytes Data length in bytes
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void PN532::PrintHexChar(const byte * data, const uint32_t numBytes)
|
||||
{
|
||||
uint32_t szPos;
|
||||
for (szPos=0; szPos < numBytes; szPos++)
|
||||
{
|
||||
// Append leading 0 for small values
|
||||
if (data[szPos] <= 0xF)
|
||||
Serial.print("0");
|
||||
Serial.print(data[szPos], HEX);
|
||||
if ((numBytes > 1) && (szPos != numBytes - 1))
|
||||
{
|
||||
Serial.print(" ");
|
||||
}
|
||||
}
|
||||
Serial.print(" ");
|
||||
for (szPos=0; szPos < numBytes; szPos++)
|
||||
{
|
||||
if (data[szPos] <= 0x1F)
|
||||
Serial.print(".");
|
||||
else
|
||||
Serial.print(data[szPos]);
|
||||
}
|
||||
Serial.println("");
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Checks the firmware version of the PN5xx chip
|
||||
|
||||
@returns The chip's firmware version and ID
|
||||
*/
|
||||
/**************************************************************************/
|
||||
uint32_t PN532::getFirmwareVersion(void) {
|
||||
uint32_t response;
|
||||
|
||||
pn532_packetbuffer[0] = PN532_FIRMWAREVERSION;
|
||||
pn532_packetbuffer[0] = PN532_COMMAND_GETFIRMWAREVERSION;
|
||||
|
||||
if (! sendCommandCheckAck(pn532_packetbuffer, 1))
|
||||
return 0;
|
||||
|
||||
// read data packet
|
||||
readspidata(pn532_packetbuffer, 12);
|
||||
|
||||
// check some basic stuff
|
||||
if (0 != strncmp((char *)pn532_packetbuffer, (char *)pn532response_firmwarevers, 6)) {
|
||||
return 0;
|
||||
|
|
@ -59,6 +174,18 @@ uint32_t PN532::getFirmwareVersion(void) {
|
|||
}
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Sends a command and waits a specified period for the ACK
|
||||
|
||||
@param cmd Pointer to the command buffer
|
||||
@param cmdlen The size of the command in bytes
|
||||
@param timeout timeout before giving up
|
||||
|
||||
@returns 1 if everything is OK, 0 if timeout occured before an
|
||||
ACK was recieved
|
||||
*/
|
||||
/**************************************************************************/
|
||||
// default timeout of one second
|
||||
boolean PN532::sendCommandCheckAck(uint8_t *cmd, uint8_t cmdlen, uint16_t timeout) {
|
||||
uint16_t timer = 0;
|
||||
|
|
@ -95,8 +222,124 @@ boolean PN532::sendCommandCheckAck(uint8_t *cmd, uint8_t cmdlen, uint16_t timeou
|
|||
return true; // ack'd command
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
Writes an 8-bit value that sets the state of the PN532's GPIO pins
|
||||
|
||||
@warning This function is provided exclusively for board testing and
|
||||
is dangerous since it will throw an error if any pin other
|
||||
than the ones marked "Can be used as GPIO" are modified! All
|
||||
pins that can not be used as GPIO should ALWAYS be left high
|
||||
(value = 1) or the system will become unstable and a HW reset
|
||||
will be required to recover the PN532.
|
||||
|
||||
pinState[0] = P30 Can be used as GPIO
|
||||
pinState[1] = P31 Can be used as GPIO
|
||||
pinState[2] = P32 *** RESERVED (Must be 1!) ***
|
||||
pinState[3] = P33 Can be used as GPIO
|
||||
pinState[4] = P34 *** RESERVED (Must be 1!) ***
|
||||
pinState[5] = P35 Can be used as GPIO
|
||||
|
||||
@returns 1 if everything executed properly, 0 for an error
|
||||
*/
|
||||
/**************************************************************************/
|
||||
boolean PN532::writeGPIO(uint8_t pinstate) {
|
||||
uint8_t errorbit;
|
||||
|
||||
// Make sure pinstate does not try to toggle P32 or P34
|
||||
pinstate |= (1 << PN532_GPIO_P32) | (1 << PN532_GPIO_P34);
|
||||
|
||||
// Fill command buffer
|
||||
pn532_packetbuffer[0] = PN532_COMMAND_WRITEGPIO;
|
||||
pn532_packetbuffer[1] = PN532_GPIO_VALIDATIONBIT | pinstate; // P3 Pins
|
||||
pn532_packetbuffer[2] = 0x00; // P7 GPIO Pins (not used ... taken by SPI)
|
||||
|
||||
#ifdef PN532DEBUG
|
||||
Serial.print("Writing P3 GPIO: "); Serial.println(pn532_packetbuffer[1], HEX);
|
||||
#endif
|
||||
|
||||
// Send the WRITEGPIO command (0x0E)
|
||||
if (! sendCommandCheckAck(pn532_packetbuffer, 3))
|
||||
return 0x0;
|
||||
|
||||
// Read response packet (00 FF PLEN PLENCHECKSUM D5 CMD+1(0x0F) DATACHECKSUM 00)
|
||||
readspidata(pn532_packetbuffer, 8);
|
||||
|
||||
#ifdef PN532DEBUG
|
||||
Serial.print("Received: ");
|
||||
PrintHex(pn532_packetbuffer, 8);
|
||||
Serial.println("");
|
||||
#endif
|
||||
|
||||
return (pn532_packetbuffer[5] == 0x0F);
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
Reads the state of the PN532's GPIO pins
|
||||
|
||||
@returns An 8-bit value containing the pin state where:
|
||||
|
||||
pinState[0] = P30
|
||||
pinState[1] = P31
|
||||
pinState[2] = P32
|
||||
pinState[3] = P33
|
||||
pinState[4] = P34
|
||||
pinState[5] = P35
|
||||
*/
|
||||
/**************************************************************************/
|
||||
uint8_t PN532::readGPIO(void) {
|
||||
pn532_packetbuffer[0] = PN532_COMMAND_READGPIO;
|
||||
|
||||
// Send the READGPIO command (0x0C)
|
||||
if (! sendCommandCheckAck(pn532_packetbuffer, 1))
|
||||
return 0x0;
|
||||
|
||||
// Read response packet (00 FF PLEN PLENCHECKSUM D5 CMD+1(0x0D) P3 P7 IO1 DATACHECKSUM 00)
|
||||
readspidata(pn532_packetbuffer, 11);
|
||||
|
||||
/* READGPIO response should be in the following format:
|
||||
|
||||
byte Description
|
||||
------------- ------------------------------------------
|
||||
b0..5 Frame header and preamble
|
||||
b6 P3 GPIO Pins
|
||||
b7 P7 GPIO Pins (not used ... taken by SPI)
|
||||
b8 Interface Mode Pins (not used ... bus select pins)
|
||||
b9..10 checksum */
|
||||
|
||||
#ifdef PN532DEBUG
|
||||
Serial.print("Received: ");
|
||||
PrintHex(pn532_packetbuffer, 11);
|
||||
Serial.println("");
|
||||
Serial.print("P3 GPIO: 0x"); Serial.println(pn532_packetbuffer[6], HEX);
|
||||
Serial.print("P7 GPIO: 0x"); Serial.println(pn532_packetbuffer[7], HEX);
|
||||
Serial.print("IO GPIO: 0x"); Serial.println(pn532_packetbuffer[8], HEX);
|
||||
// Note: You can use the IO GPIO value to detect the serial bus being used
|
||||
switch(pn532_packetbuffer[8])
|
||||
{
|
||||
case 0x00: // Using UART
|
||||
Serial.println("Using UART (IO = 0x00)");
|
||||
break;
|
||||
case 0x01: // Using I2C
|
||||
Serial.println("Using I2C (IO = 0x01)");
|
||||
break;
|
||||
case 0x02: // Using SPI
|
||||
Serial.println("Using SPI (IO = 0x02)");
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
return pn532_packetbuffer[6];
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Configures the SAM (Secure Access Module)
|
||||
*/
|
||||
/**************************************************************************/
|
||||
boolean PN532::SAMConfig(void) {
|
||||
pn532_packetbuffer[0] = PN532_SAMCONFIGURATION;
|
||||
pn532_packetbuffer[0] = PN532_COMMAND_SAMCONFIGURATION;
|
||||
pn532_packetbuffer[1] = 0x01; // normal mode;
|
||||
pn532_packetbuffer[2] = 0x14; // timeout 50ms * 20 = 1 second
|
||||
pn532_packetbuffer[3] = 0x01; // use IRQ pin!
|
||||
|
|
@ -110,11 +353,23 @@ boolean PN532::SAMConfig(void) {
|
|||
return (pn532_packetbuffer[5] == 0x15);
|
||||
}
|
||||
|
||||
/***** ISO14443A Commands ******/
|
||||
|
||||
uint32_t PN532::readPassiveTargetID(uint8_t cardbaudrate) {
|
||||
uint32_t cid;
|
||||
|
||||
pn532_packetbuffer[0] = PN532_INLISTPASSIVETARGET;
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
Waits for an ISO14443A target to enter the field
|
||||
|
||||
@param cardBaudRate Baud rate of the card
|
||||
@param uid Pointer to the array that will be populated
|
||||
with the card's UID (up to 7 bytes)
|
||||
@param uidLength Pointer to the variable that will hold the
|
||||
length of the card's UID.
|
||||
|
||||
@returns 1 if everything executed properly, 0 for an error
|
||||
*/
|
||||
/**************************************************************************/
|
||||
boolean PN532::readPassiveTargetID(uint8_t cardbaudrate, uint8_t * uid, uint8_t * uidLength) {
|
||||
pn532_packetbuffer[0] = PN532_COMMAND_INLISTPASSIVETARGET;
|
||||
pn532_packetbuffer[1] = 1; // max 1 cards at once (we can set this to 2 later)
|
||||
pn532_packetbuffer[2] = cardbaudrate;
|
||||
|
||||
|
|
@ -124,31 +379,444 @@ uint32_t PN532::readPassiveTargetID(uint8_t cardbaudrate) {
|
|||
// read data packet
|
||||
readspidata(pn532_packetbuffer, 20);
|
||||
// check some basic stuff
|
||||
|
||||
/* ISO14443A card response should be in the following format:
|
||||
|
||||
Serial.print("Found "); Serial.print(pn532_packetbuffer[7], DEC); Serial.println(" tags");
|
||||
byte Description
|
||||
------------- ------------------------------------------
|
||||
b0..6 Frame header and preamble
|
||||
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 */
|
||||
|
||||
#ifdef MIFAREDEBUG
|
||||
Serial.print("Found "); Serial.print(pn532_packetbuffer[7], DEC); Serial.println(" tags");
|
||||
#endif
|
||||
if (pn532_packetbuffer[7] != 1)
|
||||
return 0;
|
||||
|
||||
uint16_t sens_res = pn532_packetbuffer[9];
|
||||
sens_res <<= 8;
|
||||
sens_res |= pn532_packetbuffer[10];
|
||||
Serial.print("Sens Response: 0x"); Serial.println(sens_res, HEX);
|
||||
Serial.print("Sel Response: 0x"); Serial.println(pn532_packetbuffer[11], HEX);
|
||||
cid = 0;
|
||||
for (uint8_t i=0; i< pn532_packetbuffer[12]; i++) {
|
||||
cid <<= 8;
|
||||
cid |= pn532_packetbuffer[13+i];
|
||||
Serial.print(" 0x"); Serial.print(pn532_packetbuffer[13+i], HEX);
|
||||
#ifdef MIFAREDEBUG
|
||||
Serial.print("ATQA: 0x"); Serial.println(sens_res, HEX);
|
||||
Serial.print("SAK: 0x"); Serial.println(pn532_packetbuffer[11], HEX);
|
||||
#endif
|
||||
|
||||
/* Card appears to be Mifare Classic */
|
||||
*uidLength = pn532_packetbuffer[12];
|
||||
#ifdef MIFAREDEBUG
|
||||
Serial.print("UID:");
|
||||
#endif
|
||||
for (uint8_t i=0; i < pn532_packetbuffer[12]; i++)
|
||||
{
|
||||
uid[i] = pn532_packetbuffer[13+i];
|
||||
#ifdef MIFAREDEBUG
|
||||
Serial.print(" 0x");Serial.print(uid[i], HEX);
|
||||
#endif
|
||||
}
|
||||
Serial.println();
|
||||
#ifdef MIFAREDEBUG
|
||||
Serial.println();
|
||||
#endif
|
||||
|
||||
return cid;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/***** Mifare Classic Functions ******/
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
Indicates whether the specified block number is the first block
|
||||
in the sector (block 0 relative to the current sector)
|
||||
*/
|
||||
/**************************************************************************/
|
||||
bool PN532::mifareclassic_IsFirstBlock (uint32_t 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
|
||||
*/
|
||||
/**************************************************************************/
|
||||
bool PN532::mifareclassic_IsTrailerBlock (uint32_t 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. See section 7.3.8 of the PN532 User Manual
|
||||
for more information on sending MIFARE and other commands.
|
||||
|
||||
@param uid Pointer to a byte array containing the card UID
|
||||
@param uidLen The length (in bytes) of the card's UID (Should
|
||||
be 4 for MIFARE Classic)
|
||||
@param blockNumber The block number to authenticate. (0..63 for
|
||||
1KB cards, and 0..255 for 4KB cards).
|
||||
@param keyNumber Which key type to use during authentication
|
||||
(0 = MIFARE_CMD_AUTH_A, 1 = MIFARE_CMD_AUTH_B)
|
||||
@param keyData Pointer to a byte array containing the 6 byte
|
||||
key value
|
||||
|
||||
@returns 1 if everything executed properly, 0 for an error
|
||||
*/
|
||||
/**************************************************************************/
|
||||
uint8_t PN532::mifareclassic_AuthenticateBlock (uint8_t * uid, uint8_t uidLen, uint32_t blockNumber, uint8_t keyNumber, uint8_t * keyData)
|
||||
{
|
||||
uint8_t len;
|
||||
uint8_t i;
|
||||
|
||||
// Hang on to the key and uid data
|
||||
memcpy (_key, keyData, 6);
|
||||
memcpy (_uid, uid, uidLen);
|
||||
_uidLen = uidLen;
|
||||
|
||||
#ifdef MIFAREDEBUG
|
||||
Serial.print("Trying to authenticate card ");
|
||||
PN532::PrintHex(_uid, _uidLen);
|
||||
Serial.print("Using authentication KEY ");Serial.print(keyNumber ? 'B' : 'A');Serial.print(": ");
|
||||
PN532::PrintHex(_key, 6);
|
||||
#endif
|
||||
|
||||
// Prepare the authentication command //
|
||||
pn532_packetbuffer[0] = PN532_COMMAND_INDATAEXCHANGE; /* Data Exchange Header */
|
||||
pn532_packetbuffer[1] = 1; /* Max card numbers */
|
||||
pn532_packetbuffer[2] = (keyNumber) ? MIFARE_CMD_AUTH_A : MIFARE_CMD_AUTH_B;
|
||||
pn532_packetbuffer[3] = blockNumber; /* Block Number (1K = 0..63, 4K = 0..255 */
|
||||
memcpy (pn532_packetbuffer+4, _key, 6);
|
||||
for (i = 0; i < _uidLen; i++)
|
||||
{
|
||||
pn532_packetbuffer[10+i] = _uid[i]; /* 4 byte card ID */
|
||||
}
|
||||
|
||||
if (! sendCommandCheckAck(pn532_packetbuffer, 10+_uidLen))
|
||||
return 0;
|
||||
|
||||
// Read the response packet
|
||||
readspidata(pn532_packetbuffer, 12);
|
||||
// ToDo: How to check if the response is valid and we are authenticated???
|
||||
// #ifdef PN532DEBUG
|
||||
// Serial.println("Authentification failed%s");
|
||||
// #endif
|
||||
// return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
Tries to read an entire 16-byte data block at the specified block
|
||||
address.
|
||||
|
||||
@param blockNumber The block number to authenticate. (0..63 for
|
||||
1KB cards, and 0..255 for 4KB cards).
|
||||
@param data Pointer to the byte array that will hold the
|
||||
retrieved data (if any)
|
||||
|
||||
@returns 1 if everything executed properly, 0 for an error
|
||||
*/
|
||||
/**************************************************************************/
|
||||
uint8_t PN532::mifareclassic_ReadDataBlock (uint8_t blockNumber, uint8_t * data)
|
||||
{
|
||||
#ifdef MIFAREDEBUG
|
||||
Serial.print("Trying to read 16 bytes from block ");Serial.println(blockNumber);
|
||||
#endif
|
||||
|
||||
/* Prepare the command */
|
||||
pn532_packetbuffer[0] = PN532_COMMAND_INDATAEXCHANGE;
|
||||
pn532_packetbuffer[1] = 1; /* Card number */
|
||||
pn532_packetbuffer[2] = MIFARE_CMD_READ; /* Mifare Read command = 0x30 */
|
||||
pn532_packetbuffer[3] = blockNumber; /* Block Number (0..63 for 1K, 0..255 for 4K) */
|
||||
|
||||
/* Send the command */
|
||||
if (! sendCommandCheckAck(pn532_packetbuffer, 4))
|
||||
{
|
||||
#ifdef MIFAREDEBUG
|
||||
Serial.println("Failed to receive ACK for read command");
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Read the response packet */
|
||||
readspidata(pn532_packetbuffer, 26);
|
||||
|
||||
/* If byte 8 isn't 0x00 we probably have an error */
|
||||
if (pn532_packetbuffer[7] != 0x00)
|
||||
{
|
||||
//#ifdef MIFAREDEBUG
|
||||
Serial.println("Unexpected response");
|
||||
PN532::PrintHexChar(pn532_packetbuffer, 26);
|
||||
//#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Copy the 16 data bytes to the output buffer */
|
||||
/* Block content starts at byte 9 of a valid response */
|
||||
memcpy (data, pn532_packetbuffer+8, 16);
|
||||
|
||||
/* Display data for debug if requested */
|
||||
#ifdef MIFAREDEBUG
|
||||
Serial.print("Block ");
|
||||
Serial.println(blockNumber);
|
||||
PN532::PrintHexChar(data, 16);
|
||||
#endif
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
Tries to write an entire 16-byte data block at the specified block
|
||||
address.
|
||||
|
||||
@param blockNumber The block number to authenticate. (0..63 for
|
||||
1KB cards, and 0..255 for 4KB cards).
|
||||
@param data The byte array that contains the data to write.
|
||||
|
||||
@returns 1 if everything executed properly, 0 for an error
|
||||
*/
|
||||
/**************************************************************************/
|
||||
uint8_t PN532::mifareclassic_WriteDataBlock (uint8_t blockNumber, uint8_t * data)
|
||||
{
|
||||
#ifdef MIFAREDEBUG
|
||||
Serial.print("Trying to write 16 bytes to block ");Serial.println(blockNumber);
|
||||
#endif
|
||||
|
||||
/* Prepare the first command */
|
||||
pn532_packetbuffer[0] = PN532_COMMAND_INDATAEXCHANGE;
|
||||
pn532_packetbuffer[1] = 1; /* Card number */
|
||||
pn532_packetbuffer[2] = MIFARE_CMD_WRITE; /* Mifare Write command = 0xA0 */
|
||||
pn532_packetbuffer[3] = blockNumber; /* Block Number (0..63 for 1K, 0..255 for 4K) */
|
||||
memcpy (pn532_packetbuffer+4, data, 16); /* Data Payload */
|
||||
|
||||
/* Send the command */
|
||||
if (! sendCommandCheckAck(pn532_packetbuffer, 20))
|
||||
{
|
||||
#ifdef MIFAREDEBUG
|
||||
Serial.println("Failed to receive ACK for write command");
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
delay(10);
|
||||
|
||||
/* Read the response packet */
|
||||
readspidata(pn532_packetbuffer, 26);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
Formats a Mifare Classic card to store NDEF Records
|
||||
|
||||
@returns 1 if everything executed properly, 0 for an error
|
||||
*/
|
||||
/**************************************************************************/
|
||||
uint8_t PN532::mifareclassic_FormatNDEF (void)
|
||||
{
|
||||
uint8_t sectorbuffer1[16] = {0x14, 0x01, 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1};
|
||||
uint8_t sectorbuffer2[16] = {0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1};
|
||||
uint8_t sectorbuffer3[16] = {0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0x78, 0x77, 0x88, 0xC1, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
|
||||
|
||||
// Write block 1 and 2 to the card
|
||||
if (!(mifareclassic_WriteDataBlock (1, sectorbuffer1)))
|
||||
return 0;
|
||||
if (!(mifareclassic_WriteDataBlock (2, sectorbuffer2)))
|
||||
return 0;
|
||||
// Write key A and access rights card
|
||||
if (!(mifareclassic_WriteDataBlock (3, sectorbuffer3)))
|
||||
return 0;
|
||||
|
||||
// Seems that everything was OK (?!)
|
||||
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.
|
||||
|
||||
@param sectorNumber The sector that the URI record should be written
|
||||
to (can be 1..15 for a 1K card)
|
||||
@param uriIdentifier The uri identifier code (0 = none, 0x01 =
|
||||
"http://www.", etc.)
|
||||
@param url The uri text to write (max 38 characters).
|
||||
|
||||
@returns 1 if everything executed properly, 0 for an error
|
||||
*/
|
||||
/**************************************************************************/
|
||||
uint8_t PN532::mifareclassic_WriteNDEFURI (uint8_t sectorNumber, uint8_t uriIdentifier, const char * url)
|
||||
{
|
||||
// Figure out how long the string is
|
||||
uint8_t len = strlen(url);
|
||||
|
||||
// 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;
|
||||
|
||||
// Setup the sector buffer (w/pre-formatted TLV wrapper and NDEF message)
|
||||
uint8_t sectorbuffer1[16] = {0x00, 0x00, 0x03, len+5, 0xD1, 0x01, len+1, 0x55, uriIdentifier, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||
uint8_t sectorbuffer2[16] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||
uint8_t sectorbuffer3[16] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||
uint8_t sectorbuffer4[16] = {0xD3, 0xF7, 0xD3, 0xF7, 0xD3, 0xF7, 0x7F, 0x07, 0x88, 0x40, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
|
||||
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 (!(mifareclassic_WriteDataBlock (sectorNumber*4, sectorbuffer1)))
|
||||
return 0;
|
||||
if (!(mifareclassic_WriteDataBlock ((sectorNumber*4)+1, sectorbuffer2)))
|
||||
return 0;
|
||||
if (!(mifareclassic_WriteDataBlock ((sectorNumber*4)+2, sectorbuffer3)))
|
||||
return 0;
|
||||
if (!(mifareclassic_WriteDataBlock ((sectorNumber*4)+3, sectorbuffer4)))
|
||||
return 0;
|
||||
|
||||
// Seems that everything was OK (?!)
|
||||
return 1;
|
||||
}
|
||||
|
||||
/***** Mifare Ultralight Functions ******/
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
Tries to read an entire 4-byte page at the specified address.
|
||||
|
||||
@param page The page number (0..63 in most cases)
|
||||
@param buffer Pointer to the byte array that will hold the
|
||||
retrieved data (if any)
|
||||
*/
|
||||
/**************************************************************************/
|
||||
uint8_t PN532::mifareultralight_ReadPage (uint8_t page, uint8_t * buffer)
|
||||
{
|
||||
if (page >= 64)
|
||||
{
|
||||
#ifdef MIFAREDEBUG
|
||||
Serial.println("Page value out of range");
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef MIFAREDEBUG
|
||||
Serial.print("Reading page ");Serial.println(page);
|
||||
#endif
|
||||
|
||||
/* Prepare the command */
|
||||
pn532_packetbuffer[0] = PN532_COMMAND_INDATAEXCHANGE;
|
||||
pn532_packetbuffer[1] = 1; /* Card number */
|
||||
pn532_packetbuffer[2] = MIFARE_CMD_READ; /* Mifare Read command = 0x30 */
|
||||
pn532_packetbuffer[3] = page; /* Page Number (0..63 in most cases) */
|
||||
|
||||
/* Send the command */
|
||||
if (! sendCommandCheckAck(pn532_packetbuffer, 4))
|
||||
{
|
||||
#ifdef MIFAREDEBUG
|
||||
Serial.println("Failed to receive ACK for write command");
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Read the response packet */
|
||||
readspidata(pn532_packetbuffer, 26);
|
||||
#ifdef MIFAREDEBUG
|
||||
Serial.println("Received: ");
|
||||
PN532::PrintHexChar(pn532_packetbuffer, 26);
|
||||
#endif
|
||||
|
||||
/* If byte 8 isn't 0x00 we probably have an error */
|
||||
if (pn532_packetbuffer[7] == 0x00)
|
||||
{
|
||||
/* Copy the 4 data bytes to the output buffer */
|
||||
/* Block content starts at byte 9 of a valid response */
|
||||
/* Note that the command actually reads 16 byte or 4 */
|
||||
/* pages at a time ... we simply discard the last 12 */
|
||||
/* bytes */
|
||||
memcpy (buffer, pn532_packetbuffer+8, 4);
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef MIFAREDEBUG
|
||||
Serial.println("Unexpected response reading block: ");
|
||||
PN532::PrintHexChar(pn532_packetbuffer, 26);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Display data for debug if requested */
|
||||
#ifdef MIFAREDEBUG
|
||||
Serial.print("Page ");Serial.print(page);Serial.println(":");
|
||||
PN532::PrintHexChar(buffer, 4);
|
||||
#endif
|
||||
|
||||
// Return OK signal
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/************** high level SPI */
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Tries to read the SPI ACK signal
|
||||
*/
|
||||
/**************************************************************************/
|
||||
boolean PN532::spi_readack() {
|
||||
uint8_t ackbuff[6];
|
||||
|
||||
|
|
@ -159,6 +827,11 @@ boolean PN532::spi_readack() {
|
|||
|
||||
/************** mid level SPI */
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Reads the SPI status register (to know if the PN532 is ready)
|
||||
*/
|
||||
/**************************************************************************/
|
||||
uint8_t PN532::readspistatus(void) {
|
||||
digitalWrite(_ss, LOW);
|
||||
delay(2);
|
||||
|
|
@ -170,6 +843,14 @@ uint8_t PN532::readspistatus(void) {
|
|||
return x;
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Reads n bytes of data from the PN532 via SPI
|
||||
|
||||
@param buff Pointer to the buffer where data will be written
|
||||
@param n Number of bytes to be read
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void PN532::readspidata(uint8_t* buff, uint8_t n) {
|
||||
digitalWrite(_ss, LOW);
|
||||
delay(2);
|
||||
|
|
@ -194,6 +875,15 @@ void PN532::readspidata(uint8_t* buff, uint8_t n) {
|
|||
digitalWrite(_ss, HIGH);
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Writes a command to the PN532, automatically inserting the
|
||||
preamble and required frame details (checksum, len, etc.)
|
||||
|
||||
@param cmd Pointer to the command buffer
|
||||
@param cmdlen Command length in bytes
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void PN532::spiwritecommand(uint8_t* cmd, uint8_t cmdlen) {
|
||||
uint8_t checksum;
|
||||
|
||||
|
|
@ -247,6 +937,13 @@ void PN532::spiwritecommand(uint8_t* cmd, uint8_t cmdlen) {
|
|||
}
|
||||
/************** low level SPI */
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Low-level SPI write wrapper
|
||||
|
||||
@param c 8-bit command to write to the SPI bus
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void PN532::spiwrite(uint8_t c) {
|
||||
int8_t i;
|
||||
digitalWrite(_clk, HIGH);
|
||||
|
|
@ -262,6 +959,13 @@ void PN532::spiwrite(uint8_t c) {
|
|||
}
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Low-level SPI read wrapper
|
||||
|
||||
@returns The 8-bit value that was read from the SPI bus
|
||||
*/
|
||||
/**************************************************************************/
|
||||
uint8_t PN532::spiread(void) {
|
||||
int8_t i, x;
|
||||
x = 0;
|
||||
|
|
|
|||
171
PN532.h
171
PN532.h
|
|
@ -1,49 +1,162 @@
|
|||
// PN532 library by adafruit/ladyada
|
||||
// MIT license
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@file PN532.h
|
||||
@author Adafruit Industries
|
||||
@license BSD (see license.txt)
|
||||
|
||||
@section HISTORY
|
||||
|
||||
#if ARDUINO >= 100
|
||||
#include "Arduino.h"
|
||||
#else
|
||||
#include "WProgram.h"
|
||||
#endif
|
||||
v1.1 - Added full command list
|
||||
- Added 'verbose' mode flag to constructor to toggle debug output
|
||||
- Changed readPassiveTargetID() to return variable length values
|
||||
|
||||
*/
|
||||
/**************************************************************************/
|
||||
|
||||
#define PN532_PREAMBLE 0x00
|
||||
#define PN532_STARTCODE1 0x00
|
||||
#define PN532_STARTCODE2 0xFF
|
||||
#define PN532_POSTAMBLE 0x00
|
||||
#include <WProgram.h>
|
||||
|
||||
#define PN532_HOSTTOPN532 0xD4
|
||||
#define PN532_PREAMBLE (0x00)
|
||||
#define PN532_STARTCODE1 (0x00)
|
||||
#define PN532_STARTCODE2 (0xFF)
|
||||
#define PN532_POSTAMBLE (0x00)
|
||||
|
||||
#define PN532_FIRMWAREVERSION 0x02
|
||||
#define PN532_GETGENERALSTATUS 0x04
|
||||
#define PN532_SAMCONFIGURATION 0x14
|
||||
#define PN532_INLISTPASSIVETARGET 0x4A
|
||||
#define PN532_WAKEUP 0x55
|
||||
#define PN532_HOSTTOPN532 (0xD4)
|
||||
|
||||
// PN532 Commands
|
||||
#define PN532_COMMAND_DIAGNOSE (0x00)
|
||||
#define PN532_COMMAND_GETFIRMWAREVERSION (0x02)
|
||||
#define PN532_COMMAND_GETGENERALSTATUS (0x04)
|
||||
#define PN532_COMMAND_READREGISTER (0x06)
|
||||
#define PN532_COMMAND_WRITEREGISTER (0x08)
|
||||
#define PN532_COMMAND_READGPIO (0x0C)
|
||||
#define PN532_COMMAND_WRITEGPIO (0x0E)
|
||||
#define PN532_COMMAND_SETSERIALBAUDRATE (0x10)
|
||||
#define PN532_COMMAND_SETPARAMETERS (0x12)
|
||||
#define PN532_COMMAND_SAMCONFIGURATION (0x14)
|
||||
#define PN532_COMMAND_POWERDOWN (0x16)
|
||||
#define PN532_COMMAND_RFCONFIGURATION (0x32)
|
||||
#define PN532_COMMAND_RFREGULATIONTEST (0x58)
|
||||
#define PN532_COMMAND_INJUMPFORDEP (0x56)
|
||||
#define PN532_COMMAND_INJUMPFORPSL (0x46)
|
||||
#define PN532_COMMAND_INLISTPASSIVETARGET (0x4A)
|
||||
#define PN532_COMMAND_INATR (0x50)
|
||||
#define PN532_COMMAND_INPSL (0x4E)
|
||||
#define PN532_COMMAND_INDATAEXCHANGE (0x40)
|
||||
#define PN532_COMMAND_INCOMMUNICATETHRU (0x42)
|
||||
#define PN532_COMMAND_INDESELECT (0x44)
|
||||
#define PN532_COMMAND_INRELEASE (0x52)
|
||||
#define PN532_COMMAND_INSELECT (0x54)
|
||||
#define PN532_COMMAND_INAUTOPOLL (0x60)
|
||||
#define PN532_COMMAND_TGINITASTARGET (0x8C)
|
||||
#define PN532_COMMAND_TGSETGENERALBYTES (0x92)
|
||||
#define PN532_COMMAND_TGGETDATA (0x86)
|
||||
#define PN532_COMMAND_TGSETDATA (0x8E)
|
||||
#define PN532_COMMAND_TGSETMETADATA (0x94)
|
||||
#define PN532_COMMAND_TGGETINITIATORCOMMAND (0x88)
|
||||
#define PN532_COMMAND_TGRESPONSETOINITIATOR (0x90)
|
||||
#define PN532_COMMAND_TGGETTARGETSTATUS (0x8A)
|
||||
|
||||
#define PN532_SPI_STATREAD 0x02
|
||||
#define PN532_SPI_DATAWRITE 0x01
|
||||
#define PN532_SPI_DATAREAD 0x03
|
||||
#define PN532_SPI_READY 0x01
|
||||
#define PN532_WAKEUP (0x55)
|
||||
|
||||
#define PN532_MIFARE_ISO14443A 0x0
|
||||
#define PN532_SPI_STATREAD (0x02)
|
||||
#define PN532_SPI_DATAWRITE (0x01)
|
||||
#define PN532_SPI_DATAREAD (0x03)
|
||||
#define PN532_SPI_READY (0x01)
|
||||
|
||||
#define PN532_MIFARE_ISO14443A (0x00)
|
||||
|
||||
// Mifare Commands
|
||||
#define MIFARE_CMD_AUTH_A (0x60)
|
||||
#define MIFARE_CMD_AUTH_B (0x61)
|
||||
#define MIFARE_CMD_READ (0x30)
|
||||
#define MIFARE_CMD_WRITE (0xA0)
|
||||
#define MIFARE_CMD_TRANSFER (0xB0)
|
||||
#define MIFARE_CMD_DECREMENT (0xC0)
|
||||
#define MIFARE_CMD_INCREMENT (0xC1)
|
||||
#define MIFARE_CMD_STORE (0xC2)
|
||||
|
||||
// Prefixes for NDEF Records (to identify record type)
|
||||
#define NDEF_URIPREFIX_NONE (0x00)
|
||||
#define NDEF_URIPREFIX_HTTP_WWWDOT (0x01)
|
||||
#define NDEF_URIPREFIX_HTTPS_WWWDOT (0x02)
|
||||
#define NDEF_URIPREFIX_HTTP (0x03)
|
||||
#define NDEF_URIPREFIX_HTTPS (0x04)
|
||||
#define NDEF_URIPREFIX_TEL (0x05)
|
||||
#define NDEF_URIPREFIX_MAILTO (0x06)
|
||||
#define NDEF_URIPREFIX_FTP_ANONAT (0x07)
|
||||
#define NDEF_URIPREFIX_FTP_FTPDOT (0x08)
|
||||
#define NDEF_URIPREFIX_FTPS (0x09)
|
||||
#define NDEF_URIPREFIX_SFTP (0x0A)
|
||||
#define NDEF_URIPREFIX_SMB (0x0B)
|
||||
#define NDEF_URIPREFIX_NFS (0x0C)
|
||||
#define NDEF_URIPREFIX_FTP (0x0D)
|
||||
#define NDEF_URIPREFIX_DAV (0x0E)
|
||||
#define NDEF_URIPREFIX_NEWS (0x0F)
|
||||
#define NDEF_URIPREFIX_TELNET (0x10)
|
||||
#define NDEF_URIPREFIX_IMAP (0x11)
|
||||
#define NDEF_URIPREFIX_RTSP (0x12)
|
||||
#define NDEF_URIPREFIX_URN (0x13)
|
||||
#define NDEF_URIPREFIX_POP (0x14)
|
||||
#define NDEF_URIPREFIX_SIP (0x15)
|
||||
#define NDEF_URIPREFIX_SIPS (0x16)
|
||||
#define NDEF_URIPREFIX_TFTP (0x17)
|
||||
#define NDEF_URIPREFIX_BTSPP (0x18)
|
||||
#define NDEF_URIPREFIX_BTL2CAP (0x19)
|
||||
#define NDEF_URIPREFIX_BTGOEP (0x1A)
|
||||
#define NDEF_URIPREFIX_TCPOBEX (0x1B)
|
||||
#define NDEF_URIPREFIX_IRDAOBEX (0x1C)
|
||||
#define NDEF_URIPREFIX_FILE (0x1D)
|
||||
#define NDEF_URIPREFIX_URN_EPC_ID (0x1E)
|
||||
#define NDEF_URIPREFIX_URN_EPC_TAG (0x1F)
|
||||
#define NDEF_URIPREFIX_URN_EPC_PAT (0x20)
|
||||
#define NDEF_URIPREFIX_URN_EPC_RAW (0x21)
|
||||
#define NDEF_URIPREFIX_URN_EPC (0x22)
|
||||
#define NDEF_URIPREFIX_URN_NFC (0x23)
|
||||
|
||||
#define PN532_GPIO_VALIDATIONBIT (0x80)
|
||||
#define PN532_GPIO_P30 (0)
|
||||
#define PN532_GPIO_P31 (1)
|
||||
#define PN532_GPIO_P32 (2)
|
||||
#define PN532_GPIO_P33 (3)
|
||||
#define PN532_GPIO_P34 (4)
|
||||
#define PN532_GPIO_P35 (5)
|
||||
|
||||
class PN532{
|
||||
public:
|
||||
PN532(uint8_t cs, uint8_t clk, uint8_t mosi, uint8_t miso);
|
||||
|
||||
void begin(void);
|
||||
|
||||
|
||||
// Generic PN532 functions
|
||||
boolean SAMConfig(void);
|
||||
uint32_t getFirmwareVersion(void);
|
||||
uint32_t readPassiveTargetID(uint8_t cardbaudrate);
|
||||
|
||||
boolean sendCommandCheckAck(uint8_t *cmd, uint8_t cmdlen, uint16_t timeout = 1000);
|
||||
|
||||
//
|
||||
boolean sendCommandCheckAck(uint8_t *cmd, uint8_t cmdlen, uint16_t timeout = 1000);
|
||||
boolean writeGPIO(uint8_t pinstate);
|
||||
uint8_t readGPIO(void);
|
||||
|
||||
// ISO14443A functions
|
||||
boolean readPassiveTargetID(uint8_t cardbaudrate, uint8_t * uid, uint8_t * uidLength);
|
||||
|
||||
// Mifare Classic functions
|
||||
bool mifareclassic_IsFirstBlock (uint32_t uiBlock);
|
||||
bool mifareclassic_IsTrailerBlock (uint32_t uiBlock);
|
||||
uint8_t mifareclassic_AuthenticateBlock (uint8_t * uid, uint8_t uidLen, uint32_t blockNumber, uint8_t keyNumber, uint8_t * keyData);
|
||||
uint8_t mifareclassic_ReadDataBlock (uint8_t blockNumber, uint8_t * data);
|
||||
uint8_t mifareclassic_WriteDataBlock (uint8_t blockNumber, uint8_t * data);
|
||||
uint8_t mifareclassic_FormatNDEF (void);
|
||||
uint8_t mifareclassic_WriteNDEFURI (uint8_t sectorNumber, uint8_t uriIdentifier, const char * url);
|
||||
|
||||
// Mifare Ultralight functions
|
||||
uint8_t mifareultralight_ReadPage (uint8_t page, uint8_t * buffer);
|
||||
|
||||
// Help functions to display formatted text
|
||||
static void PrintHex(const byte * data, const uint32_t numBytes);
|
||||
static void PrintHexChar(const byte * pbtData, const uint32_t numBytes);
|
||||
|
||||
private:
|
||||
uint8_t _ss, _clk, _mosi, _miso;
|
||||
uint8_t _uid[7]; // ISO14443A uid
|
||||
uint8_t _uidLen; // uid len
|
||||
uint8_t _key[6]; // Mifare Classic key
|
||||
|
||||
boolean spi_readack();
|
||||
uint8_t readspistatus(void);
|
||||
|
|
|
|||
71
examples/iso14443a_uid/iso14443a_uid.pde
Normal file
71
examples/iso14443a_uid/iso14443a_uid.pde
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
/**************************************************************************/
|
||||
/*!
|
||||
@file iso14443a_uid.pde
|
||||
@author Adafruit Industries
|
||||
@license BSD (see license.txt)
|
||||
|
||||
This example will attempt to connect to an ISO14443A
|
||||
card or tag and retrieve some basic information about it
|
||||
that can be used to determine what type of card it is.
|
||||
|
||||
Note that you need the baud rate to be 115200 because we need to print
|
||||
out the data and read from the card at the same time!
|
||||
*/
|
||||
/**************************************************************************/
|
||||
|
||||
#include <PN532.h>
|
||||
|
||||
#define SCK (2)
|
||||
#define MOSI (3)
|
||||
#define SS (4)
|
||||
#define MISO (5)
|
||||
|
||||
PN532 nfc(SCK, MISO, MOSI, SS);
|
||||
|
||||
void setup(void) {
|
||||
Serial.begin(115200);
|
||||
Serial.println("Hello!");
|
||||
|
||||
nfc.begin();
|
||||
|
||||
uint32_t versiondata = nfc.getFirmwareVersion();
|
||||
if (! versiondata) {
|
||||
Serial.print("Didn't find PN53x board");
|
||||
while (1); // halt
|
||||
}
|
||||
|
||||
// Got ok data, print it out!
|
||||
Serial.print("Found chip PN5"); Serial.println((versiondata>>24) & 0xFF, HEX);
|
||||
Serial.print("Firmware ver. "); Serial.print((versiondata>>16) & 0xFF, DEC);
|
||||
Serial.print('.'); Serial.println((versiondata>>8) & 0xFF, DEC);
|
||||
|
||||
// configure board to read RFID tags
|
||||
nfc.SAMConfig();
|
||||
|
||||
Serial.println("Waiting for an ISO14443A card");
|
||||
}
|
||||
|
||||
|
||||
void loop(void) {
|
||||
boolean success;
|
||||
uint8_t uid[] = { 0, 0, 0, 0, 0, 0, 0 }; // Buffer to store the returned UID
|
||||
uint8_t uidLength; // Length of the UID (4 or 7 bytes depending on ISO14443A card type)
|
||||
|
||||
// Wait for an ISO14443A type cards (Mifare, etc.). When one is found
|
||||
// 'uid' will be populated with the UID, and uidLength will indicate
|
||||
// if the uid is 4 bytes (Mifare Classic) or 7 bytes (Mifare Ultralight)
|
||||
success = nfc.readPassiveTargetID(PN532_MIFARE_ISO14443A, &uid[0], &uidLength);
|
||||
|
||||
if (success) {
|
||||
Serial.println("Found a card!");
|
||||
Serial.print("UID Length: ");Serial.print(uidLength, DEC);Serial.println(" bytes");
|
||||
Serial.print("UID Value: ");
|
||||
for (uint8_t i=0; i < uidLength; i++)
|
||||
{
|
||||
Serial.print(" 0x");Serial.print(uid[i], HEX);
|
||||
}
|
||||
Serial.println("");
|
||||
// Wait 1 second before continuing
|
||||
delay(1000);
|
||||
}
|
||||
}
|
||||
148
examples/mifareclassic_formatndef/mifareclassic_formatndef.pde
Normal file
148
examples/mifareclassic_formatndef/mifareclassic_formatndef.pde
Normal file
|
|
@ -0,0 +1,148 @@
|
|||
/**************************************************************************/
|
||||
/*!
|
||||
@file mifareclassic_formatndef.pde
|
||||
@author Adafruit Industries
|
||||
@license BSD (see license.txt)
|
||||
|
||||
This example attempts to format a Mifare Classic
|
||||
card for NDEF Records and writes an NDEF URI Record
|
||||
|
||||
Note that you need the baud rate to be 115200 because we need to print
|
||||
out the data and read from the card at the same time!
|
||||
*/
|
||||
/**************************************************************************/
|
||||
|
||||
#include <PN532.h>
|
||||
|
||||
#define SCK (2)
|
||||
#define MOSI (3)
|
||||
#define SS (4)
|
||||
#define MISO (5)
|
||||
|
||||
PN532 nfc(SCK, MISO, MOSI, SS);
|
||||
|
||||
const char * url = "adafruit.com";
|
||||
|
||||
void setup(void) {
|
||||
Serial.begin(115200);
|
||||
Serial.println("Looking for PN532...");
|
||||
|
||||
nfc.begin();
|
||||
|
||||
uint32_t versiondata = nfc.getFirmwareVersion();
|
||||
if (! versiondata) {
|
||||
Serial.print("Didn't find PN53x board");
|
||||
while (1); // halt
|
||||
}
|
||||
|
||||
// Got ok data, print it out!
|
||||
Serial.print("Found chip PN5"); Serial.println((versiondata>>24) & 0xFF, HEX);
|
||||
Serial.print("Firmware ver. "); Serial.print((versiondata>>16) & 0xFF, DEC);
|
||||
Serial.print('.'); Serial.println((versiondata>>8) & 0xFF, DEC);
|
||||
|
||||
// configure board to read RFID tags
|
||||
nfc.SAMConfig();
|
||||
|
||||
Serial.println("");
|
||||
Serial.println("Place your Mifare Classic card on the reader to format with NDEF");
|
||||
Serial.println("and press any key to continue ...");
|
||||
// Wait for user input before proceeding
|
||||
Serial.flush();
|
||||
while (!Serial.available());
|
||||
Serial.flush();
|
||||
}
|
||||
|
||||
void loop(void) {
|
||||
uint8_t success; // Flag to check if there was an error with the PN532
|
||||
uint8_t uid[] = { 0, 0, 0, 0, 0, 0, 0 }; // Buffer to store the returned UID
|
||||
uint8_t uidLength; // Length of the UID (4 or 7 bytes depending on ISO14443A card type)
|
||||
bool authenticated = false; // Flag to indicate if the sector is authenticated
|
||||
|
||||
// Use the default key
|
||||
uint8_t keya[6] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
|
||||
|
||||
// Wait for an ISO14443A type card (Mifare, etc.). When one is found
|
||||
// 'uid' will be populated with the UID, and uidLength will indicate
|
||||
// if the uid is 4 bytes (Mifare Classic) or 7 bytes (Mifare Ultralight)
|
||||
success = nfc.readPassiveTargetID(PN532_MIFARE_ISO14443A, uid, &uidLength);
|
||||
|
||||
if (success)
|
||||
{
|
||||
// Display some basic information about the card
|
||||
Serial.println("Found an ISO14443A card");
|
||||
Serial.print(" UID Length: ");Serial.print(uidLength, DEC);Serial.println(" bytes");
|
||||
Serial.print(" UID Value: ");
|
||||
nfc.PrintHex(uid, uidLength);
|
||||
Serial.println("");
|
||||
|
||||
// Make sure this is a Mifare Classic card
|
||||
if (uidLength != 4)
|
||||
{
|
||||
Serial.println("Ooops ... this doesn't seem to be a Mifare Classic card!");
|
||||
return;
|
||||
}
|
||||
|
||||
// We probably have a Mifare Classic card ...
|
||||
Serial.println("Seems to be a Mifare Classic card (4 byte UID)");
|
||||
|
||||
// Try to format the card for NDEF data
|
||||
success = nfc.mifareclassic_AuthenticateBlock (uid, uidLength, 0, 0, keya);
|
||||
if (!success)
|
||||
{
|
||||
Serial.println("Unable to authenticate block 0 to enable card formatting!");
|
||||
return;
|
||||
}
|
||||
success = nfc.mifareclassic_FormatNDEF();
|
||||
if (!success)
|
||||
{
|
||||
Serial.println("Unable to format the card for NDEF");
|
||||
return;
|
||||
}
|
||||
|
||||
Serial.println("Card has been formatted for NDEF data using MAD1");
|
||||
|
||||
// Try to authenticate block 4 (first block of sector 1) using our key
|
||||
success = nfc.mifareclassic_AuthenticateBlock (uid, uidLength, 4, 0, keya);
|
||||
|
||||
// Make sure the authentification process didn't fail
|
||||
if (!success)
|
||||
{
|
||||
Serial.println("Authentication failed.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Try to write a URL
|
||||
Serial.println("Writing URI to sector 1 as an NDEF Message");
|
||||
|
||||
// Authenticated seems to have worked
|
||||
// Try to write an NDEF record to sector 1
|
||||
// Use 0x01 for the URI Identifier Code to prepend "http://www."
|
||||
// to the url (and save some space). For information on URI ID Codes
|
||||
// see http://www.ladyada.net/wiki/private/articlestaging/nfc/ndef
|
||||
if (strlen(url) > 38)
|
||||
{
|
||||
// The length is also checked in the WriteNDEFURI function, but lets
|
||||
// warn users here just in case they change the value and it's bigger
|
||||
// than it should be
|
||||
Serial.println("URI is too long ... must be less than 38 characters long");
|
||||
return;
|
||||
}
|
||||
|
||||
// URI is within size limits ... write it to the card and report success/failure
|
||||
success = nfc.mifareclassic_WriteNDEFURI(1, NDEF_URIPREFIX_HTTP_WWWDOT, url);
|
||||
if (success)
|
||||
{
|
||||
Serial.println("NDEF URI Record written to sector 1");
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.println("NDEF Record creation failed! :(");
|
||||
}
|
||||
}
|
||||
|
||||
// Wait a bit before trying again
|
||||
Serial.println("\n\nDone!");
|
||||
Serial.flush();
|
||||
while (!Serial.available());
|
||||
Serial.flush();
|
||||
}
|
||||
152
examples/mifareclassic_memdump/mifareclassic_memdump.pde
Normal file
152
examples/mifareclassic_memdump/mifareclassic_memdump.pde
Normal file
|
|
@ -0,0 +1,152 @@
|
|||
/**************************************************************************/
|
||||
/*!
|
||||
@file mifareclassic_memdump.pde
|
||||
@author Adafruit Industries
|
||||
@license BSD (see license.txt)
|
||||
|
||||
This example attempts to dump the contents of a Mifare Classic 1K card
|
||||
|
||||
Note that you need the baud rate to be 115200 because we need to print
|
||||
out the data and read from the card at the same time!
|
||||
*/
|
||||
/**************************************************************************/
|
||||
|
||||
#include <PN532.h>
|
||||
|
||||
#define SCK (2)
|
||||
#define MOSI (3)
|
||||
#define SS (4)
|
||||
#define MISO (5)
|
||||
|
||||
PN532 nfc(SCK, MISO, MOSI, SS);
|
||||
|
||||
void setup(void) {
|
||||
Serial.begin(115200);
|
||||
Serial.println("Looking for PN532...");
|
||||
|
||||
nfc.begin();
|
||||
|
||||
uint32_t versiondata = nfc.getFirmwareVersion();
|
||||
if (! versiondata) {
|
||||
Serial.print("Didn't find PN53x board");
|
||||
while (1); // halt
|
||||
}
|
||||
// Got ok data, print it out!
|
||||
Serial.print("Found chip PN5"); Serial.println((versiondata>>24) & 0xFF, HEX);
|
||||
Serial.print("Firmware ver. "); Serial.print((versiondata>>16) & 0xFF, DEC);
|
||||
Serial.print('.'); Serial.println((versiondata>>8) & 0xFF, DEC);
|
||||
|
||||
// configure board to read RFID tags
|
||||
nfc.SAMConfig();
|
||||
|
||||
Serial.println("Waiting for an ISO14443A Card ...");
|
||||
}
|
||||
|
||||
|
||||
void loop(void) {
|
||||
uint8_t success; // Flag to check if there was an error with the PN532
|
||||
uint8_t uid[] = { 0, 0, 0, 0, 0, 0, 0 }; // Buffer to store the returned UID
|
||||
uint8_t uidLength; // Length of the UID (4 or 7 bytes depending on ISO14443A card type)
|
||||
uint8_t currentblock; // Counter to keep track of which block we're on
|
||||
bool authenticated = false; // Flag to indicate if the sector is authenticated
|
||||
uint8_t data[16]; // Array to store block data during reads
|
||||
|
||||
// Use the default KEYA: FF FF FF FF FF FF
|
||||
uint8_t keya[6] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
|
||||
uint8_t keyb[6] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
|
||||
// uint8_t keya[6] = { 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5 };
|
||||
// uint8_t keyb[6] = { 0xD3, 0xF7, 0xD3, 0xF7, 0xD3, 0xF7 };
|
||||
|
||||
// Wait for an ISO14443A type cards (Mifare, etc.). When one is found
|
||||
// 'uid' will be populated with the UID, and uidLength will indicate
|
||||
// if the uid is 4 bytes (Mifare Classic) or 7 bytes (Mifare Ultralight)
|
||||
success = nfc.readPassiveTargetID(PN532_MIFARE_ISO14443A, uid, &uidLength);
|
||||
|
||||
if (success) {
|
||||
// Display some basic information about the card
|
||||
Serial.println("Found an ISO14443A card");
|
||||
Serial.print(" UID Length: ");Serial.print(uidLength, DEC);Serial.println(" bytes");
|
||||
Serial.print(" UID Value: ");
|
||||
nfc.PrintHex(uid, uidLength);
|
||||
Serial.println("");
|
||||
|
||||
if (uidLength == 4)
|
||||
{
|
||||
// We probably have a Mifare Classic card ...
|
||||
Serial.println("Seems to be a Mifare Classic card (4 byte UID)");
|
||||
|
||||
// Now we try to go through all 16 sector (each having 4 blocks)
|
||||
// authenticating each sector, and then dumping the blocks
|
||||
for (currentblock = 0; currentblock < 64; currentblock++)
|
||||
{
|
||||
// Check if this is a new block so that we can reauthenticate
|
||||
if (nfc.mifareclassic_IsFirstBlock(currentblock)) authenticated = false;
|
||||
|
||||
// If the sector hasn't been authenticated, do so first
|
||||
if (!authenticated)
|
||||
{
|
||||
// Starting of a new sector ... try to to authenticate
|
||||
Serial.print("------------------------Sector ");Serial.print(currentblock/4, DEC);Serial.println("-------------------------");
|
||||
if (currentblock == 0)
|
||||
{
|
||||
success = nfc.mifareclassic_AuthenticateBlock (uid, uidLength, currentblock, 0, keya);
|
||||
}
|
||||
else
|
||||
{
|
||||
success = nfc.mifareclassic_AuthenticateBlock (uid, uidLength, currentblock, 0, keyb);
|
||||
}
|
||||
if (success)
|
||||
{
|
||||
authenticated = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.println("Authentication error");
|
||||
}
|
||||
}
|
||||
// If we're still not authenticated just skip the block
|
||||
if (!authenticated)
|
||||
{
|
||||
Serial.print("Block ");Serial.print(currentblock, DEC);Serial.println(" unable to authenticate");
|
||||
}
|
||||
else
|
||||
{
|
||||
// Authenticated ... we should be able to read the block now
|
||||
// Dump the data into the 'data' array
|
||||
success = nfc.mifareclassic_ReadDataBlock(currentblock, data);
|
||||
if (success)
|
||||
{
|
||||
// Read successful
|
||||
Serial.print("Block ");Serial.print(currentblock, DEC);
|
||||
if (currentblock < 10)
|
||||
{
|
||||
Serial.print(" ");
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.print(" ");
|
||||
}
|
||||
// Dump the raw data
|
||||
nfc.PrintHexChar(data, 16);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Oops ... something happened
|
||||
Serial.print("Block ");Serial.print(currentblock, DEC);
|
||||
Serial.println(" unable to read this block");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.println("Ooops ... this doesn't seem to be a Mifare Classic card!");
|
||||
}
|
||||
}
|
||||
// Wait a bit before trying again
|
||||
Serial.println("\n\nSend a character to run the mem dumper again!");
|
||||
Serial.flush();
|
||||
while (!Serial.available());
|
||||
Serial.flush();
|
||||
}
|
||||
|
||||
|
|
@ -1,9 +1,33 @@
|
|||
/**************************************************************************/
|
||||
/*!
|
||||
@file readMifare.pde
|
||||
@author Adafruit Industries
|
||||
@license BSD (see license.txt)
|
||||
|
||||
This example will wait for any ISO14443A card or tag, and
|
||||
depending on the size of the UID will attempt to read from it.
|
||||
|
||||
If the card has a 4-byte UID it is probably a Mifare
|
||||
Classic card, and the following steps are taken:
|
||||
|
||||
- Authenticate block 4 (the first block of Sector 1) using
|
||||
the default KEYA of 0XFF 0XFF 0XFF 0XFF 0XFF 0XFF
|
||||
- If authentication succeeds, we can then read any of the
|
||||
4 blocks in that sector (though only block 4 is read here)
|
||||
|
||||
If the card has a 7-byte UID it is probably a Mifare
|
||||
Ultralight card, and the 4 byte pages can be read directly.
|
||||
Page 4 is read by default since this is the first 'general-
|
||||
purpose' page on the tags.
|
||||
*/
|
||||
/**************************************************************************/
|
||||
|
||||
#include <PN532.h>
|
||||
|
||||
#define SCK 2
|
||||
#define MOSI 3
|
||||
#define SS 4
|
||||
#define MISO 5
|
||||
#define SCK (2)
|
||||
#define MOSI (3)
|
||||
#define SS (4)
|
||||
#define MISO (5)
|
||||
|
||||
PN532 nfc(SCK, MISO, MOSI, SS);
|
||||
|
||||
|
|
@ -22,21 +46,104 @@ void setup(void) {
|
|||
Serial.print("Found chip PN5"); Serial.println((versiondata>>24) & 0xFF, HEX);
|
||||
Serial.print("Firmware ver. "); Serial.print((versiondata>>16) & 0xFF, DEC);
|
||||
Serial.print('.'); Serial.println((versiondata>>8) & 0xFF, DEC);
|
||||
Serial.print("Supports "); Serial.println(versiondata & 0xFF, HEX);
|
||||
|
||||
// configure board to read RFID tags
|
||||
nfc.SAMConfig();
|
||||
|
||||
Serial.println("Waiting for an ISO14443A Card ...");
|
||||
}
|
||||
|
||||
|
||||
void loop(void) {
|
||||
uint32_t id;
|
||||
// look for MiFare type cards
|
||||
id = nfc.readPassiveTargetID(PN532_MIFARE_ISO14443A);
|
||||
uint8_t success;
|
||||
uint8_t uid[] = { 0, 0, 0, 0, 0, 0, 0 }; // Buffer to store the returned UID
|
||||
uint8_t uidLength; // Length of the UID (4 or 7 bytes depending on ISO14443A card type)
|
||||
|
||||
// Wait for an ISO14443A type cards (Mifare, etc.). When one is found
|
||||
// 'uid' will be populated with the UID, and uidLength will indicate
|
||||
// if the uid is 4 bytes (Mifare Classic) or 7 bytes (Mifare Ultralight)
|
||||
success = nfc.readPassiveTargetID(PN532_MIFARE_ISO14443A, uid, &uidLength);
|
||||
|
||||
if (id != 0) {
|
||||
Serial.print("Read card #"); Serial.println(id);
|
||||
if (success) {
|
||||
// Display some basic information about the card
|
||||
Serial.println("Found an ISO14443A card");
|
||||
Serial.print(" UID Length: ");Serial.print(uidLength, DEC);Serial.println(" bytes");
|
||||
Serial.print(" UID Value: ");
|
||||
nfc.PrintHex(uid, uidLength);
|
||||
Serial.println("");
|
||||
|
||||
if (uidLength == 4)
|
||||
{
|
||||
// We probably have a Mifare Classic card ...
|
||||
Serial.println("Seems to be a Mifare Classic card (4 byte UID)");
|
||||
|
||||
// Now we need to try to authenticate it for read/write access
|
||||
// Try with the factory default KeyA: 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF
|
||||
Serial.println("Trying to authenticate block 4 with default KEYA value");
|
||||
uint8_t keya[6] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
|
||||
|
||||
// Start with block 4 (the first block of sector 1) since sector 0
|
||||
// contains the manufacturer data and it's probably better just
|
||||
// to leave it alone unless you know what you're doing
|
||||
success = nfc.mifareclassic_AuthenticateBlock(uid, uidLength, 4, 0, keya);
|
||||
|
||||
if (success)
|
||||
{
|
||||
Serial.println("Sector 1 (Blocks 4..7) has been authenticated");
|
||||
uint8_t data[16];
|
||||
|
||||
// If you want to write something to block 4 to test with, uncomment
|
||||
// the following line and this text should be read back in a minute
|
||||
// data = { 'a', 'd', 'a', 'f', 'r', 'u', 'i', 't', '.', 'c', 'o', 'm', 0, 0, 0, 0};
|
||||
// success = nfc.mifareclassic_WriteDataBlock (4, data);
|
||||
|
||||
// Try to read the contents of block 4
|
||||
success = nfc.mifareclassic_ReadDataBlock(4, data);
|
||||
|
||||
if (success)
|
||||
{
|
||||
// Data seems to have been read ... spit it out
|
||||
Serial.println("Reading Block 4:");
|
||||
nfc.PrintHexChar(data, 16);
|
||||
Serial.println("");
|
||||
|
||||
// Wait a bit before reading the card again
|
||||
delay(1000);
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.println("Ooops ... unable to read the requested block. Try another key?");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.println("Ooops ... authentication failed: Try another key?");
|
||||
}
|
||||
}
|
||||
|
||||
if (uidLength == 7)
|
||||
{
|
||||
// We probably have a Mifare Ultralight card ...
|
||||
Serial.println("Seems to be a Mifare Ultralight tag (7 byte UID)");
|
||||
|
||||
// Try to read the first general-purpose user page (#4)
|
||||
Serial.println("Reading page 4");
|
||||
uint8_t data[32];
|
||||
success = nfc.mifareultralight_ReadPage (4, data);
|
||||
if (success)
|
||||
{
|
||||
// Data seems to have been read ... spit it out
|
||||
nfc.PrintHexChar(data, 4);
|
||||
Serial.println("");
|
||||
|
||||
// Wait a bit before reading the card again
|
||||
delay(1000);
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.println("Ooops ... unable to read the requested page!?");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
89
examples/readMifareClassic/readMifareClassic.pde
Normal file
89
examples/readMifareClassic/readMifareClassic.pde
Normal file
|
|
@ -0,0 +1,89 @@
|
|||
/**************************************************************************/
|
||||
/*!
|
||||
@file readMifareClassic.pde
|
||||
@author Adafruit Industries
|
||||
@license BSD (see license.txt)
|
||||
|
||||
This example will wait for any ISO14443A card or tag, and
|
||||
depending on the size of the UID will attempt to read from it.
|
||||
|
||||
If the card has a 4-byte UID it is probably a Mifare
|
||||
Classic card, and the following steps are taken:
|
||||
|
||||
Reads the 4 byte (32 bit) ID of a MiFare Classic card.
|
||||
Since the classic cards have only 32 bit identifiers you can stick
|
||||
them in a single variable and use that to compare card ID's as a
|
||||
number. This doesn't work for ultralight cards that have longer 7
|
||||
byte IDs!
|
||||
|
||||
Note that you need the baud rate to be 115200 because we need to
|
||||
print out the data and read from the card at the same time!
|
||||
*/
|
||||
/**************************************************************************/
|
||||
|
||||
#include <PN532.h>
|
||||
|
||||
#define SCK (2)
|
||||
#define MOSI (3)
|
||||
#define SS (4)
|
||||
#define MISO (5)
|
||||
|
||||
PN532 nfc(SCK, MISO, MOSI, SS);
|
||||
|
||||
void setup(void) {
|
||||
Serial.begin(115200);
|
||||
Serial.println("Hello!");
|
||||
|
||||
nfc.begin();
|
||||
|
||||
uint32_t versiondata = nfc.getFirmwareVersion();
|
||||
if (! versiondata) {
|
||||
Serial.print("Didn't find PN53x board");
|
||||
while (1); // halt
|
||||
}
|
||||
// Got ok data, print it out!
|
||||
Serial.print("Found chip PN5"); Serial.println((versiondata>>24) & 0xFF, HEX);
|
||||
Serial.print("Firmware ver. "); Serial.print((versiondata>>16) & 0xFF, DEC);
|
||||
Serial.print('.'); Serial.println((versiondata>>8) & 0xFF, DEC);
|
||||
|
||||
// configure board to read RFID tags
|
||||
nfc.SAMConfig();
|
||||
|
||||
Serial.println("Waiting for an ISO14443A Card ...");
|
||||
}
|
||||
|
||||
|
||||
void loop(void) {
|
||||
uint8_t success;
|
||||
uint8_t uid[] = { 0, 0, 0, 0, 0, 0, 0 }; // Buffer to store the returned UID
|
||||
uint8_t uidLength; // Length of the UID (4 or 7 bytes depending on ISO14443A card type)
|
||||
|
||||
// Wait for an ISO14443A type cards (Mifare, etc.). When one is found
|
||||
// 'uid' will be populated with the UID, and uidLength will indicate
|
||||
// if the uid is 4 bytes (Mifare Classic) or 7 bytes (Mifare Ultralight)
|
||||
success = nfc.readPassiveTargetID(PN532_MIFARE_ISO14443A, uid, &uidLength);
|
||||
|
||||
if (success) {
|
||||
// Display some basic information about the card
|
||||
Serial.println("Found an ISO14443A card");
|
||||
Serial.print(" UID Length: ");Serial.print(uidLength, DEC);Serial.println(" bytes");
|
||||
Serial.print(" UID Value: ");
|
||||
nfc.PrintHex(uid, uidLength);
|
||||
|
||||
if (uidLength == 4)
|
||||
{
|
||||
// We probably have a Mifare Classic card ...
|
||||
uint32_t cardid = uid[0];
|
||||
cardid <<= 8;
|
||||
cardid |= uid[1];
|
||||
cardid <<= 8;
|
||||
cardid |= uid[2];
|
||||
cardid <<= 8;
|
||||
cardid |= uid[3];
|
||||
Serial.print("Seems to be a Mifare Classic card #");
|
||||
Serial.println(cardid);
|
||||
}
|
||||
Serial.println("");
|
||||
}
|
||||
}
|
||||
|
||||
26
license.txt
Normal file
26
license.txt
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
Software License Agreement (BSD License)
|
||||
|
||||
Copyright (c) 2012, Adafruit Industries
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
3. Neither the name of the copyright holders nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
|
||||
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
Loading…
Reference in a new issue