Search code examples
javaandroidnfcrfidmifare

MifareUltralight: sector select causes TagLostException


I am trying to use SECTOR_SELECT to read and write to/from specified sectors, but get a TagLostException when I send the second part of the command through MifareUltralight.transceive(). How can I select and manipulate sectors?

I am using an Android Nexus 6 (6.0.1) to send commands to and get data from an NXP NTAG (NT3H1201). I am able to use the GET_VERSION command (60h) with transceive (both through NfcA and MifareUltralight).

The method I am using to select a sector:

public void selectSector(byte sector, MifareUltralight mifareUltralight) throws IOException {
    if (mifareUltralight.isConnected()) {
        mifareUltralight.close();
    }

    // SECTOR_SELECT command (see nxp p. 46)
    byte[] sectorSelectCmdPacket1 = new byte[2];
    byte[] sectorSelectCmdPacket2 = new byte[4];

    sectorSelectCmdPacket1[0] = (byte) 0xc2; // Sector select command
    sectorSelectCmdPacket1[1] = (byte) 0xff;

    sectorSelectCmdPacket2[0] = sector; // Memory sector to be selected; 1 for I2C 2k version
    sectorSelectCmdPacket2[1] = (byte) 0x00;
    sectorSelectCmdPacket2[2] = (byte) 0x00;
    sectorSelectCmdPacket2[3] = (byte) 0x00;

    mifareUltralight.connect();

    try {
        // ACK = 0A
        byte[] sectorSelectResp1 = mifareUltralight.transceive(sectorSelectCmdPacket1);
        Log.w(TAG, bytesToHex(sectorSelectResp1));
    } catch (IOException e) {
        Log.w(TAG, "selectSector: there was an exception while sending first sector select command");
        e.printStackTrace();
    }

    try {
        mifareUltralight.transceive(sectorSelectCmdPacket2);
        Log.w(TAG, "Second sector select command sent");
    } catch (IOException e) {
        Log.w(TAG, "selectSector: there was an exception while sending second sector select command");
        e.printStackTrace();
    }

    mifareUltralight.close();
}

When I call the selectSector method, the first transceive completes but the second does not, resulting in the error

android.nfc.TagLostException: Tag was lost.

How can I select and manipulate sectors without getting the TagLostException?


Solution

  • It's normal that the second stage of the SECTOR_SELECT command results in a TagLostException. This happens on many Android devices and is caused by the way the second stage of the SECTOR_SELECT command is acknowledged (passive ACK). You can safely continue to communicate with the tag after you received the exception for that specific command. Only if you receive a TagLostException for a command where you expect an explicit ACK/response data there is something wrong with the communication.

    Also note that you should not close the connection after selecting the sector as this will reset the tag on some Android devices. Consequently, the sector may no longer be selected when you later re-connect the tag.

    A typical sector select method would look something like this:

    public boolean selectSector(int sector) throws IOException {
        byte[] cmd_sel1 = { (byte)0xC2, (byte)0xFF };
        byte[] cmd_sel2 = { (byte)sector, (byte)0x00, (byte)0x00, (byte)0x00 };
    
        byte[] result1 = transceive(cmd_sel1);
        if (result1 == null) {
            throw new TagLostException();
        } else if ((result1.length == 1) && ((result1[0] & 0x00A) == 0x000)) {
            // NACK response according to DigitalProtocol
            return false;
        } else {
            try {
                byte[] result2 = transceive(cmd_sel2);
                if (result2 == null) {
                    throw new TagLostException();
                } else if ((result2.length == 1) && ((result2[0] & 0x00A) == 0x000)) {
                    // NACK response according to DigitalProtocol
                    return false;
                } else {
                    return true;
                }
            } catch (Exception e) {
                // passive ACK
                return true;
            }
        }
    }