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

複数のGP-IB機器を制御する

第 4 章  より高度な処理を行おう 37

4.3  複数のGP-IB機器を制御する

List4-5は、LinuxプロセスとRTLinuxモジュール間で、共通で使う定義ファイルです。ファイル名

を『pm_control.h』として保存してください。

List4-5

pm_control.h

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 50 51 52

/* 複数の機器を制御するプログラム 共通定義ヘッダファイル(pm_control.h)

Copyright 2002 Interface Corporation. All rights reserved.

*/ #if !defined(___PM_CONTROL_H)

#define ___PM_CONTROL_H

#include "pcigpib.h"

/* Constants --- */

#define FIFO_COMMAND 1 /* Linuxプロセスから指令を受け取るRT-FIFO */

/* Agilent34401A用 */

#define FIFO_HP_THRU_CMD 2 /* ハンドラからRTLinuxスレッドへ指令を受け渡しするRT-FIFO */

#define FIFO_HP_RESULT 3 /* Linuxプロセスへ結果を送るRT-FIFO */

/* YOKOGAWA 7561用 */

#define FIFO_YK_THRU_CMD 4 /* ハンドラからRTLinuxスレッドへ指令を受け渡しするRT-FIFO */

#define FIFO_YK_RESULT 5 /* Linuxプロセスへ結果を送るRT-FIFO */

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

#defineHP34401A _ADR 22 /* Agilent34401Aのプライマリアドレス値 */

#define YK7561_ADR 14 /* YOKOGAWA 7561のプライマリアドレス値 */

#define RECV_BUFF_DEF_SIZE 80 /* 受信バッファのデフォルトサイズ */

#define BUFF_SIZE 1000 /* Linuxプロセスへ結果を送るRT-FIFOのサイズ */

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

#define ARRAY_SIZE(tag) (sizeof(tag) / sizeof(tag[0])) /* Command ID --- */

/* GP-IB機器のID */

enum TYPE_IDS {

HP34401A, /* Agilent34401Aを示すID値 */

YK7561 /* YOKOGAWA 7561を示すID値 */

};

/* コマンドID群(RTLinuxスレッドへの指示用) */

enum CMD_IDS {

ID_START, /* 周期的な送受信のスタート指示 */

ID_STOP /* 周期的な送受信のストップ指示 */

};

/* コマンド指示用の構造体 */

struct CMD_STRUCT {

enum TYPE_IDS type; /* GP-IB機器のID */

enum CMD_IDS id; /* コマンドID */

/* 各コマンドに対する設定パラメータ */

long smp_period_ms; /* ID_START時使用:監視周期の設定(ms単位) */

};

#endif

List4-6は、RTLinuxモジュールのソースファイルです。ファイル名を『pm_transtask.c』として保

存してください。

List4-6

pm_transtask.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 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69

/* 複数の機器を制御するプログラム 共通定義ヘッダファイル(pm_transtask.c)

Copyright 2002 Interface Corporation. All rights reserved.

*/ #include <rtl.h>

#include <rtl_sched.h>

#include <rtl_fifo.h>

#include <pthread.h>

#include <linux/vmalloc.h>

#include "pm_control.h"

unsigned long recv_buff_size = RECV_BUFF_DEF_SIZE; /* 受信バッファサイズ */

MODULE_PARM(recv_buff_size, "l"); /* モジュール組み込み時のオプション用 */

char* hp_recv_buff = NULL; /* 受信バッファ(Agilent34401A用) */

char* yk_recv_buff = NULL; /* 受信バッファ(YOKOGAWA 7561用) */

pthread_t hp34401a_task_info;

pthread_t yk7561_task_info;

pthread_mutex_t sync_obj; /* 同期用のミューテックスオブジェクト */

/* YOKOGAWA7561からのSRQ発行時に呼ばれるコールバック関数 */

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

int device_no = (int)ulUserData;

long recv_size;

char* recv_buff = yk_recv_buff;

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

int stb_tbl[ARRAY_SIZE(adrs_tbl)];

int stb_adrs[ARRAY_SIZE(adrs_tbl)];

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

if(ulEventFactor & GPIB_DETECT_SRQ){

pthread_mutex_lock(&sync_obj); /* ↓同期ロック */

do {

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

ret = PciGpibExExecSpoll( device_no,

adrs_tbl,

stb_tbl,

stb_adrs);

if(ret){

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

break;

} else {

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

}

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

/* 注意事項:

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

*/

for(i = 0; i < ARRAY_SIZE(stb_tbl); i++){

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

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

}

/* YOKOGAWA 7561からのAD変換終了サービスリクエストであることを確認 */

if((stb_adrs[0] == YK7561_ADR) && (stb_tbl[0] == 0x41)){

/* YOKOGAWA 7561から、データの受信 */

recv_size = recv_buff_size - DELIM_SIZE;

ret = PciGpibExRecvData( device_no,

stb_adrs,

&recv_size,

recv_buff,

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 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144

NULL);

recv_buff[recv_size] = '¥0';

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

pthread_mutex_unlock(&sync_obj); /* ↑同期アンロック */

/* 受信したデータを、RT-FIFO経由でLinuxプロセスに送る */

rtf_put(FIFO_YK_RESULT, recv_buff, recv_size);

return;

} } while(0);

pthread_mutex_unlock(&sync_obj); /* ↑同期アンロック */

} return;

}

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

int send_data(int* adrs_tbl, char* send_data) { int ret;

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

pthread_mutex_lock(&sync_obj); /* ↓同期ロック */

/* 指定されたGP-IB機器に対して、データの送信 */

ret = PciGpibExSendData( GPIB_BOARDNO,

adrs_tbl,

strlen(send_data),

send_data,

NULL);

pthread_mutex_unlock(&sync_obj); /* ↑同期アンロック */

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

return ret;

}

/* Agilent34401Aに対してデータ送受信周期実行を行うスレッド */

void* hp34401a_task(void* arg) { int ret;

struct CMD_STRUCT cmd;

long recv_size;

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

char* recv_buff = hp_recv_buff;

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

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

if(send_data(adrs_tbl, "*RST") != 0) return 0;

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

if(send_data(adrs_tbl, "*CLS") != 0) return 0;

/* RTLinuxスレッド組み込み中、動作する永久ループ */

while(1) {

/* 自スレッドを、次の周期までスリープさせる */

pthread_wait_np();

/* RT-FIFOからの指示があれば取り込み */

ret = rtf_get(FIFO_HP_THRU_CMD, &cmd, sizeof(cmd));

if(ret == sizeof(cmd)){

rtl_printf("hp34401a_task: get command id=%d¥n", cmd.id);

switch(cmd.id){

case ID_START: /* 周期的なデータ送受信のスタート */

rtl_printf("hp34401a_task: start transfer¥n");

/* RTLinuxスレッドの周期設定 */

pthread_make_periodic_np(pthread_self(), gethrtime(),

cmd.smp_period_ms * 1000 * 1000);

break;

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 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221

/* RTLinuxスレッド実行の一時停止 */

pthread_suspend_np(pthread_self());

break;

} }

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

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

/* から、電圧値データの受信 */

recv_size = recv_buff_size - DELIM_SIZE;

pthread_mutex_lock(&sync_obj); /* ↓同期ロック */

ret = PciGpibExRecvData( GPIB_BOARDNO,

adrs_tbl,

&recv_size,

recv_buff,

NULL);

pthread_mutex_unlock(&sync_obj); /* ↑同期アンロック */

if(ret) {

rtl_printf("hp34401a_task: RecvData error [%d]¥n", ret);

break;

}

recv_buff[recv_size] = '¥0';

rtl_printf("hp34401a_task: RecvData success [%d, %d, %s]¥n", ret, recv_size, recv_buff);

/* 受信したデータを、RT-FIFO経由でLinuxプロセスに送る */

rtf_put(FIFO_HP_RESULT, recv_buff, recv_size);

} return 0;

}

/* YOKOGAWA7561に対してサンプリングの開始、停止を指定するRTLinuxスレッド */

void* yk7561_task(void* arg) { int ret;

struct CMD_STRUCT cmd;

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

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

/* RTLinuxスレッド組み込み中、動作する永久ループ */

while(1) {

/* 自スレッドを、次の周期までスリープさせる */

pthread_wait_np();

/* RT-FIFOからの指示があれば取り込み */

ret = rtf_get(FIFO_YK_THRU_CMD, &cmd, sizeof(cmd));

if(ret == sizeof(cmd)){

rtl_printf("yk7561_task: get command id=%d¥n", cmd.id);

switch(cmd.id){

case ID_START: /* 周期的なデータ送受信のスタート */

rtl_printf("yk7561_task: start transfer¥n");

/* 初期設定コマンドの送信 */

send_data(adrs_tbl, "F1R0M0SI1000MS1");

/* 補足説明:

コマンドの意味は以下の通り。

F1R0 = 直流電圧(Auto)

M0 = オートサンプリング

SI1000 = サンプリングインターバルは1000ms

MS1 = SRQマスク(AD変換終了割り込み有効)

*/

break;

case ID_STOP: /* 周期的なデータ送受信のストップ */

rtl_printf("trans_task: stop transfer¥n");

/* 終了コマンドの送信 */

send_data(adrs_tbl, "MS0");

/* 補足説明:

コマンドの説明は以下の通り。

MS0 = SRQマスク(SRQ割り込み無効)

*/

222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296

break;

} } } return 0;

}

/* Linuxプロセスからの指令を受け取るハンドラ */

int my_handler(unsigned int fifo) { int ret;

struct CMD_STRUCT cmd;

rtl_printf("my_handler called fifo=%d¥n", fifo);

/* Linuxプロセスの指示に従って、RTLinuxスレッド等の制御を行う */

while((ret = rtf_get(FIFO_COMMAND, &cmd, sizeof(cmd))) == sizeof(cmd)){

rtl_printf("my_handler: get command type=%d id=%d¥n", cmd.type, cmd.id);

switch(cmd.type){

case :

rtf_put(FIFO_HP_THRU_CMD, &cmd, sizeof(cmd));

pthread_wakeup_np(hp34401a_task_info);

break;

case YK7561:

rtf_put(FIFO_YK_THRU_CMD, &cmd, sizeof(cmd));

pthread_wakeup_np(yk7561_task_info);

break;

default:

rtl_printf("my_handler: unknown type(%d)¥n", cmd.type);

return -EINVAL;

} } if(ret != 0){

rtl_printf("my_handler: error!!(%d)¥n", ret);

return -EINVAL;

} return 0;

}

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

int init_module(void) { long ret;

rtl_printf("init_module called¥n");

EXPORT_NO_SYMBOLS;

/* Linuxプロセスからの指示を受け取るハンドラとRT-FIFOを生成する */

rtf_destroy(FIFO_COMMAND);

rtf_create(FIFO_COMMAND, sizeof(struct CMD_STRUCT));

rtf_create_handler(FIFO_COMMAND, my_handler);

/* ハンドラとRTLinuxスレッドの間のRT-FIFOを生成する(Agilent34401A用) */

rtf_destroy(FIFO_HP_THRU_CMD);

rtf_create(FIFO_HP_THRU_CMD, sizeof(struct CMD_STRUCT));

/* Linuxプロセスへ結果を返すRT-FIFOを生成する(Agilent34401A用) */

rtf_destroy(FIFO_HP_RESULT);

rtf_create(FIFO_HP_RESULT, sizeof(char) * BUFF_SIZE);

/* ハンドラとRTLinuxスレッドの間のRT-FIFOを生成する(YOKOGAWA 7561用) */

rtf_destroy(FIFO_YK_THRU_CMD);

rtf_create(FIFO_YK_THRU_CMD, sizeof(struct CMD_STRUCT));

/* Linuxプロセスへ結果を返すRT-FIFOを生成する(YOKOGAWA 7561用) */

rtf_destroy(FIFO_YK_RESULT);

rtf_create(FIFO_YK_RESULT, sizeof(char) * BUFF_SIZE);

/* Agilent34401A用 受信バッファの確保 */

rtl_printf("recv_buff_size = %ld¥n", recv_buff_size);

hp_recv_buff = vmalloc(recv_buff_size);

if(hp_recv_buff == NULL) {

rtl_printf("Receive Buffer allocate error¥n");

return -ENOMEM;

299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373

/* YOKOGAWA 7561用 受信バッファの確保 */

yk_recv_buff = vmalloc(recv_buff_size);

if(yk_recv_buff == NULL) {

rtl_printf("Receive Buffer allocate error¥n");

return -ENOMEM;

}

/* 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;

} else {

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

}

/* 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;

}

/* ミューテックスの初期化 */

pthread_mutex_init(&sync_obj, NULL);

/* データ送受信周期実行スレッド生成(Agilent34401A用) */

ret = pthread_create(&hp34401a_task_info, NULL, (void*)hp34401a_task, 0);

if(ret) return ret;

/* データ送受信周期実行スレッド生成(YOKOGAWA 7561用) */

return pthread_create(&yk7561_task_info, NULL, (void*)yk7561_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);

}

/* Agilent34401A用 受信バッファの解除 */

if(hp_recv_buff != NULL){

vfree(hp_recv_buff);

hp_recv_buff = NULL;

}

/* YOKOGAWA 7561用 受信バッファの解除 */

if(yk_recv_buff != NULL){

vfree(yk_recv_buff);

374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392

yk_recv_buff = NULL;

}

/* ミューテックスの破棄 */

pthread_mutex_destroy(&sync_obj);

/* RT-FIFOを閉じる */

rtf_destroy(FIFO_COMMAND);

rtf_destroy(FIFO_HP_THRU_CMD);

rtf_destroy(FIFO_HP_RESULT);

rtf_destroy(FIFO_YK_THRU_CMD);

rtf_destroy(FIFO_YK_RESULT);

/* RTLinuxスレッドを終了させる */

pthread_cancel(hp34401a_task_info);

pthread_join(hp34401a_task_info, NULL);

pthread_cancel(yk7561_task_info);

pthread_join(yk7561_task_info, NULL);

}

List4-7はLinuxプロセスのソースファイルです。ファイル名を『pm_datadisp.app.c』として保存し

てください。

List4-7

pm_datadisp_app.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

/* 周期的にデータの送受信を行うプログラム Linuxプロセスのソースコード(pt_datadisp_app.c) Copyright 2002 Interface Corporation. All rights reserved.

*/ #include <stdio.h>

#include <string.h>

#include <fcntl.h>

#include <unistd.h>

#include <sys/time.h>

#include <sys/ioctl.h>

#include <rtl_fifo.h>

#include "pt_control.h"

/* Linuxプロセスのメインルーチン */

int main(void)

{ int fd_cmd, fd_result;

fd_set rfds;

struct timeval tv;

struct CMD_STRUCT cmd;

char rt_fifo_name[80];

int i;

char recv_buff[RECV_BUFF_DEF_SIZE]; /* 受信データを格納するバッファ */

int recv_size;

/* RTLinuxモジュールに指令を送るRT-FIFOのオープン */

sprintf(rt_fifo_name, "/dev/rtf%d", FIFO_COMMAND);

if((fd_cmd = open(rt_fifo_name, O_WRONLY)) < 0){

fprintf(stderr, "Fail to open %s¥n", rt_fifo_name);

return -1;

}

/* RTLinuxモジュールからの結果を受け取るRT-FIFOのオープン */

sprintf(rt_fifo_name, "/dev/rtf%d", FIFO_RESULT);

if((fd_result = open(rt_fifo_name, O_RDONLY)) < 0){

fprintf(stderr, "Fail to open %s¥n", rt_fifo_name);

return -2;

}

/* 周期的な送受信の開始指示 */

cmd.id = ID_START;

cmd.smp_period_ms = 500; /* 500ms周期の送受信設定 */

if(write(fd_cmd, &cmd, sizeof(cmd)) < 0){

fprintf(stderr, "failed to send the start command¥n");

return -3;

}

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

FD_ZERO(&rfds);

FD_SET(fd_result, &rfds);

tv.tv_sec = 30; /* select関数のタイムアウト値の設定:30秒 */

tv.tv_usec = 0;

/* 受信データの受け取り */

if(select(FD_SETSIZE, &rfds, NULL, NULL, &tv) > 0){

if(FD_ISSET(fd_result, &rfds)){ /* fd_resultに対してFIFOの書き込みがあった */

recv_size = read(fd_result, recv_buff, RECV_BUFF_DEF_SIZE - DELIM_SIZE);

if(recv_size >= 0){

recv_buff[recv_size] = '¥0';

printf("%d. recv data = %s¥n", i, recv_buff);

} } }

} fprintf(stderr, "datadisp_app: now sending commands to stop RT-tasks¥n");

/* 周期的なデータ送受信の停止指示 */

cmd.id = ID_STOP;

if(write(fd_cmd, &cmd, sizeof(cmd)) < 0){

fprintf(stderr, "failed to send the stop command¥n");

return -4;

}

printf("fd_cmd:%d¥n", close(fd_cmd));

printf("fd_result:%d¥n", close(fd_result));

printf("The Linux proccess is successfully completed.¥n");

return 0;

}

List4-8は、上記ファイルをコンパイルするメイクファイルです。ファイル名を『Makefile』として

保存してください。

List4-8

Makefile

1

2 3 4 5 6 7 8

include /usr/include/rtlinux/rtl.mk all: pt_transtask.o pt_datadisp_app pt_datadisp_app: pt_datadisp_app.c

$(CC) $(INCLUDE) $(USER_CFLAGS) -O3 -Wall -o pt_datadisp_app pt_datadisp_app.c pt_transtask.o: pt_transtask.c

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

コンパイルし、insmodコマンドでRTLinuxモジュールを組み込みます。

# make ← コンパイルします

# ls ← コンパイルしたファイルを一覧表示します

Makefile pm_datadisp_app pm_transtask.c pm_control.h pm_datadisp_app.c pm_transtask.o

# insmod pm_transtask.o ← RTLinuxモジュールを組み込んでいます

次に、Linuxプロセスを実行します。

# ./pm_datadisp_app ← Linuxプロセスを実行します

実行画面を以下に示します。

(画面左上のウィンドウがLinuxプロセスを実行しているコンソール。画面右下のウィンドウは

RTLinuxモジュールのログメッセージを表示させているコンソールです)

サンプルの実行画面例

pm_datadisp_appを実行させると、 Agilent34401Aからの取得電圧値は「Agilent34401A: recv data =

電 圧値」と繰り返し表示され、

YOKOGAWA 7561からの取得電圧値は「YOKOGAWA 7561: recv data

=

電圧値」と繰り返し表示されます。

50回表示した後、「datadisp_app: now sending commands to stop

RT-tasks」と表示され、電圧値取得を終了します。