Search code examples
c#serial-portusingdata-loss

C# "using" SerialPort transmit with data loss


I'm new to this forum, and I have a question that has been bothering me for a while. My setup is a serial enabled character display connected to my pc with a usb/uart converter. I'm transmitting bytes to the display via the serialPort class in a separate write buffer thread in a C++ style:

private void transmitThread(){
    while(threadAlive){
        if(q.Count > 0){ // Queue not empty
            byte[] b = q.Dequeue();
            s.Write(b,0,b.Length);
            System.Threading.Thread.Sleep(100);
        }
        else{ // Queue empty
            System.Threading.Thread.Sleep(10);
        }
    }
}

Assuming the serial port is already opened, this works perfectly and transmits all the data to the display. There are though no exception handling at all in this snippet. Therefore I was looking into implementing a typical C# feature, the 'using' statement and only opening the port when needed, like so:

private void transmitThread(){
    while(threadAlive){
        if(q.Count > 0){ // Queue not empty
            byte[] b = q.Dequeue();
            using(s){ //using the serialPort
                s.Open();
                s.Write(b,0,b.Length);
                s.Close();
            }
            System.Threading.Thread.Sleep(100);
        }
        else{ // Queue empty
            System.Threading.Thread.Sleep(10);
        }
    }
}

The problem with this function is, that it only transmits a random amount of the data, typically about one third of the byte-array of 80 bytes. I have tried different priority settings of the thread, but nothing changes.

Am I missing something important, or do I simply close the port too fast after a transmit request?

I hope you can help me. Thanks :)


Solution

  • No, that was a Really Bad Idea. The things that go wrong, roughly in the order you'll encounter them:

    • the serial port driver discards any bytes left in the transmit buffer that were not yet transmitted when you close the port. Which is what you are seeing now.

    • the MSDN article for SerialPort.Close() warns that you must "wait a while" before opening the port again. There's an internal worker thread that needs to shut down. The amount of time you have to wait is not specified and is variable, depending on machine load.

    • closing a port allows another program to grab the port and open it. Serial ports cannot be shared, your program will fail when you try to open it again.

    Serial ports were simply not designed to be opened and closed on-the-fly. Only open it at the start of your program, close it when it ends. Not calling Close() at all is quite acceptable and avoids a deadlock scenario.