C# SerialPort Recieve Problem

Posted on 2010-08-30
Last Modified: 2013-12-17
Hello guys,
I have a cash register and I communicate with it on a low level. So, the idea is the following. The fiscal printer has got fiscal memory. IN this memory it records everything you've sold. But before I make a sale I want to check if this memory is full, cos I'll have problems with registring the sale. How do I do this? By sending a request that return something and with this something the state of the printer. So I write the following funcion that sends data.

FiscalPrinters.DatecsFP1000 fiscal = new FiscalPrinters.DatecsFP1000();
            if(serialPort.IsOpen == false)
            fiscal.izpratiKomanda(0x3E, 0x20);
            serialPort.Write(fiscal.izpratiKomanda(0x3E, 0x20), 0, fiscal.izpratiKomanda(0x3E, 0x20).Length);

I leave the port opened to recieve the data. I use a program to monitor the communication. The data sended is:
01 24 20 3E 05 30 30 38 37 03  in HEX
The recieved data is:
01 3C 20 3E 33 30 2D 30 38 2D 31 30 20 30 39 3A
35 38 3A 32 30 04 88 80 C0 86 86 92 05 30 37 35   in Hex
3B 03

and in string 30-08-10 it gives me the date. Which means everything in the sent command is OK :).
So, to read this line, which contains a control bit, that says is there free memory in the printer, I've written the following functuin attaced to a SerialPort DataRecieved event.

if (!serialPort.IsOpen)

But the event eider doesn't trigger, or throws the following exception:
The I/O operation has been aborted because of either a thread exit or an application request.

What am I doing wrong?
Question by:IncognitoMan
  • 7

Expert Comment

ID: 33558110

The ReadLine() function will wait (freezing your program) until some data is received and is terminated by CrLf (carriage return line feed). Are you sure that the printer responses are terminated with CrLf? I don't see them in the data that you said is sent back. (Hex values are 13, 10, respectively)

Make sure you do not close the serial port an ANY time after you send the data or any time before you read the response. Just to make sure you don't close it, you should use this code instead of the one you posted above:

(In DataReceived event handler)

if (!serialPort.IsOpen)
   throw new Exception("Serial Port is not Open");

Open in new window


Expert Comment

ID: 33558130
If the device doesn't send CrLf, then you can just use Read() instead, and specify the number of bytes to read. You will know which method to use by looking at the protocol for the device, which should tell you whether or not CrLf is used.

Expert Comment

ID: 33558193
What this means, almost certainly, is that the SerialPort object attempted to complete the call to ReadLine after the port was been closed.  

This can happen because of the lack of synchronization between UI events which may cause the port to close, and the background thread in the SerialPort object that is performing the actual ReadFile operation (this executes as a result of ReadLine in your delegate).

The problem with ReadLine, and the reason that you way not want to use it, is that it blocks (i.e. freezes your program) until the the line terminating condition occurs (CrLf) -- this may be AFTER you have closed the port.  Thus the exception.

You could simply use ReadExisting () and buffer the data in byte[] variable and test the buffer for the CrLf terminating characters.  
Remember to clear this buffer AFTER you have processed and displayed its content.  If you do this, the exception should be resolved.
DevOps Toolchain Recommendations

Read this Gartner Research Note and discover how your IT organization can automate and optimize DevOps processes using a toolchain architecture.


Expert Comment

ID: 33558639
1.- As stated before, binary data cannot be handled with the ReadLine command. Looking at your response data there is no CrLf to indicate end of string so I would not expect ReadLine to do anything sensible.
2.- I cannot see where you initialise the serial port parameters. These have to be set the same way as the printer. You need to do something like this for 8 bit clear comms:
            serialPort = new SerialPort("COM1");
            serialPort.BaudRate = 9600;
            serialPort.DataBits = 8;
            serialPort.Parity = Parity.Even;
            serialPort.HandShake = Handshake.None;
3.- Use the Read function and the set up a state machine to handle the data. Given that this is a syncrhonous request/response protocol it is quite easy to handle. You need to do something like this:
            serialPort.Write(command, command.Length())
            int status=1
            while(status > 0)
                        byte[] buffer = new buffer[256];
                        int bytes = serialPort.Read(buffer, 256)
                        int byte;
                        for (byte=0;byte < bytes;byte++)
                                    byte b = buffer[byte];
                                     case 1:
                                                if (b == ????)

I can't help you much more with the state machine as I do not know the protocol that this particular printer uses.

Author Comment

ID: 33559376
Strange, very strange. Your method worked. It did solve the exception. So what I did was, I read the data, and then convert the string into a byte array.
string str = serialPort.ReadExisting();
                byte[] data = new byte[str.Length];
                data = System.Text.ASCIIEncoding.ASCII.GetBytes(str);

But using a Serial Port monitoring program, I saw that the device is returning the folloing:
01 3C 20 3E 33 30 2D 30 38 2D 31 30 20 31 38 3A
30 33 3A 30 39 04 88 80 C0 86 86 92 05 30 37 35   (HEX)
38 03

And the contents ot the byte array are:

01 66 32 63 51 48 45 48 56 45 49 48 32 49 56 58
48 51 58 48 57 04 63 63 63 63 63 63 05 48 55 53    (DEC)
56 03

The information that I want to read is between the 04 and 05 bytes on the second line. But in the port monitoring program they are 88 80 C0 86 86 92, which is exactly what should be returned, and the byte array in the program has got 63 63 63 63 63 63 which is totolly wrong. It cant return this :).
Maybo the problem is that I convert the string into byte array. But is there a way to read this message from the device and but it derectly into a byte array?

Expert Comment

ID: 33559659

That is strange indeed.
Yes, I would recommend you switch to using the Read(byte[], int) method so that you read the bytes directly without converting to a string.

You can use the "BytesToRead" property to get the length of the buffer you need.
Something like this:

int count = serialPort.BytesToRead;
byte[] buf = new byte[count];
serialPort.Read(buf, count);
//now buf contains the bytes that were read.

Here is a more abbreviated version:
byte[] buf = new byte[serialPort.BytesToRead];
serialPort.Read(buf, buf.Length);

Let me know how that goes.

Accepted Solution

ricovox earned 500 total points
ID: 33559695
oops, I made a mistake.

the Read method takes three parameters: Read(buffer, start, length)
so it should be
Read(buf, 0, count) or Read(buf, 0, buf.Length) in the above example code

Expert Comment

ID: 33559793
If it turns out that you are still getting invalid data, perhaps you could write a small utility to convert the bytes you receive from DEC to HEX, and that might help clarify things.


foreach(byte b in buf)

That way you can directly compare the output in C# to that in your port monitoring program

Expert Comment

ID: 33559803
P.S. Better use "PrintLine" or Print(b.ToString("X") + " ");
so the numbers won't all run together.

Featured Post

Master Your Team's Linux and Cloud Stack!

The average business loses $13.5M per year to ineffective training (per 1,000 employees). Keep ahead of the competition and combine in-person quality with online cost and flexibility by training with Linux Academy.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

Introduction Hi all and welcome to my first article on Experts Exchange. A while ago, someone asked me if i could do some tutorials on object oriented programming. I decided to do them on C#. Now you may ask me, why's that? Well, one of the re…
A long time ago (May 2011), I have written an article showing you how to create a DLL using Visual Studio 2005 to be hosted in SQL Server 2005. That was valid at that time and it is still valid if you are still using these versions. You can still re…
In a recent question ( here at Experts Exchange, a member asked how to add page numbers to a PDF file using Adobe Acrobat XI Pro. This short video Micro Tutorial sh…
Finds all prime numbers in a range requested and places them in a public primes() array. I've demostrated a template size of 30 (2 * 3 * 5) but larger templates can be built such 210  (2 * 3 * 5 * 7) or 2310  (2 * 3 * 5 * 7 * 11). The larger templa…

831 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question