3

I have a C program which opens a handle to a COM port, writes some bytes to it, reads some bytes out, then closes the handle and exits. However, when I run the program like 10 times in a row, it starts to take very long to complete the GetCommState function and to get stuck in the SetCommState function. The same thing happens in C# with a simple SerialPort object.

The only fix I could find is reconnecting the device to the port. Is there some more elegant way to get rid of this freeze? Is it maybe just some PC configuration error?

Update

I've rewritten the code to make it use DeviceIoControl instead of SetCommState. However, it's exactly the same problem here.

device = 
    CreateFileW(
        L"\\\\.\\COM3", GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 
        FILE_FLAG_OVERLAPPED, NULL);

static int SetBaudRate (HANDLE device) {
    int error = 0;
    int success = 0;
    OVERLAPPED overlapped = {0};
    overlapped.hEvent = CreateEvent(NULL, TRUE, 0, NULL);
    if (overlapped.hEvent) {
        SERIAL_BAUD_RATE baudRate = {0};
        baudRate.BaudRate = SERIAL_BAUD_115200;
        error = 
            DeviceIoControl(
                device, IOCTL_SERIAL_SET_BAUD_RATE, &baudRate, 
                sizeof(SERIAL_BAUD_RATE), NULL, 0, NULL, &overlapped);
        if (error || (!error && GetLastError() == ERROR_IO_PENDING)) {
            DWORD bytes = 0;
            if (GetOverlappedResult(device, &overlapped, &bytes, TRUE)) {
                success = 1;
            }
        }
    }
    CloseHandle(overlapped.hEvent);
    return success;
}

First problem: DeviceIoControl doesn't return immediately (although called asynchronously) and hangs for about two minutes. Second problem: It fails with error code 121 (ERR_SEM_TIMEOUT: "The semaphore timeout period has expired.") after those two minutes.

  • The used driver is the standard windows driver usbser.sys
  • Any idea on why the function call doesn't return immediately? And if not, how to set a shorter timeout for the function?
  • Any idea on why the function is failing?

Update 2

Sample C# code which freezes also (like the C program above):

using System;
using System.IO.Ports;

sealed class Program {
    static void Main (string[] args) {
        int i = 0;
        while (true) {
            Console.WriteLine(++i);
            SerialPort p = 
                new SerialPort("com3", 115200, Parity.None, 8, StopBits.One);
            p.DtrEnable = true;
            p.RtsEnable = true;
            p.ParityReplace = 0;
            p.WriteTimeout = 10000;
            p.ReadTimeout = 3000;
            try {
                p.Open();
                Console.WriteLine("Success!");
            } catch (Exception e) {
                Console.WriteLine(e.GetType().Name + ": " + e.Message);
            }
            p.Close();
            Console.ReadLine();
        }
    }
}

A sample output is the following:

1 (device not yet connected)
IOException: The port 'com3' does not exist.

2 (device connected but not yet in windows device manager)
IOException: The port 'com3' does not exist.

3
IOException: The port 'com3' does not exist.

4 (device connected and recognized)
Success!

5
Success!

[...] (with about one second between each enter press)

15
Success!

16 (device still connected and recognized - nothing touched! after two minutes of freeze, semaphore timeout exactly as in the C version)
IOException: The semaphore timeout period has expired.


17 (device disconnected during the two minutes of freeze. it then returns instantly)
IOException: A device attached to the system is not functioning.


18 (device still disconnected - note that the exception is a different one than the one in the beginning although it's the same case: device not connected)
IOException: The specified port does not exist.

19
IOException: The port 'com3' does not exist.
Etan
  • 17,014
  • 17
  • 89
  • 148
  • When you say it "freezes the system" is the "system" just your program or your whole computer? – Gabe Jul 19 '11 at 15:58
  • Just the program. When I step through the code with a debugger, GetCommState returns after like 1 minute and SetCommState takes much longer until it fails due to timeout. – Etan Jul 19 '11 at 17:19
  • Is this a built-in serial port, a virtual port, a USB serial port, or something else? – Gabe Jul 19 '11 at 17:24
  • The options are "built-in" *or* "USB". What is a "built-in USB" COM port? – Gabe Jul 19 '11 at 17:29
  • So, wait, your computer has a USB-to-serial converter on the motherboard? What? – bdonlan Jul 19 '11 at 17:29
  • I connect the device to the USB-port of the computer, and access it over COM3 for example where it registers itself. – Etan Jul 19 '11 at 17:47
  • Check if there are updated drivers for your USB serial device. – Michael Burr Jul 19 '11 at 19:16
  • You are NOT accessing a USB port. You are accessing a COM port, which is something entirely different. Your device, when plugged in, adds a virtual COM port, to which you are communicating. But the whole USB thing is hidden from your program. – Vilx- Jul 26 '11 at 11:35
  • From MSDN: "`lpOverlapped` must point to a valid `OVERLAPPED` structure that contains a handle to an event object. Otherwise, the function fails in unpredictable ways." Also, you have to allocate your `OVERLAPPED` structure -- you can't use a local variable for that. – Gabe Jul 26 '11 at 11:46
  • Since I wait for the completion of the overlapped operation inside the function, the operation completes without the overlapped structure going out of scope. However, the detail with the event object may be helpful - trying it now with an additional manualresetevent. Updated the code also in the code snippet above - no change - error persists. – Etan Jul 26 '11 at 12:01

1 Answers1

0

This is a working part of my c++ class for handling Serial Port communication changed a bit to accommodate C and your needs. If it doesn't work then its probably your driver for virtual port that's faulty

 DCB SerialPortSettings;
 HANDLE SerialPort;

int OpenPort(WCHAR* PortName,int BaudRate)
{

    SerialPort = CreateFileW(PortName,
        GENERIC_READ|GENERIC_WRITE,
        0,
        NULL,
        OPEN_EXISTING,
        FILE_FLAG_OVERLAPPED,
        NULL);

    if(SerialPort==INVALID_HANDLE_VALUE)
        return -2;

    RtlZeroMemory(&SerialPortSettings,sizeof(DCB));
    SerialPortSettings.DCBlength = sizeof(DCB);
    if(!GetCommState(SerialPort,&SerialPortSettings))
    {
        CloseHandle(SerialPort);
        return -3;
    }

    //8n1 RS485
    SerialPortSettings.BaudRate = BaudRate;
    SerialPortSettings.ByteSize = 8;
    SerialPortSettings.Parity = NOPARITY;
    SerialPortSettings.StopBits = ONESTOPBIT;
    SerialPortSettings.fRtsControl = RTS_CONTROL_TOGGLE;

    if(!SetCommState(SerialPort,&SerialPortSettings))
    {
        CloseHandle(SerialPort);
        return -4;
    }


    return 0;

}

Edit: Try downloading a driver from http://www.ftdichip.com/Drivers/VCP.htm, as the problem you are describing is most likely a driver or a device issue. Worked for Etan :)

Djole
  • 1,145
  • 5
  • 10
  • I use a standard driver which is included with windows to connect the usb device to a virtual com port. The problem is not that it is not working at all, but only sometimes - for example when opening and closing the serial port multiple times. I'll add a simple c# example to the question as well which produces the bug. – Etan Jul 26 '11 at 13:51
  • Try downloading a driver from http://www.ftdichip.com/Drivers/VCP.htm, as the problem you are describing is most likely a driver or a device issue – Djole Jul 26 '11 at 14:20
  • 1
    Could you repost this as an answer? The problem originated from a faulty firmware of the device. An upgrade solved the freeze problems. – Etan Jul 28 '11 at 09:46