PN532 NFC library for Seeed Studio's NFC Shield
Fork of PN532 by
PN532.cpp@0:9c6b9280c0e1, 2013-10-08 (annotated)
- 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?
User | Revision | Line number | New 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 | } |