• 検索結果がありません。

GP-IB機器からのサービスリクエスト(SRQ)を捉える

第 3 章  GP-IB I/O モジュール制御の第一歩 20

3.4  GP-IB機器からのサービスリクエスト(SRQ)を捉える

GP-IB機器によっては、機器内で発生した事象の変化(計測完了,エラー検出等)をコントローラ (GP-IB I/Oモジュール)に伝えるために、サービスリクエスト(SRQ)を発行するものがあります。弊

社製品は、このサービスリクエストを割り込みとして検知し、プログラムにて登録されたコール バック関数を呼び出すことで、事象の変化を伝達する仕組みを提供しています。

ここでは、Agilent34401Aに対して電圧の計測を指示し、計測完了時に発生するサービスリクエス トをコールバック関数で捉え、シリアルポーリングを行い、Agilent34401Aから計測したデータを 受信するプログラムを作成します。

エディタを起動し、List3-3に示すプログラムを入力し、ファイル名を『srqevent.c』として保存し てください。

List3-3 srqevent.c

1 2

3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49

#include <rtl.h>

#include <rtl_sched.h>

#include "pcigpib.h"

#define GPIB_BOARDNO 0 /* GP-IB I/Oモジュールのデバイス番号 */

#define ADRS_TBL_SIZE 2 /* GP-IB機器アドレステーブルの配列サイズ */

#define RECV_DATA_SIZE 80 /* 受信バッファのサイズ */

#define DELIM_SIZE 2 /* 受信時のデリミタサイズ(CRLF) */

pthread_t send_task_info;

int adrs_tbl[ADRS_TBL_SIZE] = { 22, -1 }; /* GP-IB機器アドレステーブル */

/* コールバック関数 */

void srq_callback(unsigned long ulEventFactor, unsigned long ulUserData) { int i, ret;

int device_no = (int)ulUserData;

int stb_tbl[ADRS_TBL_SIZE];

int stb_adrs[ADRS_TBL_SIZE];

char recv_data[RECV_DATA_SIZE];

long recv_size;

rtl_printf("srq_callback called [%#lx, %ld]¥n", ulEventFactor, ulUserData);

/* SRQイベントかチェック */

if(ulEventFactor & GPIB_DETECT_SRQ){

/* シリアルポール実行 */

ret = PciGpibExExecSpoll( device_no,

adrs_tbl,

stb_tbl,

stb_adrs);

if(ret){

rtl_printf("Serial poll error[%d]:ret=%d¥n", GPIB_BOARDNO, ret);

return;

} else {

rtl_printf("Serial poll success!!¥n");

}

/* シリアルポールの結果を表示 */

/* 注意事項:

コードを簡素化するため、GP-IB機器が1次アドレスのみで構成されている 前提で処理しています。

*/

for(i = 0; i < ADRS_TBL_SIZE; i++){

if(stb_tbl[i] == -1) break;

rtl_printf("no.%d status byte=%02x addrss=%d¥n", i, stb_tbl[i], stb_adrs[i]);

}

50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124

/* Agilent34401Aから、データの受信 */

recv_size = RECV_DATA_SIZE - DELIM_SIZE;

ret = PciGpibExRecvData( device_no,

stb_adrs,

&recv_size,

recv_data,

NULL);

recv_data[recv_size] = '¥0';

rtl_printf("PciGpibExRecvData [%d, %d, %s]¥n", ret, recv_size, recv_data);

} }

/* 送信処理を行うサブルーチン(0=成功) */

int send_data(char* send_data) { int ret;

rtl_printf("send_data called [%s]¥n", send_data);

/* Agilent34401Aに対して、データの送信 */

ret = PciGpibExSendData(GPIB_BOARDNO,

adrs_tbl,

strlen(send_data),

send_data,

NULL);

rtl_printf("send_data %s [ret=%d]¥n", (ret == 0) ? "success!!" : "error", ret);

return ret;

}

/* 送信処理を行うRTLinuxスレッド */

void* send_task(void* arg)

{ rtl_printf("send_task called arg=%d¥n", arg);

do {

/* Agilent34401Aをリセットします */

if(send_data("*RST") != 0) break;

/* レジスタクリアします */

if(send_data("*CLS") != 0) break;

/* SRQ割り込みを有効にします */

if(send_data("*SRE 16") != 0) break;

usleep(100L * 1000); /* ウェイト100ms */

/* 電圧測定を行います */

if(send_data("MEASure:VOLTage:DC?") != 0) break;

/* 補足説明

上の電圧測定を指示し、電圧を測定完了すると、Agilent34401Aは SRQ割り込みを発生させます。

ドライバモジュールは、SRQ割り込みを検出した後、srq_callback 関数を呼び出します。

*/

}while(0);

return 0;

}

/* 初期化関数(モジュールが組み込まれた時、呼ばれる関数) */

int init_module(void) { int ret;

rtl_printf("init_module called¥n");

EXPORT_NO_SYMBOLS;

/* GP-IB I/Oモジュールの初期化 */

ret = PciGpibExInitBoard(GPIB_BOARDNO, 0);

if(ret){

rtl_printf("Board open error[%d]:ret=%d¥n", GPIB_BOARDNO, ret);

return -1;

127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175

}

/* IFCを送出します */

ret = PciGpibExSetIfc(GPIB_BOARDNO, 1);

if(ret){

rtl_printf("Set IFC error[%d]:ret=%d¥n", GPIB_BOARDNO, ret);

return -2;

}

/* RENの設定(リモート状態にします) */

ret = PciGpibExSetRen(GPIB_BOARDNO);

if(ret){

rtl_printf("Set REN error[%d]:ret=%d¥n", GPIB_BOARDNO, ret);

return -3;

}

/* イベントマスクおよびコールバック関数登録設定 */

ret = PciGpibExSetEventMask(GPIB_BOARDNO,

GPIB_DETECT_SRQ,

srq_callback,

GPIB_BOARDNO);

if(ret){

rtl_printf("Set event mask error[%d]:ret=%d¥n", GPIB_BOARDNO, ret);

return -4;

}

/* データ送信のためのスレッドを生成、起動する */

return pthread_create(&send_task_info, NULL, (void*)send_task, 0);

}

/* 終了関数(モジュールが取り外される時、呼ばれる関数) */

void cleanup_module(void) { int ret;

rtl_printf("cleanup_module called¥n");

/* GP-IB I/Oモジュールの終了処理 */

ret = PciGpibExFinishBoard(GPIB_BOARDNO);

if(ret){

rtl_printf("Board close error[%d]:ret=%d¥n", GPIB_BOARDNO, ret);

} else {

rtl_printf("Board close success!! [%d]¥n", GPIB_BOARDNO);

}

/* データ送信のためのスレッドを削除 */

pthread_cancel(send_task_info);

pthread_join(send_task_info, NULL);

}

次に、

List3-4に示すプログラムを入力し、ファイル名を『Makefile』として保存してください。こ

れは、上記プログラムをコンパイルするメイクファイルです。

List3-4

Makefile

1

2 3 4 5 6

include /usr/include/rtlinux/rtl.mk all: srqevent.o

srqevent.o: srqevent.c

$(CC) $(INCLUDE) $(CFLAGS) -o srqevent.o -c srqevent.c

コンパイルすると、RTLinuxモジュールsrqevent.oができます。insmodコマンドで、RTLinux モジュールを組み込みます。

# make

# ls

Makefile srqevent.c srqevent.o

# insmod srqevent.o

srqevent.oを組み込むと、コンソールに以下のメッセージが出力され、 Agilent34401Aからのサービ

スリクエストの検知とコールバック処理が行われたことがわかります。

# insmod srqevent.o init_module called

Board open success!! [0]

send_task called arg=0 send_data called [*RST]

send_data success!! [ret=0]

send_data called [*CLS]

send_data success!! [ret=0]

send_data called [*SRE 16]

send_data success!! [ret=0]

send_data called [MEASure:VOLTage:DC?]

send_data success!! [ret=0]

srq_callback called [0x4000000, 0]

Serial poll success!!

no.0 status byte=50 addrss=22

PciGpibExRecvData [0, 15, +5.98390000E-05]

次に、組み込んだRTLinuxモジュールを取り外しは、rmmodコマンドで行います。

# rmmod srqevent