diff --git a/Adafruit_PN532.cpp b/Adafruit_PN532.cpp index 0f55579..774da25 100644 --- a/Adafruit_PN532.cpp +++ b/Adafruit_PN532.cpp @@ -2,23 +2,22 @@ /*! @file Adafruit_PN532.cpp @author Adafruit Industries - @license BSD (see license.txt) + @license BSD (see license.txt) - Driver for NXP's PN532 NFC/13.56MHz RFID Transceiver + Driver for NXP's PN532 NFC/13.56MHz RFID Transceiver - This is a library for the Adafruit PN532 NFC/RFID breakout boards - This library works with the Adafruit NFC breakout - ----> https://www.adafruit.com/products/364 + This is a library 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 SPI or I2C to communicate. + 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! + Adafruit invests time and resources providing this open source code, + please support Adafruit and open-source hardware by purchasing + products from Adafruit! - - @section HISTORY + @section HISTORY v2.1 - Added NTAG2xx helper functions @@ -1370,6 +1369,109 @@ uint8_t Adafruit_PN532::ntag2xx_WritePage (uint8_t page, uint8_t * data) return 1; } +/**************************************************************************/ +/*! + Writes an NDEF URI Record starting at the specified page (4..nn) + + Note that this function assumes that the NTAG2xx card is + already formatted to work as an "NFC Forum Tag". + + @param uriIdentifier The uri identifier code (0 = none, 0x01 = + "http://www.", etc.) + @param url The uri text to write (null-terminated string). + @param dataLen The size of the data area for overflow checks. + + @returns 1 if everything executed properly, 0 for an error +*/ +/**************************************************************************/ +uint8_t Adafruit_PN532::ntag2xx_WriteNDEFURI (uint8_t uriIdentifier, char * url, uint8_t dataLen) +{ + uint8_t pageBuffer[4] = { 0, 0, 0, 0 }; + + // Remove NDEF record overhead from the URI data (pageHeader below) + uint8_t wrapperSize = 12; + + // Figure out how long the string is + uint8_t len = strlen(url); + + // Make sure the URI payload will fit in dataLen (include 0xFE trailer) + if ((len < 1) || (len+1 > (dataLen-wrapperSize))) + return 0; + + // Setup the record header + // See NFCForum-TS-Type-2-Tag_1.1.pdf for details + uint8_t pageHeader[12] = + { + /* NDEF Lock Control TLV (must be first and always present) */ + 0x01, /* Tag Field (0x01 = Lock Control TLV) */ + 0x03, /* Payload Length (always 3) */ + 0xA0, /* The position inside the tag of the lock bytes (upper 4 = page address, lower 4 = byte offset) */ + 0x10, /* Size in bits of the lock area */ + 0x44, /* Size in bytes of a page and the number of bytes each lock bit can lock (4 bit + 4 bits) */ + /* NDEF Message TLV - URI Record */ + 0x03, /* Tag Field (0x03 = NDEF Message) */ + len+5, /* Payload Length (not including 0xFE trailer) */ + 0xD1, /* NDEF Record Header (TNF=0x1:Well known record + SR + ME + MB) */ + 0x01, /* Type Length for the record type indicator */ + len+1, /* Payload len */ + 0x55, /* Record Type Indicator (0x55 or 'U' = URI Record) */ + uriIdentifier /* URI Prefix (ex. 0x01 = "http://www.") */ + }; + + // Write 12 byte header (three pages of data starting at page 4) + memcpy (pageBuffer, pageHeader, 4); + if (!(ntag2xx_WritePage (4, pageBuffer))) + return 0; + memcpy (pageBuffer, pageHeader+4, 4); + if (!(ntag2xx_WritePage (5, pageBuffer))) + return 0; + memcpy (pageBuffer, pageHeader+8, 4); + if (!(ntag2xx_WritePage (6, pageBuffer))) + return 0; + + // Write URI (starting at page 7) + uint8_t currentPage = 7; + char * urlcopy = url; + while(len) + { + if (len < 4) + { + memset(pageBuffer, 0, 4); + memcpy(pageBuffer, urlcopy, len); + pageBuffer[len] = 0xFE; // NDEF record footer + if (!(ntag2xx_WritePage (currentPage, pageBuffer))) + return 0; + // DONE! + return 1; + } + else if (len == 4) + { + memcpy(pageBuffer, urlcopy, len); + if (!(ntag2xx_WritePage (currentPage, pageBuffer))) + return 0; + memset(pageBuffer, 0, 4); + pageBuffer[0] = 0xFE; // NDEF record footer + currentPage++; + if (!(ntag2xx_WritePage (currentPage, pageBuffer))) + return 0; + // DONE! + return 1; + } + else + { + // More than one page of data left + memcpy(pageBuffer, urlcopy, 4); + if (!(ntag2xx_WritePage (currentPage, pageBuffer))) + return 0; + currentPage++; + urlcopy+=4; + len-=4; + } + } + + // Seems that everything was OK (?!) + return 1; +} /************** high level communication functions (handles both I2C and SPI) */ diff --git a/Adafruit_PN532.h b/Adafruit_PN532.h index 48f1a1f..e5888bf 100644 --- a/Adafruit_PN532.h +++ b/Adafruit_PN532.h @@ -189,6 +189,7 @@ class Adafruit_PN532{ // NTAG2xx functions uint8_t ntag2xx_ReadPage (uint8_t page, uint8_t * buffer); uint8_t ntag2xx_WritePage (uint8_t page, uint8_t * data); + uint8_t ntag2xx_WriteNDEFURI (uint8_t uriIdentifier, char * url, uint8_t dataLen); // Help functions to display formatted text static void PrintHex(const byte * data, const uint32_t numBytes); diff --git a/examples/ntag2xx_erase/ntag2xx_erase.pde b/examples/ntag2xx_erase/ntag2xx_erase.pde index 5e58153..a14a62a 100644 --- a/examples/ntag2xx_erase/ntag2xx_erase.pde +++ b/examples/ntag2xx_erase/ntag2xx_erase.pde @@ -1,6 +1,6 @@ /**************************************************************************/ /*! - @file readntag203.pde + @file ntag2xx_erase.pde @author KTOWN (Adafruit Industries) @license BSD (see license.txt) diff --git a/examples/ntag2xx_updatendef/ntag2xx_updatendef.pde b/examples/ntag2xx_updatendef/ntag2xx_updatendef.pde new file mode 100644 index 0000000..fc8f27a --- /dev/null +++ b/examples/ntag2xx_updatendef/ntag2xx_updatendef.pde @@ -0,0 +1,213 @@ +/**************************************************************************/ +/*! + @file ntag2xx_updatendef.pde + @author KTOWN (Adafruit Industries) + @license BSD (see license.txt) + + This example will wait for any NTAG203 or NTAG213 card or tag, + and will attempt to add or update an NDEF URI at the start of the + tag's memory. + + 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 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! +*/ +/**************************************************************************/ +#include +#include +#include + +// If using the breakout with SPI, define the pins for SPI communication. +#define PN532_SCK (2) +#define PN532_MOSI (3) +#define PN532_SS (4) +#define PN532_MISO (5) + +// If using the breakout or shield with I2C, define just the pins connected +// to the IRQ and reset lines. Use the values below (2, 3) for the shield! +#define PN532_IRQ (2) +#define PN532_RESET (3) // Not connected by default on the NFC Shield + +// Uncomment just _one_ line below depending on how your breakout or shield +// is connected to the Arduino: + +// Use this line for a breakout with a software SPI connection (recommended): +Adafruit_PN532 nfc(PN532_SCK, PN532_MISO, PN532_MOSI, PN532_SS); + +// Use this line for a breakout with a hardware SPI connection. Note that +// the PN532 SCK, MOSI, and MISO pins need to be connected to the Arduino's +// hardware SPI SCK, MOSI, and MISO pins. On an Arduino Uno these are +// SCK = 13, MOSI = 11, MISO = 12. The SS line can be any digital IO pin. +//Adafruit_PN532 nfc(PN532_SS); + +// Or use this line for a breakout or shield with an I2C connection: +//Adafruit_PN532 nfc(PN532_IRQ, PN532_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: +char * url = "adafruit.com/blog/"; +uint8_t ndefprefix = NDEF_URIPREFIX_HTTP_WWWDOT; + +// for an email address +//char * url = "mail@example.com"; +//uint8_t ndefprefix = NDEF_URIPREFIX_MAILTO; + +// for a phone number +//char * url = "+1 212 555 1212"; +//uint8_t ndefprefix = NDEF_URIPREFIX_TEL; + +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(); +} + +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) + uint8_t dataLength; + + // Require some user feedback before running this example! + Serial.println("\r\nPlace your NDEF formatted NTAG2xx tag on the reader to update the"); + Serial.println("NDEF record and press any key to continue ...\r\n"); + // Wait for user input before proceeding + while (!Serial.available()); + // a key was pressed1 + while (Serial.available()) Serial.read(); + + // 1.) Wait for an NTAG203 card. When one is found 'uid' will be populated with + // the UID, and uidLength will indicate the size of the UID (normally 7) + success = nfc.readPassiveTargetID(PN532_MIFARE_ISO14443A, uid, &uidLength); + + // It seems we found a valid ISO14443A Tag! + if (success) + { + // 2.) 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 != 7) + { + Serial.println("This doesn't seem to be an NTAG203 tag (UUID length != 7 bytes)!"); + } + else + { + uint8_t data[32]; + + // We probably have an NTAG2xx card (though it could be Ultralight as well) + Serial.println("Seems to be an NTAG2xx tag (7 byte UID)"); + + // NTAG2x3 cards have 39*4 bytes of user pages (156 user bytes), + // starting at page 4 ... larger cards just add pages to the end of + // this range: + + // See: http://www.nxp.com/documents/short_data_sheet/NTAG203_SDS.pdf + + // TAG Type PAGES USER START USER STOP + // -------- ----- ---------- --------- + // NTAG 203 42 4 39 + // NTAG 213 45 4 39 + // NTAG 215 135 4 129 + // NTAG 216 231 4 225 + + + // 3.) Check if the NDEF Capability Container (CC) bits are already set + // in OTP memory (page 3) + memset(data, 0, 4); + success = nfc.ntag2xx_ReadPage(3, data); + if (!success) + { + Serial.println("Unable to read the Capability Container (page 3)"); + return; + } + else + { + // If the tag has already been formatted as NDEF, byte 0 should be: + // Byte 0 = Magic Number (0xE1) + // Byte 1 = NDEF Version (Should be 0x10) + // Byte 2 = Data Area Size (value * 8 bytes) + // Byte 3 = Read/Write Access (0x00 for full read and write) + if (!((data[0] == 0xE1) && (data[1] == 0x10))) + { + Serial.println("This doesn't seem to be an NDEF formatted tag."); + Serial.println("Page 3 should start with 0xE1 0x10."); + } + else + { + // 4.) Determine and display the data area size + dataLength = data[2]*8; + Serial.print("Tag is NDEF formatted. Data area size = "); + Serial.print(dataLength); + Serial.println(" bytes"); + + // 5.) Erase the old data area + Serial.print("Erasing previous data area "); + for (uint8_t i = 4; i < (dataLength/4)+4; i++) + { + memset(data, 0, 4); + success = nfc.ntag2xx_WritePage(i, data); + Serial.print("."); + if (!success) + { + Serial.println(" ERROR!"); + return; + } + } + Serial.println(" DONE!"); + + // 6.) Try to add a new NDEF URI record + Serial.print("Writing URI as NDEF Record ... "); + success = nfc.ntag2xx_WriteNDEFURI(ndefprefix, url, dataLength); + if (success) + { + Serial.println("DONE!"); + } + else + { + Serial.println("ERROR! (URI length?)"); + } + + } // CC contents NDEF record check + } // CC page read check + } // UUID length check + + // Wait a bit before trying again + Serial.flush(); + while (!Serial.available()); + while (Serial.available()) { + Serial.read(); + } + Serial.flush(); + } // Start waiting for a new ISO14443A tag +} \ No newline at end of file