diff --git a/Adafruit_PN532.cpp b/Adafruit_PN532.cpp index 44f72de..08d3505 100644 --- a/Adafruit_PN532.cpp +++ b/Adafruit_PN532.cpp @@ -77,7 +77,7 @@ byte pn532response_firmwarevers[] = {0x00, 0xFF, 0x06, 0xFA, 0xD5, 0x03}; #define PN532_SPI_CLOCKDIV SPI_CLOCK_DIV16 #endif -#define PN532_PACKBUFFSIZ 64 +#define PN532_PACKBUFFSIZ 255 byte pn532_packetbuffer[PN532_PACKBUFFSIZ]; #ifndef _BV @@ -292,6 +292,20 @@ void Adafruit_PN532::PrintHexChar(const byte * data, const uint32_t numBytes) PN532DEBUGPRINT.println(); } +void Adafruit_PN532::PrintHex8(const uint8_t d) { + PN532DEBUGPRINT.print(" 0x"); + PN532DEBUGPRINT.print( (d >> 4) & 0x0F, HEX); + PN532DEBUGPRINT.print( d & 0x0F, HEX); +} +void Adafruit_PN532::PrintHex16(const uint16_t d) { + PN532DEBUGPRINT.print(" 0x"); + PN532DEBUGPRINT.print( (d >> 12) & 0x0F, HEX); + PN532DEBUGPRINT.print( (d >> 8) & 0x0F, HEX); + PN532DEBUGPRINT.print( (d >> 4) & 0x0F, HEX); + PN532DEBUGPRINT.print( d & 0x0F, HEX); +} + + /**************************************************************************/ /*! @brief Checks the firmware version of the PN5xx chip @@ -1485,6 +1499,565 @@ uint8_t Adafruit_PN532::ntag2xx_WriteNDEFURI (uint8_t uriIdentifier, char * url, } + +/***** FeliCa Functions ******/ +/**************************************************************************/ +/*! + @brief Poll FeliCa card. PN532 acting as reader/initiator, + peer acting as card/responder. + @param[in] systemCode Designation of System Code. When sending FFFFh as System Code, + all the FeliCa cards can return response. + @param[in] requestCode Designation of Request Data as follows: + 00h: No Request + 01h: System Code request (to acquire System Code of the card) + 02h: Communication perfomance request + @param[out] idm IDm of the card (8 bytes) + @param[out] pmm PMm of the card (8 bytes) + @param[out] systemCodeResponse System Code of the card (2bytes) + @return 1: A FeliCa card has detected, 0: No card has detected, -1: error + +*/ +/**************************************************************************/ +int8_t Adafruit_PN532::felica_Polling(uint16_t systemCode, uint8_t requestCode, + uint8_t *idm, uint8_t *pmm, uint16_t *systemCodeResponse, uint16_t timeout) +{ + pn532_packetbuffer[0] = PN532_COMMAND_INLISTPASSIVETARGET; + pn532_packetbuffer[1] = 1; + pn532_packetbuffer[2] = 1; + pn532_packetbuffer[3] = FELICA_CMD_POLLING; + pn532_packetbuffer[4] = (systemCode >> 8) & 0xff; + pn532_packetbuffer[5] = systemCode & 0xFF; + pn532_packetbuffer[6] = requestCode; + pn532_packetbuffer[7] = 0; + + if (!sendCommandCheckAck(pn532_packetbuffer,8,timeout)) { + #ifdef PN532DEBUG + PN532DEBUGPRINT.println(F("Could not send Polling command")); + #endif + return -1; + } + + // Wait card response + if (!waitready(timeout)) { + return -2; + } + + readdata(pn532_packetbuffer, 9+20+2); + if ( !felica_checkResponse(PN532_RESPONSE_INLISTPASSIVETARGET) ) { + return -2; + } + + // Check NbTg (pn532_packetbuffer[7]) + if (pn532_packetbuffer[7] == 0) { + // No card have found + return 0; + } else if (pn532_packetbuffer[7] != 1) { + #ifdef PN532DEBUG + PN532DEBUGPRINT.print (F("Unhandled number of targets inlisted. NbTg = ")); + PN532DEBUGPRINT.println(pn532_packetbuffer[7], HEX); + #endif + return -3; + } + + _inListedTag = pn532_packetbuffer[8]; + #ifdef PN532DEBUG + PN532DEBUGPRINT.print(F("Tag number: ")); + PN532DEBUGPRINT.println(_inListedTag); + #endif + + // length check + uint8_t responseLength = pn532_packetbuffer[9]; + if (responseLength != 18 && responseLength != 20) { + #ifdef PN532DEBUG + PN532DEBUGPRINT.println(F("Wrong response length")); + #endif + return -4; + } + + uint8_t i; + for (i=0; i<8; ++i) { + idm[i] = pn532_packetbuffer[11+i]; + _felicaIDm[i] = pn532_packetbuffer[11+i]; + pmm[i] = pn532_packetbuffer[19+i]; + _felicaPMm[i] = pn532_packetbuffer[19+i]; + } + + if ( responseLength == 20 ) { + *systemCodeResponse = (uint16_t)((pn532_packetbuffer[26] << 8) + pn532_packetbuffer[27]); + } + + return 1; +} + + +/**************************************************************************/ +/*! + @brief Sends an FeliCa command with the currently inlisted peer + + @param[in] commandBuf FeliCa command packet. (e.g. 00 FF FF 00 00 for Polling command) + @param[in] commandlength Length of the FeliCa command packet. (e.g. 0x05 for above Polling command ) + @param[out] responseBuf FeliCa response packet. (e.g. 01 NFCID2(8 bytes) PAD for Polling response) + @param[out] responselength Length of the FeliCa response packet. (e.g. 0x12 for above Polling command ) +*/ +/**************************************************************************/ +int8_t Adafruit_PN532::felica_SendCommand (const uint8_t *commandBuf, uint8_t commandlength, + uint8_t *responseBuf, uint8_t expectedResLen, uint8_t *responseLength) +{ + if (commandlength > PN532_PACKBUFFSIZ-3) { + #ifdef PN532DEBUG + PN532DEBUGPRINT.println(F("Command length too long for packet buffer")); + #endif + return -1; + } + + pn532_packetbuffer[0] = 0x40; // PN532_COMMAND_INDATAEXCHANGE; + pn532_packetbuffer[1] = _inListedTag; + pn532_packetbuffer[2] = commandlength + 1; + memcpy(&pn532_packetbuffer[3], commandBuf, commandlength); + + if (!sendCommandCheckAck(pn532_packetbuffer,commandlength+3,200)) { + #ifdef PN532DEBUG + PN532DEBUGPRINT.println(F("Could not send Command")); + #endif + return -2; + } + + // Wait card response ( longer than 102.4ms ) + if (!waitready(110)) { + #ifdef PN532DEBUG + PN532DEBUGPRINT.println(F("Could not receive response")); + #endif + return -3; + } + + readdata(pn532_packetbuffer,expectedResLen); + if ( !felica_checkResponse(PN532_RESPONSE_INDATAEXCHANGE) ) { + #ifdef PN532DEBUG + PN532DEBUGPRINT.println(F("Could not receive response")); + #endif + return -3; + } + + // Check status (pn532_packetbuffer[7]) + if ((pn532_packetbuffer[7] & 0x3F)!=0) { + #ifdef PN532DEBUG + PN532DEBUGPRINT.print(F("Status code indicates an error: ")); + PN532DEBUGPRINT.println(pn532_packetbuffer[7], HEX); + #endif + return -4; + } + + // length check + *responseLength = pn532_packetbuffer[8] - 1; + if (pn532_packetbuffer[3] - 4 != *responseLength) { + #ifdef PN532DEBUG + PN532DEBUGPRINT.println(F("Wrong response length")); + #endif + return -5; + } + + memcpy(responseBuf, &pn532_packetbuffer[9], *responseLength); + + return 1; +} + + +/**************************************************************************/ +/*! + @brief Sends FeliCa Request Service command + + @param[in] numNode Number of Node + @param[in] nodeCodeList Node Code List (Big Endian) + @param[out] keyVersions Key Version of each Node (Big Endian) +*/ +/**************************************************************************/ +int8_t Adafruit_PN532::felica_RequestService(uint8_t numNode, uint16_t *nodeCodeList, uint16_t *keyVersions) +{ + if (numNode > FELICA_REQ_SERVICE_MAX_NODE_NUM) { + #ifdef PN532DEBUG + PN532DEBUGPRINT.println(F("numNode is too large")); + #endif + return -1; + } + + uint8_t i, j=0; + uint8_t cmdLen = 1 + 8 + 1 + 2*numNode; + uint8_t cmd[cmdLen]; + cmd[j++] = FELICA_CMD_REQUEST_SERVICE; + for (i=0; i<8; ++i) { + cmd[j++] = _felicaIDm[i]; + } + cmd[j++] = numNode; + for (i=0; i> 8) & 0xff; + } + + uint8_t responseBuf[10+2*numNode]; + uint8_t responseLength; + + if (!felica_SendCommand(cmd, cmdLen, responseBuf, 8 + 11 + 2*numNode + 2, &responseLength)) { + #ifdef PN532DEBUG + PN532DEBUGPRINT.println(F("Request Service command failed")); + #endif + return -2; + } + + // length check + if ( responseLength != 10+2*numNode ) { + #ifdef PN532DEBUG + PN532DEBUGPRINT.println(F("Request Service command failed (wrong response length)")); + #endif + return -3; + } + + for(i=0; i FELICA_READ_MAX_SERVICE_NUM) { + #ifdef PN532DEBUG + PN532DEBUGPRINT.println(F("numService is too large")); + #endif + return -1; + } + if (numBlock > FELICA_READ_MAX_BLOCK_NUM) { + #ifdef PN532DEBUG + PN532DEBUGPRINT.println(F("numBlock is too large")); + #endif + return -2; + } + + uint8_t i, j=0; + uint8_t cmdLen = 1 + 8 + 1 + 2*numService + 1 + 2*numBlock; + uint8_t cmd[cmdLen]; + cmd[j++] = FELICA_CMD_READ_WITHOUT_ENCRYPTION; + for (i=0; i<8; ++i) { + cmd[j++] = _felicaIDm[i]; + } + cmd[j++] = numService; + for (i=0; i> 8) & 0xff; + } + cmd[j++] = numBlock; + for (i=0; i> 8) & 0xFF; + cmd[j++] = blockList[i] & 0xff; + } + + uint8_t responseBuf[12+16*numBlock]; + uint8_t responseLength; + if (!felica_SendCommand(cmd, cmdLen, responseBuf, 8+13+16*numBlock + 2, &responseLength)) { + #ifdef PN532DEBUG + PN532DEBUGPRINT.println(F("Read Without Encryption command failed")); + #endif + return -3; + } + + // length check + if ( responseLength != 12+16*numBlock ) { + #ifdef PN532DEBUG + PN532DEBUGPRINT.println(F("Read Without Encryption command failed (wrong response length)")); + #endif + return -4; + } + + // status flag check + if ( responseBuf[9] != 0 || responseBuf[10] != 0 ) { + #ifdef PN532DEBUG + PN532DEBUGPRINT.print(F("Read Without Encryption command failed (Status Flag: ")); + PrintHex8(responseBuf[9]); + PrintHex8(responseBuf[10]); + PN532DEBUGPRINT.println(F(")")); + #endif + return -5; + } + + int k = 12; + for(i=0; i FELICA_WRITE_MAX_SERVICE_NUM) { + #ifdef PN532DEBUG + PN532DEBUGPRINT.println(F("numService is too large")); + #endif + } + if (numBlock > FELICA_WRITE_MAX_BLOCK_NUM) { + #ifdef PN532DEBUG + PN532DEBUGPRINT.println(F("numBlock is too large")); + #endif + return -2; + } + + uint8_t i, j=0, k; + uint8_t cmdLen = 1 + 8 + 1 + 2*numService + 1 + 2*numBlock + 16 * numBlock; + uint8_t cmd[cmdLen]; + cmd[j++] = FELICA_CMD_WRITE_WITHOUT_ENCRYPTION; + for (i=0; i<8; ++i) { + cmd[j++] = _felicaIDm[i]; + } + cmd[j++] = numService; + for (i=0; i> 8) & 0xff; + } + cmd[j++] = numBlock; + for (i=0; i> 8) & 0xFF; + cmd[j++] = blockList[i] & 0xff; + } + for (i=0; i https://www.adafruit.com/products/364 - - Check out the links above for our tutorials and wiring diagrams + + Check out the links above for our tutorials and wiring diagrams These chips use SPI or I2C to communicate. - - Adafruit invests time and resources providing this open source code, - please support Adafruit and open-source hardware by purchasing + + Adafruit invests time and resources providing this open source code, + please support Adafruit and open-source hardware by purchasing products from Adafruit! @section HISTORY @@ -23,10 +23,9 @@ v1.1 - Added full command list - Added 'verbose' mode flag to constructor to toggle debug output - Changed readPassiveTargetID() to return variable length values - + */ /**************************************************************************/ - #ifndef ADAFRUIT_PN532_H #define ADAFRUIT_PN532_H @@ -80,6 +79,7 @@ #define PN532_RESPONSE_INDATAEXCHANGE (0x41) #define PN532_RESPONSE_INLISTPASSIVETARGET (0x4B) +#define PN532_RESPONSE_INRELEASE (0x53) #define PN532_WAKEUP (0x55) @@ -107,6 +107,15 @@ #define MIFARE_CMD_STORE (0xC2) #define MIFARE_ULTRALIGHT_CMD_WRITE (0xA2) +// FeliCa Commands +#define FELICA_CMD_POLLING (0x00) +#define FELICA_CMD_REQUEST_SERVICE (0x02) +#define FELICA_CMD_REQUEST_RESPONSE (0x04) +#define FELICA_CMD_READ_WITHOUT_ENCRYPTION (0x06) +#define FELICA_CMD_WRITE_WITHOUT_ENCRYPTION (0x08) +#define FELICA_CMD_REQUEST_SYSTEM_CODE (0x0C) + + // Prefixes for NDEF Records (to identify record type) #define NDEF_URIPREFIX_NONE (0x00) #define NDEF_URIPREFIX_HTTP_WWWDOT (0x01) @@ -153,26 +162,35 @@ #define PN532_GPIO_P34 (4) #define PN532_GPIO_P35 (5) + +// FeliCa consts +#define FELICA_READ_MAX_SERVICE_NUM 16 +#define FELICA_READ_MAX_BLOCK_NUM 12 // for typical FeliCa card +#define FELICA_WRITE_MAX_SERVICE_NUM 16 +#define FELICA_WRITE_MAX_BLOCK_NUM 10 // for typical FeliCa card +#define FELICA_REQ_SERVICE_MAX_NODE_NUM 32 + + class Adafruit_PN532{ public: Adafruit_PN532(uint8_t clk, uint8_t miso, uint8_t mosi, uint8_t ss); // Software SPI Adafruit_PN532(uint8_t irq, uint8_t reset); // Hardware I2C Adafruit_PN532(uint8_t ss); // Hardware SPI void begin(void); - + // Generic PN532 functions bool SAMConfig(void); uint32_t getFirmwareVersion(void); - bool sendCommandCheckAck(uint8_t *cmd, uint8_t cmdlen, uint16_t timeout = 1000); + bool sendCommandCheckAck(uint8_t *cmd, uint8_t cmdlen, uint16_t timeout = 1000); bool writeGPIO(uint8_t pinstate); uint8_t readGPIO(void); bool setPassiveActivationRetries(uint8_t maxRetries); - + // ISO14443A functions bool readPassiveTargetID(uint8_t cardbaudrate, uint8_t * uid, uint8_t * uidLength, uint16_t timeout = 0); //timeout 0 means no timeout - will block forever. bool inDataExchange(uint8_t * send, uint8_t sendLength, uint8_t * response, uint8_t * responseLength); bool inListPassiveTarget(); - + // Mifare Classic functions bool mifareclassic_IsFirstBlock (uint32_t uiBlock); bool mifareclassic_IsTrailerBlock (uint32_t uiBlock); @@ -181,7 +199,7 @@ class Adafruit_PN532{ 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); uint8_t mifareultralight_WritePage (uint8_t page, uint8_t * data); @@ -190,10 +208,26 @@ class Adafruit_PN532{ uint8_t ntag2xx_ReadPage (uint8_t page, uint8_t * buffer); uint8_t ntag2xx_WritePage (uint8_t page, uint8_t * data); uint8_t ntag2xx_WriteNDEFURI (uint8_t uriIdentifier, char * url, uint8_t dataLen); - + + // FeliCa Functions + int8_t felica_Polling(uint16_t systemCode, uint8_t requestCode, uint8_t *idm, uint8_t *pmm, uint16_t *systemCodeResponse, uint16_t timeout = 0); + int8_t felica_SendCommand (const uint8_t *commandBuf, uint8_t commandlength, uint8_t *responseBuf, uint8_t expectedResLen, uint8_t *responseLength); + int8_t felica_RequestService(uint8_t numNode, uint16_t *nodeCodeList, uint16_t *keyVersions) ; + int8_t felica_RequestResponse(uint8_t *mode); + int8_t felica_ReadWithoutEncryption (uint8_t numService, const uint16_t *serviceCodeList, uint8_t numBlock, const uint16_t *blockList, uint8_t blockData[][16]); + int8_t felica_WriteWithoutEncryption (uint8_t numService, const uint16_t *serviceCodeList, uint8_t numBlock, const uint16_t *blockList, uint8_t blockData[][16]); + int8_t felica_RequestSystemCode(uint8_t *numSystemCode, uint16_t *systemCodeList); + int8_t felica_Release(); +// int8_t felica_FormatNDEF (void); +// int8_t felica_WriteNDEFURI (uint8_t sectorNumber, uint8_t uriIdentifier, const char *url); +// int8_t felicalites_InternalAuthentication (const uint8_t *random, const uint8_t *ck ); +// int8_t felicalites_ExternalAuthentication (void); + // Help functions to display formatted text static void PrintHex(const byte * data, const uint32_t numBytes); static void PrintHexChar(const byte * pbtData, const uint32_t numBytes); + static void PrintHex8(const uint8_t d); + static void PrintHex16(const uint16_t d); private: uint8_t _ss, _clk, _mosi, _miso; @@ -204,6 +238,9 @@ class Adafruit_PN532{ uint8_t _inListedTag; // Tg number of inlisted tag. bool _usingSPI; // True if using SPI, false if using I2C. bool _hardwareSPI; // True is using hardware SPI, false if using software SPI. + uint8_t _felicaIDm[8]; // FeliCa IDm (NFCID2) + uint8_t _felicaPMm[8]; // FeliCa PMm (PAD) + // Low level communication functions that handle both SPI and I2C. void readdata(uint8_t* buff, uint8_t n); @@ -216,6 +253,9 @@ class Adafruit_PN532{ void spi_write(uint8_t c); uint8_t spi_read(void); + bool felica_checkResponse(uint8_t PN532_command); + + // Note there are i2c_read and i2c_write inline functions defined in the .cpp file. }; diff --git a/examples/FeliCa_card_detection/FeliCa_card_detection.pde b/examples/FeliCa_card_detection/FeliCa_card_detection.pde new file mode 100644 index 0000000..041e7e0 --- /dev/null +++ b/examples/FeliCa_card_detection/FeliCa_card_detection.pde @@ -0,0 +1,128 @@ +/**************************************************************************/ +/*! + @file FeliCa_nfcid2.pde + @author tomo mas + @license BSD (see license.txt) + + This example will attempt to connect to an FeliCa + card or tag and retrieve some basic information such as IDm, PMm, and System Code. + + Note that you need the baud rate to be 115200 because we need to print + out the data and read from the card at the same time! +*/ +/**************************************************************************/ +#include +#include +#include + +// If using the breakout with SPI, define the pins for SPI communication. +#define PN532_SCK (2) +#define PN532_MOSI (3) +#define PN532_SS (4) +#define PN532_MISO (5) + +// If using the breakout or shield with I2C, define just the pins connected +// to the IRQ and reset lines. Use the values below (2, 3) for the shield! +#define PN532_IRQ (2) +#define PN532_RESET (3) // Not connected by default on the NFC Shield + +// Uncomment just _one_ line below depending on how your breakout or shield +// is connected to the Arduino: + +// Use this line for a breakout with a SPI connection: +//Adafruit_PN532 nfc(PN532_SCK, PN532_MISO, PN532_MOSI, PN532_SS); + +// Use this line for a breakout with a hardware SPI connection. Note that +// the PN532 SCK, MOSI, and MISO pins need to be connected to the Arduino's +// hardware SPI SCK, MOSI, and MISO pins. On an Arduino Uno these are +// SCK = 13, MOSI = 11, MISO = 12. The SS line can be any digital IO pin. +Adafruit_PN532 nfc(PN532_SS); + +// Or use this line for a breakout or shield with an I2C connection: +//Adafruit_PN532 nfc(PN532_IRQ, PN532_RESET); + +#if defined(ARDUINO_ARCH_SAMD) +// for Zero, output on USB Serial console, remove line below if using programming port to program the Zero! +// also change #define in Adafruit_PN532.cpp library file + #define Serial SerialUSB +#endif + +uint8_t _prevIDm[8]; //IDm of the card previously detected +unsigned long _prevTime; + +void setup(void) { + #ifndef ESP8266 + while (!Serial); // for Leonardo/Micro/Zero + #endif + Serial.begin(115200); + Serial.println("Hello!"); + + nfc.begin(); + + uint32_t versiondata = nfc.getFirmwareVersion(); + if (! versiondata) { + Serial.print("Didn't find PN53x board"); + while (1); // halt + } + + // Got ok data, print it out! + Serial.print("Found chip PN5"); Serial.println((versiondata>>24) & 0xFF, HEX); + Serial.print("Firmware ver. "); Serial.print((versiondata>>16) & 0xFF, DEC); + Serial.print('.'); Serial.println((versiondata>>8) & 0xFF, DEC); + + // Set the max number of retry attempts to read from a card + // This prevents us from waiting forever for a card, which is + // the default behaviour of the PN532. + nfc.setPassiveActivationRetries(0xFF); + + // configure board to read RFID tags + nfc.SAMConfig(); + + Serial.println("Waiting for an FeliCa card"); +} + +void loop(void) { + uint8_t ret; + uint16_t systemCode = 0xFFFF; + uint8_t requestCode = 0x01; // System Code request + uint8_t idm[8]; + uint8_t pmm[8]; + uint16_t systemCodeResponse; + + // Wait for an FeliCa type cards. + // When one is found, some basic information such as IDm, PMm, and System Code are retrieved. + Serial.print("Waiting for an FeliCa card... "); + ret = nfc.felica_Polling(systemCode, requestCode, idm, pmm, &systemCodeResponse, 5000); + + if (ret != 1) + { + Serial.println("Could not find a card"); + delay(500); + return; + } + + if ( memcmp(idm, _prevIDm, 8) == 0 ) { + if ( (millis() - _prevTime) < 3000 ) { + Serial.println("Same card"); + delay(500); + return; + } + } + + Serial.println("Found a card!"); + Serial.print(" IDm: "); + nfc.PrintHex(idm, 8); + Serial.print(" PMm: "); + nfc.PrintHex(pmm, 8); + Serial.print(" System Code: "); + nfc.PrintHex16(systemCodeResponse); + Serial.print("\n"); + + memcpy(_prevIDm, idm, 8); + _prevTime = millis(); + + + // Wait 1 second before continuing + Serial.println("Card access completed!\n"); + delay(1000); +} diff --git a/examples/FeliCa_card_read/FeliCa_card_read.pde b/examples/FeliCa_card_read/FeliCa_card_read.pde new file mode 100644 index 0000000..9db7fcd --- /dev/null +++ b/examples/FeliCa_card_read/FeliCa_card_read.pde @@ -0,0 +1,171 @@ +/**************************************************************************/ +/*! + @file FeliCa_nfcid2.pde + @author tomo mas + @license BSD (see license.txt) + + This example will attempt to connect to an FeliCa + card or tag and retrieve some basic information such as IDm, PMm, and System Code. + + Note that you need the baud rate to be 115200 because we need to print + out the data and read from the card at the same time! +*/ +/**************************************************************************/ +#include +#include +#include + +// If using the breakout with SPI, define the pins for SPI communication. +#define PN532_SCK (2) +#define PN532_MOSI (3) +#define PN532_SS (4) +#define PN532_MISO (5) + +// If using the breakout or shield with I2C, define just the pins connected +// to the IRQ and reset lines. Use the values below (2, 3) for the shield! +#define PN532_IRQ (2) +#define PN532_RESET (3) // Not connected by default on the NFC Shield + +// Uncomment just _one_ line below depending on how your breakout or shield +// is connected to the Arduino: + +// Use this line for a breakout with a SPI connection: +//Adafruit_PN532 nfc(PN532_SCK, PN532_MISO, PN532_MOSI, PN532_SS); + +// Use this line for a breakout with a hardware SPI connection. Note that +// the PN532 SCK, MOSI, and MISO pins need to be connected to the Arduino's +// hardware SPI SCK, MOSI, and MISO pins. On an Arduino Uno these are +// SCK = 13, MOSI = 11, MISO = 12. The SS line can be any digital IO pin. +Adafruit_PN532 nfc(PN532_SS); + +// Or use this line for a breakout or shield with an I2C connection: +//Adafruit_PN532 nfc(PN532_IRQ, PN532_RESET); + +#if defined(ARDUINO_ARCH_SAMD) +// for Zero, output on USB Serial console, remove line below if using programming port to program the Zero! +// also change #define in Adafruit_PN532.cpp library file + #define Serial SerialUSB +#endif + +uint8_t _prevIDm[8]; //IDm of the card previously detected +unsigned long _prevTime; + +void setup(void) { + #ifndef ESP8266 + while (!Serial); // for Leonardo/Micro/Zero + #endif + Serial.begin(115200); + Serial.println("Hello!"); + + nfc.begin(); + + uint32_t versiondata = nfc.getFirmwareVersion(); + if (! versiondata) { + Serial.print("Didn't find PN53x board"); + while (1); // halt + } + + // Got ok data, print it out! + Serial.print("Found chip PN5"); Serial.println((versiondata>>24) & 0xFF, HEX); + Serial.print("Firmware ver. "); Serial.print((versiondata>>16) & 0xFF, DEC); + Serial.print('.'); Serial.println((versiondata>>8) & 0xFF, DEC); + + // Set the max number of retry attempts to read from a card + // This prevents us from waiting forever for a card, which is + // the default behaviour of the PN532. + nfc.setPassiveActivationRetries(0xFF); + + // configure board to read RFID tags + nfc.SAMConfig(); + + Serial.println("Waiting for an FeliCa card"); +} + +void loop(void) { + uint8_t ret; + uint16_t systemCode = 0xFFFF; + uint8_t requestCode = 0x01; // System Code request + uint8_t idm[8]; + uint8_t pmm[8]; + uint16_t systemCodeResponse; + + // Wait for an FeliCa type cards. + // When one is found, some basic information such as IDm, PMm, and System Code are retrieved. + Serial.print("Waiting for an FeliCa card... "); + ret = nfc.felica_Polling(systemCode, requestCode, idm, pmm, &systemCodeResponse, 5000); + + if (ret != 1) + { + Serial.println("Could not find a card"); + delay(500); + return; + } + + if ( memcmp(idm, _prevIDm, 8) == 0 ) { + if ( (millis() - _prevTime) < 3000 ) { + Serial.println("Same card"); + delay(1000); + return; + } + } + + Serial.println("Found a card!"); + Serial.print(" IDm: "); + nfc.PrintHex(idm, 8); + Serial.print(" PMm: "); + nfc.PrintHex(pmm, 8); + Serial.print(" System Code: "); + nfc.PrintHex16(systemCodeResponse); + Serial.print("\n"); + + memcpy(_prevIDm, idm, 8); + _prevTime = millis(); + + uint8_t blockData[3][16]; + uint16_t serviceCodeList[1]; + uint16_t blockList[3]; + + Serial.println("Write Without Encryption command "); + serviceCodeList[0] = 0x0009; + blockList[0] = 0x8000; + unsigned long now = millis(); + blockData[0][3] = now & 0xFF; + blockData[0][2] = (now >>= 8) & 0xFF; + blockData[0][1] = (now >>= 8) & 0xFF; + blockData[0][0] = (now >>= 8) & 0xFF; + Serial.print(" Writing current millis ("); + nfc.PrintHex8(blockData[0][0]); + nfc.PrintHex8(blockData[0][1]); + nfc.PrintHex8(blockData[0][2]); + nfc.PrintHex8(blockData[0][3]); + Serial.print(" ) to Block 0 -> "); + ret = nfc.felica_WriteWithoutEncryption(1, serviceCodeList, 1, blockList, blockData); + if (ret != 1) + { + Serial.println("error"); + } else { + Serial.println("OK!"); + } + memset(blockData[0], 0, 16); + + Serial.print("Read Without Encryption command -> "); + serviceCodeList[0] = 0x000B; + blockList[0] = 0x8000; + blockList[1] = 0x8001; + blockList[2] = 0x8002; + ret = nfc.felica_ReadWithoutEncryption(1, serviceCodeList, 3, blockList, blockData); + if (ret != 1) + { + Serial.println("error"); + } else { + Serial.println("OK!"); + for(int i=0; i<3; i++ ) { + Serial.print(" Block no. "); Serial.print(i, DEC); Serial.print(": "); + nfc.PrintHex(blockData[i], 16); + } + } + + // Wait 1 second before continuing + Serial.println("Card access completed!\n"); + delay(1000); +}