Processing text coming out of a sequential line in C #

I have an embedded Linux device that I can communicate with through RS232. I am trying to programmatically control it from an existing .NET application, so I was cheating on the System.IO.Ports.SerialPort class. I am currently reading data from the port using the SerialPortDataRecieved event handler and checking the number of bytes read, and then passing the byte[] this size, THEN dragging that byte[] to Queue<byte[]> for further processing, for example:

 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); } } } 

Then another thread then reads from this queue to perform processing, printing to the terminal, etc. This works fine for printing, but I want to be able to reuse the data I retrieve. The problem is that the number of bytes returned by SerialPort is unpredictable and completely unaware of what information it sends, so the pieces of data that I receive are usually fragmented strings.

What I'm looking for is a simple, efficient multi-threaded way of moving from a piece of a byte[] string to a string , which is sorted by string . One of my ideas was to infinitely infinitely alternate between an infinite stream that would dequeue Dequeue byte[] , turn them into string s, add them to StringBuilder , and then split the string returned from StringBuilder.ToString() along newlines , take the LAST string and use it to create a new StringBuilder next time, then insert all the other lines in the Queue<string> - this way the fragments will be returned together ... but this will not work in the most important case when I wait for find the shell prompt, since this line will never be n Substituted in the second place.

Ideas?

+6
source share
2 answers

You can make a small state machine. For each byte received, if it is not a newline, add it to the data of the current line.

If this is a new line, run the "new data"; event.

If you find that the "current row" is equal to the expected "shell prompt", fire the "new data" event.

Perform this processing for each byte received in turn. Of course, this does not stop you, of course, reading all the available bytes from the port.

+4
source

I would just encode the characters in the DataReceivedHandler until I found a new line, and then drop the characters before the new line (\ r \ n) as a line and save the remaining characters in the buffer until the next new line. Usually for situations \ r \ n I always clean out \ r and interpret only \ n.

Here you can quickly go to the source for illustration.

 public class SerialTalk{ SerialPort s; Queue<string> RecQueue=new Queue<string>(); //...bunch of irrelevant stuff here (ctors etc) string innerBuffer = ""; //a buffer we keep in between DataReceiveHandlers for the portion of text not newlined yet private void DataReceivedHandler(Object sender, object e) { byte[] recv; lock (s_lock) { int bytes = s.BytesToRead; recv = new byte[bytes]; s.Read(recv, 0, bytes); } innerBuffer += System.Text.Encoding.GetEncoding("utf-8").GetString(recv).Replace("\r\n","\n"); //could be enhanced using stringbuilder. string[] lines = innerBuffer.Split('\n'); innerBuffer = lines[lines.Length-1]; //always keep the portion after the last newline in the buffer Console.Write(recv); lock (RecQueue) { for(int x=0;x<innerBuffer.Length-2;x++) //-2 here instead of -1 as you don't want to send the remainder of the inner buffer until the next newline RecQueue.Enqueue(lines[x]); } } } 

* It should be noted that converting to utf-8 from your byte array may cause additional problems. If you still want to send it as a byte [] to the queue, you can still store the buffer locally, as is done in the innerBuffer line, but the markup marks will not be as trivial as finding Split, although still not a big deal.

0
source

Source: https://habr.com/ru/post/895158/


All Articles