serial port communication with POS from .NET
-
04-03-2021 - |
Question
I am trying to communicate with a cash register through the serial port from a C# app I am building and I have a small utility provided from the manufacturer which gives me some info about the device like firmware version etc.
In the protocol specification it states that communication begins with the "ENQ" ASCII control (0x05h) code on the sender end, to which the receiver must respond "ACK"(0x06h). Then a request packet can be sent that contains a command etc.
Connection settings:
- Baud rate: 9600 baud
- Parity: none
- Data: 8
- Stop: 1
- Flow control: none
Transmission:
Sender Receiver
Idle
Idle
Enquire
Acknowledge
Packet
Acknowledge
The packet structure is the following (STX = 0x02h , ETX = 0x03h):
+-----+--------- - - -+-----+
| STX | Data | ETX |
+-----+--------- - - -+-----+
Fields in data section are separated with '/':
+--------++---------+---------+---------+- - - +---------++----------+
| Header || Field 1 / Field 2 / .... / Field N || Checksum |
+--------++---------+---------+---------+- - - +---------++-
Sender/Receiver states:
Sender Receiver
---------------------------------------------------
IDLE IDLE
ENQUIRE --------------------->
<--------------------- ACKNOWLEDGE
PACKET ---------------------> (verify error)
<--------------------- NOT ACKNOWLEDGE
PACKET ---------------------> (verify error)
<--------------------- NOT ACKNOWLEDGE
PACKET ---------------------> (verify success)
<--------------------- ACKNOWLEDGE
.
.
(Rest of packet exchange)
---------------------------------------------------
So I try to communicate and I get nothing back. I downloaded a serial port sniffer, run the manufacturers utility and pressed the "get device version" button. I got:
# Time Port Data ASCII
000001 20:03:06.484 COM2 << 18 18 18 05 ....
000002 20:03:06.500 COM2 >> 06 06 ..
000003 20:03:06.500 COM2 << 02 76 2F 36 35 03 .v/65.
000004 20:03:06.515 COM2 >> 02 30 30 2F 30 30 2F 30 32 2F 31 2E 30 31 2F 31 .00/00/02/1.01/1
000005 2E 30 31 2F 20 35 38 2F 35 30 30 30 2F 31 34 30 .01/ 58/5000/140
000006 2F 32 30 2F 31 30 2F 31 30 2F 20 36 2F 20 35 2F /20/10/10/ 6/ 5/
000007 33 30 2F 37 37 03 30/77.
000008 20:03:06.515 COM2 << 06 .
000009 20:03:07.015 COM2 >> 06 .
000010 20:03:07.015 COM2 << 18 18 18 05 02 61 2F 34 34 03 .....a/44.
000011 20:03:07.015 COM2 >> 06 02 30 30 2F 30 30 2F 30 32 2F 30 37 30 30 33 ..00/00/02/07003
000012 36 34 35 2F 31 2F CD D0 20 2F 44 4C 38 30 4C 49 645/1/ΞΞ /DL80LI
000013 56 31 52 31 35 20 20 20 20 20 2F 39 34 03 V1R15 /94.
000014 20:03:07.015 COM2 << 06 .
000015 20:03:07.515 COM2 >> 06 06 02 30 30 2F 30 30 2F 30 32 2F 31 38 31 31 ...00/00/02/1811
000016 31 31 11
000017 20:03:07.515 COM2 << 18 18 18 05 02 74 2F 36 33 03 .....t/63.
000018 20:03:07.531 COM2 >> 2F 31 39 32 30 30 39 2F 31 31 03 /192009/11.
000019 20:03:07.531 COM2 << 06 .
**********(ENQ = 05, ACK = 06, STX = 02 , ETX = 03, CAN = 18, '/' = 2F)
The code:
public partial class Form1 : Form
{
// Add this variable
string RxString;
public Form1()
{
InitializeComponent();
}
private void buttonStart_Click(object sender, EventArgs e)
{
serialPort1.PortName = "COM2";
serialPort1.BaudRate = 9600;
serialPort1.DataBits = 8;
serialPort1.Parity = System.IO.Ports.Parity.None;
serialPort1.StopBits = System.IO.Ports.StopBits.One;
serialPort1.DtrEnable = true;
serialPort1.RtsEnable = true;
try
{
serialPort1.Open();
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
if (serialPort1.IsOpen)
{
buttonStart.Enabled = false;
buttonStop.Enabled = true;
textBox1.ReadOnly = false;
}
}
private void buttonStop_Click(object sender, EventArgs e)
{
if (serialPort1.IsOpen)
{
serialPort1.Close();
buttonStart.Enabled = true;
buttonStop.Enabled = false;
textBox1.ReadOnly = true;
}
}
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
if (serialPort1.IsOpen) serialPort1.Close();
}
private void textBox1_KeyPress(object sender, KeyPressEventArgs e)
{
// If the port is closed, don't try to send a character.
if (!serialPort1.IsOpen) return;
// If the port is Open, declare a char[] array with one element.
char[] buff = new char[1];
// Load element 0 with the key character.
buff[0] = e.KeyChar;
// Send the one character buffer.
serialPort1.Write(buff, 0, 1);
// Set the KeyPress event as handled so the character won't
// display locally. If you want it to display, omit the next line.
e.Handled = true;
}
private void DisplayText(object sender, EventArgs e)
{
textBox1.AppendText(RxString);
}
private void serialPort1_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
{
RxString = serialPort1.ReadExisting();
this.Invoke(new EventHandler(DisplayText));
}
private void buttonENQ_Click(object sender, EventArgs e)
{
// If the port is closed, don't try to send a character.
if (!serialPort1.IsOpen) return;
byte[] Buff = new byte[4];
Buff[0] = 0x18;
Buff[1] = 0x18;
Buff[2] = 0x18;
Buff[3] = 0x05;
serialPort1.Write(Buff, 0, 4);
}
}
I managed to send the commands from my app and logged the communication (18 18 18 05 is being sent) but I get no response at all from the register. Everything I send seems correct. Any ideas? Am I missing something stupid?
Solution
Ok I 've got it. I found an older version of the communication protocol where it says: - Baud rate: 9600/115200 baud . So I changed the baudrate to 115200 and it worked. This is stupid.