Solved

C# SerialPort Recieve Problem

Posted on 2010-08-30
9
2,371 Views
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)
                serialPort.Open();
            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)
            {
                serialPort.Open();
                MessageBox.Show(serialPort.ReadLine());
                serialPort.Close();
            }
            else
            {
                MessageBox.Show(serialPort.ReadLine());
            }

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?
0
Comment
Question by:IncognitoMan
  • 7
9 Comments
 
LVL 4

Expert Comment

by:ricovox
ID: 33558110
Hello,

First:
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)

Second:
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");

MessageBox.Show(serialPort.ReadLine());

Open in new window

0
 
LVL 4

Expert Comment

by:ricovox
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.
0
 
LVL 4

Expert Comment

by:ricovox
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.
0
 
LVL 1

Expert Comment

by:spm_cl
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];
                                    switch(status)
                                    {
                                     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.
0
Enabling OSINT in Activity Based Intelligence

Activity based intelligence (ABI) requires access to all available sources of data. Recorded Future allows analysts to observe structured data on the open, deep, and dark web.

 

Author Comment

by:IncognitoMan
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?
0
 
LVL 4

Expert Comment

by:ricovox
ID: 33559659
Hello,

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.
0
 
LVL 4

Accepted Solution

by:
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
0
 
LVL 4

Expert Comment

by:ricovox
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.

ie.

foreach(byte b in buf)
   System.Diagnostics.Debug.Print(b.ToString("X"));

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

Expert Comment

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

Featured Post

Enabling OSINT in Activity Based Intelligence

Activity based intelligence (ABI) requires access to all available sources of data. Recorded Future allows analysts to observe structured data on the open, deep, and dark web.

Join & Write a Comment

Suggested Solutions

We all know that functional code is the leg that any good program stands on when it comes right down to it, however, if your program lacks a good user interface your product may not have the appeal needed to keep your customers happy. This issue can…
Real-time is more about the business, not the technology. In day-to-day life, to make real-time decisions like buying or investing, business needs the latest information(e.g. Gold Rate/Stock Rate). Unlike traditional days, you need not wait for a fe…
In this seventh video of the Xpdf series, we discuss and demonstrate the PDFfonts utility, which lists all the fonts used in a PDF file. It does this via a command line interface, making it suitable for use in programs, scripts, batch files — any pl…
Get a first impression of how PRTG looks and learn how it works.   This video is a short introduction to PRTG, as an initial overview or as a quick start for new PRTG users.

708 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

Need Help in Real-Time?

Connect with top rated Experts

13 Experts available now in Live!

Get 1:1 Help Now