// SeveralThingsAtTheSameTime -- adafruit multitaskingP1 version
// https://wokwi.com/projects/397172393690134529
// See the Adafruit series at https://learn.adafruit.com/multi-tasking-the-arduino-part-1/all-together-now 
//
// An implementation of the Robin2 function based SevralThingsAtTheSameTime from:  
// https://forum.arduino.cc/t/demonstration-code-for-several-things-at-the-same-time/217158/1
// https://forum.arduino.cc/t/demonstration-code-for-several-things-at-the-same-time/217158/2
// Sim: Wokwi: https://wokwi.com/projects/366664987128970241
// per 
// https://forum.arduino.cc/t/circuit-with-1-button-and-3-leds/1134897/3

// An expansion of the BlinkWithoutDelay concept to illustrate how a script
//  can appear to do several things at the same time

// this sketch does the following
//    it blinks three lights at different rates on pins 10,11,12, inhibiting #10 when the button is pressed
//    it sweeps a servo (connected to pin 5) back and forth
//    it sweeps a servo (connected to pin 6) back and forth slower, and only when the button isn't pressed
//    when the button is pressed, it inhibits the pin10 LED and pin 6 servo

//  One leg of each LED should be connected to the relevant pin and the other leg should be connected to a
//   resistor of 470 ohms or more and the other end of the resistor to the Arduino GND. 
//   If the LED doesn't light its probably connected the wrong way round.

//  The Arduino is not capable of supplying enough 5v power to operate a servo
//    The servo should have it's own power supply and the power supply Ground should
//      be connected to the Arduino Ground.

//=======

#include <Servo.h> 


class Flasher
{
	// Class Member Variables
	// These are initialized at startup
	int ledPin;      // the number of the LED pin
	long OnTime;     // milliseconds of on-time
	long OffTime;    // milliseconds of off-time

	// These maintain the current state
	int ledState;             		// ledState used to set the LED
	unsigned long previousMillis;  	// will store last time LED was updated

  // Constructor - creates a Flasher 
  // and initializes the member variables and state
  public:
  Flasher(int pin, long on, long off)
  {
	ledPin = pin;
	pinMode(ledPin, OUTPUT);     
	  
	OnTime = on;
	OffTime = off;
	
	ledState = LOW; 
	previousMillis = 0;
  }

  void Update()
  {
    // check to see if it's time to change the state of the LED
    unsigned long currentMillis = millis();
     
    if((ledState == HIGH) && (currentMillis - previousMillis >= OnTime))
    {
    	ledState = LOW;  // Turn it off
      previousMillis = currentMillis;  // Remember the time
      digitalWrite(ledPin, ledState);  // Update the actual LED
    }
    else if ((ledState == LOW) && (currentMillis - previousMillis >= OffTime))
    {
      ledState = HIGH;  // turn it on
      previousMillis = currentMillis;   // Remember the time
      digitalWrite(ledPin, ledState);	  // Update the actual LED
    }
  }
};

class Sweeper
{
  Servo servo;              // the servo
  int pos;              // current servo position 
  int increment;        // increment to move for each interval
  int  updateInterval;      // interval between updates
  unsigned long lastUpdate; // last update of position

public: 
  Sweeper(int interval)
  {
    updateInterval = interval;
    increment = 1;
  }
  
  void Attach(int pin)
  {
    servo.attach(pin);
  }
  
  void Detach()
  {
    servo.detach();
  }
  
  void Update()
  {
    if((millis() - lastUpdate) > updateInterval)  // time to update
    {
      lastUpdate = millis();
      pos += increment;
      servo.write(pos);
    //  Serial.println(pos);
      if ((pos >= 180) || (pos <= 0)) // end of sweep
      {
        // reverse direction
        increment = -increment;
      }
    }
  }
};
 
 
Flasher led1(10, 123, 400);
Flasher led2(11, 350, 350);
Flasher led3(12, 200, 222);

Sweeper sweeper1(15);
Sweeper sweeper2(25);
 
void setup() 
{ 
  Serial.begin(9600);
  pinMode(2, INPUT_PULLUP); 
  sweeper1.Attach(5);
  sweeper2.Attach(6);
} 
 
 
void loop() 
{ 
  sweeper1.Update();
  
  if(digitalRead(2) == HIGH)
  {
     sweeper2.Update();
     led1.Update();
  }
  
  led2.Update();
  led3.Update();
}