1

私はシリアルポートに取り組んでいます。データを受信するとデータが不完全になるという新しい問題に直面しています。データが完全であるかどうかを確認してから処理し、そうでない場合は処理しないようにするにはどうすればよいですか?

これが私のデータ受信と送信機能です:

 private void Send(byte[] cmd)
        {
            bResponse = new byte[0];
            Write(cmd);        
        }

 void comPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            int iCount = comPort.BytesToRead;
            byte[] bBuffer = new byte[iCount];
            comPort.Read(bBuffer, 0, iCount)
            if (bBuffer.Length == 1 && bBuffer[0] == ACK)
                Write(new byte[] { ENQ });
            else if (bBuffer.Length == 1 && bBuffer[0] == NAK)
            {
                Debug.WriteLine("Incomplete Message detected!");  
            }
            else
            {
                bResponse = bResponse.Concat(bBuffer).ToArray();
                    rResponse = Decode(bResponse);
                    Write(new byte[] { ACK });
            }
        }

データがいくつかのパッケージで受信され、応答が完了するまで待つ必要があることはわかっていますが、上記のコードに基づいてわかりません。データが完全であるかどうかを確認して、待機するかどうかを判断するにはどうすればよいですか?(追記:受信した応答のサイズは異なります。)

4

3 に答える 3

2

完全性またはパケット サイズの組み込みの概念はありません。

あなた(または他の誰か)がプロトコル仕様の一部として定義した認識可能なパケットの終わりのパターンが表示されるまで、バッファに追加する必要があります。- 探しているものが見つからない場合は、しばらくするとタイムアウトになる可能性があります。

于 2013-02-01T01:14:45.950 に答える
0

コードがあります。まず、DataReceived イベントを実装します (既に行ったように)。このイベントは、処理するデータがある場合にのみ呼び出されます。私はそれを割り込みベースとは呼びませんが(「リアルタイム対応」のように)、ポーリングではありません。どっちがいい。

2 番目: イベントが呼び出されたとき、1 バイトしかない場合もありますが、それ以上のバイトがある場合もあります。各パケットをキャプチャするには、カスタム バッファを実装する必要があります。

3 番目: バッファーに 1 バイトを追加した後、バッファーに有効なパケットが含まれているかどうかを確認します。その場合は処理してください。そうでない場合: 別のものを追加します。バイトが残っていない場合は、イベントが再度呼び出されるまで待ちます。

コードでは次のようになります。

const BUFFERLENGTH = 17; // Bytes
byte[] buffer = new byte[BUFFERLENGTH];


private void COM_Port_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
    var port = (SerialPort)sender;
    while (port.BytesToRead > 0)
    {
        var data = (byte)port.ReadByte();
        Read(data);
    }
}

private void Read(byte value)
{
    // Append Byte to buffer
    System.Buffer.BlockCopy(buffer, 1, buffer, 0, BUFFERLENGTH- 1);
    buffer[BUFFERLENGTH - 1] = value;

    // Check for valid Packet
    if (IsValidPacket(buffer))
    {
        // Yeah! Gotcha :-)
        // Now copy your Packet from the Buffer to your struct/whatever
    }
}

private bool IsValidPacket(byte[] buffer)
{
    // Todo: Check whether buffer contains a valid Packet.
    // Some think like:
    // return buffer != null && buffer[0] == 0xF4 && buffer[2] == buffer.length
    throw new NotImplementedException();
}

「バイトをバッファに追加」しなかったことに注意してください。最初のバイトを破棄し、すべてのバイトを 1 つずつシフトして、最後に新しいバイトを挿入しました。有効なパケットが見つかった場合は、それを 1 つのブロックで構造体にコピーするだけです。そのため、バッファ サイズは常に一定で、正確に 1 つのパケットと同じ長さです。

これは最速のコードではないかもしれません (各バイトを個別に読み取るため) が、私にとってはうまく機能します :-)

ああ、それを GUI に表示したい場合は、Begininvoke() を使用することを忘れないでください。

于 2013-02-01T03:53:30.533 に答える
0

古いプロジェクトの例。最初のインデックス、最後のインデックスに注意してください。長さを知るために文字を入力します。開始/終了文字は事前定義されており、任意の文字を選択できます。一般的な文字を使用しないように注意してください。

これは tcp/ip 用ですが、シリアルポートにも同じ原則を使用できます

    public void ReceiveMessage(IAsyncResult ar) 
    {
        int bytesRead;
        try
        {
            lock (client1.GetStream()) 
            {
                bytesRead = client1.GetStream().EndRead(ar);
            }
            string messageReceived = System.Text.Encoding.ASCII.GetString(data, 0, bytesRead);
            received = messageReceived;
            int firstindex = received.IndexOf((char)2);
            int lastindex = received.IndexOf((char)3);
            if (firstindex > 0 && lastindex > 0)
            {
                string first = received.Substring(firstindex, 1);
                string last = received.Substring(lastindex, 1);
            }
            lock (client1.GetStream())
            {
                client1.GetStream().BeginRead(data, 0, System.Convert.ToInt32(client1.ReceiveBufferSize), ReceiveMessage, null);
            }
        }
        catch (Exception ex)
        {
            MessageBox.Show(ex.ToString());
        }
    }
于 2013-02-01T01:32:26.683 に答える