Python CA の新機能

Python CA の新機能
Noboru Yamamoto
High Energy Accelerator Research Org.,
Accelerator Lab.
1-1 Oho, Tsukuba, Ibaraki JAPAN, 305-0801
DRAFT January 29, 2001
Abstract
Python から EPICS のデ−タベ−スに収められたデ−タを読み出すためのモジュ−ル ca.py および ca.c
は、初期のバ−ジョンから随時機能を増強してきた。初期のバ−ジョンでは基本的な put/get/monitor を
サポ−トしていただけであるが、その後、get/put の callback や Synchronous Group などの機能が追加
されている。これらの新機能と合わせ、ca.py の使用法について説明する。
1
はじめに
Python から EPICS のデ−タベ−スに収められたデ−タを読み出すためのモジュ−ル ca.py および ca.c
は、初期のバ−ジョンから随時機能を増強してきた。初期のバ−ジョンでは基本的な put/get/monitor を
サポ−トしていただけであるが、その後、get/put の callback や Synchronous Group などの機能が追加
されている。これらの新機能と合わせ、ca.py の使用法について説明する。
channel オブジェクトは ca.py の基本となるデ−タ型である。すべての CA による EPICS デ−タベ−
スのアクセスはこの channel オブジェクトのメソッドを呼ぶことが基本となる。3 節以降の数節ではこの
channel オブジェクトのメソッドとアトリビュ−トについて説明する。
2
EPICS CA Library 制御関数
ca.py には個々のチャンネルには関係しない CA Library の機能を使うための関数もいくつか用意されてい
る。その内特に重要なものは ca.pend event() および ca.pend io() である。これらの関数の使い道を理解
するためには、EPICS CA Library の仕組みを若干理解しておく必要がある。
EPICS CA library ではすべてのチャンネルとの入出力はいったんバッファにためられる。これによっ
て複数の要求や応答を一つのネットワ−クパケットに詰め込むことができ、ネットワ−クの効率的な利用
を目指している。
すべての入出力がバッファされているため、CA library を利用するプログラムは、バッファを吐き出
したり、非同期の応答を処理するために、必要に応じて制御を CA Library に渡してやる必要がある。
ca pend io() および ca pend event() はこのような目的のために用意された CA library の関数である。
これらの関数の中では、出力バッファを吐き出し、処理待ちの入力があれば callback 関数を呼び出すなどの
必要な処理を行う。これらの処理が際限なく行われていては、これらの関数を呼び出している本来のプログラ
ムの動作が停止してしまうことになるので、これらの関数は引数として実行時間の上限値として受け取って
いる。処理の途中で実行時間の上限値に到達すると、これらの関数は制御を呼び出し元のプログラムに返す。
ca.pend io() と ca.pend event() の違いは引数の timeout の取り扱いの違いである。[実際、CA Library 上
ではこれらの関数は一つの関数 ca pend() へのマクロとして実現されている。] ca.pend io() では、EPICS
のバッフアを処理した後は timeout をまたないで制御は関数の呼出元に戻されるが、ca.pend event() は、
buffer 等の処理を行った後も timeout の間制御は呼出元に戻っては来ない。
幸いなことに、Tkinter をつかった環境では、Tk の event lopp の中で、channel に入出力がある場合
ca.pend event() が定期的に呼ばれるようになっている。したがって、ユ−ザは特に ca.pend event() ある
いは ca.pend io() を明示的に呼び出す必要はない。
しかしながら、Tkinter の GUI を使わない Python/EPICS のプログラムでは、適当な所で ca.pend event
あるいは ca.pend io を読んでやる必要がある。
1
pend io および pend event() 関数は次節で説明する ca.channel オブジェクトの method としても存在
する。どちらの形式を使っても結果は同じである。
3
channel オブジェクトの生成
channel オブジェクトのインスタンスはチャンネル名を引数として、生成子 channel() を実行することで生
成される。
ch=ca.channel("caexample:channel1.VAL")
channel オブジェクトを生成しただけでは、このオブジェクトは EPICS database のチャンネルとの間の
通信路が確立されていない。通信路の確立を確認するには、それぞれのオブジェクトの state() メソッドあ
るいは conn state アトリビュ−トを利用する。接続が確立されている場合には、各オブジェクトの state()
メソッドば値 0 を返す。またアトリビュ−ト conn status は 2 となっている。
isConnected() メソッドは接続が確立されていれば TRUE(1) さもなければ false(0) を返す。wait conn()
メソッドは通信路確立まで、引数に指定された回数だけチェックを行う。指定された回数の間に接続が確立
されなかった場合には Python の例外を引き起こす。
ch.wait_conn(10)
4
デ−タの入出力:put and get
チャンネル・オブジェクトを通じて EPICS デ−タベ−ス中のチャネルの読み書きの基本となるのが get お
よび put である。EPICS CA の非同期的な振る舞いのために、get() メソッドは値を直接には返さない。
get() 呼出に続く pend io() あるいは pend event() の呼び出しの中でチャンネル・オブジェクトの.val ア
トリビュ−トが更新される。
print ch.val
ch.get()
ch.pend_event()
print ch.val
ch.pend event() は指定された時間の間、CA ライブラリに IOC から返される値を見ているだけなので、
timeout の指定が短すぎる場合には、一度の pend event() で値が更新されるとは限らない。値が確実に
更新されたことを確認するには後述のコ−ルバック・ル−チンの方法か synchronous group の機能を利用
する。
put も同様に非同期の動作である。put() メソッドの呼び出しは CA のリクエストをバッファにおくだ
けである。それに続く、pend event() 等の呼び出しで、バッフアが吐き出される。put 操作が IOC 側で完
了したことを確認するには、後述の put and notify() メソッドでコ−ルバック関数をしていする。
WF デ−タに値を put するには、Python の apply() 関数を用いる。apply() の第2引数には tuple だ
けが許されることに注意する必要がある。デ−タを list 等で作った場合には、tuple() 関数で明示的に型変
換を行う。
ch=ca.channel("myWF")
ch.wait_conn()
apply(ch.put,range(10))
ch.get(); ch.pend_event(0.01)
print ch.val
2
デ−タの非同期読み込み:monitor
5
CA の monitor 機能は EPICS の特徴的な機能であり、不要なデ−タのポ−リングを避けることで、効率
的な通信をおこなう。
Python/CA では、channel オブジェクトのメソッド monitor() がこの機能のために用意されている。
monitor の引数は callback 関数オブジェクトである。 monitor() のコ−ルバック関数は次の例のように
一つの引数をもつ。
def myCB(val):
print val
ch.monitor(myCB)
コ−ルバック関数が呼ばれたとき、この引数には、
(レコ−ドの値、レコ−ドのシビアリティ、レコ−ドのステ−タス、タイムスタンプ)
からなる tuple が割り当てられている。monitor() のコ−ルバック関数は、それに束縛されたチャン
ネルのオブジェクトの値 (.val) を自動的に更新することはない。値の更新にはコ−ルバックオブジェクの
update val() メソッドを呼んでやる必要がある。
class myChan(ca.channel):
def __init__(self,name):
ca.channel.__init__(self,name)
def myCB(self,val):
self.update_val(val)
print val
ch=myChan()
ch.monitor(myCB)
5.1
monitor の取り消し
monitor で登録したコ−ルバックを取り消すためには、clear monitor() メソッドを使う。clear monitor()
の引数は monitor() メソッドが返すモニタの登録番号 (evid) である。 引数を省略した場合、チャンネル・
オブジェクトに登録されているすべての monitor コ−ルバックが取り消される。 evid=ch.monitor(myCB)
.
.
.
ch.clear_monitor(evid)
チャンネル・オブジェクトに登録されているコ−ルバックの登録番号は,evid アトリビュ−トで見るこ
とができる。登録したコ−ルバックの関数オブジェクトは callbacks アトリビュ−トのインデックスにモニ
タの登録番号 (evid) を指定することで引きだすことができる。
6
非同期処理とコ−ルバック・ル−チン
monitor() の例のように EPICS では IOC の処理と、CA クライアントは独立に動作しているため、
monitor() 以外でもコ−ルバック関数が利用できる。put and notify() および get() の両メソッドでもコ−
ルバック関数が利用できる。put and notify(),get() のコ−ルバックの指定には名前つきの引数を利用する。
def putCB():
print "value was set"
ch.put_and_notify(100,cb=putCB)
put and nofity() のコ−ルバックは引数が無いことに注意しておく。put and nofity で引数 cb に call
back ル−チンを指定してじっこうすると、”put 操作およびそれに付随するすべての動作が終了した時点”
で指定した callback ル−チンが実行 (callback) される。put and notify() 自体の実行は IOC に put リク
3
エストを送った所で終了する。callback が実行されるためには、pend event() が実行されることが必要で
ある。put する値の形式は put() メソッドと同様である。
get() のコ−ルバックは monitor() のコ−ルバックと同じ形式である。コ−ルバックが指定された場合
には、通常の get() の呼び出しとは異なり、チャンネルオブジェクトの val アトリビュ−ト等の更新は行わ
れない。monitor() のコ−ルバックと同様に明示的に update val() メソッドをコ−ルバックの中で呼ぶ必
要がある。
ch.get(cb=myCB)
7
チャンネル・オブジェクトのアトリビュ−ト
チャンネル・オブジェクトは以下に示すアトリビュ−トを持つ。
name チャンネルオブジェクト生成時に与えられたチャンネル名
element count チャンネルの保持する要素の数。
conn state チャンネルの接続状態を示す。接続状態では 2 となる。
hostname チャンネルの接続先の IOC 名。
sevr get()/update val() によって更新される。チャネル接続先のレコ−ドのシビアリティを示す。
ts get()/update val() によって更新される。更新時間。EPICS の EPOCH(1990 年 1 月 1 日午前 0 時 0
分 0 秒)からの秒数。実数である。
status get()/update val() によって更新される。チャネル接続先のレコ−ドの状態を示す。
evid monitor() によって登録されたコ−ルバックの登録番号のリスト
8
入出力の同期:synhronous group
Synchronous Group は複数の put/get を発行したさいにすべてのリクエストが処理されたことを確認する
ことを可能にする1 。
Synchrous Group を使うには、まず Synchronous Group オブジェクトを生成する。
sg=ca.SyncGroup()
次にこの Synchronous Group に所属させるチャンネルのチャンネル・オブジェクトを add() メソッド
を用いて登録する。
sg.add(ch)
登録されたすべてのチャンネルの値を更新するには、GetAll() メソッドを使う。
sg.GetAll(tmo=1.0)
GetAll は tmo(秒) に指定された時間の間、登録されたすべてのチャンネル・オブジェクトの値 (val) が更新
されるのをまつ。tmo 内にすべてのチャンネル・オブジェクトが更新されない場合には、例外を発生する。
登録されたチャンネルの一部の値を更新あるいは値をチャンネルに設定するには get()、put() メソッド
をつかう。
sg.get(ch)
sg.put(ch, 1.0)
これらのリクエストはいったんバッファに蓄えられている。バッファを吐き出し、実行が終わるのを
wait() メソッドを使って待つ。wait の引数は GetAll() と同じくタイムアウトの時間 (秒) である。
sg.wait(1)
get() の場合には wait() が正常に終了した後、get() を発行したチャンネルオブジェクトに対して、
SynchGroup オブジェクトの convert() メソッドを適用する必要がある。
sg.convert(ch)
これによって、SyncGroup オブジェクト内のバッファ領域からチャンネル・オブジェクトに値がコピ−
される。
いったん発行した put/get の要求は、reset() メソッドの呼出で取り消すことができる。reset() は引数
を持たない。
sg.reset()
1 synchronous
group 機能は現在の所 Alpha マシンでは動作しない。
4
レコ−ドのコントロ−ル情報の読み込み
9
EPICS レコ−ドの数字型のレコ−ドでは、運転可能な範囲 (HOPR/LOPR) やアラ−ムを出す敷居値
(HIGH/HIHI/LOW/LOLO) などのコントロ−ル情報を持っている。また bi/bo や mbbi/mbbo 等の離散
型のレコ−ドではレコ−ドの値に表示すべき文字列などの情報を持っている。これらのコントロ−ル情報は
get() メソッドのオプション・パラメ−タ type を利用することで、取得可能である。type に指定できるのは、
ca モジュ−ル中で定義されている、DBR CTRL CHAR, DBR CTRL LONG, DBR CTRL DOUBLE,
DBR CTRL ENUM のうちいずれかである。
get() メソッドを type 引数に上記の値のいずれかを指定して実行すると、値の更新時にチャンネル・オ
ブジェクトに ctrl アトリビュ−トを追加する。このアトリビュ−トは Tuple を値としてもち、tuple の各
成分の意味は以下の様である。
DBR CTRL CHAR、DBR CTRL LONG:
{< 単位名 (UNIT)>,< 表示上限値 >,< 表示下限値 >,< 警報上限値 >,< 注意上限値 >,< 注意下限値
>,< 警報下限値 >,< 操作上限値 >,< 操作下限値 >}
DBR CTRL DOUBLE:
{< 単位名 (UNIT)>,< 表示上限値 >,< 表示下限値 >,< 警報上限値 >,< 注意上限値 >,< 注意下限値
>,< 警報下限値 >,< 操作上限値 >,< 操作下限値 >,< 表示精度 >}
DBR CTRL ENUM
{< 値の最大値 >,{< 文字列 0>,< 文字列 1>,...}}
次にこの機能を実際につかった例を示す。
>>>
>>>
>>>
>>>
10
>>>
(4,
>>>
import ca
ch=ca.channel("CO_BELLE:Status")
ch.wait_conn()
ch.get(type=ca.DBR_CTRL_ENUM);ch.pend_event(0.01)
ch.ctrl
(’No Injection’, ’Enable Inj.’, ’Belle HV ON’, ’Enable BELLE-HV’))
10
10.1
その他のユ−ティリティ関数
Get()
引数にチャンネル名(文字列)をあたえると値を返す。接続されるまで、内部でル−プしている。
10.2
Put() および Put and Notify()
引数にチャンネル名(文字列)と put する値を与える。現在のバ−ジョンは Waveform に対応していない。
Put and Nofity() には名前付き引数 cb でコ−ルバック関数を渡す。put and notify() メソッドと同様に
Put が終了した段階でコ−ルバック関数が実行される。
10.3
TS2Ascii()
EPICS のタイムスタンプを時刻を表す文字列に変換する。
10.4
TS2time
EPICS のタイムスタンプを Python で使われる時間を表す Tuple に変換する。
A
プログラムの実行
現在のところ、この文章で説明したバ−ジョンの Python/CA は通常使われているバ−ジョンの python と
は別のディレクトリに置かれている。
5
ABCO1 では、
/proj/GNU/Python-1.5.2/HP-UX/python
また、
ACSAD0/ACSAD2/ACSAD3 では、
/proj/GNU/Python-1.5.2/OSF1/python
を使って見て下さい。(この python は開発用ですので、随時置き換えられることがあります。)テスト期間
を置いた後、通常の場所
/proj/local/PA8000/bin
および
/proj/local/ALPHA/bin
に移動します。
6