ook_vis: Minor code simplifications.
[libsigrokdecode.git] / decoders / ook_vis / pd.py
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 from common.srdhelper import bcd2int
22
23 class Decoder(srd.Decoder):
24     api_version = 3
25     id = 'ook_vis'
26     name = 'OOK visualisation'
27     longname = 'On-off keying visualisation'
28     desc = 'OOK visualisation in various formats.'
29     license = 'gplv2+'
30     inputs = ['ook']
31     outputs = ['ook']
32     annotations = (
33         ('bit', 'Bit'),
34         ('ref', 'Reference'),
35         ('field', 'Field'),
36         ('ref_field', 'Ref field'),
37         ('level2', 'L2'),
38         ('ref_level2', 'Ref L2'),
39     )
40     annotation_rows = (
41         ('bits', 'Bits', (0,)),
42         ('compare', 'Compare', (1,)),
43         ('fields', 'Fields', (2,)),
44         ('ref_fields', 'Ref fields', (3,)),
45         ('level2', 'L2', (4,)),
46         ('ref_level2', 'Ref L2', (5,)),
47     )
48     options = (
49         {'id': 'displayas', 'desc': 'Display as', 'default': 'Nibble - Hex',
50          'values': ('Byte - Hex', 'Byte - Hex rev', 'Byte - BCD',
51          'Byte - BCD rev', 'Nibble - Hex', 'Nibble - Hex rev', 'Nibble - BCD',
52          'Nibble - BCD rev')},
53         {'id': 'synclen', 'desc': 'Sync length', 'default': '4',
54          'values': ('0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '10')},
55         {'id': 'syncoffset', 'desc': 'Sync offset', 'default': '0',
56          'values': ('-4', '-3', '-2', '-1', '0', '1', '2', '3', '4')},
57         {'id': 'refsample', 'desc': 'Compare', 'default': 'off', 'values':
58         ('off', 'show numbers', '1', '2', '3', '4', '5', '6', '7', '8', '9',
59          '10', '11', '12', '13', '14', '15', '16', '17', '18', '19', '20',
60          '21', '22', '23', '24', '25', '26', '27', '28', '29', '30')},
61     )
62
63     def __init__(self):
64         self.reset()
65
66     def reset(self):
67         self.decoded = [] # Local cache of decoded OOK.
68         self.ookstring = ''
69         self.ookcache = []
70         self.trace_num = 0
71
72     def start(self):
73         self.out_ann = self.register(srd.OUTPUT_ANN)
74         self.out_python = self.register(srd.OUTPUT_PYTHON)
75         self.displayas = self.options['displayas']
76         self.sync_length = self.options['synclen']
77         self.sync_offset = self.options['syncoffset']
78         self.ref = self.options['refsample']
79
80     def putx(self, data):
81         self.put(self.ss, self.es, self.out_ann, data)
82
83     def putp(self, data):
84         self.put(self.ss, self.es, self.out_python, data)
85
86     def display_level2(self, bits, line):
87         self.decode_pos = 0
88         ook = self.decoded
89         # Find the end of the preamble which could be 1010 or 1111.
90         if len(ook) > 1:
91             preamble_end = len(ook) + 1
92             char_first = ook[0][2]
93             char_second = ook[1][2]
94             if char_first == char_second: # 1111
95                 preamble = '1111'
96                 char_last = char_first
97             else:
98                 preamble = '1010'
99                 char_last = char_second
100             for i in range(len(ook)):
101                 if preamble == '1111':
102                     if ook[i][2] != char_last:
103                         preamble_end = i
104                         break
105                     else:
106                         char_last = ook[i][2]
107                 else:
108                     if ook[i][2] != char_last:
109                         char_last = ook[i][2]
110                     else:
111                         preamble_end = i
112                         break
113
114             if len(ook) >= preamble_end:
115                 preamble_end += int(self.sync_offset) - 1
116                 self.ss, self.es = ook[0][0], ook[preamble_end][1]
117                 self.putx([line, ['Preamble', 'Pre', 'P']])
118                 self.decode_pos += preamble_end
119
120                 if len(ook) > self.decode_pos + int(self.sync_length):
121                     self.ss = self.es
122                     self.es = ook[self.decode_pos + int(self.sync_length)][1]
123                     self.putx([line, ['Sync', 'Syn', 'S']])
124                     self.decode_pos += int(self.sync_length) + 1
125
126                 ookstring = self.ookstring[self.decode_pos:]
127                 rem_nibbles = len(ookstring) // bits
128                 for i in range(rem_nibbles): # Display the rest of nibbles.
129                     self.ss = ook[self.decode_pos][0]
130                     self.es = ook[self.decode_pos + bits - 1][1]
131                     self.put_field(bits, line)
132
133     def put_field(self, numbits, line):
134         param = self.ookstring[self.decode_pos:self.decode_pos + numbits]
135         if 'rev' in self.displayas:
136             param = param[::-1]     # Reversed from right.
137         if not 'E' in param:        # Format if no errors.
138             if 'Hex' in self.displayas:
139                 param = hex(int(param, 2))[2:]
140             elif 'BCD' in self.displayas:
141                 param = bcd2int(int(param, 2))
142         self.putx([line, [str(param)]])
143         self.decode_pos += numbits
144
145     def display_all(self):
146         ookstring = ''
147         self.decode_pos = 0
148         ook = self.decoded
149         for i in range(len(ook)):
150             self.ookstring += ook[i][2]
151         bits = 4 if 'Nibble' in self.displayas else 8
152         rem_nibbles = len(self.ookstring) // bits
153         for i in range(rem_nibbles): # Display the rest of the nibbles.
154             self.ss = ook[self.decode_pos][0]
155             self.es = ook[self.decode_pos + bits - 1][1]
156             self.put_field(bits, 2)
157
158         self.display_level2(bits, 4) # Display L2 decode.
159
160         if (self.ref != 'off' and self.ref != 'show numbers' and
161             len(self.ookcache) >= int(self.ref)): # Compare traces.
162             ref = int(self.ref) - 1
163             self.display_ref(self.trace_num, ref)
164             if len(self.ookcache) == int(self.ref): # Backfill.
165                 for i in range(0, ref):
166                     self.display_ref(i, ref)
167         elif self.ref == 'show numbers': # Display ref numbers.
168             self.ss = self.ookcache[self.trace_num][0][0]
169             end_sig = len(self.ookcache[self.trace_num]) - 1
170             self.es = self.ookcache[self.trace_num][end_sig][1]
171             self.putx([1, [str(self.trace_num + 1)]])
172
173     def display_ref(self, t_num, ref):
174         display_len = len(self.ookcache[ref])
175         if len(self.ookcache[t_num]) < len(self.ookcache[ref]):
176             display_len = len(self.ookcache[t_num])
177         for i in range(display_len):
178             self.ss = self.ookcache[t_num][i][0]
179             self.es = self.ookcache[t_num][i][1]
180             self.putx([1, [self.ookcache[ref][i][2]]])
181
182     def add_to_cache(self): # Cache the OOK so it can be used as a reference.
183         self.ookcache.append(self.decoded)
184
185     def decode(self, ss, es, data):
186         self.decoded = data
187         self.add_to_cache()
188         self.display_all()
189         self.ookstring = ''
190         self.trace_num += 1
191         self.ss = ss
192         self.es = es
193         self.putp(data) # Send data up the stack.