赤外線リモコン信号の解析アプリケーション

リモコン信号の信号解析アプリケーション

信号解析アプリケーション

以前に用意したアプリケーションのおまけに解析器を付けておきました。
メニューのInfra-redページでリモコン信号をコピペすると確認できます。

注: ↑は成り行きで追加していたらいつの間にかフロントヘビーに育ってしまったので今度分割します。

React Native for Windowsを使ってデスクトップアプリにしました。
このページへどうぞ。

三菱電機とパナソニック製エアコンのリモコン信号を解析する

三菱電機とパナソニック製エアコンのリモコン信号の資料 on GitHub

三菱電機とパナソニック製エアコンのリモコン信号の資料が GitHub にあるのを見つけたので, それを解析するソフトウェアを実装した。

三菱電機製エアコンの信号解析

資料によると第1フレームと第2フレームは共通の信号なので片方を解析すればよいようだ。

フレームは18バイト。

ということのようですね。

自分は三菱電機製エアコンを持っていないから, 三菱電機製エアコンの部分はネットで拾ってきたコードなので正確な所はよくわからない。

Qiitaで拾ってきた三菱電機製エアコン冷房27度 オンのコードらしい。
pigpioのirrp.py形式

JSON
{"ac:cool27": [3452, 1665, 449, 1271, 449, 1271, 449, 411, 449, 411, 449, 411, 449, 1271, 449, 411, 449, 411, 449, 1271, 449, 1271, 449, 411, 449, 1271, 449, 411, 449, 411, 449, 1271, 449, 1271, 449, 411, 449, 1271, 449, 1271, 449, 411, 449, 411, 449, 1271, 449, 411, 449, 411, 449, 1271, 449, 411, 449, 411, 449, 411, 449, 411, 449, 411, 449, 411, 449, 411, 449, 411, 449, 411, 449, 411, 449, 411, 449, 411, 449, 411, 449, 411, 449, 411, 449, 411, 449, 411, 449, 411, 449, 411, 449, 411, 449, 1271, 449, 411, 449, 411, 449, 411, 449, 411, 449, 411, 449, 1271, 449, 1271, 449, 411, 449, 411, 449, 411, 449, 1271, 449, 1271, 449, 411, 449, 1271, 449, 411, 449, 411, 449, 411, 449, 411, 449, 411, 449, 1271, 449, 1271, 449, 411, 449, 1271, 449, 1271, 449, 411, 449, 411, 449, 411, 449, 411, 449, 411, 449, 1271, 449, 411, 449, 411, 449, 1271, 449, 411, 449, 411, 449, 411, 449, 411, 449, 411, 449, 411, 449, 411, 449, 411, 449, 411, 449, 411, 449, 411, 449, 411, 449, 411, 449, 411, 449, 411, 449, 411, 449, 411, 449, 411, 449, 411, 449, 411, 449, 411, 449, 411, 449, 411, 449, 411, 449, 411, 449, 411, 449, 411, 449, 411, 449, 411, 449, 411, 449, 411, 449, 411, 449, 411, 449, 411, 449, 411, 449, 411, 449, 411, 449, 411, 449, 411, 449, 411, 449, 411, 449, 411, 449, 411, 449, 411, 449, 411, 449, 411, 449, 411, 449, 411, 449, 411, 449, 411, 449, 411, 449, 411, 449, 411, 449, 411, 449, 411, 449, 411, 449, 411, 449, 411, 449, 1271, 449, 1271, 449, 411, 449, 1271, 449, 411, 449, 1271, 449, 1271, 449, 13342, 3452, 1665, 449, 1271, 449, 1271, 449, 411, 449, 411, 449, 411, 449, 1271, 449, 411, 449, 411, 449, 1271, 449, 1271, 449, 411, 449, 1271, 449, 411, 449, 411, 449, 1271, 449, 1271, 449, 411, 449, 1271, 449, 1271, 449, 411, 449, 411, 449, 1271, 449, 411, 449, 411, 449, 1271, 449, 411, 449, 411, 449, 411, 449, 411, 449, 411, 449, 411, 449, 411, 449, 411, 449, 411, 449, 411, 449, 411, 449, 411, 449, 411, 449, 411, 449, 411, 449, 411, 449, 411, 449, 411, 449, 411, 449, 411, 449, 1271, 449, 411, 449, 411, 449, 411, 449, 411, 449, 411, 449, 1271, 449, 1271, 449, 411, 449, 411, 449, 411, 449, 1271, 449, 1271, 449, 411, 449, 1271, 449, 411, 449, 411, 449, 411, 449, 411, 449, 411, 449, 1271, 449, 1271, 449, 411, 449, 1271, 449, 1271, 449, 411, 449, 411, 449, 411, 449, 411, 449, 411, 449, 1271, 449, 411, 449, 411, 449, 1271, 449, 411, 449, 411, 449, 411, 449, 411, 449, 411, 449, 411, 449, 411, 449, 411, 449, 411, 449, 411, 449, 411, 449, 411, 449, 411, 449, 411, 449, 411, 449, 411, 449, 411, 449, 411, 449, 411, 449, 411, 449, 411, 449, 411, 449, 411, 449, 411, 449, 411, 449, 411, 449, 411, 449, 411, 449, 411, 449, 411, 449, 411, 449, 411, 449, 411, 449, 411, 449, 411, 449, 411, 449, 411, 449, 411, 449, 411, 449, 411, 449, 411, 449, 411, 449, 411, 449, 411, 449, 411, 449, 411, 449, 411, 449, 411, 449, 411, 449, 411, 449, 411, 449, 411, 449, 411, 449, 411, 449, 411, 449, 411, 449, 411, 449, 411, 449, 1271, 449, 1271, 449, 411, 449, 1271, 449, 411, 449, 1271, 449, 1271, 449]}
クリックして展開し、詳細を表示

運転: 冷房27度のコード
最後を見てみると

となっているので解析できてる様な気がするね。

運転: 暖房22度のコード

PLAINTEXT
850040001200320011003200120010001200110013000F00120032001100110012001100110032001200310013000F001200320011001100120011001300300013003000120011001100320013003000130010001100110013003000130010001200100013003000120011001300100013000F001200110012001100110011001200110012001100110011001200110013001000110011001300100012001000120011001300100011001100120011001300100011001100130030001200110012001000120011001200110011001100120031001300100013001000120010001200110012001000120032001100320011001100120011001200110011001100120011001200110011001100120011001200100012003100120032001200100012001100130010001100110012001100120010001200110013001000110032001100320013000F00130010001200110013000F00120011001200110013000F001200110012001100120010001200110012001100110011001200110012001000120011001300100013000F00120011001200110011001100120011001200110011001100120011001300100011001100120011001200100012001100130010001200100012001100120010001200110013003000120031001200110012001100120010001200110013000F001300100013001000120010001200110012001100110011001200110012001100110011001200110013001000120010001300100012001000120032001100320013000F00120031001300100013000F0012003100130010001200EE0184004200110032001300300012001100110011001200110012003100120010001200110013003000120031001300100012003100120011001100110012003100130030001300100012003100130030001200110013000F001200320011001100120011001100320013000F0013001000120011001100110013001000130010001100110012001100120011001100110013001000120011001100110012001100120010001200110012001100110011001200110012001000120031001200110012001100110011001200110013000F0012003200110011001300100013000F00120011001300100011003200120031001200110011001100120011001200110011001100130010001200100013001000120011001200310013003000120011001100110012001100120011001100110012001100120011001100110012003100120031001200110012001100110011001200110012001100120010001200110012001100110011001300100012001000120011001200110012001000120011001200110013000F00130010001200110011001100120011001200110011001100130010001200100012001100120011001100110013001000120011001100110012001100120010001200110012001100110032001200310012001100110011001300100013000F00120011001200110012001000120011001200110011001100120011001200110011001100120011001200110012001000120011001200100013001000120031001200310012001100110032001200100012001100120031001200110011004F03
クリックして展開し、詳細を表示

運転: 暖房22度のコード

停止: 暖房22度のコード

PLAINTEXT
850041001200310012003200110011001200110012001000130030001300100012001100110032001200310012001000120032001100110012001100120031001200310012001100110032001300300012001100110011001300300012001100120010001200310012001100120011001100110012001100120011001100110013001000120011001100110013001000120010001200110012001100120010001200110012001100110011001200110012001000120011001200110012001000120011001200110011001100130010001100320013000F00120011001200110013000F001300100012003100120031001200110012001100120010001300100013000F001300100013001000120010001200110013003000120031001300100012001000120011001200110012001000130010001200110011001100120031001200320013000F0012001100120011001100110012001100120010001200110013001000120010001200110013001000120010001300100012001100110011001300100013001000110011001200110012001000120011001300100013000F00120011001300100011001100120011001300100011001100120011001200110011001100130010001200100013001000120031001300300012001100120011001100110013001000130010001200100012001100120010001200110012001100110011001200110012001100110011001200110012001100110011001200110013000F0012003200120031001100110013003000120011001200310013000F00120011001200EE018400420011003200120031001200110012001000120011001100310013000F001200110012003100130030001200110013003000120011001100110012003100120031001300100012003100130030001200110012001000120031001300100012001100130030001200100012001100120011001200100012001100120011001100110012001100130010001200100012001100120010001300100013001000120010001200110012001000120011001200110012001000120011001200110011001100120011001300100013000F00130030001200110012001000120011001200110013000F001200310012003200110011001200110013001000120010001300100013000F00120011001200110013000F0013003000120032001200100012001100120010001200110012001100110011001200110012001000120032001300300012001000120011001200110012001000130010001200110013000F00120011001300100011001100120011001200110011001100120011001200100013001000130010001200100012001100120011001200100012001100130010001200100012001100130010001100110012001100120010001200110013001000110011001300100013000F001300100013003000120031001300100013001000110011001200110012001000120011001200110012001000120011001200110012001000130010001200110013000F001200110012001000120011001300100012001000120031001300310012001000130030001300100012003100130010001100110012004F03
クリックして展開し、詳細を表示

停止: 暖房22度のコード

運転: 冷房26度のコード

PLAINTEXT
8500410013003000130030001300100013000F0013001000130030001300100013000F00130030001300310012001000130030001300100013000F00130030001300310012001000130030001300310012001000130010001200310013000F0013001000130030001300100013000F00130010001300100013000F001300100013001000120010001300100013000F001300100014000F0013000F001300100013001000120010001300100013000F0013001000130010001200310013000F0013001000130010001200100013001000120031001300300013001000120010001300100013000F001300310012001000130030001300100013000F0014000F001300100013000F0013003000130031001200100013003000130030001300100013001000120010001300100013001000120010001300100013000F001300300013003100120010001300100013000F00130010001300100013000F00130010001300100013000F001300100013001000120010001300100013000F001300100014000F0013000F00130010001300100013000F0013001000130010001200100014000F0013001000120010001300100013001000120010001300100013000F001300100013000F0013001000130010001200310013000F0014000F0013001000120010001300100013001000120010001300100013000F00130010001300100013000F00130010001300100013000F0013001000130010001200100014000F0013000F00130030001300100013003000130010001200310013000F0013003000130010001300ED018500410012003100130030001300100012001000130010001300300013000F00130010001300300013003000130010001200310013000F00130010001300300014002F001300100013003000130030001300100013000F00130030001300100013000F0013003100120010001300100013000F00130010001300100013000F00130010001300100013000F001300100013001000120010001300100013000F001300100013001000120010001300100013000F0013001000130030001300100013000F00130010001300100013000F0014002F0013003100120010001300100013000F001300100014002F00130010001200310013000F001300100013001000120010001300100013003000130030001300100013003000130030001300100013000F001300100013001000120010001300100013001000120010001300300013003000130010001300100013000F001300100013001000120010001300100013000F00130010001300100013000F00130010001300100013000F001300100013001000120010001300100013001000120010001300100013000F00130010001300100013000F00130010001300100013000F001300100013001000120010001300100013000F001300100013000F0013003100120010001300100013001000120010001300100013000F00130010001300100013000F001300100013001000120010001300100013001000120010001300100013000F00130010001300100013000F0013003000130010001300300013000F001300300013001000130030001300100013004F03
クリックして展開し、詳細を表示

運転: 冷房26度のコード

パナソニック製エアコンの信号解析

資料によると第1フレームは共通の信号で, 第2フレームに個別の信号の2フレーム構成で出来ているようだ。

第1フレームは8バイトの共通の信号。
この2つは同じ信号だよ。実際のソースコードを見てみると分かるはず。

b1b2b3b4b5b6b7b8bit order
0220e00400000006LSB first
4004072000000060MSB first

第2フレームはLSB firstビットオーダーの信号で19バイト。

ということ。

実際のリモコンで確かめる

運転: 暖房23度, 風向: 自動, 風量: 自動

運転: 暖房23度, 風向: 自動, 風量: 自動

PLAINTEXT
840042000E0010000E0030000E0010000E0010000E0010000E000E000E0010000E0010000E000E000E0010000E0010000E0010000C0010000E0032000E000E000E0010000E0010000E0010000E000E000E0010000E0010000E0030000E0032000E0030000E0010000E000E000E0032000E0010000E000E000E0010000E0010000E000E000E0010000E0010000E0010000E000E000E0010000E0010000E000E000E0010000E0010000E000E0010000E000E0010000E0010000E000E000E0010000E0010000E000E0010000E000E0010000E0010000E000E000E0010000E0010000E000E0010000E000E0032000E0030000E0010000E000E0010000E000E0010000E0010000E007E01840040000E0010000E0032000E000E000E0010000E0010000E000E000E0010000E0010000E0010000E000E000E0010000E0010000E000E000E0032000E0010000E000E000E0010000E0010000E000E000E0010000E0010000E0030000E0032000E0030000E0010000E0010000E0030000E0010000E000E000E0010000E0010000E0010000E000E000E0010000E0010000E000E000E0010000E0010000E0010000E000E000E0032000E000E000E0010000E0010000E0010000E000E000E0032000E000E000E0010000E0032000E0030000E0030000E0010000E0032000E000E000E0010000E0010000E000E000E0010000E0010000E0010000E000E000E0010000E0030000E0032000E0030000E0032000E0030000E0010000E0030000E0010000E0030000E0010000E0010000E0010000E000E000E0010000E0010000E000E000E0010000E0010000E0010000E000E000E0010000E0010000E000E000E0010000E0010000E0010000E0030000E0030000E0010000E0010000E0010000E000E000E0010000E0010000E000E000E0010000E0010000E0010000E0030000E0030000E0010000E0010000E0010000E000E000E0010000E0010000E000E000E0010000E0010000E0010000E000E000E0010000E0010000E000E000E0010000E0010000E000E0010000E000E0010000E0010000E000E000E0010000E0010000E000E000E0032000E0010000E000E000E0010000E0010000E000E000E0010000E0010000E0010000E000E000E0032000E0030000E0010000E0010000E000E000E0010000E0010000E000E000E0010000E0010000E0010000E0030000E0010000E000E000E0032000E008E02
クリックして展開し、詳細を表示

運転: 暖房23度, 風向: 自動, 風量: 自動

運転: 冷房21度, 風向: 自動, 風量: 自動

運転: 冷房21度, 風向: 自動, 風量: 自動

PLAINTEXT
860042000E000E000E0032000E0010000E000E000E0010000E0010000E000E000E0010000E0010000E0010000E000E000E0010000E0010000E0030000E0010000E0010000E000E000E0010000E0010000E000E000E0010000E0032000E0030000E0030000E0010000E0010000E0030000E0010000E0010000E000E000E0010000E0010000E0010000E000E000E0010000E0010000E000E000E0010000E0010000E0010000E000E000E0010000E0010000E000E000E0010000E0010000E0010000E000E000E0010000E0010000E000E000E0010000E0010000E0010000E000E000E0010000E0010000E0030000E0032000E000E000E0010000E0010000E000E000E0010000E008001820042000E0010000E0030000E0010000E0010000E000E000E0010000E0010000E0010000C0010000E0010000E0010000E000E000E0010000E0030000E0010000E0010000E0010000E000E000E0010000E0010000E0010000E0030000E0030000E0032000E0010000E000E000E0032000E000E000E0010000E0010000E0010000E000E000E0010000E0010000E000E000E0010000E0010000E0010000E000E000E0010000E0030000E0010000E0010000E0010000E0030000E0030000E0010000E0010000E0010000E0030000E0010000E0030000E0010000E0030000E0010000E0010000E000E000E0010000E0010000E0010000E000E000E0010000E0010000E0030000E0032000E0030000E0030000E0032000E0010000E0030000E0010000E0030000E0010000E0010000E000E000E0010000E0010000E000E000E0010000E0010000E0010000E000E000E0010000E0010000E000E000E0010000E0010000E0010000E000E000E0032000E0030000E0010000E0010000E000E000E0010000E0010000E000E000E0010000E0010000E0010000E000E000E0032000E0030000E0010000E0010000E000E000E0010000E0010000E000E000E0010000E0010000E0010000E000E000E0010000E0010000E000E000E0010000E0010000E0010000E000E000E0010000E0010000E000E000E0010000E0010000E0010000E000E000E0032000E000E000E0010000E0010000E0010000E000E000E0010000E0010000E000E000E0010000E0032000E0030000E0010000E0030000E0010000E0010000E000E000E0010000E0010000E0030000E0032000E000E000E0010000E0010000E0030000E008E02
クリックして展開し、詳細を表示

運転: 冷房21度, 風向: 自動, 風量: 自動

停止: 冷房16度, 風向: 水平, 風量: 最大

停止信号を送るとディスプレイが消えたのでこの写真は運転状態の写真です。

停止: 冷房16度, 風向: 水平, 風量: 最大

PLAINTEXT
840042000E0010000E0030000E0010000E000E000E0010000E0010000E0010000E000E000E0010000E0010000E000E000E0010000E0010000E0030000E0010000E0010000E000E000E0010000E0010000E0010000E000E000E0032000E0030000E0032000E000E000E0010000E0030000E0010000E0010000E0010000E000E000E0010000E0010000E000E000E0010000E0010000E0010000E000E000E0010000E0010000E000E000E0010000E0010000E0010000E000E000E0010000E0010000E000E000E0010000E0010000E0010000C0010000E0010000E0010000E000E000E0010000E0010000E0030000E0032000E000E000E0010000E0010000E0010000E000E000E008001820042000E0010000E0030000E0010000E0010000E000E000E0010000E0010000E0010000E000E000E0010000E0010000E000E000E0010000E0032000E000E000E0010000E0010000E000E000E0010000E0010000E0010000E0030000E0030000E0032000E0010000E000E000E0032000E000E000E0010000E0010000E0010000E000E000E0010000E0010000E000E000E0010000E0010000E0010000C0010000E0010000E0010000E000E000E0010000E0010000E0030000E0032000E000E000E0010000E0010000E0010000E000E000E0010000E0010000E0030000E0010000E0010000E000E000E0010000E0010000E000E000E0010000E0010000E0010000E0030000E0030000E0010000E0010000E0010000E0030000E0030000E0032000E0010000E000E000E0010000E0010000E000E000E0010000E0010000E0010000E000E000E0010000E0010000E000E000E0010000E0010000E0010000E000E000E0010000E0010000E0030000E0032000E000E000E0010000E0010000E000E000E0010000E0010000E0010000E000E000E0010000E0010000E0030000E0032000E000E000E0010000E0010000E000E000E0010000E0010000E0010000E000E000E0010000E0010000E000E000E0010000E0010000E0010000E000E000E0010000E0010000E000E000E0010000E0010000E0010000E000E000E0010000E0010000E0030000E0010000E0010000E000E000E0010000E0010000E000E000E0010000E0010000E000E000E0032000E0030000E0010000E0010000E000E000E0010000E0010000E0030000E0032000E000E000E0010000C0030000E0032000E0010000E000E000E008E02
クリックして展開し、詳細を表示

停止: 冷房16度, 風向: 水平, 風量: 最大

以上で資料が正しいことを確認できた。

ダイキン工業製エアコンの信号解析

ページを分けました。
ダイキンエアコンのリモコン信号を解析する


解析対象のリモコン信号を入手

信号解析アプリケーションで解析するリモコン信号は以下の方法で手に入れてください。

パーサーがこれだから

赤外線リモコン信号の構造

アプリケーションノートより NEC, SIRC(SONY) フォーマット赤外線リモコン信号の構造を引用します。

NECフォーマット赤外線リモコン信号

Texas Instruments - Application Report SLAA644B
Infrared Remote Control Implementation With MSP430FR4xx1

より引用しました。

こんなインターネット上の文書より, SLAA644B1 アプリケーションノートを信用して欲しい。

1 Introduction

Figure1

中央の矢印で表現されている赤外線通信信号より左側が送信機, 右側が受信機。

5.1章で書かれている内容が NECフォーマット
この構造は家製協(AEHA)フォーマットも大筋で同じ

5.1 Pulse Distance Protocol

Pulse distance protocol is widely used by many appliances companies. It uses ASK modulation and pulse distance encoding with a carrier frequency of 38 kHz.

5.1.1 Frame Format

There are two kinds of frames in protocol: data frame and repeat frame.

A data frame consists of a leading code and data payload. The leading code is a burst with a length of 9 ms, followed by a pause of 4.5 ms. The data payload consists of 8 bits address to identify the device and 8 bits command for control words. Both are sent twice for reliability. The second transmission of address and command are complementary, therefore the total length of the data frame is constant (67.5 ms). The payload is finalized by a 560-µs carrier modulated tail pulse, to finish the last bit data gap.

Logic 1 is defined as a 560-µs carrier modulated period followed by a 1690-µs space period. Logic 0 is defined as a 560-µs carrier modulated period followed by a 560-µs space period (see Figure 12).

Figure12

A complete data frame format is shown in Figure 13.

Figure13

Repeat frame is defined to handle auto-repeat function and does not carry any address or command information. It includes train pulses and a tail pulse following (its format is shown in Figure 14). The repeat frame is repeated every 110 ms while the same key is still pressed.

Figure14

The full sequence format of pulse distance protocol is shown in Figure 15.

Figure15

SIRC(SONY)フォーマット赤外線リモコン信号

SLAA644B アプリケーションノートにはSIRCフォーマットが書かれていないので

Texas Instruments - Application Note AN091
RemoTI TM IR Signal Generation Application Note2

より引用しました。

3.4 SIRC Format

3.4.1 Modulation

The SIRC format uses a combination of the pulse distance and pulse width modulation technique. SIRC modulation is based on varying both the active period and duty cycle to distinguish between a logical “1” and a logical “0”. Note that the non-active period for both logical “1” and logical “0” is constant. Figure 7 below illustrates the principle of a combined pulse distance and pulse width modulation.

Figure7

SIRC format timing information:

  • Carrier: 40 kHz with 1/3 or 1/4 duty cycle
  • Active period:
    • Logical “0”: 600 µS
    • Logical “1”: 1.2 ms
  • Duty Cycle
    • Logical “0”: Active Period Logical “0” + 600 µS: 1.8 ms
    • Logical “1”: Active Period Logical “1” + 600 µS: 1.2 ms

3.4.2 Protocol

The SIRC protocol uses a 7-bit command and a 5-bit address length for each transfer. Other versions with different command and address length also exist. The command and address bits are preceded by a preamble with active period of 2.4 ms and duty cycle of 3 ms. The command and data bits are transferred with LSB first. See Figure 8 below for an illustration of the protocol.

Figure8

3.4.3 Repeat Sequence

The protocol described in Figure 8 is also used as the repeat pattern. This means initial frame and repeat frames are identical. The frame is repeated every 45 ms as long as the key remains pressed. See Figure 9 for an illustration of the repeat sequence.

Figure9

ざっと見ていると情報通信でおなじみの階層構造をなしているわけで。

NECフォーマットを例にして説明すると
送信機(リモコン)では情報(メッセージ)を

Figure12
Pulse Distance Protocol (または Pulse Position Modulation) によってエンコードして

を一つのフレームに組み立てて物理層に送る。

Figure13

物理層(伝送路3)では(NECフォーマットの場合)このように見える。

Figure15

ついでに

物理層(伝送路3)では(SIRCフォーマットの場合)このように見える。

Figure9

こういうものを情報通信用語で「カプセル化」といいますね。

赤外線リモコン信号を解析する

送信機でカプセル化された通信であるから, 受信側プログラムはその反対「非カプセル化」を行なえば元の情報が得られる。

これは PureScript4 で書いたソースコードで
このプログラムの動作は上で図示されている構造を解体。つまり「非カプセル化」するということ。

このプログラムはこの3段階で解体するように作りました。

ここで

リモコンから送信された物理層のASK5変調信号(アプリケーションノート参照)は受信側の赤外線受信モジュールによって包絡線6が取り出されているので, このプログラムはそれを入力とします。

この図をよく見て欲しい。

Figure1

余談だけれど, 取り扱っているデータを

のお話ね。

以下簡単に説明します。

データ型宣言

Count型
38kHzの時間での何カウントになるか
HASKELL
newtype Count = Count Int
derive newtype instance eqCount               :: Eq Count
derive newtype instance ordCount              :: Ord Count
derive newtype instance showCount             :: Show Count
derive newtype instance semiringCount         :: Semiring Count
derive newtype instance ringCount             :: Ring Count
derive newtype instance commutativeRingCount  :: CommutativeRing Count
derive newtype instance eucideanRingCount     :: EuclideanRing Count
クリックして展開し、詳細を表示

比較するためにクラス Eq, クラス Ord
表示するためにクラス Show
四則演算するためにクラス Semiring, クラス Ring, クラス CommutativeRing, クラス EuclideanRing
のインスタンスにしている。

Baseband型
パーサーからデコーダーに渡される中間表現であってON時間, OFF時間の配列。
HASKELL
type Pulse = {on :: Count, off :: Count}

-- |
newtype Baseband = Baseband (Array Pulse)
derive newtype instance eqBaseband    :: Eq Baseband
derive newtype instance showBaseband  :: Show Baseband
クリックして展開し、詳細を表示
Bit型
1ビットを表現する。

これは2値を表せたら表現は何でもよいんですけどね。
赤外線リモコン信号回路には負論理信号が混ざるので, 今回はAssert/Negateでいきます。

HASKELL
data Bit
  = Negate
  | Assert
クリックして展開し、詳細を表示
InfraredLeader
リーダー信号
AEHA | NEC | SIRC(SONY) | 不明のどれか
HASKELL
data InfraredLeader
  = LeaderAeha Pulse 
  | LeaderNec Pulse 
  | LeaderSirc Pulse 
  | LeaderUnknown Pulse 
クリックして展開し、詳細を表示

InfraredLeader のコンストラクタ

ON時間 / OFF時間からリーダー信号を得る
それぞれの判定に使う時間は参考リンクにある通りで, 許容誤差の上限下限を 0.2ms にしておいた。

HASKELL
makeInfraredLeader :: Pulse -> InfraredLeader 
makeInfraredLeader = case _ of
  p | aeha p    -> LeaderAeha p
    | nec p     -> LeaderNec p
    | sirc p    -> LeaderSirc p
    | otherwise -> LeaderUnknown p
  where

  -- | upper lower tolerance 0.2ms
  typical = withTolerance {upper: Milliseconds 0.2, lower: Milliseconds 0.2}

  -- | H-level width, typical 3.4ms
  -- | L-level width, typical 1.7ms
  aeha :: Pulse -> Boolean
  aeha pulse =
    let on_   = typical (Milliseconds 3.4)
        off_  = typical (Milliseconds 1.7)
    in
    (Array.any (_ == pulse.on) on_) && (Array.any (_ == pulse.off) off_)

  -- | H-level width, typical 9.0ms
  -- | L-level width, typical 4.5ms
  nec :: Pulse -> Boolean
  nec pulse =
    let on_   = typical (Milliseconds 9.0)
        off_  = typical (Milliseconds 4.5)
    in
    (Array.any (_ == pulse.on) on_) && (Array.any (_ == pulse.off) off_)

  -- | H-level width, typical 2.4ms
  -- | L-level width, typical 0.6ms
  sirc :: Pulse -> Boolean
  sirc pulse =
    let on_   = typical (Milliseconds 2.4)
        off_  = typical (Milliseconds 0.6)
    in
    (Array.any (_ == pulse.on) on_) && (Array.any (_ == pulse.off) off_)
クリックして展開し、詳細を表示
InfraredCode
赤外線リモコン信号。
正しい入力なら, 最後はこれに変換される。
HASKELL
data InfraredCode
  = Unknown (Array Bit)
  | AEHA {custom :: LsbFirst, parity :: LsbFirst, data0 :: LsbFirst, data :: Array LsbFirst, stop :: Bit}
  | NEC  {custom :: LsbFirst, data :: LsbFirst, invData :: LsbFirst, stop :: Bit}
  | SIRC {command :: LsbFirst, address :: LsbFirst}
クリックして展開し、詳細を表示

入力文字列のパーサー

参考リンクのADRSIR文書情報で定義された入力をデコーダーに渡す中間表現に変換する。

HASKELL
infraredHexStringParser:: Parser InfraredHexString Baseband
infraredHexStringParser = do
    arr <- Array.some (pulse <* skipSpaces)
    eof
    pure (Baseband arr)
  where

  pulse = do
    -- 入力値はon -> offの順番
    ton <- valueOf32Bit <?> "on-counts"
    toff <- valueOf32Bit <?> "off-counts"
    pure {on: Count ton, off: Count toff}

  valueOf32Bit = do
    -- 入力値はLower -> Higherの順番
    lower <- hexd16bit <?> "lower-pair hex digit"
    higher<- hexd16bit <?> "higher-pair hex digit"
    -- ここは普通の数字の書き方(位取り記数法: 高位が前, 下位が後)
    let str = higher <> lower
        maybeNum = Int.fromStringAs Int.hexadecimal str
    -- 入力値は検査済みなのでfromJustでよい
    pure (unsafePartial $ fromJust maybeNum)

  hexd16bit = do
    a <- hexDigit
    b <- hexDigit
    pure $ fromCharArray [ a, b ]
クリックして展開し、詳細を表示

デコーダー

中間表現から赤外線リモコン信号に変換する。
書いてある通りに Phase1, Phase2, Phase3 の3段階で砕く。

«<7 は関数合成演算子でHaskellの . ドット
traverse8 は Haskellの mapM
<=<9 はモナドの合成演算子でHaskellと同じ

HASKELL
decodeBaseband :: Baseband -> Either ProcessError (Array InfraredCode)
decodeBaseband =
  traverse (decodePhase3 <=< decodePhase2) <<< decodePhase1 
クリックして展開し、詳細を表示

デコード第1段階

リモコンから複数フレームが送られる事があるので, 1段目は入力を各フレームに変換する。
OFF時間 8ms継続でフレームを切り離す。
8msは参考リンクにある通りAEHA規格が根拠であるが, SIRC(SONY)規格でも有効。

HASKELL
decodePhase1 :: Baseband -> Array (Array Pulse)
decodePhase1 (Baseband bb) =
  unfoldr1 chop bb
  where

  chop :: Array Pulse -> Tuple (Array Pulse) (Maybe (Array Pulse))
  chop xs = 
    case frames xs of
      { init: a, rest: [] } -> Tuple a Nothing
      { init: a, rest: b_ } -> Tuple a (Just b_)

  frames :: Array Pulse -> {init :: Array Pulse, rest :: Array Pulse}
  frames pulses = 
    let sep = Array.span (\count -> count.off < threshold) pulses
    in
    { init: sep.init <> Array.take 1 sep.rest
    , rest: Array.drop 1 sep.rest
    }

  threshold :: Count
  threshold = fromMilliseconds (Milliseconds 8.0)
クリックして展開し、詳細を表示

デコード第2段階

入力フレームをリーダ部とビット配列にする

HASKELL
decodePhase2 :: Array Pulse -> Either ProcessError (Tuple InfraredLeader (Array Bit))
decodePhase2 tokens =
  case Array.uncons tokens of
    Just {head: x, tail: xs} ->
      let leader = makeInfraredLeader x
      in
      Right $ Tuple leader (demodulate leader xs)

    Nothing ->
      Left "Unexpected end of input"
クリックして展開し、詳細を表示

デコード第3段階

AEHA / NEC / SIRC / 不明 それぞれ対応する関数で変換する

HASKELL
decodePhase3 :: Tuple InfraredLeader (Array Bit) -> Either ProcessError InfraredCode
decodePhase3 (Tuple leader bitarray) =
  evalState (runExceptT decoder) bitarray
  where

  decoder :: DecodeMonad ProcessError InfraredCode
  decoder = case leader of
    LeaderAeha _    -> decodeAeha
    LeaderNec _     -> decodeNec
    LeaderSirc _    -> decodeSirc
    LeaderUnknown _ -> decodeUnknown
クリックして展開し、詳細を表示

デコード用モナド

HASKELL
type DecodeMonad e a = ExceptT e (State (Array Bit)) a
クリックして展開し、詳細を表示

この2つのモナドを合成している。

HASKELL
State (Array Bit)
クリックして展開し、詳細を表示

ここに書かれているとおりStateモナドのフィールドがビットの配列となっているので,

などのアクセッサーを通じてフィールドにアクセスすることになる。
この部分は他言語でいう Getter / Setter のこと。

Haskell / PureScript のようないわゆる純粋関数型言語では変数の取り扱いに特別の配慮が必要なんでこんなことになる。
純粋にこだわらない言語ではこんなめんどくさい事をしなくても普通に変数を使えばよいですね。

1ビットを取り出す

HASKELL
takeBit :: ProcessError -> DecodeMonad ProcessError Bit
takeBit errmsg = do
  state <- State.get
  case Array.uncons state of
    Nothing ->
      throwError errmsg

    Just x -> do
      State.put x.tail
      pure x.head
クリックして展開し、詳細を表示

ここでの動作は State.getでビット配列を取得して 取得したビット配列が

nビットを取り出す

HASKELL
takeBits :: Int -> ProcessError -> DecodeMonad ProcessError (NonEmptyArray Bit)
takeBits n errmsg = do
  state <- State.get
  let bitarray  = Array.take n state
      nextState = Array.drop n state
  State.put nextState
  maybe (throwError errmsg) pure do
    guard (Array.length bitarray == n)
    NEA.fromArray bitarray
クリックして展開し、詳細を表示

残りのビットをすべて取り出す

HASKELL
takeEnd :: ProcessError -> DecodeMonad ProcessError (NonEmptyArray Bit)
takeEnd errmsg = do
  array <- State.get
  State.put []
  maybe (throwError errmsg) pure $ NEA.fromArray array
クリックして展開し、詳細を表示

デコード (AEHA)

先頭から以下の順番で取り出す

  1. カスタムコード(16ビットlsb first)
  2. パリティ(4ビット lsb first)
  3. data0(4ビット lsb first)
  4. dataN(8ビット lsb first)
  5. ストップビット
HASKELL
aehaProtocol :: DecodeMonad ProcessError InfraredCode
aehaProtocol = do
  custom <- takeBits 16 "fail to read: custom code (AEHA)"
  parity <- takeBits 4 "fail to read: parity (AEHA)"
  data_0 <- takeBits 4 "fail to read: data0 (AEHA)"
  data_N <- takeEnd "fail to read: data (AEHA)"
  let init = NEA.init data_N
      last = NEA.last data_N
      octets = toArrayNonEmptyArray 8 init
  pure $ AEHA { custom: LsbFirst custom
              , parity: LsbFirst parity
              , data0: LsbFirst data_0
              , data: map LsbFirst octets
              , stop: last
              }
クリックして展開し、詳細を表示

デコード(NEC)

先頭から以下の順番で取り出す

  1. カスタムコード(16ビットlsb first)
  2. data(8ビット lsb first)
  3. dataの反転(8ビット lsb first)
HASKELL
necProtocol :: DecodeMonad ProcessError InfraredCode
necProtocol = do
  custom <- takeBits 16 "fail to read: custom code (NEC)"
  data__ <- takeBits 8 "fail to read: data (NEC)"
  i_data <- takeBits 8 "fail to read: inv-data (NEC)"
  stopbt <- takeBit "fail to read: stop bit (NEC)"
  pure $ NEC  { custom: LsbFirst custom
              , data: LsbFirst data__
              , invData: LsbFirst i_data
              , stop: stopbt
              }
クリックして展開し、詳細を表示

デコード(SIRC)

先頭から以下の順番で取り出す

  1. コマンド(7ビットlsb first)
  2. アドレス(5/8/13ビット lsb first)
  3. ストップビット
HASKELL
sircProtocol :: DecodeMonad ProcessError InfraredCode
sircProtocol = do
  comm <- takeBits 7 "fail to read: command code (SIRC)"
  addr <- takeEnd "fail to read: address (SIRC)"
  pure $ SIRC { command: LsbFirst comm
              , address: LsbFirst addr
              }
クリックして展開し、詳細を表示

赤外線リモコン信号の解析はこれでいいと思う。

さいごに

入力文字列が各段階で変換される様子を見ているのが上のページ。

フロントエンドはPureScriptで書いていますが, このプログラムの動作はまさにコレ

プログラミングはデータの変換をするものだ

—プログラミングElixir 第1.1章

参考文献

赤外線リモコン誕生記 - 特許を取れなかった技術,取らなかった技術

赤外線信号

ADRSIR

メーカーによるソフトウェアダウンロードページから

http://bit-trade-one.co.jp/support/download/

I2C仕様文書, リモコンコードCSVファイルをダウンロードする。

リモコンデーターの構造

1 赤外線データのON-OFF-ON-OFF…の時間を38kHzの時間での何カウントになるかを求めます
3.2msの場合は、3.2ms / 0.026ms(38kHz) = 123 (0x7B)

2 各カウント値を2バイトデータとして先頭からカウント値のLoバイト、Hiバイトの順番にデータを送信します

データ
送信データ長は、ON-OFFで1データとなります。よって、この場合のデータ長は8となります。
0x7B, 0x00, 0x3D, 0x00, 0x0F, 0x00, 0x0F, 0x00, 0x0F, 0x00, 0x2E, 0x00, 0x0F, 0x00, 0x0F, 0x00, 0x0F, 0x00, 0x0F, 0x00, 0x0F, 0x00, 0x2E, 0x00, 0x0F, 0x00, 0x2E, 0x00, 0x0F, 0x00, 0x0F, 0x00

ADRSIR I2C仕様文書

著作権表示

著者: Akihiro Yamamoto

リンク: https://ak1211.com/posts/7141/

ライセンス: CC BY-NC-SA 4.0

This work is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License. Please attribute the source, use non-commercially, and maintain the same license.

コメント

検索を開始

キーワードを入力して記事を検索

↑↓
ESC
⌘K ショートカット