Search code examples
androidxamarintagsnfciso-15693

NFC-V "Tag Lost" exception with Xamarin and ST M24LR tag


I am new to Xamarin as well as Android development. I have an NFC tag, specifically a ST M24LR64E, with data on it. I can see the blocks of data using the ST app on Google Play. In my Xamarin app, I cannot send a message to the tag without getting a TagLostException. I can query the tag ID with no issue, but trying to read a single block of data, I get the exception. Any direction would be grateful.

byte[] response = new byte[] { 0x0A };

byte[] cmd = new byte[]
{
    (byte) 0x26,
    (byte) 0x01,
    0x00
};
response = nfcv.Transceive(cmd);

byte[] single = new byte[]
{
    (byte) 0x40, // FLAGS
    (byte) 0x20, // READ_SINGLE_BLOCK
    0, 0, 0, 0, 0, 0, 0, 0,
    (byte) (0 & 0x0ff)
};
Array.Copy(id, 0, single, 2, 8);
response = nfcv.Transceive(single);

The first Transceive() is ok and I see 10 bytes coming back. As soon as I try to read a block of data, I get the TagLostException.


Solution

  • With the NfcV tag technology, a TagLostException may indicate that the reader can no longer communicate with the tag or that the command resulted in an error.

    According to its manual, the M24LR64E only supports the extended version (Protocol Extension flag set) of the READ_SINGLE_BLOCK command:

    The Protocol_extension_flag should be set to 1 for the M24LR64E-R to operate correctly. If the Protocol_extension_flag is at 0, the M24LR64E-R answers with an error code.

    Consequently, your version of the READ_SINGLE_BLOCK command is not compatible with the tag. You need to set the Protocol Extension flag and provide a 16 bit block number. A version that should work is:

    int blockNumber = 0;
    byte[] readSingleBlock = new byte[] {
            (byte) 0x28, // Flags: Addressed (bit 5), Protocol Extension (bit 3)
            (byte) 0x20, // Command: READ_SINGLE_BLOCK
            0, 0, 0, 0, 0, 0, 0, 0,  // placeholder for UID
            (byte) (blockNumber & 0x0ff),
            (byte) ((blockNumber >> 8) & 0x0ff)
    };
    byte[] id = nfcv.GetTag().GetId();
    Array.Copy(id, 0, readSingleBlock, 2, 8);
    response = nfcv.Transceive(readSingleBlock);
    

    Since you used the high data rate (Data_rate flag set) with the INVENTORY command, you might also want to use the high data rate with the READ_SINGLE_BLOCK command. You would use the flags value 0x2A (instead of 0x28) in that case.

    Finally, you should avoid sending anti-collision/enumeration commands such as the INVENTORY command over any NfcX tag technology object. While this may work, you might confuse the internal state-keeping of the ANdroid NFC stack since it already performs these commands for you and keeps track of the enumerated tag(s). You can get all the information that you would obtain through the INVENTORY request from the Tag object and the NfcV object:

    • tag.GetId() gives you the UID of the tag.
    • nfcv.GetDsfId() gives you the DSFID of the tag.
    • nfcv.GetResponseFlags() gives you the flags byte of the INVENTORY response.