/*
  Simple demo of using all the timing helpers elapsedMillis makes available.

 Code from https://github.com/pfeerick/elapsedMillis/blob/master/examples/blinkingLeds/blinkingLeds.ino

  Modified to test the rollover of elapsedSeconds.
  Wokwi: https://wokwi.com/projects/402859003988453377

  See https://github.com/pfeerick/elapsedMillis/issues/16

  Either attach LEDs with series resistors to the indicated pins, or a
  six led / six bit 'Chartreuse' module plugged into pins 8 through GND.

  Wired up in order, the leds have a nice walking/counting effect.

  This example code is in the public domain.
*/


class elapsedMicros
{
private:
	unsigned long us;
public:
	elapsedMicros(void) { us = micros(); }
	elapsedMicros(unsigned long val) { us = micros() - val; }
	elapsedMicros(const elapsedMicros &orig) { us = orig.us; }
	operator unsigned long () const { return micros() - us; }
	elapsedMicros & operator = (const elapsedMicros &rhs) { us = rhs.us; return *this; }
	elapsedMicros & operator = (unsigned long val) { us = micros() - val; return *this; }
	elapsedMicros & operator -= (unsigned long val)      { us += val ; return *this; }
	elapsedMicros & operator += (unsigned long val)      { us -= val ; return *this; }
	elapsedMicros operator - (int val) const           { elapsedMicros r(*this); r.us += val; return r; }
	elapsedMicros operator - (unsigned int val) const  { elapsedMicros r(*this); r.us += val; return r; }
	elapsedMicros operator - (long val) const          { elapsedMicros r(*this); r.us += val; return r; }
	elapsedMicros operator - (unsigned long val) const { elapsedMicros r(*this); r.us += val; return r; }
	elapsedMicros operator + (int val) const           { elapsedMicros r(*this); r.us -= val; return r; }
	elapsedMicros operator + (unsigned int val) const  { elapsedMicros r(*this); r.us -= val; return r; }
	elapsedMicros operator + (long val) const          { elapsedMicros r(*this); r.us -= val; return r; }
	elapsedMicros operator + (unsigned long val) const { elapsedMicros r(*this); r.us -= val; return r; }
};

class elapsedMillis
{
private:
	unsigned long ms;
public:
	elapsedMillis(void) { ms = millis(); }
	elapsedMillis(unsigned long val) { ms = millis() - val; }
	elapsedMillis(const elapsedMillis &orig) { ms = orig.ms; }
	operator unsigned long () const { return millis() - ms; }
	elapsedMillis & operator = (const elapsedMillis &rhs) { ms = rhs.ms; return *this; }
	elapsedMillis & operator = (unsigned long val) { ms = millis() - val; return *this; }
	elapsedMillis & operator -= (unsigned long val)      { ms += val ; return *this; }
	elapsedMillis & operator += (unsigned long val)      { ms -= val ; return *this; }
	elapsedMillis operator - (int val) const           { elapsedMillis r(*this); r.ms += val; return r; }
	elapsedMillis operator - (unsigned int val) const  { elapsedMillis r(*this); r.ms += val; return r; }
	elapsedMillis operator - (long val) const          { elapsedMillis r(*this); r.ms += val; return r; }
	elapsedMillis operator - (unsigned long val) const { elapsedMillis r(*this); r.ms += val; return r; }
	elapsedMillis operator + (int val) const           { elapsedMillis r(*this); r.ms -= val; return r; }
	elapsedMillis operator + (unsigned int val) const  { elapsedMillis r(*this); r.ms -= val; return r; }
	elapsedMillis operator + (long val) const          { elapsedMillis r(*this); r.ms -= val; return r; }
	elapsedMillis operator + (unsigned long val) const { elapsedMillis r(*this); r.ms -= val; return r; }
};

class elapsedSeconds
{
private:
	unsigned long ms;
public:
	elapsedSeconds(void) { ms = millis(); }
	elapsedSeconds(unsigned long val) { ms = millis() - val * 1000; }
	elapsedSeconds(const elapsedSeconds &orig) { ms = orig.ms; }
	operator unsigned long () const { return (millis() - ms) / 1000; }
	elapsedSeconds & operator = (const elapsedSeconds &rhs) { ms = rhs.ms; return *this; }
	elapsedSeconds & operator = (unsigned long val)         { ms = millis() - val * 1000; return *this; }
	elapsedSeconds & operator -= (unsigned long val)    { ms += val * 1000; return *this; }
	elapsedSeconds & operator += (unsigned long val)    { ms -= val * 1000; return *this; }
	elapsedSeconds operator - (int val) const           { elapsedSeconds r(*this); r.ms += val * 1000; return r; }
	elapsedSeconds operator - (unsigned int val) const  { elapsedSeconds r(*this); r.ms += val * 1000; return r; }
	elapsedSeconds operator - (long val) const          { elapsedSeconds r(*this); r.ms += val * 1000; return r; }
	elapsedSeconds operator - (unsigned long val) const { elapsedSeconds r(*this); r.ms += val * 1000; return r; }
	elapsedSeconds operator + (int val) const           { elapsedSeconds r(*this); r.ms -= val * 1000; return r; }
	elapsedSeconds operator + (unsigned int val) const  { elapsedSeconds r(*this); r.ms -= val * 1000; return r; }
	elapsedSeconds operator + (long val) const          { elapsedSeconds r(*this); r.ms -= val * 1000; return r; }
	elapsedSeconds operator + (unsigned long val) const { elapsedSeconds r(*this); r.ms -= val * 1000; return r; }
};

//declare these global if you don't want them reset every time loop runs
elapsedMicros LED1micro;
elapsedMicros LED2micro;
elapsedMillis LED3millis;
elapsedMillis LED4millis;
elapsedSeconds LED5seconds;
elapsedSeconds LED6seconds;

const int LED1 = 8;
const int LED2 = 9;
const int LED3 = 10;
const int LED4 = 11;
const int LED5 = 12;
const int LED6 = 13;

// delay between blinks of the LED
unsigned long LED1_Interval = 62500;
unsigned long LED2_Interval = 125000;
unsigned long LED3_Interval = 250;
unsigned long LED4_Interval = 500;
unsigned long LED5_Interval = 1;
unsigned long LED6_Interval = 2;

extern volatile unsigned long timer0_millis;

void setup()
{
  // initialize the LED pins as outputs
  pinMode(LED1, OUTPUT);
  pinMode(LED2, OUTPUT);
  pinMode(LED3, OUTPUT);
  pinMode(LED4, OUTPUT);
  pinMode(LED5, OUTPUT);
  pinMode(LED6, OUTPUT);
  noInterrupts ();
  timer0_millis = -7200;
  interrupts ();

  LED1micro = LED2micro = LED3millis = LED4millis = LED5seconds = LED6seconds = 0;
}

void loop()
{
  if (LED1micro >= LED1_Interval)
  {
    digitalWrite(LED1, !(digitalRead(LED1))); // toggle the LED state
    LED1micro -= LED1_Interval;                           // reset the counter to 0 so the counting starts over...
  }

  if (LED2micro >= LED2_Interval)
  {
    digitalWrite(LED2, !(digitalRead(LED2))); // toggle the LED state
    LED2micro -= LED2_Interval;                            // reset the counter to 0 so the counting starts over...
  }

  if (LED3millis >= LED3_Interval)
  {
    digitalWrite(LED3, !(digitalRead(LED3))); // toggle the LED state
    LED3millis -= LED3_Interval;                           // reset the counter to 0 so the counting starts over...
  }

  if (LED4millis >= LED4_Interval)
  {
    digitalWrite(LED4, !(digitalRead(LED4))); // toggle the LED state
    LED4millis -= LED4_Interval;                           // reset the counter to 0 so the counting starts over...
  }

  if (LED5seconds >= LED5_Interval)
  {
    digitalWrite(LED5, !(digitalRead(LED5))); // toggle the LED state
    LED5seconds -= LED5_Interval;                          // reset the counter to 0 so the counting starts over...
  }

  if (LED6seconds >= LED6_Interval)
  {
    digitalWrite(LED6, !(digitalRead(LED6))); // toggle the LED state
    LED6seconds -= LED6_Interval;                         // reset the counter to 0 so the counting starts over...
  }
}