Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

First commit

  • Loading branch information...
commit fa033227081cf491bde9a049a4a060d730acf178 1 parent aed248b
K.Townsend authored
View
1,005 Adafruit_NFCShield_I2C.cpp
@@ -0,0 +1,1005 @@
+/**************************************************************************/
+/*!
+ @file Adafruit_NFCShield_I2C.cpp
+ @author Adafruit Industries
+ @license BSD (see license.txt)
+
+ I2C Driver for NXP's PN532 NFC/13.56MHz RFID Transceiver
+
+ This is a library for the Adafruit PN532 NFC/RFID shields
+ This library works with the Adafruit NFC breakout
+ ----> https://www.adafruit.com/products/364
+
+ Check out the links above for our tutorials and wiring diagrams
+ These chips use I2C to communicate
+
+ Adafruit invests time and resources providing this open source code,
+ please support Adafruit and open-source hardware by purchasing
+ products from Adafruit!
+
+ @section HISTORY
+
+ v1.3 - Modified to work with I2C
+
+ 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)
+*/
+/**************************************************************************/
+#if ARDUINO >= 100
+ #include "Arduino.h"
+#else
+ #include "WProgram.h"
+#endif
+
+#include <Wire.h>
+
+#include "Adafruit_NFCShield_I2C.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(I2C) and/or MIFARE related code
+// #define PN532DEBUG
+// #define MIFAREDEBUG
+
+#define PN532_PACKBUFFSIZ 64
+byte pn532_packetbuffer[PN532_PACKBUFFSIZ];
+
+/**************************************************************************/
+/*!
+ @brief Sends a single byte via I2C
+
+ @param x The byte to send
+*/
+/**************************************************************************/
+static inline void wiresend(uint8_t x)
+{
+ #if ARDUINO >= 100
+ Wire.write((uint8_t)x);
+ #else
+ Wire.send(x);
+ #endif
+}
+
+/**************************************************************************/
+/*!
+ @brief Reads a single byte via I2C
+*/
+/**************************************************************************/
+static inline uint8_t wirerecv(void)
+{
+ #if ARDUINO >= 100
+ return Wire.read();
+ #else
+ return Wire.receive();
+ #endif
+}
+
+/**************************************************************************/
+/*!
+ @brief Instantiates a new PN532 class
+
+ @param irq Location of the IRQ pin
+ @param reset Location of the RSTPD_N pin
+*/
+/**************************************************************************/
+Adafruit_NFCShield_I2C::Adafruit_NFCShield_I2C(uint8_t irq, uint8_t reset) {
+ _irq = irq;
+ _reset = reset;
+
+ pinMode(_irq, INPUT);
+ pinMode(_reset, OUTPUT);
+}
+
+/**************************************************************************/
+/*!
+ @brief Setups the HW
+*/
+/**************************************************************************/
+void Adafruit_NFCShield_I2C::begin() {
+ Wire.begin();
+
+ // Reset the PN532
+ digitalWrite(_reset, HIGH);
+ digitalWrite(_reset, LOW);
+ delay(400);
+ digitalWrite(_reset, HIGH);
+}
+
+/**************************************************************************/
+/*!
+ @brief Prints a hexadecimal value in plain characters
+
+ @param data Pointer to the byte data
+ @param numBytes Data length in bytes
+*/
+/**************************************************************************/
+void Adafruit_NFCShield_I2C::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 Adafruit_NFCShield_I2C::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 Adafruit_NFCShield_I2C::getFirmwareVersion(void) {
+ uint32_t response;
+
+ pn532_packetbuffer[0] = PN532_COMMAND_GETFIRMWAREVERSION;
+
+ if (! sendCommandCheckAck(pn532_packetbuffer, 1))
+ return 0;
+
+ // read data packet
+ wirereaddata(pn532_packetbuffer, 12);
+
+ // check some basic stuff
+ if (0 != strncmp((char *)pn532_packetbuffer, (char *)pn532response_firmwarevers, 6)) {
+ #ifdef PN532DEBUG
+ Serial.println("Firmware doesn't match!");
+ #endif
+ return 0;
+ }
+
+ response = pn532_packetbuffer[7];
+ response <<= 8;
+ response |= pn532_packetbuffer[8];
+ response <<= 8;
+ response |= pn532_packetbuffer[9];
+ response <<= 8;
+ response |= pn532_packetbuffer[10];
+
+ return response;
+}
+
+
+/**************************************************************************/
+/*!
+ @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 Adafruit_NFCShield_I2C::sendCommandCheckAck(uint8_t *cmd, uint8_t cmdlen, uint16_t timeout) {
+ uint16_t timer = 0;
+
+ // write the command
+ wiresendcommand(cmd, cmdlen);
+
+ // Wait for chip to say its ready!
+ while (wirereadstatus() != PN532_I2C_READY) {
+ if (timeout != 0) {
+ timer+=10;
+ if (timer > timeout)
+ return false;
+ }
+ delay(10);
+ }
+
+ #ifdef PN532DEBUG
+ Serial.println("IRQ received");
+ #endif
+
+ // read acknowledgement
+ if (!readackframe()) {
+ #ifdef PN532DEBUG
+ Serial.println("No ACK frame received!");
+ #endif
+ return false;
+ }
+
+ 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 Adafruit_NFCShield_I2C::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 I2C)
+
+ #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 00 FF PLEN PLENCHECKSUM D5 CMD+1(0x0F) DATACHECKSUM)
+ wirereaddata(pn532_packetbuffer, 8);
+
+ #ifdef PN532DEBUG
+ Serial.print("Received: ");
+ PrintHex(pn532_packetbuffer, 8);
+ Serial.println("");
+ #endif
+
+ return (pn532_packetbuffer[6] == 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 Adafruit_NFCShield_I2C::readGPIO(void) {
+ pn532_packetbuffer[0] = PN532_COMMAND_READGPIO;
+
+ // Send the READGPIO command (0x0C)
+ if (! sendCommandCheckAck(pn532_packetbuffer, 1))
+ return 0x0;
+
+ // Read response packet (00 00 FF PLEN PLENCHECKSUM D5 CMD+1(0x0D) P3 P7 IO1 DATACHECKSUM)
+ wirereaddata(pn532_packetbuffer, 11);
+
+ /* READGPIO response should be in the following format:
+
+ byte Description
+ ------------- ------------------------------------------
+ b0..6 Frame header and preamble
+ b7 P3 GPIO Pins
+ b8 P7 GPIO Pins (not used ... taken by I2C)
+ b9 Interface Mode Pins (not used ... bus select pins)
+ b10 checksum */
+
+ #ifdef PN532DEBUG
+ Serial.print("Received: ");
+ PrintHex(pn532_packetbuffer, 11);
+ Serial.println("");
+ Serial.print("P3 GPIO: 0x"); Serial.println(pn532_packetbuffer[7], HEX);
+ Serial.print("P7 GPIO: 0x"); Serial.println(pn532_packetbuffer[8], HEX);
+ Serial.print("IO GPIO: 0x"); Serial.println(pn532_packetbuffer[9], HEX);
+ // Note: You can use the IO GPIO value to detect the serial bus being used
+ switch(pn532_packetbuffer[9])
+ {
+ 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 I2C
+ Serial.println("Using I2C (IO = 0x02)");
+ break;
+ }
+ #endif
+
+ return pn532_packetbuffer[6];
+}
+
+/**************************************************************************/
+/*!
+ @brief Configures the SAM (Secure Access Module)
+*/
+/**************************************************************************/
+boolean Adafruit_NFCShield_I2C::SAMConfig(void) {
+ 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!
+
+ if (! sendCommandCheckAck(pn532_packetbuffer, 4))
+ return false;
+
+ // read data packet
+ wirereaddata(pn532_packetbuffer, 8);
+
+ return (pn532_packetbuffer[6] == 0x15);
+}
+
+/***** ISO14443A Commands ******/
+
+/**************************************************************************/
+/*!
+ 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 Adafruit_NFCShield_I2C::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;
+
+ if (! sendCommandCheckAck(pn532_packetbuffer, 3))
+ {
+ #ifdef PN532DEBUG
+ Serial.println("No card(s) read");
+ #endif
+ return 0x0; // no cards read
+ }
+
+ // Wait for a card to enter the field
+ uint8_t status = PN532_I2C_BUSY;
+ #ifdef PN532DEBUG
+ Serial.println("Waiting for IRQ (indicates card presence)");
+ #endif
+ while (wirereadstatus() != PN532_I2C_READY)
+ {
+ delay(10);
+ }
+
+ #ifdef PN532DEBUG
+ Serial.println("Found a card");
+ #endif
+
+ // read data packet
+ wirereaddata(pn532_packetbuffer, 20);
+
+ // check some basic stuff
+ /* ISO14443A card response should be in the following format:
+
+ 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];
+#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
+ }
+#ifdef MIFAREDEBUG
+ Serial.println();
+#endif
+
+ 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 Adafruit_NFCShield_I2C::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 Adafruit_NFCShield_I2C::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 Adafruit_NFCShield_I2C::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 ");
+ Adafruit_NFCShield_I2C::PrintHex(_uid, _uidLen);
+ Serial.print("Using authentication KEY ");Serial.print(keyNumber ? 'B' : 'A');Serial.print(": ");
+ Adafruit_NFCShield_I2C::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
+ wirereaddata(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 Adafruit_NFCShield_I2C::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 */
+ wirereaddata(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");
+ Adafruit_NFCShield_I2C::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);
+ Adafruit_NFCShield_I2C::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 Adafruit_NFCShield_I2C::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 */
+ wirereaddata(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 Adafruit_NFCShield_I2C::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 Adafruit_NFCShield_I2C::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 Adafruit_NFCShield_I2C::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 */
+ wirereaddata(pn532_packetbuffer, 26);
+ #ifdef MIFAREDEBUG
+ Serial.println("Received: ");
+ Adafruit_NFCShield_I2C::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: ");
+ Adafruit_NFCShield_I2C::PrintHexChar(pn532_packetbuffer, 26);
+ #endif
+ return 0;
+ }
+
+ /* Display data for debug if requested */
+ #ifdef MIFAREDEBUG
+ Serial.print("Page ");Serial.print(page);Serial.println(":");
+ Adafruit_NFCShield_I2C::PrintHexChar(buffer, 4);
+ #endif
+
+ // Return OK signal
+ return 1;
+}
+
+
+
+/************** high level I2C */
+
+
+/**************************************************************************/
+/*!
+ @brief Tries to read the PN532 ACK frame (not to be confused with
+ the I2C ACK signal)
+*/
+/**************************************************************************/
+boolean Adafruit_NFCShield_I2C::readackframe(void) {
+ uint8_t ackbuff[6];
+
+ wirereaddata(ackbuff, 6);
+
+ return (0 == strncmp((char *)ackbuff, (char *)pn532ack, 6));
+}
+
+/************** mid level I2C */
+
+/**************************************************************************/
+/*!
+ @brief Checks the IRQ pin to know if the PN532 is ready
+
+ @returns 0 if the PN532 is busy, 1 if it is free
+*/
+/**************************************************************************/
+uint8_t Adafruit_NFCShield_I2C::wirereadstatus(void) {
+ uint8_t x = digitalRead(_irq);
+
+ if (x == 1)
+ return PN532_I2C_BUSY;
+ else
+ return PN532_I2C_READY;
+}
+
+/**************************************************************************/
+/*!
+ @brief Reads n bytes of data from the PN532 via I2C
+
+ @param buff Pointer to the buffer where data will be written
+ @param n Number of bytes to be read
+*/
+/**************************************************************************/
+void Adafruit_NFCShield_I2C::wirereaddata(uint8_t* buff, uint8_t n) {
+ uint16_t timer = 0;
+
+ delay(2);
+
+#ifdef PN532DEBUG
+ Serial.print("Reading: ");
+#endif
+ // Start read (n+1 to take into account leading 0x01 with I2C)
+ Wire.requestFrom((uint8_t)PN532_I2C_ADDRESS, (uint8_t)(n+2));
+ // Discard the leading 0x01
+ wirerecv();
+ for (uint8_t i=0; i<n; i++) {
+ delay(1);
+ buff[i] = wirerecv();
+#ifdef PN532DEBUG
+ Serial.print(" 0x");
+ Serial.print(buff[i], HEX);
+#endif
+ }
+ // Discard trailing 0x00 0x00
+ // wirerecv();
+
+#ifdef PN532DEBUG
+ Serial.println();
+#endif
+}
+
+/**************************************************************************/
+/*!
+ @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 Adafruit_NFCShield_I2C::wiresendcommand(uint8_t* cmd, uint8_t cmdlen) {
+ uint8_t checksum;
+
+ cmdlen++;
+
+#ifdef PN532DEBUG
+ Serial.print("\nSending: ");
+#endif
+
+ delay(2); // or whatever the delay is for waking up the board
+
+ // I2C START
+ Wire.beginTransmission(PN532_I2C_ADDRESS);
+ checksum = PN532_PREAMBLE + PN532_PREAMBLE + PN532_STARTCODE2;
+ wiresend(PN532_PREAMBLE);
+ wiresend(PN532_PREAMBLE);
+ wiresend(PN532_STARTCODE2);
+
+ wiresend(cmdlen);
+ wiresend(~cmdlen + 1);
+
+ wiresend(PN532_HOSTTOPN532);
+ checksum += PN532_HOSTTOPN532;
+
+#ifdef PN532DEBUG
+ Serial.print(" 0x"); Serial.print(PN532_PREAMBLE, HEX);
+ Serial.print(" 0x"); Serial.print(PN532_PREAMBLE, HEX);
+ Serial.print(" 0x"); Serial.print(PN532_STARTCODE2, HEX);
+ Serial.print(" 0x"); Serial.print(cmdlen, HEX);
+ Serial.print(" 0x"); Serial.print(~cmdlen + 1, HEX);
+ Serial.print(" 0x"); Serial.print(PN532_HOSTTOPN532, HEX);
+#endif
+
+ for (uint8_t i=0; i<cmdlen-1; i++) {
+ wiresend(cmd[i]);
+ checksum += cmd[i];
+#ifdef PN532DEBUG
+ Serial.print(" 0x"); Serial.print(cmd[i], HEX);
+#endif
+ }
+
+ wiresend(~checksum);
+ wiresend(PN532_POSTAMBLE);
+
+ // I2C STOP
+ Wire.endTransmission();
+
+#ifdef PN532DEBUG
+ Serial.print(" 0x"); Serial.print(~checksum, HEX);
+ Serial.print(" 0x"); Serial.print(PN532_POSTAMBLE, HEX);
+ Serial.println();
+#endif
+}
+
View
190 Adafruit_NFCShield_I2C.h
@@ -0,0 +1,190 @@
+/**************************************************************************/
+/*!
+ @file Adafruit_NFCShield_I2C.h
+ @author Adafruit Industries
+ @license BSD (see license.txt)
+
+ This is a library for the Adafruit PN532 NFC/RFID shield
+ This library works with the Adafruit NFC breakout
+ ----> https://www.adafruit.com/products/364
+
+ Check out the links above for our tutorials and wiring diagrams
+ These chips use I2C to communicate
+
+ Adafruit invests time and resources providing this open source code,
+ please support Adafruit and open-source hardware by purchasing
+ products from Adafruit!
+
+ @section HISTORY
+
+ v1.3 - Modified to work with I2C
+
+ v1.1 - Added full command list
+ - Added 'verbose' mode flag to constructor to toggle debug output
+ - Changed readPassiveTargetID() to return variable length values
+
+*/
+/**************************************************************************/
+
+#if ARDUINO >= 100
+ #include "Arduino.h"
+#else
+ #include "WProgram.h"
+#endif
+
+#include <Wire.h>
+
+#define PN532_PREAMBLE (0x00)
+#define PN532_STARTCODE1 (0x00)
+#define PN532_STARTCODE2 (0xFF)
+#define PN532_POSTAMBLE (0x00)
+
+#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_WAKEUP (0x55)
+
+#define PN532_SPI_STATREAD (0x02)
+#define PN532_SPI_DATAWRITE (0x01)
+#define PN532_SPI_DATAREAD (0x03)
+#define PN532_SPI_READY (0x01)
+
+#define PN532_I2C_ADDRESS (0x48 >> 1)
+#define PN532_I2C_READBIT (0x01)
+#define PN532_I2C_BUSY (0x00)
+#define PN532_I2C_READY (0x01)
+#define PN532_I2C_READYTIMEOUT (20)
+
+#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 Adafruit_NFCShield_I2C{
+ public:
+ Adafruit_NFCShield_I2C(uint8_t irq, uint8_t reset);
+ void begin(void);
+
+ // Generic PN532 functions
+ boolean SAMConfig(void);
+ uint32_t getFirmwareVersion(void);
+ 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 _irq, _reset;
+ uint8_t _uid[7]; // ISO14443A uid
+ uint8_t _uidLen; // uid len
+ uint8_t _key[6]; // Mifare Classic key
+
+ boolean readackframe(void);
+ uint8_t wirereadstatus(void);
+ void wirereaddata(uint8_t* buff, uint8_t n);
+ void wiresendcommand(uint8_t* cmd, uint8_t cmdlen);
+};
View
4 README.md
@@ -1,4 +0,0 @@
-Adafruit_NFCShield_I2C
-======================
-
-I2C Driver for Adafruit's PN532-based NFC Shield
View
24 README.txt
@@ -0,0 +1,24 @@
+This is a library for the Adafruit PN532 NFC/RFID breakout boards
+This library works with the Adafruit NFC breakout and shield
+ ----> https://www.adafruit.com/products/364
+ ----> https://www.adafruit.com/products/789
+
+Check out the links above for our tutorials and wiring diagrams
+These chips use SPI or I2C to communicate
+
+Adafruit invests time and resources providing this open source code,
+please support Adafruit and open-source hardware by purchasing
+products from Adafruit!
+
+Written by Limor Fried/Ladyada & Kevin Townsend for Adafruit Industries.
+BSD license, check license.txt for more information
+All text above must be included in any redistribution
+
+To download. click the DOWNLOADS button in the top right corner, rename
+the uncompressed folder Adafruit_NFCShield_I2C. Check that the
+Adafruit_NFCShield_I2C folder contains Adafruit_NFCShield_I2C.cpp and
+Adafruit_NFCShield_I2C.h
+
+Place the Adafruit_NFCShield_I2C library folder your
+<arduinosketchfolder>/libraries/ folder. You may need to create the
+libraries subfolder if its your first library. Restart the IDE.
View
80 examples/iso14443a_uid/iso14443a_uid.pde
@@ -0,0 +1,80 @@
+/**************************************************************************/
+/*!
+ @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!
+
+ This is an example sketch for the Adafruit PN532 NFC/RFID breakout boards
+ This library works with the Adafruit NFC breakout
+ ----> https://www.adafruit.com/products/364
+
+ Check out the links above for our tutorials and wiring diagrams
+ These chips use I2C to communicate, 4 pins required to interface:
+ SDA (I2C Data) and SCL (I2C Clock), IRQ and RESET (any digital line)
+
+ Adafruit invests time and resources providing this open source code,
+ please support Adafruit and open-source hardware by purchasing
+ products from Adafruit!
+*/
+/**************************************************************************/
+#include <Wire.h>
+#include <Adafruit_NFCShield_I2C.h>
+
+#define IRQ (2)
+#define RESET (3) // Not connected by default on the NFC Shield
+
+Adafruit_NFCShield_I2C nfc(IRQ, RESET);
+
+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);
+ }
+}
View
172 examples/mifareclassic_formatndef/mifareclassic_formatndef.pde
@@ -0,0 +1,172 @@
+/**************************************************************************/
+/*!
+ @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!
+
+ This is an example sketch for the Adafruit PN532 NFC/RFID breakout boards
+ This library works with the Adafruit NFC Shield
+ ----> https://www.adafruit.com/products/789
+
+ Check out the links above for our tutorials and wiring diagrams
+ These chips use I2C to communicate
+
+ Adafruit invests time and resources providing this open source code,
+ please support Adafruit and open-source hardware by purchasing
+ products from Adafruit!
+
+*/
+/**************************************************************************/
+
+#include <Wire.h>
+#include <Adafruit_NFCShield_I2C.h>
+
+#define IRQ (2)
+#define RESET (3) // Not connected by default on the NFC Shield
+
+Adafruit_NFCShield_I2C nfc(IRQ, RESET);
+
+/*
+ We can encode many different kinds of pointers to the card,
+ from a URL, to an Email address, to a phone number, and many more
+ check the library header .h file to see the large # of supported
+ prefixes!
+*/
+// For a http://www. url:
+const char * url = "adafruit.com";
+uint8_t ndefprefix = NDEF_URIPREFIX_HTTP_WWWDOT;
+
+// for an email address
+//const char * url = "mail@example.com";
+//uint8_t ndefprefix = NDEF_URIPREFIX_MAILTO;
+
+// for a phone number
+//const char * url = "+1 212 555 1212";
+//uint8_t ndefprefix = NDEF_URIPREFIX_TEL;
+
+
+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();
+}
+
+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 };
+
+ 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
+ while (!Serial.available());
+ // a key was pressed1
+ while (Serial.available()) Serial.read();
+
+ // 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, ndefprefix, 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!");
+}
View
164 examples/mifareclassic_memdump/mifareclassic_memdump.pde
@@ -0,0 +1,164 @@
+/**************************************************************************/
+/*!
+ @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!
+
+ This is an example sketch for the Adafruit PN532 NFC/RFID breakout boards
+ This library works with the Adafruit NFC breakout
+ ----> https://www.adafruit.com/products/364
+
+ Check out the links above for our tutorials and wiring diagrams
+ These chips use I2C to communicate
+
+ Adafruit invests time and resources providing this open source code,
+ please support Adafruit and open-source hardware by purchasing
+ products from Adafruit!
+
+*/
+/**************************************************************************/
+
+#include <Wire.h>
+#include <Adafruit_NFCShield_I2C.h>
+
+#define IRQ (2)
+#define RESET (3) // Not connected by default on the NFC Shield
+
+Adafruit_NFCShield_I2C nfc(IRQ, RESET);
+
+void setup(void) {
+ // has to be fast to dump the entire memory contents!
+ 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();
+}
+
View
159 examples/readMifare/readMifare.pde
@@ -0,0 +1,159 @@
+/**************************************************************************/
+/*!
+ @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.
+
+
+ This is an example sketch for the Adafruit PN532 NFC/RFID breakout boards
+ This library works with the Adafruit NFC breakout
+ ----> https://www.adafruit.com/products/364
+
+ Check out the links above for our tutorials and wiring diagrams
+ These chips use I2C to communicate
+
+ Adafruit invests time and resources providing this open source code,
+ please support Adafruit and open-source hardware by purchasing
+ products from Adafruit!
+*/
+/**************************************************************************/
+#include <Wire.h>
+#include <Adafruit_NFCShield_I2C.h>
+
+#define IRQ (2)
+#define RESET (3) // Not connected by default on the NFC Shield
+
+Adafruit_NFCShield_I2C nfc(IRQ, RESET);
+
+void setup(void) {
+ Serial.begin(9600);
+ 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);
+ 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!?");
+ }
+ }
+ }
+}
+
View
26 license.txt
@@ -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.

0 comments on commit fa03322

Please sign in to comment.
Something went wrong with that request. Please try again.