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 SamplerateError(Exception):
27 class Decoder(srd.Decoder):
32 desc = 'NEC infrared remote control protocol.'
37 {'id': 'ir', 'name': 'IR', 'desc': 'Data line'},
40 {'id': 'polarity', 'desc': 'Polarity', 'default': 'active-low',
41 'values': ('active-low', 'active-high')},
45 ('agc-pulse', 'AGC pulse'),
46 ('longpause', 'Long pause'),
47 ('shortpause', 'Short pause'),
48 ('stop-bit', 'Stop bit'),
49 ('leader-code', 'Leader code'),
51 ('addr-inv', 'Address#'),
53 ('cmd-inv', 'Command#'),
54 ('repeat-code', 'Repeat code'),
56 ('warnings', 'Warnings'),
59 ('bits', 'Bits', (0, 1, 2, 3, 4)),
60 ('fields', 'Fields', (5, 6, 7, 8, 9, 10)),
61 ('remote', 'Remote', (11,)),
62 ('warnings', 'Warnings', (12,)),
66 self.put(self.ss_start, self.samplenum, self.out_ann, data)
69 self.put(self.ss_bit, self.samplenum, self.out_ann, data)
72 name = self.state.title()
73 d = {'ADDRESS': 6, 'ADDRESS#': 7, 'COMMAND': 8, 'COMMAND#': 9}
74 s = {'ADDRESS': ['ADDR', 'A'], 'ADDRESS#': ['ADDR#', 'A#'],
75 'COMMAND': ['CMD', 'C'], 'COMMAND#': ['CMD#', 'C#']}
76 self.putx([d[self.state], ['%s: 0x%02X' % (name, data),
77 '%s: 0x%02X' % (s[self.state][0], data),
78 '%s: 0x%02X' % (s[self.state][1], data), s[self.state][1]]])
80 def putstop(self, ss):
81 self.put(ss, ss + self.stop, self.out_ann,
82 [4, ['Stop bit', 'Stop', 'St', 'S']])
84 def putpause(self, p):
85 self.put(self.ss_start, self.ss_other_edge, self.out_ann,
86 [1, ['AGC pulse', 'AGC', 'A']])
87 idx = 2 if p == 'Long' else 3
88 self.put(self.ss_other_edge, self.samplenum, self.out_ann,
89 [idx, [p + ' pause', '%s-pause' % p[0], '%sP' % p[0], 'P']])
92 dev = address.get(self.addr, 'Unknown device')
93 buttons = command.get(self.addr, None)
95 btn = ['Unknown', 'Unk']
97 btn = buttons.get(self.cmd, ['Unknown', 'Unk'])
98 self.put(self.ss_remote, self.ss_bit + self.stop, self.out_ann,
99 [11, ['%s: %s' % (dev, btn[0]), '%s: %s' % (dev, btn[1]),
104 self.ss_bit = self.ss_start = self.ss_other_edge = self.ss_remote = 0
105 self.data = self.count = self.active = self.old_ir = None
106 self.addr = self.cmd = None
109 self.out_ann = self.register(srd.OUTPUT_ANN)
110 self.active = 0 if self.options['polarity'] == 'active-low' else 1
111 self.old_ir = 1 if self.active == 0 else 0
113 def metadata(self, key, value):
114 if key == srd.SRD_CONF_SAMPLERATE:
115 self.samplerate = value
116 self.margin = int(self.samplerate * 0.0001) - 1 # 0.1ms
117 self.lc = int(self.samplerate * 0.0135) - 1 # 13.5ms
118 self.rc = int(self.samplerate * 0.01125) - 1 # 11.25ms
119 self.dazero = int(self.samplerate * 0.001125) - 1 # 1.125ms
120 self.daone = int(self.samplerate * 0.00225) - 1 # 2.25ms
121 self.stop = int(self.samplerate * 0.000652) - 1 # 0.652ms
123 def handle_bit(self, tick):
125 if tick in range(self.dazero - self.margin, self.dazero + self.margin):
127 elif tick in range(self.daone - self.margin, self.daone + self.margin):
130 self.putb([0, ['%d' % ret]])
131 self.data |= (ret << self.count) # LSB-first
132 self.count = self.count + 1
133 self.ss_bit = self.samplenum
136 ret, name = (self.data >> 8) & (self.data & 0xff), self.state.title()
138 if self.state == 'ADDRESS':
139 self.addr = self.data
140 if self.state == 'COMMAND':
143 self.ss_start = self.samplenum
146 self.putd(self.data >> 8)
148 self.putx([12, ['%s error: 0x%04X' % (name, self.data)]])
149 self.data = self.count = 0
150 self.ss_bit = self.ss_start = self.samplenum
153 def decode(self, ss, es, data):
154 if not self.samplerate:
155 raise SamplerateError('Cannot decode without samplerate.')
156 for (self.samplenum, pins) in data:
159 # Wait for an "interesting" edge, but also record the other ones.
160 if self.old_ir == self.ir:
162 if self.ir != self.active:
163 self.ss_other_edge = self.samplenum
164 self.old_ir = self.ir
167 b = self.samplenum - self.ss_bit
170 if self.state == 'IDLE':
171 if b in range(self.lc - self.margin, self.lc + self.margin):
172 self.putpause('Long')
173 self.putx([5, ['Leader code', 'Leader', 'LC', 'L']])
174 self.ss_remote = self.ss_start
175 self.data = self.count = 0
176 self.state = 'ADDRESS'
177 elif b in range(self.rc - self.margin, self.rc + self.margin):
178 self.putpause('Short')
179 self.putstop(self.samplenum)
180 self.samplenum += self.stop
181 self.putx([10, ['Repeat code', 'Repeat', 'RC', 'R']])
182 self.data = self.count = 0
183 self.ss_bit = self.ss_start = self.samplenum
184 elif self.state == 'ADDRESS':
187 self.state = 'ADDRESS#' if self.data_ok() else 'IDLE'
188 elif self.state == 'ADDRESS#':
191 self.state = 'COMMAND' if self.data_ok() else 'IDLE'
192 elif self.state == 'COMMAND':
195 self.state = 'COMMAND#' if self.data_ok() else 'IDLE'
196 elif self.state == 'COMMAND#':
199 self.state = 'STOP' if self.data_ok() else 'IDLE'
200 elif self.state == 'STOP':
201 self.putstop(self.ss_bit)
203 self.ss_bit = self.ss_start = self.samplenum
206 self.old_ir = self.ir