// Forum: https://forum.arduino.cc/t/using-analogwrite-and-getting-strange-initial-results/1260900/
// This Wokwi project: https://wokwi.com/projects/398128680494393345

// SIM Day Night Control Rel.3 ver.0


#define initRed 0
#define initGrn 0
#define initBlu 200

int prevRedPWM = initRed; // start with 6:00 AM values
int prevGrnPWM = initGrn;
int prevBluPWM = initBlu;

int RedPWMTarget, GrnPWMTarget, BluPWMTarget; // PWM variables
float diffRed, diffGrn, diffBlu;

int  iter, maxiter; // time/schedule variables
unsigned long fadeTime;
unsigned long currentTime, beginTime, loopBegin;

int RedOut = 11; // GPIO ouput pins in use (no input GPIO pins) 9,11,10
int GrnOut = 10;
int BluOut = 9;


//test bool readln_PWMColors(int& Value1, int& Value2, int& Value3);
bool doneRed = false, doneGrn = false, doneBlu = false; // status boolean variables

int RedPWM = initRed;
int GrnPWM = initGrn;
int BluPWM = initBlu;
const unsigned long   deltaSchedule = 5000ul;
const int indexMax = 10;
int simData [indexMax] [3] = {
  //  R  G  B

  { 0, 0, 200}, // night
  { 0, 0, 200},
  { 50, 0, 200},
  { 254, 84, 0}, // sunrise
  { 254, 84, 0},
  { 245, 245, 245}, // daylight
  { 245, 245, 245},
  { 245, 245, 245},
  { 152, 0, 217}, // sunset
  { 152, 0, 217}

};



// =======
//  setup
// =======

void setup() {
  Serial.begin(9600);
  fadeTime = (unsigned long) ((deltaSchedule / 256) - 1);
  maxiter = deltaSchedule / fadeTime;
  pinMode(RedOut, OUTPUT); // GPIO ouput pins in use (no input GPIO pins)
  pinMode(GrnOut, OUTPUT);
  pinMode(BluOut, OUTPUT);

  Serial.print("Test blinks... ");
  for(int b=255; b>0; b/=2)
  {
    analogWrite(RedOut, b);
    analogWrite(GrnOut, b);
    analogWrite(BluOut, b);
    delay(200);
    analogWrite(RedOut, 0);
    analogWrite(GrnOut, 0);
    analogWrite(BluOut, 0);
    delay(200);
  }
  Serial.println("Done");
  delay(1000);

  // Set up initial state
  analogWrite(RedOut, initRed); // output initial PWM values
  analogWrite(GrnOut, initGrn);
  analogWrite(BluOut, initBlu);
}




// ======
//  loop
// ======

void loop() {
  // Wait for color change command,,,
  //test### while ( !Serial.available());
  for (int index = 0; index < indexMax; index++) { //test

    // test### Get target PWM connands from test/sim array
    // Get target PWM values for LED colors from serial port.
    // test### readln_PWMColors(RedPWMTarget, GrnPWMTarget, BluPWMTarget);
    RedPWMTarget = simData [index][0]; //test###
    GrnPWMTarget = simData [index][1]; //test###
    BluPWMTarget = simData [index][2]; //test###

    // Calculate incremental differences to target PWM values
    diffRed = (float)(RedPWMTarget - prevRedPWM) / (float)maxiter; // Calculate PWM changes for Red fade
    diffGrn = (float)(GrnPWMTarget - prevGrnPWM) / (float)maxiter; // ditto for Green fade
    diffBlu = (float)(BluPWMTarget - prevBluPWM) / (float)maxiter; // ditto for Blue fade

    // initialize flags  (doneXxx)mand times (xxxxTime/xxxxBegin)
    doneRed = false; doneGrn = false; doneBlu = false; // set color output status
    beginTime = millis(); currentTime = millis(); loopBegin = millis(); iter = 1;

    //while elapsed time is less than the defined time for each loop
    while (currentTime - loopBegin <= deltaSchedule)
    {
      currentTime = millis();
      if (currentTime - beginTime >= fadeTime) { // fade from old to new PWM values in the current timeslice
        //                                          while elapsed time is less than the calculated fade time
        // Red PWM
        if (!doneRed) { // not done displaying Red
          RedPWM = (int)((float)prevRedPWM +  ((float)iter * diffRed)); // calculate next(?previous) PWM value
          if (abs(RedPWM - RedPWMTarget) <= 1) { // check for end of fade
            RedPWM = RedPWMTarget; // set PWM value = target
            doneRed = true;  // set flag indicating finished fading to target PWM value
          }
        }
        // Grn PWM
        if (!doneGrn) {
          GrnPWM = (int)((float)prevGrnPWM +  ((float)iter * diffGrn));
          if (abs(GrnPWM - GrnPWMTarget) <= 1) { // check for end of fade
            GrnPWM = GrnPWMTarget;
            doneGrn = true;
          }
        }
        // Blu PWM
        if (!doneBlu) {
          BluPWM = (int)((float)prevBluPWM +  ((float)iter * diffBlu));
          if (abs(BluPWM - BluPWMTarget) <= 1) { // check for end of fade
            BluPWM = BluPWMTarget;
            doneBlu = true;
          }
        }
        analogWrite(RedOut, RedPWM); // output intermediate/final PWM values
        analogWrite(GrnOut, GrnPWM);
        analogWrite(BluOut, BluPWM);
        iter++; // test###
        beginTime = millis(); // set beginning of next timeslice
      } // for fading time slice
    } // while in current scenario
    prevRedPWM = RedPWM;
    prevGrnPWM = GrnPWM;
    prevBluPWM = BluPWM;
  } // end fade command (while/for)
  RedPWM = 0; GrnPWM = 0; BluPWM = 0;
}
common anode
common cathode