Приложение не получает последовательные данные от COM-порта - C ++ - PullRequest
0 голосов
/ 13 января 2011

Мое приложение неправильно получает данные от 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 ]

1 голос
/ 19 января 2011

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

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

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

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

while(continue)
{
    ReadFileEx();
    WaitForSingleObject(s_hSerialPortRxThreadExitEvent);
    . . . etc . . .
}
1 голос
/ 19 января 2011

Я не знаю, вижу ли я ваш код неправильно, но я вижу, что вы настраиваете событие и ожидаете событие, не сообщая O / S, чего вы ждете, вы должны сначала выполнить ReadFileEx (), чтобысообщить O / S, что вы ожидаете события, когда в буфере есть данные для чтения, затем вы выполняете 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);

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

0 голосов
/ 13 января 2011

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

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

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