应用程序未从COM端口接收串行数据 - C ++

时间:2011-01-12 22:57:27

标签: c++ serial-port serial-communication overlapped-io

我的应用程序没有正确地从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 );

3 个答案:

答案 0 :(得分:1)

  

另外,根据我在MSDN上阅读的内容   网站,它看起来像   FileIOCompletionRoutine将获得   在它自己的异步调用   线。这是对的吗?

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

  

ReadFileEx函数忽略了   OVERLAPPED结构的hEvent成员。   应用程序可以免费使用   成员为了自己的目的   ReadFileEx调用的上下文。   ReadFileEx标志着它的完成   通过呼叫或排队来读取操作   调用完成例程   由lpCompletionRoutine指向,所以   它不需要事件句柄。

因此,您创建的事件无效。此外,在调用ReadFileEx之前不会处理读取,因此您必须在等待时撤消订单。你在阅读循环中应该做的是这样的(在伪代码中):

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

答案 1 :(得分: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);

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

答案 2 :(得分:0)

如果您确定已收到某些内容(应该),则可能是& dwWritten的双重用法。尝试使用两个单独的变量(一个用于ReadFile,另一个用于GetOverlappedResult)。 当然要检查它们。

另外,您是否已将完整重叠结构初始化为0(beffore将事件分配给它)?