Skip to content

Commit

Permalink
Version 1.8
Browse files Browse the repository at this point in the history
  • Loading branch information
ATrappmann committed Aug 19, 2021
1 parent 000843a commit 1ded2e4
Show file tree
Hide file tree
Showing 6 changed files with 309 additions and 8 deletions.
9 changes: 6 additions & 3 deletions PN5180.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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<len; i++) {
PN5180DEBUG(formatHex(readBuffer[i]));
PN5180DEBUG(formatHex(buffer[i]));
PN5180DEBUG(" ");
}
PN5180DEBUG("\n");
Expand Down
2 changes: 1 addition & 1 deletion PN5180.h
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ class PN5180 {
/* cmd 0x09 */
bool sendData(uint8_t *data, int len, uint8_t validBits = 0);
/* cmd 0x0a */
uint8_t * readData(int len);
uint8_t * readData(int len, uint8_t *buffer = NULL);

/* cmd 0x11 */
bool loadRFConfig(uint8_t txConf, uint8_t rxConf);
Expand Down
242 changes: 242 additions & 0 deletions PN5180ISO14443.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,242 @@
// 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.
//
// #define DEBUG 1

#include <Arduino.h>
#include "PN5180ISO14443.h"
#include <PN5180.h>
#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);
}

46 changes: 46 additions & 0 deletions PN5180ISO14443.h
Original file line number Diff line number Diff line change
@@ -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 */
11 changes: 10 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
7 changes: 4 additions & 3 deletions keywords.txt
Original file line number Diff line number Diff line change
@@ -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
Expand Down

0 comments on commit 1ded2e4

Please sign in to comment.