PN532 NFC library for Seeed Studio's NFC Shield

Fork of PN532 by Yihui Xiong

Committer:
yihui
Date:
Thu Oct 17 06:37:26 2013 +0000
Revision:
1:b8cab5222fd0
Parent:
0:9c6b9280c0e1
Child:
2:f618fb2169c4
format code

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