/*
dhtxx.c
2020-11-18
Public Domain
http://abyz.me.uk/lg/lgpio.html
gcc -Wall -o dhtxx dhtxx.c -llgpio
./dhtxx gpio ...
*/
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <unistd.h>
#include <inttypes.h>
#include <lgpio.h>
#define DHTAUTO 0
#define DHT11 1
#define DHTXX 2
#define DHT_GOOD 0
#define DHT_BAD_CHECKSUM 1
#define DHT_BAD_DATA 2
#define DHT_TIMEOUT 3
/*
gcc -o dhtxx dhtxx.c -llg
*/
#define MAX_GPIO 32
static int decode_dhtxx(uint64_t reading, int model, float *rh, float *temp)
{
/*
+-------+-------+
| DHT11 | DHTXX |
+-------+-------+
Temp C| 0-50 |-40-125|
+-------+-------+
RH% | 20-80 | 0-100 |
+-------+-------+
0 1 2 3 4
+------+------+------+------+------+
DHT11 |check-| 0 | temp | 0 | RH% |
|sum | | | | |
+------+------+------+------+------+
DHT21 |check-| temp | temp | RH% | RH% |
DHT22 |sum | LSB | MSB | LSB | MSB |
DHT33 | | | | | |
DHT44 | | | | | |
+------+------+------+------+------+
*/
uint8_t byte[5];
uint8_t chksum;
float t, h;
int valid;
int status;
byte[0] = (reading ) & 255;
byte[1] = (reading>> 8) & 255;
byte[2] = (reading>>16) & 255;
byte[3] = (reading>>24) & 255;
byte[4] = (reading>>32) & 255;
chksum = (byte[1] + byte[2] + byte[3] + byte[4]) & 0xFF;
valid = 0;
if (chksum == byte[0])
{
if (model == DHT11)
{
if ((byte[1] == 0) && (byte[3] == 0))
{
valid = 1;
t = byte[2];
if (t > 60.0) valid = 0;
h = byte[4];
if ((h < 10.0) || (h > 90.0)) valid = 0;
}
}
else if (model == DHTXX)
{
valid = 1;
h = ((float)((byte[4]<<8) + byte[3]))/10.0;
if (h > 110.0) valid = 0;
if (byte
[2] & 128) div = -10.0; else div = 10.0;
t
= ((float)(((byte
[2]&127)<<8) + byte
[1])) / div;
if ((t < -50.0) || (t > 135.0)) valid = 0;
}
else /* AUTO */
{
valid = 1;
/* Try DHTXX first. */
h = ((float)((byte[4]<<8) + byte[3]))/10.0;
if (h > 110.0) valid = 0;
if (byte
[2] & 128) div = -10.0; else div = 10.0;
t
= ((float)(((byte
[2]&127)<<8) + byte
[1])) / div;
if ((t < -50.0) || (t > 135.0)) valid = 0;
if (!valid)
{
/* If not DHTXX try DHT11. */
if ((byte[1] == 0) && (byte[3] == 0))
{
valid = 1;
t = byte[2];
if (t > 60.0) valid = 0;
h = byte[4];
if ((h < 10.0) || (h > 90.0)) valid = 0;
}
}
}
if (valid)
{
status = DHT_GOOD;
*rh = h;
*temp = t;
}
else status = DHT_BAD_DATA;
}
else status = DHT_BAD_CHECKSUM;
return status;
}
static int status;
static float h=0, t=0;
void afunc(int e, lgGpioAlert_p evt, void *data)
{
int i;
uint64_t edge_len, now_tick;
static int bits = 0;
static uint64_t reading = 0;
static uint64_t last_tick = 0;
for (i=0; i<e; i++)
{
if (evt[i].report.level != LG_TIMEOUT)
{
now_tick = evt[i].report.timestamp;
edge_len = now_tick - last_tick;
last_tick = now_tick;
if (edge_len > 1e6) // a millisecond
{
reading = 0;
bits = 0;
}
else
{
reading <<= 1;
if (edge_len > 1e5) reading |= 1; // longer than 100 micros
++bits;
}
}
else
{
status = decode_dhtxx(reading, DHTAUTO, &t, &h);
reading = 0;
bits = 0;
}
}
}
int main(int argc, char *argv[])
{
int i, g;
int v;
int loop;
int fd;
int chip;
int num_gpio;
int gpio[MAX_GPIO];
int err;
int count;
chip = lgGpiochipOpen(0);
if (argc > 1)
{
num_gpio=argc-1;
if (num_gpio > MAX_GPIO) num_gpio = MAX_GPIO;
for (g
=0; g
<num_gpio
; g
++) gpio
[g
] = atoi(argv
[g
+1]); }
else
{
num_gpio = 1;
gpio[0] = 4;
}
if (chip >= 0)
{
lgGpioSetUser(chip, "niagra");
lgGpioSetSamplesFunc(afunc, (void*)123456);
for (g=0; g<num_gpio; g++)
{
lgGpioSetWatchdog(chip, gpio[g], 1000); /* millisecond watchdog */
}
for (loop=0; loop<200000; loop++)
{
for (g=0; g<num_gpio; g++)
{
err = lgGpioClaimOutput(chip, 0, gpio[g], 0);
if (err
) fprintf(stderr
, "set out err %d\n", err
);
usleep(15000);
err = lgGpioClaimAlert(
chip, 0, LG_RISING_EDGE, gpio[g], -1);
if (err
) fprintf(stderr
, "set event err %d\n", err
);
count = 0;
status = DHT_TIMEOUT;
while ((status == DHT_TIMEOUT) && (++count<11)) usleep(1000);
printf("%d %.1f %.1f (g=%d)\n", status
, t
, h
, gpio
[g
]);
}
sleep(3);
}
lgGpiochipClose(chip);
}
else
{
fprintf(stderr
, "open /dev/gpiochip0 failed (%d)\n", chip
); }
}