/*
* Copyright (c) 2023-2028, SpaceTouch Inc.
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date          Author      Notes
* 2023-04-18    dongx       the first version
* 2023-08-11    jinyaoh     add comments
*/
#include <stdio.h>
#include "platform.h"
#include "dev_uartn.h"
#include "hal_log.h"
#include "hal_uart.h"
#include "hal_gpio.h"
#include "hal_common.h"
#include "hal_dma.h"
#include "hal_cmu.h"
#include "board.h"
#include "debug.h"
// 为兼容DMA模式，这里TX RX阈值均为1
#define DEV_UARTn_CFG_TX_FIFO_THR       1
#define DEV_UARTn_CFG_RX_FIFO_THR       1


static uart_callback_t uart_rx_cb[UART_NUM];

/**
 * This function changes the properties of the serial port through struct uart_config
 *
 * @param uart_port: The value ranges from 0 to 2
 * @param uart_config: The structure contains the properties of the serial port
 *
 * @return None
 */
void hal_uart_hw_set_change(int32_t uart_port, uart_config_t *uart_config)
{
    uint32_t uart_cfg = 0;
    uint32_t uart_ctl = 0;
    uint32_t uart_div = 0;
    //uart config
    uart_cfg |= uart_config->data_width; //bit

    if (uart_config->stop_bit == UART_STOP_BIT_1)
        uart_cfg |= DEV_UARTn_CFG_STOP_BIT_1BIT;

    if (uart_config->stop_bit == UART_STOP_BIT_2)
        uart_cfg |= DEV_UARTn_CFG_STOP_BIT_2BIT;

    if (uart_config->parity == UART_PARITY_ODD)
        uart_cfg |= DEV_UARTn_CFG_PARITY_EN_ENABLE | DEV_UARTn_CFG_PARITY_SEL_ODD_PARITY;
    else if (uart_config->parity == UART_PARITY_EVEN)
        uart_cfg |= DEV_UARTn_CFG_PARITY_EN_ENABLE | DEV_UARTn_CFG_PARITY_SEL_EVEN_PARITY;
    else if (uart_config->parity == UART_PARITY_NONE)
        uart_cfg |= DEV_UARTn_CFG_PARITY_EN_DISABLE;

    uart_cfg |= (DEV_UARTn_CFG_TX_FIFO_THR << 8) | (DEV_UARTn_CFG_RX_FIFO_THR << 12);
    uart_div = DEV_UARTn_DIV_RX_DIV(24000000, uart_config->baudrate) |
               DEV_UARTn_DIV_TX_DIV(24000000, uart_config->baudrate);
    uart_ctl = DEV_UARTn_CTL_TX_EN_ENABLE | DEV_UARTn_CTL_RX_EN_ENABLE;

    if (uart_port == UART_0)
    {
        cmu_uart_set_clk(UART_0, CMU_Clock_OSC_XTAL);
        //配置
        DEV_UART0->CFG = uart_cfg;
        //波特率
        DEV_UART0->DIV = uart_div;
        //io
#ifdef HAL_UART0_TX_PIN
        hal_gpio_pinmux_set_function(HAL_UART0_TX_PIN, HAL_UART0_TX_MUXSEL_FUNCTION);
        hal_gpio_set_pull(HAL_UART0_TX_PIN, GPIO_PULL_UP);
#endif

#ifdef HAL_UART0_RX_PIN
        hal_gpio_pinmux_set_function(HAL_UART0_RX_PIN, HAL_UART0_RX_MUXSEL_FUNCTION);
        hal_gpio_set_pull(HAL_UART0_RX_PIN, GPIO_PULL_UP);
#endif
        DEV_UART0->PD = DEV_UARTn_PD_RX_FIFO_THR;
        DEV_UART0->CTL = uart_ctl;
    }
    else if (uart_port == UART_1)
    {
        cmu_uart_set_clk(UART_1, CMU_Clock_OSC_XTAL);
        //配置
        DEV_UART1->CFG = uart_cfg;
        //波特率
        DEV_UART1->DIV = uart_div;
        //io
#ifdef HAL_UART1_TX_PIN
        hal_gpio_pinmux_set_function(HAL_UART1_TX_PIN, HAL_UART1_TX_MUXSEL_FUNCTION);
        hal_gpio_set_pull(HAL_UART1_TX_PIN, GPIO_PULL_UP);
#endif

#ifdef HAL_UART1_RX_PIN
        hal_gpio_pinmux_set_function(HAL_UART1_RX_PIN, GPIO_MUXSEL_FUNCTION2);
        hal_gpio_set_pull(HAL_UART1_RX_PIN, GPIO_PULL_UP);
#endif
        DEV_UART1->PD = DEV_UARTn_PD_RX_FIFO_THR;
        DEV_UART1->CTL = uart_ctl;
    }
    else if (uart_port == UART_2)
    {
        cmu_uart_set_clk(UART_2, CMU_Clock_OSC_XTAL);
        //配置
        DEV_UART2->CFG = uart_cfg;
        //波特率
        DEV_UART2->DIV = uart_div;
        //io
#ifdef HAL_UART2_TX_PIN
        hal_gpio_pinmux_set_function(HAL_UART2_TX_PIN, HAL_UART2_TX_MUXSEL_FUNCTION);
        hal_gpio_set_pull(HAL_UART2_TX_PIN, GPIO_PULL_UP);
#endif

#ifdef HAL_UART2_RX_PIN
        hal_gpio_pinmux_set_function(HAL_UART2_RX_PIN, HAL_UART2_RX_MUXSEL_FUNCTION);
        hal_gpio_set_pull(HAL_UART2_RX_PIN, GPIO_PULL_UP);
#endif
        DEV_UART2->PD = DEV_UARTn_PD_RX_FIFO_THR;
        DEV_UART2->CTL = uart_ctl;
    }
}

/**
 * This function sets the baud rate of the serial port
 *
 * @param uart_port: The value ranges from 0 to 2
 * @param baudrate: Baud rate of the serial port
 *
 * @return None
 */
void hal_uart_set_baudrate(int32_t uart_port, uint32_t baudrate)
{
    uint32_t uart_div = DEV_UARTn_DIV_RX_DIV(24000000, baudrate) |
                        DEV_UARTn_DIV_TX_DIV(24000000, baudrate);

    if (uart_port == UART_0)
    {
        DEV_UART0->DIV = uart_div;
    }
    else if (uart_port == UART_1)
    {
        DEV_UART1->DIV = uart_div;
    }
    else if (uart_port == UART_2)
    {
        DEV_UART2->DIV = uart_div;
    }
}

/**
 * This function sets the data bit width
 *
 * @param uart_port: The value ranges from 0 to 2
 * @param data_width: The value ranges from 5 to 8
 *
 * @return None
 */
void hal_uart_set_data_width(int32_t uart_port, uint32_t data_width)
{
    uint8_t res_data_width = data_width - 5;

    if (res_data_width > 3)
        res_data_width = 3;

    if (uart_port == UART_0)
    {
        DEV_UART0->CFG &= ~DEV_UARTn_CFG_DATA_WIDTH_MASK;
        DEV_UART0->CFG |= res_data_width;
    }
    else if (uart_port == UART_1)
    {
        DEV_UART1->CFG &= ~DEV_UARTn_CFG_DATA_WIDTH_MASK;
        DEV_UART1->CFG |= res_data_width;
    }
    else if (uart_port == UART_2)
    {
        DEV_UART2->CFG &= ~DEV_UARTn_CFG_DATA_WIDTH_MASK;
        DEV_UART2->CFG |= res_data_width;
    }
}

/**
 * This function sets the stop bit width
 *
 * @param uart_port: The value ranges from 0 to 2
 * @param stop_bit: The value ranges from 0 to 1
 *
 * @return None
 */
void hal_uart_set_stop_bit(int32_t uart_port, uint32_t stop_bit)
{
    if (stop_bit > 1)
        stop_bit = 1;

    if (uart_port == UART_0)
    {
        DEV_UART0->CFG &= ~DEV_UARTn_CFG_STOP_BIT_MASK;
        DEV_UART0->CFG |= (stop_bit << 2);
    }
    else if (uart_port == UART_1)
    {
        DEV_UART1->CFG &= ~DEV_UARTn_CFG_STOP_BIT_MASK;
        DEV_UART1->CFG |= (stop_bit << 2);
    }
    else if (uart_port == UART_2)
    {
        DEV_UART2->CFG &= ~DEV_UARTn_CFG_STOP_BIT_MASK;
        DEV_UART2->CFG |= (stop_bit << 2);
    }
}

/**
 * This function sets the parity bit
 *
 * @param uart_port: The value ranges from 0 to 2
 * @param parity: The value ranges from 0 to 2
 *
 * @return None
 */
void hal_uart_set_parity(int32_t uart_port, uint32_t parity)
{
    if (uart_port == UART_0)
    {
        DEV_UART0->CFG &= ~DEV_UARTn_CFG_PARITY_EN_MASK;
        DEV_UART0->CFG &= ~DEV_UARTn_CFG_PARITY_SEL_MASK;
    }
    else if (uart_port == UART_1)
    {
        DEV_UART1->CFG &= ~DEV_UARTn_CFG_PARITY_EN_MASK;
        DEV_UART1->CFG &= ~DEV_UARTn_CFG_PARITY_SEL_MASK;
    }
    else if (uart_port == UART_2)
    {
        DEV_UART2->CFG &= ~DEV_UARTn_CFG_PARITY_EN_MASK;
        DEV_UART2->CFG &= ~DEV_UARTn_CFG_PARITY_SEL_MASK;
    }

    if (parity == 0)
    {
        if (uart_port == UART_0)
        {
            DEV_UART0->CFG |= DEV_UARTn_CFG_PARITY_EN_DISABLE;
        }
        else if (uart_port == UART_1)
        {
            DEV_UART1->CFG |= DEV_UARTn_CFG_PARITY_EN_DISABLE;
        }
        else if (uart_port == UART_2)
        {
            DEV_UART2->CFG |= DEV_UARTn_CFG_PARITY_EN_DISABLE;
        }
    }
    else
    {
        if (uart_port == UART_0)
        {
            DEV_UART0->CFG |= DEV_UARTn_CFG_PARITY_EN_ENABLE;
        }
        else if (uart_port == UART_1)
        {
            DEV_UART1->CFG |= DEV_UARTn_CFG_PARITY_EN_ENABLE;
        }
        else if (uart_port == UART_2)
        {
            DEV_UART2->CFG |= DEV_UARTn_CFG_PARITY_EN_ENABLE;
        }

        if (parity == 1)
        {
            if (uart_port == UART_0)
            {
                DEV_UART0->CFG |= DEV_UARTn_CFG_PARITY_SEL_ODD_PARITY;
            }
            else if (uart_port == UART_1)
            {
                DEV_UART1->CFG |= DEV_UARTn_CFG_PARITY_SEL_ODD_PARITY;
            }
            else if (uart_port == UART_2)
            {
                DEV_UART2->CFG |= DEV_UARTn_CFG_PARITY_SEL_ODD_PARITY;
            }
        }
        else
        {
            if (uart_port == UART_0)
            {
                DEV_UART0->CFG |= DEV_UARTn_CFG_PARITY_SEL_EVEN_PARITY;
            }
            else if (uart_port == UART_1)
            {
                DEV_UART1->CFG |= DEV_UARTn_CFG_PARITY_SEL_EVEN_PARITY;
            }
            else if (uart_port == UART_2)
            {
                DEV_UART2->CFG |= DEV_UARTn_CFG_PARITY_SEL_EVEN_PARITY;
            }
        }
    }
}

/**
 * This function will enable automatic baud rate calculation of the serial port
 *
 * @param uart_port: The value ranges from 0 to 2
 *
 * @return None
 */
void hal_uart_auto_baud_rate_detect(int32_t uart_port)
{
    if (uart_port == UART_0)
    {
        DEV_UART0->CTL_f.ABD = 1;
    }
    else if (uart_port == UART_1)
    {
        DEV_UART1->CTL_f.ABD = 1;
    }
    else if (uart_port == UART_2)
    {
        DEV_UART2->CTL_f.ABD = 1;
    }
}

/**
 * This function will get the results of the automatic baud rate calculation
 *
 * @param uart_port: The value ranges from 0 to 2
 *
 * @return the results of the automatic baud rate calculation
 */
uint16_t hal_uart_get_rx_div(int32_t uart_port)
{
    uint16_t res_rx_cnt = 0;

    if (uart_port == UART_0)
    {
        res_rx_cnt = DEV_UART0->RX_CNT_f.RX_CNT;
    }
    else if (uart_port == UART_1)
    {
        res_rx_cnt = DEV_UART1->RX_CNT_f.RX_CNT;
    }
    else if (uart_port == UART_2)
    {
        res_rx_cnt = DEV_UART2->RX_CNT_f.RX_CNT;
    }

    return res_rx_cnt;
}

/**
 * This function will retrieve the received bytes
 *
 * @param uart_port: The value ranges from 0 to 2
 *
 * @return the received bytes
 */
int32_t hal_uart_get_char(int32_t uart_port)
{
    int32_t val = -1;

    if (uart_port == UART_0)
    {
        if ((DEV_UART0->STA & DEV_UARTn_STA_RX_FIFO_EMPTY) != DEV_UARTn_STA_RX_FIFO_EMPTY)
        {
            val = DEV_UART0->RX_DAT;
        }
    }
    else if (uart_port == UART_1)
    {
        if ((DEV_UART1->STA & DEV_UARTn_STA_RX_FIFO_EMPTY) != DEV_UARTn_STA_RX_FIFO_EMPTY)
        {
            val = DEV_UART1->RX_DAT;
        }
    }
    else if (uart_port == UART_2)
    {
        if ((DEV_UART2->STA & DEV_UARTn_STA_RX_FIFO_EMPTY) != DEV_UARTn_STA_RX_FIFO_EMPTY)
        {
            val = DEV_UART2->RX_DAT;
        }
    }

    return val;
}

/**
 * This function will send bytes
 *
 * @param uart_port: The value ranges from 0 to 2
 * @param c: Character to be sent
 *
 * @return 1
 */
int32_t hal_uart_put_char(int32_t uart_port, char c)
{
    if (uart_port == UART_0)
    {
        while (DEV_UART0->STA & DEV_UARTn_STA_TX_FIFO_FULL);

        DEV_UART0->TX_DAT = c;
    }
    else if (uart_port == UART_1)
    {
        while (DEV_UART1->STA & DEV_UARTn_STA_TX_FIFO_FULL);

        DEV_UART1->TX_DAT = c;
    }
    else if (uart_port == UART_2)
    {
        while (DEV_UART2->STA & DEV_UARTn_STA_TX_FIFO_FULL);

        DEV_UART2->TX_DAT = c;
    }

    return 1;
}

/**
 * This function will initialize the serial port
 *
 * @param uart_port: The value ranges from 0 to 2
 *
 * @return 1
 */
int32_t hal_uart_init(int32_t uart_port)
{
    if (uart_port == UART_0)
    {
        cmu_uart_set_clk(UART_0, CMU_Clock_OSC_XTAL);
        //配置
        DEV_UART0->CFG = DEV_UARTn_CFG_DATA_WIDTH_8BIT
                         | DEV_UARTn_CFG_STOP_BIT_1BIT
                         | (1 << 12)
                         | (1 << 8);
        //波特率
        DEV_UART0->DIV = DEV_UARTn_DIV_RX_DIV(24000000, HAL_UART0_BAUDRATE)
                         | DEV_UARTn_DIV_TX_DIV(24000000, HAL_UART0_BAUDRATE);
        //io
#ifdef HAL_UART0_TX_PIN
        hal_gpio_pinmux_set_function(HAL_UART0_TX_PIN, HAL_UART0_TX_MUXSEL_FUNCTION);
        hal_gpio_set_pull(HAL_UART0_TX_PIN, GPIO_PULL_UP);
#endif

#ifdef HAL_UART0_RX_PIN
        hal_gpio_pinmux_set_function(HAL_UART0_RX_PIN, HAL_UART0_RX_MUXSEL_FUNCTION);
        hal_gpio_set_pull(HAL_UART0_RX_PIN, GPIO_PULL_UP);
#endif
        DEV_UART0->PD = DEV_UARTn_PD_RX_FIFO_THR;
        DEV_UART0->CTL = DEV_UARTn_CTL_RX_FIFO_RST_ENABLE | DEV_UARTn_CTL_TX_FIFO_RST_ENABLE;
        DEV_UART0->CTL = DEV_UARTn_CTL_TX_EN_ENABLE | DEV_UARTn_CTL_RX_EN_ENABLE;
    }
    else if (uart_port == UART_1)
    {
        cmu_uart_set_clk(UART_1, CMU_Clock_OSC_XTAL);
        //配置
        DEV_UART1->CFG = DEV_UARTn_CFG_DATA_WIDTH_8BIT
                         | DEV_UARTn_CFG_STOP_BIT_1BIT
                         | (1 << 12)
                         | (1 << 8);
#ifdef HAL_UART1_BAUDRATE
        //波特率
        DEV_UART1->DIV = DEV_UARTn_DIV_RX_DIV(24000000, HAL_UART1_BAUDRATE)
                         | DEV_UARTn_DIV_TX_DIV(24000000, HAL_UART1_BAUDRATE);
#endif
        //io
#ifdef HAL_UART1_TX_PIN
        hal_gpio_pinmux_set_function(HAL_UART1_TX_PIN, HAL_UART1_TX_MUXSEL_FUNCTION);
        hal_gpio_set_pull(HAL_UART1_TX_PIN, GPIO_PULL_UP);
#endif

#ifdef HAL_UART1_RX_PIN
        hal_gpio_pinmux_set_function(HAL_UART1_RX_PIN, HAL_UART1_RX_MUXSEL_FUNCTION);
        hal_gpio_set_pull(HAL_UART1_RX_PIN, GPIO_PULL_UP);
#endif
        DEV_UART1->PD = DEV_UARTn_PD_RX_FIFO_THR;
        DEV_UART1->CTL = DEV_UARTn_CTL_RX_FIFO_RST_ENABLE | DEV_UARTn_CTL_TX_FIFO_RST_ENABLE;
        DEV_UART1->CTL = DEV_UARTn_CTL_TX_EN_ENABLE | DEV_UARTn_CTL_RX_EN_ENABLE;

    }
    else if (uart_port == UART_2)
    {
        cmu_uart_set_clk(UART_2, CMU_Clock_OSC_XTAL);
        //配置
        DEV_UART2->CFG = DEV_UARTn_CFG_DATA_WIDTH_8BIT
                         | DEV_UARTn_CFG_STOP_BIT_1BIT
                         | (1 << 12)
                         | (1 << 8);
#ifdef HAL_UART2_BAUDRATE
        //波特率
        DEV_UART2->DIV = DEV_UARTn_DIV_RX_DIV(24000000, HAL_UART2_BAUDRATE)
                         | DEV_UARTn_DIV_TX_DIV(24000000, HAL_UART2_BAUDRATE);
#endif
        //io
#ifdef HAL_UART2_TX_PIN
        hal_gpio_pinmux_set_function(HAL_UART2_TX_PIN, HAL_UART2_TX_MUXSEL_FUNCTION);
        hal_gpio_set_pull(HAL_UART2_TX_PIN, GPIO_PULL_UP);
#endif
#ifdef HAL_UART2_RX_PIN
        hal_gpio_pinmux_set_function(HAL_UART2_RX_PIN, HAL_UART2_RX_MUXSEL_FUNCTION);
        hal_gpio_set_pull(HAL_UART2_RX_PIN, GPIO_PULL_UP);
#endif
        DEV_UART2->PD = DEV_UARTn_PD_RX_FIFO_THR;
        DEV_UART2->CTL = DEV_UARTn_CTL_RX_FIFO_RST_ENABLE | DEV_UARTn_CTL_TX_FIFO_RST_ENABLE;
        DEV_UART2->CTL = DEV_UARTn_CTL_TX_EN_ENABLE | DEV_UARTn_CTL_RX_EN_ENABLE;
    }

    return 1;
}

/**
 * This function sets the callback function that the serial port receives
 *
 * @param uart_port: The value ranges from 0 to 2
 * @param uart_port: The value ranges from 0 to 2
 *
 * @return Return 0 if normal, -1 if abnormal
 */
int32_t hal_uart_set_rx_callback(int32_t uart_port, void *callback, void *param, uint32_t flag, uart_dma_handle *dma_handle)
{
    if (uart_port < UART_0 || uart_port >= UART_NUM)
        return -1;

    uart_rx_cb[uart_port].callback = (uart_callback)callback;
    uart_rx_cb[uart_port].param = param;
    uart_rx_cb[uart_port].flag = flag;
    uart_rx_cb[uart_port].dma_handle = dma_handle;
    return 0;
}

/**
 * This function will turn on or off the serial port receiving timeout interrupt
 *
 * @param uart_port: The value ranges from 0 to 2
 * @param enale: DISABLE or ENABLE
 *
 * @return Return 0 if normal, -1 if abnormal
 */
int32_t hal_uart_set_rx_timeout_interrupt(int32_t uart_port, uint8_t enale)
{
    uint32_t reg;

    if (uart_port < UART_0 || uart_port >= UART_NUM)
        return -1;

    if (uart_port == UART_0)
    {
        reg = DEV_UART0->IE;
        enale ? (reg |= DEV_UARTn_IE_TIME_OUT) : (reg &= ~DEV_UARTn_IE_TIME_OUT);
        DEV_UART0->IE = reg;
        DEV_UART0->CFG_f.TO_DIV = 10;
    }
    else if (uart_port == UART_1)
    {
        reg = DEV_UART1->IE;
        enale ? (reg |= DEV_UARTn_IE_TIME_OUT) : (reg &= ~DEV_UARTn_IE_TIME_OUT);
        DEV_UART1->IE = reg;
        DEV_UART1->CFG_f.TO_DIV = 10;
    }
    else if (uart_port == UART_2)
    {
        reg = DEV_UART2->IE;
        enale ? (reg |= DEV_UARTn_IE_TIME_OUT) : (reg &= ~DEV_UARTn_IE_TIME_OUT);
        DEV_UART2->IE = reg;
        DEV_UART2->CFG_f.TO_DIV = 10;
    }

    return 0;
}

/**
 * This function will turn on or off the serial port receiving interrupt
 *
 * @param uart_port: The value ranges from 0 to 2
 * @param enale: DISABLE or ENABLE
 *
 * @return Return 0 if normal, -1 if abnormal
 */
int32_t hal_uart_set_rx_interrupt(int32_t uart_port, uint8_t enale)
{
    uint32_t reg;

    if (uart_port < UART_0 || uart_port >= UART_NUM)
        return -1;

    if (uart_port == UART_0)
    {
        reg = DEV_UART0->IE;
        enale ? (reg |= DEV_UARTn_IE_RX_FIFO_THR) : (reg &= ~DEV_UARTn_IE_RX_FIFO_THR);
        DEV_UART0->IE = reg;
    }
    else if (uart_port == UART_1)
    {
        reg = DEV_UART1->IE;
        enale ? (reg |= DEV_UARTn_IE_RX_FIFO_THR) : (reg &= ~DEV_UARTn_IE_RX_FIFO_THR);
        DEV_UART1->IE = reg;
    }
    else if (uart_port == UART_2)
    {
        reg = DEV_UART2->IE;
        enale ? (reg |= DEV_UARTn_IE_RX_FIFO_THR) : (reg &= ~DEV_UARTn_IE_RX_FIFO_THR);
        DEV_UART2->IE = reg;
    }

    return 0;
}

/**
 * This function will turn on or off the serial port sending interrupt
 *
 * @param uart_port: The value ranges from 0 to 2
 * @param enale: DISABLE or ENABLE
 *
 * @return Return 0 if normal, -1 if abnormal
 */
int32_t hal_uart_set_tx_interrupt(int32_t uart_port, uint8_t enale)
{
    uint32_t reg;

    if (uart_port < UART_0 || uart_port >= UART_NUM)
        return -1;

    if (uart_port == UART_0)
    {
        reg = DEV_UART0->IE;
        enale ? (reg |= DEV_UARTn_IE_TX_END) : (reg &= ~DEV_UARTn_IE_TX_END);
        DEV_UART0->IE = reg;
    }
    else if (uart_port == UART_1)
    {
        reg = DEV_UART1->IE;
        enale ? (reg |= DEV_UARTn_IE_TX_END) : (reg &= ~DEV_UARTn_IE_TX_END);
        DEV_UART1->IE = reg;
    }
    else if (uart_port == UART_2)
    {
        reg = DEV_UART2->IE;
        enale ? (reg |= DEV_UARTn_IE_TX_END) : (reg &= ~DEV_UARTn_IE_TX_END);
        DEV_UART2->IE = reg;
    }

    return 0;
}

/**
 * This function will turn on or off serial port DMA sending
 *
 * @param uart_port: The value ranges from 0 to 2
 * @param enale: DISABLE or ENABLE
 *
 * @return Return 0 if normal, -1 if abnormal
 */
int32_t hal_uart_set_tx_DMA_enable(int32_t uart_port, uint8_t enale)
{
    uint32_t reg;

    if (uart_port < UART_0 || uart_port >= UART_NUM)
        return -1;

    if (uart_port == UART_0)
    {
        reg = DEV_UART0->CTL;
        enale ? (reg |= DEV_UARTn_CTL_TX_DMA_EN_ENABLE) : (reg &= ~DEV_UARTn_CTL_TX_DMA_EN_ENABLE);
        DEV_UART0->CTL = reg;
    }
    else if (uart_port == UART_1)
    {
        reg = DEV_UART1->CTL;
        enale ? (reg |= DEV_UARTn_CTL_TX_DMA_EN_ENABLE) : (reg &= ~DEV_UARTn_CTL_TX_DMA_EN_ENABLE);
        DEV_UART1->CTL = reg;
    }
    else if (uart_port == UART_2)
    {
        reg = DEV_UART2->CTL;
        enale ? (reg |= DEV_UARTn_CTL_TX_DMA_EN_ENABLE) : (reg &= ~DEV_UARTn_CTL_TX_DMA_EN_ENABLE);
        DEV_UART2->CTL = reg;
    }

    return 0;
}

/**
 * This function will turn on or off the serial port DMA reception
 *
 * @param uart_port: The value ranges from 0 to 2
 * @param enale: DISABLE or ENABLE
 *
 * @return Return 0 if normal, -1 if abnormal
 */
int32_t hal_uart_set_rx_DMA_enable(int32_t uart_port, uint8_t enale)
{
    uint32_t reg;

    if (uart_port < UART_0 || uart_port >= UART_NUM)
        return -1;

    if (uart_port == UART_0)
    {
        reg = DEV_UART0->CTL;
        enale ? (reg |= DEV_UARTn_CTL_RX_DMA_EN_ENABLE) : (reg &= ~DEV_UARTn_CTL_RX_DMA_EN_ENABLE);
        DEV_UART0->CTL = reg;
    }
    else if (uart_port == UART_1)
    {
        reg = DEV_UART1->CTL;
        enale ? (reg |= DEV_UARTn_CTL_RX_DMA_EN_ENABLE) : (reg &= ~DEV_UARTn_CTL_RX_DMA_EN_ENABLE);
        DEV_UART1->CTL = reg;
    }
    else if (uart_port == UART_2)
    {
        reg = DEV_UART2->CTL;
        enale ? (reg |= DEV_UARTn_CTL_RX_DMA_EN_ENABLE) : (reg &= ~DEV_UARTn_CTL_RX_DMA_EN_ENABLE);
        DEV_UART2->CTL = reg;
    }

    return 0;
}

void hal_console_putc(char c)
{
    while (DEV_UART0->STA & DEV_UARTn_STA_TX_FIFO_FULL);

    DEV_UART0->TX_DAT = c;
}

void hal_console_sendstr(const char *string)
{
    while (*string)
    {
        hal_console_putc(*string++);
    }
}

#define hal_uart_tx_dma_config_default                  \
{                                                       \
    8,                          /* channel */           \
    DMA_Address_Type_Inc,       /* src_inc */           \
    DMA_Address_Type_Fix,       /* dst_inc */           \
    DMA_Data_Width_8Bit,        /* src_data_width  */   \
    DMA_Data_Width_8Bit,        /* dst_data_width */    \
    DMA_Data_Location_Select_Low,  /* src_data_loc */       \
    DMA_Data_Location_Select_Low,   /* dst_data_loc */      \
    DMA_Burst_Length_Burst1,    /* memory_burst */      \
    DMA_Mode_Single,            /* mode */              \
    1                           /* priority */          \
}

#define hal_uart_rx_dma_config_default                  \
{                                                       \
    8,                          /* channel */           \
    DMA_Address_Type_Fix,       /* src_inc */           \
    DMA_Address_Type_Inc,       /* dst_inc */           \
    DMA_Data_Width_8Bit,        /* src_data_width  */   \
    DMA_Data_Width_8Bit,        /* dst_data_width */    \
    DMA_Data_Location_Select_Low,  /* src_data_loc */       \
    DMA_Data_Location_Select_Low,   /* dst_data_loc */      \
    DMA_Burst_Length_Burst1,    /* memory_burst */      \
    DMA_Mode_Single,            /* mode */              \
    1                           /* priority */          \
}

/**
 * This function initializes the sending DMA
 *
 * @param uart_port: The value ranges from 0 to 2
 * @param dma_handle: DMA structure
 *
 * @return 1
 */
int32_t hal_uart_tx_dma_init(int32_t uart_port, DMA_HandleTypeDef *dma_handle)
{
    DMA_InitTypeDef init_default = (DMA_InitTypeDef)hal_uart_tx_dma_config_default;
    init_default.channel = DMA_CHANNLE_DEFAULT;
    dma_handle->init = (DMA_InitTypeDef)init_default;
    dma_handle->state = HAL_DMA_STATE_READY;
    return 1;
}

/**
 * This function initializes the receiving DMA
 *
 * @param uart_port: The value ranges from 0 to 2
 * @param dma_handle: DMA structure
 *
 * @return 1
 */
int32_t hal_uart_rx_dma_init(int32_t uart_port, DMA_HandleTypeDef *dma_handle)
{
    DMA_InitTypeDef init_default = (DMA_InitTypeDef)hal_uart_rx_dma_config_default;
    init_default.channel = DMA_CHANNLE_DEFAULT;
    init_default.mode = DMA_Mode_Circular;//DMA_Mode_Circular;
    dma_handle->init = init_default;
    dma_handle->state = HAL_DMA_STATE_READY;
    return 1;
}

/**
 * This function will start by DMA transfers data
 *
 * @param hdma: DMA structure
 * @param srca_ddress: Source address
 * @param data_length: Data length
 * @param uart_port: The value ranges from 0 to 2
 * @param param: This parameter may be used in DMA interrupt callback functions
 *
 * @return None
 */
void hal_uart_tx_dma_start(DMA_HandleTypeDef *hdma, uint32_t srca_ddress, uint32_t data_length, int32_t uart_port, void *param)
{
    if (uart_port == UART_0)
    {
        hal_dma_start_it(hdma, srca_ddress, (uint32_t)&DEV_UART0->TX_DAT, data_length, param);
    }
    else if (uart_port == UART_1)
    {
        hal_dma_start_it(hdma, srca_ddress, (uint32_t)&DEV_UART1->TX_DAT, data_length, param);
    }
    else if (uart_port == UART_2)
    {
        hal_dma_start_it(hdma, srca_ddress, (uint32_t)&DEV_UART2->TX_DAT, data_length, param);
    }
}

/**
 * This function will start by DMA receive data
 *
 * @param hdma: DMA structure
 * @param dst_address: Destination address
 * @param data_length: Data length
 * @param uart_port: The value ranges from 0 to 2
 * @param param: This parameter may be used in DMA interrupt callback functions
 *
 * @return None
 */
void hal_uart_rx_dma_start(DMA_HandleTypeDef *hdma, uint32_t dst_address, uint32_t data_length, int32_t uart_port, void *param)
{
    if (uart_port == UART_0)
    {
        hal_dma_start_it(hdma, (uint32_t)&DEV_UART0->RX_DAT, dst_address, data_length, param);
    }
    else if (uart_port == UART_1)
    {
        hal_dma_start_it(hdma, (uint32_t)&DEV_UART1->RX_DAT, dst_address, data_length, param);
    }
    else if (uart_port == UART_2)
    {
        hal_dma_start_it(hdma, (uint32_t)&DEV_UART2->RX_DAT, dst_address, data_length, param);
    }
}

/**
 * This function will get the amount of data received by DMA
 *
 * @param channel: DMA channel
 *
 * @return The amount of data received
 */
uint32_t hal_get_rx_length_by_DMA(uint8_t channel)
{
    uint32_t dma_length = 0;

    if (DEV_DMAC->DMA_CHN[channel].STA & 0xffff0000)
        dma_length = (DEV_DMAC->DMA_CHN[channel].LEN & 0xffff) + (DEV_DMAC->DMA_CHN[channel].STA & 0xffff) + 1;
    else
        dma_length = DEV_DMAC->DMA_CHN[channel].STA & 0xffff;

    return dma_length;
}


void hal_uart_isr(int32_t uart_port)
{
    uint32_t res_pd = 0;//PD
    uint32_t res_ie = 0;//IE

    if (uart_port == UART_0)
    {
        res_pd = DEV_UART0->PD;
        res_ie = DEV_UART0->IE;
    }
    else if (uart_port == UART_1)
    {
        res_pd = DEV_UART1->PD;
        res_ie = DEV_UART1->IE;
    }
    else if (uart_port == UART_2)
    {
        res_pd = DEV_UART2->PD;
        res_ie = DEV_UART2->IE;
    }

    if ((res_ie & DEV_UARTn_IE_RX_FIFO_THR) == DEV_UARTn_IE_RX_FIFO_THR)
    {
        // 常规接收中断
        if ((res_pd & DEV_UARTn_PD_RX_FIFO_THR) == DEV_UARTn_PD_RX_FIFO_THR)
        {
            if (uart_rx_cb[uart_port].callback != 0)
            {
                void *param = uart_rx_cb[uart_port].param;
                uint32_t flag = uart_rx_cb[uart_port].flag;
                uart_rx_cb[uart_port].callback(param, flag);
            }

            if (uart_port == UART_0)
            {
                DEV_UART0->PD = DEV_UARTn_PD_RX_FIFO_THR;
            }
            else if (uart_port == UART_1)
            {
                DEV_UART1->PD = DEV_UARTn_PD_RX_FIFO_THR;
            }
            else if (uart_port == UART_2)
            {
                DEV_UART2->PD = DEV_UARTn_PD_RX_FIFO_THR;
            }
        }
    }
    else if ((res_ie & DEV_UARTn_IE_TIME_OUT) == DEV_UARTn_IE_TIME_OUT)
    {
        // RX接收超时中断，用于DMA传输
        if ((res_pd & DEV_UARTn_PD_TIME_OUT) == DEV_UARTn_PD_TIME_OUT)
        {
            if (uart_port == UART_0)
            {
                DEV_UART0->PD = DEV_UARTn_IE_TIME_OUT;
            }
            else if (uart_port == UART_1)
            {
                DEV_UART1->PD = DEV_UARTn_IE_TIME_OUT;
            }
            else if (uart_port == UART_2)
            {
                DEV_UART2->PD = DEV_UARTn_IE_TIME_OUT;
            }

            if (uart_rx_cb[uart_port].callback != 0)
            {
                uart_dma_handle *dma_handle = uart_rx_cb[uart_port].dma_handle;
                void *param = uart_rx_cb[uart_port].param;
                uint32_t flag = uart_rx_cb[uart_port].flag;
                uint8_t dma_channel = dma_handle->dma_handle_rx.init.channel;
                uint32_t length = hal_get_rx_length_by_DMA(dma_channel);
                uart_rx_cb[uart_port].callback(param, ((dma_handle->dma_rx_num - length) << 8) | flag);
                dma_handle->dma_rx_num = length;
            }
        }
    }
}

void hal_uart0_send_bytes(uint8_t *addr, uint32_t length)
{
    for (uint32_t i = 0; i < length; i++)
    {
        hal_console_putc(*addr);
        addr++;
    }
}

__WEAK  void uart0_rxd_listen_handle(void)
{
  hal_uart_isr(UART_0);
  return;
}

void uart0_irq_handler()
{
	uart0_rxd_listen_handle();
}

void uart1_irq_handler()
{
    hal_uart_isr(UART_1);
}

void uart2_irq_handler()
{
    hal_uart_isr(UART_2);
}
