Class MFRC522

java.lang.Object
com.diozero.devices.MFRC522
All Implemented Interfaces:
Closeable, AutoCloseable

public class MFRC522
extends Object
implements Closeable

Datasheet
Example Python code
MiFare Classic Universal toolKit (MFCUK)
Work-in-progress!

Wiring:

  • SDA: SPI0 CE0 (GPIO8)
  • SCK: SPI0 SCLK (GPIO11)
  • MOSI: SPI0 MOSI (GPIO10)
  • MISO: SPI0 MISO (GPIO9)
  • IRQ: Not connected
  • GND: GND
  • RST: Any free GPIO (GPIO25)
  • 3v3: 3v3

Java port from MFRC522 Library to use ARDUINO RFID MODULE KIT 13.56 MHZ WITH TAGS SPI W AND R BY COOQROBOT that was created by Miguel Balboa (circuitito.com).

There are three hardware components involved:

  1. The controller, e.g. Arduino, Raspberry Pi
  2. The PCD (Proximity C oupling Device), e.g. NXP MFRC522 Contactless Reader
  3. The PICC (Proximity Integrated Circuit Card): A card or tag using the ISO 14443A interface, e.g. Mifare or NTAG203.

The microcontroller and card reader uses SPI for communication. The protocol is described in the MFRC522 datasheet.

The card reader and the tags communicate using a 13.56MHz electromagnetic field. The protocol is defined in http://wg8.de/wg8n1496_17n3613_Ballot_FCD14443-3.pdf:

  • ISO/IEC 14443-3 Identification cards
  • Contactless integrated circuit cards
  • Proximity cards
  • Part 3: Initialization and anticollision"
  • Chapter 6, Type A ? Initialization and anticollision

If only the PICC UID is wanted, the above documents have all the information needed.
To read and write from MIFARE PICCs, the MIFARE protocol is used after the PICC has been selected.
The MIFARE Classic and Ultralight chips and protocols are described in the datasheets:

MIFARE Classic 1K (MF1S503x)

Has 16 sectors * 4 blocks/sector * 16 bytes/block = 1024 bytes.
The blocks are numbered 0-63.
Block 3 in each sector is the Sector Trailer. See sections 8.6 and 8.7:

   Bytes 0-5:   Key A
   Bytes 6-8:   Access Bits
   Bytes 9:     User data
   Bytes 10-15: Key B (or user data)
 

Block 0 is read-only manufacturer data, sometimes as follows:

 0 1 2 3 |4  | 5 |6   |7 8 9 A B C D E F
 UID     |BCC|SAK|ATAQ|Manufacturer data
 

To access a block, an authentication using a key from the block's sector must be performed first.
Example: To read from block 10, first authenticate using a key from sector 3 (blocks 8-11).
All keys are set to FFFFFFFFFFFFh at chip delivery.
Warning: Please read section 8.7 "Memory Access". It includes this text: if the PICC detects a format violation the whole sector is irreversibly blocked.
To use a block in "value block" mode (for Increment/Decrement operations) you need to change the sector trailer. Use setAccessBits() to calculate the bit patterns.

MIFARE Classic 4K (MF1S703x)

Has (32 sectors * 4 blocks/sector + 8 sectors * 16 blocks/sector) * 16 bytes/block = 4096 bytes.
The blocks are numbered 0-255.
The last block in each sector is the Sector Trailer like above.

MIFARE Classic Mini (MF1 IC S20)

Has 5 sectors * 4 blocks/sector * 16 bytes/block = 320 bytes.
The blocks are numbered 0-19.
The last block in each sector is the Sector Trailer like above.

MIFARE Ultralight (MF0ICU1)

Has 16 pages of 4 bytes = 64 bytes.
Pages 0 + 1 is used for the 7-byte UID.
Page 2 contains the last check 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.
Pages 4-15 are read/write unless blocked by the lock bytes in page 2.

MIFARE Ultralight C (MF0ICU2)

Has 48 pages of 4 bytes = 192 bytes.
Pages 0 + 1 is used for the 7-byte UID.
Page 2 contains the last check 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.
Pages 4-39 are read/write unless blocked by the lock bytes in page 2.
Page 40 Lock bytes
Page 41 16 bit one way counter
Pages 42-43 Authentication configuration
Pages 44-47 Authentication key

Access conditions for sector trailer

   KeyA  Bits  KeyB
   R  W  R  W  R  W
 0 -  A  A  -  A  A
 1 -  A  A  A  A  A Default
 2 -  -  A  -  A  -
 3 -  B  AB B  -  B
 4 -  B  AB -  -  B
 5 -  -  AB B  -  -
 6 -  -  AB -  -  -
 7 -  -  AB -  -  -
 

Access conditions for data blocks

     R   W   +  -X
 0  AB  AB  AB  AB Data  Default
 1  AB  --  --  AB Value
 2  AB  --  --  -- Data
 3   B   B  --  -- Data
 4  AB   B  --  -- Data
 5   B  --  --  -- Data
 6  AB   B   B  AB Value
 7  --  --  --  -- Data
 

Workflow

  1. Call ISO_Request() to check to see if a tag is in range and if so get its ATQA.
  2. Upon success call ISO_Anticollision() which returns the UID of the active tag in range.
  3. Upon success call ISO_Select(UID) which selects the active tag in range by its UID and returns its SAK.
  4. If the card needs authentication call ISO_Authenticate(blockAddr, keyId, key, UID) to authenticate access to a block.
  5. Call ISO_StopCrypto() when you have finished talking to a card which requires authentication.
  • Field Details

    • DEFAULT_KEY

      public static final byte[] DEFAULT_KEY
    • MFRC522_firmware_referenceV0_0

      public static final byte[] MFRC522_firmware_referenceV0_0
    • MFRC522_firmware_referenceV1_0

      public static final byte[] MFRC522_firmware_referenceV1_0
    • MFRC522_firmware_referenceV2_0

      public static final byte[] MFRC522_firmware_referenceV2_0
    • FM17522_firmware_reference

      public static final byte[] FM17522_firmware_reference
    • MF_ACK

      public static final byte MF_ACK
      See Also:
      Constant Field Values
    • MF_KEY_SIZE

      public static final byte MF_KEY_SIZE
      See Also:
      Constant Field Values
    • MI_OK

      public static final byte MI_OK
      See Also:
      Constant Field Values
    • MI_NOTAGERR

      public static final byte MI_NOTAGERR
      See Also:
      Constant Field Values
    • MI_ERR

      public static final byte MI_ERR
      See Also:
      Constant Field Values
  • Constructor Details

    • MFRC522

      public MFRC522​(int chipSelect, int resetGpio)
    • MFRC522

      public MFRC522​(int controller, int chipSelect, int resetGpio)
    • MFRC522

      public MFRC522​(int controller, int chipSelect, DigitalOutputDevice resetPin)
  • Method Details

    • close

      public void close()
      Specified by:
      close in interface AutoCloseable
      Specified by:
      close in interface Closeable
    • setLogReadsAndWrites

      public void setLogReadsAndWrites​(boolean logReadsAndWrites)
    • init

      public void init()
      Initializes the MFRC522 chip.
    • setAntennaOn

      public void setAntennaOn​(boolean on)
      Open antennas, each time you start or shut down the natural barrier between the transmitter should be at least 1ms interval
      Parameters:
      on - on/off value
    • getAntennaGain

      public MFRC522.AntennaGain getAntennaGain()
      Get the current MFRC522 Receiver Gain (RxGain[2:0]) value. See 9.3.3.6 / table 98 in http://www.nxp.com/documents/data_sheet/MFRC522.pdf NOTE: Return value scrubbed with (0x07<<4)=01110000b as RCFfgReg may use reserved bits.
      Returns:
      Value of the RxGain, scrubbed to the 3 bits used.
    • setAntennaGain

      public void setAntennaGain​(MFRC522.AntennaGain gain)
      Set the MFRC522 Receiver Gain (RxGain) to value specified by given mask. See 9.3.3.6 / table 98 in http://www.nxp.com/documents/data_sheet/MFRC522.pdf NOTE: Given mask is scrubbed with (0x07<<4)=01110000b as RCFfgReg may use reserved bits.
      Parameters:
      gain - New antenna gain value
    • performSelfTest

      public boolean performSelfTest()
      Performs a self-test of the MFRC522 See 16.1.1 in http://www.nxp.com/documents/data_sheet/MFRC522.pdf
      Returns:
      Whether or not the test passed. Or false if no firmware reference is available.
    • getVersion

      public int getVersion()
    • requestA

      public MFRC522.StatusCode requestA​(byte[] bufferATQA)
      Transmits a REQuest command, Type A. Invites PICCs in state IDLE to go to READY and prepare for anticollision or selection. 7 bit frame. Beware: When two PICCs are in the field at the same time I often get STATUS_TIMEOUT - probably due do bad antenna design.
      Parameters:
      bufferATQA - The buffer to store the ATQA (Answer to request) in
      Returns:
      STATUS_OK on success, STATUS_??? otherwise.
    • wakeupA

      public MFRC522.StatusCode wakeupA​(byte[] bufferATQA)
      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. Beware: When two PICCs are in the field at the same time I often get STATUS_TIMEOUT - probably due do bad antenna design.
      Parameters:
      bufferATQA - The buffer to store the ATQA (Answer to request) in
      Returns:
      STATUS_OK on success, STATUS_??? otherwise.
    • requestAOrWakeUpA

      public MFRC522.StatusCode requestAOrWakeUpA​(com.diozero.devices.MFRC522.PiccCommand command, byte[] bufferATQA)
      Transmits REQA or WUPA commands. Beware: When two PICCs are in the field at the same time I often get STATUS_TIMEOUT - probably due do bad antenna design.
      Parameters:
      command - The command to send - PICC_CMD_REQA or PICC_CMD_WUPA
      bufferATQA - The buffer to store the ATQA (Answer to request) in
      Returns:
      STATUS_OK on success, STATUS_??? otherwise.
    • select

      public MFRC522.UID select()
    • select

      public MFRC522.UID select​(byte validBits)
      Transmits SELECT/ANTICOLLISION commands to select a single PICC. Before calling this function the PICCs must be placed in the READY(*) state by calling PICC_RequestA() or PICC_WakeupA(). On success: - The chosen PICC is in state ACTIVE(*) and all other PICCs have returned to state IDLE/HALT. (Figure 7 of the ISO/IEC 14443-3 draft.) - The UID size and value of the chosen PICC is returned in *uid along with the SAK. A PICC UID consists of 4, 7 or 10 bytes. Only 4 bytes can be specified in a SELECT command, so for the longer UIDs two or three iterations are used: UID size Number of UID bytes Cascade levels Example of PICC ======== =================== ============== =============== single 4 1 MIFARE Classic double 7 2 MIFARE Ultralight triple 10 3 Not currently in use?
      Parameters:
      validBits - The number of known UID bits supplied in *uid. Normally 0. If set you must also supply uid->size.
      Returns:
      UID object or null if there was an error.
    • haltA

      public MFRC522.StatusCode haltA()
      Instructs a PICC in state ACTIVE(*) to go to state HALT.
      Returns:
      STATUS_OK on success, STATUS_??? otherwise.
    • authenticate

      public MFRC522.StatusCode authenticate​(boolean authKeyA, byte blockAddr, byte[] key, MFRC522.UID uid)
      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. The authentication is described in the MFRC522 datasheet section 10.3.1.9 and http://www.nxp.com/documents/data_sheet/MF1S503x.pdf section 10.1. For use with MIFARE Classic PICCs. The PICC must be selected - ie in state ACTIVE(*) - before calling this function. Remember to call PCD_StopCrypto1() after communicating with the authenticated PICC - otherwise no new communications can start. All keys are set to FFFFFFFFFFFFh at chip delivery.
      Parameters:
      authKeyA - PICC_CMD_MF_AUTH_KEY_A or PICC_CMD_MF_AUTH_KEY_B
      blockAddr - The block number. See numbering in the comments in the .h file.
      key - Crypto1 key to use (6 bytes)
      uid - Pointer to Uid struct. The first 4 bytes of the UID is used.
      Returns:
      STATUS_OK on success, STATUS_??? otherwise. Probably STATUS_TIMEOUT if you supply the wrong key.
    • stopCrypto1

      public void stopCrypto1()
      Used to exit the PCD from its authenticated state. Remember to call this function after communicating with an authenticated PICC - otherwise no new communications can start.
    • mifareRead

      public byte[] mifareRead​(byte blockAddr)
      Reads 16 bytes (+ 2 bytes CRC_A) from the active PICC. For MIFARE Classic the sector containing the block must be authenticated before calling this function. For MIFARE Ultralight only addresses 00h to 0Fh are decoded. The MF0ICU1 returns a NAK for higher addresses. The MF0ICU1 responds to the READ command by sending 16 bytes starting from the page address defined by the command argument. For example; if blockAddr is 03h then pages 03h, 04h, 05h, 06h are returned. A roll-back is implemented: If blockAddr is 0Eh, then the contents of pages 0Eh, 0Fh, 00h and 01h are returned. The buffer must be at least 18 bytes because a CRC_A is also returned. Checks the CRC_A before returning STATUS_OK.
      Parameters:
      blockAddr - MIFARE Classic: The block (0-0xff) number. MIFARE Ultralight: The first page to return data from.
      Returns:
      STATUS_OK on success, STATUS_??? otherwise.
    • mifareWrite

      public MFRC522.StatusCode mifareWrite​(byte blockAddr, byte[] buffer)
      Writes 16 bytes to the active PICC. For MIFARE Classic the sector containing the block must be authenticated before calling this function. For MIFARE Ultralight the operation is called "COMPATIBILITY WRITE". Even though 16 bytes are transferred to the Ultralight PICC, only the least significant 4 bytes (bytes 0 to 3) are written to the specified address. It is recommended to set the remaining bytes 04h to 0Fh to all logic 0.
      Parameters:
      blockAddr - MIFARE Classic: The block (0-0xff) number. MIFARE Ultralight: The page (2-15) to write to.
      buffer - The 16 bytes to write to the PICC
      Returns:
      STATUS_OK on success, STATUS_??? otherwise.
    • mifareUltralightWrite

      public MFRC522.StatusCode mifareUltralightWrite​(byte page, byte[] buffer)
      Writes a 4 byte page to the active MIFARE Ultralight PICC.
      Parameters:
      page - The page (2-15) to write to.
      buffer - The 4 bytes to write to the PICC
      Returns:
      STATUS_OK on success, STATUS_??? otherwise.
    • mifareDecrement

      public MFRC522.StatusCode mifareDecrement​(byte blockAddr, int delta)
      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. Only for blocks in "value block" mode, ie with access bits [C1 C2 C3] = [110] or [001]. Use MIFARE_Transfer() to store the result in a block.
      Parameters:
      blockAddr - The block (0-0xff) number.
      delta - This number is subtracted from the value of block blockAddr.
      Returns:
      STATUS_OK on success, STATUS_??? otherwise.
    • mifareIncrement

      public MFRC522.StatusCode mifareIncrement​(byte blockAddr, int delta)
      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. Only for blocks in "value block" mode, ie with access bits [C1 C2 C3] = [110] or [001]. Use MIFARE_Transfer() to store the result in a block.
      Parameters:
      blockAddr - The block (0-0xff) number.
      delta - This number is added to the value of block blockAddr.
      Returns:
      STATUS_OK on success, STATUS_??? otherwise.
    • mifareRestore

      public MFRC522.StatusCode mifareRestore​(byte blockAddr)
      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. Only for blocks in "value block" mode, ie with access bits [C1 C2 C3] = [110] or [001]. Use MIFARE_Transfer() to store the result in a block.
      Parameters:
      blockAddr - The block (0-0xff) number.
      Returns:
      STATUS_OK on success, STATUS_??? otherwise.
    • mifareTwoStepHelper

      public MFRC522.StatusCode mifareTwoStepHelper​(com.diozero.devices.MFRC522.PiccCommand command, byte blockAddr, int data)
      Helper function for the two-step MIFARE Classic protocol operations Decrement, Increment and Restore.
      Parameters:
      command - The command to use
      blockAddr - The block (0-0xff) number.
      data - The data to transfer in step 2
      Returns:
      STATUS_OK on success, STATUS_??? otherwise.
    • mifareTransfer

      public MFRC522.StatusCode mifareTransfer​(byte blockAddr)
      MIFARE Transfer writes the value stored in the volatile memory into one MIFARE Classic block. 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].
      Parameters:
      blockAddr - The block (0-0xff) number.
      Returns:
      STATUS_OK on success, STATUS_??? otherwise.
    • mifareGetValue

      public Integer mifareGetValue​(byte blockAddr)
      Helper routine to read the current value from a Value Block. Only for MIFARE Classic and only for blocks in "value block" mode, that is: with access bits [C1 C2 C3] = [110] or [001]. The sector containing the block must be authenticated before calling this function.
      Parameters:
      blockAddr - The block (0x00-0xff) number.
      Returns:
      Integer value or null if error.
    • mifareSetValue

      public MFRC522.StatusCode mifareSetValue​(byte blockAddr, int value)
      Helper routine to write a specific value into a Value Block. Only for MIFARE Classic and only for blocks in "value block" mode, that is: with access bits [C1 C2 C3] = [110] or [001]. The sector containing the block must be authenticated before calling this function.
      Parameters:
      blockAddr - The block (0x00-0xff) number.
      value - New value of the Value Block.
      Returns:
      STATUS_OK on success, STATUS_??? otherwise.
    • mifareTransceive

      public MFRC522.StatusCode mifareTransceive​(byte[] sendData)
    • mifareTransceive

      public MFRC522.StatusCode mifareTransceive​(byte[] sendData, boolean acceptTimeout)
      Wrapper for MIFARE protocol communication. Adds CRC_A, executes the Transceive command and checks that the response is MF_ACK or a timeout.
      Parameters:
      sendData - Data to transfer to the FIFO. Do NOT include the CRC_A.
      acceptTimeout - A timeout is also success
      Returns:
      STATUS_OK on success, STATUS_??? otherwise.
    • getPiccType

      public static MFRC522.PiccType getPiccType​(byte sak)
      Translates the SAK (Select Acknowledge) to a PICC type.
      Parameters:
      sak - The SAK byte returned from PICC_Select().
      Returns:
      PICC_Type
    • mifareOpenUidBackdoor

      public boolean mifareOpenUidBackdoor()
      Performs the "magic sequence" needed to get Chinese UID changeable Mifare cards to allow writing to sector 0, where the card UID is stored. Note that you do not need to have selected the card through REQA or WUPA, this sequence works immediately when the card is in the reader vicinity. This means you can use this method even on "bricked" cards that your reader does not recognise anymore (see MFRC522::MIFARE_UnbrickUidSector). Of course with non-bricked devices, you're free to select them before calling this function.
      Returns:
      Status
    • mifareSetUid

      public boolean mifareSetUid​(byte[] newUid, MFRC522.UID uid, byte[] authKey)
      Reads entire block 0, including all manufacturer data, and overwrites that block with the new UID, a freshly calculated BCC, and the original manufacturer data. Make sure to have selected the card before this function is called.
      Parameters:
      newUid - New UID.
      uid - Current UID
      authKey - Authentication key
      Returns:
      Status
    • mifareUnbrickUidSector

      public boolean mifareUnbrickUidSector()
      Resets entire sector 0 to zeroes, so the card can be read again by readers.
      Returns:
      Status
    • isNewCardPresent

      public boolean isNewCardPresent()
      Returns true if a PICC responds to PICC_CMD_REQA. Only "new" cards in state IDLE are invited. Sleeping cards in state HALT are ignored.
      Returns:
      bool
    • readCardSerial

      public MFRC522.UID readCardSerial()
      Simple wrapper around PICC_Select. Returns the UID of the card if present, otherwise null. Remember to call PICC_IsNewCardPresent(), PICC_RequestA() or PICC_WakeupA() first.
      Returns:
      The UID is a card could be read, otherwise null
    • dumpVersionToConsole

      public void dumpVersionToConsole()
      Dumps debug info about the connected PCD to Serial. Shows all known firmware versions
    • dumpToConsole

      @Deprecated public void dumpToConsole​(MFRC522.UID uid)
      Deprecated.
      Kept for backward compatibility
      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.
      Parameters:
      uid - UID returned from a successful PICC_Select().
    • dumpToConsole

      @Deprecated public void dumpToConsole​(MFRC522.UID uid, byte[] key)
      Deprecated.
    • dumpDetailsToConsole

      @Deprecated public static void dumpDetailsToConsole​(MFRC522.UID uid)
      Deprecated.
      kept for backward compatibility
      Dumps card info (UID,SAK,Type) about the selected PICC to Serial.
      Parameters:
      uid - UID struct returned from a successful PICC_Select().
    • dumpMifareClassicToConsole

      public void dumpMifareClassicToConsole​(MFRC522.UID uid, byte[] key)
      Dumps memory contents of a MIFARE Classic PICC. On success the PICC is halted after dumping the data.
      Parameters:
      uid - UID returned from a successful PICC_Select().
      key - Key A used for all sectors.
    • dumpMifareClassicSectorToConsole

      public void dumpMifareClassicSectorToConsole​(MFRC522.UID uid, byte[] key, byte sector)
      Dumps memory contents of a sector of a MIFARE Classic PICC. Uses PCD_Authenticate(), MIFARE_Read() and PCD_StopCrypto1. Always uses PICC_CMD_MF_AUTH_KEY_A because only Key A can always read the sector trailer access bits.
      Parameters:
      uid - UID returned from a successful select().
      key - Key A for the sector.
      sector - The sector to dump, 0..39.
    • dumpMifareUltralightToConsole

      public void dumpMifareUltralightToConsole()
      Dumps memory contents of a MIFARE Ultralight PICC.