#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/gpio.h"
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
 
/* defines - LCD */
#define LCD_16X2_CLEAN_LINE     "                "
#define LCD_16X2_I2C_ADDRESS    0x27
#define LCD_16X2_COLS           16
#define LCD_16X2_ROWS           2
 
 
/* defines - LED */
#define LED_PIN 5
// #define LED_PIN_LDR 3
// #define LDR_PIN A1
//int VALUE_LDR=0;

#define LED_THRESHOLD           4.0 /* V */
// #define LDR_THRESHOLD           400 /* V */
#define LED_THRESHOLD_MEDIUM           2.0 /* V */
 
/* defines - ADC */
#define ADC_MAX 1023.0
#define MAX_VOLTAGE_ADC 5.0
 
/* tasks */
void task_breathing_light( void *pvParameters );
void task_serial( void *pvParameters );
void task_lcd( void *pvParameters );
void task_sensor( void *pvParameters );
void task_led( void *pvParameters );
void task_led_yellow( void *pvParameters );
void task_led_green( void *pvParameters );
 
/* Variaveis relacionadas ao LCD */
LiquidCrystal_I2C lcd = LiquidCrystal_I2C(0x27, 16, 2);
 
/* filas (queues) */
QueueHandle_t xQueue_SENSOR, xQueue_LED, xQueue_LDR;
 
/* semaforos utilizados */
SemaphoreHandle_t xSerial_semaphore;
 
 
void setup() 
{
    /* Inicializa serial (baudrate 9600) */
    Serial.begin(9600);
    
    /* Inicializa o LCD, liga o backlight e limpa o LCD */
    lcd.init();
    lcd.backlight();
    lcd.clear();
 
    /* Inicializa e configura GPIO do LED */
    pinMode(LED_PIN, OUTPUT);
    digitalWrite(LED_PIN, LOW);

    // pinMode(LED_PIN_LDR, OUTPUT);
    // digitalWrite(LED_PIN_LDR, LOW);

    // pinMode(LDR_PIN, INPUT);//Define ldr (pino analógico A0) como saída
    
    while (!Serial) {
    ; /* Somente vai em frente quando a serial estiver pronta para funcionar */
    }
 
         /* Criação da fila (queue) */
    xQueue_SENSOR = xQueueCreate( 1, sizeof( float ) );
    //xQueue_LED = xQueueCreate( 1, sizeof( float ) );
    //xQueue_LDR = xQueueCreate( 1, sizeof( float ) );

 
    /* Criação dos semaforos */
    xSerial_semaphore = xSemaphoreCreateMutex();
 
    if (xSerial_semaphore == NULL)
    {
        Serial.println("Erro: nao e possivel criar o semaforo");
        while(1); /* Sem semaforo o funcionamento esta comprometido. Nada mais deve ser feito. */
    }
 
    /* Criação das tarefas */
//    xTaskCreate( task_ldr /* Funcao a qual esta implementado o que a tarefa deve fazer */
//               ,"sensor_ldr" /* Nome (para fins de debug, se necessário) */
//               , 32 /* Tamanho da stack (em words) reservada para essa tarefa */
//               , NULL /* Parametros passados (nesse caso, não há) */
//               , 6 /* Prioridade */
//               , NULL ); /* Handle da tarefa, opcional (nesse caso, não há) */
//   xTaskCreate( task_led_ldr /* Funcao a qual esta implementado o que a tarefa deve fazer */
//               ,"led_ldr" /* Nome (para fins de debug, se necessário) */
//               , 32 /* Tamanho da stack (em words) reservada para essa tarefa */
//               , NULL /* Parametros passados (nesse caso, não há) */
//               , 5 /* Prioridade */
//               , NULL ); /* Handle da tarefa, opcional (nesse caso, não há) */
 
    // xTaskCreate( task_sensor /* Funcao a qual esta implementado o que a tarefa deve fazer */
    //            ,"sensor" /* Nome (para fins de debug, se necessário) */
    //            , 2000 /* Tamanho da stack (em words) reservada para essa tarefa */
    //            , NULL /* Parametros passados (nesse caso, não há) */
    //            , 4 /* Prioridade */
    //            , NULL ); /* Handle da tarefa, opcional (nesse caso, não há) */

    xTaskCreatePinnedToCore(task_sensor, 
                        "sensor", 
                        2048, 
                        NULL, 
                        4, 
                        NULL,
                         APP_CPU_NUM);
    // xTaskCreate(task_lcd
    //            ,"LCD"
    //            , 2000
    //            , NULL
    //            , 3
    //            , NULL );

    xTaskCreatePinnedToCore(task_lcd, 
                        "LCD", 
                        1024, 
                        NULL, 
                        3, 
                        NULL,
                         APP_CPU_NUM);
 
    // xTaskCreate(task_led
    //            , "LED"
    //            , 2000
    //            , NULL
    //            , 2
    //            , NULL );

    xTaskCreatePinnedToCore(task_led, 
                        "LED", 
                        1024, 
                        NULL, 
                        2, 
                        NULL,
                         APP_CPU_NUM);
}
 
void loop()
{
    /* Tudo é executado nas tarefas. Há nada a ser feito aqui. */
}
 
/* --------------------------------------------------*/
/* ---------------------- Tarefas -------------------*/
/* --------------------------------------------------*/
 
void task_sensor( void *pvParameters )
{
    (void) pvParameters;
    int adc_read=0;
    UBaseType_t uxHighWaterMark;
    float voltage = 0.0;
 
    while(1)
    {
          adc_read = analogRead(0);
          voltage = ((float)adc_read/ADC_MAX)*MAX_VOLTAGE_ADC;
     
          /* Envia tensão lida em A0 para as tarefas a partir de filas */
          xQueueOverwrite(xQueue_SENSOR, (void *)&voltage);
          //xQueueOverwrite(xQueue_LED, (void *)&voltage);
 
         /* Espera um segundo */
         vTaskDelay( 1000 / portTICK_PERIOD_MS );
 
        /* Para fins de teste de ocupação de stack, printa na serial o high water mark */
        xSemaphoreTake(xSerial_semaphore, portMAX_DELAY );
        uxHighWaterMark = uxTaskGetStackHighWaterMark( NULL );
        Serial.print("task_sensor high water mark (words): ");
        Serial.println(uxHighWaterMark);
        Serial.println("---");
        xSemaphoreGive(xSerial_semaphore);
   }
}
 
 
void task_lcd( void *pvParameters )
{
    (void) pvParameters;
    float voltage_rcv = 0.0;
    UBaseType_t uxHighWaterMark;
  
    while(1)
    {
        /* Espera até algo ser recebido na queue */
        xQueueReceive(xQueue_SENSOR, (void *)&voltage_rcv, portMAX_DELAY);
 
        /* Uma vez recebida a informação na queue, a escreve no display LCD */
        lcd.setCursor(0,0);
        lcd.print("Tensao ADC:");
        lcd.setCursor(0,1);
        lcd.print(LCD_16X2_CLEAN_LINE);
        lcd.setCursor(0,1);
        lcd.print(voltage_rcv);
        lcd.setCursor(15,1);
        lcd.print("V");
 
        /* Para fins de teste de ocupação de stack, printa na serial o high water mark */
        xSemaphoreTake(xSerial_semaphore, portMAX_DELAY );
        uxHighWaterMark = uxTaskGetStackHighWaterMark( NULL );
        Serial.print("task_lcd high water mark (words): ");
        Serial.println(uxHighWaterMark);
        Serial.println("---");
        xSemaphoreGive(xSerial_semaphore);
        vTaskDelay(100);
    }
}
 
void task_led( void *pvParameters )
{
    (void) pvParameters;
    float voltage_rcv = 0.0;
    UBaseType_t uxHighWaterMark;
 
    while(1)
    {
        /* ATENÇÃO: NUNCA USE A FUNÇÃO delay() QUANDO ESTIVER USANDO FREERTOS!
           em seu lugar, use a função vTaskDelay( tempo / portTICK_PERIOD_MS );, substituindo "tempo" pelo tempo de delay 
          (em ms) desejado.
        */
        xQueueReceive(xQueue_SENSOR, (void *)&voltage_rcv, portMAX_DELAY);
        
        if(voltage_rcv >= LED_THRESHOLD)
          digitalWrite(LED_PIN, HIGH);

        else
          digitalWrite(LED_PIN,LOW);
        
        
        /* Para fins de teste de ocupação de stack, printa na serial o high water mark */
        xSemaphoreTake(xSerial_semaphore, portMAX_DELAY );
        
        uxHighWaterMark = uxTaskGetStackHighWaterMark( NULL );
        Serial.print("task_led high water mark (words): ");
        Serial.println(uxHighWaterMark);
        Serial.println("---");
        xSemaphoreGive(xSerial_semaphore);
    }
}

// void task_ldr( void *pvParameters )
// {
//     (void) pvParameters;
//     UBaseType_t uxHighWaterMark;
//     float value_ldr;
 
//     while(1)
//     {
//         /* ATENÇÃO: NUNCA USE A FUNÇÃO delay() QUANDO ESTIVER USANDO FREERTOS!
//            em seu lugar, use a função vTaskDelay( tempo / portTICK_PERIOD_MS );, substituindo "tempo" pelo tempo de delay 
//           (em ms) desejado.
//         */
//         value_ldr=analogRead(LDR_PIN);//Lê o valor do sensor ldr e armazena na variável valorldr
//         xQueueOverwrite(xQueue_LDR, (void *)&value_ldr);
 
//         /* Espera um segundo */
//         vTaskDelay( 1000 / portTICK_PERIOD_MS );

//         /* Para fins de teste de ocupação de stack, printa na serial o high water mark */
//         xSemaphoreTake(xSerial_semaphore, portMAX_DELAY );
        
//         uxHighWaterMark = uxTaskGetStackHighWaterMark( NULL );
//         Serial.print("task_ldr high water mark (words): ");
//         Serial.println(uxHighWaterMark);
//         Serial.println("---");
//         Serial.print("Valor lido pelo LDR = ");//Imprime na serial a mensagem Valor lido pelo LDR
//         Serial.println(value_ldr);//Imprime na serial os dados de valorldr
//         xSemaphoreGive(xSerial_semaphore);
//     }
// }

// void task_led_ldr( void *pvParameters )
// {
//     (void) pvParameters;
//     float value_ldr_rcv = 0;
//     UBaseType_t uxHighWaterMark;
 
//     while(1)
//     {
//         /* ATENÇÃO: NUNCA USE A FUNÇÃO delay() QUANDO ESTIVER USANDO FREERTOS!
//            em seu lugar, use a função vTaskDelay( tempo / portTICK_PERIOD_MS );, substituindo "tempo" pelo tempo de delay 
//           (em ms) desejado.
//         */
//         xQueueReceive(xQueue_LDR, (void *)&value_ldr_rcv, portMAX_DELAY);
        
//         if(value_ldr_rcv <= LDR_THRESHOLD){
//           Serial.println("to aqui porra");
//           digitalWrite(LED_PIN_LDR, HIGH);}

//         else
//           digitalWrite(LED_PIN_LDR,LOW);
        
        
//         /* Para fins de teste de ocupação de stack, printa na serial o high water mark */
//         xSemaphoreTake(xSerial_semaphore, portMAX_DELAY );
        
//         uxHighWaterMark = uxTaskGetStackHighWaterMark( NULL );
//         Serial.print("task_led_ldr high water mark (words): ");
//         Serial.println(uxHighWaterMark);
//         Serial.println("---");
//         xSemaphoreGive(xSerial_semaphore);
//     }
// }
$abcdeabcde151015202530354045505560fghijfghij