2009-07-27 8 views
2

前のquestionの回答に基づいて、ここに私の埋め込みCアプリケーション用の単純なエラー報告システムのためのデザインがあります。私はいくつかのフィードバックを感謝します。これは埋め込みCアプリケーションのための良いエラー報告ソリューションですか?

私のアプリには、全体的なプログラムといくつかの下位レベルライブラリの層が形成されたコードがあります。最下位レベルでは、ライブラリはエラーコードに使用するバイトを取得します。そのため、合計255のエラーが発生します。彼らは同様に、列挙型でエンコードされます:

unsigned char lib1ErrNo; 

次のより高いレベルは、それが使用するライブラリのエラーコードが含まれています。これは、グローバル変数を介してチェーンのどちらかを渡され

enum lib1ErrorCodes { 
    ERR_NO_ERROR, 
    ERR_NO_CONNECTION, 
    ... 
    ERR_MISC 
}; 

enum lib2ErrorCodes { 
    ERR_NO_ERROR, 
    ERR_LIB1, 
    ERR_FILE_EXISTS, 
    ... 
    ERR_MISC 
} 

LIB1のエラーが検出され、このレベルのエラー変数にフラグが立てられている:

それは、ユーザーにこのすべてを報告するための時間になったときに、これらが検出されたトップレベルで

if (lib3ErrNo == ERR_LIB2) 
    if (lib2ErrNo == ERR_LIB1) 
     printf("Error %d: %s", lib1ErrNo, lib1ErrDesc); 

私はこの方式で考えることができる唯一のネガはさておき、数を設定する必要がありますそのライブラリの下にあるライブラリを指し示すためのエラーコードと、エラーコードのこれらのレベルをすべて含む最上位のプログラムのためのものです。

これを行うには適切な方法はありますか?

私がしたい:すべての方法のトップレベルまで

  • ユニークな誤差伝播をので、私はそれを報告することができます。
  • 埋め込まれたアプリであるため、大きな構造物を避けて移動することは好ましくありません。あなたの例では、両方のERR_NO_CONNECTIONERR_LIB1 1の値を持っている - -

答えて

3

は、私は別のエラーに対して同じ値を持つことだと思う賢明ではありません。

各ライブラリの値の範囲を予約し、これらの値をエラーコードに明示的に割り当てることをお勧めします。

enum lib1ErrorCodes { 
    ERR_NO_ERROR = 0, 
    ERR_NO_CONNECTION = 1, 
    ... 
    ERR_MISC = ... 
}; 


enum lib2ErrorCodes { 
    ERR_NO_ERROR = 0, 
    ERR_LIB1 = 101, 
    ERR_FILE_EXISTS = 102, 
    ... 
    ERR_MISC = ... 
} 
+1

私はこのシステムの下でどのライブラリがどのエラー範囲を取得するのかを積極的に管理する必要があると思いますか? 私が制御できないサードパーティのライブラリはどうですか? – jparker

+1

あなたは正しいと思います。サードパーティのライブラリについては、それぞれ独自のロジックを持っていると思います。 – mouviciel

+0

この戦略に対するポイントは、モジュール間に隠れた依存関係を作成することです。カップリングを最小にする、と私は言う。 –

0

私は、エラーコードとそれがどのライブラリから来たのかを示すフラグビットを格納する傾向があります。

2

私は各層で自分の誤りを翻訳しようとする傾向があります。その意味では意味があります。たとえば、通信スタックを呼び出すメインプログラムがあり、シリアルスタックドライバを呼び出すとします。通信スタックが持つかもしれない

typedef enum 
{ 
    SER_NO_ERR, 
    SER_TX_ERR, 
    SER_BAD_ARGS, 
    ... 
} SER_ERR; 

:シリアルドライバは、いくつかのエラーなどの可能性がありますあなたのCOMMスタックで

typedef enum 
{ 
    COMM_OK, 
    COMM_TIMEOUT, 
    COMM_TX_ERR, 
    ... 
} COMM_ERR; 

あなたかもしれないように見えるいくつかのコード:私は実現

// lets assume you are using the global variables serErr and commErr 
// to store error codes for their respective libraries. 
serial_transmit(someDataPtr, someSize); 
switch(serErr) 
{ 
    case SER_NO_ERR: 
     commErr = COMM_OK; 
     break; 
    case SER_BAD_ARGS: 
    case SER_TX_ERR: 
     commErr = COMM_TX_ERR; 
     break; 
    ... 
} 

かなりの量のコードが導入されるかもしれませんが、私はレイヤー間の抽象化を維持するのが好きです。また同様に、翻訳を処理するためにいくつかの関数を定義することができます。

void comm_handle_serial_error(SER_ERR err) 
{ 
    //copy in the switch statement from above 
} 

が、エラーは異なるコンテキストで異なるものを意味するかもしれないので、あなたがシステムを設計するように私は心の中でそれを保つことをお勧めします。

通信機能を呼び出すときに、COMM_ERRで定義されているすべてのエラーを処理することが、最高レベルでは心配です。これらの例はいずれも少し工夫されていますが、うまくいけばそのアイデアを得ることができます。

4

まず、8ビットアーキテクチャでない限り、すべてのエラーを保持するために大きな変数を使用します。

第2に、私は複雑なシステムを作りません。私はすべてのエラーの列挙型を持っているだけで、エラーが発生するたびに、エラーハンドラを呼び出してそれを前方に報告します。多くの場合、1つのエラーが発生すると多くのエラーが発生し、ライブラリごとに1つのエラーコードがあると、何かを失うリスクがあります。何も許可しないことを非常に気にしない限り、それ以外の場合は、エラーが発生した後に発生します。これはまたかなり複雑になることがあります。

3

私の経験では、エラーについてより多くの情報を報告することができれば、より良い結果が得られます。

私がこれらのタイプの問題を解決した1つの方法は、すべてのパッケージが問題を発見した場合に、それがインタフェースできる中央の「ステータスマネージャ」を考え出すことです。最低限、Status Managerは、問題を示すenumと、問題の場所を特定するのに役立つ別のenum/integerで呼び出すことができます。 - いくつかのシステム(通常は少なくとも128KのRAMを搭載した16ビット+システム)では、問題を説明するテキスト文字列を格納することさえ知られています。

また、このデータを抽出するために使用できるバックドアインターフェイスおよび/または独自のインターフェイスを確立できると仮定しています。

0

あなたのプログラムのスペース/ RAM /スピードの制限によっては、Cでの例外処理のようなC++のフレームワークがあります。This is an excellent article私は過去にこのような問題をダイナミックメモリ割り当て利用不可。適切に使用すると、コールツリーのエラーコードを渡すことに関連する問題がなくなります。

一方、いくつかの状況では他の提供された回答と同様のアーキテクチャを使用しています。最も一般的なものは、エラーコードを受け入れ、適切な処理機能を呼び出す集中エラー状態モジュールです。

0

__FILE__、__FUNCTION__、および__LINE__マクロを使用して場所を識別します。モジュールが特定されて以来、ユニークなエラーコードは必要ありません。以下を考慮してください。

#define ERROR_PRINTF(code, fmt, ...) error_printf("\n%s::%s(%u) Error %u : " fmt "\n", __FILE__, __FUNCTION__, __LINE__, code, __VA_ARGS__) 

int error_printf(const char* fmt, ...) 
{ 
    va_list args ; 
    va_start (args, fmt) ; 
    vprintf (fmt, args) ; 
    va_end (args) ; 
} 

次に、次の行がメインに表示されます。C、main()関数内の行20:

ERROR_PRINTF(ERR_NO_CONNECTION, "Connection failed on port %d", port) ; 

次のテキストが表示されます:個人

main.c::main(20) : Error 1 : Connection failed on port 2 

、これは表現エラーメッセージと正確な位置を可能にするので、私は気にしないであろうエラーコードビジネス。すべてのエラーはその場所によって一意に識別されますが、これははるかに便利です。