Main Content

XCP サーバー ソフトウェアのカスタマイズ

Simulink® エクスターナル モード シミュレーション用の XCP 通信プロトコルは、クライアント/サーバー方式の通信プロトコルです。既定では、ソフトウェアは次の XCP エクスターナル モード シミュレーションをサポートします。

  • ERT (ert.tlc) および GRT (grt.tlc) システム ターゲット ファイルを使用して生成されるコードのための開発用コンピューター上。

  • 一部のサポート パッケージ用。

カスタム ターゲット ハードウェアのシステム ターゲット ファイルが ERT または GRT システム ターゲット ファイルから派生している場合、用意された API を使用して XCP ターゲットの接続性を提供できます。XCP エクスターナル モードの制限事項が適用されます。

エクスターナル モードのターゲット接続性ソフトウェアは以下で構成されます。

  • エクスターナル モード抽象化レイヤー

  • XCP サーバー プロトコル層

  • XCP サーバー トランスポート層

  • XCP プラットフォーム抽象化レイヤー

エクスターナル モード抽象化レイヤー

エクスターナル モード シミュレーション中に Simulink と通信するには、ターゲット アプリケーションはエクスターナル モード抽象化レイヤーから関数を呼び出さなければなりません。

ソース コード ファイルの親フォルダーは次のとおりです。

matlabroot\toolbox\coder\xcp\src\target\ext_mode

この層の API は include\ext_mode.h で宣言され、src\xcp_ext_mode.c で実装されます。

Simulink と通信するために、ターゲット アプリケーションはエクスターナル モード抽象化レイヤーで公開されたサービスを使用します。このフロー チャートは、Simulink との通信を確立するために必要なターゲット アプリケーションの段階を表しています。

次の表は、ターゲット アプリケーションが各段階で呼び出さなければならない関数を示しています。

段階関数目的

INITIALIZE

extmodeParseArgs

エクスターナル モードのコマンド ライン引数を抽出する。

modelName_initialize

生成された Simulink モデル コードを初期化する。

extmodeInit

エクスターナル モードのターゲット接続性を初期化する。

HOST START REQUEST

extmodeWaitForHostRequest

[実行] ボタンをクリックしたときに作成される、開発用コンピューターからの開始要求を待機する。

RUN

modelName_step

生成された Simulink モデル コードの 1 つのステップを実行する。

extmodeEvent

モデルのサンプル時間 ID の場合、モデル ステップ関数によって生成された信号をサンプリングし、開発用コンピューターに送信するために通信プロトコルのトランスポート層にパケットの内容を渡す。

extmodeBackgroundRun

物理的な通信インターフェイスとのパケットの送受信を行い、選択した通信プロトコルに従ってパケットの内容を処理する。

HOST STOP REQUEST OR SIMULATION COMPLETE

extmodeStopRequested

エクスターナル モード シミュレーションの停止要求を開発用コンピューターのモデルから受信するかどうかをチェックする。この要求は、[停止] ボタンをクリックしたときに作成される。

extmodeSimulationComplete

生成されたモデル コードの実行が完了したかどうかをチェックする。
RESET

modelName_terminate

生成された Simulink モデル コードを終了する。

extmodeReset

エクスターナル モードのターゲット接続性を初期状態にリセットする。

以下の疑似コード例は、ターゲット アプリケーションでさまざまなフローチャート段階を実装する方法を示しています。RUN 段階の間は、エクスターナル モードの実行時環境には少なくとも 2 つのスレッドが必要です。

  • 生成されたモデル コードの実行を行う周期的なスレッド。

  • エクスターナル モード通信スタックの実行とパケットの送信と受信を行うバックグラウンド スレッド。

疑似コードは、同じ while() ループ内で periodicThreadextmodeBackgroundRun を逐次的に実行することで、マルチスレッドのシミュレーションを行います。

/*------------- Pseudo-Code Example -------------*/
/* Define periodic thread */
void periodicThread(void)
{
  /* Run model step function */
  modelName_step();
  /* Notify external mode abstraction layer about periodic event */
  extmodeEvent(PERIODIC_EVENT_ID, currentSimulationTime);
}

/* Main function for target application */
main(int argc, char *argv[])
{
  /*------------- INITIALIZE -------------*/
  /* Parse external mode command line arguments */
  extmodeParseArgs(argc, argv);
 
  /* Initialize model */
  modelName_initialize();
 
  /* Initialize external mode target connectivity */
  extmodeInit(extModeInfo, finalSimulationTime);

  /*------------- HOST START REQUEST -------------*/
  /* Wait until a start request is received from development computer */
  extmodeWaitForHostRequest(EXTMODE_WAIT_FOREVER);
  

  /*------- HOST STOP REQUEST OR SIMULATION COMPLETE -------*/    
  /* While simulation is not complete and stop request is not received */
  while (!extmodeSimulationComplete() && !extmodeStopRequested()) {

    /*------------- RUN -------------*/    
    periodicThread();
    extmodeBackgroundRun();
  }

  /*------------- RESET -------------*/
  /* Terminate model */
  modelName_terminate();

  /* Reset external mode target connectivity */
  extmodeReset();
  return 0;
}

関数を呼び出すコードを表示するには、[システム ターゲット ファイル][ert.tlc] に設定してXCP 通信を使用したエクスターナル モード シミュレーションの例を実行します。次に、コード ジェネレーター フォルダーにある ert_main.c を開きます。

メモ

システム ターゲット ファイルが grt.tlc または GRT ベースの場合、コード ジェネレーターは rt_main.c を作成し、既定では、内部ファイル ext_work.h で定義された API を使用します。ext_mode.h API の使用を有効にするには、ターゲット アプリケーションをビルドする前に以下を実行します。

set_param(model, 'TLCOptions', '-aExtModeXCPClassicInterface=0');

システム ターゲット ファイルが ert.tlc または ERT ベースであり、GenerateSampleERTMain'on' に設定されている場合、コード ジェネレーターは ert_main.c を作成し、既定では、ext_mode.h で定義された API を使用します。ext_work.h API の使用を有効にするには、ターゲット アプリケーションをビルドする前に以下を実行します。

set_param(model, 'TLCOptions', '-aExtModeXCPClassicInterface=1');

XCP サーバー プロトコル層

XCP サーバー プロトコル層では、自動化システムと測定システムの国際標準化団体 (ASAM) の規格である ASAM MCD-1 XCP に従って XCP コマンドとデータを解釈します。

ソース コード フォルダーは次のとおりです。

matlabroot\toolbox\coder\xcp\src\target\server\protocol\src
エクスターナル モード シミュレーションでは、ビルド プロセスによって必要なファイルがビルド情報オブジェクトに自動的に追加されます。

XCP サーバー トランスポート層

XCP サーバー トランスポート層は、ASAM の仕様に従って通信メディアに対してメッセージを送受信します。

ソース フォルダーは以下のとおりです。

matlabroot\toolbox\coder\xcp\src\target\server\transport\src
エクスターナル モード シミュレーションでは、ビルド プロセスによって必要なファイルがビルド情報オブジェクトに自動的に追加されます。

XCP プラットフォーム抽象化レイヤー

XCP プラットフォーム抽象化レイヤーは次のものを提供します。

targetパッケージを使用して Simulink とターゲット ハードウェアの間の接続性を指定できます。次のようにして指定します。

  • XCP ドライバーには target.CommunicationInterface クラスを使用します。

  • XCP プラットフォーム抽象化レイヤーの他の部分には target.XCPPlatformAbstraction クラスを使用します。

XCP プラットフォーム抽象化レイヤーを指定しない場合、ソフトウェアで既定のプラットフォーム抽象化レイヤーが使用されます。Linux®、Windows®、および Mac の各プラットフォームがサポートされています。詳細については、XCP エクスターナル モード シミュレーションの接続性のカスタマイズを参照してください。

カスタマイズの例については、カスタム抽出化レイヤーの作成を参照してください。

XCP ドライバー

XCP ドライバーは通信チャネルを通じて XCP メッセージを送受信します。エクスターナル モード シミュレーションでは、ビルド プロセスによってドライバー ファイルがビルド情報に自動的に追加されます。

XCP ドライバーは rtiostream API に基づいています。たとえば、ホストベースのエクスターナル モード シミュレーションでは以下の rtiostream ファイルが使用されます。

  • matlabroot\toolbox\coder\rtiostream\src\rtiostreamtcpip\rtiostream_tcpip.c

  • matlabroot\toolbox\coder\rtiostream\src\rtiostreamserial\rtiostream_serial.c

rtiostream 通信チャネルの実装とテストの詳細については、以下を参照してください。

rtiostream の情報は次のようにして指定します。

詳細については、カスタム抽出化レイヤーの作成を参照してください。

メモリ アロケーター

XCP サーバー ソフトウェアでは、内部データ構造体を保持するために、可変サイズの連続メモリ ブロックを動的に割り当てる必要があります。エクスターナル モード シミュレーションでは、ビルド プロセスによってメモリ アロケーター ファイルがビルド情報オブジェクトに自動的に追加されます。

XCP_MEM_ALIGNMENT プリプロセッサ マクロによるメモリ アロケーターのアライメントを構成します。次に例を示します。

#define XCP_MEM_ALIGNMENT 8

接続性にtargetパッケージを使用する場合は、target.XCPPlatformAbstraction クラスの BuildDependencies プロパティを使用します。次に例を示します。

xcpPlatformAbstraction.BuildDependencies.Defines = {'XCP_MEM_ALIGNMENT=8'};
XCP エクスターナル モード シミュレーションの接続性のカスタマイズを参照してください。

その他のプラットフォーム抽象化レイヤーの機能

このファイルでは、プラットフォーム抽象化レイヤー インターフェイスが定義されます。

matlabroot\toolbox\coder\xcp\src\target\server\platform\include\xcp_platform.h

以下の表では、ターゲット ハードウェアで展開する XCP サーバー ソフトウェアに提供しなければならない機能について説明します。

機能詳細

相互排除

"相互排除" サポートを使用してシステムのデータ構造にアクセスするために、XCP ドライバーは基本 API に依存して定義、初期化、ロックおよびロック解除を行います。

ターゲット ハードウェアの相互排除をサポートするには、カスタム実装を提供します。

Linux および Windows の既定の実装では、相互排除がサポートされています。

#if defined(_WIN32) || defined(__WIN32__) || defined(WIN32)
...
#define XCP_MUTEX_DEFINE(lock) HANDLE lock
#define XCP_MUTEX_INIT(lock) lock = CreateMutex(0, FALSE, 0)
#define XCP_MUTEX_LOCK(lock) WaitForSingleObject((lock), INFINITE)
#define XCP_MUTEX_UNLOCK(lock) ReleaseMutex(lock)

#else 
...
#include <pthread.h>
#define XCP_MUTEX_DEFINE(lock) pthread_mutex_t lock
#define XCP_MUTEX_INIT(lock) pthread_mutex_init(&(lock), NULL)
#define XCP_MUTEX_LOCK(lock) pthread_mutex_lock(&(lock))
#define XCP_MUTEX_UNLOCK(lock) pthread_mutex_unlock(&(lock))
...
#endif

スリープ

指定された時間が経過するまで呼び出しスレッド スリープを作成するスリープ API を提供します。Linux および Windows システムの既定の実装は次のとおりです。

#if defined(_WIN32) || defined(__WIN32__) || defined(WIN32)
...
#define XCP_SLEEP(seconds,microseconds)  Sleep((seconds) * 1000 \  
+ (((microseconds) + 1000 - 1) / 1000))

#else 
...
#if _POSIX_C_SOURCE >= 199309L
#define XCP_SLEEP(seconds,microseconds)  do {struct timespec t;\
 t.tv_sec = seconds; t.tv_nsec = microseconds * 1000; nanosleep(&t, NULL);} while(0)
#else
/* nanosleep is not available. Use select instead. */
#define XCP_SLEEP(seconds,microseconds)  do {struct timeval t; t.tv_sec = seconds;\
 t.tv_usec = microseconds; select(0, NULL, NULL, NULL, &t);} while(0)
#endif /* _POSIX_C_SOURCE >= 199309L */
...
#endif

ログ

診断メッセージを生成するために、XCP サーバー ソフトウェアにはターゲット ハードウェアによって提供されるログ サービスをサポートするカスタム出力 API が必要です。XCP_PRINTF プリプロセッサ マクロを定義しない場合、既定の実装は空です。

アドレス変換

XCP 標準は、メモリ内の変数のアドレスを 32 ビットのアドレスと 8 ビット拡張として表します。

XCP クライアントは、ビルド プロセスによって作成されるデバッグ情報を解析して、モデルの信号およびパラメーターのアドレスを抽出します。デバッグ情報は DWARF または PDB 形式です。

XCP クライアントは、引数 addressExtension および address を含む XCP コマンドを送信して、パラメーターおよび信号へのアクセスを要求します。

addressExtension および address の情報がターゲット ハードウェアによって受信されると、XCP サーバーはアドレスをターゲット ハードウェアのメモリ内の変数の位置に変換しなければなりません。変数の位置はローダーによって割り当てられ、ターゲット固有です。

XCP_ADDRESS_GET() マクロを使用して変換ロジックを指定します。Linux および Windows システムの既定の実装は次のとおりです。

#if defined(__MINGW32__) || defined(__MINGW64__)
#define XCP_ADDRESS_GET(addressExtension, address) \ 
(uint8_T*) ((uintptr_t) address)
#else
#define XCP_ADDRESS_GET(addressExtension, address) \ 
(uint8_T*) ((address) + (uint8_T*)&__ImageBase)
#endif
現在、32 ビットのハードウェア アーキテクチャのみがサポートされているため、addressExtension は 0 です。

メモリの設定およびコピー

メモリのコピー操作およびメモリの設定操作の最適化されたバージョンを指定できます。

XCP_MEMCPY および XCP_MEMSET プリプロセッサ マクロを定義しないと、既定の実装では標準 C 関数 memcpy および memset が指定されます。

#ifndef XCP_MEMCPY
#define XCP_MEMCPY memcpy
#endif

#ifndef XCP_MEMSET
#define XCP_MEMSET memset
#endif

コマンド ライン引数の解析

ターゲット ハードウェアでコマンド ライン引数の解析がサポートされていない場合、プリプロセッサ マクロ EXTMODE_DISABLE_ARGS_PROCESSING を定義します。

-w オプションを置き換えるために、このコマンドを使用して Simulink から接続メッセージを受け取るまでターゲット アプリケーションが待機状態に移行したままになることを指定できます。

set_param(modelName, 'OnTargetWaitForStart', 'on');
ビルド プロセスは必要なオプション (-DON_TARGET_WAIT_FOR_START=1) をコンパイラに提供します。

構造体のパッキングと配置

XCP ソフトウェア スタックの実装では、一部の内部 C 構造体のパッキングと配置が必要です。プラットフォーム抽象化レイヤーでは、コンパイラ固有のプリプロセッサ命令を使用してパッキングと配置の情報を提供します。

C 構造体をパッキングおよび配置するために、以下のプリプロセッサ命令を提供します。

#define XCP_PRAGMA_PACK_BEGIN(n)
#define XCP_PRAGMA_PACK_END()
#define XCP_ATTRIBUTE_ALIGNED(n)
#define XCP_ATTRIBUTE_PACKED
例:
XCP_PRAGMA_PACK_BEGIN(1)
typedef struct XCP_ATTRIBUTE_PACKED XcpSetDaqListModeCmdPacketFrame {
    uint8_T    PID;       /* Packet identifier, always XCP_PID_SET_DAQ_LIST_MODE */
    uint8_T    mode;      /* DAQ list mode (XCP DAQ Mode bit masks) */
    uint16_T   daqListId; /* DAQ list Id */
    uint16_T   eventId;   /* Event Channel Id */
    uint8_T    prescaler; /* Transmission rate prescaler */
    uint8_T    priority;  /* DAQ list priority (0xFF -> highest) */
}   XcpSetDaqListModeCmdPacketFrame;
XCP_PRAGMA_PACK_END()

XCP_PRAGMA_PACK_BEGIN(XCP_MEM_ALIGNMENT)
struct XCP_ATTRIBUTE_ALIGNED(XCP_MEM_ALIGNMENT) xcpFifoEntry {
    struct xcpFifoEntry *next;
    size_t msgFrameSize;    /* in AG units */
};
XCP_PRAGMA_PACK_END()

GCC コンパイラでは、以下の命令を使用します。

#define XCP_PRAGMA_PACK_BEGIN(n)
#define XCP_PRAGMA_PACK_END()
#define XCP_ATTRIBUTE_ALIGNED(n)  __attribute__((aligned(n)))
#define XCP_ATTRIBUTE_PACKED      __attribute__((packed))

Microsoft® Visual C++® コンパイラでは、以下の命令を使用します。

#define PRAGMA(n)   _Pragma(#n)
#define XCP_PRAGMA_PACK_BEGIN(n)  PRAGMA(pack(push, n))
#define XCP_PRAGMA_PACK_END()     PRAGMA(pack(pop))
#define XCP_ATTRIBUTE_ALIGNED(n)
#define XCP_ATTRIBUTE_PACKED

カスタム抽出化レイヤーの作成

カスタム プラットフォーム抽象化レイヤーを作成するには、以下を実行します。

  1. ヘッダー ファイル xcp_platform_custom.h を指定します。この Linux の例では必要な関数が定義されます。

    #ifndef XCP_PLATFORM_CUSTOM_H
    #define XCP_PLATFORM_CUSTOM_H
    
    /* XCP_ADDRESS_GET */
    #include <stdint.h>
    #define XCP_ADDRESS_GET(addressExtension, address)  (uint8_T*) ((uintptr_t) address)
    
    /* XCP_MUTEX */
    #include <pthread.h>
    #define XCP_MUTEX_DEFINE(lock)    pthread_mutex_t lock
    #define XCP_MUTEX_INIT(lock)      pthread_mutex_init(&(lock), NULL)
    #define XCP_MUTEX_LOCK(lock)      pthread_mutex_lock(&(lock))
    #define XCP_MUTEX_UNLOCK(lock)    pthread_mutex_unlock(&(lock))
    
    /* XCP_SLEEP */
    #include <sys/time.h>    /* gettimeofday */ 
    #if _POSIX_C_SOURCE >= 199309L
    #include <time.h>       /* for nanosleep */
    #else
    #include <stddef.h>
    #include <sys/select.h> /* for select */
    #endif
    
    /* _POSIX_C_SOURCE >= 199309L */
    #if _POSIX_C_SOURCE >= 199309L
    #define XCP_SLEEP(seconds,microseconds)  do {struct timespec t;\
     t.tv_sec = seconds; t.tv_nsec = microseconds * 1000; nanosleep(&t, NULL);} while(0)
    #else
    /* nanosleep is not available. Use select instead. */
    #define XCP_SLEEP(seconds,microseconds)  do {struct timeval t; t.tv_sec = seconds;\
     t.tv_usec = microseconds; select(0, NULL, NULL, NULL, &t);} while(0)
    #endif /* _POSIX_C_SOURCE >= 199309L */
    #endif
    

  2. ヘッダー ファイルを登録します。

    • 接続性にtargetパッケージを使用する場合は、target.XCPPlatformAbstraction クラスの BuildDependencies プロパティを使用して必要な情報を指定します。XCP エクスターナル モード シミュレーションの接続性のカスタマイズを参照してください。

    • 接続性にtargetパッケージを使用しない場合は、コード生成後のコマンドを定義します。

      function myXCPTargetPostCodeGenCommand(buildInfo)
       
        buildInfo.addDefines('-DXCP_CUSTOM_PLATFORM', 'OPTS');
      
        % Add my rtiostream
        buildInfo.addSourceFiles(customRtIOStreamFileName, ...
                                 customRtIOStreamSrcPath);
       
        % If the target hardware does not support parsing of command
        % line arguments
          buildInfo.addDefines('-DEXTMODE_DISABLE_ARGS_PROCESSING', 'OPTS');
       
      end

参考

| | | | | | | | |

関連するトピック

外部の Web サイト