第 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モジュールを制御するプログラム』に挙げられた プログラムとこのサンプルを比較してみてください。非常に良く似ています。
このように、