• 検索結果がありません。

RTLinuxモジュールの動き

第 4 章  より高度な処理を行う 29

4.5  AdStartSamplingを使った永続的なサンプリングの解説

4.5.2  RTLinuxモジュールの動き

ここでは、RTLinuxモジュール(module3.o)の動きを解説します。

RTLinuxモジュールでは、サンプリングを実現するためにinit_module関数内で幾つかリソースを生

成しています。それを下表に示します。

項  目  内  容 

RT-FIFO(FIFO_COMMAND) Linuxプロセスからの指示を受けるためのRT-FIFOです。

指示は、ハンドラmy_handlerに渡されます。

RT-FIFO(FIFO_THRU_CMD)

ハンドラにて、

Linuxプロセスから受け取った情報を、 RTLinuxス

レッド(my_task)に渡すためのRT-FIFOです。

RT-FIFO(FIFO_RESULT) ADデバイスドライバにてサンプリングしたデータを、Linuxプロ

セスに渡すための

RT-FIFOです。

RT-FIFO(FIFO_STATUS) ADドライバモジュールにてサンプリング中の状態をRTLinuxス

レッドで監視し、そのデータをLinuxプロセスに渡すための

RT-FIFOです。

ハンドラ

(my_handler)

Linuxプロセスからの指示を受け取るための処理の入り口です。

RT-FIFO経由で送られた情報は、一旦このハンドラが受け取り、

然る処理に回されます。

RTLinuxスレッド (my_task)

ADドライバモジュールに対して、サンプリングのスタート,スト

ップを指示するRTLinuxスレッドです。

サンプリング中は状態を監視し、情報をLinuxプロセスに渡しま す。

コールバック関数

(my_smp_callback)

ADドライバモジュールにてサンプリング中に、指定件数のデー

タが溜まると呼び出されるコールバック関数です。

サンプリングデータは、ここで抜き出され、Linuxプロセスに渡 されます。

上表にて、ほとんどのリソース生成は、RTLinuxに用意されたAPIを用いて作成されますが、コー ルバック関数のみADドライバモジュールの提供するAPIを使って生成されます。

次に、生成された各リソースの相互関係と処理の流れを下図に示します。

ハンドラ(my_handler)

RTLinuxスレッド(my_task) FFO_COMMAND

FIFO_THRU_CMD

FIFO_STATUS Linuxプロセス

ADドライバモジュール

ID_START ID_STOP

サンプリング開始

サンプリング停止

周期呼び出し 周期監視

AdGetStatus関数

AdStartSampling関数

AdStopSampling関数

コールバック関数 (my_smp_callback)

データ抜き取り 指定件数サンプリング

AdGetSamplingData関数 FIFO_RESULT コマンド指示

サンプリング状態

サンプリング データ

『37ページ 

4.2.2  RTLinuxモジュールの動き』の図と比較してください。

先のサンプルでは、ADデータを取り込むサンプリング処理は、RTLinuxスレッド(my_task)にて行 っていましたが、ここでのサンプリング処理は、ADドライバモジュール内で行われます。

代わりに、RTLinuxスレッドでは、ADドライバモジュールのサンプリング状態を送るようにして います。

実際のサンプリング処理を行っているのは、ADドライバモジュールです。

このサンプルでは、トリガを指定せずにサンプリングしているので、ストップ指令を送らない限 りサンプリングを続けるようになっています。

このままだと、内部サンプリングバッファが固定長なので、サンプリングデータを上書きしてし まうことが考えられます。

サンプリングデータを上書きするのを避けるため、一定件数のデータが集まると、

ADドライバモ

ジュールからコールバックされる関数

(my_smp_callback)を登録しています。

サンプルでは、このコールバック関数が呼び出されたら内部サンプリングバッファからデータを 抜き取り、LinuxプロセスにRT-FIFO経由で送っています。

これにより、永続的なサンプリングを実現しています。

LinuxプロセスからRTLinuxスレッドへの指示は、ハンドラ(my_handler)を経由して行われます。

このサンプルのハンドラは、Linuxプロセスからの指示をそのまま横流しする単純なものです。

(157〜171行目:RT-FIFOおよびハンドラの生成)

init_module関数の最初の段階では、RTLinuxモジュールおよびLinuxプロセスで使用するRT-FIFO

および、Linuxプロセスからの指示を受け取るハンドラを生成しています。

(174行目:AdOpenEx関数)

次に、AD製品の制御を開始するためにAdOpenEx関数を使ってオープンしています。

ここで取得するデバイス番号は、他の関数で共通して使われるため、グローバル変数g_device_no に格納されています。

(183行目:コールバック関数の登録)

AdSetBoardConfig関数は、指定件数をサンプリングしたらコールバックされる関数を登録してい

ます。登録すべきコールバック関数のプロトタイプ形式は、以下の通りです。

void CallbackFunc(int userArg);

第3引数でコールバック関数の関数ポインタ

(上の例では、CallbackFunc)を、第4引数でコールバッ

ク関数の第1引数のパラメータを渡します。

例えば、第4引数に123を渡すと、上の例ではuserArg変数に123が渡されます。

(190〜211行目:サンプリング条件の設定)

AdSetSamplingConfig関数は、サンプリング条件の設定を行います。

「どのチャンネルをサンプリングするか?」「どんな入力方式を使うか?」「サンプリング周波 数はいくらでサンプリングするか?」等の設定をここで行います。

サンプルでは、AdGetSamplingConfig関数にてADドライバモジュールが保持するデフォルトのサ ンプリング条件の設定パラメータを取得し、これに修正を加える形式を取っています。

デフォルトのパラメータは、ADドライバモジュールがオープン時に初期値として持っています。

この値は、「その製品でサンプリングできる、理想的と思われる値」がセットされています。

ここでは、デフォルト値に修正を加える形式にすることで、サンプリング条件の諸設定を簡易に しています。

設定しているサンプリング条件の中で、重要なパラメータの一つが、サンプリングのデータ件数 を指定するulSmplNum変数とコールバック関数を呼び出すデータ件数を指定するulSmplEventNum 変数, トリガ条件を指定するulTrigMode変数です。

ulSmplNum変数は、 ulTrigMode変数のパラメータ値がAD_ETERNITYかそうでないかによって、若

干意味合いが変化します。

下表に比較を示します。

ulTrigMode変数 AD_ETERNITY AD_ETERNITY以外 ulSmplNum変数

内部サンプリングバッファの大きさ

を意味します。

上位が指示しない限りサンプリング が続けられるので、データ件数は無 制限であると言えます。

(ただし、何もしないと古いデータが

上書きされるので、何らかの処理を 必要とします)

サンプリングするデータ件数を意味 します。

(実際には、ここで設定した件数を保

持できるだけのバッファが内部に確 保され、サンプリングが行われます)

サンプルでは、サンプリング中にデータを抜き出す処理を行っています。

これを行うため、指定件数のサンプリングデータが溜まるとコールバックが行われ、コールバッ ク関数内でデータを抜き取る処理を行っています。

ulSmplEventNum変数は、このコールバックを呼びだすための指定件数の値を設定しています。

(218行目:AdSetSamplingBuffer関数)

AdSetSamplingBuffer関数では、お客様が用意したADドライバモジュール用の固定長のサンプリン

グバッファを渡しています。

ADドライバモジュールが使用するサンプリングバッファは、お客様がRTLinuxモジュール組み込

み時に確保し、ADドライバモジュールに指示してやる必要があります。

確保するバッファの大きさは、以下の式で求めることができます。

バッファのサイズ = 1データのサイズ × チャンネル数 × データ件数 1データのサイズ:

  AD製品の分解能により決定します。

分解能 データサイズ

8ビット 1バイト

12ビット 2バイト

16ビット 2バイト

24ビット 4バイト

チャンネル数:

  AdSetSamplingConfig関数の第2引数ADSMPLREQ構造体のulChCount変数と同値。

データ件数:

  AdSetSamplingConfig関数の第2引数ADSMPLREQ構造体のulSmplNum変数と同値。

サンプルでは、グローバル変数としてバッファ領域を確保し、そのポインタをAdSetSamplingBuffer 関数にて渡しています。

★何故、バッファの指定にグローバル変数を使用しているか?

大きめのバッファを取っているので、普通ならkmallocもしくはvmalloc関数を使う所でしょう。

何故動的なメモリ確保関数を使わないのでしょうか?これは、メモリの確保時に、同期性の問題が生じる からです。

例えば、AとBの2つのRTLinuxスレッドを想定します。ここでAのスレッドがメモリ確保の関数を呼び出し ている間、Bのスレッドに処理がプリエンプトされ、同じくメモリ確保の関数を呼び出そうとした時、どう なるでしょうか?

Aのスレッドでは、メモリ確保が完了してないので、Bのスレッドで、メモリ確保を行うことはできません。

何故なら、確保されるメモリ領域が重なることは許されないからです。

もし、メモリ確保を動的に行いたいのであれば、シビアな処理を要求しない個所、例えば、RTLinuxモジュー ルを組み込むinit_module関数内で呼び出すと良いでしょう。

(225行目:pthread_create関数)

pthread_create関数では、周期サンプリングを実行するRTLinuxスレッド(my_task)を生成しています。

(133〜141行目:ハンドラの処理)

ハンドラ(my_handler)の役目は、LinuxプロセスからRT-FIFOを経由して送られる指示を、RTLinux スレッド(my_task)に渡すことにあります。

この処理は、ほとんど定型的なものです。

RT-FIFO RT-FIFO

my_handler ハンドラ

rtf_get rtf_put

Linuxプロセス側 RTLinuxスレッド側

LinuxプロセスからRTLinuxスレッドへのデータの流れ

(74〜121行目:RTLinuxスレッドの処理)

RTLinuxスレッド(my_task)の処理の中心は、この74〜121行のwhileループです。

ここで、

Linuxプロセスから与えられた指示によって、サンプリングの開始と停止を行い(83〜109

行の処理)、周期実行ごとにサンプリング状態の取得を行い(112行目のAdGetStatus関数)、結果を

Linuxプロセスに渡しています(119行目のrtf_put関数)。

周期実行の開始と停止は、先に述べたCMD_IDS列挙体の定数値により決定されます。

列挙定数値  内  容 

ID_START AdStartSampling関数を呼び出し、ADドライバモジュールに対してサンプリン

グを開始させる。smp_period_msメンバ変数の値をms単位の実行周期として、

pthread_make_periodic_np関数を呼び出し、自身の実行周期の間隔を指定してい

ます。

ID_STOP AdStopSampling関数を呼び出し、ADドライバモジュールに対してサンプリン

グを停止させる。pthread_suspend_np関数を呼び出し、自身のスレッドを スリープ状態にしています。

周期実行の間隔は、smp_period_msの値により決定されます。

例えばここで5の値が指定されると、5msごとにサンプリング状態の取得が行われます。

★AdStartSampling関数の同期/非同期指定について

90行目のAdStartSampling関数では、第2引数にFLAG_ASYNCを指定しています。

これは、サンプリングを非同期に行うよう指示するものです。この引数を指定して関数を呼び出すと、サンプ リング処理が完了するのを待たず、すぐ関数の呼び出しから戻ります。

FLAG_SYNCを指定すると、サンプリングを同期で行うよう指示することになります。

100件のサンプリングを行うよう指示していた場合、この関数の呼び出しから戻った時、100件のサンプリング

が終了しています。

FLAG_ASYNCを指定した場合、サンプリングが終了している保証はありませんので、AdGetStatus関数やコー ルバック関数を用いて、サンプリングが終了したことを監視する必要があります。

サンプルでは、トリガ条件をAD_ETERNITYとしているので、FLAG_SYNCを指定すると、関数の呼び出しか ら戻らず、永遠にサンプリングを続けてしまいます。

従って、ここではFLAG_ASYNCを指定しています。

関連したドキュメント