2016-09-05 4 views
2

要求された動作:Stream/SerialPortで特定のバッファが受信されるまで、呼び出しスレッドを中断するための提案された一般的な解決策を聞きたいと思います。当分の間、タイムアウトなどは心配していませんが、堅牢なものが必要です。WaitFor() - 特定のバッファがSteam/SerialPortに到着するのを待つ方法は?

試みた方法:私はこれで成功の合理的な量を持っていた

Class myClass 
    { 
     private SerialPort _port; //Assume configured and connected. 

     public void WaitFor(byte[] buffer) 
     {    
      int bufferLength = buffer.Length; 
      byte[] comparisonBuffer = new byte[bufferLength]; 

      while(true) 
      { 
       if(_port.BytesToRead >= bufferLength) 
       { 
        _port.Read(comparisonBuffer, 0, bufferLength); 
        if (comparisonBuffer.SequenceEqual(buffer)) { return; } 
       } 
      } 
     } 
    { 

は、しかし、それはちょうどそれを感じる「ハック」を持っています。非常にしばしば私にトラブルを引き起こしました。私はそれが予想されるパケットの前後に他のデータが受信されないことを保証できないという事実によると考えられます。当然、この方法はストリームを同期外れて読み終え​​る可能性があります。このような場合、先行/後続のデータを失いたくはありませんが、メソッドはスレッドを解放する必要があります。

私は手続き型の性質で実装する必要があるので、イベント駆動型のメソッドは実際に私のためには機能しません。一般的な意味では、私は実装できるようにしたい。

Do thing; 
    WaitFor(mybuffer); 
    Do other thing; 

答えて

0

あなたはこの溶液にどう思いますか?

public override byte[] WaitFor(byte[] buffer, int timeout) 
{ 
    // List to stack stream into 
    List<byte> stack = new List<byte>(); 
    // Index of first comparison byte 
    int index = 0; 
    // Index of last comparison byte 
    int upperBound = buffer.Length - 1; 
    // Timeout Manager 
    Stopwatch Sw = new Stopwatch(); 

    Sw.Start(); 
    while (Sw.Elapsed.Seconds <= timeout) 
    { 
     // Read off the last byte receievd and add to the stack 
     stack.Add((byte)_port.ReadByte()); 

     // If my stack contains enough bytes to compare to the buffer 
     if (stack.Count > upperBound) 
     { 
      // If my first comparison byte matches my first buffer byte 
      if (stack[index] == buffer[0]) 
      { 
       // Extract the comparison block to array 
       byte[] compBuffer = stack.GetRange(index,upperBound +1).ToArray(); 

       // If the comparison matches, break and return the redundent bytes should I wish to handle them. 
       if ((compBuffer.SequenceEqual(buffer) && (index-1 > 0))) { return stack.GetRange(0, index - 1).ToArray(); } 
       // If there were no redundent bytes, just return zero. 
       else if (compBuffer.SequenceEqual(buffer)) { return new byte[] { 0}; } 
      } 

      // Increments 
      index += 1; 
      upperBound += 1; 
     } 

    } 

    throw new TimeoutException("Timeout: Expected buffer was not received prior to timeout"); 
} 
+0

@Sir Rufo 思考?どうもありがとう。 –

+0

このメソッドは、シーケンス全体ではなく1バイトだけ待機します。 IMHOはあなたの質問に答えません。コードレビューをしたい場合はhttp://codereview.stackexchange.com/ –

+0

謝罪のために私のwhileループをオフにしてください。ああ、codereviewについて知りませんでした、チップのおかげで。良いものを持っている。 –

0

SerialPort.Read()はすでにブロックは、少なくとも1つのバイトが到着しましたまで。したがって、あなたはあなたの道を使う必要はありません。そして、あなたはHORRIBLEのビジーウェイトループを導入しました。代わりに

、このような何か:

// Reads 'count' bytes from a serial port into the specified 
// part of a buffer. This blocks until all the bytes have been read. 

public void BlockingRead(SerialPort port, byte[] buffer, int offset, int count) 
{ 
    while (count > 0) 
    { 
     // SerialPort.Read() blocks until at least one byte has been read, or SerialPort.ReadTimeout milliseconds 
     // have elapsed. If a timeout occurs a TimeoutException will be thrown. 
     // Because SerialPort.Read() blocks until some data is available this is not a busy loop, 
     // and we do NOT need to issue any calls to Thread.Sleep(). 

     int bytesRead = port.Read(buffer, offset, count); 
     offset += bytesRead; 
     count -= bytesRead; 
    } 
} 

は、ここでは、BlockingRead()の面であなたの元のコードを実装してみましょう:

public void WaitFor(SerialPort port, byte[] buffer) 
{ 
    byte[] comparisonBuffer = new byte[buffer.Length]; 

    while (true) 
    { 
     BlockingRead(port, comparisonBuffer, 0, comparisonBuffer.Length); 

     if (comparisonBuffer.SequenceEqual(buffer)) 
      return; 
    } 
} 
+0

OK、ありがとう。ポイントは常にBytesToReadを再評価していますが、ここで書いたことは私が求めた機能を提供していません。 ポートで利用可能な10バイトで関数を入力すると、count = 10と仮定します。終了カウントでは、count - = bytesReadによって0になり、ループが解放されます。 今私は私が受け取ったものに関係なく、もう待っていません。あなたの関数は 'port.Read()'よりももう機能しません。 –

+0

@GeorgeKerwoodはい、読んだバイト数、つまり渡された 'count'パラメータを読み込みます。 'SerialPort.Read()'は、呼び出された時点で利用可能なバイト数だけを読み込みます。しかしあなたの質問を読んで、それはあなたが求めているものが何か違っているようです... –

+0

ブロックがターゲット配列の内容と一致するまで 'count'バイトのブロックを読み込もうとしているようです正しい?そして、あなたは匹敵しないブロックを投げ捨てるでしょう。 –

0

問題

は、あなたがバイトを待つと仮定しましょうパターン{1,1,1,2,2}とシリアルポートはバッファされています{1,1,1,1,2,2,5}

コードは、パターンと一致しない最初の5バイトの{1,1,1,1,2}を読み取ります。しかし、ポートから読み取った後、読み取ったデータはバッファーから削除され、{2,5}しか含まれておらず、一致することはありません。

ソリューション

public void WaitFor(byte[ ] buffer) 
{ 
    if (buffer.Length == 0) 
     return; 

    var q = new List<byte>(buffer.Length); 

    while (true) 
    { 
     var current = _reader.ReadByte(); 
     q.Add((byte)current); 
     // sequence match so far 
     if (q.Last == buffer[ q.Count - 1 ]) 
     { 
      // check for total match 
      if (q.Count == buffer.Length) 
       return; 
     } 
     else 
     { 
      // shift the data 
      while (q.Any() && !q.SequenceEqual(buffer.Take(q.Count))) 
      { 
       q.RemoveAt(0); 
      } 
     } 
    } 
} 
+0

それはチケットです!ありがとう。 私はこのように考えるようになりました(前回の回答の最後のコメントを読んでください)。 ありがとうございます。 –

+0

@GeorgeKerwoodしかし、あなたがスキップしたかもしれないバイトはどうですか?あなたは今それらを投げ捨てていないのですか?重要でない場合、なぜ送信されていますか? –

+0

@MatthewWatsonそれは別の質問の一部でなければなりません:o) –

関連する問題