0

組み込み機器向けのシンプルな固定長プロトコルを設計しました。各パケットはわずか 2 バイトです。

 bits |  15..12  |    11..4     |  3..0   |
      |  OpCode  |     DATA     |  CRC4   |

「crc ベースのフレーミング」を使用します。つまり、レシーバーは 2 バイトを収集し、CRC4 を計算し、それが一致する場合、フレームは有効と見なされます。ご覧のとおり、フレームの開始またはフレームの終了はありません。

問題があります。CRC4 の推奨メッセージ長は 11 ビットですが、ここでは 12 ビットで計算されています。私が理解している限り、これは CRC エラー検出特性が低下することを意味します (ただし、どの程度かはわかりません)。

(ちなみに、誰かが CRC4 (またはその他) のコードを必要とし、それを自分で書くのに十分なスキルを持っていないと感じている場合、boost には任意の crc を計算できる非常に優れた boost::crc 関数があります)

問題は、この crc ベースのフレーミングが機能せず、フレーミング エラーが発生することです。つまり、あるメッセージの 2 番目のバイトと次のメッセージの最初のバイトが正しいメッセージを形成することがあります。

私の質問は - バイトを追加せずにフレーミングを修正する方法はありますか? その 2 バイトにすべてを詰め込むのにかなりの時間を費やしますが、そのように捨てるのはちょっと悲しいことです。ただし、オペコード フィールドにはスペア ビットがあります。

  • 無線チャネルは一度に複数のパケットを「吐き出す」ことを好むため、時間ベースのフレーミングはあまり信頼できません。
  • CRC4 よりもうまく機能するエラー検出方法が他にあるのではないでしょうか?

さらにバイトを追加する必要がある場合、それを行う最善の方法は何でしょうか?

  • フレーム開始バイトとバイトスタッフィング (COBS など) を使用できます (+2 バイトですが、破損したメッセージをどうするかはわかりません)。
  • フレーム開始ニブルを使用して、CRC を CRC8 (+1 バイト) に拡張できます。
  • 他の何か?
4

3 に答える 3

2

あなたが求めていることを行う一般的な方法は、起動時に「フレーミングを探して」、パケットを受け入れる前に N 個の連続した良好なパケットを要求することです。これは、HUNT、LOF (フレーム損失)、SYNC の 3 つの状態を持つステート マシンを使用して実装できます。

それは次のようなものかもしれません:

#define GOOD_PACKETS_REQUIRED_BEFORE_SYNC 8
int state = HUNT;
int good_count = 0;

Packet GetPacket(void)
{
    unsigned char fb = 0;
    unsigned char sb = 0;

    while (1)
    {
        if (state == HUNT)
        {
            fb = sb;
            sb = GetNextByteFromUART();

            if (IsValidCRC(fb, sb))
            {
                state = LOF;
                good_count = 1;
            }
        }
        else if (state == LOF)
        {
            fb = GetNextByteFromUART();
            sb = GetNextByteFromUART();

            if (IsValidCRC(fb, sb))
            {
                good_count++;
                if (good_count >= GOOD_PACKETS_REQUIRED_BEFORE_SYNC)
                {
                    state = SYNC;
                }
            }
            else
            {
                state = HUNT;
                good_count = 0;
            }
        }
        else if (state == SYNC)
        {
            fb = GetNextByteFromUART();
            sb = GetNextByteFromUART();

            if (IsValidCRC(fb, sb))
            {
                return packet(fb, sb);;
            }

            // SYNC lost! Start a new hunt for correct framing
            state = HUNT;
            good_count = 0;
        }
    } 
}

ATM や E1 ( https://en.wikipedia.org/wiki/E-carrier ) など、この (または同様の) 手法を使用するいくつかの標準通信プロトコルを見つけることができます。原理にはさまざまなバリエーションがあります。たとえば、最初の不良パケットを受信したときに SYNC から LOF に移行し (good_count を減らす)、2 番目の連続した不良パケットで LOF から HUNT に移行したい場合があります。これにより、フレームの再作成にかかる時間が短縮されます。上記は非常に単純なバリアントを示しています。

注意: 実際のコードでは、おそらく上記のようなブロッキング関数を受け入れることはできません。上記のコードは、原則を説明するためにのみ提供されています。

CRC が必要か、固定フレームワード (0xB など) を使用できるかは、メディアによって異なります。

于 2016-08-18T13:21:10.620 に答える
0

問題があります。CRC4 の推奨メッセージ長は 11 ビットですが、ここでは 12 ビットで計算されています。

いいえ、ここでは 16 ビットで計算されています。

私が理解している限り、これは CRC エラー検出特性が低下することを意味します (ただし、どの程度かはわかりません)。

CRC に関する推奨事項は、シングル ビット エラーを検出する可能性が 100% かどうかに言及している可能性があります。すべての CRC でマルチビット エラーが発生し、必ずしも検出されるとは限りません。

UART の CRC 信頼性に関する計算を扱うときは、開始ビットと停止ビットも考慮する必要があります。ここでビット エラーが発生することもあり、その場合、ハードウェアがエラーの検出を支援する場合と支援しない場合があります。

1 つのメッセージの 2 番目のバイトと次のメッセージの最初のバイトが正しいメッセージを形成する場合があります

もちろん。同期メカニズムがありません。何を期待しますか? これはCRCとは関係ありません。

私の質問は - バイトを追加せずにフレーミングを修正する方法はありますか?

同期フラグとして 1 バイトあたり 1 ビットを犠牲にするか、パケット長を増やす必要があります。または、データ ビット間に異なる遅延を使用することもできます。たぶん、2 バイトを互いに直接送信してから、遅延を使用します。

どの方法を選択するかは、データの性質と仕様によって異なります。SO の誰もあなたの仕様がどのように見えるかを教えてくれません。

CRC4 よりもうまく機能するエラー検出方法が他にあるのではないでしょうか?

ありそうもない。CRC は、ほぼ唯一の専門的なチェックサム アルゴリズムです。多項式は、ノイズの例外的な性質に基づいて選択されます。ノイズを可能な限り思い出させない多項式が選択されます。ただし、特定のアプリケーションでノイズがどのように見えるかを CRC の第一人者が知ることはできないため、これは主に学術的な関心事です。

代替手段は、合計、xor、パリティ、1のカウント数などです...それらはすべて確率的に非常に悪いです。

さらにバイトを追加する必要がある場合、それを行う最善の方法は何でしょうか?

データの性質を知らずにその質問に答えることはできません。

于 2016-08-18T13:00:00.647 に答える
0

CRC が主にパラノイア用である場合 (コメントから)、フレーミングのためにエラー チェックの堅牢性とプロセッサ時間を放棄することができます。

オペコードには空きビットがあるため、常に最初のバイトの最上位ビットをゼロに設定してください。次に、送信前に CRC を計算した後、2 番目のバイトの最上位ビットを 1 に設定します。

フレームは、最初の最上位ビットが 0 で 2 番目のビットが 1 である連続する 2 バイトです。2 バイトが CRC チェックに失敗した場合は、2 番目のバイトの最上位ビットをゼロに設定し、再計算して、送信前にパケットのビットが反転したかどうかを確認します。

欠点は、約半分の時間で CRC が 2 回計算されることです。また、フレーミング用のビットを設定すると、無効なデータが CRC と一致する場合があります。

于 2016-08-19T23:29:55.463 に答える