#include <Arduino_FreeRTOS.h>
#include <task.h>
#include <semphr.h>

//estructura de objeto que almacena info de un mensaje, en este caso sera el pin
typedef struct AMessage {
  int interrupcion_pin;
} Objeto;  

//pines
const int infraccion_auto = 2;
const int infraccion_peaton = 3;
const int btn_peaton = 18;
const int interrupcion_auto_b = 19;
const int interrupcion_auto_a = 20;
const int interrupcion_ambulancia = 21;

//tareas
void vehicleNormalTask(void *parameters);
void tareaInterrupcionAutoRojo(void *parameters);
void tareaInterrupcionPeatonRojo(void *parameters);
void tareaInterrupcionPeaton(void *parameters);
void tareaInterrupcionAmbulancia(void *parameters);
void tareaInterrupcionAutoA(void *parameters);
void tareaInterrupcionAutoB(void *parameters);

//semaforo y cola
SemaphoreHandle_t mutex;
QueueHandle_t cola;

void setup() {
  Serial.begin(9600);
  //modo de los pines
  pinMode(infraccion_auto, INPUT_PULLUP);
  pinMode(infraccion_peaton, INPUT_PULLUP);
  pinMode(btn_peaton, INPUT_PULLUP);
  pinMode(interrupcion_auto_b, INPUT_PULLUP);
  pinMode(interrupcion_auto_a, INPUT_PULLUP);
  pinMode(interrupcion_ambulancia, INPUT_PULLUP);

  //inicializacion de la cola y el semaforo
  cola = xQueueCreate(6, sizeof(Objeto));
  mutex = xSemaphoreCreateMutex();

  //creacion de la tarea principal que corre el ciclo del semaforo
  xTaskCreate(vehicleNormalTask, "NormalA", 128, NULL, 1, NULL);

  //declaracion de interrupciones
  if (mutex != NULL) {
    attachInterrupt(digitalPinToInterrupt(infraccion_auto), interrupcionAutoRojo, FALLING);
    attachInterrupt(digitalPinToInterrupt(infraccion_peaton), interrupcionPeatonRojo, FALLING);
    attachInterrupt(digitalPinToInterrupt(btn_peaton), interrupcionPeaton, FALLING);
    attachInterrupt(digitalPinToInterrupt(interrupcion_auto_b), interrupcionAutoB, FALLING);
    attachInterrupt(digitalPinToInterrupt(interrupcion_auto_a), interrupcionAutoA, FALLING);
    attachInterrupt(digitalPinToInterrupt(interrupcion_ambulancia), interrupcionAmbulancia, FALLING);
  }

  //inicializacion del planificador
  vTaskStartScheduler();

}
// -----------------------------------------------------------------------------------------------
// -----------------------------------------------------------------------------------------------
// interrupcion y tarea de si un auto pasa el semaforo en rojo

void interrupcionAutoRojo(){
  //establezco una tarea auxiliar
  TaskHandle_t xHandle = NULL;
  //creo la tarea de la interrupcion y le paso por parametro el auxiliar para eliminarlo al finalizar el ciclo
  xTaskCreate(tareaInterrupcionAutoRojo, "Tarea Interrupcion Auto Rojo", 128, NULL, 1, &xHandle);
  //establezco el pin del objeto
  Objeto obj = { 2 };
  //libero el semaforo desde la ISR
  xSemaphoreGiveFromISR(mutex, NULL);
  //reviso si el semaforo esta ocupado
  if(xSemaphoreTakeFromISR(mutex, NULL) == pdTRUE) {
    //agrego la tarea a la cola
    if(xQueueSendFromISR(cola, &obj, NULL) == pdPASS) Serial.println("Se envio la interrupcion");
    xSemaphoreGiveFromISR(mutex, NULL);
  }
  //elimino la tarea despues de la ejecucion de la tarea
  if( xHandle != NULL ){vTaskDelete( xHandle );}
}

void tareaInterrupcionAutoRojo(void *parameters){
  while(1){
    //tomo el semaforo si esta libre 
    if(xSemaphoreTake(mutex, portMAX_DELAY) == pdTRUE)
    {
      // le digo que suene la bocina
      Serial.println("Cruzo un auto en rojo");
      tone(4, 1000, 4000);
      }
    } 
    //espero 3 seg
    vTaskDelay(3000/portTICK_PERIOD_MS);
    //libero el semaforo
    xSemaphoreGive(mutex);
  }

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

// ******* LAS DEMAS TAREAS E INTERRUPCIONES TIENEN LA MISMA ESTRUCTURA Y LOGICA QUE LAS PRIMERAS ******* 
// ******* LAS DEMAS TAREAS E INTERRUPCIONES TIENEN LA MISMA ESTRUCTURA Y LOGICA QUE LAS PRIMERAS ******* 
// ******* LAS DEMAS TAREAS E INTERRUPCIONES TIENEN LA MISMA ESTRUCTURA Y LOGICA QUE LAS PRIMERAS ******* 

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

void interrupcionPeatonRojo(){
  TaskHandle_t xHandle = NULL;
  xTaskCreate(tareaInterrupcionPeatonRojo, "Tarea Interrupcion Peaton Rojo", 128, NULL, 1,  &xHandle);
  Objeto obj = { 3 };
  xSemaphoreGiveFromISR(mutex, NULL);
  if(xSemaphoreTakeFromISR(mutex, NULL) == pdTRUE) {
    if(xQueueSendFromISR(cola, &obj, NULL) == pdPASS) Serial.println("Se envio la interrupcion");
    xSemaphoreGiveFromISR(mutex, NULL);
  }
  //elimino la tarea despues de la ejecucion de la tarea
  if( xHandle != NULL ){vTaskDelete( xHandle );}
}

void tareaInterrupcionPeatonRojo(void *parameters){
  while(1){
    if(xSemaphoreTake(mutex, portMAX_DELAY) == pdTRUE){
      Serial.println("Cruzo un peaton en rojo");
      tone(4, 1000, 4000);
      }
    } 
    vTaskDelay(5000/portTICK_PERIOD_MS);
    xSemaphoreGive(mutex);
  
}

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

void interrupcionPeaton(){
  TaskHandle_t xHandle = NULL;
  xTaskCreate(tareaInterrupcionPeaton, "Tarea Interrupcion Peaton", 128, NULL, 1, &xHandle );
  Objeto obj = { 18 };
    xSemaphoreGiveFromISR(mutex, NULL);
    if(xSemaphoreTakeFromISR(mutex, NULL) == pdTRUE) {
      if(xQueueSendFromISR(cola, &obj, NULL) == pdPASS) Serial.println("Se envio la interrupcion");
      xSemaphoreGiveFromISR(mutex, NULL);
    }
    
   //elimino la tarea despues de la ejecucion de la tarea
  if( xHandle != NULL ){vTaskDelete( xHandle );}

}

void tareaInterrupcionPeaton(void *parameters){
  while(1){
    if(xSemaphoreTake(mutex, portMAX_DELAY) == pdTRUE)
    {
      Serial.println("PEATON CRUZANDO");
      semaforoA();
    } 
  }
  
  xSemaphoreGive(mutex);
}

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

void interrupcionAutoB(){
  TaskHandle_t xHandle = NULL;
  xTaskCreate(tareaInterrupcionAutoB, "Tarea Interrupcion Auto B", 128, NULL, 1, &xHandle );
  Objeto obj = { 19 };
  xSemaphoreGiveFromISR(mutex, NULL);
  if(xSemaphoreTakeFromISR(mutex, NULL) == pdTRUE) {
    if(xQueueSendFromISR(cola, &obj, NULL) == pdPASS) Serial.println("Se envio la interrupcion");
    xSemaphoreGiveFromISR(mutex, NULL);
  }
  //elimino la tarea despues de la ejecucion de la tarea
  if( xHandle != NULL ){vTaskDelete( xHandle );}
}

void tareaInterrupcionAutoB(void *parameters){
  while(1){
    if(xSemaphoreTake(mutex, portMAX_DELAY) == pdTRUE)
    {
      Serial.println("semaforo b en verde");
      semaforoB();
    }
  }
  vTaskDelay(5000/portTICK_PERIOD_MS);
  xSemaphoreGive(mutex);
}

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

void interrupcionAutoA(){
  TaskHandle_t xHandle = NULL;
  xTaskCreate(tareaInterrupcionAutoA, "Tarea Interrupcion Auto A", 128, NULL, 1, &xHandle);
  Objeto obj = { 20 };
  xSemaphoreGiveFromISR(mutex, NULL);
  if(xSemaphoreTakeFromISR(mutex, NULL) == pdTRUE) {
    if(xQueueSendFromISR(cola, &obj, NULL) == pdPASS) Serial.println("Se envio la interrupcion");
    xSemaphoreGiveFromISR(mutex, NULL);
  }
  //elimino la tarea despues de la ejecucion de la tarea
  if( xHandle != NULL ){vTaskDelete( xHandle );}
}

void tareaInterrupcionAutoA(void *parameters){
  while(1){
    if(xSemaphoreTake(mutex, portMAX_DELAY) == pdTRUE)
    {
        Serial.println("semaforo a en verde");
        semaforoA();
    } 
  }
  vTaskDelay(5000/portTICK_PERIOD_MS);
  xSemaphoreGive(mutex);
}

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

void interrupcionAmbulancia(){
  TaskHandle_t xHandle = NULL;
  xTaskCreate(tareaInterrupcionAmbulancia, "Tarea Interrupcion Ambulancia", 128, NULL, 1, &xHandle);
  Objeto obj = { 21 };
  xSemaphoreGiveFromISR(mutex, NULL);
  if(xSemaphoreTakeFromISR(mutex, NULL) == pdTRUE) {
    if(xQueueSendFromISR(cola, &obj, NULL) == pdPASS) Serial.println("Se envio la interrupcion");
    xSemaphoreGiveFromISR(mutex, NULL);
  }
  //elimino la tarea despues de la ejecucion de la tarea
  if( xHandle != NULL ){vTaskDelete( xHandle );}
}

void tareaInterrupcionAmbulancia(void *parameters){
  while(1){
    if(xSemaphoreTake(mutex, portMAX_DELAY) == pdTRUE)
    {
      Serial.println("Ambulancia cruzando...");
      semaforoB();
    } 
  }
  vTaskDelay(2000/portTICK_PERIOD_MS);
  xSemaphoreGive(mutex);
}

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

//Tarea ciclica del semaforo
void vehicleNormalTask(void *pvParameters) {
  while (true) { 
    Serial.println("calle A");
    semaforoA();
    vTaskDelay(3000/portTICK_PERIOD_MS);
    Serial.println("calle B");
    semaforoB();
    vTaskDelay(3000/portTICK_PERIOD_MS);
  } 
}

//prende y apaga luces semaforo A
void semaforoA(){
  digitalWrite(7, LOW);
  digitalWrite(5, LOW);
  digitalWrite(6, HIGH);
  digitalWrite(8, HIGH);
}
//prende y apaga luces semaforo B
void semaforoB(){
  digitalWrite(8, LOW);
  digitalWrite(6, LOW);
  digitalWrite(7, HIGH);
  digitalWrite(5, HIGH);
}

// -----------------------------------------------------------------------------------------------
// -----------------------------------------------------------------------------------------------
void loop() { }
$abcdeabcde151015202530354045505560fghijfghij