#ifndef _CUSTOM_USART_
#define _CUSTOM_USART_

#include "custom_usart.h"

UART_HandleTypeDef huart_boot;
DMA_HandleTypeDef hdma_usart_boot_rx;

// CUSTOM UART INIT
// DMA INIT (RCC, NVIC) SHOULD BE ADDED IN DMA.C
void User_UART_Init(UART_HandleTypeDef* huart, DMA_HandleTypeDef *DMAhuart, struct UARTSettings *uuart)
{ // function takes uart handler, dma handler and setting structure for init
	
	// get setting for uart from UARTSettings structure
	huart->Instance = uuart->UARTx;
  huart->Init.BaudRate = uuart->UART_Speed;
	
	// everything else is default (for now, maybe this settings would be added in UARTSettings structure later)
  huart->Init.WordLength = UART_WORDLENGTH_8B;
  huart->Init.StopBits = UART_STOPBITS_1;
  huart->Init.Parity = UART_PARITY_NONE;
  huart->Init.Mode = UART_MODE_TX_RX;
  huart->Init.HwFlowCtl = UART_HWCONTROL_NONE;
  huart->Init.OverSampling = UART_OVERSAMPLING_16;
  if (HAL_UART_Init(huart) != HAL_OK)
  {
    Error_Handler();
  }
	
	// init gpio from UARTSettings structure
	UART_GPIO_Init(uuart->GPIOx, uuart->GPIO_PIN_RX, uuart->GPIO_PIN_TX);
	// init dma from UARTSettings structure if need
	if (uuart->DMAChannel != 0)
		UART_DMA_Init(huart, DMAhuart, uuart->DMAChannel);
}


void UART_GPIO_Init(GPIO_TypeDef *GPIOx, uint16_t GPIO_PIN_RX, uint16_t GPIO_PIN_TX)
{ // function takes port and pins (for rx and tx)
  GPIO_InitTypeDef GPIO_InitStruct = {0};
	
	// choose port for enable clock
	if (GPIOx==GPIOA)
		__HAL_RCC_GPIOA_CLK_ENABLE();
	else if (GPIOx==GPIOB)
		__HAL_RCC_GPIOB_CLK_ENABLE();
	else if (GPIOx==GPIOC)
		__HAL_RCC_GPIOC_CLK_ENABLE();
	else if (GPIOx==GPIOD)
		__HAL_RCC_GPIOD_CLK_ENABLE();
	
// USART3 GPIO Configuration
//GPIO_PIN_TX ------> USART_TX
	GPIO_InitStruct.Pin = GPIO_PIN_TX;
	GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
	GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
	HAL_GPIO_Init(GPIOx, &GPIO_InitStruct);

//	GPIO_PIN_RX ------> USART_RX	
	GPIO_InitStruct.Pin = GPIO_PIN_RX;
	GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
	GPIO_InitStruct.Pull = GPIO_NOPULL;
	HAL_GPIO_Init(GPIOx, &GPIO_InitStruct);
}


void UART_DMA_Init(UART_HandleTypeDef *huart, DMA_HandleTypeDef *hdma_rx, DMA_Channel_TypeDef *DMAhuart)
{ // function takes uart and dma handlers and dmachannel for uart
	// for now only dma rx is supported, tx maybe later if needed
	
	/* USART3 DMA Init */
	/* USART3_RX Init */
	hdma_rx->Instance = DMAhuart;
	hdma_rx->Init.Direction = DMA_PERIPH_TO_MEMORY;
	hdma_rx->Init.PeriphInc = DMA_PINC_DISABLE;
	hdma_rx->Init.MemInc = DMA_MINC_ENABLE;
	hdma_rx->Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
	hdma_rx->Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
	hdma_rx->Init.Mode = DMA_CIRCULAR;
	hdma_rx->Init.Priority = DMA_PRIORITY_LOW;
	if (HAL_DMA_Init(hdma_rx) != HAL_OK)
	{
		Error_Handler();
	}

	__USER_LINKDMA(huart,hdmarx,hdma_rx); 
	// __USER_LINKDMA is need because __HAL_LINKDMA is written for global defined hdma_rx
	// so you get error because hal uses . insted of ->
}



void HAL_UART_MspInit(UART_HandleTypeDef* huart) // redefine hal function
{ // left only rcc and interrupt init for USART_1,2,3 (maybe UART_4,5 need to be added)
	// GPIO and DMA init was move to their own functions
  if(huart->Instance==USART3)
  {
	/* USART3 clock enable */
	__HAL_RCC_USART3_CLK_ENABLE();
	
	/* USART3 interrupt Init */
	HAL_NVIC_SetPriority(USART3_IRQn, 0, 0);
  HAL_NVIC_EnableIRQ(USART3_IRQn);
  }
	else if(huart->Instance==USART2)
  {
	/* USART3 clock enable */
	__HAL_RCC_USART2_CLK_ENABLE();
	
	/* USART3 interrupt Init */
	HAL_NVIC_SetPriority(USART2_IRQn, 0, 0);
  HAL_NVIC_EnableIRQ(USART2_IRQn);
  }
	else if(huart->Instance==USART1)
  {
	/* USART3 clock enable */
	__HAL_RCC_USART1_CLK_ENABLE();
	
	/* USART3 interrupt Init */
	HAL_NVIC_SetPriority(USART1_IRQn, 0, 0);
  HAL_NVIC_EnableIRQ(USART1_IRQn);
  }
}

#endif