应用程序未从COM端口接收串行数据-C ++
-
10-10-2019 - |
题
我的应用程序无法从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(将事件分配给它)?