#include <TemperatureDHT22.h>



CTemperatureDHT22::CTemperatureDHT22(uint8_t pindata)
  {
    FPinData = pindata;
  };


//
uint8_t CTemperatureDHT22::GetLastError(void)
{
  return FLastError;
}
//
//-----------------------------------------------------
// Debug / Internal
//-----------------------------------------------------
uint64_t CTemperatureDHT22::GetRawData()
{
  readSensor();
  return _rawData;
}
//
String CTemperatureDHT22::GetRawStringData()
{
  String r="";
  for(int8_t i=39;i>=0;i--)
  {
    if (bitRead(_rawData,i)) r +="1"; else r +="0";
    if (i==24 || i==8) r +=" ";
  }
  return r;
}
void CTemperatureDHT22::measureTimings()
{
  //dht22 sampling rate ~0.5Hz
  if(!_firstStart && (millis()-_timer) < cSamplingTime){
    return;
  }
  _timer = millis();
  _firstStart=false;
  
  _timingBit0 = 0;
  _timingBit1 = 0;
  // sending START : Level LOW for at least 1ms
  pinMode(FPinData,OUTPUT);
  digitalWrite(FPinData,LOW);// specs 1-10ms mini
  delay(2);

  //Level HIGH and wait for sensor
  digitalWrite(FPinData,HIGH);
  pinMode(FPinData,INPUT);
  
  // sensor-> MCU
  uint32_t t = micros();
  uint32_t m = 0;
  while(digitalRead(FPinData)==1) 
  {// wait for Level LOW specs 20-40µs
    if ( (micros()-t) > 60) return;    
  }
  t = micros();
  while(digitalRead(FPinData)==0) 
  {// Level LOW 80µs
    m = micros()-t;
    if ( m > 100) return;    
  }
  _timing80L = m;
  t = micros();
  while(digitalRead(FPinData)==1) 
  {// Level HIGH 80µs
    m = micros()-t;
    if ( m > 100) return;    
  }
  _timing80H = m;
  t = micros();
  while(digitalRead(FPinData)==0)
  {//specs Level LOW 50µ$
    m = micros()-t;
    if (m > 60) return;    
  }
  _timing50 = m;
  t = micros();
  while(_timingBit0==0 || _timingBit1==0)
  {
    while(digitalRead(FPinData)==1)
    {//specs Level HIGH 26-28µs for "0" 70µs for "1"
      m = micros()-t;
      if (m > 100) return; 
    }
    if (m > 40)
    {
      _timingBit1 = m;
    } else 
    {
      _timingBit0 = m;
    } 
    t = micros();
    while(digitalRead(FPinData)==0)
    {//wait for new bit
      m = micros()-t;
      if (m > 100) return; 
    }
    t = micros();
  }
}

uint8_t CTemperatureDHT22::readSensor()
{ //dht22 sampling rate ~0.5Hz
  if(!_firstStart && (millis()-_timer) < cSamplingTime)
  {
    return OK;
  }
  _timer = millis();
  _firstStart = false;
  
  // sending START : Level LOW for at least 1ms
  pinMode(FPinData,OUTPUT);
  digitalWrite(FPinData,LOW);// specs 1-10ms mini
  delay(2);

  //Level HIGH and wait for sensor
  digitalWrite(FPinData,HIGH);
  pinMode(FPinData,INPUT);
  int32_t t = pulseIn(FPinData, HIGH, 250);
  if (t==0) return (FLastError = ERROR_TIMING_80);

  _rawData = 0;
  //reading 40 bits
  for (uint8_t i=0;i<40;i++) 
  {
    t = micros();
    while(digitalRead(FPinData)==0){//specs Level LOW 50µ$
      if ( (micros()-t) > _timing50+T) return (FLastError = ERROR_TIMING_50) ;
    }
    delayMicroseconds(40);
    if (digitalRead(FPinData)==1) _rawData++;//specs Level HIGH 26-28µs for "0" 70µs for "1"
    if (i!=39) _rawData <<=1;
    t = micros();
    while(digitalRead(FPinData)==1)
    {//if "1" wait for next 50µs Level LOW
      if ( (micros()-t) > _timingBit1) return (FLastError = ERROR_TIMING_BITS) ;
    }
  }
  delayMicroseconds(10);
  pinMode(FPinData,OUTPUT);
  digitalWrite(FPinData,HIGH);
  _h16bits = _rawData>>24;
  _t16bits = _rawData>>8;
  _crc8bits = _rawData;
  if (computeCRC()) return (FLastError = NO_ERROR);
  else return (FLastError = ERROR_CRC);
}

String CTemperatureDHT22::Debug()
{
  String d = "### BEGIN DEDUG ###\nlook at datasheet for timing specs\n";
  measureTimings();
  
  d +="t_80L\tt_80H\tt_50\tt_Bit0\tt_Bit1\n";
  d += String(_timing80L) +"\t";
  d += String(_timing80H) +"\t";
  d += String(_timing50) +"\t";
  d += String(_timingBit0) +"\t";
  d += String(_timingBit1) +"\n";

  delay(cSamplingTime); // f is 0.5Hz
  uint8_t err = readSensor();
  d += "error : "+String(err)+"\n";  

  d += GetRawStringData();
  d +="\nh\tt\tcrc\n";
  d += String(GetHumidityP(),1) +"\t";
  d += String(GetTemperatureC(),1) +"\t";
  if (err != ERROR_CRC) d+="TRUE"; else d+="FALSE";
  d+="\n### END DEDUG ###";
  return d;
}
//
bool CTemperatureDHT22::computeCRC()
{
  uint8_t sum = highByte(_h16bits) + lowByte(_h16bits) + highByte(_t16bits) + lowByte(_t16bits) ; 
  return (sum == _crc8bits);
}
//
//-----------------------------------------------------
//  Public
//-----------------------------------------------------
void CTemperatureDHT22::Open(void)
{
  pinMode(FPinData, INPUT);
}
float CTemperatureDHT22::GetHumidityP(void)
{
  if (readSensor() != OK) return -1;
  else return _h16bits/10.0; // [%]
}

float CTemperatureDHT22::GetTemperatureC(void)
{
  if (readSensor() != OK) return -273;
  float temperaturec = (bitRead(_t16bits, 15)) ? (_t16bits & 0x7FFF) / -10.0 : _t16bits / 10.0;
  return temperaturec; // [C]
}
float CTemperatureDHT22::GetTemperatureF(void)
{
  if (readSensor() != OK) return -273;
  float temperaturec = (bitRead(_t16bits, 15)) ? (_t16bits & 0x7FFF) / -10.0 : _t16bits / 10.0;
  return ConvertCtoF(temperaturec); // [F]
}
float CTemperatureDHT22::GetTemperatureK(void)
{
  if (readSensor() != OK) return -273;
  float temperaturec = (bitRead(_t16bits, 15)) ? (_t16bits & 0x7FFF) / -10.0 : _t16bits / 10.0;
  return ConvertCtoK(temperaturec); // [K]
}
//
float CTemperatureDHT22::GetHeatIndexC(float temperaturec, float humidityp)
{ // C -> F -> C
  float TF = ConvertCtoF(temperaturec);
  float HP = humidityp;
  float HIF = 0.5 * (TF + 61.0 + ((TF - 68.0) * 1.2) + (HP * 0.094));
  if (HIF > 79)
  {
    HIF = -42.379 + 2.04901523 * TF + 10.14333127 * HP +
          -0.22475541 * TF * HP +
          -0.00683783 * pow(TF, 2) +
          -0.05481717 * pow(HP, 2) +
          0.00122874 * pow(TF, 2) * HP +
          0.00085282 * TF * pow(HP, 2) +
          -0.00000199 * pow(TF, 2) * pow(HP, 2);
    if ((HP < 13) && (TF >= 80.0) && (TF <= 112.0))
      HIF -= ((13.0 - HP) * 0.25) * sqrt((17.0 - abs(TF - 95.0)) * 0.05882);
    else if ((HP > 85.0) && (TF >= 80.0) && (TF <= 87.0))
      HIF += ((HP - 85.0) * 0.1) * ((87.0 - TF) * 0.2);
  }
  return ConvertFtoC(HIF); // [C]
}
//
float CTemperatureDHT22::GetHeatIndexF(float temperaturef, float humidityp)
{ // F 
  float TF = temperaturef;
  float HP = humidityp;
  float HIF = 0.5 * (TF + 61.0 + ((TF - 68.0) * 1.2) + (HP * 0.094));
  if (HIF > 79)
  {
    HIF = -42.379 + 2.04901523 * TF + 10.14333127 * HP +
          -0.22475541 * TF * HP +
          -0.00683783 * pow(TF, 2) +
          -0.05481717 * pow(HP, 2) +
          0.00122874 * pow(TF, 2) * HP +
          0.00085282 * TF * pow(HP, 2) +
          -0.00000199 * pow(TF, 2) * pow(HP, 2);
    if ((HP < 13) && (TF >= 80.0) && (TF <= 112.0))
      HIF -= ((13.0 - HP) * 0.25) * sqrt((17.0 - abs(TF - 95.0)) * 0.05882);
    else if ((HP > 85.0) && (TF >= 80.0) && (TF <= 87.0))
      HIF += ((HP - 85.0) * 0.1) * ((87.0 - TF) * 0.2);
  }
  return HIF; // [F]
}
//
//------------------------------------------------
//  Celsius - Fahrenheit
//------------------------------------------------
// Convert Celsius to Fahrenheit
float CTemperatureDHT22::ConvertCtoF(float tc) 
{ 
  return 32 + 1.8 * tc; // [F]
}
// Convert Fahrenheit to Celsius
float CTemperatureDHT22::ConvertFtoC(float tf) 
{ 
  return 5 * (tf - 32) / 9; // [C]
}
//
//------------------------------------------------
//  Celsius - Kelvin
//------------------------------------------------
// Convert Celsius to Kelvin
float CTemperatureDHT22::ConvertCtoK(float tc) 
{ 
  return tc + 273.15; // [K]
}
// Convert Kelvin to Celsius
float CTemperatureDHT22::ConvertKtoC(float tk) 
{ 
  return tk - 273.15; // [C]
}
//
//------------------------------------------------
//  Fahrenheit - Kelvin
//------------------------------------------------
// Convert Fahrenheit to Kelvin
float CTemperatureDHT22::ConvertFtoK(float tf) 
{ 
  return 273.15 + 5 * (tf - 32) / 9; // [K]
}
// Convert Kelvin to Fahrenheit
float CTemperatureDHT22::ConvertKtoF(float tk) 
{ 
  return 32 + 9 * (tk - 273.15) / 5; // [C]
}
//------------------------------------------------

















