//###########################################################################
//
// FILE:   sci.h
//
// TITLE:  C28x SCI driver.
//
//###########################################################################
// $TI Release: F28002x Support Library v3.04.00.00 $
// $Release Date: Fri Feb 12 18:58:34 IST 2021 $
// $Copyright:
// Copyright (C) 2021 Texas Instruments Incorporated - http://www.ti.com/
//
// 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.
// 
//   Neither the name of Texas Instruments Incorporated nor the names of
//   its contributors may be used to endorse or promote products derived
//   from this software without specific prior written permission.
// 
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 
// LIMITED TO, 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 SCI_H
#define SCI_H

//*****************************************************************************
//
// If building with a C++ compiler, make all of the definitions in this header
// have a C binding.
//
//*****************************************************************************
#ifdef __cplusplus
extern "C"
{
#endif

//*****************************************************************************
//
//! \addtogroup sci_api SCI
//! @{
//
//*****************************************************************************

#include <stdbool.h>
#include <stdint.h>
#include "inc/hw_memmap.h"
#include "inc/hw_sci.h"
#include "inc/hw_types.h"
#include "debug.h"

//*****************************************************************************
//
// Values that can be passed to SCI_enableInterrupt, SCI_disableInterrupt, and
// SCI_clearInterruptStatus as the intFlags parameter, and returned from
// SCI_getInterruptStatus.
//
//*****************************************************************************
#define SCI_INT_RXERR          0x01U  //!< RXERR interrupt
#define SCI_INT_RXRDY_BRKDT    0x02U  //!< RXRDY interrupt
#define SCI_INT_TXRDY          0x04U  //!< TXRDY interrupt
#define SCI_INT_TXFF           0x08U  //!< TX FIFO level interrupt
#define SCI_INT_RXFF           0x10U  //!< RX FIFO level interrupt
#define SCI_INT_FE             0x20U  //!< Frame Error
#define SCI_INT_OE             0x40U  //!< Overrun Error
#define SCI_INT_PE             0x80U  //!< Parity Error

//*****************************************************************************
//
// Values that can be passed to SCI_setConfig as the config parameter
// and returned by SCI_getConfig in the config parameter.
// Additionally, the SCI_CONFIG_PAR_* enum subset can be passed to
// SCI_setParityMode as the parity parameter, and are returned by
// SCI_getParityMode.
//
//*****************************************************************************
#define SCI_CONFIG_WLEN_MASK   0x0007U  //!< Mask for extracting word length
#define SCI_CONFIG_WLEN_8      0x0007U  //!< 8 bit data
#define SCI_CONFIG_WLEN_7      0x0006U  //!< 7 bit data
#define SCI_CONFIG_WLEN_6      0x0005U  //!< 6 bit data
#define SCI_CONFIG_WLEN_5      0x0004U  //!< 5 bit data
#define SCI_CONFIG_WLEN_4      0x0003U  //!< 4 bit data
#define SCI_CONFIG_WLEN_3      0x0002U  //!< 3 bit data
#define SCI_CONFIG_WLEN_2      0x0001U  //!< 2 bit data
#define SCI_CONFIG_WLEN_1      0x0000U  //!< 1 bit data
#define SCI_CONFIG_STOP_MASK   0x0080U  //!< Mask for extracting stop bits
#define SCI_CONFIG_STOP_ONE    0x0000U  //!< One stop bit
#define SCI_CONFIG_STOP_TWO    0x0080U  //!< Two stop bits
#define SCI_CONFIG_PAR_MASK    0x0060U  //!< Parity Mask

//*****************************************************************************
//
//! Values that can be used with SCI_setParityMode() and SCI_getParityMode() to
//! describe the parity of the SCI communication.
//
//*****************************************************************************
typedef enum
{
    SCI_CONFIG_PAR_NONE = 0x0000U,  //!< No parity
    SCI_CONFIG_PAR_EVEN = 0x0060U,  //!< Even parity
    SCI_CONFIG_PAR_ODD  = 0x0020U   //!< Odd parity
} SCI_ParityType;

//*****************************************************************************
//
//! Values that can be passed to SCI_setFIFOInterruptLevel() as the txLevel
//! parameter and returned by SCI_getFIFOInteruptLevel() and
//! SCI_getTxFIFOStatus().
//
//*****************************************************************************
typedef enum
{
    SCI_FIFO_TX0  = 0x0000U, //!< Transmit interrupt empty
    SCI_FIFO_TX1  = 0x0001U, //!< Transmit interrupt 1/16 full
    SCI_FIFO_TX2  = 0x0002U, //!< Transmit interrupt 2/16 full
    SCI_FIFO_TX3  = 0x0003U, //!< Transmit interrupt 3/16 full
    SCI_FIFO_TX4  = 0x0004U, //!< Transmit interrupt 4/16 full
    SCI_FIFO_TX5  = 0x0005U, //!< Transmit interrupt 5/16 full
    SCI_FIFO_TX6  = 0x0006U, //!< Transmit interrupt 6/16 full
    SCI_FIFO_TX7  = 0x0007U, //!< Transmit interrupt 7/16 full
    SCI_FIFO_TX8  = 0x0008U, //!< Transmit interrupt 8/16 full
    SCI_FIFO_TX9  = 0x0009U, //!< Transmit interrupt 9/16 full
    SCI_FIFO_TX10 = 0x000AU, //!< Transmit interrupt 10/16 full
    SCI_FIFO_TX11 = 0x000BU, //!< Transmit interrupt 11/16 full
    SCI_FIFO_TX12 = 0x000CU, //!< Transmit interrupt 12/16 full
    SCI_FIFO_TX13 = 0x000DU, //!< Transmit interrupt 13/16 full
    SCI_FIFO_TX14 = 0x000EU, //!< Transmit interrupt 14/16 full
    SCI_FIFO_TX15 = 0x000FU, //!< Transmit interrupt 15/16 full
    SCI_FIFO_TX16 = 0x0010U  //!< Transmit interrupt full
} SCI_TxFIFOLevel;

//*****************************************************************************
//
//! Values that can be passed to SCI_setFIFOInterruptLevel() as the rxLevel
//! parameter and returned by SCI_getFIFOInterruptLevel() and
//! SCI_getRxFIFOStatus().
//
//*****************************************************************************
typedef enum
{
    SCI_FIFO_RX0  = 0x0000U, //!< Receive interrupt empty
    SCI_FIFO_RX1  = 0x0001U, //!< Receive interrupt 1/16 full
    SCI_FIFO_RX2  = 0x0002U, //!< Receive interrupt 2/16 full
    SCI_FIFO_RX3  = 0x0003U, //!< Receive interrupt 3/16 full
    SCI_FIFO_RX4  = 0x0004U, //!< Receive interrupt 4/16 full
    SCI_FIFO_RX5  = 0x0005U, //!< Receive interrupt 5/16 full
    SCI_FIFO_RX6  = 0x0006U, //!< Receive interrupt 6/16 full
    SCI_FIFO_RX7  = 0x0007U, //!< Receive interrupt 7/16 full
    SCI_FIFO_RX8  = 0x0008U, //!< Receive interrupt 8/16 full
    SCI_FIFO_RX9  = 0x0009U, //!< Receive interrupt 9/16 full
    SCI_FIFO_RX10 = 0x000AU, //!< Receive interrupt 10/16 full
    SCI_FIFO_RX11 = 0x000BU, //!< Receive interrupt 11/16 full
    SCI_FIFO_RX12 = 0x000CU, //!< Receive interrupt 12/16 full
    SCI_FIFO_RX13 = 0x000DU, //!< Receive interrupt 13/16 full
    SCI_FIFO_RX14 = 0x000EU, //!< Receive interrupt 14/16 full
    SCI_FIFO_RX15 = 0x000FU, //!< Receive interrupt 15/16 full
    SCI_FIFO_RX16 = 0x0010U  //!< Receive interrupt full
} SCI_RxFIFOLevel;

//*****************************************************************************
//
// Values returned from SCI_getRxStatus().  These correspond to the different
// bits and flags of the SCIRXST register.
//
//*****************************************************************************
#define SCI_RXSTATUS_WAKE       0x0002U  //!< Receiver wake up detect
#define SCI_RXSTATUS_PARITY     0x0004U  //!< Parity error
#define SCI_RXSTATUS_OVERRUN    0x0008U  //!< Overrun error
#define SCI_RXSTATUS_FRAMING    0x0010U  //!< Framing error
#define SCI_RXSTATUS_BREAK      0x0020U  //!< Break detect
#define SCI_RXSTATUS_READY      0x0040U  //!< Receiver ready
#define SCI_RXSTATUS_ERROR      0x0080U  //!< Receiver error

//*****************************************************************************
//
// API Function prototypes
//
//*****************************************************************************
//*****************************************************************************
//
//! \internal
//! Checks a SCI base address.
//!
//! \param base is the base address of the SCI port.
//!
//! This function determines if a SCI port base address is valid.
//!
//! \return Returns \b true if the base address is valid and \b false
//! otherwise.
//
//*****************************************************************************
#ifdef DEBUG
static inline bool
SCI_isBaseValid(uint32_t base)
{
    return(
           (base == SCIA_BASE)
          );
}
#endif

//*****************************************************************************
//
//! Sets the type of parity.
//!
//! \param base is the base address of the SCI port.
//! \param parity specifies the type of parity to use.
//!
//! Sets the type of parity to use for transmitting and expect when receiving.
//! The \e parity parameter must be one of the following:
//! \b SCI_CONFIG_PAR_NONE, \b SCI_CONFIG_PAR_EVEN, \b SCI_CONFIG_PAR_ODD.
//!
//! \return None.
//
//*****************************************************************************
static inline void
SCI_setParityMode(uint32_t base, SCI_ParityType parity)
{
    //
    // Check the arguments.
    //
    ASSERT(SCI_isBaseValid(base));

    //
    // Set the parity mode.
    //
    HWREGH(base + SCI_O_CCR) = ((HWREGH(base + SCI_O_CCR) &
                                 ~(SCI_CONFIG_PAR_MASK)) | (uint16_t)parity);
}

//*****************************************************************************
//
//! Gets the type of parity currently being used.
//!
//! \param base is the base address of the SCI port.
//!
//! This function gets the type of parity used for transmitting data and
//! expected when receiving data.
//!
//! \return Returns the current parity settings, specified as one of the
//! following:
//! \b SCI_CONFIG_PAR_NONE, \b SCI_CONFIG_PAR_EVEN, \b SCI_CONFIG_PAR_ODD.
//
//*****************************************************************************
static inline SCI_ParityType
SCI_getParityMode(uint32_t base)
{
    uint16_t parity;

    //
    // Check the arguments.
    //
    ASSERT(SCI_isBaseValid(base));

    //
    // Return the current parity setting.
    //
    parity = (HWREGH(base + SCI_O_CCR) & (SCI_CONFIG_PAR_MASK));

    return((SCI_ParityType)parity);
}

//*****************************************************************************
//
//! Locks Autobaud.
//!
//! \param base is the base address of the SCI port.
//!
//! This function performs an autobaud lock for the SCI.
//!
//! \return None.
//
//*****************************************************************************
static inline void
SCI_lockAutobaud(uint32_t base)
{
    //
    // Check the arguments.
    //
    ASSERT(SCI_isBaseValid(base));

    //
    // Prime the baud register
    //
    HWREGH(base + SCI_O_HBAUD) = 0x0U;
    HWREGH(base + SCI_O_LBAUD) = 0x1U;

    //
    // Prepare for autobaud detection.
    // Set the CDC bit to enable autobaud detection and clear the ABD bit.
    //
    HWREGH(base + SCI_O_FFCT) |= SCI_FFCT_CDC;
    HWREGH(base + SCI_O_FFCT) |= SCI_FFCT_ABDCLR;

    //
    // Wait until we correctly read an 'A' or 'a' and lock
    //
    while((HWREGH(base + SCI_O_FFCT) & SCI_FFCT_ABD) != SCI_FFCT_ABD)
    {
    }

    //
    // After autobaud lock, clear the ABD and CDC bits
    //
    HWREGH(base + SCI_O_FFCT) |= SCI_FFCT_ABDCLR;
    HWREGH(base + SCI_O_FFCT) &= ~SCI_FFCT_CDC;
}

//*****************************************************************************
//
//! Sets the FIFO interrupt level at which interrupts are generated.
//!
//! \param base is the base address of the SCI port.
//! \param txLevel is the transmit FIFO interrupt level, specified as one of
//! the following:
//! \b SCI_FIFO_TX0, \b SCI_FIFO_TX1, \b SCI_FIFO_TX2, . . . or
//! \b SCI_FIFO_TX15.
//! \param rxLevel is the receive FIFO interrupt level, specified as one of
//! the following
//! \b SCI_FIFO_RX0, \b SCI_FIFO_RX1, \b SCI_FIFO_RX2, ... or \b SCI_FIFO_RX15.
//!
//! This function sets the FIFO level at which transmit and receive interrupts
//! are generated.
//!
//! \return None.
//
//*****************************************************************************
static inline void
SCI_setFIFOInterruptLevel(uint32_t base, SCI_TxFIFOLevel txLevel,
                          SCI_RxFIFOLevel rxLevel)
{
    //
    // Check the arguments.
    //
    ASSERT(SCI_isBaseValid(base));

    //
    // Set the FIFO interrupt levels.
    //
    HWREGH(base + SCI_O_FFTX) = (HWREGH(base + SCI_O_FFTX) &
                                 (~SCI_FFTX_TXFFIL_M)) | (uint16_t)txLevel;
    HWREGH(base + SCI_O_FFRX) = (HWREGH(base + SCI_O_FFRX) &
                                 (~SCI_FFRX_RXFFIL_M)) | (uint16_t)rxLevel;
}

//*****************************************************************************
//
//! Gets the FIFO interrupt level at which interrupts are generated.
//!
//! \param base is the base address of the SCI port.
//! \param txLevel is a pointer to storage for the transmit FIFO interrupt
//! level, returned as one of the following:
//! \b SCI_FIFO_TX0, \b SCI_FIFO_TX1, \b SCI_FIFO_TX2, ... or \b SCI_FIFO_TX15.
//! \param rxLevel is a pointer to storage for the receive FIFO interrupt
//! level, returned as one of the following:
//! \b SCI_FIFO_RX0, \b SCI_FIFO_RX1, \b SCI_FIFO_RX2, ... or \b SCI_FIFO_RX15.
//!
//! This function gets the FIFO level at which transmit and receive interrupts
//! are generated.
//!
//! \return None.
//
//*****************************************************************************
static inline void
SCI_getFIFOInterruptLevel(uint32_t base, SCI_TxFIFOLevel *txLevel,
                          SCI_RxFIFOLevel *rxLevel)
{

    //
    // Check the arguments.
    //
    ASSERT(SCI_isBaseValid(base));

    //
    // Extract the transmit and receive FIFO levels.
    //
    *txLevel = (SCI_TxFIFOLevel)(HWREGH(base + SCI_O_FFTX) &
                                 SCI_FFTX_TXFFIL_M);
    *rxLevel = (SCI_RxFIFOLevel)(HWREGH(base + SCI_O_FFRX) &
                                 SCI_FFRX_RXFFIL_M);
}

//*****************************************************************************
//
//! Gets the current configuration of a SCI.
//!
//! \param base is the base address of the SCI port.
//! \param lspclkHz is the rate of the clock supplied to the SCI module.  This
//! is the LSPCLK.
//! \param baud is a pointer to storage for the baud rate.
//! \param config is a pointer to storage for the data format.
//!
//! The baud rate and data format for the SCI is determined, given an
//! explicitly provided peripheral clock (hence the ExpClk suffix).  The
//! returned baud rate is the actual baud rate; it may not be the exact baud
//! rate requested or an ``official'' baud rate.  The data format returned in
//! \e config is enumerated the same as the \e config parameter of
//! SCI_setConfig().
//!
//! The peripheral clock is the low speed peripheral clock.  This will be
//! the value returned by SysCtl_getLowSeedClock(), or it can be explicitly
//! hard coded if it is constant and known (to save the code/execution overhead
//! of a call to SysCtl_getLowSpeedClock()).
//!
//! \return None.
//
//*****************************************************************************
static inline void
SCI_getConfig(uint32_t base, uint32_t lspclkHz, uint32_t *baud,
              uint32_t *config)
{
    //
    // Check the arguments.
    //
    ASSERT(SCI_isBaseValid(base));

    //
    // Compute the baud rate.
    //
    *baud = lspclkHz /
            ((1U + (uint32_t)((uint32_t)(HWREGH(base + SCI_O_HBAUD) << 8U) |
               HWREGH(base + SCI_O_LBAUD))) * 8U);

    //
    // Get the parity, data length, and number of stop bits.
    //
    *config = HWREGH(base + SCI_O_CCR) & (SCI_CONFIG_PAR_MASK |
                                          SCI_CONFIG_STOP_MASK |
                                          SCI_CONFIG_WLEN_MASK);
}

//*****************************************************************************
//
//! Enables transmitting and receiving.
//!
//! \param base is the base address of the SCI port.
//!
//! Enables SCI by taking SCI out of the software reset. Sets the TXENA, and
//! RXENA bits which enables transmit and receive.
//!
//! \return None.
//
//*****************************************************************************
static inline void
SCI_enableModule(uint32_t base)
{
    //
    // Check the arguments.
    //
    ASSERT(SCI_isBaseValid(base));

    //
    // Enable RX, TX, and the SCI.
    //
    HWREGH(base + SCI_O_CTL1) |= (SCI_CTL1_TXENA | SCI_CTL1_RXENA |
                                  SCI_CTL1_SWRESET);
}

//*****************************************************************************
//
//! Disables transmitting and receiving.
//!
//! \param base is the base address of the SCI port.
//!
//! Clears the SCIEN, TXE, and RXE bits. The user should ensure that all the
//! data has been sent before disable the module during transmission.
//!
//! \return None.
//
//*****************************************************************************
static inline void
SCI_disableModule(uint32_t base)
{
    //
    // Check the arguments.
    //
    ASSERT(SCI_isBaseValid(base));

    //
    // Disable the FIFO.
    //
    HWREGH(base + SCI_O_FFTX) &= ~(SCI_FFTX_SCIFFENA);

    //
    // Disable the SCI.
    //
    HWREGH(base + SCI_O_CTL1) &= ~(SCI_CTL1_TXENA | SCI_CTL1_RXENA);
}

//*****************************************************************************
//
//! Enables the transmit and receive FIFOs.
//!
//! \param base is the base address of the SCI port.
//!
//! This functions enables the transmit and receive FIFOs in the SCI.
//!
//! \return None.
//
//*****************************************************************************
static inline void
SCI_enableFIFO(uint32_t base)
{
    //
    // Check the arguments.
    //
    ASSERT(SCI_isBaseValid(base));

    //
    // Enable the FIFO.
    //
    HWREGH(base + SCI_O_FFTX) |= SCI_FFTX_SCIRST;
    HWREGH(base + SCI_O_FFTX) |= SCI_FFTX_SCIFFENA | SCI_FFTX_TXFIFORESET;
    HWREGH(base + SCI_O_FFRX) |= SCI_FFRX_RXFIFORESET;
}

//*****************************************************************************
//
//! Disables the transmit and receive FIFOs.
//!
//! \param base is the base address of the SCI port.
//!
//! This functions disables the transmit and receive FIFOs in the SCI.
//!
//! \return None.
//
//*****************************************************************************
static inline void
SCI_disableFIFO(uint32_t base)
{
    //
    // Check the arguments.
    //
    ASSERT(SCI_isBaseValid(base));

    //
    // Disable the FIFO.
    //
    HWREGH(base + SCI_O_FFTX) &= ~SCI_FFTX_SCIFFENA;
}

//*****************************************************************************
//
//! Determines if the FIFO enhancement is enabled.
//!
//! \param base is the base address of the SCI port.
//!
//! This function returns a flag indicating whether or not the FIFO enhancement
//! is enabled.
//!
//! \return Returns \b true if the FIFO enhancement is enabled or \b false
//! if the FIFO enhancement is disabled.
//
//*****************************************************************************
static inline bool
SCI_isFIFOEnabled(uint32_t base)
{
    //
    // Check the arguments.
    //
    ASSERT(SCI_isBaseValid(base));

    //
    // Return true if the FIFO is enabled and false if it is disabled.
    //
    return(((HWREGH(base + SCI_O_FFTX) & SCI_FFTX_SCIFFENA) ==
            SCI_FFTX_SCIFFENA) ? true : false);
}

//*****************************************************************************
//
//! Resets the receive FIFO.
//!
//! \param base is the base address of the SCI port.
//!
//! This functions resets the receive FIFO of the SCI.
//!
//! \return None.
//
//*****************************************************************************
static inline void
SCI_resetRxFIFO(uint32_t base)
{
    //
    // Check the arguments.
    //
    ASSERT(SCI_isBaseValid(base));

    //
    // Reset the specified FIFO.
    //
    HWREGH(base + SCI_O_FFRX) &= ~SCI_FFRX_RXFIFORESET;
    HWREGH(base + SCI_O_FFRX) |= SCI_FFRX_RXFIFORESET;
}

//*****************************************************************************
//
//! Resets the transmit FIFO.
//!
//! \param base is the base address of the SCI port.
//!
//! This functions resets the transmit FIFO of the SCI.
//!
//! \return None.
//
//*****************************************************************************
static inline void
SCI_resetTxFIFO(uint32_t base)
{
    //
    // Check the arguments.
    //
    ASSERT(SCI_isBaseValid(base));

    //
    // Reset the specified FIFO.
    //
    HWREGH(base + SCI_O_FFTX) &= ~SCI_FFTX_TXFIFORESET;
    HWREGH(base + SCI_O_FFTX) |= SCI_FFTX_TXFIFORESET;
}

//*****************************************************************************
//
//! Resets the SCI Transmit and Receive Channels
//!
//! \param base is the base address of the SCI port.
//!
//! This functions resets transmit and receive channels in the SCI.
//!
//! \return None.
//
//*****************************************************************************
static inline void
SCI_resetChannels(uint32_t base)
{
    //
    // Check the arguments.
    //
    ASSERT(SCI_isBaseValid(base));

    //
    // Reset the Tx and Rx Channels
    //
    HWREGH(base + SCI_O_FFTX) &= ~SCI_FFTX_SCIRST;
    HWREGH(base + SCI_O_FFTX) |= SCI_FFTX_SCIRST;
}

//*****************************************************************************
//
//! Determines if there are any characters in the receive buffer when the
//! FIFO enhancement is not enabled.
//!
//! \param base is the base address of the SCI port.
//!
//! This function returns a flag indicating whether or not there is data
//! available in the receive buffer.
//!
//! \return Returns \b true if there is data in the receive buffer or \b false
//! if there is no data in the receive buffer.
//
//*****************************************************************************
static inline bool
SCI_isDataAvailableNonFIFO(uint32_t base)
{
    //
    // Check the arguments.
    //
    ASSERT(SCI_isBaseValid(base));

    //
    // Return the availability of characters with FIFO disabled.
    //
    return(((HWREGH(base + SCI_O_RXST) & SCI_RXST_RXRDY) ==
            SCI_RXST_RXRDY) ? true : false);
}

//*****************************************************************************
//
//! Determines if there is any space in the transmit buffer when the FIFO
//! enhancement is not enabled.
//!
//! \param base is the base address of the SCI port.
//!
//! This function returns a flag indicating whether or not there is space
//! available in the transmit buffer when not using the FIFO enhancement.
//!
//! \return Returns \b true if there is space available in the transmit buffer
//! or \b false if there is no space available in the transmit buffer.
//
//*****************************************************************************
static inline bool
SCI_isSpaceAvailableNonFIFO(uint32_t base)
{
    //
    // Check the arguments.
    //
    ASSERT(SCI_isBaseValid(base));

    //
    // Return the availability of space.
    //
    return(((HWREGH(base + SCI_O_CTL2) & SCI_CTL2_TXRDY) ==
            SCI_CTL2_TXRDY) ? true : false);
}

//*****************************************************************************
//
//! Get the transmit FIFO status
//!
//! \param base is the base address of the SCI port.
//!
//! This functions gets the current number of words in the transmit FIFO.
//!
//! \return Returns the current number of words in the transmit FIFO specified
//! as one of the following:
//! \b SCI_FIFO_TX0, \b SCI_FIFO_TX1, \b SCI_FIFO_TX2, \b SCI_FIFO_TX3
//! \b SCI_FIFO_TX4, ..., or \b SCI_FIFO_TX16
//
//*****************************************************************************
static inline SCI_TxFIFOLevel
SCI_getTxFIFOStatus(uint32_t base)
{
    //
    // Check the arguments.
    //
    ASSERT(SCI_isBaseValid(base));

    //
    // Get the current FIFO status
    //
    return((SCI_TxFIFOLevel)((HWREGH(base + SCI_O_FFTX) & SCI_FFTX_TXFFST_M) >>
                             SCI_FFTX_TXFFST_S));
}

//*****************************************************************************
//
//! Get the receive FIFO status
//!
//! \param base is the base address of the SCI port.
//!
//! This functions gets the current number of words in the receive FIFO.
//!
//! \return Returns the current number of words in the receive FIFO specified
//! as one of the following:
//! \b SCI_FIFO_RX0, \b SCI_FIFO_RX1, \b SCI_FIFO_RX2, \b SCI_FIFO_RX3
//! \b SCI_FIFO_RX4, ..., or \b SCI_FIFO_RX16
//
//*****************************************************************************
static inline SCI_RxFIFOLevel
SCI_getRxFIFOStatus(uint32_t base)
{
    //
    // Check the arguments.
    //
    ASSERT(SCI_isBaseValid(base));

    //
    // Get the current FIFO status
    //
    return((SCI_RxFIFOLevel)((HWREGH(base + SCI_O_FFRX) & SCI_FFRX_RXFFST_M) >>
                             SCI_FFRX_RXFFST_S));
}

//*****************************************************************************
//
//! Determines whether the SCI transmitter is busy or not.
//!
//! \param base is the base address of the SCI port.
//!
//! Allows the caller to determine whether all transmitted bytes have cleared
//! the transmitter hardware when the FIFO is not enabled.  When the FIFO is
//! enabled, this function allows the caller to determine whether there is any
//! data in the FIFO.
//!
//! Without the FIFO enabled, if \b false is returned, the transmit buffer and
//! shift registers are empty and the transmitter is not busy. With the FIFO
//! enabled, if \b false is returned, the FIFO is empty.  This does not
//! necessarily mean that the transmitter is not busy.  The empty FIFO does not
//! reflect the status of the transmitter shift register. The FIFO may be empty
//! while the transmitter is still transmitting data.
//!
//! \return Returns \b true if the SCI is transmitting or \b false if
//! transmissions are complete.
//
//*****************************************************************************
static inline bool
SCI_isTransmitterBusy(uint32_t base)
{
    //
    // Check the argument.
    //
    ASSERT(SCI_isBaseValid(base));

    //
    // Check if FIFO enhancement is enabled.
    //
    if(SCI_isFIFOEnabled(base))
    {
        //
        // With FIFO enhancement, determine if the SCI is busy.
        //
        return(((HWREGH(base + SCI_O_FFTX) & SCI_FFTX_TXFFST_M) !=
                 0) ? true : false);
    }
    else
    {
        //
        // Without FIFO enhancement, determine if the SCI is busy.
        // Check if the transmit buffer and shift register empty.
        //
        return(((HWREGH(base + SCI_O_CTL2) & SCI_CTL2_TXEMPTY) ==
                SCI_CTL2_TXEMPTY) ? false : true);
    }
}

//*****************************************************************************
//
//! Waits to send a character from the specified port when the FIFO enhancement
//! is enabled.
//!
//! \param base is the base address of the SCI port.
//! \param data is the character to be transmitted.
//!
//! Sends the character \e data to the transmit buffer for the specified port.
//! If there is no space available in the transmit FIFO, this function waits
//! until there is space available before returning. \e data is a uint16_t but
//! only 8 bits are written to the SCI port.  SCI only transmits 8 bit
//! characters.
//!
//! \return None.
//
//*****************************************************************************
static inline void
SCI_writeCharBlockingFIFO(uint32_t base, uint16_t data)
{
    //
    // Check the arguments.
    //
    ASSERT(SCI_isBaseValid(base));

    //
    // Wait until space is available in the transmit FIFO.
    //
    while(SCI_getTxFIFOStatus(base) == SCI_FIFO_TX15)
    {
    }

    //
    // Send a char.
    //
    HWREGH(base + SCI_O_TXBUF) = data;
}

//*****************************************************************************
//
//! Waits to send a character from the specified port.
//!
//! \param base is the base address of the SCI port.
//! \param data is the character to be transmitted.
//!
//! Sends the character \e data to the transmit buffer for the specified port.
//! If there is no space available in the transmit buffer, or the transmit
//! FIFO if it is enabled, this function waits until there is space available
//! before returning. \e data is a uint16_t but only 8 bits are written to the
//! SCI port.  SCI only transmits 8 bit characters.
//!
//! \return None.
//
//*****************************************************************************
static inline void
SCI_writeCharBlockingNonFIFO(uint32_t base, uint16_t data)
{
    //
    // Check the arguments.
    //
    ASSERT(SCI_isBaseValid(base));

    //
    // Wait until space is available in the transmit buffer.
    //
    while(!SCI_isSpaceAvailableNonFIFO(base))
    {
    }

    //
    // Send a char.
    //
    HWREGH(base + SCI_O_TXBUF) = data;
}

//*****************************************************************************
//
//! Sends a character to the specified port.
//!
//! \param base is the base address of the SCI port.
//! \param data is the character to be transmitted.
//!
//! Writes the character \e data to the transmit buffer for the specified port.
//! This function does not block and only writes to the transmit buffer.
//! The user should use SCI_isSpaceAvailableNonFIFO() or SCI_getTxFIFOStatus()
//! to determine if the transmit buffer or FIFO have space available.
//! \e data is a uint16_t but only 8 bits are written to the SCI port.  SCI
//! only transmits 8 bit characters.
//!
//! This function replaces the original SCICharNonBlockingPut() API and
//! performs the same actions.  A macro is provided in <tt>sci.h</tt> to map
//! the original API to this API.
//!
//! \return None.
//
//*****************************************************************************
static inline void
SCI_writeCharNonBlocking(uint32_t base, uint16_t data)
{
    //
    // Check the arguments.
    //
    ASSERT(SCI_isBaseValid(base));

    //
    // Send a char.
    //
    HWREGH(base + SCI_O_TXBUF) = data;
}

//*****************************************************************************
//
//! Gets current receiver status flags.
//!
//! \param base is the base address of the SCI port.
//!
//! This function returns the current receiver status flags.  The returned
//! error flags are equivalent to the error bits returned via the previous
//! reading or receiving of a character with the exception that the overrun
//! error is set immediately the overrun occurs rather than when a character
//! is next read.
//!
//! \return Returns a bitwise OR combination of the receiver status flags,
//! \b SCI_RXSTATUS_WAKE, \b SCI_RXSTATUS_PARITY, \b SCI_RXSTATUS_OVERRUN,
//! \b SCI_RXSTATUS_FRAMING, \b SCI_RXSTATUS_BREAK, \b SCI_RXSTATUS_READY,
//! and \b SCI_RXSTATUS_ERROR.
//
//*****************************************************************************
static inline uint16_t
SCI_getRxStatus(uint32_t base)
{
    //
    // Check the arguments.
    //
    ASSERT(SCI_isBaseValid(base));

    //
    // Return the current value of the receive status register.
    //
    return(HWREGH(base + SCI_O_RXST));
}

//*****************************************************************************
//
//! Waits for a character from the specified port when the FIFO enhancement
//! is enabled.
//!
//! \param base is the base address of the SCI port.
//!
//! Gets a character from the receive FIFO for the specified port.  If there
//! are no characters available, this function waits until a character is
//! received before returning. Returns immediately in case of Error.
//!
//! \return Returns the character read from the specified port as \e uint16_t
//!         or 0x0 in case of Error. The application must use
//!         SCI_getRxStatus() API to check if some error occurred before
//!         consuming the data
//
//*****************************************************************************
static inline uint16_t
SCI_readCharBlockingFIFO(uint32_t base)
{
    //
    // Check the arguments.
    //
    ASSERT(SCI_isBaseValid(base));

    //
    // Wait until a character is available in the receive FIFO.
    //
    while(SCI_getRxFIFOStatus(base) == SCI_FIFO_RX0)
    {
        //
        //If there is any error return
        //
        if((SCI_getRxStatus(base) & SCI_RXSTATUS_ERROR) != 0U)
        {
            return 0U;
        }
    }

    //
    // Return the character from the receive buffer.
    //
    return(uint16_t)(HWREGH(base + SCI_O_RXBUF) & SCI_RXBUF_SAR_M);
}

//*****************************************************************************
//
//! Waits for a character from the specified port when the FIFO enhancement
//! is not enabled.
//!
//! \param base is the base address of the SCI port.
//!
//! Gets a character from the receive buffer for the specified port.  If there
//! is no characters available, this function waits until a character is
//! received before returning.
//!
//! \return Returns the character read from the specified port as \e uint16_t.
//
//*****************************************************************************
static inline uint16_t
SCI_readCharBlockingNonFIFO(uint32_t base)
{
    //
    // Check the arguments.
    //
    ASSERT(SCI_isBaseValid(base));

    //
    // Wait until a character is available in the receive FIFO.
    //
    while(!SCI_isDataAvailableNonFIFO(base))
    {
    }

    //
    // Return the character from the receive buffer.
    //
    return(uint16_t)(HWREGH(base + SCI_O_RXBUF) & SCI_RXBUF_SAR_M);
}

//*****************************************************************************
//
//! Receives a character from the specified port.
//!
//! \param base is the base address of the SCI port.
//!
//! Gets a character from the receive buffer for the specified port. This
//! function does not block and only reads the receive buffer.  The user should
//! use SCI_isDataAvailableNonFIFO() or SCI_getRxFIFOStatus() to determine if
//! the receive buffer or FIFO have data available.
//!
//! This function replaces the original SCICharNonBlockingGet() API and
//! performs the same actions.  A macro is provided in <tt>sci.h</tt> to map
//! the original API to this API.
//!
//! \return Returns \e uin16_t which is read from the receive buffer.
//
//*****************************************************************************
static inline uint16_t
SCI_readCharNonBlocking(uint32_t base)
{
    //
    // Check the arguments.
    //
    ASSERT(SCI_isBaseValid(base));

    //
    // Return the character from the receive buffer.
    //
    return(uint16_t)(HWREGH(base + SCI_O_RXBUF) & SCI_RXBUF_SAR_M);
}

//*****************************************************************************
//
//! Performs a software reset of the SCI and Clears all reported receiver
//! status flags.
//!
//! \param base is the base address of the SCI port.
//!
//! This function performs a software reset of the SCI port.  It affects the
//! operating flags of the SCI, but it neither affects the configuration bits
//! nor restores the reset values.
//!
//! \return None.
//
//*****************************************************************************
static inline void
SCI_performSoftwareReset(uint32_t base)
{
    //
    // Check the arguments.
    //
    ASSERT(SCI_isBaseValid(base));

    //
    // To clear all errors a sw reset of the module is required
    //
    HWREGH(base + SCI_O_CTL1) &= ~SCI_CTL1_SWRESET;
    HWREGH(base + SCI_O_CTL1) |= SCI_CTL1_SWRESET;
}

//*****************************************************************************
//
//! Enables Loop Back Test Mode
//!
//! \param base is the base address of the SCI port.
//!
//! Enables the loop back test mode where the Tx pin is internally connected
//! to the Rx pin.
//!
//! \return None.
//
//*****************************************************************************
static inline void
SCI_enableLoopback(uint32_t base)
{
    //
    // Check the arguments.
    //
    ASSERT(SCI_isBaseValid(base));

    //
    // Set the loop back mode.
    //
    HWREGH(base + SCI_O_CCR) |= SCI_CCR_LOOPBKENA;
}

//*****************************************************************************
//
//! Disables Loop Back Test Mode
//!
//! \param base is the base address of the SCI port.
//!
//! Disables the loop back test mode where the Tx pin is no longer internally
//! connected to the Rx pin.
//!
//! \return None.
//
//*****************************************************************************
static inline void
SCI_disableLoopback(uint32_t base)
{
    //
    // Check the arguments.
    //
    ASSERT(SCI_isBaseValid(base));

    //
    // Clear the loop back mode.
    //
    HWREGH(base + SCI_O_CCR) &= ~SCI_CCR_LOOPBKENA;
}

//*****************************************************************************
//
//! Get the receive FIFO Overflow flag status
//!
//! \param base is the base address of the SCI port.
//!
//! This functions gets the receive FIFO overflow flag status.
//!
//! \return Returns \b true if overflow has occurred, else returned \b false if
//! an overflow hasn't occurred.
//
//*****************************************************************************
static inline bool
SCI_getOverflowStatus(uint32_t base)
{
    //
    // Check the arguments.
    //
    ASSERT(SCI_isBaseValid(base));

    //
    // Return the current FIFO overflow status
    //
    return((HWREGH(base + SCI_O_FFRX) & SCI_FFRX_RXFFOVF) == SCI_FFRX_RXFFOVF);
}

//*****************************************************************************
//
//! Clear the receive FIFO Overflow flag status
//!
//! \param base is the base address of the SCI port.
//!
//! This functions clears the receive FIFO overflow flag status.
//!
//! \return None.
//
//*****************************************************************************
static inline void
SCI_clearOverflowStatus(uint32_t base)
{
    //
    // Check the arguments.
    //
    ASSERT(SCI_isBaseValid(base));

    //
    // Clear the current FIFO overflow status
    //
    HWREGH(base + SCI_O_FFRX) |= SCI_FFRX_RXFFOVRCLR;
}

//*****************************************************************************
//
//! Sets the configuration of a SCI.
//!
//! \param base is the base address of the SCI port.
//! \param lspclkHz is the rate of the clock supplied to the SCI module.  This
//! is the LSPCLK.
//! \param baud is the desired baud rate.
//! \param config is the data format for the port (number of data bits,
//! number of stop bits, and parity).
//!
//! This function configures the SCI for operation in the specified data
//! format.  The baud rate is provided in the \e baud parameter and the data
//! format in the \e config parameter.
//!
//! The \e config parameter is the bitwise OR of three values: the number of
//! data bits, the number of stop bits, and the parity.  \b SCI_CONFIG_WLEN_8,
//! \b SCI_CONFIG_WLEN_7, \b SCI_CONFIG_WLEN_6, \b SCI_CONFIG_WLEN_5,
//! \b SCI_CONFIG_WLEN_4, \b SCI_CONFIG_WLEN_3, \b SCI_CONFIG_WLEN_2, and
//! \b SCI_CONFIG_WLEN_1. Select from eight to one data bits per byte
//! (respectively).
//! \b SCI_CONFIG_STOP_ONE and \b SCI_CONFIG_STOP_TWO select one or two stop
//! bits (respectively).  \b SCI_CONFIG_PAR_NONE, \b SCI_CONFIG_PAR_EVEN,
//! \b SCI_CONFIG_PAR_ODD, select the parity mode (no parity bit, even parity
//! bit, odd parity bit respectively).
//!
//! The peripheral clock is the low speed peripheral clock.  This will be
//! the value returned by SysCtl_getLowSpeedClock(), or it can be explicitly
//! hard coded if it is constant and known (to save the code/execution overhead
//! of a call to SysCtl_getLowSpeedClock()).
//!
//! \return None.
//
//*****************************************************************************
extern void
SCI_setConfig(uint32_t base, uint32_t lspclkHz, uint32_t baud,
              uint32_t config);

//*****************************************************************************
//
//! Waits to send an array of characters from the specified port.
//!
//! \param base is the base address of the SCI port.
//! \param array is the address of the array of characters to be transmitted.
//!   It is pointer to the array of characters to be transmitted.
//! \param length is the length of the array, or number of characters in the
//!   array to be transmitted.
//!
//! Sends the number of characters specified by \e length, starting at the
//! address \e array, out of the transmit buffer for the specified port.
//! If there is no space available in the transmit buffer, or the transmit
//! FIFO if it is enabled, this function waits until there is space available
//! and \e length number of characters are transmitted before returning.
//! \e array is a pointer to uint16_ts but only the least significant 8 bits
//! are written to the SCI port.  SCI only transmits 8 bit characters.
//!
//! \return None.
//
//*****************************************************************************
extern void
SCI_writeCharArray(uint32_t base, const uint16_t * const array,
                   uint16_t length);

//*****************************************************************************
//
//! Waits to receive an array of characters from the specified port.
//!
//! \param base is the base address of the SCI port.
//! \param array is the address of the array of characters to be received.
//!   It is a pointer to the array of characters to be received.
//! \param length is the length of the array, or number of characters in the
//!   array to be received.
//!
//! Receives an array of characters from the receive buffer for the specified
//! port, and stores them as an array of characters starting at address
//! \e array.  This function waits until the \e length number of characters are
//! received before returning.
//!
//! \return None.
//
//*****************************************************************************
extern void
SCI_readCharArray(uint32_t base, uint16_t * const array, uint16_t length);

//*****************************************************************************
//
//! Enables individual SCI interrupt sources.
//!
//! \param base is the base address of the SCI port.
//! \param intFlags is the bit mask of the interrupt sources to be enabled.
//!
//! Enables the indicated SCI interrupt sources.  Only the sources that are
//! enabled can be reflected to the processor interrupt; disabled sources have
//! no effect on the processor.
//!
//! The \e intFlags parameter is the bitwise OR of any of the following:
//!
//! - \b SCI_INT_RXERR      - RXERR Interrupt
//! - \b SCI_INT_RXRDY_BRKDT - RXRDY/BRKDT Interrupt
//! - \b SCI_INT_TXRDY      - TXRDY Interrupt
//! - \b SCI_INT_TXFF       - TX FIFO Level Interrupt
//! - \b SCI_INT_RXFF       - RX FIFO Level Interrupt
//! - \b SCI_INT_FE         - Frame Error
//! - \b SCI_INT_OE         - Overrun Error
//! - \b SCI_INT_PE         - Parity Error
//!
//! \return None.
//
//*****************************************************************************
extern void
SCI_enableInterrupt(uint32_t base, uint32_t intFlags);

//*****************************************************************************
//
//! Disables individual SCI interrupt sources.
//!
//! \param base is the base address of the SCI port.
//! \param intFlags is the bit mask of the interrupt sources to be disabled.
//!
//! Disables the indicated SCI interrupt sources.  Only the sources that are
//! enabled can be reflected to the processor interrupt; disabled sources have
//! no effect on the processor.
//!
//! The \e intFlags parameter has the same definition as the \e intFlags
//! parameter to SCI_enableInterrupt().
//!
//! \return None.
//
//*****************************************************************************
extern void
SCI_disableInterrupt(uint32_t base, uint32_t intFlags);

//*****************************************************************************
//
//! Gets the current interrupt status.
//!
//! \param base is the base address of the SCI port.
//!
//! \return Returns the current interrupt status, enumerated as a bit field of
//! values described in SCI_enableInterrupt().
//
//*****************************************************************************
extern uint32_t
SCI_getInterruptStatus(uint32_t base);

//*****************************************************************************
//
//! Clears SCI interrupt sources.
//!
//! \param base is the base address of the SCI port.
//! \param intFlags is a bit mask of the interrupt sources to be cleared.
//!
//! The specified SCI interrupt sources are cleared, so that they no longer
//! assert.  This function must be called in the interrupt handler to keep the
//! interrupt from being recognized again immediately upon exit.
//!
//! The \e intFlags parameter has the same definition as the \e intFlags
//! parameter to SCI_enableInterrupt().
//!
//! \return None.
//
//*****************************************************************************
extern void
SCI_clearInterruptStatus(uint32_t base, uint32_t intFlags);

//*****************************************************************************
//
//! Sets SCI Baud rate.
//!
//! \param base is the base address of the SCI port.
//! \param lspclkHz is the rate of the clock supplied to the SCI module.  This
//! is the LSPCLK.
//! \param baud is the desired baud rate.
//!
//! This function configures the SCI for operation in the specified baud rate
//! The baud rate is provided in the \e baud parameter.
//!
//! The peripheral clock is the low speed peripheral clock.  This will be
//! the value returned by SysCtl_getLowSpeedClock()
//!
//! \return None.
//
//*****************************************************************************
extern void
SCI_setBaud(uint32_t base, uint32_t lspclkHz, uint32_t baud);

//*****************************************************************************
//
// Close the Doxygen group.
//! @}
//
//*****************************************************************************

//*****************************************************************************
//
// Mark the end of the C bindings section for C++ compilers.
//
//*****************************************************************************
#ifdef __cplusplus
}
#endif

#endif //  SCI_H
