简体   繁体   English

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

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

I am using an Android Cilico F750 and the dedicated RFID reader is CF-RS103.我使用的是 Android Cilico F750,专用 RFID 阅读器是 CF-RS103。 The RFID tag type is MIFARE Ultralight type C. RFID 标签类型为 MIFARE Ultralight type C。

When read with a dedicated card reader the id of tag is: 2054270212(10 digit).用专用读卡器读取时,标签id为:2054270212(10位)。

But when read with Android phone the id is: 36139312876727556(17digit) and reversed id is: 1316602805183616 (16digit).但是当用 Android 手机读取时,id 是:36139312876727556(17digit),反向 id 是:1316602805183616(16digit)。

Does anyone know why this happens and if its possible to convert the 10digit id to 17digit id or vice versa.有谁知道为什么会发生这种情况,以及是否可以将 10digit id 转换为 17digit id,反之亦然。

I use intents to detect tag and to resolve intent I use this:我使用意图来检测标签并解决我使用的意图:

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);
    }}

And this are my helper functions:这是我的辅助功能:

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;
}`

EDIT: I managed to resolve this issue by truncating the 7-byte HEX ID to 4-bytes.编辑:我设法通过将 7 字节的十六进制 ID 截断为 4 字节来解决这个问题。 And then formating the decimal ID if its total lenght is less than 10 digits with this statement that basically adds zeroes from left side if DEC ID is smaller than 10 digits:然后如果总长度小于 10 位,则使用此语句格式化十进制 ID,如果 DEC ID 小于 10 位,则基本上从左侧添加零:

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

This document that describes how the ID is converted from HEX8 TO DEC10 helped me alot aswell: https://www.batag.com/download/rfidreader/LF/RAD-A200-R00-125kHz.8H10D.EM.V1.1.pdf这份描述如何将 ID 从 HEX8 转换为 DEC10 的文档也对我有很大帮助: https ://www.batag.com/download/rfidreader/LF/RAD-A200-R00-125kHz.8H10D.EM.V1.1 。 pdf

And a huge thanks to @Andrew and @Karam for helping me resolve this!非常感谢@Andrew 和@Karam 帮助我解决了这个问题!

I don't know why are you trying always to convert to decimal?我不知道你为什么总是试图转换为十进制? and please try to explain more about the code you use to read the UID.请尝试解释更多有关您用于读取 UID 的代码的信息。

about your numbers and to convert 17 digits to 10 digits;关于您的数字并将 17 位数字转换为 10 位数字; I convert both of them to Hex:我将它们都转换为十六进制:

36139312876727556(17digit) in Hex : 8064837A71AD04. 36139312876727556(17 位)十六进制:8064837A71AD04。

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

as you notice you can just tirm first three bytes to get the 10 digits.正如您所注意到的,您只需 tim 前三个字节即可获得 10 位数字。

and I do belive the both of them are not the UID.我相信他们两个都不是 UID。 but the 7bytes as sayed Andrew, and you already read it in the your photo : (04:B5:71:7A:83:64:80)但是安德鲁所说的 7 字节,你已经在你的照片中读到了:(04:B5:71:7A:83:64:80)

So I think the answer is that because you are converting a 7 byte ID to decimal you are getting variable lengths of numbers because of the conversion to decimal.所以我认为答案是,因为您将 7 字节 ID 转换为十进制,所以由于转换为十进制,您将获得可变长度的数字。

"The byte data type is an 8-bit signed two's complement integer. It has a minimum value of -128 and a maximum value of 127 (inclusive)." “字节数据类型是一个 8 位有符号二进制补码整数。它的最小值为 -128,最大值为 127(含)。”

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

Could generate a decimal number with 1,2 or 3 characters thus as decimal the id can vary in length.可以生成具有 1,2 或 3 个字符的十进制数,因此作为十进制,id 的长度可以不同。

It also looks like that conversion is going wrong as in theory it should have negative numbers in there as well.看起来转换也出错了,因为理论上它也应该有负数。

It is much better to handle it as a hex string if you want it to be human readable.如果您希望它是人类可读的,最好将其作为十六进制字符串处理。

The correct method in Java to convert the 2 pages of the ID to hex is 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]));
                    }

Note as per the spec sheet of the card https://www.nxp.com/docs/en/data-sheet/MF0ICU2_SDS.pdf (Section 7.3.1)请注意卡的规格表https://www.nxp.com/docs/en/data-sheet/MF0ICU2_SDS.pdf (第 7.3.1 节)

There is check byte that is part of the ID, while this will always be the same on the same card and will still give you a unique ID it is technically not part of the ID.校验字节是 ID 的一部分,而这在同一张卡上总是相同的,并且仍然会给你一个唯一的 ID,它在技术上不是 ID 的一部分。

Or if not reading at a low level then或者如果不是在低水平阅读,那么

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

will get you the id.会给你身份证。

Note that the "36139312876727556(17digit) and reversed id" when converted to hex and reversed actual is 7 bytes and start with the right number.请注意,“36139312876727556(17digit) and reversed id”在转换为十六进制和反向实际时为 7 个字节,并以正确的数字开头。

The 10 digit just looks like the first 4 bytes of the 7 byte number also reversed. 10 位数字看起来就像 7 字节数字的前 4 个字节也颠倒了。

The card reader on the PC is configured wrong, it is configured by default to display the ID as 10 digit decimal number (4 byte) when the card has a 7 byte ID. PC上的读卡器配置错误,当卡有7字节ID时,默认将ID显示为10位十进制数(4字节)。

It thus has to loose some data, it is doing this by truncating the ID to the first 4 bytes of the 7 byte ID因此它必须丢失一些数据,它是通过将 ID 截断为 7 字节 ID 的前4个字节来实现的

Use the software on the PC change the output format to something suitable for the ID size on the Mifare Ultralight C cards (8 Hex?)使用 PC 上的软件将输出格式更改为适合 Mifare Ultralight C 卡(8 Hex?)上的 ID 大小的格式。

or或者

Use Mifare Classic cards instead as these had 4 byte ID改用 Mifare Classic 卡,因为这些卡有 4 字节 ID

or或者

truncate the 7 byte ID to 4 bytes eg change bytes.length to 4 (a hard coding to the first 4 bytes in the 7 byte ID) in your code and handle the fact that there is a very large number (around 16.7 million) of Mifare Ultralight C cards that will seem to have the same "ID" as you want to display it将代码中的 7 字节 ID 截断为 4 字节,例如将bytes.length更改为4 (对 7 字节 ID 中的前 4 个字节进行硬编码),并处理存在大量(约 1670 万) Mifare Ultralight C 卡看起来与您想要显示的“ID”相同

This is because the spec's give by a seller on Amazon https://www.amazon.co.uk/Chafon-CF-RS103-Multiple-Support-Compatible-Black/dp/B017VXVZ66 (I cannot find any details on the manufacturer's site)这是因为亚马逊卖家提供的规范https://www.amazon.co.uk/Chafon-CF-RS103-Multiple-Support-Compatible-Black/dp/B017VXVZ66 (我在制造商的网站上找不到任何详细信息)

It says "Default output 10 digit Dec, control output format through software. "上面写着“默认输出10位十进制,通过软件控制输出格式。”

"Support with windows,linux and android system, but can only set output format in windows pcs.No programming and software required, just plug and play. " “支持windows、linux和android系统,但只能在windows pcs中设置输出格式。无需编程和软件,即插即用。”

The only sensible answer is move everything to use a 7 byte ID.唯一明智的答案是移动一切以使用 7 字节 ID。

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

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