Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Processing text coming off a serial line in C#

I've got an embedded device running Linux that I can communicate with via RS232. I'm attempting to programmatically control it from within an existing .NET application, so I've been fooling around with the System.IO.Ports.SerialPort class. I'm reading data off the port right now by using the SerialPortDataRecieved event handler and checking for the amount of bytes to read, then passing in a byte[] of that size, THEN shoving that byte[] into a Queue<byte[]> for further processing, like this:

public class SerialTalk{
SerialPort s;    
Queue<byte[]> RecQueue=new Queue<byte[]>;
//...bunch of irrelevant stuff here (ctors etc)
   private void DataReceivedHandler(Object sender, SerialDataReceivedEventArgs e)
   {
        byte[] recv;
        lock (s_lock)
        {
            int bytes = s.BytesToRead;
            recv = new byte[bytes];
            s.Read(recv, 0, bytes);
        }

        Console.Write(recv);
        lock (RecQueue)
        {
            RecQueue.Enqueue(recv);
        }
   }
}

Another thread then reads from that queue to perform processing, printing to the terminal, etc. This has been working great for printing, but I want to be able to regex the data I'm retrieving. The problem is, the amount of bytes returned by the SerialPort is unpredictable and completely unaware of what information it is sending, so the chunks of data I'm getting are, generally, fragments of lines.

What I'm looking for is a simple, performant, multithreaded way to go from line fragment byte[] to strings that are organized neatly according to lines. One idea I had was to have another thread looping infinitely that would Dequeue byte[]s from the queue, turn them into strings, append them to a StringBuilder, then split the string returned from StringBuilder.ToString() along the newlines, the take the LAST string and use it to construct a new StringBuilder for the next time around, then enqueue all the other strings into a Queue<string> -- this way, fragments would get put back together... but this won't work in the most important case of all, which is when I'm waiting to find the shell prompt, since that string won't ever get put into the second queue.

Ideas?

like image 597
Alexander Questioning Bresee Avatar asked Aug 16 '11 15:08

Alexander Questioning Bresee


1 Answers

You can do a small state machine. For each byte received, if it's not a newline, add it to the 'current string' data.

If it is a newline, fire the 'new-data'; event.

If you detect that the 'current string' is equal to the expected 'shell prompt', fire the 'new-data' event.

Perform that processing for each byte received in turn. That doesn't stop you reading all available bytes from the port at once, of course.

like image 123
Kieren Johnstone Avatar answered Oct 12 '22 01:10

Kieren Johnstone