我有很多NfcA新手问题。 docs和网络上的其他地方似乎对此没有什么指导,所以我希望没有人介意我在这里将一些基本问题拼凑起来...

我正在使用nfcA.transceive()将数据写入NTAG213标签,如下所示:

    byte[] result = nfcA.transceive(new byte[] {
            (byte)0xA2,  // WRITE
            (byte)(pageNum & 0x0ff),
            myData[0], myData[1], myData[2], myData[3]
    });

1. result数组是值10的单个字节。这意味着什么,我还应该注意其他什么值?

我也使用相同的方法从我的NTAG213标签读取数据:
    byte[] result = nfcA.transceive(new byte[] {
            (byte)0x30,  // READ
            (byte)(pageNum & 0x0ff)
    });

2. 我希望它返回4个字节的用户数据(即,与我的pageNum对应的4个字节),但是它返回了16个字节。为什么会这样?

3. ,在调用nfcA.isConnected()之前检查nfcA.connect()是一种好习惯吗?如果这样,这样做可能会导致明显的性能损失吗? (我问,因为我已经从两个著名的来源中看到了代码示例。)

4. 更好地在nfcA.setTimeout()之前或之后调用nfcA.connect()吗?

5. 对于我的NTAG213标签,nfcA.getMaxTransceiveLength()返回253。这是否真的意味着我可以一次性写入多达251个字节的用户数据(加上其他2个字节),如果这样,建议这样做还是最好写入每个页面(4个字节)具有单独的nfcA.transceive()调用?

最佳答案

1. WRITE命令的结果数组是单个字节的值10。这意味着什么?我还应注意其他什么值?

值10(十六进制的Ah或二进制表示的1010b)是一个显式ACK,当不返回任何数据的命令成功执行时,将返回一个确认。

可能的值为实际数据,ACK,被动ACK或NACK。这些由NFC论坛数字协议(protocol)规范和NFC论坛2类标签操作规范定义。

  • 如果期望命令成功返回实际数据,则返回数据而不是显式ACK值。
  • ACK被定义为值为1010b(Ah)的4位短帧(有关详细信息,请参阅NFC论坛数字协议(protocol)规范和ISO/IEC 14443-3)。
  • 被动ACK定义为标签在一定的超时时间内完全不发送响应。
  • NACK被定义为值为0x0xb(其中x为0或1)的4位短帧。

  • NTAG213/215/216产品数据表对可能的NACK值进行了更详细的说明:
  • 0000b(0h)表示无效的命令参数。
  • 0001b(1h)表示奇偶校验或CRC错误。
  • 0100b(4h)指示无效的身份验证计数器溢出。
  • 0101b(5h)表示EEPROM写错误。

  • 除了上述内容之外,某些设备上的NFC堆栈实现还无法将NACK响应正确传播到应用程序。相反,他们要么抛出TagLostException要么返回null。同样,您可能会获得一个指示被动ACK的TagLostException

    因此,通常将检查以下方法的收发方法的结果(除非发送预期会导致被动ACK的命令):
    try {
       response = nfca.transceive(command);
       if (response == null) {
           // either communication to the tag was lost or a NACK was received
       } else if ((response.length == 1) && ((response[0] & 0x00A) != 0x00A)) {
           // NACK response according to Digital Protocol/T2TOP
       } else {
           // success: response contains ACK or actual data
       }
    } catch (TagLostException e) {
       // either communication to the tag was lost or a NACK was received
    }
    

    2.我期望READ方法返回4个字节的用户数据(即,与我的pageNum对应的4个字节),但是它返回了16个字节。为什么会这样?

    定义READ命令以从指定的块编号开始返回4个数据块(在NFC论坛2型标签操作规范中)。因此,如果您发送块4的READ命令,您将获得块4、5、6和7的数据。

    3.在调用nfcA.isConnected()之前检查nfcA.connect()是一种好习惯吗?如果是的话,这样做可能会导致明显的性能损失吗?

    如果您直接从NFC系统服务(通过NFC Intent )接收到Tag句柄,则将不会连接标签。因此,除非您在调用Tag之前使用nfca.connect()句柄,否则我不明白您为什么要在之前调用nfca.isConnected()。但是,在连接之前调用该方法几乎没有任何性能开销,因为在fa​​mmwork API无需调用NFC系统服务的情况下,将由famework API处理在封闭标签技术对象上调用isConnected()的情况。因此,在if对象的 bool 成员变量上,这比简单的NfcA开销要大得多。

    4.最好在nfcA.setTimeout()之前或之后调用nfcA.connect()

    我不确定那个。但是,收发超时通常在断开标签技术时重置。

    5.对于我的NTAG213标签,nfcA.getMaxTransceiveLength()返回253。这是否真的意味着我可以一次性写入多达251个字节的用户数据(加上其他2个字节),如果这样,建议还是最好编写每个页面(4个字节)具有单独的nfcA.transceive()调用?

    不可以,一次只能写一个块。这受NTAG213的WRITE命令的限制,该命令仅支持一个块作为数据输入。

    但是,收发缓冲区的大小为253,使您可以使用FAST_READ命令一次读取多个块(最多可以读取62个块,对于NTAG213最多可以读取45个块):
    int firstBlockNum = 0;
    int lastBlockNum = 42;
    byte[] result = nfcA.transceive(new byte[] {
            (byte)0x3A,  // FAST_READ
            (byte)(firstBlockNum & 0x0ff),
            (byte)(lastBlockNum & 0x0ff),
    });
    

    10-04 12:01