Gordons Projects

--> Projects Top-Level GIT

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