アプリ版:「スタンプのみでお礼する」機能のリリースについて

AdvantechのPCM-9575ボードにRedHat9を入れてCOM2
をRS-485にして115kでシリアル通信しています。
プログラム的には"/dev/ttyS1"を使用して普通の23
2Cポートと同じように操作できますが、送信イネー
ブル信号(RTS 信号がつながっているのでioctl()
関数で制御できます)を操作してやらないと送受信
できないので、送信直前にセットし、送信完了直後
にクリアしたいと考えているのですが、write() 関
数が送信完了まで待ってくれないので、タイミング
を作るのに困っています。
シリアルの送信完了待ちの方法とかご存じでないし
ょうか?

A 回答 (4件)

今回の問題はドライバレベル以下で起こっているのだと思います。

SIOには例えば16バイトのFIFOがあって、ドライバはハードに書き込んだら、すぐにカーネルに戻ってしまうのでしょう(FIFOの目的を考えれば当然ですね)。だからプロセスレベルでBLOCKINGであろうとなかろうと短時間ではバッファリングが起きているのだろう ... という理解になりました。質問主さんは最初からお気づきだったのでしょう。

ドライバのソースを読んだところでは、closeをするとハードウェアFIFOが空になるのをちゃんと待っています。ですからwrite直後にcloseしたら完全に送信完了ということになります。またcloseでは
if (!info->tty || (info->tty->termios->c_cflag & HUPCL))
info->MCR &= ~(UART_MCR_DTR|UART_MCR_RTS);
serial_outp(info, UART_MCR, info->MCR);
ということをしているので、RTSも一緒にクリアされるようです。

open/closeを繰り返すのはコストが高いので避けたいですけれど、そうでないなら単にcloseすることで質問主さんの目的は達せられるのではないでしょうか?私のボスと話したところでは、OSの内部をいじりたくないのであれば質問主さんのnanosleepがベストの解決だろう、という結論になりました。

その他の解決さくとしてはNo.3で書いたハードを直接見る方法(Linux流の行儀の悪いプログラム)や、ハードウェアFIFOにバッファリングをさせないためにはサイズを1バイトにしてしまう手があります。でもこれをすると山ほど割り込みが発生するのでダメかもしれません。とにかく全体のパフォーマンスは犠牲にしてもrs_writeがFIFOが空になるのを待つようなオプションをドライバ開発者に付けてもらうのがいいと思います。すでにトランスミッタが完全に送信したかどうかをチェックする関数がありますから、ちょっとの改造でできるはずです。きっと他の人の需要もあると思います。

ところで
>出終わってなければ再実行
これは
for (nwritten = 0;nwritten < n;nwritten += rv) {
rv = write (fd, buf+nwritten, n-nwritten);
if (rv < 0) break; // Error: bail out. //
}
こうしているということですよね?
    • good
    • 1
この回答へのお礼

ありがとうございます!!
詳しいところまで...助かります。
ドライバの深いところまではまだ読んでなかったのですが、なんとなく分かってきました。
close() は送信頻度が今は30Hzくらいですが完成予定では600Hzくらいになるので無理っぽいです。
アプリケーションレベルからの周期監視も実行時間を喰うから避けたいかなと考えてます。
(のですが、割り込みがとれなければそれしかないんでしょうね)
他の作業に追われて今は時間をかけられないので、一段落したらドライバいじりに挑戦しようと考えてます。
またそのときにはお知恵を拝借させてください。
>こうしているということですよね?
だいたいそんな感じです。(プロセスがFIFOで誤動作すると実行時間を食い尽くすのでスリープで保険かけてます)

お礼日時:2004/07/09 12:55

うむむ、そうでしたか.....ううむなんでだろう。

すみません、ネタ切れです(^^;

格好悪いですけれども、write直後にUARTのポートを直接読みに行ってLSR内でTHRの状態を見るのはいかがでしょうか。

#今からドライバをDEBUGオプション付きで再コンパイルして眺めてみます。
    • good
    • 1

こちらにはRS232の環境しかないのですけれど、実験してみたところ、普通にopenしてwriteしたらちゃんと待ってくれました。

openするときにワザワザO_NDELAYとかO_NONBLOCKなんてセットしてないですよね....?writeが待ってくれないのはどのようにして確認されたのでしょう?writeの戻り値は送信したバイト数と同じ数になっていますか?
    • good
    • 0
この回答へのお礼

ありがとうございます。
write()の返値はあっています。(出終わってなければ再実行させています)
openの引数は(O_RDWR|O_NOCTTY)です。
確認は、ソフト的にはwrite()直後にioctl()でRTSラインを操作し、信号線の電位をオシロで見ています。
開通後にtcsetattr()を引数(struct termios)
c_iflag,c_oflag,c_lflag,c_cc[VTIME],c_cc[VMIN],c_cc[VEOL],c_cc[VEOF]
をそれぞれ0にしてコールしています。

お礼日時:2004/07/08 08:28

経験の無い者ですみません。

思いつきでアドバイスです。

termios.hのtcdrainをwriteのあとに入れるのはいかがでしょうか?
    • good
    • 0
この回答へのお礼

ありがとうございます。早速やってみました。
プロセスを休眠させるようで、起床は次のカーネル
のスケジューラ処理後になるようです。
(今カーネルは10ms周期ですが、応答が1.5
ms程度で来るので間に合いません)
Linux 始めて間がないもんで、このへんの動きが
さっぱり分からないので、他にも思いつきでいい
ので情報いただけると嬉しいです。
とりあえず今は実測で1char=95.5usから待ち時間
を算出してnanosleep() 使って待たせてます。^^;

お礼日時:2004/07/07 18:46

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!

このQ&Aを見た人はこんなQ&Aも見ています