Commit | Line | Data |
---|---|---|
63efb482 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 | |
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': 'Timeout packet after X ms, 0 to disable', 'default': 10}, | |
41 | {'id': 'unit', 'desc': 'Convert units', 'default': 'keep', 'values': ('keep', 'mm', 'inch')}, | |
487a386c | 42 | {'id': 'changes', 'desc': 'Changes only', 'default': 'no', 'values': ('no', 'yes')}, |
63efb482 TM |
43 | ) |
44 | tags = ['Analog/digital', 'IC', 'Sensor'] | |
45 | annotations = ( | |
46 | ('measurements', 'Measurements'), | |
47 | ('warning', 'Warnings'), | |
48 | ) | |
49 | annotation_rows = ( | |
50 | ('measurements', 'Measurements', (0,)), | |
51 | ('warnings', 'Warnings', (1,)), | |
52 | ) | |
53 | ||
54 | def reset_data(self): | |
55 | self.bits = 0 | |
56 | self.number = 0 | |
57 | self.flags = 0 | |
58 | ||
59 | def metadata(self, key, value): | |
60 | if key == srd.SRD_CONF_SAMPLERATE: | |
61 | self.samplerate = value | |
62 | ||
63 | def __init__(self): | |
64 | self.reset() | |
65 | ||
66 | def reset(self): | |
67 | self.ss_cmd, self.es_cmd = 0, 0 | |
68 | self.reset_data() | |
69 | ||
70 | def start(self): | |
71 | self.out_ann = self.register(srd.OUTPUT_ANN) | |
72 | ||
73 | #Switch bit order of variable x, which is l bit long | |
74 | def bitr(self,x,l): | |
75 | return int(bin(x)[2:].zfill(l)[::-1], 2) | |
76 | ||
77 | def decode(self): | |
487a386c | 78 | self.last_measurement = None |
63efb482 TM |
79 | while True: |
80 | clk, data = self.wait([{0: 'r'},{'skip': round(self.samplerate/1000)}]) | |
81 | #print([clk,data]) | |
82 | ||
83 | #Timeout after inactivity | |
84 | if(self.options['timeout_ms'] > 0): | |
85 | if self.samplenum > self.es_cmd + (self.samplerate/(1000/self.options['timeout_ms'])): | |
86 | if self.bits > 0: | |
87 | self.put(self.ss_cmd, self.samplenum, self.out_ann, [1, ['timeout with %s bits in buffer'%(self.bits),'timeout']]) | |
88 | self.reset() | |
89 | ||
90 | #Do nothing if there was timeout without rising clock edge | |
91 | if self.matched == (False, True): | |
92 | continue | |
93 | ||
94 | #Store position of last activity | |
95 | self.es_cmd = self.samplenum | |
96 | ||
97 | #Store position of first bit | |
98 | if self.ss_cmd == 0: | |
99 | self.ss_cmd = self.samplenum | |
100 | ||
101 | #Shift in measured number | |
102 | if self.bits < 16: | |
103 | self.number = (self.number << 1) | (data & 0b1) | |
104 | self.bits+=1 | |
105 | continue | |
106 | ||
107 | #Shift in flag bits | |
108 | if self.bits < 24: | |
109 | self.flags = (self.flags << 1) | (data & 0b1) | |
110 | self.bits+=1 | |
111 | if self.bits < 24: | |
112 | continue | |
113 | #Hooray! We got last bit of data | |
114 | self.es_cmd = self.samplenum | |
115 | ||
116 | #Do actual decoding | |
117 | ||
118 | #print(format(self.flags, '08b')); | |
119 | ||
120 | negative = ((self.flags & 0b00001000) >> 3) | |
121 | inch = (self.flags & 0b00000001) | |
122 | ||
123 | number = self.bitr(self.number, 16) | |
124 | ||
125 | #print(format(number, '016b')) | |
126 | ||
127 | if negative > 0: | |
128 | number = -number | |
129 | ||
130 | inchmm = 25.4 #how many mms in inch | |
131 | ||
132 | if inch: | |
133 | number = number/2000 | |
134 | if self.options['unit'] == 'mm': | |
135 | number *= inchmm | |
136 | inch = 0 | |
137 | else: | |
138 | number = number/100 | |
139 | if self.options['unit'] == 'inch': | |
140 | number = round(number/inchmm,4) | |
141 | inch = 1 | |
142 | ||
143 | units = "in" if inch else "mm" | |
144 | ||
145 | measurement = (str(number)+units) | |
146 | #print(measurement) | |
147 | ||
487a386c TM |
148 | if ((self.options['changes'] == 'no') or (self.last_measurement != measurement)): |
149 | self.put(self.ss_cmd, self.es_cmd, self.out_ann, [0, [measurement, str(number)]]) | |
150 | self.last_measurement = measurement | |
63efb482 TM |
151 | |
152 | #Prepare for next packet | |
153 | self.reset() |