2009-08-18 19 views
1

私はリモート診断デバイスと通信するためにシリアルポートを使用しています。SerialPort.DataReceivedは定期的に購読/購読解除します

リモートデバイスからの応答の長さは、コマンドによって異なりますが、あらかじめわかっています。したがって、現在、私はコマンドを送信し、必要な数の応答バイトが受信されるのを待ちます。

私が積極的にデータを要求していないときはいつでも、 'SerialPort.DataReceived'イベントに登録します。このイベントのハンドラは、単に「迷惑な」受信データをログにダンプします(通常、リモートデバイスが予期せず再起動した場合にのみ非請求データが受信されます)。

場合によっては、約60Hzの速度でコマンドを送信したいと考えています。

私の質問は、私が 'SendCommand'メソッドを呼び出してデータを積極的に求めてくるたびに 'SerialPort.DataReceived'イベントを購読/購読解除するのが最善かどうかです。あるいは、イベント購読だけを残して、私が積極的にそれを求めているときにDataReceivedハンドラが着信データを無視するために使用できるTransferInProgressフラグ?私が正しく、単にDataReceivedハンドラ内のすべての受信データを処理したり、一つの他のオプションを持っているだろう理解していた場合

public virtual bool SendCommand(byte[] command, ref byte[] response) { 

    try { 
     TransferInProgress = true; 
     OnTransferStarted(); 

     // temporarily unsubscribe since we're actively soliciting data 
     _port.DataReceived -= 
      new SerialDataReceivedEventHandler(SerialPort_DataReceived); 

     _port.DiscardInBuffer(); 
     _port.Write(command, 0, command.Length); 
     OnCommandSent(command); 

     // read the requested number of response bytes 
     int responseBytesRead = 0; 

     while (responseBytesRead < response.Length) { 
      responseBytesRead += 
       _port.Read(response, responseBytesRead, (response.Length - responseBytesRead)); 
     } 

     OnCommandResponseReceived(response); 
     return true; 
    } 
    catch (Exception ex) { 
     OnCommandSendFailed(ex.Message); 
     return false; 
    } 
    finally { 
     _port.DataReceived += 
      new SerialDataReceivedEventHandler(SerialPort_DataReceived); 
     OnTransferComplete(); 
     TransferInProgress = false; 
    } 
} 

-Trevor

答えて

0

すべてのデータ受信を1か所で処理することを考えましたか?あなたは送信したコマンドを火として扱い、忘れて、応答のために受け取ったデータを解析することができます。応答に識別ヘッダーがなく、解析する方法がわかっているだけの場合は、送信したコマンドと応答の長さを知ることによって、キューで送信されたコマンドを追跡できます。データ受信ハンドラでは、レスポンスを待っているコマンドのキューをチェックし、今すぐ受け取ったデータを解析します。

要するに、すべての受信データを1か所で処理することをお勧めします。

+0

キューを使用してコマンドを追跡するというアイデアは気に入っていますが、私は迷惑なデータをどのように検出できるのでしょうか?この方法を使用して、リモートデバイスがコマンドの間に数バイトを発生させるかどうかをどのように判断できますか? (注:リモートデバイスは時折、自分自身をリセットしていくつかの 'スタートアップ'タイプのバイトを送信するようですが、残念なことにこれを制御できません)。 – user158485

+0

あなたはまだデータ受信ハンドラで迷惑なデータを検出していますが、 "SentCommandsQueue"にコマンドがないため、迷惑だとわかるでしょう。 私はシリアル通信で同様の問題を抱えていました。受信したデータをバッファリングして、リセットメッセージを解析する回答をまとめる必要があります。完全な応答が得られたら、キューからコマンドを削除します。リセットバイトはシーケンスの先頭に何らかの署名があるように見えるので、簡単にそれらを解析することができます。 – nathan

+0

私はおそらくこのようなものを実装できると思います。私の唯一の予約は、リセットバイトが必ずしも同じではない(順序または数量で)ため、リセットされたデータが通常のコマンドの間に受信された場合に、意図しないオフセットで終わる可能性があります。 つまり、この特定のシリアルデバイスにはコマンドエコーを有効にするオプションがあると思います。レスポンス配列の解析中に、コマンドヘッダを識別ヘッダとして使用できます。 – user158485

0

私の意見:ここ

は、現在の実装です。

実際のリクエストの間に受け取ったデータがそれほど多くない場合は、リクエストを送信する前にバッファを読み取りログに記録するだけです。シリアルドライバ受信バッファは、少量のデータを格納するのに十分な場合があります。その後、要求を送信し、応答だけを読み込みます。これは、より簡単な方法と簡単なコードになるでしょう。

0

私は通常ブール値を切り替えます。サブスクリプション/サブスクライブ解除では、同じイベントに複数回サブスクライブするリスクがあります。たとえば、コード内でOnTransferStarted()が例外をスローした場合は、DataReceivedイベントに2回申し込みます。

関連する問題