
/******************************************************************************
*@file  : app.c
*@brief : application
******************************************************************************/

#include "app.h" 

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

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

volatile uint32_t rx_cnt = 0;
uint32_t read_size = BUF_SIZE;
volatile uint32_t tx_cnt = 0;
uint32_t send_size = BUF_SIZE;

volatile bool flag_idlei = false;
volatile bool TX_DMA_Status = false;

void UART_RxCpltCallback(void)
{
    uint32_t ChannelIndex;

    ChannelIndex = ((uint32_t)(DMA1_Channel1) - (uint32_t)(DMA1_Channel0)) >> 5;

    /* DMA Channel Abort */
    DMA_AbortCmd(DMA1_Channel1, ENABLE);
    
    /* Wait until data clearing in FIFO  */
    while (DMA1_Channel1->CHCONFIG & DMA_CHCONFIG_ACTIVE);
    
    DMA_AbortCmd(DMA1_Channel1, DISABLE);
    
    /* DMA Channel Disable */
    DMA_Cmd(DMA1_Channel1, DISABLE);
    
    /* Disable interrupt */
    DMA_ITConfig(DMA1_Channel1, DMA_CHCONFIG_IHFTC | DMA_CHCONFIG_ITC | DMA_CHCONFIG_IHFTC, DISABLE);
    
    /* Clear TC ERR Falg */
    DMA_ClearFlag(DMA1_Channel1, DMA_FLAG_TC | DMA_FLAG_HTC);
    DMA_ClearFlag(DMA1_Channel1, DMA_FLAG_ERR);

    while (DMA1->ENCHSTATUS & ChannelIndex);
    
    flag_idlei = true;
}

void UART1_GPIO_Config()
{
    GPIO_InitTypeDef GPIO_InitStructure;
    
    __RCC_GPIOA_CLK_ENABLE();
    
    GPIO_InitStructure.Pin       = GPIO_PIN_9 | GPIO_PIN_10;;
    GPIO_InitStructure.Mode      = GPIO_MODE_AF_PP;
    GPIO_InitStructure.Pull      = GPIO_PULLUP;
    GPIO_InitStructure.Drive     = GPIO_DRIVE_LEVEL3;
    GPIO_InitStructure.Alternate = GPIO_FUNCTION_1;
    GPIO_Init(GPIOA, &GPIO_InitStructure);
    
    printfS("UART1 TXD:PA9 , RXD:PA10\r\n");
}


void UART1_Init(void)
{
    UART_InitTypeDef   UART_InitStructure;
    
    __RCC_UART1_CLK_ENABLE();

    UART_InitStructure.BaudRate     = 115200;
    UART_InitStructure.WordLength   = UART_WORDLENGTH_8B;
    UART_InitStructure.StopBits     = UART_STOPBITS_1;
    UART_InitStructure.Parity       = UART_PARITY_NONE;
    UART_InitStructure.HwFlowCtl    = UART_HWCONTROL_NONE;
    UART_InitStructure.Mode         = UART_MODE_RX | UART_MODE_TX;
    UART_Init(UART1, &UART_InitStructure);
    
    /* NVIC Config */
    NVIC_ClearPendingIRQ(UART1_IRQn);
    NVIC_SetPriority(UART1_IRQn, 5);
    NVIC_EnableIRQ(UART1_IRQn);
        
    /* Enable UART */
    UART_Cmd(UART1, ENABLE);

    printfS("UART1 Baudrate: %d\r\n", UART_InitStructure.BaudRate);
}

/******************************************************************************
*@brief : app test
*@param : none
*@return: none
******************************************************************************/
void APP_Test(enum_TEST_MODE_t fe_Mode)
{
    switch (fe_Mode)
    {
        /* UART1 Loop mode */
        case TEST_UART1_LOOP: 
        {
            printfS("----------UART1 LOOP Demo ----------\r\n");
            printfS("%s to [UART1]\r\n\r\n", prompt_str);
            
            UART1_Init();
            
            UART1_GPIO_Config();

            for(;;)
            {
                rx_cnt = 0;
                
                UART_ClearITPendingBit(UART1, UART_ISR_IDLEI);
                
                while(UART_GetISRStatus(UART1, UART_ISR_IDLEI) != SET)
                {
                    while(!UART_GetFlagStatus(UART1, UART_FR_RXFE))
                    {
                        /* Read one byte from the receive data register */
                        RxBuffer[rx_cnt++] = (UART_ReceiveData(UART1) & 0xFF);
                        if( rx_cnt >= BUF_SIZE )
                            rx_cnt = 0;
                    }
                }

                send_size = rx_cnt;
                tx_cnt = 0;
                while(send_size--)
                {
                    while(UART_GetFlagStatus(UART1, UART_FR_TXFF))
                    {
                    }
                    
                    UART_SendData(UART1, RxBuffer[tx_cnt++]);
                }
            }
        }break;
        
        /* UART1 IT mode */
        case TEST_UART1_IT: 
        {
            printfS("----------UART1 IT Demo ----------\r\n");
            printfS("%s to [UART1]\r\n\r\n", prompt_str);
            
            UART1_Init();
            UART1_GPIO_Config();
            
            UART_ITConfig(UART1, UART_IT_RXI, ENABLE);
            UART_ITConfig(UART1, UART_IT_IDLEI, ENABLE);

            for(;;)
            {
                rx_cnt = 0;
                UART_ITConfig(UART1, UART_IT_RXI, ENABLE);
                while(!flag_idlei);
                flag_idlei = false;
                memcpy(TxBuffer, RxBuffer, rx_cnt);
                send_size = rx_cnt;
                tx_cnt = 0;
                UART_ITConfig(UART1, UART_IT_TXI, ENABLE);

                while((!UART_GetFlagStatus(UART1, UART_FR_TXFF)) && (tx_cnt < send_size))
                {
                    UART_SendData(UART1, TxBuffer[tx_cnt++]);
                }
            }
        }break;        
        
        case TEST_UART1_DMA: 
        {
            DMA_InitTypeDef InitData;
            
            printfS("----------UART1 DMA Demo ----------\r\n");
            printfS("%s to [UART1]\r\n\r\n", prompt_str);
            
            UART1_Init();
            
            UART1_GPIO_Config();
            
            UART_RX_FIFO_Level_Set(UART1, UART_RX_FIFO_1_16);
            UART_TX_FIFO_Level_Set(UART1, UART_TX_FIFO_1_16);
            
            /* UART RX DMA Enable */
            UART_DMACmd(UART1, UART_DMAReq_Rx, ENABLE);
            
            /* UART TX DMA Enable */
            UART_DMACmd(UART1, UART_DMAReq_Tx, ENABLE);   
            
            __RCC_DMA1_CLK_ENABLE();

            DMA_StructInit(&InitData);
            
            InitData.SrcInc      = DMA_SRCINC_ENABLE;
            InitData.DestInc     = DMA_DESTINC_DISABLE;
            InitData.DataFlow = DMA_DATAFLOW_M2P;
            InitData.ReqID = DMA1_REQ5_UART1_SEND;            
            DMA_Init(DMA1_Channel0, &InitData);
                        
            InitData.SrcInc      = DMA_SRCINC_DISABLE;
            InitData.DestInc     = DMA_DESTINC_ENABLE;
            InitData.DataFlow = DMA_DATAFLOW_P2M;
            InitData.ReqID = DMA1_REQ6_UART1_RECV;            
            DMA_Init(DMA1_Channel1, &InitData);

            NVIC_ClearPendingIRQ(DMA1_IRQn);
            NVIC_SetPriority(DMA1_IRQn, 5);
            NVIC_EnableIRQ(DMA1_IRQn);
            
            UART_ClearITPendingBit(UART1, UART_ISR_IDLEI);
            
            UART_ITConfig(UART1, UART_IT_IDLEI, ENABLE);
            
            
            for(;;)
            {
                rx_cnt = 0;
                
                /* Set source address and desination address */
                DMA_SrcAddrConfig(DMA1_Channel1, (uint32_t)&UART1->DR);
                
                DMA_DestAddrConfig(DMA1_Channel1, (uint32_t)RxBuffer);

                /* Set Transfer Size and enable LLI interrupt */
                DMA_SetTransferSize(DMA1_Channel1, sizeof(RxBuffer));
                    
                /* DMA Channel Enable */
                DMA_Cmd(DMA1_Channel1, ENABLE);
                
                while(!flag_idlei);
                flag_idlei = false;
                rx_cnt = DMA_GetTransferSize(DMA1_Channel1);
                rx_cnt = sizeof(RxBuffer) - DMA_GetTransferSize(DMA1_Channel1);
                memcpy(TxBuffer, RxBuffer, rx_cnt);
                                	
                /* Set source address and desination address */
                DMA_SrcAddrConfig(DMA1_Channel0, (uint32_t)TxBuffer);
                
                DMA_DestAddrConfig(DMA1_Channel0, (uint32_t)&UART1->DR);

                /* Set Transfer Size and enable LLI interrupt */
                DMA_SetTransferSize(DMA1_Channel0, rx_cnt);

                DMA_ITConfig(DMA1_Channel0, DMA_CHCONFIG_ITC | DMA_CHCONFIG_IE , ENABLE);
                    
                /* DMA Channel Enable */
                DMA_Cmd(DMA1_Channel0, ENABLE);
                
                while(TX_DMA_Status == false);

                TX_DMA_Status = false;
                memset(RxBuffer, 0, BUF_SIZE);

            }
        }break;
        
        default:
            break;
    }
}
