2 ## This file is part of the libsigrokdecode project.
4 ## Copyright (C) 2018 Steve R <steversig@virginmedia.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
24 Samples: The Samples array is sent when a DECODE_TIMEOUT occurs.
25 [<start>, <finish>, <state>]
26 <start> is the sample number of the start of the decoded bit. This may not line
27 up with the pulses that were converted into the decoded bit particularly for
29 <finish> is the sample number of the end of the decoded bit.
30 <state> is a single character string which is the state of the decoded bit.
34 'E' Error or invalid. This can be caused by missing transitions or the wrong
35 pulse lengths according to the rules for the particular encoding. In some cases
36 this is intentional (Oregon 1 preamble) and is part of the sync pattern. In
37 other cases the signal could simply be broken.
39 If there are more than self.max_errors (default 5) in decoding then the
40 OUTPUT_PYTHON is not sent as the data is assumed to be worthless.
41 There also needs to be a low for five times the preamble period at the end of
42 each set of pulses to trigger a DECODE_TIMEOUT and get the OUTPUT_PYTHON sent.
45 class SamplerateError(Exception):
48 class Decoder(srd.Decoder):
52 longname = 'On-off keying'
53 desc = 'On-off keying protocol.'
59 {'id': 'data', 'name': 'Data', 'desc': 'Data line'},
66 ('diffman', 'Diff man'),
70 ('frames', 'Framing', (0,)),
71 ('info-vals', 'Info', (1,)),
72 ('man1111', 'Man 1111', (2,)),
73 ('man1010', 'Man 1010', (3,)),
74 ('diffmans', 'Diff man', (4,)),
75 ('nrz-vals', 'NRZ', (5,)),
78 ('pulse-lengths', 'Pulse lengths'),
81 {'id': 'invert', 'desc': 'Invert data', 'default': 'no',
82 'values': ('no', 'yes')},
83 {'id': 'decodeas', 'desc': 'Decode type', 'default': 'Manchester',
84 'values': ('NRZ', 'Manchester', 'Diff Manchester')},
85 {'id': 'preamble', 'desc': 'Preamble', 'default': 'auto',
86 'values': ('auto', '1010', '1111')},
87 {'id': 'preamlen', 'desc': 'Filter length', 'default': '7',
88 'values': ('0', '3', '4', '5', '6', '7', '8', '9', '10')},
89 {'id': 'diffmanvar', 'desc': 'Transition at start', 'default': '1',
90 'values': ('1', '0')},
97 self.samplerate = None
98 self.ss = self.es = -1
99 self.ss_1111 = self.ss_1010 = -1
100 self.samplenumber_last = None
101 self.sample_first = None
105 self.word_first = None
109 self.lstate_1010 = None
110 self.insync = 0 # Preamble in sync flag
112 self.man_errors_1010 = 0
113 self.preamble = [] # Preamble buffer
114 self.half_time = -1 # Half time for man 1111
115 self.half_time_1010 = 0 # Half time for man 1010
116 self.pulse_lengths = [] # Pulse lengths
117 self.decoded = [] # Decoded stream
118 self.decoded_1010 = [] # Decoded stream
119 self.diff_man_trans = '0' # Transition
120 self.diff_man_len = 1 # Length of pulse in half clock periods
121 self.max_errors = 5 # Max number of errors to output OOK
123 def metadata(self, key, value):
124 if key == srd.SRD_CONF_SAMPLERATE:
125 self.samplerate = value
128 self.out_ann = self.register(srd.OUTPUT_ANN)
129 self.out_python = self.register(srd.OUTPUT_PYTHON)
130 self.out_binary = self.register(srd.OUTPUT_BINARY)
131 self.invert = self.options['invert']
132 self.decodeas = self.options['decodeas']
133 self.preamble_val = self.options['preamble']
134 self.preamble_len = self.options['preamlen']
135 self.diffmanvar = self.options['diffmanvar']
137 def putx(self, data):
138 self.put(self.ss, self.es, self.out_ann, data)
140 def putp(self, data):
141 self.put(self.ss, self.es, self.out_python, data)
143 def dump_pulse_lengths(self):
145 self.pulse_lengths[-1] = self.sample_first # Fix final pulse length.
147 s += ','.join(str(int(int(x) * 1000000 / self.samplerate))
148 for x in self.pulse_lengths)
150 self.put(self.samplenum - 10, self.samplenum, self.out_binary,
151 [0, bytes([ord(c) for c in s])])
153 def decode_nrz(self, start, samples, state):
154 self.pulse_lengths.append(samples)
155 # Use different high and low widths to compensate skewed waveforms.
156 dsamples = self.sample_high if state == '1' else self.sample_low
157 self.ss, self.es = start, start + samples
158 while samples > dsamples * 0.5:
159 if samples >= dsamples * 1.5: # More than one bit.
160 self.es = self.ss + dsamples
161 self.putx([5, [state]])
162 self.decoded.append([self.ss, self.es, state])
164 elif samples >= dsamples * 0.5 and samples < dsamples * 1.5: # Last bit.
165 self.putx([5, [state]])
166 self.decoded.append([self.ss, self.es, state])
174 # Ensure 2nd row doesn't go past end of 1st row.
175 if self.es > self.samplenum:
176 self.es = self.samplenum
178 if self.state == 'DECODE_TIMEOUT': # Five bits - reset.
179 self.ss = self.decoded[0][0]
180 self.es = self.decoded[len(self.decoded) - 1][1]
181 self.dump_pulse_lengths()
182 self.putp(self.decoded)
183 self.decode_timeout()
186 def lock_onto_preamble(self, samples, state): # Filters and recovers clock.
188 l2s = 5 # Max ratio of long to short pulses.
190 # Filter incoming pulses to remove random noise.
191 if self.state == 'DECODE_TIMEOUT':
194 self.word_first = self.samplenum
195 self.sample_first = self.samplenum - self.samplenumber_last
196 self.state = 'WAITING_FOR_PREAMBLE'
199 pre_detect = int(self.preamble_len) # Number of valid pulses to detect.
200 pre_samples = self.samplenum - self.samplenumber_last
201 if len(self.preamble) > 0:
202 if (pre_samples * l2s < self.preamble[-1][1] or
203 self.preamble[-1][1] * l2s < pre_samples): # Garbage in.
204 self.put(self.samplenum, self.samplenum,
205 self.out_ann, [0, ['R']]) # Display resets.
206 self.preamble = [] # Clear buffer.
207 self.preamble.append([self.samplenumber_last,
210 self.samplenumber_last = self.samplenum
211 self.word_first = self.samplenum
213 self.preamble.append([self.samplenumber_last,
216 self.preamble.append([self.samplenumber_last,
220 if len(self.preamble) == pre_detect: # Have a valid series of pulses.
221 if self.preamble[0][2] == '1':
222 self.sample_high = self.preamble[0][1] # Allows skewed pulses.
223 self.sample_low = self.preamble[1][1]
225 self.sample_high = self.preamble[1][1]
226 self.sample_low = self.preamble[0][1]
230 for i in range(len(self.preamble)):
232 if (pre[i][1] > pre[i - 2][1] * 1.25 or
233 pre[i][1] * 1.25 < pre[i - 2][1]): # Adjust ref width.
235 self.sample_high = pre[i][1]
237 self.sample_low = pre[i][1]
239 # Display start of preamble.
240 if self.decodeas == 'NRZ':
241 self.decode_nrz(pre[i][0], pre[i][1], pre[i][2])
242 if self.decodeas == 'Manchester':
243 self.decode_manchester(pre[i][0], pre[i][1], pre[i][2])
244 if self.decodeas == 'Diff Manchester':
245 self.es = pre[i][0] + pre[i][1]
246 self.decode_diff_manchester(pre[i][0], pre[i][1], pre[i][2])
248 # Used to timeout signal.
249 self.sample_first = int((self.sample_high + self.sample_low)/2)
251 self.state = 'DECODING'
253 self.lstate_1010 = state
255 def decode_diff_manchester(self, start, samples, state):
256 self.pulse_lengths.append(samples)
258 # Use different high and low widths to compensate skewed waveforms.
259 dsamples = self.sample_high if state == '1' else self.sample_low
261 self.es = start + samples
262 p_length = round(samples / dsamples) # Find relative pulse length.
264 if self.edge_count == 0:
265 self.diff_man_trans = '1' # Very first pulse must be a transition.
266 self.diff_man_len = 1 # Must also be a half pulse.
268 elif self.edge_count % 2 == 1: # Time to make a decision.
269 if self.diffmanvar == '0': # Transition at self.ss is a zero.
270 self.diff_man_trans = '0' if self.diff_man_trans == '1' else '1'
271 if self.diff_man_len == 1 and p_length == 1:
272 self.putx([4, [self.diff_man_trans]])
273 self.decoded.append([self.ss, self.es, self.diff_man_trans])
274 self.diff_man_trans = '1'
275 elif self.diff_man_len == 1 and p_length == 2:
276 self.es -= int(samples / 2)
277 self.putx([4, [self.diff_man_trans]])
278 self.decoded.append([self.ss, self.es, self.diff_man_trans])
279 self.diff_man_trans = '0'
280 self.edge_count += 1 # Add a virt edge to keep in sync with clk.
281 elif self.diff_man_len == 2 and p_length == 1:
282 self.putx([4, [self.diff_man_trans]])
283 self.decoded.append([self.ss, self.es, self.diff_man_trans])
284 self.diff_man_trans = '1'
285 elif self.diff_man_len == 2 and p_length == 2: # Double illegal E E.
287 self.putx([4, ['E']])
288 self.decoded.append([self.ss, self.es, 'E'])
291 self.putx([4, ['E']])
292 self.decoded.append([self.ss, self.es, 'E'])
293 self.diff_man_trans = '1'
294 elif self.diff_man_len == 1 and p_length > 4:
295 if self.state == 'DECODE_TIMEOUT':
296 self.es = self.ss + 2 * self.sample_first
297 self.putx([4, [self.diff_man_trans]]) # Write error.
298 self.decoded.append([self.ss, self.es, self.diff_man_trans])
299 self.ss = self.decoded[0][0]
300 self.es = self.decoded[len(self.decoded) - 1][1]
301 self.dump_pulse_lengths()
302 if self.man_errors < self.max_errors:
303 self.putp(self.decoded)
305 error_message = 'Probably not Diff Manchester encoded'
306 self.ss = self.word_first
307 self.putx([1, [error_message]])
308 self.decode_timeout()
309 self.diff_man_trans = '1'
311 self.diff_man_len = p_length # Save the previous length.
314 def decode_manchester_sim(self, start, samples, state,
315 dsamples, half_time, lstate, ss, pream):
318 if self.edge_count == 0:
320 if samples > 0.75 * dsamples and samples <= 1.5 * dsamples: # Long p.
322 if half_time % 2 == 0: # Transition.
325 es = start + int(samples / 2)
329 if not (self.edge_count == 0 and pream == '1010'): # Skip first p.
330 ook_bit = [ss, es, lstate]
333 elif samples > 0.25 * dsamples and samples <= 0.75 * dsamples: # Short p.
335 if (half_time % 2 == 0): # Transition.
337 ook_bit = [ss, es, lstate]
343 else: # Too long or too short - error.
345 if self.state != 'DECODE_TIMEOUT': # Error condition.
348 else: # Assume final half bit buried in timeout pulse.
349 es = ss + self.sample_first
350 ook_bit = [ss, es, lstate]
353 return (half_time, lstate, ss, ook_bit, errors)
355 def decode_manchester(self, start, samples, state):
356 self.pulse_lengths.append(samples)
358 # Use different high and low widths to compensate skewed waveforms.
359 dsamples = self.sample_high if state == '1' else self.sample_low
361 if self.preamble_val != '1010': # 1111 preamble is half clock T.
362 (self.half_time, self.lstate, self.ss_1111, ook_bit, errors) = (
363 self.decode_manchester_sim(start, samples, state, dsamples * 2,
364 self.half_time, self.lstate,
365 self.ss_1111, '1111'))
366 self.man_errors += errors
368 self.decoded.append([ook_bit[0], ook_bit[1], ook_bit[2]])
370 if self.preamble_val != '1111': # 1010 preamble is clock T.
371 (self.half_time_1010, self.lstate_1010, self.ss_1010,
373 self.decode_manchester_sim(start, samples, state, dsamples,
374 self.half_time_1010, self.lstate_1010,
375 self.ss_1010, '1010'))
376 self.man_errors_1010 += errors
378 self.decoded_1010.append([ook_bit[0], ook_bit[1], ook_bit[2]])
382 # Stream display and save ook_bit.
384 self.ss, self.es = ook_bit[0], ook_bit[1]
385 if self.preamble_val == '1111':
386 self.putx([2, [ook_bit[2]]])
387 if self.preamble_val == '1010':
388 self.putx([3, [ook_bit[2]]])
390 if self.state == 'DECODE_TIMEOUT': # End of packet.
391 self.dump_pulse_lengths()
394 # If 1010 preamble has less errors use it.
395 if (self.preamble_val == '1010' or
396 (self.man_errors_1010 < self.max_errors and
397 self.man_errors_1010 < self.man_errors and
398 len(self.decoded_1010) > 0)):
399 decoded = self.decoded_1010
400 man_errors = self.man_errors_1010
403 decoded = self.decoded
404 man_errors = self.man_errors
407 if self.preamble_val == 'auto': # Display OOK packet.
408 for i in range(len(decoded)):
409 self.ss, self.es = decoded[i][0], decoded[i][1]
410 self.putx([d_row, [decoded[i][2]]])
412 if (man_errors < self.max_errors and len(decoded) > 0):
413 self.ss, self.es = decoded[0][0], decoded[len(decoded) - 1][1]
416 error_message = 'Not Manchester encoded or wrong preamble'
417 self.ss = self.word_first
418 self.putx([1, [error_message]])
420 self.put(self.es, self.es, self.out_ann, [0, ['T']]) # Mark timeout.
421 self.decode_timeout()
423 def decode_timeout(self):
425 self.samplenumber_last = None
427 self.man_errors = 0 # Clear the bit error counters.
428 self.man_errors_1010 = 0
430 self.wait({0: 'e'}) # Get rid of long pulse.
431 self.samplenumber_last = self.samplenum
432 self.word_first = self.samplenum
433 self.insync = 0 # Preamble in sync flag
434 self.preamble = [] # Preamble buffer
435 self.half_time = -1 # Half time for man 1111
436 self.half_time_1010 = 0 # Half time for man 1010
437 self.decoded = [] # Decoded bits
438 self.decoded_1010 = [] # Decoded bits for man 1010
439 self.pulse_lengths = []
443 if self.edge_count == 0: # Waiting for a signal.
444 pin = self.wait({0: 'e'})
445 self.state = 'DECODING'
447 pin = self.wait([{0: 'e'}, {'skip': 5 * self.sample_first}])
448 if self.matched[1] and not self.matched[0]: # No edges for 5 p's.
449 self.state = 'DECODE_TIMEOUT'
451 if not self.samplenumber_last: # Set counters to start of signal.
452 self.samplenumber_last = self.samplenum
453 self.word_first = self.samplenum
455 samples = self.samplenum - self.samplenumber_last
456 if not self.sample_first: # Get number of samples for first pulse.
457 self.sample_first = samples
460 if self.state == 'DECODE_TIMEOUT': # No edge so flip the state.
461 pinstate = int(not pinstate)
462 if self.invert == 'yes': # Invert signal.
463 pinstate = int(not pinstate)
464 state = '0' if pinstate else '1'
466 # No preamble filtering or checking and no skew correction.
467 if self.preamble_len == '0':
468 self.sample_high = self.sample_first
469 self.sample_low = self.sample_first
473 self.lock_onto_preamble(samples, state)
475 if self.decodeas == 'NRZ':
476 self.decode_nrz(self.samplenumber_last, samples, state)
477 if self.decodeas == 'Manchester':
478 self.decode_manchester(self.samplenumber_last,
480 if self.decodeas == 'Diff Manchester':
481 self.decode_diff_manchester(self.samplenumber_last,
484 self.samplenumber_last = self.samplenum