あなたが書いたコードをデバッグするための最も良い方法は、Linux マシンを
もう一台用意し、二台のコンピュータをヌルモデムケーブルで接続することで
す。miniterm(LDP プログラマーズガイド
(ftp://sunsite.unc.edu/pub/Linux/docs/LDP/programmers-guide/lpg-0.4.tar.gz
の'examples'ディレクトリにあります)を使って、あなたの Linux マシンへ文
字を送ってみましょう。miniterm は非常に簡単にコンパイルでき、キーボー
ド入力をシリアルポート経由でそのまま(raw)送ります。ただ、define 文
#define MODEMDEVICE "/dev/ttyS0"
の部分だけはチェックしなくて
はなりません。この部分は、ケーブルで接続するのが COM1 であれば
ttyS0
、COM2であればttyS1
のように設定します。このテス
トで大事な点は、全ての文字はそのまま(raw, 出力処理無しに)送信され
ることです。接続テストをするときは、両方のマシンで miniterm を実行し、
キーボードを叩くだけです。片方のマシンで入力された文字は、もう一方のマ
シンで出力されます。その逆も同じです。入力した文字は、入力した方のマシ
ンの画面にはエコーされません。
ヌルモデムケーブルを自作するには、TxD(送信)とRxD(受信)の結線をクロスさ せます。ケーブルについての詳しい解説は、Serial-HOWTO の第7章にあります。
未使用のシリアルポートが2つあるのならば、一台のコンピュータでこのテス
トを実行することもできます。この場合は、2つの仮想コンソールでそれぞれ
miniterm を実行します。シリアルマウスを外してシリアルポートを空ける場
合には、/dev/mouse
を書換えることを忘れないようにしましょう。
マルチポートシリアルカードを使っている場合には、設定が正しいことを確認
しましょう。筆者は自分のマシンで間違った設定をしていたために、自分のマ
シンでテストした時だけうまく動作するという事態になったことがあります。
この設定で他のコンピュータに接続した時には、文字が消えてしまいました。
2つのプログラムを1つのコンピュータで動かすことは、完全に非同期とは言え
ません。
/dev/ttyS*
というデバイスは端末を Linux マシンに繋ぐためのもの
で、通信を始めた後は端末に合わせた設定が行われます。この点は raw デバ
イスを使って通信するプログラムを行う場合には、注意しておかなければなり
まん。例えば、送ったキャラクタをエコーバックさせるようにシリアルポート
を設定されていますが、通常データ送信のためにはこの設定は変更しなければ
いけません。
全てのパラメータはプログラム内で簡単に設定できます。設定は
ヘッダファイル<asm/termbits.h>
で定義されている
termios 構造体
に保存されます。
#define NCCS 19
struct termios {
tcflag_t c_iflag; /* 入力モードフラグ */
tcflag_t c_oflag; /* 出力モードフラグ */
tcflag_t c_cflag; /* 制御モードフラグ */
tcflag_t c_lflag; /* ローカルモードフラグ */
cc_t c_line; /* ラインディシプリン(line discipline) */
cc_t c_cc[NCCS]; /* 制御文字 */
};
この<asm/termbits.h>
ファイルには、フラグの定義も全て記
述されています。c_iflag
フラグには入力モードのフラグがいくつ
か含まれており、全ての入力処理を指定します。入力処理とは、デバイスから
送られたキャラクタは、read
で読み出される前に処理することがで
きるということです。同様に、c_oflag
は出力処理を扱います。
c_cflag
は、ボーレートや文字毎のビット数、ストップビットなどの
ポート設定を記録しています。c_lflag
内のローカルモードフラグ
は、文字がエコーされるかどうか、プログラムにシグナルが送られるかどうか
等を指定します。最後に、配列 c_cc
では、ファイル終端、stop 等
の制御文字を定義します。制御文字のデフォルト値は
<asm/termios.h>
で定義されています。各フラグについては、
オンラインマニュアルの termios(3)
に説明があります。
termios
には c_line
というメンバがあります。このメン
バについては、Linux の termios のマニュアルにも、Solaris 2.5 のマニュ
アルにも説明がありません。ご存じの方がいらっしゃれば、是非ご教示ください。
c_line メンバは termio
構造体だけに含まれているものなのではな
いのでしょうか?
ここでは、3つの異なる種類の入力の概念を説明します。利用目的に従って、
適切な概念を選択してください。文字列全体を取得するのに、1文字読み込み
のループを使うことはできる限り避けるべきです。私はこれをやったとき、
読み込み時に read
が全くエラーを出力しなかったのにもかかわら
ず、文字が欠けてしまったことがありました。
これは端末に対しての通常の処理モードですが、他のデバイスとの通信の時に
も便利です。全ての入力は行単位で処理されます。つまり、read
は
入力の1行全体のみを返してきます。デフォルトでは、行はNL
(ASCII
のLF
)、ファイル終端、行終端文字のいずれかで終ります。標準の設
定では、CR
(DOS/Windows のデフォルトの行終端文字)は行の終端と
はなりません。
カノニカル入力処理では、消去(erase)、単語の削除(delete word)、文字の再
出力(reprint characters)、CR
のNL
への変換などを扱うこ
とができます。
非カノニカル入力処理は、read 毎に決まった数の文字を扱う方法で、キャラ クタタイマを利用することもできます。このモードはアプリケーションが決まっ た文字数のキャラクタを読み込む時や、接続したデバイスが大量の文字を送っ てくる場合に使用します。
上記2つのモードは、同期及び非同期モードで使うことができます。デフォル
トは、入力がうまくいくまで read
文がブロックされる同期モード
です。非同期モードでは、read
文は即座に終了し、後で読み込みが
完了した時にプログラムにシグナルが送られます。このシグナルは、シグナル
ハンドラを使って受け取ります。
これは別の入力モードというわけではありませんが、複数のデバイスを扱う時 に便利です。筆者のアプリケーションでは、TCP/IP ソケット経由の入力と他 のコンピュータからのシリアル接続経由の入力を擬似的に同時に扱っています。 以下に示すプログラム例では、異なる2つの入力ソースからの入力待ちを行い ます。片方のソースからの入力が可能になると、その入力が処理され、プログ ラムは次の入力を待ちます。
以下に示すアプローチはちょっと複雑に見えますが、Linux はマルチプロセッ
シング OS であることを忘れてはいけません。select
システムコー
ルは入力待ちの間は CPU に負荷を与えませんが、ループを使った入力待ちを
行うと、同時に実行されている他のプロセスが遅くなってしまいます。