Reputation: 81
I'm taking data from a serial instrument for plotting on a chart. The data stream is 230 kbps, and the serial pipeline is less than 50% full, data arrives about 100 kbps and actually doesn't vary really and rate or quantity.
Having used just a serial terminal program, like Teraterm, on the same computer; I can capture data and prove that both the source of the data as well as the test reception method are fine and I see no errors to the captured data.
The Windows Forms application I'm developing loses data. I've reduced it from receiving, capturing (in parallel), parsing, and plotting, to just receiving and capturing. And have found that I still see lost data in the capture.
I'm not a long experienced Windows person, so therefore may not know of better ways to accomplish the same functions. Here are the actions I'm taking to perform receive actions:
I'm using a System.IO.Ports.SerialPort class. I modify the .DataReceived event via:
+= new SerialDataReceivedEventHandler(comPort_DataReceive);
I then call the open() method.
Note: I may be doing something incorrect here, I never clear the .DataReceived event with a -= at any point, instead each time I open, the event is added yet again. Nevertheless, these problems occur even when I've only talked to the port once.
Here's my code for the data receive function. RxString is a string.
private void comPort_DataReceive(object sender, SerialDataReceivedEventArgs e)
{
RxString = comPort.ReadExisting();
this.Invoke(new EventHandler(ParseData));
}
private void ParseData(object sender, EventArgs e)
{
// Save to capture file, if capture is enabled
if ((WriteToFileEnabled == true) && (WriteToFileName != null))
{
writeFileHandle.Write(RxString);
}
return;
// Previously would parse and plot data
}
So, how would persons execute a receive in this situation to get this data without losing it?
Follow on questions are things like: How big is the buffer for serial receive, or do I need to worry about that if I have a reasonably responsive application? Flow control is irrelevant, the remote device is going to send data no matter what, so it would be up to my computer to take that data and process it or ignore it. But how would I know if I've lost data or experienced framing errors and stuff? (I ask that last one without having searched much on the SerialPort class structure, sorry.)
Upvotes: 1
Views: 588
Reputation: 11773
Lets assume that your device is sending messages that are 85 bytes in length. The DataReceive event handler may or may not fire once to receive those 85 bytes. Since it might fire more than once your code must account for that. The DataReceive event handler should read the bytes available and append them to a buffer that is processed later.
Also, only one of the events raised by the SerialPort class can execute at a time. In the example assume the handler has to fire three times to receive the 85 bytes. While processing the first part the other two can't execute. If while processing the first part one of the other events, PinChanged or ErrorReceived, are needed they can't be executed either.
My first two experiences with the SerialPort class were a 9600 bps terminal and a 1 Mbps bluetooth device. What worked for the slower did not work for the faster, but when I figured out how to get the faster to work the slower could use the same methodology.
My methodology:
Before opening the serial port I start two other background threads that run in a do loop. The first one(Receive) reads all available bytes from the serial port, adds them to a buffer, and signals the second thread on every read. The second one(Protocol) determines if a full message has arrived, does any byte to string conversion, updates the UI, etc. Depending on the application I may start a third thread that handles errors and pin changes. All of these threads are throttled by a Threading AutoResetEvent.
My DataReceive event handler has one line in it, a Set on the AutoResetEvent that is throttling Receive.
A VB example of this can be found here SerialPort Methodology. Since adopting this methodology I have not had any of the problems that seem to plague other SerialPort users and have used it successfully with speeds up to 2Mbps.
Upvotes: 3