/*
 * uart5.c
 *
 *  Created on: Sep 17, 2021
 *      Author: thomm
 *
 *  NOTE: UART5 is not brought out to accessible pins on MPHOX v1 or MFET v2 or NANOFET
 *     uart5.c is defined as a pattern for other UART code to fix the crazy flexiblity caused by using TI eval code which solved a portability problem that is not a requirement
 *
 *     Procedure:
 *     copy uart5.c into uartx.c (x being 0 to 4).  For example, rename with case sensitive UART5 to UART1 (for intance), then rename uart5 to uart1.
 *     Fix the #defines at the top for the correct pinmux definitions.
 *     Then fix uart1_init, uart1_setup, uart1_port_open and uart1_port_close.   Plug the uart1_isr into tm4c123gh6pge_startup_ccs.c (TODO: need to look at isr table for the 64pin part)
 *     Next copy the uart5.h prototypes into uart1.h and rename uart5 to uart1
 *
 */


#include "system.h"
#include "uart5.h"
#include "board_util.h"



// BOARD UART5 Pin Mux defines


// FOR future hardware, the defines above would be conditionally defined to match the specific hardware

#if BOARD_MPHOX >= 1 || BOARD_MFET >= 2 || BOARD_MSC == 2
#define BOARD_GPIO_PORT_BASE      GPIO_PORTE_BASE
#define BOARD_GPIO_PERIPH         SYSCTL_PERIPH_GPIOE
#define BOARD_GPIO_PIN_NAME_RX    GPIO_PE4_U5RX
#define BOARD_GPIO_PIN_NAME_TX    GPIO_PE5_U5TX
#define BOARD_GPIO_PIN_NUMBER_RX  GPIO_PIN_4
#define BOARD_GPIO_PIN_NUMBER_TX  GPIO_PIN_5
#define UART5_PINMUX_SUPPORTED    0             // Verify on schematic
#define UART5_BOARD_SUPPORTED     0
#endif

#if BOARD_NANOFET >= 1 || BOARD_MSC == 3
#define BOARD_GPIO_PORT_BASE      GPIO_PORTE_BASE
#define BOARD_GPIO_PERIPH         SYSCTL_PERIPH_GPIOE
#define BOARD_GPIO_PIN_NAME_RX    GPIO_PE4_U5RX
#define BOARD_GPIO_PIN_NAME_TX    GPIO_PE5_U5TX
#define BOARD_GPIO_PIN_NUMBER_RX  GPIO_PIN_4
#define BOARD_GPIO_PIN_NUMBER_TX  GPIO_PIN_5
#define UART5_PINMUX_SUPPORTED    1
#define UART5_BOARD_SUPPORTED     0     // Not routed on Rev1 NanoFET
#endif



#if BOARD_TESTFIT == 1
#define BOARD_GPIO_PORT_BASE      GPIO_PORTE_BASE
#define BOARD_GPIO_PERIPH         SYSCTL_PERIPH_GPIOE
#define BOARD_GPIO_PIN_NAME_RX    GPIO_PE4_U5RX         // NOTE: Error on v1.4
#define BOARD_GPIO_PIN_NAME_TX    GPIO_PE5_U5TX
#define BOARD_GPIO_PIN_NUMBER_RX  GPIO_PIN_4
#define BOARD_GPIO_PIN_NUMBER_TX  GPIO_PIN_5
#define UART5_PINMUX_SUPPORTED    1
#define UART5_BOARD_SUPPORTED     1
#endif

#define UART5_RX_BUFFER_SIZE     128
#define UART5_TX_BUFFER_SIZE     128


//*****************************************************************************
//
// This global controls whether or not the isr will echo characters back to the
// transmitter.  By default, echo is enabled but if using this module as a
// convenient method of implementing a buffered serial interface over which
// you will be running an application protocol, you are likely to want to
// disable echo by calling UARTEchoSet(false).
//
//*****************************************************************************
static bool g_bDisableEcho;

//*****************************************************************************
//
// Output ring buffer.  Buffer is full if g_ui32UARTTxReadIndex is one ahead of
// g_ui32UARTTxWriteIndex.  Buffer is empty if the two indices are the same.
//
//*****************************************************************************
static unsigned char g_pcUARTTxBuffer[UART5_TX_BUFFER_SIZE];
static volatile uint32_t g_ui32UARTTxWriteIndex = 0;
static volatile uint32_t g_ui32UARTTxReadIndex = 0;

//*****************************************************************************
//
// Input ring buffer.  Buffer is full if g_ui32UARTTxReadIndex is one ahead of
// g_ui32UARTTxWriteIndex.  Buffer is empty if the two indices are the same.
//
//*****************************************************************************
static unsigned char g_pcUARTRxBuffer[UART5_RX_BUFFER_SIZE];
static volatile uint32_t g_ui32UARTRxWriteIndex = 0;
static volatile uint32_t g_ui32UARTRxReadIndex = 0;

//*****************************************************************************
//
// Macros to determine number of free and used bytes in the transmit buffer.
//
//*****************************************************************************
#define TX_BUFFER_USED          (GetBufferCount(&g_ui32UARTTxReadIndex,  \
                                                &g_ui32UARTTxWriteIndex, \
                                                UART5_TX_BUFFER_SIZE))
#define TX_BUFFER_FREE          (UART5_TX_BUFFER_SIZE - TX_BUFFER_USED)
#define TX_BUFFER_EMPTY         (IsBufferEmpty(&g_ui32UARTTxReadIndex,   \
                                               &g_ui32UARTTxWriteIndex))
#define TX_BUFFER_FULL          (IsBufferFull(&g_ui32UARTTxReadIndex,  \
                                              &g_ui32UARTTxWriteIndex, \
                                              UART5_TX_BUFFER_SIZE))
#define ADVANCE_TX_BUFFER_INDEX(Index) \
                                (Index) = ((Index) + 1) % UART5_TX_BUFFER_SIZE

//*****************************************************************************
//
// Macros to determine number of free and used bytes in the receive buffer.
//
//*****************************************************************************
#define RX_BUFFER_USED          (GetBufferCount(&g_ui32UARTRxReadIndex,  \
                                                &g_ui32UARTRxWriteIndex, \
                                                UART5_RX_BUFFER_SIZE))
#define RX_BUFFER_FREE          (UART5_RX_BUFFER_SIZE - RX_BUFFER_USED)
#define RX_BUFFER_EMPTY         (IsBufferEmpty(&g_ui32UARTRxReadIndex,   \
                                               &g_ui32UARTRxWriteIndex))
#define RX_BUFFER_FULL          (IsBufferFull(&g_ui32UARTRxReadIndex,  \
                                              &g_ui32UARTRxWriteIndex, \
                                              UART5_RX_BUFFER_SIZE))
#define ADVANCE_RX_BUFFER_INDEX(Index) \
                                (Index) = ((Index) + 1) % UART5_RX_BUFFER_SIZE


//*****************************************************************************
//
//! Determines whether the ring buffer whose pointers and size are provided
//! is full or not.
//!
//! \param pui32Read points to the read index for the buffer.
//! \param pui32Write points to the write index for the buffer.
//! \param ui32Size is the size of the buffer in bytes.
//!
//! This function is used to determine whether or not a given ring buffer is
//! full.  The structure of the code is specifically to ensure that we do not
//! see warnings from the compiler related to the order of volatile accesses
//! being undefined.
//!
//! \return Returns \b true if the buffer is full or \b false otherwise.
//
//*****************************************************************************
static bool IsBufferFull(volatile uint32_t *pui32Read,
             volatile uint32_t *pui32Write, uint32_t ui32Size)
{
    uint32_t ui32Write;
    uint32_t ui32Read;

    ui32Write = *pui32Write;
    ui32Read = *pui32Read;

    return((((ui32Write + 1) % ui32Size) == ui32Read) ? true : false);
}

//*****************************************************************************
//
//! Determines whether the ring buffer whose pointers and size are provided
//! is empty or not.
//!
//! \param pui32Read points to the read index for the buffer.
//! \param pui32Write points to the write index for the buffer.
//!
//! This function is used to determine whether or not a given ring buffer is
//! empty.  The structure of the code is specifically to ensure that we do not
//! see warnings from the compiler related to the order of volatile accesses
//! being undefined.
//!
//! \return Returns \b true if the buffer is empty or \b false otherwise.
//
//*****************************************************************************
static bool IsBufferEmpty(volatile uint32_t *pui32Read,
              volatile uint32_t *pui32Write)
{
    uint32_t ui32Write;
    uint32_t ui32Read;

    ui32Write = *pui32Write;
    ui32Read = *pui32Read;

    return((ui32Write == ui32Read) ? true : false);
}

//*****************************************************************************
//
//! Determines the number of bytes of data contained in a ring buffer.
//!
//! \param pui32Read points to the read index for the buffer.
//! \param pui32Write points to the write index for the buffer.
//! \param ui32Size is the size of the buffer in bytes.
//!
//! This function is used to determine how many bytes of data a given ring
//! buffer currently contains.  The structure of the code is specifically to
//! ensure that we do not see warnings from the compiler related to the order
//! of volatile accesses being undefined.
//!
//! \return Returns the number of bytes of data currently in the buffer.
//
//*****************************************************************************
static uint32_t GetBufferCount(volatile uint32_t *pui32Read,
               volatile uint32_t *pui32Write, uint32_t ui32Size)
{
    uint32_t ui32Write;
    uint32_t ui32Read;

    ui32Write = *pui32Write;
    ui32Read = *pui32Read;

    return((ui32Write >= ui32Read) ? (ui32Write - ui32Read) :
           (ui32Size - (ui32Read - ui32Write)));
}

//*****************************************************************************
//
// Take as many bytes from the transmit buffer as we have space for and move
// them into the UART transmit FIFO.
//
//*****************************************************************************
static void UART5_tx_prime(void)
{
    //
    // Do we have any data to transmit?
    //
    if(!TX_BUFFER_EMPTY)
    {
        //
        // Disable the UART interrupt.  If we don't do this there is a race
        // condition which can cause the read index to be corrupted.
        //
        //MAP_IntDisable(g_ui32UARTInt[g_ui32PortNum]);
        MAP_IntDisable(INT_UART5);

        //
        // Yes - take some characters out of the transmit buffer and feed
        // them to the UART transmit FIFO.
        //
        while(MAP_UARTSpaceAvail(UART5_BASE) && !TX_BUFFER_EMPTY)
        {
            MAP_UARTCharPutNonBlocking(UART5_BASE,
                                      g_pcUARTTxBuffer[g_ui32UARTTxReadIndex]);
            ADVANCE_TX_BUFFER_INDEX(g_ui32UARTTxReadIndex);
        }

        //
        // Reenable the UART interrupt.
        //
        MAP_IntEnable(INT_UART5);
    }
}






/*
 *  Initialize UART peripheral, timebase, and GPIO for power pins (D4, pin 141 L7, pin 95)
 */
void uart5_init(void)
{
    // Set up PORTXXX power pin
    MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOL);
    MAP_GPIOPinTypeGPIOOutput(GPIO_PORTL_BASE, GPIO_PIN_7);
    MAP_GPIOPinWrite(GPIO_PORTL_BASE, GPIO_PIN_7, 0x00);    // Power off

    // AUX2 UART PWRDOWN (PK4, pin 112, shared with AUX1) pin
    MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOK);
    MAP_GPIOPinTypeGPIOOutput(GPIO_PORTK_BASE, GPIO_PIN_4);
    MAP_GPIOPinWrite(GPIO_PORTK_BASE, GPIO_PIN_4, 0x00);    // Power down

    // Set up UART5 pins
    MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_UART5);
    MAP_SysCtlPeripheralEnable(BOARD_GPIO_PERIPH);
    MAP_GPIOPinConfigure(BOARD_GPIO_PIN_NAME_RX);              // Set up the pins
    MAP_GPIOPinConfigure(BOARD_GPIO_PIN_NAME_TX);
    MAP_GPIOPinTypeUART(BOARD_GPIO_PORT_BASE, BOARD_GPIO_PIN_NUMBER_RX | BOARD_GPIO_PIN_NUMBER_TX);

    // Use the internal 16MHz oscillator as the UART clock source.
    UARTClockSourceSet(UART5_BASE, UART_CLOCK_PIOSC);

    uart5_echo_set(0);   // Disable echo by default
}


/*
 * uart5_port_open enables power output and activates the RS-232 driver
 */
void uart5_port_open(void)
{
    PORTXXX_on();      // Power on (formerly Aux2)
    MAP_GPIOPinWrite(GPIO_PORTK_BASE, GPIO_PIN_4, 0xff);    // COM2 RS-232 driver on
    uart5_echo_set(0);    // Disable echo
}

/*
 * uart5_port_close removes power and shuts down the RS-232 driver
 */
void uart5_port_close(void)
{
    PORTXXX_off();     // Power off
    MAP_GPIOPinWrite(GPIO_PORTK_BASE, GPIO_PIN_4, 0x00);    // COM2 RS-232 driver off
}


//*****************************************************************************
//
//! Configures the UART console.
//!
//! \param ui32Baud is the bit rate that the UART is to be configured to use.
//! \param ui32SrcClock is the frequency of the source clock for the UART
//! module.
//!
//! This function will configure the specified serial port to be used as a
//! serial console.  The serial parameters are set to the baud rate
//! specified by the \e ui32Baud parameter and use 8 bit, no parity, and 1 stop
//! bit.
//!
//! This function must be called prior to using any of the other UART console
//! functions: uprintf() or UARTgets().  This function assumes that the
//! caller has previously configured the relevant UART pins for operation as a
//! UART rather than as GPIOs.
//!
//! \return None.
//
//*****************************************************************************
void uart5_setup(uint32_t ui32Baud, uint32_t ui32SrcClock)
{

    // Check to make sure the UART peripheral is present.
    //
    //if(!MAP_SysCtlPeripheralPresent(g_ui32UARTPeriph[ui32PortNum]))
    if(!MAP_SysCtlPeripheralPresent(SYSCTL_PERIPH_UART5))
    {
        return;
    }


    //
    // Enable the UART peripheral for use.
    //
    MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_UART5);

    //
    // Configure the UART for 115200, n, 8, 1
    //
    MAP_UARTConfigSetExpClk(UART5_BASE, ui32SrcClock, ui32Baud,
                            (UART_CONFIG_PAR_NONE | UART_CONFIG_STOP_ONE |
                             UART_CONFIG_WLEN_8));

    //
    // Set the UART to interrupt whenever the TX FIFO is almost empty or
    // when any character is received.
    //
    MAP_UARTFIFOLevelSet(UART5_BASE, UART_FIFO_TX1_8, UART_FIFO_RX1_8);

    //
    // Flush both the buffers.
    //
    uart5_rx_bufr_flush();
    uart5_tx_bufr_flush(true);

    //
    // We are configured for buffered output so enable the master interrupt
    // for this UART and the receive interrupts.  We don't actually enable the
    // transmit interrupt in the UART itself until some data has been placed
    // in the transmit buffer.
    //
    MAP_UARTIntDisable(UART5_BASE, 0xFFFFFFFF);
    MAP_UARTIntEnable(UART5_BASE, UART_INT_RX | UART_INT_RT);
    MAP_IntEnable(INT_UART5);

    //
    // Enable the UART operation.
    //
    MAP_UARTEnable(UART5_BASE);
}

//*****************************************************************************
//
//! Writes a string of characters to the UART output.
//!
//! \param pcBuf points to a buffer containing the string to transmit.
//! \param ui32Len is the length of the string to transmit.
//!
//! This function will transmit the string to the UART output.  The number of
//! characters transmitted is determined by the \e ui32Len parameter.  This
//! function does no interpretation or translation of any characters.  Since
//! the output is sent to a UART, any LF (/n) characters encountered will be
//! replaced with a CRLF pair.
//!
//! Besides using the \e ui32Len parameter to stop transmitting the string, if
//! a null character (0) is encountered, then no more characters will be
//! transmitted and the function will return.
//!
//! In non-buffered mode, this function is blocking and will not return until
//! all the characters have been written to the output FIFO.  In buffered mode,
//! the characters are written to the UART transmit buffer and the call returns
//! immediately.  If insufficient space remains in the transmit buffer,
//! additional characters are discarded.
//!
//! \return Returns the count of characters written.
//
//*****************************************************************************
int uart5_write(const char *pcBuf, uint32_t ui32Len)
{
    unsigned int uIdx;

    //
    // Send the characters
    //
    for(uIdx = 0; uIdx < ui32Len; uIdx++)
    {
        //
        // If the character to the UART is \n, then add a \r before it so that
        // \n is translated to \n\r in the output.
        //
        if(pcBuf[uIdx] == '\n')
        {
            if(!TX_BUFFER_FULL)
            {
                g_pcUARTTxBuffer[g_ui32UARTTxWriteIndex] = '\r';
                ADVANCE_TX_BUFFER_INDEX(g_ui32UARTTxWriteIndex);
            }
            else
            {
                //
                // Buffer is full - discard remaining characters and return.
                //
                break;
            }
        }

        //
        // Send the character to the UART output.
        //
        if(!TX_BUFFER_FULL)
        {
            g_pcUARTTxBuffer[g_ui32UARTTxWriteIndex] = pcBuf[uIdx];
            ADVANCE_TX_BUFFER_INDEX(g_ui32UARTTxWriteIndex);
        }
        else
        {
            //
            // Buffer is full - discard remaining characters and return.
            //
            break;
        }
    }

    //
    // If we have anything in the buffer, make sure that the UART is set
    // up to transmit it.
    //
    if(!TX_BUFFER_EMPTY)
    {
        UART5_tx_prime();
        MAP_UARTIntEnable(UART5_BASE, UART_INT_TX);
    }

    //
    // Return the number of characters written.
    //
    return(uIdx);
}

//*****************************************************************************
//! uart5_rx_str(char *pcBuf, uint32_t ui32Len)
//!
//! A simple UART based get string function, with some line processing.
//!
//! \param pcBuf points to a buffer for the incoming string from the UART.
//! \param ui32Len is the length of the buffer for storage of the string,
//! including the trailing 0.
//!
//! This function will receive a string from the UART input and store the
//! characters in the buffer pointed to by \e pcBuf.  The characters will
//! continue to be stored until a termination character is received.  The
//! termination characters are CR, LF, or ESC.  A CRLF pair is treated as a
//! single termination character.  The termination characters are not stored in
//! the string.  The string will be terminated with a 0 and the function will
//! return.
//!
//! In both buffered and unbuffered modes, this function will block until
//! a termination character is received.  If non-blocking operation is required
//! in buffered mode, a call to UARTPeek() may be made to determine whether
//! a termination character already exists in the receive buffer prior to
//! calling UARTgets().
//!
//! Since the string will be null terminated, the user must ensure that the
//! buffer is sized to allow for the additional null character.
//!
//! \return Returns the count of characters that were stored, not including
//! the trailing 0.
//
//*****************************************************************************
int uart5_rx_str(char *pcBuf, uint32_t ui32Len)
{
    uint32_t ui32Count = 0;
    int8_t cChar;

    //
    // Adjust the length back by 1 to leave space for the trailing
    // null terminator.
    //
    ui32Len--;

    //
    // Process characters until a newline is received.
    //
    while(1)
    {
        //
        // Read the next character from the receive buffer.
        //
        if(!RX_BUFFER_EMPTY)
        {
            cChar = g_pcUARTRxBuffer[g_ui32UARTRxReadIndex];
            ADVANCE_RX_BUFFER_INDEX(g_ui32UARTRxReadIndex);

            //
            // See if a newline or escape character was received.
            //
            if((cChar == '\r') || (cChar == '\n') || (cChar == 0x1b))
            {
                //
                // Stop processing the input and end the line.
                //
                break;
            }

            //
            // Process the received character as long as we are not at the end
            // of the buffer.  If the end of the buffer has been reached then
            // all additional characters are ignored until a newline is
            // received.
            //
            if(ui32Count < ui32Len)
            {
                //
                // Store the character in the caller supplied buffer.
                //
                pcBuf[ui32Count] = cChar;

                //
                // Increment the count of characters received.
                //
                ui32Count++;
            }
        }
    }

    //
    // Add a null termination to the string.
    //
    pcBuf[ui32Count] = 0;

    //
    // Return the count of int8_ts in the buffer, not counting the trailing 0.
    //
    return(ui32Count);
}

//*****************************************************************************
//
//! Read a single character from the UART, blocking if necessary.
//!
//! This function will receive a single character from the UART and store it at
//! the supplied address.
//!
//! In both buffered and unbuffered modes, this function will block until a
//! character is received.  If non-blocking operation is required in buffered
//! mode, a call to UARTRxAvail() may be made to determine whether any
//! characters are currently available for reading.
//!
//! \return Returns the character read.
//
//*****************************************************************************
unsigned char uart5_rx_byte(void)
{
    unsigned char cChar;

    //
    // Wait for a character to be received.
    //
    while(RX_BUFFER_EMPTY)
    {
        //
        // Block waiting for a character to be received (if the buffer is
        // currently empty).
        //
    }

    //
    // Read a character from the buffer.
    //
    cChar = g_pcUARTRxBuffer[g_ui32UARTRxReadIndex];
    ADVANCE_RX_BUFFER_INDEX(g_ui32UARTRxReadIndex);

    //
    // Return the character to the caller.
    //
    return(cChar);
}

/*****************************************************************************
 * uart5_tx_byte()
 ******************************************************************************/
void uart5_tx_byte(unsigned char c)
{

    // Send the character to the UART output.
    if(!TX_BUFFER_FULL)
    {
        g_pcUARTTxBuffer[g_ui32UARTTxWriteIndex] = c;
        ADVANCE_TX_BUFFER_INDEX(g_ui32UARTTxWriteIndex);
    }
    else return 0;  // Buffer full. No character written

    // Flush the TX buffer
    if(!TX_BUFFER_EMPTY)
    {
        UART5_tx_prime();
        MAP_UARTIntEnable(UART5_BASE, UART_INT_TX);
    }

    return 1; // Success
}


//*****************************************************************************
//
//! Returns the number of bytes available in the receive buffer.
//!
//! This function, available only when the module is built to operate in
//! buffered mode using \b UART_BUFFERED, may be used to determine the number
//! of bytes of data currently available in the receive buffer.
//!
//! \return Returns the number of available bytes.
//
//*****************************************************************************
int uart5_rx_bytes_avail(void)
{
    return(RX_BUFFER_USED);
}



//*****************************************************************************
//
//! Returns the number of bytes free in the transmit buffer.
//!
//! This function, available only when the module is built to operate in
//! buffered mode using \b UART_BUFFERED, may be used to determine the amount
//! of space currently available in the transmit buffer.
//!
//! \return Returns the number of free bytes.
//
//*****************************************************************************
int uart5_tx_bufr_bytes_free(void)
{
    return(TX_BUFFER_FREE);
}

//*****************************************************************************
//
//! Looks ahead in the receive buffer for a particular character.
//!
//! \param ucChar is the character that is to be searched for.
//!
//! This function, available only when the module is built to operate in
//! buffered mode using \b UART_BUFFERED, may be used to look ahead in the
//! receive buffer for a particular character and report its position if found.
//! It is typically used to determine whether a complete line of user input is
//! available, in which case ucChar should be set to CR ('\\r') which is used
//! as the line end marker in the receive buffer.
//!
//! \return Returns -1 to indicate that the requested character does not exist
//! in the receive buffer.  Returns a non-negative number if the character was
//! found in which case the value represents the position of the first instance
//! of \e ucChar relative to the receive buffer read pointer.
//
//*****************************************************************************
int uart5_rx_bufr_peek(unsigned char ucChar)
{
    int iCount;
    int iAvail;
    uint32_t ui32ReadIndex;

    //
    // How many characters are there in the receive buffer?
    //
    iAvail = (int)RX_BUFFER_USED;
    ui32ReadIndex = g_ui32UARTRxReadIndex;

    //
    // Check all the unread characters looking for the one passed.
    //
    for(iCount = 0; iCount < iAvail; iCount++)
    {
        if(g_pcUARTRxBuffer[ui32ReadIndex] == ucChar)
        {
            //
            // We found it so return the index
            //
            return(iCount);
        }
        else
        {
            //
            // This one didn't match so move on to the next character.
            //
            ADVANCE_RX_BUFFER_INDEX(ui32ReadIndex);
        }
    }

    //
    // If we drop out of the loop, we didn't find the character in the receive
    // buffer.
    //
    return(-1);
}

//*****************************************************************************
//
//! Flushes the receive buffer.
//!
//! This function, available only when the module is built to operate in
//! buffered mode using \b UART_BUFFERED, may be used to discard any data
//! received from the UART but not yet read using UARTgets().
//!
//! \return None.
//
//*****************************************************************************
void uart5_rx_bufr_flush(void)
{
    uint32_t ui32Int;

    //
    // Temporarily turn off interrupts.
    //
    ui32Int = MAP_IntMasterDisable();

    //
    // Flush the receive buffer.
    //
    g_ui32UARTRxReadIndex = 0;
    g_ui32UARTRxWriteIndex = 0;

    //
    // If interrupts were enabled when we turned them off, turn them
    // back on again.
    //
    if(!ui32Int)
    {
        MAP_IntMasterEnable();
    }
}

//*****************************************************************************
//
//! Flushes the transmit buffer.
//!
//! \param bDiscard indicates whether any remaining data in the buffer should
//! be discarded (\b true) or transmitted (\b false).
//!
//! This function, available only when the module is built to operate in
//! buffered mode using \b UART_BUFFERED, may be used to flush the transmit
//! buffer, either discarding or transmitting any data received via calls to
//! uprintf() that is waiting to be transmitted.  On return, the transmit
//! buffer will be empty.
//!
//! \return None.
//
//*****************************************************************************
void uart5_tx_bufr_flush(bool bDiscard)
{
    uint32_t ui32Int;

    //
    // Should the remaining data be discarded or transmitted?
    //
    if(bDiscard)
    {
        //
        // The remaining data should be discarded, so temporarily turn off
        // interrupts.
        //
        ui32Int = MAP_IntMasterDisable();

        //
        // Flush the transmit buffer.
        //
        g_ui32UARTTxReadIndex = 0;
        g_ui32UARTTxWriteIndex = 0;

        //
        // If interrupts were enabled when we turned them off, turn them
        // back on again.
        //
        if(!ui32Int)
        {
            MAP_IntMasterEnable();
        }
    }
    else
    {
        //
        // Wait for all remaining data to be transmitted before returning.
        //
        while(!TX_BUFFER_EMPTY)
        {
        }
    }
}

//*****************************************************************************
//
//! Enables or disables echoing of received characters to the transmitter.
//!
//! \param bEnable must be set to \b true to enable echo or \b false to
//! disable it.
//!
//! This function, available only when the module is built to operate in
//! buffered mode using \b UART_BUFFERED, may be used to control whether or not
//! received characters are automatically echoed back to the transmitter.  By
//! default, echo is enabled and this is typically the desired behavior if
//! the module is being used to support a serial command line.  In applications
//! where this module is being used to provide a convenient, buffered serial
//! interface over which application-specific binary protocols are being run,
//! however, echo may be undesirable and this function can be used to disable
//! it.
//!
//! \return None.
//
//*****************************************************************************
void uart5_echo_set(bool bEnable)
{
    g_bDisableEcho = !bEnable;
}





//*****************************************************************************
//
//! Handles UART interrupts.
//!
//! This function handles interrupts from the UART.  It will copy data from the
//! transmit buffer to the UART transmit FIFO if space is available, and it
//! will copy data from the UART receive FIFO to the receive buffer if data is
//! available.
//!
//! \return None.
//
//*****************************************************************************
void uart5_isr(void)
{
    uint32_t ui32Ints;
    int8_t cChar;
    int32_t i32Char;
    static bool bLastWasCR = false;

    //
    // Get and clear the current interrupt source(s)
    //
    ui32Ints = MAP_UARTIntStatus(UART5_BASE, true);
    MAP_UARTIntClear(UART5_BASE, ui32Ints);

    //
    // Are we being interrupted because the TX FIFO has space available?
    //
    if(ui32Ints & UART_INT_TX)
    {
        //
        // Move as many bytes as we can into the transmit FIFO.
        //
        UART5_tx_prime();

        //
        // If the output buffer is empty, turn off the transmit interrupt.
        //
        if(TX_BUFFER_EMPTY)
        {
            MAP_UARTIntDisable(UART5_BASE, UART_INT_TX);
        }
    }

    //
    // Are we being interrupted due to a received character?
    //
    if(ui32Ints & (UART_INT_RX | UART_INT_RT))
    {
        //
        // Get all the available characters from the UART.
        //
        while(MAP_UARTCharsAvail(UART5_BASE))
        {
            //
            // Read a character
            //
            i32Char = MAP_UARTCharGetNonBlocking(UART5_BASE);
            cChar = (unsigned char)(i32Char & 0xFF);

            //
            // If echo is disabled, we skip the various text filtering
            // operations that would typically be required when supporting a
            // command line.
            //
            if(!g_bDisableEcho)
            {
                //
                // Handle backspace by erasing the last character in the
                // buffer.
                //
                if(cChar == '\b')
                {
                    //
                    // If there are any characters already in the buffer, then
                    // delete the last.
                    //
                    if(!RX_BUFFER_EMPTY)
                    {
                        //
                        // Rub out the previous character on the users
                        // terminal.
                        //
                        UARTwrite("\b \b", 3);

                        //
                        // Decrement the number of characters in the buffer.
                        //
                        if(g_ui32UARTRxWriteIndex == 0)
                        {
                            g_ui32UARTRxWriteIndex = UART5_RX_BUFFER_SIZE - 1;
                        }
                        else
                        {
                            g_ui32UARTRxWriteIndex--;
                        }
                    }

                    //
                    // Skip ahead to read the next character.
                    //
                    continue;
                }

                //
                // If this character is LF and last was CR, then just gobble up
                // the character since we already echoed the previous CR and we
                // don't want to store 2 characters in the buffer if we don't
                // need to.
                //
                if((cChar == '\n') && bLastWasCR)
                {
                    bLastWasCR = false;
                    continue;
                }

                //
                // See if a newline or escape character was received.
                //
                if((cChar == '\r') || (cChar == '\n') || (cChar == 0x1b))
                {
                    //
                    // If the character is a CR, then it may be followed by an
                    // LF which should be paired with the CR.  So remember that
                    // a CR was received.
                    //
                    if(cChar == '\r')
                    {
                        bLastWasCR = 1;
                    }

                    //
                    // Regardless of the line termination character received,
                    // put a CR in the receive buffer as a marker telling
                    // UARTgets() where the line ends.  We also send an
                    // additional LF to ensure that the local terminal echo
                    // receives both CR and LF.
                    //
                    cChar = '\r';
                    UARTwrite("\n", 1);
                }
            }

            //
            // If there is space in the receive buffer, put the character
            // there, otherwise throw it away.
            //
            if(!RX_BUFFER_FULL)
            {
                //
                // Store the new character in the receive buffer
                //
                g_pcUARTRxBuffer[g_ui32UARTRxWriteIndex] =
                    (unsigned char)(i32Char & 0xFF);
                ADVANCE_RX_BUFFER_INDEX(g_ui32UARTRxWriteIndex);

                //
                // If echo is enabled, write the character to the transmit
                // buffer so that the user gets some immediate feedback.
                //
                if(!g_bDisableEcho)
                {
                    UARTwrite((const char *)&cChar, 1);
                }
            }
        }

        //
        // If we wrote anything to the transmit buffer, make sure it actually
        // gets transmitted.
        //
        UART5_tx_prime();
        MAP_UARTIntEnable(UART5_BASE, UART_INT_TX);
    }
}


