SerialPort and SerialDataReceivedEventHandler help

K

Kevin.M.Jonas

I have the following method that handles the data received event:
private void _port_DataReceived(object sender,
SerialDataReceivedEventArgs e)
{
string data = _port.ReadExisting();
_log.LogToFile(data, true);
}

The LogToFile function logs data to a file. The second parameter
indicate if the file should timestamp the message.

On the initial test of this method I got the following result:
[9/19/2008 4:40:04 PM]10??I 1
[9/19/2008 4:40:04 PM] 1909081
[9/19/2008 4:40:04 PM]640?

This is not what I expected. I converting an old VB 6.0 program to
C#. If I add Thread.Sleep(500) before the ReadExisting() I get the
string I was expecting:
[9/19/2008 4:57:47 PM]10??I 1 1909081657?

Notice in the first try it is sending 8 bytes at a time. Is there
anyway to avoid using Thread.Sleep to achieve this?
 
S

Stefan Hoffmann

hi Kevin,

On the initial test of this method I got the following result:
[9/19/2008 4:40:04 PM]10??I 1
[9/19/2008 4:40:04 PM] 1909081
[9/19/2008 4:40:04 PM]640?

This is not what I expected. I converting an old VB 6.0 program to
C#. If I add Thread.Sleep(500) before the ReadExisting() I get the
string I was expecting:
[9/19/2008 4:57:47 PM]10??I 1 1909081657?
The first result looks good. I don't know, what device you are querying,
but your string has obviously an explicit start and end symbol. Just
read it in a loop as long as your string is not complete.


mfG
--> stefan <--
 
S

Stefan Hoffmann

hi,

Stefan said:
The first result looks good. I don't know, what device you are querying,
but your string has obviously an explicit start and end symbol. Just
read it in a loop as long as your string is not complete.
Better than a loop (i'm using <> as start/end tags):

private string _Data = null;
private void _port_DataReceived(object sender,
SerialDataReceivedEventArgs e)
{
string data = _port.ReadExisting();

if (_Data == null && data.StartsWith("<"))
{
_Data = data;
data = null;
}
if (_Data != null && data != null)
_Data += data;
if (_Data != null)
if (_Data.EndsWith(">"))
{
_log.LogToFile(_Data, true);
_Data = null;
}
}

Depending on the kind of device, you must consider that you get strings
like "789><123897"


mfG
--> stefan <--
 
K

Kevin.M.Jonas

I tried that. There is still only 8 bytes available at a time. The
only solution I have found so far is to add the sleep. I don't want
to do that because then I have to make the sleep long enough to get
the larger messages but not so large any timeouts will be triggered.
 
K

Kevin.M.Jonas

hi,



Better than a loop (i'm using <> as start/end tags):

private string _Data = null;
private void _port_DataReceived(object sender,
   SerialDataReceivedEventArgs e)
{
   string data = _port.ReadExisting();

   if (_Data == null && data.StartsWith("<"))
   {
     _Data = data;
     data = null;
   }
   if (_Data != null && data != null)
     _Data += data;
   if (_Data != null)
     if (_Data.EndsWith(">"))
     {
       _log.LogToFile(_Data, true);
       _Data = null;
     }

}

Depending on the kind of device, you must consider that you get strings
like "789><123897"

mfG
--> stefan <--

That's interesting. What isn't being displayed in my post is the
start and end character - 0x02 and 0x03.
 
R

Rick Lones

I have the following method that handles the data received event:
private void _port_DataReceived(object sender,
SerialDataReceivedEventArgs e)
{
string data = _port.ReadExisting();
_log.LogToFile(data, true);
}

The LogToFile function logs data to a file. The second parameter
indicate if the file should timestamp the message.

On the initial test of this method I got the following result:
[9/19/2008 4:40:04 PM]10??I 1
[9/19/2008 4:40:04 PM] 1909081
[9/19/2008 4:40:04 PM]640?

This is not what I expected. I converting an old VB 6.0 program to
C#. If I add Thread.Sleep(500) before the ReadExisting() I get the
string I was expecting:
[9/19/2008 4:57:47 PM]10??I 1 1909081657?

Notice in the first try it is sending 8 bytes at a time. Is there
anyway to avoid using Thread.Sleep to achieve this?

If you know the minimum length of an incoming message, then you could change the
ReceivedBytesThreshold property of the SerialPort. Or, if your incoming message
contains a known end byte that you can synch on, you could use the ReadTo()
method.

HTH,
-rick-
 
K

Kevin.M.Jonas

I cannot change the baud rate, I have to match the machine, right?
The minimum number of characters could be one. The machine sends an
ACK once and a while to see if anything is listening. This is
receiving data from a medical device. There is a comments field that
can be filled out and that will be in the data stream

I said VB but that was my mistake. It's a service that uses Vb to
manage it. The code that monitors the serial port is C++. here's the
C++ code:
if(ReadFile(hComm,buf,4096,&dwBytesTransferred,NULL) == TRUE)

That will read the entire stream into the buffer.

Someone suggested to me to use SerialPort.ReadLine. None of these
make a difference. First, there may be new line characters in the
data stream that is part of the data. I've tried all of the read
functions, the program is only getting 8 bytes at a time unless I put
a sleep in there.

I have even tried something like
while (_port.BytesToRead > 0)
{
iRead = _port.Read(buffer, iRead, _port.BytesToRead);
iTotal += iRead;
}

Only the first 8 bytes unless I put a sleep in the loop. A sleep
probably isn't bad, it just has to be large enough that on slower
machines it will still get all the data into the buffer but not so
long that it causes any timeouts.

I think I have to do what Stefan suggested if I want to be safe.

BTW, thanks for the responses. I tried to get a response on the msdn
forum but apparently my question was off topic for the general C#
forum.
 
R

Rick Lones

That's interesting. What isn't being displayed in my post is the
start and end character - 0x02 and 0x03.

Then, again I will suggest ReadTo(). It looks as if your data may consist of a
fixed length ASCII string bracketed by start and end framing values. You could
use ReadTo() to read up to the next start byte, as per

string startPattern = Encoding.ASCII.GetString(new byte[]{2});
string input, junk;
while (1)
{
/*
Read previous previous input through end byte
(should be 20 bytes as per your example). Then
read and discard the start byte you just found.
*/
input = myPort.ReadTo(startPattern);
junk = myPort.ReadByte(); //
}

If your data pattern is as simple as you indicate then this simple loop or
something very like it may work for you. You would probably want to add
validation of the start and end bytes plus code to recover your framing if you
happen, e.g., to get a short input string.

HTH,
-rick-
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top