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

// Semáforos e filas
SemaphoreHandle_t interruptSemaphore;
SemaphoreHandle_t mutex_v;
QueueHandle_t ledQueue;

// Variáveis para debounce e estado do LED
volatile unsigned long last_micros = 0;

long debouncing_time = 150;  // Tempo de debounce em milissegundos
volatile uint8_t ledState = 0;  // Estado do LED: 0: off, 1: red, 2: green, 3: blue

void setup() {
  Serial.begin(9600);

  // Configuração dos pinos dos LEDs e botão
  pinMode(2, INPUT_PULLUP);
  pinMode(10, OUTPUT);  // LED vermelho
  pinMode(11, OUTPUT);  // LED verde
  pinMode(12, OUTPUT);  // LED azul

  // Configura interrupção para o botão no pino 2
  attachInterrupt(digitalPinToInterrupt(2), handleInterrupt, CHANGE);

  // Inicialização de semáforos e fila
  interruptSemaphore = xSemaphoreCreateBinary();
  mutex_v = xSemaphoreCreateMutex();
  ledQueue = xQueueCreate(10, sizeof(uint8_t));
  if (interruptSemaphore == NULL || mutex_v == NULL || ledQueue == NULL) {
    Serial.println("Erro ao criar semáforo/mutex/fila");
  }

  // Criação de tarefas
  xTaskCreate(TaskLEDControl, "LEDControl", 128, NULL, 1, NULL);
  xTaskCreate(Task1, "Task1", 128, NULL, 1, NULL);
  xTaskCreate(Task2, "Task2", 128, NULL, 1, NULL);
}

void loop() {
  // Função loop vazia em programas FreeRTOS
}

// Função de interrupção chamada pelo botão
void handleInterrupt() {
  unsigned long currentMicros = micros();
  if (currentMicros - last_micros > debouncing_time * 1000) {
    last_micros = currentMicros;
    xSemaphoreGiveFromISR(interruptSemaphore, NULL);
  }
}

// Tarefa que controla o LED RGB
void TaskLEDControl(void *pvParameters) {
  while (1) {
    if (xSemaphoreTake(interruptSemaphore, portMAX_DELAY) == pdTRUE) {
      ledState = (ledState + 1) % 4;  // Alterna entre 0 (off) e 1, 2, 3 (cores)
      switch (ledState) {
        case 0: digitalWrite(10, LOW); digitalWrite(11, LOW); digitalWrite(12, LOW); break;  // Desliga todos
        case 1: digitalWrite(10, HIGH); digitalWrite(11, LOW); digitalWrite(12, LOW); break;  // Vermelho
        case 2: digitalWrite(10, LOW); digitalWrite(11, HIGH); digitalWrite(12, LOW); break;  // Verde
        case 3: digitalWrite(10, LOW); digitalWrite(11, LOW); digitalWrite(12, HIGH); break;  // Azul
      }
    }
  }
}

// Tarefa 1: Envia mensagens periódicas na porta serial
void Task1(void *pvParameters) {
  while (1) {
    if (xSemaphoreTake(mutex_v, portMAX_DELAY) == pdTRUE) {
      Serial.println("Task 1 is running");
      xSemaphoreGive(mutex_v);
      vTaskDelay(pdMS_TO_TICKS(1000));
    }
  }
}

// Tarefa 2: Envia mensagens mais frequentes na porta serial
void Task2(void *pvParameters) {
  while (1) {
    if (xSemaphoreTake(mutex_v, portMAX_DELAY) == pdTRUE) {
      Serial.println("Task 2 is running");
      xSemaphoreGive(mutex_v);
      vTaskDelay(pdMS_TO_TICKS(500));
    }
  }
}