/*
  ******************************************************************************
  * @file    APP.c
  * @author  
  * @version V1.0.0
  * @date    2024
  * @brief   UART demo source code.
  ******************************************************************************
*/
#include "app.h"

uint8_t RxBuffer[BUF_SIZE];
uint8_t TxBuffer[BUF_SIZE];

uint8_t fifo_level_minus1 = 4;

volatile uint8_t  gu8_UART2RecvFlag =0;

UART_HandleTypeDef UartHandle;

uint8_t UART_RX_FIFO_ITTrigCount(UART_TypeDef* UARTx)
{
    uint8_t rxiflsel = 1;
    
    assert_param(IS_UART_ALL_INSTANCE(UARTx));
    
    switch(UARTx->IFLS & 0x38)
    {
        case UART_RX_FIFO_1_16:
            rxiflsel = 1;
            break;
        case UART_RX_FIFO_1_2:
            rxiflsel = 8;
            break;
        
        case UART_RX_FIFO_1_4:
            rxiflsel = 4;
            break;
        
        case UART_RX_FIFO_1_8:
            rxiflsel = 2;
            break;
        
        case UART_RX_FIFO_3_4:
            rxiflsel = 12;
            break;
        
        case UART_RX_FIFO_7_8:
            rxiflsel = 14;
            break;
    }
    
    return rxiflsel;
}

void UART_RxCpltCallback(UART_HandleTypeDef* huart)
{
    gu8_UART2RecvFlag =1;
    UART_ITConfig(UART2, UART_IT_RXI, DISABLE);	/* RX isr disable */	
}

void UART_TxCpltCallback(UART_HandleTypeDef* huart)
{
    UART_ITConfig(UART2, UART_IT_TXI, DISABLE); 
    UART_ITConfig(UART2, UART_IT_RXI, ENABLE);	/* RX isr enable */	
}

/*********************************************************************************
* Function    : UartParaInit
* Description : Load UARTx Parameters
* Input       : None
* Output      : None
* Author      :                        Data : 2021年
**********************************************************************************/
static void UartParaInit(void)
{
    UartHandle.Instance = UART2;
    UartHandle.TxData = TxBuffer;
    UartHandle.RxData = RxBuffer;
    UartHandle.TxCount = 0;
    UartHandle.RxCount = 0;
    UartHandle.TxSize = 0;
    UartHandle.RxSize = 0;
    UartHandle.ErrorCode = 0;
    UartHandle.TxBusy = false;
    UartHandle.RxBusy = false;
    UartHandle.RxCpltCallback = UART_RxCpltCallback;
    UartHandle.TxCpltCallback = UART_TxCpltCallback;
    UartHandle.ErrorCallback = NULL;
}

/*********************************************************************************
* Function    : UART2_Init
* Description : Init  UART2 
* Input       : None
* Output      : None
**********************************************************************************/
static void UART2_Init(void)
{
    GPIO_InitTypeDef GPIO_InitStruct;
    UART_InitTypeDef UART2_InitStruc;

    //Enable GPIO and UART Clock
    System_Module_Enable(EN_UART2);
    System_Module_Enable(EN_GPIOAB);
    System_Module_Reset(RST_UART2);
    //Config GPIO
    /* A2:Tx  A3:Rx */
    GPIO_InitStruct.Pin       = GPIO_PIN_2 | GPIO_PIN_3;
    GPIO_InitStruct.Mode      = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull      = GPIO_PULLUP;
    GPIO_InitStruct.Alternate = GPIO_FUNCTION_2;
    GPIO_Init(GPIOA, &GPIO_InitStruct);
    //UART Config
    UART2_InitStruc.UART_BaudRate    = 115200;  
    UART2_InitStruc.UART_WordLength  = UART_WORDLENGTH_8B;
    UART2_InitStruc.UART_StopBits    = UART_STOPBITS_1;
    UART2_InitStruc.UART_Parity      = UART_PARITY_NONE;
    UART2_InitStruc.UART_Mode        = UART_MODE_TX_RX;
    UART2_InitStruc.UART_HardwareFlowControl =UART_HWCONTROL_NONE;    
    UART_Init(UART2,&UART2_InitStruc);					
    /* NVIC Config */
    NVIC_ClearPendingIRQ(UART2_IRQn);
    NVIC_SetPriority(UART2_IRQn, 5);
    NVIC_EnableIRQ(UART2_IRQn);
		    
    //Enable UART
    UART_Cmd(UART2,ENABLE);
}

UART_StatusTypeDef UART_Transmit(UART_HandleTypeDef *huart, uint8_t *fu8_Data, uint32_t fu32_Size, uint32_t fu32_Timeout)
{
    uint32_t lu32_Timeout;
    
    assert_param(IS_UART_ALL_INSTANCE(huart->Instance));
    
    if(_IS_UART_HALFDUPLEX_MODE(huart->Instance))
    {
        _UART_RX_DISABLE(huart->Instance);
    }

    huart->TxCount = 0;
    
    while (fu32_Size--) 
    {
        huart->Instance->DR = *fu8_Data++;

        huart->TxCount++;
        
        /* have no timeout */
        if (fu32_Timeout == 0) 
        {
            while (huart->Instance->FR & UART_FR_TXFF);
        }
        else 
        {
            lu32_Timeout = fu32_Timeout *256;
            
            while (huart->Instance->FR & UART_FR_TXFF)
            {
                if (lu32_Timeout-- == 0) 
                {
                    return UART_TIMEOUT;
                }
            }
        }
    }
    
    UART_Wait_TX_Done(huart->Instance);
    
    if(_IS_UART_HALFDUPLEX_MODE(huart->Instance))
    {
        _UART_RX_ENABLE(huart->Instance);
    }
    
    return UART_OK;
}

UART_StatusTypeDef UART_Receive(UART_HandleTypeDef *huart, uint8_t *fu8_Data, uint32_t fu32_Size, uint32_t fu32_Timeout)
{
    uint32_t lu32_Timeout;
    
    assert_param(IS_UART_ALL_INSTANCE(huart->Instance));

    huart->RxCount = 0;

    while (fu32_Size--) 
    {
        if (fu32_Timeout == 0) 
        {
            while(huart->Instance->FR & UART_FR_RXFE);
            
            *fu8_Data++ = huart->Instance->DR;
            
            huart->RxCount++;
        }
        else 
        {
            lu32_Timeout = fu32_Timeout * 256;
            
            while(huart->Instance->FR & UART_FR_RXFE)
            {
                if (lu32_Timeout-- == 0) 
                {
                    return UART_TIMEOUT;
                }
            }

            *fu8_Data++ = huart->Instance->DR;

            huart->RxCount++;
        }
    }
    
    return UART_OK;
}

/*********************************************************************************
* Function    : UARTx_DMA_Config
* Description : Config UART DMA Channel
* Input       : None
* Output      : None

**********************************************************************************/
void UARTx_DMA_Config(void)
{    
	
	DMA_InitTypeDef  DMA_InitStructure;	
	
	UART_DMACmd(UART2, UART_DMACR_TXDMAE, DISABLE);
    UART_DMACmd(UART2, UART_DMACR_RXDMAE, DISABLE);
    /* Enable DMA Module */
    System_Module_Enable(EN_DMA);
    System_Module_Reset(RST_DMA);
    /* NVIC configuration */
    NVIC_ClearPendingIRQ(DMA_IRQn);
    NVIC_EnableIRQ(DMA_IRQn);
    
    
    /* DMA channel0 configuration for UART2 TX */
    DMA_DeInit(DMA_Channel0);
    DMA_InitStructure.Request_ID = REQ7_UART2_SEND;
    DMA_InitStructure.SrcAddr = (uint32_t)TxBuffer;
    DMA_InitStructure.DstAddr = (uint32_t)(&UART2->DR);
    DMA_InitStructure.Data_Flow = DMA_DATA_FLOW_M2P;
    DMA_InitStructure.DMA_BufferSize = DMA_TX_SIZE;
    DMA_InitStructure.Source_Inc = DMA_SOURCE_ADDR_INCREASE_ENABLE;
    DMA_InitStructure.Desination_Inc = DMA_DST_ADDR_INCREASE_DISABLE;
    DMA_InitStructure.Source_Width = DMA_SRC_WIDTH_BYTE;
    DMA_InitStructure.Desination_Width = DMA_DST_WIDTH_BYTE;
    DMA_InitStructure.DMA_Mode = DMA_NORMAL;
    DMA_Init(DMA_Channel0, &DMA_InitStructure);	
        
    /* DMA channel1 configuration for UART2 RX */
    DMA_DeInit(DMA_Channel1);
    DMA_InitStructure.Request_ID = REQ8_UART2_RECV;
    DMA_InitStructure.SrcAddr = (uint32_t)(&UART2->DR);
    DMA_InitStructure.DstAddr = (uint32_t)RxBuffer;
    DMA_InitStructure.Data_Flow = DMA_DATA_FLOW_P2M;
    DMA_InitStructure.DMA_BufferSize = BUF_SIZE;
    DMA_InitStructure.Source_Inc = DMA_SOURCE_ADDR_INCREASE_DISABLE;
    DMA_InitStructure.Desination_Inc = DMA_DST_ADDR_INCREASE_ENABLE;
    DMA_InitStructure.Source_Width = DMA_SRC_WIDTH_BYTE;
    DMA_InitStructure.Desination_Width = DMA_DST_WIDTH_BYTE;
    DMA_InitStructure.DMA_Mode = DMA_NORMAL;
    DMA_Init(DMA_Channel1, &DMA_InitStructure);	
}

/*********************************************************************************
* Function    : APP_Uart_Test
* Description : Test UART Function By Various Way
* Input       : fe_Mode
* Output      : None

**********************************************************************************/
void APP_Uart_Test(enum_TEST_MODE_t fe_Mode)
{
	static char prompt_str[] ={"UART2 Test Demo, Please enter any data\r\n"};
	volatile uint16_t i;
	
    UartParaInit();
    UART2_Init();
    
    UART_Transmit(&UartHandle, (uint8_t*)&prompt_str[0], strlen(prompt_str), 0);
	
    switch (fe_Mode)
    {
        /* 循环模式 */
        case TEST_LOOP: 
        {			
            for(;;)
            {
                UART_Receive(&UartHandle, RxBuffer, BUF_SIZE, 100);
                
                if(UartHandle.RxCount)
                {
                    memcpy(TxBuffer, RxBuffer, UartHandle.RxCount);
                    UART_Transmit(&UartHandle, TxBuffer, UartHandle.RxCount, 0);
                }
            }		
        }break;

        /* 中断模式 */
        case TEST_UART_IT: 
        {
            uint32_t rlen;
            /* Do NOT set RXFIFO level at UART_RX_FIFO_1_16, when receiving random length data in interrupt mode */
            UART_FIFO_Level_Set(UART2, UART_TX_FIFO_1_16, UART_RX_FIFO_1_8);
            UART_FIFOCmd(UART2, ENABLE);
            
            fifo_level_minus1 = UART_RX_FIFO_ITTrigCount(UART2) - 1;
            UART_ITConfig(UART2, UART_IT_RXI, ENABLE);	/* 使能接收中断 */	
            UART_ITConfig(UART2, UART_IT_RTI, ENABLE);
			
			for(;;)
			{
				while(!gu8_UART2RecvFlag);	
				
				gu8_UART2RecvFlag =0;
                
                rlen = UartHandle.RxCount;                
                UartHandle.RxCount = 0;
                
                memcpy(UartHandle.TxData, RxBuffer, rlen);
                UartHandle.TxCount = 0;
                UartHandle.TxSize = rlen;
                
                if(_IS_UART_HALFDUPLEX_MODE(UART2))
                {
                    _UART_RX_DISABLE(UART2);
                }
                
                while(UartHandle.TxCount < UartHandle.TxSize && !READ_BIT(UartHandle.Instance->FR, UART_FR_TXFF))                    
                {
                    UartHandle.Instance->DR = UartHandle.TxData[UartHandle.TxCount++];
                }
                
                UART_ITConfig(UART2, UART_IT_TXI, ENABLE);
                
                if(_IS_UART_HALFDUPLEX_MODE(UART2))
                {
                    UART_Wait_TX_Done(UART2);                
                    _UART_RX_ENABLE(UART2);
                }
                
			}
        }break;        
        /* DMA模式 */
        case TEST_DMA: 
        {	
            uint32_t rx_count;
            uint32_t left_size, last_left_size;
            					
			UARTx_DMA_Config();
            
            while(1)
            {
                UARTx_DMA_Config();
                
                UART_DMACmd(UART2, UART_DMACR_RXDMAE, ENABLE);	
                
                DMA_Cmd(DMA_Channel1, ENABLE);
                
                while((DMA_Channel1->CTRL & 0xFFFF) == BUF_SIZE);
                last_left_size = left_size = (DMA_Channel1->CTRL & 0xFFFF);
                while(1)
                {
                    System_Delay_MS(10);
                    left_size = (DMA_Channel1->CTRL & 0xFFFF);
                    if(left_size == last_left_size)
                        break;
                    else
                        last_left_size = left_size;
                }
                
                rx_count = BUF_SIZE - left_size;
                
                memcpy(TxBuffer, RxBuffer, rx_count);
                
                if(_IS_UART_HALFDUPLEX_MODE(UART2))
                {
                    _UART_RX_DISABLE(UART2);
                }
                
                DMA_Channel0->CTRL = (DMA_Channel0->CTRL & ~(uint32_t)0xFFFFUL) | rx_count;
                
                DMA_Cmd(DMA_Channel0, ENABLE);
                
                UART_DMACmd(UART2, UART_DMACR_TXDMAE, ENABLE);			
                while (RESET == DMA_GetFlagStatus(DMA_IT_FLAG_TC0));
                
                if(_IS_UART_HALFDUPLEX_MODE(UART2))
                {
                    UART_Wait_TX_Done(UART2);
                    _UART_RX_ENABLE(UART2);
                }
            }
			          
        }break;

        default: break; 
    }
}
