Communication problems with NTAG213

Asked by Tomasz Koperski


I'm working with NXP NTAG213 using nfcpy. I am able to perform basic READ and WRITE operations, but I'm not able to perform any other commands.

The two commands working are:

READ (\x30)
WRITE (\xA2)

the ones that do not seem to work:

READ_CNT (\x39)

I've tried the simplest way to communicate with the tag, mentioned here: by Stephen. Code available here:

When I use this method to read 16 bytes starting at block 0 (\x30\x00) with this code:

def readdemo(tag):
        uid = tag.uid
        data = tag.transceive("\x30\x00", timeout=0.2)
        print hexlify(uid), hexlify(data)

I get this:
It looks OK - I get proper 16 bytes of data read from the tag.

now if I use the same method for any of the mentioned other functions, like READ_SIG with this code:

def readsign(tag):
        uid = tag.uid
        sig = tag.transceive("\x3C\x00", timeout=0.2)
        print hexlify(uid), hexlify(sig)

I get this:

The same goes for any other method mentioned. It always ends with
<<< 8000000000000000fe00
transmited from USB reader.

My reader is:

output for 'nfc-list':
nfc-list uses libnfc libnfc-1.7.1
NFC device: ACS / ACR122U PICC Interface opened
1 ISO14443A passive target(s) found:
ISO/IEC 14443A (106 kbps) target:
    ATQA (SENS_RES): 00 44
       UID (NFCID1): 04 01 1e 3a 98 37 81
      SAK (SEL_RES): 00

Any idea what might be the problem here?

Question information

English Edit question
nfcpy Edit question
No assignee Edit question
Solved by:
Tomasz Koperski
Last query:
Last reply:
Revision history for this message
Tomasz Koperski (t-koperski) said :

We've played with it and were able to get around it by modifying nfc/dev/

The problem was caused by the fact, that for the mentioned commands nfcpy uses
self.chipset.in_data_exchange method, while it should use self.chipset.in_communicate_through

This changed the cmd_code from 0x40 to 0x42 while sending commands line PWD_AUTH or READ_SIG, which fixed the problem.

For now we're selecting the right method basing on the cmd_data value, for the command marked with [2] here: (screen from NTAG213 documentation by NXP).

Revision history for this message
Stephen Tiedemann (stephen-tiedemann) said :

Many thanks for spotting this problem with pn53x based readers. I'll work out an update to use in_communicate_thru for tag reading.

Revision history for this message
corzand (acorzani) said :

Hello Tomasz,

I think I have the same issue trying to read the signature of NXP NTAG212!

Is it possible to have the updated code of nfc/dev/ ?

Thanks again

Revision history for this message
Tomasz Koperski (t-koperski) said :

Hi there,

I've ended up with a quick fix in the command methind inside nfc/dev/ (I use the ACR122U reader).
Here's the changed definition of this function:

    def command(self, cmd_code, cmd_data=None, timeout=100):
        """Send a chip command and return the chip response."""
        cmd_name = "PN53x "+self.CMD.get(cmd_code, "0x{0:02X}".format(cmd_code))
        log.debug("{0} called with timeout {1} ms".format(cmd_name, timeout))

        if cmd_data is None: cmd_data = ""
 if len(cmd_data) > 1 and bytearray(cmd_data)[1] in [0x1B, 0x3C, 0x60, 0x39]:
   cmd_code = 0x42
   cmd_data = cmd_data[1:]
        frame = bytearray([0xD4, cmd_code]) + bytearray(cmd_data)
 # Temporary fix, nfcpy problem described here:
 # Manually overriding cmd_code value to 0x42
 ### end fix
        frame = bytearray([0xFF, 0x00, 0x00, 0x00, len(frame)]) + frame

        frame = self.ccid_xfr_block(frame, timeout)
        if not frame or len(frame) < 4:
            log.error("insufficient data for decoding chip response")
            raise IOError(errno.EIO, os.strerror(errno.EIO))
        if not (frame[0] == 0xD5 and frame[1] == cmd_code + 1):
            log.error("received invalid chip response")
            raise IOError(errno.EIO, os.strerror(errno.EIO))
        if not (frame[-2] == 0x90 and frame[-1] == 0x00):
            log.error("received pseudo apdu with error status")
            raise IOError(errno.EIO, os.strerror(errno.EIO))
        return frame[2:-2]

I manually change the method code to 0x42 if I detect specific NTAG213 (will also work with NTAG212).
This is definitely not the best way to implement this change, but it was enough in my case.

Revision history for this message
corzand (acorzani) said :

Thank you Tomasz, this solved my problem

Revision history for this message
Stephen Tiedemann (stephen-tiedemann) said :

A comprehensive fix is on the way. You can try the development version with "bzr branch lp:~stephen-tiedemann/nfcpy/dev-tags", it'll give you improved handling of type 2 tags, authenticate(...) and protect(...) for Ultralight C and NTAG21x plus the signature bytes accessible with just "sig = tag.signature". The got parameters authenticate and protect with password, see the commit message at for some usage explanantion.

Eventually this will merge into trunk but there's still some other tags to do and to test.