9bbd37fdf1fd13032bfb60ac34a14870fa8368b3
[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 = ook[0][0]
117                 self.es = ook[preamble_end][1]
118                 self.putx([line, ['Preamble', 'Pre', 'P']])
119                 self.decode_pos += preamble_end
120
121                 if len(ook) > self.decode_pos + int(self.sync_length):
122                     self.ss = self.es
123                     self.es = ook[self.decode_pos + int(self.sync_length)][1]
124                     self.putx([line, ['Sync', 'Syn', 'S']])
125                     self.decode_pos += int(self.sync_length) + 1
126
127                 ookstring = self.ookstring[self.decode_pos:]
128                 rem_nibbles = len(ookstring) // bits
129                 for i in range(rem_nibbles): # Display the rest of nibbles.
130                     self.ss = ook[self.decode_pos][0]
131                     self.es = ook[self.decode_pos + bits - 1][1]
132                     self.put_field(bits, line)
133
134     def put_field(self, numbits, line):
135         param = self.ookstring[self.decode_pos:self.decode_pos + numbits]
136         if 'rev' in self.displayas:
137             param = param[::-1]     # Reversed from right.
138         if not 'E' in param:        # Format if no errors.
139             if 'Hex' in self.displayas:
140                 param = hex(int(param, 2))[2:]
141             elif 'BCD' in self.displayas:
142                 param = bcd2int(int(param, 2))
143         self.putx([line, [str(param)]])
144         self.decode_pos += numbits
145
146     def display_all(self):
147         ookstring = ''
148         self.decode_pos = 0
149         ook = self.decoded
150         for i in range(len(ook)):
151             self.ookstring += ook[i][2]
152         if 'Nibble' in self.displayas:
153             bits = 4
154         else:
155             bits = 8
156         rem_nibbles = len(self.ookstring) // bits
157         for i in range(rem_nibbles): # Display the rest of the nibbles.
158             self.ss = ook[self.decode_pos][0]
159             self.es = ook[self.decode_pos + bits - 1][1]
160             self.put_field(bits, 2)
161
162         self.display_level2(bits, 4) # Display L2 decode.
163
164         if (self.ref != 'off' and self.ref != 'show numbers' and
165             len(self.ookcache) >= int(self.ref)): # Compare traces.
166             ref = int(self.ref) - 1
167             self.display_ref(self.trace_num, ref)
168             if len(self.ookcache) == int(self.ref): # Backfill.
169                 for i in range(0, ref):
170                     self.display_ref(i, ref)
171         elif self.ref == 'show numbers': # Display ref numbers.
172             self.ss = self.ookcache[self.trace_num][0][0]
173             end_sig = len(self.ookcache[self.trace_num]) - 1
174             self.es = self.ookcache[self.trace_num][end_sig][1]
175             self.putx([1, [str(self.trace_num + 1)]])
176
177     def display_ref(self, t_num, ref):
178         display_len = len(self.ookcache[ref])
179         if len(self.ookcache[t_num]) < len(self.ookcache[ref]):
180             display_len = len(self.ookcache[t_num])
181         for i in range(display_len):
182             self.ss = self.ookcache[t_num][i][0]
183             self.es = self.ookcache[t_num][i][1]
184             self.putx([1, [self.ookcache[ref][i][2]]])
185
186     def add_to_cache(self): # Cache the OOK so it can be used as a reference.
187         self.ookcache.append(self.decoded)
188
189     def decode(self, ss, es, data):
190         self.decoded = data
191         self.add_to_cache()
192         self.display_all()
193         self.ookstring = ''
194         self.trace_num += 1
195         self.ss = ss
196         self.es = es
197         self.putp(data) # Send data up the stack.