// See  https://forum.arduino.cc/t/traffic-light-time-to-green-count-down/1168737
// See  https://www.circuitstate.com/tutorials/how-to-write-parallel-multitasking-applications-for-esp32-using-freertos-arduino/


#include <LiquidCrystal_I2C.h>

const uint8_t redPin = 14 ;
const uint8_t amberPin = 12 ;
const uint8_t greenPin = 13 ;

int32_t counter = 0 ;
uint32_t redStartAtMs = 0 ;

LiquidCrystal_I2C  lcd(0x27, 16, 2);

SemaphoreHandle_t xSemaphore = NULL;  // Create a semaphore object


void setup() {
  // initialize digital pin LED_BUILTIN as an output.
  pinMode (LED_BUILTIN, OUTPUT);
  pinMode( redPin, OUTPUT) ;
  pinMode( amberPin, OUTPUT) ;
  pinMode( greenPin, OUTPUT) ;

  lcd.init( );
  lcd.backlight();

  xSemaphore = xSemaphoreCreateBinary();  // Set the semaphore as binary


  Serial.begin (115200);
  xTaskCreatePinnedToCore (
    task1,     // Function to implement the task
    "task1",   // Name of the task
    1000,      // Stack size in bytes
    NULL,      // Task input parameter
    0,         // Priority of the task
    NULL,      // Task handle.
    0          // Core where the task should run
  );

  xTaskCreatePinnedToCore (
    task2,     // Function to implement the task
    "task2",   // Name of the task
    4000,      // Stack size in bytes  LCD needs more space
    NULL,      // Task input parameter
    0,         // Priority of the task
    NULL,      // Task handle.
    0          // Core where the task should run
  );

}


void loop() {
  // this gives task1 and task2 a chance to run
  digitalWrite (LED_BUILTIN, HIGH);   
  delay (1000);   
  digitalWrite (LED_BUILTIN, LOW);  
  delay (1000);   
}

void task1 (void* pvParameters) {
  while (1) {
    redStartAtMs = millis() ;
    counter = 7 ;
    xSemaphoreGive (xSemaphore);  // Release the semaphore
    digitalWrite( redPin, HIGH) ;
    delay(8000UL) ;  
    digitalWrite( amberPin, HIGH) ;
    delay(3000UL) ;
    digitalWrite( redPin, LOW) ;
    digitalWrite( amberPin, LOW) ;
    digitalWrite( greenPin, HIGH) ;
    delay(9000UL) ;
    digitalWrite( greenPin, LOW) ;
    digitalWrite( amberPin, HIGH) ;
    delay(3000) ;
    digitalWrite( amberPin, LOW) ;
  }
}

void task2 (void* pvParameters) {
  while (1) {
     
    if (xSemaphoreTake (xSemaphore, 22000UL )) {   // timeout just under cycle time
      while ( counter > 0) {
        lcd.setCursor(0, 0);
        lcd.print("    ") ;
        lcd.setCursor(0, 0);
        lcd.print( counter -- );
        delay(1000UL);
        if ( counter <= 0 ) {
          lcd.clear() ;
        }
      }
    }
     
  }
}