PN532 customized

Fork of PN532 by Components

Committer:
stanvn
Date:
Thu Feb 11 11:56:00 2016 +0000
Revision:
10:2fcf2448d199
Parent:
9:70abe4844114
Working code for reading type-a and type-b cards

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