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

// Utility macros
#define adc_disable() (ADCSRA &= ~_BV(ADEN)) // disable ADC (before power-off)
#define adc_enable()  (ADCSRA |= _BV(ADEN)) // re-enable ADC
#define enable_pin_interrupts()  (GIMSK |= _BV(PCIE))  // Enable Pin Change Interrupts

// Pins
#define SWITCH 0
#define SENDER 2
#define CONTROLLER 4

RCSwitch mySwitch = RCSwitch();
char* WND_OPEN  =  "00000000000000000000000001000001";
char* WND_CLOSED = "00000000000000000000000001100001";

int counter = 0;
bool currentState;

void setup() {
    
  pinMode(SWITCH, INPUT_PULLUP);
  pinMode(CONTROLLER, OUTPUT);
  digitalWrite(CONTROLLER, LOW);

  mySwitch.enableTransmit(SENDER);
  mySwitch.setProtocol(2);

  updateState();
  sendWindowState();

  set_sleep_mode(SLEEP_MODE_PWR_DOWN);
  enable_pin_interrupts();
  enableWdt();

}

void loop() {
  sleep();
}

void updateState() {
  currentState = digitalRead(SWITCH);
}

void sendWindowState() {
  byte state = digitalRead(SWITCH);
  if (state == HIGH) {
    mySwitch.send(WND_OPEN);
  } else {
    mySwitch.send(WND_CLOSED);
  }
}

void sleep() {
  PCMSK |= _BV(PCINT0);                   // Use PB0 as interrupt pin
  adc_disable();
  
  sleep_enable();                         // Sets the Sleep Enable bit in the MCUCR Register (SE BIT)
  sei();                                  // Enable interrupts

  sleep_cpu();                            // sleep
  
  cli();                                  // Disable interrupts
  PCMSK &= ~_BV(PCINT0);                  // Turn off PB0 as interrupt pin
  sleep_disable();                        // Clear SE bit
  adc_enable();
  
  sei();                                  // Enable interrupts
}

ISR(PCINT0_vect) {
  sendWindowState();
}

ISR(WDT_vect) {
  bool state = digitalRead(SWITCH);
  if (state != currentState) {
    sendWindowState();
    updateState();
    return;
  }
  counter++;
  if (counter % 76 == 0) {
    sendWindowState();
    counter = 0;
  }
}

//enable the wdt for 8sec interrupt
void enableWdt()
{
    MCUSR = 0x00;
    WDTCR |= _BV(WDCE) | _BV(WDE);
    WDTCR = _BV(WDIE) | _BV(WDP3) | _BV(WDP0);    //8192ms
}

