6. リモコン信号の解析

黒豆や IRKit, KURO-RS, クロッサム2+ などのプログラマブルな学習リモコン (スマートリモコン) の信号データを、リモコン同士ツノつき合わせて学習させるのではなく、PC 上で理想的な波形に合成するためのノウハウです。

  1. 赤外線リモコンの信号定義データの合成 [表紙]
  2. 家製協フォーマットの信号データ合成
  3. NEC フォーマットの信号データ合成
  4. ソニーフォーマットの信号データ合成
  5. SHARP フォーマットの信号データ合成
  6. リモコン信号定義データの相互変換
  7. リモコン信号の解析 (このページ)
  8. メーカー純正リモコンのコード

このページでは、IRKit や KURO-RS を利用して簡便に機器付属のリモコン信号を解析するサンプルコードを紹介します。

6.1. リモコン信号の解析

汎用定義形式のデータから、リモコン信号のフォーマット (家製協/NEC/ソニー/SHARP) を判別し、デコードするための perl スクリプトです。アドホックな作りですが、そこそこの精度で解析できています。

  • 入力は、1行に定義データ一つの形式のテキストファイル。読めない行は黙って捨てる。
  • 出力は、各データを解析した結果が標準出力に書き出される。

使用例

IRKit で学習済みの定義データを解析する (irconvert は こちら を参照)

$ irconvert --in irkit 入力ファイル | iranalyze

黒豆でリモコン信号を次々に受信しながら解析する (broadlink_cli は こちら、irconvert は こちら を参照)

$ while (1)
>   broadlink_cli --device "0x2737 192.168.xx.xx xxxxxx" --learn | irconvert --in mame | iranalyze
> end

サンプルコード

#! /usr/bin/perl
#
#  Usage: iranalyze [infile ...]

while (<>) {
    chop;
    my (@run) = split (" ", $_);
    my ($freq) = shift (@run);
    my ($repeat) = shift (@run);
    next if ($freq + 0 <= 0);

    print &analyze (@run), "\n";
}

sub analyze {
    my (@run) = @_;
    my ($result) = "";

    # -- ヘッダ部の「1」の長さでフォーマット判別
    if ($run[0] <= 1200) {              # SHARPフォーマット (ヘッダなし)
        while (@run) {
            my ($t_on) = shift (@run); my ($t_off) = shift (@run);
            last if ($t_off > 3000);
            $code .= ($t_off > 1000) ? "1" : "0";
        }
        my ($len) = length ($code);
        goto unknown if ($len != 15);
        my ($id, $cmd, $exp, $chk) = ($code =~ /(.{5})(.{8})(.)(.)/);
        $result = sprintf ("sharp(%d): %d/%d/%d", $len, unpack ("SS", pack ("b16b16", $id, $cmd)), $exp);

    } elsif ($run[0] <= 2600) {         # ソニーフォーマット (仕様上は2400μsec)
        shift (@run); shift (@run);
        while (@run) {
            my ($t_on) = shift (@run); my ($t_off) = shift (@run);
            $code .= ($t_on > 900) ? "1" : "0";
            last if ($t_off > 3000);
        }
        my ($len) = length ($code);
        goto unknown if ($len != 12 && $len != 15 && $len != 20);
        my ($cmd, $id) = ($code =~ /(.{7})(.*)/);
        $result = sprintf ("sony(%d): %d/%d", $len, unpack ("SS", pack ("b16b16", $id, $cmd)));

    } elsif ($run[0] <= 4800) {         # 家製協フォーマット (仕様上は2800~4000μsec)
        shift (@run); shift (@run);
        while (@run) {
            my ($t_on) = shift (@run); my ($t_off) = shift (@run);
            last if ($t_off / $t_on > 10);
            $code .= ($t_off / $t_on > 2) ? "1" : "0";
        }
        my ($len) = length ($code);
        goto unknown if ($len % 8 != 0);
        $result = sprintf ("aeha(%d): ", $len);
        $result .= join (" ", unpack ("H2"x ($len / 8), pack ("b$len", $code)));

    } elsif ($run[0] <= 15000) {        # NECフォーマット (仕様上は9000μsec)
        shift (@run); shift (@run);
        while (@run) {
            my ($t_on) = shift (@run); my ($t_off) = shift (@run);
            last if ($t_off / $t_on > 5);
            $code .= ($t_off / $t_on > 2) ? "1" : "0";
        }
        my ($len) = length ($code);
        goto unknown if ($len != 32);
        $result = sprintf ("nec(%d): ", $len);
        $result .= join (" ", unpack ("H2"x 4, pack ("b32", $code)));

    } else {                            # 未知フォーマット
      unknown:
        $result = "unknown";
    }

    return $result;
}