]>
Commit | Line | Data |
---|---|---|
5ed5cea5 TM |
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 | |
95435ac2 GS |
25 | from common.srdhelper import bitpack |
26 | ||
27 | # Millimeters per inch. | |
28 | mm_per_inch = 25.4 | |
5ed5cea5 TM |
29 | |
30 | class Decoder(srd.Decoder): | |
31 | api_version = 3 | |
32 | id = 'caliper' | |
33 | name = 'Caliper' | |
34 | longname = 'Digital calipers' | |
4afcb4d0 | 35 | desc = 'Protocol of cheap generic digital calipers.' |
5ed5cea5 TM |
36 | license = 'mit' |
37 | inputs = ['logic'] | |
38 | outputs = [] | |
39 | channels = ( | |
4afcb4d0 GS |
40 | {'id': 'clk', 'name': 'CLK', 'desc': 'Serial clock line'}, |
41 | {'id': 'data', 'name': 'DATA', 'desc': 'Serial data line'}, | |
5ed5cea5 TM |
42 | ) |
43 | options = ( | |
4afcb4d0 GS |
44 | {'id': 'timeout_ms', 'desc': 'Packet timeout in ms, 0 to disable', |
45 | 'default': 10}, | |
46 | {'id': 'unit', 'desc': 'Convert units', 'default': 'keep', | |
47 | 'values': ('keep', 'mm', 'inch')}, | |
48 | {'id': 'changes', 'desc': 'Changes only', 'default': 'no', | |
49 | 'values': ('no', 'yes')}, | |
5ed5cea5 | 50 | ) |
4afcb4d0 | 51 | tags = ['Analog/digital', 'Sensor'] |
5ed5cea5 | 52 | annotations = ( |
4afcb4d0 GS |
53 | ('measurement', 'Measurement'), |
54 | ('warning', 'Warning'), | |
5ed5cea5 TM |
55 | ) |
56 | annotation_rows = ( | |
57 | ('measurements', 'Measurements', (0,)), | |
58 | ('warnings', 'Warnings', (1,)), | |
59 | ) | |
60 | ||
5ed5cea5 TM |
61 | def metadata(self, key, value): |
62 | if key == srd.SRD_CONF_SAMPLERATE: | |
63 | self.samplerate = value | |
64 | ||
65 | def __init__(self): | |
66 | self.reset() | |
67 | ||
68 | def reset(self): | |
95435ac2 GS |
69 | self.ss, self.es = 0, 0 |
70 | self.number_bits = [] | |
71 | self.flags_bits = [] | |
5ed5cea5 TM |
72 | |
73 | def start(self): | |
74 | self.out_ann = self.register(srd.OUTPUT_ANN) | |
75 | ||
b3fafeb4 GS |
76 | def putg(self, ss, es, cls, data): |
77 | self.put(ss, es, self.out_ann, [cls, data]) | |
78 | ||
5ed5cea5 | 79 | def decode(self): |
ea0c4cb6 | 80 | last_sent = None |
b3fafeb4 GS |
81 | timeout_ms = self.options['timeout_ms'] |
82 | want_unit = self.options['unit'] | |
83 | show_all = self.options['changes'] == 'no' | |
9e208e00 GS |
84 | wait_cond = [{0: 'r'}] |
85 | if timeout_ms: | |
86 | snum_per_ms = self.samplerate / 1000 | |
87 | timeout_snum = timeout_ms * snum_per_ms | |
88 | wait_cond.append({'skip': round(timeout_snum)}) | |
5ed5cea5 | 89 | while True: |
9e208e00 GS |
90 | # Sample data at the rising clock edge. Optionally timeout |
91 | # after inactivity for a user specified period. Present the | |
92 | # number of unprocessed bits to the user for diagnostics. | |
93 | clk, data = self.wait(wait_cond) | |
94 | if timeout_ms and not self.matched[0]: | |
95 | if self.number_bits or self.flags_bits: | |
96 | count = len(self.number_bits) + len(self.flags_bits) | |
97 | self.putg(self.ss, self.samplenum, 1, [ | |
98 | 'timeout with {} bits in buffer'.format(count), | |
99 | 'timeout ({} bits)'.format(count), | |
100 | 'timeout', | |
101 | ]) | |
102 | self.reset() | |
5ed5cea5 TM |
103 | continue |
104 | ||
95435ac2 GS |
105 | # Store position of first bit and last activity. |
106 | # Shift in measured number and flag bits. | |
107 | if not self.ss: | |
108 | self.ss = self.samplenum | |
109 | self.es = self.samplenum | |
110 | if len(self.number_bits) < 16: | |
111 | self.number_bits.append(data) | |
5ed5cea5 | 112 | continue |
95435ac2 GS |
113 | if len(self.flags_bits) < 8: |
114 | self.flags_bits.append(data) | |
115 | if len(self.flags_bits) < 8: | |
5ed5cea5 | 116 | continue |
5ed5cea5 | 117 | |
95435ac2 GS |
118 | # Get raw values from received data bits. Run the number |
119 | # conversion, controlled by flags and/or user specs. | |
120 | negative = bool(self.flags_bits[4]) | |
121 | is_inch = bool(self.flags_bits[7]) | |
122 | number = bitpack(self.number_bits) | |
123 | if negative: | |
5ed5cea5 | 124 | number = -number |
95435ac2 | 125 | if is_inch: |
ea0c4cb6 | 126 | number /= 2000 |
b3fafeb4 | 127 | if want_unit == 'mm': |
95435ac2 GS |
128 | number *= mm_per_inch |
129 | is_inch = False | |
5ed5cea5 | 130 | else: |
ea0c4cb6 | 131 | number /= 100 |
b3fafeb4 | 132 | if want_unit == 'inch': |
95435ac2 GS |
133 | number = round(number / mm_per_inch, 4) |
134 | is_inch = True | |
ea0c4cb6 | 135 | unit = 'in' if is_inch else 'mm' |
5ed5cea5 | 136 | |
ea0c4cb6 GS |
137 | # Construct and emit an annotation. |
138 | if show_all or (number, unit) != last_sent: | |
95435ac2 | 139 | self.putg(self.ss, self.es, 0, [ |
ea0c4cb6 GS |
140 | '{number}{unit}'.format(**locals()), |
141 | '{number}'.format(**locals()), | |
b3fafeb4 | 142 | ]) |
ea0c4cb6 | 143 | last_sent = (number, unit) |
5ed5cea5 | 144 | |
ea0c4cb6 | 145 | # Reset internal state for the start of the next packet. |
5ed5cea5 | 146 | self.reset() |