#include "stm32c0xx_hal.h"
#include "FreeRTOS.h"
#include "task.h"

// Task Handles
TaskHandle_t HLO;
TaskHandle_t HLG;
TaskHandle_t HLB;
TaskHandle_t HLR;

uint16_t ledBl = GPIO_PIN_0; // Blue LED, PA0
uint16_t ledOr = GPIO_PIN_1; // Orange LED, PA1
uint16_t ledGr = GPIO_PIN_4; // Green LED, PA4
uint16_t ledRd = GPIO_PIN_11; // Red LED, PA11

void ToggleLED(void* p);

int main(void)
{
  HAL_Init();
  SystemClock_Config();
  MX_GPIO_Init();

  // задачи для каждого светодиода
  xTaskCreate(ToggleLED, "LED_BL", 128, &ledBl, 1, &HLB);
  xTaskCreate(ToggleLED, "LED_OR", 128, &ledOr, 2, &HLO);
  xTaskCreate(ToggleLED, "LED_GR", 128, &ledGr, 3, &HLG);
  xTaskCreate(ToggleLED, "LED_RD", 128, &ledRd, 4, &HLR);

  // ядро
  osKernelStart();

  // планировщик задач FreeRTOS
  vTaskStartScheduler();

  while (1)
  {
  }
}

void ToggleLED(void* p)
{
  uint16_t pin = *((uint16_t*) p);
  GPIO_TypeDef* port = GPIOA;
  TaskHandle_t* selfHandle = NULL;

  if (pin == ledBl) selfHandle = &HLB;
  else if (pin == ledOr) selfHandle = &HLO;
  else if (pin == ledGr) selfHandle = &HLG;
  else if (pin == ledRd) selfHandle = &HLR;

  TickType_t xLastWakeTime = xTaskGetTickCount();
  TickType_t xSyncTime = xTaskGetTickCount();
  const TickType_t xStandardFrequency = 500 / portTICK_PERIOD_MS;
  const TickType_t xSyncFrequency = 2500 / portTICK_PERIOD_MS;

  while (1)
  {
    HAL_GPIO_TogglePin(port, pin);
    vTaskDelayUntil(&xLastWakeTime, xStandardFrequency + (pin % 3) * 100);

    // каждые 5 секунд синхронизируем светодиоды
    if ((xTaskGetTickCount() - xSyncTime) / portTICK_PERIOD_MS >= 5000) {
      HAL_GPIO_WritePin(port, ledBl | ledOr | ledGr | ledRd, GPIO_PIN_SET); // включаем все
      vTaskDelay(xSyncFrequency); // задержка на время синхронизации
      HAL_GPIO_WritePin(port, ledBl | ledOr | ledGr | ledRd, GPIO_PIN_RESET); // выключаем все

      // глушим задачу управления синим светодиодом
      if (selfHandle == &HLB) {
        vTaskSuspend(NULL);
        vTaskDelay(1500 / portTICK_PERIOD_MS);
        vTaskResume(HLB);
      }

      xSyncTime = xTaskGetTickCount(); // сброс таймера синхронизации
    }
  }
}


void MX_GPIO_Init(void)
{
  __HAL_RCC_GPIOA_CLK_ENABLE();

  GPIO_InitTypeDef GPIO_InitStruct = {0};

  GPIO_InitStruct.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_4 | GPIO_PIN_11;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
}

void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  HAL_RCC_OscConfig(&RCC_OscInitStruct);

  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSI;
  HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0);
}

void vApplicationIdleHook(void) {}