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.'
58 {'id': 'data', 'name': 'Data', 'desc': 'Data line'},
65 ('diffman', 'Diff Man'),
69 ('frame', 'Framing',(0,)),
70 ('info', 'Info', (1,)),
71 ('man1111', 'Man 1111', (2,)),
72 ('man1010', 'Man 1010', (3,)),
73 ('diffman', 'Diff Man', (4,)),
77 ('pulse-lengths', 'Pulse lengths'),
80 {'id': 'invert', 'desc': 'Invert data', 'default': 'no',
81 'values': ('no', 'yes')},
82 {'id': 'decodeas', 'desc': 'Decode type', 'default': 'Manchester',
83 'values': ('NRZ', 'Manchester', 'Diff Manchester')},
84 {'id': 'preamble', 'desc': 'Preamble', 'default': 'auto',
85 'values': ('auto', '1010', '1111')},
86 {'id': 'preamlen', 'desc': 'Filter length', 'default': '7',
87 'values': ('0', '3', '4', '5', '6', '7', '8', '9', '10')},
88 {'id': 'diffmanvar', 'desc': 'Transition at start', 'default': '1',
89 'values': ('1', '0')},
96 self.samplerate = None
97 self.ss = self.es = -1
98 self.ss_1111 = self.ss_1010 = -1
99 self.samplenumber_last = None
100 self.sample_first = None
104 self.word_first = None
108 self.lstate_1010 = None
109 self.insync = 0 # Preamble in sync flag
111 self.man_errors_1010 = 0
112 self.preamble = [] # Preamble buffer
113 self.half_time = -1 # Half time for man 1111
114 self.half_time_1010 = 0 # Half time for man 1010
115 self.pulse_lengths = [] # Pulse lengths
116 self.decoded = [] # Decoded stream
117 self.decoded_1010 = [] # Decoded stream
118 self.diff_man_trans = '0' # Transition
119 self.diff_man_len = 1 # Length of pulse in half clock periods
120 self.max_errors = 5 # Max number of errors to output OOK
122 def metadata(self, key, value):
123 if key == srd.SRD_CONF_SAMPLERATE:
124 self.samplerate = value
127 self.out_ann = self.register(srd.OUTPUT_ANN)
128 self.out_python = self.register(srd.OUTPUT_PYTHON)
129 self.out_binary = self.register(srd.OUTPUT_BINARY)
130 self.invert = self.options['invert']
131 self.decodeas = self.options['decodeas']
132 self.preamble_val = self.options['preamble']
133 self.preamble_len = self.options['preamlen']
134 self.diffmanvar = self.options['diffmanvar']
136 def putx(self, data):
137 self.put(self.ss, self.es, self.out_ann, data)
139 def putp(self, data):
140 self.put(self.ss, self.es, self.out_python, data)
142 def dump_pulse_lengths(self):
144 self.pulse_lengths[-1] = self.sample_first # Fix final pulse length.
146 s += ','.join(str(int(int(x) * 1000000 / self.samplerate))
147 for x in self.pulse_lengths)
149 self.put(self.samplenum - 10, self.samplenum, self.out_binary,
150 [0, bytes([ord(c) for c in s])])
152 def decode_nrz(self, start, samples, state):
153 self.pulse_lengths.append(samples)
154 # Use different high and low widths to compensate skewed waveforms.
155 dsamples = self.sample_high if state == '1' else self.sample_low
156 self.ss, self.es = start, start + samples
157 while samples > dsamples * 0.5:
158 if samples >= dsamples * 1.5: # More than one bit.
159 self.es = self.ss + dsamples
160 self.putx([5, [state]])
161 self.decoded.append([self.ss, self.es, state])
163 elif samples >= dsamples * 0.5 and samples < dsamples * 1.5: # Last bit.
164 self.putx([5, [state]])
165 self.decoded.append([self.ss, self.es, state])
173 # Ensure 2nd row doesn't go past end of 1st row.
174 if self.es > self.samplenum:
175 self.es = self.samplenum
177 if self.state == 'DECODE_TIMEOUT': # Five bits - reset.
178 self.ss = self.decoded[0][0]
179 self.es = self.decoded[len(self.decoded) - 1][1]
180 self.dump_pulse_lengths()
181 self.putp(self.decoded)
182 self.decode_timeout()
185 def lock_onto_preamble(self, samples, state): # Filters and recovers clock.
187 l2s = 5 # Max ratio of long to short pulses.
189 # Filter incoming pulses to remove random noise.
190 if self.state == 'DECODE_TIMEOUT':
193 self.word_first = self.samplenum
194 self.sample_first = self.samplenum - self.samplenumber_last
195 self.state = 'WAITING_FOR_PREAMBLE'
198 pre_detect = int(self.preamble_len) # Number of valid pulses to detect.
199 pre_samples = self.samplenum - self.samplenumber_last
200 if len(self.preamble) > 0:
201 if (pre_samples * l2s < self.preamble[-1][1] or
202 self.preamble[-1][1] * l2s < pre_samples): # Garbage in.
203 self.put(self.samplenum, self.samplenum,
204 self.out_ann, [0, ['R']]) # Display resets.
205 self.preamble = [] # Clear buffer.
206 self.preamble.append([self.samplenumber_last,
209 self.samplenumber_last = self.samplenum
210 self.word_first = self.samplenum
212 self.preamble.append([self.samplenumber_last,
215 self.preamble.append([self.samplenumber_last,
219 if len(self.preamble) == pre_detect: # Have a valid series of pulses.
220 if self.preamble[0][2] == '1':
221 self.sample_high = self.preamble[0][1] # Allows skewed pulses.
222 self.sample_low = self.preamble[1][1]
224 self.sample_high = self.preamble[1][1]
225 self.sample_low = self.preamble[0][1]
229 for i in range(len(self.preamble)):
231 if (pre[i][1] > pre[i - 2][1] * 1.25 or
232 pre[i][1] * 1.25 < pre[i - 2][1]): # Adjust ref width.
234 self.sample_high = pre[i][1]
236 self.sample_low = pre[i][1]
238 # Display start of preamble.
239 if self.decodeas == 'NRZ':
240 self.decode_nrz(pre[i][0], pre[i][1], pre[i][2])
241 if self.decodeas == 'Manchester':
242 self.decode_manchester(pre[i][0], pre[i][1], pre[i][2])
243 if self.decodeas == 'Diff Manchester':
244 self.es = pre[i][0] + pre[i][1]
245 self.decode_diff_manchester(pre[i][0], pre[i][1], pre[i][2])
247 # Used to timeout signal.
248 self.sample_first = int((self.sample_high + self.sample_low)/2)
250 self.state = 'DECODING'
252 self.lstate_1010 = state
254 def decode_diff_manchester(self, start, samples, state):
255 self.pulse_lengths.append(samples)
257 # Use different high and low widths to compensate skewed waveforms.
258 dsamples = self.sample_high if state == '1' else self.sample_low
260 self.es = start + samples
261 p_length = round(samples / dsamples) # Find relative pulse length.
263 if self.edge_count == 0:
264 self.diff_man_trans = '1' # Very first pulse must be a transition.
265 self.diff_man_len = 1 # Must also be a half pulse.
267 elif self.edge_count % 2 == 1: # Time to make a decision.
268 if self.diffmanvar == '0': # Transition at self.ss is a zero.
269 self.diff_man_trans = '0' if self.diff_man_trans == '1' else '1'
270 if self.diff_man_len == 1 and p_length == 1:
271 self.putx([4, [self.diff_man_trans]])
272 self.decoded.append([self.ss, self.es, self.diff_man_trans])
273 self.diff_man_trans = '1'
274 elif self.diff_man_len == 1 and p_length == 2:
275 self.es -= int(samples / 2)
276 self.putx([4, [self.diff_man_trans]])
277 self.decoded.append([self.ss, self.es, self.diff_man_trans])
278 self.diff_man_trans = '0'
279 self.edge_count += 1 # Add a virt edge to keep in sync with clk.
280 elif self.diff_man_len == 2 and p_length == 1:
281 self.putx([4, [self.diff_man_trans]])
282 self.decoded.append([self.ss, self.es, self.diff_man_trans])
283 self.diff_man_trans = '1'
284 elif self.diff_man_len == 2 and p_length == 2: # Double illegal E E.
286 self.putx([4, ['E']])
287 self.decoded.append([self.ss, self.es, 'E'])
290 self.putx([4, ['E']])
291 self.decoded.append([self.ss, self.es, 'E'])
292 self.diff_man_trans = '1'
293 elif self.diff_man_len == 1 and p_length > 4:
294 if self.state == 'DECODE_TIMEOUT':
295 self.es = self.ss + 2 * self.sample_first
296 self.putx([4, [self.diff_man_trans]]) # Write error.
297 self.decoded.append([self.ss, self.es, self.diff_man_trans])
298 self.ss = self.decoded[0][0]
299 self.es = self.decoded[len(self.decoded) - 1][1]
300 self.dump_pulse_lengths()
301 if self.man_errors < self.max_errors:
302 self.putp(self.decoded)
304 error_message = 'Probably not Diff Manchester encoded'
305 self.ss = self.word_first
306 self.putx([1, [error_message]])
307 self.decode_timeout()
308 self.diff_man_trans = '1'
310 self.diff_man_len = p_length # Save the previous length.
313 def decode_manchester_sim(self, start, samples, state,
314 dsamples, half_time, lstate, ss, pream):
317 if self.edge_count == 0:
319 if samples > 0.75 * dsamples and samples <= 1.5 * dsamples: # Long p.
321 if half_time % 2 == 0: # Transition.
324 es = start + int(samples / 2)
328 if not (self.edge_count == 0 and pream == '1010'): # Skip first p.
329 ook_bit = [ss, es, lstate]
332 elif samples > 0.25 * dsamples and samples <= 0.75 * dsamples: # Short p.
334 if (half_time % 2 == 0): # Transition.
336 ook_bit = [ss, es, lstate]
342 else: # Too long or too short - error.
344 if self.state != 'DECODE_TIMEOUT': # Error condition.
347 else: # Assume final half bit buried in timeout pulse.
348 es = ss + self.sample_first
349 ook_bit = [ss, es, lstate]
352 return (half_time, lstate, ss, ook_bit, errors)
354 def decode_manchester(self, start, samples, state):
355 self.pulse_lengths.append(samples)
357 # Use different high and low widths to compensate skewed waveforms.
358 dsamples = self.sample_high if state == '1' else self.sample_low
360 if self.preamble_val != '1010': # 1111 preamble is half clock T.
361 (self.half_time, self.lstate, self.ss_1111, ook_bit, errors) = (
362 self.decode_manchester_sim(start, samples, state, dsamples * 2,
363 self.half_time, self.lstate,
364 self.ss_1111, '1111'))
365 self.man_errors += errors
367 self.decoded.append([ook_bit[0], ook_bit[1], ook_bit[2]])
369 if self.preamble_val != '1111': # 1010 preamble is clock T.
370 (self.half_time_1010, self.lstate_1010, self.ss_1010,
372 self.decode_manchester_sim(start, samples, state, dsamples,
373 self.half_time_1010, self.lstate_1010,
374 self.ss_1010, '1010'))
375 self.man_errors_1010 += errors
377 self.decoded_1010.append([ook_bit[0], ook_bit[1], ook_bit[2]])
381 # Stream display and save ook_bit.
383 self.ss, self.es = ook_bit[0], ook_bit[1]
384 if self.preamble_val == '1111':
385 self.putx([2, [ook_bit[2]]])
386 if self.preamble_val == '1010':
387 self.putx([3, [ook_bit[2]]])
389 if self.state == 'DECODE_TIMEOUT': # End of packet.
390 self.dump_pulse_lengths()
393 # If 1010 preamble has less errors use it.
394 if (self.preamble_val == '1010' or
395 (self.man_errors_1010 < self.max_errors and
396 self.man_errors_1010 < self.man_errors and
397 len(self.decoded_1010) > 0)):
398 decoded = self.decoded_1010
399 man_errors = self.man_errors_1010
402 decoded = self.decoded
403 man_errors = self.man_errors
406 if self.preamble_val == 'auto': # Display OOK packet.
407 for i in range(len(decoded)):
408 self.ss, self.es = decoded[i][0], decoded[i][1]
409 self.putx([d_row, [decoded[i][2]]])
411 if (man_errors < self.max_errors and len(decoded) > 0):
412 self.ss, self.es = decoded[0][0], decoded[len(decoded) - 1][1]
415 error_message = 'Not Manchester encoded or wrong preamble'
416 self.ss = self.word_first
417 self.putx([1, [error_message]])
419 self.put(self.es, self.es, self.out_ann, [0, ['T']]) # Mark timeout.
420 self.decode_timeout()
422 def decode_timeout(self):
424 self.samplenumber_last = None
426 self.man_errors = 0 # Clear the bit error counters.
427 self.man_errors_1010 = 0
429 self.wait({0: 'e'}) # Get rid of long pulse.
430 self.samplenumber_last = self.samplenum
431 self.word_first = self.samplenum
432 self.insync = 0 # Preamble in sync flag
433 self.preamble = [] # Preamble buffer
434 self.half_time = -1 # Half time for man 1111
435 self.half_time_1010 = 0 # Half time for man 1010
436 self.decoded = [] # Decoded bits
437 self.decoded_1010 = [] # Decoded bits for man 1010
438 self.pulse_lengths = []
442 if self.edge_count == 0: # Waiting for a signal.
443 pin = self.wait({0: 'e'})
444 self.state = 'DECODING'
446 pin = self.wait([{0: 'e'}, {'skip': 5 * self.sample_first}])
447 if self.matched[1] and not self.matched[0]: # No edges for 5 p's.
448 self.state = 'DECODE_TIMEOUT'
450 if not self.samplenumber_last: # Set counters to start of signal.
451 self.samplenumber_last = self.samplenum
452 self.word_first = self.samplenum
454 samples = self.samplenum - self.samplenumber_last
455 if not self.sample_first: # Get number of samples for first pulse.
456 self.sample_first = samples
459 if self.state == 'DECODE_TIMEOUT': # No edge so flip the state.
460 pinstate = int(not pinstate)
461 if self.invert == 'yes': # Invert signal.
462 pinstate = int(not pinstate)
463 state = '0' if pinstate else '1'
465 # No preamble filtering or checking and no skew correction.
466 if self.preamble_len == '0':
467 self.sample_high = self.sample_first
468 self.sample_low = self.sample_first
472 self.lock_onto_preamble(samples, state)
474 if self.decodeas == 'NRZ':
475 self.decode_nrz(self.samplenumber_last, samples, state)
476 if self.decodeas == 'Manchester':
477 self.decode_manchester(self.samplenumber_last,
479 if self.decodeas == 'Diff Manchester':
480 self.decode_diff_manchester(self.samplenumber_last,
483 self.samplenumber_last = self.samplenum