I am using an NFC Tag Type 2. I am having a problem with 1-Byte ACK/NACK responses when calling a transceive() function running the Broadcom NFC Android stack. This problem doesn't happen with the NXP NFC Android stack. For example, the ACK response of a Write command is defined as 0xAh (according to the NFC Forum Tag Type 2 protocol). If the NFC tag replies something else rather than 0xAh, the Broadcom NFC stack will consider this as NACK. This issue doesn't occur in the NXP NFC stack.
Broadcom NFC stack
In /platform/packages/apps/Nfc/nci/jni/NativeNfcTag.cpp
In function “nativeNfcTag_doTransceive()” line 890
static jbyteArray nativeNfcTag_doTransceive (JNIEnv* e, jobject, jbyteArray data, jboolean raw, jintArray statusTargetLost)
{
..
..
if ((natTag.getProtocol () == NFA_PROTOCOL_T2T) &&
natTag.isT2tNackResponse (sTransceiveData, sTransceiveDataLen))
{
isNack = true;
}
if (sTransceiveDataLen)
{
if (!isNack) {
// marshall data to java for return
result.reset(e->NewByteArray(sTransceiveDataLen));
if (result.get() != NULL) {
e->SetByteArrayRegion(result.get(), 0, sTransceiveDataLen, (jbyte *) sTransceiveData);
}
else
ALOGE ("%s: Failed to allocate java byte array", __FUNCTION__);
} // else a nack is treated as a transceive failure to the upper layers
free (sTransceiveData);
sTransceiveData = NULL;
sTransceiveDataLen = 0;
}
..
..
}
When we look at function isT2tNackResponse() in /platform/packages/apps/Nfc/nci/jni/NfcTag.cpp line 1212
bool NfcTag::isT2tNackResponse (const UINT8* response, UINT32 responseLen)
{
static const char fn [] = "NfcTag::isT2tNackResponse";
bool isNack = false;
if (responseLen == 1)
{
if (response[0] == 0xA) // line 1212: T2tNackResponse always returns NACK if the first byte is NOT 0xA
isNack = false; //an ACK response, so definitely not a NACK
else
isNack = true; //assume every value is a NACK
}
ALOGD ("%s: return %u", fn, isNack);
return isNack;
}
NXP NFC stack
The same function in the NXP NFC stack
In /platform/packages/apps/Nfc/nxp/jni/com_android_nfc_NativeNfcTag.cpp
In function “com_android_nfc_NativeNfcTag_doTransceive()” line 853
static jbyteArray com_android_nfc_NativeNfcTag_doTransceive(JNIEnv *e,
jobject o, jbyteArray data, jboolean raw, jintArray statusTargetLost)
{
..
..
/* Copy results back to Java *
* In case of NfcA and raw, also check the CRC in the response
* and cut it off in the returned data.
*/
if ((nfc_jni_transceive_buffer->length > 2) && checkResponseCrc) { // line 853
if (crc_valid(nfc_jni_transceive_buffer->buffer, nfc_jni_transceive_buffer->length)) {
result = e->NewByteArray(nfc_jni_transceive_buffer->length - 2);
if (result != NULL) {
e->SetByteArrayRegion(result, 0,
nfc_jni_transceive_buffer->length - 2,
(jbyte *)nfc_jni_transceive_buffer->buffer);
}
}
} else {
result = e->NewByteArray(nfc_jni_transceive_buffer->length);
if (result != NULL) {
e->SetByteArrayRegion(result, 0,
nfc_jni_transceive_buffer->length,
(jbyte *)nfc_jni_transceive_buffer->buffer);
}
}
..
..
}
In the NXP NFC stack, everything is forwarded to Java and returned to the transceive() function.
Any help/comment would be appreciated. Thank you.
This is a known issue. The problem is actually with the NFC Forum NCI standard, on which the Broadcom stack is based. The protocol messages in the NCI standard do not distinguish between 4-bit ACK/NAK responses and normal responses of 1 byte (+ CRC, which is stripped). Both are represented by a single byte. The Broadcom stack (has to) interpret them as ACK/NAK. Hopefully, this will soon be fixed in an update to the standard and the software stack.