2 ## This file is part of the libsigrokdecode project.
4 ## Copyright (C) 2014 Gump Yang <gump.yang@gmail.com>
6 ## This program is free software; you can redistribute it and/or modify
7 ## it under the terms of the GNU General Public License as published by
8 ## the Free Software Foundation; either version 2 of the License, or
9 ## (at your option) any later version.
11 ## This program is distributed in the hope that it will be useful,
12 ## but WITHOUT ANY WARRANTY; without even the implied warranty of
13 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 ## GNU General Public License for more details.
16 ## You should have received a copy of the GNU General Public License
17 ## along with this program; if not, write to the Free Software
18 ## Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
21 import sigrokdecode as srd
24 class Decoder(srd.Decoder):
29 desc = 'NEC infrared remote control protocol.'
34 {'id': 'ir', 'name': 'IR', 'desc': 'Data line'},
37 {'id': 'polarity', 'desc': 'Polarity', 'default': 'active-low',
38 'values': ('active-low', 'active-high')},
42 ('agc-pulse', 'AGC pulse'),
43 ('longpause', 'Long pause'),
44 ('shortpause', 'Short pause'),
45 ('stop-bit', 'Stop bit'),
46 ('leader-code', 'Leader code'),
48 ('addr-inv', 'Address#'),
50 ('cmd-inv', 'Command#'),
51 ('repeat-code', 'Repeat code'),
53 ('warnings', 'Warnings'),
56 ('bits', 'Bits', (0, 1, 2, 3, 4)),
57 ('fields', 'Fields', (5, 6, 7, 8, 9, 10)),
58 ('remote', 'Remote', (11,)),
59 ('warnings', 'Warnings', (12,)),
63 self.put(self.ss_start, self.samplenum, self.out_ann, data)
66 self.put(self.ss_bit, self.samplenum, self.out_ann, data)
69 name = self.state.title()
70 d = {'ADDRESS': 6, 'ADDRESS#': 7, 'COMMAND': 8, 'COMMAND#': 9}
71 s = {'ADDRESS': ['ADDR', 'A'], 'ADDRESS#': ['ADDR#', 'A#'],
72 'COMMAND': ['CMD', 'C'], 'COMMAND#': ['CMD#', 'C#']}
73 self.putx([d[self.state], ['%s: 0x%02X' % (name, data),
74 '%s: 0x%02X' % (s[self.state][0], data),
75 '%s: 0x%02X' % (s[self.state][1], data), s[self.state][1]]])
77 def putstop(self, ss):
78 self.put(ss, ss + self.stop, self.out_ann,
79 [4, ['Stop bit', 'Stop', 'St', 'S']])
81 def putpause(self, p):
82 self.put(self.ss_start, self.ss_other_edge, self.out_ann,
83 [1, ['AGC pulse', 'AGC', 'A']])
84 idx = 2 if p == 'Long' else 3
85 self.put(self.ss_other_edge, self.samplenum, self.out_ann,
86 [idx, [p + ' pause', '%s-pause' % p[0], '%sP' % p[0], 'P']])
89 dev = address.get(self.addr, 'Unknown device')
90 buttons = command.get(self.addr, None)
92 btn = ['Unknown', 'Unk']
94 btn = buttons.get(self.cmd, ['Unknown', 'Unk'])
95 self.put(self.ss_remote, self.ss_bit + self.stop, self.out_ann,
96 [11, ['%s: %s' % (dev, btn[0]), '%s: %s' % (dev, btn[1]),
99 def __init__(self, **kwargs):
101 self.ss_bit = self.ss_start = self.ss_other_edge = self.ss_remote = 0
102 self.data = self.count = self.active = self.old_ir = None
103 self.addr = self.cmd = None
106 # self.out_python = self.register(srd.OUTPUT_PYTHON)
107 self.out_ann = self.register(srd.OUTPUT_ANN)
108 self.active = 0 if self.options['polarity'] == 'active-low' else 1
109 self.old_ir = 1 if self.active == 0 else 0
111 def metadata(self, key, value):
112 if key == srd.SRD_CONF_SAMPLERATE:
113 self.samplerate = value
114 self.margin = int(self.samplerate * 0.0001) - 1 # 0.1ms
115 self.lc = int(self.samplerate * 0.0135) - 1 # 13.5ms
116 self.rc = int(self.samplerate * 0.01125) - 1 # 11.25ms
117 self.dazero = int(self.samplerate * 0.001125) - 1 # 1.125ms
118 self.daone = int(self.samplerate * 0.00225) - 1 # 2.25ms
119 self.stop = int(self.samplerate * 0.000652) - 1 # 0.652ms
121 def handle_bit(self, tick):
123 if tick in range(self.dazero - self.margin, self.dazero + self.margin):
125 elif tick in range(self.daone - self.margin, self.daone + self.margin):
128 self.putb([0, ['%d' % ret]])
129 self.data |= (ret << self.count) # LSB-first
130 self.count = self.count + 1
131 self.ss_bit = self.samplenum
134 ret, name = (self.data >> 8) & (self.data & 0xff), self.state.title()
136 if self.state == 'ADDRESS':
137 self.addr = self.data
138 if self.state == 'COMMAND':
141 self.ss_start = self.samplenum
144 self.putd(self.data >> 8)
146 self.putx([12, ['%s error: 0x%04X' % (name, self.data)]])
147 self.data = self.count = 0
148 self.ss_bit = self.ss_start = self.samplenum
151 def decode(self, ss, es, data):
152 if self.samplerate is None:
153 raise Exception("Cannot decode without samplerate.")
154 for (self.samplenum, pins) in data:
157 # Wait for an "interesting" edge, but also record the other ones.
158 if self.old_ir == self.ir:
160 if self.ir != self.active:
161 self.ss_other_edge = self.samplenum
162 self.old_ir = self.ir
165 b = self.samplenum - self.ss_bit
168 if self.state == 'IDLE':
169 if b in range(self.lc - self.margin, self.lc + self.margin):
170 self.putpause('Long')
171 self.putx([5, ['Leader code', 'Leader', 'LC', 'L']])
172 self.ss_remote = self.ss_start
173 self.data = self.count = 0
174 self.state = 'ADDRESS'
175 elif b in range(self.rc - self.margin, self.rc + self.margin):
176 self.putpause('Short')
177 self.putstop(self.samplenum)
178 self.samplenum += self.stop
179 self.putx([10, ['Repeat code', 'Repeat', 'RC', 'R']])
180 self.data = self.count = 0
181 self.ss_bit = self.ss_start = self.samplenum
182 elif self.state == 'ADDRESS':
185 self.state = 'ADDRESS#' if self.data_ok() else 'IDLE'
186 elif self.state == 'ADDRESS#':
189 self.state = 'COMMAND' if self.data_ok() else 'IDLE'
190 elif self.state == 'COMMAND':
193 self.state = 'COMMAND#' if self.data_ok() else 'IDLE'
194 elif self.state == 'COMMAND#':
197 self.state = 'STOP' if self.data_ok() else 'IDLE'
198 elif self.state == 'STOP':
199 self.putstop(self.ss_bit)
201 self.ss_bit = self.ss_start = self.samplenum
204 raise Exception('Invalid state: %s' % self.state)
206 self.old_ir = self.ir