dvbstream起動時に、次のようなメッセージを出力しているので、信号を受信できない状態になるようです。
1 2 3 4 5 6 | 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で書いてみました。
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 | 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を表しています。
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 | 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 ; } |
もっとスマートな方法があると思いますが、udevadmコマンドでdevpathを調べることで接続しているU2H-SW4とHUB portを特定できました。
U2H-SW4のHIDは、次のように/dev/hidraw*からベンダー/プロダクトコードが一致するものを調べ、udevadmコマンドでdevpathを取得しておきます。
説明用のコードでは、見やすさのためにエラー処理はdie()にしました。
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 | 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 ; } |
ts.plでdvbstreamにSIGTERMを送った後、dvbstreamのログから直近で
SNR: 0
を見つけた場合に、電源をOn/Offするようにして使ってます。 この記事からSyntaxHighlighter を設定してみました。
0 件のコメント:
コメントを投稿