]>
Commit | Line | Data |
---|---|---|
538d386b S |
1 | ## |
2 | ## This file is part of the libsigrokdecode project. | |
3 | ## | |
4 | ## Copyright (C) 2018 Steve R <steversig@virginmedia.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, see <http://www.gnu.org/licenses/>. | |
18 | ## | |
19 | ||
20 | import sigrokdecode as srd | |
21 | ||
22 | ''' | |
23 | OUTPUT_PYTHON format: | |
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 | |
28 | Manchester encoding. | |
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. | |
31 | This can be | |
32 | '0' zero or low | |
33 | '1' one or high | |
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. | |
38 | ||
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. | |
43 | ''' | |
44 | ||
45 | class SamplerateError(Exception): | |
46 | pass | |
47 | ||
48 | class Decoder(srd.Decoder): | |
49 | api_version = 3 | |
50 | id = 'ook' | |
51 | name = 'OOK' | |
52 | longname = 'On-off keying' | |
53 | desc = 'On-off keying protocol.' | |
54 | license = 'gplv2+' | |
55 | inputs = ['logic'] | |
56 | outputs = ['ook'] | |
d6d8a8a4 | 57 | tags = ['Encoding'] |
538d386b S |
58 | channels = ( |
59 | {'id': 'data', 'name': 'Data', 'desc': 'Data line'}, | |
60 | ) | |
61 | annotations = ( | |
62 | ('frame', 'Frame'), | |
63 | ('info', 'Info'), | |
64 | ('1111', '1111'), | |
65 | ('1010', '1010'), | |
66 | ('diffman', 'Diff Man'), | |
67 | ('nrz', 'NRZ'), | |
68 | ) | |
69 | annotation_rows = ( | |
70 | ('frame', 'Framing',(0,)), | |
71 | ('info', 'Info', (1,)), | |
72 | ('man1111', 'Man 1111', (2,)), | |
73 | ('man1010', 'Man 1010', (3,)), | |
74 | ('diffman', 'Diff Man', (4,)), | |
75 | ('nrz', 'NRZ', (5,)), | |
76 | ) | |
77 | binary = ( | |
78 | ('pulse-lengths', 'Pulse lengths'), | |
79 | ) | |
80 | options = ( | |
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')}, | |
91 | ) | |
92 | ||
93 | def __init__(self): | |
94 | self.reset() | |
95 | ||
96 | def reset(self): | |
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 | |
102 | self.sample_high = 0 | |
103 | self.sample_low = 0 | |
104 | self.edge_count = 0 | |
105 | self.word_first = None | |
106 | self.word_count = 0 | |
107 | self.state = 'IDLE' | |
108 | self.lstate = None | |
109 | self.lstate_1010 = None | |
110 | self.insync = 0 # Preamble in sync flag | |
111 | self.man_errors = 0 | |
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 | |
122 | ||
123 | def metadata(self, key, value): | |
124 | if key == srd.SRD_CONF_SAMPLERATE: | |
125 | self.samplerate = value | |
126 | ||
127 | def start(self): | |
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'] | |
136 | ||
137 | def putx(self, data): | |
138 | self.put(self.ss, self.es, self.out_ann, data) | |
139 | ||
140 | def putp(self, data): | |
141 | self.put(self.ss, self.es, self.out_python, data) | |
142 | ||
143 | def dump_pulse_lengths(self): | |
144 | if self.samplerate: | |
145 | self.pulse_lengths[-1] = self.sample_first # Fix final pulse length. | |
ca4a1d1d UH |
146 | s = 'Pulses(us)=' |
147 | s += ','.join(str(int(int(x) * 1000000 / self.samplerate)) | |
148 | for x in self.pulse_lengths) | |
149 | s += '\n' | |
538d386b | 150 | self.put(self.samplenum - 10, self.samplenum, self.out_binary, |
ca4a1d1d | 151 | [0, bytes([ord(c) for c in s])]) |
538d386b S |
152 | |
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. | |
ca4a1d1d UH |
156 | dsamples = self.sample_high if state == '1' else self.sample_low |
157 | self.ss, self.es = start, start + samples | |
538d386b S |
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]) | |
163 | self.edge_count += 1 | |
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]) | |
167 | self.edge_count += 1 | |
168 | else: | |
169 | self.edge_count += 1 | |
170 | samples -= dsamples | |
171 | self.ss += dsamples | |
172 | self.es += dsamples | |
173 | ||
174 | # Ensure 2nd row doesn't go past end of 1st row. | |
175 | if self.es > self.samplenum: | |
176 | self.es = self.samplenum | |
177 | ||
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() | |
184 | break | |
185 | ||
186 | def lock_onto_preamble(self, samples, state): # Filters and recovers clock. | |
187 | self.edge_count += 1 | |
188 | l2s = 5 # Max ratio of long to short pulses. | |
189 | ||
190 | # Filter incoming pulses to remove random noise. | |
191 | if self.state == 'DECODE_TIMEOUT': | |
192 | self.preamble = [] | |
2dfe0986 | 193 | self.edge_count = 0 |
538d386b S |
194 | self.word_first = self.samplenum |
195 | self.sample_first = self.samplenum - self.samplenumber_last | |
196 | self.state = 'WAITING_FOR_PREAMBLE' | |
197 | self.man_errors = 0 | |
198 | ||
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, | |
208 | pre_samples, state]) | |
2dfe0986 | 209 | self.edge_count = 0 |
538d386b S |
210 | self.samplenumber_last = self.samplenum |
211 | self.word_first = self.samplenum | |
212 | else: | |
213 | self.preamble.append([self.samplenumber_last, | |
214 | pre_samples, state]) | |
215 | else: | |
216 | self.preamble.append([self.samplenumber_last, | |
217 | pre_samples, state]) | |
218 | ||
219 | pre = self.preamble | |
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] | |
224 | else: | |
225 | self.sample_high = self.preamble[1][1] | |
226 | self.sample_low = self.preamble[0][1] | |
227 | ||
228 | self.edge_count = 0 | |
229 | ||
230 | for i in range(len(self.preamble)): | |
231 | if i > 1: | |
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. | |
234 | if pre[i][2] == '1': | |
235 | self.sample_high = pre[i][1] | |
236 | else: | |
237 | self.sample_low = pre[i][1] | |
238 | ||
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]) | |
247 | ||
248 | # Used to timeout signal. | |
249 | self.sample_first = int((self.sample_high + self.sample_low)/2) | |
250 | self.insync = 1 | |
251 | self.state = 'DECODING' | |
252 | self.lstate = state | |
253 | self.lstate_1010 = state | |
254 | ||
255 | def decode_diff_manchester(self, start, samples, state): | |
256 | self.pulse_lengths.append(samples) | |
257 | ||
258 | # Use different high and low widths to compensate skewed waveforms. | |
ca4a1d1d | 259 | dsamples = self.sample_high if state == '1' else self.sample_low |
538d386b S |
260 | |
261 | self.es = start + samples | |
262 | p_length = round(samples / dsamples) # Find relative pulse length. | |
263 | ||
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. | |
267 | self.ss = start | |
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. | |
286 | self.es -= samples | |
287 | self.putx([4, ['E']]) | |
288 | self.decoded.append([self.ss, self.es, 'E']) | |
289 | self.ss = self.es | |
290 | self.es += samples | |
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) | |
304 | else: | |
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' | |
310 | self.ss = self.es | |
311 | self.diff_man_len = p_length # Save the previous length. | |
312 | self.edge_count += 1 | |
313 | ||
314 | def decode_manchester_sim(self, start, samples, state, | |
315 | dsamples, half_time, lstate, ss, pream): | |
316 | ook_bit = [] | |
317 | errors = 0 | |
318 | if self.edge_count == 0: | |
319 | half_time += 1 | |
320 | if samples > 0.75 * dsamples and samples <= 1.5 * dsamples: # Long p. | |
321 | half_time += 2 | |
322 | if half_time % 2 == 0: # Transition. | |
323 | es = start | |
324 | else: | |
325 | es = start + int(samples / 2) | |
326 | if ss == start: | |
327 | lstate = 'E' | |
328 | es = start + samples | |
329 | if not (self.edge_count == 0 and pream == '1010'): # Skip first p. | |
330 | ook_bit = [ss, es, lstate] | |
331 | lstate = state | |
332 | ss = es | |
333 | elif samples > 0.25 * dsamples and samples <= 0.75 * dsamples: # Short p. | |
334 | half_time += 1 | |
335 | if (half_time % 2 == 0): # Transition. | |
336 | es = start + samples | |
337 | ook_bit = [ss, es, lstate] | |
338 | lstate = state | |
339 | ss = es | |
340 | else: # 1st half. | |
341 | ss = start | |
342 | lstate = state | |
343 | else: # Too long or too short - error. | |
344 | errors = 1 | |
345 | if self.state != 'DECODE_TIMEOUT': # Error condition. | |
346 | lstate = 'E' | |
347 | es = ss + samples | |
348 | else: # Assume final half bit buried in timeout pulse. | |
349 | es = ss + self.sample_first | |
350 | ook_bit = [ss, es, lstate] | |
351 | ss = es | |
352 | ||
353 | return (half_time, lstate, ss, ook_bit, errors) | |
354 | ||
355 | def decode_manchester(self, start, samples, state): | |
356 | self.pulse_lengths.append(samples) | |
357 | ||
358 | # Use different high and low widths to compensate skewed waveforms. | |
ca4a1d1d | 359 | dsamples = self.sample_high if state == '1' else self.sample_low |
538d386b S |
360 | |
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 | |
367 | if ook_bit != []: | |
368 | self.decoded.append([ook_bit[0], ook_bit[1], ook_bit[2]]) | |
369 | ||
370 | if self.preamble_val != '1111': # 1010 preamble is clock T. | |
371 | (self.half_time_1010, self.lstate_1010, self.ss_1010, | |
372 | ook_bit, errors) = ( | |
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 | |
377 | if ook_bit != []: | |
378 | self.decoded_1010.append([ook_bit[0], ook_bit[1], ook_bit[2]]) | |
379 | ||
380 | self.edge_count += 1 | |
381 | ||
382 | # Stream display and save ook_bit. | |
383 | if ook_bit != []: | |
ca4a1d1d | 384 | self.ss, self.es = ook_bit[0], ook_bit[1] |
538d386b S |
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]]]) | |
389 | ||
390 | if self.state == 'DECODE_TIMEOUT': # End of packet. | |
391 | self.dump_pulse_lengths() | |
392 | ||
393 | decoded = [] | |
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 | |
401 | d_row = 3 | |
402 | else: | |
403 | decoded = self.decoded | |
404 | man_errors = self.man_errors | |
405 | d_row = 2 | |
406 | ||
407 | if self.preamble_val == 'auto': # Display OOK packet. | |
408 | for i in range(len(decoded)): | |
ca4a1d1d | 409 | self.ss, self.es = decoded[i][0], decoded[i][1] |
538d386b S |
410 | self.putx([d_row, [decoded[i][2]]]) |
411 | ||
412 | if (man_errors < self.max_errors and len(decoded) > 0): | |
ca4a1d1d | 413 | self.ss, self.es = decoded[0][0], decoded[len(decoded) - 1][1] |
538d386b S |
414 | self.putp(decoded) |
415 | else: | |
416 | error_message = 'Not Manchester encoded or wrong preamble' | |
417 | self.ss = self.word_first | |
418 | self.putx([1, [error_message]]) | |
419 | ||
420 | self.put(self.es, self.es, self.out_ann, [0, ['T']]) # Mark timeout. | |
421 | self.decode_timeout() | |
422 | ||
423 | def decode_timeout(self): | |
424 | self.word_count = 0 | |
425 | self.samplenumber_last = None | |
426 | self.edge_count = 0 | |
427 | self.man_errors = 0 # Clear the bit error counters. | |
428 | self.man_errors_1010 = 0 | |
429 | self.state = 'IDLE' | |
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 = [] | |
440 | ||
441 | def decode(self): | |
442 | while True: | |
443 | if self.edge_count == 0: # Waiting for a signal. | |
444 | pin = self.wait({0: 'e'}) | |
445 | self.state = 'DECODING' | |
446 | else: | |
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' | |
450 | ||
451 | if not self.samplenumber_last: # Set counters to start of signal. | |
452 | self.samplenumber_last = self.samplenum | |
453 | self.word_first = self.samplenum | |
454 | continue | |
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 | |
458 | ||
459 | pinstate = pin[0] | |
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) | |
ca4a1d1d | 464 | state = '0' if pinstate else '1' |
538d386b S |
465 | |
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 | |
470 | self.insync = 0 | |
471 | ||
472 | if self.insync == 0: | |
473 | self.lock_onto_preamble(samples, state) | |
474 | else: | |
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, | |
479 | samples, state) | |
480 | if self.decodeas == 'Diff Manchester': | |
481 | self.decode_diff_manchester(self.samplenumber_last, | |
482 | samples, state) | |
483 | ||
484 | self.samplenumber_last = self.samplenum |