web-dev-qa-db-ja.com

Cによるモジュール式プログラミング:デバイスロジックを通信プロトコルロジックから分離

Cの経験はありません(C++以上の言語のみ)。現在、私は試してみましたが見つかりませんでしたプログラムロジックを他のパーツと組み合わせたり、他のプロジェクトで再利用したりできる置き換え可能なパーツに明確に分離できるように、優れたCコードを記述する方法に関する一般的なガイドラインです。

コンテキストを与えるには:

受信したメッセージに対して計算を実行し、その結果を何度も送受信する必要があるチャネル(例:TCPまたはシリアルポートなど)を介して通信する2人の当事者がいます。計算の正確な性質と通信のタイプの両方を変更する必要があるかもしれません。このため、通信と周辺機器の部分を計算ロジックの部分から「モジュール」に分離したいと思います(正確に言うと、実装)、これを「周辺モジュール」と「プロトコルモジュール」と呼びます。通信は非対称です。「マスター」と「スレーブ」の両方を呼び出します。どちらも同じ単一のコンパイル済みプログラムとして実装する必要があると思います。 、ユーザー入力で指定されたマスター/スレーブ動作を選択します。

私が想像しているようなものは次のとおりです。「マスター」プロセスは、「スレーブ」プロセスとの接続を確立し、一部のデータを初期化/フェッチする「ペリフェラルモジュール」から始まります。 「スレーブプロセス」にメッセージを送信(および受信)する方法に関する(可能な限り一般的な)指示とともに、「プロトコルモジュール」にデータを渡します。プロトコルモジュールが引き継ぎ、「スレーブプロセス」にメッセージを送信します。そこで「メッセージはその「プロトコルモジュール」によって受信され、通信が続行されます。実行中、「プロトコルモジュール」は、デバッグ/ステータス情報を「周辺モジュール」に送り返すことができます。これは、個別のスレッドとして実行される場合とされない場合があります(現在、絶対に必要だとは思いません)。送信されるメッセージの数、長さ、および構造は、「プロトコルモジュール」に依存し、ステータス/デバッグ情報の正確な性質も異なります。 「周辺モジュール」にはいくつかの異なるバージョンがあり、さまざまなOSで実行され、場合によっては統合デバイスでも動作するように設計されているため、すべて「プロトコルモジュール」の実装を使用できます。 「プロトコルモジュール」のいくつかの異なる実装もあるかもしれません。

私の現在の実装のアイデア:

各モジュールのすべての実装が準拠すべき「プロトコルモジュール」と「周辺モジュール」の間のインターフェースとして機能するヘッダーファイル「interface.h」を作成します。このヘッダーファイルは、次のような関数(すべて外部リンケージを含む)を宣言します(「interface.h」でも定義されている意味を持つエラーコードを返します)。

  • int recieve_data(char* data, int num_bytes)
  • int send_data(char* buffer, int num_bytes)
  • int status_info_output(char* buffer, int num_bytes)
  • int begin_protocol(char* initial_data, int num_bytes, SOME_STRUCT config)

メソッドrecieve_datasend_dataおよびstatus_info_outputは「peripherals.c」によって定義され、「protocol.c」から呼び出されますが、begin_protocolは「protocol.c」で定義され、「peripherals.c」から呼び出されます。モジュール「protocol.c」には、構成パラメーターを定義するグローバル変数があります。 (静的リンケージとおそらく目に見えるアクセスメソッドを使用して、各「プロトコルモジュール」実装に固有の「protocolXY.h」ヒアリングファイルで宣言されています)。

問題は、SOME_STRUCTをどこでどのように定義するかです。その正確な内容は、「protocol.c」の実装によって異なります(大きなオーバーラップがあるため)。また、「プロトコルモジュール」は、プログラムの実行中に監視する必要がある情報を含むメッセージヘッダーを定義します。 status_info_outputは、そのような機能を提供するのに十分な用途があります。また、「ユーザーが実行中に通信を中断している」などのステータスメッセージやコマンドを、相手と明確に通信し、「プロトコルモジュール」とは独立して実装できる方法(つまり、最も可能性が高い)を含める方法もわかりません。それの異なる実装の間で違いはありません)。

さらに気になるのは、設計の観点から見ると、「プロトコルモジュール」はある種の静的ライブラリと見なすことができるということです(そのようにリンクする必要はありません)。特定の機能を定義するためにライブラリヘッダーがユーザー(「周辺モジュール」)に要求するのを見たことはありません。私はbegin_protocolには、通信方法を伝えるために関数ポインターが渡されますが、これはより複雑で、おそらくパフォーマンスの最適化には悪いようです(統合システムにとって重要な場合があります)。

このようなプロジェクトをCで構造化する方法、およびモジュール式プログラム(およびおそらくライブラリ)を作成する際の一般的な慣行についてのアドバイスはありますか?

前もって感謝します!

1
Adomas Baliuka

別のペリフェラル実装を使用するときに新しい実行可能ファイルを作成する必要がある場合は、デザインはほとんど問題ありません。 Cでは、1つのヘッダーファイルでインターフェイスを指定し、複数のソースファイルでさまざまな方法で実装して、ビルドシステムが使用するソースファイルを決定することは珍しくありません。

私が別の方法で行うことをお勧めするのは、あなたが最も疑問を抱く分野でもあります。私の意見では、ペリフェラルレイヤー/モジュールは、通信リンクを介して相手側にバイトを取得し、そこで受信することのみを担当する必要があります。

マスターノードが通信リンクを介して使用されるプロトコルを選択する責任があることを望む場合、それは周辺モジュールに属するものではありません。両方のモジュールを「プロトコル選択」プロトコルで起動することをお勧めします。次に、マスターは「プロトコル選択」プロトコルを使用してスレーブと通信し、残りの通信にどのプロトコルを使用するかを決定し、両方のデバイスがそのプロトコルをアクティブにするか、そのプロトコルに切り替えます。このようにして、すべての利用可能な/サポートされているプロトコルを知っている管理レイヤーが初期化を処理できます。