]> sigrok.org Git - libsigrokdecode.git/blame - decoders/ir_nec/pd.py
Rename 'probe' to 'channel' everywhere.
[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):
25 api_version = 1
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):
106 # self.out_python = self.register(srd.OUTPUT_PYTHON)
107 self.out_ann = self.register(srd.OUTPUT_ANN)
73fc79e0
UH
108 self.active = 0 if self.options['polarity'] == 'active-low' else 1
109 self.old_ir = 1 if self.active == 0 else 0
5e6fa9cc
GY
110
111 def metadata(self, key, value):
112 if key == srd.SRD_CONF_SAMPLERATE:
113 self.samplerate = value
73fc79e0
UH
114 self.margin = int(self.samplerate * 0.0001) - 1 # 0.1ms
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
70835fd4 119 self.stop = int(self.samplerate * 0.000652) - 1 # 0.652ms
5e6fa9cc 120
70835fd4 121 def handle_bit(self, tick):
5bb61a25 122 ret = None
00962e76 123 if tick in range(self.dazero - self.margin, self.dazero + self.margin):
5e6fa9cc 124 ret = 0
00962e76 125 elif tick in range(self.daone - self.margin, self.daone + self.margin):
5e6fa9cc 126 ret = 1
5bb61a25 127 if ret in (0, 1):
5e6fa9cc 128 self.putb([0, ['%d' % ret]])
5bb61a25 129 self.data |= (ret << self.count) # LSB-first
5e6fa9cc 130 self.count = self.count + 1
5e6fa9cc 131 self.ss_bit = self.samplenum
5e6fa9cc 132
70835fd4 133 def data_ok(self):
73fc79e0 134 ret, name = (self.data >> 8) & (self.data & 0xff), self.state.title()
70835fd4 135 if self.count == 8:
12fecc8f
UH
136 if self.state == 'ADDRESS':
137 self.addr = self.data
138 if self.state == 'COMMAND':
139 self.cmd = self.data
70835fd4
UH
140 self.putd(self.data)
141 self.ss_start = self.samplenum
142 return True
5e6fa9cc 143 if ret == 0:
5bb61a25 144 self.putd(self.data >> 8)
5e6fa9cc 145 else:
12fecc8f 146 self.putx([12, ['%s error: 0x%04X' % (name, self.data)]])
5e6fa9cc
GY
147 self.data = self.count = 0
148 self.ss_bit = self.ss_start = self.samplenum
70835fd4 149 return ret == 0
5e6fa9cc
GY
150
151 def decode(self, ss, es, data):
152 if self.samplerate is None:
153 raise Exception("Cannot decode without samplerate.")
154 for (self.samplenum, pins) in data:
155 self.ir = pins[0]
00962e76 156
70835fd4
UH
157 # Wait for an "interesting" edge, but also record the other ones.
158 if self.old_ir == self.ir:
159 continue
160 if self.ir != self.active:
161 self.ss_other_edge = self.samplenum
73fc79e0 162 self.old_ir = self.ir
5e6fa9cc
GY
163 continue
164
73fc79e0
UH
165 b = self.samplenum - self.ss_bit
166
167 # State machine.
168 if self.state == 'IDLE':
169 if b in range(self.lc - self.margin, self.lc + self.margin):
70835fd4
UH
170 self.putpause('Long')
171 self.putx([5, ['Leader code', 'Leader', 'LC', 'L']])
12fecc8f 172 self.ss_remote = self.ss_start
73fc79e0
UH
173 self.data = self.count = 0
174 self.state = 'ADDRESS'
175 elif b in range(self.rc - self.margin, self.rc + self.margin):
70835fd4
UH
176 self.putpause('Short')
177 self.putstop(self.samplenum)
178 self.samplenum += self.stop
179 self.putx([10, ['Repeat code', 'Repeat', 'RC', 'R']])
73fc79e0
UH
180 self.data = self.count = 0
181 self.ss_bit = self.ss_start = self.samplenum
182 elif self.state == 'ADDRESS':
70835fd4
UH
183 self.handle_bit(b)
184 if self.count == 8:
185 self.state = 'ADDRESS#' if self.data_ok() else 'IDLE'
186 elif self.state == 'ADDRESS#':
187 self.handle_bit(b)
188 if self.count == 16:
189 self.state = 'COMMAND' if self.data_ok() else 'IDLE'
73fc79e0 190 elif self.state == 'COMMAND':
70835fd4
UH
191 self.handle_bit(b)
192 if self.count == 8:
193 self.state = 'COMMAND#' if self.data_ok() else 'IDLE'
194 elif self.state == 'COMMAND#':
195 self.handle_bit(b)
196 if self.count == 16:
197 self.state = 'STOP' if self.data_ok() else 'IDLE'
198 elif self.state == 'STOP':
199 self.putstop(self.ss_bit)
12fecc8f 200 self.putremote()
70835fd4
UH
201 self.ss_bit = self.ss_start = self.samplenum
202 self.state = 'IDLE'
203 else:
204 raise Exception('Invalid state: %s' % self.state)
5e6fa9cc
GY
205
206 self.old_ir = self.ir
207