refactor class

move new rats functions to extra class
This commit is contained in:
Rotzbua
2017-03-13 21:57:41 +01:00
parent 45b7e60584
commit 4edd4acca6
4 changed files with 1281 additions and 964 deletions

View File

@@ -5,7 +5,7 @@
*/
#include <Arduino.h>
#include <MFRC522.h>
#include "MFRC522.h"
/////////////////////////////////////////////////////////////////////////////////////
// Functions for setting up the Arduino
@@ -472,7 +472,7 @@ MFRC522::StatusCode MFRC522::PCD_CommunicateWithPICC( byte command, ///< The co
byte _validBits = 0;
// If the caller wants data back, get it from the MFRC522.
// If the caller wants data back, get it from the MFRC522.
if (backData && backLen) {
byte n = PCD_ReadRegister(FIFOLevelReg); // Number of bytes in the FIFO
if (n > *backLen) {
@@ -790,102 +790,6 @@ MFRC522::StatusCode MFRC522::PICC_Select( Uid *uid, ///< Pointer to Uid struct
// Set correct uid->size
uid->size = 3 * cascadeLevel + 1;
// IF SAK bit 6 = 1 then it is ISO/IEC 14443-4 (T=CL)
// A Request ATS command should be sent
// We also check SAK bit 3 is cero, as it stands for UID complete (1 would tell us it is incomplete)
if ((uid->sak & 0x24) == 0x20) {
Ats ats;
result = PICC_RequestATS(&ats);
if (result == STATUS_OK) {
// Check the ATS
if (ats.size > 0)
{
// TA1 has been transmitted?
// PPS must be supported...
if (ats.ta1.transmitted)
{
// TA1
// 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | Description
// ---+---+---+---+---+---+---+---+------------------------------------------
// 0 | - | - | - | 0 | - | - | - | Different D for each direction supported
// 1 | - | - | - | 0 | - | - | - | Only same D for both direction supported
// - | x | x | x | 0 | - | - | - | DS (Send D)
// - | - | - | - | 0 | x | x | x | DR (Receive D)
//
// D to bitrate table
// 3 | 2 | 1 | Value
// ---+---+---+-----------------------------
// 1 | - | - | 848 kBaud is supported
// - | 1 | - | 424 kBaud is supported
// - | - | 1 | 212 kBaud is supported
// 0 | 0 | 0 | Only 106 kBaud is supported
//
// Note: 106 kBaud is always supported
//
// I have almost constant timeouts when changing speeds :(
TagBitRates ds = BITRATE_106KBITS;
TagBitRates dr = BITRATE_106KBITS;
//// Not working at 848 or 424
//if (ats.ta1.ds & 0x04)
//{
// ds = BITRATE_848KBITS;
//}
//else if (ats.ta1.ds & 0x02)
//{
// ds = BITRATE_424KBITS;
//}
//else if (ats.ta1.ds & 0x01)
//{
// ds = BITRATE_212KBITS;
//}
//else
//{
// ds = BITRATE_106KBITS;
//}
if (ats.ta1.ds & 0x01)
{
ds = BITRATE_212KBITS;
}
else
{
ds = BITRATE_106KBITS;
}
//// Not working at 848 or 424
//if (ats.ta1.dr & 0x04)
//{
// dr = BITRATE_848KBITS;
//}
//else if (ats.ta1.dr & 0x02)
//{
// dr = BITRATE_424KBITS;
//}
//else if (ats.ta1.dr & 0x01)
//{
// dr = BITRATE_212KBITS;
//}
//else
//{
// dr = BITRATE_106KBITS;
//}
if (ats.ta1.dr & 0x01)
{
dr = BITRATE_212KBITS;
}
else
{
dr = BITRATE_106KBITS;
}
PICC_PPS(ds, dr);
}
}
}
}
return STATUS_OK;
} // End PICC_Select()
@@ -923,615 +827,6 @@ MFRC522::StatusCode MFRC522::PICC_HaltA() {
return result;
} // End PICC_HaltA()
/**
* Transmits a Request command for Answer To Select (ATS).
*
* @return STATUS_OK on success, STATUS_??? otherwise.
*/
MFRC522::StatusCode MFRC522::PICC_RequestATS(Ats *ats)
{
byte count;
MFRC522::StatusCode result;
byte bufferATS[FIFO_SIZE];
byte bufferSize = FIFO_SIZE;
memset(bufferATS, 0, FIFO_SIZE);
// Build command buffer
bufferATS[0] = PICC_CMD_RATS;
// The CID defines the logical number of the addressed card and has a range of 0
// through 14; 15 is reserved for future use (RFU).
//
// FSDI codes the maximum frame size (FSD) that the terminal can receive.
//
// FSDI | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9-F
// ------------+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----------
// FSD (bytes) | 16 | 24 | 32 | 40 | 48 | 64 | 96 | 128 | 256 | RFU > 256
//
bufferATS[1] = 0x50; // FSD=64, CID=0
// Calculate CRC_A
result = PCD_CalculateCRC(bufferATS, 2, &bufferATS[2]);
if (result != STATUS_OK) {
return result;
}
// Transmit the buffer and receive the response, validate CRC_A.
result = PCD_TransceiveData(bufferATS, 4, bufferATS, &bufferSize, NULL, 0, true);
if (result != STATUS_OK) {
PICC_HaltA();
}
// Set the ats structure data
ats->size = bufferATS[0];
// T0 byte:
//
// b8 | b7 | b6 | b5 | b4 | b3 | b2 | b1 | Meaning
//----+----+----+----+----+----+----+----+---------------------------
// 0 | ...| ...| ...| ...|... | ...| ...| Set to 0 (RFU)
// 0 | 1 | x | x | ...|... | ...| ...| TC1 transmitted
// 0 | x | 1 | x | ...|... | ...| ...| TB1 transmitted
// 0 | x | x | 1 | ...|... | ...| ...| TA1 transmitted
// 0 | ...| ...| ...| x | x | x | x | Maximum frame size (FSCI)
//
// FSCI | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9-F
// ------------+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----------
// FSC (bytes) | 16 | 24 | 32 | 40 | 48 | 64 | 96 | 128 | 256 | RFU > 256
//
// Default FSCI is 2 (32 bytes)
if (ats->size > 0x01)
{
// TC1, TB1 and TA1 where NOT transmitted
ats->ta1.transmitted = (bool)(bufferATS[1] & 0x40);
ats->tb1.transmitted = (bool)(bufferATS[1] & 0x20);
ats->tc1.transmitted = (bool)(bufferATS[1] & 0x10);
// Decode FSCI
switch (bufferATS[1] & 0x0F)
{
case 0x00:
ats->fsc = 16;
break;
case 0x01:
ats->fsc = 24;
break;
case 0x02:
ats->fsc = 32;
break;
case 0x03:
ats->fsc = 40;
break;
case 0x04:
ats->fsc = 48;
break;
case 0x05:
ats->fsc = 64;
break;
case 0x06:
ats->fsc = 96;
break;
case 0x07:
ats->fsc = 128;
break;
case 0x08:
// This value cannot be hold by a byte
// The reason I ignore it is that MFRC255 FIFO is 64 bytes so this is not a possible value (or atleast it shouldn't)
//ats->fsc = 256;
break;
// TODO: What to do with RFU (Reserved for future use)?
}
// TA1
if (ats->ta1.transmitted)
{
ats->ta1.sameD = (bool)(bufferATS[2] & 0x80);
ats->ta1.ds = (TagBitRates)((bufferATS[2] & 0x70) >> 4);
ats->ta1.dr = (TagBitRates)(bufferATS[2] & 0x07);
}
else
{
// Default TA1
ats->ta1.ds = BITRATE_106KBITS;
ats->ta1.dr = BITRATE_106KBITS;
}
// TB1
if (ats->tb1.transmitted)
{
uint8_t tb1Index = 2;
if (ats->ta1.transmitted)
tb1Index++;
ats->tb1.fwi = (bufferATS[tb1Index] & 0xF0) >> 4;
ats->tb1.sfgi = bufferATS[tb1Index] & 0x0F;
}
else
{
// Defaults for TB1
ats->tb1.fwi = 0; // TODO: Don't know the default for this!
ats->tb1.sfgi = 0; // The default value of SFGI is 0 (meaning that the card does not need any particular SFGT)
}
// TC1
if (ats->tc1.transmitted)
{
uint8_t tc1Index = 2;
if (ats->ta1.transmitted)
tc1Index++;
if (ats->tb1.transmitted)
tc1Index++;
ats->tc1.supportsCID = (bool)(bufferATS[tc1Index] & 0x02);
ats->tc1.supportsNAD = (bool)(bufferATS[tc1Index] & 0x01);
}
else
{
// Defaults for TC1
ats->tc1.supportsCID = true;
ats->tc1.supportsNAD = false;
}
}
else
{
// TC1, TB1 and TA1 where NOT transmitted
ats->ta1.transmitted = false;
ats->tb1.transmitted = false;
ats->tc1.transmitted = false;
// Default FSCI
ats->fsc = 32; // Defaults to FSCI 2 (32 bytes)
// Default TA1
ats->ta1.sameD = false;
ats->ta1.ds = BITRATE_106KBITS;
ats->ta1.dr = BITRATE_106KBITS;
// Defaults for TB1
ats->tb1.transmitted = false;
ats->tb1.fwi = 0; // TODO: Don't know the default for this!
ats->tb1.sfgi = 0; // The default value of SFGI is 0 (meaning that the card does not need any particular SFGT)
// Defaults for TC1
ats->tc1.transmitted = false;
ats->tc1.supportsCID = true;
ats->tc1.supportsNAD = false;
}
memcpy(ats->data, bufferATS, bufferSize - 2);
return result;
} // End PICC_RequestATS()
/**
* Transmits Protocol and Parameter Selection Request (PPS) without parameter 1
*
* @return STATUS_OK on success, STATUS_??? otherwise.
*/
MFRC522::StatusCode MFRC522::PICC_PPS()
{
StatusCode result;
byte ppsBuffer[4];
byte ppsBufferSize = 4;
// Start byte: The start byte (PPS) consists of two parts:
// The upper nibble(b8b5) is set toD'to identify the PPS. All other values are RFU.
// -The lower nibble(b4b1), which is called the card identifier (CID), defines the logical number of the addressed card.
ppsBuffer[0] = 0xD0; // CID is hardcoded as 0 in RATS
ppsBuffer[1] = 0x00; // PPS0 indicates whether PPS1 is present
// Calculate CRC_A
result = PCD_CalculateCRC(ppsBuffer, 2, &ppsBuffer[2]);
if (result != STATUS_OK) {
return result;
}
// Transmit the buffer and receive the response, validate CRC_A.
result = PCD_TransceiveData(ppsBuffer, 4, ppsBuffer, &ppsBufferSize, NULL, 0, true);
if (result == STATUS_OK)
{
// Enable CRC for T=CL
byte txReg = PCD_ReadRegister(TxModeReg) | 0x80;
byte rxReg = PCD_ReadRegister(RxModeReg) | 0x80;
PCD_WriteRegister(TxModeReg, txReg);
PCD_WriteRegister(RxModeReg, rxReg);
}
return result;
} // End PICC_PPS()
/**
* Transmits Protocol and Parameter Selection Request (PPS)
*
* @return STATUS_OK on success, STATUS_??? otherwise.
*/
MFRC522::StatusCode MFRC522::PICC_PPS(TagBitRates sendBitRate, ///< DS
TagBitRates receiveBitRate ///< DR
) {
StatusCode result;
byte txReg = PCD_ReadRegister(TxModeReg) & 0x8F;
byte rxReg = PCD_ReadRegister(RxModeReg) & 0x8F;
byte ppsBuffer[5];
byte ppsBufferSize = 5;
// Start byte: The start byte (PPS) consists of two parts:
// The upper nibble(b8b5) is set toD'to identify the PPS. All other values are RFU.
// -The lower nibble(b4b1), which is called the card identifier (CID), defines the logical number of the addressed card.
ppsBuffer[0] = 0xD0; // CID is hardcoded as 0 in RATS
ppsBuffer[1] = 0x11; // PPS0 indicates whether PPS1 is present
// Bit 8 - Set to '0' as MFRC522 allows different bit rates for send and receive
// Bit 4 - Set to '0' as it is Reserved for future use.
//ppsBuffer[2] = (((sendBitRate & 0x03) << 4) | (receiveBitRate & 0x03)) & 0xE7;
ppsBuffer[2] = (((sendBitRate & 0x03) << 2) | (receiveBitRate & 0x03)) & 0xE7;
// Calculate CRC_A
result = PCD_CalculateCRC(ppsBuffer, 3, &ppsBuffer[3]);
if (result != STATUS_OK) {
return result;
}
// Transmit the buffer and receive the response, validate CRC_A.
result = PCD_TransceiveData(ppsBuffer, 5, ppsBuffer, &ppsBufferSize, NULL, 0, true);
if (result == STATUS_OK)
{
// Make sure it is an answer to our PPS
// We should receive our PPS byte and 2 CRC bytes
if ((ppsBufferSize == 3) && (ppsBuffer[0] == 0xD0)) {
byte txReg = PCD_ReadRegister(TxModeReg) & 0x8F;
byte rxReg = PCD_ReadRegister(RxModeReg) & 0x8F;
// Set bit rate and enable CRC for T=CL
txReg = (txReg & 0x8F) | ((receiveBitRate & 0x03) << 4) | 0x80;
rxReg = (rxReg & 0x8F) | ((sendBitRate & 0x03) << 4) | 0x80;
rxReg &= 0xF0; //Enforce although this should be set already
// From ConfigIsoType
//rxReg |= 0x06;
PCD_WriteRegister(TxModeReg, txReg);
PCD_WriteRegister(RxModeReg, rxReg);
// At 212kBps
switch (sendBitRate) {
case BITRATE_212KBITS:
{
//PCD_WriteRegister(ModWidthReg, 0x13);
PCD_WriteRegister(ModWidthReg, 0x15);
}
break;
case BITRATE_424KBITS:
{
PCD_WriteRegister(ModWidthReg, 0x0A);
}
break;
case BITRATE_848KBITS:
{
PCD_WriteRegister(ModWidthReg, 0x05);
}
break;
default:
{
PCD_WriteRegister(ModWidthReg, 0x26); // Default value
}
break;
}
//PCD_WriteRegister(RxThresholdReg, 0x84); // ISO-14443.4 Type A (default)
//PCD_WriteRegister(ControlReg, 0x10);
delayMicroseconds(10);
}
else
{
return STATUS_ERROR;
}
}
return result;
} // End PICC_PPS()
/////////////////////////////////////////////////////////////////////////////////////
// Functions for communicating with ISO/IEC 14433-4 cards
/////////////////////////////////////////////////////////////////////////////////////
MFRC522::StatusCode MFRC522::TCL_Transceive(PcbBlock *send, PcbBlock *back)
{
MFRC522::StatusCode result;
byte inBuffer[FIFO_SIZE];
byte inBufferSize = FIFO_SIZE;
byte outBuffer[send->inf.size + 5]; // PCB + CID + NAD + INF + EPILOGUE (CRC)
byte outBufferOffset = 1;
byte inBufferOffset = 1;
// Set the PCB byte
outBuffer[0] = send->prologue.pcb;
// Set the CID byte if available
if (send->prologue.pcb & 0x08) {
outBuffer[outBufferOffset] = send->prologue.cid;
outBufferOffset++;
}
// Set the NAD byte if available
if (send->prologue.pcb & 0x04) {
outBuffer[outBufferOffset] = send->prologue.nad;
outBufferOffset++;
}
// Copy the INF field if available
if (send->inf.size > 0) {
memcpy(&outBuffer[outBufferOffset], send->inf.data, send->inf.size);
outBufferOffset += send->inf.size;
}
// Is the CRC enabled for transmission?
byte txModeReg = PCD_ReadRegister(TxModeReg);
if ((txModeReg & 0x80) != 0x80) {
// Calculate CRC_A
result = PCD_CalculateCRC(outBuffer, outBufferOffset, &outBuffer[outBufferOffset]);
if (result != STATUS_OK) {
return result;
}
outBufferOffset += 2;
}
// Transceive the block
result = PCD_TransceiveData(outBuffer, outBufferOffset, inBuffer, &inBufferSize);
if (result != STATUS_OK) {
return result;
}
// We want to turn the received array back to a PcbBlock
back->prologue.pcb = inBuffer[0];
// CID byte is present?
if (send->prologue.pcb & 0x08) {
back->prologue.cid = inBuffer[inBufferOffset];
inBufferOffset++;
}
// NAD byte is present?
if (send->prologue.pcb & 0x04) {
back->prologue.nad = inBuffer[inBufferOffset];
inBufferOffset++;
}
// Check if CRC is taken care of by MFRC522
byte rxModeReg = PCD_ReadRegister(TxModeReg);
if ((rxModeReg & 0x80) != 0x80) {
Serial.print("CRC is not taken care of by MFRC522: ");
Serial.println(rxModeReg, HEX);
// Check the CRC
// We need at least the CRC_A value.
if ((int)(inBufferSize - inBufferOffset) < 2) {
return STATUS_CRC_WRONG;
}
// Verify CRC_A - do our own calculation and store the control in controlBuffer.
byte controlBuffer[2];
MFRC522::StatusCode status = PCD_CalculateCRC(inBuffer, inBufferSize - 2, controlBuffer);
if (status != STATUS_OK) {
return status;
}
if ((inBuffer[inBufferSize - 2] != controlBuffer[0]) || (inBuffer[inBufferSize - 1] != controlBuffer[1])) {
return STATUS_CRC_WRONG;
}
// Take away the CRC bytes
inBufferSize -= 2;
}
// Got more data?
if (inBufferSize > inBufferOffset) {
if ((inBufferSize - inBufferOffset) > back->inf.size) {
return STATUS_NO_ROOM;
}
memcpy(back->inf.data, &inBuffer[inBufferOffset], inBufferSize - inBufferOffset);
back->inf.size = inBufferSize - inBufferOffset;
} else {
back->inf.size = 0;
}
// If the response is a R-Block check NACK
if (((inBuffer[0] & 0xC0) == 0x80) && (inBuffer[0] & 0x20)) {
return STATUS_MIFARE_NACK;
}
return result;
}
/**
* Send an I-Block (Application)
*/
MFRC522::StatusCode MFRC522::TCL_Transceive(TagInfo *tag, byte *sendData, byte sendLen, byte *backData, byte *backLen)
{
MFRC522::StatusCode result;
PcbBlock out;
PcbBlock in;
byte outBuffer[FIFO_SIZE];
byte outBufferSize = FIFO_SIZE;
byte totalBackLen = *backLen;
// This command sends an I-Block
out.prologue.pcb = 0x02;
if (tag->ats.tc1.supportsCID) {
out.prologue.pcb |= 0x08;
out.prologue.cid = 0x00; // CID is curentlly hardcoded as 0x00
}
// This command doe not support NAD
out.prologue.pcb &= 0xFB;
out.prologue.nad = 0x00;
// Set the block number
if (tag->blockNumber) {
out.prologue.pcb |= 0x01;
}
// Do we have data to send?
if (sendData && (sendLen > 0)) {
out.inf.size = sendLen;
out.inf.data = sendData;
} else {
out.inf.size = 0;
out.inf.data = NULL;
}
// Initialize the receiving data
in.inf.data = outBuffer;
in.inf.size = outBufferSize;
result = TCL_Transceive(&out, &in);
if (result != STATUS_OK) {
return result;
}
// Swap block number on success
if (tag->blockNumber)
tag->blockNumber = false;
else
tag->blockNumber = true;
if (backData && (backLen > 0)) {
if (*backLen < in.inf.size)
return STATUS_NO_ROOM;
*backLen = in.inf.size;
memcpy(backData, in.inf.data, in.inf.size);
}
// Check chaining
if (in.prologue.pcb & 0x10 == 0x00)
return result;
// Result is chained
// Send an ACK to receive more data
// TODO: Should be checked I've never needed to send an ACK
while (in.prologue.pcb & 0x10) {
byte ackData[FIFO_SIZE];
byte ackDataSize = FIFO_SIZE;
result = TCL_TransceiveRBlock(tag, true, ackData, &ackDataSize);
if (result != STATUS_OK)
return result;
if (backData && (backLen > 0)) {
if ((*backLen + ackDataSize) > totalBackLen)
return STATUS_NO_ROOM;
memcpy(&(backData[*backLen]), ackData, ackDataSize);
*backLen += ackDataSize;
}
}
return result;
} // End TCL_Transceive()
/**
* Send R-Block to the PICC.
*/
MFRC522::StatusCode MFRC522::TCL_TransceiveRBlock(TagInfo *tag, bool ack, byte *backData, byte *backLen)
{
MFRC522::StatusCode result;
PcbBlock out;
PcbBlock in;
byte outBuffer[FIFO_SIZE];
byte outBufferSize = FIFO_SIZE;
// This command sends an R-Block
if (ack)
out.prologue.pcb = 0xA2; // ACK
else
out.prologue.pcb = 0xB2; // NAK
if (tag->ats.tc1.supportsCID) {
out.prologue.pcb |= 0x08;
out.prologue.cid = 0x00; // CID is curentlly hardcoded as 0x00
}
// This command doe not support NAD
out.prologue.pcb &= 0xFB;
out.prologue.nad = 0x00;
// Set the block number
if (tag->blockNumber) {
out.prologue.pcb |= 0x01;
}
// No INF data for R-Block
out.inf.size = 0;
out.inf.data = NULL;
// Initialize the receiving data
in.inf.data = outBuffer;
in.inf.size = outBufferSize;
result = TCL_Transceive(&out, &in);
if (result != STATUS_OK) {
return result;
}
// Swap block number on success
if (tag->blockNumber)
tag->blockNumber = false;
else
tag->blockNumber = true;
if (backData && backLen) {
if (*backLen < in.inf.size)
return STATUS_NO_ROOM;
*backLen = in.inf.size;
memcpy(backData, in.inf.data, in.inf.size);
}
return result;
} // End TCL_TransceiveRBlock()
/**
* Send an S-Block to deselect the card.
*/
MFRC522::StatusCode MFRC522::TCL_Deselect(TagInfo *tag)
{
MFRC522::StatusCode result;
byte outBuffer[4];
byte outBufferSize = 1;
byte inBuffer[FIFO_SIZE];
byte inBufferSize = FIFO_SIZE;
outBuffer[0] = 0xC2;
if (tag->ats.tc1.supportsCID)
{
outBuffer[0] |= 0x08;
outBuffer[1] = 0x00; // CID is hardcoded
outBufferSize = 2;
}
result = PCD_TransceiveData(outBuffer, outBufferSize, inBuffer, &inBufferSize);
if (result != STATUS_OK) {
return result;
}
// TODO:Maybe do some checks? In my test it returns: CA 00 (Same data as I sent to my card)
return result;
} // End TCL_Deselect()
/////////////////////////////////////////////////////////////////////////////////////
// Functions for communicating with MIFARE PICCs
/////////////////////////////////////////////////////////////////////////////////////
@@ -1963,36 +1258,6 @@ const __FlashStringHelper *MFRC522::GetStatusCodeName(MFRC522::StatusCode code /
}
} // End GetStatusCodeName()
/**
* Get the PICC type.
*
* @return PICC_Type
*/
MFRC522::PICC_Type MFRC522::PICC_GetType(TagInfo *tag ///< The TagInfo returned from PICC_Select().
) {
// http://www.nxp.com/documents/application_note/AN10833.pdf
// 3.2 Coding of Select Acknowledge (SAK)
// ignore 8-bit (iso14443 starts with LSBit = bit 1)
// fixes wrong type for manufacturer Infineon (http://nfc-tools.org/index.php?title=ISO14443A)
byte sak = tag->uid.sak & 0x7F;
switch (sak) {
case 0x04: return PICC_TYPE_NOT_COMPLETE; // UID not complete
case 0x09: return PICC_TYPE_MIFARE_MINI;
case 0x08: return PICC_TYPE_MIFARE_1K;
case 0x18: return PICC_TYPE_MIFARE_4K;
case 0x00: return PICC_TYPE_MIFARE_UL;
case 0x10:
case 0x11: return PICC_TYPE_MIFARE_PLUS;
case 0x01: return PICC_TYPE_TNP3XXX;
case 0x20:
if (tag->atqa == 0x0344)
return PICC_TYPE_MIFARE_DESFIRE;
return PICC_TYPE_ISO_14443_4;
case 0x40: return PICC_TYPE_ISO_18092;
default: return PICC_TYPE_UNKNOWN;
}
} // End PICC_GetType()
/**
* Translates the SAK (Select Acknowledge) to a PICC type.
*
@@ -2065,56 +1330,6 @@ void MFRC522::PCD_DumpVersionToSerial() {
Serial.println(F("WARNING: Communication failure, is the MFRC522 properly connected?"));
} // End PCD_DumpVersionToSerial()
/**
* Dumps debug info about the selected PICC to Serial.
* On success the PICC is halted after dumping the data.
* For MIFARE Classic the factory default key of 0xFFFFFFFFFFFF is tried.
*/
void MFRC522::PICC_DumpToSerial(TagInfo *tag)
{
MIFARE_Key key;
// Dump UID, SAK and Type
PICC_DumpDetailsToSerial(tag);
// Dump contents
PICC_Type piccType = PICC_GetType(tag->uid.sak);
switch (piccType) {
case PICC_TYPE_MIFARE_MINI:
case PICC_TYPE_MIFARE_1K:
case PICC_TYPE_MIFARE_4K:
// All keys are set to FFFFFFFFFFFFh at chip delivery from the factory.
for (byte i = 0; i < 6; i++) {
key.keyByte[i] = 0xFF;
}
PICC_DumpMifareClassicToSerial(&tag->uid, piccType, &key);
break;
case PICC_TYPE_MIFARE_UL:
PICC_DumpMifareUltralightToSerial();
break;
case PICC_TYPE_ISO_14443_4:
case PICC_TYPE_MIFARE_DESFIRE:
PICC_DumpISO14443_4(tag);
Serial.println(F("Dumping memory contents not implemented for that PICC type."));
break;
case PICC_TYPE_ISO_18092:
case PICC_TYPE_MIFARE_PLUS:
case PICC_TYPE_TNP3XXX:
Serial.println(F("Dumping memory contents not implemented for that PICC type."));
break;
case PICC_TYPE_UNKNOWN:
case PICC_TYPE_NOT_COMPLETE:
default:
break; // No memory dump here
}
Serial.println();
PICC_HaltA(); // Already done if it was a MIFARE Classic PICC.
}
/**
* Dumps debug info about the selected PICC to Serial.
* On success the PICC is halted after dumping the data.
@@ -2164,45 +1379,6 @@ void MFRC522::PICC_DumpToSerial(Uid *uid ///< Pointer to Uid struct returned fro
PICC_HaltA(); // Already done if it was a MIFARE Classic PICC.
} // End PICC_DumpToSerial()
/**
* Dumps card info (UID,SAK,Type) about the selected PICC to Serial.
*/
void MFRC522::PICC_DumpDetailsToSerial(TagInfo *tag ///< Pointer to TagInfo struct returned from a successful PICC_Select().
) {
// ATQA
Serial.print(F("Card ATQA:"));
if (((tag->atqa & 0xFF00u) >> 8) < 0x10)
Serial.print(F(" 0"));
Serial.print((tag->atqa & 0xFF00u) >> 8, HEX);
if ((tag->atqa & 0x00FFu) < 0x10)
Serial.print(F("0"));
else
Serial.print(F(" "));
Serial.println(tag->atqa & 0x00FFu, HEX);
// UID
Serial.print(F("Card UID:"));
for (byte i = 0; i < tag->uid.size; i++) {
if (tag->uid.uidByte[i] < 0x10)
Serial.print(F(" 0"));
else
Serial.print(F(" "));
Serial.print(tag->uid.uidByte[i], HEX);
}
Serial.println();
// SAK
Serial.print(F("Card SAK: "));
if (tag->uid.sak < 0x10)
Serial.print(F("0"));
Serial.println(tag->uid.sak, HEX);
// (suggested) PICC type
PICC_Type piccType = PICC_GetType(tag);
Serial.print(F("PICC type: "));
Serial.println(PICC_GetTypeName(piccType));
} // End PICC_DumpDetailsToSerial()
/**
* Dumps card info (UID,SAK,Type) about the selected PICC to Serial.
*
@@ -2465,26 +1641,6 @@ void MFRC522::PICC_DumpMifareUltralightToSerial() {
}
} // End PICC_DumpMifareUltralightToSerial()
/**
* Dumps memory contents of a ISO-14443-4 PICC.
*/
void MFRC522::PICC_DumpISO14443_4(TagInfo *tag)
{
// ATS
if (tag->ats.size > 0x00) { // The first byte is the ATS length including the length byte
Serial.print(F("Card ATS:"));
for (byte offset = 0; offset < tag->ats.size; offset++) {
if (tag->ats.data[offset] < 0x10)
Serial.print(F(" 0"));
else
Serial.print(F(" "));
Serial.print(tag->ats.data[offset], HEX);
}
Serial.println();
}
} // End PICC_DumpISO14443_4
/**
* Calculates the bit pattern needed for the specified access bits. In the [C1 C2 C3] tuples C1 is MSB (=4) and C3 is LSB (=1).
*/
@@ -2725,34 +1881,7 @@ bool MFRC522::PICC_IsNewCardPresent() {
PCD_WriteRegister(ModWidthReg, 0x26);
MFRC522::StatusCode result = PICC_RequestA(bufferATQA, &bufferSize);
if (result == STATUS_OK || result == STATUS_COLLISION) {
tag.atqa = ((uint16_t)bufferATQA[1] << 8) | bufferATQA[0];
tag.ats.size = 0;
tag.ats.fsc = 32; // default FSC value
// Defaults for TA1
tag.ats.ta1.transmitted = false;
tag.ats.ta1.sameD = false;
tag.ats.ta1.ds = BITRATE_106KBITS;
tag.ats.ta1.dr = BITRATE_106KBITS;
// Defaults for TB1
tag.ats.tb1.transmitted = false;
tag.ats.tb1.fwi = 0; // TODO: Don't know the default for this!
tag.ats.tb1.sfgi = 0; // The default value of SFGI is 0 (meaning that the card does not need any particular SFGT)
// Defaults for TC1
tag.ats.tc1.transmitted = false;
tag.ats.tc1.supportsCID = true;
tag.ats.tc1.supportsNAD = false;
memset(tag.ats.data, 0, FIFO_SIZE - 2);
tag.blockNumber = false;
return true;
}
return false;
return (result == STATUS_OK || result == STATUS_COLLISION);
} // End PICC_IsNewCardPresent()
/**
@@ -2764,15 +1893,6 @@ bool MFRC522::PICC_IsNewCardPresent() {
* @return bool
*/
bool MFRC522::PICC_ReadCardSerial() {
MFRC522::StatusCode result = PICC_Select(&tag.uid);
// Backward compatibility
uid.size = tag.uid.size;
uid.sak = tag.uid.sak;
memcpy(uid.uidByte, tag.uid.uidByte, sizeof(tag.uid.uidByte));
if (result != STATUS_OK)
return false;
return true;
MFRC522::StatusCode result = PICC_Select(&uid);
return (result == STATUS_OK);
} // End

View File

@@ -77,6 +77,7 @@
#include <Arduino.h>
#include <SPI.h>
#include <stdint.h>
#define MFRC522_SPICLOCK SPI_CLOCK_DIV4 // MFRC522 accept upto 10MHz
@@ -306,14 +307,6 @@ public:
STATUS_CRC_WRONG , // The CRC_A does not match
STATUS_MIFARE_NACK = 0xff // A MIFARE PICC responded with NAK.
};
// ISO/IEC 14443-4 bit rates
enum TagBitRates : byte {
BITRATE_106KBITS = 0x00,
BITRATE_212KBITS = 0x01,
BITRATE_424KBITS = 0x02,
BITRATE_848KBITS = 0x03
};
// A struct used for passing the UID of a PICC.
typedef struct {
@@ -322,65 +315,13 @@ public:
byte sak; // The SAK (Select acknowledge) byte returned from the PICC after successful selection.
} Uid;
// Structure to store ISO/IEC 14443-4 ATS
typedef struct {
byte size;
byte fsc; // Frame size for proximity card
struct {
bool transmitted;
bool sameD; // Only the same D for both directions supported
TagBitRates ds; // Send D
TagBitRates dr; // Receive D
} ta1;
struct {
bool transmitted;
byte fwi; // Frame waiting time integer
byte sfgi; // Start-up frame guard time integer
} tb1;
struct {
bool transmitted;
bool supportsCID;
bool supportsNAD;
} tc1;
// Raw data from ATS
byte data[FIFO_SIZE - 2]; // ATS cannot be bigger than FSD - 2 bytes (CRC), according to ISO 14443-4 5.2.2
} Ats;
// A struct used for passing the PICC information
typedef struct {
uint16_t atqa;
Uid uid;
Ats ats;
// For Block PCB
bool blockNumber;
} TagInfo;
// A struct used for passing a MIFARE Crypto1 key
typedef struct {
byte keyByte[MF_KEY_SIZE];
} MIFARE_Key;
// A struct used for passing PCB Block
typedef struct {
struct {
byte pcb;
byte cid;
byte nad;
} prologue;
struct {
byte size;
byte *data;
} inf;
} PcbBlock;
// Member variables
Uid uid; // Used by PICC_ReadCardSerial().
TagInfo tag;
/////////////////////////////////////////////////////////////////////////////////////
// Functions for setting up the Arduino
@@ -422,19 +363,8 @@ public:
StatusCode PICC_RequestA(byte *bufferATQA, byte *bufferSize);
StatusCode PICC_WakeupA(byte *bufferATQA, byte *bufferSize);
StatusCode PICC_REQA_or_WUPA(byte command, byte *bufferATQA, byte *bufferSize);
StatusCode PICC_Select(Uid *uid, byte validBits = 0);
virtual StatusCode PICC_Select(Uid *uid, byte validBits = 0);
StatusCode PICC_HaltA();
StatusCode PICC_RequestATS(Ats *ats);
StatusCode PICC_PPS(); // PPS command without bitrate parameter
StatusCode PICC_PPS(TagBitRates sendBitRate, TagBitRates receiveBitRate); // Different D values
/////////////////////////////////////////////////////////////////////////////////////
// Functions for communicating with ISO/IEC 14433-4 cards
/////////////////////////////////////////////////////////////////////////////////////
StatusCode TCL_Transceive(PcbBlock *send, PcbBlock *back);
StatusCode TCL_Transceive(TagInfo * tag, byte *sendData, byte sendLen, byte *backData = NULL, byte *backLen = NULL);
StatusCode TCL_TransceiveRBlock(TagInfo *tag, bool ack, byte *backData = NULL, byte *backLen = NULL);
StatusCode TCL_Deselect(TagInfo *tag);
/////////////////////////////////////////////////////////////////////////////////////
// Functions for communicating with MIFARE PICCs
@@ -460,21 +390,17 @@ public:
//const char *GetStatusCodeName(byte code);
static const __FlashStringHelper *GetStatusCodeName(StatusCode code);
static PICC_Type PICC_GetType(byte sak);
static PICC_Type PICC_GetType(TagInfo *tag);
// old function used too much memory, now name moved to flash; if you need char, copy from flash to memory
//const char *PICC_GetTypeName(byte type);
static const __FlashStringHelper *PICC_GetTypeName(PICC_Type type);
// Support functions for debuging
void PCD_DumpVersionToSerial();
void PICC_DumpToSerial(TagInfo *tag);
void PICC_DumpToSerial(Uid *uid);
void PICC_DumpDetailsToSerial(TagInfo *tag);
void PICC_DumpDetailsToSerial(Uid *uid);
void PICC_DumpMifareClassicToSerial(Uid *uid, PICC_Type piccType, MIFARE_Key *key);
void PICC_DumpMifareClassicSectorToSerial(Uid *uid, MIFARE_Key *key, byte sector);
void PICC_DumpMifareUltralightToSerial();
void PICC_DumpISO14443_4(TagInfo *tag);
// Advanced functions for MIFARE
void MIFARE_SetAccessBits(byte *accessBitBuffer, byte g0, byte g1, byte g2, byte g3);
@@ -485,10 +411,10 @@ public:
/////////////////////////////////////////////////////////////////////////////////////
// Convenience functions - does not add extra functionality
/////////////////////////////////////////////////////////////////////////////////////
bool PICC_IsNewCardPresent();
bool PICC_ReadCardSerial();
virtual bool PICC_IsNewCardPresent();
virtual bool PICC_ReadCardSerial();
private:
protected:
byte _chipSelectPin; // Arduino pin connected to MFRC522's SPI slave select input (Pin 24, NSS, active low)
byte _resetPowerDownPin; // Arduino pin connected to MFRC522's reset and power down input (Pin 6, NRSTPD, active low)
StatusCode MIFARE_TwoStepHelper(byte command, byte blockAddr, int32_t data);

1161
MFRC522Extended.cpp Normal file

File diff suppressed because it is too large Load Diff

110
MFRC522Extended.h Normal file
View File

@@ -0,0 +1,110 @@
/**
* Library extends MFRC522.h to support RATS for ISO-14443-4 PICC.
* RATS - Request for Answer To Select.
* @author JPG-Consulting
*/
#ifndef MFRC522Extended_h
#define MFRC522Extended_h
#include <Arduino.h>
#include "MFRC522.h"
class MFRC522Extended : public MFRC522 {
public:
// ISO/IEC 14443-4 bit rates
enum TagBitRates : byte {
BITRATE_106KBITS = 0x00,
BITRATE_212KBITS = 0x01,
BITRATE_424KBITS = 0x02,
BITRATE_848KBITS = 0x03
};
// Structure to store ISO/IEC 14443-4 ATS
typedef struct {
byte size;
byte fsc; // Frame size for proximity card
struct {
bool transmitted;
bool sameD; // Only the same D for both directions supported
TagBitRates ds; // Send D
TagBitRates dr; // Receive D
} ta1;
struct {
bool transmitted;
byte fwi; // Frame waiting time integer
byte sfgi; // Start-up frame guard time integer
} tb1;
struct {
bool transmitted;
bool supportsCID;
bool supportsNAD;
} tc1;
// Raw data from ATS
byte data[FIFO_SIZE - 2]; // ATS cannot be bigger than FSD - 2 bytes (CRC), according to ISO 14443-4 5.2.2
} Ats;
// A struct used for passing the PICC information
typedef struct {
uint16_t atqa;
Uid uid;
Ats ats;
// For Block PCB
bool blockNumber;
} TagInfo;
// A struct used for passing PCB Block
typedef struct {
struct {
byte pcb;
byte cid;
byte nad;
} prologue;
struct {
byte size;
byte *data;
} inf;
} PcbBlock;
// Member variables
TagInfo tag;
/////////////////////////////////////////////////////////////////////////////////////
// Functions for communicating with PICCs
/////////////////////////////////////////////////////////////////////////////////////
StatusCode PICC_Select(Uid *uid, byte validBits = 0); // overwrite
StatusCode PICC_RequestATS(Ats *ats);
StatusCode PICC_PPS(); // PPS command without bitrate parameter
StatusCode PICC_PPS(TagBitRates sendBitRate, TagBitRates receiveBitRate); // Different D values
/////////////////////////////////////////////////////////////////////////////////////
// Functions for communicating with ISO/IEC 14433-4 cards
/////////////////////////////////////////////////////////////////////////////////////
StatusCode TCL_Transceive(PcbBlock *send, PcbBlock *back);
StatusCode TCL_Transceive(TagInfo * tag, byte *sendData, byte sendLen, byte *backData = NULL, byte *backLen = NULL);
StatusCode TCL_TransceiveRBlock(TagInfo *tag, bool ack, byte *backData = NULL, byte *backLen = NULL);
StatusCode TCL_Deselect(TagInfo *tag);
/////////////////////////////////////////////////////////////////////////////////////
// Support functions
/////////////////////////////////////////////////////////////////////////////////////
static PICC_Type PICC_GetType(TagInfo *tag);
// Support functions for debuging
void PICC_DumpToSerial(TagInfo *tag);
void PICC_DumpDetailsToSerial(TagInfo *tag);
void PICC_DumpISO14443_4(TagInfo *tag);
/////////////////////////////////////////////////////////////////////////////////////
// Convenience functions - does not add extra functionality
/////////////////////////////////////////////////////////////////////////////////////
bool PICC_IsNewCardPresent(); // overwrite
bool PICC_ReadCardSerial(); // overwrite
};
#endif