5. リモコン信号定義データの相互変換¶
黒豆や IRKit, KURO-RS, クロッサム2+ などのプログラマブルな学習リモコン (スマートリモコン) の信号データを、リモコン同士ツノつき合わせて学習させるのではなく、PC 上で理想的な波形に合成するためのノウハウです。
- 赤外線リモコンの信号定義データの合成 [表紙]
 - 家製協フォーマットの信号データ合成
 - NEC フォーマットの信号データ合成
 - ソニーフォーマットの信号データ合成
 - SHARP フォーマットの信号データ合成
 - リモコン信号定義データの相互変換 (このページ)
 - リモコン信号の解析
 - メーカー純正リモコンのコード
 
このページでは、黒豆、IRKit 用の定義データや、事実上の世界標準である Pronto HEX 形式の信号定義データを、相互に変換するサンプルコードを紹介します。本稿の他のページで使用している汎用定義データ形式との変換も可能です。
5.1. 信号定義データの相互変換¶
使い方¶
irconvert [--in FORMAT] [--out FORMAT] [--repeat nn] [ファイル名 ...]
- 入力は、1行に定義データ一つの形式のテキストファイル。ファイル名をしていないときは標準入力を読む。
 - 出力は、入力の各行を変換したテキスト (標準出力)。
 
なお、変換時に丸め誤差が出るため、変換を繰り返すと信号波形が劣化します。
オプション¶
--in      ; 入力の形式
              pronto, mame (黒豆), irkit, kurors, generic (汎用定義)
              デフォルトは generic
--out     ; 出力の形式
              pronto, mame (黒豆), irkit, kurors, generic (汎用定義)
              デフォルトは generic
--repeat  ; 信号を指定回数繰り返す定義を出力する
使用例¶
IRKit で学習済みの定義データを黒豆用に変換する
$ irconvert --in irkit --out mame 入力ファイル
インターネットで検索して入手した Pronto HEX 形式の定義データを黒豆用に変換する
$ echo 0000 006D .... 0235 | irconvert --in pronto --out mame
ソニー BRAVIA に「電源 OFF」を 3 回送信する IRKit 用定義データを作成する (irsony は こちら を参照)
$ irsony 1 46 | irconvert --repeat 3 --out irkit
シャープ AQUOS に「電源 ON」を 2 回送信する黒豆用定義データを作成する (irsharp は こちら を参照)
$ irsharp 17 74 1 | irconvert --repeat 2 --out mame
パナソニック VIERA に「電源 OFF」を送信する KURO-RS 用定義データを作成する (iraeha は こちら を参照)
$ iraeha 02 20 80 00 3f bf | irconvert --out kurors
サンプルコード¶
#! /usr/bin/perl
#
#  Usage: irconvert [options ...] [input_file ...]
#    options:
#      --in FORMAT
#      --out FORMAT
#      --repeat num
#    FORMAT:
#      pronto, rm, irkit, kurors, generic
#---------------------------------------------------------------- 定数値
%input_functions = (
    'pronto' => \&pronto2ic, 'hex' => \&pronto2ic,
    'rm' => \&rm2ic, 'mame' => \&rm2ic, 'kuromame' => \&rm2ic,
    'irkit' => \&irkit2ic,
    'kurors' => \&kurors2ic, 'pcoprs1' => \&kurors2ic,
    'generic' => \&gen2ic, 'raw' => \&gen2ic,
);
%output_functions = (
    'pronto' => \&ic2pronto, 'hex' => \&ic2pronto,
    'rm' => \&ic2rm, 'mame' => \&ic2rm, 'kuromame' => \&ic2rm,
    'irkit' => \&ic2irkit,
    'kurors' => \&ic2kurors, 'pcoprs1' => \&ic2kurors,
    'generic' => \&ic2gen, 'raw' => \&ic2gen,
);
#-----------------------------------------------------------デフォルト値
$input_function = $input_functions{'generic'};
$output_function = $output_functions{'generic'};
$repeat_user_specified = 0;
#---------------------------------------------- コマンドライン引数の解析
push (@ARGV, $eol = "--##END_OF_ARGV##--");
while (@ARGV > 0 && ($argv = shift (@ARGV)) ne $eol) {
    if ($argv =~ /^--(.*)/) {
        $option = $1;
        if ($option eq 'in') {
            $format = shift (@ARGV);
            if (! defined ($input_functions{$format})) {
                print STDERR "$0: unknown input format '$format'\n";
                exit 1;
            }
            $input_function = $input_functions{$format};
        } elsif ($option eq 'out') {
            $format = shift (@ARGV);
            if (! defined ($output_functions{$format})) {
                print STDERR "$0: unknown output format '$format'\n";
                exit 1;
            }
            $output_function = $output_functions{$format};
        } elsif ($option eq 'repeat') {
            $repeat_user_specified = shift (@ARGV);
        } else {
            print STDERR "$0: unknown option '--$option'\n";
            exit 1;
        }
    } else {
        push (@ARGV, $argv);
    }
}
#---------------------------------------------------------- メインループ
while (<>) {
    ($freq, $repeat, @data) = &$input_function ($_);
    if ($freq < 0) {
        print "$0: $.: $repeat\n";
    } else {
        $repeat = $repeat_user_specified if ($repeat_user_specified > 0);
        $code = &$output_function ($freq, $repeat, @data);
        print $code, "\n";
    }
}
exit 0;
#------------------------------------------ フォーマット変換サブルーチン
sub pronto2ic {         # pronto hex -> 内部表現
    my ($str) = shift (@_);
    my (@run) = ($str =~ /\b([0-9a-f]{4})\b/isg);
    return (-1, "pronto2ic: invalid form") if (shift (@run) != 0);
    @run = map { $_ = hex ($_); } @run;
    my ($freq) = 1000 / (shift (@run) * .241246);
    my ($length) = shift (@run) + shift (@run);
    return (-1, "pronto2ic: too short") if (scalar (@run) != $length * 2);
    @run = map { $_ = $_ / $freq * 1000; } @run;
    return ($freq, 1, @run);
}
sub ic2pronto {         # 内部表現 -> pronto hex
    my ($freq, $repeat, @run) = @_;
    push (@run, 40000) if (@run % 2 != 0);
    $freq = int (1000 / $freq / .241246 + 0.5);
    my ($clock) = 1 / ($freq * .241246);
    my ($r) = 0.5;
    my (@run1) = ();
    while ($repeat-- > 0) {
        foreach (@run) {
            my ($t) = $_ * $clock + $r;
            push (@run1, int ($t));
            $r = $t - int ($t);
        }
    }
    unshift (@run1, 0, $freq, 0, scalar (@run1) / 2);
    @run1 = map { sprintf ("%04x", $_); } @run1;
    my ($code) = join (" ", @run1);
    return ($code);
}
sub rm2ic {             # 黒豆 -> 内部表現
    my ($str) = shift (@_);
    $str =~ s/[^0-9a-f]//isg;
    my (@run) = map (hex, ($str =~ /(..)/isg));
    return (-1, "rm2ic: invalid form") if (shift (@run) != 0x26);
    my ($repeat) = shift (@run) + 1;
    my ($length) = shift (@run) + shift (@run) * 256;
    return (-1, "rm2ic: too short") if (@run < $length);
    @run = @run[0..$length - 1];
    my (@run1) = ();
    while (@run > 0) {
        if (($_ = shift (@run)) == 0) {
            $_ = shift (@run) * 256 + shift (@run);
        }
        push (@run1, $_ * 1000 / 32.768);
    }
    return (38, $repeat, @run1);
}
sub ic2rm {             # 内部表現 -> 黒豆
    my ($freq, $repeat, @run) = @_;
    push (@run, 40000) if (@run % 2 != 0);
    my ($clock) = 32768 / 1000000;
    my ($r) = 0.5;
    my (@run1) = ();
    while ($repeat-- > 0) {
        foreach (@run) {
            my ($t) = $_ * $clock + $r;
            push (@run1, int ($t));
            $r = $t - int ($t);
        }
    }
    $run1[$#run1] = 0x0d05;
    @run1 = map { sprintf ($_ >= 256 ? "00%04x" : "%02x", $_); } @run1;
    my ($code) = join ("", @run1);
    my ($len) = length ($code) / 2;
    $code = sprintf ("2600%02x%02x", $len % 256, $len / 256) . $code;
    return ($code);
}
sub irkit2ic {          # IRKit -> 内部表現
    my ($str) = shift (@_);
    return (-1, "irkit2ic: invalid form") if ($str !~ /"format":"raw"/);
    return (-1, "irkit2ic: invalid form") if ($str !~ /"freq":(\d+)/);
    my ($freq) = $1;
    return (-1, "irkit2ic: invalid form") if ($str !~ /"data":\[(.*?)\]/);
    my (@run) = split (",", $1);
    my (@run1) = ();
    while (@run > 0) {
        my ($t) = shift (@run);
        if ($t == 0) {
            $t = shift (@run);
            @run1[$#run1] += $t / 2;
        } else {
            push (@run1, $t / 2);
        }
    }
    return ($freq, 1, @run1);
}
sub ic2irkit {          # 内部表現 -> IRKit
    my ($freq, $repeat, @run) = @_;
    push (@run, 40000) if (@run % 2 != 0);
    $freq = ($freq > 39) ? 40 : 38;
    my ($clock) = 2;
    my ($r) = 0.5;
    my ($code)  = qq({);
    $code .= qq("format":"raw",);
    $code .= qq("freq":$freq,);
    $code .= qq("data":[);
    my ($delim) = "";
    while ($repeat-- > 0) {
        my (@run1) = @run;
        while (@run1) {
            my ($t) = shift (@run1) * $clock + $r;
            while ($t > 65535) {
                $code .= $delim . "65535,0";
                $delim = ",";
                $t -= 65535;
            }
            $code .= $delim . sprintf ("%d", int ($t));
            $delim = ",";
            $r = $t - int ($t);
        }
    }
    $code .= "]}";
    return ($code);
}
sub kurors2ic { # KURO-RS -> 内部表現
    my ($str) = shift (@_);
    $str =~ s/[^0-9a-f]//isg;
    return (-1, "kurors2ic: invalid form") if (length ($str) != 480);
    my ($data) = pack ("H*", $str);
    $data = unpack ("b1920", $data);
    my (@run) = map (length, $data =~ /(0+|1+)/g);
    @run = map { $_ *= 100; } @run;
    return (38, 1, @run)
}
sub ic2kurors { # 内部表現 -> KURO-RS
    my ($freq, $repeat, @run) = @_;
    push (@run, 40000) if (@run % 2 != 0);
    my ($clock) = 0.01;
    my ($r) = 0.5;
    my ($code) = "";
    my ($phase) = 1;
    while ($repeat-- > 0) {
        foreach (@run) {
            my ($t) = $_ * $clock + $r;
            $code .= $phase x $t;
            $r = $t - int ($t);
            $phase = 1 - $phase;
        }
    }
    $code = substr ($code . "0" x 1920, 0, 1920);
    $code = unpack ("H*", pack ("b1920", $code));
    return ($code);
}
sub gen2ic {    # generic -> 内部表現
    my (@run) = split (" ", shift (@_));
    if ($run[0] <= 0) {
        return (-1, "gen2ic: invalid form");
    }
    return (@run);
}
sub ic2gen {    # 内部表現 -> generic
    return (join (" ", @_));
}