/*
   Tree Ornament
   By Chris Ritchie 17/3/2017
   Watchdog timer code by Sparkfun from H2OhNo - https://github.com/sparkfun/H2OhNo
 */

#include <avr/sleep.h> //Needed for sleep_mode
#include <avr/wdt.h> //Needed to enable/disable watch dog timer

byte randomNumber;
struct LEDS
{
  byte selected: 1;
};

struct LEDS flash[5];
byte flashed = 0;

ISR(WDT_vect) {

}


void setup() {
  randomSeed(analogRead(2));
  pinMode(0, OUTPUT);
  pinMode(1, OUTPUT);
  pinMode(2, OUTPUT);
  pinMode(3, OUTPUT);
  pinMode(4, OUTPUT);


// Turn on all leds
  for (int i = 0; i <= 4; i++)
    digitalWrite(i, HIGH);
  delay(100);
  for (int i = 0; i <= 4; i++)
    digitalWrite(i, LOW);
  delay(200);

  //Power down various bits of hardware to lower power usage
  set_sleep_mode(SLEEP_MODE_PWR_DOWN); //Power down everything, wake up from WDT
  sleep_enable();
}

void loop()
{
  ADCSRA &= ~(1 << ADEN); //Disable ADC, saves ~230uA
 
 // If all all 5 sets of leds have flashed, reset
  if (flashed >= 5)
  {
    reset();
  }

  randomNumber = random(5);

  // Only flash led if it hasn't already flashed
  if (flash[randomNumber].selected == false)
  {
    wdt_disable();

    digitalWrite(randomNumber, HIGH);
    delay(500);
    digitalWrite(randomNumber, LOW);

    setup_watchdog(7); //Setup watchdog to go off after 1sec
    sleep_mode();
    ADCSRA |= (1 << ADEN); //Enable ADC
    flash[randomNumber].selected = true;
    flashed++;
  }
}

void reset()
{
  for (int i = 0; i < 5; i++)
  {
    flash[i].selected = false;
  }
  flashed = 0;
  return;
}

//Sets the watchdog timer to wake us up, but not reset
//0=16ms, 1=32ms, 2=64ms, 3=128ms, 4=250ms, 5=500ms
//6=1sec, 7=2sec, 8=4sec, 9=8sec
//From: http://interface.khm.de/index.php/lab/experiments/sleep_watchdog_battery/
void setup_watchdog(int timerPrescaler) {

  if (timerPrescaler > 9 ) timerPrescaler = 9; //Limit incoming amount to legal settings

  byte bb = timerPrescaler & 7;
  if (timerPrescaler > 7) bb |= (1 << 5); //Set the special 5th bit if necessary

  //This order of commands is important and cannot be combined
  MCUSR &= ~(1 << WDRF); //Clear the watch dog reset
  WDTCR |= (1 << WDCE) | (1 << WDE); //Set WD_change enable, set WD enable
  WDTCR = bb; //Set new watchdog timeout value
  WDTCR |= _BV(WDIE); //Set the interrupt enable, this will keep unit from resetting after each int
}