]> sigrok.org Git - libsigrokdecode.git/blob - decoders/wiegand/pd.py
graycode, morse, pwm, usb_request, wiegand: cope with absent sample rate
[libsigrokdecode.git] / decoders / wiegand / pd.py
1 ##
2 ## This file is part of the libsigrokdecode project.
3 ##
4 ## Copyright (C) 2016 Sean Burford <sburford@google.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 class SamplerateError(Exception):
23     pass
24
25 class Decoder(srd.Decoder):
26     api_version = 3
27     id = 'wiegand'
28     name = 'Wiegand'
29     longname = 'Wiegand interface'
30     desc = 'Wiegand interface for electronic entry systems.'
31     license = 'gplv2+'
32     inputs = ['logic']
33     outputs = ['wiegand']
34     channels = (
35         {'id': 'd0', 'name': 'D0', 'desc': 'Data 0 line'},
36         {'id': 'd1', 'name': 'D1', 'desc': 'Data 1 line'},
37     )
38     options = (
39         {'id': 'active', 'desc': 'Data lines active level',
40          'default': 'low', 'values': ('low', 'high')},
41         {'id': 'bitwidth_ms', 'desc': 'Single bit width in milliseconds',
42          'default': 4, 'values': (1, 2, 4, 8, 16, 32)},
43     )
44     annotations = (
45         ('bits', 'Bits'),
46         ('state', 'State'),
47     )
48     annotation_rows = (
49         ('bits', 'Binary value', (0,)),
50         ('state', 'Stream state', (1,)),
51     )
52
53     def __init__(self):
54         self.reset()
55
56     def reset(self):
57         self.samplerate = None
58         self._samples_per_bit = 10
59
60         self._d0_prev = None
61         self._d1_prev = None
62
63         self._state = None
64         self.ss_state = None
65
66         self.ss_bit = None
67         self.es_bit = None
68         self._bit = None
69         self._bits = []
70
71     def start(self):
72         'Register output types and verify user supplied decoder values.'
73         self.out_ann = self.register(srd.OUTPUT_ANN)
74         self._active = 1 if self.options['active'] == 'high' else 0
75         self._inactive = 1 - self._active
76
77     def metadata(self, key, value):
78         'Receive decoder metadata about the data stream.'
79         if key == srd.SRD_CONF_SAMPLERATE:
80             self.samplerate = value
81             if self.samplerate:
82                 ms_per_sample = 1000 * (1.0 / self.samplerate)
83                 ms_per_bit = float(self.options['bitwidth_ms'])
84                 self._samples_per_bit = int(max(1, int(ms_per_bit / ms_per_sample)))
85
86     def _update_state(self, state, bit=None):
87         'Update state and bit values when they change.'
88         if self._bit is not None:
89             self._bits.append(self._bit)
90             self.put(self.ss_bit, self.samplenum, self.out_ann,
91                      [0, [str(self._bit)]])
92         self._bit = bit
93         self.ss_bit = self.samplenum
94         if bit is not None:
95             # Set a timeout so that the final bit ends.
96             self.es_bit = self.samplenum + self._samples_per_bit
97         else:
98             self.es_bit = None
99
100         if state != self._state:
101             ann = None
102             if self._state == 'data':
103                 accum_bits = ''.join(str(x) for x in self._bits)
104                 ann = [1, ['%d bits %s' % (len(self._bits), accum_bits),
105                            '%d bits' % len(self._bits)]]
106             elif self._state == 'invalid':
107                 ann = [1, [self._state]]
108             if ann:
109                 self.put(self.ss_state, self.samplenum, self.out_ann, ann)
110             self.ss_state = self.samplenum
111             self._state = state
112             self._bits = []
113
114     def decode(self):
115         if not self.samplerate:
116             raise SamplerateError('Cannot decode without samplerate.')
117         while True:
118             # TODO: Come up with more appropriate self.wait() conditions.
119             (d0, d1) = self.wait()
120
121             if d0 == self._d0_prev and d1 == self._d1_prev:
122                 if self.es_bit and self.samplenum >= self.es_bit:
123                     if (d0, d1) == (self._inactive, self._inactive):
124                         self._update_state('idle')
125                     else:
126                         self._update_state('invalid')
127                 continue
128
129             if self._state in (None, 'idle', 'data'):
130                 if (d0, d1) == (self._active, self._inactive):
131                     self._update_state('data', 0)
132                 elif (d0, d1) == (self._inactive, self._active):
133                     self._update_state('data', 1)
134                 elif (d0, d1) == (self._active, self._active):
135                     self._update_state('invalid')
136             elif self._state == 'invalid':
137                 # Wait until we see an idle state before leaving invalid.
138                 # This prevents inverted lines from being misread.
139                 if (d0, d1) == (self._inactive, self._inactive):
140                     self._update_state('idle')
141
142             self._d0_prev, self._d1_prev = d0, d1
143
144     def report(self):
145         return '%s: %s D0 %d D1 %d (active on %d), %d samples per bit' % (
146             self.name, self._state, self._d0_prev, self._d1_prev,
147             self._active, self._samples_per_bit)