/******************************************************************************
*@file  : app.c
*@brief : UART Demos 
******************************************************************************/
#include "app.h"

uint8_t TxBuffer[512];
uint8_t RxBuffer[512];

const char *prompt_str = "Please enter any String/Data \r\n";

UART_HandleTypeDef  UART1_Handle;
UART_HandleTypeDef  UART2_Handle;
UART_HandleTypeDef  UART3_Handle;
 
DMA_HandleTypeDef  DMA_CH1_Handle;
DMA_HandleTypeDef  DMA_CH2_Handle;

volatile uint32_t TX_DMA_Status = false;
volatile uint32_t RX_DMA_Status = false;

volatile uint32_t TxCpltStatus = false, TxCpltStatus2 = false, TxCpltStatus3 = false;

volatile uint32_t RxCpltStatus = false, RxCpltStatus2 = false, RxCpltStatus3 = false;

/******************************************************************************
*@brief : UART1 config and init
*@param : none
*@return: none
******************************************************************************/
void UART1_Init(void) 
{
    UART1_Handle.Instance        = UART1;    
    UART1_Handle.Init.BaudRate   = 115200; 
    UART1_Handle.Init.WordLength = UART_WORDLENGTH_8B;
    UART1_Handle.Init.StopBits   = UART_STOPBITS_1;
    UART1_Handle.Init.Parity     = UART_PARITY_NONE;
    UART1_Handle.Init.Mode       = UART_MODE_TX_RX;
    UART1_Handle.Init.HwFlowCtl  = UART_HWCONTROL_NONE;
    
    HAL_UART_Init(&UART1_Handle);  
}

/******************************************************************************
*@brief : UART2 config and init
*@param : none
*@return: none
******************************************************************************/
void UART2_Init(void) 
{
    UART2_Handle.Instance        = UART2;    
    UART2_Handle.Init.BaudRate   = 115200; 
    UART2_Handle.Init.WordLength = UART_WORDLENGTH_8B;
    UART2_Handle.Init.StopBits   = UART_STOPBITS_1;
    UART2_Handle.Init.Parity     = UART_PARITY_NONE;
    UART2_Handle.Init.Mode       = UART_MODE_TX_RX;
    UART2_Handle.Init.HwFlowCtl  = UART_HWCONTROL_NONE;
    
    HAL_UART_Init(&UART2_Handle);  
}

/******************************************************************************
*@brief : UART3 config and init
*@param : none
*@return: none
******************************************************************************/
void UART3_Init(void) 
{
    UART3_Handle.Instance        = UART3;    
    UART3_Handle.Init.BaudRate   = 115200; 
    UART3_Handle.Init.WordLength = UART_WORDLENGTH_8B;
    UART3_Handle.Init.StopBits   = UART_STOPBITS_1;
    UART3_Handle.Init.Parity     = UART_PARITY_NONE;
    UART3_Handle.Init.Mode       = UART_MODE_TX_RX;
    UART3_Handle.Init.HwFlowCtl  = UART_HWCONTROL_NONE;
    
    HAL_UART_Init(&UART3_Handle);               
}

/******************************************************************************
*@brief : UART1 IT tx completed callback
*@param : none
*@return: none
******************************************************************************/
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
{
    if(huart->Instance ==UART1)  // Transfor Data By UART1
    {
		TxCpltStatus= true;
    }
    else if(huart->Instance ==UART2) //Transfor Data By UART2 
	{
		TxCpltStatus2 =true;
	}
	else if(huart->Instance ==UART3) // Transfor Data By UART3
	{
		TxCpltStatus3 =true;
	}
}

void UART1_TX_DMA_Complete_Callback(DMA_HandleTypeDef *h)
{
    TX_DMA_Status = true;
}

void UART1_RX_DMA_Complete_Callback(DMA_HandleTypeDef *h)
{
    UART_HandleTypeDef *huart = (UART_HandleTypeDef *)((DMA_HandleTypeDef *)h)->Parent;
    CLEAR_BIT(huart->Instance->IE, UART_IE_IDLEI);
    CLEAR_STATUS(huart->Instance->ISR, UART_ISR_IDLEI);
    huart->RxBusy = false;
    huart->RxCount = huart->RxSize - (h->Instance->CHCTRL & DMA_CHCTRL_TRANSFERSIZE_Msk);
    RX_DMA_Status = true;
}


void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{	
    if(huart->Instance == UART1)  // receive data by UART1
    {
		RxCpltStatus = true;
    }
    else if(huart->Instance == UART2) //receive data by UART2  
	{
		RxCpltStatus2 = true;
	}
	else if(huart->Instance == UART3) // receive data by UART3  
	{
		RxCpltStatus3 = true;
	}
}

void HAL_UART_IdleCallback(UART_HandleTypeDef *huart)
{
    /* This code can be modified by user */
    if(huart->HDMA_Rx != NULL)
    {
        /* UART DMA transfer when idle line occured, */
        huart->RxCount = huart->RxSize - (huart->HDMA_Rx->Instance->CHCTRL & DMA_CHCTRL_TRANSFERSIZE_Msk);

        HAL_DMA_Abort(huart->HDMA_Rx);

        RX_DMA_Status = true;
    }
    else
    {
        /* UART IT received mode */
        HAL_UART_RxCpltCallback(huart);
    } 
}

void APP_Uart_Test(enum_TEST_MODE_t fe_Mode)
{
	uint8_t ret;
    
    switch (fe_Mode)
    {
        /* Loop mode*/
        case TEST_UART1_LOOP: 
        {
            printfS("----------UART1 LOOP Demo ----------\r\n");
            printfS("%s\r\n\r\n", prompt_str);
            for(;;)
            {
                //HAL_UART_Receive(&UART1_Handle, RxBuffer, sizeof(RxBuffer), 10);
                HAL_UART_Receive_To_IDLEorBCNT(&UART1_Handle, RxBuffer, sizeof(RxBuffer), RECEIVE_TOIDLE, 115200);
                if (UART1_Handle.RxCount)
                {
                    HAL_UART_Transmit(&UART1_Handle, RxBuffer, UART1_Handle.RxCount, HAL_MAX_DELAY);  

                    memset(RxBuffer, 0, sizeof(RxBuffer)); 
                }
            }
        }break;

        /* Interrupt mode */
        case TEST_UART1_IT: 
        {
            printfS("----------UART1 IT Demo ----------\r\n");
            printfS("%s\r\n\r\n", prompt_str);
            while(1)
            {
                /* receive variable length data by intrrupt method */
                HAL_UART_Receive_IT(&UART1_Handle, RxBuffer, sizeof(RxBuffer)); 
						
                while (!RxCpltStatus);
                
                RxCpltStatus=false;
                
                memcpy(TxBuffer, RxBuffer, UART1_Handle.RxCount);

                HAL_UART_Transmit_IT(&UART1_Handle, TxBuffer, UART1_Handle.RxCount); 
                
                while (!TxCpltStatus);  
            
                TxCpltStatus =false;
            
            }
        }break;
        
        /* DMA mode */
        case TEST_UART1_DMA: 
        {
            uint32_t Uart_Dma_Len = sizeof(RxBuffer);
            printfS("----------UART1 DMA Demo ----------\r\n");
            printfS("The UART1 DMA transfer size is set to %d bytes\r\n\r\n", Uart_Dma_Len);
            printfS("%s\r\n\r\n", prompt_str);
            
            __HAL_RCC_DMA1_CLK_ENABLE();
            DMA_CH1_Handle.Instance             = DMA1_Channel1;
            DMA_CH1_Handle.Init.DataFlow        = DMA_DATAFLOW_M2P;
            DMA_CH1_Handle.Init.ReqID           = DMA1_REQ5_UART1_SEND;
            DMA_CH1_Handle.Init.SrcInc          = DMA_SRCINC_ENABLE;
            DMA_CH1_Handle.Init.DestInc         = DMA_DESTINC_DISABLE;
            DMA_CH1_Handle.Init.SrcWidth        = DMA_SRCWIDTH_BYTE;
            DMA_CH1_Handle.Init.DestWidth       = DMA_DESTWIDTH_BYTE;
            DMA_CH1_Handle.Init.SrcBurst        = DMA_SRCBURST_1;
            DMA_CH1_Handle.Init.DestBurst       = DMA_DESTBURST_1;
            DMA_CH1_Handle.XferCpltCallback     = UART1_TX_DMA_Complete_Callback;
            
            HAL_DMA_Init(&DMA_CH1_Handle);
            
            /* UART1_Handle.HDMA_Tx = &DMA_CH1_Handle; DMA_CH1_Handle.Parent = &UART1_Handle; */
            __HAL_LINKDMA(&UART1_Handle, HDMA_Tx, DMA_CH1_Handle);

            DMA_CH2_Handle.Instance             = DMA1_Channel0;
            DMA_CH2_Handle.Init.DataFlow        = DMA_DATAFLOW_P2M;
            DMA_CH2_Handle.Init.ReqID           = DMA1_REQ6_UART1_RECV;
            DMA_CH2_Handle.Init.SrcInc          = DMA_SRCINC_DISABLE;
            DMA_CH2_Handle.Init.DestInc         = DMA_DESTINC_ENABLE;
            DMA_CH2_Handle.Init.SrcWidth        = DMA_SRCWIDTH_BYTE;
            DMA_CH2_Handle.Init.DestWidth       = DMA_DESTWIDTH_BYTE;
            DMA_CH2_Handle.Init.SrcBurst        = DMA_SRCBURST_1;
            DMA_CH2_Handle.Init.DestBurst       = DMA_DESTBURST_1;
            DMA_CH2_Handle.XferCpltCallback     = UART1_RX_DMA_Complete_Callback;
            
            HAL_DMA_Init(&DMA_CH2_Handle);
            
            /* UART1_Handle.HDMA_Rx = &DMA_CH2_Handle; DMA_CH2_Handle.Parent = &UART1_Handle; */
            __HAL_LINKDMA(&UART1_Handle, HDMA_Rx, DMA_CH2_Handle);
            
            NVIC_ClearPendingIRQ(DMA1_IRQn);
            NVIC_EnableIRQ(DMA1_IRQn);
            
            TX_DMA_Status = true;
            
            for(;;)
            {
                if (TX_DMA_Status) 
                {
                    TX_DMA_Status = false;
                    
                    memset(RxBuffer, 0, 512);
                }
                
                ret = HAL_UART_Receive_DMA(&UART1_Handle, RxBuffer, Uart_Dma_Len);
                
                while(RX_DMA_Status == false);
                RX_DMA_Status = false;

                ret = HAL_UART_Transmit_DMA(&UART1_Handle, RxBuffer, UART1_Handle.RxCount);
                while(TX_DMA_Status == false);

            }
        }break;
        
		case TEST_UART2:
		{
            UART2_Init();
            
            printfS("----------UART2 Demo ----------\r\n");
            printfS("%s\r\n\r\n", prompt_str);
            
			while(1)
			{
				HAL_UART_Receive_IT(&UART2_Handle, RxBuffer, sizeof(RxBuffer));    // length should <= sizeof(RxBuffer)   
						
				while(1)  
				{
					while (!RxCpltStatus2);
				
					RxCpltStatus2=false;
				
					memcpy(TxBuffer, RxBuffer, UART2_Handle.RxCount);

					HAL_UART_Transmit_IT(&UART2_Handle, TxBuffer, UART2_Handle.RxCount); 
				
					while (!TxCpltStatus2);  
				
					TxCpltStatus2 =false;
                    
                    /* wait tx xfer completed */
                    while ((UART2_Handle.Instance->FR & UART_FR_BUSY));

					break;		   
				}
			}
		}break;
        
		case TEST_UART3:
		{
            UART3_Init();
            
            printfS("----------UART3 Demo ----------\r\n");
            printfS("%s\r\n\r\n", prompt_str);
            
			while(1)
			{
				HAL_UART_Receive_IT(&UART3_Handle, RxBuffer, sizeof(RxBuffer));    // length should <= sizeof(RxBuffer)   
                
                while (!RxCpltStatus3);
				
                RxCpltStatus3=false;
            
                memcpy(TxBuffer, RxBuffer, UART3_Handle.RxCount);
            
                HAL_UART_Transmit_IT(&UART3_Handle, TxBuffer, UART3_Handle.RxCount); 
            
                while (!TxCpltStatus3);  
            
                TxCpltStatus3 =false;
			}
		}break;

        default: break; 
    }
}
