2009-06-12 3 views
1

SerialPort からデータを読み取り、バイト[]を返す関数を作成したいとしましょう。明らかに、これはSerialPortで読み取る正しい方法ではない

public byte[] RequestData(byte[] data) 
{ 
    //See code below 
} 

これは実際に動作しない/よく実行し、非常に信頼性がないんのような単純なもの:

while (port.BytesToRead < 14) 
{ 
    //Maybe Thread.Sleep(10) here? 
} 

byte[] response = new byte[port.ReadBufferSize]; 

port.Open();  
port.Write(data, 0, data.Length); 

Thread.Sleep(300); //Without this it doesn't even work at all 

Console.WriteLine("Bytes to read: {0}", port.BytesToRead); 

int count = port.Read(response, 0, port.ReadBufferSize); 

Console.WriteLine("Read {0} bytes", count); 

port.Close(); 
port.Dispose();  

return response.GetSubByteArray(0, count); 

を私はまた、のようなものとのThread.sleepを交換してみました

しかし、それは問題を引き起こします。 (PS:私は、少なくとも14バイトを必要と知っている)もちろん

(と思う)のようなもの持っているだろうより良い方法:

port.ReceivedBytesThreshold = 14; 
port.DataReceived += new SerialDataReceivedEventHandler(port_DataReceived); 
port.Open(); 

port.Write(data, 0, data.Length); 

そしてもちろんのハンドラた:

void port_DataReceived(object sender, SerialDataReceivedEventArgs e) 
{ 
    var port = (SerialPort)sender; 

    while (port.BytesToRead > 0) 
    { 
     //Read the data here 
    } 
} 

しかし、定義したい機能の結果としてデータを返すことはできません。 これを使用しているクライアントコードは、このコードで生成されたイベントのサブスクリプションを行う必要がありますが、 ですが、実際にはその応答が実際に要求に対する応答であることはどのように分かりますか。

(複数のメッセージが送信される可能性があり、一方のメッセージがもう一方のメッセージよりも処理に時間がかかります)

任意のアドバイスは

UPDATE

次のコードはかなり良く動作しますが、私はのThread.sleep()文を削除した場合、それが再び正常に動作を停止した歓迎されるであろう。例えば、シリアルポート監視ツールは、シリアルラインに17バイトが書き込まれていることを明確に示しています。最初のBytesToRead = 10と次回のBytesToRead = 4でしたが、BytesToReadは0のままなので、最後の3バイトはどこに行きましたか?ここで

void port_DataReceived(object sender, SerialDataReceivedEventArgs e) 
{ 
    Thread.Sleep(100); 
    while (port.BytesToRead > 0) 
    { 
     Console.WriteLine("Bytes to read: {0}", port.BytesToRead); 
     var count = port.BytesToRead; 

     byte[] buffer = new byte[count]; 

     var read = port.Read(buffer, 0, count); 

     if (count != read) 
      Console.WriteLine("Count <> Read : {0} {1}", count, read); 

     var collectAction = new Action(() => 
     { 
      var response = dataCollector.Collect(buffer); 

      if (response != null) 
      { 
       this.OnDataReceived(response); 
      } 
     }); 

     collectAction.BeginInvoke(null, null); 
     Thread.Sleep(100); 
    }  
} 

答えて

0

問題:

void port_DataReceived(object sender, SerialDataReceivedEventArgs e) 
{ 
    var count = port.BytesToRead; 
    byte[] buffer = new byte[count]; 
    var read = port.Read(buffer, 0, count); 

    var response = dataCollector.Collect(buffer); 

    if (response != null) 
    { 
     this.OnDataReceived(response); 
    }    
} 

問題が実際にこのコードが、dataCollector.Collect()メソッドのコードではなかったようです。

+1

これはまだSerialPortを読む方法ではありません。 –

+0

これは本当に今働いているからです – TimothyP

+0

これを読んでいる人にはちょうどいいね。DataReceivedイベントは、SerialPortインスタンスを作成したスレッドとは別のスレッドで起動されます。 http://msdn.microsoft.com/en-us/library/system.io.ports.serialport.datareceived.aspxを参照してください。 – rkagerer

3

は、私はそれをやった方法は次のとおりです。

私は、コンストラクタで接続するための重要なデータを受け入れ、そのコンストラクタで基本的なセットアップを行うクラスのラッパーを持っています。クラスのコンシューマはConnectメソッドを呼び出し、接続を実行するために別のスレッドを起動します(ノンブロッキング)。

接続が完了すると、接続が完了したことを示すStateEventが発生します。この時点で送信キューが設定され、そのキューを動作させるスレッドがオフになり、読み取りスレッドも設定されます。読み込みスレッドは、SerialPortから128文字のデータを読み込み、それを文字列に変換し、イベントを起動して受信データを渡します。これは、接続が維持されている間ループするwhileスレッドでラップされます。消費者が何かを送信したいとき、Sendメソッドは送信されるデータを単にエンキューします。

応答が実際に送信されたものに対する応答であることが分かっている限り、実際には接続クラスの仕事ではありません。それを扱いやすいように接続を抽象化することによって、クラスの消費者は、応答が期待どおりであるかどうかを決定するロジックをきれいに維持することができます。

+0

マインドでコードを共有していますか? – TimothyP

+0

残念ながら、プロプライエタリなコードはあなたが興味を持っているコードとあまりにも絡み合っています。 – jasonh

+0

どんな場合でも問題はありません。 – TimothyP

0

シリアルポートは楽しいものではありません。私の唯一の考えは、お使いのデバイスに1つが有効になっていると仮定すると、あなたのfifoがオーバーランしているということです。解決