Gordons Projects

--> Projects Top-Level GIT

Many changes - tidying up the extensions interfaces.
[wiringPi] / devLib / maxdetect.c
1 /*
2  * maxdetect.c:
3  *      Driver for the MaxDetect series sensors
4  *
5  * Copyright (c) 2013 Gordon Henderson.
6  ***********************************************************************
7  * This file is part of wiringPi:
8  *      https://projects.drogon.net/raspberry-pi/wiringpi/
9  *
10  *    wiringPi is free software: you can redistribute it and/or modify
11  *    it under the terms of the GNU Lesser General Public License as published by
12  *    the Free Software Foundation, either version 3 of the License, or
13  *    (at your option) any later version.
14  *
15  *    wiringPi is distributed in the hope that it will be useful,
16  *    but WITHOUT ANY WARRANTY; without even the implied warranty of
17  *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  *    GNU Lesser General Public License for more details.
19  *
20  *    You should have received a copy of the GNU Lesser General Public License
21  *    along with wiringPi.  If not, see <http://www.gnu.org/licenses/>.
22  ***********************************************************************
23  */
24
25 #include <sys/time.h>
26 #include <stdio.h>
27 //#include <stdlib.h>
28 //#include <unistd.h>
29
30 #include <wiringPi.h>
31
32 #include "maxdetect.h"
33
34 #ifndef TRUE
35 #  define       TRUE    (1==1)
36 #  define       FALSE   (1==2)
37 #endif
38
39
40 /*
41  * maxDetectLowHighWait:
42  *      Wait for a transition from low to high on the bus
43  *********************************************************************************
44  */
45
46 static int maxDetectLowHighWait (const int pin)
47 {
48   struct timeval now, timeOut, timeUp ;
49
50 // If already high then wait for pin to go low
51
52   gettimeofday (&now, NULL) ;
53   timerclear   (&timeOut) ;
54   timeOut.tv_usec = 1000 ;
55   timeradd     (&now, &timeOut, &timeUp) ;
56
57   while (digitalRead (pin) == HIGH)
58   {
59     gettimeofday (&now, NULL) ;
60     if (timercmp (&now, &timeUp, >))
61       return FALSE ;
62   }
63
64 // Wait for it to go HIGH
65
66   gettimeofday (&now, NULL) ;
67   timerclear (&timeOut) ;
68   timeOut.tv_usec = 1000 ;
69   timeradd (&now, &timeOut, &timeUp) ;
70
71   while (digitalRead (pin) == LOW)
72   {
73     gettimeofday (&now, NULL) ;
74     if (timercmp (&now, &timeUp, >))
75       return FALSE ;
76   }
77
78   return TRUE ;
79 }
80
81
82 /*
83  * maxDetectClockByte:
84  *      Read in a single byte from the MaxDetect bus
85  *********************************************************************************
86  */
87
88 static unsigned int maxDetectClockByte (const int pin)
89 {
90   unsigned int byte = 0 ;
91   int bit ;
92
93   for (bit = 0 ; bit < 8 ; ++bit)
94   {
95     if (!maxDetectLowHighWait (pin))
96       return 0 ;
97
98 // bit starting now - we need to time it.
99
100     delayMicroseconds (30) ;
101     byte <<= 1 ;
102     if (digitalRead (pin) == HIGH)      // It's a 1
103       byte |= 1 ;
104   }
105
106   return byte ;
107 }
108
109
110 /*
111  * maxDetectRead:
112  *      Read in and return the 4 data bytes from the MaxDetect sensor.
113  *      Return TRUE/FALSE depending on the checksum validity
114  *********************************************************************************
115  */
116
117 int maxDetectRead (const int pin, unsigned char buffer [4])
118 {
119   int i ;
120   unsigned int checksum ;
121   unsigned char localBuf [5] ;
122   struct timeval now, then, took ;
123
124 // See how long we took
125
126   gettimeofday (&then, NULL) ;
127
128 // Wake up the RHT03 by pulling the data line low, then high
129 //      Low for 10mS, high for 40uS.
130
131   pinMode      (pin, OUTPUT) ;
132   digitalWrite (pin, 0) ; delay             (10) ;
133   digitalWrite (pin, 1) ; delayMicroseconds (40) ;
134   pinMode      (pin, INPUT) ;
135
136 // Now wait for sensor to pull pin low
137
138   if (!maxDetectLowHighWait (pin))
139     return FALSE ;
140
141 // and read in 5 bytes (40 bits)
142
143   for (i = 0 ; i < 5 ; ++i)
144     localBuf [i] = maxDetectClockByte (pin) ;
145
146   checksum = 0 ;
147   for (i = 0 ; i < 4 ; ++i)
148   {
149     buffer [i] = localBuf [i] ;
150     checksum += localBuf [i] ;
151   }
152   checksum &= 0xFF ;
153
154 // See how long we took
155   
156   gettimeofday (&now, NULL) ;
157   timersub (&now, &then, &took) ;
158
159 // Total time to do this should be:
160 //      10mS + 40µS - reset
161 //      + 80µS + 80µS - sensor doing its low -> high thing
162 //      + 40 * (50µS + 27µS (0) or 70µS (1) )
163 //      = 15010µS
164 // so if we take more than that, we've had a scheduling interruption and the
165 // reading is probably bogus.
166
167   if ((took.tv_sec != 0) || (took.tv_usec > 16000))
168     return FALSE ;
169
170   return checksum == localBuf [4] ;
171 }
172
173
174 /*
175  * readRHT03:
176  *      Read the Temperature & Humidity from an RHT03 sensor
177  *      Values returned are *10, so 123 is 12.3.
178  *********************************************************************************
179  */
180
181 int readRHT03 (const int pin, int *temp, int *rh)
182 {
183   static struct timeval then ;  // will initialise to zero
184   static        int     lastTemp = 0 ;
185   static        int     lastRh   = 0 ;
186
187   int result ;
188   struct timeval now, timeOut ;
189   unsigned char buffer [4] ;
190
191 // The data sheets say to not read more than once every 2 seconds, so you
192 //      get the last good reading
193
194   gettimeofday (&now, NULL) ;
195   if (timercmp (&now, &then, <))
196   {
197     *rh   = lastRh ;
198     *temp = lastTemp ;
199     return TRUE ;
200   }
201
202 // Set timeout for next read
203
204   gettimeofday (&now, NULL) ;
205   timerclear   (&timeOut) ;
206   timeOut.tv_sec = 2 ;
207   timeradd (&now, &timeOut, &then) ;
208
209 // Read ...
210   
211   result = maxDetectRead (pin, buffer) ;
212
213   if (!result) // Try again, but just once
214     result = maxDetectRead (pin, buffer) ;
215
216   if (!result)
217     return FALSE ;
218
219   *rh   = (buffer [0] * 256 + buffer [1]) ;
220   *temp = (buffer [2] * 256 + buffer [3]) ;
221
222   if ((*temp & 0x8000) != 0)    // Negative
223   {
224     *temp &= 0x7FFF ;
225     *temp = -*temp ;
226   }
227
228 // Discard obviously bogus readings - the checksum can't detect a 2-bit error
229 //      (which does seem to happen - no realtime here)
230
231   if ((*rh > 999) || (*temp > 800) || (*temp < -400))
232     return FALSE ;
233
234   lastRh   = *rh ;
235   lastTemp = *temp ;
236
237   return TRUE ;
238 }