Приложение не получает последовательные данные от COM-порта - C++

Мое приложение неправильно получает данные от COM-порта. Это раньше работало. Я не знаю, что случилось. Я знаю, что по линии отправляются / принимаются правильные данные, потому что я вижу их на своем анализаторе протоколов.

ПК попадает в WAIT_OBJECT_0 + 1 состояние, но содержимое буфера всегда равно нулю. Я знаю, что это много, но если кто-то может указать, что я делаю неправильно, я был бы очень признателен. Я могу добавить / удалить детали в соответствии с просьбой. Благодарю.

РЕДАКТИРОВАТЬ: Дополнительная информация

Я смог убедиться, что компьютер звонит ReadFileExи это "успешно". Тем не менее, компьютер никогда не попадает в FileIOCompletionRoutine, Есть идеи? (Я удалил обработку ошибок из кода, чтобы упростить жизнь.) Кроме того, из того, что я прочитал на веб-сайте MSDN, это выглядит так FileIOCompletionRoutine будет вызываться асинхронно в своем собственном потоке. Это верно? Благодарю.

РЕДАКТИРОВАТЬ: окончательное решение

Это то, что я придумал. Очевидно, что код инициализации и обработки ошибок не здесь. Мы не можем сделать вещи слишком легкими.:)

// Load event handles.
pHandles[0] = s_hSerialPortRxThreadExitEvent;
// OVERLAPPED structure event handle is loaded in loop.

while ( blContinue )
{
    // Wait for a communications event.
    if ( !::WaitCommEvent( s_hSerialPort, &dwEventMask, &s_ov ) )
    {
        if ( ::GetLastError() != ERROR_IO_PENDING )
        {
            blContinue = FALSE;
            continue;
        }
        else if ( ::WaitForSingleObject( pHandles[0], 0 ) == WAIT_OBJECT_0 )
        {
            // The thread-exit event has been signaled.  Get out of here.
            blContinue = FALSE;
            continue;
        }
    }
    else
    {
        // Load OVERLAPPED structure event handle.
        pHandles[1] = s_ov.hEvent;
    }

    if ( dwEventMask & EV_RXCHAR )
    {
        if ( !::ReadFile( s_hSerialPort, pBuf, RX_BUF_SIZE, NULL, &s_ov ) )
        {
            if ( ::GetLastError() == ERROR_IO_PENDING )
            {
                // Wait for events.
                dwObjectWaitState = ::WaitForMultipleObjects( 2, pHandles, FALSE, INFINITE );

                // Switch on event.
                switch ( dwObjectWaitState )
                {
                case WAIT_OBJECT_0:             // thread exit event signaled
                    blContinue = FALSE;
                    continue;

                case WAIT_OBJECT_0 + 1:         // OVERLAPPED structure event signalled
                    // Reset event first to mitigate underrun condition.
                    if ( !::ResetEvent( pHandles[1] ) )
                    {
                        blContinue = FALSE;
                        continue;
                    }

                    // Get the OVERLAPPED result.
                    if ( !::GetOverlappedResult( s_hSerialPort, &s_ov, &dwBytesRead, FALSE ) )
                    {
                        blContinue = FALSE;
                        continue;
                    }
                    break;

                default:                        // Error
                    blContinue = FALSE;
                    continue;
                }
            }
        }
        else if ( !::GetOverlappedResult( s_hSerialPort, &s_ov, &dwBytesRead, FALSE ) )
        {
            blContinue = FALSE;
            continue;
        }

        // If bytes were read...
        if ( dwBytesRead > 0 )
        {
            // Copy received data from local buffer to thread-safe serial port buffer.
            ::EnterCriticalSection( &s_csRxRingBuffer );
            blSuccess = s_pobjRxRingBuffer->Add( pBuf, dwBytesRead, TRUE );
            ::LeaveCriticalSection( &s_csRxRingBuffer );

            if ( !blSuccess )
            {
                blContinue = FALSE;
                continue;
            }

            // Set the received data event.
            if ( !::SetEvent( s_phEventIds[RECEIVE_EVENT] ) )
            {
                blContinue = FALSE;
                continue;
            }
        }
    }

    if ( dwEventMask & EV_TXEMPTY )
    {
        // Set the transmit complete event.
        if ( !::SetEvent( s_phEventIds[TRANSMIT_EVENT] ) )
        {
            blContinue = FALSE;
            continue;
        }
    }

} // end while ( blContinue );

3 ответа

Решение

Я не знаю, вижу ли я ваш код неправильно, но я вижу, что вы настраиваете событие и ожидаете событие, не сообщая O/S, чего вы ждете, сначала вы должны выполнить ReadFileEx(), чтобы сообщить O / Если вы ожидаете события, когда в буфере есть данные для чтения, то вы делаете WFSO()/WFMO(), что я делаю в моей библиотеке последовательного порта (в потоке приемника):

do
{
    byteRead = 0;
    readBuffer = 0;
    if(!::ReadFile(this->commHandle,&readBuffer,
                   1,NULL,&this->readOverlapIO))
    {
         if(GetLastError() == ERROR_IO_PENDING)
         {
             if(::WaitForSingleObject(this->readOverlapIO.hEvent,INFINITE) == WAIT_OBJECT_0)
             {
                 if(!::GetOverlappedResult(this->commHandle,&this->readOverlapIO,&byteRead,FALSE))
                 {
                     byteRead = 0;
                 }
             }
         }
    }
    else
    {
         if(!::GetOverlappedResult(this->commHandle,&this->readOverlapIO,&byteRead,FALSE))
         {
              byteRead = 0;
         }
    }
    if(byteRead > 0)
    {
          totalByteRead += this->ringBuffer.push(readBuffer,1);
    }
}while(byteRead);

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

Кроме того, из того, что я прочитал на веб-сайте MSDN, похоже, что FileIOCompletionRoutine будет вызываться асинхронно в своем собственном потоке. Это верно?

Нет, это не правильно. Процедура завершения вызывается в контексте потока, в котором она была вызвана ReadFileEx. Когда он готов к запуску, он ставится в очередь до тех пор, пока поток не перейдет в "состояние ожидания с оповещением". Обычно это происходит при вызове одной из функций Wait*. Кроме того, в MSDN для ReadFileEx говорится:

Функция ReadFileEx игнорирует член hEvent структуры OVERLAPPED. Приложение может свободно использовать этот элемент в своих целях в контексте вызова ReadFileEx. ReadFileEx сигнализирует о завершении своей операции чтения, вызывая или помещая в очередь вызов подпрограммы завершения, на которую указывает lpCompletionRoutine, поэтому ему не нужен дескриптор события.

Таким образом, событие, которое вы создали, не имеет никакого эффекта. Кроме того, чтение не будет обрабатываться до тех пор, пока не будет вызван ReadFileEx, поэтому вы должны изменить порядок с вашим ожиданием. То, что вы должны делать в цикле чтения, выглядит примерно так (в псевдокоде):

while(continue)
{
    ReadFileEx();
    WaitForSingleObject(s_hSerialPortRxThreadExitEvent);
    . . . etc . . .
}

Если вы уверены, что что-то (должно) было получено, возможно, это двойное использование &dwWritten. Попробуйте использовать две отдельные переменные (одна для ReadFile, а другая для GetOverlappedResult). Проверьте оба из них, конечно.

Кроме того, инициализировали ли вы полностью перекрывающуюся структуру нулями (перед назначением ей события)?

Другие вопросы по тегам