]> sigrok.org Git - libsigrokdecode.git/blame - decoders/ir_nec/pd.py
All PDs: Drop unneeded exceptions.
[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
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
19##
20
21import sigrokdecode as srd
12fecc8f 22from .lists import *
5e6fa9cc
GY
23
24class Decoder(srd.Decoder):
12851357 25 api_version = 2
00962e76
UH
26 id = 'ir_nec'
27 name = 'IR NEC'
28 longname = 'IR NEC'
29 desc = 'NEC infrared remote control protocol.'
5e6fa9cc
GY
30 license = 'gplv2+'
31 inputs = ['logic']
00962e76 32 outputs = ['ir_nec']
6a15597a 33 channels = (
5e6fa9cc 34 {'id': 'ir', 'name': 'IR', 'desc': 'Data line'},
bee57ee8
UH
35 )
36 options = (
37 {'id': 'polarity', 'desc': 'Polarity', 'default': 'active-low',
38 'values': ('active-low', 'active-high')},
39 )
40 annotations = (
41 ('bit', 'Bit'),
42 ('agc-pulse', 'AGC pulse'),
43 ('longpause', 'Long pause'),
44 ('shortpause', 'Short pause'),
45 ('stop-bit', 'Stop bit'),
46 ('leader-code', 'Leader code'),
47 ('addr', 'Address'),
48 ('addr-inv', 'Address#'),
49 ('cmd', 'Command'),
50 ('cmd-inv', 'Command#'),
51 ('repeat-code', 'Repeat code'),
52 ('remote', 'Remote'),
53 ('warnings', 'Warnings'),
54 )
5e6fa9cc 55 annotation_rows = (
70835fd4
UH
56 ('bits', 'Bits', (0, 1, 2, 3, 4)),
57 ('fields', 'Fields', (5, 6, 7, 8, 9, 10)),
12fecc8f
UH
58 ('remote', 'Remote', (11,)),
59 ('warnings', 'Warnings', (12,)),
5e6fa9cc
GY
60 )
61
5e6fa9cc
GY
62 def putx(self, data):
63 self.put(self.ss_start, self.samplenum, self.out_ann, data)
64
65 def putb(self, data):
66 self.put(self.ss_bit, self.samplenum, self.out_ann, data)
67
70835fd4
UH
68 def putd(self, data):
69 name = self.state.title()
70 d = {'ADDRESS': 6, 'ADDRESS#': 7, 'COMMAND': 8, 'COMMAND#': 9}
71 s = {'ADDRESS': ['ADDR', 'A'], 'ADDRESS#': ['ADDR#', 'A#'],
72 'COMMAND': ['CMD', 'C'], 'COMMAND#': ['CMD#', 'C#']}
73 self.putx([d[self.state], ['%s: 0x%02X' % (name, data),
74 '%s: 0x%02X' % (s[self.state][0], data),
75 '%s: 0x%02X' % (s[self.state][1], data), s[self.state][1]]])
76
77 def putstop(self, ss):
78 self.put(ss, ss + self.stop, self.out_ann,
79 [4, ['Stop bit', 'Stop', 'St', 'S']])
80
81 def putpause(self, p):
82 self.put(self.ss_start, self.ss_other_edge, self.out_ann,
83 [1, ['AGC pulse', 'AGC', 'A']])
84 idx = 2 if p == 'Long' else 3
85 self.put(self.ss_other_edge, self.samplenum, self.out_ann,
86 [idx, [p + ' pause', '%s-pause' % p[0], '%sP' % p[0], 'P']])
87
12fecc8f
UH
88 def putremote(self):
89 dev = address.get(self.addr, 'Unknown device')
90 buttons = command.get(self.addr, None)
91 if buttons is None:
92 btn = ['Unknown', 'Unk']
93 else:
94 btn = buttons.get(self.cmd, ['Unknown', 'Unk'])
95 self.put(self.ss_remote, self.ss_bit + self.stop, self.out_ann,
96 [11, ['%s: %s' % (dev, btn[0]), '%s: %s' % (dev, btn[1]),
97 '%s' % btn[1]]])
98
5e6fa9cc 99 def __init__(self, **kwargs):
5e6fa9cc 100 self.state = 'IDLE'
12fecc8f 101 self.ss_bit = self.ss_start = self.ss_other_edge = self.ss_remote = 0
73fc79e0 102 self.data = self.count = self.active = self.old_ir = None
12fecc8f 103 self.addr = self.cmd = None
5e6fa9cc
GY
104
105 def start(self):
5e6fa9cc 106 self.out_ann = self.register(srd.OUTPUT_ANN)
73fc79e0
UH
107 self.active = 0 if self.options['polarity'] == 'active-low' else 1
108 self.old_ir = 1 if self.active == 0 else 0
5e6fa9cc
GY
109
110 def metadata(self, key, value):
111 if key == srd.SRD_CONF_SAMPLERATE:
112 self.samplerate = value
73fc79e0
UH
113 self.margin = int(self.samplerate * 0.0001) - 1 # 0.1ms
114 self.lc = int(self.samplerate * 0.0135) - 1 # 13.5ms
115 self.rc = int(self.samplerate * 0.01125) - 1 # 11.25ms
116 self.dazero = int(self.samplerate * 0.001125) - 1 # 1.125ms
117 self.daone = int(self.samplerate * 0.00225) - 1 # 2.25ms
70835fd4 118 self.stop = int(self.samplerate * 0.000652) - 1 # 0.652ms
5e6fa9cc 119
70835fd4 120 def handle_bit(self, tick):
5bb61a25 121 ret = None
00962e76 122 if tick in range(self.dazero - self.margin, self.dazero + self.margin):
5e6fa9cc 123 ret = 0
00962e76 124 elif tick in range(self.daone - self.margin, self.daone + self.margin):
5e6fa9cc 125 ret = 1
5bb61a25 126 if ret in (0, 1):
5e6fa9cc 127 self.putb([0, ['%d' % ret]])
5bb61a25 128 self.data |= (ret << self.count) # LSB-first
5e6fa9cc 129 self.count = self.count + 1
5e6fa9cc 130 self.ss_bit = self.samplenum
5e6fa9cc 131
70835fd4 132 def data_ok(self):
73fc79e0 133 ret, name = (self.data >> 8) & (self.data & 0xff), self.state.title()
70835fd4 134 if self.count == 8:
12fecc8f
UH
135 if self.state == 'ADDRESS':
136 self.addr = self.data
137 if self.state == 'COMMAND':
138 self.cmd = self.data
70835fd4
UH
139 self.putd(self.data)
140 self.ss_start = self.samplenum
141 return True
5e6fa9cc 142 if ret == 0:
5bb61a25 143 self.putd(self.data >> 8)
5e6fa9cc 144 else:
12fecc8f 145 self.putx([12, ['%s error: 0x%04X' % (name, self.data)]])
5e6fa9cc
GY
146 self.data = self.count = 0
147 self.ss_bit = self.ss_start = self.samplenum
70835fd4 148 return ret == 0
5e6fa9cc
GY
149
150 def decode(self, ss, es, data):
151 if self.samplerate is None:
152 raise Exception("Cannot decode without samplerate.")
153 for (self.samplenum, pins) in data:
154 self.ir = pins[0]
00962e76 155
70835fd4
UH
156 # Wait for an "interesting" edge, but also record the other ones.
157 if self.old_ir == self.ir:
158 continue
159 if self.ir != self.active:
160 self.ss_other_edge = self.samplenum
73fc79e0 161 self.old_ir = self.ir
5e6fa9cc
GY
162 continue
163
73fc79e0
UH
164 b = self.samplenum - self.ss_bit
165
166 # State machine.
167 if self.state == 'IDLE':
168 if b in range(self.lc - self.margin, self.lc + self.margin):
70835fd4
UH
169 self.putpause('Long')
170 self.putx([5, ['Leader code', 'Leader', 'LC', 'L']])
12fecc8f 171 self.ss_remote = self.ss_start
73fc79e0
UH
172 self.data = self.count = 0
173 self.state = 'ADDRESS'
174 elif b in range(self.rc - self.margin, self.rc + self.margin):
70835fd4
UH
175 self.putpause('Short')
176 self.putstop(self.samplenum)
177 self.samplenum += self.stop
178 self.putx([10, ['Repeat code', 'Repeat', 'RC', 'R']])
73fc79e0
UH
179 self.data = self.count = 0
180 self.ss_bit = self.ss_start = self.samplenum
181 elif self.state == 'ADDRESS':
70835fd4
UH
182 self.handle_bit(b)
183 if self.count == 8:
184 self.state = 'ADDRESS#' if self.data_ok() else 'IDLE'
185 elif self.state == 'ADDRESS#':
186 self.handle_bit(b)
187 if self.count == 16:
188 self.state = 'COMMAND' if self.data_ok() else 'IDLE'
73fc79e0 189 elif self.state == 'COMMAND':
70835fd4
UH
190 self.handle_bit(b)
191 if self.count == 8:
192 self.state = 'COMMAND#' if self.data_ok() else 'IDLE'
193 elif self.state == 'COMMAND#':
194 self.handle_bit(b)
195 if self.count == 16:
196 self.state = 'STOP' if self.data_ok() else 'IDLE'
197 elif self.state == 'STOP':
198 self.putstop(self.ss_bit)
12fecc8f 199 self.putremote()
70835fd4
UH
200 self.ss_bit = self.ss_start = self.samplenum
201 self.state = 'IDLE'
5e6fa9cc
GY
202
203 self.old_ir = self.ir
204