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

AdInputADExを使った周期的なサンプリングの解説

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

4.2  AdInputADExを使った周期的なサンプリングの解説

それでは、前述のプログラムの解説を行います。

まず、LinuxプロセスとRTLinuxモジュールの関係を下図に示します。

main

init_module cleanup_module

my_task my_handler

生成

生成

指令

指令の転送 結果の通知

破棄

破棄 カーネル空間

ユーザ空間

Linuxプロセス(sample2)

RTLinuxモジュール(module2.o) FIFO_COMMAND

FIFO_THRU_CMD FIFO_RESULT

LinuxプロセスとRTLinuxモジュールの相関関係

・RTLinuxモジュールmodule2.oでは、init_module関数呼び出し時に、my_handlerとmy_taskを生成 します。cleanup_module関数は、逆に2つを破棄します。

・init_moduleでは、AD製品のオープンとmy_taskで実行するサンプリングのための前処理

(AdSetInputADEx関数)を行っています。

cleanup_moduleでは、逆にAD製品のクローズを行っています。

・my_handlerは、Linuxプロセスからの指令を受け取る専用のハンドラです。

・my_taskは、周期的な処理を行う専用のRTLinuxスレッドです。プログラムでは、スレッドのス タートとストップをサポートし、指定間隔の周期処理がスタートされると、ストップ指令を受 けるまで周期呼び出しごとにAdInputADEx関数を呼び出し、1件のAD入力を続けて行います。

取り込んだデータは、RT-FIFOを経由して、Linuxプロセスに対して送られます。

・Linuxプロセスsample2のmain関数内では、RTLinuxモジュールmodule2.oに対して、RTLinuxスレ ッドmy_taskへのスタートおよびストップを指令します。

Linuxプロセスのmain, RTLinuxモジュール内のハンドラ(my_handler),

スレッド(my_task)との間の 情報のやり取りは、RT-FIFOと呼ばれる専用の通信路を使ってやり取りされます。

RT-FIFOは、main

とmy_handler間, my_handlerとmy_taskの間, my_taskとmainの間の合計3つの

RT-FIFOが設定されます。

各スレッドおよびハンドラは、このRT-FIFOを情報の通信路として利用します。

詳細は後述しますが、このRT-FIFOを用いることで、RTLinuxスレッドはLinuxプロセスの動きに 引っ張られることなく、確実な周期実行を可能にしています。

4.2.1 共通定義ファイルの役割

共通定義ファイル(sample2.h)は、LinuxプロセスとRTLinuxモジュールが、共通で使用する定数等 を抜き出したものです。

共通定義ファイルでは、以下の設定を行っています。

行番号  内  容 

12〜21行目 #define宣言,typedef定義>

RT-FIFOの番号の定義,

各関数で使用する定数値の指定, バッファサイズの指定。

25~28行目 enum宣言>

LinuxプロセスからRTLinuxモジュールに対して指令を出す際のコマンドのID値を

指定。

31〜36行目 struct宣言>

LinuxプロセスからRTLinuxモジュールに対して指令を出す際のコマンドの構造を

指定。

ここで重要なのがLinuxプロセスからRTLinuxモジュールに対して指令を出すために使用されるコ マンドの構造体(CMD_STRUCT)です。

Linuxプロセスでは、この構造体に値をセットしてRTLinuxモジュールのハンドラに渡します。

ハンドラでは、この構造体ごと受け取って、指示された内容に従って処理を行います。

Linuxプロセス

RTLinuxモジュール struct CMD_STRUCT {

enum CMD_IDS id;

long

smp_period_ms;

};

LinuxプロセスからRTLinuxモジュールのハンドラへのコマンドの流れ

コマンドの構造体は、簡単な2つのメンバ変数で構成されています。RTLinuxモジュールに、どん な作業をして欲しいか指示を出すID値

(idメンバ変数)と、ID値を補足する情報(smp_period_msメン

バ変数)です。

作業を指示するID値は、25〜28行の列挙体 ID_STARTとID_STOPで定義されています。以下に、

LinuxプロセスからRTLinuxモジュールに指示する際の取り決めを簡単にまとめます。

id変数

内  容

ID_START smp_period_msで指定した時間間隔(ms)で、RTLinuxモジュール内の

サンプリング用 周期スレッドをスタートする。

ID_STOP

周期スレッドをストップさせる。

この構造体は、後の説明にも出てきますので注意して読み進めてください。

4.2.2 RTLinux モジュールの動き

ここでは、RTLinuxモジュール(module2.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)

周期サンプリングを行うRTLinuxスレッド(my_task)で取得した

ADデータをLinuxプロセスに渡すためのRT-FIFOです。

ハンドラ(my_handler) Linuxプロセスからの指示を受け取るための処理の入り口です。

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

然る処理に回されます。

RTLinuxスレッド(my_task)

周期サンプリングを実現するRTLinuxスレッドです。

Linuxプロセスから送られる指示は、最終的にここに送られ、周

期サンプリングを実現します。

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

ハンドラ(my_handler)

RTLinuxスレッド(my_task) FFO_COMMAND

FIFO_THRU_CMD

FIFO_RESULT Linuxプロセス

周期実行

ID_START ID_STOP

開始 停止

AdInputADEx関数 ←周期実行呼び出し

RTLinuxモジュール内の処理の流れ

RTLinuxモジュール内で中心となるのは、周期サンプリングを実現するRTLinuxスレッド(my_task)

です。

このスレッドは、Linuxプロセスからの指令により、スタート(ID_START), ストップ(ID_STOP)を 行います。スタート後の実行中、スレッドは周期ごとに1件のAD入力を行い、結果をLinuxプロセ スに返すという動作を行います。

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

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

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

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

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

(107行目:AdOpenEx関数)

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

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

(120行目:AdSetInputADEx関数)

『23ページ 

3.2  1件のAD入力を行う』では、1件のAD入力を行うためにAdInputAD関数を使用

していました。

ここでは、設定を行うAdSetInputADEx関数と、

AD入力のみを行うAdInputADEx関数のペアを使用

しています。

★何故、AdSetInputADEx関数を使うのか?

AdSetInputADEx関数とAdInputADEx関数の組み合わせは、AdInputAD関数とほぼ同じ処理内容です。

これは、周期サンプリング実行時の1件のAD入力の処理負荷を少しでも減らすために用意されています。

つまり、AdSetInputADEx関数で、1件のAD入力の処理を行う際に必要な前処理を行い、AdInputADEx関数の呼

び出しでは、AD入力の処理のみを行うようデザインされています。

(131行目:pthread_create関数)

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

(71〜79行目:ハンドラの処理)

ハンドラ(my_handler)の役目は、

LinuxプロセスからRT-FIFOを経由して送られる指示をRTLinuxス

レッド(my_task)に渡すことにあります。

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

RT-FIFO RT-FIFO

my_handler

ハンドラ

rtf_get rtf_put

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

(25〜58行目:RTLinuxスレッドの処理)

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

ここで、Linuxプロセスから与えられた指示によって、周期実行の開始と停止を行い(30〜48行の 処理)、周期実行ごとに1件のAD入力を行い(51行目のAdInputADEx関数

)、結果をLinuxプロセスに

渡しています(56行目のrtf_put関数)。

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

列挙定数値  内    容 

ID_START smp_period_msメンバ変数の値をms単位の実行周期として、

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

います。

ID_STOP pthread_suspend_np関数を呼び出し、自身のスレッドをスリープ状態にしてい

ます。

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

例えばここで5の値が指定されると、5msごとに1件のAD入力が行われます。これはサンプリング 周波数に換算すると、1 ÷ 5(ms) = 200Hzです。

4.2.3 Linux プロセスの動き

ここでは、Linuxプロセス(sample2)の動きを解説します。

まず、LinuxプロセスとRTLinuxモジュールとの関係を、下図に示します。

main

RT-FIFO(FIFO_RESULT) RT-FIFO(FIFO_COMMAND)

ADデータ値取得

コマンド指令 RTLinux

モジュール

LinuxプロセスとRTLinuxモジュールとのRT-FIFOの関係

Linuxプロセスは、RT-FIFOを2デバイスほどオープンし、それぞれコマンド指令とRTLinux

モジュールからのADデータの取得に使用しています。

(27〜37行目:RT-FIFOのオープン処理)

ここでは、

open関数を使用し、 RTLinuxモジュールとデータのやり取りを行うRT-FIFOをオープン

しています。

(40〜45行目:サンプリングの開始)

ここでは、RTLinuxモジュールに対してサンプリングを開始させるため、CMD_STRUCT構造体に サンプリング開始を意味するID_START列挙定数と周期間隔を指定し、

write関数を使ってRT-FIFO

で指示を送っています。

RTLinuxモジュール側では、この指示をハンドラで受けて処理を行います。

(48〜63行目:サンプリングのADデータの取得 )

ここでは、RTLinuxモジュール内で実行されるサンプリングのADデータを、select関数とread関数 を使って、取得しています。

ADデータの取得は、100回行われます。

(66〜71行目:サンプリングの停止)

ここでは、RTLinuxモジュールに対して、サンプリングを停止させるため、

CMD_STRUCT構造体

に、サンプリング停止を意味するID_STOP列挙定数を指定し、write関数を使ってRT-FIFOで指示 を送っています。

RTLinuxモジュールは、この指示を受け取った後、実行を停止します。

4.2.4 まとめ

ここまでの説明で使用したADドライバモジュールの関数を挙げてみます。

・AdOpenEx関数

・AdSetInputADEx関数

・AdInputADEx関数

・AdClose関数

たった4つの関数だけで、周期的なサンプリングを実現できました。

そして、導入編の『LinuxプロセスからRTLinuxモジュールを制御するプログラム』に挙げられた プログラムとこのサンプルを比較してみてください。非常に良く似ています。

このように、

RTLinuxプログラムといえど特に難しいものではなく、ある種のパターンに従ってプ

ログラムできることがわかります。

関連したドキュメント