iio: dht11: Simplify decoding algorithm
authorHarald Geyer <harald@ccbib.org>
Sun, 17 Jan 2016 16:13:30 +0000 (16:13 +0000)
committerJonathan Cameron <jic23@kernel.org>
Sat, 30 Jan 2016 16:27:13 +0000 (16:27 +0000)
The new algorithm uses a 'one size fits em all' threshold, which should
be easier to understand and debug. I believe there are no regressions
compared to the old adaptive threshold algorithm. I don't remember why
I chose the old algorithm when I initially wrote the driver.

Signed-off-by: Harald Geyer <harald@ccbib.org>
Signed-off-by: Jonathan Cameron <jic23@kernel.org>
drivers/iio/humidity/dht11.c

index 1ca284aaacfcc578855c14c8f63c0bbd99c5d585..96185f8fad88fab9be3989c21e04aca2c80e3c79 100644 (file)
 #define DHT11_EDGES_PER_READ (2 * DHT11_BITS_PER_READ + \
                              DHT11_EDGES_PREAMBLE + 1)
 
-/* Data transmission timing (nano seconds) */
+/*
+ * Data transmission timing:
+ * Data bits are encoded as pulse length (high time) on the data line.
+ * 0-bit: 22-30uS -- typically 26uS (AM2302)
+ * 1-bit: 68-75uS -- typically 70uS (AM2302)
+ * The acutal timings also depend on the properties of the cable, with
+ * longer cables typically making pulses shorter.
+ *
+ * Our decoding depends on the time resolution of the system:
+ * timeres > 34uS ... don't know what a 1-tick pulse is
+ * 34uS > timeres > 30uS ... no problem (30kHz and 32kHz clocks)
+ * 30uS > timeres > 23uS ... don't know what a 2-tick pulse is
+ * timeres < 23uS ... no problem
+ *
+ * Luckily clocks in the 33-44kHz range are quite uncommon, so we can
+ * support most systems if the threshold for decoding a pulse as 1-bit
+ * is chosen carefully. If somebody really wants to support clocks around
+ * 40kHz, where this driver is most unreliable, there are two options.
+ * a) select an implementation using busy loop polling on those systems
+ * b) use the checksum to do some probabilistic decoding
+ */
 #define DHT11_START_TRANSMISSION       18  /* ms */
-#define DHT11_SENSOR_RESPONSE  80000
-#define DHT11_START_BIT                50000
-#define DHT11_DATA_BIT_LOW     27000
-#define DHT11_DATA_BIT_HIGH    70000
+#define DHT11_MIN_TIMERES      34000  /* ns */
+#define DHT11_THRESHOLD                49000  /* ns */
+#define DHT11_AMBIG_LOW                23000  /* ns */
+#define DHT11_AMBIG_HIGH       30000  /* ns */
 
 struct dht11 {
        struct device                   *dev;
@@ -76,43 +96,39 @@ struct dht11 {
        struct {s64 ts; int value; }    edges[DHT11_EDGES_PER_READ];
 };
 
-static unsigned char dht11_decode_byte(int *timing, int threshold)
+static unsigned char dht11_decode_byte(char *bits)
 {
        unsigned char ret = 0;
        int i;
 
        for (i = 0; i < 8; ++i) {
                ret <<= 1;
-               if (timing[i] >= threshold)
+               if (bits[i])
                        ++ret;
        }
 
        return ret;
 }
 
-static int dht11_decode(struct dht11 *dht11, int offset, int timeres)
+static int dht11_decode(struct dht11 *dht11, int offset)
 {
-       int i, t, timing[DHT11_BITS_PER_READ], threshold;
+       int i, t;
+       char bits[DHT11_BITS_PER_READ];
        unsigned char temp_int, temp_dec, hum_int, hum_dec, checksum;
 
-       threshold = DHT11_DATA_BIT_HIGH / timeres;
-       if (DHT11_DATA_BIT_LOW / timeres + 1 >= threshold)
-               pr_err("dht11: WARNING: decoding ambiguous\n");
-
-       /* scale down with timeres and check validity */
        for (i = 0; i < DHT11_BITS_PER_READ; ++i) {
                t = dht11->edges[offset + 2 * i + 2].ts -
                        dht11->edges[offset + 2 * i + 1].ts;
                if (!dht11->edges[offset + 2 * i + 1].value)
                        return -EIO;  /* lost synchronisation */
-               timing[i] = t / timeres;
+               bits[i] = t > DHT11_THRESHOLD;
        }
 
-       hum_int = dht11_decode_byte(timing, threshold);
-       hum_dec = dht11_decode_byte(&timing[8], threshold);
-       temp_int = dht11_decode_byte(&timing[16], threshold);
-       temp_dec = dht11_decode_byte(&timing[24], threshold);
-       checksum = dht11_decode_byte(&timing[32], threshold);
+       hum_int = dht11_decode_byte(bits);
+       hum_dec = dht11_decode_byte(&bits[8]);
+       temp_int = dht11_decode_byte(&bits[16]);
+       temp_dec = dht11_decode_byte(&bits[24]);
+       checksum = dht11_decode_byte(&bits[32]);
 
        if (((hum_int + hum_dec + temp_int + temp_dec) & 0xff) != checksum)
                return -EIO;
@@ -166,7 +182,7 @@ static int dht11_read_raw(struct iio_dev *iio_dev,
        mutex_lock(&dht11->lock);
        if (dht11->timestamp + DHT11_DATA_VALID_TIME < ktime_get_real_ns()) {
                timeres = ktime_get_resolution_ns();
-               if (DHT11_DATA_BIT_HIGH < 2 * timeres) {
+               if (timeres > DHT11_MIN_TIMERES) {
                        dev_err(dht11->dev, "timeresolution %dns too low\n",
                                timeres);
                        /* In theory a better clock could become available
@@ -176,6 +192,10 @@ static int dht11_read_raw(struct iio_dev *iio_dev,
                        ret = -EAGAIN;
                        goto err;
                }
+               if (timeres > DHT11_AMBIG_LOW && timeres < DHT11_AMBIG_HIGH)
+                       dev_warn(dht11->dev,
+                                "timeresolution: %dns - decoding ambiguous\n",
+                                timeres);
 
                reinit_completion(&dht11->completion);
 
@@ -211,7 +231,7 @@ static int dht11_read_raw(struct iio_dev *iio_dev,
                offset = DHT11_EDGES_PREAMBLE +
                                dht11->num_edges - DHT11_EDGES_PER_READ;
                for (; offset >= 0; --offset) {
-                       ret = dht11_decode(dht11, offset, timeres);
+                       ret = dht11_decode(dht11, offset);
                        if (!ret)
                                break;
                }