是不是我们从其他标签复制的 NDEF 格式对我们的标签无效?
这正是问题所在。查看内存转储的前 12 个字节,您显然从 NXP NTAG203(或类似设备)复制了数据块,如制造商代码(字节 0:)0x04
和功能容器中的内存大小(字节 13:0x12
)。NXP 的 NTAG 和 MIFARE Ultralight 系列遵循 NFC Forum Type 2 标签操作规范。但是,您的 TI 芯片 (RF430FRL152H) 基于 ISO/IEC 15693,因此遵循 NFC 论坛类型 5 标签操作规范。标签操作规范定义了将 NFC 标签转换为 NDEF 标签的数据格式和命令集。由于 NFC 技术结合了多种不同的射频标准(ISO/IEC 14443、FeliCa、ISO/IEC 15693),并且使用了在 NFC 之前已经存在的用于这些标准的标签硬件,因此有多种(目前为 5 种)不同的此类规范。
为什么 NFC TagInfo 有时会看到块,然后在检测到 NDEF 时看到页面?块和页是一样的吗?
在这种情况下,块和页是等价的。不同的措辞只是来自芯片制造商使用的术语。请注意,RF430FRL152H 芯片使用术语“页”来对多个块进行分组,因此具有不同的含义。
如果一个人只是在正确的块中写入正确的字节,那么任何东西都可以作为 NDEF 被拾取,毕竟,在低级别有什么区别?
不同之处在于您的 TI RF430FRL152H 标签芯片需要对 NDEF 内存区域使用与 NXP 标签不同的编码。这仅仅是因为它使用不同的低级通信技术(调制、编码、成帧、命令集),因此遵循不同的 NFC 论坛标签操作规范。
为了使您的标签芯片成为 NDEF 标签,您需要对从块 0 开始的 NDEF 内存区域使用以下编码: 请注意,功能容器填充了假定块大小为 8 字节的值。您可以使用固件控制寄存器中的标志 ISOBlockSize 更改 ISO 块大小选项(请参阅RF430FRL15xH 固件用户指南中的第 7.54 节“固件系统控制寄存器” )。
E1 40 F2 09 03 0B D1 01
07 54 02 65 6E 41 42 43
44 FE 00 00 00 00 00 00
这将导致包含一条带有消息“ABCD”的文本记录的 NDEF 消息。
前 4 个字节 ( E1 40 F2 09
) 是能力容器:
0xE1
是标识标签的能力容器的幻数,其中完整的内存区域可以用一个字节的块地址寻址。
0x40
编码类型 5 标签内存映射的 1.0 版,并指示对内存的自由读/写访问。
0xF2
将整个 NDEF 内存区域(CC 字节除外)定义为长度为 242 ( 0xF2
) 乘以 8 字节(= 1936 字节)。请参阅下面的“理论与实践”部分!
0x09
表示您的标签支持 READ_MULTIPLE_BLOCKS 命令(设置位 0)和 LOCK_BLOCK 命令(设置位 3)。
接下来的 2 个字节 ( 03 0B
) 是 NDEF 消息 TLV(标签长度值编码数据结构)的标头:
0x03
: 表示 NDEF 消息 TLV 的头字节。
0x0B
: NDEF 消息 TLV 的长度 = 11 个字节。
接下来的 11 个字节 ( D1 01 07 54 02 656E 41424344
) 是 NDEF 消息:
0xD1
:记录头字节:
- 位 7 和 6:这是 NDEF 消息的唯一记录。
- 第 4 位:这是一个短记录(即有效载荷长度用单个字节编码)。
- 位 2..0:记录类型编码 NFC 论坛知名类型。
0x01
:类型名称字段的长度为 1 个字节。
0x07
:有效载荷字段的长度为 7 个字节。
0x54
:类型名称(ASCII:“T”),表示 NFC 论坛众所周知的文本记录类型(Text RTD)。
0x02
.. 0x44
:文本记录的有效负载字段:
0x02
:文本以 UTF-8 编码,语言字段由 2 个字节组成。
0x65 0x6E
:语言字段(ASCII:“en”),表示语言英语。
0x41 0x42 0x43 0x44
:文本负载(UTF-8 格式:“ABCD”)。
下一个字节 ( FE
) 是终止符 TLV,指示已使用数据区的结束。该块的剩余字节应用零 ( 0x00
) 填充,以避免某些 Android 设备出现问题。
块锁定有什么不同吗?
不,块锁定不会改变您的标签被检测到的方式。它仅更改读取 (Android) 设备访问它的方式:读/写访问或只读访问。
是否可以在所有 Android 设备上检测到此标签?
抱歉不行。NFC 论坛第 5 类标签操作规范仅在 2015 年 7 月完成。虽然一些 Android 设备在该日期之前在 ISO/IEC 15693 (NFC-V) 标签上实施了 NDEF,但不要期望所有 Android 设备都是这种情况。不过,它应该适用于从 Android 5.0 开始的大多数设备。即使从 Android 4.3 开始,某些 Android 设备也应该能够在某些 NFC-V 标签上支持 NDEF。
理论与实践
经过一些进一步的测试,我发现即使在 5 类(NFC-V)标签上支持 NDEF 的设备在其 NFC 堆栈的实现中似乎也有很大的限制(错误???)。我使用 TI Tag-it HF-I 系列中的两种标签类型测试了三星 Galaxy S6(Android 5.1.1):
- Tag-it HF-I Plus(2048 位用户存储器,64 x 4 字节块)
- Tag-it HF-I 标准(256 位用户存储器,8 x 4 字节块)
不幸的是,他们都没有使用我上面描述的功能容器与 Galaxy S6 一起工作。问题在于 NDEF 内存区域的大小(MLEN,存储在 CC 的第三个字节中)。显然,上面使用的尺寸对于这两个标签来说太长了。因此,我减少了它以匹配每个标签的标签内存大小:
- Tag-it HF-I Plus:
- 64 x 4 字节 = 256 字节
- 256 字节 / 8 = 32(MLEN 始终计算为 8 字节的倍数)
- 减 1 块,因为 CC 不计为数据区的一部分(根据类型 5 标记操作规范)
- MLEN = 31 = 0x1F
- 抄送:
E1 40 1F 09
- Tag-it HF-I 标准:
- 8 x 4 字节 = 32 字节
- 32 字节 / 8 = 4(MLEN 始终计算为 8 字节的倍数)
- 减 1 块,因为 CC 不计为数据区的一部分(根据类型 5 标记操作规范)
- MLEN = 3 = 0x03
- 抄送:
E1 40 03 09
不过,这并没有奏效。标签未被检测为 NDEF 标签(仅作为NdefFormatable
)。最后,我发现 Galaxy S6只有在 MLEN 字节准确地反映了整个内存区域(包括 CC 字节)的大小时才会检测到这些标签。因此,只有以下值有效:
- Tag-it HF-I Plus:
- Tag-it HF-I 标准:
更糟糕的是,虽然 CCE1 40 04 09
可以处理 Tag-it HF-I 标准标签,但它不能处理 Tag-it HF-I Plus 标签。因此,Galaxy S6 的 NFC 堆栈似乎期望不同标签产品上的 CC 具有非常具体的值。
基于此,以下 CC 值应适用于 RF430FRL152H:
- 当块大小设置为 8 字节时:
E1 40 F3 09
- 当块大小设置为 4 字节时:
E1 40 79 09
“应该”,因为不清楚如何识别标签并将其映射到预期的 CC 值。此外,尚不清楚 Galaxy S6 是否知道该特定芯片的任何预期 CC 值。
另一种找到 CC 字节“正确”(= 预期)值的方法是使用该技术将 NDEF 消息写入标签NdefFormatable
,然后使用 NFC TagInfo 等标签阅读器应用程序读取 CC 字节:
Tag tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
NdefFormatable ndefFormatable = NdefFormatable.get(tag);
if (ndefFormatable != null) {
try {
ndefFormatable.connect();
ndefFormatable.format(new NdefMessage(NdefRecord.createTextRecord("en", "ABCD")));
} catch (Exception e) {
} finally {
try {
ndefFormatable.close();
} catch (Exception e) {
}
}
}
使用一些通用的标签编写器应用程序也可以完成相同的操作(NXP TagWriter 除外,它似乎无法写入标签)。
其他一切都失败了,我们如何在 Android 中实现简单的块读取,就像 NFC TagInfo 执行其十六进制转储一样?
RF430FRL152H 应被 Android 检测为 NFC-V(NFC 术语中的 ISO/IEC 15693)标签。因此,一旦您收到 NFC 意图,您就可以获取标签句柄并为其获取NfcV
类的实例:
Tag tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
NfcV nfcV = NfcV.get(tag);
您可以使用收发方法连接到标签并交换低级命令(例如 READ_SINGLE_BLOCK):
nfcV.connect();
byte[] tagUid = tag.getId(); // store tag UID for use in addressed commands
int blockAddress = 0;
byte[] cmd = new byte[] {
(byte)0x60, // FLAGS
(byte)0x20, // READ_SINGLE_BLOCK
0, 0, 0, 0, 0, 0, 0, 0,
(byte)(blockAddress & 0x0ff)
};
System.arraycopy(tagUid, 0, cmd, 2, 8);
byte[] response = nfcV.transceive(cmd);
nfcV.close();
我在哪里可以获得有关标签格式、NDEF 和低级命令的更多信息?
NFC Forum Type 5 Tag Operation specification:来自NFC Forum 网站(不幸的是,NFC Forum 规范不再免费提供)。
重要提示:请注意不要将其与 open-nfc.org 提供的“NFC Tag Type 5 Specification”混为一谈。尽管两个规范都谈到了标签“ Type 5 ”,但它们指的是完全不同的标签平台。open-nfc.org 的规范与 RF430FRL15xH 芯片不兼容。
- 与最终 NFC Forum Type 5 Tag Operation 规范非常接近的公共文档是 NXP 应用笔记AN11032 NXP Type ICODE Tag Operation。然而,NFC 论坛类型 5 标签操作规范与该应用说明之间存在一些显着差异(特别是关于能力容器的格式)。
- NFC 数据交换格式 (NDEF) 规范:也来自 NFC 论坛网站或来自此处。
- NFC 记录类型定义 (RTD) 规范:也来自 NFC 论坛网站或来自此处。
- 文本记录类型定义规范:也来自 NFC 论坛网站或来自此处。
- 数字协议规范中的 NFC-V:也来自 NFC 论坛网站。
- ISO/IEC 15693:该标准定义了标准的低级命令。
- RF430FRL15xH 用户指南:您可以在第 4.2ff 节中找到用于访问 RAM 存储区的自定义命令。