Получите неверный серийный номер карты mifare

При использовании устройства чтения карт, которое я использую, протокол для получения серийного номера карты MIFARE выглядит следующим образом:

Антиколлизия Mifare, 0x0202:
Функциональная карта антиколлизии
Формат aa bb 05 00 00 00 02 02 00
Ответ aa bb 0a 00 52 51 02 02 00 46 ff a6 b8 a4

Где 46 ff a6 b8 — серийный номер карты в приведенном выше ответе.

Я реализую этот протокол на С# следующим образом:

private SerialPort _serialPort = new SerialPort();
private string _receivedData = null;

public MifareCardReader(string comPort, int baudRate)
{
    _serialPort = new SerialPort();
    _serialPort.PortName = comPort;
    _serialPort.BaudRate = baudRate;
    _serialPort.DataBits = 8;
    _serialPort.Parity = Parity.None;
    _serialPort.StopBits = StopBits.One;
    _serialPort.Handshake = Handshake.None;
    _serialPort.Open();   

    // Add event
    _serialPort.DataReceived += SerialPort_DataReceived;     
}

public string MifareAnticollision()
{
    if (_serialPort != null && _serialPort.IsOpen)
    {
        string message = "AABB050000000202000D";
        byte[] data = StringToByteArray(message);
        _serialPort.Write(data, 0, data.Length);
    }
}

private void SerialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
    _receivedData += _serialPort.ReadExisting();
    byte[] data = Encoding.ASCII.GetBytes(receivedData);
    if (data.Length >= 9)
    {
        if (data[8] == 0) // OK
        {
            // Response data is complete
            if (data.Length == 14)
            {
                StringBuilder hex = new StringBuilder(8);
                hex.AppendFormat("{0:X2}", data[9]);
                hex.AppendFormat("{0:X2}", data[10]);
                hex.AppendFormat("{0:X2}", data[11]);
                hex.AppendFormat("{0:X2}", data[12]);

                string cardID = hex.ToString();
                _receivedData = string.Empty;
            }
        }
        else // fail
        {
            _receivedData = string.Empty;
        }
    }
}

Я проверил это с 3 разными картами MIFARE, однако результат оказался не таким, как я ожидал:

  • Карта 1: получено: 3F463F3F, ожидается: 974682D6
  • Карта 2: получено: 3F450B3F, ожидается: EA450B91
  • Карточка 3: получено: 070D3F3F, ожидается: 070DEBD6

Что мне нужно изменить, чтобы получить правильный результат?


person Van Duoc    schedule 08.11.2015    source источник
comment
а в чем твой вопрос?   -  person Sebastian 506563    schedule 08.11.2015
comment
Я сделал в точности как в протоколе, но не получил правильный серийный номер карты. Я не знаю почему. Мой алгоритм неверен или протокол отсутствует???   -  person Van Duoc    schedule 09.11.2015
comment
Итак, у вас плохой вывод, просто дайте мне 3 примера вашего ввода в виде шестнадцатеричных значений и вывода, который вы хотите получить, и я исправлю это для вас :) Card3: 070D3F3F - плохой вывод? или это ввод?   -  person Sebastian 506563    schedule 09.11.2015
comment
С чем вы разговариваете через последовательный порт?   -  person vlp    schedule 10.11.2015
comment
Если это этот ридер. Почему вы не используете комбинированную команду Mifare S50 select a card (запрос + антиколлизия + выбор) 0x0200? У меня нет опыта работы с этим конкретным ридером, но обычно REQA (в вашем случае команда 0x0201) должна предшествовать CL1 (в вашем случае команда 0x0202).   -  person vlp    schedule 10.11.2015


Ответы (1)


Проблема, с которой вы столкнулись, заключается в том, что байты со значением выше 0x7F заменены на 0x3F (символ вопросительного знака ("?")). т.е. только 7-битные значения отображаются правильно, а значения с 8-м битом превращаются в "?" (0x3F). Например. для карты 1 974682D6 "получается" как 3F463F3F, потому что 0x97, 0x82 и 0xD6 имеют установленный 8-й бит.

Источником этой проблемы является то, что вы используете метод ReadExisting() для чтения строкового значения из последовательного порта. По умолчанию ReadExisting() считывает байты из последовательного порта, переводит их с использованием кодировки ASCII (System.Text.ASCIIEncoding) и возвращает результирующую строку. Затем вы берете эту строку и преобразуете ее обратно в массив байтов (снова используя кодировку ASCII).

Проблемными шагами являются преобразования с использованием System.Text.ASCIIEncoding/Encoding.ASCII. В документации говорится :

Поскольку ASCII является 7-битной кодировкой, символы ASCII ограничены младшими 128 символами Unicode, от U+0000 до U+007F. [...] символы за пределами этого диапазона заменяются вопросительным знаком (?) перед выполнением операции кодирования.

Следовательно, вы должны считывать байты непосредственно в массив байтов, используя методы Read() или ReadByte(). Например. с участием

byte[] buffer = new byte[_serialPort.ReadBufferSize];
int bytesRead = _serialPort.Read(buffer, 0, buffer.Length);
person Michael Roland    schedule 19.11.2015