MSR206 Magstripe serial port communication - c#

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:
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?

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.

Related

C# TCP/IP message is being changed

I am writing my program in Microsoft Visual Studio 2013 professional C#. I used the debugger and I looked at my array called Message3 and it has the right information, but when it gets to the connected computer modbus program, the message is different. So I used Wireshark and wireshark agrees with the Modbus program. It is weird because it only does it for some values
like the value 7600 in modbus it is sent out in two registers as 29 and 176 and my program has that in the array but wireshark is seeing 29 194 176.
it somehow added a 194 that was not in my array.
[0] 0 '\0' char
[1] 4 '' char
[2] 0 '\0' char
[3] 0 '\0' char
[4] 0 '\0' char
[5] 5 '' char
[6] 1 '' char
[7] 3 '' char
[8] 2 '' char
[9] 29 '' char
[10] 176 '°' char
that is what my debugger has and this is what wire shark see:
0 4 0 0 0 6 1 3 0 5 0 1 03 02 1d c2 b0
I have tried both: writer.Flush and writer.FlushAsync but nothing helps.
again it is only some values it does this too.
here is my code :
void Listener_function()
{
IPHostEntry host;
string localIP = "?";
host = Dns.GetHostEntry(Dns.GetHostName());
listener = null;
try
{
listener = new TcpListener(IPAddress.Parse(Moxa_IPtxt.Text), Convert.ToInt16(modemPorttxt.Text));
listener.Start();
// ErrorBox.Text = " EchoServer started ... /n";
connect_flag = true;
MessageBox.Show(" waiting for incoming client connections.../n /r");
client = listener.AcceptTcpClient();
MessageBox.Show(" Accepted new client coneection ...");
StreamReader reader = new StreamReader(client.GetStream());
StreamWriter writer = new StreamWriter(client.GetStream());
while (true)
{
string s = string.Empty;
char[] temp = new char[12];
int s1 = reader.Read(temp, 0, 12);
int Registers_number = (((int)temp[10] << 8) + (int)temp[11]);
int Message_Size = (Registers_number * 2) + 9;
char[] Message3 = new char[Message_Size];
TCPProcessing(temp, Message3);
if (writeData == true)
{
writer.Write(Message3);
// writer.Flush();
writer.FlushAsync();
}
}
}
catch (Exception e)
{
MessageBox.Show(e.ToString());
//button1.Text = "Connect";
//ErrorBox.Text = e.ToString();
}
finally
{
if (listener != null)
{
listener.Stop();
}
}
}
any ideas ?
again I had a breakpoint at the } after FlushAsync and I copy what message has and it does not have a 194 ( Please see above)
Brandon, you don't seem to read carefully what I wrote .
don't use StreamReader/StreamWriter which are for text operations. Use directly client.GetStream
Here is a code to show you
var m = new MemoryStream();
var wr = new StreamWriter(m);
wr.Write(new char[] { (char)29, (char)176 }, 0, 2);
wr.Flush();
var bytes2 = m.ToArray();
content of bytes2 is: 29,194,176 as in your case. So I repeat, use client.GetStream, not StreamReader/StreamWriter

How to send numbers from C# to Arduino Uno with a usb port?

I want to send integer numbers (between 101 and 1616)from the c# program to the arduino Uno using a usb port.
I know how to use registers of the arduino Uno and wanted to know if there is a interrupt when reviving data over this USB port.
At the moment I am using this but it isn't working.
if(Serial.available()!=0)
{
input= (unsigned char)Serial.read();
}
And on the C# program I am using this code:
byte[] b = BitConverter.GetBytes(MyIntx);
SerialPort.Write(b, 0, 4);
How can i send bigger numbers between the c# program and the arduino uno?
And is there a special interrupt for receiving these type of numbers?
What you need to do is send byte by byte. There are complex solutions and there are easy ones
Complex: from https://www.baldengineer.com/arduino-multi-digit-integers.html
void setup() {
Serial.begin(9600);
}
unsigned int integerValue=0; // Max value is 65535
char incomingByte;
void loop() {
if (Serial.available() > 0) { // something came across serial
integerValue = 0; // throw away previous integerValue
while(1) { // force into a loop until 'n' is received
incomingByte = Serial.read();
if (incomingByte == '\n') break; // exit the while(1), we're done receiving
if (incomingByte == -1) continue; // if no characters are in the buffer read() returns -1
integerValue *= 10; // shift left 1 decimal place
// convert ASCII to integer, add, and shift left 1 decimal place
integerValue = ((incomingByte - 48) + integerValue);
}
Serial.println(integerValue); // Do something with the value
}
}
My Version:
Convert Int to Char, Send byte by byte and In Arduino Convert it back to Int.
int x=150;
string x_char = x.ToString();
for(int i=0;i<x_char.length();i++)
{
//Send Each Character to Arduino "c_char[i]".
}
//Send a new line or any special character to mark the break. For Instance "\n";
IN Arduino:
String a;
void setup() {
Serial.begin(9600); // opens serial port, sets data rate to 9600 bps
}
void loop() {
while(Serial.available()) {
a= Serial.readStringUntil('\n'); //Read until new line
x = Serial.parseInt(); //This is your Integer value
}
}
Connect();
if (serialPort1.IsOpen)
{
int MyInt = ToInt32(lblMixerCase.Text);
byte[] b = GetBytes(MyInt);
serialPort1.Write(b, 0, 1);
int MyInt2 = ToInt32(txtRPM.Text);
if (MyInt2<=255)
{
byte[] z = GetBytes(MyInt2);
serialPort1.Write(z, 0, 1); //For first 1 byte numbers
}
else if (MyInt2<=510)
{
byte[] r = GetBytes(MyInt2);
serialPort1.Write(r, 0, 2); for 2 byte numbers
}
else if (MyInt2<=765)
{
byte[] a = GetBytes(MyInt2);
serialPort1.Write(a, 0, 3); //for 3 byte numbers
}
else if (MyInt2<=1020)
{
byte[] q = GetBytes(MyInt2);
serialPort1.Write(q, 0, 4); //for 4 byte numbers
}

C# how to send & receive from a hardware protocol?

I'm a C# programmer and I know nothing about hardware protocol things.
today I received a document that is some protocols of a Lock hardware, like this:
lock command
start 0x80
board address 0x01-0xf
lock address 0x00-18
command 0x33
verify code XX
sample:
machine send 0x80 0x01 0x01 0x33 0xB2
if recieve 0x80 0x01 0x01 0x01 0x91 (means unlock)
if receive 0x80 0x01 0x01 0x00 0x80 (means locked)
All I want to know is, if C# can handle these commands? if can, where I can have a quick start, or what should I search on google?
Thanks.
Yes. C# can handle this. This is call polling. Basically, the idea is
send command, receive reply, substring information that you need (in your case, most probably the last 2 bytes) and perform some function on it. I'm not sure if you understand but I'll give you an example on something I've done previously but this is event where data is send to machine whenever event is triggered.
public enum Transaction
{
LOCK = 0x01,
UNLOCK
};
private static string getTransactionDescription(Transaction transaction, string data = "")
{
string result = "";
switch (transaction)
{
case Transaction.UNLOCK:
case Transaction.LOCK:
var slot = ByteOperation.reverse4ByteBitPattern(data.Substring(32, 64));
for (int i = 8 - 1; i >= 0; i--)
{
for (int j = 0; j < 8; j++)
{
if ((Convert.ToInt32(ByteOperation.ToggleEndian_4Bytes(slot.Substring(i * 8, 8)), 16) & (1 << j)) > 0)
{
if (!string.IsNullOrWhiteSpace(result))
{
result += ", ";
}
result += "Slot " + (((7 - i) * 8) + j + 1).ToString("D3");
}
}
}
break;
}
return result;

c# how to count amount of data received in data receive handler?

I am receiving data (in byte) from serial port, and now I want to write a if else in the data receive handler.
If(condition)
{}
else
{}
condition for if is: number of bytes received / 8 = interger.
For example, I received 16 bytes of data, so 16/2=8, is an integer. I received 20 bytes of data, 20/8=2.5, it s not an integer.
private void DataReceivedHandler(object sender, SerialDataReceivedEventArgs e)
{
byte[] b = new byte[800];
int Received;
SerialPort sp = (SerialPort)sender;
if (condition)
{
MessageBox.Show(" Transmission error!");
}
else
{
Received = sp.Read(b,0,8);
if (Received < 8)
return;
float f11 = BitConverter.ToSingle(b, 0);
float f22 = BitConverter.ToSingle(b, 4);
Invoke(new Action(() =>
{
textBox3.Text += f11.ToString() + " "+f22.ToString()+"\r\n";
//MessageBox.Show(" New Message Received!");
}));
Received = 0;
}
}
You can use % operator:
if (number_of_bytes_received % 8 == 0)

Sending standard input to Arduino C#

I am trying to take the standard input from the console and send it to my Arduino Uno as plain ASCII.
I get the Input and strip \r\n from it using this code:
String Input = Console.Read().ToString().Replace("\r",string.Empty).Replace("\n",string.Empty);
When I perform doConsole.WriteLine(Input);, it outputs "72" which is correct, but when I do serialPort.Write(Input); the Arduino returns "55", which it does for everything.
What am I doing wrong?
My code for the C# side (host/PC):
String Input = Console.Read().ToString().Replace("\r", string.Empty).Replace("\n",string.Empty);
//Console.WriteLine(Input);
//serialPort.Write(Input);
char[] InputChar = Input.ToCharArray();
serialPort.Write(InputChar,0,1);
//byte[] InputByte = Encoding.ASCII.GetBytes(Input);
//Console.WriteLine(Input);
//serialPort.WriteLine(Input);
Thread.Sleep(25); //Wait 0.025 second.
//***************************************************************//
// Read anything from the serial port. //
//***************************************************************//
numBytes = serialPort.BytesToRead;
for (int i = 0; i < numBytes; i++)
rxPacket[i] = (byte)serialPort.ReadByte();
result = new char[numBytes];
for (int i = 0; i < numBytes; i++)
result[i] = (char)rxPacket[i];
Console.Write("Read this from Arduino:");
Console.WriteLine(result);
Console.WriteLine("press Enter to continue");
Console.ReadKey(); //Read nothing.
And my Arduino sketch:
const int ledPin = 13; // The pin that the LED is attached to.
int incomingByte; // A variable to read incoming serial data into.
void setup() {
// Initialize serial communication:
Serial.begin(9600);
// Initialize the LED pin as an output:
pinMode(ledPin, OUTPUT);
}
void loop() {
// see if there's incoming serial data:
if (Serial.available() > 0) {
// Read the oldest byte in the serial buffer:
incomingByte = Serial.read();
// If it's a capital H (ASCII 72), turn on the LED:
if (incomingByte == 'H') {
digitalWrite(ledPin, HIGH);
Serial.print(incomingByte);
}
// If it's an L (ASCII 76), turn off the LED:
else if (incomingByte == 'L') {
digitalWrite(ledPin, LOW);
Serial.print(incomingByte);
}
else{
Serial.print(incomingByte);
}
}
}
Edit: changed the code to the following. Still no luck; I am getting same reply.
String Input = Console.Read().ToString().Replace("\r",string.Empty).Replace("\n",string.Empty);
Console.Write(Input,0,1);
//serialPort.Write(Input);
byte[] inputByte = Encoding.ASCII.GetBytes(Input);
serialPort.Write(inputByte,0,1);
Well, I looked it up... As it turns out, ASCII code 55 = 7.
7 is the first digit of 72.
Hmm, so perhaps your sending decimal numbers to the Arduino here and the Arduino sees a 7 first. May I suggest to convert your byte and send it as a byte (a byte can only contain 0..255), but it is a single ASCII code.
Maybe for the Arduino to think about, but maybe it is not related to this. Instead of
int incomingByte; // ints are made of 2 bytes an int isn't an incomming byte
try
Byte incomingByte;
So I managed to get it working
Basically, converting it to a byte took me a while to work out.
this is the code I ended up with
String Input = Console.Read().ToString().Replace("\r", string.Empty).Replace("\n",string.Empty);
Console.Write(Input,0,1);
byte[] inputByte = new byte[1];
inputByte[0] = Convert.ToByte(Input);
serialPort.Write(inputByte, 0, 1);
//byte[] inputByte = Encoding.ASCII.GetBytes(Input);
//serialPort.Write(inputByte,0,2);
//String num = inputByte.ToString();
//serialPort.WriteLine(num);
//Console.WriteLine(Input);
//serialPort.Write(InputByte,0,1);
Thread.Sleep(25); //Wait 0.025 second.
//***************************************************************//
// Read anything from the serial port. //
//***************************************************************//
numBytes = serialPort.BytesToRead;
for (int i = 0; i < numBytes; i++)
rxPacket[i] = (byte)serialPort.ReadByte();
result = new char[numBytes];
for (int i = 0; i < numBytes; i++)
result[i] = (char)rxPacket[i];
Console.Write("Read this from Arduino:");
Console.WriteLine(result);
Console.WriteLine("press Enter to continue");
Console.ReadKey(); //Read nothing.
Seems to work Perfectly now.

Categories

Resources