Reputation: 65
With the card reader I'm using, the protocol to retrieve the serial number of a MIFARE card is as follows:
Mifare anticollision,
0x0202
:
Function card anticollision
Formataa bb 05 00 00 00 02 02 00
Responseaa bb 0a 00 52 51 02 02 00 46 ff a6 b8 a4
Where 46 ff a6 b8
is the card serial number in the above response.
I implement this protocol in C# as follows:
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;
}
}
}
I tested this with 3 different MIFARE cards, however, the output is not what I expected:
3F463F3F
, expected: 974682D6
3F450B3F
, expected: EA450B91
070D3F3F
, expected: 070DEBD6
What do I need to change to get the correct output?
Upvotes: 0
Views: 1738
Reputation: 40831
The problem that you are experiencing seems to be that bytes with a value above 0x7F
replaced with 0x3F
(the question mark ("?") character). I.e. only 7-bit values show correctly and values with the 8th bit set are turned into "?" (0x3F
). E.g. for card 1, 974682D6
is "received" as 3F463F3F
, because 0x97
, 0x82
, and 0xD6
have their 8th bit set.
The source for this problem is that you are using the ReadExisting()
method to read a string value from the serial port. By default, the ReadExisting()
reads bytes from the serial port, translates them using the ASCII encoding (System.Text.ASCIIEncoding
), and returns the resulting string. You then take that string and convert it back to a byte array (again using the ASCII encoding).
The problematic steps are the conversions using System.Text.ASCIIEncoding
/Encoding.ASCII
. The documentation says:
Because ASCII is a 7-bit encoding, ASCII characters are limited to the lowest 128 Unicode characters, from U+0000 to U+007F. [...] characters outside that range are replaced with a question mark (?) before the encoding operation is performed.
Consequently, you should read the bytes directly into a byte array using the Read()
or ReadByte()
methods. E.g. with
byte[] buffer = new byte[_serialPort.ReadBufferSize];
int bytesRead = _serialPort.Read(buffer, 0, buffer.Length);
Upvotes: 1