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 # Set the initial (assumed) value of the pin as per user-config.
112 self.initial_pins = [1 if self.active == 0 else 0]
114 def metadata(self, key, value):
115 if key == srd.SRD_CONF_SAMPLERATE:
116 self.samplerate = value
117 self.margin = int(self.samplerate * 0.0001) - 1 # 0.1ms
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 handle_bit(self, tick):
126 if tick in range(self.dazero - self.margin, self.dazero + self.margin):
128 elif tick in range(self.daone - self.margin, self.daone + self.margin):
131 self.putb([0, ['%d' % ret]])
132 self.data |= (ret << self.count) # LSB-first
133 self.count = self.count + 1
134 self.ss_bit = self.samplenum
137 ret, name = (self.data >> 8) & (self.data & 0xff), self.state.title()
139 if self.state == 'ADDRESS':
140 self.addr = self.data
141 if self.state == 'COMMAND':
144 self.ss_start = self.samplenum
147 self.putd(self.data >> 8)
149 self.putx([12, ['%s error: 0x%04X' % (name, self.data)]])
150 self.data = self.count = 0
151 self.ss_bit = self.ss_start = self.samplenum
155 if not self.samplerate:
156 raise SamplerateError('Cannot decode without samplerate.')
158 # Wait for any edge (rising or falling).
159 (self.ir,) = self.wait({0: 'e'})
161 if self.ir != self.active:
162 # Save the non-active edge, then wait for the next edge.
163 self.ss_other_edge = self.samplenum
166 b = self.samplenum - self.ss_bit
169 if self.state == 'IDLE':
170 if b in range(self.lc - self.margin, self.lc + self.margin):
171 self.putpause('Long')
172 self.putx([5, ['Leader code', 'Leader', 'LC', 'L']])
173 self.ss_remote = self.ss_start
174 self.data = self.count = 0
175 self.state = 'ADDRESS'
176 elif b in range(self.rc - self.margin, self.rc + self.margin):
177 self.putpause('Short')
178 self.putstop(self.samplenum)
179 self.samplenum += self.stop
180 self.putx([10, ['Repeat code', 'Repeat', 'RC', 'R']])
181 self.data = self.count = 0
182 self.ss_bit = self.ss_start = self.samplenum
183 elif self.state == 'ADDRESS':
186 self.state = 'ADDRESS#' if self.data_ok() else 'IDLE'
187 elif self.state == 'ADDRESS#':
190 self.state = 'COMMAND' if self.data_ok() else 'IDLE'
191 elif self.state == 'COMMAND':
194 self.state = 'COMMAND#' if self.data_ok() else 'IDLE'
195 elif self.state == 'COMMAND#':
198 self.state = 'STOP' if self.data_ok() else 'IDLE'
199 elif self.state == 'STOP':
200 self.putstop(self.ss_bit)
202 self.ss_bit = self.ss_start = self.samplenum