PN532 NFC library for Seeed Studio's NFC Shield

Fork of PN532 by Yihui Xiong

Committer:
yihui
Date:
Thu Oct 17 06:51:32 2013 +0000
Revision:
2:f618fb2169c4
Parent:
1:b8cab5222fd0
Child:
3:4189a10038e6
PN532::readPassiveTargetID() add timeout parameter

Who changed what in which revision?

UserRevisionLine numberNew contents of line
yihui 1:b8cab5222fd0 1 /**************************************************************************/
yihui 1:b8cab5222fd0 2 /*!
yihui 1:b8cab5222fd0 3 @file PN532.cpp
yihui 1:b8cab5222fd0 4 @author Adafruit Industries & Seeed Technology Inc.
yihui 1:b8cab5222fd0 5
yihui 1:b8cab5222fd0 6 NXP's PN532 NFC/13.56MHz RFID Transceiver
yihui 1:b8cab5222fd0 7
yihui 1:b8cab5222fd0 8 @section HISTORY
yihui 1:b8cab5222fd0 9 v1.6 - Ported to mbed
yihui 1:b8cab5222fd0 10
yihui 1:b8cab5222fd0 11 v1.5 - Modified to support I2C and SPI
yihui 1:b8cab5222fd0 12
yihui 1:b8cab5222fd0 13 v1.4 - Added setPassiveActivationRetries()
yihui 1:b8cab5222fd0 14
yihui 1:b8cab5222fd0 15 v1.3 - Modified to work with I2C
yihui 1:b8cab5222fd0 16
yihui 1:b8cab5222fd0 17 v1.2 - Added writeGPIO()
yihui 1:b8cab5222fd0 18 - Added readGPIO()
yihui 1:b8cab5222fd0 19
yihui 1:b8cab5222fd0 20 v1.1 - Changed readPassiveTargetID() to handle multiple UID sizes
yihui 1:b8cab5222fd0 21 - Added the following helper functions for text display
yihui 1:b8cab5222fd0 22 static void PrintHex(const uint8_t * data, const uint32_t numBytes)
yihui 1:b8cab5222fd0 23 static void PrintHexChar(const uint8_t * pbtData, const uint32_t numBytes)
yihui 1:b8cab5222fd0 24 - Added the following Mifare Classic functions:
yihui 1:b8cab5222fd0 25 bool mifareclassic_IsFirstBlock (uint32_t uiBlock)
yihui 1:b8cab5222fd0 26 bool mifareclassic_IsTrailerBlock (uint32_t uiBlock)
yihui 1:b8cab5222fd0 27 uint8_t mifareclassic_AuthenticateBlock (uint8_t * uid, uint8_t uidLen, uint32_t blockNumber, uint8_t keyNumber, uint8_t * keyData)
yihui 1:b8cab5222fd0 28 uint8_t mifareclassic_ReadDataBlock (uint8_t blockNumber, uint8_t * data)
yihui 1:b8cab5222fd0 29 uint8_t mifareclassic_WriteDataBlock (uint8_t blockNumber, uint8_t * data)
yihui 1:b8cab5222fd0 30 - Added the following Mifare Ultalight functions:
yihui 1:b8cab5222fd0 31 uint8_t mifareultralight_ReadPage (uint8_t page, uint8_t * buffer)
yihui 1:b8cab5222fd0 32 */
yihui 1:b8cab5222fd0 33 /**************************************************************************/
yihui 0:9c6b9280c0e1 34
yihui 0:9c6b9280c0e1 35 #include <string.h>
yihui 0:9c6b9280c0e1 36 #include "PN532.h"
yihui 0:9c6b9280c0e1 37 #include "debug.h"
yihui 0:9c6b9280c0e1 38
yihui 0:9c6b9280c0e1 39 #include "PN532_SPI.h"
yihui 0:9c6b9280c0e1 40
yihui 0:9c6b9280c0e1 41 #define HAL(func) (_interface->func)
yihui 0:9c6b9280c0e1 42
yihui 0:9c6b9280c0e1 43 uint8_t pn532response_firmwarevers[] = {0x00, 0xFF, 0x06, 0xFA, 0xD5, 0x03};
yihui 0:9c6b9280c0e1 44
yihui 0:9c6b9280c0e1 45 // Uncomment these lines to enable debug output for PN532(I2C) and/or MIFARE related code
yihui 0:9c6b9280c0e1 46 #define PN532DEBUG
yihui 0:9c6b9280c0e1 47 // #define MIFAREDEBUG
yihui 0:9c6b9280c0e1 48
yihui 0:9c6b9280c0e1 49 #define PN532_PACKBUFFSIZ 128
yihui 0:9c6b9280c0e1 50 uint8_t pn532_packetbuffer[PN532_PACKBUFFSIZ];
yihui 0:9c6b9280c0e1 51
yihui 1:b8cab5222fd0 52
yihui 0:9c6b9280c0e1 53 PN532::PN532(PN532Interface &interface)
yihui 0:9c6b9280c0e1 54 {
yihui 1:b8cab5222fd0 55 _interface = &interface;
yihui 0:9c6b9280c0e1 56 }
yihui 0:9c6b9280c0e1 57
yihui 0:9c6b9280c0e1 58 PN532::PN532(PinName mosi, PinName miso, PinName sclk, PinName cs)
yihui 0:9c6b9280c0e1 59 {
yihui 0:9c6b9280c0e1 60 _spi = new SPI(mosi, miso, sclk);
yihui 0:9c6b9280c0e1 61 _interface = new PN532_SPI(_spi, cs);
yihui 0:9c6b9280c0e1 62 }
yihui 0:9c6b9280c0e1 63
yihui 0:9c6b9280c0e1 64 PN532::~PN532()
yihui 0:9c6b9280c0e1 65 {
yihui 0:9c6b9280c0e1 66 if (_spi) {
yihui 0:9c6b9280c0e1 67 delete _spi;
yihui 0:9c6b9280c0e1 68 }
yihui 0:9c6b9280c0e1 69 }
yihui 0:9c6b9280c0e1 70
yihui 0:9c6b9280c0e1 71 /**************************************************************************/
yihui 1:b8cab5222fd0 72 /*!
yihui 0:9c6b9280c0e1 73 @brief Setups the HW
yihui 0:9c6b9280c0e1 74 */
yihui 0:9c6b9280c0e1 75 /**************************************************************************/
yihui 0:9c6b9280c0e1 76 void PN532::begin()
yihui 0:9c6b9280c0e1 77 {
yihui 0:9c6b9280c0e1 78 HAL(begin)();
yihui 0:9c6b9280c0e1 79 HAL(wakeup)();
yihui 0:9c6b9280c0e1 80 }
yihui 1:b8cab5222fd0 81
yihui 0:9c6b9280c0e1 82 /**************************************************************************/
yihui 1:b8cab5222fd0 83 /*!
yihui 0:9c6b9280c0e1 84 @brief Prints a hexadecimal value in plain characters
yihui 0:9c6b9280c0e1 85
yihui 0:9c6b9280c0e1 86 @param data Pointer to the uint8_t data
yihui 0:9c6b9280c0e1 87 @param numBytes Data length in bytes
yihui 0:9c6b9280c0e1 88 */
yihui 0:9c6b9280c0e1 89 /**************************************************************************/
yihui 1:b8cab5222fd0 90 void PN532::PrintHex(const uint8_t *data, const uint32_t numBytes)
yihui 0:9c6b9280c0e1 91 {
yihui 1:b8cab5222fd0 92 for (uint8_t i = 0; i < numBytes; i++) {
yihui 1:b8cab5222fd0 93 DMSG("0x");
yihui 1:b8cab5222fd0 94 DMSG_HEX(data[i]);
yihui 1:b8cab5222fd0 95 }
yihui 1:b8cab5222fd0 96 DMSG("\n");
yihui 0:9c6b9280c0e1 97 }
yihui 0:9c6b9280c0e1 98
yihui 0:9c6b9280c0e1 99 /**************************************************************************/
yihui 1:b8cab5222fd0 100 /*!
yihui 0:9c6b9280c0e1 101 @brief Prints a hexadecimal value in plain characters, along with
yihui 0:9c6b9280c0e1 102 the char equivalents in the following format
yihui 0:9c6b9280c0e1 103
yihui 0:9c6b9280c0e1 104 00 00 00 00 00 00 ......
yihui 0:9c6b9280c0e1 105
yihui 1:b8cab5222fd0 106 @param data Pointer to the data
yihui 0:9c6b9280c0e1 107 @param numBytes Data length in bytes
yihui 0:9c6b9280c0e1 108 */
yihui 0:9c6b9280c0e1 109 /**************************************************************************/
yihui 1:b8cab5222fd0 110 void PN532::PrintHexChar(const uint8_t *data, const uint32_t numBytes)
yihui 0:9c6b9280c0e1 111 {
yihui 1:b8cab5222fd0 112 for (uint8_t i = 0; i < numBytes; i++) {
yihui 1:b8cab5222fd0 113 DMSG("0x");
yihui 1:b8cab5222fd0 114 DMSG_HEX(data[i]);
yihui 1:b8cab5222fd0 115 }
yihui 1:b8cab5222fd0 116 DMSG("\n");
yihui 0:9c6b9280c0e1 117 }
yihui 1:b8cab5222fd0 118
yihui 0:9c6b9280c0e1 119 /**************************************************************************/
yihui 1:b8cab5222fd0 120 /*!
yihui 0:9c6b9280c0e1 121 @brief Checks the firmware version of the PN5xx chip
yihui 0:9c6b9280c0e1 122
yihui 0:9c6b9280c0e1 123 @returns The chip's firmware version and ID
yihui 0:9c6b9280c0e1 124 */
yihui 0:9c6b9280c0e1 125 /**************************************************************************/
yihui 1:b8cab5222fd0 126 uint32_t PN532::getFirmwareVersion(void)
yihui 1:b8cab5222fd0 127 {
yihui 1:b8cab5222fd0 128 uint32_t response;
yihui 0:9c6b9280c0e1 129
yihui 1:b8cab5222fd0 130 pn532_packetbuffer[0] = PN532_COMMAND_GETFIRMWAREVERSION;
yihui 1:b8cab5222fd0 131
yihui 1:b8cab5222fd0 132 if (HAL(writeCommand)(pn532_packetbuffer, 1)) {
yihui 1:b8cab5222fd0 133 return 0;
yihui 1:b8cab5222fd0 134 }
yihui 0:9c6b9280c0e1 135
yihui 1:b8cab5222fd0 136 // read data packet
yihui 1:b8cab5222fd0 137 int16_t status = HAL(readResponse)(pn532_packetbuffer, sizeof(pn532_packetbuffer));
yihui 1:b8cab5222fd0 138 if (0 > status) {
yihui 1:b8cab5222fd0 139 return 0;
yihui 1:b8cab5222fd0 140 }
yihui 0:9c6b9280c0e1 141
yihui 1:b8cab5222fd0 142 response = pn532_packetbuffer[0];
yihui 1:b8cab5222fd0 143 response <<= 8;
yihui 1:b8cab5222fd0 144 response |= pn532_packetbuffer[1];
yihui 1:b8cab5222fd0 145 response <<= 8;
yihui 1:b8cab5222fd0 146 response |= pn532_packetbuffer[2];
yihui 1:b8cab5222fd0 147 response <<= 8;
yihui 1:b8cab5222fd0 148 response |= pn532_packetbuffer[3];
yihui 1:b8cab5222fd0 149
yihui 1:b8cab5222fd0 150 return response;
yihui 0:9c6b9280c0e1 151 }
yihui 0:9c6b9280c0e1 152
yihui 0:9c6b9280c0e1 153
yihui 0:9c6b9280c0e1 154 /**************************************************************************/
yihui 1:b8cab5222fd0 155 /*!
yihui 0:9c6b9280c0e1 156 Writes an 8-bit value that sets the state of the PN532's GPIO pins
yihui 1:b8cab5222fd0 157
yihui 0:9c6b9280c0e1 158 @warning This function is provided exclusively for board testing and
yihui 0:9c6b9280c0e1 159 is dangerous since it will throw an error if any pin other
yihui 0:9c6b9280c0e1 160 than the ones marked "Can be used as GPIO" are modified! All
yihui 0:9c6b9280c0e1 161 pins that can not be used as GPIO should ALWAYS be left high
yihui 0:9c6b9280c0e1 162 (value = 1) or the system will become unstable and a HW reset
yihui 0:9c6b9280c0e1 163 will be required to recover the PN532.
yihui 1:b8cab5222fd0 164
yihui 0:9c6b9280c0e1 165 pinState[0] = P30 Can be used as GPIO
yihui 0:9c6b9280c0e1 166 pinState[1] = P31 Can be used as GPIO
yihui 0:9c6b9280c0e1 167 pinState[2] = P32 *** RESERVED (Must be 1!) ***
yihui 0:9c6b9280c0e1 168 pinState[3] = P33 Can be used as GPIO
yihui 0:9c6b9280c0e1 169 pinState[4] = P34 *** RESERVED (Must be 1!) ***
yihui 0:9c6b9280c0e1 170 pinState[5] = P35 Can be used as GPIO
yihui 1:b8cab5222fd0 171
yihui 0:9c6b9280c0e1 172 @returns 1 if everything executed properly, 0 for an error
yihui 0:9c6b9280c0e1 173 */
yihui 0:9c6b9280c0e1 174 /**************************************************************************/
yihui 1:b8cab5222fd0 175 bool PN532::writeGPIO(uint8_t pinstate)
yihui 1:b8cab5222fd0 176 {
yihui 1:b8cab5222fd0 177 // Make sure pinstate does not try to toggle P32 or P34
yihui 1:b8cab5222fd0 178 pinstate |= (1 << PN532_GPIO_P32) | (1 << PN532_GPIO_P34);
yihui 1:b8cab5222fd0 179
yihui 1:b8cab5222fd0 180 // Fill command buffer
yihui 1:b8cab5222fd0 181 pn532_packetbuffer[0] = PN532_COMMAND_WRITEGPIO;
yihui 1:b8cab5222fd0 182 pn532_packetbuffer[1] = PN532_GPIO_VALIDATIONBIT | pinstate; // P3 Pins
yihui 1:b8cab5222fd0 183 pn532_packetbuffer[2] = 0x00; // P7 GPIO Pins (not used ... taken by I2C)
yihui 0:9c6b9280c0e1 184
yihui 1:b8cab5222fd0 185 DMSG("Writing P3 GPIO: ");
yihui 1:b8cab5222fd0 186 DMSG_HEX(pn532_packetbuffer[1]);
yihui 1:b8cab5222fd0 187 DMSG("\n");
yihui 0:9c6b9280c0e1 188
yihui 1:b8cab5222fd0 189 // Send the WRITEGPIO command (0x0E)
yihui 1:b8cab5222fd0 190 if (HAL(writeCommand)(pn532_packetbuffer, 3))
yihui 1:b8cab5222fd0 191 return 0;
yihui 0:9c6b9280c0e1 192
yihui 1:b8cab5222fd0 193 return (0 < HAL(readResponse)(pn532_packetbuffer, sizeof(pn532_packetbuffer)));
yihui 0:9c6b9280c0e1 194 }
yihui 0:9c6b9280c0e1 195
yihui 0:9c6b9280c0e1 196 /**************************************************************************/
yihui 1:b8cab5222fd0 197 /*!
yihui 0:9c6b9280c0e1 198 Reads the state of the PN532's GPIO pins
yihui 1:b8cab5222fd0 199
yihui 0:9c6b9280c0e1 200 @returns An 8-bit value containing the pin state where:
yihui 1:b8cab5222fd0 201
yihui 1:b8cab5222fd0 202 pinState[0] = P30
yihui 1:b8cab5222fd0 203 pinState[1] = P31
yihui 1:b8cab5222fd0 204 pinState[2] = P32
yihui 1:b8cab5222fd0 205 pinState[3] = P33
yihui 1:b8cab5222fd0 206 pinState[4] = P34
yihui 1:b8cab5222fd0 207 pinState[5] = P35
yihui 0:9c6b9280c0e1 208 */
yihui 0:9c6b9280c0e1 209 /**************************************************************************/
yihui 1:b8cab5222fd0 210 uint8_t PN532::readGPIO(void)
yihui 1:b8cab5222fd0 211 {
yihui 1:b8cab5222fd0 212 pn532_packetbuffer[0] = PN532_COMMAND_READGPIO;
yihui 0:9c6b9280c0e1 213
yihui 1:b8cab5222fd0 214 // Send the READGPIO command (0x0C)
yihui 1:b8cab5222fd0 215 if (HAL(writeCommand)(pn532_packetbuffer, 1))
yihui 1:b8cab5222fd0 216 return 0x0;
yihui 1:b8cab5222fd0 217
yihui 1:b8cab5222fd0 218 HAL(readResponse)(pn532_packetbuffer, sizeof(pn532_packetbuffer));
yihui 1:b8cab5222fd0 219
yihui 1:b8cab5222fd0 220 /* READGPIO response without prefix and suffix should be in the following format:
yihui 0:9c6b9280c0e1 221
yihui 1:b8cab5222fd0 222 byte Description
yihui 1:b8cab5222fd0 223 ------------- ------------------------------------------
yihui 1:b8cab5222fd0 224 b0 P3 GPIO Pins
yihui 1:b8cab5222fd0 225 b1 P7 GPIO Pins (not used ... taken by I2C)
yihui 1:b8cab5222fd0 226 b2 Interface Mode Pins (not used ... bus select pins)
yihui 1:b8cab5222fd0 227 */
yihui 0:9c6b9280c0e1 228
yihui 0:9c6b9280c0e1 229
yihui 1:b8cab5222fd0 230 DMSG("P3 GPIO: "); DMSG_HEX(pn532_packetbuffer[7]);
yihui 1:b8cab5222fd0 231 DMSG("P7 GPIO: "); DMSG_HEX(pn532_packetbuffer[8]);
yihui 1:b8cab5222fd0 232 DMSG("I0I1 GPIO: "); DMSG_HEX(pn532_packetbuffer[9]);
yihui 1:b8cab5222fd0 233 DMSG("\n");
yihui 1:b8cab5222fd0 234
yihui 1:b8cab5222fd0 235 return pn532_packetbuffer[0];
yihui 0:9c6b9280c0e1 236 }
yihui 0:9c6b9280c0e1 237
yihui 0:9c6b9280c0e1 238 /**************************************************************************/
yihui 1:b8cab5222fd0 239 /*!
yihui 0:9c6b9280c0e1 240 @brief Configures the SAM (Secure Access Module)
yihui 0:9c6b9280c0e1 241 */
yihui 0:9c6b9280c0e1 242 /**************************************************************************/
yihui 1:b8cab5222fd0 243 bool PN532::SAMConfig(void)
yihui 1:b8cab5222fd0 244 {
yihui 1:b8cab5222fd0 245 pn532_packetbuffer[0] = PN532_COMMAND_SAMCONFIGURATION;
yihui 1:b8cab5222fd0 246 pn532_packetbuffer[1] = 0x01; // normal mode;
yihui 1:b8cab5222fd0 247 pn532_packetbuffer[2] = 0x14; // timeout 50ms * 20 = 1 second
yihui 1:b8cab5222fd0 248 pn532_packetbuffer[3] = 0x01; // use IRQ pin!
yihui 0:9c6b9280c0e1 249
yihui 1:b8cab5222fd0 250 if (HAL(writeCommand)(pn532_packetbuffer, 4))
yihui 1:b8cab5222fd0 251 return false;
yihui 1:b8cab5222fd0 252
yihui 1:b8cab5222fd0 253 return (0 < HAL(readResponse)(pn532_packetbuffer, sizeof(pn532_packetbuffer)));
yihui 0:9c6b9280c0e1 254 }
yihui 0:9c6b9280c0e1 255
yihui 0:9c6b9280c0e1 256 /**************************************************************************/
yihui 1:b8cab5222fd0 257 /*!
yihui 0:9c6b9280c0e1 258 Sets the MxRtyPassiveActivation uint8_t of the RFConfiguration register
yihui 1:b8cab5222fd0 259
yihui 0:9c6b9280c0e1 260 @param maxRetries 0xFF to wait forever, 0x00..0xFE to timeout
yihui 0:9c6b9280c0e1 261 after mxRetries
yihui 1:b8cab5222fd0 262
yihui 0:9c6b9280c0e1 263 @returns 1 if everything executed properly, 0 for an error
yihui 0:9c6b9280c0e1 264 */
yihui 0:9c6b9280c0e1 265 /**************************************************************************/
yihui 1:b8cab5222fd0 266 bool PN532::setPassiveActivationRetries(uint8_t maxRetries)
yihui 1:b8cab5222fd0 267 {
yihui 1:b8cab5222fd0 268 pn532_packetbuffer[0] = PN532_COMMAND_RFCONFIGURATION;
yihui 1:b8cab5222fd0 269 pn532_packetbuffer[1] = 5; // Config item 5 (MaxRetries)
yihui 1:b8cab5222fd0 270 pn532_packetbuffer[2] = 0xFF; // MxRtyATR (default = 0xFF)
yihui 1:b8cab5222fd0 271 pn532_packetbuffer[3] = 0x01; // MxRtyPSL (default = 0x01)
yihui 1:b8cab5222fd0 272 pn532_packetbuffer[4] = maxRetries;
yihui 1:b8cab5222fd0 273
yihui 1:b8cab5222fd0 274 if (HAL(writeCommand)(pn532_packetbuffer, 5))
yihui 1:b8cab5222fd0 275 return 0x0; // no ACK
yihui 1:b8cab5222fd0 276
yihui 1:b8cab5222fd0 277 return 1;
yihui 0:9c6b9280c0e1 278 }
yihui 0:9c6b9280c0e1 279
yihui 0:9c6b9280c0e1 280 /***** ISO14443A Commands ******/
yihui 0:9c6b9280c0e1 281
yihui 0:9c6b9280c0e1 282 /**************************************************************************/
yihui 1:b8cab5222fd0 283 /*!
yihui 0:9c6b9280c0e1 284 Waits for an ISO14443A target to enter the field
yihui 1:b8cab5222fd0 285
yihui 0:9c6b9280c0e1 286 @param cardBaudRate Baud rate of the card
yihui 0:9c6b9280c0e1 287 @param uid Pointer to the array that will be populated
yihui 0:9c6b9280c0e1 288 with the card's UID (up to 7 bytes)
yihui 0:9c6b9280c0e1 289 @param uidLength Pointer to the variable that will hold the
yihui 0:9c6b9280c0e1 290 length of the card's UID.
yihui 1:b8cab5222fd0 291
yihui 0:9c6b9280c0e1 292 @returns 1 if everything executed properly, 0 for an error
yihui 0:9c6b9280c0e1 293 */
yihui 0:9c6b9280c0e1 294 /**************************************************************************/
yihui 2:f618fb2169c4 295 bool PN532::readPassiveTargetID(uint8_t cardbaudrate, uint8_t *uid, uint8_t *uidLength, uint16_t timeout)
yihui 1:b8cab5222fd0 296 {
yihui 1:b8cab5222fd0 297 pn532_packetbuffer[0] = PN532_COMMAND_INLISTPASSIVETARGET;
yihui 1:b8cab5222fd0 298 pn532_packetbuffer[1] = 1; // max 1 cards at once (we can set this to 2 later)
yihui 1:b8cab5222fd0 299 pn532_packetbuffer[2] = cardbaudrate;
yihui 1:b8cab5222fd0 300
yihui 1:b8cab5222fd0 301 if (HAL(writeCommand)(pn532_packetbuffer, 3)) {
yihui 1:b8cab5222fd0 302 return 0x0; // command failed
yihui 1:b8cab5222fd0 303 }
yihui 1:b8cab5222fd0 304
yihui 1:b8cab5222fd0 305 // read data packet
yihui 2:f618fb2169c4 306 if (HAL(readResponse)(pn532_packetbuffer, sizeof(pn532_packetbuffer), timeout) < 0) {
yihui 2:f618fb2169c4 307 return 0x0;
yihui 2:f618fb2169c4 308 }
yihui 1:b8cab5222fd0 309
yihui 1:b8cab5222fd0 310 // check some basic stuff
yihui 1:b8cab5222fd0 311 /* ISO14443A card response should be in the following format:
yihui 0:9c6b9280c0e1 312
yihui 1:b8cab5222fd0 313 byte Description
yihui 1:b8cab5222fd0 314 ------------- ------------------------------------------
yihui 1:b8cab5222fd0 315 b0 Tags Found
yihui 1:b8cab5222fd0 316 b1 Tag Number (only one used in this example)
yihui 1:b8cab5222fd0 317 b2..3 SENS_RES
yihui 1:b8cab5222fd0 318 b4 SEL_RES
yihui 1:b8cab5222fd0 319 b5 NFCID Length
yihui 1:b8cab5222fd0 320 b6..NFCIDLen NFCID
yihui 1:b8cab5222fd0 321 */
yihui 1:b8cab5222fd0 322
yihui 1:b8cab5222fd0 323 if (pn532_packetbuffer[0] != 1)
yihui 1:b8cab5222fd0 324 return 0;
yihui 0:9c6b9280c0e1 325
yihui 1:b8cab5222fd0 326 uint16_t sens_res = pn532_packetbuffer[2];
yihui 1:b8cab5222fd0 327 sens_res <<= 8;
yihui 1:b8cab5222fd0 328 sens_res |= pn532_packetbuffer[3];
yihui 1:b8cab5222fd0 329
yihui 1:b8cab5222fd0 330 DMSG("ATQA: 0x"); DMSG_HEX(sens_res);
yihui 1:b8cab5222fd0 331 DMSG("SAK: 0x"); DMSG_HEX(pn532_packetbuffer[4]);
yihui 1:b8cab5222fd0 332 DMSG("\n");
yihui 0:9c6b9280c0e1 333
yihui 1:b8cab5222fd0 334 /* Card appears to be Mifare Classic */
yihui 1:b8cab5222fd0 335 *uidLength = pn532_packetbuffer[5];
yihui 0:9c6b9280c0e1 336
yihui 1:b8cab5222fd0 337 for (uint8_t i = 0; i < pn532_packetbuffer[5]; i++) {
yihui 1:b8cab5222fd0 338 uid[i] = pn532_packetbuffer[6 + i];
yihui 1:b8cab5222fd0 339 }
yihui 1:b8cab5222fd0 340
yihui 1:b8cab5222fd0 341 return 1;
yihui 0:9c6b9280c0e1 342 }
yihui 0:9c6b9280c0e1 343
yihui 0:9c6b9280c0e1 344
yihui 0:9c6b9280c0e1 345 /***** Mifare Classic Functions ******/
yihui 0:9c6b9280c0e1 346
yihui 0:9c6b9280c0e1 347 /**************************************************************************/
yihui 1:b8cab5222fd0 348 /*!
yihui 0:9c6b9280c0e1 349 Indicates whether the specified block number is the first block
yihui 0:9c6b9280c0e1 350 in the sector (block 0 relative to the current sector)
yihui 0:9c6b9280c0e1 351 */
yihui 0:9c6b9280c0e1 352 /**************************************************************************/
yihui 0:9c6b9280c0e1 353 bool PN532::mifareclassic_IsFirstBlock (uint32_t uiBlock)
yihui 0:9c6b9280c0e1 354 {
yihui 1:b8cab5222fd0 355 // Test if we are in the small or big sectors
yihui 1:b8cab5222fd0 356 if (uiBlock < 128)
yihui 1:b8cab5222fd0 357 return ((uiBlock) % 4 == 0);
yihui 1:b8cab5222fd0 358 else
yihui 1:b8cab5222fd0 359 return ((uiBlock) % 16 == 0);
yihui 0:9c6b9280c0e1 360 }
yihui 0:9c6b9280c0e1 361
yihui 0:9c6b9280c0e1 362 /**************************************************************************/
yihui 1:b8cab5222fd0 363 /*!
yihui 0:9c6b9280c0e1 364 Indicates whether the specified block number is the sector trailer
yihui 0:9c6b9280c0e1 365 */
yihui 0:9c6b9280c0e1 366 /**************************************************************************/
yihui 0:9c6b9280c0e1 367 bool PN532::mifareclassic_IsTrailerBlock (uint32_t uiBlock)
yihui 0:9c6b9280c0e1 368 {
yihui 1:b8cab5222fd0 369 // Test if we are in the small or big sectors
yihui 1:b8cab5222fd0 370 if (uiBlock < 128)
yihui 1:b8cab5222fd0 371 return ((uiBlock + 1) % 4 == 0);
yihui 1:b8cab5222fd0 372 else
yihui 1:b8cab5222fd0 373 return ((uiBlock + 1) % 16 == 0);
yihui 0:9c6b9280c0e1 374 }
yihui 0:9c6b9280c0e1 375
yihui 0:9c6b9280c0e1 376 /**************************************************************************/
yihui 1:b8cab5222fd0 377 /*!
yihui 0:9c6b9280c0e1 378 Tries to authenticate a block of memory on a MIFARE card using the
yihui 0:9c6b9280c0e1 379 INDATAEXCHANGE command. See section 7.3.8 of the PN532 User Manual
yihui 0:9c6b9280c0e1 380 for more information on sending MIFARE and other commands.
yihui 0:9c6b9280c0e1 381
yihui 1:b8cab5222fd0 382 @param uid Pointer to a byte array containing the card UID
yihui 0:9c6b9280c0e1 383 @param uidLen The length (in bytes) of the card's UID (Should
yihui 0:9c6b9280c0e1 384 be 4 for MIFARE Classic)
yihui 0:9c6b9280c0e1 385 @param blockNumber The block number to authenticate. (0..63 for
yihui 0:9c6b9280c0e1 386 1KB cards, and 0..255 for 4KB cards).
yihui 0:9c6b9280c0e1 387 @param keyNumber Which key type to use during authentication
yihui 0:9c6b9280c0e1 388 (0 = MIFARE_CMD_AUTH_A, 1 = MIFARE_CMD_AUTH_B)
yihui 1:b8cab5222fd0 389 @param keyData Pointer to a byte array containing the 6 bytes
yihui 0:9c6b9280c0e1 390 key value
yihui 1:b8cab5222fd0 391
yihui 0:9c6b9280c0e1 392 @returns 1 if everything executed properly, 0 for an error
yihui 0:9c6b9280c0e1 393 */
yihui 0:9c6b9280c0e1 394 /**************************************************************************/
yihui 1:b8cab5222fd0 395 uint8_t PN532::mifareclassic_AuthenticateBlock (uint8_t *uid, uint8_t uidLen, uint32_t blockNumber, uint8_t keyNumber, uint8_t *keyData)
yihui 0:9c6b9280c0e1 396 {
yihui 1:b8cab5222fd0 397 uint8_t i;
yihui 1:b8cab5222fd0 398
yihui 1:b8cab5222fd0 399 // Hang on to the key and uid data
yihui 1:b8cab5222fd0 400 memcpy (_key, keyData, 6);
yihui 1:b8cab5222fd0 401 memcpy (_uid, uid, uidLen);
yihui 1:b8cab5222fd0 402 _uidLen = uidLen;
yihui 0:9c6b9280c0e1 403
yihui 1:b8cab5222fd0 404 // Prepare the authentication command //
yihui 1:b8cab5222fd0 405 pn532_packetbuffer[0] = PN532_COMMAND_INDATAEXCHANGE; /* Data Exchange Header */
yihui 1:b8cab5222fd0 406 pn532_packetbuffer[1] = 1; /* Max card numbers */
yihui 1:b8cab5222fd0 407 pn532_packetbuffer[2] = (keyNumber) ? MIFARE_CMD_AUTH_B : MIFARE_CMD_AUTH_A;
yihui 1:b8cab5222fd0 408 pn532_packetbuffer[3] = blockNumber; /* Block Number (1K = 0..63, 4K = 0..255 */
yihui 1:b8cab5222fd0 409 memcpy (pn532_packetbuffer + 4, _key, 6);
yihui 1:b8cab5222fd0 410 for (i = 0; i < _uidLen; i++) {
yihui 1:b8cab5222fd0 411 pn532_packetbuffer[10 + i] = _uid[i]; /* 4 bytes card ID */
yihui 1:b8cab5222fd0 412 }
yihui 1:b8cab5222fd0 413
yihui 1:b8cab5222fd0 414 if (HAL(writeCommand)(pn532_packetbuffer, 10 + _uidLen))
yihui 1:b8cab5222fd0 415 return 0;
yihui 0:9c6b9280c0e1 416
yihui 1:b8cab5222fd0 417 // Read the response packet
yihui 1:b8cab5222fd0 418 HAL(readResponse)(pn532_packetbuffer, sizeof(pn532_packetbuffer));
yihui 0:9c6b9280c0e1 419
yihui 1:b8cab5222fd0 420 // Check if the response is valid and we are authenticated???
yihui 1:b8cab5222fd0 421 // for an auth success it should be bytes 5-7: 0xD5 0x41 0x00
yihui 1:b8cab5222fd0 422 // Mifare auth error is technically byte 7: 0x14 but anything other and 0x00 is not good
yihui 1:b8cab5222fd0 423 if (pn532_packetbuffer[0] != 0x00) {
yihui 1:b8cab5222fd0 424 DMSG("Authentification failed\n");
yihui 1:b8cab5222fd0 425 return 0;
yihui 1:b8cab5222fd0 426 }
yihui 1:b8cab5222fd0 427
yihui 1:b8cab5222fd0 428 return 1;
yihui 0:9c6b9280c0e1 429 }
yihui 0:9c6b9280c0e1 430
yihui 0:9c6b9280c0e1 431 /**************************************************************************/
yihui 1:b8cab5222fd0 432 /*!
yihui 1:b8cab5222fd0 433 Tries to read an entire 16-bytes data block at the specified block
yihui 0:9c6b9280c0e1 434 address.
yihui 0:9c6b9280c0e1 435
yihui 0:9c6b9280c0e1 436 @param blockNumber The block number to authenticate. (0..63 for
yihui 0:9c6b9280c0e1 437 1KB cards, and 0..255 for 4KB cards).
yihui 1:b8cab5222fd0 438 @param data Pointer to the byte array that will hold the
yihui 0:9c6b9280c0e1 439 retrieved data (if any)
yihui 1:b8cab5222fd0 440
yihui 0:9c6b9280c0e1 441 @returns 1 if everything executed properly, 0 for an error
yihui 0:9c6b9280c0e1 442 */
yihui 0:9c6b9280c0e1 443 /**************************************************************************/
yihui 1:b8cab5222fd0 444 uint8_t PN532::mifareclassic_ReadDataBlock (uint8_t blockNumber, uint8_t *data)
yihui 0:9c6b9280c0e1 445 {
yihui 1:b8cab5222fd0 446 DMSG("Trying to read 16 bytes from block ");
yihui 1:b8cab5222fd0 447 DMSG_INT(blockNumber);
yihui 1:b8cab5222fd0 448
yihui 1:b8cab5222fd0 449 /* Prepare the command */
yihui 1:b8cab5222fd0 450 pn532_packetbuffer[0] = PN532_COMMAND_INDATAEXCHANGE;
yihui 1:b8cab5222fd0 451 pn532_packetbuffer[1] = 1; /* Card number */
yihui 1:b8cab5222fd0 452 pn532_packetbuffer[2] = MIFARE_CMD_READ; /* Mifare Read command = 0x30 */
yihui 1:b8cab5222fd0 453 pn532_packetbuffer[3] = blockNumber; /* Block Number (0..63 for 1K, 0..255 for 4K) */
yihui 0:9c6b9280c0e1 454
yihui 1:b8cab5222fd0 455 /* Send the command */
yihui 1:b8cab5222fd0 456 if (HAL(writeCommand)(pn532_packetbuffer, 4)) {
yihui 1:b8cab5222fd0 457 return 0;
yihui 1:b8cab5222fd0 458 }
yihui 0:9c6b9280c0e1 459
yihui 1:b8cab5222fd0 460 /* Read the response packet */
yihui 1:b8cab5222fd0 461 HAL(readResponse)(pn532_packetbuffer, sizeof(pn532_packetbuffer));
yihui 0:9c6b9280c0e1 462
yihui 1:b8cab5222fd0 463 /* If byte 8 isn't 0x00 we probably have an error */
yihui 1:b8cab5222fd0 464 if (pn532_packetbuffer[0] != 0x00) {
yihui 1:b8cab5222fd0 465 return 0;
yihui 1:b8cab5222fd0 466 }
yihui 0:9c6b9280c0e1 467
yihui 1:b8cab5222fd0 468 /* Copy the 16 data bytes to the output buffer */
yihui 1:b8cab5222fd0 469 /* Block content starts at byte 9 of a valid response */
yihui 1:b8cab5222fd0 470 memcpy (data, pn532_packetbuffer + 1, 16);
yihui 1:b8cab5222fd0 471
yihui 1:b8cab5222fd0 472 return 1;
yihui 0:9c6b9280c0e1 473 }
yihui 0:9c6b9280c0e1 474
yihui 0:9c6b9280c0e1 475 /**************************************************************************/
yihui 1:b8cab5222fd0 476 /*!
yihui 1:b8cab5222fd0 477 Tries to write an entire 16-bytes data block at the specified block
yihui 0:9c6b9280c0e1 478 address.
yihui 0:9c6b9280c0e1 479
yihui 0:9c6b9280c0e1 480 @param blockNumber The block number to authenticate. (0..63 for
yihui 0:9c6b9280c0e1 481 1KB cards, and 0..255 for 4KB cards).
yihui 1:b8cab5222fd0 482 @param data The byte array that contains the data to write.
yihui 1:b8cab5222fd0 483
yihui 0:9c6b9280c0e1 484 @returns 1 if everything executed properly, 0 for an error
yihui 0:9c6b9280c0e1 485 */
yihui 0:9c6b9280c0e1 486 /**************************************************************************/
yihui 1:b8cab5222fd0 487 uint8_t PN532::mifareclassic_WriteDataBlock (uint8_t blockNumber, uint8_t *data)
yihui 0:9c6b9280c0e1 488 {
yihui 1:b8cab5222fd0 489 /* Prepare the first command */
yihui 1:b8cab5222fd0 490 pn532_packetbuffer[0] = PN532_COMMAND_INDATAEXCHANGE;
yihui 1:b8cab5222fd0 491 pn532_packetbuffer[1] = 1; /* Card number */
yihui 1:b8cab5222fd0 492 pn532_packetbuffer[2] = MIFARE_CMD_WRITE; /* Mifare Write command = 0xA0 */
yihui 1:b8cab5222fd0 493 pn532_packetbuffer[3] = blockNumber; /* Block Number (0..63 for 1K, 0..255 for 4K) */
yihui 1:b8cab5222fd0 494 memcpy (pn532_packetbuffer + 4, data, 16); /* Data Payload */
yihui 0:9c6b9280c0e1 495
yihui 1:b8cab5222fd0 496 /* Send the command */
yihui 1:b8cab5222fd0 497 if (HAL(writeCommand)(pn532_packetbuffer, 20)) {
yihui 1:b8cab5222fd0 498 return 0;
yihui 1:b8cab5222fd0 499 }
yihui 1:b8cab5222fd0 500
yihui 1:b8cab5222fd0 501 /* Read the response packet */
yihui 1:b8cab5222fd0 502 return (0 < HAL(readResponse)(pn532_packetbuffer, sizeof(pn532_packetbuffer)));
yihui 0:9c6b9280c0e1 503 }
yihui 0:9c6b9280c0e1 504
yihui 0:9c6b9280c0e1 505 /**************************************************************************/
yihui 1:b8cab5222fd0 506 /*!
yihui 1:b8cab5222fd0 507 Formats a Mifare Classic card to store NDEF Records
yihui 1:b8cab5222fd0 508
yihui 0:9c6b9280c0e1 509 @returns 1 if everything executed properly, 0 for an error
yihui 0:9c6b9280c0e1 510 */
yihui 0:9c6b9280c0e1 511 /**************************************************************************/
yihui 0:9c6b9280c0e1 512 uint8_t PN532::mifareclassic_FormatNDEF (void)
yihui 0:9c6b9280c0e1 513 {
yihui 1:b8cab5222fd0 514 uint8_t sectorbuffer1[16] = {0x14, 0x01, 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1};
yihui 1:b8cab5222fd0 515 uint8_t sectorbuffer2[16] = {0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1};
yihui 1:b8cab5222fd0 516 uint8_t sectorbuffer3[16] = {0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0x78, 0x77, 0x88, 0xC1, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
yihui 1:b8cab5222fd0 517
yihui 1:b8cab5222fd0 518 // Note 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 must be used for key A
yihui 1:b8cab5222fd0 519 // for the MAD sector in NDEF records (sector 0)
yihui 0:9c6b9280c0e1 520
yihui 1:b8cab5222fd0 521 // Write block 1 and 2 to the card
yihui 1:b8cab5222fd0 522 if (!(mifareclassic_WriteDataBlock (1, sectorbuffer1)))
yihui 1:b8cab5222fd0 523 return 0;
yihui 1:b8cab5222fd0 524 if (!(mifareclassic_WriteDataBlock (2, sectorbuffer2)))
yihui 1:b8cab5222fd0 525 return 0;
yihui 1:b8cab5222fd0 526 // Write key A and access rights card
yihui 1:b8cab5222fd0 527 if (!(mifareclassic_WriteDataBlock (3, sectorbuffer3)))
yihui 1:b8cab5222fd0 528 return 0;
yihui 0:9c6b9280c0e1 529
yihui 1:b8cab5222fd0 530 // Seems that everything was OK (?!)
yihui 1:b8cab5222fd0 531 return 1;
yihui 0:9c6b9280c0e1 532 }
yihui 0:9c6b9280c0e1 533
yihui 0:9c6b9280c0e1 534 /**************************************************************************/
yihui 1:b8cab5222fd0 535 /*!
yihui 0:9c6b9280c0e1 536 Writes an NDEF URI Record to the specified sector (1..15)
yihui 1:b8cab5222fd0 537
yihui 0:9c6b9280c0e1 538 Note that this function assumes that the Mifare Classic card is
yihui 0:9c6b9280c0e1 539 already formatted to work as an "NFC Forum Tag" and uses a MAD1
yihui 0:9c6b9280c0e1 540 file system. You can use the NXP TagWriter app on Android to
yihui 0:9c6b9280c0e1 541 properly format cards for this.
yihui 0:9c6b9280c0e1 542
yihui 0:9c6b9280c0e1 543 @param sectorNumber The sector that the URI record should be written
yihui 0:9c6b9280c0e1 544 to (can be 1..15 for a 1K card)
yihui 1:b8cab5222fd0 545 @param uriIdentifier The uri identifier code (0 = none, 0x01 =
yihui 0:9c6b9280c0e1 546 "http://www.", etc.)
yihui 0:9c6b9280c0e1 547 @param url The uri text to write (max 38 characters).
yihui 1:b8cab5222fd0 548
yihui 0:9c6b9280c0e1 549 @returns 1 if everything executed properly, 0 for an error
yihui 0:9c6b9280c0e1 550 */
yihui 0:9c6b9280c0e1 551 /**************************************************************************/
yihui 1:b8cab5222fd0 552 uint8_t PN532::mifareclassic_WriteNDEFURI (uint8_t sectorNumber, uint8_t uriIdentifier, const char *url)
yihui 0:9c6b9280c0e1 553 {
yihui 1:b8cab5222fd0 554 // Figure out how long the string is
yihui 1:b8cab5222fd0 555 uint8_t len = strlen(url);
yihui 1:b8cab5222fd0 556
yihui 1:b8cab5222fd0 557 // Make sure we're within a 1K limit for the sector number
yihui 1:b8cab5222fd0 558 if ((sectorNumber < 1) || (sectorNumber > 15))
yihui 1:b8cab5222fd0 559 return 0;
yihui 1:b8cab5222fd0 560
yihui 1:b8cab5222fd0 561 // Make sure the URI payload is between 1 and 38 chars
yihui 1:b8cab5222fd0 562 if ((len < 1) || (len > 38))
yihui 1:b8cab5222fd0 563 return 0;
yihui 1:b8cab5222fd0 564
yihui 1:b8cab5222fd0 565 // Note 0xD3 0xF7 0xD3 0xF7 0xD3 0xF7 must be used for key A
yihui 1:b8cab5222fd0 566 // in NDEF records
yihui 0:9c6b9280c0e1 567
yihui 1:b8cab5222fd0 568 // Setup the sector buffer (w/pre-formatted TLV wrapper and NDEF message)
yihui 1:b8cab5222fd0 569 uint8_t sectorbuffer1[16] = {0x00, 0x00, 0x03, len + 5, 0xD1, 0x01, len + 1, 0x55, uriIdentifier, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
yihui 1:b8cab5222fd0 570 uint8_t sectorbuffer2[16] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
yihui 1:b8cab5222fd0 571 uint8_t sectorbuffer3[16] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
yihui 1:b8cab5222fd0 572 uint8_t sectorbuffer4[16] = {0xD3, 0xF7, 0xD3, 0xF7, 0xD3, 0xF7, 0x7F, 0x07, 0x88, 0x40, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
yihui 1:b8cab5222fd0 573 if (len <= 6) {
yihui 1:b8cab5222fd0 574 // Unlikely we'll get a url this short, but why not ...
yihui 1:b8cab5222fd0 575 memcpy (sectorbuffer1 + 9, url, len);
yihui 1:b8cab5222fd0 576 sectorbuffer1[len + 9] = 0xFE;
yihui 1:b8cab5222fd0 577 } else if (len == 7) {
yihui 1:b8cab5222fd0 578 // 0xFE needs to be wrapped around to next block
yihui 1:b8cab5222fd0 579 memcpy (sectorbuffer1 + 9, url, len);
yihui 1:b8cab5222fd0 580 sectorbuffer2[0] = 0xFE;
yihui 1:b8cab5222fd0 581 } else if ((len > 7) || (len <= 22)) {
yihui 1:b8cab5222fd0 582 // Url fits in two blocks
yihui 1:b8cab5222fd0 583 memcpy (sectorbuffer1 + 9, url, 7);
yihui 1:b8cab5222fd0 584 memcpy (sectorbuffer2, url + 7, len - 7);
yihui 1:b8cab5222fd0 585 sectorbuffer2[len - 7] = 0xFE;
yihui 1:b8cab5222fd0 586 } else if (len == 23) {
yihui 1:b8cab5222fd0 587 // 0xFE needs to be wrapped around to final block
yihui 1:b8cab5222fd0 588 memcpy (sectorbuffer1 + 9, url, 7);
yihui 1:b8cab5222fd0 589 memcpy (sectorbuffer2, url + 7, len - 7);
yihui 1:b8cab5222fd0 590 sectorbuffer3[0] = 0xFE;
yihui 1:b8cab5222fd0 591 } else {
yihui 1:b8cab5222fd0 592 // Url fits in three blocks
yihui 1:b8cab5222fd0 593 memcpy (sectorbuffer1 + 9, url, 7);
yihui 1:b8cab5222fd0 594 memcpy (sectorbuffer2, url + 7, 16);
yihui 1:b8cab5222fd0 595 memcpy (sectorbuffer3, url + 23, len - 24);
yihui 1:b8cab5222fd0 596 sectorbuffer3[len - 22] = 0xFE;
yihui 1:b8cab5222fd0 597 }
yihui 1:b8cab5222fd0 598
yihui 1:b8cab5222fd0 599 // Now write all three blocks back to the card
yihui 1:b8cab5222fd0 600 if (!(mifareclassic_WriteDataBlock (sectorNumber * 4, sectorbuffer1)))
yihui 1:b8cab5222fd0 601 return 0;
yihui 1:b8cab5222fd0 602 if (!(mifareclassic_WriteDataBlock ((sectorNumber * 4) + 1, sectorbuffer2)))
yihui 1:b8cab5222fd0 603 return 0;
yihui 1:b8cab5222fd0 604 if (!(mifareclassic_WriteDataBlock ((sectorNumber * 4) + 2, sectorbuffer3)))
yihui 1:b8cab5222fd0 605 return 0;
yihui 1:b8cab5222fd0 606 if (!(mifareclassic_WriteDataBlock ((sectorNumber * 4) + 3, sectorbuffer4)))
yihui 1:b8cab5222fd0 607 return 0;
yihui 1:b8cab5222fd0 608
yihui 1:b8cab5222fd0 609 // Seems that everything was OK (?!)
yihui 1:b8cab5222fd0 610 return 1;
yihui 0:9c6b9280c0e1 611 }
yihui 0:9c6b9280c0e1 612
yihui 0:9c6b9280c0e1 613 /***** Mifare Ultralight Functions ******/
yihui 0:9c6b9280c0e1 614
yihui 0:9c6b9280c0e1 615 /**************************************************************************/
yihui 1:b8cab5222fd0 616 /*!
yihui 1:b8cab5222fd0 617 Tries to read an entire 4-bytes page at the specified address.
yihui 0:9c6b9280c0e1 618
yihui 0:9c6b9280c0e1 619 @param page The page number (0..63 in most cases)
yihui 1:b8cab5222fd0 620 @param buffer Pointer to the byte array that will hold the
yihui 0:9c6b9280c0e1 621 retrieved data (if any)
yihui 0:9c6b9280c0e1 622 */
yihui 0:9c6b9280c0e1 623 /**************************************************************************/
yihui 1:b8cab5222fd0 624 uint8_t PN532::mifareultralight_ReadPage (uint8_t page, uint8_t *buffer)
yihui 0:9c6b9280c0e1 625 {
yihui 1:b8cab5222fd0 626 if (page >= 64) {
yihui 1:b8cab5222fd0 627 DMSG("Page value out of range\n");
yihui 1:b8cab5222fd0 628 return 0;
yihui 1:b8cab5222fd0 629 }
yihui 0:9c6b9280c0e1 630
yihui 1:b8cab5222fd0 631 /* Prepare the command */
yihui 1:b8cab5222fd0 632 pn532_packetbuffer[0] = PN532_COMMAND_INDATAEXCHANGE;
yihui 1:b8cab5222fd0 633 pn532_packetbuffer[1] = 1; /* Card number */
yihui 1:b8cab5222fd0 634 pn532_packetbuffer[2] = MIFARE_CMD_READ; /* Mifare Read command = 0x30 */
yihui 1:b8cab5222fd0 635 pn532_packetbuffer[3] = page; /* Page Number (0..63 in most cases) */
yihui 1:b8cab5222fd0 636
yihui 1:b8cab5222fd0 637 /* Send the command */
yihui 1:b8cab5222fd0 638 if (HAL(writeCommand)(pn532_packetbuffer, 4)) {
yihui 1:b8cab5222fd0 639 return 0;
yihui 1:b8cab5222fd0 640 }
yihui 0:9c6b9280c0e1 641
yihui 1:b8cab5222fd0 642 /* Read the response packet */
yihui 1:b8cab5222fd0 643 HAL(readResponse)(pn532_packetbuffer, sizeof(pn532_packetbuffer));
yihui 0:9c6b9280c0e1 644
yihui 1:b8cab5222fd0 645 /* If byte 8 isn't 0x00 we probably have an error */
yihui 1:b8cab5222fd0 646 if (pn532_packetbuffer[0] == 0x00) {
yihui 1:b8cab5222fd0 647 /* Copy the 4 data bytes to the output buffer */
yihui 1:b8cab5222fd0 648 /* Block content starts at byte 9 of a valid response */
yihui 1:b8cab5222fd0 649 /* Note that the command actually reads 16 bytes or 4 */
yihui 1:b8cab5222fd0 650 /* pages at a time ... we simply discard the last 12 */
yihui 1:b8cab5222fd0 651 /* bytes */
yihui 1:b8cab5222fd0 652 memcpy (buffer, pn532_packetbuffer + 1, 4);
yihui 1:b8cab5222fd0 653 } else {
yihui 1:b8cab5222fd0 654 return 0;
yihui 1:b8cab5222fd0 655 }
yihui 0:9c6b9280c0e1 656
yihui 1:b8cab5222fd0 657 // Return OK signal
yihui 1:b8cab5222fd0 658 return 1;
yihui 0:9c6b9280c0e1 659 }
yihui 0:9c6b9280c0e1 660
yihui 0:9c6b9280c0e1 661 /**************************************************************************/
yihui 1:b8cab5222fd0 662 /*!
yihui 0:9c6b9280c0e1 663 @brief Exchanges an APDU with the currently inlisted peer
yihui 0:9c6b9280c0e1 664
yihui 0:9c6b9280c0e1 665 @param send Pointer to data to send
yihui 0:9c6b9280c0e1 666 @param sendLength Length of the data to send
yihui 0:9c6b9280c0e1 667 @param response Pointer to response data
yihui 0:9c6b9280c0e1 668 @param responseLength Pointer to the response data length
yihui 0:9c6b9280c0e1 669 */
yihui 0:9c6b9280c0e1 670 /**************************************************************************/
yihui 1:b8cab5222fd0 671 bool PN532::inDataExchange(uint8_t *send, uint8_t sendLength, uint8_t *response, uint8_t *responseLength)
yihui 1:b8cab5222fd0 672 {
yihui 1:b8cab5222fd0 673 if (sendLength > PN532_PACKBUFFSIZ - 2) {
yihui 1:b8cab5222fd0 674 DMSG("APDU length too long for packet buffer");
yihui 1:b8cab5222fd0 675
yihui 1:b8cab5222fd0 676 return false;
yihui 1:b8cab5222fd0 677 }
yihui 1:b8cab5222fd0 678 uint8_t i;
yihui 0:9c6b9280c0e1 679
yihui 1:b8cab5222fd0 680 pn532_packetbuffer[0] = 0x40; // PN532_COMMAND_INDATAEXCHANGE;
yihui 1:b8cab5222fd0 681 pn532_packetbuffer[1] = inListedTag;
yihui 1:b8cab5222fd0 682 for (i = 0; i < sendLength; ++i) {
yihui 1:b8cab5222fd0 683 pn532_packetbuffer[i + 2] = send[i];
yihui 1:b8cab5222fd0 684 }
yihui 1:b8cab5222fd0 685
yihui 1:b8cab5222fd0 686 if (HAL(writeCommand)(pn532_packetbuffer, sendLength + 2)) {
yihui 1:b8cab5222fd0 687 return false;
yihui 1:b8cab5222fd0 688 }
yihui 0:9c6b9280c0e1 689
yihui 0:9c6b9280c0e1 690
yihui 1:b8cab5222fd0 691 int16_t status = HAL(readResponse)(pn532_packetbuffer, sizeof(pn532_packetbuffer), 1000);
yihui 1:b8cab5222fd0 692 if (status < 0) {
yihui 1:b8cab5222fd0 693 return false;
yihui 1:b8cab5222fd0 694 }
yihui 1:b8cab5222fd0 695
yihui 1:b8cab5222fd0 696 uint8_t length = status;
yihui 1:b8cab5222fd0 697
yihui 1:b8cab5222fd0 698 if ((pn532_packetbuffer[0] & 0x3f) != 0) {
yihui 1:b8cab5222fd0 699 DMSG("Status code indicates an error\n");
yihui 1:b8cab5222fd0 700 return false;
yihui 1:b8cab5222fd0 701 }
yihui 0:9c6b9280c0e1 702
yihui 1:b8cab5222fd0 703 length -= 1;
yihui 1:b8cab5222fd0 704
yihui 1:b8cab5222fd0 705 if (length > *responseLength) {
yihui 1:b8cab5222fd0 706 length = *responseLength; // silent truncation...
yihui 1:b8cab5222fd0 707 }
yihui 1:b8cab5222fd0 708
yihui 1:b8cab5222fd0 709 for (i = 0; i < length; ++i) {
yihui 1:b8cab5222fd0 710 response[i] = pn532_packetbuffer[1 + i];
yihui 1:b8cab5222fd0 711 }
yihui 1:b8cab5222fd0 712 *responseLength = length;
yihui 1:b8cab5222fd0 713
yihui 1:b8cab5222fd0 714 return true;
yihui 0:9c6b9280c0e1 715 }
yihui 0:9c6b9280c0e1 716
yihui 0:9c6b9280c0e1 717 /**************************************************************************/
yihui 1:b8cab5222fd0 718 /*!
yihui 0:9c6b9280c0e1 719 @brief 'InLists' a passive target. PN532 acting as reader/initiator,
yihui 0:9c6b9280c0e1 720 peer acting as card/responder.
yihui 0:9c6b9280c0e1 721 */
yihui 0:9c6b9280c0e1 722 /**************************************************************************/
yihui 1:b8cab5222fd0 723 bool PN532::inListPassiveTarget()
yihui 1:b8cab5222fd0 724 {
yihui 1:b8cab5222fd0 725 pn532_packetbuffer[0] = PN532_COMMAND_INLISTPASSIVETARGET;
yihui 1:b8cab5222fd0 726 pn532_packetbuffer[1] = 1;
yihui 1:b8cab5222fd0 727 pn532_packetbuffer[2] = 0;
yihui 0:9c6b9280c0e1 728
yihui 1:b8cab5222fd0 729 DMSG("inList passive target\n");
yihui 1:b8cab5222fd0 730
yihui 1:b8cab5222fd0 731 if (HAL(writeCommand)(pn532_packetbuffer, 3)) {
yihui 1:b8cab5222fd0 732 return false;
yihui 1:b8cab5222fd0 733 }
yihui 0:9c6b9280c0e1 734
yihui 1:b8cab5222fd0 735 int16_t status = HAL(readResponse)(pn532_packetbuffer, sizeof(pn532_packetbuffer), 30000);
yihui 1:b8cab5222fd0 736 if (status < 0) {
yihui 1:b8cab5222fd0 737 return false;
yihui 1:b8cab5222fd0 738 }
yihui 0:9c6b9280c0e1 739
yihui 1:b8cab5222fd0 740 if (pn532_packetbuffer[0] != 1) {
yihui 1:b8cab5222fd0 741 return false;
yihui 1:b8cab5222fd0 742 }
yihui 1:b8cab5222fd0 743
yihui 1:b8cab5222fd0 744 inListedTag = pn532_packetbuffer[1];
yihui 1:b8cab5222fd0 745
yihui 1:b8cab5222fd0 746 return true;
yihui 0:9c6b9280c0e1 747 }
yihui 0:9c6b9280c0e1 748
yihui 0:9c6b9280c0e1 749 /**
yihui 0:9c6b9280c0e1 750 * Peer to Peer
yihui 0:9c6b9280c0e1 751 */
yihui 0:9c6b9280c0e1 752 int8_t PN532::tgInitAsTarget()
yihui 0:9c6b9280c0e1 753 {
yihui 0:9c6b9280c0e1 754 static const uint8_t command[] = {
yihui 1:b8cab5222fd0 755 PN532_COMMAND_TGINITASTARGET,
yihui 1:b8cab5222fd0 756 0,
yihui 1:b8cab5222fd0 757 0x00, 0x00, //SENS_RES
yihui 1:b8cab5222fd0 758 0x00, 0x00, 0x00, //NFCID1
yihui 1:b8cab5222fd0 759 0x40, //SEL_RES
yihui 0:9c6b9280c0e1 760
yihui 1:b8cab5222fd0 761 0x01, 0xFE, 0x0F, 0xBB, 0xBA, 0xA6, 0xC9, 0x89, // POL_RES
yihui 1:b8cab5222fd0 762 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
yihui 1:b8cab5222fd0 763 0xFF, 0xFF,
yihui 0:9c6b9280c0e1 764
yihui 1:b8cab5222fd0 765 0x01, 0xFE, 0x0F, 0xBB, 0xBA, 0xA6, 0xC9, 0x89, 0x00, 0x00, //NFCID3t: Change this to desired value
yihui 0:9c6b9280c0e1 766
yihui 1:b8cab5222fd0 767 0x06, 0x46, 0x66, 0x6D, 0x01, 0x01, 0x10, 0x00// LLCP magic number and version parameter
yihui 1:b8cab5222fd0 768 };
yihui 1:b8cab5222fd0 769
yihui 0:9c6b9280c0e1 770 int8_t status = HAL(writeCommand)(command, sizeof(command));
yihui 0:9c6b9280c0e1 771 if (status < 0) {
yihui 0:9c6b9280c0e1 772 return status;
yihui 0:9c6b9280c0e1 773 }
yihui 1:b8cab5222fd0 774
yihui 0:9c6b9280c0e1 775 return HAL(readResponse)(pn532_packetbuffer, sizeof(pn532_packetbuffer), 0);
yihui 0:9c6b9280c0e1 776 }
yihui 0:9c6b9280c0e1 777
yihui 0:9c6b9280c0e1 778 int16_t PN532::tgGetData(uint8_t *buf, uint16_t len)
yihui 0:9c6b9280c0e1 779 {
yihui 0:9c6b9280c0e1 780 pn532_packetbuffer[0] = PN532_COMMAND_TGGETDATA;
yihui 1:b8cab5222fd0 781
yihui 0:9c6b9280c0e1 782 if (HAL(writeCommand)(pn532_packetbuffer, 1)) {
yihui 0:9c6b9280c0e1 783 return -1;
yihui 0:9c6b9280c0e1 784 }
yihui 1:b8cab5222fd0 785
yihui 0:9c6b9280c0e1 786 int16_t status = HAL(readResponse)(pn532_packetbuffer, sizeof(pn532_packetbuffer), 3000);
yihui 0:9c6b9280c0e1 787 if (0 > status) {
yihui 0:9c6b9280c0e1 788 return status;
yihui 0:9c6b9280c0e1 789 }
yihui 1:b8cab5222fd0 790
yihui 0:9c6b9280c0e1 791 uint16_t length = status;
yihui 0:9c6b9280c0e1 792 if (length > len) {
yihui 0:9c6b9280c0e1 793 return -4;
yihui 0:9c6b9280c0e1 794 }
yihui 1:b8cab5222fd0 795
yihui 0:9c6b9280c0e1 796 if (pn532_packetbuffer[0] != 0) {
yihui 0:9c6b9280c0e1 797 DMSG("status is not ok\n");
yihui 0:9c6b9280c0e1 798 return -5;
yihui 0:9c6b9280c0e1 799 }
yihui 1:b8cab5222fd0 800
yihui 0:9c6b9280c0e1 801 memcpy(buf, pn532_packetbuffer + 1, length - 1);
yihui 0:9c6b9280c0e1 802
yihui 1:b8cab5222fd0 803
yihui 0:9c6b9280c0e1 804 return length - 1;
yihui 0:9c6b9280c0e1 805 }
yihui 0:9c6b9280c0e1 806
yihui 0:9c6b9280c0e1 807 bool PN532::tgSetData(const uint8_t *buf, uint16_t len)
yihui 0:9c6b9280c0e1 808 {
yihui 0:9c6b9280c0e1 809 pn532_packetbuffer[0] = PN532_COMMAND_TGSETDATA;
yihui 0:9c6b9280c0e1 810 if (len > (sizeof(pn532_packetbuffer) + 1)) {
yihui 0:9c6b9280c0e1 811 return false;
yihui 0:9c6b9280c0e1 812 }
yihui 1:b8cab5222fd0 813
yihui 0:9c6b9280c0e1 814 memcpy(pn532_packetbuffer + 1, buf, len);
yihui 1:b8cab5222fd0 815
yihui 0:9c6b9280c0e1 816 if (HAL(writeCommand)(pn532_packetbuffer, len + 1)) {
yihui 0:9c6b9280c0e1 817 return false;
yihui 0:9c6b9280c0e1 818 }
yihui 1:b8cab5222fd0 819
yihui 0:9c6b9280c0e1 820 if (0 > HAL(readResponse)(pn532_packetbuffer, sizeof(pn532_packetbuffer), 3000)) {
yihui 0:9c6b9280c0e1 821 return false;
yihui 0:9c6b9280c0e1 822 }
yihui 1:b8cab5222fd0 823
yihui 0:9c6b9280c0e1 824 if (0 != pn532_packetbuffer[0]) {
yihui 0:9c6b9280c0e1 825 return false;
yihui 0:9c6b9280c0e1 826 }
yihui 1:b8cab5222fd0 827
yihui 0:9c6b9280c0e1 828 return true;
yihui 0:9c6b9280c0e1 829 }