#include "gw3323_hsuart.h"


/**
  * @brief  Initializes the hsuart peripheral according to the specified
  *         parameters in the hsuart_init_struct.
  * @param  hsuart_init_struct: pointer to a hsuart_init_typedef structure that
  *         contains the configuration information for the specified HSUART peripheral.
  * @retval None
  */
void hsuart_init(hsuart_init_typedef* hsuart_init_struct)
{
    uint32_t tmp_reg, sys_clk_val, baud_reg;

    tmp_reg = HSUART->con;
    //---------- hsuart Tx configuration ----------//
    tmp_reg &= ~(uint32_t)(HSUT0_CON_SPBITSEL_NS | HSUT0_CON_TXBITSEL_NS | HSUT0_CON_TXTRSMODE);
    tmp_reg |= hsuart_init_struct->tx_stop_bit;
    tmp_reg |= hsuart_init_struct->tx_word_len;
    tmp_reg |= hsuart_init_struct->tx_mode;

    //---------- hsuart Rx configuration ----------//
    tmp_reg &= ~(HSUT0_CON_RXBITSEL_NS | HSUT0_CON_RXTRSMODE);
    tmp_reg |= hsuart_init_struct->rx_word_len;
    tmp_reg |= hsuart_init_struct->rx_mode;

    HSUART->con = tmp_reg;

    //---------- hsuart baud configuration ----------//
//    sys_clk_val = SYS_CLOCK_DEFINITION[get_cur_sysclk()];
    sys_clk_val = 24000000;
    baud_reg = (uint16_t)((sys_clk_val / hsuart_init_struct->baud) - 1);
    tmp_reg = (uint32_t)((baud_reg << 16) | baud_reg);

    HSUART->baud = tmp_reg;
}

/**
  * @brief  Enable or disable the specified HSUART peripheral.
  * @param  rec_tra_sel: select whether Rx or Tx needs to be configured.
  *         this parameter cna be: HSUT_TRANSMIT or HSUT_RECEIVE.
  * @param  state: the state of the HSUART peripheral.
  *         this parameter can be: ENABLE or DISABLE.
  * @retval None
  */
AT(.com_text.hsuart)
void hsuart_cmd(uint32_t rec_tra_sel, FUNCTIONAL_STATE state)
{
    if (state != DISABLE) {
        // Rx idle detection value is 0x0f by default.
        if ((rec_tra_sel & HSUT_RECEIVE) != RESET) {
            HSUART->tmr_cnt = 0x0f;
        }
        HSUART->con |= (uint32_t)rec_tra_sel;
        HSUART->con |= (HSUT0_CON_UPTXCFG | HSUT0_CON_UPRXCFG);
    } else {
        HSUART->con &= ~(uint32_t)rec_tra_sel;
    }
}

/**
  * @brief  Transmits data through the HSUART buf mode.
  * @param  data: the data to transmit.
  * @retval None
  */
AT(.com_text.hsuart)
void hsuart_send_data(uint16_t data)
{
    HSUART->data = (uint32_t)(data & 0x1ff);
}

/**
  * @brief  Return the received data lastly by the buf mode.
  * @retval The received data.
  */
AT(.com_text.hsuart)
uint16_t hsuart_receive_data(void)
{
    return (HSUART->fifo & 0xff);
}

/**
  * @brief  Enable or disable the specified HSUART interrupt.
  * @param  isr: Function to be executed for service interruption.
  * @param  pr: Priority of service interruption.
  * @param  hsuart_ie_bit: specifies the HSUART interrupt sources to be enable or disable.
  *         this parameter can be one of the following values:
  *             @arg HSUART_IT_RX: Receive single or n bytes data finish interrupt enable bit.
  *             @arg HSUART_IT_TX: Transmit single or n bytes data finish interrupt enable bit.
  * @param  state: the state of the HSUART peripheral.
  *         this parameter can be: ENABLE or DISABLE.
  * @retval None
  */
void hsuart_pic_config(isr_t isr, int pr, uint16_t hsuart_ie_bit, FUNCTIONAL_STATE state)
{
    if (state != DISABLE) {
        sys_irq_init(HSUART_DVP_IRQn, pr, isr);
        HSUART->con |= hsuart_ie_bit;
    } else {
        PICEN &= ~BIT(HSUART_DVP_IRQn);
        HSUART->con &= ~(uint32_t)hsuart_ie_bit;
    }
}

/**
  * @brief  Check the specified HSUART flag is set or not.
  * @param  hsuart_flag: specifies the flag to check.
  *         this parameter can be one of the following values:
  *             @arg HSUART_FLAG_RX: Receive single or n bytes data finish interrupt.
  *             @arg HSUART_FLAG_TX: Transmit single or n bytes data finish interrupt.
  *             @arg HSUART_FLAG_TMROV: Rx idle timer overflow interrupt.
  *             @arg HSUART_FLAG_RXOV: Rx loop mode buf overflow interrupt.
  * @retval The state of uart_flag (SET or RESET).
  */
AT(.com_text.hsuart)
FLAG_STATE hsuart_get_flag(uint16_t hsuart_flag)
{
    if ((HSUART->con & hsuart_flag) != RESET) {
        return SET;
    } else {
        return RESET;
    }
}

/**
  * @brief  Clear the HSUART's pending flag.
  * @param  hsuart_flag: specifies the flag to check.
  *         this parameter can be one of the following values:
  *             @arg HSUART_FLAG_RX: Receive single or n bytes data finish interrupt.
  *             @arg HSUART_FLAG_TX: Transmit single or n bytes data finish interrupt.
  *             @arg HSUART_FLAG_TMROV: Rx idle timer overflow interrupt.
  *             @arg HSUART_FLAG_RXOV: Rx loop mode buf overflow interrupt.
  * @retval None
  */
AT(.com_text.hsuart)
void hsuart_clear_flag(uint16_t hsuart_flag)
{
    HSUART->cpnd |= (uint32_t)hsuart_flag;
}

/**
  * @brief  Configure DMA for Tx or Rx.
  * @param  rec_tra_sel: Tx or Rx to configure.
  *         this parameter can be: (HSUT_TRANSMIT or HSUT_RECEIVE)
  * @param  addr: DMA start address.
  * @retval None
  */
void hsuart_dma_config(uint32_t rec_tra_sel, uint32_t addr)
{
    if (rec_tra_sel == HSUT_RECEIVE) {
        HSUART->rx_adr = addr;
        // By default, it supports receiving indefinite length data.
        HSUART->con |= HSUT0_CON_HSUTTMREN_NS;
    } else if (rec_tra_sel == HSUT_TRANSMIT) {
        HSUART->tx_adr = addr;
    }
}

/**
  * @brief  Configure Rx idle tmr up-limit value.
  * @param  t: value of the TMR_CNT.
  * @retval None
  */
void hsuart_rx_idle_config(uint32_t t)
{
    HSUART->tmr_cnt = (uint32_t)t;
}

/**
  * @brief  Start send or receive dma.
  * @param  rec_tra_sel: Tx or Rx to configure.
  *         this parameter can be: (HSUT_TRANSMIT or HSUT_RECEIVE)
  * @param  addr: DMA start address.
  * @param  len: DMA transmit len.
  * @retval None
  */
AT(.com_text.hsuart)
void hsuart_dma_start(uint32_t rec_tra_sel, uint32_t addr, uint16_t len)
{
    if (rec_tra_sel == HSUT_RECEIVE) {
        HSUART->rx_adr = addr;
        HSUART->rx_cnt = (uint32_t)len;
    } else if (rec_tra_sel == HSUT_TRANSMIT) {
        while(hsuart_get_flag(HSUART_FLAG_TX) == RESET);
        hsuart_clear_flag(HSUART_FLAG_TX);
        /*HSUT0TXCNT = 0;
        HSUT0TXADR = (uint32_t)SEND_BUF;
        HSUT0TXCNT = (uint32_t)len;*/
        HSUART->tx_cnt = 0;
        HSUART->tx_adr = addr;
        HSUART->tx_cnt = (uint32_t)len;

    }
}

/**
  * @brief  stop send or receive dma.
  * @param  rec_tra_sel: Tx or Rx to configure.
  *         this parameter can be: (HSUT_TRANSMIT or HSUT_RECEIVE)
  * @retval None
  */
AT(.com_text.hsuart)
void hsuart_dma_stop(uint32_t rec_tra_sel)
{
    if (rec_tra_sel == HSUT_RECEIVE) {
        HSUART->rx_cnt = 0;
    } else if (rec_tra_sel == HSUT_TRANSMIT) {
        HSUART->tx_cnt = 0;
    }
}
