]> sigrok.org Git - libsigrokdecode.git/blob - decoders/caliper/pd.py
6d07a8714654f8cf3395f301d1c0d28b5a887cf1
[libsigrokdecode.git] / decoders / caliper / pd.py
1 ##
2 ## This file is part of the libsigrokdecode project.
3 ##
4 ## Copyright (C) 2020 Tomas Mudrunka <harvie@github>
5 ##
6 ## Permission is hereby granted, free of charge, to any person obtaining a copy
7 ## of this software and associated documentation files (the "Software"), to deal
8 ## in the Software without restriction, including without limitation the rights
9 ## to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 ## copies of the Software, and to permit persons to whom the Software is
11 ## furnished to do so, subject to the following conditions:
12 ##
13 ## The above copyright notice and this permission notice shall be included in all
14 ## copies or substantial portions of the Software.
15 ##
16 ## THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 ## IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 ## FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 ## AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 ## LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 ## OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 ## SOFTWARE.
23
24 import sigrokdecode as srd
25
26 class Decoder(srd.Decoder):
27     api_version = 3
28     id = 'caliper'
29     name = 'Caliper'
30     longname = 'Digital calipers'
31     desc = 'Protocol of cheap generic digital calipers.'
32     license = 'mit'
33     inputs = ['logic']
34     outputs = []
35     channels = (
36         {'id': 'clk', 'name': 'CLK', 'desc': 'Serial clock line'},
37         {'id': 'data', 'name': 'DATA', 'desc': 'Serial data line'},
38     )
39     options = (
40         {'id': 'timeout_ms', 'desc': 'Packet timeout in ms, 0 to disable',
41             'default': 10},
42         {'id': 'unit', 'desc': 'Convert units', 'default': 'keep',
43             'values': ('keep', 'mm', 'inch')},
44         {'id': 'changes', 'desc': 'Changes only', 'default': 'no',
45             'values': ('no', 'yes')},
46     )
47     tags = ['Analog/digital', 'Sensor']
48     annotations = (
49         ('measurement', 'Measurement'),
50         ('warning', 'Warning'),
51     )
52     annotation_rows = (
53         ('measurements', 'Measurements', (0,)),
54         ('warnings', 'Warnings', (1,)),
55     )
56
57     def metadata(self, key, value):
58        if key == srd.SRD_CONF_SAMPLERATE:
59             self.samplerate = value
60
61     def __init__(self):
62         self.reset()
63
64     def reset(self):
65         self.ss_cmd, self.es_cmd = 0, 0
66         self.bits = 0
67         self.number = 0
68         self.flags = 0
69
70     def start(self):
71         self.out_ann = self.register(srd.OUTPUT_ANN)
72
73     def putg(self, ss, es, cls, data):
74         self.put(ss, es, self.out_ann, [cls, data])
75
76     # Switch bit order of variable x, which is l bit long.
77     def bitr(self, x, l):
78         return int(bin(x)[2:].zfill(l)[::-1], 2)
79
80     def decode(self):
81         last_measurement = None
82         timeout_ms = self.options['timeout_ms']
83         want_unit = self.options['unit']
84         show_all = self.options['changes'] == 'no'
85         while True:
86             clk, data = self.wait([{0: 'r'}, {'skip': round(self.samplerate / 1000)}])
87
88             # Timeout after inactivity.
89             if timeout_ms > 0:
90                 if self.samplenum > self.es_cmd + (self.samplerate / (1000 / timeout_ms)):
91                     if self.bits > 0:
92                         self.putg(self.ss_cmd, self.samplenum, 1, [
93                             'timeout with %s bits in buffer' % (self.bits),
94                             'timeout',
95                         ])
96                     self.reset()
97
98             # Do nothing if there was timeout without rising clock edge.
99             if self.matched == (False, True):
100                 continue
101
102             # Store position of last activity.
103             self.es_cmd = self.samplenum
104
105             # Store position of first bit.
106             if self.ss_cmd == 0:
107                 self.ss_cmd = self.samplenum
108
109             # Shift in measured number.
110             if self.bits < 16:
111                 self.number = (self.number << 1) | (data & 0b1)
112                 self.bits += 1
113                 continue
114
115             # Shift in flag bits.
116             if self.bits < 24:
117                 self.flags = (self.flags << 1) | (data & 0b1)
118                 self.bits += 1
119                 if self.bits < 24:
120                     continue
121                 # We got last bit of data.
122                 self.es_cmd = self.samplenum
123
124             # Do actual decoding.
125
126             negative = ((self.flags & 0b00001000) >> 3)
127             inch = (self.flags & 0b00000001)
128
129             number = self.bitr(self.number, 16)
130
131             if negative > 0:
132                 number = -number
133
134             inchmm = 25.4 #how many mms in inch
135
136             if inch:
137                 number = number / 2000
138                 if want_unit == 'mm':
139                     number *= inchmm
140                     inch = 0
141             else:
142                 number = number / 100
143                 if want_unit == 'inch':
144                     number = round(number / inchmm, 4)
145                     inch = 1
146
147             units = "in" if inch else "mm"
148
149             measurement = (str(number) + units)
150
151             if show_all or measurement != last_measurement:
152                 self.putg(self.ss_cmd, self.es_cmd, 0, [
153                     measurement,
154                     str(number),
155                 ])
156                 last_measurement = measurement
157
158             # Prepare for next packet.
159             self.reset()