Introduction
This is an article about the System.IO.Ports.SerialPort
bug and a work around for it.
Problem
It seems there is a flaw in the design within instances of the SerialPort
class in the .NET 2.0 Framework. When too much information comes in on the serialport instance at a rather quick rate, the dataReceived
event does not fire. For example, when using a GPS unit that adheres to the NMEA standard, information is continuously pumped to the serial port at a rather high rate. For some reason, this prevents the DataReceived
event from firing. Also, when attempting to check the size of the buffer using the BytesToRead
property on the instance there will always be a 0, so you cannot really properly size an array to its extents for a good read loop.
My colleague and I ran into this problem on a project, and as he scoured forum threads, FAQ's, and MSDN with no luck, I sat at my desk hacking at the problem. I played with various methods within the SerialPort
object, and found a little trick that may help those forum threads that never got resolved.
Solution
Create a timed event perhaps using a forms.timer
or a timer
class (if you are not doing this from within a Windows Form). On its tick
event, call your serialport
s' readbyte
method, and append the byte to a module level variable that can be concatenated with the rest of the buffer. When this is called, the serialport
instance actually gets a grasp on what is going on for a brief moment and the DataReceived
event is actually fired! YAY, now you can get your hands on the number of the bytes that are available, as well as read what is inside the buffer! But don't celebrate just yet. The SerialPort
is not fixed, and the event will only fire each time you call the readbyte
method (which is why I decided to use a timer).
This is by no means a perfect solution. We have benchmarked the results and realized that the information is not fragmented or out of order for our purpose. The DataReceived
event does not fire until after the readbyte
method is called so information does not actually show up in the wrong place. I have not attempted to do anything between the concatenation. As soon as I called the readbyte
I concatenated. It may be possible that if you perform other statements after the readbyte
and before its concatenation that the delegate
running the DataReceived
event handler will concatenate before the readbyte
since it is running on a separate thread, so keep this in mind. This may seem like a rather gimmicked work around but it works. The only way to make it perfect is for someone at Microsoft who has a little influence to catch wind of this, and make a change.
I am not sure if this is isolated to the .NET Framework, however. We were using a serialport
OCX in a .NET 1.1 application we have, and in 2.0 which had the same problem, we didn't bother to experiment with it in the 2.0 Framework and since we were porting the 1.1 application to the 2.0 Framework, there was no need to keep the OCX around. As such, it could be a flaw in the CreateFile
API (if my suspicions are correct in that the SerialPort
class may be a wrapper for the API call), or a flaw somewhere else in the code. If this is the case, they may have fixed it in the Vista recode, but something tells me that they didn't do a complete recode⦠Why fix what isn't broken (that we all know about anyway?)
History
- 23rd February, 2007: Initial post