0

我的应用程序没有从 COM 端口正确接收数据。这曾经奏效。我不知道发生了什么。我知道正确的数据正在通过线路发送/接收,因为我可以在我的协议分析器上看到它。

PC 进入该WAIT_OBJECT_0 + 1状态,但缓冲区内容始终为零。我知道这很多,但如果有人能指出我做错了什么,我会非常感激。我可以根据要求添加/删除详细信息。谢谢。

编辑:附加信息

我已经能够验证 PC 是否对 进行了调用ReadFileEx,并且它“成功”了。但是,PC 永远不会进入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 );
4

3 回答 3

1

此外,从我在 MSDN 网站上阅读的内容来看,FileIOCompletionRoutine 似乎将在其自己的线程中被异步调用。那是对的吗?

不,这是不正确的。完成例程在调用 ReadFileEx 的线程的上下文中被调用。当它准备好运行时,它会排队,直到线程处于“警报等待状态”。当您调用其中一个 Wait* 函数时,通常会发生这种情况。此外,从 MSDN for ReadFileEx,它指出:

ReadFileEx 函数忽略 OVERLAPPED 结构的 hEvent 成员。在 ReadFileEx 调用的上下文中,应用程序可以自由地将该成员用于自己的目的。ReadFileEx 通过调用或排队调用 lpCompletionRoutine 指向的完成例程来表示其读取操作的完成,因此它不需要事件句柄。

所以你创建的事件没有效果。此外,在调用 ReadFileEx 之前不会处理读取,因此您必须在等待时反转顺序。您在阅读循环中应该做的事情是这样的(在伪代码中):

while(continue)
{
    ReadFileEx();
    WaitForSingleObject(s_hSerialPortRxThreadExitEvent);
    . . . etc . . .
}
于 2011-01-18T21:35:06.723 回答
1

我不知道我是否看到您的代码错误,但我看到您正在设置事件,并等待事件而不告诉 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);

我在这里使用事件信号使用完成事件,如果您愿意,可以将其更改为完成功能。

于 2011-01-19T09:02:59.017 回答
0

如果您确定(应该)收到了某些东西,那么这可能是 &dwWritten 的双重用法。尝试使用两个单独的变量(一个用于 ReadFile,另一个用于 GetOverlappedResult)。当然检查他们两个。

另外,您是否已将完全重叠的结构初始化为 0(在将事件分配给它之前)?

于 2011-01-13T00:11:03.457 回答