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

AdStartSamplingを使った永続的なサンプリング

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

4.4  AdStartSamplingを使った永続的なサンプリング

先程では、AdInputADEx関数を使って周期的なサンプリングを実現しました。

実は同じサンプリングだけを行うなら、AdStartSampling関数を使う方が簡単に処理を実現できま す。

ここでは、AdStartSampling関数を使い、永続的なサンプリングを実現します。

以下の4つのファイルを作成します。

ファイル名  備考 

sample3.h LinuxプロセスとRTLinuxモジュールの双方で共有する定義ファイル

module3.c RTLinuxモジュールのソースコード

sample3.c Linuxプロセスのソースコード

makefile

上記ソースコードをコンパイルするためのmakefile

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

「sample3.h」として保存してください。

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

/*

sample3.h 共通定義ヘッダファイル

Copyright 2002 Interface Corporation. All rights reserved.

*/

#if !defined(___SAMPLE3_H)

#define ___SAMPLE3_H

#include "fbiad.h"

/* Constants --- */

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

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

#define FIFO_RESULT 3 /* Linuxプロセスへ結果(サンプリングデータ)を送るRT-FIFO */

#define FIFO_STATUS 4 /* Linuxプロセスへ現在の状態を送るRT-FIFO */

#define DEVICE_ID 3133 /* 製品を特定する一意のID値(PCI-3133を表す) */

#define SUB_SYSTEM_ID 0x0001 /* 製品を特定する一意のID値(PCI-3133を表す) */

#define RSW_NO 0 /* 同一型式の製品を区別するRSW1設定値 */

#define CH_NUM 2 /* 1件のAD入力の総チャンネル数 */

#define SMP_NUM 100 /* 1回のサンプリングで取得するAD入力の件数 */

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

typedef unsigned short AD_TYPE; /* ADデータの型 */

/* Command ID --- */

/* コマンドID群(周期サンプリング用スレッドへの指示用) */

enum CMD_IDS {

ID_START, /* サンプリングのスタート指示 */

ID_STOP /* サンプリングのストップ指示 */

};

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

struct CMD_STRUCT {

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

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

long smp_period_ms; /* ID_START時使用:サンプリング周期の設定(ms単位) */

};

/* サンプリング状態通知用の構造体 */

struct STAT_STRUCT { unsigned long stat;

unsigned long smp_count;

unsigned long avail_count;

};

#endif

下記は、RTLinuxモジュールのソースファイルです。ファイル名を「module3.c」として保存して ください。

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

/*

module3.c RTLinuxモジュールのソースコード

Copyright 2002 Interface Corporation. All rights reserved.

*/

#include <rtl.h>

#include <rtl_sched.h>

#include <rtl_fifo.h>

#include "sample3.h"

pthread_t my_task_info;

int g_device_no = -1; /* AD製品のデバイス番号 */

AD_TYPE inner_ad_buff[CH_NUM * SMP_NUM]; /* ドライバ内部が使用するバッファ */

AD_TYPE ad_data[CH_NUM * SMP_NUM]; /* サンプリングデータを取り込むバッファ

(my_smp_callbackで使用) */

/* サンプリング中のイベント発生時に呼ばれるコールバック関数 */

void my_smp_callback(int user_arg) {

int ret;

unsigned long event_factor;

unsigned long smp_stat, smp_cnt, smp_avail;

unsigned long smp_num;

rtl_printf("my_smp_callback called user_arg=%d¥n", user_arg);

do {

/* このコールバック関数が呼び出された発生要因を知る */

ret = AdGetBoardConfig(g_device_no, &event_factor);

if(ret){

rtl_printf("AdGetBoardConfig error [ret=%x]¥n", ret);

break;

}

/* イベントの発生要因は、指定件数の入力か? */

if(event_factor != AD_EVENT_SMPLNUM) break;

/* 現在のサンプリング状態を知る */

ret = AdGetStatus(g_device_no, &smp_stat, &smp_cnt, &smp_avail);

if(ret){

rtl_printf("AdGetStatus error [ret=%x]¥n", ret);

break;

}

/* サンプリングデータを取得する */

smp_num = SMP_NUM;

ret = AdGetSamplingData(g_device_no, ad_data, &smp_num);

if(ret){

rtl_printf("AdGetSamplingData error [ret=%x]¥n", ret);

break;

}

/* 取得したサンプリングデータを、LinuxプロセスのRT-FIFOに書き込む */

rtf_put(FIFO_RESULT, ad_data, sizeof(AD_TYPE) * CH_NUM * smp_num);

rtl_printf("my_smp_callback: success!! sampling data to user task [smp_num=%d]¥n",

smp_num);

return;

} while(0);

rtl_printf("my_smp_callback: ...¥n");

}

/* サンプリングを行うRTLinuxスレッド */

void* my_task(void* arg) {

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 145

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

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

while(1){

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

pthread_wait_np();

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

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

if(ret == sizeof(cmd)){

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

switch(cmd.id){

case ID_START: /* サンプリングのスタート */

rtl_printf("my_task: start!!¥n");

pthread_make_periodic_np(pthread_self(), gethrtime(),

cmd.smp_period_ms * 1000 * 1000);

/* サンプリングスタート */

ret = AdStartSampling(g_device_no, FLAG_ASYNC);

if(ret){

rtl_printf("AdStartSampling error [ret=%x]¥n", ret);

}

break;

case ID_STOP: /* サンプリングのストップ */

rtl_printf("my_task: stop!!¥n");

pthread_suspend_np(pthread_self());

/* サンプリングストップ */

ret = AdStopSampling(g_device_no);

if(ret){

rtl_printf("AdStopSampling error [ret=%x]¥n", ret);

}

break;

default:

rtl_printf("my_task: unknown command!!¥n");

break;

}

}

/* 現在のサンプリング状態を知る */

ret = AdGetStatus(g_device_no, &(stat.stat), &(stat.smp_count), &(stat.avail_count));

if(ret){

rtl_printf("AdGetStatus error [ret=%x]¥n", ret);

break;

} else {

/* 取り込んだ状態を、LinuxプロセスへRT-FIFOを介して返す */

rtf_put(FIFO_STATUS, &stat, sizeof(stat));

}

} 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プロセスの指示を、RT-FIFOを介して、RTLinuxスレッドに横流しする */

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

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

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

pthread_wakeup_np(my_task_info);

}

if(ret != 0){

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

return -EINVAL;

} return 0;

}

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

int init_module(void) {

int i, ret;

ADSMPLREQ smp_req; /* サンプリング条件を設定する構造体の宣言 */

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);

/* ハンドラとLinuxプロセスの間のRT-FIFOを生成する */

rtf_destroy(FIFO_THRU_CMD);

rtf_create(FIFO_THRU_CMD, sizeof(struct CMD_STRUCT));

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

rtf_destroy(FIFO_RESULT);

rtf_create(FIFO_RESULT, sizeof(AD_TYPE) * CH_NUM * BUFF_SIZE);

/* Linuxプロセスへ状態を返すRT-FIFOを生成する */

rtf_destroy(FIFO_STATUS);

rtf_create(FIFO_STATUS, sizeof(struct STAT_STRUCT));

/* AD製品のオープン */

ret = AdOpenEx(DEVICE_ID, SUB_SYSTEM_ID, RSW_NO, &g_device_no);

if(ret){

rtl_printf("AdOpenEx error [ret=%x]¥n", ret);

return -1;

} else {

rtl_printf("AdOpenEx success!! [device no=%d]¥n", g_device_no);

}

/* イベント検出時のコールバック関数の登録 */

ret = AdSetBoardConfig(g_device_no, -1, my_smp_callback, -1);

if(ret){

rtl_printf("AdSetBoardConfig error [ret=%d]¥n", ret);

return –2;

}

/* デフォルトのサンプリング条件設定を読み取る */

ret = AdGetSamplingConfig(g_device_no, &smp_req);

if(ret){

rtl_printf("AdGetSamplingConfig error [ret=%d]¥n", ret);

return –3;

}

/* サンプリング条件設定を変更 */

smp_req.ulChCount = CH_NUM; /* 1件のAD入力時の総チャンネル数の指定 */

smp_req.ulSingleDiff = AD_INPUT_SINGLE; /* 入力方式をシングルエンドに設定 */

smp_req.ulSmplNum = SMP_NUM; /* 1回のサンプリングで取得するAD入力の件数設定 */

smp_req.ulSmplEventNum = SMP_NUM / 2; /* イベントを上げるAD入力の件数設定 */

smp_req.fSmplFreq = 100.0; /* サンプリング周波数の設定 */

smp_req.ulTrigMode = AD_ETERNITY; /* トリガをフリーラン(中止命令が入るまで

永続的にサンプリング)に設定 */

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

smp_req.SmplChReq[i].ulChNo = 1 + i; /* チャンネルを指定(1,2を順に 指定しています) */

smp_req.SmplChReq[i].ulRange = AD_0_5V; /* レンジ:0〜+5Vを指定 */

}

/* 書き換えたサンプリング条件設定を設定する */

ret = AdSetSamplingConfig(g_device_no, &smp_req);

if(ret){

rtl_printf("AdSetSamplingConfig error [ret=%d]¥n", ret);

return –4;

}

/* ドライバモジュールが使用する内部バッファ領域を指定する */

ret = AdSetSamplingBuffer(g_device_no, inner_ad_buff);

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

/* スレッドを作成、起動する */

return pthread_create(&my_task_info, NULL, (void*)my_task, 0);

}

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

void cleanup_module(void) {

int ret;

rtl_printf("cleanup_module called¥n");

/* AD製品をクローズする */

ret = AdClose(g_device_no);

if(ret){

rtl_printf("AdClose error [ret=%d]¥n", ret);

}

/* RT-FIFOを閉じる */

rtf_destroy(FIFO_COMMAND);

rtf_destroy(FIFO_THRU_CMD);

rtf_destroy(FIFO_RESULT);

rtf_destroy(FIFO_STATUS);

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

pthread_cancel(my_task_info);

pthread_join(my_task_info, NULL);

}

下記は、

Linuxプロセスのソースファイルです。ファイル名を「sample3.c」として保存してくださ

い。

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

/*

sample3.c Linuxプロセスのソースコード

Copyright 2002 Interface Corporation. All rights reserved.

*/

#include <stdio.h>

#include <fcntl.h>

#include <unistd.h>

#include <math.h>

#include <sys/time.h>

#include <sys/ioctl.h>

#include <rtl_fifo.h>

#include "sample3.h"

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

int main(void) {

int i, j, ret;

int fd_result, fd_status, fd_cmd;

fd_set rfds;

struct timeval tv;

struct CMD_STRUCT cmd;

AD_TYPE ad_data[CH_NUM * SMP_NUM]; /* サンプリングデータを格納する領域 */

struct STAT_STRUCT stat;

clock_t start_time;

char rt_fifo_name[80];

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

}

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

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

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

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

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

return –3;

}

/* サンプリングの実行開始の指示 */

cmd.id = ID_START;

cmd.smp_period_ms = 100; /* 100ms周期のサンプリング設定 */

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

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

return –4;

}

/* 5秒間サンプリングを行う */

start_time = time(NULL);

while(fabs(difftime(time(NULL), start_time)) < 5.0){

FD_ZERO(&rfds);

FD_SET(fd_result, &rfds);

FD_SET(fd_status, &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に対してRT-FIFOの書き込みがあった */

ret = read(fd_result, ad_data, sizeof(AD_TYPE) * CH_NUM * SMP_NUM);

for(i = 0; i < (ret / CH_NUM / sizeof(AD_TYPE)); i++){

for(j = 0; j < CH_NUM; j++){

printf("no=%d ch=%d data=%x¥n", i, j,

ad_data[(CH_NUM * i) + j]);

}

}

}

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

read(fd_status, &stat, sizeof(stat));

printf("now status: stat=%ld smp count=%ld avail count=%ld¥n", stat.stat, stat.smp_count, stat.avail_count);

}

}

}

/* サンプリングの停止指示 */

cmd.id = ID_STOP;

cmd.smp_period_ms = 0;

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

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

return -5;

}

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

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

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

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

return 0;

}

下記は、上記ファイルをコンパイルするメイクファイルです。ファイル名を「makefile」として保 存してください。

makefile

1

2 3 4 5 6

include /usr/include/rtlinux/rtl.mk all: module3.o sample3

sample3: sample3.c

$(CC) $(INCLUDE) $(USER_CFLAGS) -O3 -Wall -o sample3 sample3.c

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

# make コンパイルします

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

makefile sample3 module3.c module3.o sample3.c sample3.h

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

次に、Linuxプログラムを実行します。

# ./sample3 ← Linuxプログラムを実行しています

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

(画面左上のウィンドウがLinuxプログラムを実行しているコンソール。画面右下のウィンドウは RTLinuxモジュールのログメッセージを表示させているコンソールです)

sample3実行時の画面

sample3を実行させると、「no=xx ch=xx data=xxxx」と表示が繰り返し出力され、しばらくしてプ

ログラムが終了します。

関連したドキュメント