Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Fork of readMifare by
Adafruit_PN532.cpp
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("\r\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 "); 00540 SERIAL_PRINT(keyNumber ? "B" : "A"); 00541 SERIAL_PRINT(": "); 00542 Adafruit_PN532::PrintHex(_key, 6); 00543 #endif 00544 00545 // Prepare the authentication command // 00546 pn532_packetbuffer[0] = PN532_COMMAND_INDATAEXCHANGE; /* Data Exchange Header */ 00547 pn532_packetbuffer[1] = 1; /* Max card numbers */ 00548 pn532_packetbuffer[2] = (keyNumber) ? MIFARE_CMD_AUTH_B : MIFARE_CMD_AUTH_A; 00549 pn532_packetbuffer[3] = blockNumber; /* Block Number (1K = 0..63, 4K = 0..255 */ 00550 memcpy (pn532_packetbuffer+4, _key, 6); 00551 for (i = 0; i < _uidLen; i++) 00552 { 00553 pn532_packetbuffer[10+i] = _uid[i]; /* 4 uint8_t card ID */ 00554 } 00555 00556 printf("Auth request:\r\n"); 00557 Adafruit_PN532::PrintHexChar(pn532_packetbuffer, 10+_uidLen); 00558 printf("\r\n"); 00559 00560 if (! sendCommandCheckAck(pn532_packetbuffer, 10+_uidLen)) 00561 return 0; 00562 00563 // Read the response packet 00564 readspidata(pn532_packetbuffer, 12); 00565 // check if the response is valid and we are authenticated??? 00566 // for an auth success it should be uint8_ts 5-7: 0xD5 0x41 0x00 00567 // Mifare auth error is technically uint8_t 7: 0x14 but anything other and 0x00 is not good 00568 if (pn532_packetbuffer[7] != 0x00) 00569 { 00570 #ifdef PN532DEBUG 00571 SERIAL_PRINT("Authentification failed: "); 00572 #endif 00573 return 0; 00574 } 00575 printf("Auth response:\r\n"); 00576 Adafruit_PN532::PrintHexChar(pn532_packetbuffer, 20); 00577 printf("\r\n"); 00578 return 1; 00579 } 00580 00581 /**************************************************************************/ 00582 /*! 00583 Tries to read an entire 16-uint8_t data block at the specified block 00584 address. 00585 00586 @param blockNumber The block number to authenticate. (0..63 for 00587 1KB cards, and 0..255 for 4KB cards). 00588 @param data Pointer to the uint8_t array that will hold the 00589 retrieved data (if any) 00590 00591 @returns 1 if everything executed properly, 0 for an error 00592 */ 00593 /**************************************************************************/ 00594 uint8_t Adafruit_PN532::mifareclassic_ReadDataBlock (uint8_t blockNumber, uint8_t * data) 00595 { 00596 #ifdef MIFAREDEBUG 00597 SERIAL_PRINT("Trying to read 16 uint8_ts from block ");SERIAL_PRINTln(blockNumber); 00598 #endif 00599 00600 /* Prepare the command */ 00601 00602 uint8_t pn532_packetbuffer2[PN532_PACKBUFFSIZ]; 00603 pn532_packetbuffer2[0] = PN532_COMMAND_INDATAEXCHANGE; /* 0x40 */ 00604 pn532_packetbuffer2[1] = 1; /* Card number */ 00605 pn532_packetbuffer2[2] = MIFARE_CMD_READ; /* Mifare Read command = 0x30 */ 00606 pn532_packetbuffer2[3] = blockNumber; /* Block Number (0..63 for 1K, 0..255 for 4K) */ 00607 00608 printf("Read request:\r\n"); 00609 Adafruit_PN532::PrintHexChar(pn532_packetbuffer2, 4); 00610 printf("\r\n"); 00611 00612 /* Send the command */ 00613 if (! sendCommandCheckAck(pn532_packetbuffer2, 4)) 00614 { 00615 #ifdef MIFAREDEBUG 00616 SERIAL_PRINTln("Failed to receive ACK for read command"); 00617 #endif 00618 return 0; 00619 } 00620 00621 /* Read the response packet */ 00622 readspidata(pn532_packetbuffer2, 26); 00623 00624 /* If uint8_t 8 isn't 0x00 we probably have an error */ 00625 if (pn532_packetbuffer2[7] != 0x00) 00626 { 00627 //#ifdef MIFAREDEBUG 00628 SERIAL_PRINT("Unexpected response"); 00629 Adafruit_PN532::PrintHexChar(pn532_packetbuffer2, 26); 00630 //#endif 00631 return 0; 00632 } 00633 00634 /* Copy the 16 data uint8_ts to the output buffer */ 00635 /* Block content starts at uint8_t 9 of a valid response */ 00636 memcpy (data, pn532_packetbuffer2+8, 16); 00637 00638 00639 printf("Read response:\r\n"); 00640 Adafruit_PN532::PrintHexChar(pn532_packetbuffer2, 26); 00641 printf("\r\n"); 00642 00643 return 1; 00644 } 00645 00646 /**************************************************************************/ 00647 /*! 00648 Tries to write an entire 16-uint8_t data block at the specified block 00649 address. 00650 00651 @param blockNumber The block number to authenticate. (0..63 for 00652 1KB cards, and 0..255 for 4KB cards). 00653 @param data The uint8_t array that contains the data to write. 00654 00655 @returns 1 if everything executed properly, 0 for an error 00656 */ 00657 /**************************************************************************/ 00658 uint8_t Adafruit_PN532::mifareclassic_WriteDataBlock (uint8_t blockNumber, uint8_t * data) 00659 { 00660 #ifdef MIFAREDEBUG 00661 SERIAL_PRINT("Trying to write 16 uint8_ts to block ");SERIAL_PRINTln(blockNumber); 00662 #endif 00663 00664 /* Prepare the first command */ 00665 pn532_packetbuffer[0] = PN532_COMMAND_INDATAEXCHANGE; 00666 pn532_packetbuffer[1] = 1; /* Card number */ 00667 pn532_packetbuffer[2] = MIFARE_CMD_WRITE; /* Mifare Write command = 0xA0 */ 00668 pn532_packetbuffer[3] = blockNumber; /* Block Number (0..63 for 1K, 0..255 for 4K) */ 00669 memcpy (pn532_packetbuffer+4, data, 16); /* Data Payload */ 00670 00671 /* Send the command */ 00672 if (! sendCommandCheckAck(pn532_packetbuffer, 20)) 00673 { 00674 #ifdef MIFAREDEBUG 00675 SERIAL_PRINTln("Failed to receive ACK for write command"); 00676 #endif 00677 return 0; 00678 } 00679 delay(10); 00680 00681 /* Read the response packet */ 00682 readspidata(pn532_packetbuffer, 26); 00683 00684 return 1; 00685 } 00686 00687 /**************************************************************************/ 00688 /*! 00689 Formats a Mifare Classic card to store NDEF Records 00690 00691 @returns 1 if everything executed properly, 0 for an error 00692 */ 00693 /**************************************************************************/ 00694 uint8_t Adafruit_PN532::mifareclassic_FormatNDEF (void) 00695 { 00696 uint8_t sectorbuffer1[16] = {0x14, 0x01, 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1}; 00697 uint8_t sectorbuffer2[16] = {0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1}; 00698 uint8_t sectorbuffer3[16] = {0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0x78, 0x77, 0x88, 0xC1, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; 00699 00700 // Write block 1 and 2 to the card 00701 if (!(mifareclassic_WriteDataBlock (1, sectorbuffer1))) 00702 return 0; 00703 if (!(mifareclassic_WriteDataBlock (2, sectorbuffer2))) 00704 return 0; 00705 // Write key A and access rights card 00706 if (!(mifareclassic_WriteDataBlock (3, sectorbuffer3))) 00707 return 0; 00708 00709 // Seems that everything was OK (?!) 00710 return 1; 00711 } 00712 00713 /**************************************************************************/ 00714 /*! 00715 Writes an NDEF URI Record to the specified sector (1..15) 00716 00717 Note that this function assumes that the Mifare Classic card is 00718 already formatted to work as an "NFC Forum Tag" and uses a MAD1 00719 file system. You can use the NXP TagWriter app on Android to 00720 properly format cards for this. 00721 00722 @param sectorNumber The sector that the URI record should be written 00723 to (can be 1..15 for a 1K card) 00724 @param uriIdentifier The uri identifier code (0 = none, 0x01 = 00725 "http://www.", etc.) 00726 @param url The uri text to write (max 38 characters). 00727 00728 @returns 1 if everything executed properly, 0 for an error 00729 */ 00730 /**************************************************************************/ 00731 uint8_t Adafruit_PN532::mifareclassic_WriteNDEFURI (uint8_t sectorNumber, uint8_t uriIdentifier, const char * url) 00732 { 00733 // Figure out how long the string is 00734 uint8_t len = strlen(url); 00735 00736 // Make sure we're within a 1K limit for the sector number 00737 if ((sectorNumber < 1) || (sectorNumber > 15)) 00738 return 0; 00739 00740 // Make sure the URI payload is between 1 and 38 chars 00741 if ((len < 1) || (len > 38)) 00742 return 0; 00743 00744 // Setup the sector buffer (w/pre-formatted TLV wrapper and NDEF message) 00745 uint8_t sectorbuffer1[16] = {0x00, 0x00, 0x03, len+5, 0xD1, 0x01, len+1, 0x55, uriIdentifier, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; 00746 uint8_t sectorbuffer2[16] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; 00747 uint8_t sectorbuffer3[16] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; 00748 uint8_t sectorbuffer4[16] = {0xD3, 0xF7, 0xD3, 0xF7, 0xD3, 0xF7, 0x7F, 0x07, 0x88, 0x40, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; 00749 if (len <= 6) 00750 { 00751 // Unlikely we'll get a url this short, but why not ... 00752 memcpy (sectorbuffer1+9, url, len); 00753 sectorbuffer1[len+9] = 0xFE; 00754 } 00755 else if (len == 7) 00756 { 00757 // 0xFE needs to be wrapped around to next block 00758 memcpy (sectorbuffer1+9, url, len); 00759 sectorbuffer2[0] = 0xFE; 00760 } 00761 else if ((len > 7) || (len <= 22)) 00762 { 00763 // Url fits in two blocks 00764 memcpy (sectorbuffer1+9, url, 7); 00765 memcpy (sectorbuffer2, url+7, len-7); 00766 sectorbuffer2[len-7] = 0xFE; 00767 } 00768 else if (len == 23) 00769 { 00770 // 0xFE needs to be wrapped around to final block 00771 memcpy (sectorbuffer1+9, url, 7); 00772 memcpy (sectorbuffer2, url+7, len-7); 00773 sectorbuffer3[0] = 0xFE; 00774 } 00775 else 00776 { 00777 // Url fits in three blocks 00778 memcpy (sectorbuffer1+9, url, 7); 00779 memcpy (sectorbuffer2, url+7, 16); 00780 memcpy (sectorbuffer3, url+23, len-24); 00781 sectorbuffer3[len-22] = 0xFE; 00782 } 00783 00784 // Now write all three blocks back to the card 00785 if (!(mifareclassic_WriteDataBlock (sectorNumber*4, sectorbuffer1))) 00786 return 0; 00787 if (!(mifareclassic_WriteDataBlock ((sectorNumber*4)+1, sectorbuffer2))) 00788 return 0; 00789 if (!(mifareclassic_WriteDataBlock ((sectorNumber*4)+2, sectorbuffer3))) 00790 return 0; 00791 if (!(mifareclassic_WriteDataBlock ((sectorNumber*4)+3, sectorbuffer4))) 00792 return 0; 00793 00794 // Seems that everything was OK (?!) 00795 return 1; 00796 } 00797 00798 /***** Mifare Ultralight Functions ******/ 00799 00800 /**************************************************************************/ 00801 /*! 00802 Tries to read an entire 4-uint8_t page at the specified address. 00803 00804 @param page The page number (0..63 in most cases) 00805 @param buffer Pointer to the uint8_t array that will hold the 00806 retrieved data (if any) 00807 */ 00808 /**************************************************************************/ 00809 uint8_t Adafruit_PN532::mifareultralight_ReadPage (uint8_t page, uint8_t * buffer) 00810 { 00811 if (page >= 64) 00812 { 00813 #ifdef MIFAREDEBUG 00814 SERIAL_PRINTln("Page value out of range"); 00815 #endif 00816 return 0; 00817 } 00818 00819 #ifdef MIFAREDEBUG 00820 SERIAL_PRINT("Reading page ");SERIAL_PRINTln(page); 00821 #endif 00822 00823 /* Prepare the command */ 00824 pn532_packetbuffer[0] = PN532_COMMAND_INDATAEXCHANGE; 00825 pn532_packetbuffer[1] = 1; /* Card number */ 00826 pn532_packetbuffer[2] = MIFARE_CMD_READ; /* Mifare Read command = 0x30 */ 00827 pn532_packetbuffer[3] = page; /* Page Number (0..63 in most cases) */ 00828 00829 /* Send the command */ 00830 if (! sendCommandCheckAck(pn532_packetbuffer, 4)) 00831 { 00832 #ifdef MIFAREDEBUG 00833 SERIAL_PRINTln("Failed to receive ACK for write command"); 00834 #endif 00835 return 0; 00836 } 00837 00838 /* Read the response packet */ 00839 readspidata(pn532_packetbuffer, 26); 00840 #ifdef MIFAREDEBUG 00841 SERIAL_PRINTln("Received: "); 00842 Adafruit_PN532::PrintHexChar(pn532_packetbuffer, 26); 00843 #endif 00844 00845 /* If uint8_t 8 isn't 0x00 we probably have an error */ 00846 if (pn532_packetbuffer[7] == 0x00) 00847 { 00848 /* Copy the 4 data uint8_ts to the output buffer */ 00849 /* Block content starts at uint8_t 9 of a valid response */ 00850 /* Note that the command actually reads 16 uint8_t or 4 */ 00851 /* pages at a time ... we simply discard the last 12 */ 00852 /* uint8_ts */ 00853 memcpy (buffer, pn532_packetbuffer+8, 4); 00854 } 00855 else 00856 { 00857 #ifdef MIFAREDEBUG 00858 SERIAL_PRINTln("Unexpected response reading block: "); 00859 Adafruit_PN532::PrintHexChar(pn532_packetbuffer, 26); 00860 #endif 00861 return 0; 00862 } 00863 00864 /* Display data for debug if requested */ 00865 #ifdef MIFAREDEBUG 00866 SERIAL_PRINT("Page ");SERIAL_PRINT(page);SERIAL_PRINTln(":"); 00867 Adafruit_PN532::PrintHexChar(buffer, 4); 00868 #endif 00869 00870 // Return OK signal 00871 return 1; 00872 } 00873 00874 00875 00876 /************** high level SPI */ 00877 00878 00879 /**************************************************************************/ 00880 /*! 00881 @brief Tries to read the SPI ACK signal 00882 */ 00883 /**************************************************************************/ 00884 bool Adafruit_PN532::spi_readack() { 00885 uint8_t ackbuff[6]; 00886 00887 readspidata(ackbuff, 6); 00888 00889 return (0 == strncmp((char *)ackbuff, (char *)pn532ack, 6)); 00890 } 00891 00892 /************** mid level SPI */ 00893 00894 /**************************************************************************/ 00895 /*! 00896 @brief Reads the SPI status register (to know if the PN532 is ready) 00897 */ 00898 /**************************************************************************/ 00899 uint8_t Adafruit_PN532::readspistatus(void) { 00900 _ss = 0; 00901 delay(2); 00902 spiwrite(PN532_SPI_STATREAD); 00903 // read uint8_t 00904 uint8_t x = spiread(); 00905 00906 _ss = 1; 00907 return x; 00908 } 00909 00910 /**************************************************************************/ 00911 /*! 00912 @brief Reads n uint8_ts of data from the PN532 via SPI 00913 00914 @param buff Pointer to the buffer where data will be written 00915 @param n Number of uint8_ts to be read 00916 */ 00917 /**************************************************************************/ 00918 void Adafruit_PN532::readspidata(uint8_t* buff, uint8_t n) { 00919 _ss = 0; 00920 delay(2); 00921 spiwrite(PN532_SPI_DATAREAD); 00922 00923 #ifdef PN532DEBUG 00924 SERIAL_PRINT("Reading: "); 00925 #endif 00926 for (uint8_t i=0; i<n; i++) { 00927 delay(1); 00928 buff[i] = spiread(); 00929 #ifdef PN532DEBUG 00930 SERIAL_PRINT(" 0x"); 00931 SERIAL_PRINT(buff[i], HEX); 00932 #endif 00933 } 00934 00935 #ifdef PN532DEBUG 00936 SERIAL_PRINTln(); 00937 #endif 00938 00939 _ss = 1; 00940 } 00941 00942 /**************************************************************************/ 00943 /*! 00944 @brief Writes a command to the PN532, automatically inserting the 00945 preamble and required frame details (checksum, len, etc.) 00946 00947 @param cmd Pointer to the command buffer 00948 @param cmdlen Command length in uint8_ts 00949 */ 00950 /**************************************************************************/ 00951 void Adafruit_PN532::spiwritecommand(uint8_t* cmd, uint8_t cmdlen) { 00952 uint8_t checksum; 00953 00954 cmdlen++; 00955 00956 #ifdef PN532DEBUG 00957 SERIAL_PRINT("\r\nSending: "); 00958 #endif 00959 00960 _ss = 0; 00961 delay(2); // or whatever the delay is for waking up the board 00962 spiwrite(PN532_SPI_DATAWRITE); 00963 00964 checksum = PN532_PREAMBLE + PN532_PREAMBLE + PN532_STARTCODE2; 00965 spiwrite(PN532_PREAMBLE); 00966 spiwrite(PN532_PREAMBLE); 00967 spiwrite(PN532_STARTCODE2); 00968 00969 spiwrite(cmdlen); 00970 spiwrite(~cmdlen + 1); 00971 00972 spiwrite(PN532_HOSTTOPN532); 00973 checksum += PN532_HOSTTOPN532; 00974 00975 #ifdef PN532DEBUG 00976 SERIAL_PRINT(" 0x"); SERIAL_PRINT(PN532_PREAMBLE, HEX); 00977 SERIAL_PRINT(" 0x"); SERIAL_PRINT(PN532_PREAMBLE, HEX); 00978 SERIAL_PRINT(" 0x"); SERIAL_PRINT(PN532_STARTCODE2, HEX); 00979 SERIAL_PRINT(" 0x"); SERIAL_PRINT(cmdlen, HEX); 00980 SERIAL_PRINT(" 0x"); SERIAL_PRINT(~cmdlen + 1, HEX); 00981 SERIAL_PRINT(" 0x"); SERIAL_PRINT(PN532_HOSTTOPN532, HEX); 00982 #endif 00983 00984 for (uint8_t i=0; i<cmdlen-1; i++) { 00985 spiwrite(cmd[i]); 00986 checksum += cmd[i]; 00987 #ifdef PN532DEBUG 00988 SERIAL_PRINT(" 0x"); SERIAL_PRINT(cmd[i], HEX); 00989 #endif 00990 } 00991 00992 spiwrite(~checksum); 00993 spiwrite(PN532_POSTAMBLE); 00994 _ss = 1; 00995 00996 #ifdef PN532DEBUG 00997 SERIAL_PRINT(" 0x"); SERIAL_PRINT(~checksum, HEX); 00998 SERIAL_PRINT(" 0x"); SERIAL_PRINT(PN532_POSTAMBLE, HEX); 00999 SERIAL_PRINTln(); 01000 #endif 01001 } 01002 /************** low level SPI */ 01003 01004 /**************************************************************************/ 01005 /*! 01006 @brief Low-level SPI write wrapper 01007 01008 @param c 8-bit command to write to the SPI bus 01009 */ 01010 /**************************************************************************/ 01011 void Adafruit_PN532::spiwrite(uint8_t c) { 01012 int8_t i; 01013 _clk = 1; 01014 01015 for (i=0; i<8; i++) { 01016 _clk = 0; 01017 if (c & _BV(i)) { 01018 _mosi = 1; 01019 } else { 01020 _mosi = 0; 01021 } 01022 _clk = 1; 01023 } 01024 } 01025 01026 /**************************************************************************/ 01027 /*! 01028 @brief Low-level SPI read wrapper 01029 01030 @returns The 8-bit value that was read from the SPI bus 01031 */ 01032 /**************************************************************************/ 01033 uint8_t Adafruit_PN532::spiread(void) { 01034 int8_t i, x; 01035 x = 0; 01036 _clk = 1; 01037 01038 for (i=0; i<8; i++) { 01039 if (_miso.read()) { 01040 x |= _BV(i); 01041 } 01042 _clk = 0; 01043 _clk = 1; 01044 } 01045 return x; 01046 }
Generated on Tue Aug 2 2022 00:11:44 by
