ReadFile ERROR_INVALID_HANDLE после нескольких чтений последовательного порта - PullRequest
0 голосов
/ 14 июня 2019

Я новичок в последовательной библиотеке Windows, поэтому любые рекомендации очень ценятся. У меня есть микроконтроллер, подключенный к USB-порту, и он постоянно отправляет данные через UART. Пример того, что должно быть получено:

Значение АЦП 1: 848 Значение АЦП 2: 972 Количество прерываний АЦП: 2300

(пауза)

Значение АЦП 1: 849 Значение АЦП 2: 971 Количество прерываний АЦП: 2301

Сама программа имеет поток в графическом интерфейсе, и как только пользователь выбирает COM-порт, создается файл с именем дескриптора hCom . Создается новый поток, и ему передается hCom . Я пытался использовать бесконечный цикл while в новом потоке для постоянного чтения порта (позже я реализую соответствующие условия проверки). Функция ReadFile читает по одному байту за раз и выводит их на экран. Это непрерывно петли. Однако после отправки первого набора (val 1, val 2, int count) данные больше не принимаются.

Создание файла и потока spawn здесь:

HANDLE hCom = CreateFile(szComPort,
                                         GENERIC_READ |
                                         GENERIC_WRITE, // desired access should be read&write
                                         0,                          // COM port must be opened in non-sharing mode
                                         NULL,                       // don't care about the security
                                         OPEN_EXISTING,              // IMPORTANT: must use OPEN_EXISTING for a COM port
                                         0,                          // usually overlapped but non-overlapped for existance test
                                         NULL);
                if (INVALID_HANDLE_VALUE == hCom) {
                    MessageBox(hwnd, "This port is not available or is in use.", "Error", MB_OK | MB_ICONERROR);
                    return WndProc(hwnd, WM_CREATE, wParam, lParam);
                }
                AppendText(hOut, "CONNECTED TO " + std::string(szComPort) + "\r\n");
                DWORD myThreadID;
                CreateThread(NULL, 0, serialHandler, &hCom, 0, &myThreadID);
return WndProc(hwnd, WM_CREATE, wParam, lParam);

Вот мой обработчик потока:

DWORD WINAPI serialHandler(LPVOID lpParameter) {
    HANDLE &hCom = *((HANDLE *) lpParameter);
    SetCommState(hCom, &dcbSerialParams);
    COMMTIMEOUTS tMyTimeOuts =  {
            MAXDWORD, //  DWORD ReadIntervalTimeout;
            0, //  DWORD ReadTotalTimeoutMultiplier;
            10000,    //  DWORD ReadTotalTimeoutConstant;
            1000,     //  DWORD WriteTotalTimeoutMultiplier;
            1000,     //  DWORD WriteTotalTimeoutConstant;
    };
    if (!SetCommTimeouts(hCom, &tMyTimeOuts))
        printf("setting port time-outs.");

    std::string sb = "";
    DWORD dwEventMask, dwSize = 0;


    while (1) {
        char szBuf;
        DWORD dwIncommingReadSize;
        do {
            int error = ReadFile(hCom, &szBuf, 1, &dwIncommingReadSize, NULL);
            if (error !=0) {
                if (dwIncommingReadSize > 0) {
                    dwSize += dwIncommingReadSize;
                    sb += szBuf;
                    printf("%c", szBuf);
                    sb = "";
                }
            } else {
                printf("No Data Received - ");
                DWORD lasterror = GetLastError();
                lasterror = GetLastError();
            }
        } while (dwIncommingReadSize > 0);
    }

    return 0;
}

EDIT: вот часть WM_CREATE, которая вызвала у меня проблемы

hCom = CreateFile(szComPort,
                                  GENERIC_READ | GENERIC_WRITE, // desired access should be read&write
                                  0,                          // COM port must be opened in non-sharing mode
                                  NULL,                       // don't care about the security
                                  OPEN_EXISTING,              // IMPORTANT: must use OPEN_EXISTING for a COM port
                                  0,                          // usually overlapped but non-overlapped for existance test
                                  NULL);                      // always NULL for a general purpose COM port

                if (INVALID_HANDLE_VALUE == hCom) {
                    if ((ERROR_ACCESS_DENIED) == GetLastError()) {   // then it exists and currently opened
                        wsprintf(szComPort, _T("&COM%d (in use)"), i);
                        AppendMenu(hSubMenu, MF_STRING, COM_PORT_MESSAGE_BASE + i, szComPort);
                    }
                } else {   // COM port exists
                    wsprintf(szComPort, _T("COM%d"), i);
                    AppendMenu(hSubMenu, MF_STRING, COM_PORT_MESSAGE_BASE + i, szComPort);
                    CloseHandle(hCom);
                }

Фактический результат:

АЦП значение 1: 848 АЦП значение 2: 972 Количество прерываний АЦП: 2879 ANo Данные получены - данные не получены - данные не получены -

И так далее. Переменная lasterror в serialhandler возвращает 6, которое равно ERROR_INVALID_HANDLE. Я не уверен, почему дескриптор переходит от действительного к недействительному после одного «набора» операций чтения.

1 Ответ

0 голосов
/ 14 июня 2019

Я открыл файловый дескриптор в другой части моего кода и забыл закрыть его. Это приводило к проблемам, когда я пытался открыть порт, и он больше не существовал, и моя функция чтения файлов не работала. Обязательно проверьте все ваши экземпляры createfile.

В частности, причина, по которой мой код не работал, была двоякой. Сначала я передал локальную копию hCom в стек другого потока.

CreateThread(NULL, 0, serialHandler, &hCom, 0, &myThreadID);

Затем я вернулся к той же функции, чтобы перерисовать графический интерфейс (я хотел обновить меню, чтобы показать, что соединение установлено).

return WndProc(hwnd, WM_CREATE, wParam, lParam);

Внутри WM_CREATE - сканирование портов, которое заново открывает все порты, чтобы проверить, открыты ли они.

hCom = CreateFile(szComPort,
                                  GENERIC_READ | GENERIC_WRITE, // desired access should be read&write
                                  0,                          // COM port must be opened in non-sharing mode
                                  NULL,                       // don't care about the security
                                  OPEN_EXISTING,              // IMPORTANT: must use OPEN_EXISTING for a COM port
                                  0,                          // usually overlapped but non-overlapped for existance test
                                  NULL);                      // always NULL for a general purpose COM port

Это мешало более раннему потоку, так как он использовал тот же дескриптор для сбора данных. Вот почему это будет работать некоторое время, пока другой поток не запустится и не использует COM-порт повторно. Я исправил эту проблему, удалив функцию возврата, передав целое число новому потоку и открыв COM-порт в новом потоке.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...