Search code examples
c#serial-portmagnetic-cards

MSR206 Magstripe serial port communication


I'm porting a legacy application from vb6 to c#, using serial port communication with a MSR206 Magstripe reader/writer. I can reset, connect, flash lights, read and write to the device successfully in both applications, and, verify the data being read/written with the EZWriter software that came with the MSR206.

However, I am having problems reconciling the programmers manual with the data being received over the serial port.

The legacy application treats any response with the byte value / ASCII code 94 ^, as an ACK. However, the user manual doesn't mention this as a valid response code. Also, I thought the ASCII code 6 is an ACK. Either way, if I treat this character as a "Success", everything works.

When I try to perform an operation, such initialisation, I only receive this one character as the response, and not what output the manual says.

e.g.

"8.1 MSR 206 INITIALIZATION

Command code: < ESC > a (Reset)

Command code: < ESC > e (Serial port test)

Response : Command test ACK: < ESC >y

Command code: < ESC > a (Reset)"

When running the initialisation, I'd expect byte[2] {27, 121} (< ESC >, y) as a response. Instead, I get:

Send: byte[2] {27, 97} (< ESC >, a)
Receive: byte[1] {94} (^)

Send: byte[2] {27, 101} (< ESC >, e)
Receive: byte[1] {94} (^)

Send: byte[2] {27, 97} (< ESC >, a)
Receive: byte[1] {94} (^)

If I try to return the firmware version:

  1. Command: Get firmware version

Command code: < ESC > v

Response: < ESC > [version]

Description: This command can get the firmware version of MSR206.
* [version] is a 5 bytes version number, format is “ REV?X.XX “

MSR206? = 0 MSR206HC? = H MSR206HL? = U

I only receive the ^, and a ?.

Send: byte[2] {27, 118} (< ESC >, v)
Receive: byte[2] {94, 161} (^, ?)

Sample code:

using System;
using System.IO.Ports;
using System.Text;
using System.Threading;

public class MSR206Test
{
    static bool _continue;
    static SerialPort _serialPort;

    public static void Main()
    {
        string message;
        StringComparer stringComparer = StringComparer.OrdinalIgnoreCase;
        _serialPort = new SerialPort("COM7", 9600, Parity.None, 8, StopBits.One);
        _serialPort.DataReceived += new SerialDataReceivedEventHandler(port_DataReceived);
        _serialPort.Open();
        _continue = true;
        Console.WriteLine("Type Command 1 to 6 or QUIT to exit");
        while (_continue)
        {
            message = Console.ReadLine();
            if (stringComparer.Equals("quit", message))
            {
                _continue = false;
            }
            else
            {
                switch (message)
                {
                    case "1":
                        Console.WriteLine("Send ESC > reset");
                        _serialPort.Write(new byte[] { 27, 97 }, 0, 2);

                        break;
                    case "2":
                        Console.WriteLine("2 Sending ESC > firmware version)");
                        _serialPort.Write(new byte[] { 27,   118 }, 0, 2);
                        break;
                    case "3":
                        Console.WriteLine("3 Sending ESC > Serial port test)");
                        _serialPort.Write(new byte[] { 27,   101 }, 0, 2);
                        break;
                    case "4":
                        Console.WriteLine("4 Sending ESC > ram test)");
                        _serialPort.Write(new byte[] { 27, 87 }, 0, 2);
                        break;
                    case "5":
                        Console.WriteLine("5 Sending ESC >  del)");
                        _serialPort.Write(new byte[] { 27, 127 }, 0, 2);
                        break;
                    case "6":
                        Console.WriteLine("6 ESC > flash)");
                        _serialPort.Write(new byte[] { 27, 40 }, 0, 2);
                        break; 
                }
            }
        }

        _serialPort.Close();
    }

    public static void port_DataReceived(object sender, SerialDataReceivedEventArgs e)
    {
        var bytes = _serialPort.BytesToRead;
        var buffer = new byte[bytes];
        _serialPort.Read(buffer, 0, _serialPort.BytesToRead);
        for(var i = 0; i < buffer.Length; i++)
        {
            Console.WriteLine($"Response index ({i}) : " + buffer[i]); 
        }
        var data = Encoding.ASCII.GetString(buffer);
        Console.WriteLine($"Response ({buffer.Length}) : " + data); 
    }
}

I must be missing something simple, as I can encode and decode cards, I just cannot make sense on what's going on / why the output doesn't match the manual?


Solution

  • It's a device age issue, it doesn't look like the firmware on this model supports these commands. I've used a new magstripe and it functions as per the manual. I've reached out to the manufacturer for a device manual that matches this revision firmware.