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, write to the Free Software
18 ## Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
21 import sigrokdecode as srd
24 class Decoder(srd.Decoder):
29 desc = 'NEC infrared remote control protocol.'
34 {'id': 'ir', 'name': 'IR', 'desc': 'Data line'},
37 {'id': 'polarity', 'desc': 'Polarity', 'default': 'active-low',
38 'values': ('active-low', 'active-high')},
42 ('agc-pulse', 'AGC pulse'),
43 ('longpause', 'Long pause'),
44 ('shortpause', 'Short pause'),
45 ('stop-bit', 'Stop bit'),
46 ('leader-code', 'Leader code'),
48 ('addr-inv', 'Address#'),
50 ('cmd-inv', 'Command#'),
51 ('repeat-code', 'Repeat code'),
53 ('warnings', 'Warnings'),
56 ('bits', 'Bits', (0, 1, 2, 3, 4)),
57 ('fields', 'Fields', (5, 6, 7, 8, 9, 10)),
58 ('remote', 'Remote', (11,)),
59 ('warnings', 'Warnings', (12,)),
63 self.put(self.ss_start, self.samplenum, self.out_ann, data)
66 self.put(self.ss_bit, self.samplenum, self.out_ann, 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]]])
77 def putstop(self, ss):
78 self.put(ss, ss + self.stop, self.out_ann,
79 [4, ['Stop bit', 'Stop', 'St', 'S']])
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']])
89 dev = address.get(self.addr, 'Unknown device')
90 buttons = command.get(self.addr, None)
92 btn = ['Unknown', 'Unk']
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]),
99 def __init__(self, **kwargs):
101 self.ss_bit = self.ss_start = self.ss_other_edge = self.ss_remote = 0
102 self.data = self.count = self.active = self.old_ir = None
103 self.addr = self.cmd = None
106 self.out_ann = self.register(srd.OUTPUT_ANN)
107 self.active = 0 if self.options['polarity'] == 'active-low' else 1
108 self.old_ir = 1 if self.active == 0 else 0
110 def metadata(self, key, value):
111 if key == srd.SRD_CONF_SAMPLERATE:
112 self.samplerate = value
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
118 self.stop = int(self.samplerate * 0.000652) - 1 # 0.652ms
120 def handle_bit(self, tick):
122 if tick in range(self.dazero - self.margin, self.dazero + self.margin):
124 elif tick in range(self.daone - self.margin, self.daone + self.margin):
127 self.putb([0, ['%d' % ret]])
128 self.data |= (ret << self.count) # LSB-first
129 self.count = self.count + 1
130 self.ss_bit = self.samplenum
133 ret, name = (self.data >> 8) & (self.data & 0xff), self.state.title()
135 if self.state == 'ADDRESS':
136 self.addr = self.data
137 if self.state == 'COMMAND':
140 self.ss_start = self.samplenum
143 self.putd(self.data >> 8)
145 self.putx([12, ['%s error: 0x%04X' % (name, self.data)]])
146 self.data = self.count = 0
147 self.ss_bit = self.ss_start = self.samplenum
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:
156 # Wait for an "interesting" edge, but also record the other ones.
157 if self.old_ir == self.ir:
159 if self.ir != self.active:
160 self.ss_other_edge = self.samplenum
161 self.old_ir = self.ir
164 b = self.samplenum - self.ss_bit
167 if self.state == 'IDLE':
168 if b in range(self.lc - self.margin, self.lc + self.margin):
169 self.putpause('Long')
170 self.putx([5, ['Leader code', 'Leader', 'LC', 'L']])
171 self.ss_remote = self.ss_start
172 self.data = self.count = 0
173 self.state = 'ADDRESS'
174 elif b in range(self.rc - self.margin, self.rc + self.margin):
175 self.putpause('Short')
176 self.putstop(self.samplenum)
177 self.samplenum += self.stop
178 self.putx([10, ['Repeat code', 'Repeat', 'RC', 'R']])
179 self.data = self.count = 0
180 self.ss_bit = self.ss_start = self.samplenum
181 elif self.state == 'ADDRESS':
184 self.state = 'ADDRESS#' if self.data_ok() else 'IDLE'
185 elif self.state == 'ADDRESS#':
188 self.state = 'COMMAND' if self.data_ok() else 'IDLE'
189 elif self.state == 'COMMAND':
192 self.state = 'COMMAND#' if self.data_ok() else 'IDLE'
193 elif self.state == 'COMMAND#':
196 self.state = 'STOP' if self.data_ok() else 'IDLE'
197 elif self.state == 'STOP':
198 self.putstop(self.ss_bit)
200 self.ss_bit = self.ss_start = self.samplenum
203 raise Exception('Invalid state: %s' % self.state)
205 self.old_ir = self.ir