Serial Ports - using events to capture 20 bytes coming from 3 different ports

I have a datalogging application that needs to capture 20 bytes worth of data coming from three serial devices that continuously stream 9600 baud serial data on their respective ports. All 20 bytes stream ends with a 0x0d terminator

I managed to get each of these device individually to send data to my EMX Fez Cobra board, but as soon as i try to get them together onto one application, the FEZ Cobra does not seem to be able to handle all the data. I might be doing something wrong in the programming and would like some help (willing to look into a consulting contract if needed).

My question is : Is the EMX module fast enough to capture 3 serial streams (with 0x0d terminators) at 9600 bauds? What is the best practices for parsing multiple short ASCII serial messages with the EMX module that will no block the rest of the program ?

Cheers,
Jean-Francois

You are talking about 3,000 characters/second…

The answer to your questions depends upon how you are handing the reception, queuing and processing of the messages.

With proper programming, I think you should be able to get all the data into a queue, or maybe multiple queues for processing. The bottom line is can the EMX keep up the processing demands of your application. That question can only be answered by you running some timing tests.

How are you handling the multiple comm ports?

Here is one of my 3 DataReceived event handlers. I process the received data from each on the three serial devices within their respective event handlers. I guess this is what is causing problems.

Ultimately i need to convert the three serial byte arrays to three global strings that will be available globally to the main application where the datalog function to the SD card writes the events , along with a GPS coordinate.

 void COM3_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            int numbytes = myLED.BytesToRead;
            bool end_of_line = false;
            // Create local array to put data from serialport in.
            byte[] bytearray = new byte[numbytes];

            // Read the bytes from the serial port
            myLED.Read(bytearray, 0, numbytes);
            myLED.DiscardInBuffer();

            for (int k = 0; k < numbytes; k++)
            {
                if (bytearray[k] == 0x0d)
                {
                    end_of_line = true;
                    if (k >= 5 && (bytearray[k - 5] < 0x7f) && (bytearray[k - 4] < 0x7f) && (bytearray[k - 3] < 0x7f)
                        && (bytearray[k - 2] < 0x7f) && (bytearray[k - 1] < 0x7f))  // make sure all 6 bytes of distance array can be converted to string
                    {
                        try
                        {
                            string soo = new string(Encoding.UTF8.GetChars(bytearray), k - 5, 5);
                            Program._last_good_Senix_distance = soo;
                            Debug.Print(Program._last_good_Senix_distance);
                            myLED.DiscardInBuffer();
                        }
                        catch 
                        {
                            myLED.DiscardInBuffer();
                        }
                    }
                }
            }
           
            
        }

You should not be doing any significant processing in an event. What you need to do in the event is put the received data into a queue, and then process it by another thread.

Events get priority, and there is only a single thread for processing events. While you are busy in an event handler, the receive buffers for the other comm ports are filling up.

What you need to do, is only empty the receive buffers in the event handler.

You can then process off the queue.

Also doing a Debug.Print in an event handler will slow things down a lot. Also, allocating memory will also slow things down, and cause garbage collection to occur.

I think you also might be assuming you get an entire message in one DataReceived event, which would be an incorrect assumption.

I don’t think you want to be discarding the input buffer?

Everything Mike said for starters and then some…

You said your streams come in continuously. This means the processor must attend to capturing the data and processing it continuously. There probably isn’t enough time to do both. In such a case an interrupt event probably just adds overhead. Try a tight loop clearing and processing the input buffers and see if you get more speed. If you don’t then you’ll probably never keep up using interrupts.

NETMF implements its own form of multitasking and it does not switch terribly fast. Add the fact that it is interpreted and you’ll see why it cannot handle really fast streams of continuous data.

Maybe also try running the GPS at 4800 baud. It will give you twice as much time to process.

Hi Mike and realiser,

Thanks for your guidance. With your input, i’ve modified the program in order to empty the three serial ports buffer using Datareceived event handlers, and process the three queues in the main loop. As suggested, GPS data comes in at 4800 baud (GPRMC string at 1 Hz) and two other serial streams (20 bytes or so) at 9600 baud (at 1 Hz also).

Here is the timing results:
500uS to clear the first input buffer for Serial Port 1 in the Datareceived Event Handler.
600uS to clear the second input buffer for Serial Port 2 in the Datareceived Event Handler.
340uS to process the GPS string and update the new coordinates
136mS to write to the SD card.

It now looks like i’ve will have enough time to process the rest of the tasks.

Thanks guys!
Jean-Francois

The word “continuous” made me think that data was arriving at a rate of 960 characters per second on each 9600 bps comm port. A total of 60 characters per second is “part de gâteau”.