2013-04-15 34 views
5

こんにちは、この質問を考えてくれてありがとう: 仮想シリアルポート経由でPCからechos組み込みシステムがコマンドを完了したときにコマンドを戻します。c#シリアルポートのエコーを待ち、それをチェックし、待ち時間がある

組み込みシステムによってコマンドが完了したときに、コマンドをうまく送信してエコーを見ることができますが、エコーされたコマンドが受信されるまでプログラムを待機または遅延させるのに問題があります。次のコマンドを送信してもよい。私は実装しようとしている "ハイレベル"フロー制御の一種と考えています。 コードはC#にあります。 PCと組み込みシステムの間で通信が失われてプログラムがフリーズしないようにするために、エコーを待ってタイムアウトしたいと思います。 これを行うためのきちんとした方法を提案できるwizzの子供たちはいますか? 私は偉大なC#プログラマーではなく、ただ学びました。このコマンドをTransmittするための呼び出しの例です

private void port_DataReceived(object sender, SerialDataReceivedEventArgs e) 
    { 
     // If the com port has been closed, do nothing 
     if (!comport.IsOpen) return; 

     // This method will be called when there is data waiting in the port's buffer 

     // Determain which mode (string or binary) the user is in 
     if (CurrentDataMode == DataMode.Text) 
     { 
      // Read all the data waiting in the buffer 
      string data = comport.ReadExisting(); 

      // Display the text to the user in the terminal 
      Log(LogMsgType.Incoming, data); 
     } 
     else 
     { 
      // Obtain the number of bytes waiting in the port's buffer 
      int bytes = comport.BytesToRead; 

      // Create a byte array buffer to hold the incoming data 
      byte[] buffer = new byte[bytes]; 

      // Read the data from the port and store it in our buffer 
      comport.Read(buffer, 0, bytes); 

      // Show the user the incoming data in hex format 
      Log(LogMsgType.Incoming, ByteArrayToHexString(buffer)); 
      } 
    } 

 text = "AR" + 50 + "\r";   //transmit a command to move 
    this.comport.Write(text); 

現在、私は時間遅延[スレッドを使用してい

これは私が持っている機能を受けています。 Sleep(TIMEGAP)]というメッセージが表示され、メッセージが実行され、組み込みシステムからのエコーバックが正常だと仮定しても、それをチェックしないで、完了まで確実に待つのに非常に長い時間待つ:

 text = "AR" + 50 + "\r";   //transmit a command to move 
    this.comport.Write(text); 
    Thread.Sleep(TIMEGAP);    //Timegap = 10000ms 

私は本当に[Thread.Sleep(TIMEGAP)]の時間遅延呼び出しを、シリアルポートの応答を監視する関数/メソッドで置き換えて、送信されたものと同じであることを確認しますプログラムコードを次のコマンドに進めることができ、正しいエコー[上記の例ではAR50 \ r]が例えば5秒間に受信されない場合、プログラムはエラーを報告する。

提案がありますか?

ありがとうございました!

+0

あなたがグローバルバッファに受信したデータを連結する必要がありますので、DataReceivedイベントは、完全なラインのために発生しません。 –

+0

Thread.Sleep()の使用を検討し始めると、DataReceivedイベントを使用する良い理由がなくなります。SerialPort.Read()を使用して応答を取得してください。これが引き起こす可能性のある長い遅延に対処することは、通常次の問題です。ロックとハードプレイス。 –

答えて

6

最も簡単な方法は、DataReceivedイベントを使用するのではなく、ReadTimeoutを設定し、Readメソッドを使用することです。

あなたはASCIIを扱っているので、ReadLineメソッドをチェックアウトする必要があります。

入力データなしでReadTimeoutが経過した場合、両方ともTimeoutExceptionをスローします。

ただし、組み込みシステムが迷惑メールを送信できる場合は、別の方法が必要です。次に、グローバル文字列変数に期待するエコーを入れ、エコーを受信したときに受信イベントをManualResetEventに設定します。その後、タイムアウトのあるManualResetEventを待つことができます。これには、lockステートメントを使用したスレッド同期も含まれます。

GCは問題ではない場合、私はおそらくこのような何かを開始します:

using System.Text; 
using System.IO.Ports; 
using System.Threading; 

namespace ConsoleApplication2 
{ 
    class Program 
    { 
     static string serialBuffer = ""; 
     static string expectedEcho = null; 
     static object expectedEchoLock = new object(); 
     static ManualResetEvent expectedEchoReceived = new ManualResetEvent(false); 
     static SerialPort port = new SerialPort("COM1", 19200, Parity.None, 8, StopBits.One); 

     static void Main(string[] args) 
     { 
      port.DataReceived += new SerialDataReceivedEventHandler(port_DataReceived); 
     } 

     static void port_DataReceived(object sender, SerialDataReceivedEventArgs e) 
     { 
      while (port.BytesToRead > 0) 
      { 
       byte[] buffer = new byte[port.BytesToRead]; 
       int bytesRead = port.Read(buffer, 0, buffer.Length); 
       if (bytesRead <= 0) return; 
       serialBuffer += Encoding.UTF8.GetString(buffer, 0, bytesRead); 
       string[] lines = serialBuffer.Split('\r', '\n'); 
       // Don't process the last part, because it's not terminated yet 
       for (int i = 0; i < (lines.Length - 1); i++) 
       { 
        if (lines[i].Length > 0) 
         ProcessLine(lines[i]); 
       } 
       serialBuffer = lines[lines.Length - 1]; // keep last part 
      } 
     } 

     static void ProcessLine(string line) 
     { 
      bool unsolicitedMessageReceived = false; 
      lock (expectedEchoLock) 
      { 
       if (line == expectedEcho) 
       { 
        expectedEchoReceived.Set(); 
       } 
       else 
       { 
        unsolicitedMessageReceived = true; 
       } 
      } 
      if (unsolicitedMessageReceived) 
      { 
       // Process unsolicited/unexpected messages 
      } 
     } 

     /// <summary> 
     /// Send a command and wait for echo 
     /// </summary> 
     /// <param name="command">The command to send</param> 
     /// <returns>True when echo has been received, false on timeout.</returns> 
     static bool SendCommand(string command) 
     { 
      lock (expectedEchoLock) 
      { 
       expectedEchoReceived.Reset(); 
       expectedEcho = command; 
      } 
      port.Write(command); 
      return expectedEchoReceived.WaitOne(5000); // timeout after 5 seconds 
     } 
    } 
} 
+0

送信コードでは、WriteTimeoutを設定したいと思うと思います。そして、私はcomport.Write()がブロッキングコールであると仮定し、フードの下では基本的に送信機に成功を通知するか、タイムアウト例外をスローします。 – Richthofen

+0

書き込みは、RTS/CTSハンドシェイクのようなフロー制御が使用されている場合にのみブロックされます。 –

+0

ありがとうWouter、Richthofen、私はこれを行ってあげるよ。それは「医者が注文したもの」と思われる、と私は思う。 – user2281033

関連する問題