//
#include "AM2302.h"
//
//----------------------------------------------------
CAM2302::CAM2302(uint8_t pin) //, uint8_t type, uint8_t count) 
{
  _pin = pin;
#ifdef __AVR
  _bit = digitalPinToBitMask(pin);
  _port = digitalPinToPort(pin);
#endif
  _maxcycles =
      microsecondsToClockCycles(1000); // 1 millisecond timeout for
                                       // reading pulses from DHT sensor.
  // Note that count is now ignored as the DHT reading algorithm adjusts itself
  // based on the speed of the processor.
}
//
//----------------------------------------------------
void CAM2302::Open(uint8_t usec) 
{
  pinMode(_pin, INPUT_PULLUP);
  _lastreadtime = millis() - MIN_INTERVAL;
  pullTime = usec;
}
//
//----------------------------------------------------
float CAM2302::ReadTemperature(void) 
{
  float f = NAN;
  if (Read()) 
  {
    f = ((word)(data[2] & 0x7F)) << 8 | data[3];
    f *= 0.1;
    if (data[2] & 0x80) {
      f *= -1;
    }
  }
  return f;
}
//
//----------------------------------------------------
float CAM2302::ConvertCtoF(float c) { return c * 1.8 + 32; }
//
//----------------------------------------------------
float CAM2302::ConvertFtoC(float f) { return (f - 32) * 0.55555; }
//
//----------------------------------------------------
float CAM2302::ReadHumidity(bool force) 
{
  float f = NAN;
  if (Read(force)) 
  {
    f = ((word)data[0]) << 8 | data[1];
    f *= 0.1;
  }
  return f;
}
//
//----------------------------------------------------
float CAM2302::ReadHeatIndex(void) 
{
  return ComputeHeatIndex(ReadTemperature(), ReadHumidity());
}
//
//----------------------------------------------------
float CAM2302::ComputeHeatIndex(float temperature, float humidity) 
{
  float HeatIndex;
  HeatIndex = 0.5 * (temperature + 61.0 + ((temperature - 68.0) * 1.2) + (humidity * 0.094));
  if (79 < HeatIndex)
  {
    HeatIndex = -42.379 + 2.04901523 * temperature + 10.14333127 * humidity +
                -0.22475541 * temperature * humidity +
                -0.00683783 * pow(temperature, 2) +
                -0.05481717 * pow(humidity, 2) +
                 0.00122874 * pow(temperature, 2) * humidity +
                 0.00085282 * temperature * pow(humidity, 2) +
                -0.00000199 * pow(temperature, 2) * pow(humidity, 2);
    if ((humidity < 13) && (temperature >= 80.0) &&
        (temperature <= 112.0))
      HeatIndex -= ((13.0 - humidity) * 0.25) * sqrt((17.0 - abs(temperature - 95.0)) * 0.05882);
    else 
      if ((humidity > 85.0) && (temperature >= 80.0) && (temperature <= 87.0))
        HeatIndex += ((humidity - 85.0) * 0.1) * ((87.0 - temperature) * 0.2);
  }
  return HeatIndex;
}
//
//----------------------------------------------------
bool CAM2302::Read(bool force) 
{ 
  uint32_t currenttime = millis();
  if (!force && ((currenttime - _lastreadtime) < MIN_INTERVAL)) 
  {
    return _lastresult; 
  }
  _lastreadtime = currenttime;
  data[0] = data[1] = data[2] = data[3] = data[4] = 0;
#if defined(ESP8266) | defined(ESP32)
  yield(); 
#endif
  pinMode(_pin, INPUT_PULLUP);
  delay(1);
  pinMode(_pin, OUTPUT);
  digitalWrite(_pin, LOW);
  delayMicroseconds(1100);
  //
  uint32_t cycles[80];
  {
    pinMode(_pin, INPUT_PULLUP);
    delayMicroseconds(pullTime);
    InterruptLock lock;
    if (ExpectPulse(LOW) == TIMEOUT) {
      _lastresult = false;
      return _lastresult;
    }
    if (ExpectPulse(HIGH) == TIMEOUT) {
      _lastresult = false;
      return _lastresult;
    }
    for (int i = 0; i < 80; i += 2) 
    {
      cycles[i] = ExpectPulse(LOW);
      cycles[i + 1] = ExpectPulse(HIGH);
    }
  }
  for (int i = 0; i < 40; ++i) 
  {
    uint32_t lowCycles = cycles[2 * i];
    uint32_t highCycles = cycles[2 * i + 1];
    if ((lowCycles == TIMEOUT) || (highCycles == TIMEOUT)) {
      _lastresult = false;
      return _lastresult;
    }
    data[i / 8] <<= 1;
    if (highCycles > lowCycles) 
    {
      data[i / 8] |= 1;
    }
  }
  if (data[4] == ((data[0] + data[1] + data[2] + data[3]) & 0xFF)) 
  {
    _lastresult = true;
    return _lastresult;
  } 
  else 
  {
    _lastresult = false;
    return _lastresult;
  }
}
//
//----------------------------------------------------
uint32_t CAM2302::ExpectPulse(bool level) 
{
#if (F_CPU > 16000000L)
  uint32_t count = 0;
#else
  uint16_t count = 0;
#endif
  while (digitalRead(_pin) == level) 
  {
    if (count++ >= _maxcycles) 
    {
      return TIMEOUT;
    }
  }
  return count;
}
//----------------------------------------------------
//
