diff --git a/CardReader/lib/PN532_SPI.diff b/CardReader/lib/PN532_SPI.diff new file mode 100644 index 0000000..9eb10f0 --- /dev/null +++ b/CardReader/lib/PN532_SPI.diff @@ -0,0 +1,29 @@ +diff PN532/PN532_SPI/PN532_SPI.cpp lib/PN532_SPI/PN532_SPI.cpp +10c10 +< PN532_SPI::PN532_SPI(SPIClass &spi, uint8_t ss) +--- +> PN532_SPI::PN532_SPI(SPIClass &spi, uint8_t sck, uint8_t miso, uint8_t mosi, uint8_t ss) +14c14,17 +< _ss = ss; +--- +> _sck = sck; +> _miso = miso; +> _mosi = mosi; +> _ss = ss; +21c24 +< _spi->begin(); +--- +> _spi->begin(_sck, _miso, _mosi, _ss); +diff PN532/PN532_SPI/PN532_SPI.h lib/PN532_SPI/PN532_SPI.h +10c10 +< PN532_SPI(SPIClass &spi, uint8_t ss); +--- +> PN532_SPI(SPIClass &spi, uint8_t sck, uint8_t miso, uint8_t mosi, uint8_t ss); +19a20,22 +> uint8_t _sck; +> uint8_t _miso; +> uint8_t _mosi; +23c26 +< boolean isReady(); +--- +> bool isReady(); diff --git a/CardReader/lib/PN532_SPI/PN532_SPI.cpp b/CardReader/lib/PN532_SPI/PN532_SPI.cpp new file mode 100644 index 0000000..6106f79 --- /dev/null +++ b/CardReader/lib/PN532_SPI/PN532_SPI.cpp @@ -0,0 +1,213 @@ + +#include "PN532_SPI.h" +#include "PN532_debug.h" +#include "Arduino.h" + +#define STATUS_READ 2 +#define DATA_WRITE 1 +#define DATA_READ 3 + +PN532_SPI::PN532_SPI(SPIClass &spi, uint8_t sck, uint8_t miso, uint8_t mosi, uint8_t ss) +{ + command = 0; + _spi = &spi; + _sck = sck; + _miso = miso; + _mosi = mosi; + _ss = ss; +} + +void PN532_SPI::begin() +{ + pinMode(_ss, OUTPUT); + + _spi->begin(_sck, _miso, _mosi, _ss); + _spi->setDataMode(SPI_MODE0); // PN532 only supports mode0 + _spi->setBitOrder(LSBFIRST); +#ifndef __SAM3X8E__ + _spi->setClockDivider(SPI_CLOCK_DIV8); // set clock 2MHz(max: 5MHz) +#else + /** DUE spi library does not support SPI_CLOCK_DIV8 macro */ + _spi->setClockDivider(42); // set clock 2MHz(max: 5MHz) +#endif + +} + +void PN532_SPI::wakeup() +{ + digitalWrite(_ss, LOW); + delay(2); + digitalWrite(_ss, HIGH); +} + + + +int8_t PN532_SPI::writeCommand(const uint8_t *header, uint8_t hlen, const uint8_t *body, uint8_t blen) +{ + command = header[0]; + writeFrame(header, hlen, body, blen); + + uint8_t timeout = PN532_ACK_WAIT_TIME; + while (!isReady()) { + delay(1); + timeout--; + if (0 == timeout) { + DMSG("Time out when waiting for ACK\n"); + return -2; + } + } + if (readAckFrame()) { + DMSG("Invalid ACK\n"); + return PN532_INVALID_ACK; + } + return 0; +} + +int16_t PN532_SPI::readResponse(uint8_t buf[], uint8_t len, uint16_t timeout) +{ + uint16_t time = 0; + while (!isReady()) { + delay(1); + time++; + if (timeout > 0 && time > timeout) { + return PN532_TIMEOUT; + } + } + + digitalWrite(_ss, LOW); + delay(1); + + int16_t result; + do { + write(DATA_READ); + + if (0x00 != read() || // PREAMBLE + 0x00 != read() || // STARTCODE1 + 0xFF != read() // STARTCODE2 + ) { + + result = PN532_INVALID_FRAME; + break; + } + + uint8_t length = read(); + if (0 != (uint8_t)(length + read())) { // checksum of length + result = PN532_INVALID_FRAME; + break; + } + + uint8_t cmd = command + 1; // response command + if (PN532_PN532TOHOST != read() || (cmd) != read()) { + result = PN532_INVALID_FRAME; + break; + } + + DMSG("read: "); + DMSG_HEX(cmd); + + length -= 2; + if (length > len) { + for (uint8_t i = 0; i < length; i++) { + DMSG_HEX(read()); // dump message + } + DMSG("\nNot enough space\n"); + read(); + read(); + result = PN532_NO_SPACE; // not enough space + break; + } + + uint8_t sum = PN532_PN532TOHOST + cmd; + for (uint8_t i = 0; i < length; i++) { + buf[i] = read(); + sum += buf[i]; + + DMSG_HEX(buf[i]); + } + DMSG('\n'); + + uint8_t checksum = read(); + if (0 != (uint8_t)(sum + checksum)) { + DMSG("checksum is not ok\n"); + result = PN532_INVALID_FRAME; + break; + } + read(); // POSTAMBLE + + result = length; + } while (0); + + digitalWrite(_ss, HIGH); + + return result; +} + +boolean PN532_SPI::isReady() +{ + digitalWrite(_ss, LOW); + + write(STATUS_READ); + uint8_t status = read() & 1; + digitalWrite(_ss, HIGH); + return status; +} + +void PN532_SPI::writeFrame(const uint8_t *header, uint8_t hlen, const uint8_t *body, uint8_t blen) +{ + digitalWrite(_ss, LOW); + delay(2); // wake up PN532 + + write(DATA_WRITE); + write(PN532_PREAMBLE); + write(PN532_STARTCODE1); + write(PN532_STARTCODE2); + + uint8_t length = hlen + blen + 1; // length of data field: TFI + DATA + write(length); + write(~length + 1); // checksum of length + + write(PN532_HOSTTOPN532); + uint8_t sum = PN532_HOSTTOPN532; // sum of TFI + DATA + + DMSG("write: "); + + for (uint8_t i = 0; i < hlen; i++) { + write(header[i]); + sum += header[i]; + + DMSG_HEX(header[i]); + } + for (uint8_t i = 0; i < blen; i++) { + write(body[i]); + sum += body[i]; + + DMSG_HEX(body[i]); + } + + uint8_t checksum = ~sum + 1; // checksum of TFI + DATA + write(checksum); + write(PN532_POSTAMBLE); + + digitalWrite(_ss, HIGH); + + DMSG('\n'); +} + +int8_t PN532_SPI::readAckFrame() +{ + const uint8_t PN532_ACK[] = {0, 0, 0xFF, 0, 0xFF, 0}; + + uint8_t ackBuf[sizeof(PN532_ACK)]; + + digitalWrite(_ss, LOW); + delay(1); + write(DATA_READ); + + for (uint8_t i = 0; i < sizeof(PN532_ACK); i++) { + ackBuf[i] = read(); + } + + digitalWrite(_ss, HIGH); + + return memcmp(ackBuf, PN532_ACK, sizeof(PN532_ACK)); +} diff --git a/CardReader/lib/PN532_SPI/PN532_SPI.h b/CardReader/lib/PN532_SPI/PN532_SPI.h new file mode 100644 index 0000000..63a495d --- /dev/null +++ b/CardReader/lib/PN532_SPI/PN532_SPI.h @@ -0,0 +1,39 @@ + +#ifndef __PN532_SPI_H__ +#define __PN532_SPI_H__ + +#include +#include "PN532Interface.h" + +class PN532_SPI : public PN532Interface { +public: + PN532_SPI(SPIClass &spi, uint8_t sck, uint8_t miso, uint8_t mosi, uint8_t ss); + + void begin(); + void wakeup(); + int8_t writeCommand(const uint8_t *header, uint8_t hlen, const uint8_t *body = 0, uint8_t blen = 0); + + int16_t readResponse(uint8_t buf[], uint8_t len, uint16_t timeout); + +private: + SPIClass* _spi; + uint8_t _sck; + uint8_t _miso; + uint8_t _mosi; + uint8_t _ss; + uint8_t command; + + bool isReady(); + void writeFrame(const uint8_t *header, uint8_t hlen, const uint8_t *body = 0, uint8_t blen = 0); + int8_t readAckFrame(); + + inline void write(uint8_t data) { + _spi->transfer(data); + }; + + inline uint8_t read() { + return _spi->transfer(0); + }; +}; + +#endif diff --git a/CardReader/src/main.cpp b/CardReader/src/main.cpp index 325bdfc..09a7c1e 100644 --- a/CardReader/src/main.cpp +++ b/CardReader/src/main.cpp @@ -2,17 +2,28 @@ #include #include +#include #include #include #include +#define PN532_MODE_I2C 1 +#define PN532_MODE_SPI 2 +#define PN532_MODE PN532_MODE_I2C + constexpr u8 NUM_LEDS = 7; constexpr u8 BR_DIM = 8; constexpr u8 BR_BRIGHT = 14; CRGB leds[NUM_LEDS]; -PN532_I2C pn532i2c(Wire); -PN532 nfc(pn532i2c); +#if PN532_MODE == PN532_MODE_SPI +PN532_SPI pn532(SPI, GPIO_NUM_36, GPIO_NUM_37, GPIO_NUM_35, GPIO_NUM_34); +#elif PN532_MODE == PN532_MODE_I2C +PN532_I2C pn532(Wire); +#else +#error Invalid PN532 mode +#endif +PN532 nfc(pn532); constexpr u8 UID_LENGTH = 8; u8 prevIDm[UID_LENGTH]; @@ -27,8 +38,10 @@ void setup() USBSerial.begin(115200); USBSerial.println("Hello!"); +#if PN532_MODE == PN532_MODE_I2C // Initialize I2C communication Wire.setPins(GPIO_NUM_4, GPIO_NUM_5); +#endif // Initialize the LED CFastLED::addLeds(leds, NUM_LEDS); @@ -53,7 +66,7 @@ void setup() // Set the max number of retry attempts to read from a card // This prevents us from waiting forever for a card, which is the default behaviour of the PN532. - nfc.setPassiveActivationRetries(0xFF); + nfc.setPassiveActivationRetries(1); nfc.SAMConfig(); // Clear the IDm buffer @@ -111,13 +124,13 @@ void loop() // When one is found, some basic information such as IDm, PMm, and System Code are retrieved. leds[0] = CRGB::BlueViolet; FastLED.show(); - if (nfc.felica_Polling(0xFFFF, 0x00, idm, pmm, &systemCode, 5) == 1) + if (nfc.felica_Polling(0xFFFF, 0x00, idm, pmm, &systemCode) == 1) foundCard(idm, UID_LENGTH, "FeliCa"); // Wait for an ISO14443A type cards (MIFARE, etc.). When one is found u8 uidLength; leds[0] = CRGB::OrangeRed; FastLED.show(); - if (nfc.readPassiveTargetID(PN532_MIFARE_ISO14443A, idm, &uidLength, 5) == 1) + if (nfc.readPassiveTargetID(PN532_MIFARE_ISO14443A, idm, &uidLength) == 1) foundCard(idm, uidLength, "ISO14443A"); }