Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Fork of PN532 by
PN532_SPI.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 | #include "PN532_SPI.h" |
| yihui | 0:9c6b9280c0e1 | 3 | #include "debug.h" |
| yihui | 0:9c6b9280c0e1 | 4 | |
| yihui | 0:9c6b9280c0e1 | 5 | #define STATUS_READ 2 |
| yihui | 0:9c6b9280c0e1 | 6 | #define DATA_WRITE 1 |
| yihui | 0:9c6b9280c0e1 | 7 | #define DATA_READ 3 |
| yihui | 0:9c6b9280c0e1 | 8 | |
| yihui | 0:9c6b9280c0e1 | 9 | PN532_SPI::PN532_SPI(SPI &spi, PinName ss) : _ss(ss) |
| yihui | 0:9c6b9280c0e1 | 10 | { |
| yihui | 0:9c6b9280c0e1 | 11 | command = 0; |
| yihui | 0:9c6b9280c0e1 | 12 | _spi = &spi; |
| yihui | 0:9c6b9280c0e1 | 13 | _spi->format(8, 0); |
| yihui | 0:9c6b9280c0e1 | 14 | _spi->frequency(2000000); |
| yihui | 0:9c6b9280c0e1 | 15 | |
| yihui | 0:9c6b9280c0e1 | 16 | _ss = 1; |
| yihui | 0:9c6b9280c0e1 | 17 | } |
| yihui | 0:9c6b9280c0e1 | 18 | |
| yihui | 0:9c6b9280c0e1 | 19 | PN532_SPI::PN532_SPI(SPI *spi, PinName ss) : _ss(ss) |
| yihui | 0:9c6b9280c0e1 | 20 | { |
| yihui | 0:9c6b9280c0e1 | 21 | command = 0; |
| yihui | 0:9c6b9280c0e1 | 22 | _spi = spi; |
| yihui | 0:9c6b9280c0e1 | 23 | _spi->format(8, 0); |
| yihui | 0:9c6b9280c0e1 | 24 | _spi->frequency(2000000); |
| yihui | 0:9c6b9280c0e1 | 25 | |
| yihui | 0:9c6b9280c0e1 | 26 | _ss = 1; |
| yihui | 0:9c6b9280c0e1 | 27 | } |
| yihui | 0:9c6b9280c0e1 | 28 | |
| yihui | 0:9c6b9280c0e1 | 29 | void PN532_SPI::begin() |
| yihui | 0:9c6b9280c0e1 | 30 | { |
| yihui | 0:9c6b9280c0e1 | 31 | |
| yihui | 0:9c6b9280c0e1 | 32 | } |
| yihui | 0:9c6b9280c0e1 | 33 | |
| yihui | 0:9c6b9280c0e1 | 34 | void PN532_SPI::wakeup() |
| yihui | 0:9c6b9280c0e1 | 35 | { |
| yihui | 0:9c6b9280c0e1 | 36 | _ss = 0; |
| yihui | 0:9c6b9280c0e1 | 37 | wait_ms(2); |
| yihui | 0:9c6b9280c0e1 | 38 | _ss = 1; |
| yihui | 0:9c6b9280c0e1 | 39 | } |
| yihui | 0:9c6b9280c0e1 | 40 | |
| yihui | 0:9c6b9280c0e1 | 41 | int8_t PN532_SPI::writeCommand(const uint8_t buf[], uint8_t len) |
| yihui | 0:9c6b9280c0e1 | 42 | { |
| yihui | 0:9c6b9280c0e1 | 43 | command = buf[0]; |
| yihui | 0:9c6b9280c0e1 | 44 | writeFrame(buf, len); |
| yihui | 0:9c6b9280c0e1 | 45 | |
| yihui | 0:9c6b9280c0e1 | 46 | uint8_t timeout = PN532_ACK_WAIT_TIME; |
| yihui | 0:9c6b9280c0e1 | 47 | while (!isReady()) { |
| yihui | 0:9c6b9280c0e1 | 48 | wait_ms(1); |
| yihui | 0:9c6b9280c0e1 | 49 | timeout--; |
| yihui | 0:9c6b9280c0e1 | 50 | if (0 == timeout) { |
| yihui | 0:9c6b9280c0e1 | 51 | DMSG("Time out when waiting for ACK\n"); |
| yihui | 0:9c6b9280c0e1 | 52 | return -2; |
| yihui | 0:9c6b9280c0e1 | 53 | } |
| yihui | 0:9c6b9280c0e1 | 54 | } |
| yihui | 0:9c6b9280c0e1 | 55 | if (readAckFrame()) { |
| yihui | 0:9c6b9280c0e1 | 56 | DMSG("Invalid ACK\n"); |
| yihui | 0:9c6b9280c0e1 | 57 | return PN532_INVALID_ACK; |
| yihui | 0:9c6b9280c0e1 | 58 | } |
| yihui | 0:9c6b9280c0e1 | 59 | return 0; |
| yihui | 0:9c6b9280c0e1 | 60 | } |
| yihui | 0:9c6b9280c0e1 | 61 | |
| yihui | 0:9c6b9280c0e1 | 62 | int16_t PN532_SPI::readResponse(uint8_t buf[], uint8_t len, uint16_t timeout) |
| yihui | 0:9c6b9280c0e1 | 63 | { |
| yihui | 0:9c6b9280c0e1 | 64 | uint16_t time = 0; |
| yihui | 0:9c6b9280c0e1 | 65 | while (!isReady()) { |
| yihui | 0:9c6b9280c0e1 | 66 | wait_ms(1); |
| yihui | 0:9c6b9280c0e1 | 67 | time++; |
| yihui | 0:9c6b9280c0e1 | 68 | if (timeout > 0 && time > timeout) { |
| yihui | 0:9c6b9280c0e1 | 69 | return PN532_TIMEOUT; |
| yihui | 0:9c6b9280c0e1 | 70 | } |
| yihui | 0:9c6b9280c0e1 | 71 | } |
| yihui | 0:9c6b9280c0e1 | 72 | |
| yihui | 0:9c6b9280c0e1 | 73 | _ss = 0; |
| yihui | 0:9c6b9280c0e1 | 74 | wait_ms(1); |
| yihui | 0:9c6b9280c0e1 | 75 | |
| yihui | 0:9c6b9280c0e1 | 76 | int16_t result; |
| yihui | 0:9c6b9280c0e1 | 77 | do { |
| yihui | 0:9c6b9280c0e1 | 78 | write(DATA_READ); |
| yihui | 0:9c6b9280c0e1 | 79 | |
| yihui | 0:9c6b9280c0e1 | 80 | if (0x00 != read() || // PREAMBLE |
| yihui | 0:9c6b9280c0e1 | 81 | 0x00 != read() || // STARTCODE1 |
| yihui | 0:9c6b9280c0e1 | 82 | 0xFF != read() // STARTCODE2 |
| yihui | 0:9c6b9280c0e1 | 83 | ) { |
| yihui | 0:9c6b9280c0e1 | 84 | |
| yihui | 0:9c6b9280c0e1 | 85 | result = PN532_INVALID_FRAME; |
| yihui | 0:9c6b9280c0e1 | 86 | break; |
| yihui | 0:9c6b9280c0e1 | 87 | } |
| yihui | 0:9c6b9280c0e1 | 88 | |
| yihui | 0:9c6b9280c0e1 | 89 | uint8_t length = read(); |
| yihui | 0:9c6b9280c0e1 | 90 | if (0 != (uint8_t)(length + read())) { // checksum of length |
| yihui | 0:9c6b9280c0e1 | 91 | result = PN532_INVALID_FRAME; |
| yihui | 0:9c6b9280c0e1 | 92 | break; |
| yihui | 0:9c6b9280c0e1 | 93 | } |
| yihui | 0:9c6b9280c0e1 | 94 | |
| yihui | 0:9c6b9280c0e1 | 95 | uint8_t cmd = command + 1; // response command |
| yihui | 0:9c6b9280c0e1 | 96 | if (PN532_PN532TOHOST != read() || (cmd) != read()) { |
| yihui | 0:9c6b9280c0e1 | 97 | result = PN532_INVALID_FRAME; |
| yihui | 0:9c6b9280c0e1 | 98 | break; |
| yihui | 0:9c6b9280c0e1 | 99 | } |
| yihui | 0:9c6b9280c0e1 | 100 | |
| yihui | 0:9c6b9280c0e1 | 101 | DMSG("read: "); |
| yihui | 0:9c6b9280c0e1 | 102 | DMSG_HEX(cmd); |
| yihui | 0:9c6b9280c0e1 | 103 | |
| yihui | 0:9c6b9280c0e1 | 104 | length -= 2; |
| yihui | 0:9c6b9280c0e1 | 105 | if (length > len) { |
| yihui | 0:9c6b9280c0e1 | 106 | for (uint8_t i = 0; i < length; i++) { |
| yihui | 0:9c6b9280c0e1 | 107 | DMSG_HEX(read()); // dump message |
| yihui | 0:9c6b9280c0e1 | 108 | } |
| yihui | 0:9c6b9280c0e1 | 109 | DMSG("\nNot enough space\n"); |
| yihui | 0:9c6b9280c0e1 | 110 | read(); |
| yihui | 0:9c6b9280c0e1 | 111 | read(); |
| yihui | 0:9c6b9280c0e1 | 112 | result = PN532_NO_SPACE; // not enough space |
| yihui | 0:9c6b9280c0e1 | 113 | break; |
| yihui | 0:9c6b9280c0e1 | 114 | } |
| yihui | 0:9c6b9280c0e1 | 115 | |
| yihui | 0:9c6b9280c0e1 | 116 | uint8_t sum = PN532_PN532TOHOST + cmd; |
| yihui | 0:9c6b9280c0e1 | 117 | for (uint8_t i = 0; i < length; i++) { |
| yihui | 0:9c6b9280c0e1 | 118 | buf[i] = read(); |
| yihui | 0:9c6b9280c0e1 | 119 | sum += buf[i]; |
| yihui | 0:9c6b9280c0e1 | 120 | |
| yihui | 0:9c6b9280c0e1 | 121 | DMSG_HEX(buf[i]); |
| yihui | 0:9c6b9280c0e1 | 122 | } |
| yihui | 0:9c6b9280c0e1 | 123 | DMSG("\n"); |
| yihui | 0:9c6b9280c0e1 | 124 | |
| yihui | 0:9c6b9280c0e1 | 125 | uint8_t checksum = read(); |
| yihui | 0:9c6b9280c0e1 | 126 | if (0 != (uint8_t)(sum + checksum)) { |
| yihui | 0:9c6b9280c0e1 | 127 | DMSG("checksum is not ok\n"); |
| yihui | 0:9c6b9280c0e1 | 128 | result = PN532_INVALID_FRAME; |
| yihui | 0:9c6b9280c0e1 | 129 | break; |
| yihui | 0:9c6b9280c0e1 | 130 | } |
| yihui | 0:9c6b9280c0e1 | 131 | read(); // POSTAMBLE |
| yihui | 0:9c6b9280c0e1 | 132 | |
| yihui | 0:9c6b9280c0e1 | 133 | result = length; |
| yihui | 0:9c6b9280c0e1 | 134 | } while (0); |
| yihui | 0:9c6b9280c0e1 | 135 | |
| yihui | 0:9c6b9280c0e1 | 136 | _ss = 1; |
| yihui | 0:9c6b9280c0e1 | 137 | |
| yihui | 0:9c6b9280c0e1 | 138 | return result; |
| yihui | 0:9c6b9280c0e1 | 139 | } |
| yihui | 0:9c6b9280c0e1 | 140 | |
| yihui | 0:9c6b9280c0e1 | 141 | bool PN532_SPI::isReady() |
| yihui | 0:9c6b9280c0e1 | 142 | { |
| yihui | 0:9c6b9280c0e1 | 143 | _ss = 0; |
| yihui | 0:9c6b9280c0e1 | 144 | |
| yihui | 0:9c6b9280c0e1 | 145 | write(STATUS_READ); |
| yihui | 0:9c6b9280c0e1 | 146 | uint8_t status = read() & 1; |
| yihui | 0:9c6b9280c0e1 | 147 | _ss = 1; |
| yihui | 0:9c6b9280c0e1 | 148 | return status; |
| yihui | 0:9c6b9280c0e1 | 149 | } |
| yihui | 0:9c6b9280c0e1 | 150 | |
| yihui | 0:9c6b9280c0e1 | 151 | void PN532_SPI::writeFrame(const uint8_t buf[], uint8_t len) |
| yihui | 0:9c6b9280c0e1 | 152 | { |
| yihui | 0:9c6b9280c0e1 | 153 | _ss = 0; |
| yihui | 0:9c6b9280c0e1 | 154 | wait_ms(2); // wake up PN532 |
| yihui | 0:9c6b9280c0e1 | 155 | |
| yihui | 0:9c6b9280c0e1 | 156 | write(DATA_WRITE); |
| yihui | 0:9c6b9280c0e1 | 157 | write(PN532_PREAMBLE); |
| yihui | 0:9c6b9280c0e1 | 158 | write(PN532_STARTCODE1); |
| yihui | 0:9c6b9280c0e1 | 159 | write(PN532_STARTCODE2); |
| yihui | 0:9c6b9280c0e1 | 160 | |
| yihui | 0:9c6b9280c0e1 | 161 | uint8_t length = len + 1; // length of data field: TFI + DATA |
| yihui | 0:9c6b9280c0e1 | 162 | write(length); |
| yihui | 0:9c6b9280c0e1 | 163 | write(~length + 1); // checksum of length |
| yihui | 0:9c6b9280c0e1 | 164 | |
| yihui | 0:9c6b9280c0e1 | 165 | write(PN532_HOSTTOPN532); |
| yihui | 0:9c6b9280c0e1 | 166 | uint8_t sum = PN532_HOSTTOPN532; // sum of TFI + DATA |
| yihui | 0:9c6b9280c0e1 | 167 | |
| yihui | 0:9c6b9280c0e1 | 168 | DMSG("write: "); |
| yihui | 0:9c6b9280c0e1 | 169 | |
| yihui | 0:9c6b9280c0e1 | 170 | for (uint8_t i = 0; i < len; i++) { |
| yihui | 0:9c6b9280c0e1 | 171 | write(buf[i]); |
| yihui | 0:9c6b9280c0e1 | 172 | sum += buf[i]; |
| yihui | 0:9c6b9280c0e1 | 173 | |
| yihui | 0:9c6b9280c0e1 | 174 | DMSG_HEX(buf[i]); |
| yihui | 0:9c6b9280c0e1 | 175 | } |
| yihui | 0:9c6b9280c0e1 | 176 | |
| yihui | 0:9c6b9280c0e1 | 177 | uint8_t checksum = ~sum + 1; // checksum of TFI + DATA |
| yihui | 0:9c6b9280c0e1 | 178 | write(checksum); |
| yihui | 0:9c6b9280c0e1 | 179 | write(PN532_POSTAMBLE); |
| yihui | 0:9c6b9280c0e1 | 180 | |
| yihui | 0:9c6b9280c0e1 | 181 | _ss = 1; |
| yihui | 0:9c6b9280c0e1 | 182 | |
| yihui | 0:9c6b9280c0e1 | 183 | DMSG("\n"); |
| yihui | 0:9c6b9280c0e1 | 184 | } |
| yihui | 0:9c6b9280c0e1 | 185 | |
| yihui | 0:9c6b9280c0e1 | 186 | int8_t PN532_SPI::readAckFrame() |
| yihui | 0:9c6b9280c0e1 | 187 | { |
| yihui | 0:9c6b9280c0e1 | 188 | const uint8_t PN532_ACK[] = {0, 0, 0xFF, 0, 0xFF, 0}; |
| yihui | 0:9c6b9280c0e1 | 189 | |
| yihui | 0:9c6b9280c0e1 | 190 | uint8_t ackBuf[sizeof(PN532_ACK)]; |
| yihui | 0:9c6b9280c0e1 | 191 | |
| yihui | 0:9c6b9280c0e1 | 192 | _ss = 0; |
| yihui | 0:9c6b9280c0e1 | 193 | wait_ms(1); |
| yihui | 0:9c6b9280c0e1 | 194 | write(DATA_READ); |
| yihui | 0:9c6b9280c0e1 | 195 | |
| yihui | 0:9c6b9280c0e1 | 196 | for (uint8_t i = 0; i < sizeof(PN532_ACK); i++) { |
| yihui | 0:9c6b9280c0e1 | 197 | ackBuf[i] = read(); |
| yihui | 0:9c6b9280c0e1 | 198 | } |
| yihui | 0:9c6b9280c0e1 | 199 | |
| yihui | 0:9c6b9280c0e1 | 200 | _ss = 1; |
| yihui | 0:9c6b9280c0e1 | 201 | |
| yihui | 0:9c6b9280c0e1 | 202 | return memcmp(ackBuf, PN532_ACK, sizeof(PN532_ACK)); |
| yihui | 0:9c6b9280c0e1 | 203 | } |
