MIFARE specific functions renamed.

Write for MIFARE Ultralight implemented.
Cleanup.
This commit is contained in:
Søren Thing Andersen
2013-10-20 16:19:49 +02:00
parent cc1294aa79
commit a3bd6ff2e5
2 changed files with 131 additions and 118 deletions

View File

@@ -1,6 +1,6 @@
/* /*
* MFRC522.cpp - Library to use ARDUINO RFID MODULE KIT 13.56 MHZ WITH TAGS SPI W AND R BY COOQROBOT. * MFRC522.cpp - Library to use ARDUINO RFID MODULE KIT 13.56 MHZ WITH TAGS SPI W AND R BY COOQROBOT.
* Please see comments in MFRC522.h * _Please_ see the comments in MFRC522.h - they give useful hints and background.
* Released into the public domain. * Released into the public domain.
*/ */
@@ -16,7 +16,7 @@
* Prepares the output pins. * Prepares the output pins.
*/ */
MFRC522::MFRC522( byte chipSelectPin, ///< Arduino pin connected to MFRC522's SPI slave select input (Pin 24, NSS, active low) MFRC522::MFRC522( 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) byte resetPowerDownPin ///< Arduino pin connected to MFRC522's reset and power down input (Pin 6, NRSTPD, active low)
) { ) {
// Set the chipSelectPin as digital output, do not select the slave yet // Set the chipSelectPin as digital output, do not select the slave yet
_chipSelectPin = chipSelectPin; _chipSelectPin = chipSelectPin;
@@ -93,9 +93,9 @@ byte MFRC522::PCD_ReadRegister( byte reg ///< The register to read from. One of
* The interface is described in the datasheet section 8.1.2. * The interface is described in the datasheet section 8.1.2.
*/ */
void MFRC522::PCD_ReadRegister( byte reg, ///< The register to read from. One of the PCD_Register enums. void MFRC522::PCD_ReadRegister( byte reg, ///< The register to read from. One of the PCD_Register enums.
byte count, ///< The number of bytes to read byte count, ///< The number of bytes to read
byte *values, ///< Byte array to store the values in. byte *values, ///< Byte array to store the values in.
byte rxAlign ///< Only bit positions rxAlign..7 in values[0] are updated. byte rxAlign ///< Only bit positions rxAlign..7 in values[0] are updated.
) { ) {
if (count == 0) { if (count == 0) {
return; return;
@@ -104,8 +104,8 @@ void MFRC522::PCD_ReadRegister( byte reg, ///< The register to read from. One o
byte address = 0x80 | (reg & 0x7E); // MSB == 1 is for reading. LSB is not used in address. Datasheet section 8.1.2.3. byte address = 0x80 | (reg & 0x7E); // MSB == 1 is for reading. LSB is not used in address. Datasheet section 8.1.2.3.
byte index = 0; // Index in values array. byte index = 0; // Index in values array.
digitalWrite(_chipSelectPin, LOW); // Select slave digitalWrite(_chipSelectPin, LOW); // Select slave
count--; // One read is performed outside of the loop count--; // One read is performed outside of the loop
SPI.transfer(address); // Tell MFRC522 which address we want to read SPI.transfer(address); // Tell MFRC522 which address we want to read
while (index < count) { while (index < count) {
if (index == 0 && rxAlign) { // Only update bit positions rxAlign..7 in values[0] if (index == 0 && rxAlign) { // Only update bit positions rxAlign..7 in values[0]
// Create bit mask for bit positions rxAlign..7 // Create bit mask for bit positions rxAlign..7
@@ -141,7 +141,7 @@ void MFRC522::PCD_SetRegisterBitMask( byte reg, ///< The register to update. One
/** /**
* Clears the bits given in mask from register reg. * Clears the bits given in mask from register reg.
*/ */
void MFRC522::PCD_ClearRegisterBitMask(byte reg, ///< The register to update. One of the PCD_Register enums. void MFRC522::PCD_ClearRegisterBitMask( byte reg, ///< The register to update. One of the PCD_Register enums.
byte mask ///< The bits to clear. byte mask ///< The bits to clear.
) { ) {
byte tmp; byte tmp;
@@ -229,7 +229,7 @@ void MFRC522::PCD_Reset() {
while (PCD_ReadRegister(CommandReg) & (1<<4)) { while (PCD_ReadRegister(CommandReg) & (1<<4)) {
// PCD still restarting - unlikely after waiting 50ms, but better safe than sorry. // PCD still restarting - unlikely after waiting 50ms, but better safe than sorry.
} }
} } // End PCD_Reset()
/** /**
* Turns the antenna on by enabling pins TX1 and TX2. * Turns the antenna on by enabling pins TX1 and TX2.
@@ -361,7 +361,7 @@ byte MFRC522::PCD_CommunicateWithPICC( byte command, ///< The command to execut
} }
return STATUS_OK; return STATUS_OK;
} // End PCD_CommunicateWithPICC } // End PCD_CommunicateWithPICC()
/** /**
* Transmits a REQuest command, Type A. Invites PICCs in state IDLE to go to READY and prepare for anticollision or selection. 7 bit frame. * Transmits a REQuest command, Type A. Invites PICCs in state IDLE to go to READY and prepare for anticollision or selection. 7 bit frame.
@@ -373,7 +373,7 @@ byte MFRC522::PICC_RequestA(byte *bufferATQA, ///< The buffer to store the ATQA
byte *bufferSize ///< Buffer size, at least two bytes. Also number of bytes returned if STATUS_OK. byte *bufferSize ///< Buffer size, at least two bytes. Also number of bytes returned if STATUS_OK.
) { ) {
return PICC_REQA_or_WUPA(PICC_CMD_REQA, bufferATQA, bufferSize); return PICC_REQA_or_WUPA(PICC_CMD_REQA, bufferATQA, bufferSize);
} } // End PICC_RequestA()
/** /**
* Transmits a Wake-UP command, Type A. Invites PICCs in state IDLE and HALT to go to READY(*) and prepare for anticollision or selection. 7 bit frame. * Transmits a Wake-UP command, Type A. Invites PICCs in state IDLE and HALT to go to READY(*) and prepare for anticollision or selection. 7 bit frame.
@@ -385,7 +385,7 @@ byte MFRC522::PICC_WakeupA( byte *bufferATQA, ///< The buffer to store the ATQA
byte *bufferSize ///< Buffer size, at least two bytes. Also number of bytes returned if STATUS_OK. byte *bufferSize ///< Buffer size, at least two bytes. Also number of bytes returned if STATUS_OK.
) { ) {
return PICC_REQA_or_WUPA(PICC_CMD_WUPA, bufferATQA, bufferSize); return PICC_REQA_or_WUPA(PICC_CMD_WUPA, bufferATQA, bufferSize);
} } // End PICC_WakeupA()
/** /**
* Transmits REQA or WUPA commands. * Transmits REQA or WUPA commands.
@@ -443,8 +443,8 @@ byte MFRC522::PICC_Select( Uid *uid, ///< Pointer to Uid struct. Normally outp
byte count; byte count;
byte index; byte index;
byte uidIndex; // The first index in uid->uidByte[] that is used in the current Cascade Level. byte uidIndex; // The first index in uid->uidByte[] that is used in the current Cascade Level.
char currentLevelKnownBits; // The number of known UID bits in the current Cascade Level. char currentLevelKnownBits; // The number of known UID bits in the current Cascade Level.
byte buffer[9]; // The SELECT/ANTICOLLISION commands uses a 7 byte standard frame + 2 bytes CRC_A byte buffer[9]; // The SELECT/ANTICOLLISION commands uses a 7 byte standard frame + 2 bytes CRC_A
byte bufferUsed; // The number of bytes used in the buffer, ie the number of bytes to transfer to the FIFO. byte bufferUsed; // The number of bytes used in the buffer, ie the number of bytes to transfer to the FIFO.
byte rxAlign; // Used in BitFramingReg. Defines the bit position for the first bit received. byte rxAlign; // Used in BitFramingReg. Defines the bit position for the first bit received.
byte txLastBits; // Used in BitFramingReg. The number of valid bits in the last transmitted byte. byte txLastBits; // Used in BitFramingReg. The number of valid bits in the last transmitted byte.
@@ -501,7 +501,7 @@ byte MFRC522::PICC_Select( Uid *uid, ///< Pointer to Uid struct. Normally outp
case 3: case 3:
buffer[0] = PICC_CMD_SEL_CL3; buffer[0] = PICC_CMD_SEL_CL3;
uidIndex = 6; uidIndex = 6;
useCascadeTag = false; // Never used in CL3. useCascadeTag = false; // Never used in CL3.
break; break;
default: default:
@@ -567,7 +567,7 @@ byte MFRC522::PICC_Select( Uid *uid, ///< Pointer to Uid struct. Normally outp
} }
// Set bit adjustments // Set bit adjustments
rxAlign = txLastBits; // Having a seperate variable is overkill. But it makes the next line easier to read. rxAlign = txLastBits; // Having a seperate variable is overkill. But it makes the next line easier to read.
PCD_WriteRegister(BitFramingReg, (rxAlign << 4) + txLastBits); // RxAlign = BitFramingReg[6..4]. TxLastBits = BitFramingReg[2..0] PCD_WriteRegister(BitFramingReg, (rxAlign << 4) + txLastBits); // RxAlign = BitFramingReg[6..4]. TxLastBits = BitFramingReg[2..0]
// Transmit the buffer and receive the response. // Transmit the buffer and receive the response.
@@ -581,7 +581,6 @@ byte MFRC522::PICC_Select( Uid *uid, ///< Pointer to Uid struct. Normally outp
if (collisionPos == 0) { if (collisionPos == 0) {
collisionPos = 32; collisionPos = 32;
} }
//Serial.print("Collision in bit "); Serial.println(collisionPos);
if (collisionPos <= currentLevelKnownBits) { // No progress - should not happen if (collisionPos <= currentLevelKnownBits) { // No progress - should not happen
return STATUS_INTERNAL_ERROR; return STATUS_INTERNAL_ERROR;
} }
@@ -605,7 +604,7 @@ byte MFRC522::PICC_Select( Uid *uid, ///< Pointer to Uid struct. Normally outp
// Run loop again to do the SELECT. // Run loop again to do the SELECT.
} }
} }
} //End of while ( ! selectDone) } // End of while ( ! selectDone)
// We do not check the CBB - it was constructed by us above. // We do not check the CBB - it was constructed by us above.
@@ -681,7 +680,6 @@ byte MFRC522::PICC_HaltA() {
// Functions for communicating with MIFARE PICCs // Functions for communicating with MIFARE PICCs
///////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////
/** /**
* Executes the MFRC522 MFAuthent command. * Executes the MFRC522 MFAuthent command.
* This command manages MIFARE authentication to enable a secure communication to any MIFARE Mini, MIFARE 1K and MIFARE 4K card. * This command manages MIFARE authentication to enable a secure communication to any MIFARE Mini, MIFARE 1K and MIFARE 4K card.
@@ -694,7 +692,7 @@ byte MFRC522::PICC_HaltA() {
* *
* @return STATUS_OK on success, STATUS_??? otherwise. Probably STATUS_TIMEOUT if you supply the wrong key. * @return STATUS_OK on success, STATUS_??? otherwise. Probably STATUS_TIMEOUT if you supply the wrong key.
*/ */
byte MFRC522::PCD_Authenticate(byte command, ///< PICC_CMD_AUTH_KEY_A or PICC_CMD_AUTH_KEY_B byte MFRC522::PCD_Authenticate(byte command, ///< PICC_CMD_MF_AUTH_KEY_A or PICC_CMD_MF_AUTH_KEY_B
byte blockAddr, ///< The block number. See numbering in the comments in the .h file. byte blockAddr, ///< The block number. See numbering in the comments in the .h file.
MIFARE_Key *key, ///< Pointer to the Crypteo1 key to use (6 bytes) MIFARE_Key *key, ///< Pointer to the Crypteo1 key to use (6 bytes)
Uid *uid ///< Pointer to Uid struct. The first 4 bytes of the UID is used. Uid *uid ///< Pointer to Uid struct. The first 4 bytes of the UID is used.
@@ -741,7 +739,7 @@ void MFRC522::PCD_StopCrypto1() {
* *
* @return STATUS_OK on success, STATUS_??? otherwise. * @return STATUS_OK on success, STATUS_??? otherwise.
*/ */
byte MFRC522::PICC_Read( byte blockAddr, ///< MIFARE Classic: The block (0-0xff) number. MIFARE Ultralight: The first page to return data from. byte MFRC522::MIFARE_Read( byte blockAddr, ///< MIFARE Classic: The block (0-0xff) number. MIFARE Ultralight: The first page to return data from.
byte *buffer, ///< The buffer to store the data in byte *buffer, ///< The buffer to store the data in
byte *bufferSize ///< Buffer size, at least 18 bytes. Also number of bytes returned if STATUS_OK. byte *bufferSize ///< Buffer size, at least 18 bytes. Also number of bytes returned if STATUS_OK.
) { ) {
@@ -753,7 +751,7 @@ byte MFRC522::PICC_Read( byte blockAddr, ///< MIFARE Classic: The block (0-0xff
} }
// Build command buffer // Build command buffer
buffer[0] = PICC_CMD_READ; buffer[0] = PICC_CMD_MF_READ;
buffer[1] = blockAddr; buffer[1] = blockAddr;
// Calculate CRC_A // Calculate CRC_A
result = PCD_CalculateCRC(buffer, 2, &buffer[2]); result = PCD_CalculateCRC(buffer, 2, &buffer[2]);
@@ -763,7 +761,7 @@ byte MFRC522::PICC_Read( byte blockAddr, ///< MIFARE Classic: The block (0-0xff
// Transmit the buffer and receive the response, validate CRC_A. // Transmit the buffer and receive the response, validate CRC_A.
return PCD_TransceiveData(buffer, 4, buffer, bufferSize, NULL, 0, true); return PCD_TransceiveData(buffer, 4, buffer, bufferSize, NULL, 0, true);
} // End PICC_Read() } // End MIFARE_Read()
/** /**
* Writes 16 bytes to the active PICC. * Writes 16 bytes to the active PICC.
@@ -776,12 +774,11 @@ byte MFRC522::PICC_Read( byte blockAddr, ///< MIFARE Classic: The block (0-0xff
* * * *
* @return STATUS_OK on success, STATUS_??? otherwise. * @return STATUS_OK on success, STATUS_??? otherwise.
*/ */
byte MFRC522::PICC_Write( byte blockAddr, ///< MIFARE Classic: The block (0-0xff) number. MIFARE Ultralight: The page (2-15) to write to. byte MFRC522::MIFARE_Write( byte blockAddr, ///< MIFARE Classic: The block (0-0xff) number. MIFARE Ultralight: The page (2-15) to write to.
byte *buffer, ///< The 16 bytes to write to the PICC byte *buffer, ///< The 16 bytes to write to the PICC
byte bufferSize ///< Buffer size, must be at least 16 bytes. Exactly 16 bytes are written. byte bufferSize ///< Buffer size, must be at least 16 bytes. Exactly 16 bytes are written.
) { ) {
byte result; byte result;
byte cmdBuffer[18]; // We need room for the 16 bytes and CRC_A.
// Sanity check // Sanity check
if (buffer == NULL || bufferSize < 16) { if (buffer == NULL || bufferSize < 16) {
@@ -790,7 +787,8 @@ byte MFRC522::PICC_Write( byte blockAddr, ///< MIFARE Classic: The block (0-0xf
// Mifare Classic protocol requires two communications to perform a write. // Mifare Classic protocol requires two communications to perform a write.
// Step 1: Tell the PICC we want to write to block blockAddr. // Step 1: Tell the PICC we want to write to block blockAddr.
cmdBuffer[0] = PICC_CMD_WRITE; byte cmdBuffer[2];
cmdBuffer[0] = PICC_CMD_MF_WRITE;
cmdBuffer[1] = blockAddr; cmdBuffer[1] = blockAddr;
result = PCD_MIFARE_Transceive(cmdBuffer, 2); // Adds CRC_A and checks that the response is MF_ACK. result = PCD_MIFARE_Transceive(cmdBuffer, 2); // Adds CRC_A and checks that the response is MF_ACK.
if (result != STATUS_OK) { if (result != STATUS_OK) {
@@ -804,60 +802,90 @@ byte MFRC522::PICC_Write( byte blockAddr, ///< MIFARE Classic: The block (0-0xf
} }
return STATUS_OK; return STATUS_OK;
} // End PICC_Write() } // End MIFARE_Write()
/**
* Writes a 4 byte page to the active MIFARE Ultralight PICC.
*
* @return STATUS_OK on success, STATUS_??? otherwise.
*/
byte MFRC522::MIFARE_Ultralight_Write( byte page, ///< The page (2-15) to write to.
byte *buffer, ///< The 4 bytes to write to the PICC
byte bufferSize ///< Buffer size, must be at least 4 bytes. Exactly 4 bytes are written.
) {
byte result;
// Sanity check
if (buffer == NULL || bufferSize < 4) {
return STATUS_INVALID;
}
// Build commmand buffer
byte cmdBuffer[6];
cmdBuffer[0] = PICC_CMD_UL_WRITE;
cmdBuffer[1] = page;
memcpy(&cmdBuffer[2], buffer, 4);
// Perform the write
result = PCD_MIFARE_Transceive(cmdBuffer, 6); // Adds CRC_A and checks that the response is MF_ACK.
if (result != STATUS_OK) {
return result;
}
return STATUS_OK;
} // End MIFARE_Ultralight_Write()
/** /**
* MIFARE Decrement subtracts the delta from the value of the addressed block, and stores the result in a volatile memory. * MIFARE Decrement subtracts the delta from the value of the addressed block, and stores the result in a volatile memory.
* For MIFARE Classic only. The sector containing the block must be authenticated before calling this function. * For MIFARE Classic only. The sector containing the block must be authenticated before calling this function.
* Only for blocks in "value block" mode, ie with access bits [C1 C2 C3] = [110] or [001]. * Only for blocks in "value block" mode, ie with access bits [C1 C2 C3] = [110] or [001].
* Use PICC_Transfer() to store the result in a block. * Use MIFARE_Transfer() to store the result in a block.
* *
* @return STATUS_OK on success, STATUS_??? otherwise. * @return STATUS_OK on success, STATUS_??? otherwise.
*/ */
byte MFRC522::PICC_Decrement( byte blockAddr, ///< The block (0-0xff) number. byte MFRC522::MIFARE_Decrement( byte blockAddr, ///< The block (0-0xff) number.
long delta ///< This number is subtracted from the value of block blockAddr. long delta ///< This number is subtracted from the value of block blockAddr.
) { ) {
return PICC_TwoStepHelper(PICC_CMD_DECREMENT, blockAddr, delta); return MIFARE_TwoStepHelper(PICC_CMD_MF_DECREMENT, blockAddr, delta);
} // End PICC_Decrement() } // End MIFARE_Decrement()
/** /**
* MIFARE Increment adds the delta to the value of the addressed block, and stores the result in a volatile memory. * MIFARE Increment adds the delta to the value of the addressed block, and stores the result in a volatile memory.
* For MIFARE Classic only. The sector containing the block must be authenticated before calling this function. * For MIFARE Classic only. The sector containing the block must be authenticated before calling this function.
* Only for blocks in "value block" mode, ie with access bits [C1 C2 C3] = [110] or [001]. * Only for blocks in "value block" mode, ie with access bits [C1 C2 C3] = [110] or [001].
* Use PICC_Transfer() to store the result in a block. * Use MIFARE_Transfer() to store the result in a block.
* *
* @return STATUS_OK on success, STATUS_??? otherwise. * @return STATUS_OK on success, STATUS_??? otherwise.
*/ */
byte MFRC522::PICC_Increment( byte blockAddr, ///< The block (0-0xff) number. byte MFRC522::MIFARE_Increment( byte blockAddr, ///< The block (0-0xff) number.
long delta ///< This number is added to the value of block blockAddr. long delta ///< This number is added to the value of block blockAddr.
) { ) {
return PICC_TwoStepHelper(PICC_CMD_INCREMENT, blockAddr, delta); return MIFARE_TwoStepHelper(PICC_CMD_MF_INCREMENT, blockAddr, delta);
} // End PICC_Increment() } // End MIFARE_Increment()
/** /**
* MIFARE Restore copies the value of the addressed block into a volatile memory. * MIFARE Restore copies the value of the addressed block into a volatile memory.
* For MIFARE Classic only. The sector containing the block must be authenticated before calling this function. * For MIFARE Classic only. The sector containing the block must be authenticated before calling this function.
* Only for blocks in "value block" mode, ie with access bits [C1 C2 C3] = [110] or [001]. * Only for blocks in "value block" mode, ie with access bits [C1 C2 C3] = [110] or [001].
* Use PICC_Transfer() to store the result in a block. * Use MIFARE_Transfer() to store the result in a block.
* *
* @return STATUS_OK on success, STATUS_??? otherwise. * @return STATUS_OK on success, STATUS_??? otherwise.
*/ */
byte MFRC522::PICC_Restore( byte blockAddr ///< The block (0-0xff) number. byte MFRC522::MIFARE_Restore( byte blockAddr ///< The block (0-0xff) number.
) { ) {
// The datasheet describes Restore as a two step operation, but does not explain what data to transfer in step 2. // The datasheet describes Restore as a two step operation, but does not explain what data to transfer in step 2.
// Doing only a single step does not work, so I chose to transfer 0L in step two. // Doing only a single step does not work, so I chose to transfer 0L in step two.
return PICC_TwoStepHelper(PICC_CMD_RESTORE, blockAddr, 0L); return MIFARE_TwoStepHelper(PICC_CMD_MF_RESTORE, blockAddr, 0L);
} // End PICC_Restore() } // End MIFARE_Restore()
/** /**
* Helper function for the two-step MIFARE Classic protocol operations Decrement, Increment and Restore. * Helper function for the two-step MIFARE Classic protocol operations Decrement, Increment and Restore.
* *
* @return STATUS_OK on success, STATUS_??? otherwise. * @return STATUS_OK on success, STATUS_??? otherwise.
*/ */
byte MFRC522::PICC_TwoStepHelper( byte command, ///< The command to use byte MFRC522::MIFARE_TwoStepHelper( byte command, ///< The command to use
byte blockAddr, ///< The block (0-0xff) number. byte blockAddr, ///< The block (0-0xff) number.
long data ///< The data to transfer in step 2 long data ///< The data to transfer in step 2
) { ) {
byte result; byte result;
byte cmdBuffer[2]; // We only need room for 2 bytes. byte cmdBuffer[2]; // We only need room for 2 bytes.
@@ -876,7 +904,7 @@ byte MFRC522::PICC_TwoStepHelper( byte command, ///< The command to use
} }
return STATUS_OK; return STATUS_OK;
} // End PICC_TwoStepHelper() } // End MIFARE_TwoStepHelper()
/** /**
* MIFARE Transfer writes the value stored in the volatile memory into one MIFARE Classic block. * MIFARE Transfer writes the value stored in the volatile memory into one MIFARE Classic block.
@@ -885,20 +913,20 @@ byte MFRC522::PICC_TwoStepHelper( byte command, ///< The command to use
* *
* @return STATUS_OK on success, STATUS_??? otherwise. * @return STATUS_OK on success, STATUS_??? otherwise.
*/ */
byte MFRC522::PICC_Transfer( byte blockAddr ///< The block (0-0xff) number. byte MFRC522::MIFARE_Transfer( byte blockAddr ///< The block (0-0xff) number.
) { ) {
byte result; byte result;
byte cmdBuffer[2]; // We only need room for 2 bytes. byte cmdBuffer[2]; // We only need room for 2 bytes.
// Tell the PICC we want to transfer the result into block blockAddr. // Tell the PICC we want to transfer the result into block blockAddr.
cmdBuffer[0] = PICC_CMD_TRANSFER; cmdBuffer[0] = PICC_CMD_MF_TRANSFER;
cmdBuffer[1] = blockAddr; cmdBuffer[1] = blockAddr;
result = PCD_MIFARE_Transceive( cmdBuffer, 2); // Adds CRC_A and checks that the response is MF_ACK. result = PCD_MIFARE_Transceive( cmdBuffer, 2); // Adds CRC_A and checks that the response is MF_ACK.
if (result != STATUS_OK) { if (result != STATUS_OK) {
return result; return result;
} }
return STATUS_OK; return STATUS_OK;
} // End PICC_Transfer() } // End MIFARE_Transfer()
///////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////
@@ -986,33 +1014,14 @@ byte MFRC522::PICC_GetType(byte sak ///< The SAK byte returned from PICC_Select
} }
switch (sak) { switch (sak) {
case 0x09: case 0x09: return PICC_TYPE_MIFARE_MINI; break;
return PICC_TYPE_MIFARE_MINI; case 0x08: return PICC_TYPE_MIFARE_1K; break;
break; case 0x18: return PICC_TYPE_MIFARE_4K; break;
case 0x00: return PICC_TYPE_MIFARE_UL; break;
case 0x08:
return PICC_TYPE_MIFARE_1K;
break;
case 0x18:
return PICC_TYPE_MIFARE_4K;
break;
case 0x00:
return PICC_TYPE_MIFARE_UL;
break;
case 0x10: case 0x10:
case 0x11: case 0x11: return PICC_TYPE_MIFARE_PLUS; break;
return PICC_TYPE_MIFARE_PLUS; case 0x01: return PICC_TYPE_TNP3XXX; break;
break; default: break;
case 0x01:
return PICC_TYPE_TNP3XXX;
break;
default:
break;
} }
if (sak & 0x20) { if (sak & 0x20) {
@@ -1033,27 +1042,26 @@ byte MFRC522::PICC_GetType(byte sak ///< The SAK byte returned from PICC_Select
const char *MFRC522::PICC_GetTypeName(byte piccType ///< One of the PICC_Type enums. const char *MFRC522::PICC_GetTypeName(byte piccType ///< One of the PICC_Type enums.
) { ) {
switch (piccType) { switch (piccType) {
case PICC_TYPE_ISO_14443_4: return "PICC compliant with ISO/IEC 14443-4"; break; case PICC_TYPE_ISO_14443_4: return "PICC compliant with ISO/IEC 14443-4"; break;
case PICC_TYPE_ISO_18092: return "PICC compliant with ISO/IEC 18092 (NFC)"; break; case PICC_TYPE_ISO_18092: return "PICC compliant with ISO/IEC 18092 (NFC)"; break;
case PICC_TYPE_MIFARE_MINI: return "MIFARE Mini, 320 bytes"; break; case PICC_TYPE_MIFARE_MINI: return "MIFARE Mini, 320 bytes"; break;
case PICC_TYPE_MIFARE_1K: return "MIFARE 1KB"; break; case PICC_TYPE_MIFARE_1K: return "MIFARE 1KB"; break;
case PICC_TYPE_MIFARE_4K: return "MIFARE 4KB"; break; case PICC_TYPE_MIFARE_4K: return "MIFARE 4KB"; break;
case PICC_TYPE_MIFARE_UL: return "MIFARE Ultralight or Ultralight C"; break; case PICC_TYPE_MIFARE_UL: return "MIFARE Ultralight or Ultralight C"; break;
case PICC_TYPE_MIFARE_PLUS: return "MIFARE Plus"; break; case PICC_TYPE_MIFARE_PLUS: return "MIFARE Plus"; break;
case PICC_TYPE_TNP3XXX: return "MIFARE TNP3XXX"; break; case PICC_TYPE_TNP3XXX: return "MIFARE TNP3XXX"; break;
case PICC_TYPE_NOT_COMPLETE: return "SAK indicates UID is not complete."; break; case PICC_TYPE_NOT_COMPLETE: return "SAK indicates UID is not complete."; break;
case PICC_TYPE_UNKNOWN: case PICC_TYPE_UNKNOWN:
default: default: return "Unknown type"; break;
return "Unknown type";
break;
} }
} // End PICC_GetTypeName() } // End PICC_GetTypeName()
/** /**
* Dumps debug info about the selected PICC to Serial. * Dumps debug info about the selected PICC to Serial.
* On success the PICC is halted after dumping the data. * 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(Uid *uid ///< Pointer to Uid struct returned from a successful PICC_Select(). void MFRC522::PICC_DumpToSerial(Uid *uid ///< Pointer to Uid struct returned from a successful PICC_Select().
) { ) {
MIFARE_Key key; MIFARE_Key key;
@@ -1145,8 +1153,8 @@ void MFRC522::PICC_DumpMifareClassicToSerial( Uid *uid, ///< Pointer to Uid str
/** /**
* Dumps memory contents of a sector of a MIFARE Classic PICC. * Dumps memory contents of a sector of a MIFARE Classic PICC.
* Uses PCD_Authenticate(), PICC_Read() and PCD_StopCrypto1. * Uses PCD_Authenticate(), MIFARE_Read() and PCD_StopCrypto1.
* Always uses PICC_CMD_AUTH_KEY_A because only Key A can always read the sector trailer access bits. * Always uses PICC_CMD_MF_AUTH_KEY_A because only Key A can always read the sector trailer access bits.
*/ */
void MFRC522::PICC_DumpMifareClassicSectorToSerial(Uid *uid, ///< Pointer to Uid struct returned from a successful PICC_Select(). void MFRC522::PICC_DumpMifareClassicSectorToSerial(Uid *uid, ///< Pointer to Uid struct returned from a successful PICC_Select().
MIFARE_Key *key, ///< Key A for the sector. MIFARE_Key *key, ///< Key A for the sector.
@@ -1207,7 +1215,7 @@ void MFRC522::PICC_DumpMifareClassicSectorToSerial(Uid *uid, ///< Pointer to U
Serial.print(" "); Serial.print(" ");
// Establish encrypted communications before reading the first block // Establish encrypted communications before reading the first block
if (isSectorTrailer) { if (isSectorTrailer) {
status = PCD_Authenticate(PICC_CMD_AUTH_KEY_A, firstBlock, key, uid); status = PCD_Authenticate(PICC_CMD_MF_AUTH_KEY_A, firstBlock, key, uid);
if (status != STATUS_OK) { if (status != STATUS_OK) {
Serial.print("PCD_Authenticate() failed: "); Serial.print("PCD_Authenticate() failed: ");
Serial.println(GetStatusCodeName(status)); Serial.println(GetStatusCodeName(status));
@@ -1216,9 +1224,9 @@ void MFRC522::PICC_DumpMifareClassicSectorToSerial(Uid *uid, ///< Pointer to U
} }
// Read block // Read block
byteCount = sizeof(buffer); byteCount = sizeof(buffer);
status = PICC_Read(blockAddr, buffer, &byteCount); status = MIFARE_Read(blockAddr, buffer, &byteCount);
if (status != STATUS_OK) { if (status != STATUS_OK) {
Serial.print("PICC_Read() failed: "); Serial.print("MIFARE_Read() failed: ");
Serial.println(GetStatusCodeName(status)); Serial.println(GetStatusCodeName(status));
continue; continue;
} }
@@ -1289,13 +1297,13 @@ void MFRC522::PICC_DumpMifareUltralightToSerial() {
byte i; byte i;
Serial.println("Page 0 1 2 3"); Serial.println("Page 0 1 2 3");
// Try reading all pages of an Ultralight C. Stop when a read fails. // Try the mpages of the original Ultralight. Ultralight C has more pages.
for (byte page = 0; page < 48; page +=4) { // Read returns data for 4 pages at a time. for (byte page = 0; page < 16; page +=4) { // Read returns data for 4 pages at a time.
// Read pages // Read pages
byteCount = sizeof(buffer); byteCount = sizeof(buffer);
status = PICC_Read(page, buffer, &byteCount); status = MIFARE_Read(page, buffer, &byteCount);
if (status != STATUS_OK) { if (status != STATUS_OK) {
Serial.print("PICC_Read() failed: "); Serial.print("MIFARE_Read() failed: ");
Serial.println(GetStatusCodeName(status)); Serial.println(GetStatusCodeName(status));
break; break;
} }
@@ -1318,7 +1326,7 @@ void MFRC522::PICC_DumpMifareUltralightToSerial() {
/** /**
* Calculates the bit pattern needed for the specified access bits. In the [C1 C2 C3] tupples C1 is MSB (=4) and C3 is LSB (=1). * Calculates the bit pattern needed for the specified access bits. In the [C1 C2 C3] tupples C1 is MSB (=4) and C3 is LSB (=1).
*/ */
void MFRC522::PICC_SetAccessBits( byte *accessBitBuffer, ///< Pointer to byte 6, 7 and 8 in the sector trailer. Bytes [0..2] will be set. void MFRC522::MIFARE_SetAccessBits( byte *accessBitBuffer, ///< Pointer to byte 6, 7 and 8 in the sector trailer. Bytes [0..2] will be set.
byte g0, ///< Access bits [C1 C2 C3] for block 0 (for sectors 0-31) or blocks 0-4 (for sectors 32-39) byte g0, ///< Access bits [C1 C2 C3] for block 0 (for sectors 0-31) or blocks 0-4 (for sectors 32-39)
byte g1, ///< Access bits C1 C2 C3] for block 1 (for sectors 0-31) or blocks 5-9 (for sectors 32-39) byte g1, ///< Access bits C1 C2 C3] for block 1 (for sectors 0-31) or blocks 5-9 (for sectors 32-39)
byte g2, ///< Access bits C1 C2 C3] for block 2 (for sectors 0-31) or blocks 10-14 (for sectors 32-39) byte g2, ///< Access bits C1 C2 C3] for block 2 (for sectors 0-31) or blocks 10-14 (for sectors 32-39)
@@ -1331,7 +1339,7 @@ void MFRC522::PICC_SetAccessBits( byte *accessBitBuffer, ///< Pointer to byte 6,
accessBitBuffer[0] = (~c2 & 0xF) << 4 | (~c1 & 0xF); accessBitBuffer[0] = (~c2 & 0xF) << 4 | (~c1 & 0xF);
accessBitBuffer[1] = c1 << 4 | (~c3 & 0xF); accessBitBuffer[1] = c1 << 4 | (~c3 & 0xF);
accessBitBuffer[2] = c3 << 4 | c2; accessBitBuffer[2] = c3 << 4 | c2;
} // End PICC_SetAccessBits() } // End MIFARE_SetAccessBits()
///////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////
// Convenience functions - does not add extra functionality // Convenience functions - does not add extra functionality
@@ -1362,4 +1370,4 @@ bool MFRC522::PICC_ReadCardSerial() {
byte result = PICC_Select(&uid); byte result = PICC_Select(&uid);
return (result == STATUS_OK); return (result == STATUS_OK);
} // End PICC_ReadCardSerial() } // End PICC_ReadCardSerial()

View File

@@ -5,6 +5,9 @@
* Rewritten by Søren Thing Andersen (access.thing.dk), fall of 2013 (Translation to English, refactored, comments, anti collision, cascade levels.) * Rewritten by Søren Thing Andersen (access.thing.dk), fall of 2013 (Translation to English, refactored, comments, anti collision, cascade levels.)
* Released into the public domain. * Released into the public domain.
* *
* Please read this file for an overview and then MFRC522.c for comments on the specific functions.
* Search for "mf-rc522" on ebay.com to purchase the MF-RC522 board.
*
* There are three hardware components involved: * There are three hardware components involved:
* 1) The micro controller: An Arduino * 1) The micro controller: An Arduino
* 2) The PCD (short for Proximity Coupling Device): NXP MFRC522 Contactless Reader IC * 2) The PCD (short for Proximity Coupling Device): NXP MFRC522 Contactless Reader IC
@@ -57,7 +60,7 @@
* Page 2 contains the last chech digit for the UID, one byte manufacturer internal data, and the lock bytes (see http://www.nxp.com/documents/data_sheet/MF0ICU1.pdf section 8.5.2) * Page 2 contains the last chech digit for the UID, one byte manufacturer internal data, and the lock bytes (see http://www.nxp.com/documents/data_sheet/MF0ICU1.pdf section 8.5.2)
* Page 3 is OTP, One Time Programmable bits. Once set to 1 they cannot revert to 0. * Page 3 is OTP, One Time Programmable bits. Once set to 1 they cannot revert to 0.
* Pages 4-15 are read/write unless blocked by the lock bytes in page 2. * Pages 4-15 are read/write unless blocked by the lock bytes in page 2.
* MIFARE Ultralight C (MF0ICUC): * MIFARE Ultralight C (MF0ICU2):
* Has 48 pages of 4 bytes = 64 bytes. * Has 48 pages of 4 bytes = 64 bytes.
* Pages 0 + 1 is used for the 7-byte UID. * Pages 0 + 1 is used for the 7-byte UID.
* Page 2 contains the last chech digit for the UID, one byte manufacturer internal data, and the lock bytes (see http://www.nxp.com/documents/data_sheet/MF0ICU1.pdf section 8.5.2) * Page 2 contains the last chech digit for the UID, one byte manufacturer internal data, and the lock bytes (see http://www.nxp.com/documents/data_sheet/MF0ICU1.pdf section 8.5.2)
@@ -159,7 +162,7 @@ public:
PCD_GenerateRandomID = 0x02, // generates a 10-byte random ID number PCD_GenerateRandomID = 0x02, // generates a 10-byte random ID number
PCD_CalcCRC = 0x03, // activates the CRC coprocessor or performs a self test PCD_CalcCRC = 0x03, // activates the CRC coprocessor or performs a self test
PCD_Transmit = 0x04, // transmits data from the FIFO buffer PCD_Transmit = 0x04, // transmits data from the FIFO buffer
PCD_NoCmdChange = 0x07, // no command change, can be used to modify the CommandReg register bits without affecting the command, for example, the PowerDown bit PCD_NoCmdChange = 0x07, // no command change, can be used to modify the CommandReg register bits without affecting the command, for example, the PowerDown bit
PCD_Receive = 0x08, // activates the receiver circuits PCD_Receive = 0x08, // activates the receiver circuits
PCD_Transceive = 0x0C, // transmits data from FIFO buffer to antenna and automatically activates the receiver after transmission PCD_Transceive = 0x0C, // transmits data from FIFO buffer to antenna and automatically activates the receiver after transmission
PCD_MFAuthent = 0x0E, // performs the MIFARE standard authentication as a reader PCD_MFAuthent = 0x0E, // performs the MIFARE standard authentication as a reader
@@ -178,14 +181,18 @@ public:
PICC_CMD_HLTA = 0x50, // HaLT command, Type A. Instructs an ACTIVE PICC to go to state HALT. PICC_CMD_HLTA = 0x50, // HaLT command, Type A. Instructs an ACTIVE PICC to go to state HALT.
// The commands used for MIFARE Classic (from http://www.nxp.com/documents/data_sheet/MF1S503x.pdf, Section 9) // The commands used for MIFARE Classic (from http://www.nxp.com/documents/data_sheet/MF1S503x.pdf, Section 9)
// Use PCD_MFAuthent to authenticate access to a sector, then use these commands to read/write/modify the blocks on the sector. // Use PCD_MFAuthent to authenticate access to a sector, then use these commands to read/write/modify the blocks on the sector.
PICC_CMD_AUTH_KEY_A = 0x60, // Perform authentication with Key A // The read/write commands can also be used for MIFARE Ultralight.
PICC_CMD_AUTH_KEY_B = 0x61, // Perform authentication with Key B PICC_CMD_MF_AUTH_KEY_A = 0x60, // Perform authentication with Key A
PICC_CMD_READ = 0x30, // Reads one 16 byte block from the authenticated sector of the PICC. Also used for MIFARE Ultralight. PICC_CMD_MF_AUTH_KEY_B = 0x61, // Perform authentication with Key B
PICC_CMD_WRITE = 0xA0, // Writes one 16 byte block to the authenticated sector of the PICC. Called "COMPATIBILITY WRITE" for MIFARE Ultralight. PICC_CMD_MF_READ = 0x30, // Reads one 16 byte block from the authenticated sector of the PICC. Also used for MIFARE Ultralight.
PICC_CMD_DECREMENT = 0xC0, // Decrements the contents of a block and stores the result in the internal data register. PICC_CMD_MF_WRITE = 0xA0, // Writes one 16 byte block to the authenticated sector of the PICC. Called "COMPATIBILITY WRITE" for MIFARE Ultralight.
PICC_CMD_INCREMENT = 0xC1, // Increments the contents of a block and stores the result in the internal data register. PICC_CMD_MF_DECREMENT = 0xC0, // Decrements the contents of a block and stores the result in the internal data register.
PICC_CMD_RESTORE = 0xC2, // Reads the contents of a block into the internal data register. PICC_CMD_MF_INCREMENT = 0xC1, // Increments the contents of a block and stores the result in the internal data register.
PICC_CMD_TRANSFER = 0xB0 // Writes the contents of the internal data register to a block. PICC_CMD_MF_RESTORE = 0xC2, // Reads the contents of a block into the internal data register.
PICC_CMD_MF_TRANSFER = 0xB0, // Writes the contents of the internal data register to a block.
// The commands used for MIFARE Ultralight (from http://www.nxp.com/documents/data_sheet/MF0ICU1.pdf, Section 8.6)
// The PICC_CMD_MF_READ and PICC_CMD_MF_WRITE can also be used for MIFARE Ultralight.
PICC_CMD_UL_WRITE = 0xA2 // Writes one 4 byte page to the PICC.
}; };
// MIFARE constants that does not fit anywhere else // MIFARE constants that does not fit anywhere else
@@ -281,15 +288,13 @@ public:
///////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////
byte PCD_Authenticate(byte command, byte blockAddr, MIFARE_Key *key, Uid *uid); byte PCD_Authenticate(byte command, byte blockAddr, MIFARE_Key *key, Uid *uid);
void PCD_StopCrypto1(); void PCD_StopCrypto1();
byte PICC_Read(byte blockAddr, byte *buffer, byte *bufferSize); byte MIFARE_Read(byte blockAddr, byte *buffer, byte *bufferSize);
byte PICC_Write(byte blockAddr, byte *buffer, byte bufferSize); byte MIFARE_Write(byte blockAddr, byte *buffer, byte bufferSize);
/* byte MIFARE_Decrement(byte blockAddr, long delta);
XXX Hvad med ultralight write/compatibility write()???? byte MIFARE_Increment(byte blockAddr, long delta);
*/ byte MIFARE_Restore(byte blockAddr);
byte PICC_Decrement(byte blockAddr, long delta); byte MIFARE_Transfer(byte blockAddr);
byte PICC_Increment(byte blockAddr, long delta); byte MIFARE_Ultralight_Write(byte page, byte *buffer, byte bufferSize);
byte PICC_Restore(byte blockAddr);
byte PICC_Transfer(byte blockAddr);
///////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////
// Support functions // Support functions
@@ -302,7 +307,7 @@ public:
void PICC_DumpMifareClassicToSerial(Uid *uid, byte piccType, MIFARE_Key *key); void PICC_DumpMifareClassicToSerial(Uid *uid, byte piccType, MIFARE_Key *key);
void PICC_DumpMifareClassicSectorToSerial(Uid *uid, MIFARE_Key *key, byte sector); void PICC_DumpMifareClassicSectorToSerial(Uid *uid, MIFARE_Key *key, byte sector);
void PICC_DumpMifareUltralightToSerial(); void PICC_DumpMifareUltralightToSerial();
void PICC_SetAccessBits(byte *accessBitBuffer, byte g0, byte g1, byte g2, byte g3); void MIFARE_SetAccessBits(byte *accessBitBuffer, byte g0, byte g1, byte g2, byte g3);
///////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////
// Convenience functions - does not add extra functionality // Convenience functions - does not add extra functionality
@@ -313,7 +318,7 @@ public:
private: private:
byte _chipSelectPin; // Arduino pin connected to MFRC522's SPI slave select input (Pin 24, NSS, active low) 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) byte _resetPowerDownPin; // Arduino pin connected to MFRC522's reset and power down input (Pin 6, NRSTPD, active low)
byte PICC_TwoStepHelper(byte command, byte blockAddr, long data); byte MIFARE_TwoStepHelper(byte command, byte blockAddr, long data);
}; };
#endif #endif