/**
 * \file    drv_uart.h
 * \brief   Uart driver header file
 *
 * \par     Copyright (c) 2018 UWE Technologies Corp., Ltd. All Rights Reserved.
 * \author  James
 * \date    2018-03-05
 * \version 
 * 
 * \history 
 *  Date        Note
 *  2018-03-05  Original Creation
 * 
 */
 
#ifndef __DRV_UART_H_
#define __DRV_UART_H_


#include "types.h"
#include "drv_reg_intf.h"
#include "reg_def_uart.h"

#pragma pack(1)


#define UART_RX_FIFO_SIZE           (16)

/** DRV UART index */
typedef enum DRV_UART_ID_e
{
    DRV_UART_ID_0,  ///< UART 0 
    DRV_UART_ID_1,  ///< UART 1 
    DRV_UART_ID_MAX,  ///< UART ID maximal
} DRV_UART_ID_t;


/** DRV UART data bits enum */
typedef enum DRV_UART_DATA_BITS_e
{
    DRV_UART_DATA_BITS_5,  ///< 5 bits
    DRV_UART_DATA_BITS_6,  ///< 6 bits
    DRV_UART_DATA_BITS_7,  ///< 7 bits
    DRV_UART_DATA_BITS_8,  ///< 8 bits
} DRV_UART_DATA_BITS_t;

/* Define the UART data type that will be queued. */
typedef struct UART_RX_DATA_s
{
	u8_t ucId:2;
	u8_t ucLength:6;
	u8_t ucData[ UART_RX_FIFO_SIZE ];
} UART_RX_DATA_t;

/** UART RX Queue length 3 */
#define UART_RX_QUEUE_LENGTH        (3)
/** UART RX Queue item size 17 bytes, Length(1Byte) + Data(16Bytes) */
#define UART_RX_QUEUE_ITEM_SIZE     sizeof( UART_RX_DATA_t )

/** \name  UART baudrate definition
 * \{ 
 */
#define DRV_UART_B1200             1200       ///< 1200  baudrate
#define DRV_UART_B2400             2400       ///< 2400  baudrate
#define DRV_UART_B4800             4800       ///< 4800  baudrate
#define DRV_UART_B9600             9600       ///< 9600  baudrate
#define DRV_UART_B14400            14400      ///< 14400 baudrate
#define DRV_UART_B19200            19200      ///< 19200 baudrate
#define DRV_UART_B38400            38400      ///< 38400 baudrate
#define DRV_UART_B57600            57600      ///< 57600 baudrate
#define DRV_UART_B115200           115200     ///< 115200 baudrate
#define DRV_UART_B230400           230400     ///< 230400 baudrate
#define DRV_UART_B380400           380400     ///< 380400 baudrate
#define DRV_UART_B460800           460800     ///< 460800 baudrate
#define DRV_UART_B921600           921600     ///< 921600 baudrate
#define DRV_UART_MAX_BAUDRATE      DRV_UART_B921600     ///< Maximal baudrate
#define DRV_UART_DEF_BAUDRATE      DRV_UART_B460800     ///< Default baudrate
/** \}*/


extern u32_t g_uart_addr_offset_map[DRV_UART_ID_MAX];

extern char g_uart_char_LF;
extern char g_uart_char_CR;

// \n
#define UART_LF                 g_uart_char_LF
// \r
#define UART_CR                 g_uart_char_CR


#pragma pack()

/**
 * Uart initialization
 *
 * \param uart_id   The UART ID
 * \see
 */
void drv_uart_common_init(DRV_UART_ID_t uart_id);


/**
 * Uart FIFO clear
 *
 * \param uart_id   The UART ID
 * \see
 */
void drv_uart_common_fifo_clear(DRV_UART_ID_t uart_id);

/**
 * Configure default uart ID
 *
 * \param uart_id   The UART ID
 * \see
 */
void drv_uart_default_set(DRV_UART_ID_t uart_id);

/**
 * Get default uart ID
 *
 * \return uart_id   The UART ID
 */
DRV_UART_ID_t drv_uart_default_get();

/**
 * Get second uart ID
 *
 * \return uart_id   The UART ID
 */
DRV_UART_ID_t drv_uart_second_get();


/** \brief Get UART interrupt state
 *
 * \param uart_id   The UART ID
 * \return          0:disabled, 1:enabled
 */
#define drv_uart_common_intr_get(uart_id) (drv_reg_field_get2(UART_IER_REG+g_uart_addr_offset_map[uart_id],UART_IER_REG_ERBFI,UART_IER_REG_ERBFI_FLDSET))

/** \brief Configure interrupt state
 *
 * \param uart_id   The UART ID
 * \param flg       0:disable interrupt, 1:enable interrupt
 */
#define drv_uart_common_intr_set(uart_id,flg) \
    do { \
        DRV_REG_SET(UART_IER_REG+g_uart_addr_offset_map[uart_id],((flg) & UART_IER_REG_ERBFI_FLDSET)); \
    } while(0)


/** \brief Configure baud rate
 *
 * \param uart_id   The UART ID
 * \param baudrate  Baud rate
 */
void drv_uart_common_baud_rate_set(DRV_UART_ID_t uart_id, u32_t baudrate);

/** \brief Get baud rate
 *
 * \param uart_id   The UART ID
 * \return          Baud rate
 */
u32_t drv_uart_common_baud_rate_get(DRV_UART_ID_t uart_id);

/** \brief Configure flow control
 *
 * \param uart_id   The UART ID
 * \param flg       0:disable flow control, 1:enable flow control
 */
#define drv_uart_common_flowctrl_set(uart_id,flg) \
    do { \
        drv_reg_field_set(UART_LCR_REG+g_uart_addr_offset_map[uart_id],UART_LCR_REG_FCTL_EN,UART_LCR_REG_FCTL_EN_WTH,flg); \
    } while(0)

/** \brief Get flow control
 *
 * \param uart_id   The UART ID
 * \return          0:disable flow control, 1:enable flow control
 */
#define drv_uart_common_flowctrl_get(uart_id) \
    (drv_reg_field_get(UART_LCR_REG+g_uart_addr_offset_map[uart_id],UART_LCR_REG_FCTL_EN,UART_LCR_REG_FCTL_EN_WTH))

/** \brief Configure data length
 *
 * \param uart_id   The UART ID
 * \param len       The data length, see DRV_UART_DATA_BITS_t
 */
#define drv_uart_common_data_length_set(uart_id,len) \
    do { \
        drv_reg_field_set(UART_LCR_REG+g_uart_addr_offset_map[uart_id],UART_LCR_REG_DLS,UART_LCR_REG_DLS_WTH,len); \
    } while(0)

/** \brief Get data length
 *
 * \param uart_id   The UART ID
 * \return          The data length, see DRV_UART_DATA_BITS_t
 */
#define drv_uart_common_data_length_get(uart_id) \
    (drv_reg_field_get(UART_LCR_REG+g_uart_addr_offset_map[uart_id],UART_LCR_REG_DLS,UART_LCR_REG_DLS_WTH))

/** \brief Configure parity check
 *
 * \param uart_id   The UART ID
 * \param en        0: disabled parity check, 1: enabled parity check
 * \param even      0: odd parity check, 1: even parity check
 */
#define drv_uart_common_parity_check_set(uart_id,en,even) \
    do { \
        drv_reg_field_set(UART_LCR_REG+g_uart_addr_offset_map[uart_id],UART_LCR_REG_EPS,UART_LCR_REG_EPS_WTH,even); \
        drv_reg_field_set(UART_LCR_REG+g_uart_addr_offset_map[uart_id],UART_LCR_REG_PEN,UART_LCR_REG_PEN_WTH,en); \
    } while(0)

/** \brief Get parity check flag
 *
 * \param uart_id   The UART ID
 * \return          0: disabled parity check, 1: enabled parity check
 */
#define drv_uart_common_parity_check_get(uart_id) \
    (drv_reg_field_get(UART_LCR_REG+g_uart_addr_offset_map[uart_id],UART_LCR_REG_PEN,UART_LCR_REG_PEN_WTH))

/** \brief Get parity check selection
 *
 * \param uart_id   The UART ID
 * \return          1 : even parity check; 0 : odd parity check.
 */
#define drv_uart_common_parity_selection_get(uart_id) \
    (drv_reg_field_get(UART_LCR_REG+g_uart_addr_offset_map[uart_id],UART_LCR_REG_EPS,UART_LCR_REG_EPS_WTH))


/** \brief Configure stop bit
 *
 * \param uart_id   The UART ID
 * \param two_bits  0 : one stop bit, 1 : two stop bits.
 */
#define drv_uart_common_stop_bit_set(uart_id,two_bits) \
    do { \
        drv_reg_field_set(UART_LCR_REG+g_uart_addr_offset_map[uart_id],UART_LCR_REG_STOP,UART_LCR_REG_STOP_WTH,two_bits); \
    } while(0)

/** \brief Get stop bit flag
 *
 * \param uart_id   The UART ID
 * \return          0 : one stop bit, 1 : two stop bits.
 */
#define drv_uart_common_stop_bit_get(uart_id) \
    (drv_reg_field_get(UART_LCR_REG+g_uart_addr_offset_map[uart_id],UART_LCR_REG_STOP,UART_LCR_REG_STOP_WTH))


/** \brief Check if the receiving data is available
 *
 * \param uart_id   The UART ID
 * \return          FALSE :No data available, TRUE : data available.
 */
#define drv_uart_common_rx_available(uart_id) \
    (DRV_REG_GET(UART_LSR_REG+g_uart_addr_offset_map[uart_id]) & UART_LSR_REG_DR_FLDSET)

/**
 * Uart read a byte
 *
 *
 * \param uart_id   The UART ID
 * \param c         The character pointer to read
 * \return          a character in unsigned char type
 *
 * \see
 */
u8_t drv_uart_common_getbyte(DRV_UART_ID_t uart_id, u8_t *c);


/**
 * Uart read wait until get a character 
 * \n
 *
 * \param uart_id   The UART ID
 * \return          a character in unsigned char type
 * \n
 * \see
 */
u8_t drv_uart_common_waitbyte(DRV_UART_ID_t uart_id);

/**
 * Uart write a character
 * \n
 *
 * \param uart_id   The UART ID
 * \param c         The character to write
 * \n
 * \see
 */
void drv_uart_common_putbyte(DRV_UART_ID_t uart_id, u8_t c);

/**
 * Uart writes string
 * \n
 *
 * \param uart_id   The UART ID
 * \param ptr       string to write
 * \n
 * \see
 */
void drv_uart_common_putstr(DRV_UART_ID_t uart_id, const char *ptr);

/** \brief Uart write char
 *
 * \param uart_id   The UART ID
 * \param c         The character to write
 * \return          TRUE or FALSE
 */
int drv_uart_common_putchar (DRV_UART_ID_t uart_id, char c);

/**
 * Uart writes string followed by a newline character ('\n')
 * \n
 *
 * \param uart_id   The UART ID
 * \param ptr       string to write
 * \n
 * \see
 */
void drv_uart_customize_init(DRV_UART_ID_t uart_id,u32_t baud_set);

void drv_uart_common_puts(DRV_UART_ID_t uart_id, const char *ptr);

void drv_uart_common_puthex64(DRV_UART_ID_t uart_id, u64_t val);
void drv_uart_common_puthex32(DRV_UART_ID_t uart_id, u32_t val);
void drv_uart_common_puthex16(DRV_UART_ID_t uart_id, u16_t val);
void drv_uart_common_puthex8(DRV_UART_ID_t uart_id, u8_t val);
void drv_uart_common_puthex4(DRV_UART_ID_t uart_id, u8_t val);
void drv_uart_common_putdec(DRV_UART_ID_t uart_id, u32_t v);
void drv_uart_common_putdouble(DRV_UART_ID_t uart_id, double v);
void drv_uart_common_puthex(DRV_UART_ID_t uart_id, u8_t *pval, int len, bool_t with_addr);


#define drv_uart_init()             drv_uart_common_init(drv_uart_default_get())
#define drv_uart_getbyte(pchar)     drv_uart_common_getbyte(drv_uart_default_get(),pchar)
#define drv_uart_waitbyte()         drv_uart_common_waitbyte(drv_uart_default_get())
#define drv_uart_putbyte(chr)       drv_uart_common_putbyte(drv_uart_default_get(),chr)
#define drv_uart_putstr(ptr)        drv_uart_common_putstr(drv_uart_default_get(),ptr)
#define drv_uart_putchar(chr)       drv_uart_common_putchar(drv_uart_default_get(),chr)
#define drv_uart_puts(ptr)          drv_uart_common_puts(drv_uart_default_get(),ptr)

#define drv_uart1_init()            drv_uart_common_init(drv_uart_second_get())
#define drv_uart1_getbyte(ptrchar)  drv_uart_common_getbyte(drv_uart_second_get(),ptrchar)
#define drv_uart1_waitbyte()        drv_uart_common_waitbyte(drv_uart_second_get())
#define drv_uart1_putbyte(chr)      drv_uart_common_putbyte(drv_uart_second_get(),chr)
#define drv_uart1_putstr(ptr)       drv_uart_common_putstr(drv_uart_second_get(),ptr)
#define drv_uart1_putchar(chr)      drv_uart_common_putchar(drv_uart_second_get(),chr)
#define drv_uart1_puts(ptr)         drv_uart_common_puts(drv_uart_second_get(),ptr)

#define drv_uart_puthex64(val)                  drv_uart_common_puthex64(drv_uart_default_get(),val)
#define drv_uart_puthex32(val)                  drv_uart_common_puthex32(drv_uart_default_get(),val)
#define drv_uart_puthex16(val)                  drv_uart_common_puthex16(drv_uart_default_get(),val)
#define drv_uart_puthex8(val)                   drv_uart_common_puthex8(drv_uart_default_get(),val)
#define drv_uart_puthex4(val)                   drv_uart_common_puthex4(drv_uart_default_get(),val)
#define drv_uart_putdec(v)                      drv_uart_common_putdec(drv_uart_default_get(),v)
#define drv_uart_putdouble(v)                   drv_uart_common_putdouble(drv_uart_default_get(),v)
#define drv_uart_puthex(pval,len,with_addr)     drv_uart_common_puthex(drv_uart_default_get(),pval,len,with_addr)

#define drv_uart1_puthex64(val)                 drv_uart_common_puthex64(drv_uart_second_get(),val)
#define drv_uart1_puthex32(val)                 drv_uart_common_puthex32(drv_uart_second_get(),val)
#define drv_uart1_puthex16(val)                 drv_uart_common_puthex16(drv_uart_second_get(),val)
#define drv_uart1_puthex8(val)                  drv_uart_common_puthex8(drv_uart_second_get(),val)
#define drv_uart1_puthex4(val)                  drv_uart_common_puthex4(drv_uart_second_get(),val)
#define drv_uart1_putdec(v)                     drv_uart_common_putdec(drv_uart_second_get(),v)
#define drv_uart1_putdouble(v)                  drv_uart_common_putdouble(drv_uart_second_get(),v)
#define drv_uart1_puthex(pval,len,with_addr)    drv_uart_common_puthex(drv_uart_second_get(),pval,len,with_addr)


#if UART1_DMA_ENABLED
/** \brief Enable UART1 DMA receiving mode
 *
 * \param en        1: enable, 0: disable
 */
void drv_uart1_dma_en_set(bool_t en);
#else
#define drv_uart1_dma_en_set(flg)
#endif /* UART1_DMA_ENABLED */


#endif /* #ifndef __DRV_UART_H_ */

