割り込み処理ルーチンは
"dc_int.c" という名前のファイルに記述してください。
デバイスドライバの make の際に自動的にインクルードされます。
実際には、実験のセットアップ毎に適当なファイル名
(例えば hogehoge.c) を付け、
% ln -s hogehoge.c dc_int.c
によってシンボリックリンクを張るのが便利でしょう。
配付パッケージでは dc_test.c というファイルに
リンクが張られています。
メインの割り込みハンドラは dc_int() という関数で、
概ね以下の事柄を記述します。
"dc_test.c" の例題では
ad hoc な解決として、
LAM をチェックして 0 が返って来たら
何もせずに割り込みルーチンを抜けるようにしています。
LAM がクリアされないので再び割り込みがかかり、
データが読めるようになるまで再帰的に待つ事になります
(これが無限ループに陥る…、という経験は今までの所有りません)。
例題として "dc_test.c" というファイルを用意しましたので、
あまり内部に立ち入りたくないという人は、
その中の
#define TDC1 6
#define OUTREG 4
#define LAM_N TDC1
#define LAM_A 0
.....
/* Data AcQuisition for 1-event */
/* User should modify from here */
for (i=0;i<8;i++) /* read 8 channels of TDC1 */
camacCcycle2(TDC1,i,0,&dc_evbuff[(dc_wp++)%EV_MAX],&stat);
/* ------------------ to here */
.....
/* Also user should modify from here */
camacCcycle2(TDC1,0,9,0,&stat); /* clear module */
.....
辺りを書き換えて使うのが簡単です。
camacCcycle2 等のインライン関数の類の説明は
"dc_aux.h" の後半部分か、
こちらを参照してください。
この例では、
ステーションナンバー 6 にある TDC のサブアドレス 0〜7 のデータを
順次読み込んでバッファにストアしているだけです。
最後にモジュールをクリアしますが、
この例では F=9 を使って個別にクリアしています。
camacCc() によって
バスにクリア信号を送出する方法は処理が短時間で済みますが、
スケーラを使ったり Output Register のレベル出力を使っている場合には、
これらも一緒にクリアされてしまうので不適当です。
例題では更に、 イベントデータを以下のレコード形式に整えて バッファに書き込んでおり、 後述のデータ収集システムのサンプル に適合させています。
+--1--2--+------------------L-+---L+2-+
| EVTLEN | Contents | DELIM |
+--------+--------------------+-------+
EVTLEN はバイト単位のイベント長 (ここでは L+2)、
DELIM は区切り子 (0x8001) です。
dc_int() 以外に、
ioctl の
DC_INTON (データ収集の開始)
および
DC_INTOFF (データ収集の停止)
から各々呼び出される
dc_int_on() および
dc_int_off() という関数を与える必要があります。
"dc_test.c" の例題が充分簡単だと思いますから、
以下に再掲します。
それぞれ LAM の enable/disable および
output register のレベル出力 ON/OFF を行っています。
static void dc_int_on() {
int stat;
# if (defined(LAM_N) && defined(LAM_A))
camacCcycle2(LAM_N,LAM_A,26,NULL,&stat);
# endif
# if defined(OUTREG)
dc_outreg |= 0xff00; /* set higher 8-bit */
camacCcycle2(OUTREG,0,16,&dc_outreg,&stat);
# endif
}
static void dc_int_off() {
int stat;
# if defined(OUTREG)
dc_outreg &= 0x00ff; /* clear higher 8-bit */
camacCcycle2(OUTREG,0,16,&dc_outreg,&stat);
# endif
# if (defined(LAM_N) && defined(LAM_A))
camacCcycle2(LAM_N,LAM_A,24,NULL,&stat);
# endif
}
以下は、自分でもっと便利なルーチンを書きたい、 或いは、通常と異なる凝った処理をしたいという人向けですので、 深入りしたくない方は読み飛ばしてください。
データ収集ルーチンとは言え、 Linux のような汎用 OS のデバイスドライバの一部を書くわけですから、 次のような一般的注意が考えられます。
例えば、 インテリジェント補助クレートコントローラ (ACC) で 割り込みを記述する場合には、 (Interrupt Register や ACC への直接のシグナル等によって) 出来るだけ早いタイミングで割り込みを発生させ、 割り込みルーチンの中では Q を見ながら ADC/TDC の変換終了を待って、 データ読み出しを行なうのが一般的と思います。 これは、データ収集の dead time を最小に抑えようとする配慮の結果ですが、 ACC が割り込み処理以外に重要な仕事をしていないからこそ 許される方法と言えます。
一方 Linux (を含む汎用 OS) では、 システムの他のサービスに対する遅延を防ぐために、 個々の割り込み処理を出来るだけ短時間に終了させたいという要請が有ります。 データ収集の効率は多少犠牲になりますが、 システム全体の有効な運用としては、 例えば以下のような方法が薦められます。
syslogd で指定されたファイル
(通常は /var/log/messages 等) となります。
この出力は、
万が一カーネルパニックが起こった時も最期の断末魔の記録を残すため、
バッファされません。
従って、頻繁に printk() を行なうとシステムの負荷が
グッと増える事に注意してください。
通常、/var/log/messages と言ったログファイルは、
セキュリティのために root のみが読み出せるように
設定されている事が多いですが、
末尾部分に関しては同等の情報を
dmesg によって得る事ができます。
最後の注意は当たり前の事ですが、