web-dev-qa-db-ja.com

組み込みシステム用のシリアルコマンドプロトコルをどのように設計しますか?

シリアル経由で通信している組み込みシステムがあります。現在のコマンド構造はインタラクティブに操作できるように設計されています。プロンプトを表示し、いくつかのコマンドを受け入れ、結果を人間が読める形式で表示します。

これをよりマシンで使用可能な形式に変更することを検討しているので、MATLAB GUIを介してあまり問題なく話すことができます(現在、インタラクティブプロンプトやさまざまなメッセージ長などで問題が発生しています)。

組み込みシステムに適したシリアルコマンドプロトコルを設計する方法を説明したドキュメントまたは標準がどこかにありますか?

40
jparker

私は、RS232を使用してメディアを制御し、デバイスを表示するソフトウェアを書くことからいくつかの好み(そしてペットのおしっこ)を持っています。ハードウェアによっては、これらのいくつかが適用されない場合があります。

  • あなたのプロトコルを自動化に対してよりフレンドリーにすることは良い考えだと思います。対話式インターフェース(コマンド行またはその他)が必要な場合は、それを個別にビルドして、自動化プロトコルを使用してください。人間が読めるようにすることについてはあまり心配しませんが、それはあなた次第です。

  • (特に)無効なコマンドを受け取った場合でも、常に応答を返します。 ACKが$ 06、NAKが$ 15のような単純なもの。または、少しだけ人間が読めるようにしたい場合は、スペルアウトしてください。

  • 任意の値を設定できる場合は、同じ値をクエリする方法がいくつかあることを確認してください。値が多い場合、それらすべてを照会するには時間がかかる場合があります。一度に複数の値を返す1つまたはいくつかのメタクエリを検討してください。

  • 設定できないが重要な情報(モデル番号、シリアル番号、バージョン、著作権など)がある場合は、起動時またはリセット時に一度だけ表示するのではなく、照会できることを確認してください。

  • 有効なコマンドに対してエラーで応答しないでください。これは明らかだと思います...

  • 言うまでもなく、ハードウェアがサポートするシリアル設定を文書化します。特に、それがあなた以外の誰かによって使用される予定であり、シリアルポート、接続、ケーブル、またはその他の理由でデバイスと通信できないかどうかを理解するために最初の30分間を費やしたくない場合彼らのソフトウェア。苦いわけではない...

  • トグル値の代わりに絶対コマンドを使用します。たとえば、同じコマンドを送信して電源トグルのオンとオフを切り替える代わりに、電源オンと電源オフに別々のコマンドを用意します。

  • 応答には、応答するコマンドに関する情報を含める必要があります。このようにして、プログラムは応答を処理するために要求した最後のことを覚えておく必要はありません(以下の追加のクレジットオプションを参照)。

  • デバイスがスタンバイモードをサポートしている(オフではあるが実際にはオフではない)場合は、この状態でもクエリが機能することを確認してください。

データの完全性についてどれほど偏執的であるかに応じて、

  • メッセージを封筒で包みます。ヘッダーには、開始文字、メッセージの長さ、終了文字を含めることができます。万が一、部分的または不正なメッセージが表示される場合があります。最初は$ 02で、最後は$ 03かもしれません。

  • メッセージの整合性について本当に偏執的である場合は、チェックサムを含めてください。しかし、それらは少し苦痛になる可能性があります。

追加のクレジット:

  • ハードウェア設定を手動で変更できる場合は、ユーザーが問い合わせた場合と同じように、この変更をシリアルポートに送信してください。たとえば、パブリックディスプレイモニターの入力ソースをユーザーが変更できないようにしたい場合があります。

これがお役に立てば幸いです。

更新:

重要なことを忘れてしまいました。これを真剣に使用する前、特に他の人に渡す前に、簡単なことを試して、期待どおりに機能することを確認し、(さらに重要なことに)何も忘れていないことを確認してください。より大きなプロジェクトの途中で問題を見つけた場合、問題を修正するのにより多くの時間と労力がかかります。

これは、コマンドプロトコル、Webサービス、データベーススキーマ、またはクラスなどを設計する場合に適した経験則です。

51
Bruce McGee

ここ は、シリアルプロトコルフレーミングに関するEli Benderskiによるすばらしい記事です。選択したパケット形式に関係なく、必ずエスケープ文字を使用してください。実際のデータ内にそのような文字を含めることができ、パケットが破損した場合の再同期が非常に簡単になります。

15
Marcelo MD

帯域幅や遅延が大きな問題でない限り、できる限りASCIIを使用してください。デバッグが非常に簡単になります。

メッセージを送信し、次に明確な「メッセージ終了」文字(「キャリッジリターン」など)を送信するプロトコルが好きです。通常、パケットの開始信号はそれほど役に立ちません(他に何がその回線にありますか?)。メッセージの終了にCRを使用すると、ターミナルプログラムを介したテストも簡単になります。

更新:Bruceは(コメントで)パケットの開始文字を使用すると、破損した場合にパケットをわずかに早く見つけることができると指摘しました。パケット開始文字がないと、次のパケットの終わりまで、どこにいるかがわかり、その時点で、1つではなく2つのパケットをスローすることになります。

7
Michael Kohne

ブルース・マギーの答えが好きです。同様のインターフェースを使用して、他のいくつかのポインターを提供できます。

  • データパケットで数値型を返す場合は、すべて同じ形式にするようにしてください。一部の数値にはsingleを使用せず、他の数値にはdoubleを使用しないでください。そしてそれを恣意的にしないでください!

  • ICDのデータパケットの例を提供します。バイトオーダーまたはビットオーダー(MSByteが最初か、最後か?最初と最後は何ですか?)で推測しなければならないのは、非常にイライラします。パケットと時間の関係を示す図を提供します(つまり、0x02が最初に送信され、次にアドレスバイト、次にメッセージIDなどが送信されます)。

  • 可能な限り、データ形式を切り替えないでください。私は、いくつかのメッセージに「ASCIIエンコードされた数値」を使用するシステムで作業してきました。バイトから先頭の「3」を取り除き、それらをまとめて実数にする必要があります。 (通常、ASCIIエンコードは、回避する必要のあるバイトシーケンス(0x02、0x04など)がある場合に使用されます。エンコードされた数値は0x30、0x32、0x30、0x34です。これを回避するには、可能であれば長さフィールドを使用するか、または少なくともそれを常に行う!)

  • ボーレート、パリティなどを間違いなく明確に文書化します。RS-485を使用している場合は、バスモード(2線式?4線式?)またはこれを使用する予定のマシンに表示される設定を文書化します。 。必要に応じてスクリーンショットを提供してください。

このインターフェイスは、おそらくデバッグに非常に役立ちます。私は、次のようなデバッグ機能を備えたいくつかのシステムを使用してきました。

  • プログラマーが「ログに記録されたパラメーター」(内部変数)のリストを作成したシステム。報告したいもの(最大8つ)をシステムに通知し、ログに記録されたパラメーターについてシステムに照会すると、1つのデータパケットで返されます。私はこれが好きでしたが、システムの複雑さに応じて、実行時にそれらを指定できる場合とできない場合があります(または、簡単なことをして、返してほしいマスクを選択するマスクをシステムに送信することもできます)。

  • 動作を「中断」し、システムの一部を個別にテストできるデータパケット(つまり、D/Aでこの電圧を出力する、DIOポートでこのバイトを刺激するなど)

幸運を!

6

独自のプロトコルが必要な場合は、

パケットフレーミングを使用してください。

SLIPほんの数行のコードのフレーミング。 (RFC 1055)で指定

したがって、すべてのパケットは常に次のようになります。

 <slip packet start>
 message
 message crc
 <slip packet start>

メッセージの長さを送信しないでください。破損して、受信側のメッセージパーサーが混乱する可能性があります。

レシーバーに小さなレシーバーバッファーがあり、それがオーバーフローする場合は、パケットの境界まで読み取るだけです。大丈夫です。

シンプルな2バイトCRCがたくさんあります。 Xmodemは簡単です。パケットのすべてのバイトをxorする必要があります。

本当に素敵な人になりたい場合は、実際のコマンドにPPP、DDNS、HTTP-RESTを使用してください。 TCP/IP LeanのJeremy BenthamによるCの16シリーズPICプロセッサでこれを行うことについての素敵な本。

次に、Webブラウザーを使用して、Webブラウザー、またはCコードのlibcurlなどと対話できます。ほとんどすべてのプログラミング言語にはhttpを実行するためのライブラリーがあるため、誰もがデバイスと通信できます。

5
Tim Williscroft

ここには多くの良い提案やアイデアがあり、さまざまな目的でそれに取り組むためのさまざまな方法があることに注意してください。良いものと悪いものの両方で多くのシリアルプロトコルを使用したことと、いくつかの独自のプロトコル(良い点と悪い点の両方)を作ったことは、ここに私の提案とコメントのいくつかです。

  • 複雑にしないでおく。シンプルなヘッダーベースのコマンド応答「パケット」で最大の成功を見つけました。

  • 人間が読めるASCIIについて心配する必要はありません。実際にプロトコルをデバッグする数時間だけ役に立ちます。その後、常にASCIIとしてデータをエンコードすることは制限され、大量のデータを転送する場合は非常に非効率的です。

  • エラーチェックを使用します。 16ビットCRCは、チェックサムよりも桁違いの保護を提供し、MD5やSHA1などのより重いアルゴリズムよりも単純で効率的であるため、私は好みます。

  • コマンドには、応答と同じパケット形式を使用します。

  • パリティなしの8ビットデータを使用します。シリアルパリティビットは、CRCまたは他のデータ整合性チェックをすでに使用していて、せいぜい不十分なエラーチェックである場合、保護を追加しません。

  • したがって、最も単純な形式のパケットヘッダーは、コマンドまたは応答、パケットのサイズ、0個以上のデータ、およびエラーチェックコード(CRC)です。

4
newts

FTPは、インタラクティブにも自動化にも適度に機能するプロトコルの例です。 1つの重要な点は、応答が、自動クライアントが注意を払うべきかどうかを示すコードで始まることです。 POP3についても同様です。

これらのプロトコルの良い点の1つは、開発/デバッグ時に通常の端末から通信を合理的に駆動したり、通常のシェルスクリプト/バッチファイル/その他を使用して通信をスクリプト化したりできることです。

ただし、彼らが行わないことの1つは、信頼性を提供することです。これは、コミュニケーションスタックの下位層によって提供されます。これは、ほとんどの組み込み通信Pahで考慮する必要があるものです。

2
Michael Burr

Modbus( http://www.modbus.org/ )を見たことはありますか?これは、各メッセージのチェックサムを含むかなりシンプルなプロトコルです。また、「戻り値」を必要としないコマンドも含め、すべてのコマンドに応答を送信するため、コマンドが正しく受信されたかどうかを確認できます。 Modbusを選択した後の唯一の選択肢は、データを格納するレジスタアドレスと、ユーザー定義関数(MODBUSプロトコルで許可されている)の形式です。

2
Sam Skuce

プロトコルの例として Firmata を見てください。

1
Matthew Murdoch