簡體   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