#include <Arduino_FreeRTOS.h>
#include <semphr.h>
SemaphoreHandle_t xSerialSemaphore;  // Cria uma variável handle para o semáforo de uso para serial
// Protótipos das tasks
void taskReadDigital(void *pvParameters);
void taskReadAnalogicParams(void *pvParameters);
// Struct com os parâmetros da task analógica
typedef struct {
  const char* pcNameTask;     // Nome da task
  const char* pcTexto;        // Texto a ser enviado pela serial
  int SensorID;               // Entrada analógica
  int TempoDelayTicks;        // Tempo entre leituras
} AnalogReadParameters_t;
// Define os parâmetros de 3 tasks analógicas
AnalogReadParameters_t xParams[3];
void setup() {
  Serial.begin(115200);
  while (!Serial) {}
  // Cria o semáforo
  if (xSerialSemaphore == NULL) {
    xSerialSemaphore = xSemaphoreCreateMutex();
    if (xSerialSemaphore != NULL) {
      xSemaphoreGive(xSerialSemaphore);
    }
  }
  // Cria a task digital
  xTaskCreate(
    taskReadDigital,
    "DigitalRead",
    128,
    NULL,
    3,
    NULL
  );
  // Define os parâmetros das 3 tasks analógicas
  xParams[0] = {"taskEntradaA1", "Sensor A1", A1, pdMS_TO_TICKS(250)};
  xParams[1] = {"taskEntradaA2", "Sensor A2", A2, pdMS_TO_TICKS(250)};
  xParams[2] = {"taskEntradaA3", "Sensor A3", A3, pdMS_TO_TICKS(250)};
  // Cria as 3 tasks analógicas
  for (int i = 0; i < 3; i++) {
    Serial.println("--------------------------------------------");
    Serial.print("CRIANDO: ");
    Serial.println(xParams[i].pcNameTask);
    xTaskCreate(
      taskReadAnalogicParams,
      xParams[i].pcNameTask,
      128,
      (void*)&xParams[i],
      2, // prioridade (menor que a digital, para variar)
      NULL
    );
  }
}
void loop() {
  // Não é necessário usar loop() com FreeRTOS
}
void serialDebugComSemaforo(const char *pzsTexto) {
  if (xSemaphoreTake(xSerialSemaphore, (TickType_t)5) == pdTRUE) {
    Serial.print(pzsTexto);
    xSemaphoreGive(xSerialSemaphore);
  }
}
void taskReadDigital(void *pvParameters) {
  uint8_t pushButton = 2;
  pinMode(pushButton, INPUT);
  for (;;) {
    int buttonState = digitalRead(pushButton);
    
    if (xSemaphoreTake(xSerialSemaphore, (TickType_t)5) == pdTRUE) {
      Serial.print("Entrada digital> ");
      Serial.println(buttonState);
      xSemaphoreGive(xSerialSemaphore);
    }
    /*
    char buffer[64];
    snprintf(buffer, sizeof(buffer), "Entrada digital> %d\n", buttonState);
    serialDebugComSemaforo(buffer);
    */
    vTaskDelay(pdMS_TO_TICKS(500));
  
  }
}
void taskReadAnalogicParams(void *pvParameters) {
  AnalogReadParameters_t *pxParams = (AnalogReadParameters_t *)pvParameters;
  for (;;) {
    int sensorValue = analogRead(pxParams->SensorID);
    
    if (xSemaphoreTake(xSerialSemaphore, (TickType_t)5) == pdTRUE) {
      Serial.print(pxParams->pcTexto);
      Serial.print(": ");
      Serial.println(sensorValue);
      xSemaphoreGive(xSerialSemaphore);
    }
    vTaskDelay(pdMS_TO_TICKS(500));
  }
}