PN532 NFC library for Seeed Studio's NFC Shield

Fork of PN532 by Yihui Xiong

Committer:
yihui
Date:
Tue Oct 08 08:33:22 2013 +0000
Revision:
0:9c6b9280c0e1
Child:
1:b8cab5222fd0
initial, ported from https://github.com/Seeed-Studio/PN532

Who changed what in which revision?

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