Main Content

レガシ コード ツールによって外部コードへの呼び出しを生成コードにインポート

レガシ コード ツールとコード生成

Simulink® レガシ コード ツールを使用して、レガシまたはカスタム コード用の完全インライン化 C MEX S-Function を生成できます。S-Function はデバイス ドライバーやルックアップ テーブルのような組み込みコンポーネント用に最適化され、既存の C 関数または C++ 関数を呼び出します。

メモ

レガシ コード ツールは、C++ 関数とインターフェイスで接続することができますが、C++ オブジェクトとは接続できません。ツールが C++ オブジェクトのインターフェイスとして機能するようにこの問題を回避するには、Legacy Code Tool Limitationsを参照してください。

このツールは以下の目的で使用できます。

  • 生成された S-Function をシミュレーション向けにコンパイルし、ビルドする。

  • 既存の外部コードを呼び出すように設定されたマスク付きの S-Function ブロックを生成する。

コードを生成しようとしているモデルにこのような S-Function を含めるには、ツールを使用して TLC ブロック ファイルを生成します。TLC ブロック ファイルは、モデルの生成コードが既存の C または C++ 関数を呼び出す方法を指定します。

S-Function の依存するファイルのフォルダーが、S-Function を動的に読み込める実行可能ファイルの含まれるフォルダーではない場合、ツールを使用して S-Function に sFunction_makecfg.m または rtwmakecfg.m ファイルを生成します。ファイルを生成することで、S-Function を含むモデルを作成するときにそれらの依存関係が維持されます。たとえば、カスタム ターゲットなどいくつかの用途では、ファイルをターゲット特有の場所に配置する可能性もあります。ビルド プロセスは、S-Function が動的に読み込める実行可能ファイルと同じフォルダーにある sFunction_makecfg.m または rtwmakecfg.m を探して、そのファイル内の関数を呼び出します。

詳細については、Integrate C Functions Using Legacy Code Toolを参照してください。

コード生成のためのインライン化 S-Function ファイルの生成

S-Function を使用するモデルのコードを生成するには、お使いのアプリケーションのコード生成要件に応じて、次のいずれかを実行します。

  • インライン化 S-Function に 1 つの .cpp ファイルを生成する。レガシ コード ツールのデータ構造体で、既存の C 関数から S-Function ソース ファイルを生成する前に、Options.singleCPPMexFile フィールドの値を true に設定する。以下に例を示します。

    def.Options.singleCPPMexFile = true;
    legacy_code('sfcn_cmex_generate', def);

  • インライン化 S-Function にソース ファイルと TLC ブロック ファイルを生成する。以下に例を示します。

    def.Options.singleCPPMexFile = false;
    legacy_code('sfcn_cmex_generate', def);
    legacy_code('sfcn_tlc_generate', def);

singleCPPMexFile の制約

以下の場合は、singleCPPMexFile フィールドを true に設定できません。

  • Options.language='C++'

  • 次の Simulink オブジェクトのいずれかを使用して、IsAlias プロパティを true に設定する場合

    • Simulink.Bus

    • Simulink.AliasType

    • Simulink.NumericType

  • レガシ コード ツールの関数の仕様で、状態引数としてスカラー作業データを表現するための void* または void** を含む場合

  • レガシ コード ツール構造体の HeaderFiles フィールドで、複数のヘッダー ファイルを指定する場合

レガシ関数へのコード スタイル設定の適用

コード スタイルのモデル コンフィギュレーション パラメーターをレガシ関数に適用するには、次の手順を実行します。

  1. レガシ コード ツールのデータ構造体を初期化します。以下に例を示します。

    def = legacy_code('initialize');
    
  2. データ構造体で、Options.singleCPPMexFile フィールドの値を true に設定します。次に例を示します。

    def.Options.singleCPPMexFile = true;

設定を確認するには、次を入力します。

def.Options.singleCPPMexFile

singleCPPMexFile の制約

以下の場合は、singleCPPMexFile フィールドを true に設定できません。

  • Options.language='C++'

  • 次の Simulink オブジェクトのいずれかを使用して、IsAlias プロパティを true に設定する場合

    • Simulink.Bus

    • Simulink.AliasType

    • Simulink.NumericType

  • レガシ コード ツールの関数の仕様で、状態引数としてスカラー作業データを表現するための void* または void** を含む場合

  • レガシ コード ツール構造体の HeaderFiles フィールドで、複数のヘッダー ファイルを指定する場合

異なる場所にあるファイルの依存関係への対処

既定の設定では、レガシ コード ツールは、S-Function が依存するファイルは、動的に読み込むことができる、その S-Function の実行可能ファイルと同じフォルダー内に存在していると仮定します。S-Function がそれ以外の場所にあるファイルに依存しており、テンプレート makefile ビルド プロセスを使用する場合は、その S-Function について sFunction_makecfg.m または rtwmakecfg.m ファイルを生成します。たとえば、レガシ コード ツール データ構造体がパス名としてコンパイルのリソースを定義するような場合に、このファイルを生成します。

sFunction_makecfg.m または rtwmakecfg.m ファイルを生成するには、'sfcn_makecfg_generate' または 'rtwmakecfg_generate' を最初の引数とし、レガシ コード ツール データ構造体の名前を 2 番目の引数として、関数 legacy_code を呼び出します。以下に例を示します。

legacy_code('sfcn_makecfg_generate', lct_spec);

同じフォルダー内の複数の登録ファイルを使用して、関数 legacy_code の単一の呼び出しでファイルごとに S-Function を生成する場合は、'sfcn_makecfg_generate' または 'rtwmakecfg_generate' を指定する関数 legacy_code の呼び出しがすべての登録ファイルに共通していなければなりません。詳細については、Handling Multiple Registration Filesを参照してください。

たとえば、レガシ コード ツール構造体の配列として defs を定義する場合は、'sfcn_makecfg_generate' で関数 legacy_code を 1 回呼び出します。

defs = [defs1(:);defs2(:);defs3(:)];
legacy_code('sfcn_makecfg_generate', defs);

詳細については、S-Function のビルド サポートを参照してください。

シミュレーションおよびコード生成のための S-Function の展開

レガシ コード ツールで S-Function を生成し、それを他のユーザーに展開することができます。シミュレーションやコードを生成するために S-Function を展開するには、次のファイルを共有します。

  • 登録ファイル

  • 動的な読み込みができるコンパイル済みの実行可能ファイル

  • TLC ブロック ファイル

  • sFunction_makecfg.m または rtwmakecfg.m ファイル

  • 生成された S-Function が依存するヘッダー、ソースおよびインクルード ファイル

これらの展開ファイルを使用するときは、次のようにします。

  • Simulink モデルで展開されたファイルを使用する前に、S-Function ファイルを格納するフォルダーを MATLAB® パスに追加。

  • レガシ コード ツール データ構造体によって、絶対パスやファイル変更の位置として必須ファイルが登録される場合は、sFunction_makecfg.m または rtwmakecfg.m ファイルを再び生成。

外部 C++ オブジェクトの統合

レガシ コード ツールは、C++ 関数とインターフェイスで接続することができますが、C++ オブジェクトとは接続できません。前の例を開始点として使用し、この制限を回避する方法の例を示します。

  • 新しいファイル adder_cpp.hppadder のクラス定義を変更します。新しい adder オブジェクトの動的な割り当て、メソッド add_one() の呼び出し、割り当てられたメモリの解放を行う 3 つの新しいマクロを追加します。それぞれのマクロは、adder オブジェクトへのポインターを受け取ります。レガシ コード ツールによって呼び出される各関数は C 言語のようなシグネチャをもたなければならないため、ポインターはキャッシュされて void* として渡されます。その後マクロ内で明示的に adder* にキャストしなければなりません。adder の新しいクラス定義を次に示します。

    #ifndef _ADDER_CPP_
    #define _ADDER_CPP_
    
    class adder {
    private:
    	int int_state;
    public:
    	adder(): int_state(0) {};
    	int add_one(int increment);
    	int get_val() {return int_state;};
    };
    
    // Method wrappers implemented as macros
    #define createAdder(work1) \
        *(work1) = new adder
    
    #define deleteAdder(work1) \
        delete(static_cast<adder*>(*(work1)))
    
    #define adderOutput(work1, u1) \
        (static_cast<adder*> ((work1)))->add_one(u1)
    
    #endif /* _ADDER_CPP_ */
  • adder_cpp.cpp を更新します。クラスの変更に伴い、1 つのグローバルなインスタンスの代わりに、生成された各 S-Function が固有の adder オブジェクトを管理します。

    #include "adder_cpp.hpp"
    
    int adder::add_one(int increment)
    {
    	int_state += increment;
        return int_state;
    }
  • 次の変更によって adder_cpp.cpp を更新します。

    • StartFcnSpec は、新しい adder オブジェクトを割り当ててポインターをキャッシュするマクロを呼び出します。

      def.StartFcnSpec  = 'createAdder(void **work1)';
      
    • OutputFcnSpec は、メソッド add_one() を呼び出してその S-Function 固有の adder ポインター オブジェクトを提供するマクロを呼び出します。

      def.OutputFcnSpec = 'int32 y1 = adderOutput(void *work1, int32 u1)';
    • TerminateFcnSpec は、メモリを解放するマクロを呼び出します。

      def.TerminateFcnSpec = 'deleteAdder(void **work1)';

参考

関連するトピック