2 ## This file is part of the libsigrokdecode project.
4 ## Copyright (C) 2014 Johannes Roemer <jroemer@physik.uni-wuerzburg.de>
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.
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.
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
21 import sigrokdecode as srd
23 # Define valid timing values (in microseconds).
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},
34 class SamplerateError(Exception):
37 class Decoder(srd.Decoder):
41 longname = 'Aosong AM230x/DHTxx'
42 desc = 'Aosong AM230x/DHTxx humidity/temperature sensor protocol.'
47 {'id': 'sda', 'name': 'SDA', 'desc': 'Single wire serial data line'},
50 {'id': 'device', 'desc': 'Device type',
51 'default': 'am230x', 'values': ('am230x', 'dht11')},
55 ('response', 'Response'),
59 ('humidity', 'Relative humidity in percent'),
60 ('temperature', 'Temperature in degrees Celsius'),
61 ('checksum', 'Checksum'),
64 ('bits', 'Bits', (0, 1, 2, 3)),
65 ('bytes', 'Bytes', (4,)),
66 ('results', 'Results', (5, 6, 7)),
69 def putfs(self, data):
70 self.put(self.fall, self.samplenum, self.out_ann, data)
73 self.put(self.bytepos[-1], self.samplenum, self.out_ann, data)
76 self.put(self.bytepos[-2], self.samplenum, self.out_ann, data)
79 self.state = 'WAIT FOR START LOW'
86 def is_valid(self, name):
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']:
96 def bits2num(self, bitlist):
98 for i in range(len(bitlist)):
99 number += bitlist[-1 - i] * 2**i
102 def calculate_humidity(self, bitlist):
104 if self.options['device'] == 'dht11':
105 h = self.bits2num(bitlist[0:8])
107 h = self.bits2num(bitlist) / 10
110 def calculate_temperature(self, bitlist):
112 if self.options['device'] == 'dht11':
113 t = self.bits2num(bitlist[0:8])
115 t = self.bits2num(bitlist[1:]) / 10
120 def calculate_checksum(self, bitlist):
122 for i in range(8, len(bitlist) + 1, 8):
123 checksum += self.bits2num(bitlist[i-8:i])
124 return checksum % 256
126 def __init__(self, **kwargs):
127 self.samplerate = None
131 self.out_ann = self.register(srd.OUTPUT_ANN)
133 def metadata(self, key, value):
134 if key != srd.SRD_CONF_SAMPLERATE:
136 self.samplerate = value
137 # Convert microseconds to sample counts.
142 self.cnt[e][t] = timing[e][t] * self.samplerate / 1000000
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:
149 if self.state == 'WAIT FOR START LOW':
152 self.fall = self.samplenum
153 self.state = 'WAIT FOR START HIGH'
154 elif self.state == 'WAIT FOR START HIGH':
157 if self.is_valid('START LOW'):
158 self.rise = self.samplenum
159 self.state = 'WAIT FOR RESPONSE LOW'
162 elif self.state == 'WAIT FOR RESPONSE LOW':
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'
171 elif self.state == 'WAIT FOR RESPONSE HIGH':
174 if self.is_valid('RESPONSE LOW'):
175 self.rise = self.samplenum
176 self.state = 'WAIT FOR FIRST BIT'
179 elif self.state == 'WAIT FOR FIRST BIT':
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'
189 elif self.state == 'WAIT FOR BIT HIGH':
192 if self.is_valid('BIT LOW'):
193 self.rise = self.samplenum
194 self.state = 'WAIT FOR BIT LOW'
197 elif self.state == 'WAIT FOR BIT LOW':
200 if self.is_valid('BIT 0 HIGH'):
202 elif self.is_valid('BIT 1 HIGH'):
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']])
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':
231 self.putfs([3, ['End', 'E']])