简体   繁体   English

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

[英]Application Not Receiving Serial Data from COM Port - C++

My application is not properly receiving data from the COM port. 我的应用程序没有从COM端口正确接收数据。 This used to work. 这曾经工作。 I don't know what happened. 我不知道发生了什么 I know that the proper data is being sent/received over the line because I can see it on my protocol analyzer. 我知道正确的数据正在通过线路发送/接收,因为我可以在协议分析器上看到它。

The PC gets into the WAIT_OBJECT_0 + 1 state, but the buffer contents are always zero. PC进入WAIT_OBJECT_0 + 1状态,但是缓冲区内容始终为零。 I know this is a lot, but if anyone can point out what I'm doing wrong, I'd really appreciate it. 我知道很多事情,但是如果有人能指出我做错了什么,我将非常感激。 I can add/remove details as requested. 我可以根据要求添加/删除详细信息。 Thanks. 谢谢。

EDIT: Additional Information 编辑:附加信息

I have been able to verify that the PC makes the call to ReadFileEx , and it "succeeds." 我已经能够验证PC是否对ReadFileEx进行了调用,并且该调用成功。 However, the PC never gets into FileIOCompletionRoutine . 但是,PC永远不会进入FileIOCompletionRoutine Any ideas? 有任何想法吗? (I removed the error-handling from the code to make life simpler.) Also, from what I read on the MSDN website, it looks like FileIOCompletionRoutine will get called asynchronously in its own thread. (我从代码中删除了错误处理,以简化工作。)此外,从我在MSDN网站上阅读的内容来看, FileIOCompletionRoutine看起来将在其自己的线程中被异步调用。 Is that correct? 那是对的吗? Thanks. 谢谢。

EDIT: Final Solution 编辑:最终解决方案

This is what I came up with. 这就是我想出的。 Obviously, the initialization and error-handling code is not here. 显然,这里没有初始化和错误处理代码。 We can't make things too easy. 我们不能使事情变得太简单。 :) :)

// 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 );

Also, from what I read on the MSDN website, it looks like FileIOCompletionRoutine will get called asynchronously in its own thread. 另外,从我在MSDN网站上阅读的内容来看,FileIOCompletionRoutine似乎将在其自己的线程中被异步调用。 Is that correct? 那是对的吗?

No, that is not correct. 不,那是不正确的。 The completion routine gets called in the context of the thread in which it the ReadFileEx called is made. 完成例程在创建ReadFileEx的线程上下文中调用。 When it is ready to run, it is queued until the thread is in an "alertable wait state". 准备好运行时,它将排队,直到线程处于“可更改的等待状态”。 That typically happens when you call one of the Wait* functions. 当您调用Wait *函数之一时,通常会发生这种情况。 Furthermore, from the MSDN for ReadFileEx , it states: 此外,从MSDN for ReadFileEx ,它指出:

The ReadFileEx function ignores the OVERLAPPED structure's hEvent member. ReadFileEx函数将忽略OVERLAPPED结构的hEvent成员。 An application is free to use that member for its own purposes in the context of a ReadFileEx call. 在ReadFileEx调用的上下文中,应用程序可以自由使用该成员用于其自身的目的。 ReadFileEx signals completion of its read operation by calling, or queuing a call to, the completion routine pointed to by lpCompletionRoutine, so it does not need an event handle. ReadFileEx通过调用lpCompletionRoutine所指向的完成例程或将其排队来发出其读取操作的完成信号,因此它不需要事件句柄。

So the event you have created has no effect. 因此,您创建的事件无效。 Also, the reads will not be processed until ReadFileEx is called, so you have to reverse the order with your wait. 另外,在调用ReadFileEx之前将不会处理读取,因此您必须等待等待才能反转顺序。 What you should be doing in your reading loop is something like this (in Pseudocode): 在阅读循环中应该做的事情是这样的(在Pseudocode中):

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

I don't know if I see your code wrong, but I see that you are setting up event, and waiting for the event without telling the O/S what are you waiting for, you should do ReadFileEx() first to tell O/S you are waiting for event when there's data in the buffer to read, then you do WFSO()/WFMO(), this what I do on my Serial port library (on receiver thread): 我不知道我的代码是否错误,但是我看到您正在设置事件,并且在不通知操作系统的情况下等待事件,您应该先执行ReadFileEx()来告诉操作系统当缓冲区中有数据要读取时,您正在等待事件,然后执行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);

I use completion event using event signal here, you can change it to completion function if you wanted to. 我在此处使用带有事件信号的完成事件,如果需要,可以将其更改为完成功能。

if youre sure that something (should) have been received ,then may it is the double usage of &dwWritten. 如果您确定已收到某些东西,则可能是&dwWritten的双重用法。 Try using two separate variables (one for ReadFile and another for GetOverlappedResult). 尝试使用两个单独的变量(一个用于ReadFile,另一个用于GetOverlappedResult)。 Check both of them of course. 当然要检查两个。

Also ,Have you initialized the full overlapped structure to 0's (beffore assigning the event to it)? 另外,您是否已将完全重叠的结构初始化为0(在将事件分配给它之前)?

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM