dvbstream起動時に、次のようなメッセージを出力しているので、信号を受信できない状態になるようです。
Bit error rate: 0 Signal strength: 0 SNR: 0 FE_STATUS: Setting filter for PID 8192 FILTER 8192: DMX SET PES FILTER: Connection timed out
こうなってしまうとUSBデバイスを抜き差ししないと回復しません。
USBデバイスへの電源On/Offでよさそうなのですが、リブートしてもUSBデバイスへの給電は切れないようなので、USBポートの電源制御をする必要があるようです。
USBコントローラーが電源制御をサポートしていれば、ソフト的に制御できることが分かったのですが、残念ながら使用しているマザーボードでは未サポートでした。
さらに調べるとポート毎に電源制御ができるUSB HUBがあり、Linux向けのソフト(節電USB・HUB(U2H-SW4)の制御ソフト)を公開している方を見つけました。
作者の方は、sianoチップ利用のワンセグ野郎ユーザーのようで、同じ症状改善のために書かれたようです。すばらしい。
早速、コンパイルして使用してみましたが、私の環境ではそのままでは上手く動きませんでした。
HUBの仕様変更を疑ってSnoopyProでデータを確認したり、あれこれ調べたところ、/dev/hidrawXとの送受信データの先頭に1byte付けてあげる(レポートID用?)と上手く動くことが分かりました。
で、ts.plに組み込みたかったので、perlで書いてみました。
set_status('/dev/hidraw0', 1, 0); # hidraw0のポート1の電源OFF usleep((1000000*0.3)); set_status('/dev/hidraw0', 1, 1); # hidraw0のポート1の電源ON sub set_status() { my ($file, $port_num, $power) = @_; sysopen my $fh, $file, O_RDWR|O_NONBLOCK or do { print STDERR "cannot open $file: $!\n"; return 0; }; my @set_status = (0,0x03,0x5d,0,0,0,0,0,0); if ($port_num == 1) { $set_status[4] = 0x05; } elsif (1 < $port_num and $port_num < 5) { $set_status[4] = int($port_num); } else { return 0; } $set_status[5] = 0x01 if ($power); my $dat = pack("C9", @set_status); my $r = syswrite $fh, $dat, 9; if ($r != 9) { print STDERR "syswrite failed: f=$file, p=$port_num: $!\n"; return 0; } close $fh; }
U2H-SW4は、lsusbで確認するとUSB portを5つ持っていて、USB port1がHIDになっているようです。
USB port5が機器に印刷されている1番ポートに対応しています。
ポートの状態確認は、次のようにして取得できます。
4byte目の該当するビットが立っている場合は、電源Onを表しています。
my $port = get_status("/dev/hidraw0"); print "$file\n"; foreach my $i (0..3) { my $on = $port & (1<< $i); printf " port%d: %s\n", $i+1, $on ? "On" : "Off"; } sub get_status() { my ($file) = shift @_; sysopen my $fh, $file, O_RDWR|O_NONBLOCK or do { print STDERR "cannot open $file: $!\n"; return undef; } my @get_status = (0,0x03,0x5d,0x02,0,0,0,0,0); my $dat = pack("C9", @get_status); my $r = syswrite $fh, $dat, 9; my ($rout, $info) = (undef, undef); my $rin = ''; vec($rin, fileno($fh), 1) = 1; my ($nfound, $timeleft) = select($rout=$rin, undef, undef, 3); $r = read $fh, $info, 9; close $fh; return undef if ($r != 9); my @st = unpack("C9", $info); if (($st[3] & 0xc3) != 0x03 and $st[5] == 0x75) { printf STDERR "unknown data received: %s\n", unpack("H*", $info); return undef; } my ($port, $i) = (0, 0); foreach my $flg (0x20, 0x04, 0x08, 0x10) { $port |= (1 << $i) if ($st[3] & $flg); $i++; } return $port; }ts.plに組み込むにあたり、dvbstreamで使用しているDVBデバイスが接続しているU2H-SW4を見つける必要があります。
もっとスマートな方法があると思いますが、udevadmコマンドでdevpathを調べることで接続しているU2H-SW4とHUB portを特定できました。
U2H-SW4のHIDは、次のように/dev/hidraw*からベンダー/プロダクトコードが一致するものを調べ、udevadmコマンドでdevpathを取得しておきます。
説明用のコードでは、見やすさのためにエラー処理はdie()にしました。
sub find_u2hsw4() { my $HIDIOCGRAWINFO = 0x80084803; opendir my $dh, '/dev' or die "cannot opendir /dev: $!"; my @files = sort grep /^hidraw\d+$/, readdir($dh); closedir $dh; my @target = (); foreach my $f (@files) { my $file = "/dev/$f"; my $info = undef; open my $fd, '+<', $file or die "cannot open $file: $!"; ioctl($fd, $HIDIOCGRAWINFO, $info) or die "ioctl failed: $file: $!"; close $fd; my ($busy, $vendor, $product) = unpack("Iss",$info); # find ActionStar USB HID if ($vendor == 0x2101 and ($product & 0xffff) == 0x8501) { my $path = `/sbin/udevadm info --query=path --name=$file`; chomp($path); $path =~ s!/hidraw/${f}$!!; push @target, [$file, $path]; } } return @target; }上記で見つけたHIDのdevpathと、dvbstreamで使用している/dev/dvb/adapterX/frontendXのdevpathを調べることにより、接続しているHUBとHUB portを見つけることが出来ます。
ts.plでdvbstreamにSIGTERMを送った後、dvbstreamのログから直近で
SNR: 0
を見つけた場合に、電源をOn/Offするようにして使ってます。 この記事からSyntaxHighlighter を設定してみました。
0 件のコメント:
コメントを投稿