I'm creating a program which communicates with a serial device which is constantly sending data. I'm reading data from device every 100ms (using a timer). I use port.ReadExisting()
to receive all currently available data from the device then I try split it into lines, because I need to check some of the received data and the best way is to check lines. The problem occurs when device sends data which doesn't end with "\r\n"
or '\n'
.
In a perfect situation port.ReadExisting()
returns: "sampletext\r\nsomesampletext\nsampletext\r\n
But a problem occurs when there's no CR or LF character at the end:
First time port.ReadExisting()
returns this: "text\nsamp"
Second time port.ReadExisting()
returns this: letext\r\ntext\r\n"
End result should look like this:
text
sampletext
text
But what I get looks like this:
text
samp
letext
text
My code:
This is the timer
which runs every 100ms:
private void CommandTimer_Tick(object sender, EventArgs e)
{
BackgroundWorker seriaDataWorker = new BackgroundWorker();
seriaDataWorker.DoWork += (obj, p) => PrintSerialData();
seriaDataWorker.RunWorkerAsync();
}
BackgroundWorker
which gets called by the timer:
private void PrintSerialData()
{
try
{
if (RandomReboot)
{
RebootWatch.Start();
}
if (COMport.IsOpen)
{
if (COMport.BytesToRead != 0)
{
SerialPrint(COMport.ReadExisting());
}
}
}
catch (System.IO.IOException SerialException)
{
return;
}
}
Function which parses received data into lines:
private void SerialPrint(string data)
{
using (var buffer = new StringReader(data))
{
string line = "";
while((line = buffer.ReadLine()) != null)
{
if (CheckForAnsw)
{
ReceivedCommandData = line;
if (ReceivedCommandData.Contains(AnswExpected))
{
ReceivedAnsw = true;
ReceivedLine = ReceivedCommandData;
ReceivedCommandData = "";
}
}
this.Invoke(new MethodInvoker(delegate
{
AppendText(TextBox_System_Log, Color.Black, line + "\r\n");
}
));
}
}
}
I know that the problem is that buffer.ReadLine()
treats remainder of the string which doesn't end with a CR or LF character as a seperate line but I don't know how to fix it.
I tried using port.ReadLine()
in the past but it is way slower and causes problems for me when serial ports get disconnected etc.
I don't think there's an easy way to handle this with the StringReader
. Instead, you can split the string yourself:
private static string _buffer = string.Empty;
private static void SerialPrint(string data)
{
// Append the new data to the leftover of the previous operation
data = _buffer + data;
int index = data.IndexOf('\n');
int start = 0;
while (index != -1)
{
var command = data.Substring(start, index - start);
ProcessCommand(command.TrimEnd('\r'));
start = index + 1;
index = data.IndexOf('\n', start);
}
// Store the leftover in the buffer
if (!data.EndsWith("\n"))
{
_buffer = data.Substring(start);
}
else
{
_buffer = string.Empty;
}
}
private static void ProcessCommand(string command)
{
Console.WriteLine(command);
}