/*
 * Copyright 2020-2022 Yuntu Microelectronics co.,ltd
 * All rights reserved.
 *
 * YUNTU Confidential. This software is owned or controlled by YUNTU and may
 * only be used strictly in accordance with the applicable license terms. By expressly
 * accepting such terms or by downloading, installing, activating and/or otherwise
 * using the software, you are agreeing that you have read, and that you agree to
 * comply with and are bound by, such license terms. If you do not agree to be
 * bound by the applicable license terms, then you may not retain, install,
 * activate or otherwise use the software. The production use license in
 * Section 2.3 is expressly granted for this software.
 */

 /*!
 * @file uart_hw_access.h
 *
 */

#ifndef UART_HW_ACCESS_H__
#define UART_HW_ACCESS_H__

#include "uart_driver.h"


/*******************************************************************************
 * Definitions
 ******************************************************************************/
#define UART_SHIFT          (16U)
#define UART_BAUD_REG_ID    (1U)
#define UART_CTRL0_REG_ID   (2U)
#define UART_CTRL1_REG_ID   (3U)
#define UART_STATUTS_REG_ID (4U)
#define UART_INTE_REG_ID      (5U)
#define UART_MATCH_REG_ID   (6U)
#define UART_DATA_REG_ID    (7U)
#define UART_TXFIFO_REG_ID  (8U)
#define UART_RXFIFO_REG_ID  (9U)

/*! @brief UART wakeup from standby method constants
 */
typedef enum
{
    UART_IDLE_LINE_WAKE = 0x0U, /*!< Idle-line wakes the UART receiver from standby. */
    UART_ADDR_MARK_WAKE = 0x1U  /*!< Addr-mark wakes UART receiver from standby.*/
} uart_wakeup_method_t;

/*!
 * @brief UART break character length settings for transmit/detect.
 *
 * The actual maximum bit times may vary depending on the UART instance.
 */
typedef enum
{
    UART_BREAK_CHAR_10_BIT_MINIMUM = 0x0U, /*!< UART break char length 10 bit times (if M = 0, SBNS = 0)
                                                  or 11 (if M = 1, SBNS = 0 or M = 0, SBNS = 1) or 12 (if M = 1,
                                                  SBNS = 1 or M10 = 1, SNBS = 0) or 13 (if M10 = 1, SNBS = 1) */
    UART_BREAK_CHAR_13_BIT_MINIMUM = 0x1U  /*!< UART break char length 13 bit times (if M = 0, SBNS = 0
                                                  or M10 = 0, SBNS = 1) or 14 (if M = 1, SBNS = 0 or M = 1,
                                                  SBNS = 1) or 15 (if M10 = 1, SBNS = 1 or M10 = 1, SNBS = 0) */
} uart_break_char_length_t;

/*!
 * @brief UART status flags.
 *
 * This provides constants for the UART status flags for use in the UART functions.
 */
typedef enum
{
    UART_TX_DATA_REG_EMPTY          = UART_INTF_TXIF_MASK,       /*!< Tx data register empty flag, sets when Tx buffer is empty */
    UART_TX_COMPLETE                = UART_INTF_TCIF_MASK,       /*!< Transmission complete flag, sets when transmission activity complete */
    UART_RX_DATA_REG_FULL           = UART_INTF_RXIF_MASK,       /*!< Rx data register full flag, sets when the receive data buffer is full */
    UART_IDLE_LINE_DETECT           = UART_INTF_IDLEIF_MASK,     /*!< Idle line detect flag, sets when idle line detected */
    UART_RX_OVERRUN                 = UART_INTF_OVRIF_MASK,      /*!< Rx Overrun sets if new data is received before data is read */
    UART_NOISE_DETECT               = UART_INTF_NOZIF_MASK,      /*!< Rx takes 3 samples of each received bit. If these differ, the flag sets */
    UART_FRAME_ERR                  = UART_INTF_FEIF_MASK,       /*!< Frame error flag, sets if logic 0 was detected where stop bit expected */
    UART_PARITY_ERR                 = UART_INTF_PARIF_MASK,      /*!< If parity enabled, sets upon parity error detection */
    UART_LIN_BREAK_DETECT           = UART_INTF_LBKDIF_MASK,     /*!< LIN break detect interrupt flag, sets when LIN break char detected */
    UART_RX_ACTIVE_EDGE_DETECT      = UART_INTF_RXEDGEIF_MASK,   /*!< Rx pin active edge interrupt flag, sets when active edge detected */
#if FEATURE_UART_HAS_ADDRESS_MATCHING
    UART_MATCH_ADDR_ONE             = UART_INTF_MATIF_MASK,      /*!< Address one match flag */
#endif
#if FEATURE_UART_FIFO_SIZE > 0U
    UART_FIFO_TX_OF                 = UART_INTF_TFEIF_MASK,      /*!< Transmitter FIFO buffer overflow */
    UART_FIFO_RX_UF                 = UART_INTF_RFEIF_MASK,      /*!< Receiver FIFO buffer underflow */
#endif
} uart_status_flag_t;

/*! @brief UART interrupt configuration structure, default settings are 0 (disabled) */
typedef enum
{
    UART_INT_LIN_BREAK_DETECT  = UART_INTE_LBKDIE_MASK,               /*!< LIN break detect. */
    UART_INT_RX_ACTIVE_EDGE    = UART_INTE_RXEDGEIE_MASK,             /*!< RX Active Edge. */
    UART_INT_TX_DATA_REG_EMPTY = UART_INTE_TXIE_MASK,                 /*!< Transmit data register empty. */
    UART_INT_TX_COMPLETE       = UART_INTE_TCIE_MASK,                 /*!< Transmission complete. */
    UART_INT_RX_DATA_REG_FULL  = UART_INTE_RXIE_MASK,                 /*!< Receiver data register full. */
    UART_INT_IDLE_LINE         = UART_INTE_IDLEIE_MASK,               /*!< Idle line. */
    UART_INT_RX_OVERRUN        = UART_INTE_OVRIE_MASK,                /*!< Receiver Overrun. */
    UART_INT_NOISE_ERR_FLAG    = UART_INTE_NOZIE_MASK,                /*!< Noise error flag. */
    UART_INT_FRAME_ERR_FLAG    = UART_INTE_FEIE_MASK,                 /*!< Framing error flag. */
    UART_INT_PARITY_ERR_FLAG   = UART_INTE_PARIE_MASK,                /*!< Parity error flag. */
#if FEATURE_UART_HAS_ADDRESS_MATCHING
    UART_INT_MATCH_ADDR_ONE    = UART_INTE_MATIE_MASK,                /*!< Match address one flag. */
#endif
} uart_interrupt_t;


/*******************************************************************************
 * API
 ******************************************************************************/

#if defined(__cplusplus)
extern "C" {
#endif

/*!
 * @name UART Common Configurations
 * @{
 */

/*!
 * @brief Initializes the UART controller.
 *
 * This function Initializes the UART controller to known state.
 *
 *
 * @param base UART base pointer.
 */
void UART_Init(UART_Type * base);

/*!
 * @brief Enable/Disable the UART transmitter.
 *
 * This function enables or disables the UART transmitter, based on the
 * parameter received.
 *
 *
 * @param base UART base pointer.
 * @param enable Enable(true) or disable(false) transmitter.
 */
static inline void UART_SetTransmitterCmd(UART_Type * base, bool enable)
{
    base->CTRL0 = (base->CTRL0 & ~UART_CTRL0_TXEN_MASK) | ((enable ? 1UL : 0UL) << UART_CTRL0_TXEN_SHIFT);
    /* Wait for the register write operation to complete */
    while((bool)((base->CTRL0 & UART_CTRL0_TXEN_MASK) != 0U) != enable) {}
}

/*!
 * @brief Enable/Disable the UART receiver.
 *
 * This function enables or disables the UART receiver, based on the
 * parameter received.
 *
 *
 * @param base UART base pointer
 * @param enable Enable(true) or disable(false) receiver.
 */
static inline void UART_SetReceiverCmd(UART_Type * base, bool enable)
{
    base->CTRL0 = (base->CTRL0 & ~UART_CTRL0_RXEN_MASK) | ((enable ? 1UL : 0UL) << UART_CTRL0_RXEN_SHIFT);
    /* Wait for the register write operation to complete */
    while((bool)((base->CTRL0 & UART_CTRL0_RXEN_MASK) != 0U) != enable) {}
}

/*!
 * @brief Sets the UART baud rate modulo divisor.
 *
 * This function sets the UART baud rate modulo divisor.
 *
 *
 * @param base UART base pointer.
 * @param baudRateDivisor The baud rate modulo division "SBR"
 */
static inline void UART_SetBaudRateDivisor(UART_Type * base, uint32_t baudRateDivisor)
{
    DEV_ASSERT((baudRateDivisor <= 0x1FFFU) && (baudRateDivisor >= 1U));
    uint32_t baudRegValTemp;

    baudRegValTemp = base->BAUD;
    baudRegValTemp &= ~(UART_BAUD_DIV_MASK);
    /* Removed the shift operation as the SBR field position is zero; shifting with 0 violates MISRA */
    baudRegValTemp |= baudRateDivisor & UART_BAUD_DIV_MASK;
    base->BAUD = baudRegValTemp;
}

/*!
 * @brief Gets the UART baud rate modulo divisor.
 *
 * This function gets the UART baud rate modulo divisor.
 *
 *
 * @param base UART base pointer.
 * @return The baud rate modulo division "SBR"
 */
static inline uint16_t UART_GetBaudRateDivisor(const UART_Type * base)
{
    return ((uint16_t)((base->BAUD & UART_BAUD_DIV_MASK) >> UART_BAUD_DIV_SHIFT));
}

#if FEATURE_UART_HAS_BAUD_RATE_OVER_SAMPLING_SUPPORT
/*!
 * @brief Sets the UART baud rate oversampling ratio
 *
 * This function sets the UART baud rate oversampling ratio.
 * (Note: Feature available on select UART instances used together with baud rate programming)
 * The oversampling ratio should be set between 4x (00011) and 32x (11111). Writing
 * an invalid oversampling ratio results in an error and is set to a default
 * 16x (01111) oversampling ratio.
 * Disable the transmitter/receiver before calling this function.
 *
 *
 * @param base UART base pointer.
 * @param overSamplingRatio The oversampling ratio "OSR"
 */
static inline void UART_SetOversamplingRatio(UART_Type * base, uint32_t overSamplingRatio)
{
    DEV_ASSERT(overSamplingRatio <= 0x1FU);
    uint32_t baudRegValTemp;

    baudRegValTemp = base->BAUD;
    baudRegValTemp &= ~(UART_BAUD_OSRVAL_MASK);
    baudRegValTemp |= UART_BAUD_OSRVAL(overSamplingRatio);
    base->BAUD = baudRegValTemp;
}

/*!
 * @brief Gets the UART baud rate oversampling ratio
 *
 * This function gets the UART baud rate oversampling ratio.
 * (Note: Feature available on select UART instances used together with baud rate programming)
 *
 *
 * @param base UART base pointer.
 * @return The oversampling ratio "OSR"
 */
static inline uint8_t UART_GetOversamplingRatio(const UART_Type * base)
{
    return ((uint8_t)((base->BAUD & UART_BAUD_OSRVAL_MASK) >> UART_BAUD_OSRVAL_SHIFT));
}
#endif

#if FEATURE_UART_HAS_BOTH_EDGE_SAMPLING_SUPPORT
/*!
 * @brief Configures the UART baud rate both edge sampling
 *
 * This function configures the UART baud rate both edge sampling.
 * (Note: Feature available on select UART instances used with baud rate programming)
 * When enabled, the received data is sampled on both edges of the baud rate clock.
 * This must be set when the oversampling ratio is between 4x and 7x.
 * This function should only be called when the receiver is disabled.
 *
 *
 * @param base UART base pointer.
 * @param enable   Enable (1) or Disable (0) Both Edge Sampling
 */
static inline void UART_EnableBothEdgeSamplingCmd(UART_Type * base)
{
    base->CTRL1 |= UART_CTRL1_BOTHEDGE_MASK;
}
#endif

/*!
 * @brief Configures the number of bits per character in the UART controller.
 *
 * This function configures the number of bits per character in the UART controller.
 * In some UART instances, the user should disable the transmitter/receiver
 * before calling this function.
 * Generally, this may be applied to all UARTs to ensure safe operation.
 *
 * @param base UART base pointer.
 * @param bitCountPerChar  Number of bits per char (8, 9, or 10, depending on the UART instance)
 * @param parity  Specifies whether parity bit is enabled
 */
void UART_SetBitCountPerChar(UART_Type * base, uart_bit_count_per_char_t bitCountPerChar, bool parity);

/*!
 * @brief Configures parity mode in the UART controller.
 *
 * This function configures parity mode in the UART controller.
 * In some UART instances, the user should disable the transmitter/receiver
 * before calling this function.
 * Generally, this may be applied to all UARTs to ensure safe operation.
 *
 * @param base UART base pointer.
 * @param parityModeType  Parity mode (enabled, disable, odd, even - see parity_mode_t struct)
 */
void UART_SetParityMode(UART_Type * base, uart_parity_mode_t parityModeType);

/*!
 * @brief Configures the number of stop bits in the UART controller.
 *
 * This function configures the number of stop bits in the UART controller.
 * In some UART instances, the user should disable the transmitter/receiver
 * before calling this function.
 * Generally, this may be applied to all UARTs to ensure safe operation.
 *
 * @param base UART base pointer.
 * @param stopBitCount Number of stop bits (1 or 2 - see uart_stop_bit_count_t struct)
 */
static inline void UART_SetStopBitCount(UART_Type * base, uart_stop_bit_count_t stopBitCount)
{
    base->CTRL1 = (base->CTRL1 & ~UART_CTRL1_STOPSZ_MASK) | ((uint32_t)stopBitCount << UART_CTRL1_STOPSZ_SHIFT);
}

/*@}*/

/*!
 * @name UART Interrupts and DMA
 * @{
 */

/*!
 * @brief Configures the UART module interrupts.
 *
 * This function configures the UART module interrupts to enable/disable various interrupt sources.
 *
 *
 * @param   base UART module base pointer.
 * @param   intSrc UART interrupt configuration data.
 * @param   enable   true: enable, false: disable.
 */
void UART_SetIntMode(UART_Type * base, uart_interrupt_t intSrc, bool enable);

/*!
 * @brief Returns UART module interrupts state.
 *
 * This function returns whether a certain UART module interrupt is enabled or disabled.
 *
 *
 * @param   base UART module base pointer.
 * @param   intSrc UART interrupt configuration data.
 * @return  true: enable, false: disable.
 */
bool UART_GetIntMode(const UART_Type * base, uart_interrupt_t intSrc);

#if FEATURE_UART_HAS_DMA_ENABLE
/*!
 * @brief Configures DMA requests.
 *
 * This function configures DMA requests for UART Transmitter.
 *
 *
 * @param base UART base pointer
 * @param enable Transmit DMA request configuration (enable:1 /disable: 0)
 */
static inline void UART_SetTxDmaCmd(UART_Type * base, bool enable)
{
    base->CTRL0 |= UART_CTRL0_TXDMAEN(enable);
}

/*!
 * @brief Configures DMA requests.
 *
 * This function configures DMA requests for UART Receiver.
 *
 *
 * @param base UART base pointer
 * @param enable Receive DMA request configuration (enable: 1/disable: 0)
 */
static inline void UART_SetRxDmaCmd(UART_Type * base, bool enable)
{
    base->CTRL0 |= UART_CTRL0_RXDMAEN(enable);
}
#endif

/*@}*/

/*!
 * @name UART Transfer Functions
 * @{
 */

/*!
 * @brief Sends the UART 8-bit character.
 *
 * This functions sends an 8-bit character.
 *
 *
 * @param base UART Instance
 * @param data     data to send (8-bit)
 */
static inline void UART_Putchar(UART_Type * base, uint8_t data)
{
    //volatile uint8_t * dataRegBytes = (volatile uint8_t *)(&(base->DATA));
    //dataRegBytes[0] = data;
    base->DATA = data;
}

/*!
 * @brief Sends the UART 9-bit character.
 *
 * This functions sends a 9-bit character.
 *
 *
 * @param base UART Instance
 * @param data     data to send (9-bit)
 */
void UART_Putchar9(UART_Type * base, uint16_t data);

/*!
 * @brief Sends the UART 10-bit character (Note: Feature available on select UART instances).
 *
 * This functions sends a 10-bit character.
 *
 *
 * @param base UART Instance
 * @param data   data to send (10-bit)
 */
void UART_Putchar10(UART_Type * base, uint16_t data);

/*!
 * @brief Gets the UART 8-bit character.
 *
 * This functions receives an 8-bit character.
 *
 *
 * @param base UART base pointer
 * @param readData Data read from receive (8-bit)
 */
static inline void UART_Getchar(const UART_Type * base, uint8_t *readData)
{
    DEV_ASSERT(readData != NULL);

    *readData = (uint8_t)base->DATA;
}

/*!
 * @brief Gets the UART 9-bit character.
 *
 * This functions receives a 9-bit character.
 *
 *
 * @param base UART base pointer
 * @param readData Data read from receive (9-bit)
 */
void UART_Getchar9(const UART_Type * base, uint16_t *readData);

/*!
 * @brief Gets the UART 10-bit character.
 *
 * This functions receives a 10-bit character.
 *
 *
 * @param base UART base pointer
 * @param readData Data read from receive (10-bit)
 */
void UART_Getchar10(const UART_Type * base, uint16_t *readData);

/*@}*/

/*!
 * @name UART Status Flags
 * @{
 */

/*!
 * @brief  UART get status flag
 *
 * This function returns the state of a status flag.
 *
 *
 * @param base UART base pointer
 * @param statusFlag  The status flag to query
 * @return Whether the current status flag is set(true) or not(false).
 */
bool UART_GetStatusFlag(const UART_Type * base, uart_status_flag_t statusFlag);

/*!
 * @brief UART clears an individual status flag.
 *
 * This function clears an individual status flag (see uart_status_flag_t for list of status bits).
 *
 *
 * @param base UART base pointer
 * @param statusFlag  Desired UART status flag to clear
 * @return STATUS_SUCCESS if successful or STATUS_ERROR if an error occured
 */
status_t UART_ClearStatusFlag(UART_Type * base, uart_status_flag_t statusFlag);

/*@}*/

/*!
 * @name UART Special Feature Configurations
 * @{
 */

/*!
 * @brief Enable or disable the UART error interrupts.
 *
 * This function configures the error interrupts (parity, noise, overrun, framing).
 *
 *
 * @param base UART base pointer
 * @param enable true - enable, false - disable error interrupts
 */
void UART_SetErrorInterrupts(UART_Type * base, bool enable);

/*!
 * @brief  Clears the error flags treated by the driver
 *
 * This function clears the error flags treated by the driver.
 * *
 * @param base UART base pointer
 */
static inline void UART_DRV_ClearErrorFlags(UART_Type * base)
{
    uint32_t mask = UART_INTF_OVRIF_MASK | \
                    UART_INTF_NOZIF_MASK | \
                    UART_INTF_FEIF_MASK  | \
                    UART_INTF_IDLEIF_MASK| \
                    UART_INTF_PARIF_MASK;

    base->INTF = (base->INTF & (~FEATURE_UART_INTF_REG_FLAGS_MASK)) | mask;
}
/*!
 * @brief  Set line idle detect size
 *
 * This function set line idle detect size
 * *
 * @param base UART base pointer
 */
static inline void UART_SetLineIdleSize(UART_Type * base, uint8_t size)
{
    base->CTRL1 &= ~(UART_CTRL1_IDLESZ_MASK);
    base->CTRL1 |= UART_CTRL1_IDLESZ(size);
}

/*@}*/

#if defined(__cplusplus)
}
#endif

#endif /* UART_HW_ACCESS_H__ */
/*******************************************************************************
 * EOF
 ******************************************************************************/
