#include <stm32c0xx_hal.h>
#include <FreeRTOS.h>
#include <task.h>
#include <queue.h>
#include <semphr.h>
#include <stdio.h>

// Définition des pins GPIO
#define HUMIDITY_SENSOR1_PIN    GPIO_PIN_0 // Capteur Humidité 1 sur PA0
#define HUMIDITY_SENSOR2_PIN    GPIO_PIN_1 // Capteur Humidité 2 sur PA1
#define VALVE1_PIN              GPIO_PIN_5 // LED simule vanne 1 sur PA5
#define VALVE2_PIN              GPIO_PIN_6 // LED simule vanne 2 sur PA6
#define EMERGENCY_BUTTON_PIN    GPIO_PIN_4 // Bouton d'arrêt d'urgence sur PA4
#define POTENTIOMETER_PIN       GPIO_PIN_3 // Potentiomètre sur PB3
#define EMERGENCY_LED_PIN       GPIO_PIN_7 // LED rouge pour arrêt d'urgence

// Variables globales
SemaphoreHandle_t emergencySemaphore;
SemaphoreHandle_t humidityThresholdMutex;
QueueHandle_t humidityQueue;
uint8_t humidityThreshold = 50; // Seuil d'humidité initial à 50%

// Prototypes des fonctions
void SystemClock_Config(void);
void GPIO_Init(void);
void ReadHumidityTask(void *pvParameters);
void ValveControlTask(void *pvParameters);
void EmergencyButtonTask(void *pvParameters);
void PotentiometerTask(void *pvParameters);
void LogEvent(const char* event);

// Fonction principale
int main(void) {
    HAL_Init();
    SystemClock_Config();
    GPIO_Init();

    // Création des sémaphores et des queues
    emergencySemaphore = xSemaphoreCreateBinary();
    humidityQueue = xQueueCreate(10, sizeof(uint8_t));
    humidityThresholdMutex = xSemaphoreCreateMutex();

    if (humidityThresholdMutex == NULL || humidityQueue == NULL || emergencySemaphore == NULL) {
        LogEvent("Erreur lors de la création des ressources FreeRTOS !");
        while (1);
    }

    // Création des tâches
    xTaskCreate(ReadHumidityTask, "Read Humidity", 128, NULL, 1, NULL);
    xTaskCreate(ValveControlTask, "Valve Control", 128, NULL, 2, NULL);
    xTaskCreate(EmergencyButtonTask, "Emergency Button", 128, NULL, 3, NULL);
    xTaskCreate(PotentiometerTask, "Potentiometer", 128, NULL, 1, NULL);

    // Démarrage du scheduler
    vTaskStartScheduler();

    // Si le scheduler échoue
    while (1) {}
}

// Initialisation des GPIO
void GPIO_Init(void) {
    GPIO_InitTypeDef GPIO_InitStruct = {0};

    __HAL_RCC_GPIOA_CLK_ENABLE();
    __HAL_RCC_GPIOB_CLK_ENABLE();

    // Configurer les pins des capteurs d'humidité et du bouton
    GPIO_InitStruct.Pin = HUMIDITY_SENSOR1_PIN | HUMIDITY_SENSOR2_PIN | EMERGENCY_BUTTON_PIN;
    GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

    // Configurer les LEDs (vannes + LED d'urgence) en sortie
    GPIO_InitStruct.Pin = VALVE1_PIN | VALVE2_PIN | EMERGENCY_LED_PIN;
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

    // Configurer le potentiomètre
    GPIO_InitStruct.Pin = POTENTIOMETER_PIN;
    GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
}

// Tâche de lecture des capteurs d'humidité
void ReadHumidityTask(void *pvParameters) {
    uint8_t humidity1, humidity2;

    while (1) {
        // Simulation des valeurs des capteurs d'humidité
        humidity1 = (uint8_t)(HAL_GPIO_ReadPin(GPIOA, HUMIDITY_SENSOR1_PIN) ? 45 : 55); // Valeur simulée
        humidity2 = (uint8_t)(HAL_GPIO_ReadPin(GPIOA, HUMIDITY_SENSOR2_PIN) ? 40 : 60); // Valeur simulée

        // Lire le seuil d'humidité protégé par un mutex
        xSemaphoreTake(humidityThresholdMutex, portMAX_DELAY);
        uint8_t currentThreshold = humidityThreshold;
        xSemaphoreGive(humidityThresholdMutex);

        // Envoyer dans la queue si l'humidité est en dessous du seuil
        if (humidity1 < currentThreshold) {
            uint8_t zone = 1;
            xQueueSend(humidityQueue, &zone, portMAX_DELAY);
        }
        if (humidity2 < currentThreshold) {
            uint8_t zone = 2;
            xQueueSend(humidityQueue, &zone, portMAX_DELAY);
        }

        vTaskDelay(pdMS_TO_TICKS(5000)); // Lire toutes les 5 secondes
    }
}

// Tâche de contrôle des vannes
void ValveControlTask(void *pvParameters) {
    uint8_t zone;

    while (1) {
        // Attendre une zone dans la queue
        if (xQueueReceive(humidityQueue, &zone, portMAX_DELAY) == pdTRUE) {
            if (zone == 1) {
                HAL_GPIO_WritePin(GPIOA, VALVE1_PIN, GPIO_PIN_SET); // Activer vanne 1
                LogEvent("Vanne 1 activée.");
                vTaskDelay(pdMS_TO_TICKS(10000)); // 10 secondes
                HAL_GPIO_WritePin(GPIOA, VALVE1_PIN, GPIO_PIN_RESET); // Désactiver vanne 1
                LogEvent("Vanne 1 désactivée.");
            } else if (zone == 2) {
                HAL_GPIO_WritePin(GPIOA, VALVE2_PIN, GPIO_PIN_SET); // Activer vanne 2
                LogEvent("Vanne 2 activée.");
                vTaskDelay(pdMS_TO_TICKS(10000)); // 10 secondes
                HAL_GPIO_WritePin(GPIOA, VALVE2_PIN, GPIO_PIN_RESET); // Désactiver vanne 2
                LogEvent("Vanne 2 désactivée.");
            }
        }
    }
}

// Tâche de gestion de l'arrêt d'urgence
void EmergencyButtonTask(void *pvParameters) {
    while (1) {
        if (HAL_GPIO_ReadPin(GPIOA, EMERGENCY_BUTTON_PIN) == GPIO_PIN_SET) {
            HAL_GPIO_WritePin(GPIOA, VALVE1_PIN | VALVE2_PIN, GPIO_PIN_RESET); // Fermer toutes les vannes
            HAL_GPIO_WritePin(GPIOA, EMERGENCY_LED_PIN, GPIO_PIN_SET); // Activer LED d'urgence
            LogEvent("Arrêt d'urgence activé !");
            xSemaphoreGive(emergencySemaphore); // Signaler l'événement critique
        }

        vTaskDelay(pdMS_TO_TICKS(50)); // Anti-rebond
    }
}

// Tâche pour lire et ajuster le seuil d'humidité
void PotentiometerTask(void *pvParameters) {
    while (1) {
        uint8_t potentiometerValue = HAL_GPIO_ReadPin(GPIOB, POTENTIOMETER_PIN) ? 60 : 40; // Valeur simulée

        // Mettre à jour le seuil d'humidité
        if (xSemaphoreTake(humidityThresholdMutex, portMAX_DELAY) == pdTRUE) {
            humidityThreshold = potentiometerValue;
            xSemaphoreGive(humidityThresholdMutex);
            LogEvent("Seuil d'humidité mis à jour.");
        }

        vTaskDelay(pdMS_TO_TICKS(5000)); // Mise à jour toutes les 5 secondes
    }
}

// Fonction pour journaliser les événements
void LogEvent(const char* event) {
    printf("%s\n", event);
}

// Configuration du système (Simulation)
void SystemClock_Config(void) {
    // Simuler la configuration du système (vide pour ce projet)
}

void loop(){
  
};