0

アプリケーションが COM ポートからデータを正しく受信していません。これは以前は機能していました。何が起こったのかわかりません。プロトコル アナライザーで確認できるので、回線上で適切なデータが送受信されていることがわかります。

PC はこのWAIT_OBJECT_0 + 1状態になりますが、バッファの内容は常にゼロです。これがたくさんあることは知っていますが、誰かが私が間違っていることを指摘できれば、本当に感謝しています. リクエストに応じて詳細を追加/削除できます。ありがとう。

編集:追加情報

ReadFileExPC が を呼び出し、「成功」することを確認できました。ただし、PC は には入りませんFileIOCompletionRoutine。何か案は?(コードからエラー処理を削除して、作業を簡素化しました。) また、MSDN Web サイトで読んだところによると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 Web サイトで読んだところによると、FileIOCompletionRoutine は独自のスレッドで非同期的に呼び出されるようです。あれは正しいですか?

いいえ、それは正しくありません。完了ルーチンは、ReadFileEx が呼び出されたスレッドのコンテキストで呼び出されます。実行の準備ができると、スレッドが「アラート可能な待機状態」になるまでキューに入れられます。これは通常、Wait* 関数のいずれかを呼び出したときに発生します。さらに、 ReadFileExの MSDN から、次のように述べています。

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 の二重使用である可能性があります。2 つの個別の変数 (ReadFile 用と GetOverlappedResult 用) を使用してみてください。もちろん両方チェック。

また、(イベントを割り当てる前に) 完全にオーバーラップした構造を 0 に初期化しましたか?

于 2011-01-13T00:11:03.457 に答える