to colorize a colorful pixel with a simple touch using nfc technology

Dependencies:   Chainable_RGB_LED mbed

use Arch, NFC Shield and Grove - Chainable RGB LED to DIY a touch pixel. Then use an Android with NFC support to colorize it.

The project is on https://github.com/Seeed-Studio/TouchPixel

Files at this revision

API Documentation at this revision

Comitter:
yihui
Date:
Fri Dec 27 01:46:32 2013 +0000
Commit message:
initial

Changed in this revision

Chainable_RGB_LED.lib Show annotated file Show diff for this revision Revisions of this file
main.cpp Show annotated file Show diff for this revision Revisions of this file
mbed.bld Show annotated file Show diff for this revision Revisions of this file
nfc/MifareClassic.cpp Show annotated file Show diff for this revision Revisions of this file
nfc/MifareClassic.h Show annotated file Show diff for this revision Revisions of this file
nfc/MifareUltralight.cpp Show annotated file Show diff for this revision Revisions of this file
nfc/MifareUltralight.h Show annotated file Show diff for this revision Revisions of this file
nfc/Ndef.cpp Show annotated file Show diff for this revision Revisions of this file
nfc/Ndef.h Show annotated file Show diff for this revision Revisions of this file
nfc/NdefMessage.cpp Show annotated file Show diff for this revision Revisions of this file
nfc/NdefMessage.h Show annotated file Show diff for this revision Revisions of this file
nfc/NdefRecord.cpp Show annotated file Show diff for this revision Revisions of this file
nfc/NdefRecord.h Show annotated file Show diff for this revision Revisions of this file
nfc/NfcAdapter.cpp Show annotated file Show diff for this revision Revisions of this file
nfc/NfcAdapter.h Show annotated file Show diff for this revision Revisions of this file
nfc/NfcDriver.h Show annotated file Show diff for this revision Revisions of this file
nfc/NfcTag.cpp Show annotated file Show diff for this revision Revisions of this file
nfc/NfcTag.h Show annotated file Show diff for this revision Revisions of this file
nfc/PN532.cpp Show annotated file Show diff for this revision Revisions of this file
nfc/PN532.h Show annotated file Show diff for this revision Revisions of this file
nfc/PN532Interface.h Show annotated file Show diff for this revision Revisions of this file
nfc/PN532_SPI.cpp Show annotated file Show diff for this revision Revisions of this file
nfc/PN532_SPI.h Show annotated file Show diff for this revision Revisions of this file
nfc/PN532_debug.h Show annotated file Show diff for this revision Revisions of this file
nfc/emulatetag.cpp Show annotated file Show diff for this revision Revisions of this file
nfc/emulatetag.h Show annotated file Show diff for this revision Revisions of this file
nfc/llcp.cpp Show annotated file Show diff for this revision Revisions of this file
nfc/llcp.h Show annotated file Show diff for this revision Revisions of this file
nfc/mac_link.cpp Show annotated file Show diff for this revision Revisions of this file
nfc/mac_link.h Show annotated file Show diff for this revision Revisions of this file
nfc/snep.cpp Show annotated file Show diff for this revision Revisions of this file
nfc/snep.h Show annotated file Show diff for this revision Revisions of this file
diff -r 000000000000 -r 88960f3eeb2c Chainable_RGB_LED.lib
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Chainable_RGB_LED.lib	Fri Dec 27 01:46:32 2013 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/seeed/code/Chainable_RGB_LED/#24631ceaa38a
diff -r 000000000000 -r 88960f3eeb2c main.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cpp	Fri Dec 27 01:46:32 2013 +0000
@@ -0,0 +1,109 @@
+
+#include "mbed.h"
+#include "ChainableLED.h"
+#include "PN532_SPI.h"
+#include "emulatetag.h"
+#include "NdefMessage.h"
+
+#include <string.h>
+
+#define LOG(args...)    
+
+BusOut leds(LED1, LED2, LED3, LED4);
+
+ChainableLED rgbled(P1_14, P1_13, 1);
+
+SPI spi(P1_22, P1_21, P1_20);
+PN532_SPI interface(spi, P0_2);
+EmulateTag nfc(interface);
+
+uint8_t ndefBuf[120];
+NdefMessage message;
+int messageSize;
+
+uint8_t uid[3] = { 0x12, 0x34, 0x56 };
+
+uint32_t getColor(uint8_t *buf)
+{
+    uint32_t x = 0;
+    for (uint8_t i = 0; i < 8; i++) {
+        uint8_t c = *buf;
+        if (c >= '0' && c <= '9') {
+            x *= 16;
+            x += c - '0';
+        } else if (c >= 'A' && c <= 'F') {
+            x *= 16;
+            x += (c - 'A') + 10;
+        } else if (c >= 'a' && c <= 'f') {
+            x *= 16;
+            x += (c - 'a') + 10;
+        } else 
+            break;
+
+        buf++;
+    }
+
+    return x;
+}
+
+void processNewNdef(uint8_t *buf, uint16_t length)
+{
+    NdefMessage msg = NdefMessage(buf, length);
+
+    NdefRecord record = msg.getRecord(0);
+    uint8_t recordbuf[32];
+    record.getType(recordbuf);
+    if (!memcmp(recordbuf, "text/c", 6)) {
+        uint8_t r, g, b;
+        uint32_t color;
+        record.getPayload(recordbuf);
+        color = getColor(recordbuf);
+        r = (color >> 16) & 0xFF;
+        g = (color >> 8) & 0xFF;
+        b = color & 0xFF;
+        
+        rgbled.setColorRGB(0, r, g, b);
+        leds = r;
+    }
+} 
+
+int main()
+{
+    LOG("------- Emulate Tag --------\n");
+    rgbled.setColorRGB(0, 0, 0, 0);
+
+    NdefRecord aarRecord = NdefRecord();
+    const uint8_t aarType[] = "android.com:pkg";
+    const uint8_t aarPayload[] = "com.seeedstudio.android.nfc.touchpixel";
+
+    aarRecord.setTnf(TNF_EXTERNAL_TYPE);
+    aarRecord.setType(aarType, sizeof(aarType) - 1);
+    aarRecord.setPayload(aarPayload, sizeof(aarPayload) - 1);
+
+    message = NdefMessage();
+    message.addMimeMediaRecord("text/c", "FF000000");
+    message.addRecord(aarRecord);
+    messageSize = message.getEncodedSize();
+    if (messageSize > sizeof(ndefBuf)) {
+        while (1) { }
+    }
+
+    LOG("Ndef encoded message size: %d\n", messageSize);
+
+    message.encode(ndefBuf);
+
+    // comment out this command for no ndef message
+    nfc.setNdefFile(ndefBuf, messageSize);
+
+    // uid must be 3 bytes!
+    nfc.setUid(uid);
+
+    nfc.init();
+
+    nfc.attach(processNewNdef);
+
+    while (1) {
+        //nfc.setNdefFile(ndefBuf, messageSize);
+        nfc.emulate();
+    }
+}
diff -r 000000000000 -r 88960f3eeb2c mbed.bld
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed.bld	Fri Dec 27 01:46:32 2013 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/mbed_official/code/mbed/builds/a9913a65894f
\ No newline at end of file
diff -r 000000000000 -r 88960f3eeb2c nfc/MifareClassic.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nfc/MifareClassic.cpp	Fri Dec 27 01:46:32 2013 +0000
@@ -0,0 +1,276 @@
+#include "MifareClassic.h"
+#include "PN532_debug.h"
+#include "string.h"
+
+#define BLOCK_SIZE 16
+#define LONG_TLV_SIZE 4
+#define SHORT_TLV_SIZE 2
+
+#define MIFARE_CLASSIC ("Mifare Classic")
+
+MifareClassic::MifareClassic(PN532& nfcShield)
+{
+  _nfcShield = &nfcShield;
+}
+
+MifareClassic::~MifareClassic()
+{
+}
+
+NfcTag MifareClassic::read(uint8_t *uid, unsigned int uidLength)
+{
+    uint8_t key[6] = { 0xD3, 0xF7, 0xD3, 0xF7, 0xD3, 0xF7 };
+    int currentBlock = 4;
+    int messageStartIndex = 0;
+    int messageLength = 0;
+    uint8_t data[BLOCK_SIZE];
+
+    // read first block to get message length
+    int success = _nfcShield->mifareclassic_AuthenticateBlock(uid, uidLength, currentBlock, 0, key);
+    if (success)
+    {
+        success = _nfcShield->mifareclassic_ReadDataBlock(currentBlock, data);
+        if (success)
+        {
+            if (!decodeTlv(data, messageLength, messageStartIndex)) {
+                return NfcTag(uid, uidLength, "ERROR"); // TODO should the error message go in NfcTag?
+            }
+        }
+        else
+        {
+            DMSG("Error. Failed read block ");
+			DMSG_INT(currentBlock);
+            return NfcTag(uid, uidLength, MIFARE_CLASSIC);
+        }
+    }
+    else
+    {
+        DMSG("Tag is not NDEF formatted.");
+        // TODO set tag.isFormatted = false
+        return NfcTag(uid, uidLength, MIFARE_CLASSIC);
+    }
+
+    // this should be nested in the message length loop
+    int index = 0;
+    int bufferSize = getBufferSize(messageLength);
+    uint8_t buffer[bufferSize];
+
+    #ifdef MIFARE_CLASSIC_DEBUG
+    DMSG("Message Length ");
+    DMSG_INT(messageLength);
+    DMSG("Buffer Size ");
+    DMSG_INT(bufferSize);
+    #endif
+
+    while (index < bufferSize)
+    {
+
+        // authenticate on every sector
+        if (_nfcShield->mifareclassic_IsFirstBlock(currentBlock))
+        {
+            success = _nfcShield->mifareclassic_AuthenticateBlock(uid, uidLength, currentBlock, 0, key);
+            if (!success)
+            {
+                DMSG("Error. Block Authentication failed for ");
+                DMSG_INT(currentBlock);
+                // TODO error handling
+            }
+        }
+
+        // read the data
+        success = _nfcShield->mifareclassic_ReadDataBlock(currentBlock, &buffer[index]);
+        if (success)
+        {
+            #ifdef MIFARE_CLASSIC_DEBUG
+            DMSG("Block ");
+            DMSG_INT(currentBlock);
+            _nfcShield->PrintHexChar(&buffer[index], BLOCK_SIZE);
+            #endif
+        }
+        else
+        {
+            DMSG("Read failed ");
+            DMSG_INT(currentBlock);
+            // TODO handle errors here
+        }
+
+        index += BLOCK_SIZE;
+        currentBlock++;
+
+        // skip the trailer block
+        if (_nfcShield->mifareclassic_IsTrailerBlock(currentBlock))
+        {
+            #ifdef MIFARE_CLASSIC_DEBUG
+            DMSG("Skipping block ");
+            DMSG_INT(currentBlock);
+            #endif
+            currentBlock++;
+        }
+    }
+
+    return NfcTag(uid, uidLength, MIFARE_CLASSIC, &buffer[messageStartIndex], messageLength);
+}
+
+int MifareClassic::getBufferSize(int messageLength)
+{
+
+    int bufferSize = messageLength;
+
+    // TLV header is 2 or 4 uint8_ts, TLV terminator is 1 uint8_t.
+    if (messageLength < 0xFF)
+    {
+        bufferSize += SHORT_TLV_SIZE + 1;
+    }
+    else
+    {
+        bufferSize += LONG_TLV_SIZE + 1;
+    }
+
+    // bufferSize needs to be a multiple of BLOCK_SIZE
+    if (bufferSize % BLOCK_SIZE != 0)
+    {
+        bufferSize = ((bufferSize / BLOCK_SIZE) + 1) * BLOCK_SIZE;
+    }
+
+    return bufferSize;
+}
+
+// skip null tlvs (0x0) before the real message
+// technically unlimited null tlvs, but we assume
+// T & L of TLV in the first block we read
+int MifareClassic::getNdefStartIndex(uint8_t *data)
+{
+
+    for (int i = 0; i < BLOCK_SIZE; i++)
+    {
+        if (data[i] == 0x0)
+        {
+            // do nothing, skip
+        }
+        else if (data[i] == 0x3)
+        {
+            return i;
+        }
+        else
+        {
+            DMSG("Unknown TLV ");
+            DMSG_HEX(data[i]);
+            return -2;
+        }
+    }
+
+    return -1;
+}
+
+// Decode the NDEF data length from the Mifare TLV
+// Leading null TLVs (0x0) are skipped
+// Assuming T & L of TLV will be in the first block
+// messageLength and messageStartIndex written to the parameters
+// success or failure status is returned
+//
+// { 0x3, LENGTH }
+// { 0x3, 0xFF, LENGTH, LENGTH }
+bool MifareClassic::decodeTlv(uint8_t *data, int &messageLength, int &messageStartIndex)
+{
+    int i = getNdefStartIndex(data);
+
+    if (i < 0 || data[i] != 0x3)
+    {
+        DMSG("Error. Can't decode message length.");
+        return false;
+    }
+    else
+    {
+        if (data[i+1] == 0xFF)
+        {
+            messageLength = ((0xFF & data[i+2]) << 8) | (0xFF & data[i+3]);
+            messageStartIndex = i + LONG_TLV_SIZE;
+        }
+        else
+        {
+            messageLength = data[i+1];
+            messageStartIndex = i + SHORT_TLV_SIZE;
+        }
+    }
+
+    return true;
+}
+
+bool MifareClassic::write(NdefMessage& m, uint8_t * uid, unsigned int uidLength)
+{
+
+    uint8_t encoded[m.getEncodedSize()];
+    m.encode(encoded);
+
+    uint8_t buffer[getBufferSize(sizeof(encoded))];
+    memset(buffer, 0, sizeof(buffer));
+
+    #ifdef MIFARE_CLASSIC_DEBUG
+    DMSG("sizeof(encoded) "));DMSG(sizeof(encoded);
+    DMSG("sizeof(buffer) "));DMSG(sizeof(buffer);
+    #endif
+
+    if (sizeof(encoded) < 0xFF)
+    {
+        buffer[0] = 0x3;
+        buffer[1] = sizeof(encoded);
+        memcpy(&buffer[2], encoded, sizeof(encoded));
+        buffer[2+sizeof(encoded)] = 0xFE; // terminator
+    }
+    else
+    {
+        buffer[0] = 0x3;
+        buffer[1] = 0xFF;
+        buffer[2] = ((sizeof(encoded) >> 8) & 0xFF);
+        buffer[3] = (sizeof(encoded) & 0xFF);
+        memcpy(&buffer[4], encoded, sizeof(encoded));
+        buffer[4+sizeof(encoded)] = 0xFE; // terminator
+    }
+
+    // Write to tag
+    int index = 0;
+    int currentBlock = 4;
+    uint8_t key[6] = { 0xD3, 0xF7, 0xD3, 0xF7, 0xD3, 0xF7 }; // this is Sector 1 - 15 key
+
+    while (index < sizeof(buffer))
+    {
+
+        if (_nfcShield->mifareclassic_IsFirstBlock(currentBlock))
+        {
+            int success = _nfcShield->mifareclassic_AuthenticateBlock(uid, uidLength, currentBlock, 0, key);
+            if (!success)
+            {
+                DMSG("Error. Block Authentication failed for ");DMSG_INT(currentBlock);
+                return false;
+            }
+        }
+
+        int write_success = _nfcShield->mifareclassic_WriteDataBlock (currentBlock, &buffer[index]);
+        if (write_success)
+        {
+            #ifdef MIFARE_CLASSIC_DEBUG
+            DMSG("Wrote block ");Serial.print(currentBlock);DMSG(" - ");
+            _nfcShield->PrintHexChar(&buffer[index], BLOCK_SIZE);
+            #endif
+        }
+        else
+        {
+            DMSG("Write failed ");DMSG_INT(currentBlock);
+            return false;
+        }
+        index += BLOCK_SIZE;
+        currentBlock++;
+
+        if (_nfcShield->mifareclassic_IsTrailerBlock(currentBlock))
+        {
+            // can't write to trailer block
+            #ifdef MIFARE_CLASSIC_DEBUG
+            DMSG("Skipping block ");DMSG(currentBlock);
+            #endif
+            currentBlock++;
+        }
+
+    }
+
+    return true;
+}
diff -r 000000000000 -r 88960f3eeb2c nfc/MifareClassic.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nfc/MifareClassic.h	Fri Dec 27 01:46:32 2013 +0000
@@ -0,0 +1,22 @@
+#ifndef MifareClassic_h
+#define MifareClassic_h
+
+#include <PN532.h>
+#include <Ndef.h>
+#include <NfcTag.h>
+
+class MifareClassic
+{
+    public:
+        MifareClassic(PN532& nfcShield);
+        ~MifareClassic();
+        NfcTag read(uint8_t *uid, unsigned int uidLength);
+        bool write(NdefMessage& ndefMessage, uint8_t *uid, unsigned int uidLength);
+    private:
+        PN532* _nfcShield;
+        int getBufferSize(int messageLength);
+        int getNdefStartIndex(uint8_t *data);
+        bool decodeTlv(uint8_t *data, int &messageLength, int &messageStartIndex);
+};
+
+#endif
diff -r 000000000000 -r 88960f3eeb2c nfc/MifareUltralight.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nfc/MifareUltralight.cpp	Fri Dec 27 01:46:32 2013 +0000
@@ -0,0 +1,165 @@
+#include "MifareUltralight.h"
+
+#include "PN532_debug.h"
+
+#define ULTRALIGHT_PAGE_SIZE 4
+#define ULTRALIGHT_READ_SIZE 4 // we should be able to read 16 uint8_ts at a time
+
+#define ULTRALIGHT_DATA_START_PAGE 4
+#define ULTRALIGHT_MESSAGE_LENGTH_INDEX 1
+#define ULTRALIGHT_DATA_START_INDEX 2
+#define ULTRALIGHT_MAX_PAGE 63
+
+#define NFC_FORUM_TAG_TYPE_2 ("NFC Forum Type 2")
+
+MifareUltralight::MifareUltralight(PN532& nfcShield)
+{
+    nfc = &nfcShield;
+    ndefStartIndex = 0;
+    messageLength = 0;
+}
+
+MifareUltralight::~MifareUltralight()
+{
+}
+
+NfcTag MifareUltralight::read(uint8_t * uid, unsigned int uidLength)
+{
+    if (isUnformatted())
+    {
+        DMSG("WARNING: Tag is not formatted.");
+        return NfcTag(uid, uidLength, NFC_FORUM_TAG_TYPE_2);
+    }
+
+    readCapabilityContainer(); // meta info for tag
+    findNdefMessage();
+    calculateBufferSize();
+
+    if (messageLength == 0) { // data is 0x44 0x03 0x00 0xFE
+        NdefMessage message = NdefMessage();
+        message.addEmptyRecord();
+        return NfcTag(uid, uidLength, NFC_FORUM_TAG_TYPE_2, message);
+    }
+
+    bool success;
+    uint8_t page;
+    uint8_t index = 0;
+    uint8_t buffer[bufferSize];
+    for (page = ULTRALIGHT_DATA_START_PAGE; page < ULTRALIGHT_MAX_PAGE; page++)
+    {
+        // read the data
+        success = nfc->mifareultralight_ReadPage(page, &buffer[index]);
+        if (success)
+        {
+            #ifdef MIFARE_ULTRALIGHT_DEBUG
+            DMSG("Page ");Serial.print(page);DMSG(" ");
+            nfc->PrintHexChar(&buffer[index], ULTRALIGHT_PAGE_SIZE);
+            #endif
+        }
+        else
+        {
+            DMSG("Read failed ");DMSG_INT(page);
+            // TODO error handling
+            messageLength = 0;
+            break;
+        }
+
+        if (index >= (messageLength + ndefStartIndex))
+        {
+            break;
+        }
+
+        index += ULTRALIGHT_PAGE_SIZE;
+    }
+
+    NdefMessage ndefMessage = NdefMessage(&buffer[ndefStartIndex], messageLength);
+    return NfcTag(uid, uidLength, NFC_FORUM_TAG_TYPE_2, ndefMessage);
+
+}
+
+bool MifareUltralight::isUnformatted()
+{
+    uint8_t page = 4;
+    uint8_t data[ULTRALIGHT_READ_SIZE];
+    bool success = nfc->mifareultralight_ReadPage (page, data);
+    if (success)
+    {
+        return (data[0] == 0xFF && data[1] == 0xFF && data[2] == 0xFF && data[3] == 0xFF);
+    }
+    else
+    {
+        DMSG("Error. Failed read page ");DMSG_INT(page);
+        return false;
+    }
+}
+
+// page 3 has tag capabilities
+void MifareUltralight::readCapabilityContainer()
+{
+    uint8_t data[ULTRALIGHT_PAGE_SIZE];
+    int success = nfc->mifareultralight_ReadPage (3, data);
+    if (success)
+    {
+        // See AN1303 - different rules for Mifare Family uint8_t2 = (additional data + 48)/8
+        tagCapacity = data[2] * 8;
+        #ifdef MIFARE_ULTRALIGHT_DEBUG
+        DMSG("Tag capacity "));Serial.print(tagCapacity);DMSG(F(" uint8_ts");
+        #endif
+
+        // TODO future versions should get lock information
+    }
+}
+
+// read enough of the message to find the ndef message length
+void MifareUltralight::findNdefMessage()
+{
+    int page;
+    uint8_t data[12]; // 3 pages
+    uint8_t* data_ptr = &data[0];
+
+    // the nxp read command reads 4 pages, unfortunately adafruit give me one page at a time
+    bool success = true;
+    for (page = 4; page < 6; page++)
+    {
+        success = success && nfc->mifareultralight_ReadPage(page, data_ptr);
+        #ifdef MIFARE_ULTRALIGHT_DEBUG
+        DMSG("Page "));Serial.print(page);Serial.print(F(" - ");
+        nfc->PrintHexChar(data_ptr, 4);
+        #endif
+        data_ptr += ULTRALIGHT_PAGE_SIZE;
+    }
+
+    if (success)
+    {
+        if (data[0] == 0x03)
+        {
+            messageLength = data[1];
+            ndefStartIndex = 2;
+        }
+        else if (data[5] == 0x3) // page 5 uint8_t 1
+        {
+            // TODO should really read the lock control TLV to ensure uint8_t[5] is correct
+            messageLength = data[6];
+            ndefStartIndex = 7;
+        }
+    }
+
+    #ifdef MIFARE_ULTRALIGHT_DEBUG
+    DMSG("messageLength ");DMSG(messageLength);
+    DMSG("ndefStartIndex ");DMSG(ndefStartIndex);
+    #endif
+}
+
+// buffer is larger than the message, need to handle some data before and after
+// message and need to ensure we read full pages
+void MifareUltralight::calculateBufferSize()
+{
+    // TLV terminator 0xFE is 1 uint8_t
+    bufferSize = messageLength + ndefStartIndex + 1;
+
+    if (bufferSize % ULTRALIGHT_READ_SIZE != 0)
+    {
+        // buffer must be an increment of page size
+        bufferSize = ((bufferSize / ULTRALIGHT_READ_SIZE) + 1) * ULTRALIGHT_READ_SIZE;
+    }
+}
diff -r 000000000000 -r 88960f3eeb2c nfc/MifareUltralight.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nfc/MifareUltralight.h	Fri Dec 27 01:46:32 2013 +0000
@@ -0,0 +1,26 @@
+#ifndef MifareUltralight_h
+#define MifareUltralight_h
+
+#include <PN532.h>
+#include <NfcTag.h>
+#include <Ndef.h>
+
+class MifareUltralight
+{
+    public:
+        MifareUltralight(PN532& nfcShield);
+        ~MifareUltralight();
+        NfcTag read(uint8_t *uid, unsigned int uidLength);
+    private:
+        PN532* nfc;
+        unsigned int tagCapacity;
+        unsigned int messageLength;
+        unsigned int bufferSize;
+        unsigned int ndefStartIndex;
+        bool isUnformatted();
+        void readCapabilityContainer();
+        void findNdefMessage();
+        void calculateBufferSize();
+};
+
+#endif
diff -r 000000000000 -r 88960f3eeb2c nfc/Ndef.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nfc/Ndef.cpp	Fri Dec 27 01:46:32 2013 +0000
@@ -0,0 +1,52 @@
+#include "Ndef.h"
+#include "PN532_debug.h"
+
+// Borrowed from Adafruit_NFCShield_I2C
+void PrintHex(const uint8_t * data, const long numuint8_ts)
+{
+  uint32_t szPos;
+  for (szPos=0; szPos < numuint8_ts; szPos++)
+  {
+    DMSG("0x");
+    // Append leading 0 for small values
+    if (data[szPos] <= 0xF)
+      DMSG("0");
+    DMSG_HEX(data[szPos]&0xff);
+    if ((numuint8_ts > 1) && (szPos != numuint8_ts - 1))
+    {
+      DMSG(" ");
+    }
+  }
+  DMSG("");
+}
+
+// Borrowed from Adafruit_NFCShield_I2C
+void PrintHexChar(const uint8_t * data, const long numuint8_ts)
+{
+  uint32_t szPos;
+  for (szPos=0; szPos < numuint8_ts; szPos++)
+  {
+    // Append leading 0 for small values
+    DMSG_HEX(data[szPos]);
+  }
+  DMSG("   ");
+  for (szPos=0; szPos < numuint8_ts; szPos++)
+  {
+    if (data[szPos] <= 0x1F)
+      DMSG(".");
+    else
+      DMSG("%c", (char)data[szPos]);
+  }
+  DMSG("\n");
+}
+
+// Note if buffer % blockSize != 0, last block will not be written
+void DumpHex(const uint8_t * data, const long numuint8_ts, const unsigned int blockSize)
+{
+    int i;
+    for (i = 0; i < (numuint8_ts / blockSize); i++)
+    {
+        PrintHexChar(data, blockSize);
+        data += blockSize;
+    }
+}
diff -r 000000000000 -r 88960f3eeb2c nfc/Ndef.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nfc/Ndef.h	Fri Dec 27 01:46:32 2013 +0000
@@ -0,0 +1,13 @@
+#ifndef Ndef_h
+#define Ndef_h
+
+/* NOTE: To use the Ndef library in your code, don't include Ndef.h
+   See README.md for details on which files to include in your sketch.
+*/
+#include <stdint.h>
+
+void PrintHex(const uint8_t *data, const long numuint8_ts);
+void PrintHexChar(const uint8_t *data, const long numuint8_ts);
+void DumpHex(const uint8_t *data, const long numuint8_ts, const int blockSize);
+
+#endif
diff -r 000000000000 -r 88960f3eeb2c nfc/NdefMessage.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nfc/NdefMessage.cpp	Fri Dec 27 01:46:32 2013 +0000
@@ -0,0 +1,278 @@
+#include "NdefMessage.h"
+#include "PN532_debug.h"
+
+NdefMessage::NdefMessage(void)
+{
+    _recordCount = 0;
+}
+
+NdefMessage::NdefMessage(const uint8_t * data, const int numuint8_ts)
+{
+    #ifdef NDEF_DEBUG
+    DMSG("Decoding "));Serial.print(numuint8_ts);DMSG(F(" uint8_ts");
+    PrintHexChar(data, numuint8_ts);
+    //DumpHex(data, numuint8_ts, 16);
+    #endif
+
+    _recordCount = 0;
+
+    int index = 0;
+
+    while (index <= numuint8_ts)
+    {
+
+        // decode tnf - first uint8_t is tnf with bit flags
+        // see the NFDEF spec for more info
+        uint8_t tnf_uint8_t = data[index];
+        bool mb = (tnf_uint8_t & 0x80) != 0;
+        bool me = (tnf_uint8_t & 0x40) != 0;
+        bool cf = (tnf_uint8_t & 0x20) != 0;
+        bool sr = (tnf_uint8_t & 0x10) != 0;
+        bool il = (tnf_uint8_t & 0x8) != 0;
+        uint8_t tnf = (tnf_uint8_t & 0x7);
+
+        NdefRecord record = NdefRecord();
+        record.setTnf(tnf);
+
+        index++;
+        int typeLength = data[index];
+
+        int payloadLength = 0;
+        if (sr)
+        {
+            index++;
+            payloadLength = data[index];
+        }
+        else
+        {
+            payloadLength = ((0xFF & data[++index]) << 24) | ((0xFF & data[++index]) << 26) |
+            ((0xFF & data[++index]) << 8) | (0xFF & data[++index]);
+        }
+
+        int idLength = 0;
+        if (il)
+        {
+            index++;
+            idLength = data[index];
+        }
+
+        index++;
+        record.setType(&data[index], typeLength);
+        index += typeLength;
+
+        if (il)
+        {
+            record.setId(&data[index], idLength);
+            index += idLength;
+        }
+
+        record.setPayload(&data[index], payloadLength);
+        index += payloadLength;
+
+        addRecord(record);
+
+        if (me) break; // last message
+    }
+
+}
+
+NdefMessage::NdefMessage(const NdefMessage& rhs)
+{
+
+    _recordCount = rhs._recordCount;
+    for (int i = 0; i < _recordCount; i++)
+    {
+        _records[i] = rhs._records[i];
+    }
+
+}
+
+NdefMessage::~NdefMessage()
+{
+}
+
+NdefMessage& NdefMessage::operator=(const NdefMessage& rhs)
+{
+
+    if (this != &rhs)
+    {
+
+        // delete existing records
+        for (int i = 0; i < _recordCount; i++)
+        {
+            // TODO Dave: is this the right way to delete existing records?
+            _records[i] = NdefRecord();
+        }
+
+        _recordCount = rhs._recordCount;
+        for (int i = 0; i < _recordCount; i++)
+        {
+            _records[i] = rhs._records[i];
+        }
+    }
+    return *this;
+}
+
+unsigned int NdefMessage::getRecordCount()
+{
+    return _recordCount;
+}
+
+int NdefMessage::getEncodedSize()
+{
+    int size = 0;
+    for (int i = 0; i < _recordCount; i++)
+    {
+        size += _records[i].getEncodedSize();
+    }
+    return size;
+}
+
+// TODO change this to return uint8_t*
+void NdefMessage::encode(uint8_t* data)
+{
+    // assert sizeof(data) >= getEncodedSize()
+    uint8_t* data_ptr = &data[0];
+
+    for (int i = 0; i < _recordCount; i++)
+    {
+        _records[i].encode(data_ptr, i == 0, (i + 1) == _recordCount);
+        // TODO can NdefRecord.encode return the record size?
+        data_ptr += _records[i].getEncodedSize();
+    }
+
+}
+
+bool NdefMessage::addRecord(NdefRecord& record)
+{
+
+    if (_recordCount < MAX_NDEF_RECORDS)
+    {
+        _records[_recordCount] = record;
+        _recordCount++;
+        return true;
+    }
+    else
+    {
+        DMSG("WARNING: Too many records. Increase MAX_NDEF_RECORDS.");
+        return false;
+    }
+}
+
+void NdefMessage::addMimeMediaRecord(string mimeType, string payload)
+{
+
+    uint8_t payloaduint8_ts[payload.length() + 1];
+    payload.copy((char*)payloaduint8_ts, sizeof(payloaduint8_ts));
+
+    addMimeMediaRecord(mimeType, payloaduint8_ts, payload.length());
+}
+
+void NdefMessage::addMimeMediaRecord(string mimeType, uint8_t* payload, int payloadLength)
+{
+    NdefRecord r = NdefRecord();
+    r.setTnf(TNF_MIME_MEDIA);
+
+    uint8_t type[mimeType.length() + 1];
+    mimeType.copy((char*)type, sizeof(type));
+    r.setType(type, mimeType.length());
+
+    r.setPayload(payload, payloadLength);
+
+    addRecord(r);
+}
+
+void NdefMessage::addTextRecord(string text)
+{
+    addTextRecord(text, "en");
+}
+
+void NdefMessage::addTextRecord(string text, string encoding)
+{
+    NdefRecord r = NdefRecord();
+    r.setTnf(TNF_WELL_KNOWN);
+
+    uint8_t RTD_TEXT[1] = { 0x54 }; // TODO this should be a constant or preprocessor
+    r.setType(RTD_TEXT, sizeof(RTD_TEXT));
+
+    // X is a placeholder for encoding length
+    // TODO is it more efficient to build w/o string concatenation?
+    string payloadString = "X" + encoding + text;
+
+    uint8_t payload[payloadString.length() + 1];
+    payloadString.copy((char*)payload, sizeof(payload));
+
+    // replace X with the real encoding length
+    payload[0] = encoding.length();
+
+    r.setPayload(payload, payloadString.length());
+
+    addRecord(r);
+}
+
+void NdefMessage::addUriRecord(string uri)
+{
+    NdefRecord* r = new NdefRecord();
+    r->setTnf(TNF_WELL_KNOWN);
+
+    uint8_t RTD_URI[1] = { 0x55 }; // TODO this should be a constant or preprocessor
+    r->setType(RTD_URI, sizeof(RTD_URI));
+
+    // X is a placeholder for identifier code
+    string payloadString = "X" + uri;
+
+    uint8_t payload[payloadString.length() + 1];
+    payloadString.copy((char*)payload, sizeof(payload));
+
+    // add identifier code 0x0, meaning no prefix substitution
+    payload[0] = 0x0;
+
+    r->setPayload(payload, payloadString.length());
+
+    addRecord(*r);
+    delete(r);
+}
+
+void NdefMessage::addEmptyRecord()
+{
+    NdefRecord* r = new NdefRecord();
+    r->setTnf(TNF_EMPTY);
+    addRecord(*r);
+    delete(r);
+}
+
+NdefRecord NdefMessage::getRecord(int index)
+{
+    if (index > -1 && index < _recordCount)
+    {
+        return _records[index];
+    }
+    else
+    {
+        return NdefRecord(); // would rather return NULL
+    }
+}
+
+NdefRecord NdefMessage::operator[](int index)
+{
+    return getRecord(index);
+}
+
+void NdefMessage::print()
+{
+    DMSG("\nNDEF Message ");
+    DMSG_INT(_recordCount);
+    DMSG(" record");
+    if (_recordCount == 1) {
+        DMSG(", ");
+    } else {
+        DMSG("s, ");
+    }
+    DMSG_INT(getEncodedSize());
+
+    int i;
+    for (i = 0; i < _recordCount; i++)
+    {
+         _records[i].print();
+    }
+}
diff -r 000000000000 -r 88960f3eeb2c nfc/NdefMessage.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nfc/NdefMessage.h	Fri Dec 27 01:46:32 2013 +0000
@@ -0,0 +1,39 @@
+#ifndef NdefMessage_h
+#define NdefMessage_h
+
+#include <Ndef.h>
+#include <NdefRecord.h>
+
+#define MAX_NDEF_RECORDS 4
+
+class NdefMessage
+{
+    public:
+        NdefMessage(void);
+        NdefMessage(const uint8_t *data, const int numuint8_ts);
+        NdefMessage(const NdefMessage& rhs);
+        ~NdefMessage();
+        NdefMessage& operator=(const NdefMessage& rhs);
+
+        int getEncodedSize(); // need so we can pass array to encode
+        void encode(uint8_t *data);
+
+        bool addRecord(NdefRecord& record);
+        void addMimeMediaRecord(string mimeType, string payload);
+        void addMimeMediaRecord(string mimeType, uint8_t *payload, int payloadLength);
+        void addTextRecord(string text);
+        void addTextRecord(string text, string encoding);
+        void addUriRecord(string uri);
+        void addEmptyRecord();
+
+        unsigned int getRecordCount();
+        NdefRecord getRecord(int index);
+        NdefRecord operator[](int index);
+
+        void print();
+    private:
+        NdefRecord _records[MAX_NDEF_RECORDS];
+        unsigned int _recordCount;
+};
+
+#endif
diff -r 000000000000 -r 88960f3eeb2c nfc/NdefRecord.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nfc/NdefRecord.cpp	Fri Dec 27 01:46:32 2013 +0000
@@ -0,0 +1,363 @@
+
+#include <string>
+#include <string.h>
+#include <stdlib.h>
+
+#include "NdefRecord.h"
+#include "PN532_debug.h"
+
+NdefRecord::NdefRecord()
+{
+    //DMSG("NdefRecord Constructor 1");
+    _tnf = 0;
+    _typeLength = 0;
+    _payloadLength = 0;
+    _idLength = 0;
+    _type = (uint8_t *)NULL;
+    _payload = (uint8_t *)NULL;
+    _id = (uint8_t *)NULL;
+}
+
+NdefRecord::NdefRecord(const NdefRecord& rhs)
+{
+    //DMSG("NdefRecord Constructor 2 (copy)");
+
+    _tnf = rhs._tnf;
+    _typeLength = rhs._typeLength;
+    _payloadLength = rhs._payloadLength;
+    _idLength = rhs._idLength;
+    _type = (uint8_t *)NULL;
+    _payload = (uint8_t *)NULL;
+    _id = (uint8_t *)NULL;
+
+    if (_typeLength)
+    {
+        _type = (uint8_t*)malloc(_typeLength);
+        memcpy(_type, rhs._type, _typeLength);
+    }
+
+    if (_payloadLength)
+    {
+        _payload = (uint8_t*)malloc(_payloadLength);
+        memcpy(_payload, rhs._payload, _payloadLength);
+    }
+
+    if (_idLength)
+    {
+        _id = (uint8_t*)malloc(_idLength);
+        memcpy(_id, rhs._id, _idLength);
+    }
+
+}
+
+// TODO NdefRecord::NdefRecord(tnf, type, payload, id)
+
+NdefRecord::~NdefRecord()
+{
+    //DMSG("NdefRecord Destructor");
+    if (_typeLength)
+    {
+        free(_type);
+    }
+
+    if (_payloadLength)
+    {
+        free(_payload);
+    }
+
+    if (_idLength)
+    {
+        free(_id);
+    }
+}
+
+NdefRecord& NdefRecord::operator=(const NdefRecord& rhs)
+{
+    //DMSG("NdefRecord ASSIGN");
+
+    if (this != &rhs)
+    {
+        // free existing
+        if (_typeLength)
+        {
+            free(_type);
+        }
+
+        if (_payloadLength)
+        {
+            free(_payload);
+        }
+
+        if (_idLength)
+        {
+            free(_id);
+        }
+
+        _tnf = rhs._tnf;
+        _typeLength = rhs._typeLength;
+        _payloadLength = rhs._payloadLength;
+        _idLength = rhs._idLength;
+
+        if (_typeLength)
+        {
+            _type = (uint8_t*)malloc(_typeLength);
+            memcpy(_type, rhs._type, _typeLength);
+        }
+
+        if (_payloadLength)
+        {
+            _payload = (uint8_t*)malloc(_payloadLength);
+            memcpy(_payload, rhs._payload, _payloadLength);
+        }
+
+        if (_idLength)
+        {
+            _id = (uint8_t*)malloc(_idLength);
+            memcpy(_id, rhs._id, _idLength);
+        }
+    }
+    return *this;
+}
+
+// size of records in uint8_ts
+int NdefRecord::getEncodedSize()
+{
+    int size = 2; // tnf + typeLength
+    if (_payloadLength > 0xFF)
+    {
+        size += 4;
+    }
+    else
+    {
+        size += 1;
+    }
+
+    if (_idLength)
+    {
+        size += 1;
+    }
+
+    size += (_typeLength + _payloadLength + _idLength);
+
+    return size;
+}
+
+void NdefRecord::encode(uint8_t *data, bool firstRecord, bool lastRecord)
+{
+    // assert data > getEncodedSize()
+
+    uint8_t* data_ptr = &data[0];
+
+    *data_ptr = getTnfuint8_t(firstRecord, lastRecord);
+    data_ptr += 1;
+
+    *data_ptr = _typeLength;
+    data_ptr += 1;
+
+    if (_payloadLength <= 0xFF) {  // short record
+        *data_ptr = _payloadLength;
+        data_ptr += 1;
+    } else { // long format
+        // 4 uint8_ts but we store length as an int
+        data_ptr[0] = 0x0; // (_payloadLength >> 24) & 0xFF;
+        data_ptr[1] = 0x0; // (_payloadLength >> 16) & 0xFF;
+        data_ptr[2] = (_payloadLength >> 8) & 0xFF;
+        data_ptr[3] = _payloadLength & 0xFF;
+        data_ptr += 4;
+    }
+
+    if (_idLength)
+    {
+        *data_ptr = _idLength;
+        data_ptr += 1;
+    }
+
+    //DMSG(2);
+    memcpy(data_ptr, _type, _typeLength);
+    data_ptr += _typeLength;
+
+    memcpy(data_ptr, _payload, _payloadLength);
+    data_ptr += _payloadLength;
+
+    if (_idLength)
+    {
+        memcpy(data_ptr, _id, _idLength);
+        data_ptr += _idLength;
+    }
+}
+
+uint8_t NdefRecord::getTnfuint8_t(bool firstRecord, bool lastRecord)
+{
+    int value = _tnf;
+
+    if (firstRecord) { // mb
+        value = value | 0x80;
+    }
+
+    if (lastRecord) { //
+        value = value | 0x40;
+    }
+
+    // chunked flag is always false for now
+    // if (cf) {
+    //     value = value | 0x20;
+    // }
+
+    if (_payloadLength <= 0xFF) {
+        value = value | 0x10;
+    }
+
+    if (_idLength) {
+        value = value | 0x8;
+    }
+
+    return value;
+}
+
+uint8_t NdefRecord::getTnf()
+{
+    return _tnf;
+}
+
+void NdefRecord::setTnf(uint8_t tnf)
+{
+    _tnf = tnf;
+}
+
+unsigned int NdefRecord::getTypeLength()
+{
+    return _typeLength;
+}
+
+int NdefRecord::getPayloadLength()
+{
+    return _payloadLength;
+}
+
+unsigned int NdefRecord::getIdLength()
+{
+    return _idLength;
+}
+
+string NdefRecord::getType()
+{
+    char type[_typeLength + 1];
+    memcpy(type, _type, _typeLength);
+    type[_typeLength] = '\0'; // null terminate
+    return string(type);
+}
+
+// this assumes the caller created type correctly
+void NdefRecord::getType(uint8_t* type)
+{
+    memcpy(type, _type, _typeLength);
+}
+
+void NdefRecord::setType(const uint8_t * type, const unsigned int numuint8_ts)
+{
+    if(_typeLength)
+    {
+        free(_type);
+    }
+
+    _type = (uint8_t*)malloc(numuint8_ts);
+    memcpy(_type, type, numuint8_ts);
+    _typeLength = numuint8_ts;
+}
+
+// assumes the caller sized payload properly
+void NdefRecord::getPayload(uint8_t *payload)
+{
+    memcpy(payload, _payload, _payloadLength);
+}
+
+void NdefRecord::setPayload(const uint8_t * payload, const int numuint8_ts)
+{
+    if (_payloadLength)
+    {
+        free(_payload);
+    }
+
+    _payload = (uint8_t*)malloc(numuint8_ts);
+    memcpy(_payload, payload, numuint8_ts);
+    _payloadLength = numuint8_ts;
+}
+
+string NdefRecord::getId()
+{
+    char id[_idLength + 1];
+    memcpy(id, _id, _idLength);
+    id[_idLength] = '\0'; // null terminate
+    return string(id);
+}
+
+void NdefRecord::getId(uint8_t *id)
+{
+    memcpy(id, _id, _idLength);
+}
+
+void NdefRecord::setId(const uint8_t * id, const unsigned int numuint8_ts)
+{
+    if (_idLength)
+    {
+        free(_id);
+    }
+
+    _id = (uint8_t*)malloc(numuint8_ts);
+    memcpy(_id, id, numuint8_ts);
+    _idLength = numuint8_ts;
+}
+
+void NdefRecord::print()
+{
+    DMSG("  NDEF Record");
+    DMSG("    TNF 0x");
+    DMSG_HEX(_tnf);
+    DMSG(" ");
+    switch (_tnf) {
+    case TNF_EMPTY:
+        DMSG("Empty");
+        break;
+    case TNF_WELL_KNOWN:
+        DMSG("Well Known");
+        break;
+    case TNF_MIME_MEDIA:
+        DMSG("Mime Media");
+        break;
+    case TNF_ABSOLUTE_URI:
+        DMSG("Absolute URI");
+        break;
+    case TNF_EXTERNAL_TYPE:
+        DMSG("External");
+        break;
+    case TNF_UNKNOWN:
+        DMSG("Unknown");
+        break;
+    case TNF_UNCHANGED:
+        DMSG("Unchanged");
+        break;
+    case TNF_RESERVED:
+        DMSG("Reserved");
+        break;
+    default:
+        DMSG("\n");
+    }
+    DMSG("    Type Length 0x");
+    DMSG_HEX(_typeLength);
+    DMSG("    Payload Length 0x");
+    DMSG_HEX(_payloadLength);
+    if (_idLength)
+    {
+        DMSG("    Id Length 0x");
+        DMSG_HEX(_idLength);
+    }
+    DMSG("    Type ");PrintHexChar(_type, _typeLength);
+    // TODO chunk large payloads so this is readable
+    DMSG("    Payload ");PrintHexChar(_payload, _payloadLength);
+    if (_idLength)
+    {
+        DMSG("    Id ");PrintHexChar(_id, _idLength);
+    }
+    DMSG("    Record is ");
+    DMSG_INT(getEncodedSize());
+}
\ No newline at end of file
diff -r 000000000000 -r 88960f3eeb2c nfc/NdefRecord.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nfc/NdefRecord.h	Fri Dec 27 01:46:32 2013 +0000
@@ -0,0 +1,59 @@
+#ifndef NdefRecord_h
+#define NdefRecord_h
+
+#include <string>
+#include <Ndef.h>
+
+using namespace std;
+
+#define TNF_EMPTY 0x0
+#define TNF_WELL_KNOWN 0x01
+#define TNF_MIME_MEDIA 0x02
+#define TNF_ABSOLUTE_URI 0x03
+#define TNF_EXTERNAL_TYPE 0x04
+#define TNF_UNKNOWN 0x05
+#define TNF_UNCHANGED 0x06
+#define TNF_RESERVED 0x07
+
+class NdefRecord
+{
+    public:
+        NdefRecord();
+        NdefRecord(const NdefRecord& rhs);
+        ~NdefRecord();
+        NdefRecord& operator=(const NdefRecord& rhs);
+
+        int getEncodedSize();
+        void encode(uint8_t *data, bool firstRecord, bool lastRecord);
+
+        unsigned int getTypeLength();
+        int getPayloadLength();
+        unsigned int getIdLength();
+
+        uint8_t getTnf();
+        void getType(uint8_t *type);
+        void getPayload(uint8_t *payload);
+        void getId(uint8_t *id);
+
+        // convenience methods
+        string getType();
+        string getId();
+
+        void setTnf(uint8_t tnf);
+        void setType(const uint8_t *type, const unsigned int numuint8_ts);
+        void setPayload(const uint8_t *payload, const int numuint8_ts);
+        void setId(const uint8_t *id, const unsigned int numuint8_ts);
+
+        void print();
+    private:
+        uint8_t getTnfuint8_t(bool firstRecord, bool lastRecord);
+        uint8_t _tnf; // 3 bit
+        unsigned int _typeLength;
+        int _payloadLength;
+        unsigned int _idLength;
+        uint8_t *_type;
+        uint8_t *_payload;
+        uint8_t *_id;
+};
+
+#endif
diff -r 000000000000 -r 88960f3eeb2c nfc/NfcAdapter.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nfc/NfcAdapter.cpp	Fri Dec 27 01:46:32 2013 +0000
@@ -0,0 +1,128 @@
+#include <NfcAdapter.h>
+#include <PN532_debug.h>
+
+NfcAdapter::NfcAdapter(PN532Interface &interface)
+{
+    shield = new PN532(interface);
+}
+
+NfcAdapter::~NfcAdapter(void)
+{
+    delete shield;
+}
+
+void NfcAdapter::begin()
+{
+    shield->begin();
+
+    uint32_t versiondata = shield->getFirmwareVersion();
+    if (! versiondata) {
+        DMSG("Didn't find PN53x board");
+        while (1); // halt
+    }
+    
+    DMSG("Found chip PN5%2X\r\n", versiondata >> 24);
+    DMSG("Firmware V%d.%d\r\n", (versiondata >> 16) & 0xFF, (versiondata >> 8) & 0xFF);
+
+    // configure board to read RFID tags
+    shield->SAMConfig();
+}
+
+bool NfcAdapter::tagPresent()
+{
+    uint8_t success;
+    uidLength = 0;
+
+    // TODO is cast of uidLength OK?
+    success = shield->readPassiveTargetID(PN532_MIFARE_ISO14443A, uid, (uint8_t*)&uidLength);
+
+    // if (success)
+    // {
+    //   DMSG("Found an ISO14443A card");
+    //   DMSG("  UID Length: ");Serial.print(uidLength, DEC);DMSG(" uint8_ts");
+    //   DMSG("  UID Value: ");
+    //   shield->PrintHex(uid, uidLength);
+    //   DMSG("");
+    // }
+
+    return success;
+}
+
+NfcTag NfcAdapter::read()
+{
+
+    uint8_t type = guessTagType();
+
+    // TODO need an abstraction of Driver
+    if (type == TAG_TYPE_MIFARE_CLASSIC)
+    {
+        #ifdef NDEF_DEBUG
+        DMSG("Reading Mifare Classic");
+        #endif
+        MifareClassic mifareClassic = MifareClassic(*shield);
+        return mifareClassic.read(uid, uidLength);
+    }
+    else if (type == TAG_TYPE_2)
+    {
+        #ifdef NDEF_DEBUG
+        DMSG("Reading Mifare Ultralight");
+        #endif
+        MifareUltralight ultralight = MifareUltralight(*shield);
+        return ultralight.read(uid, uidLength);
+    }
+    else if (type == TAG_TYPE_UNKNOWN)
+    {
+        DMSG("Can not determine tag type");
+        //DMSG("Can not determine tag type for ATQA 0x");
+        //Serial.print(atqa, HEX);DMSG(" SAK 0x");DMSG(sak, HEX);
+        return NfcTag(uid, uidLength);
+    }
+    else
+    {
+        DMSG("No driver for card type ");
+        DMSG_INT(type);
+        // TODO should set type here
+        return NfcTag(uid, uidLength);
+    }
+
+}
+
+bool NfcAdapter::write(NdefMessage& ndefMessage)
+{
+    bool success;
+
+    if (uidLength == 4)
+    {
+        MifareClassic mifareClassic = MifareClassic(*shield);
+        success = mifareClassic.write(ndefMessage, uid, uidLength);
+    }
+    else
+    {
+        DMSG("Unsupported Tag");
+        success = false;
+    }
+    return success;
+}
+
+// TODO this should return a Driver MifareClassic, MifareUltralight, Type 4, Unknown
+// Guess Tag Type by looking at the ATQA and SAK values
+// Need to follow spec for Card Identification. Maybe AN1303, AN1305 and ???
+unsigned int NfcAdapter::guessTagType()
+{
+
+    // 4 uint8_t id - Mifare Classic
+    //  - ATQA 0x4 && SAK 0x8
+    // 7 uint8_t id
+    //  - ATQA 0x44 && SAK 0x8 - Mifare Classic
+    //  - ATQA 0x44 && SAK 0x0 - Mifare Ultralight NFC Forum Type 2
+    //  - ATQA 0x344 && SAK 0x20 - NFC Forum Type 4
+
+    if (uidLength == 4)
+    {
+        return TAG_TYPE_MIFARE_CLASSIC;
+    }
+    else
+    {
+        return TAG_TYPE_2;
+    }
+}
diff -r 000000000000 -r 88960f3eeb2c nfc/NfcAdapter.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nfc/NfcAdapter.h	Fri Dec 27 01:46:32 2013 +0000
@@ -0,0 +1,43 @@
+#ifndef NfcAdapter_h
+#define NfcAdapter_h
+
+#include <PN532Interface.h>
+#include <PN532.h>
+#include <NfcTag.h>
+#include <Ndef.h>
+
+// Drivers
+#include <MifareClassic.h>
+#include <MifareUltralight.h>
+
+#define TAG_TYPE_MIFARE_CLASSIC (0)
+#define TAG_TYPE_1 (1)
+#define TAG_TYPE_2 (2)
+#define TAG_TYPE_3 (3)
+#define TAG_TYPE_4 (4)
+#define TAG_TYPE_UNKNOWN (99)
+
+#define IRQ   (2)
+#define RESET (3)  // Not connected by default on the NFC Shield
+
+class NfcAdapter {
+    public:
+        NfcAdapter(PN532Interface &interface);
+
+        ~NfcAdapter(void);
+        void begin(void);
+        bool tagPresent(); // tagAvailable
+        NfcTag read();
+        bool write(NdefMessage& ndefMessage);
+        // FUTURE bool share(NdefMessage& ndefMessage);
+        // FUTURE bool unshare();
+        // FUTURE bool erase();
+        // FUTURE bool format();
+    private:
+        PN532* shield;
+        uint8_t uid[7];    // Buffer to store the returned UID
+        unsigned int uidLength; // Length of the UID (4 or 7 uint8_ts depending on ISO14443A card type)
+        unsigned int guessTagType();
+};
+
+#endif
diff -r 000000000000 -r 88960f3eeb2c nfc/NfcDriver.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nfc/NfcDriver.h	Fri Dec 27 01:46:32 2013 +0000
@@ -0,0 +1,9 @@
+// eventually the NFC drivers should extend this class
+class NfcDriver
+{
+    public:
+        virtual NfcTag read(uint8_t * uid, int uidLength) = 0;
+        virtual bool write(NdefMessage& message, uint8_t * uid, int uidLength) = 0;
+        // erase()
+        // format()
+}
\ No newline at end of file
diff -r 000000000000 -r 88960f3eeb2c nfc/NfcTag.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nfc/NfcTag.cpp	Fri Dec 27 01:46:32 2013 +0000
@@ -0,0 +1,127 @@
+#include <NfcTag.h>
+#include <string.h>
+#include <PN532_debug.h>
+
+NfcTag::NfcTag()
+{
+    _uid = 0;
+    _uidLength = 0;
+    _tagType = "Unknown";
+    _ndefMessage = (NdefMessage*)NULL;
+}
+
+NfcTag::NfcTag(uint8_t *uid, unsigned int uidLength)
+{
+    _uid = uid;
+    _uidLength = uidLength;
+    _tagType = "Unknown";
+    _ndefMessage = (NdefMessage*)NULL;
+}
+
+NfcTag::NfcTag(uint8_t *uid, unsigned int  uidLength, string tagType)
+{
+    _uid = uid;
+    _uidLength = uidLength;
+    _tagType = tagType;
+    _ndefMessage = (NdefMessage*)NULL;
+}
+
+NfcTag::NfcTag(uint8_t *uid, unsigned int  uidLength, string tagType, NdefMessage& ndefMessage)
+{
+    _uid = uid;
+    _uidLength = uidLength;
+    _tagType = tagType;
+    _ndefMessage = new NdefMessage(ndefMessage);
+}
+
+// I don't like this version, but it will use less memory
+NfcTag::NfcTag(uint8_t *uid, unsigned int uidLength, string tagType, const uint8_t *ndefData, const int ndefDataLength)
+{
+    _uid = uid;
+    _uidLength = uidLength;
+    _tagType = tagType;
+    _ndefMessage = new NdefMessage(ndefData, ndefDataLength);
+}
+
+NfcTag::~NfcTag()
+{
+    delete _ndefMessage;
+}
+
+NfcTag& NfcTag::operator=(const NfcTag& rhs)
+{
+    if (this != &rhs)
+    {
+        delete _ndefMessage;
+        _uid = rhs._uid;
+        _uidLength = rhs._uidLength;
+        _tagType = rhs._tagType;
+        // TODO do I need a copy here?
+        _ndefMessage = rhs._ndefMessage;
+    }
+    return *this;
+}
+
+uint8_t NfcTag::getUidLength()
+{
+    return _uidLength;
+}
+
+void NfcTag::getUid(uint8_t *uid, unsigned int uidLength)
+{
+    memcpy(_uid, uid, uidLength);
+}
+
+string NfcTag::getUidString()
+{
+    string uidString = "";
+#if 0
+    for (int i = 0; i < _uidLength; i++)
+    {
+        if (i > 0)
+        {
+            uidString += " ";
+        }
+
+        if (_uid[i] < 0xF)
+        {
+            uidString += "0";
+        }
+
+        uidString += string((unsigned int)_uid[i], 16);
+    }
+    uidString.toUpperCase();
+#endif
+    return uidString;
+}
+
+string NfcTag::getTagType()
+{
+    return _tagType;
+}
+
+bool NfcTag::hasNdefMessage()
+{
+    return (_ndefMessage != NULL);
+}
+
+NdefMessage NfcTag::getNdefMessage()
+{
+    return *_ndefMessage;
+}
+
+void NfcTag::print()
+{
+    DMSG("NFC Tag - ");
+    DMSG_INT(_tagType);
+    DMSG("UID - ");
+    DMSG(getUidString().c_str());
+    if (_ndefMessage == NULL)
+    {
+        DMSG("\nNo NDEF Message");
+    }
+    else
+    {
+        _ndefMessage->print();
+    }
+}
diff -r 000000000000 -r 88960f3eeb2c nfc/NfcTag.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nfc/NfcTag.h	Fri Dec 27 01:46:32 2013 +0000
@@ -0,0 +1,33 @@
+#ifndef NfcTag_h
+#define NfcTag_h
+
+#include <stdint.h>
+#include <NdefMessage.h>
+
+class NfcTag
+{
+    public:
+        NfcTag();
+        NfcTag(uint8_t *uid, unsigned int uidLength);
+        NfcTag(uint8_t *uid, unsigned int uidLength, string tagType);
+        NfcTag(uint8_t *uid, unsigned int uidLength, string tagType, NdefMessage& ndefMessage);
+        NfcTag(uint8_t *uid, unsigned int uidLength, string tagType, const uint8_t *ndefData, const int ndefDataLength);
+        ~NfcTag(void);
+        NfcTag& operator=(const NfcTag& rhs);
+        uint8_t getUidLength();
+        void getUid(uint8_t *uid, unsigned int uidLength);
+        string getUidString();
+        string getTagType();
+        bool hasNdefMessage();
+        NdefMessage getNdefMessage();
+        void print();
+    private:
+        uint8_t *_uid;
+        unsigned int _uidLength;
+        string _tagType; // Mifare Classic, NFC Forum Type {1,2,3,4}, Unknown
+        NdefMessage* _ndefMessage;
+        // TODO capacity
+        // TODO isFormatted
+};
+
+#endif
diff -r 000000000000 -r 88960f3eeb2c nfc/PN532.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nfc/PN532.cpp	Fri Dec 27 01:46:32 2013 +0000
@@ -0,0 +1,851 @@
+/**************************************************************************/
+/*!
+    @file     PN532.cpp
+    @author   Adafruit Industries & Seeed Studio
+    @license  BSD
+*/
+/**************************************************************************/
+
+#include "PN532.h"
+#include "PN532_debug.h"
+#include <string.h>
+
+#ifdef ARDUINO
+#include "Arduino.h"
+#else
+#include <stdio.h>
+#endif
+
+#define HAL(func)   (_interface->func)
+
+PN532::PN532(PN532Interface &interface)
+{
+    _interface = &interface;
+}
+
+/**************************************************************************/
+/*!
+    @brief  Setups the HW
+*/
+/**************************************************************************/
+void PN532::begin()
+{
+    HAL(begin)();
+    HAL(wakeup)();
+}
+
+/**************************************************************************/
+/*!
+    @brief  Prints a hexadecimal value in plain characters
+
+    @param  data      Pointer to the uint8_t data
+    @param  numBytes  Data length in bytes
+*/
+/**************************************************************************/
+void PN532::PrintHex(const uint8_t *data, const uint32_t numBytes)
+{
+#ifdef ARDUINO
+    for (uint8_t i = 0; i < numBytes; i++) {
+        if (data[i] < 0x10) {
+            Serial.print(" 0");
+        } else {
+            Serial.print(' ');
+        }
+        Serial.print(data[i], HEX);
+    }
+    Serial.println("");
+#else
+    for (uint8_t i = 0; i < numBytes; i++) {
+        printf(" %2X", data[i]);
+    }
+    printf("\n");
+#endif
+}
+
+/**************************************************************************/
+/*!
+    @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 data
+    @param  numBytes  Data length in bytes
+*/
+/**************************************************************************/
+void PN532::PrintHexChar(const uint8_t *data, const uint32_t numBytes)
+{
+#ifdef ARDUINO
+    for (uint8_t i = 0; i < numBytes; i++) {
+        if (data[i] < 0x10) {
+            Serial.print(" 0");
+        } else {
+            Serial.print(' ');
+        }
+        Serial.print(data[i], HEX);
+    }
+    Serial.print("    ");
+    for (uint8_t i = 0; i < numBytes; i++) {
+        char c = data[i];
+        if (c <= 0x1f || c > 0x7f) {
+            Serial.print('.');
+        } else {
+            Serial.print(c);
+        }
+    }
+    Serial.println("");
+#else
+    for (uint8_t i = 0; i < numBytes; i++) {
+        printf(" %2X", data[i]);
+    }
+    printf("    ");
+    for (uint8_t i = 0; i < numBytes; i++) {
+        char c = data[i];
+        if (c <= 0x1f || c > 0x7f) {
+            printf(".");
+        } else {
+            printf("%c", c);
+        }
+        printf("\n");
+    }
+#endif
+}
+
+/**************************************************************************/
+/*!
+    @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_COMMAND_GETFIRMWAREVERSION;
+
+    if (HAL(writeCommand)(pn532_packetbuffer, 1)) {
+        return 0;
+    }
+
+    // read data packet
+    int16_t status = HAL(readResponse)(pn532_packetbuffer, sizeof(pn532_packetbuffer));
+    if (0 > status) {
+        return 0;
+    }
+
+    response = pn532_packetbuffer[0];
+    response <<= 8;
+    response |= pn532_packetbuffer[1];
+    response <<= 8;
+    response |= pn532_packetbuffer[2];
+    response <<= 8;
+    response |= pn532_packetbuffer[3];
+
+    return response;
+}
+
+
+/**************************************************************************/
+/*!
+    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
+*/
+/**************************************************************************/
+bool PN532::writeGPIO(uint8_t pinstate)
+{
+    // 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)
+
+    DMSG("Writing P3 GPIO: ");
+    DMSG_HEX(pn532_packetbuffer[1]);
+    DMSG("\n");
+
+    // Send the WRITEGPIO command (0x0E)
+    if (HAL(writeCommand)(pn532_packetbuffer, 3))
+        return 0;
+
+    return (0 < HAL(readResponse)(pn532_packetbuffer, sizeof(pn532_packetbuffer)));
+}
+
+/**************************************************************************/
+/*!
+    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 (HAL(writeCommand)(pn532_packetbuffer, 1))
+        return 0x0;
+
+    HAL(readResponse)(pn532_packetbuffer, sizeof(pn532_packetbuffer));
+
+    /* READGPIO response without prefix and suffix should be in the following format:
+
+      byte            Description
+      -------------   ------------------------------------------
+      b0              P3 GPIO Pins
+      b1              P7 GPIO Pins (not used ... taken by I2C)
+      b2              Interface Mode Pins (not used ... bus select pins)
+    */
+
+
+    DMSG("P3 GPIO: "); DMSG_HEX(pn532_packetbuffer[7]);
+    DMSG("P7 GPIO: "); DMSG_HEX(pn532_packetbuffer[8]);
+    DMSG("I0I1 GPIO: "); DMSG_HEX(pn532_packetbuffer[9]);
+    DMSG("\n");
+
+    return pn532_packetbuffer[0];
+}
+
+/**************************************************************************/
+/*!
+    @brief  Configures the SAM (Secure Access Module)
+*/
+/**************************************************************************/
+bool PN532::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!
+
+    DMSG("SAMConfig\n");
+
+    if (HAL(writeCommand)(pn532_packetbuffer, 4))
+        return false;
+
+    return (0 < HAL(readResponse)(pn532_packetbuffer, sizeof(pn532_packetbuffer)));
+}
+
+/**************************************************************************/
+/*!
+    Sets the MxRtyPassiveActivation uint8_t of the RFConfiguration register
+
+    @param  maxRetries    0xFF to wait forever, 0x00..0xFE to timeout
+                          after mxRetries
+
+    @returns 1 if everything executed properly, 0 for an error
+*/
+/**************************************************************************/
+bool PN532::setPassiveActivationRetries(uint8_t maxRetries)
+{
+    pn532_packetbuffer[0] = PN532_COMMAND_RFCONFIGURATION;
+    pn532_packetbuffer[1] = 5;    // Config item 5 (MaxRetries)
+    pn532_packetbuffer[2] = 0xFF; // MxRtyATR (default = 0xFF)
+    pn532_packetbuffer[3] = 0x01; // MxRtyPSL (default = 0x01)
+    pn532_packetbuffer[4] = maxRetries;
+
+    if (HAL(writeCommand)(pn532_packetbuffer, 5))
+        return 0x0;  // no ACK
+
+    return (0 < HAL(readResponse)(pn532_packetbuffer, sizeof(pn532_packetbuffer)));
+}
+
+/***** 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
+*/
+/**************************************************************************/
+bool PN532::readPassiveTargetID(uint8_t cardbaudrate, uint8_t *uid, uint8_t *uidLength, uint16_t timeout)
+{
+    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 (HAL(writeCommand)(pn532_packetbuffer, 3)) {
+        return 0x0;  // command failed
+    }
+
+    // read data packet
+    if (HAL(readResponse)(pn532_packetbuffer, sizeof(pn532_packetbuffer), timeout) < 0) {
+        return 0x0;
+    }
+
+    // check some basic stuff
+    /* ISO14443A card response should be in the following format:
+
+      byte            Description
+      -------------   ------------------------------------------
+      b0              Tags Found
+      b1              Tag Number (only one used in this example)
+      b2..3           SENS_RES
+      b4              SEL_RES
+      b5              NFCID Length
+      b6..NFCIDLen    NFCID
+    */
+
+    if (pn532_packetbuffer[0] != 1)
+        return 0;
+
+    uint16_t sens_res = pn532_packetbuffer[2];
+    sens_res <<= 8;
+    sens_res |= pn532_packetbuffer[3];
+
+    DMSG("ATQA: 0x");  DMSG_HEX(sens_res);
+    DMSG("SAK: 0x");  DMSG_HEX(pn532_packetbuffer[4]);
+    DMSG("\n");
+
+    /* Card appears to be Mifare Classic */
+    *uidLength = pn532_packetbuffer[5];
+
+    for (uint8_t i = 0; i < pn532_packetbuffer[5]; i++) {
+        uid[i] = pn532_packetbuffer[6 + i];
+    }
+
+    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 bytes
+                          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 i;
+
+    // Hang on to the key and uid data
+    memcpy (_key, keyData, 6);
+    memcpy (_uid, uid, uidLen);
+    _uidLen = uidLen;
+
+    // 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_B : MIFARE_CMD_AUTH_A;
+    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 bytes card ID */
+    }
+
+    if (HAL(writeCommand)(pn532_packetbuffer, 10 + _uidLen))
+        return 0;
+
+    // Read the response packet
+    HAL(readResponse)(pn532_packetbuffer, sizeof(pn532_packetbuffer));
+
+    // Check if the response is valid and we are authenticated???
+    // for an auth success it should be bytes 5-7: 0xD5 0x41 0x00
+    // Mifare auth error is technically byte 7: 0x14 but anything other and 0x00 is not good
+    if (pn532_packetbuffer[0] != 0x00) {
+        DMSG("Authentification failed\n");
+        return 0;
+    }
+
+    return 1;
+}
+
+/**************************************************************************/
+/*!
+    Tries to read an entire 16-bytes 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)
+{
+    DMSG("Trying to read 16 bytes from block ");
+    DMSG_INT(blockNumber);
+
+    /* 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 (HAL(writeCommand)(pn532_packetbuffer, 4)) {
+        return 0;
+    }
+
+    /* Read the response packet */
+    HAL(readResponse)(pn532_packetbuffer, sizeof(pn532_packetbuffer));
+
+    /* If byte 8 isn't 0x00 we probably have an error */
+    if (pn532_packetbuffer[0] != 0x00) {
+        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 + 1, 16);
+
+    return 1;
+}
+
+/**************************************************************************/
+/*!
+    Tries to write an entire 16-bytes 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)
+{
+    /* 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 (HAL(writeCommand)(pn532_packetbuffer, 20)) {
+        return 0;
+    }
+
+    /* Read the response packet */
+    return (0 < HAL(readResponse)(pn532_packetbuffer, sizeof(pn532_packetbuffer)));
+}
+
+/**************************************************************************/
+/*!
+    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};
+
+    // Note 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 must be used for key A
+    // for the MAD sector in NDEF records (sector 0)
+
+    // 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;
+
+    // Note 0xD3 0xF7 0xD3 0xF7 0xD3 0xF7 must be used for key A
+    // in NDEF records
+
+    // 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-bytes 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) {
+        DMSG("Page value out of range\n");
+        return 0;
+    }
+
+    /* 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 (HAL(writeCommand)(pn532_packetbuffer, 4)) {
+        return 0;
+    }
+
+    /* Read the response packet */
+    HAL(readResponse)(pn532_packetbuffer, sizeof(pn532_packetbuffer));
+
+    /* If byte 8 isn't 0x00 we probably have an error */
+    if (pn532_packetbuffer[0] == 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 bytes or 4  */
+        /* pages at a time ... we simply discard the last 12  */
+        /* bytes                                              */
+        memcpy (buffer, pn532_packetbuffer + 1, 4);
+    } else {
+        return 0;
+    }
+
+    // Return OK signal
+    return 1;
+}
+
+/**************************************************************************/
+/*!
+    @brief  Exchanges an APDU with the currently inlisted peer
+
+    @param  send            Pointer to data to send
+    @param  sendLength      Length of the data to send
+    @param  response        Pointer to response data
+    @param  responseLength  Pointer to the response data length
+*/
+/**************************************************************************/
+bool PN532::inDataExchange(uint8_t *send, uint8_t sendLength, uint8_t *response, uint8_t *responseLength)
+{
+    uint8_t i;
+
+    pn532_packetbuffer[0] = 0x40; // PN532_COMMAND_INDATAEXCHANGE;
+    pn532_packetbuffer[1] = inListedTag;
+
+    if (HAL(writeCommand)(pn532_packetbuffer, 2, send, sendLength)) {
+        return false;
+    }
+
+    int16_t status = HAL(readResponse)(response, *responseLength, 1000);
+    if (status < 0) {
+        return false;
+    }
+
+    if ((response[0] & 0x3f) != 0) {
+        DMSG("Status code indicates an error\n");
+        return false;
+    }
+
+    uint8_t length = status;
+    length -= 1;
+
+    if (length > *responseLength) {
+        length = *responseLength; // silent truncation...
+    }
+
+    for (uint8_t i = 0; i < length; i++) {
+        response[i] = response[i + 1];
+    }
+    *responseLength = length;
+
+    return true;
+}
+
+/**************************************************************************/
+/*!
+    @brief  'InLists' a passive target. PN532 acting as reader/initiator,
+            peer acting as card/responder.
+*/
+/**************************************************************************/
+bool PN532::inListPassiveTarget()
+{
+    pn532_packetbuffer[0] = PN532_COMMAND_INLISTPASSIVETARGET;
+    pn532_packetbuffer[1] = 1;
+    pn532_packetbuffer[2] = 0;
+
+    DMSG("inList passive target\n");
+
+    if (HAL(writeCommand)(pn532_packetbuffer, 3)) {
+        return false;
+    }
+
+    int16_t status = HAL(readResponse)(pn532_packetbuffer, sizeof(pn532_packetbuffer), 30000);
+    if (status < 0) {
+        return false;
+    }
+
+    if (pn532_packetbuffer[0] != 1) {
+        return false;
+    }
+
+    inListedTag = pn532_packetbuffer[1];
+
+    return true;
+}
+
+int8_t PN532::tgInitAsTarget(const uint8_t* command, const uint8_t len, const uint16_t timeout){
+  
+  int8_t status = HAL(writeCommand)(command, len);
+    if (status < 0) {
+        return -1;
+    }
+
+    status = HAL(readResponse)(pn532_packetbuffer, sizeof(pn532_packetbuffer), timeout);
+    if (status > 0) {
+        return 1;
+    } else if (PN532_TIMEOUT == status) {
+        return 0;
+    } else {
+        return -2;
+    }
+}
+
+/**
+ * Peer to Peer
+ */
+int8_t PN532::tgInitAsTarget(uint16_t timeout)
+{
+    const uint8_t command[] = {
+        PN532_COMMAND_TGINITASTARGET,
+        0,
+        0x00, 0x00,         //SENS_RES
+        0x00, 0x00, 0x00,   //NFCID1
+        0x40,               //SEL_RES
+
+        0x01, 0xFE, 0x0F, 0xBB, 0xBA, 0xA6, 0xC9, 0x89, // POL_RES
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0xFF, 0xFF,
+
+        0x01, 0xFE, 0x0F, 0xBB, 0xBA, 0xA6, 0xC9, 0x89, 0x00, 0x00, //NFCID3t: Change this to desired value
+
+        0x06, 0x46,  0x66, 0x6D, 0x01, 0x01, 0x10, 0x00// LLCP magic number and version parameter
+    };
+    return tgInitAsTarget(command, sizeof(command), timeout);
+}
+
+int16_t PN532::tgGetData(uint8_t *buf, uint8_t len)
+{
+    buf[0] = PN532_COMMAND_TGGETDATA;
+
+    if (HAL(writeCommand)(buf, 1)) {
+        return -1;
+    }
+
+    int16_t status = HAL(readResponse)(buf, len, 3000);
+    if (0 >= status) {
+        return status;
+    }
+
+    uint16_t length = status - 1;
+
+
+    if (buf[0] != 0) {
+        DMSG("status is not ok\n");
+        return -5;
+    }
+
+    for (uint8_t i = 0; i < length; i++) {
+        buf[i] = buf[i + 1];
+    }
+
+    return length;
+}
+
+bool PN532::tgSetData(const uint8_t *header, uint8_t hlen, const uint8_t *body, uint8_t blen)
+{
+    if (hlen > (sizeof(pn532_packetbuffer) - 1)) {
+        if ((body != 0) || (header == pn532_packetbuffer)) {
+            DMSG("tgSetData:buffer too small\n");
+            return false;
+        }
+
+        pn532_packetbuffer[0] = PN532_COMMAND_TGSETDATA;
+        if (HAL(writeCommand)(pn532_packetbuffer, 1, header, hlen)) {
+            return false;
+        }
+    } else {
+        for (int8_t i = hlen - 1; i >= 0; i--){
+            pn532_packetbuffer[i + 1] = header[i];
+        }
+        pn532_packetbuffer[0] = PN532_COMMAND_TGSETDATA;
+
+        if (HAL(writeCommand)(pn532_packetbuffer, hlen + 1, body, blen)) {
+            return false;
+        }
+    }
+
+    if (0 > HAL(readResponse)(pn532_packetbuffer, sizeof(pn532_packetbuffer), 3000)) {
+        return false;
+    }
+
+    if (0 != pn532_packetbuffer[0]) {
+        return false;
+    }
+
+    return true;
+}
+
+int16_t PN532::inRelease(const uint8_t relevantTarget){
+
+    pn532_packetbuffer[0] = PN532_COMMAND_INRELEASE;
+    pn532_packetbuffer[1] = relevantTarget;
+
+    if (HAL(writeCommand)(pn532_packetbuffer, 2)) {
+        return 0;
+    }
+
+    // read data packet
+    return HAL(readResponse)(pn532_packetbuffer, sizeof(pn532_packetbuffer));
+}
+
+
diff -r 000000000000 -r 88960f3eeb2c nfc/PN532.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nfc/PN532.h	Fri Dec 27 01:46:32 2013 +0000
@@ -0,0 +1,177 @@
+/**************************************************************************/
+/*!
+    @file     PN532.h
+    @author   Adafruit Industries & Seeed Studio
+    @license  BSD
+*/
+/**************************************************************************/
+
+#ifndef __PN532_H__
+#define __PN532_H__
+
+#include <stdint.h>
+#include "PN532Interface.h"
+
+// 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_RESPONSE_INDATAEXCHANGE       (0x41)
+#define PN532_RESPONSE_INLISTPASSIVETARGET  (0x4B)
+
+
+#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(PN532Interface &interface);
+
+    void begin(void);
+
+    // Generic PN532 functions
+    bool SAMConfig(void);
+    uint32_t getFirmwareVersion(void);
+    bool writeGPIO(uint8_t pinstate);
+    uint8_t readGPIO(void);
+    bool setPassiveActivationRetries(uint8_t maxRetries);
+
+    /**
+    * @brief    Init PN532 as a target
+    * @param    timeout max time to wait, 0 means no timeout
+    * @return   > 0     success
+    *           = 0     timeout
+    *           < 0     failed
+    */
+    int8_t tgInitAsTarget(uint16_t timeout = 0);
+    int8_t tgInitAsTarget(const uint8_t* command, const uint8_t len, const uint16_t timeout = 0);
+
+    int16_t tgGetData(uint8_t *buf, uint8_t len);
+    bool tgSetData(const uint8_t *header, uint8_t hlen, const uint8_t *body = 0, uint8_t blen = 0);
+
+    int16_t inRelease(const uint8_t relevantTarget = 0);
+
+    // ISO14443A functions
+    bool inListPassiveTarget();
+    bool readPassiveTargetID(uint8_t cardbaudrate, uint8_t *uid, uint8_t *uidLength, uint16_t timeout = 1000);
+    bool inDataExchange(uint8_t *send, uint8_t sendLength, uint8_t *response, uint8_t *responseLength);
+
+    // 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 uint8_t *data, const uint32_t numBytes);
+    static void PrintHexChar(const uint8_t *pbtData, const uint32_t numBytes);
+
+    uint8_t *getBuffer(uint8_t *len) {
+        *len = sizeof(pn532_packetbuffer) - 4;
+        return pn532_packetbuffer;
+    };
+
+private:
+    uint8_t _uid[7];  // ISO14443A uid
+    uint8_t _uidLen;  // uid len
+    uint8_t _key[6];  // Mifare Classic key
+    uint8_t inListedTag; // Tg number of inlisted tag.
+
+    uint8_t pn532_packetbuffer[64];
+
+    PN532Interface *_interface;
+};
+
+#endif
diff -r 000000000000 -r 88960f3eeb2c nfc/PN532Interface.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nfc/PN532Interface.h	Fri Dec 27 01:46:32 2013 +0000
@@ -0,0 +1,56 @@
+
+
+#ifndef __PN532_INTERFACE_H__
+#define __PN532_INTERFACE_H__
+
+#include <stdint.h>
+
+#define PN532_PREAMBLE                (0x00)
+#define PN532_STARTCODE1              (0x00)
+#define PN532_STARTCODE2              (0xFF)
+#define PN532_POSTAMBLE               (0x00)
+
+#define PN532_HOSTTOPN532             (0xD4)
+#define PN532_PN532TOHOST             (0xD5)
+
+#define PN532_ACK_WAIT_TIME           (10)  // ms, timeout of waiting for ACK
+
+#define PN532_INVALID_ACK             (-1)
+#define PN532_TIMEOUT                 (-2)
+#define PN532_INVALID_FRAME           (-3)
+#define PN532_NO_SPACE                (-4)
+
+#define REVERSE_BITS_ORDER(b)         b = (b & 0xF0) >> 4 | (b & 0x0F) << 4; \
+                                      b = (b & 0xCC) >> 2 | (b & 0x33) << 2; \
+                                      b = (b & 0xAA) >> 1 | (b & 0x55) << 1
+
+class PN532Interface
+{
+public:
+    virtual void begin() = 0;
+    virtual void wakeup() = 0;
+
+    /**
+    * @brief    write a command and check ack
+    * @param    header  packet header
+    * @param    hlen    length of header
+    * @param    body    packet body
+    * @param    blen    length of body
+    * @return   0       success
+    *           not 0   failed
+    */
+    virtual int8_t writeCommand(const uint8_t *header, uint8_t hlen, const uint8_t *body = 0, uint8_t blen = 0) = 0;
+
+    /**
+    * @brief    read the response of a command, strip prefix and suffix
+    * @param    buf     to contain the response data
+    * @param    len     lenght to read
+    * @param    timeout max time to wait, 0 means no timeout
+    * @return   >=0     length of response without prefix and suffix
+    *           <0      failed to read response
+    */
+    virtual int16_t readResponse(uint8_t buf[], uint8_t len, uint16_t timeout = 1000) = 0;
+};
+
+#endif
+
diff -r 000000000000 -r 88960f3eeb2c nfc/PN532_SPI.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nfc/PN532_SPI.cpp	Fri Dec 27 01:46:32 2013 +0000
@@ -0,0 +1,209 @@
+
+#include "PN532_SPI.h"
+#include "PN532_debug.h"
+
+#define STATUS_READ     2
+#define DATA_WRITE      1
+#define DATA_READ       3
+
+PN532_SPI::PN532_SPI(SPI &spi, PinName ss) : _ss(ss)
+{
+    command = 0;
+    _spi = &spi;
+    _spi->format(8, 0);
+    _spi->frequency(2000000);
+
+    _ss  = 1;
+}
+
+PN532_SPI::PN532_SPI(SPI *spi, PinName ss) : _ss(ss)
+{
+    command = 0;
+    _spi = spi;
+    _spi->format(8, 0);
+    _spi->frequency(2000000);
+
+    _ss  = 1;
+}
+
+void PN532_SPI::begin()
+{
+
+}
+
+void PN532_SPI::wakeup()
+{
+    _ss = 0;
+    wait_ms(2);
+    _ss = 1;
+}
+
+int8_t PN532_SPI::writeCommand(const uint8_t *header, uint8_t hlen, const uint8_t *body, uint8_t blen)
+{
+    command = header[0];
+    writeFrame(header, hlen, body, blen);
+
+    uint8_t timeout = PN532_ACK_WAIT_TIME;
+    while (!isReady()) {
+        wait_ms(1);
+        timeout--;
+        if (0 == timeout) {
+            DMSG("Time out when waiting for ACK\n");
+            return -2;
+        }
+    }
+    if (readAckFrame()) {
+        DMSG("Invalid ACK\n");
+        return PN532_INVALID_ACK;
+    }
+    return 0;
+}
+
+int16_t PN532_SPI::readResponse(uint8_t buf[], uint8_t len, uint16_t timeout)
+{
+    uint16_t time = 0;
+    while (!isReady()) {
+        wait_ms(1);
+        time++;
+        if (timeout > 0 && time > timeout) {
+            return PN532_TIMEOUT;
+        }
+    }
+
+    _ss = 0;
+    wait_ms(1);
+
+    int16_t result;
+    do {
+        write(DATA_READ);
+
+        if (0x00 != read()      ||       // PREAMBLE
+                0x00 != read()  ||       // STARTCODE1
+                0xFF != read()           // STARTCODE2
+           ) {
+
+            result = PN532_INVALID_FRAME;
+            break;
+        }
+
+        uint8_t length = read();
+        if (0 != (uint8_t)(length + read())) {   // checksum of length
+            result = PN532_INVALID_FRAME;
+            break;
+        }
+
+        uint8_t cmd = command + 1;               // response command
+        if (PN532_PN532TOHOST != read() || (cmd) != read()) {
+            result = PN532_INVALID_FRAME;
+            break;
+        }
+
+        DMSG("read:  ");
+        DMSG_HEX(cmd);
+
+        length -= 2;
+        if (length > len) {
+            for (uint8_t i = 0; i < length; i++) {
+                DMSG_HEX(read());                 // dump message
+            }
+            DMSG("\nNot enough space\n");
+            read();
+            read();
+            result = PN532_NO_SPACE;  // not enough space
+            break;
+        }
+
+        uint8_t sum = PN532_PN532TOHOST + cmd;
+        for (uint8_t i = 0; i < length; i++) {
+            buf[i] = read();
+            sum += buf[i];
+
+            DMSG_HEX(buf[i]);
+        }
+        DMSG("\n");
+
+        uint8_t checksum = read();
+        if (0 != (uint8_t)(sum + checksum)) {
+            DMSG("checksum is not ok\n");
+            result = PN532_INVALID_FRAME;
+            break;
+        }
+        read();         // POSTAMBLE
+
+        result = length;
+    } while (0);
+
+    _ss = 1;
+
+    return result;
+}
+
+bool PN532_SPI::isReady()
+{
+    _ss = 0;
+
+    write(STATUS_READ);
+    uint8_t status = read() & 1;
+    _ss = 1;
+    return status;
+}
+
+void PN532_SPI::writeFrame(const uint8_t *header, uint8_t hlen, const uint8_t *body, uint8_t blen)
+{
+    _ss = 0;
+    wait_ms(2);               // wake up PN532
+
+    write(DATA_WRITE);
+    write(PN532_PREAMBLE);
+    write(PN532_STARTCODE1);
+    write(PN532_STARTCODE2);
+
+    uint8_t length = hlen + blen + 1;   // length of data field: TFI + DATA
+    write(length);
+    write(~length + 1);         // checksum of length
+
+    write(PN532_HOSTTOPN532);
+    uint8_t sum = PN532_HOSTTOPN532;    // sum of TFI + DATA
+
+    DMSG("write: ");
+
+    for (uint8_t i = 0; i < hlen; i++) {
+        write(header[i]);
+        sum += header[i];
+
+        DMSG_HEX(header[i]);
+    }
+    for (uint8_t i = 0; i < blen; i++) {
+        write(body[i]);
+        sum += body[i];
+        
+        DMSG_HEX(header[i]);
+    }
+
+    uint8_t checksum = ~sum + 1;        // checksum of TFI + DATA
+    write(checksum);
+    write(PN532_POSTAMBLE);
+
+    _ss = 1;
+
+    DMSG("\n");
+}
+
+int8_t PN532_SPI::readAckFrame()
+{
+    const uint8_t PN532_ACK[] = {0, 0, 0xFF, 0, 0xFF, 0};
+
+    uint8_t ackBuf[sizeof(PN532_ACK)];
+
+    _ss = 0;
+    wait_ms(1);
+    write(DATA_READ);
+
+    for (uint8_t i = 0; i < sizeof(PN532_ACK); i++) {
+        ackBuf[i] = read();
+    }
+
+    _ss = 1;
+
+    return memcmp(ackBuf, PN532_ACK, sizeof(PN532_ACK));
+}
diff -r 000000000000 -r 88960f3eeb2c nfc/PN532_SPI.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nfc/PN532_SPI.h	Fri Dec 27 01:46:32 2013 +0000
@@ -0,0 +1,39 @@
+
+#ifndef __PN532_SPI_H__
+#define __PN532_SPI_H__
+
+#include "mbed.h"
+#include "PN532Interface.h"
+
+class PN532_SPI : public PN532Interface
+{
+public:
+    PN532_SPI(SPI &spi, PinName ss);
+    PN532_SPI(SPI *spi, PinName ss);
+
+    virtual void begin();
+    virtual void wakeup();
+    virtual int8_t writeCommand(const uint8_t *header, uint8_t hlen, const uint8_t *body, uint8_t blen);
+    virtual int16_t readResponse(uint8_t buf[], uint8_t len, uint16_t timeout);
+
+private:
+    SPI        *_spi;
+    DigitalOut  _ss;
+    uint8_t     command;
+
+    bool isReady();
+    void writeFrame(const uint8_t *header, uint8_t hlen, const uint8_t *body, uint8_t blen);
+    int8_t readAckFrame();
+
+    inline void write(uint8_t data) {
+        REVERSE_BITS_ORDER(data);
+        _spi->write(data);
+    }
+    inline uint8_t read() {
+        uint8_t data =  _spi->write(0);
+        REVERSE_BITS_ORDER(data);
+        return data;
+    }
+};
+
+#endif
diff -r 000000000000 -r 88960f3eeb2c nfc/PN532_debug.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nfc/PN532_debug.h	Fri Dec 27 01:46:32 2013 +0000
@@ -0,0 +1,24 @@
+#ifndef __DEBUG_H__
+#define __DEBUG_H__
+
+//#define DEBUG
+
+#ifdef DEBUG
+
+#include <stdio.h>
+
+#define DMSG(args...)   printf(args)
+#define DMSG_STR(str)   printf("%s\n", str)
+#define DMSG_INT(num)   printf("%d\n", num)
+#define DMSG_HEX(num)   printf("%2X ", num)
+
+#else
+
+#define DMSG(args...)
+#define DMSG_STR(str)
+#define DMSG_INT(num)
+#define DMSG_HEX(num)
+
+#endif  // DEBUG
+
+#endif  // __DEBUG_H__
diff -r 000000000000 -r 88960f3eeb2c nfc/emulatetag.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nfc/emulatetag.cpp	Fri Dec 27 01:46:32 2013 +0000
@@ -0,0 +1,255 @@
+/**************************************************************************/
+/*!
+    @file     emulatetag.cpp
+    @author   Armin Wieser
+    @license  BSD
+*/
+/**************************************************************************/
+
+#include "emulatetag.h"
+#include "PN532_debug.h"
+
+#include <string.h>
+
+#define MAX_TGREAD
+
+
+// Command APDU
+#define C_APDU_CLA   0
+#define C_APDU_INS   1 // instruction
+#define C_APDU_P1    2 // parameter 1
+#define C_APDU_P2    3 // parameter 2
+#define C_APDU_LC    4 // length command
+#define C_APDU_DATA  5 // data
+
+#define C_APDU_P1_SELECT_BY_ID   0x00
+#define C_APDU_P1_SELECT_BY_NAME 0x04
+
+// Response APDU
+#define R_APDU_SW1_COMMAND_COMPLETE 0x90 
+#define R_APDU_SW2_COMMAND_COMPLETE 0x00 
+
+#define R_APDU_SW1_NDEF_TAG_NOT_FOUND 0x6a
+#define R_APDU_SW2_NDEF_TAG_NOT_FOUND 0x82
+
+#define R_APDU_SW1_FUNCTION_NOT_SUPPORTED 0x6A
+#define R_APDU_SW2_FUNCTION_NOT_SUPPORTED 0x81
+
+#define R_APDU_SW1_MEMORY_FAILURE 0x65
+#define R_APDU_SW2_MEMORY_FAILURE 0x81
+
+#define R_APDU_SW1_END_OF_FILE_BEFORE_REACHED_LE_BYTES 0x62
+#define R_APDU_SW2_END_OF_FILE_BEFORE_REACHED_LE_BYTES 0x82
+
+// ISO7816-4 commands
+#define ISO7816_SELECT_FILE 0xA4
+#define ISO7816_READ_BINARY 0xB0
+#define ISO7816_UPDATE_BINARY 0xD6
+
+typedef enum { NONE, CC, NDEF } tag_file;   // CC ... Compatibility Container
+
+bool EmulateTag::init(){
+  pn532.begin();
+  return pn532.SAMConfig();
+}
+
+void EmulateTag::setNdefFile(const uint8_t* ndef, const int16_t ndefLength){
+  if(ndefLength >  (NDEF_MAX_LENGTH -2)){
+	DMSG("ndef file too large (> NDEF_MAX_LENGHT -2) - aborting");
+	return;
+  }
+
+  ndef_file[0] = ndefLength >> 8;
+  ndef_file[1] = ndefLength & 0xFF;
+  memcpy(ndef_file+2, ndef, ndefLength);
+}
+
+void EmulateTag::setUid(uint8_t* uid){
+  uidPtr = uid;
+}
+
+bool EmulateTag::emulate(const uint16_t tgInitAsTargetTimeout){
+
+  uint8_t command[] = {
+        PN532_COMMAND_TGINITASTARGET,
+        5,                  // MODE: PICC only, Passive only
+
+        0x04, 0x00,         // SENS_RES
+        0x00, 0x00, 0x00,   // NFCID1
+        0x20,               // SEL_RES
+
+        0,0,0,0,0,0,0,0,
+        0,0,0,0,0,0,0,0,   // FeliCaParams
+        0,0,
+
+        0,0,0,0,0,0,0,0,0,0, // NFCID3t
+
+        0, // length of general bytes
+        0  // length of historical bytes
+  };
+
+  if(uidPtr != 0){  // if uid is set copy 3 bytes to nfcid1
+    memcpy(command + 4, uidPtr, 3);
+  }
+
+  if(1 != pn532.tgInitAsTarget(command,sizeof(command), tgInitAsTargetTimeout)){
+    DMSG("tgInitAsTarget failed or timed out!");
+    return false;
+  }
+
+  uint8_t compatibility_container[] = {
+    0, 0x0F,
+    0x20,
+    0, 0x54,
+    0, 0xFF,
+    0x04,       // T
+    0x06,       // L
+    0xE1, 0x04, // File identifier
+    ((NDEF_MAX_LENGTH & 0xFF00) >> 8), (NDEF_MAX_LENGTH & 0xFF), // maximum NDEF file size
+    0x00,       // read access 0x0 = granted
+    0x00        // write access 0x0 = granted | 0xFF = deny
+  };
+
+  if(tagWriteable == false){
+    compatibility_container[14] = 0xFF;
+  }
+
+  tagWrittenByInitiator = false;
+
+  uint8_t rwbuf[128];
+  uint8_t sendlen;
+  int16_t status;
+  tag_file currentFile = NONE;
+  uint16_t cc_size = sizeof(compatibility_container);
+  bool runLoop = true;
+
+  while(runLoop){
+    status = pn532.tgGetData(rwbuf, sizeof(rwbuf));
+    if(status < 0){
+      DMSG("tgGetData failed!\n");
+      pn532.inRelease();
+      return true;
+    }
+
+    uint8_t p1 = rwbuf[C_APDU_P1];
+    uint8_t p2 = rwbuf[C_APDU_P2];
+    uint8_t lc = rwbuf[C_APDU_LC];
+    uint16_t p1p2_length = ((int16_t) p1 << 8) + p2;
+
+    switch(rwbuf[C_APDU_INS]){
+    case ISO7816_SELECT_FILE:
+      switch(p1){
+      case C_APDU_P1_SELECT_BY_ID:
+	if(p2 != 0x0c){
+	  DMSG("C_APDU_P2 != 0x0c\n");
+	  setResponse(COMMAND_COMPLETE, rwbuf, &sendlen);
+	} else if(lc == 2 && rwbuf[C_APDU_DATA] == 0xE1 && (rwbuf[C_APDU_DATA+1] == 0x03 || rwbuf[C_APDU_DATA+1] == 0x04)){
+	  setResponse(COMMAND_COMPLETE, rwbuf, &sendlen);
+	  if(rwbuf[C_APDU_DATA+1] == 0x03){
+	    currentFile = CC;
+	  } else if(rwbuf[C_APDU_DATA+1] == 0x04){
+	    currentFile = NDEF;
+	  }
+	} else {
+	  setResponse(TAG_NOT_FOUND, rwbuf, &sendlen);
+	}
+	break;
+      case C_APDU_P1_SELECT_BY_NAME: 
+        const uint8_t ndef_tag_application_name_v2[] = {0, 0x7, 0xD2, 0x76, 0x00, 0x00, 0x85, 0x01, 0x01 };
+	if(0 == memcmp(ndef_tag_application_name_v2, rwbuf + C_APDU_P2, sizeof(ndef_tag_application_name_v2))){
+	  setResponse(COMMAND_COMPLETE, rwbuf, &sendlen);
+	} else{
+	  DMSG("function not supported\n");
+	  setResponse(FUNCTION_NOT_SUPPORTED, rwbuf, &sendlen);
+	} 
+	break;
+      }
+      break;
+    case ISO7816_READ_BINARY:
+      switch(currentFile){
+      case NONE:
+	setResponse(TAG_NOT_FOUND, rwbuf, &sendlen);
+	break;
+      case CC:
+	if( p1p2_length > NDEF_MAX_LENGTH){
+	  setResponse(END_OF_FILE_BEFORE_REACHED_LE_BYTES, rwbuf, &sendlen);
+	}else {
+	  memcpy(rwbuf,compatibility_container + p1p2_length, lc);
+	  setResponse(COMMAND_COMPLETE, rwbuf + lc, &sendlen, lc);
+	}
+	break;
+      case NDEF:
+	if( p1p2_length > NDEF_MAX_LENGTH){
+	  setResponse(END_OF_FILE_BEFORE_REACHED_LE_BYTES, rwbuf, &sendlen);
+	}else {
+	  memcpy(rwbuf, ndef_file + p1p2_length, lc);
+	  setResponse(COMMAND_COMPLETE, rwbuf + lc, &sendlen, lc);
+	}
+	break;
+      }
+      break;    
+    case ISO7816_UPDATE_BINARY:
+      if(!tagWriteable){
+	  setResponse(FUNCTION_NOT_SUPPORTED, rwbuf, &sendlen);
+      } else{      
+	if( p1p2_length > NDEF_MAX_LENGTH){
+	  setResponse(MEMORY_FAILURE, rwbuf, &sendlen);
+	}
+	else{
+	  memcpy(ndef_file + p1p2_length, rwbuf + C_APDU_DATA, lc);
+	  setResponse(COMMAND_COMPLETE, rwbuf, &sendlen);
+	  tagWrittenByInitiator = true;
+      
+      uint16_t ndef_length = (ndef_file[0] << 8) + ndef_file[1];
+      if ((ndef_length > 0) && (updateNdefCallback != 0)) {
+        updateNdefCallback(ndef_file + 2, ndef_length);
+      }
+	}
+      }
+      break;
+    default:
+      DMSG("Command not supported!");
+      DMSG_HEX(rwbuf[C_APDU_INS]);
+      DMSG("\n");
+      setResponse(FUNCTION_NOT_SUPPORTED, rwbuf, &sendlen);
+    }
+    status = pn532.tgSetData(rwbuf, sendlen);
+    if(status < 0){
+      DMSG("tgSetData failed\n!");
+      pn532.inRelease();
+      return true;
+    }
+  }
+  pn532.inRelease();
+  return true;
+}
+
+void EmulateTag::setResponse(responseCommand cmd, uint8_t* buf, uint8_t* sendlen, uint8_t sendlenOffset){
+  switch(cmd){
+  case COMMAND_COMPLETE:
+    buf[0] = R_APDU_SW1_COMMAND_COMPLETE;
+    buf[1] = R_APDU_SW2_COMMAND_COMPLETE;
+    *sendlen = 2 + sendlenOffset;
+    break;
+  case TAG_NOT_FOUND:
+    buf[0] = R_APDU_SW1_NDEF_TAG_NOT_FOUND;
+    buf[1] = R_APDU_SW2_NDEF_TAG_NOT_FOUND;
+    *sendlen = 2;    
+    break;
+  case FUNCTION_NOT_SUPPORTED:
+    buf[0] = R_APDU_SW1_FUNCTION_NOT_SUPPORTED;
+    buf[1] = R_APDU_SW2_FUNCTION_NOT_SUPPORTED;
+    *sendlen = 2; 
+    break;
+  case MEMORY_FAILURE:
+    buf[0] = R_APDU_SW1_MEMORY_FAILURE;
+    buf[1] = R_APDU_SW2_MEMORY_FAILURE;
+    *sendlen = 2;
+    break;
+  case END_OF_FILE_BEFORE_REACHED_LE_BYTES:
+    buf[0] = R_APDU_SW1_END_OF_FILE_BEFORE_REACHED_LE_BYTES;
+    buf[1] = R_APDU_SW2_END_OF_FILE_BEFORE_REACHED_LE_BYTES;
+    *sendlen= 2;
+    break;
+  }
+}
diff -r 000000000000 -r 88960f3eeb2c nfc/emulatetag.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nfc/emulatetag.h	Fri Dec 27 01:46:32 2013 +0000
@@ -0,0 +1,71 @@
+/**************************************************************************/
+/*!
+    @file     emulatetag.h
+    @author   Armin Wieser
+    @license  BSD
+
+    Implemented using NFC forum documents & library of libnfc
+*/
+/**************************************************************************/
+
+#ifndef __EMULATETAG_H__
+#define __EMULATETAG_H__
+
+#include "PN532.h"
+
+#define NDEF_MAX_LENGTH 128  // altough ndef can handle up to 0xfffe in size, arduino cannot.
+typedef enum {COMMAND_COMPLETE, TAG_NOT_FOUND, FUNCTION_NOT_SUPPORTED, MEMORY_FAILURE, END_OF_FILE_BEFORE_REACHED_LE_BYTES} responseCommand;
+
+class EmulateTag{
+
+public:
+EmulateTag(PN532Interface &interface) : pn532(interface), uidPtr(0), tagWrittenByInitiator(false), tagWriteable(true), updateNdefCallback(0) { }
+  
+  bool init();
+
+  bool emulate(const uint16_t tgInitAsTargetTimeout = 0);
+
+  /*
+   * @param uid pointer to byte array of length 3 (uid is 4 bytes - first byte is fixed) or zero for uid 
+   */
+  void setUid(uint8_t* uid = 0);
+
+  void setNdefFile(const uint8_t* ndef, const int16_t ndefLength);
+
+  void getContent(uint8_t** buf, uint16_t* length){
+    *buf = ndef_file + 2; // first 2 bytes = length
+    *length = (ndef_file[0] << 8) + ndef_file[1];
+  }
+
+  bool writeOccured(){
+    return tagWrittenByInitiator;
+  }
+
+  void setTagWriteable(bool setWriteable){
+    tagWriteable = setWriteable;
+  }
+
+  uint8_t* getNdefFilePtr(){
+    return ndef_file;
+  }
+
+  uint8_t getNdefMaxLength(){
+    return NDEF_MAX_LENGTH;
+  }
+
+  void attach(void (*func)(uint8_t *buf, uint16_t length)) {
+    updateNdefCallback = func;
+  };
+
+private:
+  PN532 pn532;
+  uint8_t ndef_file[NDEF_MAX_LENGTH];
+  uint8_t* uidPtr;
+  bool tagWrittenByInitiator;
+  bool tagWriteable;
+  void (*updateNdefCallback)(uint8_t *ndef, uint16_t length);
+
+  void setResponse(responseCommand cmd, uint8_t* buf, uint8_t* sendlen, uint8_t sendlenOffset = 0);
+};
+
+#endif
diff -r 000000000000 -r 88960f3eeb2c nfc/llcp.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nfc/llcp.cpp	Fri Dec 27 01:46:32 2013 +0000
@@ -0,0 +1,309 @@
+
+#include "llcp.h"
+#include "PN532_debug.h"
+
+// LLCP PDU Type Values
+#define PDU_SYMM    0x00
+#define PDU_PAX     0x01
+#define PDU_CONNECT 0x04
+#define PDU_DISC    0x05
+#define PDU_CC      0x06
+#define PDU_DM      0x07
+#define PDU_I       0x0c
+#define PDU_RR      0x0d
+
+uint8_t LLCP::SYMM_PDU[2] = {0, 0};
+
+inline uint8_t getPType(const uint8_t *buf)
+{
+    return ((buf[0] & 0x3) << 2) + (buf[1] >> 6);
+}
+
+inline uint8_t getSSAP(const uint8_t *buf)
+{
+    return  buf[1] & 0x3f;
+}
+
+inline uint8_t getDSAP(const uint8_t *buf)
+{
+    return buf[0] >> 2;
+}
+
+int8_t LLCP::activate(uint16_t timeout)
+{
+    return link.activateAsTarget(timeout);
+}
+
+int8_t LLCP::waitForConnection(uint16_t timeout)
+{
+    uint8_t type;
+
+    mode = 1;
+    ns = 0;
+    nr = 0;
+
+    // Get CONNECT PDU
+    DMSG("wait for a CONNECT PDU\n");
+    do {
+        if (2 > link.read(headerBuf, headerBufLen)) {
+            return -1;
+        }
+
+        type = getPType(headerBuf);
+        if (PDU_CONNECT == type) {
+            break;
+        } else if (PDU_SYMM == type) {
+            if (!link.write(SYMM_PDU, sizeof(SYMM_PDU))) {
+                return -2;
+            }
+        } else {
+            return -3;
+        }
+
+    } while (1);
+
+    // Put CC PDU
+    DMSG("put a CC(Connection Complete) PDU to response the CONNECT PDU\n");
+    ssap = getDSAP(headerBuf);
+    dsap = getSSAP(headerBuf);
+    headerBuf[0] = (dsap << 2) + ((PDU_CC >> 2) & 0x3);
+    headerBuf[1] = ((PDU_CC & 0x3) << 6) + ssap;
+    if (!link.write(headerBuf, 2)) {
+        return -2;
+    }
+
+    return 1;
+}
+
+int8_t LLCP::waitForDisconnection(uint16_t timeout)
+{
+    uint8_t type;
+
+    // Get DISC PDU
+    DMSG("wait for a DISC PDU\n");
+    do {
+        if (2 > link.read(headerBuf, headerBufLen)) {
+            return -1;
+        }
+
+        type = getPType(headerBuf);
+        if (PDU_DISC == type) {
+            break;
+        } else if (PDU_SYMM == type) {
+            if (!link.write(SYMM_PDU, sizeof(SYMM_PDU))) {
+                return -2;
+            }
+        } else {
+            return -3;
+        }
+
+    } while (1);
+
+    // Put DM PDU
+    DMSG("put a DM(Disconnect Mode) PDU to response the DISC PDU\n");
+    // ssap = getDSAP(headerBuf);
+    // dsap = getSSAP(headerBuf);
+    headerBuf[0] = (dsap << 2) + (PDU_DM >> 2);
+    headerBuf[1] = ((PDU_DM & 0x3) << 6) + ssap;
+    if (!link.write(headerBuf, 2)) {
+        return -2;
+    }
+
+    return 1;
+}
+
+int8_t LLCP::connect(uint16_t timeout)
+{
+    uint8_t type;
+
+    mode = 0;
+    dsap = LLCP_DEFAULT_DSAP;
+    ssap = LLCP_DEFAULT_SSAP;
+    ns = 0;
+    nr = 0;
+
+    // try to get a SYMM PDU
+    if (2 > link.read(headerBuf, headerBufLen)) {
+        return -1;
+    }
+    type = getPType(headerBuf);
+    if (PDU_SYMM != type) {
+        return -1;
+    }
+
+    // put a CONNECT PDU
+    headerBuf[0] = (LLCP_DEFAULT_DSAP << 2) + (PDU_CONNECT >> 2);
+    headerBuf[1] = ((PDU_CONNECT & 0x03) << 6) + LLCP_DEFAULT_SSAP;
+    uint8_t body[] = "  urn:nfc:sn:snep";
+    body[0] = 0x06;
+    body[1] = sizeof(body) - 2 - 1;
+    if (!link.write(headerBuf, 2, body, sizeof(body) - 1)) {
+        return -2;
+    }
+
+    // wait for a CC PDU
+    DMSG("wait for a CC PDU\n");
+    do {
+        if (2 > link.read(headerBuf, headerBufLen)) {
+            return -1;
+        }
+
+        type = getPType(headerBuf);
+        if (PDU_CC == type) {
+            break;
+        } else if (PDU_SYMM == type) {
+            if (!link.write(SYMM_PDU, sizeof(SYMM_PDU))) {
+                return -2;
+            }
+        } else {
+            return -3;
+        }
+
+    } while (1);
+
+    return 1;
+}
+
+int8_t LLCP::disconnect(uint16_t timeout)
+{
+    uint8_t type;
+
+    // try to get a SYMM PDU
+    if (2 > link.read(headerBuf, headerBufLen)) {
+        return -1;
+    }
+    type = getPType(headerBuf);
+    if (PDU_SYMM != type) {
+        return -1;
+    }
+
+    // put a DISC PDU
+    headerBuf[0] = (LLCP_DEFAULT_DSAP << 2) + (PDU_DISC >> 2);
+    headerBuf[1] = ((PDU_DISC & 0x03) << 6) + LLCP_DEFAULT_SSAP;
+    if (!link.write(headerBuf, 2)) {
+        return -2;
+    }
+
+    // wait for a DM PDU
+    DMSG("wait for a DM PDU\n");
+    do {
+        if (2 > link.read(headerBuf, headerBufLen)) {
+            return -1;
+        }
+
+        type = getPType(headerBuf);
+        if (PDU_CC == type) {
+            break;
+        } else if (PDU_DM == type) {
+            if (!link.write(SYMM_PDU, sizeof(SYMM_PDU))) {
+                return -2;
+            }
+        } else {
+            return -3;
+        }
+
+    } while (1);
+
+    return 1;
+}
+
+bool LLCP::write(const uint8_t *header, uint8_t hlen, const uint8_t *body, uint8_t blen)
+{
+    uint8_t type;
+    uint8_t buf[3];
+
+    if (mode) {
+        // Get a SYMM PDU
+        if (2 != link.read(buf, sizeof(buf))) {
+            return false;
+        }
+    }
+
+    if (headerBufLen < (hlen + 3)) {
+        return false;
+    }
+
+    for (int8_t i = hlen - 1; i >= 0; i--) {
+        headerBuf[i + 3] = header[i];
+    }
+
+    headerBuf[0] = (dsap << 2) + (PDU_I >> 2);
+    headerBuf[1] = ((PDU_I & 0x3) << 6) + ssap;
+    headerBuf[2] = (ns << 4) + nr;
+    if (!link.write(headerBuf, 3 + hlen, body, blen)) {
+        return false;
+    }
+
+    ns++;
+
+    // Get a RR PDU
+    int16_t status;
+    do {
+        status = link.read(headerBuf, headerBufLen);
+        if (2 > status) {
+            return false;
+        }
+
+        type = getPType(headerBuf);
+        if (PDU_RR == type) {
+            break;
+        } else if (PDU_SYMM == type) {
+            if (!link.write(SYMM_PDU, sizeof(SYMM_PDU))) {
+                return false;
+            }
+        } else {
+            return false;
+        }
+    } while (1);
+
+    if (!link.write(SYMM_PDU, sizeof(SYMM_PDU))) {
+        return false;
+    }
+
+    return true;
+}
+
+int16_t LLCP::read(uint8_t *buf, uint8_t length)
+{
+    uint8_t type;
+    uint16_t status;
+
+    // Get INFO PDU
+    do {
+        status = link.read(buf, length);
+        if (2 > status) {
+            return -1;
+        }
+
+        type = getPType(buf);
+        if (PDU_I == type) {
+            break;
+        } else if (PDU_SYMM == type) {
+            if (!link.write(SYMM_PDU, sizeof(SYMM_PDU))) {
+                return -2;
+            }
+        } else {
+            return -3;
+        }
+
+    } while (1);
+
+    uint8_t len = status - 3;
+    ssap = getDSAP(buf);
+    dsap = getSSAP(buf);
+
+    headerBuf[0] = (dsap << 2) + (PDU_RR >> 2);
+    headerBuf[1] = ((PDU_RR & 0x3) << 6) + ssap;
+    headerBuf[2] = (buf[2] >> 4) + 1;
+    if (!link.write(headerBuf, 3)) {
+        return -2;
+    }
+
+    for (uint8_t i = 0; i < len; i++) {
+        buf[i] = buf[i + 3];
+    }
+
+    nr++;
+
+    return len;
+}
diff -r 000000000000 -r 88960f3eeb2c nfc/llcp.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nfc/llcp.h	Fri Dec 27 01:46:32 2013 +0000
@@ -0,0 +1,75 @@
+
+#ifndef __LLCP_H__
+#define __LLCP_H__
+
+#include "mac_link.h"
+
+#define LLCP_DEFAULT_TIMEOUT  20000
+#define LLCP_DEFAULT_DSAP     0x04
+#define LLCP_DEFAULT_SSAP     0x20
+
+class LLCP {
+public:
+	LLCP(PN532Interface &interface) : link(interface) {
+        headerBuf = link.getHeaderBuffer(&headerBufLen);
+        ns = 0;
+        nr = 0;
+	};
+
+	/**
+    * @brief    Actiave PN532 as a target
+    * @param    timeout max time to wait, 0 means no timeout
+    * @return   > 0     success
+    *           = 0     timeout
+    *           < 0     failed
+    */
+	int8_t activate(uint16_t timeout = 0);
+
+    int8_t waitForConnection(uint16_t timeout = LLCP_DEFAULT_TIMEOUT);
+
+    int8_t waitForDisconnection(uint16_t timeout = LLCP_DEFAULT_TIMEOUT);
+
+    int8_t connect(uint16_t timeout = LLCP_DEFAULT_TIMEOUT);
+
+    int8_t disconnect(uint16_t timeout = LLCP_DEFAULT_TIMEOUT);
+
+	/**
+    * @brief    write a packet, the packet should be less than (255 - 2) bytes
+    * @param    header  packet header
+    * @param    hlen    length of header
+    * @param    body    packet body
+    * @param    blen    length of body
+    * @return   true    success
+    *           false   failed
+    */
+    bool write(const uint8_t *header, uint8_t hlen, const uint8_t *body = 0, uint8_t blen = 0);
+
+    /**
+    * @brief    read a  packet, the packet will be less than (255 - 2) bytes
+    * @param    buf     the buffer to contain the packet
+    * @param    len     lenght of the buffer
+    * @return   >=0     length of the packet 
+    *           <0      failed
+    */
+    int16_t read(uint8_t *buf, uint8_t len);
+
+    uint8_t *getHeaderBuffer(uint8_t *len) {
+        uint8_t *buf = link.getHeaderBuffer(len);
+        len -= 3;       // I PDU header has 3 bytes
+        return buf;
+    };
+
+private:
+	MACLink link;
+    uint8_t mode;
+	uint8_t ssap;
+	uint8_t dsap;
+    uint8_t *headerBuf;
+    uint8_t headerBufLen;
+    uint8_t ns;         // Number of I PDU Sent
+    uint8_t nr;         // Number of I PDU Received
+
+	static uint8_t SYMM_PDU[2];
+};
+
+#endif // __LLCP_H__
diff -r 000000000000 -r 88960f3eeb2c nfc/mac_link.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nfc/mac_link.cpp	Fri Dec 27 01:46:32 2013 +0000
@@ -0,0 +1,20 @@
+
+#include "mac_link.h"
+#include "PN532_debug.h"
+
+int8_t MACLink::activateAsTarget(uint16_t timeout)
+{
+	pn532.begin();
+	pn532.SAMConfig();
+    return pn532.tgInitAsTarget(timeout);
+}
+
+bool MACLink::write(const uint8_t *header, uint8_t hlen, const uint8_t *body, uint8_t blen)
+{
+    return pn532.tgSetData(header, hlen, body, blen);
+}
+
+int16_t MACLink::read(uint8_t *buf, uint8_t len)
+{
+    return pn532.tgGetData(buf, len);
+}
diff -r 000000000000 -r 88960f3eeb2c nfc/mac_link.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nfc/mac_link.h	Fri Dec 27 01:46:32 2013 +0000
@@ -0,0 +1,51 @@
+
+
+#ifndef __MAC_LINK_H__
+#define __MAC_LINK_H__
+
+#include "PN532.h"
+
+class MACLink {
+public:
+    MACLink(PN532Interface &interface) : pn532(interface) {
+
+    };
+    
+    /**
+    * @brief    Activate PN532 as a target
+    * @param    timeout max time to wait, 0 means no timeout
+    * @return   > 0     success
+    *           = 0     timeout
+    *           < 0     failed
+    */
+    int8_t activateAsTarget(uint16_t timeout = 0);
+
+    /**
+    * @brief    write a PDU packet, the packet should be less than (255 - 2) bytes
+    * @param    header  packet header
+    * @param    hlen    length of header
+    * @param 	body	packet body
+    * @param 	blen	length of body
+    * @return   true    success
+    *           false   failed
+    */
+    bool write(const uint8_t *header, uint8_t hlen, const uint8_t *body = 0, uint8_t blen = 0);
+
+    /**
+    * @brief    read a PDU packet, the packet will be less than (255 - 2) bytes
+    * @param    buf     the buffer to contain the PDU packet
+    * @param    len     lenght of the buffer
+    * @return   >=0     length of the PDU packet 
+    *           <0      failed
+    */
+    int16_t read(uint8_t *buf, uint8_t len);
+
+    uint8_t *getHeaderBuffer(uint8_t *len) {
+        return pn532.getBuffer(len);
+    };
+    
+private:
+    PN532 pn532;
+};
+
+#endif // __MAC_LINK_H__
diff -r 000000000000 -r 88960f3eeb2c nfc/snep.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nfc/snep.cpp	Fri Dec 27 01:46:32 2013 +0000
@@ -0,0 +1,106 @@
+
+#include "snep.h"
+#include "PN532_debug.h"
+
+int8_t SNEP::write(const uint8_t *buf, uint8_t len, uint16_t timeout)
+{
+	if (0 >= llcp.activate(timeout)) {
+		DMSG("failed to activate PN532 as a target\n");
+		return -1;
+	}
+
+	if (0 >= llcp.connect(timeout)) {
+		DMSG("failed to set up a connection\n");
+		return -2;
+	}
+
+	// response a success SNEP message
+	headerBuf[0] = SNEP_DEFAULT_VERSION;
+	headerBuf[1] = SNEP_REQUEST_PUT;
+	headerBuf[2] = 0;
+	headerBuf[3] = 0;
+	headerBuf[4] = 0;
+	headerBuf[5] = len;
+	if (0 >= llcp.write(headerBuf, 6, buf, len)) {
+		return -3;
+	}
+
+	uint8_t rbuf[16];
+	if (6 > llcp.read(rbuf, sizeof(rbuf))) {
+		return -4;
+	}
+
+	// check SNEP version
+	if (SNEP_DEFAULT_VERSION != rbuf[0]) {
+		DMSG("The received SNEP message's major version is different\n");
+		// To-do: send Unsupported Version response
+		return -4;
+	}
+
+	// expect a put request
+	if (SNEP_RESPONSE_SUCCESS != rbuf[1]) {
+		DMSG("Expect a success response\n");
+		return -4;
+	}
+
+	llcp.disconnect(timeout);
+
+	return 1;
+}
+
+int16_t SNEP::read(uint8_t *buf, uint8_t len, uint16_t timeout)
+{
+	if (0 >= llcp.activate(timeout)) {
+		DMSG("failed to activate PN532 as a target\n");
+		return -1;
+	}
+
+	if (0 >= llcp.waitForConnection(timeout)) {
+		DMSG("failed to set up a connection\n");
+		return -2;
+	}
+
+	uint16_t status = llcp.read(buf, len);
+	if (6 > status) {
+		return -3;
+	}
+
+
+	// check SNEP version
+	if (SNEP_DEFAULT_VERSION != buf[0]) {
+		DMSG("The received SNEP message's major version is different\n");
+		// To-do: send Unsupported Version response
+		return -4;
+	}
+
+	// expect a put request
+	if (SNEP_REQUEST_PUT != buf[1]) {
+		DMSG("Expect a put request\n");
+		return -4;
+	}
+
+	// check message's length
+	uint32_t length = (buf[2] << 24) + (buf[3] << 16) + (buf[4] << 8) + buf[5];
+	// length should not be more than 244 (header + body < 255, header = 6 + 3 + 2)
+	if (length > (status - 6)) {
+		DMSG("The SNEP message is too large: "); 
+        DMSG_INT(length);
+        DMSG_INT(status - 6);
+		DMSG("\n");
+		return -4;
+	}
+	for (uint8_t i = 0; i < length; i++) {
+		buf[i] = buf[i + 6];
+	}
+
+	// response a success SNEP message
+	headerBuf[0] = SNEP_DEFAULT_VERSION;
+	headerBuf[1] = SNEP_RESPONSE_SUCCESS;
+	headerBuf[2] = 0;
+	headerBuf[3] = 0;
+	headerBuf[4] = 0;
+	headerBuf[5] = 0;
+	llcp.write(headerBuf, 6);
+
+	return length;
+}
diff -r 000000000000 -r 88960f3eeb2c nfc/snep.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nfc/snep.h	Fri Dec 27 01:46:32 2013 +0000
@@ -0,0 +1,49 @@
+
+
+#ifndef __SNEP_H__
+#define __SNEP_H__
+
+#include "llcp.h"
+
+#define SNEP_DEFAULT_VERSION	0x10	// Major: 1, Minor: 0
+
+#define SNEP_REQUEST_PUT		0x02
+#define SNEP_REQUEST_GET		0x01
+
+#define SNEP_RESPONSE_SUCCESS	0x81
+#define SNEP_RESPONSE_REJECT	0xFF
+
+class SNEP {
+public:
+	SNEP(PN532Interface &interface) : llcp(interface) {
+		headerBuf = llcp.getHeaderBuffer(&headerBufLen);
+	};
+
+	/**
+    * @brief    write a SNEP packet, the packet should be less than (255 - 2 - 3) bytes
+    * @param    buf     the buffer to contain the packet
+    * @param    len     lenght of the buffer
+    * @param    timeout max time to wait, 0 means no timeout
+    * @return   >0      success
+    *			=0      timeout
+    *           <0      failed
+    */
+    int8_t write(const uint8_t *buf, uint8_t len, uint16_t timeout = 0);
+
+    /**
+    * @brief    read a SNEP packet, the packet will be less than (255 - 2 - 3) bytes
+    * @param    buf     the buffer to contain the packet
+    * @param    len     lenght of the buffer
+    * @param    timeout max time to wait, 0 means no timeout
+    * @return   >=0     length of the packet 
+    *           <0      failed
+    */
+    int16_t read(uint8_t *buf, uint8_t len, uint16_t timeout = 0);
+
+private:
+	LLCP llcp;
+	uint8_t *headerBuf;
+	uint8_t headerBufLen;
+};
+
+#endif // __SNEP_H__