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.
145 mystring = 'Pulses(us)='
146 mystring += ','.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 mystring])])
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.
156 dsamples = self.sample_high
158 dsamples = self.sample_low
160 self.es = start + samples
161 while samples > dsamples * 0.5:
162 if samples >= dsamples * 1.5: # More than one bit.
163 self.es = self.ss + dsamples
164 self.putx([5, [state]])
165 self.decoded.append([self.ss, self.es, state])
167 elif samples >= dsamples * 0.5 and samples < dsamples * 1.5: # Last bit.
168 self.putx([5, [state]])
169 self.decoded.append([self.ss, self.es, state])
177 # Ensure 2nd row doesn't go past end of 1st row.
178 if self.es > self.samplenum:
179 self.es = self.samplenum
181 if self.state == 'DECODE_TIMEOUT': # Five bits - reset.
182 self.ss = self.decoded[0][0]
183 self.es = self.decoded[len(self.decoded) - 1][1]
184 self.dump_pulse_lengths()
185 self.putp(self.decoded)
186 self.decode_timeout()
189 def lock_onto_preamble(self, samples, state): # Filters and recovers clock.
191 l2s = 5 # Max ratio of long to short pulses.
193 # Filter incoming pulses to remove random noise.
194 if self.state == 'DECODE_TIMEOUT':
197 self.word_first = self.samplenum
198 self.sample_first = self.samplenum - self.samplenumber_last
199 self.state = 'WAITING_FOR_PREAMBLE'
202 pre_detect = int(self.preamble_len) # Number of valid pulses to detect.
203 pre_samples = self.samplenum - self.samplenumber_last
204 if len(self.preamble) > 0:
205 if (pre_samples * l2s < self.preamble[-1][1] or
206 self.preamble[-1][1] * l2s < pre_samples): # Garbage in.
207 self.put(self.samplenum, self.samplenum,
208 self.out_ann, [0, ['R']]) # Display resets.
209 self.preamble = [] # Clear buffer.
210 self.preamble.append([self.samplenumber_last,
213 self.samplenumber_last = self.samplenum
214 self.word_first = self.samplenum
216 self.preamble.append([self.samplenumber_last,
219 self.preamble.append([self.samplenumber_last,
223 if len(self.preamble) == pre_detect: # Have a valid series of pulses.
224 if self.preamble[0][2] == '1':
225 self.sample_high = self.preamble[0][1] # Allows skewed pulses.
226 self.sample_low = self.preamble[1][1]
228 self.sample_high = self.preamble[1][1]
229 self.sample_low = self.preamble[0][1]
233 for i in range(len(self.preamble)):
235 if (pre[i][1] > pre[i - 2][1] * 1.25 or
236 pre[i][1] * 1.25 < pre[i - 2][1]): # Adjust ref width.
238 self.sample_high = pre[i][1]
240 self.sample_low = pre[i][1]
242 # Display start of preamble.
243 if self.decodeas == 'NRZ':
244 self.decode_nrz(pre[i][0], pre[i][1], pre[i][2])
245 if self.decodeas == 'Manchester':
246 self.decode_manchester(pre[i][0], pre[i][1], pre[i][2])
247 if self.decodeas == 'Diff Manchester':
248 self.es = pre[i][0] + pre[i][1]
249 self.decode_diff_manchester(pre[i][0], pre[i][1], pre[i][2])
251 # Used to timeout signal.
252 self.sample_first = int((self.sample_high + self.sample_low)/2)
254 self.state = 'DECODING'
256 self.lstate_1010 = state
258 def decode_diff_manchester(self, start, samples, state):
259 self.pulse_lengths.append(samples)
261 # Use different high and low widths to compensate skewed waveforms.
263 dsamples = self.sample_high
265 dsamples = self.sample_low
267 self.es = start + samples
268 p_length = round(samples / dsamples) # Find relative pulse length.
270 if self.edge_count == 0:
271 self.diff_man_trans = '1' # Very first pulse must be a transition.
272 self.diff_man_len = 1 # Must also be a half pulse.
274 elif self.edge_count % 2 == 1: # Time to make a decision.
275 if self.diffmanvar == '0': # Transition at self.ss is a zero.
276 self.diff_man_trans = '0' if self.diff_man_trans == '1' else '1'
277 if self.diff_man_len == 1 and p_length == 1:
278 self.putx([4, [self.diff_man_trans]])
279 self.decoded.append([self.ss, self.es, self.diff_man_trans])
280 self.diff_man_trans = '1'
281 elif self.diff_man_len == 1 and p_length == 2:
282 self.es -= int(samples / 2)
283 self.putx([4, [self.diff_man_trans]])
284 self.decoded.append([self.ss, self.es, self.diff_man_trans])
285 self.diff_man_trans = '0'
286 self.edge_count += 1 # Add a virt edge to keep in sync with clk.
287 elif self.diff_man_len == 2 and p_length == 1:
288 self.putx([4, [self.diff_man_trans]])
289 self.decoded.append([self.ss, self.es, self.diff_man_trans])
290 self.diff_man_trans = '1'
291 elif self.diff_man_len == 2 and p_length == 2: # Double illegal E E.
293 self.putx([4, ['E']])
294 self.decoded.append([self.ss, self.es, 'E'])
297 self.putx([4, ['E']])
298 self.decoded.append([self.ss, self.es, 'E'])
299 self.diff_man_trans = '1'
300 elif self.diff_man_len == 1 and p_length > 4:
301 if self.state == 'DECODE_TIMEOUT':
302 self.es = self.ss + 2 * self.sample_first
303 self.putx([4, [self.diff_man_trans]]) # Write error.
304 self.decoded.append([self.ss, self.es, self.diff_man_trans])
305 self.ss = self.decoded[0][0]
306 self.es = self.decoded[len(self.decoded) - 1][1]
307 self.dump_pulse_lengths()
308 if self.man_errors < self.max_errors:
309 self.putp(self.decoded)
311 error_message = 'Probably not Diff Manchester encoded'
312 self.ss = self.word_first
313 self.putx([1, [error_message]])
314 self.decode_timeout()
315 self.diff_man_trans = '1'
317 self.diff_man_len = p_length # Save the previous length.
320 def decode_manchester_sim(self, start, samples, state,
321 dsamples, half_time, lstate, ss, pream):
324 if self.edge_count == 0:
326 if samples > 0.75 * dsamples and samples <= 1.5 * dsamples: # Long p.
328 if half_time % 2 == 0: # Transition.
331 es = start + int(samples / 2)
335 if not (self.edge_count == 0 and pream == '1010'): # Skip first p.
336 ook_bit = [ss, es, lstate]
339 elif samples > 0.25 * dsamples and samples <= 0.75 * dsamples: # Short p.
341 if (half_time % 2 == 0): # Transition.
343 ook_bit = [ss, es, lstate]
349 else: # Too long or too short - error.
351 if self.state != 'DECODE_TIMEOUT': # Error condition.
354 else: # Assume final half bit buried in timeout pulse.
355 es = ss + self.sample_first
356 ook_bit = [ss, es, lstate]
359 return (half_time, lstate, ss, ook_bit, errors)
361 def decode_manchester(self, start, samples, state):
362 self.pulse_lengths.append(samples)
364 # Use different high and low widths to compensate skewed waveforms.
366 dsamples = self.sample_high
368 dsamples = self.sample_low
370 if self.preamble_val != '1010': # 1111 preamble is half clock T.
371 (self.half_time, self.lstate, self.ss_1111, ook_bit, errors) = (
372 self.decode_manchester_sim(start, samples, state, dsamples * 2,
373 self.half_time, self.lstate,
374 self.ss_1111, '1111'))
375 self.man_errors += errors
377 self.decoded.append([ook_bit[0], ook_bit[1], ook_bit[2]])
379 if self.preamble_val != '1111': # 1010 preamble is clock T.
380 (self.half_time_1010, self.lstate_1010, self.ss_1010,
382 self.decode_manchester_sim(start, samples, state, dsamples,
383 self.half_time_1010, self.lstate_1010,
384 self.ss_1010, '1010'))
385 self.man_errors_1010 += errors
387 self.decoded_1010.append([ook_bit[0], ook_bit[1], ook_bit[2]])
391 # Stream display and save ook_bit.
395 if self.preamble_val == '1111':
396 self.putx([2, [ook_bit[2]]])
397 if self.preamble_val == '1010':
398 self.putx([3, [ook_bit[2]]])
400 if self.state == 'DECODE_TIMEOUT': # End of packet.
401 self.dump_pulse_lengths()
404 # If 1010 preamble has less errors use it.
405 if (self.preamble_val == '1010' or
406 (self.man_errors_1010 < self.max_errors and
407 self.man_errors_1010 < self.man_errors and
408 len(self.decoded_1010) > 0)):
409 decoded = self.decoded_1010
410 man_errors = self.man_errors_1010
413 decoded = self.decoded
414 man_errors = self.man_errors
417 if self.preamble_val == 'auto': # Display OOK packet.
418 for i in range(len(decoded)):
419 self.ss = decoded[i][0]
420 self.es = decoded[i][1]
421 self.putx([d_row, [decoded[i][2]]])
423 if (man_errors < self.max_errors and len(decoded) > 0):
424 self.ss = decoded[0][0]
425 self.es = decoded[len(decoded) - 1][1]
428 error_message = 'Not Manchester encoded or wrong preamble'
429 self.ss = self.word_first
430 self.putx([1, [error_message]])
432 self.put(self.es, self.es, self.out_ann, [0, ['T']]) # Mark timeout.
433 self.decode_timeout()
435 def decode_timeout(self):
437 self.samplenumber_last = None
439 self.man_errors = 0 # Clear the bit error counters.
440 self.man_errors_1010 = 0
442 self.wait({0: 'e'}) # Get rid of long pulse.
443 self.samplenumber_last = self.samplenum
444 self.word_first = self.samplenum
445 self.insync = 0 # Preamble in sync flag
446 self.preamble = [] # Preamble buffer
447 self.half_time = -1 # Half time for man 1111
448 self.half_time_1010 = 0 # Half time for man 1010
449 self.decoded = [] # Decoded bits
450 self.decoded_1010 = [] # Decoded bits for man 1010
451 self.pulse_lengths = []
455 if self.edge_count == 0: # Waiting for a signal.
456 pin = self.wait({0: 'e'})
457 self.state = 'DECODING'
459 pin = self.wait([{0: 'e'}, {'skip': 5 * self.sample_first}])
460 if self.matched[1] and not self.matched[0]: # No edges for 5 p's.
461 self.state = 'DECODE_TIMEOUT'
463 if not self.samplenumber_last: # Set counters to start of signal.
464 self.samplenumber_last = self.samplenum
465 self.word_first = self.samplenum
467 samples = self.samplenum - self.samplenumber_last
468 if not self.sample_first: # Get number of samples for first pulse.
469 self.sample_first = samples
472 if self.state == 'DECODE_TIMEOUT': # No edge so flip the state.
473 pinstate = int(not pinstate)
474 if self.invert == 'yes': # Invert signal.
475 pinstate = int(not pinstate)
481 # No preamble filtering or checking and no skew correction.
482 if self.preamble_len == '0':
483 self.sample_high = self.sample_first
484 self.sample_low = self.sample_first
488 self.lock_onto_preamble(samples, state)
490 if self.decodeas == 'NRZ':
491 self.decode_nrz(self.samplenumber_last, samples, state)
492 if self.decodeas == 'Manchester':
493 self.decode_manchester(self.samplenumber_last,
495 if self.decodeas == 'Diff Manchester':
496 self.decode_diff_manchester(self.samplenumber_last,
499 self.samplenumber_last = self.samplenum