/************************************************************************************
 * Description: create simple tasks for STM32F4
 *
 *
 *
 ************************************************************************************/

#include "main.h"            // inlcude "stm32f4xx_hal.h"
#include "cmsis_os.h"        // include "FreeRTOS.h" and "task.h"
#include <stdio.h>

#define	GREEN	GPIO_PIN_12  // LEFT
#define ORANGE	GPIO_PIN_13  // UP
#define RED	    GPIO_PIN_14  // RIGHT
#define BLUE	GPIO_PIN_15  // DOWN

// UART2
UART_HandleTypeDef huart2;
static void UART2_Init(void);
int __io_putchar(int ch);


// GPIO Setup
void GPIO_Init(void);


// Private function prototypes
void SystemClock_Config(void);


// FreeRTOS Tasks
void vBlueLedControllerTask(void *pvParamters);
void vRedLedControllerTask(void *pvParamters);
void vGreenLedControllerTask(void *pvParamters);
void vOrangeLedControllerTask(void *pvParamters);

typedef uint32_t TaskProfiler;

TaskProfiler BlueTaskProfiler, RedTaskProfiler, GreenTaskProfiler, OrangeTaskProfiler;

int main(void) {

	HAL_Init();

	// Configure the system clock
	SystemClock_Config();

	GPIO_Init();

	UART2_Init();

	/********************************** Create FreeRTOS tasks **********************************/

	// xTaskCreate(task_func, task_descriptive_name, stack_size, task_func_params, priority_num, task_handle)
	// For STM32, 32 bit (4 bytes) x 100 as the task size. The higher number, the higher priority

	xTaskCreate(vBlueLedControllerTask,
			    "Blue Led Controller",
				100,
				NULL,
				1, // task priority
				NULL);

	xTaskCreate(vRedLedControllerTask,
			    "Red Led Controller",
				100,
				NULL,
				1, // task priority
				NULL);

	xTaskCreate(vGreenLedControllerTask,
			    "Green Led Controller",
				100,
				NULL,
				1, // task priority
				NULL);

	xTaskCreate(vOrangeLedControllerTask,
			    "Orange Led Controller",
				100,
				NULL,
				1, // task priority
				NULL);

	vTaskStartScheduler();

	while (1) {
	}

}


// Blue Led Controller Task
void vBlueLedControllerTask(void *pvParamters) {
	while(1) {
		HAL_GPIO_TogglePin(GPIOD, BLUE);
//		printf("Blue LED ... \n\r");
		HAL_Delay(500); // 500ms
		BlueTaskProfiler++;

	}
}


// Red Led Controller Task
void vRedLedControllerTask(void *pvParamters) {
	while(1){
		HAL_GPIO_TogglePin(GPIOD, RED);
//		printf("Red LED ... \n\r");
		HAL_Delay(1000); // 1000ms
		RedTaskProfiler++;
	}
}


// Green Led Controller Task
void vGreenLedControllerTask(void *pvParamters) {
	while(1){
		HAL_GPIO_TogglePin(GPIOD, GREEN);
		HAL_Delay(1000); // 1000ms
//		GreenTaskProfiler++;
	}
}


// Orange Led Controller Task
void vOrangeLedControllerTask(void *pvParamters) {
	while(1){
		HAL_GPIO_TogglePin(GPIOD, ORANGE);
		HAL_Delay(500); // 500ms
//		OrangeTaskProfiler++;
	}
}


//--------------------------------------------------------------------------------------------


// GPIO Setup
void GPIO_Init(void) {

	GPIO_InitTypeDef GPIO_InitStruct = {0};

	// GPIO Ports for LEDs
	__HAL_RCC_GPIOD_CLK_ENABLE();

	// Set to low, GPIO_PIN_RESET means low
	HAL_GPIO_WritePin(GPIOD, GPIO_PIN_12|GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15, GPIO_PIN_RESET);

	// Configure GPIO pins: PD12 PD13 PD14 PD15
	GPIO_InitStruct.Pin   = GPIO_PIN_12|GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15;
	GPIO_InitStruct.Mode  = GPIO_MODE_OUTPUT_PP;  // Set to output pushpull
	GPIO_InitStruct.Pull  = GPIO_NOPULL;          // No pull
	GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;  // Frequency low
	HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);	      // Init as GPIO

}



// UART2
static void UART2_Init(void) {

	GPIO_InitTypeDef GPIO_InitStruct = {0};

	// Enable UART pins clock access
	__HAL_RCC_GPIOA_CLK_ENABLE();

	// Enable UART module clock access
	__HAL_RCC_USART2_CLK_ENABLE();

	// Configure pins to act as alternate function pins (UART)
	GPIO_InitStruct.Pin       = GPIO_PIN_2 | GPIO_PIN_3;
	GPIO_InitStruct.Mode      = GPIO_MODE_AF_PP;
	GPIO_InitStruct.Alternate = GPIO_AF7_USART2;
	GPIO_InitStruct.Pull      = GPIO_NOPULL;
	GPIO_InitStruct.Speed     = GPIO_SPEED_FREQ_VERY_HIGH;
	HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);


	huart2.Instance          = USART2;
	huart2.Init.BaudRate     = 115200;
	huart2.Init.WordLength   = UART_WORDLENGTH_8B;
	huart2.Init.StopBits     = UART_STOPBITS_1;
	huart2.Init.Parity       = UART_PARITY_NONE;
	huart2.Init.Mode         = UART_MODE_TX_RX;
	huart2.Init.HwFlowCtl    = UART_HWCONTROL_NONE;
	huart2.Init.OverSampling = UART_OVERSAMPLING_16;

	if (HAL_UART_Init(&huart2) != HAL_OK) {
		Error_Handler();
	}

}


// Implement printf function
int __io_putchar(int ch) {
	HAL_UART_Transmit(&huart2, (uint8_t *)&ch, 1, 100);
	return ch;
}


/********************************************** CubeMX Settings **********************************************/


/**
  * @brief System Clock Configuration
  * @retval None
  */
void SystemClock_Config(void) {

  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

  // Configure the main internal regulator output voltage
  __HAL_RCC_PWR_CLK_ENABLE();
  __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);

  // Initializes the RCC Oscillators according to the specified parameters
  // in the RCC_OscInitTypeDef structure.
  RCC_OscInitStruct.OscillatorType      = RCC_OSCILLATORTYPE_HSI;
  RCC_OscInitStruct.HSIState            = RCC_HSI_ON;
  RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
  RCC_OscInitStruct.PLL.PLLState        = RCC_PLL_NONE;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) {
    Error_Handler();
  }

  // Initializes the CPU, AHB and APB buses clocks
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                               |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
  RCC_ClkInitStruct.SYSCLKSource   = RCC_SYSCLKSOURCE_HSI;
  RCC_ClkInitStruct.AHBCLKDivider  = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0) != HAL_OK) {
    Error_Handler();
  }

}


/**
  * @brief  Period elapsed callback in non blocking mode
  * @note   This function is called  when TIM7 interrupt took place, inside
  * HAL_TIM_IRQHandler(). It makes a direct call to HAL_IncTick() to increment
  * a global variable "uwTick" used as application time base.
  * @param  htim : TIM handle
  * @retval None
  */
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) {
  if (htim->Instance == TIM7) {
    HAL_IncTick();
  }
}

/**
  * @brief  This function is executed in case of error occurrence.
  * @retval None
  */
void Error_Handler(void) {
  __disable_irq();
  while (1) {}
}


#ifdef  USE_FULL_ASSERT
/**
  * @brief  Reports the name of the source file and the source line number
  *         where the assert_param error has occurred.
  * @param  file: pointer to the source file name
  * @param  line: assert_param error line source number
  * @retval None
  */
void assert_failed(uint8_t *file, uint32_t line) {
  /* USER CODE BEGIN 6 */
  /* User can add his own implementation to report the file name and line number,
     ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
  /* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */


// --------------------------------------------------------------------------------

















