]> sigrok.org Git - libsigrokdecode.git/blame - decoders/ir_nec/pd.py
atsha204a: Add the reset() method.
[libsigrokdecode.git] / decoders / ir_nec / pd.py
CommitLineData
5e6fa9cc
GY
1##
2## This file is part of the libsigrokdecode project.
3##
4## Copyright (C) 2014 Gump Yang <gump.yang@gmail.com>
5##
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.
10##
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.
15##
16## You should have received a copy of the GNU General Public License
4539e9ca 17## along with this program; if not, see <http://www.gnu.org/licenses/>.
5e6fa9cc
GY
18##
19
20import sigrokdecode as srd
12fecc8f 21from .lists import *
5e6fa9cc 22
21cda951
UH
23class SamplerateError(Exception):
24 pass
25
5e6fa9cc 26class Decoder(srd.Decoder):
5844bb0f 27 api_version = 3
00962e76
UH
28 id = 'ir_nec'
29 name = 'IR NEC'
30 longname = 'IR NEC'
31 desc = 'NEC infrared remote control protocol.'
5e6fa9cc
GY
32 license = 'gplv2+'
33 inputs = ['logic']
00962e76 34 outputs = ['ir_nec']
6a15597a 35 channels = (
5e6fa9cc 36 {'id': 'ir', 'name': 'IR', 'desc': 'Data line'},
bee57ee8
UH
37 )
38 options = (
39 {'id': 'polarity', 'desc': 'Polarity', 'default': 'active-low',
40 'values': ('active-low', 'active-high')},
fb1870b0 41 {'id': 'cd_freq', 'desc': 'Carrier Frequency', 'default': 0},
bee57ee8
UH
42 )
43 annotations = (
44 ('bit', 'Bit'),
45 ('agc-pulse', 'AGC pulse'),
46 ('longpause', 'Long pause'),
47 ('shortpause', 'Short pause'),
48 ('stop-bit', 'Stop bit'),
49 ('leader-code', 'Leader code'),
50 ('addr', 'Address'),
51 ('addr-inv', 'Address#'),
52 ('cmd', 'Command'),
53 ('cmd-inv', 'Command#'),
54 ('repeat-code', 'Repeat code'),
55 ('remote', 'Remote'),
56 ('warnings', 'Warnings'),
57 )
5e6fa9cc 58 annotation_rows = (
70835fd4
UH
59 ('bits', 'Bits', (0, 1, 2, 3, 4)),
60 ('fields', 'Fields', (5, 6, 7, 8, 9, 10)),
12fecc8f
UH
61 ('remote', 'Remote', (11,)),
62 ('warnings', 'Warnings', (12,)),
5e6fa9cc
GY
63 )
64
5e6fa9cc
GY
65 def putx(self, data):
66 self.put(self.ss_start, self.samplenum, self.out_ann, data)
67
68 def putb(self, data):
69 self.put(self.ss_bit, self.samplenum, self.out_ann, data)
70
70835fd4
UH
71 def putd(self, 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]]])
79
80 def putstop(self, ss):
81 self.put(ss, ss + self.stop, self.out_ann,
82 [4, ['Stop bit', 'Stop', 'St', 'S']])
83
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']])
90
12fecc8f
UH
91 def putremote(self):
92 dev = address.get(self.addr, 'Unknown device')
93 buttons = command.get(self.addr, None)
94 if buttons is None:
95 btn = ['Unknown', 'Unk']
96 else:
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]),
100 '%s' % btn[1]]])
101
92b7b49f 102 def __init__(self):
10aeb8ea
GS
103 self.reset()
104
105 def reset(self):
5e6fa9cc 106 self.state = 'IDLE'
12fecc8f 107 self.ss_bit = self.ss_start = self.ss_other_edge = self.ss_remote = 0
5844bb0f 108 self.data = self.count = self.active = None
12fecc8f 109 self.addr = self.cmd = None
5e6fa9cc
GY
110
111 def start(self):
5e6fa9cc 112 self.out_ann = self.register(srd.OUTPUT_ANN)
73fc79e0 113 self.active = 0 if self.options['polarity'] == 'active-low' else 1
5844bb0f 114
5e6fa9cc
GY
115 def metadata(self, key, value):
116 if key == srd.SRD_CONF_SAMPLERATE:
117 self.samplerate = value
82ea183f 118 self.tolerance = 0.05 # +/-5%
73fc79e0
UH
119 self.lc = int(self.samplerate * 0.0135) - 1 # 13.5ms
120 self.rc = int(self.samplerate * 0.01125) - 1 # 11.25ms
121 self.dazero = int(self.samplerate * 0.001125) - 1 # 1.125ms
122 self.daone = int(self.samplerate * 0.00225) - 1 # 2.25ms
70835fd4 123 self.stop = int(self.samplerate * 0.000652) - 1 # 0.652ms
5e6fa9cc 124
82ea183f
GM
125 def compare_with_tolerance(self, measured, base):
126 return (measured >= base * (1 - self.tolerance)
127 and measured <= base * (1 + self.tolerance))
128
70835fd4 129 def handle_bit(self, tick):
5bb61a25 130 ret = None
82ea183f 131 if self.compare_with_tolerance(tick, self.dazero):
5e6fa9cc 132 ret = 0
82ea183f 133 elif self.compare_with_tolerance(tick, self.daone):
5e6fa9cc 134 ret = 1
5bb61a25 135 if ret in (0, 1):
5e6fa9cc 136 self.putb([0, ['%d' % ret]])
5bb61a25 137 self.data |= (ret << self.count) # LSB-first
5e6fa9cc 138 self.count = self.count + 1
5e6fa9cc 139 self.ss_bit = self.samplenum
5e6fa9cc 140
70835fd4 141 def data_ok(self):
73fc79e0 142 ret, name = (self.data >> 8) & (self.data & 0xff), self.state.title()
70835fd4 143 if self.count == 8:
12fecc8f
UH
144 if self.state == 'ADDRESS':
145 self.addr = self.data
146 if self.state == 'COMMAND':
147 self.cmd = self.data
70835fd4
UH
148 self.putd(self.data)
149 self.ss_start = self.samplenum
150 return True
5e6fa9cc 151 if ret == 0:
5bb61a25 152 self.putd(self.data >> 8)
5e6fa9cc 153 else:
12fecc8f 154 self.putx([12, ['%s error: 0x%04X' % (name, self.data)]])
5e6fa9cc
GY
155 self.data = self.count = 0
156 self.ss_bit = self.ss_start = self.samplenum
70835fd4 157 return ret == 0
5e6fa9cc 158
5844bb0f 159 def decode(self):
21cda951
UH
160 if not self.samplerate:
161 raise SamplerateError('Cannot decode without samplerate.')
fb1870b0
GS
162
163 cd_count = None
164 if self.options['cd_freq']:
165 cd_count = int(self.samplerate / self.options['cd_freq']) + 1
166 prev_ir = None
167
5844bb0f 168 while True:
fb1870b0
GS
169 # Detect changes in the presence of an active input signal.
170 # The decoder can either be fed an already filtered RX signal
171 # or optionally can detect the presence of a carrier. Periods
172 # of inactivity (signal changes slower than the carrier freq,
173 # if specified) pass on the most recently sampled level. This
174 # approach works for filtered and unfiltered input alike, and
175 # only slightly extends the active phase of input signals with
176 # carriers included by one period of the carrier frequency.
177 # IR based communication protocols can cope with this slight
178 # inaccuracy just fine by design. Enabling carrier detection
179 # on already filtered signals will keep the length of their
180 # active period, but will shift their signal changes by one
181 # carrier period before they get passed to decoding logic.
182 if cd_count:
183 (cur_ir,) = self.wait([{0: 'e'}, {'skip': cd_count}])
184 if self.matched[0]:
185 cur_ir = self.active
186 if cur_ir == prev_ir:
187 continue
188 prev_ir = cur_ir
189 self.ir = cur_ir
190 else:
191 (self.ir,) = self.wait({0: 'e'})
00962e76 192
70835fd4 193 if self.ir != self.active:
5844bb0f 194 # Save the non-active edge, then wait for the next edge.
70835fd4 195 self.ss_other_edge = self.samplenum
5e6fa9cc
GY
196 continue
197
73fc79e0
UH
198 b = self.samplenum - self.ss_bit
199
200 # State machine.
201 if self.state == 'IDLE':
82ea183f 202 if self.compare_with_tolerance(b, self.lc):
70835fd4
UH
203 self.putpause('Long')
204 self.putx([5, ['Leader code', 'Leader', 'LC', 'L']])
12fecc8f 205 self.ss_remote = self.ss_start
73fc79e0
UH
206 self.data = self.count = 0
207 self.state = 'ADDRESS'
82ea183f 208 elif self.compare_with_tolerance(b, self.rc):
70835fd4
UH
209 self.putpause('Short')
210 self.putstop(self.samplenum)
211 self.samplenum += self.stop
212 self.putx([10, ['Repeat code', 'Repeat', 'RC', 'R']])
73fc79e0
UH
213 self.data = self.count = 0
214 self.ss_bit = self.ss_start = self.samplenum
215 elif self.state == 'ADDRESS':
70835fd4
UH
216 self.handle_bit(b)
217 if self.count == 8:
218 self.state = 'ADDRESS#' if self.data_ok() else 'IDLE'
219 elif self.state == 'ADDRESS#':
220 self.handle_bit(b)
221 if self.count == 16:
222 self.state = 'COMMAND' if self.data_ok() else 'IDLE'
73fc79e0 223 elif self.state == 'COMMAND':
70835fd4
UH
224 self.handle_bit(b)
225 if self.count == 8:
226 self.state = 'COMMAND#' if self.data_ok() else 'IDLE'
227 elif self.state == 'COMMAND#':
228 self.handle_bit(b)
229 if self.count == 16:
230 self.state = 'STOP' if self.data_ok() else 'IDLE'
231 elif self.state == 'STOP':
232 self.putstop(self.ss_bit)
12fecc8f 233 self.putremote()
70835fd4
UH
234 self.ss_bit = self.ss_start = self.samplenum
235 self.state = 'IDLE'