#pragma once
#include <stm32h7xx_hal.h>
#include <stm32_hal_legacy.h>

#include <memory.h>

UART_HandleTypeDef UartHandle;
ALIGN_32BYTES(uint8_t pubx00Cmd[]) = "$PUBX,00*33\r\n";
ALIGN_32BYTES(uint8_t gpsRXBuffer[128]);

void usart2CharMatchCallback(UART_HandleTypeDef *huart);

extern "C" void USART2_IRQHandler(void)
{
	HAL_UART_IRQHandler(&UartHandle);

	if (__HAL_UART_GET_FLAG(&UartHandle, UART_FLAG_CMF))
	{
		usart2CharMatchCallback(&UartHandle);
		HAL_UART_DMAStop(&UartHandle);
		__HAL_UART_CLEAR_FLAG(&UartHandle, USART_ICR_CMCF);
	}
}

void usart2CharMatchCallback(UART_HandleTypeDef *huart)
{
	HAL_Delay(1);
	//printf("hit HAL_UART_CharMatchIdleCallback\n");
}

extern "C" void HAL_UART_TxCpltCallback(UART_HandleTypeDef *UartHandle)
{
	__NOP();
}

//extern "C" void HAL_UART_RxCpltCallback(UART_HandleTypeDef *UartHandle)
//{
//	__NOP();
//}

extern "C" void HAL_UART_ErrorCallback(UART_HandleTypeDef *UartHandle)
{
	__NOP();
}

//This is the RX stream handler
extern "C" void DMA1_Stream1_IRQHandler()
{
	__NOP();
}

//This is the TX stream handler
extern "C" void DMA1_Stream7_IRQHandler()
{
	__NOP();
}

class USART2Class
{
private:
	static void Error_Handler(void)
	{
		/* Turn LED3 on */
		//BSP_LED_On(redLED);

		while(1)
		{
		}  
	}
	
public:
	USART2Class()
	{
		//ALIGN_32BYTES(uint8_t pubx00Cmd[]) = "$PUBX,00*33\r\n";
	}
	
	void txrx()
	{
		//memset(gpsRXBuffer, 0, sizeof(gpsRXBuffer));
		
//		if(HAL_UART_Receive_DMA(&UartHandle, (uint8_t *)gpsRXBuffer, sizeof(gpsRXBuffer)) != HAL_OK)
		if(HAL_UART_Receive_DMA(&UartHandle, (uint8_t *)gpsRXBuffer, sizeof(gpsRXBuffer)) != HAL_OK)
		{
			Error_Handler();
		}

		if (HAL_UART_Transmit_DMA(&UartHandle, (uint8_t*)pubx00Cmd, sizeof(pubx00Cmd)) != HAL_OK)
		{
			Error_Handler();
		}
	}

	void initUSART2(UART_HandleTypeDef *huart)
	{
		static DMA_HandleTypeDef hdma_tx;
		static DMA_HandleTypeDef hdma_rx;
		GPIO_InitTypeDef  GPIO_InitStruct;
  
		/*##-1- Enable peripherals and GPIO Clocks #################################*/
		/* Enable GPIO TX/RX clock */
		__HAL_RCC_GPIOD_CLK_ENABLE();

		/* Enable USARTx clock */
		__HAL_RCC_USART2_CLK_ENABLE();

		/* Enable DMA clock */
		__HAL_RCC_DMA1_CLK_ENABLE();

		__HAL_UART_ENABLE_IT(&UartHandle, UART_IT_CM);
		uint32_t cr2Value = 0;
		cr2Value = USART2->CR2;
		uint32_t clearMask = 0xFF000000;
		uint32_t setMask = 0x0D;
		MODIFY_REG(USART2->CR2, clearMask, setMask);
		
		/*##-2- Configure peripheral GPIO ##########################################*/  
		/* UART TX GPIO pin configuration  */
		GPIO_InitStruct.Pin       = GPIO_PIN_5;
		GPIO_InitStruct.Mode      = GPIO_MODE_AF_PP;
		GPIO_InitStruct.Pull      = GPIO_PULLUP;
		GPIO_InitStruct.Speed     = GPIO_SPEED_FREQ_VERY_HIGH;
		GPIO_InitStruct.Alternate = GPIO_AF7_USART2;

		HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);

		/* UART RX GPIO pin configuration  */
		GPIO_InitStruct.Pin = GPIO_PIN_6;
		GPIO_InitStruct.Alternate = GPIO_AF7_USART2;

		HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);

		/*##-3- Configure the DMA ##################################################*/
		/* Configure the DMA handler for Transmission process */
		hdma_tx.Instance                 = DMA1_Stream7;
		hdma_tx.Init.Direction           = DMA_MEMORY_TO_PERIPH;
		hdma_tx.Init.PeriphInc           = DMA_PINC_DISABLE;
		hdma_tx.Init.MemInc              = DMA_MINC_ENABLE;
		hdma_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
		hdma_tx.Init.MemDataAlignment    = DMA_MDATAALIGN_BYTE;
		hdma_tx.Init.Mode                = DMA_NORMAL;
		hdma_tx.Init.Priority            = DMA_PRIORITY_LOW;
		hdma_tx.Init.FIFOMode            = DMA_FIFOMODE_DISABLE;
		hdma_tx.Init.FIFOThreshold       = DMA_FIFO_THRESHOLD_FULL;
		hdma_tx.Init.MemBurst            = DMA_MBURST_INC4;
		hdma_tx.Init.PeriphBurst         = DMA_PBURST_INC4;
		hdma_tx.Init.Request             = DMA_REQUEST_USART2_TX;

		HAL_DMA_Init(&hdma_tx);

		/* Associate the initialized DMA handle to the UART handle */
		__HAL_LINKDMA(huart, hdmatx, hdma_tx);

		/* Configure the DMA handler for reception process */
		hdma_rx.Instance                 = DMA1_Stream1;
		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_NORMAL;
		hdma_rx.Init.Priority            = DMA_PRIORITY_HIGH;
		hdma_rx.Init.FIFOMode            = DMA_FIFOMODE_DISABLE;
		hdma_rx.Init.FIFOThreshold       = DMA_FIFO_THRESHOLD_FULL;
		hdma_rx.Init.MemBurst            = DMA_MBURST_INC4;
		hdma_rx.Init.PeriphBurst         = DMA_PBURST_INC4;
		hdma_rx.Init.Request             = DMA_REQUEST_USART2_RX;

		HAL_DMA_Init(&hdma_rx);

		/* Associate the initialized DMA handle to the the UART handle */
		__HAL_LINKDMA(huart, hdmarx, hdma_rx);
    
		/*##-4- Configure the NVIC for DMA #########################################*/
		/* NVIC configuration for DMA transfer complete interrupt (USART2_TX) */
		HAL_NVIC_SetPriority(DMA1_Stream7_IRQn, 0, 1);
		HAL_NVIC_EnableIRQ(DMA1_Stream7_IRQn);
    
		/* NVIC configuration for DMA transfer complete interrupt (USART2_RX) */
		HAL_NVIC_SetPriority(DMA1_Stream1_IRQn, 0, 0);
		HAL_NVIC_EnableIRQ(DMA1_Stream1_IRQn);
  
		/* NVIC for USART, to catch the TX complete */
		HAL_NVIC_SetPriority(USART2_IRQn, 0, 1);
		HAL_NVIC_EnableIRQ(USART2_IRQn);
		
		UartHandle.Instance        = USART2;
		UartHandle.Init.BaudRate   = 9600;
		UartHandle.Init.WordLength = UART_WORDLENGTH_8B;
		UartHandle.Init.StopBits   = UART_STOPBITS_1;
		UartHandle.Init.Parity     = UART_PARITY_NONE;
		UartHandle.Init.HwFlowCtl  = UART_HWCONTROL_NONE;
		UartHandle.Init.Mode       = UART_MODE_TX_RX;
		UartHandle.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
		if (HAL_UART_DeInit(&UartHandle) != HAL_OK)
		{
			Error_Handler();
		}  
		if (HAL_UART_Init(&UartHandle) != HAL_OK)
		{
			Error_Handler();
		}
		

	}

};
