]> sigrok.org Git - libsigrokdecode.git/blob - decoders/am230x/pd.py
am230x: Use slightly more liberal timing values.
[libsigrokdecode.git] / decoders / am230x / pd.py
1 ##
2 ## This file is part of the libsigrokdecode project.
3 ##
4 ## Copyright (C) 2014 Johannes Roemer <jroemer@physik.uni-wuerzburg.de>
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, write to the Free Software
18 ## Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
19 ##
20
21 import sigrokdecode as srd
22
23 # Define valid timing values (in microseconds).
24 timing = {
25     'START LOW'     : {'min': 750, 'max': 25000},
26     'START HIGH'    : {'min': 10, 'max': 10000},
27     'RESPONSE LOW'  : {'min': 50, 'max': 90},
28     'RESPONSE HIGH' : {'min': 50, 'max': 90},
29     'BIT LOW'       : {'min': 45, 'max': 90},
30     'BIT 0 HIGH'    : {'min': 20, 'max': 35},
31     'BIT 1 HIGH'    : {'min': 65, 'max': 80},
32 }
33
34 class SamplerateError(Exception):
35     pass
36
37 class Decoder(srd.Decoder):
38     api_version = 2
39     id = 'am230x'
40     name = 'AM230x/DHTxx'
41     longname = 'Aosong AM230x/DHTxx'
42     desc = 'Aosong AM230x/DHTxx humidity/temperature sensor protocol.'
43     license = 'gplv2+'
44     inputs = ['logic']
45     outputs = ['am230x']
46     channels = (
47         {'id': 'sda', 'name': 'SDA', 'desc': 'Single wire serial data line'},
48     )
49     options = (
50         {'id': 'device', 'desc': 'Device type',
51             'default': 'am230x', 'values': ('am230x', 'dht11')},
52     )
53     annotations = (
54         ('start', 'Start'),
55         ('response', 'Response'),
56         ('bit', 'Bit'),
57         ('end', 'End'),
58         ('byte', 'Byte'),
59         ('humidity', 'Relative humidity in percent'),
60         ('temperature', 'Temperature in degrees Celsius'),
61         ('checksum', 'Checksum'),
62     )
63     annotation_rows = (
64         ('bits', 'Bits', (0, 1, 2, 3)),
65         ('bytes', 'Bytes', (4,)),
66         ('results', 'Results', (5, 6, 7)),
67     )
68
69     def putfs(self, data):
70         self.put(self.fall, self.samplenum, self.out_ann, data)
71
72     def putb(self, data):
73         self.put(self.bytepos[-1], self.samplenum, self.out_ann, data)
74
75     def putv(self, data):
76         self.put(self.bytepos[-2], self.samplenum, self.out_ann, data)
77
78     def reset(self):
79         self.state = 'WAIT FOR START LOW'
80         self.samplenum = 0
81         self.fall = 0
82         self.rise = 0
83         self.bits = []
84         self.bytepos = []
85
86     def is_valid(self, name):
87         dt = 0
88         if name.endswith('LOW'):
89             dt = self.samplenum - self.fall
90         elif name.endswith('HIGH'):
91             dt = self.samplenum - self.rise
92         if dt >= self.cnt[name]['min'] and dt <= self.cnt[name]['max']:
93             return True
94         return False
95
96     def bits2num(self, bitlist):
97         number = 0
98         for i in range(len(bitlist)):
99             number += bitlist[-1 - i] * 2**i
100         return number
101
102     def calculate_humidity(self, bitlist):
103         h = 0
104         if self.options['device'] == 'dht11':
105             h = self.bits2num(bitlist[0:8])
106         else:
107             h = self.bits2num(bitlist) / 10
108         return h
109
110     def calculate_temperature(self, bitlist):
111         t = 0
112         if self.options['device'] == 'dht11':
113             t = self.bits2num(bitlist[0:8])
114         else:
115             t = self.bits2num(bitlist[1:]) / 10
116             if bitlist[0] == 1:
117                 t = -t
118         return t
119
120     def calculate_checksum(self, bitlist):
121         checksum = 0
122         for i in range(8, len(bitlist) + 1, 8):
123             checksum += self.bits2num(bitlist[i-8:i])
124         return checksum % 256
125
126     def __init__(self, **kwargs):
127         self.samplerate = None
128         self.reset()
129
130     def start(self):
131         self.out_ann = self.register(srd.OUTPUT_ANN)
132
133     def metadata(self, key, value):
134         if key != srd.SRD_CONF_SAMPLERATE:
135             return
136         self.samplerate = value
137         # Convert microseconds to sample counts.
138         self.cnt = {}
139         for e in timing:
140             self.cnt[e] = {}
141             for t in timing[e]:
142                 self.cnt[e][t] = timing[e][t] * self.samplerate / 1000000
143
144     def decode(self, ss, es, data):
145         if not self.samplerate:
146             raise SamplerateError('Cannot decode without samplerate.')
147         for (self.samplenum, (sda,)) in data:
148             # State machine.
149             if self.state == 'WAIT FOR START LOW':
150                 if sda != 0:
151                     continue
152                 self.fall = self.samplenum
153                 self.state = 'WAIT FOR START HIGH'
154             elif self.state == 'WAIT FOR START HIGH':
155                 if sda != 1:
156                     continue
157                 if self.is_valid('START LOW'):
158                     self.rise = self.samplenum
159                     self.state = 'WAIT FOR RESPONSE LOW'
160                 else:
161                     self.reset()
162             elif self.state == 'WAIT FOR RESPONSE LOW':
163                 if sda != 0:
164                     continue
165                 if self.is_valid('START HIGH'):
166                     self.putfs([0, ['Start', 'S']])
167                     self.fall = self.samplenum
168                     self.state = 'WAIT FOR RESPONSE HIGH'
169                 else:
170                     self.reset()
171             elif self.state == 'WAIT FOR RESPONSE HIGH':
172                 if sda != 1:
173                     continue
174                 if self.is_valid('RESPONSE LOW'):
175                     self.rise = self.samplenum
176                     self.state = 'WAIT FOR FIRST BIT'
177                 else:
178                     self.reset()
179             elif self.state == 'WAIT FOR FIRST BIT':
180                 if sda != 0:
181                     continue
182                 if self.is_valid('RESPONSE HIGH'):
183                     self.putfs([1, ['Response', 'R']])
184                     self.fall = self.samplenum
185                     self.bytepos.append(self.samplenum)
186                     self.state = 'WAIT FOR BIT HIGH'
187                 else:
188                     self.reset()
189             elif self.state == 'WAIT FOR BIT HIGH':
190                 if sda != 1:
191                     continue
192                 if self.is_valid('BIT LOW'):
193                     self.rise = self.samplenum
194                     self.state = 'WAIT FOR BIT LOW'
195                 else:
196                     self.reset()
197             elif self.state == 'WAIT FOR BIT LOW':
198                 if sda != 0:
199                     continue
200                 if self.is_valid('BIT 0 HIGH'):
201                     bit = 0
202                 elif self.is_valid('BIT 1 HIGH'):
203                     bit = 1
204                 else:
205                     self.reset()
206                     continue
207                 self.bits.append(bit)
208                 self.putfs([2, ['Bit: %d' % bit, '%d' % bit]])
209                 self.fall = self.samplenum
210                 self.state = 'WAIT FOR BIT HIGH'
211                 if len(self.bits) % 8 == 0:
212                     byte = self.bits2num(self.bits[-8:])
213                     self.putb([4, ['Byte: %#04x' % byte, '%#04x' % byte]])
214                     if len(self.bits) == 16:
215                         h = self.calculate_humidity(self.bits[-16:])
216                         self.putv([5, ['Humidity: %.1f %%' % h, 'RH = %.1f %%' % h]])
217                     elif len(self.bits) == 32:
218                         t = self.calculate_temperature(self.bits[-16:])
219                         self.putv([6, ['Temperature: %.1f °C' % t, 'T = %.1f °C' % t]])
220                     elif len(self.bits) == 40:
221                         parity = self.bits2num(self.bits[-8:])
222                         if parity == self.calculate_checksum(self.bits[0:32]):
223                             self.putb([7, ['Checksum: OK', 'OK']])
224                         else:
225                             self.putb([7, ['Checksum: not OK', 'NOK']])
226                         self.state = 'WAIT FOR END'
227                     self.bytepos.append(self.samplenum)
228             elif self.state == 'WAIT FOR END':
229                 if sda != 1:
230                     continue
231                 self.putfs([3, ['End', 'E']])
232                 self.reset()