mbed code for the Kinoma team's wireless assignment

Dependencies:   mbed

Fork of idd_hw5_kinoma_rememberkeys by Sean McQueen

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers Adafruit_PN532.cpp Source File

Adafruit_PN532.cpp

Go to the documentation of this file.
00001 /**************************************************************************/
00002 /*! 
00003     @file     Adafruit_PN532.cpp
00004     @author   Adafruit Industries
00005     @license  BSD (see license.txt)
00006     
00007     SPI Driver for NXP's PN532 NFC/13.56MHz RFID Transceiver
00008 
00009     This is a library for the Adafruit PN532 NFC/RFID breakout boards
00010     This library works with the Adafruit NFC breakout 
00011     ----> https://www.adafruit.com/products/364
00012     
00013     Check out the links above for our tutorials and wiring diagrams 
00014     These chips use SPI to communicate, 4 required to interface
00015     
00016     Adafruit invests time and resources providing this open source code, 
00017     please support Adafruit and open-source hardware by purchasing 
00018     products from Adafruit!
00019 
00020 
00021     @section  HISTORY
00022 
00023     v1.4 - Added setPassiveActivationRetries()
00024     
00025     v1.2 - Added writeGPIO()
00026          - Added readGPIO()
00027 
00028     v1.1 - Changed readPassiveTargetID() to handle multiple UID sizes
00029          - Added the following helper functions for text display
00030              static void PrintHex(const uint8_t * data, const uint32_t numuint8_ts)
00031              static void PrintHexChar(const uint8_t * pbtData, const uint32_t numuint8_ts)
00032          - Added the following Mifare Classic functions:
00033              bool mifareclassic_IsFirstBlock (uint32_t uiBlock)
00034              bool mifareclassic_IsTrailerBlock (uint32_t uiBlock)
00035              uint8_t mifareclassic_AuthenticateBlock (uint8_t * uid, uint8_t uidLen, uint32_t blockNumber, uint8_t keyNumber, uint8_t * keyData)
00036              uint8_t mifareclassic_ReadDataBlock (uint8_t blockNumber, uint8_t * data)
00037              uint8_t mifareclassic_WriteDataBlock (uint8_t blockNumber, uint8_t * data)
00038          - Added the following Mifare Ultalight functions:
00039              uint8_t mifareultralight_ReadPage (uint8_t page, uint8_t * buffer) 
00040 */
00041 /**************************************************************************/
00042 
00043 #include "Adafruit_PN532.h "
00044 
00045 uint8_t pn532ack[] = {0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00};
00046 uint8_t pn532response_firmwarevers[] = {0x00, 0xFF, 0x06, 0xFA, 0xD5, 0x03};
00047 
00048 // Uncomment these lines to enable debug output for PN532(SPI) and/or MIFARE related code
00049 // #define PN532DEBUG
00050 // #define MIFAREDEBUG
00051 
00052 Serial serial(USBTX, USBRX);
00053 #define SERIAL_PRINT serial.printf
00054 
00055 #define _BV(bit) (1 << (bit))
00056 #define PN532_PACKBUFFSIZ 64
00057 uint8_t pn532_packetbuffer[PN532_PACKBUFFSIZ];
00058 
00059 void delay(int delayInMS) {
00060   wait(1.0 * delayInMS / 1000);
00061 }
00062 
00063 /**************************************************************************/
00064 /*! 
00065     @brief  Instantiates a new PN532 class
00066 
00067     @param  clk       SPI clock pin (SCK)
00068     @param  miso      SPI MISO pin 
00069     @param  mosi      SPI MOSI pin
00070     @param  ss        SPI chip select pin (CS/SSEL)
00071 */
00072 /**************************************************************************/
00073 Adafruit_PN532::Adafruit_PN532(DigitalOut clk, DigitalIn miso,
00074                                DigitalOut mosi, DigitalOut ss)
00075     : _clk(clk), _miso(miso), _mosi(mosi), _ss(ss) {}
00076 
00077 Adafruit_PN532::Adafruit_PN532(PinName clk_pin, PinName miso_pin,
00078                                PinName mosi_pin, PinName ss_pin)
00079     : _clk(DigitalOut(clk_pin)), _miso(DigitalIn(miso_pin)),
00080       _mosi(DigitalOut(mosi_pin)), _ss(DigitalOut(ss_pin)) {}
00081 
00082 /**************************************************************************/
00083 /*! 
00084     @brief  Setups the HW
00085 */
00086 /**************************************************************************/
00087 void Adafruit_PN532::begin() {
00088   _ss = 0;  
00089   delay(1000);
00090 
00091   // not exactly sure why but we have to send a dummy command to get synced up
00092   pn532_packetbuffer[0] = PN532_COMMAND_GETFIRMWAREVERSION;
00093   sendCommandCheckAck(pn532_packetbuffer, 1);
00094 
00095   // ignore response!
00096 }
00097  
00098 /**************************************************************************/
00099 /*! 
00100     @brief  Prints a hexadecimal value in plain characters
00101 
00102     @param  data      Pointer to the uint8_t data
00103     @param  numuint8_ts  Data length in uint8_ts
00104 */
00105 /**************************************************************************/
00106 void Adafruit_PN532::PrintHex(const uint8_t * data, const uint32_t numuint8_ts)
00107 {
00108   uint32_t szPos;
00109   for (szPos=0; szPos < numuint8_ts; szPos++) 
00110   {
00111     SERIAL_PRINT("0x");
00112     // Append leading 0 for small values
00113     if (data[szPos] <= 0xF)
00114       SERIAL_PRINT("0");
00115     SERIAL_PRINT("%d", data[szPos]);
00116     if ((numuint8_ts > 1) && (szPos != numuint8_ts - 1))
00117     {
00118       SERIAL_PRINT(" ");
00119     }
00120   }
00121   SERIAL_PRINT("\n");
00122 }
00123 
00124 /**************************************************************************/
00125 /*! 
00126     @brief  Prints a hexadecimal value in plain characters, along with
00127             the char equivalents in the following format
00128 
00129             00 00 00 00 00 00  ......
00130 
00131     @param  data      Pointer to the uint8_t data
00132     @param  numuint8_ts  Data length in uint8_ts
00133 */
00134 /**************************************************************************/
00135 void Adafruit_PN532::PrintHexChar(const uint8_t * data, const uint32_t numuint8_ts)
00136 {
00137   uint32_t szPos;
00138   for (szPos=0; szPos < numuint8_ts; szPos++) 
00139   {
00140     // Append leading 0 for small values
00141     if (data[szPos] <= 0xF)
00142       SERIAL_PRINT("0");
00143     SERIAL_PRINT("%x", data[szPos]);
00144     if ((numuint8_ts > 1) && (szPos != numuint8_ts - 1))
00145     {
00146       SERIAL_PRINT(" ");
00147     }
00148   }
00149   SERIAL_PRINT(" ");
00150   for (szPos=0; szPos < numuint8_ts; szPos++) 
00151   {
00152     if (data[szPos] <= 0x1F)
00153       SERIAL_PRINT(".");
00154     else
00155       SERIAL_PRINT("%c", data[szPos]);
00156   }
00157   SERIAL_PRINT("");
00158 }
00159  
00160 /**************************************************************************/
00161 /*! 
00162     @brief  Checks the firmware version of the PN5xx chip
00163 
00164     @returns  The chip's firmware version and ID
00165 */
00166 /**************************************************************************/
00167 uint32_t Adafruit_PN532::getFirmwareVersion(void) {
00168   uint32_t response;
00169 
00170   pn532_packetbuffer[0] = PN532_COMMAND_GETFIRMWAREVERSION;
00171   
00172   if (! sendCommandCheckAck(pn532_packetbuffer, 1))
00173     return 0;
00174   
00175   // read data packet
00176   readspidata(pn532_packetbuffer, 12);
00177   
00178   // check some basic stuff
00179   if (0 != strncmp((char *)pn532_packetbuffer, (char *)pn532response_firmwarevers, 6)) {
00180     return 0;
00181   }
00182   
00183   response = pn532_packetbuffer[6];
00184   response <<= 8;
00185   response |= pn532_packetbuffer[7];
00186   response <<= 8;
00187   response |= pn532_packetbuffer[8];
00188   response <<= 8;
00189   response |= pn532_packetbuffer[9];
00190 
00191   return response;
00192 }
00193 
00194 
00195 /**************************************************************************/
00196 /*! 
00197     @brief  Sends a command and waits a specified period for the ACK
00198 
00199     @param  cmd       Pointer to the command buffer
00200     @param  cmdlen    The size of the command in uint8_ts 
00201     @param  timeout   timeout before giving up
00202     
00203     @returns  1 if everything is OK, 0 if timeout occured before an
00204               ACK was recieved
00205 */
00206 /**************************************************************************/
00207 // default timeout of one second
00208 bool Adafruit_PN532::sendCommandCheckAck(uint8_t *cmd, uint8_t cmdlen, uint16_t timeout) {
00209   uint16_t timer = 0;
00210   
00211   // write the command
00212   spiwritecommand(cmd, cmdlen);
00213   
00214   // Wait for chip to say its ready!
00215   while (readspistatus() != PN532_SPI_READY) {
00216     if (timeout != 0) {
00217       timer+=10;
00218       if (timer > timeout)  
00219         return false;
00220     }
00221     delay(10);
00222   }
00223   
00224   // read acknowledgement
00225   if (!spi_readack()) {
00226     return false;
00227   }
00228   
00229   timer = 0;
00230   // Wait for chip to say its ready!
00231   while (readspistatus() != PN532_SPI_READY) {
00232     if (timeout != 0) {
00233       timer+=10;
00234       if (timer > timeout)  
00235         return false;
00236     }
00237     delay(10);
00238   }
00239   
00240   return true; // ack'd command
00241 }
00242 
00243 /**************************************************************************/
00244 /*! 
00245     Writes an 8-bit value that sets the state of the PN532's GPIO pins
00246     
00247     @warning This function is provided exclusively for board testing and
00248              is dangerous since it will throw an error if any pin other
00249              than the ones marked "Can be used as GPIO" are modified!  All
00250              pins that can not be used as GPIO should ALWAYS be left high
00251              (value = 1) or the system will become unstable and a HW reset
00252              will be required to recover the PN532.
00253     
00254              pinState[0]  = P30     Can be used as GPIO
00255              pinState[1]  = P31     Can be used as GPIO
00256              pinState[2]  = P32     *** RESERVED (Must be 1!) ***
00257              pinState[3]  = P33     Can be used as GPIO
00258              pinState[4]  = P34     *** RESERVED (Must be 1!) ***
00259              pinState[5]  = P35     Can be used as GPIO
00260     
00261     @returns 1 if everything executed properly, 0 for an error
00262 */
00263 /**************************************************************************/
00264 bool Adafruit_PN532::writeGPIO(uint8_t pinstate) {
00265   // Make sure pinstate does not try to toggle P32 or P34
00266   pinstate |= (1 << PN532_GPIO_P32) | (1 << PN532_GPIO_P34);
00267   
00268   // Fill command buffer
00269   pn532_packetbuffer[0] = PN532_COMMAND_WRITEGPIO;
00270   pn532_packetbuffer[1] = PN532_GPIO_VALIDATIONBIT | pinstate;  // P3 Pins
00271   pn532_packetbuffer[2] = 0x00;    // P7 GPIO Pins (not used ... taken by SPI)
00272 
00273   #ifdef PN532DEBUG
00274     SERIAL_PRINT("Writing P3 GPIO: "); SERIAL_PRINTln(pn532_packetbuffer[1], HEX);
00275   #endif
00276 
00277   // Send the WRITEGPIO command (0x0E)  
00278   if (! sendCommandCheckAck(pn532_packetbuffer, 3))
00279     return 0x0;
00280   
00281   // Read response packet (00 FF PLEN PLENCHECKSUM D5 CMD+1(0x0F) DATACHECKSUM 00)
00282   readspidata(pn532_packetbuffer, 8);
00283 
00284   #ifdef PN532DEBUG
00285     SERIAL_PRINT("Received: ");
00286     PrintHex(pn532_packetbuffer, 8);
00287     SERIAL_PRINTln("");
00288   #endif  
00289   
00290   return  (pn532_packetbuffer[5] == 0x0F);
00291 }
00292 
00293 /**************************************************************************/
00294 /*! 
00295     Reads the state of the PN532's GPIO pins
00296     
00297     @returns An 8-bit value containing the pin state where:
00298     
00299              pinState[0]  = P30     
00300              pinState[1]  = P31     
00301              pinState[2]  = P32     
00302              pinState[3]  = P33     
00303              pinState[4]  = P34     
00304              pinState[5]  = P35     
00305 */
00306 /**************************************************************************/
00307 uint8_t Adafruit_PN532::readGPIO(void) {
00308   pn532_packetbuffer[0] = PN532_COMMAND_READGPIO;
00309 
00310   // Send the READGPIO command (0x0C)  
00311   if (! sendCommandCheckAck(pn532_packetbuffer, 1))
00312     return 0x0;
00313   
00314   // Read response packet (00 FF PLEN PLENCHECKSUM D5 CMD+1(0x0D) P3 P7 IO1 DATACHECKSUM 00)
00315   readspidata(pn532_packetbuffer, 11);
00316 
00317   /* READGPIO response should be in the following format:
00318   
00319     uint8_t            Description
00320     -------------   ------------------------------------------
00321     b0..5           Frame header and preamble
00322     b6              P3 GPIO Pins
00323     b7              P7 GPIO Pins (not used ... taken by SPI)
00324     b8              Interface Mode Pins (not used ... bus select pins) 
00325     b9..10          checksum */
00326   
00327   #ifdef PN532DEBUG
00328     SERIAL_PRINT("Received: ");
00329     PrintHex(pn532_packetbuffer, 11);
00330     SERIAL_PRINTln("");
00331     SERIAL_PRINT("P3 GPIO: 0x"); SERIAL_PRINTln(pn532_packetbuffer[6], HEX);
00332     SERIAL_PRINT("P7 GPIO: 0x"); SERIAL_PRINTln(pn532_packetbuffer[7], HEX);
00333     SERIAL_PRINT("IO GPIO: 0x"); SERIAL_PRINTln(pn532_packetbuffer[8], HEX);
00334     // Note: You can use the IO GPIO value to detect the serial bus being used
00335     switch(pn532_packetbuffer[8])
00336     {
00337       case 0x00:    // Using UART
00338         SERIAL_PRINTln("Using UART (IO = 0x00)");
00339         break;
00340       case 0x01:    // Using I2C 
00341         SERIAL_PRINTln("Using I2C (IO = 0x01)");
00342         break;
00343       case 0x02:    // Using SPI
00344         SERIAL_PRINTln("Using SPI (IO = 0x02)");
00345         break;
00346     }
00347   #endif
00348 
00349   return pn532_packetbuffer[6];
00350 }
00351 
00352 /**************************************************************************/
00353 /*! 
00354     @brief  Configures the SAM (Secure Access Module)
00355 */
00356 /**************************************************************************/
00357 bool Adafruit_PN532::SAMConfig(void) {
00358   pn532_packetbuffer[0] = PN532_COMMAND_SAMCONFIGURATION;
00359   pn532_packetbuffer[1] = 0x01; // normal mode;
00360   pn532_packetbuffer[2] = 0x14; // timeout 50ms * 20 = 1 second
00361   pn532_packetbuffer[3] = 0x01; // use IRQ pin!
00362   
00363   if (! sendCommandCheckAck(pn532_packetbuffer, 4))
00364      return false;
00365 
00366   // read data packet
00367   readspidata(pn532_packetbuffer, 8);
00368   
00369   return  (pn532_packetbuffer[5] == 0x15);
00370 }
00371 
00372 /**************************************************************************/
00373 /*! 
00374     Sets the MxRtyPassiveActivation uint8_t of the RFConfiguration register
00375     
00376     @param  maxRetries    0xFF to wait forever, 0x00..0xFE to timeout
00377                           after mxRetries
00378     
00379     @returns 1 if everything executed properly, 0 for an error
00380 */
00381 /**************************************************************************/
00382 bool Adafruit_PN532::setPassiveActivationRetries(uint8_t maxRetries) {
00383   pn532_packetbuffer[0] = PN532_COMMAND_RFCONFIGURATION;
00384   pn532_packetbuffer[1] = 5;    // Config item 5 (MaxRetries)
00385   pn532_packetbuffer[2] = 0xFF; // MxRtyATR (default = 0xFF)
00386   pn532_packetbuffer[3] = 0x01; // MxRtyPSL (default = 0x01)
00387   pn532_packetbuffer[4] = maxRetries;
00388 
00389 #ifdef MIFAREDEBUG
00390   SERIAL_PRINT("Setting MxRtyPassiveActivation to "); SERIAL_PRINT(maxRetries, DEC); SERIAL_PRINTln(" ");
00391 #endif
00392   
00393   if (! sendCommandCheckAck(pn532_packetbuffer, 5))
00394     return 0x0;  // no ACK
00395   
00396   return 1;
00397 }
00398 
00399 /***** ISO14443A Commands ******/
00400 
00401 /**************************************************************************/
00402 /*! 
00403     Waits for an ISO14443A target to enter the field
00404     
00405     @param  cardBaudRate  Baud rate of the card
00406     @param  uid           Pointer to the array that will be populated
00407                           with the card's UID (up to 7 uint8_ts)
00408     @param  uidLength     Pointer to the variable that will hold the
00409                           length of the card's UID.
00410     
00411     @returns 1 if everything executed properly, 0 for an error
00412 */
00413 /**************************************************************************/
00414 bool Adafruit_PN532::readPassiveTargetID(uint8_t cardbaudrate, uint8_t * uid, uint8_t * uidLength) {
00415   pn532_packetbuffer[0] = PN532_COMMAND_INLISTPASSIVETARGET;
00416   pn532_packetbuffer[1] = 1;  // max 1 cards at once (we can set this to 2 later)
00417   pn532_packetbuffer[2] = cardbaudrate;
00418   
00419   if (! sendCommandCheckAck(pn532_packetbuffer, 3))
00420     return 0x0;  // no cards read
00421   
00422   // read data packet
00423   readspidata(pn532_packetbuffer, 20);
00424   // check some basic stuff
00425 
00426   /* ISO14443A card response should be in the following format:
00427   
00428     uint8_t            Description
00429     -------------   ------------------------------------------
00430     b0..6           Frame header and preamble
00431     b7              Tags Found
00432     b8              Tag Number (only one used in this example)
00433     b9..10          SENS_RES
00434     b11             SEL_RES
00435     b12             NFCID Length
00436     b13..NFCIDLen   NFCID                                      */
00437   
00438 #ifdef MIFAREDEBUG
00439     SERIAL_PRINT("Found "); SERIAL_PRINT(pn532_packetbuffer[7], DEC); SERIAL_PRINTln(" tags");
00440 #endif
00441   if (pn532_packetbuffer[7] != 1) 
00442     return 0;
00443     
00444   uint16_t sens_res = pn532_packetbuffer[9];
00445   sens_res <<= 8;
00446   sens_res |= pn532_packetbuffer[10];
00447 #ifdef MIFAREDEBUG
00448     SERIAL_PRINT("ATQA: 0x");  SERIAL_PRINTln(sens_res, HEX); 
00449     SERIAL_PRINT("SAK: 0x");  SERIAL_PRINTln(pn532_packetbuffer[11], HEX); 
00450 #endif
00451   
00452   /* Card appears to be Mifare Classic */
00453   *uidLength = pn532_packetbuffer[12];
00454 #ifdef MIFAREDEBUG
00455     SERIAL_PRINT("UID:"); 
00456 #endif
00457   for (uint8_t i=0; i < pn532_packetbuffer[12]; i++) 
00458   {
00459     uid[i] = pn532_packetbuffer[13+i];
00460 #ifdef MIFAREDEBUG
00461       SERIAL_PRINT(" 0x");SERIAL_PRINT(uid[i], HEX); 
00462 #endif
00463   }
00464 #ifdef MIFAREDEBUG
00465     SERIAL_PRINTln();
00466 #endif
00467 
00468   uint8_t bTestDeselect[2];
00469   bTestDeselect[0] = PN532_COMMAND_INDESELECT;
00470   bTestDeselect[1] = pn532_packetbuffer[8];
00471   sendCommandCheckAck(bTestDeselect,2);
00472 
00473   return 1;
00474 }
00475 
00476 
00477 /***** Mifare Classic Functions ******/
00478 
00479 /**************************************************************************/
00480 /*! 
00481       Indicates whether the specified block number is the first block
00482       in the sector (block 0 relative to the current sector)
00483 */
00484 /**************************************************************************/
00485 bool Adafruit_PN532::mifareclassic_IsFirstBlock (uint32_t uiBlock)
00486 {
00487   // Test if we are in the small or big sectors
00488   if (uiBlock < 128)
00489     return ((uiBlock) % 4 == 0);
00490   else
00491     return ((uiBlock) % 16 == 0);
00492 }
00493 
00494 /**************************************************************************/
00495 /*! 
00496       Indicates whether the specified block number is the sector trailer
00497 */
00498 /**************************************************************************/
00499 bool Adafruit_PN532::mifareclassic_IsTrailerBlock (uint32_t uiBlock)
00500 {
00501   // Test if we are in the small or big sectors
00502   if (uiBlock < 128)
00503     return ((uiBlock + 1) % 4 == 0);
00504   else
00505     return ((uiBlock + 1) % 16 == 0);
00506 }
00507 
00508 /**************************************************************************/
00509 /*! 
00510     Tries to authenticate a block of memory on a MIFARE card using the
00511     INDATAEXCHANGE command.  See section 7.3.8 of the PN532 User Manual
00512     for more information on sending MIFARE and other commands.
00513 
00514     @param  uid           Pointer to a uint8_t array containing the card UID
00515     @param  uidLen        The length (in uint8_ts) of the card's UID (Should
00516                           be 4 for MIFARE Classic)
00517     @param  blockNumber   The block number to authenticate.  (0..63 for
00518                           1KB cards, and 0..255 for 4KB cards).
00519     @param  keyNumber     Which key type to use during authentication
00520                           (0 = MIFARE_CMD_AUTH_A, 1 = MIFARE_CMD_AUTH_B)
00521     @param  keyData       Pointer to a uint8_t array containing the 6 uint8_t
00522                           key value
00523     
00524     @returns 1 if everything executed properly, 0 for an error
00525 */
00526 /**************************************************************************/
00527 uint8_t Adafruit_PN532::mifareclassic_AuthenticateBlock (uint8_t * uid, uint8_t uidLen, uint32_t blockNumber, uint8_t keyNumber, uint8_t * keyData)
00528 {
00529   uint8_t i;
00530   
00531   // Hang on to the key and uid data
00532   memcpy (_key, keyData, 6); 
00533   memcpy (_uid, uid, uidLen); 
00534   _uidLen = uidLen;  
00535 
00536   #ifdef MIFAREDEBUG
00537   SERIAL_PRINT("Trying to authenticate card ");
00538   Adafruit_PN532::PrintHex(_uid, _uidLen);
00539   SERIAL_PRINT("Using authentication KEY ");SERIAL_PRINT(keyNumber ? 'B' : 'A');SERIAL_PRINT(": ");
00540   Adafruit_PN532::PrintHex(_key, 6);
00541   #endif
00542   
00543   // Prepare the authentication command //
00544   pn532_packetbuffer[0] = PN532_COMMAND_INDATAEXCHANGE;   /* Data Exchange Header */
00545   pn532_packetbuffer[1] = 1;                              /* Max card numbers */
00546   pn532_packetbuffer[2] = (keyNumber) ? MIFARE_CMD_AUTH_B : MIFARE_CMD_AUTH_A;
00547   pn532_packetbuffer[3] = blockNumber;                    /* Block Number (1K = 0..63, 4K = 0..255 */
00548   memcpy (pn532_packetbuffer+4, _key, 6);
00549   for (i = 0; i < _uidLen; i++)
00550   {
00551     pn532_packetbuffer[10+i] = _uid[i];                /* 4 uint8_t card ID */
00552   }
00553 
00554   if (! sendCommandCheckAck(pn532_packetbuffer, 10+_uidLen))
00555     return 0;
00556 
00557   // Read the response packet
00558   readspidata(pn532_packetbuffer, 12);
00559   // check if the response is valid and we are authenticated???
00560   // for an auth success it should be uint8_ts 5-7: 0xD5 0x41 0x00
00561   // Mifare auth error is technically uint8_t 7: 0x14 but anything other and 0x00 is not good
00562   if (pn532_packetbuffer[7] != 0x00)
00563   {
00564     #ifdef PN532DEBUG
00565     SERIAL_PRINT("Authentification failed: ");
00566     Adafruit_PN532::PrintHexChar(pn532_packetbuffer, 12);
00567     #endif
00568     return 0;
00569   }
00570 
00571   return 1;
00572 }
00573 
00574 /**************************************************************************/
00575 /*! 
00576     Tries to read an entire 16-uint8_t data block at the specified block
00577     address.
00578 
00579     @param  blockNumber   The block number to authenticate.  (0..63 for
00580                           1KB cards, and 0..255 for 4KB cards).
00581     @param  data          Pointer to the uint8_t array that will hold the
00582                           retrieved data (if any)
00583     
00584     @returns 1 if everything executed properly, 0 for an error
00585 */
00586 /**************************************************************************/
00587 uint8_t Adafruit_PN532::mifareclassic_ReadDataBlock (uint8_t blockNumber, uint8_t * data)
00588 {
00589   #ifdef MIFAREDEBUG
00590   SERIAL_PRINT("Trying to read 16 uint8_ts from block ");SERIAL_PRINTln(blockNumber);
00591   #endif
00592   
00593   /* Prepare the command */
00594   pn532_packetbuffer[0] = PN532_COMMAND_INDATAEXCHANGE;
00595   pn532_packetbuffer[1] = 1;                      /* Card number */
00596   pn532_packetbuffer[2] = MIFARE_CMD_READ;        /* Mifare Read command = 0x30 */
00597   pn532_packetbuffer[3] = blockNumber;            /* Block Number (0..63 for 1K, 0..255 for 4K) */
00598 
00599   /* Send the command */
00600   if (! sendCommandCheckAck(pn532_packetbuffer, 4))
00601   {
00602     #ifdef MIFAREDEBUG
00603     SERIAL_PRINTln("Failed to receive ACK for read command");
00604     #endif
00605     return 0;
00606   }
00607 
00608   /* Read the response packet */
00609   readspidata(pn532_packetbuffer, 26);
00610 
00611   /* If uint8_t 8 isn't 0x00 we probably have an error */
00612   if (pn532_packetbuffer[7] != 0x00)
00613   {
00614     //#ifdef MIFAREDEBUG
00615     SERIAL_PRINT("Unexpected response");
00616     Adafruit_PN532::PrintHexChar(pn532_packetbuffer, 26);
00617     //#endif
00618     return 0;
00619   }
00620     
00621   /* Copy the 16 data uint8_ts to the output buffer        */
00622   /* Block content starts at uint8_t 9 of a valid response */
00623   memcpy (data, pn532_packetbuffer+8, 16);
00624 
00625   /* Display data for debug if requested */
00626   #ifdef MIFAREDEBUG
00627     SERIAL_PRINT("Block ");
00628     SERIAL_PRINTln(blockNumber);
00629     Adafruit_PN532::PrintHexChar(data, 16);
00630   #endif
00631 
00632   return 1;  
00633 }
00634 
00635 /**************************************************************************/
00636 /*! 
00637     Tries to write an entire 16-uint8_t data block at the specified block
00638     address.
00639 
00640     @param  blockNumber   The block number to authenticate.  (0..63 for
00641                           1KB cards, and 0..255 for 4KB cards).
00642     @param  data          The uint8_t array that contains the data to write.
00643     
00644     @returns 1 if everything executed properly, 0 for an error
00645 */
00646 /**************************************************************************/
00647 uint8_t Adafruit_PN532::mifareclassic_WriteDataBlock (uint8_t blockNumber, uint8_t * data)
00648 {
00649   #ifdef MIFAREDEBUG
00650   SERIAL_PRINT("Trying to write 16 uint8_ts to block ");SERIAL_PRINTln(blockNumber);
00651   #endif
00652   
00653   /* Prepare the first command */
00654   pn532_packetbuffer[0] = PN532_COMMAND_INDATAEXCHANGE;
00655   pn532_packetbuffer[1] = 1;                      /* Card number */
00656   pn532_packetbuffer[2] = MIFARE_CMD_WRITE;       /* Mifare Write command = 0xA0 */
00657   pn532_packetbuffer[3] = blockNumber;            /* Block Number (0..63 for 1K, 0..255 for 4K) */
00658   memcpy (pn532_packetbuffer+4, data, 16);          /* Data Payload */
00659 
00660   /* Send the command */
00661   if (! sendCommandCheckAck(pn532_packetbuffer, 20))
00662   {
00663     #ifdef MIFAREDEBUG
00664     SERIAL_PRINTln("Failed to receive ACK for write command");
00665     #endif
00666     return 0;
00667   }  
00668   delay(10);
00669   
00670   /* Read the response packet */
00671   readspidata(pn532_packetbuffer, 26);
00672 
00673   return 1;  
00674 }
00675 
00676 /**************************************************************************/
00677 /*! 
00678     Formats a Mifare Classic card to store NDEF Records 
00679     
00680     @returns 1 if everything executed properly, 0 for an error
00681 */
00682 /**************************************************************************/
00683 uint8_t Adafruit_PN532::mifareclassic_FormatNDEF (void)
00684 {
00685   uint8_t sectorbuffer1[16] = {0x14, 0x01, 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1};
00686   uint8_t sectorbuffer2[16] = {0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1};
00687   uint8_t sectorbuffer3[16] = {0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0x78, 0x77, 0x88, 0xC1, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
00688 
00689   // Write block 1 and 2 to the card
00690   if (!(mifareclassic_WriteDataBlock (1, sectorbuffer1)))
00691     return 0;
00692   if (!(mifareclassic_WriteDataBlock (2, sectorbuffer2)))
00693     return 0;
00694   // Write key A and access rights card
00695   if (!(mifareclassic_WriteDataBlock (3, sectorbuffer3)))
00696     return 0;
00697 
00698   // Seems that everything was OK (?!)
00699   return 1;
00700 }
00701 
00702 /**************************************************************************/
00703 /*! 
00704     Writes an NDEF URI Record to the specified sector (1..15)
00705     
00706     Note that this function assumes that the Mifare Classic card is
00707     already formatted to work as an "NFC Forum Tag" and uses a MAD1
00708     file system.  You can use the NXP TagWriter app on Android to
00709     properly format cards for this.
00710 
00711     @param  sectorNumber  The sector that the URI record should be written
00712                           to (can be 1..15 for a 1K card)
00713     @param  uriIdentifier The uri identifier code (0 = none, 0x01 = 
00714                           "http://www.", etc.)
00715     @param  url           The uri text to write (max 38 characters).
00716     
00717     @returns 1 if everything executed properly, 0 for an error
00718 */
00719 /**************************************************************************/
00720 uint8_t Adafruit_PN532::mifareclassic_WriteNDEFURI (uint8_t sectorNumber, uint8_t uriIdentifier, const char * url)
00721 {
00722   // Figure out how long the string is
00723   uint8_t len = strlen(url);
00724   
00725   // Make sure we're within a 1K limit for the sector number
00726   if ((sectorNumber < 1) || (sectorNumber > 15))
00727     return 0;
00728   
00729   // Make sure the URI payload is between 1 and 38 chars
00730   if ((len < 1) || (len > 38))
00731     return 0;
00732     
00733   // Setup the sector buffer (w/pre-formatted TLV wrapper and NDEF message)
00734   uint8_t sectorbuffer1[16] = {0x00, 0x00, 0x03, len+5, 0xD1, 0x01, len+1, 0x55, uriIdentifier, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
00735   uint8_t sectorbuffer2[16] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
00736   uint8_t sectorbuffer3[16] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
00737   uint8_t sectorbuffer4[16] = {0xD3, 0xF7, 0xD3, 0xF7, 0xD3, 0xF7, 0x7F, 0x07, 0x88, 0x40, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
00738   if (len <= 6)
00739   {
00740     // Unlikely we'll get a url this short, but why not ...
00741     memcpy (sectorbuffer1+9, url, len);
00742     sectorbuffer1[len+9] = 0xFE;
00743   }
00744   else if (len == 7)
00745   {
00746     // 0xFE needs to be wrapped around to next block
00747     memcpy (sectorbuffer1+9, url, len);
00748     sectorbuffer2[0] = 0xFE;
00749   }
00750   else if ((len > 7) || (len <= 22))
00751   {
00752     // Url fits in two blocks
00753     memcpy (sectorbuffer1+9, url, 7);
00754     memcpy (sectorbuffer2, url+7, len-7);
00755     sectorbuffer2[len-7] = 0xFE;
00756   }
00757   else if (len == 23)
00758   {
00759     // 0xFE needs to be wrapped around to final block
00760     memcpy (sectorbuffer1+9, url, 7);
00761     memcpy (sectorbuffer2, url+7, len-7);
00762     sectorbuffer3[0] = 0xFE;
00763   }
00764   else
00765   {
00766     // Url fits in three blocks
00767     memcpy (sectorbuffer1+9, url, 7);
00768     memcpy (sectorbuffer2, url+7, 16);
00769     memcpy (sectorbuffer3, url+23, len-24);
00770     sectorbuffer3[len-22] = 0xFE;
00771   }
00772   
00773   // Now write all three blocks back to the card
00774   if (!(mifareclassic_WriteDataBlock (sectorNumber*4, sectorbuffer1)))
00775     return 0;
00776   if (!(mifareclassic_WriteDataBlock ((sectorNumber*4)+1, sectorbuffer2)))
00777     return 0;
00778   if (!(mifareclassic_WriteDataBlock ((sectorNumber*4)+2, sectorbuffer3)))
00779     return 0;
00780   if (!(mifareclassic_WriteDataBlock ((sectorNumber*4)+3, sectorbuffer4)))
00781     return 0;
00782 
00783   // Seems that everything was OK (?!)
00784   return 1;
00785 }
00786 
00787 /***** Mifare Ultralight Functions ******/
00788 
00789 /**************************************************************************/
00790 /*! 
00791     Tries to read an entire 4-uint8_t page at the specified address.
00792 
00793     @param  page        The page number (0..63 in most cases)
00794     @param  buffer      Pointer to the uint8_t array that will hold the
00795                         retrieved data (if any)
00796 */
00797 /**************************************************************************/
00798 uint8_t Adafruit_PN532::mifareultralight_ReadPage (uint8_t page, uint8_t * buffer)
00799 {
00800   if (page >= 64)
00801   {
00802     #ifdef MIFAREDEBUG
00803     SERIAL_PRINTln("Page value out of range");
00804     #endif
00805     return 0;
00806   }
00807 
00808   #ifdef MIFAREDEBUG
00809     SERIAL_PRINT("Reading page ");SERIAL_PRINTln(page);
00810   #endif
00811 
00812   /* Prepare the command */
00813   pn532_packetbuffer[0] = PN532_COMMAND_INDATAEXCHANGE;
00814   pn532_packetbuffer[1] = 1;                   /* Card number */
00815   pn532_packetbuffer[2] = MIFARE_CMD_READ;     /* Mifare Read command = 0x30 */
00816   pn532_packetbuffer[3] = page;                /* Page Number (0..63 in most cases) */
00817 
00818   /* Send the command */
00819   if (! sendCommandCheckAck(pn532_packetbuffer, 4))
00820   {
00821     #ifdef MIFAREDEBUG
00822     SERIAL_PRINTln("Failed to receive ACK for write command");
00823     #endif
00824     return 0;
00825   }
00826   
00827   /* Read the response packet */
00828   readspidata(pn532_packetbuffer, 26);
00829   #ifdef MIFAREDEBUG
00830     SERIAL_PRINTln("Received: ");
00831     Adafruit_PN532::PrintHexChar(pn532_packetbuffer, 26);
00832   #endif
00833 
00834   /* If uint8_t 8 isn't 0x00 we probably have an error */
00835   if (pn532_packetbuffer[7] == 0x00)
00836   {
00837     /* Copy the 4 data uint8_ts to the output buffer         */
00838     /* Block content starts at uint8_t 9 of a valid response */
00839     /* Note that the command actually reads 16 uint8_t or 4  */
00840     /* pages at a time ... we simply discard the last 12  */
00841     /* uint8_ts                                              */
00842     memcpy (buffer, pn532_packetbuffer+8, 4);
00843   }
00844   else
00845   {
00846     #ifdef MIFAREDEBUG
00847       SERIAL_PRINTln("Unexpected response reading block: ");
00848       Adafruit_PN532::PrintHexChar(pn532_packetbuffer, 26);
00849     #endif
00850     return 0;
00851   }
00852 
00853   /* Display data for debug if requested */
00854   #ifdef MIFAREDEBUG
00855     SERIAL_PRINT("Page ");SERIAL_PRINT(page);SERIAL_PRINTln(":");
00856     Adafruit_PN532::PrintHexChar(buffer, 4);
00857   #endif
00858 
00859   // Return OK signal
00860   return 1;
00861 }
00862 
00863 
00864 
00865 /************** high level SPI */
00866 
00867 
00868 /**************************************************************************/
00869 /*! 
00870     @brief  Tries to read the SPI ACK signal
00871 */
00872 /**************************************************************************/
00873 bool Adafruit_PN532::spi_readack() {
00874   uint8_t ackbuff[6];
00875   
00876   readspidata(ackbuff, 6);
00877   
00878   return (0 == strncmp((char *)ackbuff, (char *)pn532ack, 6));
00879 }
00880 
00881 /************** mid level SPI */
00882 
00883 /**************************************************************************/
00884 /*! 
00885     @brief  Reads the SPI status register (to know if the PN532 is ready)
00886 */
00887 /**************************************************************************/
00888 uint8_t Adafruit_PN532::readspistatus(void) {
00889   _ss = 0;
00890   delay(2);
00891   spiwrite(PN532_SPI_STATREAD);
00892   // read uint8_t
00893   uint8_t x = spiread();
00894   
00895   _ss = 1;
00896   return x;
00897 }
00898 
00899 /**************************************************************************/
00900 /*! 
00901     @brief  Reads n uint8_ts of data from the PN532 via SPI
00902 
00903     @param  buff      Pointer to the buffer where data will be written
00904     @param  n         Number of uint8_ts to be read
00905 */
00906 /**************************************************************************/
00907 void Adafruit_PN532::readspidata(uint8_t* buff, uint8_t n) {
00908   _ss = 0;
00909   delay(2); 
00910   spiwrite(PN532_SPI_DATAREAD);
00911 
00912 #ifdef PN532DEBUG
00913   SERIAL_PRINT("Reading: ");
00914 #endif
00915   for (uint8_t i=0; i<n; i++) {
00916     delay(1);
00917     buff[i] = spiread();
00918 #ifdef PN532DEBUG
00919     SERIAL_PRINT(" 0x");
00920     SERIAL_PRINT(buff[i], HEX);
00921 #endif
00922   }
00923 
00924 #ifdef PN532DEBUG
00925   SERIAL_PRINTln();
00926 #endif
00927 
00928   _ss = 1;
00929 }
00930 
00931 /**************************************************************************/
00932 /*! 
00933     @brief  Writes a command to the PN532, automatically inserting the
00934             preamble and required frame details (checksum, len, etc.)
00935 
00936     @param  cmd       Pointer to the command buffer
00937     @param  cmdlen    Command length in uint8_ts 
00938 */
00939 /**************************************************************************/
00940 void Adafruit_PN532::spiwritecommand(uint8_t* cmd, uint8_t cmdlen) {
00941   uint8_t checksum;
00942 
00943   cmdlen++;
00944   
00945 #ifdef PN532DEBUG
00946   SERIAL_PRINT("\nSending: ");
00947 #endif
00948 
00949   _ss = 0;
00950   delay(2);     // or whatever the delay is for waking up the board
00951   spiwrite(PN532_SPI_DATAWRITE);
00952 
00953   checksum = PN532_PREAMBLE + PN532_PREAMBLE + PN532_STARTCODE2;
00954   spiwrite(PN532_PREAMBLE);
00955   spiwrite(PN532_PREAMBLE);
00956   spiwrite(PN532_STARTCODE2);
00957 
00958   spiwrite(cmdlen);
00959   spiwrite(~cmdlen + 1);
00960  
00961   spiwrite(PN532_HOSTTOPN532);
00962   checksum += PN532_HOSTTOPN532;
00963 
00964 #ifdef PN532DEBUG
00965   SERIAL_PRINT(" 0x"); SERIAL_PRINT(PN532_PREAMBLE, HEX);
00966   SERIAL_PRINT(" 0x"); SERIAL_PRINT(PN532_PREAMBLE, HEX);
00967   SERIAL_PRINT(" 0x"); SERIAL_PRINT(PN532_STARTCODE2, HEX);
00968   SERIAL_PRINT(" 0x"); SERIAL_PRINT(cmdlen, HEX);
00969   SERIAL_PRINT(" 0x"); SERIAL_PRINT(~cmdlen + 1, HEX);
00970   SERIAL_PRINT(" 0x"); SERIAL_PRINT(PN532_HOSTTOPN532, HEX);
00971 #endif
00972 
00973   for (uint8_t i=0; i<cmdlen-1; i++) {
00974    spiwrite(cmd[i]);
00975    checksum += cmd[i];
00976 #ifdef PN532DEBUG
00977    SERIAL_PRINT(" 0x"); SERIAL_PRINT(cmd[i], HEX);
00978 #endif
00979   }
00980   
00981   spiwrite(~checksum);
00982   spiwrite(PN532_POSTAMBLE);
00983   _ss = 1;
00984 
00985 #ifdef PN532DEBUG
00986   SERIAL_PRINT(" 0x"); SERIAL_PRINT(~checksum, HEX);
00987   SERIAL_PRINT(" 0x"); SERIAL_PRINT(PN532_POSTAMBLE, HEX);
00988   SERIAL_PRINTln();
00989 #endif
00990 } 
00991 /************** low level SPI */
00992 
00993 /**************************************************************************/
00994 /*! 
00995     @brief  Low-level SPI write wrapper
00996 
00997     @param  c       8-bit command to write to the SPI bus
00998 */
00999 /**************************************************************************/
01000 void Adafruit_PN532::spiwrite(uint8_t c) {
01001   int8_t i;
01002   _clk = 1;
01003   
01004   for (i=0; i<8; i++) {
01005     _clk = 0;
01006     if (c & _BV(i)) {
01007       _mosi = 1;
01008     } else {
01009       _mosi = 0;
01010     }
01011     _clk = 1;
01012   }
01013 }
01014 
01015 /**************************************************************************/
01016 /*! 
01017     @brief  Low-level SPI read wrapper
01018 
01019     @returns The 8-bit value that was read from the SPI bus
01020 */
01021 /**************************************************************************/
01022 uint8_t Adafruit_PN532::spiread(void) {
01023   int8_t i, x;
01024   x = 0;
01025   _clk = 1;
01026 
01027   for (i=0; i<8; i++) {
01028     if (_miso.read()) {
01029       x |= _BV(i);
01030     }
01031     _clk = 0;
01032     _clk = 1;
01033   }
01034   return x;
01035 }