Search code examples
nfcuniqueidentifierrfidandroid-thingsserial-number

Different NFC ID and RFID UID value


I'm developing software for an Android Things device with RFID reader RC522. I use this library: https://github.com/Galarzaa90/android-things-rc522

My task querying the RC533 RFID reader:

protected Boolean doInBackground(Object... params) {
    mRc522.stopCrypto();
    while (true) {
        ........
        byte[] uuid = mRc522.getUid();
        return mRc522.selectTag(uuid);
    }
}

In my activity I use this to convert the UID value into a string:

String tagRC522 = toHexString(mRc522.getUid(), "")

Another application in our ecosystem used to scan the NFC tags on an Android smartphone:

public void onNewIntent(Intent intent) {
    Tag tagFromIntent = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);

    String tagNFC = bytesToHex(tagFromIntent.getId());
    ....
}

Other apps from Play Store (e.g. NFC Tools) give the same results as the code of the smartphone app above.

The problem I face now is that the value tagRC522 (on the Android Things device using RC522) does not match the value tagNFC (in the smartphone app).

Tag1  
    tagRC522 = 45DOD86528
    tagNFC   = 45DOD865

Tag2 
    tagRC522 = 3567500103
    tagNFC   = 35675001

Tag3
    tagRC522 = 88046f12F1
    tagNFC   =   046F12CA193A84

Tag4
    tagRC522 = 3EBA46D517
    tagNFC   = 3EBA46D5

Why are the results between the two applications different? How must I change my Android Things code? Android mobile is production code and a many data in firebase in tagNFC version, I couldn't change that.

(Image of the tags)


Solution

  • The results are essentially the same for the RC522 and Android's built-in NFC reader. The main differences are that the library that you use for the RC522

    1. includes the checksum (BCC) in the UID field, and
    2. performs anti-collision only for cascade level 1.

    This means that only the first 4 bytes of the value obtained through mRc522.getUid() are the UID value. The last (5th byte) is the XOR checksum over the previous 4 bytes. This is the BCC byte from the raw anti-collsion frame. If you want to calculate that for the value received through tagFromIntent.getId(), you could do something like this:

    byte[] uid = tagFromIntent.getId();
    byte[] uidWithBCC = new byte[5];
    for (int i = 0; i < 4; ++i) {
        uidWithBCC[i] = uid[i];
        uidWithBCC[4] ^= uid[i];
    }
    

    Similarly, in order to turn the value from mRc522.getUid() into the value from tagFromIntent.getId(), you could just drop the last byte:

    byte[] uidWithBCC = mRc522.getUid();
    byte[] uid = new byte[4];
    for (int i = 0; i < 4; ++i) {
        uid[i] = uidWithBCC[i];
    }
    

    Moreover, for tags with a double or tripple size UID, the value returned by mRc522.getUid() is the value raw response of the PICC to casecade level 1 anti-collision. Consequently, it consists of the cascade tag (0x88) followed by the first 3 bytes of the UID, followed by the BCC. Hence, if you want to map the value that you received through tagFromIntent.getId() to the value obtained from mRc522.getUid(), you need to extract the first 3 bytes of the UID, prepend the cascade tag and append the BCC:

        byte[] uid = tagFromIntent.getId();
        if (uid.length > 4) {
            uid[0] = (byte)0x88;
        }
        byte[] trimmedUidWithBCC = new byte[5];
        for (int i = 0; i < 4; ++i) {
            trimmedUidWithBCC[i] = uid[i];
            trimmedUidWithBCC[4] ^= uid[i];
        }
    

    Unfortunately, this cannot easily be done the other way round. The missing bytes on the Android Things/RC522 side are not something that you could easily calculate from the other bytes. Instead, you would need to modify the library to perform further cascade levels in the anti-collision procedure. Only then you will be able to obtain the complete double and tripple size UIDs.