Question

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 :)

Was it helpful?

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.

OTHER TIPS

I think you're missing the point of the using block. A typical using block will look like this:

using (var resource = new SomeResource())
{
    resource.DoSomething();
}

The opening happens at the very beginning. Typically as part of the constructor. But sometimes on the first line of the using block.

But the big red flag I see is that the closing happens automatically. You don't need the .Close() call.

If the successful operation of your serial device is dependent on the calls to Thread.Sleep then perhaps the thread is being interrupted at some point, sufficient to make the data transmission out of sync with the device. There would most likely be ways to solve this but the first thing I would do is try to use the .NET SerialPort class instead. The Write method is very similar to what you want to do, and there are C++ code examples in those articles.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top