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

// Définition des pins pour les LEDs
#define LED1_PIN GPIO_PIN_5
#define LED2_PIN GPIO_PIN_6
#define LED_PORT GPIOA

// Déclaration du mutex
SemaphoreHandle_t uartMutex;

// Fonction pour simuler l'envoi de messages UART
void UART_Send(const char *message) {
    printf("%s", message);  // Utilisation de printf pour envoyer via UART (Wokwi fait la redirection automatiquement)
}

// Tâche 1 - Envoie un message et contrôle les LEDs
void UART_Task1(void *pvParameters) {
    for (;;) {
        // ------------------- À compléter -------------------
        // Acquérir le mutex pour protéger l'accès à la ressource partagée (UART)
        if (xSemaphoreTake(uartMutex, portMAX_DELAY)) {
            // Envoyer un message via UART
            UART_Send("Task 1: Hello from UART!\r\n");

            // Allumer LED1
            HAL_GPIO_WritePin(LED_PORT, LED1_PIN, GPIO_PIN_SET);
            vTaskDelay(pdMS_TO_TICKS(500));  // LED1 allumée pendant 500ms

            // Éteindre LED1
            HAL_GPIO_WritePin(LED_PORT, LED1_PIN, GPIO_PIN_RESET);

            // ------------------- À compléter -------------------
            // Libérer le mutex après utilisation
            xSemaphoreGive(uartMutex);  
        }
        vTaskDelay(pdMS_TO_TICKS(1000));  // Pause de 1 seconde
    }
}

// Tâche 2 - Envoie un message et contrôle les LEDs
void UART_Task2(void *pvParameters) {
    for (;;) {
        // ------------------- À compléter -------------------
        // Acquérir le mutex pour protéger l'accès à la ressource partagée (UART)
        if (xSemaphoreTake(uartMutex, portMAX_DELAY)) {
            // Envoyer un message via UART
            UART_Send("Task 2: Message from UART\r\n");

            // Allumer LED2
            HAL_GPIO_WritePin(LED_PORT, LED2_PIN, GPIO_PIN_SET);
            vTaskDelay(pdMS_TO_TICKS(500));  // LED2 allumée pendant 500ms

            // Éteindre LED2
            HAL_GPIO_WritePin(LED_PORT, LED2_PIN, GPIO_PIN_RESET);

            // ------------------- À compléter -------------------
            // Libérer le mutex après utilisation
            xSemaphoreGive(uartMutex);  
        }
        vTaskDelay(pdMS_TO_TICKS(1500));  // Pause de 1,5 seconde
    }
}

void MX_GPIO_Init(void) {
    __HAL_RCC_GPIOA_CLK_ENABLE();

    GPIO_InitTypeDef GPIO_InitStruct = {0};

    // Initialiser LED1 (Pin 5)
    GPIO_InitStruct.Pin = LED1_PIN;
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
    HAL_GPIO_Init(LED_PORT, &GPIO_InitStruct);

    // Initialiser LED2 (Pin 6)
    GPIO_InitStruct.Pin = LED2_PIN;
    HAL_GPIO_Init(LED_PORT, &GPIO_InitStruct);
}

int main(void) {
    HAL_Init();
    MX_GPIO_Init();  // Initialisation des GPIOs pour les LEDs

    // ------------------- À compléter -------------------
    // Créer un mutex pour protéger l'accès à l'UART
    uartMutex = xSemaphoreCreateMutex();

    if (uartMutex != NULL) {
        // ------------------- À compléter -------------------
        // Créer les tâches UART_Task1 et UART_Task2 avec des priorités différentes
        xTaskCreate(UART_Task1, "UART Task 1", 256, NULL, 1, NULL);  // Priorité 1 pour Task 1
        xTaskCreate(UART_Task2, "UART Task 2", 256, NULL, 2, NULL);  // Priorité 2 pour Task 2
        
        // Démarrer le scheduler FreeRTOS
        vTaskStartScheduler();
    }

    // Si le système arrive ici, cela signifie que la mémoire est insuffisante
    while (1) {
    }
}