1 / 34

EPICS レコード/デバイス / ドライバ サポート

EPICS レコード/デバイス / ドライバ サポート. kasemir@lanl.gov, many slides copied from johill@lanl.gov. ハードウェアとの接続. General Idea. EPICS. Software. IOC Core: Db, CA, …. Record Support. “Driver”. Device Support. Hardware. Hardware. Driver Support. どこを拡張するのか …. よくある場合 : 新しいハードウェア (I/O Board,..)

rianne
Download Presentation

EPICS レコード/デバイス / ドライバ サポート

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. EPICSレコード/デバイス/ドライバサポート kasemir@lanl.gov,many slides copied from johill@lanl.gov

  2. ハードウェアとの接続 General Idea EPICS Software IOC Core: Db, CA, … Record Support “Driver” Device Support Hardware Hardware Driver Support

  3. どこを拡張するのか… • よくある場合:新しいハードウェア (I/O Board,..) • ドライバ:ハードウェアに直接アクセスする低レベルのソフトウェア。EPICSについて何も関知しない。 • デバイス:EPICS特有のドライバレコード(のサブセット)をつなぐ糊ソフトウェア • 時々:特定目的レコード • 既存のレコードサポートを少し変えてつくる。 • まれに: 新しいレコードタイプ • SNLや既存のレコードを組み合わせてできないだろうか?

  4. ドライバ/デバイス/レコード • これらについて何かしようと考える前に、“IOC Application Developer’s Guide” を読むこと! • 共通の考え方: • 新しいドライバ/デバイス/レコードをDBDファイル(Database Description File, ASCII)に記述する • 機能を実装し、ドライバ/デバイス/レコードサポートに特有な関数テーブルを用意する。 • 関数テーブルを外部参照とするコンパイル済みバイナリをLink/loadする。(関数自体はstaticな関数となる) • 初期化時にiocCore/iocshはDBDファイルを解釈し、関数テーブルを設置し、適切な関数を実行する。 • 新しいサポートを追加するためのインタフェースはよく定義されており、再コンパイルは最小限でよい。

  5. ドライバサポート • ドライバは一般に複雑になる: • Bus-level access, critical timing, interrupts, semaphores, threads, deadlocks, fail-safe, OS-specific (vxWorks, Linux, Win32), … • 典型的な関数の集合体:Check, report, init, read, write, setup_trigger(callback),… • “EPICS part”: オプショナル & 自明!

  6. ドライバ・サポート・エントリ・テーブル(DRVET)ドライバ・サポート・エントリ・テーブル(DRVET) /* EPICS Base include file <drvSup.h> */ typedef long (*DRVSUPFUN) (); struct drvet { long number; /*number of support routines*/DRVSUPFUN report; /*print report*/DRVSUPFUN init; /*init the driver */ }; • どの関数ポインタもNULLとすることができる。

  7. DRVET の例 /* xy.c */ #include<drvSup.h> static long xy_report() { printf(“XY Driver Info:\n); … } static long xy_init() { if (xy_check()) { … } struct drvet drvXy = {2, xy_report, xy_init };

  8. EPICSへのドライバの登録 • EPICS DBD File への登録 • driver(drvXy) • 結果: • EPICS iocInitは”drvXy”をシンボルテーブルから探し出し、その中の”init”ルーチンを呼び出す。 • VxShell/iocshでdbiorを使うと “report”ルーチンを実行する。

  9. よい習慣 • Wrong:2枚の XY boardがあり一枚のbase addressは 0x1234 でもう一枚は 0x4567二あると仮定し、ドライバプログラムに書き込んだ。 • Best: “configure” ルーチンを用意し、 vxWorks/iocshのスタートアップファイルでiocInitが実行される前にこの”conifugre”関数を実行する。 # EPICS records that refer to XY #0 will # access board at base addr. 0xfe12 # in mode 15 xy_config(0, 0xfe12, 15)

  10. デバイス サポート • レコードとドライバをつなぐ糊ソフトウェアでレコード型それぞれに特有のものとなる。(デバイス型xレコード型): • AI record, DTYP=“XY”, INP=“#C0 S5”:デバイスサポートは”XY”のドライバをカード#0にたいして呼び出し、信号#5を読み出してレコードのRVALに収める。 • デバイス・サポートの名前は、debAiSoft.cなどのようにdev<RecType><Device>.cとするのが慣習。 • すべてのレコードに共通なDev.Sup. 関数: • Report: 情報を表示 • Init: 初期化、一度だけ呼ばれる。 • Init_Record: レコード毎に呼ばれる。 • Get I/O Interrupt Info: SCAN=“I/O Intr”で使われる。 これらは省略可能であるが、それぞれのレコード型についてチェックが必要。

  11. デバイス・サポート・エントリ・テーブル(DSET)デバイス・サポート・エントリ・テーブル(DSET) /* Defined in devSup.h */ struct dset { long number; /* number of support routines */ DEVSUPFUN report; /* print report*/ DEVSUPFUN init; /* init support*/ DEVSUPFUN init_record; /* init particular record */ DEVSUPFUN get_ioint_info; /* get I/O Intr. Info */ /* Rest specific to record, e.g. BI:*/ DEVSUPFUN read_bi; /* Result: (0,2,error) 0 -> raw value stored in RVAL, convert to VAL 2 -> value already stored in VAL, don’t convert */ }

  12. デバイス・サポートの登録 • EPICS DBD ファイル: • device(ai,INST_IO,devAiXX,“My XX") • 結果: iocCore … • DTYP=“My XX” を ai recordsで指定できる。 • DSET “devAiXX” をシンボル・テーブルから見つけ出し、init()関数を実行し、それぞれのレコードについてinit_record()を実行する。レコードが「処理」される毎にread()関数が実行される。

  13. Dev.Supを実装する前に • ドライバの使い方を理解しておくこと。 • 以下の文献を読むこと: • “Application Developer Guide” • 対象となるレコードXXのソースコードをよみ、どのようにレコードサポートルーチンがデバイスサポートを呼び出すかを理解すること。 • EPICS baseのサンプルを読む: base/src/dev/softDev/devXXSoft.c

  14. 共通 report initialization initialize instance 機器からの割り込み AI特有 Read: aiレコードにデバイスの値を読み込む 線形変換(RVAL->VAL) AI レコードのデバイスサポート

  15. AI Dev. Sup.の初期化 long aiDevInit (unsigned pass) • すべてのレコード型に共通 • デバイス特有の初期化 • pass = 0, “iocInit()“ですべてのレコードの初期化前に呼ばれる。 • HWのチェックなど、ただし、レコードはまだデータを取り扱える状態ではない。 • pass = 1, “iocInit()“中で個々のレコードの初期化が終わった後にもう一度呼び出される。 • トリガを有効にするなど

  16. AI デバイス レポート long aiDevReport (struct aiRecord * pai, int level); • すべてのレコードに共通。ただし特有のレコード型へのポインタを引数としてとる。 • ユーザが”dbior <level>”を実行した際に、それぞれのレコードの実体にたいして一度ずつ呼び出される。 • デバイス状態をstdoutに出力する。 • Idea: “level”をあげることでより詳細な情報を得る。

  17. レコード毎のAI デバイスの初期化 long aiDevInitInstance(struct aiRecord *pai) • “iocInit()”中でデイスに接続されているレコードのそれぞれについて一度ずつ呼び出される。 • 典型的な役割 • デバイスアドレス (pai->inp)の解釈とチェック • デバイス固有データ(シグナル#、ドライバハンドラなど)のDPVTフィールドへの保存、: pvt = (X *) calloc(1, sizeof(X)); pvt->signal = signal_this_record_wants; pvt->drv = magic_handle_we_got_from_driver; pai->dpvt = (void *) pvt;

  18. 信号の値を読む long aiDevRead_(struct aiRecord * pai){ long rval; if (device OK){ rval=pDevMemoryMap-> aiRegister[pai->dpvt->signal]; pai->rval = rval;} else recGblSetSevr(pai, READ_ALARM, INVALID_ALARM); }

  19. AI 線形変換 long aiDevLinearConv ( struct aiRecord *pai, int after); • 制御値への変換のスロープとオフセットの設定if (!after) return S_XXXX_OK; /* A 12 bit DAC is assumed here */ pai->eslo = (pai->eguf - pai->egul)/0x0FFF; pai->roff = 0;/* roff could be different for device w/ e.g. +-5V, half scale = 0V */

  20. From convert() in aiRecord.c double val; val = pai->rval + pai->roff; /* * adjust with slope/offset * if linear convert is used */ if ( pai->aslo != 0.0 ) val *= pai->aslo; if( pai->aoff != 0.0 ) val+= pai->aoff; if(pai->linr == menuConvertLINEAR) val = (val * pai->eslo) + pai->eoff;

  21. Device supports interrupts, want to use SCAN=“I/O Intr” 高速なレコードのスキャン デバイスと同期したスキャン 困難な点: 割り込み: interrupt levelで動作, ほとんどのOS機能は使えない。 Record 処理: 通常タスクレベルで動作 IOSCANPVT 割り込みに応答してレコードの処理を行うためにEPICS Core に用意された仕組み Advanced: 割り込み

  22. IOSCANPVT • 独立した割り込み要因毎にIOSCANPVT構造体を用意し、初期化しておく。/* Record’s DPVT points to struct X* which contains IOCSCANPVT ioscanpvt */X = (X *) rec->dpvt;scanIoInit(&X->ioscanpvt); • 割り込み処理ルーチン (ISR)の中では: scanIoRequest(X->ioscanpvt); • ISRの中から呼んでも安全である。 • ただし、iocInitが終了する前(データベースの初期化完了前)にscanIoRequest()が呼ばれてはならない。(extern volatile int interruptAccept;)

  23. IO 割り込みの情報を提供 long aiDevGetIoIntInfo ( int cmd, struct aiRecord *pai, IOSCANPVT *ppvt); • 割り込みソースとレコード関連づける *ppvt = X->ioscanpvt; • cmd==0 - IO 割り込みによるスキャンに登録 • cmd==1 -登録から外す

  24. 非同期デバイス • read/write 関数は “PACT” をtrue に設定し、0を正常終了として返す。 • 非同期IO終了コールバックがレコードの「処理」を終了させる。(PACT=False) • ISR(Interupt Service Routine)中ではレコード処理関数を呼び出してはいけない。

  25. 非同期読み込みの例 long devXxxRead (struct aiRecord *pai) { if (pai->pact) return S_devXxx_OK; /* zero */ pai->pact = TRUE devXxxBeginAsyncIO(pai->dpvt); return S_devXxx_OK; }

  26. 非同期読み込み完了の例 void devXxxAsyncIOCompletion(struct aiRecord *pai, long ioStatus) { struct rset *prset = (struct rset *) pai->rset; dbScanLock(pai); if (ioStatus != S_devXxx_OK) { recGblSetSevr(pai, READ_ALARM, INVALID_ALARM); } (*prset->process)(pai); dbScanUnlock(pai); }

  27. レコードサポート • デバイス/ドライバサポートと類似している: • いくつかの関数は実装されなければならない。 • コンパイルされたバイナリファイルは“Record support entry table” を外部参照としてもつ。 • レコードとそれぞれのフィールド (name, data type,maybe menu of enumerated values, …)の情報は.DBDファイルに定義される。

  28. レコード DBD ファイル • 完全なDBDの文法については、 “IOC Application Developer’s Guide”を読む必要がある! • makeBaseAppでつくられるxxxRecord を例にとる recordtype(xxx){ # Each record needs to start w/ the common fields! include "dbCommon.dbd" field(VAL,DBF_DOUBLE) { prompt("Current EGU Value") asl(ASL0) pp(TRUE) } … }

  29. レコード・サポート・エントリ・テーブル:RSETレコード・サポート・エントリ・テーブル:RSET • 初期化: • レコードタイプ毎の初期化と、レコード毎の初期化 • プロセス関数:レコードの機能を実装する。. Often • このレコード特有のデバイスサポートを呼び出す • アラームのチェック • モニタの掲示 • フォワードリンクの処理 • ユーティリティ関数を用意することで、iocCoreが正しく読み書きされようにする。

  30. レコード・サポート・エントリ・テーブル(RSET)レコード・サポート・エントリ・テーブル(RSET) • レコードの実装はstruct rset <xxxRecord>RSET;を外部参照におく。 struct rset /* record support entry table */ { long number; /* number of support routine */ RECSUPFUN report; /* print report */ RECSUPFUN init; /* init support */ RECSUPFUN init_record; /* init record */ RECSUPFUN process; /* process record */ RECSUPFUN special; /* special processing */ RECSUPFUN get_value; /* OBSOLETE: Just leave NULL */ RECSUPFUN cvt_dbaddr; /* cvt dbAddr */ RECSUPFUN get_array_info; RECSUPFUN put_array_info; RECSUPFUN get_units; RECSUPFUN get_precision; RECSUPFUN get_enum_str; /* get string from enum */ RECSUPFUN get_enum_strs; /* get all enum strings */ RECSUPFUN put_enum_str; /* put enum from string */ RECSUPFUN get_graphic_double; RECSUPFUN get_control_double; RECSUPFUN get_alarm_double; };

  31. 初期化 • init() • IOC 起動時に一回呼ばれる。 • init_record(void *precord, int pass) • 一つのレコードにつき一回ずつ呼ばれる。. Second pass can affect other records.

  32. 処理 • 通常はこのExample に従えばよい。 static long process(void *precord) { xxxRecord*pxxx = (xxxRecord *)precord; xxxdset *pdset = (xxxdset *)pxxx->dset; long status; unsigned char pact=pxxx->pact; if( (pdset==NULL) || (pdset->read_xxx==NULL) ) { /* leave pact true so that dbProcess doesnt call again*/ pxxx->pact=TRUE; recGblRecordError(S_dev_missingSup, pxxx, ”read_xxx”); return (S_dev_missingSup); } /* pact must not be set true until read_xxx completes*/ status=(*pdset->read_xxx)(pxxx); /* read the new value */ /* return if beginning of asynch processing*/ if(!pact && pxxx->pact) return(0); pxxx->pact = TRUE; recGblGetTimeStamp(pxxx); /* check for alarms */ alarm(pxxx); /* check event list */ monitor(pxxx); /* process the forward scan link record */ recGblFwdLink(pxxx); pxxx->pact=FALSE; return(status); }

  33. ユーティティ関数 • 次の動作を実装できる。 • フィードが読み書きされたときレコードはどう反応すればよいか • ユニット、精度、リミット;VALフィールドだけではない。

  34. ユーティリティ関数… • special(DBADDR *addr, int after) • Addrで指定されたフィールドに誰かがアクセスする前後にとるアクションを記述できる。 • get_units(DBADDR *addr, char *units),get_precision(DBADDR *addr, long *prec),get_array_info(…) • EGUあるいはPRECフィールドの値を返すだけである。またaddrで指定されるフィールドに特有の情報を提供する。

More Related