繁体   English   中英

为什么使用 Android 手机读取 NFCtag 时会获得与使用专用阅读器读取时不同的标签 ID?

[英]Why when reading NFCtag with Android phone you get different tag ID then when reading with dedicated reader?

我使用的是 Android Cilico F750,专用 RFID 阅读器是 CF-RS103。 RFID 标签类型为 MIFARE Ultralight type C。

用专用读卡器读取时,标签id为:2054270212(10位)。

但是当用 Android 手机读取时,id 是:36139312876727556(17digit),反向 id 是:1316602805183616(16digit)。

有谁知道为什么会发生这种情况,以及是否可以将 10digit id 转换为 17digit id,反之亦然。

我使用意图来检测标签并解决我使用的意图:

public void resolveIntent(Intent intent){

    String action = intent.getAction();

    if(NfcAdapter.ACTION_TAG_DISCOVERED.equals(action)
            ||NfcAdapter.ACTION_TECH_DISCOVERED.equals(action)
            ||NfcAdapter.ACTION_NDEF_DISCOVERED.equals(action))

    {
        Parcelable[] rawMsgs = intent.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES);
        NdefMessage[] msgs;

        if(rawMsgs!=null)
        {
            msgs= new NdefMessage[rawMsgs.length];

            for(int i=0; i<rawMsgs.length; i++)
            {
                msgs[i]=(NdefMessage) rawMsgs[i];
            }
        }

        else
        {
            byte[] empty = new byte[0];
            byte[] id = intent.getByteArrayExtra(NfcAdapter.EXTRA_ID);
            Tag tag = (Tag) intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
            byte[] payload = dumpTagData(tag).getBytes();
            NdefRecord record = new NdefRecord(NdefRecord.TNF_UNKNOWN,empty,id,payload);
            NdefMessage msg = new NdefMessage(new NdefRecord[]{record});
            msgs= new NdefMessage[] {msg};
        }
        displayMsgs(msgs);
    }}

这是我的辅助功能:

private void displayMsgs(NdefMessage[] msgs)
{
    if(msgs==null || msgs.length==0) {
        return;
    }

    StringBuilder builder = new StringBuilder();
    List<ParsedNdefRecord> records= NdefMessageParser.parse(msgs[0]);
    final int size = records.size();

    for(int i=0;i<size;i++)
    {
        ParsedNdefRecord record = records.get(i);
        String str = record.str();
        builder.append(str).append("\n");
    }

    text.setText(builder.toString());
}



private String dumpTagData(Tag tag) {
StringBuilder sb = new StringBuilder();
byte[] id = tag.getId();
sb.append("ID (hex): ").append(toHex(id)).append('\n');
sb.append("ID (reversed hex):").append(toReversedHex(id)).append('\n');
sb.append("ID (dec): ").append(toDec(id)).append('\n');
sb.append("ID (reversed dec):").append(toReversedDec(id)).append('\n');

String prefix = "android.nfc.tech.";
sb.append("Technologies: ");
for (String tech: tag.getTechList()) {
    sb.append(tech.substring(prefix.length()));
    sb.append(", ");
}

sb.delete(sb.length() - 2, sb.length());

for (String tech: tag.getTechList()) {
    if (tech.equals(MifareClassic.class.getName())) {
        sb.append('\n');
        String type = "Unknown";

        try {
            MifareClassic mifareTag = MifareClassic.get(tag);

            switch (mifareTag.getType()) {
                case MifareClassic.TYPE_CLASSIC:
                    type = "Classic";
                    break;
                case MifareClassic.TYPE_PLUS:
                    type = "Plus";
                    break;
                case MifareClassic.TYPE_PRO:
                    type = "Pro";
                    break;
            }
            sb.append("Mifare Classic type: ");
            sb.append(type);
            sb.append('\n');

            sb.append("Mifare size: ");
            sb.append(mifareTag.getSize() + " bytes");
            sb.append('\n');

            sb.append("Mifare sectors: ");
            sb.append(mifareTag.getSectorCount());
            sb.append('\n');

            sb.append("Mifare blocks: ");
            sb.append(mifareTag.getBlockCount());
        } catch (Exception e) {
            sb.append("Mifare classic error: " + e.getMessage());
        }
    }

    if (tech.equals(MifareUltralight.class.getName())) {
        sb.append('\n');
        MifareUltralight mifareUlTag = MifareUltralight.get(tag);
        String type = "Unknown";
        switch (mifareUlTag.getType()) {
            case MifareUltralight.TYPE_ULTRALIGHT:
                type = "Ultralight";
                break;
            case MifareUltralight.TYPE_ULTRALIGHT_C:
                type = "Ultralight C";
                break;
        }
        sb.append("Mifare Ultralight type: ");
        sb.append(type);
    }
}

return sb.toString();
}

private String toHex(byte[] bytes) {
    StringBuilder sb = new StringBuilder();
    for (int i = bytes.length - 1; i >= 0; --i) {
        int b = bytes[i] & 0xff;
        if (b < 0x10)
            sb.append('0');
        sb.append(Integer.toHexString(b));
        if (i > 0) {
            sb.append(" ");
        }
    }
    return sb.toString();
}

private String toReversedHex(byte[] bytes) {
    StringBuilder sb = new StringBuilder();
    for (int i = 0; i < bytes.length; ++i) {
        if (i > 0) {
            sb.append(" ");
        }
        int b = bytes[i] & 0xff;
        if (b < 0x10)
            sb.append('0');
        sb.append(Integer.toHexString(b));
    }
    return sb.toString();
}

private long toDec(byte[] bytes) {
    long result = 0;
    long factor = 1;
    for (int i = 0; i < bytes.length; ++i) {
        long value = bytes[i] & 0xffl;
        result += value * factor;
        factor *= 256l;
    }
    return result;
}

private long toReversedDec(byte[] bytes) {
    long result = 0;
    long factor = 1;
    for (int i = bytes.length - 1; i >= 0; --i) {
        long value = bytes[i] & 0xffl;
        result += value * factor;
        factor *= 256l;
    }
    return result;
}`

编辑:我设法通过将 7 字节的十六进制 ID 截断为 4 字节来解决这个问题。 然后如果总长度小于 10 位,则使用此语句格式化十进制 ID,如果 DEC ID 小于 10 位,则基本上从左侧添加零:

String strFinal=String.format("%010d", Long.parseLong(str));

这份描述如何将 ID 从 HEX8 转换为 DEC10 的文档也对我有很大帮助: https ://www.batag.com/download/rfidreader/LF/RAD-A200-R00-125kHz.8H10D.EM.V1.1 。 pdf

非常感谢@Andrew 和@Karam 帮助我解决了这个问题!

我不知道你为什么总是试图转换为十进制? 请尝试解释更多有关您用于读取 UID 的代码的信息。

关于您的数字并将 17 位数字转换为 10 位数字; 我将它们都转换为十六进制:

36139312876727556(17 位)十六进制:8064837A71AD04。

2054270212(10 位)十六进制:7A71AD04

正如您所注意到的,您只需 tim 前三个字节即可获得 10 位数字。

我相信他们两个都不是 UID。 但是安德鲁所说的 7 字节,你已经在你的照片中读到了:(04:B5:71:7A:83:64:80)

所以我认为答案是,因为您将 7 字节 ID 转换为十进制,所以由于转换为十进制,您将获得可变长度的数字。

“字节数据类型是一个 8 位有符号二进制补码整数。它的最小值为 -128,最大值为 127(含)。”

来自https://docs.oracle.com/javase/tutorial/java/nutsandbolts/datatypes.html

可以生成具有 1,2 或 3 个字符的十进制数,因此作为十进制,id 的长度可以不同。

看起来转换也出错了,因为理论上它也应该有负数。

如果您希望它是人类可读的,最好将其作为十六进制字符串处理。

Java中将ID的2页转换为十六进制的正确方法是

StringBuilder Uid;
for (int i = 0; i < result.length; i++) {
                        // byte 4 is a check byte
                        if (i == 3) continue;
                        Uid.append(String.format("%02X ", result[i]));
                    }

请注意卡的规格表https://www.nxp.com/docs/en/data-sheet/MF0ICU2_SDS.pdf (第 7.3.1 节)

校验字节是 ID 的一部分,而这在同一张卡上总是相同的,并且仍然会给你一个唯一的 ID,它在技术上不是 ID 的一部分。

或者如果不是在低水平阅读,那么

https://developer.android.com/reference/android/nfc/Tag#getId()

会给你身份证。

请注意,“36139312876727556(17digit) and reversed id”在转换为十六进制和反向实际时为 7 个字节,并以正确的数字开头。

10 位数字看起来就像 7 字节数字的前 4 个字节也颠倒了。

PC上的读卡器配置错误,当卡有7字节ID时,默认将ID显示为10位十进制数(4字节)。

因此它必须丢失一些数据,它是通过将 ID 截断为 7 字节 ID 的前4个字节来实现的

使用 PC 上的软件将输出格式更改为适合 Mifare Ultralight C 卡(8 Hex?)上的 ID 大小的格式。

或者

改用 Mifare Classic 卡,因为这些卡有 4 字节 ID

或者

将代码中的 7 字节 ID 截断为 4 字节,例如将bytes.length更改为4 (对 7 字节 ID 中的前 4 个字节进行硬编码),并处理存在大量(约 1670 万) Mifare Ultralight C 卡看起来与您想要显示的“ID”相同

这是因为亚马逊卖家提供的规范https://www.amazon.co.uk/Chafon-CF-RS103-Multiple-Support-Compatible-Black/dp/B017VXVZ66 (我在制造商的网站上找不到任何详细信息)

上面写着“默认输出10位十进制,通过软件控制输出格式。”

“支持windows、linux和android系统,但只能在windows pcs中设置输出格式。无需编程和软件,即插即用。”

唯一明智的答案是移动一切以使用 7 字节 ID。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM