How to communicate with an NFC reader

There are two modes considered here. INITIATOR and TARGET. It is a matter of 
sending the right APDUs to the reader. In Java 6 you can use the 
"javax.smartcardio.*" API for this [6]. For other platforms there are probably 
similar ways of communicating with readers.
Communicating with the reader happens through APDUs (which are byte arrays of 
data) in which certain functionality of for example a smart card are accessed.
The ACS ACR122 is however a little bit different as it also supports "pseudo 
APDUs" which talk to the reader itself rather then to a smart card. By sending 
a specific (pseudo) APDU you can access the functionality of the PN532 chip 
built in, or some reader specific functionality like modifying the status of 
the LED. 
The header for sending commands meant for the PN532 is:
0xff 0x00 0x00 0x00 0xii
Where "ii" is the size of the rest of the command including the command 
instruction. An example of an actual APDU command sent to the terminal to send 
data to a target (see below) looks like this (>>). The response is 
also shown (<<)
>> 0xff 0x00 0x00 0x00 0x09 0xd4 0x40 0x01 0x30 0x31 0x32 0x33 0x34 0x00
<< 0xd5 0x41 0x00 0x30 0x31 0x32 0x33 0x34 0x00 0x90 0x00
This sends the data `0x30 0x31 0x32 0x33 0x34 0x00` which is a string 
representation of `01234`. The response includes the same data in this example.
We also didn't mention that the responses to the commands all end with 0x90 
0x00 as that is always the case with successfully executed APDUs. In case of a 
wrong command the result will only be two bytes which indicate an error. See 
for example [2] for a description of some errors for the ACR122.
NFCIP Initiator Mode
--------------------
The first step is to set the mode to initiator and wait for a target to appear. 
This is done by sending the command "InJumpForDEP" which is "0xd4 0x56". It has
a few parameters that are encoded in the APDU. A full example:
Configure as initiator and wait for targets
-------------------------------------------
There are two ways to do this. You can ask for a target and the first one to 
reply becomes your target, or the other method is to ask for multiple targets 
and select the one you want (possibly alternating), so you can manage two 
targets at the same time.
Activating one target
---------------------
This is used to initialize and activate a target directly with one command, you 
get one active target this way.
** Command to PN532 **
0xd4 0x56                   InJumpForDEP instruction code
0x00                        Look for Passive/Active Target 
(0x00 = passive, 0x01 = active)
0x02                        Baud Rate 
(0x00 = 106kbps, 0x01 = 212kbps, 0x02 = 424kbps)
0x01                        Whether or not there is a payload in this command
(0x01 = yes)
0x00 0xff 0xff 0x00 0x00    Polling Request?
Every command is answered with a response, in this case as soon as a target is 
in range.
** Response from PN532 **
0xd5 0x57                   InJumpForDEP response code
0x00                        Status 
(0x00 = no error)
0x01                        Target number (used for sending data later)
This is followed by the ATR_RES bytes which we won't be using in the rest of 
the protocol.
Initializing and activate one or more targets
---------------------------------------------
There is also another way to select and initialize a target, or multiple 
targets. The PN532 supports two targets at a time. This command is to list and 
initialize one or more targets:
** Command to PN532 **
0xd4 0x4a                   InListPassivTargets instruction code
0x01                        Look for this number of targets
0x02                        Baud Rate 
(0x00 = 106kbps, 0x01 = 212kbps, 0x02 = 424kbps)
0x00 0xff 0xff 0x00 0x00    Polling Request?
** Response from PN532 **
0xd5 0x4b                   InListPassivTargets response code
0x01                        Number of targets found 
(here 1 target found)
0x01                        The following bytes describe target 1
0x12                        The target information has 12 bytes including 
this one
0x01                        Maybe the real communication speed?
0x01 0xFE 0xDD 0x8E 0xCF 0x70 0x29 0xE2
This target NFCID3 
(used for selecting it with InSelect later)
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
Padding?
Activate target:
** Command to PN532 **
0xd4 0x50                   InATR instruction code
0x01                        Activate target with this number
(here number 1)
0x01 0xFE 0xDD 0x8E 0xCF 0x70 0x29 0xE2
The NFCID3 from previous response
** Response from PN532 **
0xd5 0x51                   InATR` response code
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 
0x00 0x00 0x00 0x00 0x00 0x00 0x0A 0x00
ATR_RES?
The sending and receiving of data is the same as with the other method (see 
below). The advantage here is that you can scan for targets and select the one 
you need, allowing for multiple targets at the same time!
Send data to a target
---------------------
** Command to PN532 **
0xd4 0x40                   InDataExchange instruction code
0x01                        Target to send to 
(see response from previous command)
... ... ...                 The rest are the bytes to be send to the target.
The maximum number of bytes seems to be 252?
** Response from PN532 **
0xd5 0x41                   InDataExchange reponse code
0x00                        Status 
(0x00 = no error)
... ... ...                 The rest are the bytes received from the target, 
this is how the target sends data to the 
initiator by replying with it in the response 
to the received data
Release a target
----------------
** Command to PN532 **
0xd4 0x52                   InRelease instruction code
0x01                        Target to release
(0x00 = release all targets)
** Response from PN532 **
0xd5 0x53                   InRelease response code
0x00                        Status 
(0x00 = no error)
NFCIP Target Mode
-----------------
Configure as target and wait for initiators
-------------------------------------------
** Command to PN532 **
0xd4 0x8c                   TgInitAsTarget instruction code
0x00                        Acceptable modes 
(0x00 = allow all, 0x01 = only allow to be 
initialized as passive, 0x02 = allow DEP only)
_6 bytes (_MIFARE_)_:
0x08 0x00                   SENS_RES
0x12 0x34 0x56              NFCID1
0x40                        SEL_RES
_18 bytes (_Felica_)_:
0x01 0xfe 0xa2 0xa3 0xa4 0xa5 0xa6 0xa7
NFCID2
0xc0 0xc1 0xc2 0xc3 0xc4 0xc5 0xc6 0xc7
?
0xff 0xff                   System parameters?
0xaa 0x99 0x88 0x77 0x66 0x55 0x44 0x33 0x22 0x11
NFCID3
0x00                        ?
0x00                        ?
This is the response when an initiator activated this target:
** Response from PN532 **
0xd5 0x8d                   TgInitAsTarget response code
0x04                        Mode
(0x04 = DEP, 106kbps)
... ... ...                 ?
Receive data from initiator
---------------------------
** Command to PN532 **
0xd4 0x86                   TgGetData instruction code
** Response from PN532 **
0xd5 0x87                   TgGetData response code
0x00                        Status 
(0x00 = no error, bit 6 set: See "Meta Chaining")
... ... ...                 The rest are the bytes received from initiator
Send data to initiator
----------------------
** Command to PN532 **
0xd4 0x8e                   TgSetData instruction code
... ... ...                 The rest are the bytes to be send to initiator
** Reponse from the PN532 **
0xd5 0x8f                   TgSetData response code
0x00                        Status 
(0x00 = no error)
Send data to initiator (Meta Chaining)
--------------------------------------
** Command to PN532 **
0xd4 0x94                   TgSetMetaData instruction code
... ... ...                 The rest are the bytes to be send to initiator
** Reponse from the PN532 **
0xd5 0x95                   TgSetMetaData response code
0x00                        Status 
(0x00 = no error)
Chaining
--------
Whenever you want to send more data then possible (the amount of data is 
seemingly limited to 252 bytes) you have can use "chaining". There are two ways 
to do this with the PN532. You can either implement it yourself completely or 
use the "meta chaining" provided by the PN532. Below both techniques will be 
shown:
Initiator Meta Chaining
-----------------------
First we look at the situation from the initiator. Using meta chaining the 
initiator uses the InDataExchange command specifying the target and setting bit
6 of the target field to indicate that there is more data coming. This bit 6 
remains set while there is more data and is removed in the last data block.
The response from the InDataExchange command can be ignored, except with the 
last block where bit 6 is not set. At this point the returned data is the data
the target wants to send back. The status byte of the returned data indicates
whether also the target wants to send more data back than just one block. If 
bit 6 is set in the status field the initiator can request the rest using an
empty InDataExchange command, just specifying the target.
InDataExchange(target byte with bit 6 set,     block 1)
InDataExchange(target byte with bit 6 set,     block 2)
:              :
InDataExchange(target byte with bit 6 cleared, block n)
look at the response code from the last InDataExchange, if bit 6 is set
there is more data coming than just the data in this block
InDataExchange(target), while status byte has bit 6 set

 

Leave a Reply

Your email address will not be published. Required fields are marked *