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 件のコメント:
コメントを投稿