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 string
s 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 string
s, 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?
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With