// https://arduino.stackexchange.com/questions/95476/fixing-a-pedestrian-traffic-light-sequence-pattern-in-a-cycle-using-millis-and-w

// for simulation, see https://wokwi.com/projects/389132610627050497

const int redLED   = 2;
const int greenLED = 3;

unsigned int timeInterval  [4] = {  5,  3,  4,  0};             // timers reload with these values
unsigned int timeCounter   [4] = {  0,  0,  0,  0};             // these are the actual timers

//boolean     reloadable    [4] = {true, true, false, false};   // this determines if the timer will restart upon reaching end
                                                                // put value in <timeCounter> for oneshot event 
                                                                // 3rd and 4th timers are not used in this example sketch

boolean       tick [4]  = {false, false, false, false};         // countdown timers flags
boolean       mainTick  = false;
boolean       subTick   = false;

boolean       red       = false;
boolean       green     = false;
boolean       blink     = false;


unsigned long previousMillis = 0;

void setup() {

  Serial.begin(115200);

//memcpy(timeCounter, timeInterval, 4 * sizeof(long));           // preload timers

  green = true;                                                  // start with green
  timeCounter[0] = 1;                                            // load the first counter

}

void loop() {

  unsigned long currentMillis = millis();

// -------------------------------------------------------------------

  if (currentMillis - previousMillis >= 500) {                    // 0.5 s tick
    previousMillis = currentMillis;
    subTick = !subTick;                                           // alternate the value

    if (subTick) {
      mainTick = true;                                            // 1 s tick

  //  Serial.println("tick");                                     // debugging code

      for (int i = 0; i < 4; i++) {                               // keep track of 4 time intervals

        timeCounter[i]-- ;                                        // decrement counter

        if (timeCounter[i] == 0) {
  //      if (reloadable[i])  timeCounter[i] = timeInterval[i];   // reached zero, reload counter if it is reloadable
          tick[i] = true;                                         // emit a "tick"
        }
      }
    }
  }

// -------------------------------------------------------------------

  if (mainTick) {                                         // 1 s tick
  }

// -------------------------------------------------------------------

  if (tick[0]) {                                          //
    tick[0] = false;
    timeCounter[1] = timeInterval[1];                     // setup the next tick

    red   = false;                                        // setup flags
    green = true;
    blink = false;
  }

// -------------------------------------------------------------------

  if (tick[1]) {                                          //
    tick[1] = false;                                      // clear flag so that code runs only once every tick
    timeCounter[2] = timeInterval[2];                     // setuop the next tick

    red   = true;
    green = false;
    blink = false;
  }

// -------------------------------------------------------------------

  if (tick[2]) {                                          //
    tick[2] = false;                                      // clear flag so that code runs only once every tick
    timeCounter[0] = timeInterval[0];                     // setuop the next tick

    red   = false;
    green = false;
    blink = true;
  }

// -------------------------------------------------------------------

  if (mainTick) {                                         // can have multiples of these
    mainTick = false;                                     // clear the flag in the last one
  }

// -------------------------------------------------------------------

  digitalWrite(redLED  , red             ? HIGH:LOW);     // C++ ternary operator
  digitalWrite(greenLED, green           ? HIGH:LOW);
  digitalWrite(redLED  , blink && subTick? HIGH:LOW);     // subTick changes every 500 ms
}