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, see <http://www.gnu.org/licenses/>.
20 import sigrokdecode as srd
23 class SamplerateError(Exception):
26 class Decoder(srd.Decoder):
31 desc = 'NEC infrared remote control protocol.'
36 {'id': 'ir', 'name': 'IR', 'desc': 'Data line'},
39 {'id': 'polarity', 'desc': 'Polarity', 'default': 'active-low',
40 'values': ('active-low', 'active-high')},
44 ('agc-pulse', 'AGC pulse'),
45 ('longpause', 'Long pause'),
46 ('shortpause', 'Short pause'),
47 ('stop-bit', 'Stop bit'),
48 ('leader-code', 'Leader code'),
50 ('addr-inv', 'Address#'),
52 ('cmd-inv', 'Command#'),
53 ('repeat-code', 'Repeat code'),
55 ('warnings', 'Warnings'),
58 ('bits', 'Bits', (0, 1, 2, 3, 4)),
59 ('fields', 'Fields', (5, 6, 7, 8, 9, 10)),
60 ('remote', 'Remote', (11,)),
61 ('warnings', 'Warnings', (12,)),
65 self.put(self.ss_start, self.samplenum, self.out_ann, data)
68 self.put(self.ss_bit, self.samplenum, self.out_ann, data)
71 name = self.state.title()
72 d = {'ADDRESS': 6, 'ADDRESS#': 7, 'COMMAND': 8, 'COMMAND#': 9}
73 s = {'ADDRESS': ['ADDR', 'A'], 'ADDRESS#': ['ADDR#', 'A#'],
74 'COMMAND': ['CMD', 'C'], 'COMMAND#': ['CMD#', 'C#']}
75 self.putx([d[self.state], ['%s: 0x%02X' % (name, data),
76 '%s: 0x%02X' % (s[self.state][0], data),
77 '%s: 0x%02X' % (s[self.state][1], data), s[self.state][1]]])
79 def putstop(self, ss):
80 self.put(ss, ss + self.stop, self.out_ann,
81 [4, ['Stop bit', 'Stop', 'St', 'S']])
83 def putpause(self, p):
84 self.put(self.ss_start, self.ss_other_edge, self.out_ann,
85 [1, ['AGC pulse', 'AGC', 'A']])
86 idx = 2 if p == 'Long' else 3
87 self.put(self.ss_other_edge, self.samplenum, self.out_ann,
88 [idx, [p + ' pause', '%s-pause' % p[0], '%sP' % p[0], 'P']])
91 dev = address.get(self.addr, 'Unknown device')
92 buttons = command.get(self.addr, None)
94 btn = ['Unknown', 'Unk']
96 btn = buttons.get(self.cmd, ['Unknown', 'Unk'])
97 self.put(self.ss_remote, self.ss_bit + self.stop, self.out_ann,
98 [11, ['%s: %s' % (dev, btn[0]), '%s: %s' % (dev, btn[1]),
106 self.ss_bit = self.ss_start = self.ss_other_edge = self.ss_remote = 0
107 self.data = self.count = self.active = None
108 self.addr = self.cmd = None
111 self.out_ann = self.register(srd.OUTPUT_ANN)
112 self.active = 0 if self.options['polarity'] == 'active-low' else 1
114 def metadata(self, key, value):
115 if key == srd.SRD_CONF_SAMPLERATE:
116 self.samplerate = value
117 self.tolerance = 0.05 # +/-5%
118 self.lc = int(self.samplerate * 0.0135) - 1 # 13.5ms
119 self.rc = int(self.samplerate * 0.01125) - 1 # 11.25ms
120 self.dazero = int(self.samplerate * 0.001125) - 1 # 1.125ms
121 self.daone = int(self.samplerate * 0.00225) - 1 # 2.25ms
122 self.stop = int(self.samplerate * 0.000652) - 1 # 0.652ms
124 def compare_with_tolerance(self, measured, base):
125 return (measured >= base * (1 - self.tolerance)
126 and measured <= base * (1 + self.tolerance))
128 def handle_bit(self, tick):
130 if self.compare_with_tolerance(tick, self.dazero):
132 elif self.compare_with_tolerance(tick, self.daone):
135 self.putb([0, ['%d' % ret]])
136 self.data |= (ret << self.count) # LSB-first
137 self.count = self.count + 1
138 self.ss_bit = self.samplenum
141 ret, name = (self.data >> 8) & (self.data & 0xff), self.state.title()
143 if self.state == 'ADDRESS':
144 self.addr = self.data
145 if self.state == 'COMMAND':
148 self.ss_start = self.samplenum
151 self.putd(self.data >> 8)
153 self.putx([12, ['%s error: 0x%04X' % (name, self.data)]])
154 self.data = self.count = 0
155 self.ss_bit = self.ss_start = self.samplenum
159 if not self.samplerate:
160 raise SamplerateError('Cannot decode without samplerate.')
162 # Wait for any edge (rising or falling).
163 (self.ir,) = self.wait({0: 'e'})
165 if self.ir != self.active:
166 # Save the non-active edge, then wait for the next edge.
167 self.ss_other_edge = self.samplenum
170 b = self.samplenum - self.ss_bit
173 if self.state == 'IDLE':
174 if self.compare_with_tolerance(b, self.lc):
175 self.putpause('Long')
176 self.putx([5, ['Leader code', 'Leader', 'LC', 'L']])
177 self.ss_remote = self.ss_start
178 self.data = self.count = 0
179 self.state = 'ADDRESS'
180 elif self.compare_with_tolerance(b, self.rc):
181 self.putpause('Short')
182 self.putstop(self.samplenum)
183 self.samplenum += self.stop
184 self.putx([10, ['Repeat code', 'Repeat', 'RC', 'R']])
185 self.data = self.count = 0
186 self.ss_bit = self.ss_start = self.samplenum
187 elif self.state == 'ADDRESS':
190 self.state = 'ADDRESS#' if self.data_ok() else 'IDLE'
191 elif self.state == 'ADDRESS#':
194 self.state = 'COMMAND' if self.data_ok() else 'IDLE'
195 elif self.state == 'COMMAND':
198 self.state = 'COMMAND#' if self.data_ok() else 'IDLE'
199 elif self.state == 'COMMAND#':
202 self.state = 'STOP' if self.data_ok() else 'IDLE'
203 elif self.state == 'STOP':
204 self.putstop(self.ss_bit)
206 self.ss_bit = self.ss_start = self.samplenum