// DHT11_EH.cpp
// Test for sensor DHT11 (temperature + humidity)
// Sends a request to the sensor
// Reads 40 bit of data and outputs the obtained values
// Note that fractional parts are not shown as they were alway 0 
//      during my tests
// Tested with NXP LCP1768: works
// Note:
// DHT11 delivers wrong results for humidity - temperature is OK
// This is confirmed by many complaints on the Internet
// Dr. E.Huckert 09-2016

#include "mbed.h"
 
DigitalInOut pin8(p8);

#define MAX_LOOP 500  // must be adapted for other CPU speeds (here for LCP1768)
#define BIT_HIGH 200  // must be adapted for other CPU speeds (here for LCP1768)
#define TEMP_OFFS -2  // must be adapted for the respective DHT11
#define HUM_OFFS  22  // must be adapted for the respective DHT11

// global data
char bitStr[64];
unsigned bits[40];
int verbose = 0;         // set to <> 0 if more output  is needed

// ----------------------------------------------------------------
// Assumes that array bit[] has been filled
// Output is sent to a serial console (Windows: use TeraTerm or sim.)
void outputResults()
{
    char aux[8];
    int numVal = 0;
    int patt = 128;
    //
    memset(bitStr, 0, sizeof(bitStr));
    for (int noBit=0; noBit < 40; noBit++)
    {
        if (bits[noBit] < BIT_HIGH)
          strcat(bitStr, "0");
        else 
        {
          strcat(bitStr, "1");
          numVal = numVal + patt;
        }
        patt = patt >> 1;
        if (((noBit + 1) % 8) == 0) 
        {
          sprintf(aux, " %u ", numVal);
          strcat(bitStr, aux);
          numVal = 0;
          patt   = 128;
        }
    }   // end for...
    printf("bit string=%s\r\n", bitStr);
}   // end outputResults()

// ----------------------------------------------------------------
// Assumes that array bit[] has been filled
// returns only the non fractional part
// the fractional part is always 0 ???
unsigned getHumidity()
{
    unsigned hum = 0;
    unsigned patt = 128;
    //
    for (int noBit=0; noBit < 8; noBit++)
    {
        if (bits[noBit] < BIT_HIGH)
          ;
        else 
        {
          hum = hum + patt;
        }
        patt = patt >> 1;
    }   // end for...
    //
    return hum;
}  // end getHumidity()

// ----------------------------------------------------------------
// Assumes that array bit[] has been filled
// returns only the non fractional part
// the fractional part is always 0 ???
int getTemperature()
{
    int temp = 0;
    int patt = 128;
    //
    for (int noBit=16; noBit < 24; noBit++)
    {
        if (bits[noBit] < BIT_HIGH)
          ;
        else 
        {
          temp = temp  + patt;
        }
        patt = patt >> 1;
    }   // end for...
    //
    return temp;
}   // end getTemperature()

// ----------------------------------------------------------------
// Assumes that array bit[] has been filled
unsigned getChecksum()
{
    unsigned cs = 0;
    unsigned patt = 128;
    //
    for (int noBit=32; noBit < 40; noBit++)
    {
        if (bits[noBit] < BIT_HIGH)
          ;
        else 
        {
          cs = cs + patt;
        }
        patt = patt >> 1;
    }   // end for...
    //
    return cs;
}  // end getChecksum()

// ---------------------------------------------------------------
// Fills array bits() with (uninterpreted) measurement values
// Returns: 0 if OK, < 0 upon error
int getMeasBits()
{
    int retValue = 0;
    int ret, noBit;
    int loopOK   = 0;
    //
    // start request
    pin8.output();
    pin8.write(0);  // 18 ms low   
    wait_us(19000); // must  be >= 18 ms 
    pin8.write(1);  // 40 us high, not necessary 
    wait_us(40);
    //
    // wait for response 
    // should be 54us low, then 80u s high
    pin8.input();
    wait_us(10);
    loopOK = 0;
    for (int n=0; n < MAX_LOOP; n++)  // wait for response high
    {
      ret = pin8.read();
      if (ret == 1) { loopOK = 1; break; }
    }
    if (loopOK  == 0)
      goto ErrorReturn;
    loopOK = 0;
    for (int n=0; n< MAX_LOOP; n++)   // wait for response low
    {
      ret = pin8.read();
      if (ret == 0) { loopOK = 1; break; }
    }
    if (loopOK  == 0)
      goto ErrorReturn;
    wait_us(10);
    //
    // wait for 40 bit data
    // each bit: 54 us low, then 24-70 us high
    noBit = 0;
    for (int n=0; n < 40; n++)
    {
      bits[n] = 0;
    }
    while (noBit < 40)
    {
      loopOK = 0;
      for (int n=0; n< MAX_LOOP; n++)   // wait for data bit high
      {
        ret = pin8.read();
        if (ret == 1) { loopOK = 1; break; }
      }
      if (loopOK  == 0)
        goto ErrorReturn;
      wait_us(10);
      loopOK = 0;      
      for (int n=0; n< MAX_LOOP; n++)   // wait for data bit low
      {
        ret = pin8.read();
        if (ret == 0) { loopOK = 1; break; }
        bits[noBit] += 1;
      }
      if (loopOK  == 0)
        goto ErrorReturn;
      wait_us(10);  
      noBit++;
    }   // end while noBit...
    //
    // OK here
    retValue = 0;
    return retValue;
    //
  ErrorReturn:
    retValue = -1;
    return retValue;
}   // end getMeasBits()

// ----------------------------------------------------------------
int main() 
{
  int ret;
  //
  while (1)
  {
    wait(3.0);  // not lower than 2 secs
    if (verbose)
      printf("starting request\r\n");
    //
    // fills array bits[] if OK
    ret = getMeasBits();
    if (ret < 0)
      printf("+++ DHT11 comm.error +++\r\n");
    if (verbose)
    {
      printf("result getMeasBits()=%d\r\n", ret);
      outputResults();
    }
    // note that we output here the results with correction offsets
    //printf("Hum.=%u   Temp.=%d CS=%u\r\n", 
    //        getHumidity() + HUM_OFFS, getTemperature()+ TEMP_OFFS, 
    //        getChecksum());
    printf("Hum.=%u   Temp.=%d\r\n", 
            getHumidity() + HUM_OFFS, getTemperature()+ TEMP_OFFS);
  }  // end while (1)
  //printf("terminated\r\n");
}   // end main()
