1. 家製協フォーマットの信号データ合成

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

  1. 赤外線リモコンの信号定義データの合成 [表紙]
  2. 家製協フォーマットの信号データ合成 (このページ)
  3. NEC フォーマットの信号データ合成
  4. ソニーフォーマットの信号データ合成
  5. 黒豆, IRKit, KURO-RS によるリモコン信号の解析
  6. 機器付属リモコンのコード

このページでは家製協フォーマットを取り上げます。

1.1. リモコン信号の詳細

「家製協 (家電製品協会/AEHA) フォーマット」と呼ばれているもの。

フォーマット

+-----------------------------------------------------
| リーダー部 | データ部          | トレーラー部 | ...
+-----------------------------------------------------

リーダー部

ON(8T)→OFF(4T)
Tは0.35〜0.5msecと規定されている。典型的には中央値0.425msecを使用する。

データ部

3バイト以上・任意バイト数の送信データ。各バイトはLSB first。
データ「0」は ON(1T)→OFF(1T)
データ「1」は ON(1T)→OFF(3T)

なお、データの内容は

  • 1〜2バイト目がカスタムコード (ベンダー/機器の識別)
  • 3バイト目以降がデータコード (コマンド等)

である。コードの具体的な値 (Panasonic 製デジタルチューナーの例) は後述。

トレーラー部

ON(1T)→OFF(nn)
nnは8msec以上と規定されている。後述する Panasonic 製デジタルチューナー付属のリモコンの場合は約75msec。

キャリア周波数

赤外線 LED の発光時 (ON時) の点滅周波数。
33〜40kHzが推奨されている。典型的には中央値に近い36.7kHzを使用する。

1.2. RM mini3 / eRemote mini 用信号定義データへの変換方法

この節は以下のページを参考にしました。

データ形式

家製協フォーマットの Broadlink RM mini3 (通称「黒豆」), LinkJapan eRemote mini 用信号定義データは以下のようになる。

26          ; おまじない
00          ; 信号送出の繰り返し回数 (0=単発, 1=2回送出, ...)
66 00       ; この後に続くバイト数 (little endian)。102バイト=0x0066バイト

6f 37       ; リーダー。ON(8T)→OFF(4T)、T=425msec
              ONが0x6fクロック続いた後、OFFが0x37クロック続く
              クロック周波数は (269/8192)GHz
                [8T=8*425msec*(269/8192)GHz=111.6≒0x6f]
0d 0d       ; データ「0」。ON(1T)→OFF(1T)
0d 29       ; データ「1」。ON(1T)→OFF(3T)
  :             (ビット数分続く)
0d 00 0d 05 ; トレーラー。ON(1T)→OFF(nnT)
            ; OFF部分は0x00 0x0d 0x05で固定

サンプルコード

送信データを家製協フォーマットにエンコードする perl のサンプルコードを示す。

#! /usr/bin/perl
# データはコマンド行引数に16進数の列で与える
@data = map { hex($_) & 0xff } @ARGV;

# データを0/1列に変換
$bytes = scalar (@data); $bits = $bytes * 8;
$data = unpack ("b$bits", pack ("C" x $bytes, @data));

# 出力の作成
$t = 425.0 * 269 / 8192;         # T=0.425ms

# パケットヘッダ
$code  = "26\n00\n";
$code .= sprintf ("%02x %02x\n", ($bits * 2 + 6) % 256, ($bits * 2 + 6) / 256);

# 信号部
# --- リーダー部 ON(8T)->OFF(4T)
$code .= sprintf ("%02x %02x\n", 8 * $t, 4 * $t);

# --- データ部 0:ON(1T)->OFF(1T), 1:ON(1T)->OFF(3T)
foreach $bit (split ("", $data)) {
    if ($bit eq "0") {
        $code .= sprintf ("%02x %02x\n", 1 * $t, 1 * $t);
    } else {
        $code .= sprintf ("%02x %02x\n", 1 * $t, 3 * $t);
    }
}

# --- トレーラー部 ON(1T)->OFF(NNmsec)
$code .= sprintf ("%02x 00 0d 05\n", 1 * $t);

# ベタ書きにしたいとき
# $code =~ s/\s//sg;
# $code .= "\n";

# 画面に出力
print $code;

# 黒豆に直接コマンド発行 (python-broadlinkを利用)
# $code =~ s/\s//sg;
# $device = "0x2737 192.168.xx.xx yyyyyyyyyyyy";    # broadlink_discoverの返値
# system "broadlink_cli --device '$device' --send '$code'";

このようにして作成したデータを、python-broadlink, BlackBeanControl 等で黒豆に転送する。

1.3. IRKit 用信号定義データへの変換方法

データ形式

家製協フォーマットの IRKit 用信号定義データは以下のようになる (キャリア周波数 38kHz、T=0.425msec、トレーラー長 75msecの場合)。IRKit に関する詳細な技術情報は 公式サイト を参照のこと。

{                : JSON形式
"format":"raw",  ; 定数
"freq":38,       ; キャリア周波数。38と40しかないので38を選ぶ。
"data":[         ; ここから信号データ。
6800,3400,       ; リーダー。ON(8T)→OFF(4T)。
                 ;  [0.425msec*2MHz*8=6800, 0.425msec*2MHz*4=3400]
850,850,         ; データ「0」のとき。ON(1T)→OFF(1T)
850,2550,        ; データ「1」のとき。ON(1T)→OFF(3T)
                 ; (送信データのビット数分続く)
850,2550,
850,65535,       ; トレーラー。ON(1T)→OFF(75msec)
0,65535,         ;  [75msec*2MHz=150000=65535+65535+18930]
0,18930
]}               ; JSONおわり

サンプルコード

送信データを家製協フォーマットにエンコードする perl のサンプルコードを示す。

#! /usr/bin/perl
# データはコマンド行引数に16進数の列で与える
@data = map { hex($_) & 0xff } @ARGV;

# データを0/1列に変換
$bytes = scalar (@data); $bits = $bytes * 8;
$data = unpack ("b$bits", pack ("C" x $bytes, @data));

# 出力の作成
$f = 38;                # キャリア周波数は38kHz (IRKitには38と40しかない)
$t = 0.425 * 2000;      # T=0.425msec
$len = 135 * 2000;      # 1送信単位を135msecとする

# JSON open
$json  = qq({\n);
$json .= qq("format":"raw",\n);
$json .= qq("freq":$f,\n);
$json .= qq("data":[\n);

# リーダー部 ON(8T)->OFF(4T)
$json .= (8 * $t) . "," . (4 * $t) . ",\n";
$len -= 12 * $t;

# データ部 0:ON(1T)->OFF(1T), 1:ON(1T)->OFF(3T)
foreach $bit (split ("", $data)) {
    if ($bit eq "0") {
        $json .= (1 * $t) . "," . (1 * $t) . ",\n";
        $len -= 2 * $t;
    } else {
        $json .= (1 * $t) . "," . (3 * $t) . ",\n";
        $len -= 4 * $t;
    }
}

# トレーラー部 ON(1T)->OFF(Nmsec) Nはここまでの全体が1送信単位(135msec)になるように決める
$json .= (1 * $t) . ",";
$len -= 1 * $t;
$len = 8 * 2000 if ($len < 8 * 2000); # 最小8msec
while ($len > 0) {
    if ($len >= 65536) {
        $json .= "65535,\n0,";
        $len -= 65535;
    } else {
        $json .= "$len\n";
        last;
    }
}

# JSON close
$json .= "]}\n";

# ベタ書きにしたいとき
#$json =~ s/\n//sg;
#$json .= "\n";

# 画面に出力
print $json;

# IRKitに直接コマンド発行
#$json =~ s/\n//sg;
#system qq(curl -s -i 'http://192.168.xx.xx/messages' -d '$json');

このようにして作成したデータを、http POST プロトコルで IRKit に送信する。

1.4. KURO-RS / PC-OP-RS1用信号定義データへの変換方法

データ形式

KURO-RS (玄人志向) および PC-OP-RS1 (Buffalo) の信号定義データは、10kHz (0.1msecごと) でサンプリングした LED ON/OFF の raw データを192msec分 (1920ビット) のフレームにパックして与える。キャリア周波数は指定できない。

111111111111     ; ON  1.2msec
0000             ; OFF 0.4msec
1111111111       ; ON  1.0msec
000000           ; OFF 0.6msec
  :
0000000000       ; 全体が1920ビットになるようにパディング

サンプルコード

送信データを家製協フォーマットにエンコードする perl のサンプルコードを示す。

#! /usr/bin/perl
# データはコマンド行引数に16進数の列で与える
@data = map { hex($_) & 0xff } @ARGV;

# データを0/1列に変換
$bytes = scalar (@data); $bits = $bytes * 8;
$data = unpack ("b$bits", pack ("C" x $bytes, @data));

# リーダー部 ON(8T)->OFF(4T)   T = 0.4msec
$raw = "1" x 32 . "0" x 16;

# データ部 0:ON(1T)->OFF(1T), 1:ON(1T)->OFF(3T)
$b[0] = "1" x 4 . "0" x 4;
$b[1] = "1" x 4 . "0" x 12;
$data =~ s/./$b[$&]/ge;
$raw .= $data;

# トレーラー部 ON(1T)->OFF(Nmsec) Nはここまでの全体が1送信単位(192msec)になるように決める
$raw .= "1" x 4;
$raw = substr ($raw . "0" x 1920, 0, 1920);

# 画面に出力 (1/0列のまま)
print $raw, "\n";

# バイナリに変換
$raw = pack ("b1920", $raw)

このようにして作成したデータを、KURO-RS 等が接続された USB シリアルポートにコマンドと共に送信する。

1.5. クロッサム2+ 用信号定義データへの変換方法

データ形式

家製協フォーマットのクロッサム2+ 用信号定義データは以下のようになる (キャリア周波数 36.7kHz、T=0.425msec、トレーラー長 75msecの場合)。

00            ; おまじない。
04            ; 信号波形定義の数。
                ひと組の波形定義で「ON→OFF→」の一周期分を定義する。
22            ; キャリア周波数を決める分周比
                 [2.5MHz/36.7kHz/2=34.1≒0x22]。
              ; --- ここから信号波形定義 ---
260400 260400 ; データ「0」の波形。ON(1T)→OFF(1T)、すなわち
                ONが0x000426クロック継続したあとOFFが0x000426クロック継続
                 [1T=0.425msec*2.5MHz=1062.5≒0x426]。
260400 730c00 ; データ「1」の波形。ON(1T)→OFF(3T)。
342100 9a1000 ; リーダーの波形。ON(8T)→OFF(4T)。
260400 6cdc02 ; トレーラーの波形。ON(1T)→OFF(75msec)。
              ; --- ここから送信信号の定義 ---
2             ; リーダー (波形「2」)
01101001      ; データ1バイト目 (0=波形「0」/1=波形「1」)
10010110      ; 2バイト目
01101001      ; 3バイト目
  :
10010110      ; nバイト目
3             ; トレーラー (波形「3」)
feXX          ; 直前のXX波形を永久に繰り返す、という制御コード。
                XXには直前の「2...3」の文字数を入れる。
                これにより、ボタンを押している間リーダー〜トレーラーの信号が出続ける。

サンプルコード

送信データを家製協フォーマットにエンコードする perl のサンプルコードを示す。

#! /usr/bin/perl
sub b8 {
    local($_) = shift;
    return join("", reverse(split("", sprintf("%08b", $_))));
}
sub hh3 {
    local($_) = shift;
    return join("", (split("", sprintf("%06x", $_)))[4,5,2,3,0,1]);
}

# データはコマンド行引数に16進数の列で与える
@data = map { hex($_) & 0xff } @ARGV;

# 出力の作成
$f = 2500 / 36.7 / 2;   # キャリア周波数は36.7kHz
$t = 0.425 * 2500;      # T=0.425msec
$nn = 75 * 2500;        # トレーラー長は75msec
$out = "00\n";
$out .= "04\n";
$out .= sprintf("%02x\n", $f);
$out .= hh3(1*$t)." ".hh3(1*$t)."\n";
$out .= hh3(1*$t)." ".hh3(3*$t)."\n";
$out .= hh3(8*$t)." ".hh3(4*$t)."\n";
$out .= hh3(1*$t)." ".hh3($nn)."\n";
$out .= "2\n";
foreach (@data) {
    $out .= b8($_)."\n";
}
$out .= "3\n";
$out .= sprintf("fe%02x\n", @data * 8 + 2);

# ベタ書きにしたいとき (クロッサム・エクスプローラ風)
#$out =~ s/[^0-9a-f]//g;
#$out .= "\n";

# バイトごとに分かち書きしたいとき (Sweet Memories風)
#$out =~ s/[^0-9a-f]//g;
#$out =~ s/(..)/$&,/g;
#$out =~ s/.*/"$&"\n/;

print $out;

このようにして作成したデータを、Sweet Memories 等によりクロッサム2+ に転送する。

1.6. 例: Panasonic 製デジタルチューナー [TU-MHD500] のリモコンコード

全体構成

カスタムコードを含め、6バイトで構成されている。

  • 1〜4バイト目は「02 20 80 0f」で固定。
  • 5バイト目は、リモコンのボタンごとに異なる機能コード (下記)。
  • 6バイト目は、3〜5バイト目のパリティ。

各ボタンの機能コード

コード ボタン コード ボタン コード ボタン
50 画面表示 74 チャンネル+ b0 (CS) 1
52 戻る 75 チャンネル- b1 (CS) 2
53 決定 76 前選局 b2 (CS) 3
54 メニュー 77 お好み選局 b3 (CS) 4
55 番組表 80 音声切替 b4 (CS) 5
56 文字クリア 81 字幕 b5 (CS) 6
58 番組内容 85 番組ナビ b6 (CS) 7
5a カーソル← 87 便利機能 b7 (CS) 8
5b カーソル→ 89 文字切替 b8 (CS) 9
5d カーソル ↑ 8a Tnavi b9 (CS) 10/0
5e カーソル ↓ 8b ネット操作 ba (CS) 11/*
5f 元の画面 8d 電源 bb (CS) 12/#
60 1 90 データ/d c0 (地上D) 1
61 2 91 c1 (地上D) 2
62 3 92 c2 (地上D) 3
63 4 93 c3 (地上D) 4
64 5 94 c4 (地上D) 5
65 6 9e 機器操作 c5 (地上D) 6
66 7 a0 (BS) 1 c6 (地上D) 7
67 8 a1 (BS) 2 c7 (地上D) 8
68 9 a2 (BS) 3 c8 (地上D) 9
69 10/0 a3 (BS) 4 c9 (地上D) 10/0
6a 地上 a4 (BS) 5 ca (地上D) 11/*
6b BS a5 (BS) 6 cb (地上D) 12/#
6c CS 1/2 a6 (BS) 7    
6f 11/# a7 (BS) 8    
70 12/* a8 (BS) 9    
71 チャンネル番号入力 a9 (BS) 10/0    
72 放送切替 aa (BS) 11/*    
73 サービス切替 ab (BS) 12/#    

参考

上記各 perl スクリプトの入力部分、すなわち

# データはコマンド行引数に16進数の列で与える
@data = map { hex($_) & 0xff } @ARGV;

の部分を以下のように改変すれば、機能コードを与えるだけで特定ボタンのリモコン信号定義を自動生成できる。

# 機能コードはコマンド行引数に16進数1個で与える
@data = ( 0x02, 0x20, 0x80, 0x0f, hex(shift) & 0xff );
$data[5] = $data[2] ^ $data[3] ^ $data[4];    # 6バイト目はパリティ