Had to implement a 9-bit serial port protocol under c#. Normally, the 8 bit information transfer is supported by the .NET SerialPort class, whereas the extra bit is used for parity check.
To send a 9 bit through the serial port is pretty easy: Send the first 8 bits normally with either a Mark(=1)/Space(=0) parity setting for the extra 9th bit.
The hell I went through involves SENDING each 9 bits, and this is where my story starts…
Using the .NET SerialPort Class
To recieve byte, I set my serial port to a Space(=0) parity setting, and for each byte I would check for a parity error. No parity error = 9th bit 0, whereas a parity error = 9th bit 1.
Sounds easy, right? WRONG!
.NET Serial Class gives you 2 interfaces to identify parity errors. The first is an event called ErrorRecieved which according to MS:
ErrorReceived events may be called out of order, and there may be a slight delay between when the underlying stream reports the error and when code can when the event handler is executed.
The ErrorReceived event is raised on a secondary thread when an error is received from the SerialPort object. Because this event is raised on a secondary thread, and not the main thread
According to this and the event delegate signature, when a parity error occures you can not rely it will happen in a reasonable time nor will you know on which of the bytes the error had occured.
Second way is to use the ParityReplace member which quite effectively, replace a parity errored-byte into a value of your choosing. This allows parity detection for the price of the 8 bits it follows. No good as well.
Using Windows API functions
So I wrote a new SerialPort class which encapsulates the P/Invoke’ed Win32 API functions using some nice examples across the web. This time, detecting a parity error went without a hitch, I’d ReadFile a single byte from the port and then check for the last error for a parity problem. Another nice touch is to use the fAbortOnError member in the DCB which stops all read operation upon stumbling an error (specifically, a parity error).
This proved to be a working solution, until it was used under the production environment. It appeared that detecting parity errors (the 9th bit) worked inconsistently. Further inspection of both the program and the web, revealed that the root of the problem lies in a much lower level – the windows serial.sys device driver.
The Serial Port Device Driver
Every unhandled incoming data recieved by the serial port is queued into the driver FIFO buffer to be handled by the next API read. Whoever wrote this driver, only queued the recieved bytes and not the recieved data (both the 8 bits and the parity bit). So if your program is polling information fast enough not to let any byte enter the buffer you’re safe, and if you plan any other non-serial-polling-software-centric you’re not.
So i turned to the Windows Driver Kit to revise the current serial.sys (code included with the WDK) driver to fit to my needs. It took a while, but now when the serial port recieves a byte, it enqueues two bytes: the recieved byte and the parity.