diff --git a/PN5180.cpp b/PN5180.cpp index 661bcd1..81d4d34 100644 --- a/PN5180.cpp +++ b/PN5180.cpp @@ -336,11 +336,14 @@ bool PN5180::sendData(uint8_t *data, int len, uint8_t validBits) { * preceding an RF data reception, no exception is raised but the data read back from the * reception buffer is invalid. If the condition is not fulfilled, an exception is raised. */ -uint8_t * PN5180::readData(int len) { +uint8_t * PN5180::readData(int len, uint8_t *buffer /* = NULL */) { if (len > 508) { Serial.println(F("*** FATAL: Reading more than 508 bytes is not supported!")); return 0L; } + if (NULL == buffer) { + buffer = readBuffer; + } PN5180DEBUG(F("Reading Data (len=")); PN5180DEBUG(len); @@ -349,13 +352,13 @@ uint8_t * PN5180::readData(int len) { uint8_t cmd[2] = { PN5180_READ_DATA, 0x00 }; SPI.beginTransaction(PN5180_SPI_SETTINGS); - transceiveCommand(cmd, 2, readBuffer, len); + transceiveCommand(cmd, 2, buffer, len); SPI.endTransaction(); #ifdef DEBUG PN5180DEBUG(F("Data read: ")); for (int i=0; i +#include "PN5180ISO14443.h" +#include +#include "Debug.h" + +PN5180ISO14443::PN5180ISO14443(uint8_t SSpin, uint8_t BUSYpin, uint8_t RSTpin) + : PN5180(SSpin, BUSYpin, RSTpin) { +} + +bool PN5180ISO14443::setupRF() { + PN5180DEBUG(F("Loading RF-Configuration...\n")); + if (loadRFConfig(0x00, 0x80)) { // ISO14443 parameters + PN5180DEBUG(F("done.\n")); + } + else return false; + + PN5180DEBUG(F("Turning ON RF field...\n")); + if (setRF_on()) { + PN5180DEBUG(F("done.\n")); + } + else return false; + + return true; +} + +uint16_t PN5180ISO14443::rxBytesReceived() { + uint32_t rxStatus; + uint16_t len = 0; + readRegister(RX_STATUS, &rxStatus); + // Lower 9 bits has length + len = (uint16_t)(rxStatus & 0x000001ff); + return len; +} +/* +* buffer : must be 10 byte array +* buffer[0-1] is ATQA +* buffer[2] is sak +* buffer[3..6] is 4 byte UID +* buffer[7..9] is remaining 3 bytes of UID for 7 Byte UID tags +* kind : 0 we send REQA, 1 we send WUPA +* +* return value: the uid length: +* - zero if no tag was recognized +* - single Size UID (4 byte) +* - double Size UID (7 byte) +* - triple Size UID (10 byte) - not yet supported +*/ +uint8_t PN5180ISO14443::activateTypeA(uint8_t *buffer, uint8_t kind) { + uint8_t cmd[7]; + uint8_t uidLength = 0; + // Load standard TypeA protocol + if (!loadRFConfig(0x0, 0x80)) + return 0; + + // OFF Crypto + if (!writeRegisterWithAndMask(SYSTEM_CONFIG, 0xFFFFFFBF)) + return 0; + // Clear RX CRC + if (!writeRegisterWithAndMask(CRC_RX_CONFIG, 0xFFFFFFFE)) + return 0; + // Clear TX CRC + if (!writeRegisterWithAndMask(CRC_TX_CONFIG, 0xFFFFFFFE)) + return 0; + //Send REQA/WUPA, 7 bits in last byte + cmd[0] = (kind == 0) ? 0x26 : 0x52; + if (!sendData(cmd, 1, 0x07)) + return 0; + // READ 2 bytes ATQA into buffer + if (!readData(2, buffer)) + return 0; + //Send Anti collision 1, 8 bits in last byte + cmd[0] = 0x93; + cmd[1] = 0x20; + if (!sendData(cmd, 2, 0x00)) + return 0; + //Read 5 bytes, we will store at offset 2 for later usage + if (!readData(5, cmd+2)) + return 0; + //Enable RX CRC calculation + if (!writeRegisterWithOrMask(CRC_RX_CONFIG, 0x01)) + return 0; + //Enable TX CRC calculation + if (!writeRegisterWithOrMask(CRC_TX_CONFIG, 0x01)) + return 0; + //Send Select anti collision 1, the remaining bytes are already in offset 2 onwards + cmd[0] = 0x93; + cmd[1] = 0x70; + if (!sendData(cmd, 7, 0x00)) + return 0; + //Read 1 byte SAK into buffer[2] + if (!readData(1, buffer+2)) + return 0; + // Check if the tag is 4 Byte UID or 7 byte UID and requires anti collision 2 + // If Bit 3 is 0 it is 4 Byte UID + if ((buffer[2] & 0x04) == 0) { + // Take first 4 bytes of anti collision as UID store at offset 3 onwards. job done + for (int i = 0; i < 4; i++) buffer[3+i] = cmd[2 + i]; + uidLength = 4; + } + else { + // Take First 3 bytes of UID, Ignore first byte 88(CT) + if (cmd[2] != 0x88) + return 0; + for (int i = 0; i < 3; i++) buffer[3+i] = cmd[3 + i]; + // Clear RX CRC + if (!writeRegisterWithAndMask(CRC_RX_CONFIG, 0xFFFFFFFE)) + return 0; + // Clear TX CRC + if (!writeRegisterWithAndMask(CRC_TX_CONFIG, 0xFFFFFFFE)) + return 0; + // Do anti collision 2 + cmd[0] = 0x95; + cmd[1] = 0x20; + if (!sendData(cmd, 2, 0x00)) + return 0; + //Read 5 bytes. we will store at offset 2 for later use + if (!readData(5, cmd+2)) + return 0; + // first 4 bytes belongs to last 4 UID bytes, we keep it. + for (int i = 0; i < 4; i++) { + buffer[6 + i] = cmd[2+i]; + } + //Enable RX CRC calculation + if (!writeRegisterWithOrMask(CRC_RX_CONFIG, 0x01)) + return 0; + //Enable TX CRC calculation + if (!writeRegisterWithOrMask(CRC_TX_CONFIG, 0x01)) + return 0; + //Send Select anti collision 2 + cmd[0] = 0x95; + cmd[1] = 0x70; + if (!sendData(cmd, 7, 0x00)) + return 0; + //Read 1 byte SAK into buffer[2] + if (!readData(1, buffer + 2)) + return 0; + uidLength = 7; + } + return uidLength; +} + +bool PN5180ISO14443::mifareBlockRead(uint8_t blockno, uint8_t *buffer) { + bool success = false; + uint16_t len; + uint8_t cmd[2]; + // Send mifare command 30,blockno + cmd[0] = 0x30; + cmd[1] = blockno; + if (!sendData(cmd, 2, 0x00)) + return false; + //Check if we have received any data from the tag + delay(5); + len = rxBytesReceived(); + if (len == 16) { + // READ 16 bytes into buffer + if (readData(16, buffer)) + success = true; + } + return success; +} + + +uint8_t PN5180ISO14443::mifareBlockWrite16(uint8_t blockno, uint8_t *buffer) { + uint8_t cmd[1]; + // Clear RX CRC + writeRegisterWithAndMask(CRC_RX_CONFIG, 0xFFFFFFFE); + + // Mifare write part 1 + cmd[0] = 0xA0; + cmd[1] = blockno; + sendData(cmd, 2, 0x00); + readData(1, cmd); + + // Mifare write part 2 + sendData(buffer,16, 0x00); + delay(10); + + // Read ACK/NAK + readData(1, cmd); + + //Enable RX CRC calculation + writeRegisterWithOrMask(CRC_RX_CONFIG, 0x1); + return cmd[0]; +} + +bool PN5180ISO14443::mifareHalt() { + uint8_t cmd[1]; + //mifare Halt + cmd[0] = 0x50; + cmd[1] = 0x00; + sendData(cmd, 2, 0x00); + return true; +} + +uint8_t PN5180ISO14443::readCardSerial(uint8_t *buffer) { + + uint8_t response[10]; + uint8_t uidLength; + // Always return 10 bytes + // Offset 0..1 is ATQA + // Offset 2 is SAK. + // UID 4 bytes : offset 3 to 6 is UID, offset 7 to 9 to Zero + // UID 7 bytes : offset 3 to 9 is UID + for (int i = 0; i < 10; i++) response[i] = 0; + uidLength = activateTypeA(response, 1); + if ((response[0] == 0xFF) && (response[1] == 0xFF)) + return 0; + // check for valid uid + if ((response[3] == 0x00) && (response[4] == 0x00) && (response[5] == 0x00) && (response[6] == 0x00)) + return 0; + if ((response[3] == 0xFF) && (response[4] == 0xFF) && (response[5] == 0xFF) && (response[6] == 0xFF)) + return 0; + for (int i = 0; i < 7; i++) buffer[i] = response[i+3]; + mifareHalt(); + return uidLength; +} + +bool PN5180ISO14443::isCardPresent() { + uint8_t buffer[10]; + return (readCardSerial(buffer) >=4); +} + diff --git a/PN5180ISO14443.h b/PN5180ISO14443.h new file mode 100644 index 0000000..166d183 --- /dev/null +++ b/PN5180ISO14443.h @@ -0,0 +1,46 @@ +// NAME: PN5180ISO14443.h +// +// DESC: ISO14443 protocol on NXP Semiconductors PN5180 module for Arduino. +// +// Copyright (c) 2019 by Dirk Carstensen. All rights reserved. +// +// This file is part of the PN5180 library for the Arduino environment. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +#ifndef PN5180ISO14443_H +#define PN5180ISO14443_H + +#include "PN5180.h" + +class PN5180ISO14443 : public PN5180 { + +public: + PN5180ISO14443(uint8_t SSpin, uint8_t BUSYpin, uint8_t RSTpin); + +private: + uint16_t rxBytesReceived(); +public: + // Mifare TypeA + uint8_t activateTypeA(uint8_t *buffer, uint8_t kind); + bool mifareBlockRead(uint8_t blockno,uint8_t *buffer); + uint8_t mifareBlockWrite16(uint8_t blockno, uint8_t *buffer); + bool mifareHalt(); + /* + * Helper functions + */ +public: + bool setupRF(); + uint8_t readCardSerial(uint8_t *buffer); + bool isCardPresent(); +}; + +#endif /* PN5180ISO14443_H */ diff --git a/README.md b/README.md index 2797aef..3c28508 100644 --- a/README.md +++ b/README.md @@ -7,10 +7,19 @@ Arduino Uno / Arduino ESP-32 library for PN5180-NFC Module from NXP Semiconducto Release Notes: +Version 1.8 - 19.08.2021 + + * Added readData and ISO1443 support. + +Version 1.7 - 12.07.2021 + + * Migrated branch from Dirk Carstensen for ISO14443 tags to the library. + * See https://github.com/tueddy/PN5180-Library/tree/ISO14443 + Version 1.6 - 13.03.2021 * Added PN5180::writeEEPROM - + Version 1.5 - 29.01.2020 * Fixed offset in readSingleBlock. Was off by 1. diff --git a/keywords.txt b/keywords.txt index 6ce7138..7393b18 100644 --- a/keywords.txt +++ b/keywords.txt @@ -1,15 +1,16 @@ ####################################### # Syntax Coloring Map For PN5180-Library -####################################### +####################################### # Class ####################################### PN5180 KEYWORD1 PN5180ISO15693 KEYWORD1 +PN5180ISO14443 KEYWORD1 ####################################### -# Methods and Functions -####################################### +# Methods and Functions +####################################### writeRegister KEYWORD2 writeRegisterWithOrMask KEYWORD2