Reading range sensor data from one Serial Port and writing output to another











up vote
2
down vote

favorite
1












I'm reading range/distance sensor data from one Serial Port, decoding it and then transmitting it to a secondary device in ASCII format. The sensor uses a 2-byte header with each byte containing the following hex values: 0x59 0x59. Additional data from the sensor is also sent in a 7-byte message, subsequent to the header.



The code works but I'm not convinced that I'm reading the data correctly in DataReceived event handler. How can I improve this code?



internal static class Program
{
private static long _validMessageCount;

private static SerialPort _distanceOutputSerialPort;

private const int FrameHeader = 0x59;

public static void Main()
{
SerialPort lidarSensorSerialPort = null;

try
{
lidarSensorSerialPort = new SerialPort(AppSettings.InputPort)
{
BaudRate = AppSettings.InputBaudRate,
DataBits = AppSettings.InputDataBits,
Handshake = Handshake.None,
Parity = Parity.None,
StopBits = StopBits.One
};

_distanceOutputSerialPort = new SerialPort(AppSettings.OutputPort)
{
BaudRate = AppSettings.OutputBaudRate,
DataBits = AppSettings.OutputDataBits,
Handshake = Handshake.None,
Parity = Parity.None,
StopBits = StopBits.One,
NewLine = "r",
Encoding = Encoding.ASCII
};

_distanceOutputSerialPort.Open();
lidarSensorSerialPort.DataReceived += DataReceivedHandler;
lidarSensorSerialPort.Open();

Console.Write("Waiting for data...");
Console.ReadKey();
}
catch (IOException e)
{
Console.WriteLine(e.Message);
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
finally
{
lidarSensorSerialPort?.Close();
_distanceOutputSerialPort?.Close();

Console.Write("Press any key to exit...");
Console.ReadKey();
}
}

private static void DataReceivedHandler(object sender, SerialDataReceivedEventArgs e)
{
var headerBytes = new byte[2];
var measuredRangeBytes = new byte[7];
var serialPort = (SerialPort) sender;

if (serialPort.BytesToRead < 9)
return;

while (true)
{
if (headerBytes[0] == FrameHeader && headerBytes[1] == FrameHeader)
break;

serialPort.Read(headerBytes, 0, headerBytes.Length);
}

var bytesRead = serialPort.Read(measuredRangeBytes, 0, measuredRangeBytes.Length);

if (bytesRead < measuredRangeBytes.Length)
{
Console.WriteLine($"Invalid data Received. [{bytesRead}]");
return;
}

var completeBytes = headerBytes.Concat(measuredRangeBytes).ToArray();
var checksum = Helpers.CalculateChecksum(completeBytes);
var check = measuredRangeBytes[6];

if (checksum != check)
{
Console.WriteLine("Invalid Checksum");
return;
}

CalculateDistance(measuredRangeBytes);
}

private static void CalculateDistance(IList<byte> distanceBytes)
{
var distanceLow = distanceBytes[0];
var distanceHigh = distanceBytes[1];
var strengthLow = distanceBytes[2];
var strengthHigh = distanceBytes[3];
var realibilityLevel = distanceBytes[4];
var exposureTime = distanceBytes[5];
var distance = Math.Round(distanceHigh * 256d + distanceLow, 2);
var strength = strengthHigh * 256 + strengthLow;
var time = $"{DateTime.Now:HH:mm:ss.fff}";

_validMessageCount++;

Console.WriteLine(
$"{_validMessageCount}. {time} | {distance} | {strength} | {realibilityLevel} | {exposureTime}");

ConvertOuput(distance);
}

private static void ConvertOuput(double distance)
{
var distanceInMeters = Math.Round(distance / 100d, 2);
var mdlLmSensorOutput = $"{distanceInMeters.ToString("F").PadLeft(6, '0')}m";

_distanceOutputSerialPort.WriteLine(mdlLmSensorOutput);

Console.WriteLine($"Output: {mdlLmSensorOutput}");
}
}









share|improve this question
























  • If you don't get an answer till tuesday, I will answer your question. Unfortunately I am out of the office till then.
    – Heslacher
    Nov 7 at 7:05















up vote
2
down vote

favorite
1












I'm reading range/distance sensor data from one Serial Port, decoding it and then transmitting it to a secondary device in ASCII format. The sensor uses a 2-byte header with each byte containing the following hex values: 0x59 0x59. Additional data from the sensor is also sent in a 7-byte message, subsequent to the header.



The code works but I'm not convinced that I'm reading the data correctly in DataReceived event handler. How can I improve this code?



internal static class Program
{
private static long _validMessageCount;

private static SerialPort _distanceOutputSerialPort;

private const int FrameHeader = 0x59;

public static void Main()
{
SerialPort lidarSensorSerialPort = null;

try
{
lidarSensorSerialPort = new SerialPort(AppSettings.InputPort)
{
BaudRate = AppSettings.InputBaudRate,
DataBits = AppSettings.InputDataBits,
Handshake = Handshake.None,
Parity = Parity.None,
StopBits = StopBits.One
};

_distanceOutputSerialPort = new SerialPort(AppSettings.OutputPort)
{
BaudRate = AppSettings.OutputBaudRate,
DataBits = AppSettings.OutputDataBits,
Handshake = Handshake.None,
Parity = Parity.None,
StopBits = StopBits.One,
NewLine = "r",
Encoding = Encoding.ASCII
};

_distanceOutputSerialPort.Open();
lidarSensorSerialPort.DataReceived += DataReceivedHandler;
lidarSensorSerialPort.Open();

Console.Write("Waiting for data...");
Console.ReadKey();
}
catch (IOException e)
{
Console.WriteLine(e.Message);
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
finally
{
lidarSensorSerialPort?.Close();
_distanceOutputSerialPort?.Close();

Console.Write("Press any key to exit...");
Console.ReadKey();
}
}

private static void DataReceivedHandler(object sender, SerialDataReceivedEventArgs e)
{
var headerBytes = new byte[2];
var measuredRangeBytes = new byte[7];
var serialPort = (SerialPort) sender;

if (serialPort.BytesToRead < 9)
return;

while (true)
{
if (headerBytes[0] == FrameHeader && headerBytes[1] == FrameHeader)
break;

serialPort.Read(headerBytes, 0, headerBytes.Length);
}

var bytesRead = serialPort.Read(measuredRangeBytes, 0, measuredRangeBytes.Length);

if (bytesRead < measuredRangeBytes.Length)
{
Console.WriteLine($"Invalid data Received. [{bytesRead}]");
return;
}

var completeBytes = headerBytes.Concat(measuredRangeBytes).ToArray();
var checksum = Helpers.CalculateChecksum(completeBytes);
var check = measuredRangeBytes[6];

if (checksum != check)
{
Console.WriteLine("Invalid Checksum");
return;
}

CalculateDistance(measuredRangeBytes);
}

private static void CalculateDistance(IList<byte> distanceBytes)
{
var distanceLow = distanceBytes[0];
var distanceHigh = distanceBytes[1];
var strengthLow = distanceBytes[2];
var strengthHigh = distanceBytes[3];
var realibilityLevel = distanceBytes[4];
var exposureTime = distanceBytes[5];
var distance = Math.Round(distanceHigh * 256d + distanceLow, 2);
var strength = strengthHigh * 256 + strengthLow;
var time = $"{DateTime.Now:HH:mm:ss.fff}";

_validMessageCount++;

Console.WriteLine(
$"{_validMessageCount}. {time} | {distance} | {strength} | {realibilityLevel} | {exposureTime}");

ConvertOuput(distance);
}

private static void ConvertOuput(double distance)
{
var distanceInMeters = Math.Round(distance / 100d, 2);
var mdlLmSensorOutput = $"{distanceInMeters.ToString("F").PadLeft(6, '0')}m";

_distanceOutputSerialPort.WriteLine(mdlLmSensorOutput);

Console.WriteLine($"Output: {mdlLmSensorOutput}");
}
}









share|improve this question
























  • If you don't get an answer till tuesday, I will answer your question. Unfortunately I am out of the office till then.
    – Heslacher
    Nov 7 at 7:05













up vote
2
down vote

favorite
1









up vote
2
down vote

favorite
1






1





I'm reading range/distance sensor data from one Serial Port, decoding it and then transmitting it to a secondary device in ASCII format. The sensor uses a 2-byte header with each byte containing the following hex values: 0x59 0x59. Additional data from the sensor is also sent in a 7-byte message, subsequent to the header.



The code works but I'm not convinced that I'm reading the data correctly in DataReceived event handler. How can I improve this code?



internal static class Program
{
private static long _validMessageCount;

private static SerialPort _distanceOutputSerialPort;

private const int FrameHeader = 0x59;

public static void Main()
{
SerialPort lidarSensorSerialPort = null;

try
{
lidarSensorSerialPort = new SerialPort(AppSettings.InputPort)
{
BaudRate = AppSettings.InputBaudRate,
DataBits = AppSettings.InputDataBits,
Handshake = Handshake.None,
Parity = Parity.None,
StopBits = StopBits.One
};

_distanceOutputSerialPort = new SerialPort(AppSettings.OutputPort)
{
BaudRate = AppSettings.OutputBaudRate,
DataBits = AppSettings.OutputDataBits,
Handshake = Handshake.None,
Parity = Parity.None,
StopBits = StopBits.One,
NewLine = "r",
Encoding = Encoding.ASCII
};

_distanceOutputSerialPort.Open();
lidarSensorSerialPort.DataReceived += DataReceivedHandler;
lidarSensorSerialPort.Open();

Console.Write("Waiting for data...");
Console.ReadKey();
}
catch (IOException e)
{
Console.WriteLine(e.Message);
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
finally
{
lidarSensorSerialPort?.Close();
_distanceOutputSerialPort?.Close();

Console.Write("Press any key to exit...");
Console.ReadKey();
}
}

private static void DataReceivedHandler(object sender, SerialDataReceivedEventArgs e)
{
var headerBytes = new byte[2];
var measuredRangeBytes = new byte[7];
var serialPort = (SerialPort) sender;

if (serialPort.BytesToRead < 9)
return;

while (true)
{
if (headerBytes[0] == FrameHeader && headerBytes[1] == FrameHeader)
break;

serialPort.Read(headerBytes, 0, headerBytes.Length);
}

var bytesRead = serialPort.Read(measuredRangeBytes, 0, measuredRangeBytes.Length);

if (bytesRead < measuredRangeBytes.Length)
{
Console.WriteLine($"Invalid data Received. [{bytesRead}]");
return;
}

var completeBytes = headerBytes.Concat(measuredRangeBytes).ToArray();
var checksum = Helpers.CalculateChecksum(completeBytes);
var check = measuredRangeBytes[6];

if (checksum != check)
{
Console.WriteLine("Invalid Checksum");
return;
}

CalculateDistance(measuredRangeBytes);
}

private static void CalculateDistance(IList<byte> distanceBytes)
{
var distanceLow = distanceBytes[0];
var distanceHigh = distanceBytes[1];
var strengthLow = distanceBytes[2];
var strengthHigh = distanceBytes[3];
var realibilityLevel = distanceBytes[4];
var exposureTime = distanceBytes[5];
var distance = Math.Round(distanceHigh * 256d + distanceLow, 2);
var strength = strengthHigh * 256 + strengthLow;
var time = $"{DateTime.Now:HH:mm:ss.fff}";

_validMessageCount++;

Console.WriteLine(
$"{_validMessageCount}. {time} | {distance} | {strength} | {realibilityLevel} | {exposureTime}");

ConvertOuput(distance);
}

private static void ConvertOuput(double distance)
{
var distanceInMeters = Math.Round(distance / 100d, 2);
var mdlLmSensorOutput = $"{distanceInMeters.ToString("F").PadLeft(6, '0')}m";

_distanceOutputSerialPort.WriteLine(mdlLmSensorOutput);

Console.WriteLine($"Output: {mdlLmSensorOutput}");
}
}









share|improve this question















I'm reading range/distance sensor data from one Serial Port, decoding it and then transmitting it to a secondary device in ASCII format. The sensor uses a 2-byte header with each byte containing the following hex values: 0x59 0x59. Additional data from the sensor is also sent in a 7-byte message, subsequent to the header.



The code works but I'm not convinced that I'm reading the data correctly in DataReceived event handler. How can I improve this code?



internal static class Program
{
private static long _validMessageCount;

private static SerialPort _distanceOutputSerialPort;

private const int FrameHeader = 0x59;

public static void Main()
{
SerialPort lidarSensorSerialPort = null;

try
{
lidarSensorSerialPort = new SerialPort(AppSettings.InputPort)
{
BaudRate = AppSettings.InputBaudRate,
DataBits = AppSettings.InputDataBits,
Handshake = Handshake.None,
Parity = Parity.None,
StopBits = StopBits.One
};

_distanceOutputSerialPort = new SerialPort(AppSettings.OutputPort)
{
BaudRate = AppSettings.OutputBaudRate,
DataBits = AppSettings.OutputDataBits,
Handshake = Handshake.None,
Parity = Parity.None,
StopBits = StopBits.One,
NewLine = "r",
Encoding = Encoding.ASCII
};

_distanceOutputSerialPort.Open();
lidarSensorSerialPort.DataReceived += DataReceivedHandler;
lidarSensorSerialPort.Open();

Console.Write("Waiting for data...");
Console.ReadKey();
}
catch (IOException e)
{
Console.WriteLine(e.Message);
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
finally
{
lidarSensorSerialPort?.Close();
_distanceOutputSerialPort?.Close();

Console.Write("Press any key to exit...");
Console.ReadKey();
}
}

private static void DataReceivedHandler(object sender, SerialDataReceivedEventArgs e)
{
var headerBytes = new byte[2];
var measuredRangeBytes = new byte[7];
var serialPort = (SerialPort) sender;

if (serialPort.BytesToRead < 9)
return;

while (true)
{
if (headerBytes[0] == FrameHeader && headerBytes[1] == FrameHeader)
break;

serialPort.Read(headerBytes, 0, headerBytes.Length);
}

var bytesRead = serialPort.Read(measuredRangeBytes, 0, measuredRangeBytes.Length);

if (bytesRead < measuredRangeBytes.Length)
{
Console.WriteLine($"Invalid data Received. [{bytesRead}]");
return;
}

var completeBytes = headerBytes.Concat(measuredRangeBytes).ToArray();
var checksum = Helpers.CalculateChecksum(completeBytes);
var check = measuredRangeBytes[6];

if (checksum != check)
{
Console.WriteLine("Invalid Checksum");
return;
}

CalculateDistance(measuredRangeBytes);
}

private static void CalculateDistance(IList<byte> distanceBytes)
{
var distanceLow = distanceBytes[0];
var distanceHigh = distanceBytes[1];
var strengthLow = distanceBytes[2];
var strengthHigh = distanceBytes[3];
var realibilityLevel = distanceBytes[4];
var exposureTime = distanceBytes[5];
var distance = Math.Round(distanceHigh * 256d + distanceLow, 2);
var strength = strengthHigh * 256 + strengthLow;
var time = $"{DateTime.Now:HH:mm:ss.fff}";

_validMessageCount++;

Console.WriteLine(
$"{_validMessageCount}. {time} | {distance} | {strength} | {realibilityLevel} | {exposureTime}");

ConvertOuput(distance);
}

private static void ConvertOuput(double distance)
{
var distanceInMeters = Math.Round(distance / 100d, 2);
var mdlLmSensorOutput = $"{distanceInMeters.ToString("F").PadLeft(6, '0')}m";

_distanceOutputSerialPort.WriteLine(mdlLmSensorOutput);

Console.WriteLine($"Output: {mdlLmSensorOutput}");
}
}






c# console serial-port






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Nov 6 at 16:33









t3chb0t

33.3k744106




33.3k744106










asked Nov 6 at 15:38









Thabiso Mofokeng

234




234












  • If you don't get an answer till tuesday, I will answer your question. Unfortunately I am out of the office till then.
    – Heslacher
    Nov 7 at 7:05


















  • If you don't get an answer till tuesday, I will answer your question. Unfortunately I am out of the office till then.
    – Heslacher
    Nov 7 at 7:05
















If you don't get an answer till tuesday, I will answer your question. Unfortunately I am out of the office till then.
– Heslacher
Nov 7 at 7:05




If you don't get an answer till tuesday, I will answer your question. Unfortunately I am out of the office till then.
– Heslacher
Nov 7 at 7:05










2 Answers
2






active

oldest

votes

















up vote
2
down vote













The main problem I see is that you could miss the frame header if it was preceeded by odd number of different bytes (0xAA 0x59 0x59 ... you will try to match AA59 and then 59XX missing 5959). I would therefore rewrite it like this:



static int headerBytes; // counter to help us find 5959
static byte message = new byte[7]; // no need to allocate new array every time
static void DataReceivedHandler(object sender, SerialDataReceivedEventArgs e)
{
// loop to process all messages in case we get 18B or more
for(;;)
{
// read until we find two header bytes
while(headerByes < 2)
{
// see Heslacher's answer for why this check is so important
if (serialPort.BytesToRead == 0) return;
int b = serialPort.ReadByte();
if (b == FrameHeader) headerBytes++;
else headerBytes = 0;
}
// wait until we have full message (7 bytes)
if (serialPort.BytesToRead < message.Length)
return;
// read the message
var bytesRead = serialPort.Read(message, 0, message.Length)
// reset headerBytes counter before any return statement
headerBytes = 0;
// check that everything is according to plan
if (bytesRead < message.Length)
{// this should never happen because we checked BytesToRead
Console.WriteLine($"Invalid data Received. [{bytesRead}]");
return;
}
// now do something with the message, but beware that it does not contain the header now
// so, Helpers.CalculateChecksum would have to be modified
// or message made bigger to always include the header (and change the code above a bit)
// ...
CalculateDistance(message);
}
}


EDIT: I didn't know that ReadByte can throw TimeoutException (see Heslacher's answer), was expecting -1 in that case. I actually do not use SerialPort but my own version, because SerialPort was bugged in .NET 3.5 and caused uncatchable exceptions in GC (from finalizer) when used with Virtual COM (USB) - that could crash whole App and there was no way to fight it.






share|improve this answer



















  • 1




    The downvoter care to explain?
    – firda
    Nov 9 at 10:55


















up vote
2
down vote













This




if (serialPort.BytesToRead < 9)
return;

while (true)
{
if (headerBytes[0] == FrameHeader && headerBytes[1] == FrameHeader)
break;

serialPort.Read(headerBytes, 0, headerBytes.Length);
}



can get dangerous. Not only because what @firda has stated in his answer but the reading of the serialport without questioning the serialPort.BytesToRead again. Assume that at the if you get a serialPort.BytesToRead == 9 but if (headerBytes[0] == FrameHeader && headerBytes[1] == FrameHeader) isn't true then somewhere down the road your code could crash with a TimeoutException because you read but there aren't any bytes left to read.



A better approach would be to just read all the bytes avaible and place them in a ConcurrentQueue<List<byte>> like so



private static ConcurrentQueue<List<byte>> dataQueue = new ConcurrentQueue<List<byte>>();
static void DataReceivedHandler(object sender, SerialDataReceivedEventArgs e)
{
var serialPort = sender as SerialPort;
if (serialPort == null || serialPort.BytesToRead == 0) { return; }

var receivedData = new byte[serialPort.BytesToRead];
var readBytes = serialPort.Read(receivedData, 0, serialPort.BytesToRead);

dataQueue.Enqueue(receivedData.Take(readBytes).ToList());

}


which keeps your DataReceived eventhandler short and clean.



To process the received data you can add a Timer e.g set to an interval of 250ms which calls a method ProcessData in its elapsed event only if dataQueue.Count > 0 like so



private static System.Timers.Timer timer = new System.Timers.Timer();
static void Main(string args)
{
timer.Interval = 250;
timer.Elapsed += new ElapsedEventHandler(timer_Elapsed);
timer.Start();

// Your SerialPort initialization stuff here

}

static void timer_Elapsed(object sender, ElapsedEventArgs e)
{
if (dataQueue.Count == 0) { return; }
ProcessData();
}


And last but not least the ProcessData()



private static readonly ReaderWriterLockSlim locker = new ReaderWriterLockSlim();
private static void ProcessData()
{
if (dataQueue.Count == 0) { return; }
if (!locker.TryEnterWriteLock(100)) { return; }

if (isProcessing)
{
locker.ExitWriteLock();
return;
}
isProcessing = true;


List<byte> currentData;
var data = new List<byte>();
var headerIndex = 0;
while (dataQueue.Count > 0)
{
dataQueue.TryDequeue(out currentData);
data.AddRange(currentData);
if (data.Count >= 9)
{
headerIndex = FindHeaderBytesIndex(data);
if (headerIndex != -1 && data.Count - headerIndex >= 9)
{
// now process the message starting at headerIndex
byte message = new byte[9];
data.CopyTo(message, headerIndex);
var checksum = Helpers.CalculateChecksum(message);

var check = message[8];
if (checksum != check)
{
Console.WriteLine("Invalid Checksum");
}
CalculateDistance(message.Skip(2).ToArray());
}
}
}

isProcessing = false;
locker.ExitWriteLock();
}


which needs to be tested by you but at a quick glance it should work.



If you want to know more about SerialPort althought most code is VB.NET, take a look at this.






share|improve this answer























  • if (dataQueue.Count > 0) { return; } in ProcessData - really? I would just call ProcessData from DataReceivedHandler instead of using timer, but good catch with TimeoutException, didn't know => +1
    – firda
    2 hours ago










  • @firda the timer is used because the DataReceived event won't be raised only once. Hence using a timer will avoid blocking the eventhandler.
    – Heslacher
    2 hours ago










  • DataReceived will get raised many times, but never simultaneously in two threads, afaik. ProcessData is not blocking, so I see no problem in calling it from DataReceived (and you even included locking and isProcessing). Second thing I found is that default SerialPort.ReadTimeout is InfiniteTimeout, so, it won't throw TimeoutException unless you change that property. My original version could block the thread, which is not nice, but not catastrophic.
    – firda
    2 hours ago










  • @firda Good point about ReadTimeout. Just a quick question regarding the docs (you linked to the cz version), are the docs as poorly translated to your language like it is for german ?
    – Heslacher
    2 hours ago












  • Yes, very poor, that is why I always switch to english and that is why I didn't notice the link is for CZ. (Reminder: I believe your first line in ProcessData is wrong, should be == 0 not > 0).
    – firda
    1 hour ago











Your Answer





StackExchange.ifUsing("editor", function () {
return StackExchange.using("mathjaxEditing", function () {
StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix) {
StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
});
});
}, "mathjax-editing");

StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");

StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "196"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});

function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
convertImagesToLinks: false,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: null,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});


}
});














 

draft saved


draft discarded


















StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f207078%2freading-range-sensor-data-from-one-serial-port-and-writing-output-to-another%23new-answer', 'question_page');
}
);

Post as a guest
































2 Answers
2






active

oldest

votes








2 Answers
2






active

oldest

votes









active

oldest

votes






active

oldest

votes








up vote
2
down vote













The main problem I see is that you could miss the frame header if it was preceeded by odd number of different bytes (0xAA 0x59 0x59 ... you will try to match AA59 and then 59XX missing 5959). I would therefore rewrite it like this:



static int headerBytes; // counter to help us find 5959
static byte message = new byte[7]; // no need to allocate new array every time
static void DataReceivedHandler(object sender, SerialDataReceivedEventArgs e)
{
// loop to process all messages in case we get 18B or more
for(;;)
{
// read until we find two header bytes
while(headerByes < 2)
{
// see Heslacher's answer for why this check is so important
if (serialPort.BytesToRead == 0) return;
int b = serialPort.ReadByte();
if (b == FrameHeader) headerBytes++;
else headerBytes = 0;
}
// wait until we have full message (7 bytes)
if (serialPort.BytesToRead < message.Length)
return;
// read the message
var bytesRead = serialPort.Read(message, 0, message.Length)
// reset headerBytes counter before any return statement
headerBytes = 0;
// check that everything is according to plan
if (bytesRead < message.Length)
{// this should never happen because we checked BytesToRead
Console.WriteLine($"Invalid data Received. [{bytesRead}]");
return;
}
// now do something with the message, but beware that it does not contain the header now
// so, Helpers.CalculateChecksum would have to be modified
// or message made bigger to always include the header (and change the code above a bit)
// ...
CalculateDistance(message);
}
}


EDIT: I didn't know that ReadByte can throw TimeoutException (see Heslacher's answer), was expecting -1 in that case. I actually do not use SerialPort but my own version, because SerialPort was bugged in .NET 3.5 and caused uncatchable exceptions in GC (from finalizer) when used with Virtual COM (USB) - that could crash whole App and there was no way to fight it.






share|improve this answer



















  • 1




    The downvoter care to explain?
    – firda
    Nov 9 at 10:55















up vote
2
down vote













The main problem I see is that you could miss the frame header if it was preceeded by odd number of different bytes (0xAA 0x59 0x59 ... you will try to match AA59 and then 59XX missing 5959). I would therefore rewrite it like this:



static int headerBytes; // counter to help us find 5959
static byte message = new byte[7]; // no need to allocate new array every time
static void DataReceivedHandler(object sender, SerialDataReceivedEventArgs e)
{
// loop to process all messages in case we get 18B or more
for(;;)
{
// read until we find two header bytes
while(headerByes < 2)
{
// see Heslacher's answer for why this check is so important
if (serialPort.BytesToRead == 0) return;
int b = serialPort.ReadByte();
if (b == FrameHeader) headerBytes++;
else headerBytes = 0;
}
// wait until we have full message (7 bytes)
if (serialPort.BytesToRead < message.Length)
return;
// read the message
var bytesRead = serialPort.Read(message, 0, message.Length)
// reset headerBytes counter before any return statement
headerBytes = 0;
// check that everything is according to plan
if (bytesRead < message.Length)
{// this should never happen because we checked BytesToRead
Console.WriteLine($"Invalid data Received. [{bytesRead}]");
return;
}
// now do something with the message, but beware that it does not contain the header now
// so, Helpers.CalculateChecksum would have to be modified
// or message made bigger to always include the header (and change the code above a bit)
// ...
CalculateDistance(message);
}
}


EDIT: I didn't know that ReadByte can throw TimeoutException (see Heslacher's answer), was expecting -1 in that case. I actually do not use SerialPort but my own version, because SerialPort was bugged in .NET 3.5 and caused uncatchable exceptions in GC (from finalizer) when used with Virtual COM (USB) - that could crash whole App and there was no way to fight it.






share|improve this answer



















  • 1




    The downvoter care to explain?
    – firda
    Nov 9 at 10:55













up vote
2
down vote










up vote
2
down vote









The main problem I see is that you could miss the frame header if it was preceeded by odd number of different bytes (0xAA 0x59 0x59 ... you will try to match AA59 and then 59XX missing 5959). I would therefore rewrite it like this:



static int headerBytes; // counter to help us find 5959
static byte message = new byte[7]; // no need to allocate new array every time
static void DataReceivedHandler(object sender, SerialDataReceivedEventArgs e)
{
// loop to process all messages in case we get 18B or more
for(;;)
{
// read until we find two header bytes
while(headerByes < 2)
{
// see Heslacher's answer for why this check is so important
if (serialPort.BytesToRead == 0) return;
int b = serialPort.ReadByte();
if (b == FrameHeader) headerBytes++;
else headerBytes = 0;
}
// wait until we have full message (7 bytes)
if (serialPort.BytesToRead < message.Length)
return;
// read the message
var bytesRead = serialPort.Read(message, 0, message.Length)
// reset headerBytes counter before any return statement
headerBytes = 0;
// check that everything is according to plan
if (bytesRead < message.Length)
{// this should never happen because we checked BytesToRead
Console.WriteLine($"Invalid data Received. [{bytesRead}]");
return;
}
// now do something with the message, but beware that it does not contain the header now
// so, Helpers.CalculateChecksum would have to be modified
// or message made bigger to always include the header (and change the code above a bit)
// ...
CalculateDistance(message);
}
}


EDIT: I didn't know that ReadByte can throw TimeoutException (see Heslacher's answer), was expecting -1 in that case. I actually do not use SerialPort but my own version, because SerialPort was bugged in .NET 3.5 and caused uncatchable exceptions in GC (from finalizer) when used with Virtual COM (USB) - that could crash whole App and there was no way to fight it.






share|improve this answer














The main problem I see is that you could miss the frame header if it was preceeded by odd number of different bytes (0xAA 0x59 0x59 ... you will try to match AA59 and then 59XX missing 5959). I would therefore rewrite it like this:



static int headerBytes; // counter to help us find 5959
static byte message = new byte[7]; // no need to allocate new array every time
static void DataReceivedHandler(object sender, SerialDataReceivedEventArgs e)
{
// loop to process all messages in case we get 18B or more
for(;;)
{
// read until we find two header bytes
while(headerByes < 2)
{
// see Heslacher's answer for why this check is so important
if (serialPort.BytesToRead == 0) return;
int b = serialPort.ReadByte();
if (b == FrameHeader) headerBytes++;
else headerBytes = 0;
}
// wait until we have full message (7 bytes)
if (serialPort.BytesToRead < message.Length)
return;
// read the message
var bytesRead = serialPort.Read(message, 0, message.Length)
// reset headerBytes counter before any return statement
headerBytes = 0;
// check that everything is according to plan
if (bytesRead < message.Length)
{// this should never happen because we checked BytesToRead
Console.WriteLine($"Invalid data Received. [{bytesRead}]");
return;
}
// now do something with the message, but beware that it does not contain the header now
// so, Helpers.CalculateChecksum would have to be modified
// or message made bigger to always include the header (and change the code above a bit)
// ...
CalculateDistance(message);
}
}


EDIT: I didn't know that ReadByte can throw TimeoutException (see Heslacher's answer), was expecting -1 in that case. I actually do not use SerialPort but my own version, because SerialPort was bugged in .NET 3.5 and caused uncatchable exceptions in GC (from finalizer) when used with Virtual COM (USB) - that could crash whole App and there was no way to fight it.







share|improve this answer














share|improve this answer



share|improve this answer








edited 2 hours ago

























answered Nov 9 at 10:36









firda

2,642627




2,642627








  • 1




    The downvoter care to explain?
    – firda
    Nov 9 at 10:55














  • 1




    The downvoter care to explain?
    – firda
    Nov 9 at 10:55








1




1




The downvoter care to explain?
– firda
Nov 9 at 10:55




The downvoter care to explain?
– firda
Nov 9 at 10:55












up vote
2
down vote













This




if (serialPort.BytesToRead < 9)
return;

while (true)
{
if (headerBytes[0] == FrameHeader && headerBytes[1] == FrameHeader)
break;

serialPort.Read(headerBytes, 0, headerBytes.Length);
}



can get dangerous. Not only because what @firda has stated in his answer but the reading of the serialport without questioning the serialPort.BytesToRead again. Assume that at the if you get a serialPort.BytesToRead == 9 but if (headerBytes[0] == FrameHeader && headerBytes[1] == FrameHeader) isn't true then somewhere down the road your code could crash with a TimeoutException because you read but there aren't any bytes left to read.



A better approach would be to just read all the bytes avaible and place them in a ConcurrentQueue<List<byte>> like so



private static ConcurrentQueue<List<byte>> dataQueue = new ConcurrentQueue<List<byte>>();
static void DataReceivedHandler(object sender, SerialDataReceivedEventArgs e)
{
var serialPort = sender as SerialPort;
if (serialPort == null || serialPort.BytesToRead == 0) { return; }

var receivedData = new byte[serialPort.BytesToRead];
var readBytes = serialPort.Read(receivedData, 0, serialPort.BytesToRead);

dataQueue.Enqueue(receivedData.Take(readBytes).ToList());

}


which keeps your DataReceived eventhandler short and clean.



To process the received data you can add a Timer e.g set to an interval of 250ms which calls a method ProcessData in its elapsed event only if dataQueue.Count > 0 like so



private static System.Timers.Timer timer = new System.Timers.Timer();
static void Main(string args)
{
timer.Interval = 250;
timer.Elapsed += new ElapsedEventHandler(timer_Elapsed);
timer.Start();

// Your SerialPort initialization stuff here

}

static void timer_Elapsed(object sender, ElapsedEventArgs e)
{
if (dataQueue.Count == 0) { return; }
ProcessData();
}


And last but not least the ProcessData()



private static readonly ReaderWriterLockSlim locker = new ReaderWriterLockSlim();
private static void ProcessData()
{
if (dataQueue.Count == 0) { return; }
if (!locker.TryEnterWriteLock(100)) { return; }

if (isProcessing)
{
locker.ExitWriteLock();
return;
}
isProcessing = true;


List<byte> currentData;
var data = new List<byte>();
var headerIndex = 0;
while (dataQueue.Count > 0)
{
dataQueue.TryDequeue(out currentData);
data.AddRange(currentData);
if (data.Count >= 9)
{
headerIndex = FindHeaderBytesIndex(data);
if (headerIndex != -1 && data.Count - headerIndex >= 9)
{
// now process the message starting at headerIndex
byte message = new byte[9];
data.CopyTo(message, headerIndex);
var checksum = Helpers.CalculateChecksum(message);

var check = message[8];
if (checksum != check)
{
Console.WriteLine("Invalid Checksum");
}
CalculateDistance(message.Skip(2).ToArray());
}
}
}

isProcessing = false;
locker.ExitWriteLock();
}


which needs to be tested by you but at a quick glance it should work.



If you want to know more about SerialPort althought most code is VB.NET, take a look at this.






share|improve this answer























  • if (dataQueue.Count > 0) { return; } in ProcessData - really? I would just call ProcessData from DataReceivedHandler instead of using timer, but good catch with TimeoutException, didn't know => +1
    – firda
    2 hours ago










  • @firda the timer is used because the DataReceived event won't be raised only once. Hence using a timer will avoid blocking the eventhandler.
    – Heslacher
    2 hours ago










  • DataReceived will get raised many times, but never simultaneously in two threads, afaik. ProcessData is not blocking, so I see no problem in calling it from DataReceived (and you even included locking and isProcessing). Second thing I found is that default SerialPort.ReadTimeout is InfiniteTimeout, so, it won't throw TimeoutException unless you change that property. My original version could block the thread, which is not nice, but not catastrophic.
    – firda
    2 hours ago










  • @firda Good point about ReadTimeout. Just a quick question regarding the docs (you linked to the cz version), are the docs as poorly translated to your language like it is for german ?
    – Heslacher
    2 hours ago












  • Yes, very poor, that is why I always switch to english and that is why I didn't notice the link is for CZ. (Reminder: I believe your first line in ProcessData is wrong, should be == 0 not > 0).
    – firda
    1 hour ago















up vote
2
down vote













This




if (serialPort.BytesToRead < 9)
return;

while (true)
{
if (headerBytes[0] == FrameHeader && headerBytes[1] == FrameHeader)
break;

serialPort.Read(headerBytes, 0, headerBytes.Length);
}



can get dangerous. Not only because what @firda has stated in his answer but the reading of the serialport without questioning the serialPort.BytesToRead again. Assume that at the if you get a serialPort.BytesToRead == 9 but if (headerBytes[0] == FrameHeader && headerBytes[1] == FrameHeader) isn't true then somewhere down the road your code could crash with a TimeoutException because you read but there aren't any bytes left to read.



A better approach would be to just read all the bytes avaible and place them in a ConcurrentQueue<List<byte>> like so



private static ConcurrentQueue<List<byte>> dataQueue = new ConcurrentQueue<List<byte>>();
static void DataReceivedHandler(object sender, SerialDataReceivedEventArgs e)
{
var serialPort = sender as SerialPort;
if (serialPort == null || serialPort.BytesToRead == 0) { return; }

var receivedData = new byte[serialPort.BytesToRead];
var readBytes = serialPort.Read(receivedData, 0, serialPort.BytesToRead);

dataQueue.Enqueue(receivedData.Take(readBytes).ToList());

}


which keeps your DataReceived eventhandler short and clean.



To process the received data you can add a Timer e.g set to an interval of 250ms which calls a method ProcessData in its elapsed event only if dataQueue.Count > 0 like so



private static System.Timers.Timer timer = new System.Timers.Timer();
static void Main(string args)
{
timer.Interval = 250;
timer.Elapsed += new ElapsedEventHandler(timer_Elapsed);
timer.Start();

// Your SerialPort initialization stuff here

}

static void timer_Elapsed(object sender, ElapsedEventArgs e)
{
if (dataQueue.Count == 0) { return; }
ProcessData();
}


And last but not least the ProcessData()



private static readonly ReaderWriterLockSlim locker = new ReaderWriterLockSlim();
private static void ProcessData()
{
if (dataQueue.Count == 0) { return; }
if (!locker.TryEnterWriteLock(100)) { return; }

if (isProcessing)
{
locker.ExitWriteLock();
return;
}
isProcessing = true;


List<byte> currentData;
var data = new List<byte>();
var headerIndex = 0;
while (dataQueue.Count > 0)
{
dataQueue.TryDequeue(out currentData);
data.AddRange(currentData);
if (data.Count >= 9)
{
headerIndex = FindHeaderBytesIndex(data);
if (headerIndex != -1 && data.Count - headerIndex >= 9)
{
// now process the message starting at headerIndex
byte message = new byte[9];
data.CopyTo(message, headerIndex);
var checksum = Helpers.CalculateChecksum(message);

var check = message[8];
if (checksum != check)
{
Console.WriteLine("Invalid Checksum");
}
CalculateDistance(message.Skip(2).ToArray());
}
}
}

isProcessing = false;
locker.ExitWriteLock();
}


which needs to be tested by you but at a quick glance it should work.



If you want to know more about SerialPort althought most code is VB.NET, take a look at this.






share|improve this answer























  • if (dataQueue.Count > 0) { return; } in ProcessData - really? I would just call ProcessData from DataReceivedHandler instead of using timer, but good catch with TimeoutException, didn't know => +1
    – firda
    2 hours ago










  • @firda the timer is used because the DataReceived event won't be raised only once. Hence using a timer will avoid blocking the eventhandler.
    – Heslacher
    2 hours ago










  • DataReceived will get raised many times, but never simultaneously in two threads, afaik. ProcessData is not blocking, so I see no problem in calling it from DataReceived (and you even included locking and isProcessing). Second thing I found is that default SerialPort.ReadTimeout is InfiniteTimeout, so, it won't throw TimeoutException unless you change that property. My original version could block the thread, which is not nice, but not catastrophic.
    – firda
    2 hours ago










  • @firda Good point about ReadTimeout. Just a quick question regarding the docs (you linked to the cz version), are the docs as poorly translated to your language like it is for german ?
    – Heslacher
    2 hours ago












  • Yes, very poor, that is why I always switch to english and that is why I didn't notice the link is for CZ. (Reminder: I believe your first line in ProcessData is wrong, should be == 0 not > 0).
    – firda
    1 hour ago













up vote
2
down vote










up vote
2
down vote









This




if (serialPort.BytesToRead < 9)
return;

while (true)
{
if (headerBytes[0] == FrameHeader && headerBytes[1] == FrameHeader)
break;

serialPort.Read(headerBytes, 0, headerBytes.Length);
}



can get dangerous. Not only because what @firda has stated in his answer but the reading of the serialport without questioning the serialPort.BytesToRead again. Assume that at the if you get a serialPort.BytesToRead == 9 but if (headerBytes[0] == FrameHeader && headerBytes[1] == FrameHeader) isn't true then somewhere down the road your code could crash with a TimeoutException because you read but there aren't any bytes left to read.



A better approach would be to just read all the bytes avaible and place them in a ConcurrentQueue<List<byte>> like so



private static ConcurrentQueue<List<byte>> dataQueue = new ConcurrentQueue<List<byte>>();
static void DataReceivedHandler(object sender, SerialDataReceivedEventArgs e)
{
var serialPort = sender as SerialPort;
if (serialPort == null || serialPort.BytesToRead == 0) { return; }

var receivedData = new byte[serialPort.BytesToRead];
var readBytes = serialPort.Read(receivedData, 0, serialPort.BytesToRead);

dataQueue.Enqueue(receivedData.Take(readBytes).ToList());

}


which keeps your DataReceived eventhandler short and clean.



To process the received data you can add a Timer e.g set to an interval of 250ms which calls a method ProcessData in its elapsed event only if dataQueue.Count > 0 like so



private static System.Timers.Timer timer = new System.Timers.Timer();
static void Main(string args)
{
timer.Interval = 250;
timer.Elapsed += new ElapsedEventHandler(timer_Elapsed);
timer.Start();

// Your SerialPort initialization stuff here

}

static void timer_Elapsed(object sender, ElapsedEventArgs e)
{
if (dataQueue.Count == 0) { return; }
ProcessData();
}


And last but not least the ProcessData()



private static readonly ReaderWriterLockSlim locker = new ReaderWriterLockSlim();
private static void ProcessData()
{
if (dataQueue.Count == 0) { return; }
if (!locker.TryEnterWriteLock(100)) { return; }

if (isProcessing)
{
locker.ExitWriteLock();
return;
}
isProcessing = true;


List<byte> currentData;
var data = new List<byte>();
var headerIndex = 0;
while (dataQueue.Count > 0)
{
dataQueue.TryDequeue(out currentData);
data.AddRange(currentData);
if (data.Count >= 9)
{
headerIndex = FindHeaderBytesIndex(data);
if (headerIndex != -1 && data.Count - headerIndex >= 9)
{
// now process the message starting at headerIndex
byte message = new byte[9];
data.CopyTo(message, headerIndex);
var checksum = Helpers.CalculateChecksum(message);

var check = message[8];
if (checksum != check)
{
Console.WriteLine("Invalid Checksum");
}
CalculateDistance(message.Skip(2).ToArray());
}
}
}

isProcessing = false;
locker.ExitWriteLock();
}


which needs to be tested by you but at a quick glance it should work.



If you want to know more about SerialPort althought most code is VB.NET, take a look at this.






share|improve this answer














This




if (serialPort.BytesToRead < 9)
return;

while (true)
{
if (headerBytes[0] == FrameHeader && headerBytes[1] == FrameHeader)
break;

serialPort.Read(headerBytes, 0, headerBytes.Length);
}



can get dangerous. Not only because what @firda has stated in his answer but the reading of the serialport without questioning the serialPort.BytesToRead again. Assume that at the if you get a serialPort.BytesToRead == 9 but if (headerBytes[0] == FrameHeader && headerBytes[1] == FrameHeader) isn't true then somewhere down the road your code could crash with a TimeoutException because you read but there aren't any bytes left to read.



A better approach would be to just read all the bytes avaible and place them in a ConcurrentQueue<List<byte>> like so



private static ConcurrentQueue<List<byte>> dataQueue = new ConcurrentQueue<List<byte>>();
static void DataReceivedHandler(object sender, SerialDataReceivedEventArgs e)
{
var serialPort = sender as SerialPort;
if (serialPort == null || serialPort.BytesToRead == 0) { return; }

var receivedData = new byte[serialPort.BytesToRead];
var readBytes = serialPort.Read(receivedData, 0, serialPort.BytesToRead);

dataQueue.Enqueue(receivedData.Take(readBytes).ToList());

}


which keeps your DataReceived eventhandler short and clean.



To process the received data you can add a Timer e.g set to an interval of 250ms which calls a method ProcessData in its elapsed event only if dataQueue.Count > 0 like so



private static System.Timers.Timer timer = new System.Timers.Timer();
static void Main(string args)
{
timer.Interval = 250;
timer.Elapsed += new ElapsedEventHandler(timer_Elapsed);
timer.Start();

// Your SerialPort initialization stuff here

}

static void timer_Elapsed(object sender, ElapsedEventArgs e)
{
if (dataQueue.Count == 0) { return; }
ProcessData();
}


And last but not least the ProcessData()



private static readonly ReaderWriterLockSlim locker = new ReaderWriterLockSlim();
private static void ProcessData()
{
if (dataQueue.Count == 0) { return; }
if (!locker.TryEnterWriteLock(100)) { return; }

if (isProcessing)
{
locker.ExitWriteLock();
return;
}
isProcessing = true;


List<byte> currentData;
var data = new List<byte>();
var headerIndex = 0;
while (dataQueue.Count > 0)
{
dataQueue.TryDequeue(out currentData);
data.AddRange(currentData);
if (data.Count >= 9)
{
headerIndex = FindHeaderBytesIndex(data);
if (headerIndex != -1 && data.Count - headerIndex >= 9)
{
// now process the message starting at headerIndex
byte message = new byte[9];
data.CopyTo(message, headerIndex);
var checksum = Helpers.CalculateChecksum(message);

var check = message[8];
if (checksum != check)
{
Console.WriteLine("Invalid Checksum");
}
CalculateDistance(message.Skip(2).ToArray());
}
}
}

isProcessing = false;
locker.ExitWriteLock();
}


which needs to be tested by you but at a quick glance it should work.



If you want to know more about SerialPort althought most code is VB.NET, take a look at this.







share|improve this answer














share|improve this answer



share|improve this answer








edited 1 hour ago

























answered 15 hours ago









Heslacher

44.4k460153




44.4k460153












  • if (dataQueue.Count > 0) { return; } in ProcessData - really? I would just call ProcessData from DataReceivedHandler instead of using timer, but good catch with TimeoutException, didn't know => +1
    – firda
    2 hours ago










  • @firda the timer is used because the DataReceived event won't be raised only once. Hence using a timer will avoid blocking the eventhandler.
    – Heslacher
    2 hours ago










  • DataReceived will get raised many times, but never simultaneously in two threads, afaik. ProcessData is not blocking, so I see no problem in calling it from DataReceived (and you even included locking and isProcessing). Second thing I found is that default SerialPort.ReadTimeout is InfiniteTimeout, so, it won't throw TimeoutException unless you change that property. My original version could block the thread, which is not nice, but not catastrophic.
    – firda
    2 hours ago










  • @firda Good point about ReadTimeout. Just a quick question regarding the docs (you linked to the cz version), are the docs as poorly translated to your language like it is for german ?
    – Heslacher
    2 hours ago












  • Yes, very poor, that is why I always switch to english and that is why I didn't notice the link is for CZ. (Reminder: I believe your first line in ProcessData is wrong, should be == 0 not > 0).
    – firda
    1 hour ago


















  • if (dataQueue.Count > 0) { return; } in ProcessData - really? I would just call ProcessData from DataReceivedHandler instead of using timer, but good catch with TimeoutException, didn't know => +1
    – firda
    2 hours ago










  • @firda the timer is used because the DataReceived event won't be raised only once. Hence using a timer will avoid blocking the eventhandler.
    – Heslacher
    2 hours ago










  • DataReceived will get raised many times, but never simultaneously in two threads, afaik. ProcessData is not blocking, so I see no problem in calling it from DataReceived (and you even included locking and isProcessing). Second thing I found is that default SerialPort.ReadTimeout is InfiniteTimeout, so, it won't throw TimeoutException unless you change that property. My original version could block the thread, which is not nice, but not catastrophic.
    – firda
    2 hours ago










  • @firda Good point about ReadTimeout. Just a quick question regarding the docs (you linked to the cz version), are the docs as poorly translated to your language like it is for german ?
    – Heslacher
    2 hours ago












  • Yes, very poor, that is why I always switch to english and that is why I didn't notice the link is for CZ. (Reminder: I believe your first line in ProcessData is wrong, should be == 0 not > 0).
    – firda
    1 hour ago
















if (dataQueue.Count > 0) { return; } in ProcessData - really? I would just call ProcessData from DataReceivedHandler instead of using timer, but good catch with TimeoutException, didn't know => +1
– firda
2 hours ago




if (dataQueue.Count > 0) { return; } in ProcessData - really? I would just call ProcessData from DataReceivedHandler instead of using timer, but good catch with TimeoutException, didn't know => +1
– firda
2 hours ago












@firda the timer is used because the DataReceived event won't be raised only once. Hence using a timer will avoid blocking the eventhandler.
– Heslacher
2 hours ago




@firda the timer is used because the DataReceived event won't be raised only once. Hence using a timer will avoid blocking the eventhandler.
– Heslacher
2 hours ago












DataReceived will get raised many times, but never simultaneously in two threads, afaik. ProcessData is not blocking, so I see no problem in calling it from DataReceived (and you even included locking and isProcessing). Second thing I found is that default SerialPort.ReadTimeout is InfiniteTimeout, so, it won't throw TimeoutException unless you change that property. My original version could block the thread, which is not nice, but not catastrophic.
– firda
2 hours ago




DataReceived will get raised many times, but never simultaneously in two threads, afaik. ProcessData is not blocking, so I see no problem in calling it from DataReceived (and you even included locking and isProcessing). Second thing I found is that default SerialPort.ReadTimeout is InfiniteTimeout, so, it won't throw TimeoutException unless you change that property. My original version could block the thread, which is not nice, but not catastrophic.
– firda
2 hours ago












@firda Good point about ReadTimeout. Just a quick question regarding the docs (you linked to the cz version), are the docs as poorly translated to your language like it is for german ?
– Heslacher
2 hours ago






@firda Good point about ReadTimeout. Just a quick question regarding the docs (you linked to the cz version), are the docs as poorly translated to your language like it is for german ?
– Heslacher
2 hours ago














Yes, very poor, that is why I always switch to english and that is why I didn't notice the link is for CZ. (Reminder: I believe your first line in ProcessData is wrong, should be == 0 not > 0).
– firda
1 hour ago




Yes, very poor, that is why I always switch to english and that is why I didn't notice the link is for CZ. (Reminder: I believe your first line in ProcessData is wrong, should be == 0 not > 0).
– firda
1 hour ago


















 

draft saved


draft discarded



















































 


draft saved


draft discarded














StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f207078%2freading-range-sensor-data-from-one-serial-port-and-writing-output-to-another%23new-answer', 'question_page');
}
);

Post as a guest




















































































Popular posts from this blog

List directoties down one level, excluding some named directories and files

list processes belonging to a network namespace

list systemd RuntimeDirectory mounts