views:

1717

answers:

4

I'm trying to write a test application for serial I/O (RS-232) with multiple units in C# and I'm running into an issue with my lack of threading experience so I'm soliciting feedback for a best known method.

I've got a pool of COM ports COM1-16 each of which can read/write at any time and I need to be able to manage them simultaneously. Is this a situation for a thread pool? What is some guidance on structuring this applet?

Edit: Upon review I was wondering is I really even need to do asynchronous threads here, I could just maintain states for each COM-port and do flow logic (i.e., statemachine) for each COM-port individually.

+2  A: 

Much of the difficulty surrounding the serial port is centered around an assumption. The assumption is that the serial port receives data in chunks that are convenient, and what is expected.

Here is an example. I know my GPS receiver sends lines (ends with CRLF). This is an example of one of the NMEA sentences:

$GPGSV,3,1,11,10,75,053,29,29,52,311,32,24,50,298,30,02,39,073,30*77

However, the serial ports DataReceived event handler might(usually does on my PC) fire several times with chunks of that data.

event fire - data

1 $
2 GPGSV,3,1,11,10
3 ,75,053,29,29,52,311,32,24,50,298,30,02,39,073,30*77

Instead of fighting this I created some routines that receive data whenever the event fires, and queue it up. When I need the data I call some other routines that put the data back together in chunk sizes I want. So using my example the first and second time I call read line(my readline) I get back an empty answer. The third time I get the entire NMEA sentence back.

The bad news is that I don't C#. The code is here SerialPort

Depending on the speed of the ports delegates may not be a good choice. I tested my routines at near 1Mbps using delegates, and not using delegates. At those speeds not using delegates was a better choice.

Here are some tips from those in the know

Kim Hamilton

dbasnett
@dbasnett - if you have a known terminating string, an alternative approach is to set the SerialPort.NewLine property (http://msdn.microsoft.com/en-us/library/system.io.ports.serialport.newline.aspx) to CRLF and then use SerialPort.ReadLine() (http://msdn.microsoft.com/en-us/library/system.io.ports.serialport.readline.aspx). This assures you get full packets.
mtrw
A: 

The .NET way to handle this is to use Events and Delegates. This will end up creating multiple threads, but it will do so in a manner that means you don't explicitly create them. If you create an event handler and add it to the DataReceived event of each port, then when any port receives data, the event handler will be called on a separate thread. Naturally, this means the method must be reentrant, and that access to any shared data structures must be protected against concurrent access.

Your handler routine will do something like the following:

  1. Call ReadExisting to get the data available.
  2. Handle data.
  3. Done.
Harper Shelby
A: 

You need to know at what speed the receiver is spitting out data. Is it once a second, twice a second, 5 times...

I had this same issue reading GPS data. You need to use the backgroundworker in C# to update your variables, screen.

Arlie Winters
A: 

If you use the backgroundworker you won't be grabbing small pieces of the data, you'll get the entire string. You need something like:

private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
    try
    {
        serialPort1.Open();
        if (serialPort1.IsOpen)
        {
            while (keepReading)
            {
                backgroundWorker1.ReportProgress(0, serialPort1.ReadLine());
                //backgroundWorker1.ReportProgress(0, sentence.Split(','));
                // split_gps_data();
            }
        }
    }
}
Arlie Winters