Заморозить на SerialPort.Open / DeviceIoControl / GetcommState с помощью usbser.sys - PullRequest
3 голосов
/ 19 июля 2011

У меня есть программа на C, которая открывает дескриптор COM-порта, записывает в него несколько байтов, считывает некоторые байты, затем закрывает дескриптор и завершает работу.Однако, когда я запускаю программу 10 раз подряд, начинается очень много времени, чтобы завершить функцию GetCommState и застрять в функции SetCommState.То же самое происходит в C # с простым SerialPort объектом.

Единственное исправление, которое я могу найти, это переподключение устройства к порту.Есть ли какой-нибудь более изящный способ избавиться от этой заморозки?Может быть, это просто какая-то ошибка конфигурации ПК?

Обновление

Я переписал код, чтобы он использовал DeviceIoControl вместо SetCommState.Тем не менее, здесь та же самая проблема.

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;
}

Первая проблема: DeviceIoControl не возвращается немедленно (хотя вызывается асинхронно) и зависает около двух минут.Вторая проблема: происходит сбой с кодом ошибки 121 (ERR_SEM_TIMEOUT: «Истекло время ожидания семафора.») По истечении этих двух минут.

  • Используемый драйвер - это стандартный драйвер Windows usbser.sys
  • Есть идеи, почему вызов функции не возвращается немедленно?А если нет, то как установить более короткое время ожидания для функции?
  • Есть идеи, почему функция не работает?

Обновление 2

Пример кода C #, который также зависает (как в приведенной выше программе на C):

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();
        }
    }
}

Пример вывода следующий:

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.

1 Ответ

0 голосов
/ 26 июля 2011

Это рабочая часть моего класса c ++ для обработки связи через последовательный порт, немного измененная для соответствия C и вашим потребностям. Если это не работает, то, вероятно, ваш драйвер для виртуального порта неисправен

 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;

}

Редактировать: Попробуйте загрузить драйвер с http://www.ftdichip.com/Drivers/VCP.htm,, поскольку описываемая вами проблема, скорее всего, связана с драйвером или устройством. Работал на Итана:)

...