平成16年度計算機演習 デバイスプログラミング

1
平成 16 年度 計算機演習
デバイスプログラミング
担当:稲邑 哲也 ([email protected])
TA:安達 隆介,大久保 康基,中西 雄飛,林 摩梨花
(情報システム工学研究室 M1)
演習ページ:http://www.jsk.t.u-tokyo.ac.jp/˜inamura/lecture/keisanki-ensyu/
2004 年 7 月 6 日/8 日
1
演習の目的
本演習では,音声デバイスのコントロールとシリアル通信を通して,ソフトウェアシステムから
ハードウェアを制御するための概念であるデバイスの原理を理解する事を目的とする.まず音声デ
バイスをコントロールし,音声データの再生,録音を行う.次に 2 人 1 組となり,シリアル通信を
用いたデータの送受信を行う.最後にこれらを総合し,与えられた文字列に対応した音声を再生す
る擬似ジュークボックスを作成する.
2
デバイスファイル
コンピュータには様々なハードウェアが接続されており,そのアクセス方法はハードウェアに
よって異なる.UNIX システムではそれらを統一的に扱うために,デバイスファイルという概念を
用いる.
まずはじめに以下のコマンドを実行してみよう.
✓
% ls -l /dev
✒
✏
✑
すると,以下のように/dev ディレクトリの下にあるデバイスファイルの一覧が表示される.
3. 音声デバイス
2
✓
✏
合計 192
-rwxr-xr-x
crw-------
1 root
1 root
root
root
20553
10, 10
4 月 11
4 月 11
2002 MAKEDEV
2002 adbmouse
crw-r--r-crw------crw-------
1 root
1 root
1 root
root
root
root
10, 175
10,
4
10,
7
4 月 11
4 月 11
4 月 11
2002 agpgart
2002 amigamouse
2002 amigamouse1
crw------drwxr-xr-x
1 inamura
2 root
root
root
10, 134
4096
4 月 11 2002 apm_bios
3 月 10 23:26 ataraid
crw------crw------crw-------
1 root
1 root
1 root
root
root
root
10,
10,
10,
5
3
3
4 月 11
4 月 11
4 月 11
2002 atarimouse
2002 atibm
2002 atimouse
crw------crw-------
1 inamura
1 inamura
root
root
14,
14,
4
20
4 月 11
4 月 11
2002 audio
2002 audio1
crw------brw-rw---crw-------
1 inamura
1 root
1 inamura
root
disk
root
14,
7
29,
0
10, 128
4 月 11
4 月 11
4 月 11
2002 audioctl
2002 aztcd
2002 beep
brw-rw---crw-------
1 root
1 root
disk
root
41,
68,
4 月 11
4 月 11
2002 bpcd
2002 capi20
✒
0
0
:
:
✑
ここで,行頭の文字が b もしくは c となっているのが,デバイスファイルである.デバイスファイ
ルは形式的には/dev ディレクトリの下にある通常のファイルのように表されるが,これらのファ
イルは,そのデバイスに割り当てられたデバイス番号などのほんのわずかな情報しか持っていな
い,実体のないファイルである.しかし,これらのファイルに対して,read() や write() などの
システムコールを通じて入出力の要求がなされると,カーネル内に組み込まれたそれぞれのデバイ
ス専用のデバイスドライバが起動され,必要な処理が行われるようになっている.この仕組みに
よって,ユーザはそれぞれのハードウェアの構造を意識することなく,あたかも一般のファイルを
扱うのと同じようにデバイスをコントロールすることができるのである.
音声デバイス
3
ここでは,Linux でサウンドカードを制御するドライバとして最も一般的な OSS/Free(Open
Sound System Free) を用いて音声デバイスを制御するプログラムを作成し,デバイスへの入出力
方法を学ぶと共に,音声情報処理プログラミングの基礎を学ぶ.
3.1
ヘッドセットの接続
各個人に一つづつ,マイクとスピーカーがセットになったヘッドセットを配布する.これを演習
用のデスクトップ PC に接続する.ヘッドセットの赤のケーブルがマイク,白のケーブルがスピー
カーとなっている.本体の裏のオーディオ端子のうち,ピンク色のマイク入力端子に赤(マイク)
3.2. 簡単な音声デバイスの使い方
3
ケーブルを,緑のスピーカー入力端子に白(スピーカー)ケーブルを,間違えないように接続する.
なお,この時,既に緑色のスピーカー入力端子にはケーブルが刺さっているが,これは液晶ディス
プレイ内臓のスピーカーに接続されている.演習が終わったら元に戻しておくように.
簡単な音声デバイスの使い方
3.2
OSS で用いる音声デバイスは/dev/dsp である.このデバイスファイルに何か書き込んでやれば,
とりあえず音は出るはずである.試しに以下のコマンドを実行してみよう.
✓
% cat hogehoge > /dev/dsp
✒
✏
✑
hogehoge のところには,テキストファイルでも何でも,なにか好きなファイル名を入れてやれば
よい.スピーカーからノイズが聞こえてくるはずである.音量が小さすぎて聞こえない場合は,
✓
✏
% gmix &
✒
✑
と入力してオーディオミキサー gmix(図 1) を起動し,音量を調節せよ.また,ファイルがあまり
に小さいと音の再生が一瞬で終わってしまうため,ある程度大きいファイルを選んだ方がわかりや
すい.
図 1: オーディオミキサー gmix の実行画面
上の例で見たように,/dev/dsp を開いてデータを書き込むことで音を出すことはできる.しか
し,ここで仮にちゃんとした音声データを cat で書き込んでやったとしても,音声が正常に再生さ
れることはまず無い.それは,その音声データに準じたデータ形式やサンプリングレート等が設定
されていないからである.その設定の実行もデバイスファイルを経由して行う.
3.3
サンプルプログラムのコンパイル
まずは,簡単な例題プログラムを使って,音声情報処理プログラミングにおける音声の再生処理
について見てみよう.最初にサンプルの sample1.c のコンパイルを行って,実行ファイルを作成
する.稲邑担当の計算機演習の Web ページ (http://www.jsk.t.u-tokyo.ac.jp/ inamura/lecture/)
からリンクをたどり,device.tar.gz をダウンロードし,以下のコマンドを実行する.
3. 音声デバイス
4
✓
✏
✒
✑
% tar xvzf device.tar.gz
% cd ensyu_inamura/sound
% make
作成されたファイルを実行し,音声が再生されれば成功である.
3.4
再生処理の流れ
再生処理の大まかな流れは図 2 のようになる.
図 2: 再生処理の流れ
まずシステムコール open() で音声デバイスファイルを開き,次に ioctl() でサンプリングレー
トなどのパラメータの設定を行う.write() で音声デバイスに音声データを書き込むと,音声が再
生される.最後に close() でデバイスファイルを閉じて処理を終了する.
以下で各システムコールの詳細を述べる.
デバイスのオープン open()
#include <fcntl.h>
int open(char *path, int oflag);
path
oflag
: パス名
: ファイルステータスフラグ
open() システムコールは,第 1 引数のパス名 path で指定されたデバイスを,第 2 引数のファイ
ルステータスフラグ oflag の値に従ってオープンする.ファイルステータスフラグ oflag には表
1 に示すフラグを論理和で複数個組み合わせることができる.
デバイスのオープンに成功すると,返り値としてファイルディスクリプタが得られる.ファイル
ディスクリプタとはそのデバイスに割り当てられた固有の番号のことで,以後デバイスへの入出力
はこのファイルディスクリプタを通して行われる.何らかの理由でデバイスのオープンに失敗した
場合は,返り値として −1 が返される.
3.4. 再生処理の流れ
5
表 1: ファイルステータスフラグ
フラグ
ファイルの処理形態
O RDONLY
読み出しのみ行う
O WRONLY
O RDWR
O NDELAY
書き込みのみ行う
O APPEND
O SYNC
O CREAT
O TRUNC
O EXCL
追加書き込みを行う.ファイルポインタをファイルの最後に設定する
読み取り/書き込みの両方を行う
オープンのブロックをするかしないかを設定する
ファイルデータとファイルステータスが更新されるまで書き込まない
ファイルが存在しない場合に作成する
ファイルが存在する場合にその大きさを 0 にする
O CREAT がセットされている場合, そのファイルが存在していればエラーを返す
デバイスの設定 ioctl()
#include <sys/ioctl.h>
int ioctl(ind fd, int request, char *arg);
fd
: ファイルディスクリプタ
request
arg
: 処理要求
: 属性情報
ioctl() システムコールは,第 1 引数にデバイスのファイルディスクリプタ fd を指定し,このデ
バイスに対して第 2 引数の処理要求 request にしたがって,第 3 引数 arg で参照する属性情報を
デバイスに設定する.デバイスの設定に失敗すると −1 を返す.第 2 引数 request に与えられる
処理要求はデバイスによって異なり,PCM (Pulse Code Modulation) 音源については表 2 のよう
な要求がよく用いられる.
表 2: PCM に与えられる処理要求
処理要求
要求する処理内容
SOUND PCM WRITE BITS
SOUND PCM WRITE CHANNELS
SOUND PCM WRITE RATE
サンプルサイズ (8 bit,16 bit) を指定する.
チャンネル数 (ステレオ: 2,モノラル: 1) を指定する.
サンプリングレートを指定する.
第 3 引数 arg の属性情報の構造はデバイスの種類と処理要求によって変化する.例えば,ここ
で用いる音声デバイスの属性情報は int 型へのポインタであるが,次章で扱うシリアル通信の属
性情報は通信時の種々の情報を格納した構造体のポインタとして与えなければならない.
3. 音声デバイス
6
デバイスへのデータの書き込み write()
#include <fcntl.h>
int write(int fd, char *buf, unsigned nbyte);
fd
buf
nbyte
: ファイルディスクリプタ
: 出力バッファ
: 書き込みバイト数
write() システムコールは,第 1 引数に open() システムコールの返り値で得られたファイルディ
スクリプタ fd を指定し,この指定されたデバイスに第 2 引数で指定する出力バッファから,第 3
引数で指定するバイト数分だけデータを書き込む.書き込みに成功すると実際に書き込まれたバイ
ト数を返し,失敗した場合には −1 を返す.
デバイスのクローズ close()
#include <fcntl.h>
int close(int fd);
fd
: ファイルディスクリプタ
close() システムコールは,open() システムコールの返り値で得られたファイルディスクリプタ
fd を指定して呼び出すことで,この指定されたデバイスをクローズする.何らかの理由でクロー
ズに失敗した場合には −1 を返す.
✓
◇ 課題 1 ◇
✏
1. sample1.c をコンパイルして実行せよ.
2. sample1.c を書き換えて,他の音声ファイルを再生せよ.
✒
3.5
✑
録音処理の流れ
録音処理の大まかな流れは図 3 のようになる.
まずシステムコール open() で音声デバイスファイルを開き,次に ioctl() でサンプリングレー
トなどのパラメータの設定を行う.read() で音声デバイスから音声データを読み出す.最後に
close() でデバイスファイルを閉じて処理を終了する.
3.5. 録音処理の流れ
7
図 3: 録音処理の流れ
デバイスからのデータの読み出し read()
#include <fcntl.h>
int read(int fd, char *buf, unsigned nbyte);
fd
buf
: ファイルディスクリプタ
: 入力バッファ
nbyte
: 読み出しバイト数
read() システムコールは,第 1 引数に open() システムコールの返り値で得られたファイルディ
スクリプタ fd を指定し,この指定されたデバイスから第 2 引数で指定する入力バッファへ,第 3
引数で指定するバイト数分だけデータを読み出す.読み出しに成功すると実際に読み出されたバイ
ト数を返し,失敗した場合には −1 を返す.
✓
◇ 課題 2 ◇
✏
1. sample1.c を参考に,マイクから入力した音声をファイルに保存するプログラム
record.c を作成せよ.保存したファイルが sample1 で正常に再生されることを確認
せよ.
(ヒント:ファイルへの保存は fwrite()) で行う
(注 1) 録音された音量が小さい場合は,gmix を起動してマイクの音量を上げよ.
2. sample1.c のサンプリングレートを変更し,早送り,スロー再生ができることを確
認せよ.
(注 2) 録音されたファイルを読み込む時,ファイルサイズの指定の仕方に注意せよ.録音さ
れているデータサイズとは違うサイズのデータを再生することになるため.
✒
✑
4. シリアル通信
8
シリアル通信
4
シリアルポートとは入出力デバイスの 1 つである.ほとんどの PC にはシリアルポートが 1 つも
しくは 2 つ装備されている.各ポートは 9 ピン (25 ピンのこともある) のコネクタを持っており,
送信ピンからデータの送信が,受信ピンからデータの受信が行える.他のピンはフロー制御と接地
のために用いられる.このシリアルポートを介した通信をシリアル通信と呼ぶ.ここではシリアル
通信を行うプログラムを作成し,コンピュータ間通信プログラミングの基礎を学ぶ.
シリアルポートのデバイスファイルは/dev/ttyS0 である.このファイルにデータを書いたり読
んだりすることで,シリアルポートとのデータの送受信が行える.あとは,音声デバイスと同様
に,各種の設定をしてやればよい.このように,音声デバイスとシリアルポートという一見全く違
うもののように見えるデバイスも,デバイスファイルを用いることで,その違いを意識することな
く扱うことができるのである.
サンプルプログラムのコンパイル
4.1
まずは,簡単な例題プログラムを使って,シリアル通信プログラミングにおけるデータの送受信
処理について見てみよう.最初にサンプルの sample2.c,sample3.c のコンパイルを行って,実行
ファイルを作成する.以下のコマンドを実行すると,sample2,sample3 の実行ファイルが生成さ
れる.
✓
% cd ../serial
% make
✒
✏
✑
ここからは 2 人 1 組のペアワークとなる.隣の人同士でペアを作ること.1 人だけ余ってしまっ
た場合には席を移動してペアを見つけること.どうしても一人余る場合には 3 人のグループを作る
こと.
サンプルプログラムの実行
サンプルプログラムは,sample2 が Server プログラム,sample3 が Client プログラムとなって
いる.配布されたクロスケーブルで 2 台のコンピュータを接続し,まず一方が Server を実行し,つ
いで他方が Client を実行する.Client から文字列が送信され,Server が受信すると,その文字列
を表示する.
4.2
送受信処理の流れ
シリアル通信の送受信処理の大まかな流れは図 4 のようになる.
送信側,受信側ともに,まずシステムコール open() でシリアルポートを開き,次に ioctl() で
通信速度などのパラメータの設定を行う.送信側が write() でシリアルポートにデータを書き込
むとデータが送信され,受信側が read() でシリアルポートからデータを読み出すとデータが受信
される.最後に双方とも close() でシリアルポートを閉じて送受信処理を終了する.
4.2. 送受信処理の流れ
9
図 4: 送受信処理の流れ
シリアルポートの設定
シリアルポートの設定も,音声デバイス同様システムコール ioctl() を用いて行う.シリアル
ポートの設定に用いられる ioctl の第 2 引数 (処理要求) を表 3 に示す.
処理要求
表 3: シリアルポートに与えられる処理要求
要求する処理内容
TCGETA
現在の設定を取り出して第 3 引数に格納する.
TCSETA
TCSETAW
第 3 引数に格納されている設定をセットする.
新しい設定をセットする前に,出力が無くなるのを待つ.
TCSETAF
TCSETAW に加えて,入力待ち行列をフラッシュする.
また,第 3 引数 (属性情報) の構造体を以下に示す.
4. シリアル通信
10
#define NCC 8
struct termio{
unsigned short int c_iflag;
unsigned short int c_oflag;
unsigned short int c_cflag;
unsigned short int c_lflag;
unsigned char c_line;
unsigned char c_cc[NCC];
};
c_iflag
c_oflag
: 入力フラグ
: 出力フラグ
c_cflag
c_lflag
c_line
: 制御フラグ
: 行制御フラグ
: 行制御
c_cc
: 制御文字
✓
◇ 課題 3 ◇
✏
1. sample2.c,sample3.c をコンパイルし,実行せよ.
2. Client プログラムからユーザの入力を受け付け,任意の文字列を送信できるように
せよ.(ヒント: キーボードからの入力は fgets() を用いる.)
✒
✑
11
5
チャレンジ課題(必ずしもやる必要はない)
✓
◇ 課題 4 ◇
✏
1. 録音された音声の時間を逆転して再生するプログラムを作成し,効果を確認せよ
2. 1 から 5 までの数字を送り,それぞれに対応する音声を再生する擬似ジュークボッ
クスシステムを作成せよ.
✒
6
✑
参考資料・参考文献
さらに詳しい情報を知りたいという人は,以下のページを見てみると深い理解が得られるだろう.
• Linux JF (Japanese FAQ) のページ.Linux についての豊富な情報源.
http://www.linux.or.jp/JF/
• LDP (Linux Documentation Project) のページ.ほぼパーフェクトと呼べる量と質の情報源.
ただし英語
http://tldp.org/
• Linux Sound HOWTO:サウンドデバイスに関する詳しい情報が書かれている
http://www.linux.or.jp/JF/JFdocs/Sound-HOWTO.html
• Linux Serial HOWTO:シリアル通信の詳しい情報が書かれている.
http://www.linux.or.jp/JF/JFdocs/Serial-HOWTO.html
A. ソースコード
12
A
A.1
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
ソースコード
sample1.c
58
59
60
61
62
63
64
65
#include <unistd.h>
66
#include <fcntl.h>
67
#include <sys/types.h>
68
#include <sys/ioctl.h>
69
#include <stdlib.h>
70
#include <stdio.h>
71
#include <linux/soundcard.h>
72
73
#define LENGTH 5
/* 再生する時間 (秒) */
74
#define RATE 16000 /* サンプリングレイト */
75
#define SIZE 16
/* サンプルサイズ */
76
#define CHANNELS 2 /* 1 = mono 2 = stereo */
77
78
int main()
79
{
80
int fd;
/* ファイルディスクリプタ */
81
int arg;
/* ioctl calls を行なうための変数*/
82
int status;
/* ステータス格納用変数 */
83
int count;
/* データ読み込みの際のエラー処理用変
84
*/
85
unsigned short buf[LENGTH*RATE*CHANNELS];
86
/* データ格納用バッファ */
87
FILE* fp;
/* ファイル書き込み用ファイルポイン
88
*/
89
90
/* サウンドデバイスのオープン */
91
/* 書き込み専用 (O_WRONLY) で開く */
92
fd = open("/dev/dsp", O_WRONLY);
93
if(fd < 0){
94
perror("open of /dev/dsp failed");
95
return 1;
96
}
97
98
/****************************/
99
/*
パラメータの設定
*/
100
/****************************/
101
102
/* サンプルサイズを設定する */
103
arg = SIZE;
104
status = ioctl(fd, SOUND_PCM_WRITE_BITS, &arg);
105
if (status == -1){
106
perror("SOUND_PCM_WRITE_BITS ioctl failed");
107
return 1;
108
}
109
110
/* ステレオかモノラルを設定する */
111
arg = CHANNELS;
112
status = ioctl(fd, SOUND_PCM_WRITE_CHANNELS, &arg); 113
if (status == -1){
114
perror("SOUND_PCM_WRITE_CHANNELS ioctl failed"); 115
return 1;
116
/*----------------------------------------------*/
/* 計算機演習 「デバイスコントロールの基礎」
*/
/*
サンプルプログラム
*/
/*
sample1.c
*/
/*
*/
/* Last modified on 2004/07/02 by T. Inamura
*/
/*----------------------------------------------*/
}
/* サンプリングレイトを設定する */
arg = RATE;
status = ioctl(fd, SOUND_PCM_WRITE_RATE, &arg);
if (status == -1){
perror("SOUND_PCM_WRITE_WRITE ioctl failed");
return 1;
}
/****************************/
/* 音声ファイルの読み込み */
/****************************/
/* ファイルを読みこみ専用でオープンする */
fp = fopen("test.raw", "rb");
if(fp == NULL){
perror("file open failed");
return 1;
}
/* 音声データを読みこむ */
count = fread(buf, sizeof(short), LENGTH*RATE*CHANNELS, fp);
if(count != LENGTH*RATE*CHANNELS){
perror("file read failed");
printf("read count is %d\n", count);
return 1;
}
/* ファイルをクローズする */
fclose(fp);
/****************************/
/*
音声ファイルの再生
*/
/****************************/
/* write コマンドを使用してデバイスに書き込む */
bufp = buf;
while (count>0) {
status = write(fd, bufp, count);
if (status==-1) {
perror("wrote wrong number of bytes");
return 1;
}
count -= status;
bufp += status;
}
/* デバイスをクローズする */
status = close(fd);
if(status == -1){
perror("device close failed");
return 1;
}
return 1;
}
//end of file
A.2. sample2.c
A.2
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
sample2.c
/*--------------------------------------------計算機演習 「デバイスプログラミング」
サンプルプログラム
sample2.c
Last modified on 2004/07/02 by T.Inamura
-----------------------------------------------*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
<sys/types.h>
<sys/stat.h>
<termio.h>
<sys/file.h>
<stdio.h>
<stdlib.h>
<fcntl.h>
<unistd.h>
<signal.h>
<string.h>
int main()
{
int fd;
/*ファイルディスクリプタ
*/
struct termio tio;
/*パラメータ設定用の構造体 */
int count, total_count;/*データ読み込み用カウンタ*/
int status;
/*エラー処理用の変数
*/
char buffer[100];
/*データ格納用バッファ
*/
char c;
/*データを読みこむ際に使用 */
char *ptr;
/*データを読みこむ際に使用 */
/****************************/
/*
デバイスのオープン
*/
/****************************/
/* 読み書き用 (O_RDWR) で開く */
fd = open("/dev/ttyS0", O_RDWR);
if(fd < 0){
perror("open of /dev/ttyS0 failed");
return 1;
}
/****************************/
/*
パラメータの設定
*/
/****************************/
/* パラメータを設定するための構造体を TCGETA で取得
する */
46
status = ioctl(fd, TCGETA, &tio);
47
if(status < 0){
48
perror("ioctl (TCGETA) failed");
49
return 1;
50
}
51
52
53
54
55
56
57
58
59
60
61
62
63
13
/* 通信速度を設定する */
tio.c_cflag |= B9600;
/* 入力された文字列をエコーしない */
tio.c_lflag &= ~ECHO;
/* カノニカルモードを無功にする */
tio.c_lflag &= ~ICANON;
/* 1 文字送られて来るまで read を終了しない */
tio.c_cc[VMIN] = 1;
tio.c_cc[VTIME] = 0;
/* 以上の設定を反映させるために TCSETA を行なう */
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
status = ioctl(fd, TCSETA, &tio);
if(status < 0){
perror("ioctl (TCSETA) failed");
return 1;
}
/****************************/
/*
client の入力待ち
*/
/****************************/
while(1){
/* client から送られる文字列を読みこむ */
printf("Waiting for client to send characters.\n");
/* 変数の初期化 */
total_count = 0;
ptr = buffer;
/* 改行文字 ’\n’、もしくは、終端文字 ’\0’ を読み
こむまで read を実行する*/
82
while(1){
83
/* 1 文字づつ読みこむ */
84
count = read(fd, &c, 1);
85
if(count < 0){
86
perror("read failed");
87
return 1;
88
}
89
total_count += count;
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
*ptr = c;
ptr++;
if(c == ’\n’ || c == ’\0’){
/* 未受信のデータを破棄する */
tcflush(fd, TCIFLUSH);
/* 終端文字 ’\0’ を設定する */
*ptr = ’\0’;
/* 受け取った文字とバイト数を表示する */
printf("read %d bytes\n", total_count);
printf("buffer is\n\n %s \n\n", buffer);
break;
}
}/* 読みこみ用ループの終了 */
/* 1 文字目が ’q’ だったらループを抜ける */
if(buffer[0] == ’q’){
printf("quit servicing!\n");
break;
}
}/* 一番外側の while ループの終了 */
/* デバイスをクローズする */
status = close(fd);
if(status == -1){
perror("device close failed");
return 1;
}
return 1;
}
/* end of file */
A. ソースコード
14
A.3
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
sample3.c
/*--------------------------------------------計算機演習 「デバイスプログラミング」
サンプルプログラム
sample3.c
Last modified on 2004/07/02 by T.Inamura
-----------------------------------------------*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
<sys/types.h>
<sys/stat.h>
<termio.h>
<sys/file.h>
<stdio.h>
<stdlib.h>
<string.h>
<fcntl.h>
<unistd.h>
<signal.h>
int main()
{
int fd; /* ファイルディスクリプタ */
struct termio tio; /* パラメータ設定用の構造体 */
int count; /* データ読み込みの際に使用 */
int status; /* エラー処理用の変数 */
char buffer[100]; /* データ格納用バッファ */
/****************************/
/*
デバイスのオープン
*/
/****************************/
/* 読み書き用 (O_RDWR) で開く */
fd = open("/dev/ttyS0", O_RDWR);
if(fd < 0){
perror("open of /dev/ttyS0 failed");
return 1;
}
/****************************/
/*
パラメータの設定
*/
/****************************/
/* パラメータを設定するための構造体を TCGETA で取得
する */
44
status = ioctl(fd, TCGETA, &tio);
45
if(status < 0){
46
perror("ioctl (TCGETA) failed");
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
return 1;
}
/* 通信速度を設定する */
tio.c_cflag |= B9600;
/* 入力された文字列をエコーしない */
tio.c_lflag &= ~ECHO;
/* カノニカルモードを無功にする */
tio.c_lflag &= ~ICANON;
/* 1 文字送られて来るまで read を終了しない */
tio.c_cc[VMIN] = 1;
tio.c_cc[VTIME] = 0;
/* 以上の設定を反映させるために TCSETA を行なう */
status = ioctl(fd, TCSETA, &tio);
if(status < 0){
perror("ioctl (TCSETA) failed");
return 1;
}
/****************************/
/*
server への文字転送
*/
/****************************/
/* コンソールの入力を読みこむ */
/* 今は一定の文字列となっている */
printf("Please input some words and return.\n");
sprintf(buffer, "Hello! JSK Lab.\n");
/* 文字列を server へ送る */
count = write(fd, buffer, strlen(buffer));
/* 送信したバイト数を表示する */
printf("write %d bytes\n", count);
/* デバイスをクローズする */
status = close(fd);
if(status == -1){
perror("device close failed");
return 1;
}
return 1;
}
/* end of file */