#include <avr/sleep.h>
#include <avr/wdt.h>

#include <RH_ASK.h>

#include <OneWire.h>
#include <DallasTemperature.h>

//#include <math.h>

#if defined(ARDUINO_AVR_NANO)
  #include "pins-nano.h"
#elif defined(ARDUINO_AVR_ATTINYX5)
  #include "pins-attiny85.h"
#else
  #error "Pins undef for this core"
#endif

#include "config.h"

#if LOGGER
  #warning "Logger"
  #define Log(l) Serial.print(l)
  #define LogLn(l) Serial.println(l)
#else
  #warning "No Logger"
  #define Log(l)
  #define LogLn(l)
#endif


OneWire oneWire(PIN_DS18B20);
DallasTemperature ds18b20(&oneWire);

#if !defined(ARDUINO_AVR_ATTINYX5) || (defined(ARDUINO_AVR_ATTINYX5) && !LOGGER)
  //RH_ASK driver(2000, -1, PIN_SEND, -1, false);   
  RH_ASK driver(2000, -1, PIN_SEND, -1, false, 8);
#endif

uint8_t rh_payload[6];

unsigned long myTime;

uint8_t sleeprepeat;
uint8_t sleeprepeatbat;
uint8_t sleepcount;

bool temp_enabled = false;

ISR(WDT_vect) {
  // Nothing needs to be done, however interrupt handler must be defined to
  // prevent a reset.
}

void setSensorType(uint8_t stype)
{
  uint8_t payload0; 
  payload0 = stype << 4;
  rh_payload[0] &= 0b00001111;
  rh_payload[0] += payload0;
}

void setBatteryStatus(uint8_t bstatus)
{
  if(bstatus == 1) {
  rh_payload[0] |= 0b00000001;
  } else {
  rh_payload[0] &= 0b11111110;
  }
}

void setBatteryVoltage(uint16_t bvoltage)
{
  uint16_t payloadbat = rh_payload[2];
  payloadbat += rh_payload[1] << 8;
  payloadbat &= 0b0000000001111111;
  payloadbat += bvoltage << 7;
  //Serial.println(payloadbat);
  rh_payload[1] = payloadbat >> 8;
  rh_payload[2] = payloadbat;
}

void setBatteryPercent(uint8_t bpercent)
{
  uint16_t payloadbat = rh_payload[2];
  payloadbat += rh_payload[1] << 8;
  payloadbat &= 0b1111111110000000;
  payloadbat += bpercent;
  //Serial.println(payloadbat);
  rh_payload[1] = payloadbat >> 8;
  rh_payload[2] = payloadbat;
}

void setTemperature()
{
  ds18b20.requestTemperaturesByIndex(0);
  delay(500);
  int16_t tempC = (int16_t) roundf(ds18b20.getTempCByIndex(0)*100);
  if(tempC != DEVICE_DISCONNECTED_C) {
    //int16_t tempC = (int16_t) (ds18b20.getTempCByIndex(0)*100.0);
    LogLn(tempC);
    rh_payload[3] = tempC >> 8;
    rh_payload[4] = tempC;
  }
}

void setHumidity()
{
  rh_payload[5] = 33;
}



void setupWatchDogTimer(int time)
{
  if (time > 9 )
    time = 9; //Limit incoming amount to legal settings

  cli();
  MCUSR &= ~(1<<WDRF); // Clear watch dog reset flag
  _WD_CONTROL_REG |= (1<<WDCE) | (1<<WDE); // Set WD_change enable, set WD enable
  _WD_CONTROL_REG = (time & 7) | (time & 8) << 2;
  _WD_CONTROL_REG |= (1<<WDIE); // enable interrupt
  sei();
}

void powerDown(void)
{
  setupWatchDogTimer(WDTO_8S);
  #if defined(BODS) && defined(BODSE)  //if MCU has bulit-in BOD it will be disabled, ATmega328P, ATtiny8>
  sleep_bod_disable();                 //disable Brown Out Detector (BOD) before going to sleep, saves mo>
  #endif
  sleep_enable();
  sleep_mode();
  sleep_disable();
}

void setup()
{
  ADCSRA &= ~(1<<ADEN); //Disable ADC, saves ~230uA
 // setupWatchDogTimer(WDTO_8S);
 set_sleep_mode(SLEEP_MODE_PWR_DOWN); //Power down everything, wake up from WDT

  if(SEND_DELAY < 8)
  { 
    sleeprepeat = 1;
  } else {
    sleeprepeat = lround(SEND_DELAY / 8);
  }

  if(SEND_DELAY_BATTERY < 8)
  { 
    sleeprepeatbat = 1;
  } else {
    sleeprepeatbat = lround(SEND_DELAY_BATTERY / (sleeprepeat*8));
  }

  #if LOGGER
    Serial.begin(9600);	  // Debugging only
    #if defined(ARDUINO_AVR_ATTINYX5)
      // Disable RX (free port PB1)
      ACSR &=~(1<<ACIE);
      ACSR |=~(1<<ACD);
    #endif
  #endif
  #if !defined(ARDUINO_AVR_ATTINYX5) || (defined(ARDUINO_AVR_ATTINYX5) && !LOGGER)
    driver.init();
    driver.setHeaderId(SENSORID);
  #endif
  LogLn("Startup");

  ds18b20.begin();
  if(ds18b20.getDeviceCount() > 0) { temp_enabled = true; }

  //rh_payload[0]=10;

  // Temperature initial (-100)
  rh_payload[3] = 0xff;
  rh_payload[4] = 0x9c;

  setSensorType(1);
  setBatteryStatus(0);

  setBatteryVoltage(123);
  setBatteryPercent(50);

  //if(temp_enabled == true) { setTemperature(); }
  //setHumidity();
}

void loop()
{
   //Serial.println("Send");
  if(temp_enabled == true) { setTemperature(); }
  setHumidity();

  #if !defined(ARDUINO_AVR_ATTINYX5) || (defined(ARDUINO_AVR_ATTINYX5) && !LOGGER)
    for(uint8_t i=0;i<3;i++)
    {
      driver.send(rh_payload, 6);
      driver.waitPacketSent();
    }
  #endif
  LogLn("Before delay");
  delay(15000);
  myTime = millis();
  LogLn(sleepcount);
  LogLn(myTime);
  if(sleepcount > sleeprepeatbat)
  {
    LogLn("Probe Battery");
    sleepcount = 0;
  } else {
    sleepcount = sleepcount + 1;
  }
  //setupWatchDogTimer(WDTO_8S);
  for (uint8_t i=0; i<sleeprepeat; i++) { powerDown(); }
  //sleep_disable();
}
