]> sigrok.org Git - libsigrokdecode.git/blob - decoders/am230x/pd.py
Use consistent __init__() format across all PDs.
[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/RHTxx'
41     longname = 'Aosong AM230x/DHTxx/RHTxx'
42     desc = 'Aosong AM230x/DHTxx/RHTxx 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/rht', '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):
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 handle_byte(self, bit):
145         self.bits.append(bit)
146         self.putfs([2, ['Bit: %d' % bit, '%d' % bit]])
147         self.fall = self.samplenum
148         self.state = 'WAIT FOR BIT HIGH'
149         if len(self.bits) % 8 == 0:
150             byte = self.bits2num(self.bits[-8:])
151             self.putb([4, ['Byte: %#04x' % byte, '%#04x' % byte]])
152             if len(self.bits) == 16:
153                 h = self.calculate_humidity(self.bits[-16:])
154                 self.putv([5, ['Humidity: %.1f %%' % h, 'RH = %.1f %%' % h]])
155             elif len(self.bits) == 32:
156                 t = self.calculate_temperature(self.bits[-16:])
157                 self.putv([6, ['Temperature: %.1f °C' % t, 'T = %.1f °C' % t]])
158             elif len(self.bits) == 40:
159                 parity = self.bits2num(self.bits[-8:])
160                 if parity == self.calculate_checksum(self.bits[0:32]):
161                     self.putb([7, ['Checksum: OK', 'OK']])
162                 else:
163                     self.putb([7, ['Checksum: not OK', 'NOK']])
164                 self.state = 'WAIT FOR END'
165             self.bytepos.append(self.samplenum)
166
167     def decode(self, ss, es, data):
168         if not self.samplerate:
169             raise SamplerateError('Cannot decode without samplerate.')
170         for (self.samplenum, (sda,)) in data:
171             # State machine.
172             if self.state == 'WAIT FOR START LOW':
173                 if sda != 0:
174                     continue
175                 self.fall = self.samplenum
176                 self.state = 'WAIT FOR START HIGH'
177             elif self.state == 'WAIT FOR START HIGH':
178                 if sda != 1:
179                     continue
180                 if self.is_valid('START LOW'):
181                     self.rise = self.samplenum
182                     self.state = 'WAIT FOR RESPONSE LOW'
183                 else:
184                     self.reset()
185             elif self.state == 'WAIT FOR RESPONSE LOW':
186                 if sda != 0:
187                     continue
188                 if self.is_valid('START HIGH'):
189                     self.putfs([0, ['Start', 'S']])
190                     self.fall = self.samplenum
191                     self.state = 'WAIT FOR RESPONSE HIGH'
192                 else:
193                     self.reset()
194             elif self.state == 'WAIT FOR RESPONSE HIGH':
195                 if sda != 1:
196                     continue
197                 if self.is_valid('RESPONSE LOW'):
198                     self.rise = self.samplenum
199                     self.state = 'WAIT FOR FIRST BIT'
200                 else:
201                     self.reset()
202             elif self.state == 'WAIT FOR FIRST BIT':
203                 if sda != 0:
204                     continue
205                 if self.is_valid('RESPONSE HIGH'):
206                     self.putfs([1, ['Response', 'R']])
207                     self.fall = self.samplenum
208                     self.bytepos.append(self.samplenum)
209                     self.state = 'WAIT FOR BIT HIGH'
210                 else:
211                     self.reset()
212             elif self.state == 'WAIT FOR BIT HIGH':
213                 if sda != 1:
214                     continue
215                 if self.is_valid('BIT LOW'):
216                     self.rise = self.samplenum
217                     self.state = 'WAIT FOR BIT LOW'
218                 else:
219                     self.reset()
220             elif self.state == 'WAIT FOR BIT LOW':
221                 if sda != 0:
222                     continue
223                 if self.is_valid('BIT 0 HIGH'):
224                     bit = 0
225                 elif self.is_valid('BIT 1 HIGH'):
226                     bit = 1
227                 else:
228                     self.reset()
229                     continue
230                 self.handle_byte(bit)
231             elif self.state == 'WAIT FOR END':
232                 if sda != 1:
233                     continue
234                 self.putfs([3, ['End', 'E']])
235                 self.reset()