Post Go back to editing

How to use ADI Files to config UART0 in ADuCM3029

Category: Choose a category
Product Number: ADZS-UCM3029EZLITE
Software Version: CrossCore 2.8.3 - ADuCM302x_DFP_3.2.0

Hi,
I'm trying to create an architecture using ADuCM3029 with CrossCore IDE and ADuCM302x_DFP_3.2.0 package.

I would like know, How I use the ADI Files to config a UART communication?

the following files are available in the package: adi_uart.c, adi_uart.h, adi_uart_def.h and adi_uart_config.h.

And adi_uart_def.h has a struct with all the settings and registers for UART0 created by Analog for this uC, but this struct is only available adi_uart.c. If you add adi_uart.h and adi_uart_def.h the compilation fails (/adi_uart_def.h:198:24: warning: 'uart_PendForBuffer' declared 'static' but never defined [-Wunused-function]). And if remove adi_uart_def.h this error occurs, error: dereferencing pointer to incomplete type 'struct _ADI_UART_DEVICE'.

Then I found the adi_uart_config.h file, where it has all registers settings and is used by adi_uart.c when using the adi_uart_Open() function to initialize the UART0 according to these parameters.

I would like to know if it is correct to change the adi_uart_config.h to parameterize UART0 when calling the adi_uart_Open() function?

Code:

#include <stddef.h>
#include <stdint.h>
#include <stdbool.h>

#include <ctype.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>

#include "adi_gpio.h"
#include "adi_uart.h"

///* Memory for the UART driver. */
//static uint8_t UartDeviceMem[ADI_UART_BIDIR_MEMORY_SIZE];

typedef struct _uart_config_t
{
struct gpio tx;
struct gpio rx;
uint32_t baudrate;
ADI_UART_TypeDef *eusart;
ADI_CLOCK_GATE clock_ref;
} uart_config_t;

static const uart_config_t uart =
{
.tx = {.port = ADI_GPIO_PORT0, .pin = 10, .mode = ADI_GPIO_IRQ_LOW_LEVEL},
.rx = {.port = ADI_GPIO_PORT0, .pin = 11, .mode = ADI_GPIO_IRQ_HIGH_LEVEL},
.baudrate = 115200,
.eusart = EUART0_HANDLER,
.clock_ref = ADI_CLOCK_GATE_PCLK
};

static void init_eusart(void)
{
// Enable EUART0 Clock
adi_pwr_EnableClock(uart.clock_ref, true);

// Initialize the EUART0 module
static ADI_UART_HANDLE init;

static ADI_UART_HANDLE init_result;

init->nBaudRate = uart.baudrate;

adi_uart_Open(0, ADI_UART_DIR_BIDIRECTION, init, ADI_UART_BIDIR_MEMORY_SIZE, &init_result);
}

/*! *****************************************************************************
 * @file:    adi_uart_def.h
 * @brief:   UART Device Driver definition for processor
 -----------------------------------------------------------------------------
Copyright (c) 2010-2018 Analog Devices, Inc.

All rights reserved.

Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
  - Redistributions of source code must retain the above copyright notice,
    this list of conditions and the following disclaimer.
  - Redistributions in binary form must reproduce the above copyright notice,
    this list of conditions and the following disclaimer in the documentation
    and/or other materials provided with the distribution.
  - Modified versions of the software must be conspicuously marked as such.
  - This software is licensed solely and exclusively for use with processors
    manufactured by or for Analog Devices, Inc.
  - This software may not be combined or merged with other code in any manner
    that would cause the software to become subject to terms and conditions
    which differ from those listed here.
  - Neither the name of Analog Devices, Inc. nor the names of its
    contributors may be used to endorse or promote products derived
    from this software without specific prior written permission.
  - The use of this software may or may not infringe the patent rights of one
    or more patent holders.  This license does not release you from the
    requirement that you obtain separate licenses from these patent holders
    to use this software.

THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-
INFRINGEMENT, TITLE, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL ANALOG DEVICES, INC. OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, PUNITIVE OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, DAMAGES ARISING OUT OF
CLAIMS OF INTELLECTUAL PROPERTY RIGHTS INFRINGEMENT; PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*****************************************************************************/
/*! \cond PRIVATE */
#ifndef DEF_UART_DEF_H
#define DEF_UART_DEF_H

/* Macro mapping from ADuCM4x50 to ADuCM302x */
#if defined(__ADUCM302x__)

#define INTR_UART0_EVT					INTR_UART_EVT
#define UART0_Int_Handler(void)			UART_Int_Handler(void)		
#define DMA_UART0_TX_Int_Handler(void)	DMA_UART_TX_Int_Handler(void)
#define DMA_UART0_RX_Int_Handler(void)	DMA_UART_RX_Int_Handler(void)

#endif /* __ADUCM302x__ */

/*!
 *****************************************************************************
 * \struct ADI_UART_BUFF_INFO
 *  Structure for managing the submitted buffers.
 *****************************************************************************/

typedef struct UART_BUFF_INFO
{
    void                      *pStartAddress;             /*!< Address of buffer passed down to the UART driver.    */
    uint32_t                   nCount;                    /*!< Size of buffer in bytes.                             */
    uint32_t                   nIndex;                    /*!< Buffer index.                                        */   
    bool                       bInUse;                    /*!< Buffer in use flag.                                  */
    bool                       bDMA;                      /*!< Transaction is using the DMA flag.                   */
    struct UART_BUFF_INFO     *pNextBuffer;               /*!< Pointer to the next buffer in the list.              */


}ADI_UART_BUFF_INFO;


/*! Function pointer typedef for the function which  submit the buffer */
typedef void (*UART_BUFFER_SUBMIT) (ADI_UART_CONST_HANDLE  const hDevice,
                                    ADI_UART_BUFF_INFO    *const pBuffer
                                    );


/*!
 *****************************************************************************
 * \struct ADI_UART_DATA_CHANNEL
 *  Structure to manage the data transfer for a given channel.
 *  One instance of this  structure will be created for managing the
 *  data transfer in each direction.
 *****************************************************************************/
 
typedef struct _ADI_UART_DATA_CHANNEL
{ 
    ADI_UART_BUFF_INFO        PingPong[2];       /*!< Ping Pong Buffers.                                            */
    ADI_UART_BUFF_INFO       *pFreeBuffer;       /*!< Pointer to free buffer (next buffer to submit).               */  
    ADI_UART_BUFF_INFO       *pFillBuffer;       /*!< Pointer to the next buffer to be filled. This is needed for 
                                                      the case where two buffers are "submitted" before a "get" is 
                                                      called.                                                       */
    ADI_UART_BUFF_INFO       *pActiveBuffer;     /*!< Pointer to active buffer (next buffer waiting for completion).*/
    ADI_UART_TRANSFER_MODE    eDataTranferMode;  /*!< Data transfer mode.                                           */ 
    UART_BUFFER_SUBMIT        pfSubmitBuffer;    /*!< Pointer to a function used for submitting a buffer.           */
    SEM_VAR_DECLR                               

}ADI_UART_DATA_CHANNEL;


/*!
 *****************************************************************************
 * \struct  ADI_UART_DEVICE_INFO
 *  Structure for storing basic device information.
 *****************************************************************************/

typedef struct _ADI_UART_DEVICE_INFO
{
    DMA_CHANn_TypeDef      dmaTxChannelNum;    /*!<  DMA channel ID-Tx.                  */       
    DMA_CHANn_TypeDef      dmaRxChannelNum;    /*!<  DMA channel ID-Rx.                  */   
    IRQn_Type              eDMATx;             /*!<  DMA channel IRQ-Tx.                 */       
    IRQn_Type              eDMARx;             /*!<  DMA channel IRQ-Rx.                 */  
    IRQn_Type              eIRQn;              /*!<  UART interrupt ID.                  */   
    ADI_UART_TypeDef      *pUartRegs;          /*!<  Base address of the UART registers. */       
    ADI_UART_HANDLE        hDevice;            /*!<  Handle for the device instance.     */

}ADI_UART_DEVICE_INFO;


/*!
 *****************************************************************************
 * \struct  ADI_UART_DEVICE
 *  Structure for managing the UART device. 
 *****************************************************************************/

typedef struct _ADI_UART_DEVICE
{
    ADI_UART_DIRECTION          eDirection;           /*!< UART operation direction.                                       */
    ADI_UART_DEVICE_INFO       *pUartInfo;            /*!< Access to device information about the uart instance.           */
    volatile ADI_UART_TypeDef  *pUARTRegs;            /*!< Access to UART Memory Mapped Registers.                         */     
    ADI_CALLBACK                pfCallback;           /*!< Callback function.                                              */
    void                       *pCBParam;             /*!< Parameter for callback function.                                */
    bool                        bAutobaudInProgress;  /*!< Autobaud in progress flag.                                      */   
    volatile uint32_t           nHwError;             /*!< Line status error(s).                                           */
    volatile uint32_t           nAutobaudError;       /*!< Autobaud error(s).                                              */         
    ADI_UART_DATA_CHANNEL      *pChannelTx;           /*!< Tx channel.                                                     */    
    ADI_UART_DATA_CHANNEL      *pChannelRx;           /*!< Rx channel.                                                     */
    volatile uint32_t           nBaudRate;            /*!< Baudrate.                                                       */
    bool                        bAutobaudCallbackMode;/*!< Autobaud detection is using callback mode flag.                 */
    bool                        bRxFifoEn;            /*!< Rx FIFO enabled. Rx buffer full interrupts will remain enabled. */
    uint8_t                     nRxFifoTrig;          /*!< Number of bytes transferred to trigger Rx FIFO interrupt.       */  
} ADI_UART_DEVICE;


/*!
 *****************************************************************************
 * \struct  ADI_UART_CONFIG
 *  Structure for initializing the static config.
 *****************************************************************************/

typedef struct _ADI_UART_CONFIG
{
    uint16_t                    LCR;                 /*!< UART_COMLCR Register. */    

    uint16_t                    DIV;                 /*!< UART_COMDIV Register. */ 

    uint16_t                    FBR;                 /*!< UART_COMFBR Register. */ 

    uint16_t                    LCR2;                /*!< UART_COMLCR2 Register.*/ 

    uint16_t                    FCR;                 /*!< UART_COMFCR Register. */ 

    uint16_t                    RSC;                 /*!< UART_COMRSC Register. */              

    uint16_t                    IEN;                 /*!< UART_COMIEN Register .*/ 

} ADI_UART_CONFIG;


/******************************************************************************
 * UART Device internal API function prototypes
 *****************************************************************************/

/*
 * UART device initialization helper function.
*/
static void uart_init(ADI_UART_CONST_HANDLE const hDevice, uint32_t const nDeviceNum);


/*
 * Data transfer helper functions.
*/
static void uart_submittxbuffer(ADI_UART_CONST_HANDLE const hDevice, ADI_UART_BUFF_INFO *const pBuffer);

static void uart_submitrxbuffer(ADI_UART_CONST_HANDLE const hDevice, ADI_UART_BUFF_INFO *const pBuffer);


/*
 * Data management helper functions.
*/
static ADI_UART_RESULT uart_getbuffer(ADI_UART_HANDLE hDevice, ADI_UART_DATA_CHANNEL *pChannel, void **ppBuffer, uint32_t *pHwError);

static ADI_UART_RESULT uart_PendForBuffer(ADI_UART_HANDLE const hDevice , ADI_UART_DATA_CHANNEL *pChannel, uint32_t *pHwError);

static void uart_ManageProcessedBuffer(ADI_UART_HANDLE hDevice, ADI_UART_DATA_CHANNEL *pChannel, ADI_UART_EVENT eEvent);

static void uart_TxDataHandler(ADI_UART_HANDLE hDevice);

static void uart_RxDataHandler(ADI_UART_HANDLE hDevice, uint8_t nBytes);


/*
 * Interrupt Handler.
*/
static void Common_Uart_Interrupt_Handler(ADI_UART_HANDLE hDevice);


/* 
 * Handle Validation function
*/
#ifdef ADI_DEBUG
static ADI_UART_RESULT  ValidateHandle(ADI_UART_CONST_HANDLE hDevice);
#endif /* ADI_DEBUG */

#endif  /* end of ifndef DEF_UART_DEF_H */
/*! \endcond */


/*! *****************************************************************************
 * @file    adi_uart.h
 * @brief   UART device driver global include file.
 * @details This a global file which includes a specific file based on the processor family.
 *          This included file will be containing UART device driver functions.
 -----------------------------------------------------------------------------
Copyright (c) 2010-2018 Analog Devices, Inc.

All rights reserved.

Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
  - Redistributions of source code must retain the above copyright notice,
    this list of conditions and the following disclaimer.
  - Redistributions in binary form must reproduce the above copyright notice,
    this list of conditions and the following disclaimer in the documentation
    and/or other materials provided with the distribution.
  - Modified versions of the software must be conspicuously marked as such.
  - This software is licensed solely and exclusively for use with processors
    manufactured by or for Analog Devices, Inc.
  - This software may not be combined or merged with other code in any manner
    that would cause the software to become subject to terms and conditions
    which differ from those listed here.
  - Neither the name of Analog Devices, Inc. nor the names of its
    contributors may be used to endorse or promote products derived
    from this software without specific prior written permission.
  - The use of this software may or may not infringe the patent rights of one
    or more patent holders.  This license does not release you from the
    requirement that you obtain separate licenses from these patent holders
    to use this software.

THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-
INFRINGEMENT, TITLE, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL ANALOG DEVICES, INC. OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, PUNITIVE OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, DAMAGES ARISING OUT OF
CLAIMS OF INTELLECTUAL PROPERTY RIGHTS INFRINGEMENT; PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*****************************************************************************/
#ifndef ADI_UART_H
#define ADI_UART_H

/** @addtogroup UART_Driver UART Driver
*  @{
*/

/*! \cond PRIVATE */

/*=============  I N C L U D E S   =============*/

#include <stdint.h>
#include <stddef.h>
#include <string.h>
#include <assert.h>
#include <adi_processor.h>
#include <adi_uart_config.h>
#include <adi_rtos_map.h>
#include <adi_dma.h>
#include <adi_pwr.h>

#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */

/*! \endcond */

/*! Amount of memory(bytes) required by the UART device driver for operating unidirectionally(Either RX or TX).
 *  This memory is completely owned by the driver until the end of the operation.
 */
#define ADI_UART_UNIDIR_MEMORY_SIZE  (48u + (60u + ADI_SEM_SIZE))

/*! Amount of memory(bytes) required by the UART device driver for operating bidirectionally(Both RX and TX).
 *  This memory is completely owned by the driver until the end of the operation.
 */
#define ADI_UART_BIDIR_MEMORY_SIZE  (48u + (60u + ADI_SEM_SIZE)*2u)

/*!
 * Handle for managing the UART device typedef.
 */
typedef struct _ADI_UART_DEVICE* ADI_UART_HANDLE;

/*!
 * Handle for managing the UART device typedef 'const' version.
 */
typedef const struct _ADI_UART_DEVICE* ADI_UART_CONST_HANDLE;

/*!
 *****************************************************************************
 *  \enum ADI_UART_DIRECTION
 *   Enumeration for the UART direction.
 *****************************************************************************/
typedef enum
{
    ADI_UART_DIR_TRANSMIT,                              /*!< UART is only transmitting.   */

    ADI_UART_DIR_RECEIVE,                               /*!< UART is only receiving.      */

    ADI_UART_DIR_BIDIRECTION                            /*!< UART in bidirectional.       */

} ADI_UART_DIRECTION;


/*!
 *****************************************************************************
 *  \enum ADI_UART_EVENT
 *   Enumeration of events notified in the application provided callback.
 *****************************************************************************/
 typedef enum
{
    ADI_UART_EVENT_RX_BUFFER_PROCESSED,                 /*!< Rx buffer is processed.                                   */

    ADI_UART_EVENT_TX_BUFFER_PROCESSED,                 /*!< Tx buffer is processed.                                   */

    ADI_UART_EVENT_NO_RX_BUFFER_EVENT,                  /*!< No Rx buffer but data is in FIFO.                         */

    ADI_UART_EVENT_AUTOBAUD_COMPLETE,                   /*!< Autobaud is complete.                                     */

    ADI_UART_EVENT_HW_ERROR_DETECTED,                   /*!< Hardware error detected.                                  */
    
    ADI_UART_EVENT_AUTOBAUD_ERROR_DETECTED              /*!< Autobaud error detected.                                  */
    
}ADI_UART_EVENT;


/*!
 *****************************************************************************
 *  \enum ADI_UART_RESULT
 *   Enumeration for result code returned from the UART device driver functions.
 *   The return value of all UART APIs returning #ADI_UART_RESULT
 *   should always be tested at the application level for success or failure.
 *****************************************************************************/
 typedef enum
{

    ADI_UART_SUCCESS,                           /*!< Generic success.                                               */

    ADI_UART_FAILED,                            /*!< Generic failure.                                               */

    ADI_UART_SEMAPHORE_FAILED,                  /*!< Semaphore error.                                               */

    ADI_UART_INVALID_HANDLE,                    /*!< Invalid device handle.                                         */

    ADI_UART_DEVICE_IN_USE,                     /*!< UART device in use.                                            */

    ADI_UART_INVALID_DEVICE_NUM,                /*!< Invalid device number.                                         */

    ADI_UART_INVALID_POINTER,                   /*!< NULL data pointer is not allowed.                              */

    ADI_UART_INSUFFICIENT_MEMORY,               /*!< Insufficent memory.                                            */

    ADI_UART_INVALID_DIR,                       /*!< Invalid UART direction.                                        */

    ADI_UART_OPERATION_NOT_ALLOWED,             /*!< Invalid operation.                                             */

    ADI_UART_INVALID_PARAMETER,                 /*!< Invalid parameter.                                             */

    ADI_UART_BUFFER_NOT_SUBMITTED,              /*!< Buffer not submitted.                                          */

    ADI_UART_INVALID_DATA_TRANSFER_MODE,        /*!< Invalid transfer mode.
                                                     Adi_uart_Read()/adi_uart_Write() is used in nonblocking mode
                                                     or adi_uart_SubmitRxBuffer()/adi_uart_SubmitTxBuffer()
                                                     is used in blocking mode.                                      */

    ADI_UART_HW_ERROR_DETECTED,                 /*!< Hardware error detected.                                       */

    ADI_UART_AUTOBAUD_ERROR_DETECTED,           /*!< Autobaud error detected.                                       */
      
    ADI_UART_ERR_DMA_REGISTER,                  /*!< Error while registering the DMA callback.                      */
      
    ADI_UART_INVALID_DATA_SIZE                  /*!< Invalid transfer size. Must be less than 1025 bytes            */

} ADI_UART_RESULT;

/*!
 *****************************************************************************
 *  \enum ADI_UART_HW_ERRORS
 *   Enumeration for UART hardware errors. If hardware error(s) occur in
 *   either callback or interrupt mode, they are mapped to #ADI_UART_HW_ERRORS.
 *   Interpretation of the break condition is application specific.
 *****************************************************************************/
typedef enum
{
    ADI_UART_NO_HW_ERROR                     = 0x00,   /*!< No hardware error.                                             */

    ADI_UART_HW_ERR_FRAMING                  = 0x10,   /*!< Rx framing error.                                              */

    ADI_UART_HW_ERR_PARITY                   = 0x20,   /*!< Rx parity error.                                               */

    ADI_UART_HW_ERR_OVERRUN                  = 0x40,   /*!< Receive overrun.                                               */
 
    ADI_UART_BREAK_INTERRUPT                 = 0x80,   /*!< Break condition.                                               */
      
    ADI_UART_HW_ERR_RX_CHAN_DMA_BUS_FAULT     = 0x100,  /*!< Rx DMA channel bus fault detected.                             */
    
    ADI_UART_HW_ERR_TX_CHAN_DMA_BUS_FAULT     = 0x200,  /*!< Tx DMA channel bus fault detected.                             */
   
    ADI_UART_HW_ERR_RX_CHAN_DMA_INVALID_DESCR = 0x400,  /*!< Rx DMA channel invalid descriptor detected.                    */
    
    ADI_UART_HW_ERR_TX_CHAN_DMA_INVALID_DESCR = 0x800,  /*!< Tx DMA channel invalid descriptor detected.                    */
    
    ADI_UART_HW_ERR_RX_CHAN_DMA_UNKNOWN_ERROR = 0x1000, /*!< Rx DMA channel unknown error detected.                         */
  
    ADI_UART_HW_ERR_TX_CHAN_DMA_UNKNOWN_ERROR = 0x2000, /*!< Tx DMA channel unknown error detected.                         */

}ADI_UART_HW_ERRORS;

/*!
 *****************************************************************************
 *  \enum ADI_UART_AUTOBAUD_ERRORS
 *   Enumeration for UART autobaud errors. If autobaud related error(s) occur
 *   they are mapped to #ADI_UART_AUTOBAUD_ERRORS.
 *****************************************************************************/
typedef enum
{
    ADI_UART_AUTOBAUD_NO_ERROR              = 0x000,  /*!< No autobaud error.                                           */

    ADI_UART_AUTOBAUD_TIMEOUT_NO_START_EDGE = 0x100,  /*!< Timeout due to no valid start edge found during autobaud.    */

    ADI_UART_AUTOBAUD_TIMEOUT_LONGBREAK     = 0x200,  /*!< Timeout due to break condition detected during autobaud.     */

    ADI_UART_AUTOBAUD_TIMEOUT_NO_END_EDGE   = 0x400   /*!< Timeout due to no valid end edge found during autobaud.      */

}ADI_UART_AUTOBAUD_ERRORS;

/*!
 *****************************************************************************
 *  \enum ADI_UART_TRIG_LEVEL
 *   Enumeration for the FIFO trigger level.
 *****************************************************************************/
typedef enum
{

    ADI_UART_RX_FIFO_TRIG_LEVEL_1BYTE   =  0 << BITP_UART_FCR_RFTRIG,  /*!< 1-byte to trigger RX interrupt.  */

    ADI_UART_RX_FIFO_TRIG_LEVEL_4BYTE   =  1 << BITP_UART_FCR_RFTRIG,  /*!< 4-byte to trigger RX interrupt.  */
    
    ADI_UART_RX_FIFO_TRIG_LEVEL_8BYTE   =  2 << BITP_UART_FCR_RFTRIG,  /*!< 8-byte to trigger RX interrupt.  */
    
    ADI_UART_RX_FIFO_TRIG_LEVEL_14BYTE  =  3 << BITP_UART_FCR_RFTRIG   /*!< 14-byte to trigger RX interrupt. */

}ADI_UART_TRIG_LEVEL;

/*!
 *****************************************************************************
 *  \enum ADI_UART_WORDLEN
 *   Enumeration for data width. 
 *****************************************************************************/
typedef enum
{
    ADI_UART_WORDLEN_5BITS,             /*!< 5 bits wide. */

    ADI_UART_WORDLEN_6BITS,             /*!< 6 bits wide. */

    ADI_UART_WORDLEN_7BITS,             /*!< 7 bits wide. */

    ADI_UART_WORDLEN_8BITS              /*!< 8 bits wide. */

} ADI_UART_WORDLEN;

/*!
 *****************************************************************************
 *  \enum ADI_UART_PARITY
 *   Enumeration for parity check.
 *****************************************************************************/
typedef enum
{
    ADI_UART_NO_PARITY          =  0x0,  /*!< No parity.          */

    ADI_UART_ODD_PARITY         =  0x8,  /*!< Odd parity.         */

    ADI_UART_EVEN_PARITY        =  0x18, /*!< Even Parity.        */

    ADI_UART_ODD_PARITY_STICKY  =  0x28, /*!< Sticky odd parity.  */

    ADI_UART_EVEN_PARITY_STICKY =  0x38  /*!< Sticky even parity. */
      
} ADI_UART_PARITY;

/*!
 *****************************************************************************
 *  \enum ADI_UART_STOPBITS
 *   Enumeration for the number of stop bits.
 *****************************************************************************/
typedef enum
{
    
    ADI_UART_ONE_STOPBIT               = 0x00,          /*! One stop bit regardless of the word length                           */
   
    ADI_UART_ONE_AND_HALF_TWO_STOPBITS = 0x04           /*! Number of stop bits based on word length. 1.5 stop bits 
                                                            for word length of 5 bits and 2 for rest( 6,7,8 bit word length)     */
      
} ADI_UART_STOPBITS;

/*!
 *****************************************************************************
 * \enum  ADI_UART_TRANSFER_MODE
 *  Enumeration for data transfer mode.
 *****************************************************************************/
typedef enum
{
    
    ADI_UART_DATA_TRANSFER_MODE_NONE,       /*! Mode of data transfer is not selected.                             */ 
    
    ADI_UART_DATA_TRANSFER_MODE_BLOCKING,   /*! Blocking mode. Only calls to adi_uart_Read or adi_uart_write  
                                                are allowed for sending or receiving data.                         */
    
    ADI_UART_DATA_TRANSFER_MODE_NONBLOCKING /*! Non-Blocking mode. Only calls to adi_uart_SubmitRxBuffer or
                                                adi_uart_SubmitTxBuffer are allowed for sending or receiving data. */

} ADI_UART_TRANSFER_MODE;


/******************************************************************************
 * UART Device external API function prototypes
 *****************************************************************************/

/*
 * Device initialization and uninitialization interfaces.
*/
ADI_UART_RESULT adi_uart_Open(
                uint32_t           const nDeviceNum,
                ADI_UART_DIRECTION const eDirection,
                void                    *pMemory,
                uint32_t           const nMemSize,
                ADI_UART_HANDLE   *const phDevice
);

ADI_UART_RESULT adi_uart_Close(
                ADI_UART_HANDLE  const   hDevice
);


/******************************************************************************
 * Eliminatable functions that may be optimized out by the linker
 *****************************************************************************/

/*
 * Non-blocking mode functions.
*/

ADI_UART_RESULT adi_uart_SubmitTxBuffer(
                ADI_UART_HANDLE const    hDevice,
                void           *const    pBuffer,
                uint32_t        const    nBufSize,
                bool            const    bDMA
);

ADI_UART_RESULT adi_uart_SubmitRxBuffer(
                ADI_UART_HANDLE const    hDevice,
                void           *const    pBuffer,
                uint32_t        const    nBufSize,
                bool            const    bDMA
);

ADI_UART_RESULT adi_uart_GetTxBuffer(
                ADI_UART_HANDLE const    hDevice,
                void          **const    ppBuffer,
                uint32_t                *pHwError
);

ADI_UART_RESULT adi_uart_GetRxBuffer(
                ADI_UART_HANDLE const    hDevice,
                void          **const    ppBuffer,
                uint32_t                *pHwError
);
ADI_UART_RESULT adi_uart_IsTxBufferAvailable(
                ADI_UART_HANDLE const    hDevice,
                bool           *const    pbAvailable
);

ADI_UART_RESULT adi_uart_IsRxBufferAvailable(
                ADI_UART_HANDLE const    hDevice,
                bool           *const    pbAvailable
);

/*
 * Blocking mode functions.
*/

ADI_UART_RESULT adi_uart_Write(
                ADI_UART_HANDLE const    hDevice,
                void           *const    pBuffer,
                uint32_t        const    nBufSize,
                bool            const    bDMA,
                uint32_t                *pHwError
);

ADI_UART_RESULT adi_uart_Read(
                ADI_UART_HANDLE const    hDevice,
                void           *const    pBuffer,
                uint32_t        const    nBufSize,
                bool            const    bDMA,
                uint32_t                *pHwError
);


/*
 * Configuration interface functions.
*/

ADI_UART_RESULT adi_uart_EnableLoopBack(
                ADI_UART_HANDLE const     hDevice,
                bool            const     bEnable
);

ADI_UART_RESULT adi_uart_EnableAutobaud(
                ADI_UART_HANDLE const     hDevice,
                bool            const     bEnable,
                bool            const     bAutobaudCallbackMode
);

ADI_UART_RESULT adi_uart_SetRxFifoTriggerLevel(
                ADI_UART_HANDLE           const hDevice,
                ADI_UART_TRIG_LEVEL       const eTriglevel
);

ADI_UART_RESULT adi_uart_EnableFifo(
                ADI_UART_HANDLE const     hDevice,
                bool            const     bEnable
);

ADI_UART_RESULT adi_uart_GetBaudRate(
                ADI_UART_HANDLE const     hDevice,
                uint32_t                 *pnBaudRate,
                uint32_t                 *pAutobaudError
);

ADI_UART_RESULT adi_uart_ForceTxBreak(
                ADI_UART_HANDLE const     hDevice,
                bool            const     bEnable
);

ADI_UART_RESULT adi_uart_SetConfiguration(
                ADI_UART_HANDLE   const  hDevice,
                ADI_UART_PARITY   const  eParity,
                ADI_UART_STOPBITS const  eStopBits,
                ADI_UART_WORDLEN  const  eWordLength
);

ADI_UART_RESULT adi_uart_ConfigBaudRate(
                ADI_UART_HANDLE   const hDevice,
                uint16_t          const nDivC,
                uint8_t           const nDivM,
                uint16_t          const nDivN,
                uint8_t           const nOSR  
);

/*
 * Channel data control functions.
*/

ADI_UART_RESULT adi_uart_FlushTxFifo(
                ADI_UART_CONST_HANDLE const  hDevice
);

ADI_UART_RESULT adi_uart_FlushRxFifo(
                ADI_UART_CONST_HANDLE const  hDevice
);

ADI_UART_RESULT adi_uart_FlushRxChannel(
                ADI_UART_CONST_HANDLE const  hDevice
);


ADI_UART_RESULT adi_uart_FlushTxChannel(
                ADI_UART_CONST_HANDLE const  hDevice
);

ADI_UART_RESULT adi_uart_IsTxComplete(
                ADI_UART_HANDLE const hDevice,
                bool           *const pbComplete
);

/*
 * Callback functions.
*/

ADI_UART_RESULT adi_uart_RegisterCallback(
                ADI_UART_HANDLE const    hDevice,
                const ADI_CALLBACK       pfCallback,
                void           *const    pCBParam
);

#ifdef __cplusplus
}
#endif /* __cplusplus */

/*@}*/

#endif /* ADI_UART_H */


/*!
 *****************************************************************************
   @file:    adi_uart_config.h
   @brief:   Configuration options for UART driver.
             This is specific to the UART driver and will be included by the driver.
             It is not required for the application to include this header file.
  -----------------------------------------------------------------------------

Copyright (c) 2016 Analog Devices, Inc.

All rights reserved.

Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
  - Redistributions of source code must retain the above copyright notice,
    this list of conditions and the following disclaimer.
  - Redistributions in binary form must reproduce the above copyright notice,
    this list of conditions and the following disclaimer in the documentation
    and/or other materials provided with the distribution.
  - Modified versions of the software must be conspicuously marked as such.
  - This software is licensed solely and exclusively for use with processors
    manufactured by or for Analog Devices, Inc.
  - This software may not be combined or merged with other code in any manner
    that would cause the software to become subject to terms and conditions
    which differ from those listed here.
  - Neither the name of Analog Devices, Inc. nor the names of its
    contributors may be used to endorse or promote products derived
    from this software without specific prior written permission.
  - The use of this software may or may not infringe the patent rights of one
    or more patent holders.  This license does not release you from the
    requirement that you obtain separate licenses from these patent holders
    to use this software.

THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. AND CONTRIBUTORS "AS IS" AND ANY
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT,
TITLE, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
NO EVENT SHALL ANALOG DEVICES, INC. OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, PUNITIVE OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, DAMAGES ARISING OUT OF CLAIMS OF INTELLECTUAL
PROPERTY RIGHTS INFRINGEMENT; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

*****************************************************************************/

#ifndef ADI_UART_CONFIG_H
#define ADI_UART_CONFIG_H

/** @addtogroup UART_Driver_Config Static Configuration
 *  @ingroup UART_Driver
 *  @{
 */


#include <adi_global_config.h>

/************** Common UART Driver configurations ************** */ 
/*!
   Enable the autobaud detection. \n
   Range: 0 to 1.
*/
#define ADI_UART_CFG_ENABLE_AUTOBAUD                 1


/** @addtogroup UART0_Driver_Config UART0 Static Configuration
 *  @ingroup UART_Driver_Config
 *  @{
 */
 
/************** UART Driver configurations FOR UART 0 ************** */
/*!
   Word length Select. \n
   0 -  5 Bits word length. \n
   1 -  6 Bits word length. \n
   2 -  7 Bits word length. \n
   3 -  8 Bits word length.
*/
#define ADI_UART0_CFG_WORD_LENGTH                  3


/*!
   Stop bit selection. \n
   0 -  Send 1 stop bit regardless of the word length. \n
   1 -  Send a number of stop bits based on the word length. \n
        WORD-LENGTH 5 Bits       => 1.5 Stop Bits. \n
        WORD-LENGTH (6/7/8) Bits => 2   Stop Bits.
*/
#define ADI_UART0_CFG_STOP_BIT                      1


/*!
   Parity Enable. Used to control the parity bit. \n
   0 -  Parity will not be transmitted or checked. \n
   1 -  Parity will be transmitted and checked.
*/
#define ADI_UART0_CFG_ENABLE_PARITY                 0


/*!
   Parity Select. This bit only has meaning if parity is enabled. \n
   0 - Odd parity will be transmitted and checked. \n
   1 - Even parity will be transmitted and checked.
*/
#define ADI_UART0_CFG_PARITY_SELECTION              0


/*!
   Stick Parity. Used to force parity to defined values. \n
   0 -  Parity will not be forced. \n
   1 -  Set parity based on the following bit settings: \n
        EPS = 1 and PEN = 1, parity will be forced to 0. \n
        EPS = 0 and PEN = 1, parity will be forced to 1. \n
        EPS = 1/0 and PEN = 0, no parity will be transmitted.
*/
#define ADI_UART0_CFG_ENABLE_STICKY_PARITY          0


/*
  Table 21-2: Baud Rate Examples Based on 26 MHz PCLK
  Baud Rate OSR COMDIV DIVM DIVN
  9600        3 24     3    1078
  19200       3 12     3    1078
  38400       3 8      2    1321
  57600       3 4      3    1078
  115200      3 4      1    1563
  230400      3 2      1    1563
  460800      3 1      1    1563
  921,600     2 1      1    1563
  1,000,000   2 1      1    1280
  1,500,000   2 1      1    171

These are calculated with the UarDivCalculator tool.
*/

/*!
   Fractional baud rate N divide value. \n
   Range: 0 to 2047.
*/
#define ADI_UART0_CFG_DIVN                           1078


/*!
   Fractional baud rate M divide value. \n
   Range: 1 to 3.
*/
#define ADI_UART0_CFG_DIVM                           3


/*!
   Fractional baud rate C divide value. \n
   Range: 1 to 65535.
*/
#define ADI_UART0_CFG_DIVC                           24


/*!
   Over Sample Rate value. \n
   Range: 0 to 3. \n
   0 - Over sample by 4. \n
   1 - Over sample by 8. \n
   2 - Over sample by 16. \n
   3 - Over sample by 32.

*/
#define ADI_UART0_CFG_OSR                            3


/*!
   Enable Internal FIFO. \n
   Range: 0 to 1.
*/
#define ADI_UART0_CFG_ENABLE_FIFO                    1


/*!
   TRIG Level for  UART device. \n
   Range: 0 to 3. \n
   0 - 1 byte to trig RX interrupt. \n
   1 - 4 bytes to trig RX interrupt. \n
   2 - 8 bytes to trig RX interrupt. \n
   3 - 14 bytes to trig RX interrupt.
*/
#define ADI_UART0_CFG_TRIG_LEVEL                     0


/*!
   Hold TX while RX is active.  \n
   Range: 0 to 1.
*/
#define ADI_UART0_CFG_HOLD_TX                        0


/*!
   Disable RX when TX is active. \n
   Range: 0 to 1. \n
   0 - 1 byte to trig RX interrupt. \n
   1 - 4 bytes to trig RX interrupt.
*/
#define ADI_UART0_CFG_DISABLE_RX                     0


/*!
   Configure the SOUT de-assertion earlier than full stop bit(s). \n
   Range: 0 to 1. \n
   0 - SOUT_EN de-assert same time as full stop bit(s). \n
   1 - SOUT_EN de-assert half-bit earlier than full stop bit(s).
*/
#define ADI_UART0_CFG_DEASSERTION                     0


/*!
   Set the SOUT polarity low. \n
   Range: 0 to 1. \n
   0 - Active high. \n
   1 - Active low.
*/
#define ADI_UART0_CFG_SOUT_POLARITY                   0

/*!
   Enable the RX status interrupt. \n
   Range: 0 to 1.
*/
#define ADI_UART0_CFG_ENABLE_RX_STATUS_INTERRUPT      1


/*!
   Enable the Modem status interrupt. \n
   Range: 0 to 1.
*/
#define ADI_UART0_CFG_ENABLE_MODEM_STATUS_INTERRUPT   0

/*! @} */


/***************  UART Driver configurations FOR UART 1 **************/

/** @addtogroup UART1_Driver_Config UART1 Static Configuration
 *  @ingroup UART_Driver_Config
 *  @{
 */

/*!
   Word length Select. \n
   0 -  5 Bits word length. \n
   1 -  6 Bits word length. \n
   2 -  7 Bits word length. \n
   3 -  8 Bits word length.
*/
#define ADI_UART1_CFG_WORD_LENGTH                     3


/*!
   Stop bit selection.\n
   0 -  Send 1 stop bit regardless of the word length. \n
   1 -  Send a number of stop bits based on the word length. \n
        WORD-LENGTH 5 Bits       => 1.5 Stop Bits. \n
        WORD-LENGTH (6/7/8) Bits => 2   Stop Bits.
*/
#define ADI_UART1_CFG_STOP_BIT                        1


/*!
   Parity Enable. Used to control the parity bit. \n
   0 -  Parity will not be transmitted or checked. \n
   1 -  Parity will be transmitted and checked.
*/
#define ADI_UART1_CFG_ENABLE_PARITY                   0


/*!
   Parity Select. This bit only has meaning if parity is enabled. \n
   0 - Odd parity will be transmitted and checked. \n
   1 - Even parity will be transmitted and checked.
*/
#define ADI_UART1_CFG_PARITY_SELECTION                0


/*!
   Stick Parity. Used to force parity to defined values. \n
   0 -  Parity will not be forced. \n
   1 -  Set parity based on the following bit settings: \n
        EPS = 1 and PEN = 1, parity will be forced to 0. \n
        EPS = 0 and PEN = 1, parity will be forced to 1. \n
        EPS = 1/0 and PEN = 0, no parity will be transmitted.
*/
#define ADI_UART1_CFG_ENABLE_STICKY_PARITY            0


/*
  Table 21-2: Baud Rate Examples Based on 26 MHz PCLK
  Baud Rate OSR COMDIV DIVM DIVN
  9600        3 24     3    1078
  19200       3 12     3    1078
  38400       3 8      2    1321
  57600       3 4      3    1078
  115200      3 4      1    1563
  230400      3 2      1    1563
  460800      3 1      1    1563
  921,600     2 1      1    1563
  1,000,000   2 1      1    1280
  1,500,000   2 1      1    171

These are calculated with the UarDivCalculator tool.
*/

/*!
   Fractional baud rate N divide value. \n
   Range: 0 to 2047.
*/
#define ADI_UART1_CFG_DIVN                              1563


/*!
   Fractional baud rate M divide value. \n
   Range: 1 to 3.
*/
#define ADI_UART1_CFG_DIVM                             1


/*!
   Fractional baud rate C divide value. \n
   Range: 1 to 65535.
*/
#define ADI_UART1_CFG_DIVC                             1


/*!
   Over Sample Rate value. \n
   Range: 0 to 3. \n
   0 - Over sample by 4. \n
   1 - Over sample by 8. \n
   2 - Over sample by 16. \n
   3 - Over sample by 32.

*/
#define ADI_UART1_CFG_OSR                              3


/*!
   Enable Internal FIFO. \n
   Range: 0 to 1.
*/
#define ADI_UART1_CFG_ENABLE_FIFO                      1


/*!
   TRIG Level for  UART device. \n
   Range: 0 to 3. \n
   0 - 1 byte to trig RX interrupt. \n
   1 - 4 bytes to trig RX interrupt. \n
   2 - 8 bytes to trig RX interrupt. \n
   3 - 14 bytes to trig RX interrupt.
*/
#define ADI_UART1_CFG_TRIG_LEVEL                       0


/*!
   Hold TX while RX is active.  \n
   Range: 0 to 1.
*/
#define ADI_UART1_CFG_HOLD_TX                          0


/*!
   Disable RX when TX is active. \n
   Range: 0 to 1. \n
   0 - 1 byte to trig RX interrupt. \n
   1 - 4 bytes to trig RX interrupt.
*/
#define ADI_UART1_CFG_DISABLE_RX                       0


/*!
   Configure the SOUT de-assertion earlier than full stop bit(s). \n
   Range: 0 to 1. \n
   0 - SOUT_EN de-assert same time as full stop bit(s). \n
   1 - SOUT_EN de-assert half-bit earlier than full stop bit(s).
*/
#define ADI_UART1_CFG_DEASSERTION                     0


/*!
   Set the SOUT polarity low. \n
   Range: 0 to 1. \n
   0 - Active high. \n
   1 - Active low.
*/
#define ADI_UART1_CFG_SOUT_POLARITY                   0

/*!
   Enable the RX status interrupt. \n
   Range: 0 to 1.
*/
#define ADI_UART1_CFG_ENABLE_RX_STATUS_INTERRUPT       1


/*!
   Enable the Modem status interrupt. \n
   Range: 0 to 1.
*/
#define ADI_UART1_CFG_ENABLE_MODEM_STATUS_INTERRUPT    0
/*! @} */

/*! @} */


/***************  UART Driver Debug Checks ************** */

/* Check word length */
#if (((ADI_UART0_CFG_WORD_LENGTH < 0) || (ADI_UART0_CFG_WORD_LENGTH > 3))  || ((ADI_UART1_CFG_WORD_LENGTH < 0) || (ADI_UART1_CFG_WORD_LENGTH > 3)))
#error "Word length needs to be between 0 and 3"
#endif

/* Check stop bit */
#if (((ADI_UART0_CFG_STOP_BIT < 0) || (ADI_UART0_CFG_STOP_BIT > 1))  || ((ADI_UART1_CFG_STOP_BIT < 0) || (ADI_UART1_CFG_STOP_BIT > 1)))
#error "Stop bit selection needs to be 0 or 1"
#endif

/* Check parity enable  */
#if (((ADI_UART0_CFG_ENABLE_PARITY < 0) || (ADI_UART0_CFG_ENABLE_PARITY > 1))  || ((ADI_UART1_CFG_ENABLE_PARITY < 0) || (ADI_UART1_CFG_ENABLE_PARITY > 1)))
#error "Parity Enable bit needs to be 0 or 1"
#endif

/* Check parity select */
#if (((ADI_UART0_CFG_PARITY_SELECTION < 0) || (ADI_UART0_CFG_PARITY_SELECTION > 1))  || ((ADI_UART1_CFG_PARITY_SELECTION < 0) || (ADI_UART1_CFG_PARITY_SELECTION > 1)))
#error "Parity bit selection needs to be 0 or 1"
#endif

/* Check enable sticky parity */
#if (((ADI_UART0_CFG_ENABLE_STICKY_PARITY < 0) || (ADI_UART0_CFG_ENABLE_STICKY_PARITY > 1))  || ((ADI_UART1_CFG_ENABLE_STICKY_PARITY < 0) || (ADI_UART1_CFG_ENABLE_STICKY_PARITY > 1)))
#error "Sticky parity enable needs to be 0 or 1"
#endif

/* Check fractional baudrate N divider value */
#if (((ADI_UART0_CFG_DIVN < 0) || (ADI_UART0_CFG_DIVN > 2047))  || ((ADI_UART1_CFG_DIVN < 0) || (ADI_UART1_CFG_DIVN > 2047)))
#error "Fractional baudrate N divider value needs to be between 0 and 2047"
#endif

/* Check fractional baudrate M divider value */
#if (((ADI_UART0_CFG_DIVM < 1) || (ADI_UART0_CFG_DIVM > 3))  || ((ADI_UART1_CFG_DIVM < 1) || (ADI_UART1_CFG_DIVM > 3)))
#error "Fractional baudrate M divider value needs to be between 1 and 3"
#endif

/* Check fractional baudrate C divider value */
#if (((ADI_UART0_CFG_DIVC < 1) || (ADI_UART0_CFG_DIVC > 65535))  || ((ADI_UART1_CFG_DIVC < 1) || (ADI_UART1_CFG_DIVC > 65535)))
#error "Fractional baudrate C divider value needs to be between 1 and 65535"
#endif

/* Check over same rate value */
#if (((ADI_UART0_CFG_OSR < 0) || (ADI_UART0_CFG_OSR > 3))  || ((ADI_UART1_CFG_OSR < 0) || (ADI_UART1_CFG_OSR > 3)))
#error "over sample rate value needs to be between 0 and 3"
#endif

/* Check enable internal FIFO */
#if (((ADI_UART0_CFG_ENABLE_FIFO < 0) || (ADI_UART0_CFG_ENABLE_FIFO > 1))  || ((ADI_UART1_CFG_ENABLE_FIFO < 0) || (ADI_UART1_CFG_ENABLE_FIFO > 1)))
#error "Enable internal FIFO needs to be 0 or 1"
#endif

/* Check UART trig level */
#if (((ADI_UART0_CFG_TRIG_LEVEL < 0) || (ADI_UART0_CFG_TRIG_LEVEL > 3))  || ((ADI_UART1_CFG_TRIG_LEVEL < 0) || (ADI_UART1_CFG_TRIG_LEVEL > 3)))
#error "Trig level for the UART device needs to be 0 or 1"
#endif

/* Check value for holding tx while rx is active */
#if (((ADI_UART0_CFG_HOLD_TX < 0) || (ADI_UART0_CFG_HOLD_TX > 1))  || ((ADI_UART1_CFG_HOLD_TX < 0) || (ADI_UART1_CFG_HOLD_TX > 1)))
#error "Value for holding Tx while Rx is active needs to be 0 or 1"
#endif

/* Check value de-assertion */
#if (((ADI_UART0_CFG_DEASSERTION < 0) || (ADI_UART0_CFG_DEASSERTION > 1))  || ((ADI_UART1_CFG_DEASSERTION < 0) || (ADI_UART1_CFG_DEASSERTION > 1)))
#error "Value for de-assertion needs to be 0 or 1"
#endif

/* Check value for SOUT polarity */
#if (((ADI_UART0_CFG_SOUT_POLARITY < 0) || (ADI_UART0_CFG_SOUT_POLARITY > 1))  || ((ADI_UART1_CFG_SOUT_POLARITY < 0) || (ADI_UART1_CFG_SOUT_POLARITY > 1)))
#error "Value for SOUT polarity needs to be 0 or 1"
#endif

/* Check value to enable autobaud detection */
#if ((ADI_UART_CFG_ENABLE_AUTOBAUD < 0) || (ADI_UART_CFG_ENABLE_AUTOBAUD > 1))
#error "Value for autobaud enable needs to be 0 or 1"
#endif

/* Check value to enable Rx status interrupt */
#if (((ADI_UART0_CFG_ENABLE_RX_STATUS_INTERRUPT < 0) || (ADI_UART0_CFG_ENABLE_RX_STATUS_INTERRUPT > 1))  || ((ADI_UART1_CFG_ENABLE_RX_STATUS_INTERRUPT < 0) || (ADI_UART1_CFG_ENABLE_RX_STATUS_INTERRUPT > 1)))
#error "Value to enable Rx status interrupt needs to be 0 or 1"
#endif

/* Check value to enable modem status interrupt */
#if (((ADI_UART0_CFG_ENABLE_MODEM_STATUS_INTERRUPT < 0) || (ADI_UART0_CFG_ENABLE_MODEM_STATUS_INTERRUPT > 1))  || ((ADI_UART1_CFG_ENABLE_MODEM_STATUS_INTERRUPT < 0) || (ADI_UART1_CFG_ENABLE_MODEM_STATUS_INTERRUPT > 1)))
#error "Value to enable modem status interrupt needs to be 0 or 1"
#endif

#endif /* ADI_UART_CONFIG_H */

/*! *****************************************************************************
 * @file:     adi_uart.c
 * @brief:    uart device driver implementation
 * @details:  This file contains the UART device driver functions
 -----------------------------------------------------------------------------
Copyright (c) 2010-2018 Analog Devices, Inc.

All rights reserved.

Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
  - Redistributions of source code must retain the above copyright notice,
    this list of conditions and the following disclaimer.
  - Redistributions in binary form must reproduce the above copyright notice,
    this list of conditions and the following disclaimer in the documentation
    and/or other materials provided with the distribution.
  - Modified versions of the software must be conspicuously marked as such.
  - This software is licensed solely and exclusively for use with processors
    manufactured by or for Analog Devices, Inc.
  - This software may not be combined or merged with other code in any manner
    that would cause the software to become subject to terms and conditions
    which differ from those listed here.
  - Neither the name of Analog Devices, Inc. nor the names of its
    contributors may be used to endorse or promote products derived
    from this software without specific prior written permission.
  - The use of this software may or may not infringe the patent rights of one
    or more patent holders.  This license does not release you from the
    requirement that you obtain separate licenses from these patent holders
    to use this software.

THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-
INFRINGEMENT, TITLE, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL ANALOG DEVICES, INC. OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, PUNITIVE OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, DAMAGES ARISING OUT OF
CLAIMS OF INTELLECTUAL PROPERTY RIGHTS INFRINGEMENT; PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*****************************************************************************/

/** @addtogroup UART_Driver
 *  @{
 *  @brief UART Driver
 *  @note  The application must include drivers/uart/adi_uart.h to use this driver
 *  @note  This driver requires the DMA driver.The application must
 *         include the DMA driver sources to avoid link errors.
 *  @note  This documentation presented here is API documentation only. The device drive user's guide,
 *         located in the Documents folder, explains how to use these APIs in an application.
 */

/*!  \cond PRIVATE */
#include <adi_uart.h>
#include <adi_dma.h>
#include "adi_uart_def.h"
#include <adi_cyclecount.h>


#ifdef __ICCARM__
/*
* IAR MISRA C 2004 error suppressions.
*
* Pm50: (MISRA C 2004 rule 14.3): a null statement shall only occur on a line by itself,
*                                 and shall not have any other text on the same line
*                                 Some Macros, such as ISR_PROLOGUE, may not have any expansion
*                                 resulting in just the terminating ';'.
*
* Pm073 (rule 14.7): A function should have a single point of exit.
* Pm143 (rule 14.7): A function should have a single point of exit at the end of the function.
*                    Multiple returns are used for error handling.
*
* Pm088 (rule 17.4): Pointer arithmetic should not be used.
*                    Relying on pointer arithmetic for buffer handling.
*
* Pm123 (rule 18.5): There shall be no definition of objects in a header file.
*
* Pm140 (rule 11.3): A cast should not be performed between a pointer type and an integral type.
*                    MMR addresses are defined as simple constants. Accessing the MMR requires casting to a pointer type.
*
* Pm152 (rule 17.4): Array indexing shall only be applied to objects defined as an array type.
*                    Relying on pointer arithmetic for buffer handling and
*                    Accessing the DMA descriptors, which are defined in the system as a pointer to an array of descriptors.
*
* Pm008: Code should not be commented out.
         This code was commented out to show what the autobaud equations would look like if there were floating point precision.
         Ideally this would be the case but for the sake of footprint size we will leave it at single point precision.
*/
#pragma diag_suppress=Pm050,Pm073,Pm088,Pm123,Pm140,Pm143,Pm152,Pm008,Pm026
#endif /* __ICCARM__ */




/**********************************************************
 * UART Data
 **********************************************************/
static  ADI_UART_DEVICE_INFO uart_device_info[ ] =
{
  {
    UART0_TX_CHANn,             /*!< DMA channel number for UART0 Tx. */
    UART0_RX_CHANn,             /*!< DMA channel number for UART0 Rx. */
    DMA0_CH8_DONE_IRQn,         /*!< DMA channel IRQ for UART0 Tx.    */
    DMA0_CH9_DONE_IRQn,         /*!< DMA channel IRQ for UART0 Rx.    */
    (IRQn_Type)INTR_UART0_EVT,  /*!< UART0 interrupt ID.              */
    pADI_UART0,                 /*!< Start address of UART0.          */
    NULL                        /*!< Device Handle for UART0.         */
  },
#if defined (__ADUCM4x50__)
  {
    UART1_TX_CHANn,             /*!< DMA channel number for UART1 Tx. */
    UART1_RX_CHANn,             /*!< DMA channel number for UART1 Rx. */
    DMA0_CH25_DONE_IRQn,        /*!< DMA channel IRQ for UART1 Tx.    */
    DMA0_CH26_DONE_IRQn,        /*!< DMA channel IRQ for UART1 Rx.    */
    (IRQn_Type)INTR_UART1_EVT,  /*!< UART1 interrupt ID.              */
    pADI_UART1,                 /*!< Start address of UART1.          */
    NULL                        /*!< Device Handle for UART1.         */
  },
#endif /* __ADUCM4x50 */ 
};

static const ADI_UART_CONFIG gUARTCfg[ ] =
{
    {
      /* Line control register.                                         */
      ((ADI_UART0_CFG_WORD_LENGTH          << BITP_UART_LCR_WLS)  |
       (ADI_UART0_CFG_STOP_BIT             << BITP_UART_LCR_STOP) |
       (ADI_UART0_CFG_ENABLE_PARITY        << BITP_UART_LCR_PEN)  |
       (ADI_UART0_CFG_PARITY_SELECTION     << BITP_UART_LCR_EPS)  |
       (ADI_UART0_CFG_ENABLE_STICKY_PARITY << BITP_UART_LCR_SP)),

      /* Div-C in baudrate divider register.                            */
      ADI_UART0_CFG_DIVC,

      /* Div-M and Div-N in fractional baudrate Register.               */
      (((uint32_t)ADI_UART0_CFG_DIVN       << BITP_UART_FBR_DIVN) |
       ((uint32_t)ADI_UART0_CFG_DIVM       << BITP_UART_FBR_DIVM) |
       ((uint32_t)BITM_UART_FBR_FBEN)),

      /* Over sample rate in second line control register.              */
      ADI_UART0_CFG_OSR,

      /* FIFO control register.                                         */
      ((ADI_UART0_CFG_ENABLE_FIFO          << BITP_UART_FCR_FIFOEN)|
       (ADI_UART0_CFG_TRIG_LEVEL           << BITP_UART_FCR_RFTRIG)),

      /* Half duplex control register.                                  */
      ((ADI_UART0_CFG_SOUT_POLARITY        << BITP_UART_RSC_OENP)  |
       (ADI_UART0_CFG_DEASSERTION          << BITP_UART_RSC_OENSP) |
       (ADI_UART0_CFG_DISABLE_RX           << BITP_UART_RSC_DISRX) |
       (ADI_UART0_CFG_HOLD_TX              << BITP_UART_RSC_DISTX)),

      /* Interrupt enable register.                                     */
      ((ADI_UART0_CFG_ENABLE_MODEM_STATUS_INTERRUPT << BITP_UART_IEN_EDSSI) |
      (ADI_UART0_CFG_ENABLE_RX_STATUS_INTERRUPT     << BITP_UART_IEN_ELSI))

    },
#if defined (__ADUCM4x50__)
    {
      /* Line control register.                                         */
      ((ADI_UART1_CFG_WORD_LENGTH          << BITP_UART_LCR_WLS)  |
       (ADI_UART1_CFG_STOP_BIT             << BITP_UART_LCR_STOP) |
       (ADI_UART1_CFG_ENABLE_PARITY        << BITP_UART_LCR_PEN)  |
       (ADI_UART1_CFG_PARITY_SELECTION     << BITP_UART_LCR_EPS)  |
       (ADI_UART1_CFG_ENABLE_STICKY_PARITY << BITP_UART_LCR_SP)),

      /* Div-C in Baudrate divider register.                            */
      ADI_UART1_CFG_DIVC,

      /* Div-M and Div-N in fractional baudrate Register.               */
      (((uint32_t)ADI_UART1_CFG_DIVN       << BITP_UART_FBR_DIVN) |
       ((uint32_t)ADI_UART1_CFG_DIVM       << BITP_UART_FBR_DIVM) |
       ((uint32_t)BITM_UART_FBR_FBEN)),

      /* Over sample rate in second line control register.              */
      ADI_UART1_CFG_OSR,

      /* FIFO control register.                                         */
      ((ADI_UART1_CFG_ENABLE_FIFO          << BITP_UART_FCR_FIFOEN)|
       (ADI_UART1_CFG_TRIG_LEVEL           << BITP_UART_FCR_RFTRIG)),

      /* Half duplex control register.                                  */
      ((ADI_UART1_CFG_SOUT_POLARITY        << BITP_UART_RSC_OENP)  |
       (ADI_UART1_CFG_DEASSERTION          << BITP_UART_RSC_OENSP) |
       (ADI_UART1_CFG_DISABLE_RX           << BITP_UART_RSC_DISRX) |
       (ADI_UART1_CFG_HOLD_TX              << BITP_UART_RSC_DISTX)),

      /* Interrupt enable register.                                     */
      ((ADI_UART1_CFG_ENABLE_MODEM_STATUS_INTERRUPT << BITP_UART_IEN_EDSSI) |
       (ADI_UART1_CFG_ENABLE_RX_STATUS_INTERRUPT    << BITP_UART_IEN_ELSI))
    }
#endif /*__ADUCM4x50*/
};

/* Number of bytes received before Rx interrupt triggers. */
static const uint8_t sFifoTriggers[] = {1u, 4u, 8u, 14u};

/*! \endcond */

/*! Number of UART devices available on the chip. */
#define ADI_UART_NUM_DEVICES (sizeof(uart_device_info)/sizeof(ADI_UART_DEVICE_INFO))

/* Override "weak" default binding in startup.c */
/*! \cond PRIVATE */
extern void UART0_Int_Handler(void);
extern void UART1_Int_Handler(void);
extern void DMA_UART0_TX_Int_Handler(void);
extern void DMA_UART0_RX_Int_Handler(void);

#if defined (__ADUCM4x50__)
extern void DMA_UART1_TX_Int_Handler(void);
extern void DMA_UART1_RX_Int_Handler(void);
#endif

/* Internal DMA Callback for receiving DMA faults from common DMA error handler. */
static void RxDmaErrorCallback(void *pCBParam, uint32_t Event, void *pArg);
static void RxDmaErrorCallback(void *pCBParam, uint32_t Event, void *pArg) {

    /* Recover the device handle. */
    ADI_UART_HANDLE hDevice = (ADI_UART_HANDLE)pCBParam;
    ADI_UART_BUFF_INFO * pNextBuff = hDevice->pChannelRx->pFillBuffer->pNextBuffer;
    uint32_t nEvent = 0u;

    /* Save the DMA error. */
    switch (Event) {
        case ADI_DMA_EVENT_ERR_BUS:
            nEvent |= (uint32_t)ADI_UART_HW_ERR_RX_CHAN_DMA_BUS_FAULT;
            break;
        case ADI_DMA_EVENT_ERR_INVALID_DESCRIPTOR:
            nEvent |= (uint32_t)ADI_UART_HW_ERR_RX_CHAN_DMA_INVALID_DESCR;
            break;
        default:
            nEvent |= (uint32_t)ADI_UART_HW_ERR_RX_CHAN_DMA_UNKNOWN_ERROR;
            break;
    }

    if((pNextBuff->pStartAddress != NULL) && (pNextBuff->bDMA == true))
    {
        hDevice->nHwError |= nEvent;
        pNextBuff->bInUse = false;
        uart_ManageProcessedBuffer(hDevice,hDevice->pChannelRx,ADI_UART_EVENT_RX_BUFFER_PROCESSED);

    }
    hDevice->nHwError |= nEvent;
    uart_ManageProcessedBuffer(hDevice,hDevice->pChannelRx,ADI_UART_EVENT_RX_BUFFER_PROCESSED);
}

static void TxDmaErrorCallback(void *pCBParam, uint32_t Event, void *pArg);
static void TxDmaErrorCallback(void *pCBParam, uint32_t Event, void *pArg) {

    /* Recover the device handle. */
    ADI_UART_HANDLE hDevice = (ADI_UART_HANDLE)pCBParam;
    ADI_UART_BUFF_INFO * pNextBuff = hDevice->pChannelTx->pFillBuffer->pNextBuffer;
    uint32_t nEvent = 0u;

    /* Save the DMA error. */
    switch (Event) {
        case ADI_DMA_EVENT_ERR_BUS:
            nEvent |= (uint32_t)ADI_UART_HW_ERR_TX_CHAN_DMA_BUS_FAULT;
            break;
        case ADI_DMA_EVENT_ERR_INVALID_DESCRIPTOR:
            nEvent |= (uint32_t)ADI_UART_HW_ERR_TX_CHAN_DMA_INVALID_DESCR;
            break;
        default:
            nEvent |= (uint32_t)ADI_UART_HW_ERR_TX_CHAN_DMA_UNKNOWN_ERROR;
            break;
    }
    if((pNextBuff->pStartAddress != NULL) && (pNextBuff->bDMA == true))
    {
        hDevice->nHwError |= nEvent;
        pNextBuff->bInUse = false;
        uart_ManageProcessedBuffer(hDevice,hDevice->pChannelTx,ADI_UART_EVENT_TX_BUFFER_PROCESSED);

    }

    hDevice->nHwError |= nEvent;
    uart_ManageProcessedBuffer(hDevice,hDevice->pChannelTx,ADI_UART_EVENT_TX_BUFFER_PROCESSED);
}
/*! \endcond */

/**********************************************************
 * General UART APIs
 **********************************************************/

/*!
 * @brief       Initialization function for the UART device.
 * @details     Opens the specified UART device. This function must be called before operating any UART device.
 *
 *
 * @param [in]  nDeviceNum     UART device instance to be opened.
 * @param [in]  eDirection     Direction of the UART operation. (i.e Rx or Tx)
 * @param [in]  pMemory        Pointer to a 32 bit aligned buffer the size of #ADI_UART_UNIDIR_MEMORY_SIZE
 *                             or #ADI_UART_BIDIR_MEMORY_SIZE.
 * @param [in]  nMemSize       Size of the buffer to which "pMemory" points. This will vary based on
 *                             direction of operation for this device instance. (i.e Rx and Tx, Rx, Tx)
 *
 * @param [out] phDevice       The caller's device handle pointer for storing the initialized device instance data pointer.
 *
 * @return      Status
 *              - #ADI_UART_SUCCESS                     Successfully initialized UART device.
 *              - #ADI_UART_SEMAPHORE_FAILED            Failed to create semaphore.
 *              - #ADI_UART_INVALID_DEVICE_NUM      [D] Device instance is invalid.
 *              - #ADI_UART_INSUFFICIENT_MEMORY     [D] Supplied memory is insufficient for the operation of specified UART device.
 *              - #ADI_UART_DEVICE_IN_USE           [D] Device is already open.
 *
 * @sa  adi_uart_Close()
 *
 * @note: Memory supplied by the API will be used by the driver for managing the UART device. This memory can be reused once
 *        device is closed.
 *
 */
ADI_UART_RESULT adi_uart_Open(
                              uint32_t            const nDeviceNum,
                              ADI_UART_DIRECTION  const eDirection,
                              void                     *pMemory,
                              uint32_t            const nMemSize,
                              ADI_UART_HANDLE    *const phDevice
                             )
{
    uint16_t regFifoTrig = 0u;
    
#ifdef ADI_DEBUG
    /* Check if the given device number is within the range of UART
     * devices present in the processor. There are two devices present here
     * so this can be a 0 or 1 for ADuCM4050 and only 0 for ADuCM302x.
     */
    if(nDeviceNum >= ADI_UART_NUM_DEVICES)
    {
        return(ADI_UART_INVALID_DEVICE_NUM);
    }

    /* Verify the device is not already open. */
    if(uart_device_info[nDeviceNum].hDevice != NULL)
    {
        return(ADI_UART_DEVICE_IN_USE);
    }

    /* Make sure there is enough memory for the device instance to operate in a single direction. */
    if(eDirection !=  ADI_UART_DIR_BIDIRECTION)
    {
        if(nMemSize < (uint32_t)ADI_UART_UNIDIR_MEMORY_SIZE)
        {
            return(ADI_UART_INSUFFICIENT_MEMORY);
        }
        assert(nMemSize == (sizeof(ADI_UART_DEVICE) + sizeof(ADI_UART_DATA_CHANNEL)));
    }

    /* Make sure there is enough memory for the device instance to operate in both directions. */
    else
    {
        if(nMemSize < (uint32_t)ADI_UART_BIDIR_MEMORY_SIZE)
        {
            return(ADI_UART_INSUFFICIENT_MEMORY);
        }
        assert(nMemSize == (sizeof(ADI_UART_DEVICE) + (sizeof(ADI_UART_DATA_CHANNEL)*2u)));
    }
#endif /* ADI_DEBUG */

    /* Initialize the device handle to NULL in case of a failure. */
    *phDevice = NULL;

    /* Link the ADI_UART_HANDLE to the ADI_UART_DEVICE structure. */
     ADI_UART_HANDLE hDevice = pMemory;

    /* Zero the device handle memory so we do not have to explicitely initialize
       the structure members to 0.
    */
    memset(pMemory, 0, nMemSize);


    /* Set the device information. */
    hDevice->pUartInfo = &uart_device_info[nDeviceNum];

    /* Set the base of the UART register address. We do this to minimize
       the cycle count when accessing the UART registers.
    */
    hDevice->pUARTRegs = uart_device_info[nDeviceNum].pUartRegs;
    
    /* Store the direction that this device will operate in. */
    hDevice->eDirection = eDirection;

    /* Increment the device handle with the size of the UART device structure
       so we can set the channel data next without overwriting
       the #ADI_UART_DEVICE data.
    */
    pMemory = ((uint8_t *)pMemory +(sizeof(ADI_UART_DEVICE)));

    /* Set up the DMA Controller. */
    adi_dma_Init();

    /* Initialize the TX-channel. */
    if(ADI_UART_DIR_RECEIVE != eDirection)
    {
         hDevice->pChannelTx = (ADI_UART_DATA_CHANNEL *)pMemory;

         /* Initialize the data transfer mode. */
         hDevice->pChannelTx->eDataTranferMode = ADI_UART_DATA_TRANSFER_MODE_NONE;

         /* Initialize Tx buffer pointers. */
         hDevice->pChannelTx->pFreeBuffer = &hDevice->pChannelTx->PingPong[0];
         hDevice->pChannelTx->pActiveBuffer = &hDevice->pChannelTx->PingPong[0];
         hDevice->pChannelTx->pFillBuffer = &hDevice->pChannelTx->PingPong[0];


         /* Create a "semaphore" (varies per OS) used for blocking buffer resource management. */
         SEM_CREATE(hDevice->pChannelTx, "UART_TX_SEM", ADI_UART_SEMAPHORE_FAILED);

         /* Set submit buffer function pointer. */
         hDevice->pChannelTx->pfSubmitBuffer = &uart_submittxbuffer;

         hDevice->pChannelTx->PingPong[0].pNextBuffer  = &hDevice->pChannelTx->PingPong[1];
         hDevice->pChannelTx->PingPong[1].pNextBuffer  = &hDevice->pChannelTx->PingPong[0];

         /*Register DMA Callback. */
         if (ADI_DMA_SUCCESS != adi_dma_RegisterCallback(hDevice->pUartInfo->dmaTxChannelNum, TxDmaErrorCallback, (void*)hDevice))
         {
              adi_uart_Close(hDevice);
              return  ADI_UART_ERR_DMA_REGISTER;
         }

         /* Increment the device handle the size of #ADI_UART_DATA_CHANNEL
            structure in case there is another channel to configure.
         */
         pMemory =  ((uint8_t *)pMemory + sizeof(ADI_UART_DATA_CHANNEL));
    }
    /* Initialize the RX-channel. */
    if(ADI_UART_DIR_TRANSMIT != eDirection)
    {
        hDevice->pChannelRx = (ADI_UART_DATA_CHANNEL *)pMemory;

        /* Initialize the data transfer mode. */
        hDevice->pChannelRx->eDataTranferMode = ADI_UART_DATA_TRANSFER_MODE_NONE;

        /* Initialize Rx buffer pointers. */
        hDevice->pChannelRx->pFreeBuffer = &hDevice->pChannelRx->PingPong[0];
        hDevice->pChannelRx->pActiveBuffer = &hDevice->pChannelRx->PingPong[0];
        hDevice->pChannelRx->pFillBuffer = &hDevice->pChannelRx->PingPong[0];

        /* Create a "semaphore" (varies per OS) used for blocking buffer resource management. */
        SEM_CREATE(hDevice->pChannelRx, "UART_RX_SEM", ADI_UART_SEMAPHORE_FAILED);

        /* Set submit buffer function pointer. */
        hDevice->pChannelRx->pfSubmitBuffer = &uart_submitrxbuffer;

        hDevice->pChannelRx->PingPong[0].pNextBuffer  = &hDevice->pChannelRx->PingPong[1];
        hDevice->pChannelRx->PingPong[1].pNextBuffer  = &hDevice->pChannelRx->PingPong[0];

         /*Register DMA Callback. */
         if (ADI_DMA_SUCCESS != adi_dma_RegisterCallback(hDevice->pUartInfo->dmaRxChannelNum, RxDmaErrorCallback, (void*)hDevice))
         {
              adi_uart_Close(hDevice);
              return  ADI_UART_ERR_DMA_REGISTER;
         }
    }

    /* Initialize the device with the static config values.*/
    uart_init(hDevice, nDeviceNum);

    /* Extract the FIFO and FIFO trigger settings.  These are required in 
     * the Rx interrupt handler to extract the right amount of data on an 
     * each Rx interrupt */
    hDevice->bRxFifoEn = ((hDevice->pUARTRegs->FCR & BITM_UART_FCR_FIFOEN) > 0u); 
    regFifoTrig = ((hDevice->pUARTRegs->FCR & BITM_UART_FCR_RFTRIG) >> BITP_UART_FCR_RFTRIG);
    
    hDevice->nRxFifoTrig = sFifoTriggers[regFifoTrig];
    
    /* Write the device data pointer to the application's handle. */
    *phDevice = hDevice;

    /* Store the device handle. */
    uart_device_info[nDeviceNum].hDevice = hDevice;


    /* Enable UART Interrupt. */
    NVIC_ClearPendingIRQ(hDevice->pUartInfo->eIRQn);
    NVIC_EnableIRQ(hDevice->pUartInfo->eIRQn);

    /* Enable the interrupt for the DMA. */
    NVIC_EnableIRQ(hDevice->pUartInfo->eDMATx);
    NVIC_EnableIRQ(hDevice->pUartInfo->eDMARx);

    /* Return SUCCESS */
    return(ADI_UART_SUCCESS);
}

/*!
 * @brief       Uninitialize the memory for the specified UART instance.
 *
 * @param [in]  hDevice   UART device handle whose operation is to be closed. This handle was obtained when the UART
 *                        device instance was opened successfully.
 *
 * @return      Status
 *    - #ADI_UART_SUCCESS               Successfully closed the UART device instance.
 *    - #ADI_UART_SEMAPHORE_FAILED      Failed to delete the semaphore.
 *    - #ADI_UART_INVALID_HANDLE    [D] Invalid UART device handle.
 *    - #ADI_UART_DEVICE_IN_USE     [D] Specified UART device is in the process of a transaction or autobaud has not completed.
 *
 * @details     Closes the operation of specified UART device. Device needs to be opened again for any further use.
 *
 * @sa  adi_uart_Open()
 *
 * @note: It is the user's responsibility to free/reuse the memory supplied during the opening of the device.
 */
ADI_UART_RESULT adi_uart_Close(
                               ADI_UART_HANDLE const hDevice
                              )
{
#ifdef ADI_DEBUG
    /* Validate the given handle. */
    if(ValidateHandle(hDevice) != ADI_UART_SUCCESS)
    {
        return(ADI_UART_INVALID_HANDLE);
    }

    /* Make sure there are no active buffers on any active channel, autobaud is not in progress and the
       Tx shift register is completely empty. This can be an issue if you submitted a nonblocking transmit
       because you will receive interrupt before the hardware has fully finished the transaction. The start
       address of the active buffer will remain in use until the buffer has been completely processed.
       Therefore if the start address is NULL it means it has not been submitted for a transaction.
    */
    if(((hDevice->pUARTRegs->LSR & BITM_UART_LSR_TEMT) != BITM_UART_LSR_TEMT)                                        ||
       ((hDevice->eDirection != ADI_UART_DIR_TRANSMIT) && (hDevice->pChannelRx->pFillBuffer->pStartAddress != NULL)) ||
       ((hDevice->eDirection != ADI_UART_DIR_RECEIVE ) && (hDevice->pChannelTx->pFillBuffer->pStartAddress != NULL)) ||
       (hDevice->bAutobaudInProgress == true))
    {
        return(ADI_UART_DEVICE_IN_USE);
    }
#endif /* ADI_DEBUG */

    /* Disable UART status interrupts. */
    hDevice->pUARTRegs->IEN = 0x00U;

    /* Disable DMA UART interrupts. */
    NVIC_DisableIRQ(hDevice->pUartInfo->eDMARx);
    NVIC_DisableIRQ(hDevice->pUartInfo->eDMATx);

    /* Disable UART event interrupt. */
    NVIC_DisableIRQ(hDevice->pUartInfo->eIRQn);

    /* Delete Tx-Channel semaphore. */
    if(hDevice->eDirection != ADI_UART_DIR_RECEIVE)
    {
        SEM_DELETE(hDevice->pChannelTx, ADI_UART_SEMAPHORE_FAILED);
    }

    /* Delete Rx-Channel semaphore. */
    if(hDevice->eDirection != ADI_UART_DIR_TRANSMIT)
    {
        SEM_DELETE(hDevice->pChannelRx, ADI_UART_SEMAPHORE_FAILED);
    }

     /* Free up the device memory. */
    hDevice->pUartInfo->hDevice = NULL;

    return(ADI_UART_SUCCESS);
}

/*!
 * @brief       Submit a "filled" buffer for transmitting data in #ADI_UART_DATA_TRANSFER_MODE_NONBLOCKING.
 *              This function sets up the apropriate interrupts associated with the transaction and marks
 *              the buffer as submitted.
 *
 * @param [in]  hDevice    Device handle obtained from adi_uart_Open().
 * @param [in]  pBuffer    Pointer to data supplied by the API that is to be transmitted.
 * @param [in]  nBufSize   Size of the buffer to be transmitted(in bytes). Must be smaller than 1024 bytes for DMA transfers.
 * @param [in]  bDMA       Submit the buffer using the DMA flag.

 *
 * @return      Status
 *    - #ADI_UART_SUCCESS                        Successfully submitted the buffer for transmission.
 *    - #ADI_UART_FAILED                     [D] Generic failure. In this case the size of the data buffer we are trying
 *                                               to submit is NULL.
 *    - #ADI_UART_INVALID_DATA_TRANSFER_MODE [D] Device is operating in #ADI_UART_DATA_TRANSFER_MODE_BLOCKING. This
 *                                               operation is only allowed in #ADI_UART_DATA_TRANSFER_MODE_NONBLOCKING.
 *    - #ADI_UART_INVALID_HANDLE             [D] Invalid UART device handle.
 *    - #ADI_UART_OPERATION_NOT_ALLOWED      [D] Device direction is set up as #ADI_UART_DIR_RECEIVE, so we can not complete
 *                                               a transmit operation. The required directions are #ADI_UART_DIR_TRANSMIT or
 *                                               #ADI_UART_DIR_BIDIRECTION.
 *    - #ADI_UART_INVALID_POINTER            [D] Pointer to the buffer being submitted is NULL.
 *    - #ADI_UART_DEVICE_IN_USE              [D] Autobaud in progress.
 *    - #ADI_UART_INVALID_DATA_SIZE          [D] DMA transfers must be smaller than 1025 bytes.
 *
 * @sa  adi_uart_IsTxBufferAvailable()
 * @sa  adi_uart_GetTxBuffer()
 * @sa  adi_uart_SubmitRxBuffer()
 *
 * @note: Only one transfer mode (DMA vs. PIO) can be used at once. For example, if you submit a buffer in PIO mode
 *        and then right away another using the DMA, this transaction will be denied.
 *
 */
ADI_UART_RESULT adi_uart_SubmitTxBuffer(
                                         ADI_UART_HANDLE const hDevice,
                                         void           *const pBuffer,
                                         uint32_t        const nBufSize,
                                         bool            const bDMA
                                       )
{

#ifdef ADI_DEBUG
    /* Validate the device handle. */
    if(ValidateHandle(hDevice) != ADI_UART_SUCCESS)
    {
        return(ADI_UART_INVALID_HANDLE);
    }

    /* Validate the pointer to the buffer memory. */
    if(pBuffer == NULL)
    {
        return(ADI_UART_INVALID_POINTER);
    }

    /* Validate the buffer size. */
    if(nBufSize == 0U)
    {
        return(ADI_UART_FAILED);
    }

    /* Autobaud in progress. */
    if(hDevice->bAutobaudInProgress == true)
    {
        return(ADI_UART_DEVICE_IN_USE);
    }

    /* Make sure we are transmitting. */
    if(ADI_UART_DIR_RECEIVE == hDevice->eDirection)
    {
        return(ADI_UART_OPERATION_NOT_ALLOWED);
    }

    /* Check the data transfer mode (only allowed in nonblocking mode). */
    if(hDevice->pChannelTx->eDataTranferMode == ADI_UART_DATA_TRANSFER_MODE_BLOCKING)
    {
        return(ADI_UART_INVALID_DATA_TRANSFER_MODE);
    }

    /* Check that there is a free buffer to use for this transmit operation. pFreeBuffer
       is the next buffer available, so if it is in use we can make the assumption that
       there are no buffers available. The start address is set to NULL once the buffer
       has finished being processed in "adi_uart_GetBuffer()" or "adi_uart_PendForBuffer()".
    */
    if(hDevice->pChannelTx->pFreeBuffer->pStartAddress != NULL)
    {
        return(ADI_UART_OPERATION_NOT_ALLOWED);
    }

    /* Make sure the DMA transfer size is not too large. */
    if((bDMA == true) && (nBufSize > DMA_TRANSFER_LIMIT))
    {
        return(ADI_UART_INVALID_DATA_SIZE);
    }

#endif /* ADI_DEBUG */

     /* Set the start address of the data buffer we are going to submit. */
     hDevice->pChannelTx->pFreeBuffer->pStartAddress =   pBuffer;

     /* Set the buffer size to the size of the data buffer passed down from the API. */
     hDevice->pChannelTx->pFreeBuffer->nCount        =   nBufSize;

     /* Initialize the buffer index to zero because we will start shifting out
        the Tx data from the first position of the buffer.
     */
     hDevice->pChannelTx->pFreeBuffer->nIndex        =   0U;

     /* Mark the buffer as in use so no other transactions can use it until this one is complete. */
     hDevice->pChannelTx->pFreeBuffer->bInUse        =   true;

     /* Mark the DMA as in use. */
     hDevice->pChannelTx->pFreeBuffer->bDMA          =   bDMA;

     /* Now that this "pFreeBuffer" is no longer free for use, update the
        "pFreeBuffer" to the other PingPong buffer. Because there are only two
        buffers in the PingPong structure, this will be the opposite of the one
        we just submitted. "pFreeBuffer" will only be updated during the process of
        submitting a buffer or a read/write operation.
     */
      hDevice->pChannelTx->pFreeBuffer = hDevice->pChannelTx->pFreeBuffer->pNextBuffer;

     /* Set the data transfer mode in case it was #ADI_UART_DATA_TRANSFER_MODE_NONE.
        This will be set back to #ADI_UART_DATA_TRANSFER_MODE_NONE once this
        transaction is complete. Then, if a buffer is not currently active, set up the
        interrupts for this transaction. Otherwise if a buffer is currently active,
        this will be taken care of in the ISR.
     */
     if (hDevice->pChannelTx->eDataTranferMode == ADI_UART_DATA_TRANSFER_MODE_NONE)
     {
         hDevice->pChannelTx->eDataTranferMode = ADI_UART_DATA_TRANSFER_MODE_NONBLOCKING;
         hDevice->pChannelTx->pfSubmitBuffer(hDevice, hDevice->pChannelTx->pFillBuffer);
     }

     return(ADI_UART_SUCCESS);
  }

/*!  \cond PRIVATE */

/*
 * @brief      This is an internal helper function for adi_uart_SubmitTxBuffer(). It sets up the Tx channel DMA
               or device interrupts for the Tx channel to transmit data.
 *
 * @param [in]  hDevice    Device handle obtained from adi_uart_Open().
 * @param [in]  pBuffer    Pointer to buffer from where data will be transmitted.
 * @param [in]  nBufSize   Size of the buffer containing the data to be transmitted(in bytes).
 * @param [in]  bDMA       Submit the buffer using the DMA.
*/
static void uart_submittxbuffer(
                                 ADI_UART_CONST_HANDLE  const hDevice,
                                 ADI_UART_BUFF_INFO    *const pBuffer
                               )
{
  /* If this transmission is using DMA... */
  if (pBuffer->bDMA)
  {
      /* Enable clear source address decrement for TX channel DMA. */
      pADI_DMA0->SRCADDR_CLR = 1u << (uint32_t)hDevice->pUartInfo->dmaTxChannelNum;

      /* Enable Tx channel DMA. */
      pADI_DMA0->EN_SET = 1u << hDevice->pUartInfo->dmaTxChannelNum;

      /* Enable UART peripheral to generate DMA requests. */
      pADI_DMA0->RMSK_CLR = 1u << hDevice->pUartInfo->dmaTxChannelNum;

      /* Set the primary control data structure as the current DMA descriptor. */
      pADI_DMA0->ALT_CLR = 1u << hDevice->pUartInfo->dmaTxChannelNum;

      /* Fill in the DMA RAM descriptors */
      pPrimaryCCD[hDevice->pUartInfo->dmaTxChannelNum].DMASRCEND =   ((uint32_t)pBuffer->pStartAddress + (uint32_t)(pBuffer->nCount - 1u));

      pPrimaryCCD[hDevice->pUartInfo->dmaTxChannelNum].DMADSTEND =   (uint32_t)&hDevice->pUARTRegs->TX;

      pPrimaryCCD[hDevice->pUartInfo->dmaTxChannelNum].DMACDC    =   ((uint32_t)ADI_DMA_INCR_NONE << DMA_BITP_CTL_DST_INC)      |
                                                                     ((uint32_t)ADI_DMA_INCR_1_BYTE << DMA_BITP_CTL_SRC_INC)    |
                                                                     (ADI_DMA_WIDTH_1_BYTE << DMA_BITP_CTL_SRC_SIZE)            |
                                                                     (0u << DMA_BITP_CTL_R_POWER)                               |
                                                                     ((pBuffer->nCount - 1u) << DMA_BITP_CTL_N_MINUS_1)         |
                                                                     (DMA_ENUM_CTL_CYCLE_CTL_BASIC << DMA_BITP_CTL_CYCLE_CTL);
      /* Enable UART DMA request interrupt for the Tx channel. */
      hDevice->pUARTRegs->IEN |= (BITM_UART_IEN_EDMAT);
  }
  else
  /* If this transmission is using UART interrupts.. */
  {
      /* Enable buffer empty interrupts.  */
      hDevice->pUARTRegs->IEN |= (BITM_UART_IEN_ETBEI);
  }
}

/*! \endcond */

/*!
 * @brief       Submit an empty buffer for receiving the data in #ADI_UART_DATA_TRANSFER_MODE_NONBLOCKING.
 *              This will set up the Rx channel for notification on incoming data using either the DMA
 *              or UART interrupts, as well as mark the buffer as submitted.
 *
 * @param [in]  hDevice    Device handle obtained from adi_uart_Open().
 * @param [in]  pBuffer    Pointer to buffer from that will be filled by the driver when data has been received.
 * @param [in]  nBufSize   Size of the buffer(in bytes). Must be smaller than 1024 bytes for DMA transfers.
 * @param [in]  bDMA       Submit the buffer using DMA flag.

 *
 * @return      Status
 *    - #ADI_UART_SUCCESS                        Successfully submitted the buffer for receiving data.
 *    - #ADI_UART_FAILED                     [D] Generic failure. In this case the size of the data buffer we are trying
 *                                               to submit is NULL.
 *    - #ADI_UART_INVALID_DATA_TRANSFER_MODE [D] Device is operating in #ADI_UART_DATA_TRANSFER_MODE_BLOCKING. This
 *                                               operation is only allowed in #ADI_UART_DATA_TRANSFER_MODE_NONBLOCKING.
 *    - #ADI_UART_INVALID_HANDLE             [D] Invalid UART device handle.
 *    - #ADI_UART_OPERATION_NOT_ALLOWED      [D] Device direction is set up as #ADI_UART_DIR_TRANSMIT, so we can not complete
 *                                               a receive operation. The required directions are #ADI_UART_DIR_RECEIVE or
 *                                               #ADI_UART_DIR_BIDIRECTION.
 *    - #ADI_UART_INVALID_POINTER            [D] Pointer to the buffer being submitted is NULL.
 *    - #ADI_UART_DEVICE_IN_USE              [D] Autobaud in progress.
 *    - #ADI_UART_INVALID_DATA_SIZE          [D] DMA transfers must be smaller than 1025 bytes.
 *
 * @sa  adi_uart_IsRxBufferAvailable()
 * @sa  adi_uart_GetRxBuffer()
 * @sa  adi_uart_SubmitTxBuffer()
 *
 * @note: Only one transfer mode (DMA vs. PIO) can be used at once. For example, if you submit a buffer in PIO mode
 *        and then right away another using the DMA, this transaction will be denied.
*/
ADI_UART_RESULT adi_uart_SubmitRxBuffer(
                                         ADI_UART_HANDLE const hDevice,
                                         void           *const pBuffer,
                                         uint32_t        const nBufSize,
                                         bool            const bDMA
                                       )
{

#ifdef ADI_DEBUG
    /* Validate the device handle. */
    if(ValidateHandle(hDevice) != ADI_UART_SUCCESS)
    {
        return(ADI_UART_INVALID_HANDLE);
    }

    /* Validate the pointer to the buffer memory. */
    if(pBuffer == NULL)
    {
        return(ADI_UART_INVALID_POINTER);
    }

    /* Validate the buffer size. */
    if(nBufSize == 0U )
    {
        return(ADI_UART_FAILED);
    }

    /* Autobaud in progress. */
    if(hDevice->bAutobaudInProgress == true)
    {
        return(ADI_UART_DEVICE_IN_USE);
    }

    /* Make sure the UART device is configured to operate in the receive direction. */
    if(ADI_UART_DIR_TRANSMIT == hDevice->eDirection)
    {
        return(ADI_UART_OPERATION_NOT_ALLOWED);
    }

    /* Check for the data transfer mode(only allowed in nonblocking mode). */
    if(hDevice->pChannelRx->eDataTranferMode == ADI_UART_DATA_TRANSFER_MODE_BLOCKING)
    {
        return(ADI_UART_INVALID_DATA_TRANSFER_MODE);
    }

    /* Check that there is a free buffer to use for this operation. pFreeBuffer
       is the next buffer available, so if it is in use we can make the assumption that
       there are no buffers available. If the start address is not set to NULL, then we
       can conclude the buffer has not finished being processed because this gets set in
       adi_uart_pend_for_buffer() and adi_uart_get_buffer().
    */
    if(hDevice->pChannelRx->pFreeBuffer->pStartAddress != NULL)
    {
        return(ADI_UART_OPERATION_NOT_ALLOWED);
    }

    /* Make sure the DMA transfer size is not too large. */
    if((bDMA == true) && (nBufSize > DMA_TRANSFER_LIMIT))
    {
        return(ADI_UART_INVALID_DATA_SIZE);
    }

#endif /* ADI_DEBUG */

    /* Set the start address of the buffer you are going to submit. */
     hDevice->pChannelRx->pFreeBuffer->pStartAddress =   pBuffer;

     /* Set the size of the buffer. */
     hDevice->pChannelRx->pFreeBuffer->nCount        =   nBufSize;

     /* Initialize the buffer index to 0, because as we receive data it will be put into
        the buffer starting at the first position.
     */
     hDevice->pChannelRx->pFreeBuffer->nIndex        =   0U;

     /* Mark the buffer as in use. */
     hDevice->pChannelRx->pFreeBuffer->bInUse        =   true;

     /* Mark the DMA as in use. */
     hDevice->pChannelRx->pFreeBuffer->bDMA          =   bDMA;

     /* Now that this "pFreeBuffer" is no longer free for use, update the
        "pFreeBuffer" to the other PingPong buffer. Because there are only two
        buffers in the PingPong structure, this will be the opposite of the one
        we just submitted. "pFreeBuffer" will only be updated during the process of
        submitting a buffer or a read/write operation.
     */
      hDevice->pChannelRx->pFreeBuffer = hDevice->pChannelRx->pFreeBuffer->pNextBuffer;


    /* Set the data transfer mode in case it was #ADI_UART_DATA_TRANSFER_MODE_NONE.
       This will be set back to #ADI_UART_DATA_TRANSFER_MODE_NONE once this
       transaction is complete. Then, if a buffer is not currently active, set up the
       interrupts for this transaction. Otherwise if a buffer is currently active,
       this will be taken care of in the ISR.
    */
     if (hDevice->pChannelRx->eDataTranferMode == ADI_UART_DATA_TRANSFER_MODE_NONE)
     {
         hDevice->pChannelRx->eDataTranferMode = ADI_UART_DATA_TRANSFER_MODE_NONBLOCKING;
         hDevice->pChannelRx->pfSubmitBuffer(hDevice, hDevice->pChannelRx->pFillBuffer);
     }

     return(ADI_UART_SUCCESS);
}

/*! \cond PRIVATE */

/*
 * @brief                  This is an internal helper function for adi_uart_SubmitRxBuffer(). It sets up the DMA
 *                         or device receive interrupts for the Rx channel to receive data.
 *
 * @param [in]  hDevice    Device handle obtained from adi_uart_Open().
 * @param [in]  pBuffer    Pointer to the empty receive buffer.
 * @param [in]  nBufSize   Size of the receive buffer(in bytes).
 * @param [in]  bDMA       Submit the buffer using the DMA.
*/
static void uart_submitrxbuffer(
                                 ADI_UART_CONST_HANDLE   const hDevice,
                                 ADI_UART_BUFF_INFO     *const pBuffer
                               )
{


    /* If this transaction is using the DMA.. */
    if (pBuffer->bDMA)
    {
        /* Enable source address decrement for RX DMA channel. */
        pADI_DMA0->DSTADDR_CLR = 1u << (uint32_t)hDevice->pUartInfo->dmaRxChannelNum;

        /* Enable Rx DMA channel. */
        pADI_DMA0->EN_SET = 1u << hDevice->pUartInfo->dmaRxChannelNum;

        /* Enable UART peripheral to generate DMA requests. */
        pADI_DMA0->RMSK_CLR = 1u << hDevice->pUartInfo->dmaRxChannelNum;

        /* Set the primary data structure as the current DMA descriptor. */
        pADI_DMA0->ALT_CLR = 1u << hDevice->pUartInfo->dmaRxChannelNum;

        /* Fill in the DMA RAM descriptors. */
        pPrimaryCCD[hDevice->pUartInfo->dmaRxChannelNum].DMASRCEND =   (uint32_t)&hDevice->pUARTRegs->RX;

        pPrimaryCCD[hDevice->pUartInfo->dmaRxChannelNum].DMADSTEND =   ((uint32_t)pBuffer->pStartAddress + (uint32_t)(pBuffer->nCount - 1u));

        pPrimaryCCD[hDevice->pUartInfo->dmaRxChannelNum].DMACDC    =   (uint32_t)(ADI_DMA_INCR_1_BYTE << DMA_BITP_CTL_DST_INC)            |
                                                                       (uint32_t)(ADI_DMA_INCR_NONE << DMA_BITP_CTL_SRC_INC)              |
                                                                       (ADI_DMA_WIDTH_1_BYTE << DMA_BITP_CTL_SRC_SIZE)                    |
                                                                       (0u << DMA_BITP_CTL_R_POWER)                                       |
                                                                       ((pBuffer->nCount - 1u) << DMA_BITP_CTL_N_MINUS_1)                 |
                                                                       (DMA_ENUM_CTL_CYCLE_CTL_BASIC << DMA_BITP_CTL_CYCLE_CTL);
        /* Enable UART receive DMA requests. */
        hDevice->pUARTRegs->IEN |= (BITM_UART_IEN_EDMAR);
    }
    /* If this transaction is using UART interrupts.. */
    else
    {
        /* Enable buffer full interrupt. */
        hDevice->pUARTRegs->IEN |= (BITM_UART_IEN_ERBFI);
    }
}

/*! \endcond */

/*!
 * @brief       Transfer buffer ownership from the device back to the API if the data
 *              transmit has completed. Otherwise it will block until completion.
 *              This allows a nonblocking call to become blocking.
 *              This function is only called in #ADI_UART_DATA_TRANSFER_MODE_NONBLOCKING.
 *
 * @param [in]  hDevice    Device handle obtained from adi_uart_Open().
 * @param [in]  ppBuffer   Contains the address of the buffer passed down from the API
 *                         for transmitting data.
 * @param [out] pHwError   Pointer to an integer that correlates with #ADI_UART_HW_ERRORS, containg the hardware status.
 *                         If there is no hardware event, this will be 0.
 *
 * @return      Status
 *    - #ADI_UART_SUCCESS                       Successfully returned buffer to the API.
 *    - #ADI_UART_HW_ERROR_DETECTED             Hardware error(s) detected. "pHwError" can be checked for the specific error code(s).
 *    - #ADI_UART_OPERATION_NOT_ALLOWED     [D] Call to this function is not allowed in #ADI_UART_DATA_TRANSFER_MODE_BLOCKING.
 *    - #ADI_UART_INVALID_HANDLE            [D] Invalid UART device handle.
 *    - #ADI_UART_BUFFER_NOT_SUBMITTED      [D] The buffer has not been submitted to the driver.
 *
 * @sa  adi_uart_IsTxBufferAvailable()
 * @sa  adi_uart_SubmitTxBuffer()
 *
 * @note: If the transaction has already completed, this will return immediately rather than block.
 */
ADI_UART_RESULT adi_uart_GetTxBuffer(
                                      ADI_UART_HANDLE const   hDevice,
                                      void          **const   ppBuffer,
                                      uint32_t               *pHwError
                                     )

{

#ifdef ADI_DEBUG
    /* Validate the device handle. */
    if(ValidateHandle(hDevice) != ADI_UART_SUCCESS)
    {
        return(ADI_UART_INVALID_HANDLE);
    }

    /* Validate that this buffer has actually been submitted. */
    if(hDevice->pChannelTx->pActiveBuffer->pStartAddress == NULL)
    {
        return(ADI_UART_BUFFER_NOT_SUBMITTED);
    }

    /* This function is allowed to be called when the channel is operating in NONBLOCKING mode. */
    if(hDevice->pChannelTx->eDataTranferMode ==  ADI_UART_DATA_TRANSFER_MODE_BLOCKING)
    {
        return(ADI_UART_OPERATION_NOT_ALLOWED);
    }
#endif /* ADI_DEBUG */

    /* Blocking call to get the submitted buffer */
    return(uart_getbuffer(hDevice, hDevice->pChannelTx, ppBuffer, pHwError));
}



/*!
 * @brief       Transfer buffer ownership from the device back to the API if the data
 *              receive has completed. Otherwise it will block until completion.
 *              This allows a nonblocking call to become blocking.
 *              This function is only called in #ADI_UART_DATA_TRANSFER_MODE_NONBLOCKING.
 *
 * @param [in]  hDevice    Device handle obtained from adi_uart_Open().
 * @param [in]  ppBuffer   Contains the address of the buffer passed down from the API
 *                         for receiving data.
 * @param [out] pHwError   Pointer to an integer that correlates with #ADI_UART_HW_ERRORS, containg the hardware status.
 *                         If there is no hardware event, this will be 0.
 *
 * @return      Status
 *    - #ADI_UART_SUCCESS                       Successfully returned buffer to the API.
 *    - #ADI_UART_HW_ERROR_DETECTED             Hardware error(s) detected. "pHwError" can be checked for the specific error code(s).
 *    - #ADI_UART_OPERATION_NOT_ALLOWED     [D] Call to this function is not allowed in #ADI_UART_DATA_TRANSFER_MODE_BLOCKING.
 *    - #ADI_UART_INVALID_HANDLE            [D] Invalid UART device handle.
 *    - #ADI_UART_BUFFER_NOT_SUBMITTED      [D] The buffer has not been submitted to the driver.
 *
 * @sa  adi_uart_IsRxBufferAvailable()
 * @sa  adi_uart_SubmitRxBuffer()
 *
 * @note: If the transaction has already completed, this will return immediately rather than block.
*/
ADI_UART_RESULT adi_uart_GetRxBuffer(
                                      ADI_UART_HANDLE  const   hDevice,
                                      void           **const   ppBuffer,
                                      uint32_t                *pHwError
                                     )

{

#ifdef ADI_DEBUG
    /* Validate the device handle. */
    if(ValidateHandle(hDevice) != ADI_UART_SUCCESS)
    {
        return(ADI_UART_INVALID_HANDLE);
    }

    /* Validate that this buffer has actually been submitted. */
    if(hDevice->pChannelRx->pActiveBuffer->pStartAddress == NULL)
    {
        return(ADI_UART_BUFFER_NOT_SUBMITTED);
    }

     /* This function is only allowed to be called when the channel is operating in NONBLOCKING mode. */
    if(hDevice->pChannelRx->eDataTranferMode ==  ADI_UART_DATA_TRANSFER_MODE_BLOCKING)
    {
        return(ADI_UART_OPERATION_NOT_ALLOWED);
    }
#endif /* ADI_DEBUG */

    /* Blocking call to get the full Rx Buffer */
    return(uart_getbuffer(hDevice, hDevice->pChannelRx, ppBuffer, pHwError));
}

/*! \cond PRIVATE */

/*
 * @brief       This is an internal helper function for adi_uart_GetRxBuffer() and adi_uart_GetTxBuffer().
 *              It blocks until until the completion of the data transaction.
 *
 * @param [in]  hDevice    Device handle obtained from adi_uart_Open().
 * @param [in]  pChannel   Pointer to UART channel data structure.
 * @param [out] ppBuffer   Contains the address of the buffer passed down from the API.
 * @param [out] pHwError   Pointer to an integer that correlates with #ADI_UART_HW_ERRORS, containg the hardware status.
 *                         If there is no hardware event, this will be 0.
 *
 * @return      Status
 *    - #ADI_UART_SUCCESS                Successfully got buffer.
 *    - #ADI_UART_HW_ERROR_DETECTED      Hardware error(s) detected. "pHwError" can be checked for the specific error code(s).
 *
*/
static ADI_UART_RESULT uart_getbuffer(
                                       ADI_UART_HANDLE        hDevice,
                                       ADI_UART_DATA_CHANNEL *pChannel,
                                       void                 **ppBuffer,
                                       uint32_t              *pHwError
                                      )
{
    /* Set ppBuffer to NULL in case there is an error. */
    *ppBuffer = NULL;

    /* Wait until the peripheral has finished processing the buffer. */
    SEM_PEND(pChannel,ADI_UART_FAILED);

    /* Save the address of the buffer that has just been processed, so it can be
       returned back to the API.
    */
    *ppBuffer = pChannel->pActiveBuffer->pStartAddress;

    /* Reinitialize the start address to NULL so this buffer can be used for a new transaction. */
    pChannel->pActiveBuffer->pStartAddress = NULL;

    /* Now that the desired data has either been transmitted or received, this buffer is no longer
       in use. We can update "pActiveBuffer" to point to the next buffer that will become or is already
       active.
    */
     pChannel->pActiveBuffer = pChannel->pActiveBuffer->pNextBuffer;

     /* Set the data transfer mode to none so that the next transfer can be either in blocking or in nonblocking mode.
        This will only be done if there are no other active buffers in flight to avoid disrupting an active transfer.
    */
     if(pChannel->pActiveBuffer->pStartAddress == NULL)
     {
        pChannel->eDataTranferMode = ADI_UART_DATA_TRANSFER_MODE_NONE;
     }

    /* If there are hardware errors and no callback, then return failure. */
    if(hDevice->nHwError != 0u)
    {
        /* Save the hardware error detected. This will be passed back to the API. */
        *pHwError = hDevice->nHwError;

        /* Clear any hardware errors detected. */
        hDevice->nHwError = 0u;

        return(ADI_UART_HW_ERROR_DETECTED);
    }
    else
    {
        return(ADI_UART_SUCCESS);
    }
}

/*! \endcond */


/*!
 * @brief       Submit the buffer for transmitting the data in #ADI_UART_DATA_TRANSFER_MODE_BLOCKING.
 *              Call to this function will not return until the entire buffer is transmitted.
 *              Returns error if this function is called when device is operating in #ADI_UART_DATA_TRANSFER_MODE_NONBLOCKING.
 *              i.e Function "adi_uart_SubmitTxBuffer()" is called and the transfer is not yet complete.
 *
 * @param [in]  hDevice    Device handle obtained from adi_uart_Open().
 * @param [in]  pBuffer    Pointer to data supplied by the API that is to be transmitted.
 * @param [in]  nBufSize   Size of the buffer(in bytes). Must be smaller than 1024 bytes for DMA transfers.
 * @param [in]  bDMA       Submit the buffer using the DMA flag.
 * @param [out] pHwError   Pointer to an integer that correlates with #ADI_UART_HW_ERRORS, containg the hardware status.
 *                         If there is no hardware event, this will be 0.
 *
 * @return      Status
 *    - #ADI_UART_SUCCESS                             Successfully transmitted the data from the submitted buffer.
 *    - #ADI_UART_HW_ERROR_DETECTED                   Hardware error(s) detected. "pHwError" can be checked for the specific error code(s).
 *    - #ADI_UART_FAILED                          [D] Generic failure. In this case the size of the data buffer we are trying
 *                                                    to submit is NULL.
 *    - #ADI_UART_INVALID_DATA_TRANSFER_MODE      [D] Device is operating in #ADI_UART_DATA_TRANSFER_MODE_NONBLOCKING. This
 *                                                    operation is only allowed in #ADI_UART_DATA_TRANSFER_MODE_BLOCKING.
 *    - #ADI_UART_OPERATION_NOT_ALLOWED           [D] Device direction is set up as #ADI_UART_DIR_RECEIVE, so we can not complete
 *                                                    a transmit operation. The required directions are #ADI_UART_DIR_TRANSMIT or
 *                                                    #ADI_UART_DIR_BIDIRECTION.
 *    - #ADI_UART_INVALID_HANDLE                  [D] Invalid UART device handle.
 *    - #ADI_UART_INVALID_POINTER                 [D] The pointer to the buffer being submitted is a NULL.
 *    - #ADI_UART_DEVICE_IN_USE                   [D] Autobaud in progress.
 *    - #ADI_UART_INVALID_DATA_SIZE               [D] DMA transfers must be smaller than 1025 bytes.
 *
 * @sa  adi_uart_Read()
 * @sa  adi_uart_SubmitTxBuffer()
 *
 * @note: This function is a blocking function which means that the function returns only after the completion of
 *        buffer transmission.
*/
ADI_UART_RESULT adi_uart_Write(
                               ADI_UART_HANDLE const hDevice,
                               void           *const pBuffer,
                               uint32_t        const nBufSize,
                               bool            const bDMA,
                               uint32_t             *pHwError
                              )
{

#ifdef ADI_DEBUG
        /* Validate the given handle. */
        if(ValidateHandle(hDevice) != ADI_UART_SUCCESS)
        {
            return(ADI_UART_INVALID_HANDLE);
        }

        /* Validate the pointer to the buffer memory. */
        if(pBuffer == NULL)
        {
            return(ADI_UART_INVALID_POINTER);
        }

        /* Validate the buffer size. */
        if(nBufSize == 0U )
        {
            return(ADI_UART_FAILED);
        }

        /* Autobaud in progress. */
        if(hDevice->bAutobaudInProgress == true)
        {
            return(ADI_UART_DEVICE_IN_USE);
        }

        /* Make sure we are transmitting. */
        if(ADI_UART_DIR_RECEIVE == hDevice->eDirection)
        {
            return(ADI_UART_OPERATION_NOT_ALLOWED);
        }

        /* Check for the data transfer mode (only allowed in blocking mode). */
        if(hDevice->pChannelTx->eDataTranferMode == ADI_UART_DATA_TRANSFER_MODE_NONBLOCKING)
        {
            return(ADI_UART_INVALID_DATA_TRANSFER_MODE);
        }

        /* Check that there is a free buffer to use for this transmit operation. "pFreeBuffer"
          is the next buffer available, so if it is in use we can make the assumption that
          there are no buffers available. The start address is set to NULL once the buffer
          has been processed.
        */
        if(hDevice->pChannelTx->pFreeBuffer->pStartAddress != NULL)
        {
            return(ADI_UART_OPERATION_NOT_ALLOWED);
        }

        /* Make sure the DMA transfer size is not too large. */
        if((bDMA == true) && (nBufSize > DMA_TRANSFER_LIMIT))
        {
            return(ADI_UART_INVALID_DATA_SIZE);
        }

#endif /* ADI_DEBUG */

        /* Set the data transfer mode in case it was #ADI_UART_DATA_TRANSFER_MODE_NONE. */
        hDevice->pChannelTx->eDataTranferMode = ADI_UART_DATA_TRANSFER_MODE_BLOCKING;

        /* Set the start address of the data buffer we are going to submit. */
        hDevice->pChannelTx->pFreeBuffer->pStartAddress  =   pBuffer;

        /* Set the buffer size to the size of the data buffer passed down from the API. */
        hDevice->pChannelTx->pFreeBuffer->nCount         =   nBufSize;

        /* Initialize the buffer index to zero because we will start shifting out
           the Tx data from the first position of the buffer.
        */
        hDevice->pChannelTx->pFreeBuffer->nIndex         =   0U;

        /* Mark the buffer as in use so no other transactions can use it until this one is complete. */
        hDevice->pChannelTx->pFreeBuffer->bInUse         =   true;

        /* Mark the DMA as in use. */
        hDevice->pChannelTx->pFreeBuffer->bDMA           =   bDMA;

        /* Now that this "pFreeBuffer" is no longer free for use, update the
           "pFreeBuffer" to the other PingPong buffer. Because there are only two
           buffers in the PingPong structure, this will be the opposite of the one
           we just submitted. "pFreeBuffer" will only be updated during the process of
           submitting a buffer or a read/write operation.
        */
        hDevice->pChannelTx->pFreeBuffer = hDevice->pChannelTx->pFreeBuffer->pNextBuffer;

        hDevice->pChannelTx->pfSubmitBuffer(hDevice, hDevice->pChannelTx->pFillBuffer);

        /* Block for the active buffer to complete. */
        return(uart_PendForBuffer(hDevice, hDevice->pChannelTx, pHwError));
}

/*!
 * @brief       Submit the buffer for reading the data in #ADI_UART_DATA_TRANSFER_MODE_BLOCKING. Call to this function will not
 *              return until the entire buffer is filled up. Returns error if this function is called when
 *              device is operating in #ADI_UART_DATA_TRANSFER_MODE_NONBLOCKING. i.e The function "adi_uart_SubmitRxBuffer()" is called
 *              when the transfer is not yet complete.
 *
 * @param [in]  hDevice    Device handle obtained from adi_uart_Open().
 * @param [in]  pBuffer    Pointer to buffer from that will be filled by the driver when data has been received.
 * @param [in]  nBufSize   Size of the buffer(in bytes). Must be smaller than 1024 bytes for DMA transfers.
 * @param [in]  bDMA       Submit the buffer using DMA flag.
 * @param [out] pHwError   Pointer to an integer that correlates with #ADI_UART_HW_ERRORS, containg the hardware status.
 *                         If there is no hardware event, this will be 0.
 *
 * @return      Status
 *    - #ADI_UART_SUCCESS                        Successfully submitted the buffer for receiving data.
 *    - #ADI_UART_HW_ERROR_DETECTED              Hardware error(s) detected. "pHwError" can be checked for the specific error code(s).
 *    - #ADI_UART_FAILED                     [D] Generic failure. In this case the size of the data buffer we are trying
 *                                               to submit is NULL.
 *    - #ADI_UART_INVALID_DATA_TRANSFER_MODE [D] Device is operating in #ADI_UART_DATA_TRANSFER_MODE_NONBLOCKING. This
 *                                               operation is only allowed in #ADI_UART_DATA_TRANSFER_MODE_BLOCKING.
 *    - #ADI_UART_INVALID_HANDLE             [D] Invalid UART device handle.
 *    - #ADI_UART_OPERATION_NOT_ALLOWED      [D] Device direction is set up as #ADI_UART_DIR_TRANSMIT, so we can not complete
 *                                               a receive operation. The required directions are #ADI_UART_DIR_RECEIVE or
 *                                               #ADI_UART_DIR_BIDIRECTION.
 *    - #ADI_UART_INVALID_POINTER            [D] Pointer to the buffer being submitted is NULL.
 *    - #ADI_UART_DEVICE_IN_USE              [D] Autobaud in progress.
 *    - #ADI_UART_INVALID_DATA_SIZE          [D] DMA transfers must be smaller than 1025 bytes.
 *
 * @sa  adi_uart_Write()
 * @sa  adi_uart_SubmitTxBuffer()
 *
 * @note: This function is a blocking function which means that the function returns only after the completion of
 *        data receive.
*/
ADI_UART_RESULT adi_uart_Read(
                              ADI_UART_HANDLE const hDevice,
                              void           *const pBuffer,
                              uint32_t        const nBufSize,
                              bool            const bDMA,
                              uint32_t             *pHwError
                             )
{

#ifdef ADI_DEBUG
     /* Validate the given handle. */
     if(ValidateHandle(hDevice) != ADI_UART_SUCCESS)
     {
         return(ADI_UART_INVALID_HANDLE);
     }

    /* Validate the pointer to the buffer memory. */
    if(pBuffer == NULL)
    {
        return(ADI_UART_INVALID_POINTER);
    }

    /* Validate the buffer size. */
    if(nBufSize == 0U )
    {
        return(ADI_UART_FAILED);
    }

    /* Autobaud in progress. */
    if(hDevice->bAutobaudInProgress == true)
    {
        return(ADI_UART_DEVICE_IN_USE);
    }

    /* Make sure the UART device is configured to operate in the receive direction. */
    if(ADI_UART_DIR_TRANSMIT == hDevice->eDirection)
    {
        return(ADI_UART_OPERATION_NOT_ALLOWED);
    }

    /* Check for the data transfer mode(only allowed in blocking mode).*/
    if(hDevice->pChannelRx->eDataTranferMode == ADI_UART_DATA_TRANSFER_MODE_NONBLOCKING)
    {
        return(ADI_UART_INVALID_DATA_TRANSFER_MODE);
    }

    /* Check that there is a free buffer to use for this receive operation. "pFreeBuffer"
       is the next buffer available, so if it is in use we can make the assumption that
       there are no buffers available. The start address gets set to NULL once the buffer
       processing has completed.
    */
    if(hDevice->pChannelRx->pFreeBuffer->pStartAddress != NULL)
    {
        return(ADI_UART_OPERATION_NOT_ALLOWED);
    }

    /* Make sure the DMA transfer size is not too large. */
    if((bDMA == true) && (nBufSize > DMA_TRANSFER_LIMIT))
    {
        return(ADI_UART_INVALID_DATA_SIZE);
    }

#endif /* ADI_DEBUG */

    /* Set the data transfer mode in case it was #ADI_UART_DATA_TRANSFER_MODE_NONE.
       This will be set back to #ADI_UART_DATA_TRANSFER_MODE_NONE once this
       transaction is complete.
    */
    hDevice->pChannelRx->eDataTranferMode = ADI_UART_DATA_TRANSFER_MODE_BLOCKING;

    /* Set the start address of the buffer you are going to submit. */
    hDevice->pChannelRx->pFreeBuffer->pStartAddress  =  pBuffer;

    /* Set the size of the buffer. */
    hDevice->pChannelRx->pFreeBuffer->nCount         =  nBufSize;

    /* Initialize the buffer index to 0, because as we receive data it will be put into
       the buffer starting at the first position.
    */
    hDevice->pChannelRx->pFreeBuffer->nIndex         =  0U;

    /* Mark the buffer as in use. */
    hDevice->pChannelRx->pFreeBuffer->bInUse         =  true;

    /* Mark the DMA as in use. */
    hDevice->pChannelRx->pFreeBuffer->bDMA           =  bDMA;


    /* Now that this "pFreeBuffer" is no longer free for use, update the
       "pFreeBuffer" to the other PingPong buffer. Because there are only two
       buffers in the PingPong structure, this will be the opposite of the one
       we just submitted. "pFreeBuffer" will only be updated during the process of
       submitting a buffer or a read/write operation.
    */
    hDevice->pChannelRx->pFreeBuffer = hDevice->pChannelRx->pFreeBuffer->pNextBuffer;

    hDevice->pChannelRx->pfSubmitBuffer(hDevice, hDevice->pChannelRx->pFillBuffer);

    /* Block for the active buffer to complete. */
    return(uart_PendForBuffer(hDevice, hDevice->pChannelRx, pHwError));
}

/*! \cond PRIVATE */

/*
 * @brief       Pends for data transaction to complete. Buffer gets returned to API.
 *
 * @param [in]  hDevice    Device handle obtained from adi_uart_Open().
 * @param [in]  pChannel   Pointer to UART channel data structure.
 * @param [out] pBuffer    Address of buffer on which data transfer being carried out.
 * @param [out] pHwError   Pointer to an integer that correlates with #ADI_UART_HW_ERRORS, containg the hardware status.
 *                         If there is no hardware event, this will be 0.
 *
 * @return      Status
 *    - #ADI_UART_SUCCESS            Successfully got buffer.
 *    - #ADI_UART_HW_ERROR_DETECTED  Hardware error(s) detected. "pHwError" can be checked for the specific error code(s).
 *
*/
static ADI_UART_RESULT uart_PendForBuffer(
                                           ADI_UART_HANDLE        const hDevice,
                                           ADI_UART_DATA_CHANNEL       *pChannel,
                                           uint32_t                    *pHwError
                                          )
{

    /* Wait until the peripheral has finished processing the buffer. */
    SEM_PEND(pChannel,ADI_UART_FAILED);

     /* Reinitialize the start address to NULL so this buffer can be used for a new transaction. */
     pChannel->pActiveBuffer->pStartAddress = NULL;

      /* Now that the desired data has either been transmitted or received, this buffer is no longer
         in use. We can update "pActiveBuffer" to point to the next buffer that will become or is already
         active. This will only be updated in places where transactions are completed,
         such as uart_PendForBuffer() and uart_GetBuffer().
      */
       pChannel->pActiveBuffer = pChannel->pActiveBuffer->pNextBuffer;

     /* Set the data transfer mode to none so that the next transfer can be either in blocking or in nonblocking mode.
        Only if there are no active buffers.
     */
     if(pChannel->pActiveBuffer->pStartAddress == NULL)
     {
        pChannel->eDataTranferMode = ADI_UART_DATA_TRANSFER_MODE_NONE;
     }

      /* If there are hardware errors and no callback, then return failure. */
      if(hDevice->nHwError != 0u)
      {
          /* Save the hardware error detected. This will be passed back to the API. */
          *pHwError = hDevice->nHwError;

          /* Clear any hardware errors detected. */
          hDevice->nHwError = 0u;

          return(ADI_UART_HW_ERROR_DETECTED);
      }
      else
      {
          return(ADI_UART_SUCCESS);
      }

}
/*! \endcond */


/*!
 * @brief       Peek function to know if an empty buffer is avilable.
 *
 * @param [in]  hDevice      Device handle obtained from adi_uart_Open().
 * @param [out] pbAvailable  Pointer to a boolean variable. Contains "true" if there is an empty buffer
 *                           and a call to "adi_uart_GetTxBuffer" is ensured to be successful. Contains
 *                           "false" if there is no empty buffer.
 * @return      Status
 *    - #ADI_UART_SUCCESS                   Successfully retrieved the status of availability of the buffer.
 *    - #ADI_UART_INVALID_HANDLE        [D] Invalid UART device handle.
 *    - #ADI_UART_OPERATION_NOT_ALLOWED [D] Call to this function is not allowed in #ADI_UART_DATA_TRANSFER_MODE_BLOCKING.
 *
 * @sa  adi_uart_GetTxBuffer()
 * @sa  adi_uart_IsRxBufferAvailable
 *
 */

ADI_UART_RESULT adi_uart_IsTxBufferAvailable(
                                              ADI_UART_HANDLE const hDevice,
                                              bool           *const pbAvailable
                                            )
{

#ifdef ADI_DEBUG
    /* Validate the given handle. */
    if(ValidateHandle(hDevice) != ADI_UART_SUCCESS)
    {
        return(ADI_UART_INVALID_HANDLE);
    }

    /* This function is only allowed to be called when the channel is operating in NONBLOCKING mode. */
    if(hDevice->pChannelTx->eDataTranferMode ==  ADI_UART_DATA_TRANSFER_MODE_BLOCKING)
    {
        return(ADI_UART_OPERATION_NOT_ALLOWED);
    }
#endif /* ADI_DEBUG */

    /* Initialize to "false" in case of an error. */
    *pbAvailable = false;

    /* Make sure the buffer has not already been processed. This would mean that there are
       currently no active buffers. This is only updated in adi_uart_GetBuffer(), which is
       called once a transaction has completed.
    */
    if (hDevice->pChannelTx->pActiveBuffer->pStartAddress != NULL)
    {
        /* If the buffer has reached the interrupt handler, "bInUse" will be
           updated so we know that the buffer has become available.
        */
        if (hDevice->pChannelTx->pActiveBuffer->bInUse == false)
        {
            *pbAvailable = true;
        }
    }
    return(ADI_UART_SUCCESS);
}

/*!
 * @brief       Peek function to know if a filled buffer is available.
 *
 *
 * @param [in]  hDevice      Device handle obtained from adi_uart_Open().
 * @param [out] pbAvailable  Pointer to a boolean variable. Contains "true" if there is an empty buffer
 *                           and a call to "adi_uart_GetTxBuffer" is ensured to be successful. Contains
 *                           "false" if there is no empty buffer.
 * @return      Status
 *    - #ADI_UART_SUCCESS                   Successfully retrieved the status of availability of the buffer.
 *    - #ADI_UART_INVALID_HANDLE        [D] Invalid UART device handle.
 *    - #ADI_UART_OPERATION_NOT_ALLOWED [D] Call to this function is not allowed in #ADI_UART_DATA_TRANSFER_MODE_BLOCKING.
 *
 * @sa  adi_uart_GetRxBuffer()
 *
 */
ADI_UART_RESULT    adi_uart_IsRxBufferAvailable(
                                                 ADI_UART_HANDLE const hDevice,
                                                 bool           *const pbAvailable
                                                )
{

#ifdef ADI_DEBUG
    /* Validate the given handle. */
    if(ValidateHandle(hDevice) != ADI_UART_SUCCESS)
    {
        return(ADI_UART_INVALID_HANDLE);
    }

    /* This function is only allowed to be called when the channel is operating in NONBLOCKING mode. */
    if(hDevice->pChannelRx->eDataTranferMode ==  ADI_UART_DATA_TRANSFER_MODE_BLOCKING)
    {
        return(ADI_UART_OPERATION_NOT_ALLOWED);
    }
#endif /* ADI_DEBUG */

    /* Initialize to "false" in case of an error. */
    *pbAvailable = false;

    /* Make sure the buffer has not already been processed. This would mean that there are
       currently no active buffers. This is only updated in adi_uart_GetBuffer(), which is
       called once a transaction has completed.
    */
    if(hDevice->pChannelRx->pActiveBuffer->pStartAddress != NULL)
    {
        /* If the buffer has reached the interrupt handler, "bInUse" will be
           updated so we know that the buffer has become available.
        */
        if (hDevice->pChannelRx->pActiveBuffer->bInUse == false)
        {
            *pbAvailable = true;
        }
    }
    return(ADI_UART_SUCCESS);
}

/*!
 * @brief       Function to let the API know if all the data had been drained from the Tx shift registers.
 *
 * @param [in]  hDevice      Device handle obtained from adi_uart_Open().
 * @param [out] pbComplete   Pointer to a boolean variable. Contains "true" if there is no data left in the
 *                           device to transmit and device can be disabled without data loss. Contains "false"
 *                           if the data transmission is not complete.
 * @return      Status
 *    - #ADI_UART_SUCCESS            Successfully retrieved the status of data transmission.
 *    - #ADI_UART_INVALID_HANDLE [D] Specified handle is invalid.
 *
 * @note  adi_uart_getTxBuffer() or the callback may indicate that a transmit transaction is complete when the
 *        device is using the DMA. This is because the interrupt will trigger once the transmit holding register is empty.
          However, there may still be a some data in the shift register. If the transmit channel needs
 *        to be closed then the application must poll the transmit channel to see if all data has indeed been transmitted before
 *        shutting down the channel. Otherwise data will be lost.
 *
 */

ADI_UART_RESULT adi_uart_IsTxComplete(
                                     ADI_UART_HANDLE const hDevice,
                                     bool           *const pbComplete
                                     )
{
#ifdef ADI_DEBUG
    /* Validate the given handle. */
    if(ValidateHandle(hDevice) != ADI_UART_SUCCESS)
    {
        return(ADI_UART_INVALID_HANDLE);
    }
#endif /* ADI_DEBUG */

    /* Initialize to false. */
    *pbComplete = false;

    /* If the register is empty, set the return variable to "true".
       This register is empty, when the value becomes a 1.
    */
    if((hDevice->pUARTRegs->LSR & BITM_UART_LSR_TEMT) == BITM_UART_LSR_TEMT)
    {
        *pbComplete = true;
    }
    return(ADI_UART_SUCCESS);
}


/*!
 * @brief       Registering a callback function.
 *
 * @param [in]  hDevice       Device handle obtained from adi_uart_Open().
 * @param [in]  pfCallback    Function pointer to callback. Passing a NULL pointer will unregister
 *                            the callback function.
 * @param [in]  pCBParam      Callback function parameter.
 *
 * @return      Status
 *    - #ADI_UART_SUCCESS                Successfully registered callback function.
 *    - #ADI_UART_DEVICE_IN_USE      [D] This operation is not allowed when a data transfer is in progress.
 *    - #ADI_UART_INVALID_HANDLE     [D] Invalid UART device handle.
 *
 *
*/
ADI_UART_RESULT adi_uart_RegisterCallback(
                                          ADI_UART_HANDLE const hDevice,
                                          const ADI_CALLBACK    pfCallback,
                                          void           *const pCBParam
                                         )
{

#ifdef ADI_DEBUG
    /* Validate the given handle. */
    if(ValidateHandle(hDevice) != ADI_UART_SUCCESS)
    {
        return(ADI_UART_INVALID_HANDLE);
    }

    /* Make sure there are no active buffers on any active channel and autobaud is not in progress. */
    if(((hDevice->eDirection != ADI_UART_DIR_TRANSMIT) && (hDevice->pChannelRx->pActiveBuffer->pStartAddress != NULL)) ||
       ((hDevice->eDirection != ADI_UART_DIR_RECEIVE ) && (hDevice->pChannelTx->pActiveBuffer->pStartAddress != NULL)) ||
       (hDevice->bAutobaudInProgress == true))
    {
        return(ADI_UART_DEVICE_IN_USE);
    }
#endif /* ADI_DEBUG */

    /* Set the device callback. */
    hDevice->pfCallback = pfCallback;

    /* Set the callback parameter. */
    hDevice->pCBParam = pCBParam;

    return(ADI_UART_SUCCESS);
}


/*!
 * @brief        Configuration of UART data.
 *
 * @details      Sets the configuration parameters for the specified UART device such as wordlength, whether to
 *               enable/disable the parity, and the number of stop bits. This function returns an error if the
 *               device has active data or autobaud is in progress.
 *
 * @param [in]  hDevice      Device handle obtained from adi_uart_Open().
 * @param [in]  eParity      Specify the type of parity check for the UART device.
 * @param [in]  eStopBits    Specify the stop-bits for the UART device.
 * @param [in]  eWordLength  Specify the word size of the data for the UART device.
 *
 * @return      Status
 *    - #ADI_UART_SUCCESS                Successfully set the data configuration.
 *    - #ADI_UART_DEVICE_IN_USE      [D] This operation is not allowed when a data transfer or autobaud is in progress.
 *    - #ADI_UART_INVALID_HANDLE     [D] Invalid UART device handle.
 *
*/
ADI_UART_RESULT adi_uart_SetConfiguration(
                                         ADI_UART_HANDLE   const hDevice,
                                         ADI_UART_PARITY   const eParity,
                                         ADI_UART_STOPBITS const eStopBits,
                                         ADI_UART_WORDLEN  const eWordLength
                                         )
{
#ifdef ADI_DEBUG
    /* Validate the given handle. */
    if(ValidateHandle(hDevice) != ADI_UART_SUCCESS)
    {
        return(ADI_UART_INVALID_HANDLE);
    }

    /* Make sure there are no active buffers on any active channel and autobaud is not in progress. */
    if(((hDevice->eDirection != ADI_UART_DIR_TRANSMIT) && (hDevice->pChannelRx->pActiveBuffer->pStartAddress != NULL)) ||
       ((hDevice->eDirection != ADI_UART_DIR_RECEIVE ) && (hDevice->pChannelTx->pActiveBuffer->pStartAddress != NULL)) ||
       (hDevice->bAutobaudInProgress == true))
    {
        return(ADI_UART_DEVICE_IN_USE);
    }
#endif /* ADI_DEBUG */

    /* Clear all the fields.  */
    uint16_t nDataCfg = hDevice->pUARTRegs->LCR & (uint16_t)(~(BITM_UART_LCR_WLS |BITM_UART_LCR_STOP |BITM_UART_LCR_PEN));

    /* Construct the configuration word. */
    nDataCfg |= (uint16_t)(((uint16_t)((uint16_t)eWordLength |(uint16_t)eStopBits) |(uint16_t)eParity));

    /* Write to the register */
    hDevice->pUARTRegs->LCR = nDataCfg;

    /* Return Success */
    return(ADI_UART_SUCCESS);
}

/*!
 * @brief        Set baudrate by configuring the fractional dividors.
 *
 * @details      Baudrate is calculated as per below equation.
 *
 *               Baudrate = (UARTCLK / (nDivM + nDivN/2048)*pow(2,nOSR+2)* nDivC)).
 *
 * @param [in]  hDevice      Device handle obtained from adi_uart_Open().
 * @param [in]  nDivC        Specify the "nDivC" in the above equation.
 * @param [in]  nDivM        Specify the "nDivM" in the above equation.
 * @param [in]  nDivN        Specify the "nDivN" in the above equation.
 * @param [in]  nOSR         Specify the "nOSR" " in the above equation.
 *
 * @return      Status
 *    - #ADI_UART_SUCCESS                 Successfully set the baudrate for the device.
 *    - #ADI_UART_INVALID_HANDLE     [D]  Invalid UART device handle.
 *    - #ADI_UART_DEVICE_IN_USE      [D]  Device is in use
 *    - #ADI_UART_INVALID_PARAMETER  [D]  Input for baud rate values are out of range.
 *
 *   @sa  adi_uart_GetBaudRate()
 *   @sa  adi_uart_EnableAutobaud();
 *
 *   @note It is expected that initialization of the power management
 *         driver is done before calling this function.
 *
 */
ADI_UART_RESULT adi_uart_ConfigBaudRate(
                                       ADI_UART_HANDLE const hDevice,
                                       uint16_t        const nDivC,
                                       uint8_t         const nDivM,
                                       uint16_t        const nDivN,
                                       uint8_t         const nOSR
                                       )
{
#ifdef ADI_DEBUG
    /* Validate the given handle */
    if(ValidateHandle(hDevice) != ADI_UART_SUCCESS)
    {
        return(ADI_UART_INVALID_HANDLE);
    }

    /* Make sure there are no active buffers on any active channel. */
    if(((hDevice->eDirection != ADI_UART_DIR_TRANSMIT) && (hDevice->pChannelRx->pActiveBuffer->pStartAddress != NULL)) ||
       ((hDevice->eDirection != ADI_UART_DIR_RECEIVE ) && (hDevice->pChannelTx->pActiveBuffer->pStartAddress != NULL)))
    {
        return(ADI_UART_DEVICE_IN_USE);
    }

    /* Check if the given baudrate is valid */
    if( (nDivM < 1u) || (nDivM > 3u)|| (nDivN > 2047u ) || (nOSR > 3u))
    {
        return ADI_UART_INVALID_PARAMETER;
    }

#endif /* ADI_DEBUG */

    /* Write back the register contents for baudrate detection in the hardware. */
    hDevice->pUARTRegs->DIV  =  nDivC;
    hDevice->pUARTRegs->FBR  =  (uint16_t)((uint16_t)nDivN | (uint16_t)((uint16_t)nDivM <<BITP_UART_FBR_DIVM)) | (uint16_t)BITM_UART_FBR_FBEN;
    hDevice->pUARTRegs->LCR2 = nOSR;

    return(ADI_UART_SUCCESS);
}


/*!
 * @brief       Get the baudrate of the UART device instance. This is used in the scenario when a callback has not been initialized.
 *              This allows the the API to know if autobaud is complete. If this returns a baudrate other than 0,
 *              it indicates that the autobaud completed, otherwise autobaud is still in progress.
 *
 * @param [in]   hDevice         Device handle obtained from adi_uart_Open().
 * @param [out]  pnBaudRate      Pointer to a location where baudrate is to be written.
 * @param [out]  pAutobaudError  Pointer to an integer that will hold the value of any baudrate error(s), that correlates with
 *                               #ADI_UART_AUTOBAUD_ERRORS. This will be 0 if there are no errors.
 *
 * @return      Status
 *    - #ADI_UART_SUCCESS                   Successfully retrieved the baudrate.
 *    - #ADI_UART_AUTOBAUD_ERROR_DETECTED   There has been an autobaud error. The API can get the specific error(s)
 *                                          by checking "pAutobaudError".
 *    - #ADI_UART_INVALID_HANDLE        [D] Invalid UART device handle.
 *    - #ADI_UART_INVALID_POINTER       [D] The pointer to baudrate or autobaud error is NULL.

 *
*/
ADI_UART_RESULT adi_uart_GetBaudRate(
                                      ADI_UART_HANDLE const     hDevice,
                                      uint32_t                 *pnBaudRate,
                                      uint32_t                 *pAutobaudError
                                    )
{

#ifdef ADI_DEBUG
    /* Validate the given handle. */
    if(ValidateHandle(hDevice) != ADI_UART_SUCCESS)
    {
        return(ADI_UART_INVALID_HANDLE);
    }

    /* Validate pointers. */
    if(pnBaudRate == NULL)
    {
        return(ADI_UART_INVALID_POINTER);
    }

#endif /* ADI_DEBUG */

    /* If an error occured during autobaud this value will be set to a
       non-zero value. The specific error can be found by checking against
       #ADI_UART_EVENT.
    */
    if(hDevice->nAutobaudError != 0u)
    {
      /* Save the autobaud error to pass back to the API.*/
      *pAutobaudError = hDevice->nAutobaudError;

      /* Clear the autobaud errors found. */
      hDevice->nAutobaudError = 0u;

      return(ADI_UART_AUTOBAUD_ERROR_DETECTED);
    }

    /* Return the baudrate. If this is 0, then autobaud has not completed. */
    *pnBaudRate = hDevice->nBaudRate;

    return(ADI_UART_SUCCESS);
}


/*!
 * @brief       Enable/Disable UART autobaud detection as well as configures the device for autobaud detection.
 *
 * @details     The baud rate is detected using the hardware support.
 *              After the baud rate is detected the interrupt handler is notified of the completion.
 *              When a callback is not registered with UART driver, the API adi_uart_GetBaudRate()
 *              can be used to know if autobaud is complete. Autobaud needs to be disabled in order to
 *              clear the internal counter and to close the device.
 *
 * @param [in]  hDevice                 Handle to UART device whose autobaud detection to be enabled/disabled.
 * @param [in]  bEnable                 Boolean flag to indicate whether to enable or disable the autobaud.
 * @param [in]  bAutobaudCallbackMode   Use a callback to report autobaud errors or type #ADI_UART_AUTOBAUD_ERRORS.
 *
 * @return      Status
 *    - #ADI_UART_SUCCESS                       Successfully enabled/disabled Autobaud detection.
 *    - #ADI_UART_DEVICE_IN_USE             [D] Trying to enable/disable Autobaud when
 *                                              dataflow is enabled or autobaud is in progress.
 *    - #ADI_UART_INVALID_HANDLE            [D] Invalid UART device handle.
 *
 * @sa  adi_uart_GetBaudRate()
 *
 * @note: For autobaud we assume the key character being used is a carrige return (0xD), so the start edge count is
 *        hardcoded to the second edge (first edge after start edge) and the last edge count is set to the fouth edge.
 *        This will give us a total bit count of 8 bits that we will time in order to figure out the baud rate (bits/second).
 */
ADI_UART_RESULT adi_uart_EnableAutobaud(
                                        ADI_UART_HANDLE          const hDevice,
                                        bool                     const bEnable,
                                        bool                     const bAutobaudCallbackMode
                                       )
{

#ifdef ADI_DEBUG
     /* Validate the given handle */
    if(ValidateHandle(hDevice) != ADI_UART_SUCCESS)
    {
        return(ADI_UART_INVALID_HANDLE);
    }

    /* Make sure there are no active buffers on any active channel and autobaud is not in progress. */
    if(((hDevice->eDirection != ADI_UART_DIR_TRANSMIT) && (hDevice->pChannelRx->pActiveBuffer->pStartAddress != NULL)) ||
       ((hDevice->eDirection != ADI_UART_DIR_RECEIVE ) && (hDevice->pChannelTx->pActiveBuffer->pStartAddress != NULL)))
    {
        return(ADI_UART_DEVICE_IN_USE);
    }

#endif /* ADI_DEBUG */

    if(bEnable)
    {
        /* Enable Autobaud, timeout interrupt and done interrupt in the autobaud control register.
           Set the starting edge trigger to the second edge. Set the ending edge count to
           the fourth edge, for the carrige return key character (0xD).
        */
        hDevice->pUARTRegs->ACR |=(BITM_UART_ACR_ABE | BITM_UART_ACR_DNIEN | BITM_UART_ACR_TOIEN |(1u << 4u) | (3u << 8u));

        /* Initialize device baudrate to 0. This will be set once autobaud is complete. */
        hDevice->nBaudRate = 0u;

        /* Change the state to indicate autobaud is in progress. */
        hDevice->bAutobaudInProgress = true;

        /* Set the callback mode for autobaud based on the user input. */
        hDevice->bAutobaudCallbackMode = bAutobaudCallbackMode;
    }
    else
    {
        /* Change the state to indicate autobaud is not in progress. */
        hDevice->bAutobaudInProgress = false;

        /* Disable Autobaud, timeout interrupt and done interrupt in the autobaud control register. */
        hDevice->pUARTRegs->ACR |= (uint16_t)(~(uint32_t)BITM_UART_ACR_ABE | ~(uint32_t)BITM_UART_ACR_DNIEN | ~(uint32_t)BITM_UART_ACR_TOIEN);

        /* Initialize device baudrate to 0. */
        hDevice->nBaudRate = 0u;
    }

    return ADI_UART_SUCCESS;
}

/*!
 * @brief       Forces the UART to send out a break signal.
 *
 * @details     Sets the UART Tx pin to a logic-low/high (depending upon the
 *              Tx polarity) asynchronously. The UART keeps transmitting break
 *              until it is disabled to send the break.
 *
 * @param [in]  hDevice             Handle to the UART whose Tx is forced to
 *                                  send a break.
 * @param [in]  bEnable             Flag which indicates whether to enable or
 *                                  disable transmitting the break.
 *
 * @return      Status
 *
 * - #ADI_UART_SUCCESS              If successfully enabled or disabled sending break.
 * - #ADI_UART_INVALID_HANDLE   [D] If the given UART handle is invalid.
 */
ADI_UART_RESULT adi_uart_ForceTxBreak(
                                      ADI_UART_HANDLE         const hDevice,
                                      bool                    const bEnable
                                     )
{

#ifdef ADI_DEBUG
     /* Validate the given handle. */
    if(ValidateHandle(hDevice) != ADI_UART_SUCCESS)
    {
        return(ADI_UART_INVALID_HANDLE);
    }
#endif /* ADI_DEBUG */

    if(bEnable == true)
    {
        /* Set the force break bit. */
        hDevice->pUARTRegs->LCR    |= BITM_UART_LCR_BRK;
    }
    else
    {
        /* Clear the force break bit. */
        hDevice->pUARTRegs->LCR    &= (uint16_t)~(BITM_UART_LCR_BRK);
    }

    return ADI_UART_SUCCESS;
}

/*!
 * @brief       Enable/Disable the loopback for the specified UART device.
 *
 * @param [in]  hDevice    Device handle obtained from adi_uart_Open().
 * @param [in]  bEnable    Boolean flag to indicate whether to enable or disable the loopback mode.
 *
 * @return      Status
 *    - #ADI_UART_SUCCESS            Successfully enable/disable the loopback.
 *    - #ADI_UART_INVALID_HANDLE     Invalid  UART device handle.
 *
*/
ADI_UART_RESULT adi_uart_EnableLoopBack(
                                        ADI_UART_HANDLE const hDevice,
                                        bool            const bEnable
                                       )
{

#ifdef ADI_DEBUG
     /* Validate the given handle. */
    if(ValidateHandle(hDevice) != ADI_UART_SUCCESS)
    {
        return(ADI_UART_INVALID_HANDLE);
    }
#endif /* ADI_DEBUG */

    if(true == bEnable)
    {
        /* Enable loopback. */
        hDevice->pUARTRegs->MCR |= (BITM_UART_MCR_LOOPBACK);
    }
    else
    {
        /* Disable loopback. */
        hDevice->pUARTRegs->MCR &= (uint16_t)~(BITM_UART_MCR_LOOPBACK);
    }
    return(ADI_UART_SUCCESS);
}

/*!
 * @brief       Sets the RX FIFO trigger level. This will be the amount of data in the FIFO
 *              that will trigger an interrupt.
 *
 *
 * @param [in]  hDevice         Device handle obtained from adi_uart_Open().
 * @param [in]  eTriglevel      Trigger level to be set in terms of number of bytes.
 *
 * @return      Status
 *  - #ADI_UART_SUCCESS             Successfully set the trigger level.
 *  - #ADI_UART_INVALID_HANDLE  [D] The given UART handle is invalid.
 */
ADI_UART_RESULT adi_uart_SetRxFifoTriggerLevel(
                                               ADI_UART_HANDLE               const hDevice,
                                               ADI_UART_TRIG_LEVEL           const eTriglevel
                                              )
{
#ifdef ADI_DEBUG
     /* Validate the given handle. */
    if(ValidateHandle(hDevice) != ADI_UART_SUCCESS)
    {
        return(ADI_UART_INVALID_HANDLE);
    }
#endif /* ADI_DEBUG */
    
    /* Clear existing FIFO trigger level. */
    hDevice->pUARTRegs->FCR &= (uint16_t)~BITM_UART_FCR_RFTRIG;

    /* Set the FIFO trigger level. */
    hDevice->pUARTRegs->FCR |= (uint16_t)eTriglevel;

    /* Update the internal structure */
    hDevice->nRxFifoTrig = sFifoTriggers[eTriglevel >> BITP_UART_FCR_RFTRIG];

    return(ADI_UART_SUCCESS);
}
/*!
 * @brief       Enables internal FIFO as to work in 16550 mode. This helps to minimize system overhead
 *              and maximize system efficiency.
 *
 * @param [in]  hDevice    Device handle obtained from adi_uart_Open().
 * @param [in]  bEnable    Boolean flag to indicate whether to enable or disable FIFO.
 *
 * @return      Status
 *  - #ADI_UART_SUCCESS              If successfully enabled FIFO for UART device.
 *  - #ADI_UART_INVALID_HANDLE   [D] The given UART handle is invalid.
 */
ADI_UART_RESULT adi_uart_EnableFifo(
                                     ADI_UART_HANDLE         const hDevice,
                                     bool                    const bEnable
                                    )
{

#ifdef ADI_DEBUG
     /* Validate the given handle. */
    if(ValidateHandle(hDevice) != ADI_UART_SUCCESS)
    {
        return(ADI_UART_INVALID_HANDLE);
    }
#endif /* ADI_DEBUG */

    if(bEnable == true)
    {
       /* Enable TX/RX FIFO. */
       hDevice->pUARTRegs->FCR    |=  BITM_UART_FCR_FIFOEN;
       hDevice->pUARTRegs->IEN |= (BITM_UART_IEN_ERBFI);

       hDevice->bRxFifoEn = true;

    }
    else
    {
       /* Disable TX/RX FIFO. */
       hDevice->pUARTRegs->FCR    &= (uint16_t)~(BITM_UART_FCR_FIFOEN);

       hDevice->bRxFifoEn = false;
    }

    return ADI_UART_SUCCESS;
}

/*!
 * @brief      To flush the TX FIFO.
 *
 *
 * @param [in]  hDevice    Device handle obtained from adi_uart_Open().
 *
 *
 * @return      Status
 *  - #ADI_UART_SUCCESS             Successfully flushed TX Fifo.
 *  - #ADI_UART_INVALID_HANDLE  [D] The given UART handle is invalid.
 */
ADI_UART_RESULT adi_uart_FlushTxFifo(
                                     ADI_UART_CONST_HANDLE         const hDevice
                                    )
{

#ifdef ADI_DEBUG
     /* Validate the given handle. */
    if(ValidateHandle(hDevice) != ADI_UART_SUCCESS)
    {
        return(ADI_UART_INVALID_HANDLE);
    }
#endif /* ADI_DEBUG */

    /* Flush the Tx FIFO. */
    hDevice->pUARTRegs->FCR    |=  BITM_UART_FCR_TFCLR;

    return(ADI_UART_SUCCESS);
}

/*!
 * @brief       Flush the RX FIFO.
 *
 *
 * @param [in]  hDevice    Device handle obtained from adi_uart_Open().
 *
 *
 * @return      Status
 *  - #ADI_UART_SUCCESS              Successfully flushed RX Fifo.
 *  - #ADI_UART_INVALID_HANDLE   [D] The given UART handle is invalid.
 */
ADI_UART_RESULT adi_uart_FlushRxFifo(
                                      ADI_UART_CONST_HANDLE         const hDevice
                                     )
{

#ifdef ADI_DEBUG
     /* Validate the given handle. */
    if(ValidateHandle(hDevice) != ADI_UART_SUCCESS)
    {
        return(ADI_UART_INVALID_HANDLE);
    }
#endif /* ADI_DEBUG */

    /* Flush RX FIFO. */
    hDevice->pUARTRegs->FCR    |=  BITM_UART_FCR_RFCLR;

    return ADI_UART_SUCCESS;
}

/*!
 * @brief      Flush the Rx channel and disable interrupts. This will stop any buffers in flight and
 *             clear out any data that was in the RX holding register as well as the Rx fifo. Once this is done,
 *             in order to turn back on Rx interrupts, a new transaction will need to be started (adi_uart_Read()
 *             or adi_uart_SubmitRxBuffer()).
 *
 *
 * @param [in]  hDevice    Device handle obtained from adi_uart_Open().
 *
 * @return      Status
 *  - #ADI_UART_SUCCESS                       Successfully flushed the Rx channel.
 *  - #ADI_UART_INVALID_HANDLE            [D] The given UART handle is invalid.
 */
ADI_UART_RESULT adi_uart_FlushRxChannel(
                                         ADI_UART_CONST_HANDLE  const hDevice
                                        )
{

#ifdef ADI_DEBUG
     /* Validate the given handle. */
    if(ValidateHandle(hDevice) != ADI_UART_SUCCESS)
    {
        return(ADI_UART_INVALID_HANDLE);
    }
#endif /* ADI_DEBUG */

    /* Disable receive interrupts in PIO mode as well as DMA mode. */
    hDevice->pUARTRegs->IEN &= (uint16_t)~(BITM_UART_IEN_ERBFI | BITM_UART_IEN_EDMAR);

    /* Clear any data in the Rx Fifo. */
    hDevice->pUARTRegs->FCR |=  BITM_UART_FCR_RFCLR;

    /* Reset the data transfer mode. */
    hDevice->pChannelRx->eDataTranferMode = ADI_UART_DATA_TRANSFER_MODE_NONE;

    /* Reset the buffers to 0. */
    memset(hDevice->pChannelRx->PingPong,0, sizeof (hDevice->pChannelRx->PingPong));

    hDevice->pChannelRx->PingPong[0].pNextBuffer  = &hDevice->pChannelRx->PingPong[1];
    hDevice->pChannelRx->PingPong[1].pNextBuffer  = &hDevice->pChannelRx->PingPong[0];

    /* Reset the buffer pointers. */
    hDevice->pChannelRx->pActiveBuffer = &hDevice->pChannelRx->PingPong[0];
    hDevice->pChannelRx->pFreeBuffer = &hDevice->pChannelRx->PingPong[0];
    hDevice->pChannelRx->pFillBuffer = &hDevice->pChannelRx->PingPong[0];

    /* Dummy read to flush the RX register. */
    hDevice->pUARTRegs->RX;

    return(ADI_UART_SUCCESS);
}

/*!
 * @brief      Flush the Tx channel and disable interrupts.This will stop any buffers in flight and
 *             clear out any data that was in the TX holding register. Any data in the TX shift register
 *             will still finish transmitting.
 *
 *
 * @param [in]  hDevice       Device handle to UART device obtained when an UART device is opened successfully.
 *
 * @return      Status
 *  - #ADI_UART_SUCCESS                   Successfully flushed the Tx channel.
 *  - #ADI_UART_INVALID_HANDLE        [D] The given UART handle is invalid.
 */
ADI_UART_RESULT adi_uart_FlushTxChannel(ADI_UART_CONST_HANDLE  const hDevice)
{

#ifdef ADI_DEBUG
     /* Validate the given handle. */
    if(ValidateHandle(hDevice) != ADI_UART_SUCCESS)
    {
        return(ADI_UART_INVALID_HANDLE);
    }
#endif /* ADI_DEBUG */

    /* Disable transmit interrupts in PIO mode as well as DMA mode. */
    hDevice->pUARTRegs->IEN &= (uint16_t)~(BITM_UART_IEN_ETBEI | BITM_UART_IEN_EDMAT);

    /* Clear any data in the Rx Fifo. */
    hDevice->pUARTRegs->FCR |=  BITM_UART_FCR_TFCLR;

    /* Reset the buffers to 0. */
    memset(hDevice->pChannelTx->PingPong,0, sizeof (hDevice->pChannelTx->PingPong));

    hDevice->pChannelTx->PingPong[0].pNextBuffer  = &hDevice->pChannelTx->PingPong[1];
    hDevice->pChannelTx->PingPong[1].pNextBuffer  = &hDevice->pChannelTx->PingPong[0];

    /* Reset the buffer pointers. */
    hDevice->pChannelTx->pActiveBuffer = &hDevice->pChannelTx->PingPong[0];
    hDevice->pChannelTx->pFreeBuffer = &hDevice->pChannelTx->PingPong[0];
    hDevice->pChannelTx->pFillBuffer = &hDevice->pChannelTx->PingPong[0];

    return(ADI_UART_SUCCESS);
}


/*! \cond PRIVATE */

void UART0_Int_Handler(void)
{
    ISR_PROLOG();
    ADI_UART_HANDLE hDevice = (ADI_UART_HANDLE)uart_device_info[0].hDevice;
    Common_Uart_Interrupt_Handler(hDevice);
#if defined(ADI_CYCLECOUNT_UART_ISR_ENABLED) && (ADI_CYCLECOUNT_UART_ISR_ENABLED == 1u)
    ADI_CYCLECOUNT_STORE(ADI_CYCLECOUNT_ISR_UART);    
#endif
    ISR_EPILOG();
    return;
}

#if defined (__ADUCM4x50__)

void UART1_Int_Handler(void)
{
    ISR_PROLOG();
    ADI_UART_HANDLE hDevice = (ADI_UART_HANDLE)uart_device_info[1].hDevice;
    Common_Uart_Interrupt_Handler(hDevice);
#if defined(ADI_CYCLECOUNT_UART_ISR_ENABLED) && (ADI_CYCLECOUNT_UART_ISR_ENABLED == 1u)
    ADI_CYCLECOUNT_STORE(ADI_CYCLECOUNT_ISR_UART);    
#endif
    ISR_EPILOG();
    return;
}
#endif

static void Common_Uart_Interrupt_Handler(ADI_UART_HANDLE hDevice)
{
      switch(hDevice->pUARTRegs->IIR & BITM_UART_IIR_STAT )
    {
        /* Tx buffer empty interrupt. This means that the data has successfully left the holding register and is
           now in transmit shift register or has completed its transfer.
        */
        case ENUM_UART_IIR_STAT_ETBEI:
          uart_TxDataHandler(hDevice);
          break;
          
        /* Rx buffer FIFO timeout interrupt. This means that we have data in the RX FIFO
           but there is not enough data to trigger an interrupt so we will process this data here.
        */
        case ENUM_UART_IIR_STAT_RFTOI:
          /* Extract as many bytes in Rx FIFO as possible.
           * subsequent timeout int will take care of remaining bytes if needed. */
          uart_RxDataHandler(hDevice, hDevice->pUARTRegs->RFC);
          break;
          
        /* Rx buffer full interrupt. This means that the RX buffer has finished receiving data. */
        case ENUM_UART_IIR_STAT_ERBFI:
          /* Extract the amount of data based on the size of the trigger */
          uart_RxDataHandler(hDevice, hDevice->nRxFifoTrig);
          break;
        
        /* Line status interrupt. */
        case ENUM_UART_IIR_STAT_RLSI:
        {
            /* Initialze the line status event to 0. */
            uint32_t nEvent = 0u;

            /* Get the interrupts status. */
            uint16_t  nStatus = hDevice->pUARTRegs->LSR;

            /* If a break signal is detected.. */
            if((BITM_UART_LSR_BI & nStatus) == BITM_UART_LSR_BI)
            {
                /* Dummy read to flush the RX register. We do this because
                   we do not actaully want to do anything with this data as it
                   is only a break indicator. */
                hDevice->pUARTRegs->RX;

                /* Set the event to a break interrupt. */
                nEvent  = (uint32_t)ADI_UART_BREAK_INTERRUPT;
            }

            /* Ignore the framing error if the break is asserted.
               We do this because a break can trigger a false framing error.
            */
            else if((BITM_UART_LSR_FE & nStatus) == BITM_UART_LSR_FE)
            {
                /* Set the event to show a framing error has been detected. */
                nEvent |= (uint32_t)ADI_UART_HW_ERR_FRAMING;
            }
            else
            {
              /* Do nothing. This is required for MISRA. */
            }

            if((BITM_UART_LSR_PE & nStatus) == BITM_UART_LSR_PE)
            {
                /* Set the event to show a parity error has been detected. */
                nEvent  |=  (uint32_t)ADI_UART_HW_ERR_PARITY;
            }
            if((BITM_UART_LSR_OE & nStatus) == BITM_UART_LSR_OE)
            {
                /* Set the event to show a hardware overrun error has been detected, meaning receive data has
                   been overwritten.
                */
                nEvent |= (uint32_t)ADI_UART_HW_ERR_OVERRUN;
            }

            /* If there was an event and autobaud is not in progress, notify the API. */
            if((nEvent != 0u) && (hDevice->bAutobaudInProgress == false))
            {
                /* Set the UART device hw error bit field. This will allow us to return the
                   specific failure to the application once we return from this ISR.
                */
                hDevice->nHwError |= nEvent;
                uart_ManageProcessedBuffer(hDevice, hDevice->pChannelRx, ADI_UART_EVENT_HW_ERROR_DETECTED);
            }
            break;
         }

         /* If there was a modem status interrupt. For our purposes, we will only check if this is related to autobaud. */
         case ENUM_UART_IIR_STAT_EDSSI:
         {
#if (ADI_UART_CFG_ENABLE_AUTOBAUD == 1)
            /* Initialize the autobaud event to 0. */
            uint32_t nEvent = 0u;

            /* Get the autobaud interrupt status but not the counter value. */
            uint16_t nStatus =  hDevice->pUARTRegs->ASRL & 0xFu;

            /* Read the autobaud control register to see if autobaud was enabled. */
            uint16_t  acr = (hDevice->pUARTRegs->ACR & BITM_UART_ACR_ABE);

            /* If there is an autobaud event and autobaud is enabled */
            if((nStatus != 0u) && (acr != 0u))
            {
                uint32_t nClock;
                uint32_t nCount;

                /*Get the clock frequency. */
                if(adi_pwr_GetClockFrequency(ADI_CLOCK_PCLK,&nClock) != ADI_PWR_SUCCESS)
                {
                  nClock = 0u;
                }

                /* Get the autobaud counter bits 12-19. */
                nCount = (uint32_t)hDevice->pUARTRegs->ASRH << 12u;

                /* Get the autobaud counter bits 0-11. */
                nCount |= (uint32_t)hDevice->pUARTRegs->ASRL >> 4u;

                /* if the autobaud event was that the autobaud is done.. */
                if((nStatus & BITM_UART_ASRL_DONE) == BITM_UART_ASRL_DONE)
                {
                    /* If the fractional baud generator is enabled, calculate the fractional portional of the baudrate.
                       It seems that in order to get a correct baudrate reading, we need the fractional divider enabled.
                    */
                    if ((hDevice->pUARTRegs->FBR & 0x8000u) == 0x8000u)
                    {
                        uint8_t nOSR = 0u;
                        uint32_t nDivN;
                        uint32_t nDivNSubtractor = 2048u;

                        /* DIVC is always 1, unless the oversample rate is 32. */
                        uint16_t nDivC = 1u;

                        /* If the oversample rate is 4.. */
                        if(nCount < (8u << 3u))
                        {
                             nDivN = ((nCount << 9u) / 8u) - nDivNSubtractor;
                        }

                        /* If the oversample rate is 8.. */
                        else if(nCount < (8u << 4u))
                        {
                             nDivN = ((nCount << 8u) / 8u) - nDivNSubtractor;
                             nOSR = 1u;
                        }

                        /* If the oversample rate is 16.. */
                        else if(nCount < (8u << 5u))
                        {
                             nDivN = ((nCount << 7u) / 8u) - nDivNSubtractor;
                             nOSR = 2u;
                        }

                        /* If the oversample rate is 32.. */
                        else
                        {
                            nDivC = (uint16_t) (nCount / 32u / 8u);
                            nDivN = ((nCount << 6u) / (8u * nDivC)) - nDivNSubtractor;
                            nOSR = 3u;
                        }

                        /* Write back the register contents for baudrate detection in the hardware. */
                        adi_uart_ConfigBaudRate(hDevice, nDivC, 1u, (uint16_t)nDivN, nOSR);

                        /* For more precise calculations we would use floating point math here. Integer precision will do for now.
                           This avoids bringing in extra libraries for floating point math. */

                        /* Baudrate = (UARTCLK / (nDivM + nDivN / 2048) * pow(2, nOSR + 2) * nDivC)
                        nOSR = (1u << (nOSR + 2u)); Seperate this out of the equation for misra compliance
                        hDevice->nBaudRate = ((float)nClock / (((float)1 + (float)nDivN / (float)2048) * (float)nOSR * (float)nDivC));
                        */

                        /* In order to avoid bringing in the extra floating point libraries, we will use the non fractional baudrate for the API. */
                        hDevice->nBaudRate = ((nClock * 8u) / nCount);
                    }
                    else
                    {
                      /* No Fractional divider: Baudrate (bits/second) = (UARTCLK (cycles/second) * counted bits (bits)) / nCount (cycles)*/
                      hDevice->nBaudRate = ((nClock * 8u) / nCount);
                    }

                    /* If there is a callback, notify the API that autobaud is complete.
                       If there is not a callback, the baudrate will be set to a non zero value so the user can call "Get_BaudRate"
                       to know that autobaud has completed.
                    */
                    if((hDevice->pfCallback != NULL) && (hDevice->bAutobaudCallbackMode == true))
                    {
                        hDevice->pfCallback(hDevice->pCBParam, ADI_UART_EVENT_AUTOBAUD_COMPLETE, (void*)hDevice->nBaudRate);
                    }
                }
                else
                {
                    if((nStatus & BITM_UART_ASRL_BRKTO) == BITM_UART_ASRL_BRKTO)
                    {
                        /* Autobaud timed out due to break error. */
                       nEvent |= (uint32_t)ADI_UART_AUTOBAUD_TIMEOUT_LONGBREAK;
                    }
                    if((nStatus & BITM_UART_ASRL_NSETO) == BITM_UART_ASRL_NSETO)
                    {
                        /* Autobaud timed out due to no valid start edge found. */
                        nEvent |= (uint32_t)ADI_UART_AUTOBAUD_TIMEOUT_NO_START_EDGE;
                    }
                    if((nStatus & BITM_UART_ASRL_NEETO) == BITM_UART_ASRL_NEETO)
                    {
                        /* Autobaud timed out due to no valid end edge found. */
                        nEvent |= (uint32_t)ADI_UART_AUTOBAUD_TIMEOUT_NO_END_EDGE;
                    }
                    /* If there is an event callback.. */
                    if((hDevice->pfCallback != NULL) && (hDevice->pChannelRx->eDataTranferMode == ADI_UART_DATA_TRANSFER_MODE_NONBLOCKING))
                    {
                      /* Notify application of errors through callback. */
                      hDevice->pfCallback(hDevice->pCBParam, ADI_UART_EVENT_AUTOBAUD_ERROR_DETECTED, (void*)nEvent);
                    }
                    else
                    {
                      /* Notify application of errors through autobaud return value. */
                      hDevice->nAutobaudError = nEvent;
                    }

                }

                /* Dummy read to flush the RX register to clear the key character that was sent while configuring autobaud. */
                hDevice->pUARTRegs->RX;
            }
#endif
            /* Clear auto baud enable and interrupt registers. We disable autobaud here because it is required in order to clear the counter.  */
             hDevice->pUARTRegs->ACR &=(uint16_t)~( BITM_UART_ACR_ABE   |
                                                       BITM_UART_ACR_DNIEN |
                                                       BITM_UART_ACR_TOIEN );

             hDevice->bAutobaudInProgress = false;
             break;
         }
        default:
          break;
    }
    return;
}


/* DMA interrupt handlers */
void DMA_UART0_TX_Int_Handler(void)
{
   ISR_PROLOG();
   ADI_UART_HANDLE const hDevice = (ADI_UART_HANDLE)uart_device_info[0].hDevice;
   uart_ManageProcessedBuffer(hDevice,hDevice->pChannelTx,ADI_UART_EVENT_TX_BUFFER_PROCESSED);
#if defined(ADI_CYCLECOUNT_UART_ISR_ENABLED) && (ADI_CYCLECOUNT_UART_ISR_ENABLED == 1u)
    ADI_CYCLECOUNT_STORE(ADI_CYCLECOUNT_ISR_DMA_UART_TX);    
#endif
   ISR_EPILOG();
}

void DMA_UART0_RX_Int_Handler(void)
{
   ISR_PROLOG();
   ADI_UART_HANDLE const hDevice = (ADI_UART_HANDLE)uart_device_info[0].hDevice;
   uart_ManageProcessedBuffer(hDevice,hDevice->pChannelRx,ADI_UART_EVENT_RX_BUFFER_PROCESSED);
#if defined(ADI_CYCLECOUNT_UART_ISR_ENABLED) && (ADI_CYCLECOUNT_UART_ISR_ENABLED == 1u)
    ADI_CYCLECOUNT_STORE(ADI_CYCLECOUNT_ISR_DMA_UART_RX);    
#endif
   ISR_EPILOG();
}

#if defined(__ADUCM4x50__)

void DMA_UART1_TX_Int_Handler(void)
{
   ISR_PROLOG();
   ADI_UART_HANDLE const hDevice = (ADI_UART_HANDLE)uart_device_info[1].hDevice;
   uart_ManageProcessedBuffer(hDevice,hDevice->pChannelTx,ADI_UART_EVENT_TX_BUFFER_PROCESSED);
#if defined(ADI_CYCLECOUNT_UART_ISR_ENABLED) && (ADI_CYCLECOUNT_UART_ISR_ENABLED == 1u)
    ADI_CYCLECOUNT_STORE(ADI_CYCLECOUNT_ISR_DMA_UART_TX);    
#endif
   ISR_EPILOG();
}

void DMA_UART1_RX_Int_Handler(void)
{
   ISR_PROLOG();
   ADI_UART_HANDLE const hDevice = (ADI_UART_HANDLE)uart_device_info[1].hDevice;
   uart_ManageProcessedBuffer(hDevice,hDevice->pChannelRx,ADI_UART_EVENT_RX_BUFFER_PROCESSED);
#if defined(ADI_CYCLECOUNT_UART_ISR_ENABLED) && (ADI_CYCLECOUNT_UART_ISR_ENABLED == 1u)
    ADI_CYCLECOUNT_STORE(ADI_CYCLECOUNT_ISR_DMA_UART_RX);    
#endif
   ISR_EPILOG();
}
#endif/*__ADUCM4x50__*/
/*
 * @brief                  UART interrupt handler for receiving the data in interrupt mode.
 *
 * @param [in]  hDevice   Device handle obtained from adi_uart_Open().
 * @param [in]  nBytes    Number of bytes to read from the RX.
 *
*/
static void uart_RxDataHandler(ADI_UART_HANDLE hDevice, uint8_t nBytes)
{
    ADI_UART_BUFF_INFO *pFillBuffer = hDevice->pChannelRx->pFillBuffer;

    /* Address of the buffer to be filled. */
    volatile uint8_t *pNextData = (uint8_t *)pFillBuffer->pStartAddress;

    bool activeBufferAvailable = (  (pNextData != NULL)
                                 && (pFillBuffer->bInUse == true)
                                 );
    /* If there is an active buffer when we enter this handler. */
    if(activeBufferAvailable)
    {

#if !defined(ADI_UART_DRAIN_RX_BUFFER) || (0==ADI_UART_DRAIN_RX_BUFFER)

        /* Extract the required amount of data from the FIFO/Rx
         * Buffer must not be overwritten
         */
        while (  (nBytes-- > 0)
              && (pFillBuffer->nIndex < pFillBuffer->nCount)
              )
        {
            /* Read data from the RX holding register into the buffer
             * at the indexed location.
             */
            pNextData[pFillBuffer->nIndex] = (uint8_t) hDevice->pUARTRegs->RX;

            /* Increment the buffer index to store the next data. */
            pFillBuffer->nIndex++;
        }

        /* If all of the data has been processed, manage the processed data
         * buffer. Otherwise we will leave everything as is and continue to
         * receive interrupts for the incoming data, until this buffer has
         * been filled.
         */
        if(pFillBuffer->nIndex == pFillBuffer->nCount)
        {
            uart_ManageProcessedBuffer( hDevice, hDevice->pChannelRx
                                      , ADI_UART_EVENT_RX_BUFFER_PROCESSED);
        }
 
#else

        /* There are two main criteria for this loop:
         *
         * - there are data in the Rx FIFO
         * - a valid buffer is available to store the data in Rx FIFO
         *
         * We keep the number of data in the Rx FIFO up to date
         */
        while (activeBufferAvailable)
        {
            /* Get the current number of bytes available in the UART Rx FIFO */
            nBytes = hDevice->pUARTRegs->RFC;

            /* if there are no bytes left then we can leave */
            if (!nBytes)
                break;

            while (nBytes--)
            {
                /* Read data from the RX holding register into the buffer
                 * at the indexed location.
                 */
                pNextData[pFillBuffer->nIndex] = hDevice->pUARTRegs->RX;

                /* Increment the buffer index to store the next data. */
                pFillBuffer->nIndex++;

                /* If the buffer is full. */
                if (pFillBuffer->nIndex == pFillBuffer->nCount)
                {
                    /* Try to get a new buffer */
                    uart_ManageProcessedBuffer(hDevice,
                        hDevice->pChannelRx,
                        ADI_UART_EVENT_RX_BUFFER_PROCESSED);

                    /* Pick up the newly submitted buffer */
                    pFillBuffer = hDevice->pChannelRx->pFillBuffer;
                    pNextData = (uint8_t *)pFillBuffer->pStartAddress;

                    /* Make sure it's an active buffer */
                    activeBufferAvailable = (  (pNextData != NULL)
                                            && (pFillBuffer->bInUse == true)
                                            );
                    /* if no active buffer is available then stop looping */
                    if (!activeBufferAvailable)
                    {
                        break;
                    }
                }
            }
        }

#endif
    }
    /* If we do not have a buffer submitted.. */
    else
    {
          /* Ask the API for a buffer so we can process this data before having
             an overflow. if there is no callback, the API will not be able to
             submit a buffer in time.
          */
          if (hDevice->pfCallback != NULL)
          {
              hDevice->pfCallback( hDevice->pCBParam
                                 , (uint32_t)ADI_UART_EVENT_NO_RX_BUFFER_EVENT
                                 , NULL);
          }

          /* This check here is in case in the callback the application
             submitted a buffer. If they did not then we need to clear
             the RX register in order to clear this interrupt.
          */
          if(   (pFillBuffer->pStartAddress == NULL)
            && (pFillBuffer->bInUse == false)
            )
          {
              hDevice->pUARTRegs->RX;
          }
    }

    return;
}

/*
 * @brief      UART interrupt handler transmitting the data in interrupt mode.
 *
 * @param [in]  hDevice   Device handle obtained from adi_uart_Open().
 *
*/
static void uart_TxDataHandler(ADI_UART_HANDLE hDevice)
{
      volatile uint8_t *pNextData;

    /* If there is an active buffer.. */
   if((hDevice->pChannelTx->pFillBuffer->pStartAddress != NULL) && (hDevice->pChannelTx->pFillBuffer->bInUse == true))
    {
           /* Get the start address of the buffer we are transmitting data from. */
           pNextData = (uint8_t *)hDevice->pChannelTx->pFillBuffer->pStartAddress;

           /* Write data to the TX holding register. This will be shifted out at the baud rate by the shift register. */
           hDevice->pUARTRegs->TX = (uint16_t)pNextData[hDevice->pChannelTx->pFillBuffer->nIndex];

           /* Increment the buffer index. */
          hDevice->pChannelTx->pFillBuffer->nIndex++;


           /* If all of the characters have been transmitted, manage the data buffer. Otherwise we will leave everything
              as is and continue to transmit this data until everything is out of the buffer. */
           if(hDevice->pChannelTx->pFillBuffer->nIndex >= hDevice->pChannelTx->pFillBuffer->nCount)
           {
                  uart_ManageProcessedBuffer(hDevice,hDevice->pChannelTx,ADI_UART_EVENT_TX_BUFFER_PROCESSED);
           }
    }
    return;
}


/*
 * @brief       Function for managing the processed buffer. This gets called after the receive buffer has been filled
 *              and when the transmit buffer has been emptied.
 *
 * @param [in]  hDevice    Device handle obtained from adi_uart_Open().
 * @param [in]  pChannel   Channel handler for the Tx or Rx.
 * @param [in]  eEvent     Indicate the event ID to be passed to registered callback function, if one has been registered.
 *
*/


static void uart_ManageProcessedBuffer(ADI_UART_HANDLE hDevice,ADI_UART_DATA_CHANNEL *pChannel, ADI_UART_EVENT eEvent)
{


    /* Now that this transaction has completed, this buffer is no longer in use. */
    pChannel->pFillBuffer->bInUse = false;

    pChannel->pFillBuffer = pChannel->pFillBuffer->pNextBuffer;

    if(eEvent == ADI_UART_EVENT_TX_BUFFER_PROCESSED)
    {
        /* Disable Tx buffer interrupts. */
        hDevice->pUARTRegs->IEN &= (uint16_t)~(BITM_UART_IEN_ETBEI | BITM_UART_IEN_EDMAT);
    }
    else
    {
        /* Disable Rx buffer interrupts for the DMA. We do not disable receive buffer full interrupts to allow
           the use of the RX FIFO.
        */
        hDevice->pUARTRegs->IEN &= (uint16_t)~(BITM_UART_IEN_EDMAR);

        if (hDevice->bRxFifoEn != true)
        {
            /* Disable Rx buffer interrupts for PIO mode if the FIFO is not enabled.
            */
            hDevice->pUARTRegs->IEN &= (uint16_t)~(BITM_UART_IEN_ERBFI);
        }

    }

    /* If there is a callback registered, notify the API that a buffer has been processed. Clean up the buffer. */
    if((hDevice->pfCallback != NULL) && (pChannel->eDataTranferMode == ADI_UART_DATA_TRANSFER_MODE_NONBLOCKING))
    {
        uint32_t nEvent = hDevice->nHwError;
        hDevice->nHwError = 0u;

        uint32_t *pBuffer = pChannel->pActiveBuffer->pStartAddress;

        /* Reinitialize the start address to NULL so this buffer can be used for a new transaction. */
        pChannel->pActiveBuffer->pStartAddress = NULL;

        /* Now that the desired data has either been transmitted or received, this buffer is no longer
           in use. We can update "pActiveBuffer" to point to the next buffer that will become or is already
           active.
        */
        pChannel->pActiveBuffer = pChannel->pActiveBuffer->pNextBuffer;

        /* Set the data transfer mode to none so that the next transfer can be either in blocking or in nonblocking mode.
           This will only be done if there are no other active buffers in flight to avoid disrupting an active transfer.
        */
        
        if(pChannel->pActiveBuffer->pStartAddress == NULL)
        {
            pChannel->eDataTranferMode = ADI_UART_DATA_TRANSFER_MODE_NONE;
        }

        if(nEvent != 0u)
        {
            hDevice->pfCallback(hDevice->pCBParam, ADI_UART_EVENT_HW_ERROR_DETECTED,(void*)nEvent);
        }
        else
        {
            hDevice->pfCallback(hDevice->pCBParam, (uint32_t)eEvent, (void*)pBuffer);
        }
        /* Post to the blocking function. If we are in blocking mode, this will allow the buffer to be returned to the API.
           If we are in nonblocking mode, this will allow adi_uart_GetBuffer() to return immediately so the API can have
           control over the buffer again.
        */ 
        SEM_POST(pChannel);
       }
   
    else
    {
        /* Wait until the last bit is gone before POSTing the SEMAPHORE */
        if(eEvent == ADI_UART_EVENT_TX_BUFFER_PROCESSED)
        while( ((hDevice->pUARTRegs->LSR & BITM_UART_LSR_TEMT) != BITM_UART_LSR_TEMT) ||(hDevice->pUARTRegs->TFC != 0u))
        {
            /*waiting until TFC becomes zero */
        }
        /* Set the data transfer mode to none so that the next transfer can be either in blocking or in nonblocking mode.
           This will only be done if there are no other active buffers in flight to avoid disrupting an active transfer.
         */
            
        if( pChannel->pActiveBuffer->pNextBuffer->pStartAddress==NULL)
        {
            pChannel->eDataTranferMode = ADI_UART_DATA_TRANSFER_MODE_NONE;
        }
           
        /* Post to the blocking function. If we are in blocking mode, this will allow the buffer to be returned to the API.
           If we are in nonblocking mode, this will allow adi_uart_GetBuffer() to return immediately so the API can have
           control over the buffer again.
        */
        SEM_POST(pChannel);
    }

    /* If there is another buffer active. The buffer we want to check is "pFillBuffer" because that is the next one that would
       be processed. So if it has been submitted, now would be the time to set up the interrupts based on its requirements.
    */
    if(pChannel->pFillBuffer->bInUse == true)
    {
        pChannel->pfSubmitBuffer(hDevice, pChannel->pFillBuffer);
    }
}



/*
 * @brief       Initialize the UART instance to the default values specified in "adi_uart_config.h".
 *
 * @param [in]  hDevice    Device handle obtained from adi_uart_Open().
 * @param [in]  nDeviceNum  UART device number
*/

static void uart_init(ADI_UART_CONST_HANDLE const hDevice, uint32_t const nDeviceNum)
{

    ADI_UART_CONFIG const* pUARTCfg = &gUARTCfg[nDeviceNum];

    /* Line Control Register. */
    hDevice->pUARTRegs->LCR = pUARTCfg->LCR;

    /* Div-C in Baudrate divider register. */
    hDevice->pUARTRegs->DIV = pUARTCfg->DIV;

    /* Div-M and Div-N in Fractional Baudrate register. */
    hDevice->pUARTRegs->FBR = pUARTCfg->FBR;

    /* Second line control register. */
    hDevice->pUARTRegs->LCR2 = pUARTCfg->LCR2;

    /* FIFO control register. */
    hDevice->pUARTRegs->FCR  = pUARTCfg->FCR;

    /* Half Duplex Control Register. */
    hDevice->pUARTRegs->RSC  = pUARTCfg->RSC;

    /* Interrupt enable register. */
    hDevice->pUARTRegs->IEN  = pUARTCfg->IEN;
}

#ifdef ADI_DEBUG
/*
 * @brief       Validate the device handle.
 *
 * @param [in]  hDevice    Device handle obtained from adi_uart_Open().
 *
 * @return      Status
 *    - #ADI_UART_SUCCESS          Specified handle is valid.
 *    - #ADI_UART_INVALID_HANDLE   Specified handle is invalid.
 *
*/

static ADI_UART_RESULT ValidateHandle(ADI_UART_CONST_HANDLE hDevice)
{
    uint32_t i;


    for(i = 0U; i <  ADI_UART_NUM_DEVICES; i++)
    {

      if((hDevice == uart_device_info[i].hDevice) && (hDevice != NULL))
       {
           return(ADI_UART_SUCCESS);
       }
    }
    return(ADI_UART_INVALID_HANDLE);
}

#endif /* ADI_DEBUG */
/*! \endcond */
/*@}*/



Remove personal lines in main code.
[edited by: thiagobrasil2022 at 8:47 PM (GMT -4) on 28 Sep 2022]