質問

これはかなり長い質問なので、私と一緒に裸にしてください。

次のハードウェア用のエミュレータを実装しています 同時に開発されています。アイデアは、サードパーティを提供することです クライアントソフトウェアをテストし、ハードウェアを提供するソフトウェアソリューション 開発者がファームウェアを実装するための参照ポイント。

ハードウェアのプロトコルを書いた人々はカスタムを使用しました INCA_XDRと呼ばれるSUN XDRのバージョン。これは、シリアル化と メッセージを逆シリアル化します。 Cで書かれており、 ネイティブコードなので、プロトコルデータを手動で解析しています。

プロトコルは本質的にかなり複雑であり、データパケット 多くの異なる構造を持つことができますが、常に同じグローバル構造を持ちます:

  

[HEAD] [INTRO] [DATA] [TAIL]

[HEAD] =
    byte sync 0x03
    byte length X       [MSB]       X = length of [HEADER] + [INTRO] + [DATA]
    byte length X       [LSB]       X = length of [HEADER] + [INTRO] + [DATA]
    byte check X        [MSB]       X = crc of [INTRO] [DATA]
    byte check X        [LSB]       X = crc of [INTRO] [DATA]
    byte headercheck X              X = XOR over [SYNC] [LENGTH] [CHECK]

[INTRO]
    byte version 0x03
    byte address X                  X = 0 for point-to-point, 1-254 for specific controller, 255 = broadcast
    byte sequence X                 X = sequence number
    byte group X        [MSB]       X = The category of the message
    byte group X        [LSB]       X = The category of the message
    byte type X         [MSB]       X = The id of the message
    byte type X         [LSB]       X = The id of the message

[DATA] =
    The actuall data for the specified message,
    this format really differs a lot.

    It always starts with a DRCode which is one byte.
    It more or less specifies the general structure of
    the data, but even within the same structure the data
    can mean many different things and have different lenghts.
    (I think this is an artifact of the INCA_XDR tool)

[TAIL] =
    byte 0x0D

ご覧のとおり、多くのオーバーヘッドデータがありますが、これは プロトコルはRS232(ポイントツーマルチポイント)とTCP / IP(p2p)の両方で動作する必要があります。

    name        size    value
    drcode      1       1   
    name        8               contains a name that can be used as a file name (only alphanumeric characters allowed)
    timestamp   14              yyyymmddhhmmss  contains timestamp of bitmap library
    size        4               size of bitmap library to be loaded
    options     1               currently no options

または、まったく異なる構造を持つ可能性があります:

    name        size    value
    drcode      1       2   
    lastblock   1       0 - 1   1 indicates last block. Firmware can be stored
    blocknumber 2               Indicates block of firmware
    blocksize   2       N       size of block to load
    blockdata   N               data of block of firmware

場合によっては単なるDRCodeであり、追加データはありません。

グループとタイプフィールドに基づいて、エミュレーター 特定のアクションを実行する必要があります。まず最初にそれらを見て 2つのフィールドとそれに基づいて、データに何を期待するかを知っています 正しく解析する必要があります。

その後、応答データを生成する必要があります。 多くの異なるデータ構造。一部のメッセージは単に生成します ACKまたはNACKメッセージ、その他はデータを含む実際の応答を生成します。

小さなものに分割することにしました。

まず、IDataProcessorがあります。

このインターフェースを実装するクラスは責任を負います 生データを検証し、Messageクラスのインスタンスを生成します。 彼らは通信に責任を負わず、単にbyte []

を渡されます

生データの検証とは、ヘッダーのチェックサム、CRC、および長さのエラーをチェックすることです。

結果のメッセージは、IMessageProcessorを実装するクラスに渡されます。 IDataProcessorにはないため、生データが無効と見なされた場合でも 応答メッセージまたは他の何かの概念、それはすべて生データを検証するだけです。

エラーについてIMessageProcessorに通知するために、いくつかの追加プロパティが追加されました Messageクラスへ:

bool nakError = false;
bool tailError = false;
bool crcError = false;
bool headerError = false;
bool lengthError = false;

これらはプロトコルに関連せず、IMessageProcessorにのみ存在します

IMessageProcessorは、実際の作業が行われる場所です。 さまざまなメッセージグループとタイプがあるため、私は パターンマッチングのため、F#を使用してIMessageProcessorインターフェイスを実装する ネストされた多数のif / elseおよびcasteステートメントを回避する良い方法のように思えました。 (F#やLINQやSQL以外の関数型言語の経験はありません)

IMessageProcessorはデータを分析し、呼び出すメソッドを決定します IHardwareControllerで。 IHardwareControllerがあると冗長に見えるかもしれませんが、 しかし、別の実装と交換できるようにしたい F#の使用も強制されません。現在の実装はWPFウィンドウです。 ただし、Cocoa#ウィンドウまたは単なるコンソールなどです。

IHardwareControllerは、状態の管理も担当します。 開発者は、ユーザーインターフェイスを介してハードウェアパラメータとエラーを操作できる必要があります。

したがって、IMessageProcessorがIHardwareControllerの正しいメソッドを呼び出すと、 応答MEssageを生成する必要があります。繰り返しますが、これらの応答メッセージのデータ 多くの異なる構造を持つことができます。

最終的には、IDataFactoryを使用して、メッセージを生のプロトコルデータに変換します 通信を担当するクラスに送信する準備ができています。 (たとえば、データの追加のカプセル化が必要になる場合があります)

これは何も「ハード」ではありません;このコードを書くことについてですが、すべて異なっています コマンドとデータ構造には多くのロットが必要です

役に立ちましたか?

解決

F#は、差別化された共用体を介してこのドメイン内のメッセージを表すのに自然に適していると思います。私は想像しています。

type Message =
    | Message1 of string * DateTime * int * byte //name,timestamp,size,options
    | Message2 of bool * short * short * byte[]  //last,blocknum,blocksize,data
    ...

バイト配列との間でメッセージを解析/解析解除するメソッドとともに。あなたが言うように、この作業は単純で退屈です。

メッセージの処理についてはあまりわかりませんが、全体的に説明に基づいて、メッセージを処理しているようです。

「ツールの柔軟性」について少し心配していますが、制約は何ですか? (例えば、.Netは、テクノロジーX、Y、Zを知っているプログラマーによって維持されなければならず、特定のパフォーマンス基準を満たす必要があります、...)

他のヒント

ここに私の2セントがあります(注意:F#はわかりません):入力ファイルが細かく指定されていますが、 完全な文法でも。ファイルのコンテンツをアクションにマップする必要があります。したがって、ファイルを解析することをお勧めします。 F#は関数型言語であり、再帰再帰解析と呼ばれる解析手法に適合します。 本" Expert F#" には、再帰降下解析の説明が含まれています。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top