第 4 章 より高度な処理を行おう 37
4.2 周期的なデータ送受信を行うプログラムの解説
それでは、先程のプログラムの解説を行います。
プログラムの大まかな動きを、下図に示します。
Linuxプロセス RTLinuxモジュール(GP-IB I/Oモジュール)
スタート指令
ストップ指令
GP-IB機器の初期化 IFC送出,REN設定等
500ms周期
Agilent34401A
データ送信
データ受信
"MEASure:VOLTage:DC?"
データ送信
データ受信
計測した電圧値のデータ
計測
データ送信
データ受信
“:Measure:Voltage:DC?¥r¥n”
データ送信
データ受信
計測した電圧値のデータ
計測 データ送付
データ送付
・・・
・・・
周期的なデータ送受信プログラムの動作概要
RTLinuxモジュールを組み込んだ段階で、IFC送出,REN設定を行い、RTLinuxスレッド(trans_task
関数)の起動直後に、“*RST”コマンド,“*CLS”コマンドを送信して、Agilent34401Aの初期化を行っ
ています。その後、Linuxプロセスから指示があるまで、RTLinuxスレッドを眠らせておきます。
Linuxプロセスからスタート指示があると、 RTLinuxスレッドからAgilent34401Aに対して、電圧値
を 測 定 す る コ マ ン ド
“MEASure:VOLTage:DC?”
が 送 信 さ れ ま す 。 コ マ ン ド を 受 け 取 っ たAgilent34401Aは現在の電圧値を計測します。その電圧値をRTLinuxスレッドで受信し、RT-FIFO
を介してLinuxプロセスにデータを送付します。これらの処理を周期的に行います。繰り返しデータを受信し、Linuxプロセスに10回分の電圧値が送られれば、Linuxプロセスから、
RTLinuxモジュールに対してストップ指示を出します。
Agilent34401Aへのデータ送受信,Linuxプロセスへのデータ送付はRTLinuxスレッド(trans_task関
数)で行っています。Linuxプロセスの仕事は、 Agilent34401Aへのデータ送受信を行うRTLinuxモジュールに対する周期
処理のスタート指令,ストップ指令, Agilent34401Aから受信した電圧値のデータを、RT-FIFO経由 で受け取ることです。
次に、LinuxプロセスとRTLinuxモジュールの関係を、下図に示します。
main
init̲module cleanup̲module
trans̲task my̲handler
生成
生成 指令
受信データ 破棄
破棄 カーネル空間
ユーザ空間
Linux プロセス(pt̲datadisp̲app)
RTLinux モジュール(pt̲transtask.o) FIFO̲COMMAND
FIFO̲RESULT FIFO̲THRU̲CMD
指令の転送
LinuxプロセスとRTLinuxモジュールの相関関係
LinuxプロセスからRTLinuxモジュールに対する指示は、RT-FIFOを経由して、一旦ハンドラ (my_handler)に送られ、そこから別のRT-FIFOを介してRTLinuxスレッド(trans_task)に送られます。
trans_task関数では、 RT-FIFOからの指令を受け取り、 ID_START指令ならば周期処理をスタートさ
せ、Agilent34401Aからの受信データを、RT-FIFOを経由してLinuxプロセスに対して送ります。
ID_STOP指令ならば、周期処理をストップさせます。
4.2.1 共通定義ファイルの役割
共通定義ファイル
(pt_control.h)は、 LinuxプロセスとRTLinuxモジュールのコードの内、共通で使用
する定義の内容を抜き出したものです。共通定義ファイルでは、以下の設定を行っています。
行番号 内 容
13〜 20行目 #define宣言>
RT-FIFOの番号の定義と、各関数で使用する定数値を指定。
24~27行目 enum宣言>
LinuxプロセスからRTLinuxモジュールに対して指令を出す際のコマンドのID値
を指定。30〜 35行目 struct宣言>
LinuxプロセスからRTLinuxモジュールに対して指令を出す際のコマンドの構造
を指定。ここで重要なのが、
LinuxプロセスからRTLinuxモジュールに対して指令を出すために使用される、
コマンドの構造体
(CMD_STRUCT)です。
Linuxプロセスでは、この構造体に値をセットしてRTLinuxモジュールのハンドラに渡します。
ハンドラでは、この構造体ごと受け取って、指示された内容に従って処理を行います。
Linux プロセス
RTLinux モジュール struct CMD̲STRUCT { enum CMD̲IDS id;
long smp̲period̲ms;
};
LinuxプロセスからRTLinuxモジュールのハンドラへのコマンドの流れ
コマンドの構造体は、RTLinuxモジュールが行う作業の指示を行うID値(idメンバ変数)と、ID値に 補足する情報(smp_period_msメンバ変数)によって構成されます。
作業の指示を行うID値の種類は、CMD_IDS列挙体にて定義されています。
id変数
内 容ID_START smp_period_msで指定した時間間隔(ms)で、 RTLinuxモジュール内のRTLinuxスレッ
ド(trans_task)をスタートする。ID_STOP RTLinuxスレッド(trans_task)をストップさせる。
この構造体は、後の説明にも出てきますので注意して読み進めてください。
4.2.2 RT-Linuxモジュールの動き
RTLinuxモジュール(pt_transtask.o)は、Linuxプロセスからの作業依頼に従って、ドライバを使って
データの送受信を行います。(136〜 190行目 :RT-FIFO,RTLinuxスレッドの生成やドライバの初期化)
RTLinuxモジュールが組み込まれる時、最初に136行から始まるinit_module関数が呼び出されます。
ここでは、RT-FIFOやRTLinuxスレッド,ハンドラ等のリソースを生成しています。
項目 内 容
RT-FIFO(FIFO_COMMAND) 146行目のrtf_create関数>
Linuxプロセスからの指示を受けるためのRT-FIFOです。指
示は、ハンドラmy_handlerに渡されます。RT-FIFO(FIFO_THRU_CMD) 151行目のrtf_create関数>
ハンドラにて、Linuxプロセスから受け取った情報を、周 期的な送受信を行うRTLinuxスレッド(trans_task)に渡すた めのRT-FIFOです。
RT-FIFO(FIFO_RESULT) 155行目のrtf_create関数>
周期的なデータ送受信を行うRTLinuxスレッド(trans_
task)で取得したデータを、Linuxプロセスに渡すための RT-FIFOです。
ハンドラ(my_handler) 147行目のrtf_create_handler関数>
Linuxプロセスからの指示を受け取るための処理の入り口
です。
RT-FIFO経由で送られた情報は、一旦このハンドラ
が受け取り、然る処理に回されます。
RTLinuxスレッド (trans_task)
189行目のpthread_create関数>
周期的なデータ送受信を行うRTLinuxスレッドです。
Linuxプロセスから送られる指示は、最終的にここに送ら
れ、パルス出力制御を行います。158〜163行では、受信バッファの確保を行っています。
recv_buff_size変数の値に従い、vmalloc関数を用いて動的にバッファを確保しています。
recv_buff_size変数は、RECV_BUFF_DEF_SIZE(= 80)
に値が初期化されていますが、15行目のMODULE_PARMマクロにより、 RTLinuxモジュール組み込み時にオプションパラメータを与える
ことで、受信バッファサイズを自由に設定できるようになっています。
例えばRTLinuxモジュール組み込み時、以下のように指定することで、
recv_buff_size変数の値を書
き換えることができます。# insmod pt_transtask.o recv_buff_size=128
↑recv_buff_sizeの値を128に書き換えます。
このようにして組み込むと、159行目のメモリ確保のサイズを表すrecv_buff_size変数の値は128と なり、128バイトの受信バッファが確保されます。
166〜186行目は、 I/Oモジュールの初期化(166行目のPciGpibExInitBoard関数),IFCの送出(175行目の PciGpibExSetIfc関数),RENの設定(182行目のPciGpibExSetRen関数)を行っています。これは定型的
な処理です。(123〜131行目:ハンドラの処理)
ハンドラ(my_handler)の役目は、LinuxプロセスからRT-FIFOを経由して送られる指示を、RTLinux スレッド(trans_task)に渡すことにあります。
この処理は、ほとんど定型的なものです。
RT‑FIFO RT‑FIFO
my̲handler
ハンドラ
rtf̲get rtf̲put
Linuxプロセス側 RTLinuxスレッド側
LinuxプロセスからRTLinuxスレッドへのデータの流れ
(49〜112行目:RTLinuxスレッド(trans_task関数)の処理)
RTLinuxスレッド(trans_task関数)は、Agilent34401Aに対するデータの送受信を行います。
58行目と61行目のsend_data関数は、Agilent34401Aに対してリセット(58行目の“*RST”コマンド送
信)とレジスタのクリア(61行目の“*CLS”コマンド送信)を行うコマンドのデータを送信していま す。この処理により、Agilent34401Aのデータ送受信の準備を行います。
RTLinuxスレッドの処理の中心は、64〜110行目のwhileループです。
ここで、Linuxプロセスから与えられた指示によって、データ送受信の周期実行の開始と停止を 行っています。
処理の決定は、CMD_IDS列挙体の定数値により決定されます。
列挙定数値 内 容
ID_START
78行目のpthread_make_periodic_np関数により、スレッドの周期実行を開始します。実行周期の間隔は、smp_period_msメンバ変数により指定されます。
ID_STOP
85行目のpthread_suspend_np関数により、スレッドの周期実行を停止します。★周期実行の周期について
ここでは、周期実行の周期を500msに設定していますが、この周期はGP-IB機器によって異なってきま す。処理の早いGP-IB機器ならばもっと早い周期でデータ送受信が行え、処理の遅いGP-IB機器ならば もっと遅い周期でしかデータ送受信が行えません。必ず、お持ちのGP-IB機器にあった周期を設定する ようにしてください。
スレッドの周期実行が開始されると、指定された周期ごとに92〜109行目のデータ送受信処理が行われ ます。
92行目のsend_data関数は、“MEASure:VOLTage:DC?"を送信して、Agilent34401Aに対して電圧を測定
するよう指示しています。96行目のPciGpibExRecvData関数は、計測したデータを受信しています。
受信したデータは、109行目のrtf_put関数にて、RT-FIFO経由でLinuxプロセスに送られます。
4.2.3 Linux プロセスの動き
Linuxプロセス(pt_datadisp_app)は、データ送受信の開始/停止の指示と、受信したデータの受け取
りを行います。main
RT‑FIFO(FIFO̲RESULT) RT‑FIFO(FIFO̲COMMAND)
受信データ取得
コマンド指令 RTLinux
モジュール
LinuxプロセスとRTLinuxモジュールとのRT-FIFOの関係
(29〜40行目:RT-FIFOのオープン処理)
ここでは、
open関数を使用し、 RTLinuxモジュールとデータのやり取りを行うRT-FIFOをオープン
しています。(43〜48行目:周期的な送受信の開始)
ここでは、RTLinuxモジュールに対して、周期的な送受信を開始させるため、
CMD_STRUCT構造
体に、周期送受信処理の実行開始を意味するID_START列挙定数と、周期間隔を指定し、write関 数を使ってRT-FIFO経由で指示を送っています。RTLinuxモジュール側では、この指示をハンドラで受けて処理を行います。
(51〜67行目:受信データの取得)
ここでは、
RTLinuxモジュール内で実行される周期的な送受信処理から、
受け取った受信データを、select関数とread関数を使って、取得しています。
データの取得は、10回行われます。
(71〜75行目:周期的な送受信処理の停止)
ここでは、RTLinuxモジュールに対して、周期的な送受信を停止させるため、CMD_STRUCT構造体に、
周期送受信処理の実行停止を意味するID_STOP列挙定数を指定し、write関数を使ってRT-FIFO経由で 指示を送っています。
RTLinuxモジュールは、この指示を受け取った後、実行を停止します。