ギリギリ行けるお一人様のライン

VisualC++6.0にて、PCと通信相手の機械との間で、同期のシリアル通信を行うツールを作成していますが、たまにWriteFile()のデータ送信が完了しない状況になってしまいます。

問題が発生している状況は、以下となります。
・WriteFile()を実行した際、戻り値としてTRUEが返却されるが、書き込んだバイト数が0byteとなっていて、送信できていない。
・上記問題が発生した際でも、ReadFile()でのデータ受信は正常に出来る。
・WriteFile()やReadFile()の実行前後でClearCommError()を実行しても、いずれもオーバーフロー等のエラー情報は検出できない。
・上記問題が発生した際、GetLastError()=0となり、エラー情報は検出できない。
・ツールを最小化したり、IE等のプログラムを立ち上げたりした際に、上記問題が発生しやすい。
・DCB構造体のfDtrControlとfRtsControlをDISABLEやENABLEに変更したが、状況は改善しなかった。
・VisualStudio2005のC++にてツールを作り直したが、状況は改善しなかった。
・処理中にSleep(1)を入れて、WriteFile()とReadFile()の間隔を広げると問題は発生しなくなる。ただし、ツールの処理時間が倍以上となってしまう為、Sleepを入れることでの解決はしたくない。

また、PCと通信相手の機械との間の通信内容は、以下となります。
・上記問題が発生するまでの通信は、正常にできている。
・シリアル通信は、仮想COMポートによるUSB2.0の通信。
・SetCommTimeouts()にて、Read/Write共に、タイムアウト時間を1500msとしている。
・通信相手からの1回あたりのデータサイズは、最大4100kByte。また、5分間で約500MByteのデータがPC側へ通知される。
・PCからは、通信相手からのデータを受信した後、ACKとして8Byteのデータを送信する。
・PCは、USB2.0に対応したWindowsXPとVistaで上記問題が発生することを確認した。

私としては、問題が起こるまでの通信は正常に出来ている点や、Sleepを入れることで、問題が発生しなくなる点から、ツールの不具合ではなく、PC内部でデータ送信できなくなる問題が発生しているのではないかと考えています。しかし、問題の特定には至っていません。

どうか上記問題として考えられる原因や、原因特定の為の調査方法をご教示ください。
よろしくお願いします。

A 回答 (4件)

おはようございます。


「仮想COMポート」って事は、RS232Cとかのシリアル通信ではなく、FTDIとかのUSBによる通信なんですよね。
速度もすさまじいですしね。
なんかこうなってくると、ドライバを疑ってみたくなってしまいますが・・・。

同期モードでやられているとの事ですが、シリアル通信は必ず非同期モードで、と、どこかで読んだ記憶があります(多分、速度上の理由であり、本件とは関係ない気もしますが)。
「GetOverlappedResult」で検索すれば、サンプルがいっぱい出てきますので、非同期を完成させてみられてはどうでしょう。
当方では、以下のような感じで正常に通信ができていますので、ご参考になれば。
・相手はFT245BL(FTDI)
・非同期モード
・受信は別スレッド
・通信データ量は質問者様よりはるかに少ないですが、少量のデータをひっきりなしにやり取りしています。
    • good
    • 0
この回答へのお礼

回答ありがとうございます。

私も初めはドライバが処理速度についていけてないのではと考えていました。
その為、別のドライバを使用して動作検証を行ってみましたが、結果は改善しませんでした。
また、使用しているドライバは私が作ったものではなく、ドライバや通信相手の機械を修正することが出来ない為、ツール側で問題を解決したいと考えている次第です。

やはり、高速な通信の場合には、非同期モードにて通信を行ったほうがいいようですね。
非同期モードにて何とか解決できる方法がないかと、本問題の根本原因について、引き続き調査していきます。

お礼日時:2011/07/22 11:16

WriteFileのリファレンスはちゃんと読まれましたか?



オーバーラップをつかって書き込んだ場合hFileのオープン時にFILE_FLAG_OVERLAPPDを指定し、lpOverlappedに有効なポインタが渡された場合 WriteFileは 0を返します
この時点では まだ転送が完了していないので GetLastErrorもERROR_IO_PENDINGを返し、まだデータ転送が終わっていないことを示します

転送できたどうかは GetOverlappedResultで取得するのですよ

本来ならhEventにCreateEventで作成したハンドルを設定しておいて
WaitForSingleObjectなどでこのイベントハンドルがシグナル状態になるのを待機して、待機が解除されたらGetOverlappedResultで確認
といった手法でしょう

本当にオーバーラップが必要なのでしょうか?
通信相手のマニュアルにはサンプル例などがないのでしょう …

この回答への補足

通信モードは、同期モードにて通信をおこなっています。
(CreateFile()にてFILE_FLAG_OVERLAPPEDを設定していません。)

また、非同期モードにて通信を行うように処理を修正しても、問題は改善しませんでした。
(詳細は、No.2の回答の補足として記載しています。)

補足日時:2011/07/21 20:40
    • good
    • 0

こんにちは。


非同期モードでオープンされているのですよね。
概ね非同期通信の想定通りの動作のように思えます。
GetLastErrorが0を返すというのが気になりますが。。。
GetOverlappedResultで、送信完了を待つとかされては、どうでしょう。

この回答への補足

回答ありがとうございます。

通信モードは、同期モードにて通信をおこなっています。
(CreateFile()にてFILE_FLAG_OVERLAPPEDを設定していません。)

また、以下のように非同期モードにてデータ送信を行うようにツールを作り直した事もありました。
(1)WriteFile()にてデータ送信を開始する。
(2)WaitForSingleObject()にてシグナル状態になるまで待機する(1000msでタイムアウト)。
(3)(2)にてシグナル状態になった際に、GetOverlappedResult()にて送信完了したデータサイズを取得する。

上記の結果としては、(2)にてタイムアウトとなり、(3)まで処理が進みませんでした。
その際、GetLastError()=997(ERROR_IO_PENDING)となりました。
また、SetCommTimeouts()やWaitForSingleObject()でのタイムアウト時間を延長しましたが、結果は変わりませんでした。

その為、同期モードでも非同期モードでも発生する問題であると考えて、現状は同期モードにて問題の調査を行っている次第です。

補足日時:2011/07/21 20:36
    • good
    • 0

WriteFile()は単にバッファにデータを転送するだけで実際のシリアル通信とは連動しません。

(通常はほぼ同時に終了)
ただし他のアプリケーションが動作していたり、最小化していれば実際の通信が終了しないことは十分に有り得ます。

lpNumberOfBytesWrittenがnNumberOfBytesToWritより小さい時Sleepを入れる、GetQueuedCompletionStatus()によって送信完了を確認するなどで解決できるのでは。

この回答への補足

回答ありがとうございます。

lpNumberOfBytesWrittenがnNumberOfBytesToWritより小さい時Sleepを入れるという方法は試してみましたが、解決出来ませんでした。
現状は、WriteFile()でのデータ送信が出来なくなったら、一度USBケーブルを抜かないと
正常にデータ送信できなくなる状況です。

GetQueuedCompletionStatus()というものは、使用したことはありませんが、以下のサイトで存在自体は知っていました。
http://keicode.com/windows/win06.php

しかし、サーバー開発に用いられると説明されていた為、今回のようなシリアル通信には使用できないと思っていました。GetQueuedCompletionStatus()は、シリアル通信にも用いることが出来るものなのでしょうか。

補足日時:2011/07/22 10:57
    • good
    • 0

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!

このQ&Aを見た人はこんなQ&Aも見ています


おすすめ情報

このQ&Aを見た人がよく見るQ&A