いとうと申します。困っている事があり、アドバイスをいただきたくメールし ます。
TriState のデジタル気圧計に FreeBSD 8.3-RELEASE でアクセスを試みていま す。こんな↓やつで、PIC18F2550 というチップを使っています。 - http://www.tristate.ne.jp/digitalbarome.htm - http://www.tristate.ne.jp/ftp/manu029.pdf umodem を使うと ugen1.4: <Mecanique> at usbus1 umodem0: <Mecanique Swordfish Virtual COM Port, class 2/0, rev 2.00/1.10, addr 4> on usbus1 umodem0: data interface 1, has no CM over data, has no break と認識され、cu -l /dev/ttyU0 で一応の動作は確認できています。 ところが擬似コードで書くと(実際のスクリプトは長いので末尾に載せます) #!/usr/bin/perl while (1) { sysopen($fd, O_RDWR | O_NONBLOCK); tcgetattr(); cflag |= CLOCAL; iflag |= ICANON; iflag &= ~(ICRNL | INLCR); oflag &= ~OPOST tcsetattr(); select(undef, fds, undef, 1.0); syswrite(); sleep(1); # これを入れないと応答が欠ける select(fds, undef, undef, 1.0); sysread(); close(); } のような操作をしたところ、回数は一定しないんですがループの15回目、24回 目、5回目、3回目、17回目、のような回数で、sysread()の手前の select()が タイムアウトしてしまいます。 一度こうなると、cu でアクセスしても反応がありません。 また、手作業なので定量的なことは言えませんが、cu で コマンドを送って応 答を受信して切断、という操作を何度も繰り返すと、同様の事象が起きました。 接続したままコマンドの送信と応答の受信を繰り返しても、根気の続く範囲の 繰り返しでは、事象は起きませんでした。 この事象が発生したとき、FreeBSD の OS 自体はハングアップしておらず、他 のプロセスは何の問題もなく動作しているように見え、気圧計の側については よくわからないんですが、LED、LCD の表示を見る限り正常動作を続けているよ うに見えます。USB ケーブルを抜き差しすると元通りコマンドと応答の送受信 ができる状態に復帰します。 それと、カーネルの心得は全然ないんですが、何か手がかりがつかめないかと 思い、sysctl で hw.usb.umodem.debug を1にしてみると、事象が起きないとい うお決まりのパターンです。 別の PC でですが、Ubuntu 12.04LTS では、同じスクリプトを実行しても事象 は起きません。 一方 #!/usr/bin/perl sysopen($fd, O_RDWR | O_NONBLOCK); tcgetattr(); cflag |= CLOCAL; iflag |= ICANON; iflag &= ~(ICRNL | INLCR); oflag &= ~OPOST tcsetattr(); while (1) { select(undef, fds, undef, 1.0); syswrite(); sleep(1); # これを入れないと応答が欠ける select(fds, undef, undef, 1.0); sysread(); } のように close()しないままループを回すと100回以上回しても平気です。 TriState の Web ページにある「★USB通信の不安定について」については、購 入時期がつい最近ですし、目視でも該当していないように見えること、上述の ように Ubuntu では事象が起きないことから、手許の個体は該当していないと 判断しています。 以上のような状況で困っています。どなたかアドバイスをいただけないでしょ うか? どうぞよろしくお願いします。 実際のスクリプト: #!/usr/bin/perl use strict; use warnings; use Fcntl; use POSIX; my ($fh, $fd, $fds, $tios, $tios0, $c_cflag, $c_iflag, $c_oflag, $tbuf, $rbuf, $tlen, $k, $n); $k = 1; $tbuf = "BARH\r\n"; $tlen = length($tbuf); #while (1) { # while (1) は、どちらか一方だけ生かす if (!sysopen($fh, $ARGV[0], O_RDWR | O_NONBLOCK) ) { print(STDERR "$0: open($ARGV[0]): $!\n"); exit(1); } $fd = fileno($fh); $tios = POSIX::Termios->new(); $tios0 = POSIX::Termios->new(); if (!($tios->getattr($fd) ) ) { print(STDERR "$0: getattr($ARGV[0]): $!\n"); exit(1); } $c_cflag = $tios->getcflag(); $tios->setcflag($c_cflag | POSIX::CLOCAL); $c_iflag = $tios->getiflag(); $tios->setiflag($c_iflag | POSIX::ICANON); $tios->setiflag($c_iflag & ~(POSIX::ICRNL | POSIX::INLCR) ); $c_oflag = $tios->getoflag(); $tios->setoflag($c_oflag & ~POSIX::OPOST); if (!$tios->setattr($fd, POSIX::TCSADRAIN) ) { close($fh); print(STDERR "$0: setattr($ARGV[0]): $!\n"); exit(1); } while (1) { # while (1) は、どちらか一方だけ生かす print(STDERR "k = $k\n"); $fds = ''; vec($fds, fileno($fh), 1) = 1; print(STDERR "calling send select()\n"); if (!($n = select(undef, $fds, undef, 1.0) ) ) { $tios0->setattr($fd, POSIX::TCSADRAIN); close($fh); print(STDERR "$0: send select(): timeout\n"); exit(1); } print(STDERR "send select(): n = $n\n"); print(STDERR "calling syswrite()\n"); if (!($n = syswrite($fh, $tbuf, $tlen) ) ) { $tios0->setattr($fd, POSIX::TCSADRAIN); close($fh); print(STDERR "$0: write($ARGV[0]): $!\n"); exit(1); } print(STDERR "back from syswrite()\n"); sleep(1); # unanalyzed timing issue... $fds = ''; vec($fds, fileno($fh), 1) = 1; print(STDERR "calling recv select()\n"); if (!($n = select($fds, undef, undef, 1.0) ) ) { $tios0->setattr($fd, POSIX::TCSADRAIN); close($fh); print(STDERR "$0: recv select(): timeout\n"); exit(1); } print(STDERR "calling sysread()\n"); if (!($n = sysread($fh, $rbuf, 16) ) ) { $tios0->setattr($fd, POSIX::TCSADRAIN); close($fh); print(STDERR "$0: read($ARGV[0]): $!\n"); exit(1); } print(STDERR "back from sysread()\n"); print("n = $n, rbuf = $rbuf\r\n"); $k++; } $tios0->setattr($fh, POSIX::TCSADRAIN); close($fh); #} exit(0); ----- kkdlabs.jp, featuring Koh-ichi Ito as just another DNS freak in town.