I'm busy with an app to emulate normal APDU communication on a Nexus 7 with CM10.1 to an ACR122U102 reader/writer. I found this blog about software card emulation and wrote an app to make my device (the nexus) appear as a card. Now I'm trying to send messages back and forth between this device and the ACR122u. So far, I've only managed to communicate with the nexus 7 by sending D4 40 01 (InDataExchange page 127) APDU's. For the application I'm writing, this should be sufficient.
The problem lays in the answer I send from the device to the reader. Using the transcieve function (android.nfc.tech.IsoPcdA with reflection), I can reply with a byte array of length > 0. This would show up on the reader-end like a normal InDataExchange response (e.g: D5 41 00 01 02 03 with {01 02 03} being the byte array supplied to the transcieve function). But I can't control the status byte nor the SW bytes in the response (D5 41 XX and both SW's). There's no documentation to be found about this IsoPcdA class except the source code itself.
What I want to be able to do is change the XX to a byte of my choice and to send answers of length = 0 (e.g: D5 41 01 without any extra data). Is it possible?
I'm not exactly sure what you are trying to achieve here. Whatever you transceive with IsoPcdA's transceive method are complete APDUs (as defined in ISO/IEC 7816-4, or rather any PDU within the ISO-DEP transport protocol). So the return value of transceive is a full C-APDU (command APDU) and the byte array parameter of transceive is a full R-APDU (response APDU) including the two bytes of the status word (SW1 | SW2). Thus, the last two bytes of that parameter are the status word. In your example SW1 would be 02 and SW2 would be 03.
What you see as status byte in the InDataExchange command of the PN532 NFC controller is not the status word of the APDU but the status of the command execution within the PN532 NFC controller. This status byte gives you information about buffer overflows, communication timeouts, etc and is not something that is returned by the card side.
EDIT : Sample code + test commands:
Sample Code running on Galaxy Nexus (CM 10):
try {
Class isoPcdA = Class.forName("android.nfc.tech.IsoPcdA");
Method isoPcdA_get = isoPcdA.getDeclaredMethod("get", Tag.class);
final IsoPcdA techIsoPcdA = (IsoPcdA)isoPcdA_get.invoke(null, tag);
if (techIsoPcdA != null) {
if (mWorker != null) {
mInterrupt = true;
mWorker.interrupt();
try {
mWorker.join();
} catch (Exception e) {}
}
mInterrupt = false;
mWorker = new Thread(new Runnable() {
public void run () {
try {
techIsoPcdA.connect();
byte[] command = techIsoPcdA.transceive(new byte[]{ (byte)0x90, (byte)0x00 });
Log.d(CardEmulationTest.class.getName(), "Connected.");
while (!mInterrupt) {
Log.d(CardEmulationTest.class.getName(), "C-APDU=" + StringUtils.convertByteArrayToHexString(command));
command = techIsoPcdA.transceive(command);
}
} catch (Exception e) {
Log.e(CardEmulationTest.class.getName(), "Exception while communicating on IsoPcdA object", e);
} finally {
try {
techIsoPcdA.close();
} catch (Exception e) {}
}
}
});
mWorker.start();
}
} catch (Exception e) {
Log.e(CardEmulationTest.class.getName(), "Exception while processing IsoPcdA object", e);
}
Test (using ACR122U):
InListPassivTargets (1 target at 106kbps)
> FF00000004 D44A 0100 00
< D54B 010100046004088821310578338800 9000
InDataExchange with DATA = 0x01
> FF00000004 D440 01 01 00
< D541 00 01 9000
So we get an error code of 0x00 from the card reader (status of InDataExchange command; not part of the actual response APDU), we get 0x01 as the response (this is the IsoDepA response APDU) and we get 0x9000 as the status code for the card reader wrapper APDU (not part of the actual response APDU).
InDataExchange with DATA = 0x01 0x02
> FF00000005 D440 01 0102 00
< D541 00 0102 9000
So we get an error code of 0x00 from the card reader (status of InDataExchange command; not part of the actual response APDU), we get 0x01 0x02 as the response (this is the IsoDepA response APDU) and we get 0x9000 as the status code for the card reader wrapper APDU (not part of the actual response APDU).
InDataExchange with DATA = 0x01 0x02 0x03
> FF00000006 D440 01 010203 00
< D541 00 010203 9000
So we get an error code of 0x00 from the card reader (status of InDataExchange command; not part of the actual response APDU), we get 0x01 0x02 0x03 as the response (this is the IsoDepA response APDU) and we get 0x9000 as the status code for the card reader wrapper APDU (not part of the actual response APDU).
InDataExchange with DATA = 0x01 0x02 0x03 0x04
> FF00000007 D440 01 01020304 00
< D541 00 01020304 9000
So we get an error code of 0x00 from the card reader (status of InDataExchange command; not part of the actual response APDU), we get 0x01 0x02 0x03 0x04 as the response (this is the IsoDepA response APDU) and we get 0x9000 as the status code for the card reader wrapper APDU (not part of the actual response APDU).
Thus, we get exactly the data taht we send as command APDU as response APDU (note that none of these APDUs is formatted according to ISO 7816-4, but that doesnt matter as the IsoPcdA card emulation works with any ISO 14443-4 transport protocol format).
The status code of 0x9000 belongs to the card reader APDU encapsulation (CLA=FF INS=00 P1P2=0000 Lc [PN542 COMMAND] Le=00) that is required as the ACR122U's PN532 is accessed over the CCID (PC/SC) interface. These are pure reader command encapsulation and have nothing to do with the communication over ISO-DEP.
The D440 01 [DATA] is the PN532 command to exchange data (e.g. APDUs) over ISO-DEP and the D541 00 [DATA] is the associated response.