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]),
103 self.ss_bit = self.ss_start = self.ss_other_edge = self.ss_remote = 0
104 self.data = self.count = self.active = None
105 self.addr = self.cmd = None
108 self.out_ann = self.register(srd.OUTPUT_ANN)
109 self.active = 0 if self.options['polarity'] == 'active-low' else 1
111 def metadata(self, key, value):
112 if key == srd.SRD_CONF_SAMPLERATE:
113 self.samplerate = value
114 self.tolerance = 0.05 # +/-5%
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 compare_with_tolerance(self, measured, base):
122 return (measured >= base * (1 - self.tolerance)
123 and measured <= base * (1 + self.tolerance))
125 def handle_bit(self, tick):
127 if self.compare_with_tolerance(tick, self.dazero):
129 elif self.compare_with_tolerance(tick, self.daone):
132 self.putb([0, ['%d' % ret]])
133 self.data |= (ret << self.count) # LSB-first
134 self.count = self.count + 1
135 self.ss_bit = self.samplenum
138 ret, name = (self.data >> 8) & (self.data & 0xff), self.state.title()
140 if self.state == 'ADDRESS':
141 self.addr = self.data
142 if self.state == 'COMMAND':
145 self.ss_start = self.samplenum
148 self.putd(self.data >> 8)
150 self.putx([12, ['%s error: 0x%04X' % (name, self.data)]])
151 self.data = self.count = 0
152 self.ss_bit = self.ss_start = self.samplenum
156 if not self.samplerate:
157 raise SamplerateError('Cannot decode without samplerate.')
159 # Wait for any edge (rising or falling).
160 (self.ir,) = self.wait({0: 'e'})
162 if self.ir != self.active:
163 # Save the non-active edge, then wait for the next edge.
164 self.ss_other_edge = self.samplenum
167 b = self.samplenum - self.ss_bit
170 if self.state == 'IDLE':
171 if self.compare_with_tolerance(b, self.lc):
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 self.compare_with_tolerance(b, self.rc):
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