我的应用程序无法从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 );
有帮助吗?

解决方案

我不知道我是否看到您的代码错误,但是我看到您正在设置事件,并在不告诉o/s的情况下等待活动,您应该在等待什么,您应该先告诉o/readfileex() 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);

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

其他提示

另外,根据我在MSDN网站上阅读的内容,看起来FileIococtionRoutine将在其自己的线程中被异步被调用。那是对的吗?

不,那是不正确的。完成readfileex所调用的线程的上下文中的完整例程被调用。准备运行时,将其排队,直到线程处于“可警报的等待状态”为止。当您调用一个wait*函数之一时,通常会发生这种情况。此外,来自MSDN ReadFileex, , 它指出:

ReadFileex函数忽略了重叠的结构的hevent成员。在ReadFileex呼叫的上下文中,可以免费使用该申请为其自己的目的。 READFILEEX信号通过致电或排队呼叫来完成其读取操作的完成,该程序由LPCompletionRoutine指向的完成例程,因此它不需要事件句柄。

因此,您创建的活动没有效果。另外,在调用ReadFileex之前,不会对读取进行处理,因此您必须在等待中扭转订单。您应该在阅读循环中要做的是这样的事情(在伪代码中):

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

如果您确定应该收到某物(应该收到),那么这可能是DWWRITTION的双重用法。尝试使用两个单独的变量(一个用于ReadFile,另一个用于GetoverPlapedResult)。当然,检查两个。

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

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top