//###########################################################################
// FILE:   softuart.c
// TITLE:  Driver for the SoftUART.
//###########################################################################
// $TI Release: F28M35x Support Library v201 $
// $Release Date: Fri Jun  7 10:51:13 CDT 2013 $
//###########################################################################

//*****************************************************************************
//! \addtogroup softuart_api
//! @{
//*****************************************************************************

#include <string.h>
#include "inc/hw_ints.h"
#include "inc/hw_memmap.h"
#include "inc/hw_sysctl.h"
#include "inc/hw_types.h"
#include "inc/hw_uart.h"
#include "driverlib/debug.h"
#include "driverlib/gpio.h"
#include "driverlib/interrupt.h"
#include "driverlib/rom.h"
#include "driverlib/rom_map.h"
#include "driverlib/uart.h"
#include "utils/softuart.h"

//*****************************************************************************
// The states in the SoftUART transmit state machine.  The code depends upon
// the fact that the value of TXSTATE_DATA_n is n + 1, and that TXSTATE_DATA_0
// is 1.
//*****************************************************************************
#define SOFTUART_TXSTATE_IDLE   0
#define SOFTUART_TXSTATE_DATA_0 1
#define SOFTUART_TXSTATE_DATA_1 2
#define SOFTUART_TXSTATE_DATA_2 3
#define SOFTUART_TXSTATE_DATA_3 4
#define SOFTUART_TXSTATE_DATA_4 5
#define SOFTUART_TXSTATE_DATA_5 6
#define SOFTUART_TXSTATE_DATA_6 7
#define SOFTUART_TXSTATE_DATA_7 8
#define SOFTUART_TXSTATE_START  9
#define SOFTUART_TXSTATE_PARITY 10
#define SOFTUART_TXSTATE_STOP_0 11
#define SOFTUART_TXSTATE_STOP_1 12
#define SOFTUART_TXSTATE_BREAK  13

//*****************************************************************************
// The states of the SoftUART receive state machine.  The code depends upon the
// the fact that the value of RXSTATE_DATA_n is n, and that RXSTATE_DATA_0 is
// 0.
//*****************************************************************************
#define SOFTUART_RXSTATE_DATA_0 0
#define SOFTUART_RXSTATE_DATA_1 1
#define SOFTUART_RXSTATE_DATA_2 2
#define SOFTUART_RXSTATE_DATA_3 3
#define SOFTUART_RXSTATE_DATA_4 4
#define SOFTUART_RXSTATE_DATA_5 5
#define SOFTUART_RXSTATE_DATA_6 6
#define SOFTUART_RXSTATE_DATA_7 7
#define SOFTUART_RXSTATE_IDLE   8
#define SOFTUART_RXSTATE_PARITY 9
#define SOFTUART_RXSTATE_STOP_0 10
#define SOFTUART_RXSTATE_STOP_1 11
#define SOFTUART_RXSTATE_BREAK  12
#define SOFTUART_RXSTATE_DELAY  13

//*****************************************************************************
// The flags in the SoftUART ucFlags structure member.
//*****************************************************************************
#define SOFTUART_FLAG_ENABLE    0x01
#define SOFTUART_FLAG_TXBREAK   0x02

//*****************************************************************************
// The flags in the SoftUART ucRxFlags structure member.
//*****************************************************************************
#define SOFTUART_RXFLAG_OE      0x08
#define SOFTUART_RXFLAG_BE      0x04
#define SOFTUART_RXFLAG_PE      0x02
#define SOFTUART_RXFLAG_FE      0x01

//*****************************************************************************
// Additional internal configuration stored in the SoftUART usConfig structure
// member.
//*****************************************************************************
#define SOFTUART_CONFIG_BASE_M  0x00ff
#define SOFTUART_CONFIG_EXT_M   0xff00
#define SOFTUART_CONFIG_TXLVL_M 0x0700
#define SOFTUART_CONFIG_TXLVL_1 0x0000
#define SOFTUART_CONFIG_TXLVL_2 0x0100
#define SOFTUART_CONFIG_TXLVL_4 0x0200
#define SOFTUART_CONFIG_TXLVL_6 0x0300
#define SOFTUART_CONFIG_TXLVL_7 0x0400
#define SOFTUART_CONFIG_RXLVL_M 0x3800
#define SOFTUART_CONFIG_RXLVL_1 0x0000
#define SOFTUART_CONFIG_RXLVL_2 0x0800
#define SOFTUART_CONFIG_RXLVL_4 0x1000
#define SOFTUART_CONFIG_RXLVL_6 0x1800
#define SOFTUART_CONFIG_RXLVL_7 0x2000

//*****************************************************************************
// The odd parity of each possible data byte.  The odd parity of N can be found
// by looking at bit N % 32 of word N / 32.
//*****************************************************************************
static unsigned long g_pulParityOdd[] =
{
    0x69969669, 0x96696996, 0x96696996, 0x69969669,
    0x96696996, 0x69969669, 0x69969669, 0x96696996
};

//*****************************************************************************
//! Initializes the SoftUART module.
//!
//! \param pUART specifies the soft UART data structure.
//!
//! This function initializes the data structure for the SoftUART module,
//! putting it into the default configuration.
//!
//! \return None.
//*****************************************************************************
void
SoftUARTInit(tSoftUART *pUART)
{
    // Clear the SoftUART data structure.
    memset(pUART, 0, sizeof(tSoftUART));

    // Set the default transmit and receive buffer interrupt level.
    pUART->usConfig = SOFTUART_CONFIG_TXLVL_4 | SOFTUART_CONFIG_RXLVL_4;
}

//*****************************************************************************
//! Sets the configuration of a SoftUART module.
//!
//! \param pUART specifies the SoftUART data structure.
//! \param ulConfig is the data format for the port (number of data bits,
//! number of stop bits, and parity).
//!
//! This function configures the SoftUART for operation in the specified data
//! format, as specified in the \e ulConfig parameter.
//!
//! The \e ulConfig parameter is the logical OR of three values: the number of
//! data bits, the number of stop bits, and the parity.
//! \b SOFTUART_CONFIG_WLEN_8, \b SOFTUART_CONFIG_WLEN_7,
//! \b SOFTUART_CONFIG_WLEN_6, and \b SOFTUART_CONFIG_WLEN_5 select from eight
//! to five data bits per byte (respectively).  \b SOFTUART_CONFIG_STOP_ONE and
//! \b SOFTUART_CONFIG_STOP_TWO select one or two stop bits (respectively).
//! \b SOFTUART_CONFIG_PAR_NONE, \b SOFTUART_CONFIG_PAR_EVEN,
//! \b SOFTUART_CONFIG_PAR_ODD, \b SOFTUART_CONFIG_PAR_ONE, and
//! \b SOFTUART_CONFIG_PAR_ZERO select the parity mode (no parity bit, even
//! parity bit, odd parity bit, parity bit always one, and parity bit always
//! zero, respectively).
//!
//! \return None.
//*****************************************************************************
void
SoftUARTConfigSet(tSoftUART *pUART, unsigned long ulConfig)
{
    // See if a GPIO pin has been set for Tx.
    if(pUART->ulTxGPIO != 0)
    {
        // Configure the Tx pin.
        MAP_GPIOPinTypeGPIOOutput(pUART->ulTxGPIO & 0xfffff000,
                                  (pUART->ulTxGPIO & 0x00000fff) >> 2);

        // Set the Tx pin high.
        HWREG(pUART->ulTxGPIO) = 255;
    }

    // See if a GPIO pin has been set for Rx.
    if(pUART->ulRxGPIOPort != 0)
    {
        // Configure the Rx pin.
        MAP_GPIOPinTypeGPIOInput(pUART->ulRxGPIOPort, pUART->ucRxPin);

        // Set the Rx pin to generate an interrupt on the next falling edge.
        MAP_GPIOIntTypeSet(pUART->ulRxGPIOPort, pUART->ucRxPin,
                           GPIO_FALLING_EDGE);

        // Enable the Rx pin interrupt.
        MAP_GPIOPinIntClear(pUART->ulRxGPIOPort, pUART->ucRxPin);
        MAP_GPIOPinIntEnable(pUART->ulRxGPIOPort, pUART->ucRxPin);
    }

    // Make sure that the transmit and receive buffers are empty.
    pUART->usTxBufferRead = 0;
    pUART->usTxBufferWrite = 0;
    pUART->usRxBufferRead = 0;
    pUART->usRxBufferWrite = 0;

    // Save the data format.
    pUART->usConfig = ((pUART->usConfig & SOFTUART_CONFIG_EXT_M) |
                       (ulConfig & SOFTUART_CONFIG_BASE_M));

    // Enable the SoftUART module.
    pUART->ucFlags |= SOFTUART_FLAG_ENABLE;

    // The next value to be written to the Tx pin is one since the SoftUART is
    // idle.
    pUART->ucTxNext = 255;

    // Start the SoftUART state machines in the idle state.
    pUART->ucTxState = SOFTUART_TXSTATE_IDLE;
    pUART->ucRxState = SOFTUART_RXSTATE_IDLE;
}

//*****************************************************************************
//! Performs the periodic update of the SoftUART transmitter.
//!
//! \param pUART specifies the SoftUART data structure.
//!
//! This function performs the periodic, time-based updates to the SoftUART
//! transmitter.  The transmission of data from the SoftUART is performed by
//! the state machine in this function.
//!
//! This function must be called at the desired SoftUART baud rate.  For
//! example, to run the SoftUART at 115,200 baud, this function must be called
//! at a 115,200 Hz rate.
//!
//! \return None.
//*****************************************************************************
void
SoftUARTTxTimerTick(tSoftUART *pUART)
{
    unsigned long ulTemp;

    // Write the next value to the Tx data line.  This value was computed on
    // the previous timer tick, which helps to reduce the jitter on the Tx
    // edges (which is important since a UART connection does not contain a
    // clock signal).
    HWREG(pUART->ulTxGPIO) = pUART->ucTxNext;

    // Determine the current state of the state machine.
    switch(pUART->ucTxState)
    {
    // The state machine is idle.
    case SOFTUART_TXSTATE_IDLE:
    {
        // See if the SoftUART module is enabled.
        if(!(pUART->ucFlags & SOFTUART_FLAG_ENABLE))
        {
            // The SoftUART module is not enabled, so do nothing and stay
            // in the idle state.
            break;
        }

        // See if the break signal should be asserted.
        else if(pUART->ucFlags & SOFTUART_FLAG_TXBREAK)
        {
            // The data line should be driven low while in the break state.
            pUART->ucTxNext = 0;

            // Move to the break state.
            pUART->ucTxState = SOFTUART_TXSTATE_BREAK;
        }

        // Otherwise, see if there is data in the transmit buffer.
        else if(pUART->usTxBufferRead != pUART->usTxBufferWrite)
        {
            // The data line should be driven low to indicate a start bit.
            pUART->ucTxNext = 0;

            // Move to the start bit state.
            pUART->ucTxState = SOFTUART_TXSTATE_START;
        }

        // This state has been handled.
        break;
    }

    // The state machine is in the start bit state.
    case SOFTUART_TXSTATE_START:
    {
        // Get the next byte to be transmitted.
        pUART->ucTxData = pUART->pucTxBuffer[pUART->usTxBufferRead];

        // The next value to be written to the data line is the LSB of the
        // next data byte.
        pUART->ucTxNext = (pUART->ucTxData & 1) ? 255 : 0;

        // Move to the data bit 0 state.
        pUART->ucTxState = SOFTUART_TXSTATE_DATA_0;

        // This state has been handled.
        break;
    }

    // In each of these states, a bit of the data byte must be output.
    // This depends upon TXSTATE_DATA_n and TXSTATE_DATA_(n+1) being
    // consecutively numbered.
    case SOFTUART_TXSTATE_DATA_0:
    case SOFTUART_TXSTATE_DATA_1:
    case SOFTUART_TXSTATE_DATA_2:
    case SOFTUART_TXSTATE_DATA_3:
    {
        // The next value to be written to the data line is the next bit of
        // the data byte.
        pUART->ucTxNext =
            (pUART->ucTxData & (1 << pUART->ucTxState)) ? 255 : 0;

        // Advance to the next state.
        pUART->ucTxState++;

        // This state has been handled.
        break;
    }

    // In each of these states, a bit of the data byte must be output.
    // Additionally, based on the configuration of the SoftUART, this bit
    // might be the last data bit of the data byte.  This depends upon
    // TXSTATE_DATA_n and TXSTATE_DATA_(n+1) being consecutively numbered.
    case SOFTUART_TXSTATE_DATA_4:
    case SOFTUART_TXSTATE_DATA_5:
    case SOFTUART_TXSTATE_DATA_6:
    case SOFTUART_TXSTATE_DATA_7:
    {
        // See if the bit that was just transferred is the last bit of the
        // data byte (based on the configuration of the SoftUART).
        if(((pUART->usConfig & SOFTUART_CONFIG_WLEN_MASK) >>
            SOFTUART_CONFIG_WLEN_S) ==
           (pUART->ucTxState - SOFTUART_TXSTATE_DATA_4))
        {
            // See if parity is enabled.
            if((pUART->usConfig & SOFTUART_CONFIG_PAR_MASK) !=
               SOFTUART_CONFIG_PAR_NONE)
            {
                // See if the parity is set to one.
                if((pUART->usConfig & SOFTUART_CONFIG_PAR_MASK) ==
                   SOFTUART_CONFIG_PAR_ONE)
                {
                    // The next value to be written to the data line is
                    // one.
                    pUART->ucTxNext = 255;
                }

                // Otherwise, see if the parity is set to zero.
                else if((pUART->usConfig & SOFTUART_CONFIG_PAR_MASK) ==
                        SOFTUART_CONFIG_PAR_ZERO)
                {
                    // The next value to be written to the data line is
                    // zero.
                    pUART->ucTxNext = 0;
                }

                // Otherwise, there is either even or odd parity.
                else
                {
                    // Find the odd parity for the data byte.
                    pUART->ucTxNext =
                        ((g_pulParityOdd[pUART->ucTxData >> 5] &
                          (1 << (pUART->ucTxData & 31))) ? 255 : 0);

                    // If the parity is set to even, then invert the
                    // parity just computed (making it even parity).
                    if((pUART->usConfig & SOFTUART_CONFIG_PAR_MASK) ==
                       SOFTUART_CONFIG_PAR_EVEN)
                    {
                        pUART->ucTxNext ^= 255;
                    }
                }

                // Advance to the parity state.
                pUART->ucTxState = SOFTUART_TXSTATE_PARITY;
            }

            // Parity is not enabled.
            else
            {
                // The next value to write to the data line is the stop
                // bit.
                pUART->ucTxNext = 255;

                // See if there are one or two stop bits.
                if((pUART->usConfig & SOFTUART_CONFIG_STOP_MASK) ==
                   SOFTUART_CONFIG_STOP_TWO)
                {
                    // Advance to the two stop bits state.
                    pUART->ucTxState = SOFTUART_TXSTATE_STOP_0;
                }
                else
                {
                    // Advance to the one stop bit state.
                    pUART->ucTxState = SOFTUART_TXSTATE_STOP_1;
                }
            }
        }

        // Otherwise, there are more data bits to transfer.
        else
        {
            // The next value to be written to the data line is the next
            // bit of the data byte.
            pUART->ucTxNext =
                (pUART->ucTxData & (1 << pUART->ucTxState)) ? 255 : 0;

            // Advance to the next state.
            pUART->ucTxState++;
        }

        // This state has been handled.
        break;
    }

    // The state machine is in the parity bit state.
    case SOFTUART_TXSTATE_PARITY:
    {
        // The next value to write to the data line is the stop bit.
        pUART->ucTxNext = 255;

        // See if there are one or two stop bits.
        if((pUART->usConfig & SOFTUART_CONFIG_STOP_MASK) ==
           SOFTUART_CONFIG_STOP_TWO)
        {
            // Advance to the two stop bits state.
            pUART->ucTxState = SOFTUART_TXSTATE_STOP_0;
        }
        else
        {
            // Advance to the one stop bit state.
            pUART->ucTxState = SOFTUART_TXSTATE_STOP_1;
        }

        // This state has been handled.
        break;
    }

    // The state machine is in the two stop bits state.
    case SOFTUART_TXSTATE_STOP_0:
    {
        // Advance to the one stop bit state.
        pUART->ucTxState = SOFTUART_TXSTATE_STOP_1;

        // This state has been handled.
        break;
    }

    // The state machine is in the one stop bit state.
    case SOFTUART_TXSTATE_STOP_1:
    {
        // The data byte has been completely transferred, so advance the
        // read pointer.
        pUART->usTxBufferRead++;
        if(pUART->usTxBufferRead == pUART->usTxBufferLen)
        {
            pUART->usTxBufferRead = 0;
        }

        // Determine the number of characters in the transmit buffer.
        if(pUART->usTxBufferRead > pUART->usTxBufferWrite)
        {
            ulTemp = (pUART->usTxBufferLen -
                      (pUART->usTxBufferRead - pUART->usTxBufferWrite));
        }
        else
        {
            ulTemp = pUART->usTxBufferWrite - pUART->usTxBufferRead;
        }

        // If the transmit buffer fullness just crossed the programmed
        // level, generate a transmit "interrupt".
        if(ulTemp == pUART->usTxBufferLevel)
        {
            pUART->usIntStatus |= SOFTUART_INT_TX;
        }

        // See if the SoftUART module is enabled.
        if(!(pUART->ucFlags & SOFTUART_FLAG_ENABLE))
        {
            // The SoftUART module is not enabled, so do advance to the
            // idle state.
            pUART->ucTxState = SOFTUART_TXSTATE_IDLE;
        }

        // See if the break signal should be asserted.
        else if(pUART->ucFlags & SOFTUART_FLAG_TXBREAK)
        {
            // The data line should be driven low while in the break state.
            pUART->ucTxNext = 0;

            // Move to the break state.
            pUART->ucTxState = SOFTUART_TXSTATE_BREAK;
        }

        // Otherwise, see if there is data in the transmit buffer.
        else if(pUART->usTxBufferRead != pUART->usTxBufferWrite)
        {
            // The data line should be driven low to indicate a start bit.
            pUART->ucTxNext = 0;

            // Move to the start bit state.
            pUART->ucTxState = SOFTUART_TXSTATE_START;
        }

        // Otherwise, there is nothing to do.
        else
        {
            // Assert the end of transmission "interrupt".
            pUART->usIntStatus |= SOFTUART_INT_EOT;

            // Advance to the idle state.
            pUART->ucTxState = SOFTUART_TXSTATE_IDLE;
        }

        // This state has been handled.
        break;
    }

    // The state machine is in the break state.
    case SOFTUART_TXSTATE_BREAK:
    {
        // See if the break should be deasserted.
        if(!(pUART->ucFlags & SOFTUART_FLAG_ENABLE) ||
           !(pUART->ucFlags & SOFTUART_FLAG_TXBREAK))
        {
            // The data line should be driven high to indicate it is idle.
            pUART->ucTxNext = 255;

            // Advance to the idle state.
            pUART->ucTxState = SOFTUART_TXSTATE_IDLE;
        }

        // This state has been handled.
        break;
    }
    }

    // Call the "interrupt" callback while there are enabled "interrupts"
    // asserted.  By calling in a loop until the "interrupts" are no longer
    // asserted, this mimics the behavior of a real hardware implementation of
    // the UART peripheral.
    while(((pUART->usIntStatus & pUART->usIntMask) != 0) &&
          (pUART->pfnIntCallback != 0))
    {
        // Call the callback function.
        pUART->pfnIntCallback();
    }
}

//*****************************************************************************
//! Handles the assertion of the receive ``interrupt''.
//!
//! \param pUART specifies the SoftUART data structure.
//!
//! This function is used to determine when to assert the receive ``interrupt''
//! as a result of writing data into the receive buffer (when characters are
//! received from the Rx pin).
//!
//! \return None.
//*****************************************************************************
static void
SoftUARTRxWriteInt(tSoftUART *pUART)
{
    unsigned long ulTemp;

    // Determine the number of characters in the receive buffer.
    if(pUART->usRxBufferWrite > pUART->usRxBufferRead)
    {
        ulTemp = pUART->usRxBufferWrite - pUART->usRxBufferRead;
    }
    else
    {
        ulTemp = (pUART->usRxBufferLen + pUART->usRxBufferWrite -
                  pUART->usRxBufferRead);
    }

    // If the receive buffer fullness just crossed the programmed level,
    // generate a receive "interrupt".
    if(ulTemp == pUART->usRxBufferLevel)
    {
        pUART->usIntStatus |= SOFTUART_INT_RX;
    }
}

//*****************************************************************************
//! Performs the periodic update of the SoftUART receiver.
//!
//! \param pUART specifies the SoftUART data structure.
//! \param bEdgeInt should be \b true if this function is being called because
//! of a GPIO edge interrupt and \b false if it is being called because of a
//! timer interrupt.
//!
//! This function performs the periodic, time-based updates to the SoftUART
//! receiver.  The reception of data to the SoftUART is performed by the state
//! machine in this function.
//!
//! This function must be called by the GPIO interrupt handler, and then
//! periodically at the desired SoftUART baud rate.  For example, to run the
//! SoftUART at 115,200 baud, this function must be called at a 115,200 Hz
//! rate.
//!
//! \return Returns \b SOFTUART_RXTIMER_NOP if the receive timer should
//! continue to operate or \b SOFTUART_RXTIMER_END if it should be stopped.
//*****************************************************************************
unsigned long
SoftUARTRxTick(tSoftUART *pUART, tBoolean bEdgeInt)
{
    unsigned long ulPinState, ulTemp, ulRet;

    // Read the current state of the Rx data line.
    ulPinState = MAP_GPIOPinRead(pUART->ulRxGPIOPort, pUART->ucRxPin);

    // The default return code inidicates that the receive timer does not need
    // to be stopped.
    ulRet = SOFTUART_RXTIMER_NOP;

    // See if this is an edge interrupt while delaying for the receive timeout
    // interrupt.
    if(bEdgeInt && (pUART->ucRxState == SOFTUART_RXSTATE_DELAY))
    {
        // The receive timeout has been cancelled since the next character has
        // started, so go to the idle state.
        pUART->ucRxState = SOFTUART_RXSTATE_IDLE;
    }

    // Determine the current state of the state machine.
    switch(pUART->ucRxState)
    {
    // The state machine is idle.
    case SOFTUART_RXSTATE_IDLE:
    {
        // The falling edge of the start bit was just sampled, so disable
        // the GPIO edge interrupt since the remainder of the character
        // will be read using a timer tick.
        MAP_GPIOPinIntClear(pUART->ulRxGPIOPort, pUART->ucRxPin);
        MAP_GPIOPinIntDisable(pUART->ulRxGPIOPort, pUART->ucRxPin);

        // Clear the receive data buffer.
        pUART->ucRxData = 0;

        // Clear all reception errors other than overrun (which is cleared
        // only when the first character after the overrun is written into
        // the receive buffer), and set the break error (which is cleared
        // if any non-zero bits are read during this character).
        pUART->ucRxFlags = ((pUART->ucRxFlags & SOFTUART_RXFLAG_OE) |
                            SOFTUART_RXFLAG_BE);

        // Advance to the first data bit state.
        pUART->ucRxState = SOFTUART_RXSTATE_DATA_0;

        // This state has been handled.
        break;
    }

    // In each of these states, a bit of the data byte is read.  This
    // depends upon RXSTATE_DATA_n and RXSTATE_DATA_(n+1) being
    // consecutively numbered.
    case SOFTUART_RXSTATE_DATA_0:
    case SOFTUART_RXSTATE_DATA_1:
    case SOFTUART_RXSTATE_DATA_2:
    case SOFTUART_RXSTATE_DATA_3:
    {
        // See if the Rx pin is high.
        if(ulPinState != 0)
        {
            // Set this bit of the received character.
            pUART->ucRxData |= 1 << pUART->ucRxState;

            // Clear the break error since a non-zero bit was received.
            pUART->ucRxFlags &= ~(SOFTUART_RXFLAG_BE);
        }

        // Advance to the next state.
        pUART->ucRxState++;

        // This state has been handled.
        break;
    }

    // In each of these states, a bit of the data byte is read.
    // Additionally, based on the configuration of the SoftUART, this bit
    // might be the last bit of the data byte.  This depends upon
    // RXSTATE_DATA_n and RXSTATE_DATA_(n+1) being consecutively numbered.
    case SOFTUART_RXSTATE_DATA_4:
    case SOFTUART_RXSTATE_DATA_5:
    case SOFTUART_RXSTATE_DATA_6:
    case SOFTUART_RXSTATE_DATA_7:
    {
        // See if the Rx pin is high.
        if(ulPinState != 0)
        {
            // Set this bit of the received character.
            pUART->ucRxData |= 1 << pUART->ucRxState;

            // Clear the break error since a non-zero bit was received.
            pUART->ucRxFlags &= ~(SOFTUART_RXFLAG_BE);
        }

        // See if the bit that was just transferred is the last bit of the
        // data byte (based on the configuration of the SoftUART).
        if(((pUART->usConfig & SOFTUART_CONFIG_WLEN_MASK) >>
            SOFTUART_CONFIG_WLEN_S) ==
           (pUART->ucRxState - SOFTUART_RXSTATE_DATA_4))
        {
            // See if parity is enabled.
            if((pUART->usConfig & SOFTUART_CONFIG_PAR_MASK) !=
               SOFTUART_CONFIG_PAR_NONE)
            {
                // Advance to the parity state.
                pUART->ucRxState = SOFTUART_RXSTATE_PARITY;
            }

            // Otherwise, see if there are one or two stop bits.
            else if((pUART->usConfig & SOFTUART_CONFIG_STOP_MASK) ==
                    SOFTUART_CONFIG_STOP_TWO)
            {
                // Advance to the two stop bits state.
                pUART->ucRxState = SOFTUART_RXSTATE_STOP_0;
            }

            // Otherwise, advance to the one stop bit state.
            else
            {
                pUART->ucRxState = SOFTUART_RXSTATE_STOP_1;
            }
        }

        // Otherwise, there are more bits to receive.
        else
        {
            // Advance to the next state.
            pUART->ucRxState++;
        }

        // This state has been handled.
        break;
    }

    // The state machine is in the parity bit state.
    case SOFTUART_RXSTATE_PARITY:
    {
        // See if the parity is set to one.
        if((pUART->usConfig & SOFTUART_CONFIG_PAR_MASK) ==
           SOFTUART_CONFIG_PAR_ONE)
        {
            // Set the expected parity to one.
            ulTemp = pUART->ucRxPin;
        }

        // Otherwise, see if the parity is set to zero.
        else if((pUART->usConfig & SOFTUART_CONFIG_PAR_MASK) ==
                SOFTUART_CONFIG_PAR_ZERO)
        {
            // Set the expected parity to zero.
            ulTemp = 0;
        }

        // Otherwise, there is either even or odd parity.
        else
        {
            // Find the odd parity for the data byte.
            ulTemp = ((g_pulParityOdd[pUART->ucRxData >> 5] &
                       (1 << (pUART->ucRxData & 31))) ?
                      pUART->ucRxPin : 0);

            // If the parity is set to even, then invert the parity just
            // computed (making it even parity).
            if((pUART->usConfig & SOFTUART_CONFIG_PAR_MASK) ==
               SOFTUART_CONFIG_PAR_EVEN)
            {
                ulTemp ^= pUART->ucRxPin;
            }
        }

        // See if the pin state matches the expected parity.
        if(ulPinState != ulTemp)
        {
            // The parity does not match, so set the parity error flag.
            pUART->ucRxFlags |= SOFTUART_RXFLAG_PE;
        }

        // See if the Rx pin is high.
        if(ulPinState != 0)
        {
            // Clear the break error since a non-zero bit was received.
            pUART->ucRxFlags &= ~(SOFTUART_RXFLAG_BE);
        }

        // See if there are one or two stop bits.
        if((pUART->usConfig & SOFTUART_CONFIG_STOP_MASK) ==
           SOFTUART_CONFIG_STOP_TWO)
        {
            // Advance to the two stop bits state.
            pUART->ucRxState = SOFTUART_RXSTATE_STOP_0;
        }
        else
        {
            // Advance to the one stop bit state.
            pUART->ucRxState = SOFTUART_RXSTATE_STOP_1;
        }

        // This state has been handled.
        break;
    }

    // The state machine is in the two stop bits state.
    case SOFTUART_RXSTATE_STOP_0:
    {
        // See if the Rx pin is low.
        if(ulPinState == 0)
        {
            // Since the Rx pin is low, there is a framing error.
            pUART->ucRxFlags |= SOFTUART_RXFLAG_FE;
        }
        else
        {
            // Clear the break error since a non-zero bit was received.
            pUART->ucRxFlags &= ~(SOFTUART_RXFLAG_BE);
        }

        // Advance to the one stop bit state.
        pUART->ucRxState = SOFTUART_RXSTATE_STOP_1;

        // This state has been handled.
        break;
    }

    // The state machine is in the one stop bit state.
    case SOFTUART_RXSTATE_STOP_1:
    {
        // See if the Rx pin is low.
        if(ulPinState == 0)
        {
            // Since the Rx pin is low, there is a framing error.
            pUART->ucRxFlags |= SOFTUART_RXFLAG_FE;
        }
        else
        {
            // Clear the break error since a non-zero bit was received.
            pUART->ucRxFlags &= ~(SOFTUART_RXFLAG_BE);
        }

        // See if the break error is still asserted (meaning that every bit
        // received was zero).
        if(pUART->ucRxFlags & SOFTUART_RXFLAG_BE)
        {
            // Since every bit was zero, advance to the break state.
            pUART->ucRxState = SOFTUART_RXSTATE_BREAK;

            // This state has been handled.
            break;
        }

        // Compute the value of the write pointer advanced by one.
        ulTemp = pUART->usRxBufferWrite + 1;
        if(ulTemp == pUART->usRxBufferLen)
        {
            ulTemp = 0;
        }

        // See if there is space in the receive buffer.
        if(ulTemp == pUART->usRxBufferRead)
        {
            // Set the overrun error flag.  This will remain set until a
            // new character can be placed into the receive buffer, which
            // will then be given this status.
            pUART->ucRxFlags |= SOFTUART_RXFLAG_OE;

            // Set the receive overrun "interrupt" and status if it is not
            // already set.
            if(!(pUART->ucRxStatus & SOFTUART_RXERROR_OVERRUN))
            {
                pUART->ucRxStatus |= SOFTUART_RXERROR_OVERRUN;
                pUART->usIntStatus |= SOFTUART_INT_OE;
            }
        }

        // Otherwise, there is space in the receive buffer.
        else
        {
            // Write this data byte, along with the receive flags, into the
            // receive buffer.
            pUART->pusRxBuffer[pUART->usRxBufferWrite] =
                pUART->ucRxData | (pUART->ucRxFlags << 8);

            // Advance the write pointer.
            pUART->usRxBufferWrite = ulTemp;

            // Clear the receive flags, most importantly the overrun flag
            // since it was just written into the receive buffer.
            pUART->ucRxFlags = 0;

            // Assert the receive "interrupt" if appropriate.
            SoftUARTRxWriteInt(pUART);
        }

        // See if this character had a parity error.
        if(pUART->ucRxFlags & SOFTUART_RXFLAG_PE)
        {
            // Assert the parity error "interrupt".
            pUART->usIntStatus |= SOFTUART_INT_PE;
        }

        // See if this character had a framing error.
        if(pUART->ucRxFlags & SOFTUART_RXFLAG_FE)
        {
            // Assert the framing error "interrupt".
            pUART->usIntStatus |= SOFTUART_INT_FE;
        }

        // Enable the falling edge interrupt on the Rx pin so that the next
        // start bit can be detected.
        MAP_GPIOPinIntClear(pUART->ulRxGPIOPort, pUART->ucRxPin);
        MAP_GPIOPinIntEnable(pUART->ulRxGPIOPort, pUART->ucRxPin);

        // Advance to the receive timeout delay state.
        pUART->ucRxData = 0;
        pUART->ucRxState = SOFTUART_RXSTATE_DELAY;

        // This state has been handled.
        break;
    }

    // The state machine is in the break state.
    case SOFTUART_RXSTATE_BREAK:
    {
        // See if the Rx pin is high.
        if(ulPinState != 0)
        {
            // Clear the break error since a non-zero bit was received.
            pUART->ucRxFlags &= ~(SOFTUART_RXFLAG_BE);
        }

        // Compute the value of the write pointer advanced by one.
        ulTemp = pUART->usRxBufferWrite + 1;
        if(ulTemp == pUART->usRxBufferLen)
        {
            ulTemp = 0;
        }

        // See if there is space in the receive buffer.
        if(ulTemp == pUART->usRxBufferRead)
        {
            // Set the overrun error flag.  This will remain set until a
            // new character can be placed into the receive buffer, which
            // will then be given this status.
            pUART->ucRxFlags |= SOFTUART_RXFLAG_OE;

            // Set the receive overrun "interrupt" and status if it is not
            // already set.
            if(!(pUART->ucRxStatus & SOFTUART_RXERROR_OVERRUN))
            {
                pUART->ucRxStatus |= SOFTUART_RXERROR_OVERRUN;
                pUART->usIntStatus |= SOFTUART_INT_OE;
            }
        }

        // Otherwise, there is space in the receive buffer.
        else
        {
            // Write this data byte, along with the receive flags, into the
            // receive buffer.
            pUART->pusRxBuffer[pUART->usRxBufferWrite] =
                pUART->ucRxData | (pUART->ucRxFlags << 8);

            // Advance the write pointer.
            pUART->usRxBufferWrite = ulTemp;

            // Clear the receive flags, most importantly the overrun flag
            // since it was just written into the receive buffer.
            pUART->ucRxFlags = 0;

            // Assert the receive "interrupt" if appropriate.
            SoftUARTRxWriteInt(pUART);
        }

        // See if this was a break error.
        if(pUART->ucRxFlags & SOFTUART_RXFLAG_BE)
        {
            // Assert the break error "interrupt".
            pUART->usIntStatus |= SOFTUART_INT_BE;
        }

        // See if this character had a parity error.
        if(pUART->ucRxFlags & SOFTUART_RXFLAG_PE)
        {
            // Assert the parity error "interrupt".
            pUART->usIntStatus |= SOFTUART_INT_PE;
        }

        // Assert the framing error "interrupt".
        pUART->usIntStatus |= SOFTUART_INT_FE;

        // Enable the falling edge interrupt on the Rx pin so that the next
        // start bit can be detected.
        MAP_GPIOPinIntClear(pUART->ulRxGPIOPort, pUART->ucRxPin);
        MAP_GPIOPinIntEnable(pUART->ulRxGPIOPort, pUART->ucRxPin);

        // Advance to the receive timeout delay state.
        pUART->ucRxData = 0;
        pUART->ucRxState = SOFTUART_RXSTATE_DELAY;

        // This state has been handled.
        break;
    }

    // The state machine is in the receive timeout delay state.
    case SOFTUART_RXSTATE_DELAY:
    {
        // See if the receive timeout has expired.
        if(pUART->ucRxData++ == 32)
        {
            // Assert the receive timeout "interrupt".
            pUART->usIntStatus |= SOFTUART_INT_RT;

            // Tell the caller that the receive timer can be disabled.
            ulRet = SOFTUART_RXTIMER_END;
        }

        // This state has been handled.
        break;
    }
    }

    // Call the "interrupt" callback while there are enabled "interrupts"
    // asserted.  By calling in a loop until the "interrupts" are no longer
    // asserted, this mimics the behavior of a real hardware implementation of
    // the UART peripheral.
    while(((pUART->usIntStatus & pUART->usIntMask) != 0) &&
          (pUART->pfnIntCallback != 0))
    {
        // Call the callback function.
        pUART->pfnIntCallback();
    }

    // Return to the caller.
    return(ulRet);
}

//*****************************************************************************
//! Sets the type of parity.
//!
//! \param pUART specifies the SoftUART data structure.
//! \param ulParity specifies the type of parity to use.
//!
//! Sets the type of parity to use for transmitting and expect when receiving.
//! The \e ulParity parameter must be one of \b SOFTUART_CONFIG_PAR_NONE,
//! \b SOFTUART_CONFIG_PAR_EVEN, \b SOFTUART_CONFIG_PAR_ODD,
//! \b SOFTUART_CONFIG_PAR_ONE, or \b SOFTUART_CONFIG_PAR_ZERO.  The last two
//! allow direct control of the parity bit; it is always either one or zero
//! based on the mode.
//!
//! \return None.
//*****************************************************************************
void
SoftUARTParityModeSet(tSoftUART *pUART, unsigned long ulParity)
{
    // Check the arguments.
    ASSERT((ulParity == SOFTUART_CONFIG_PAR_NONE) ||
           (ulParity == SOFTUART_CONFIG_PAR_EVEN) ||
           (ulParity == SOFTUART_CONFIG_PAR_ODD) ||
           (ulParity == SOFTUART_CONFIG_PAR_ONE) ||
           (ulParity == SOFTUART_CONFIG_PAR_ZERO));

    // Set the parity mode.
    pUART->usConfig = (pUART->usConfig & SOFTUART_CONFIG_PAR_MASK) | ulParity;
}

//*****************************************************************************
//! Gets the type of parity currently being used.
//!
//! \param pUART specifies the SoftUART data structure.
//!
//! 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
//! \b SOFTUART_CONFIG_PAR_NONE, \b SOFTUART_CONFIG_PAR_EVEN,
//! \b SOFTUART_CONFIG_PAR_ODD, \b SOFTUART_CONFIG_PAR_ONE, or
//! \b SOFTUART_CONFIG_PAR_ZERO.
//*****************************************************************************
unsigned long
SoftUARTParityModeGet(tSoftUART *pUART)
{
    // Return the current parity setting.
    return(pUART->usConfig & SOFTUART_CONFIG_PAR_MASK);
}

//*****************************************************************************
//! Sets the transmit ``interrupt'' buffer level.
//!
//! \param pUART specifies the soft UART data structure.
//!
//! This function computes the transmit buffer level at which the transmit
//! ``interrupt'' is generated.
//!
//! \return None.
//*****************************************************************************
static void
SoftUARTTxLevelSet(tSoftUART *pUART)
{
    // Determine the transmit buffer "interrupt" fullness setting.
    switch(pUART->usConfig & SOFTUART_CONFIG_TXLVL_M)
    {
    // The transmit "interrupt" should be generated when the buffer is 1/8
    // full.
    case SOFTUART_CONFIG_TXLVL_1:
    {
        // Set the transmit buffer level to 1/8 of the buffer length.
        pUART->usTxBufferLevel = pUART->usTxBufferLen / 8;

        // This setting has been handled.
        break;
    }

    // The transmit "interrupt" should be generated when the buffer is 1/4
    // (2/8) full.
    case SOFTUART_CONFIG_TXLVL_2:
    {
        // Set the transmit buffer level to 1/4 of the buffer length.
        pUART->usTxBufferLevel = pUART->usTxBufferLen / 4;

        // This setting has been handled.
        break;
    }

    // The transmit "interrupt" should be generated when the buffer is 1/2
    // (4/8) full.
    case SOFTUART_CONFIG_TXLVL_4:
    {
        // Set the transmit buffer level to 1/2 of the buffer length.
        pUART->usTxBufferLevel = pUART->usTxBufferLen / 2;

        // This setting has been handled.
        break;
    }

    // The transmit "interrupt" should be generated when the buffer is 3/4
    // (6/8) full.
    case SOFTUART_CONFIG_TXLVL_6:
    {
        // Set the transmit buffer level to 3/4 of the buffer length.
        pUART->usTxBufferLevel = (pUART->usTxBufferLen * 3) / 4;

        // This setting has been handled.
        break;
    }

    // The transmit "interrupt" should be generated when the buffer is 7/8
    // full.
    case SOFTUART_CONFIG_TXLVL_7:
    {
        // Set the transmit buffer level to 7/8 of the buffer length.
        pUART->usTxBufferLevel = (pUART->usTxBufferLen * 7) / 8;

        // This setting has been handled.
        break;
    }
    }
}

//*****************************************************************************
//! Sets the receive ``interrupt'' buffer level.
//!
//! \param pUART specifies the soft UART data structure.
//!
//! This function computes the receive buffer level at which the receive
//! ``interrupt'' is generated.
//!
//! \return None.
//*****************************************************************************
static void
SoftUARTRxLevelSet(tSoftUART *pUART)
{
    // Determine the receive buffer "interrupt" fullness setting.
    switch(pUART->usConfig & SOFTUART_CONFIG_RXLVL_M)
    {
    // The receive "interrupt" should be generated when the buffer is 1/8
    // full.
    case SOFTUART_CONFIG_RXLVL_1:
    {
        // Set the receive buffer level to 1/8 of the buffer length.
        pUART->usRxBufferLevel = pUART->usRxBufferLen / 8;

        // This setting has been handled.
        break;
    }

    // The receive "interrupt" should be generated when the buffer is 1/4
    // (2/8) full.
    case SOFTUART_CONFIG_RXLVL_2:
    {
        // Set the receive buffer level to 1/4 of the buffer length.
        pUART->usRxBufferLevel = pUART->usRxBufferLen / 4;

        // This setting has been handled.
        break;
    }

    // The receive "interrupt" should be generated when the buffer is 1/2
    // (4/8) full.
    case SOFTUART_CONFIG_RXLVL_4:
    {
        // Set the receive buffer level to 1/2 of the buffer length.
        pUART->usRxBufferLevel = pUART->usRxBufferLen / 2;

        // This setting has been handled.
        break;
    }

    // The receive "interrupt" should be generated when the buffer is 3/4
    // (6/8) full.
    case SOFTUART_CONFIG_RXLVL_6:
    {
        // Set the receive buffer level to 3/4 of the buffer length.
        pUART->usRxBufferLevel = (pUART->usRxBufferLen * 3) / 4;

        // This setting has been handled.
        break;
    }

    // The receive "interrupt" should be generated when the buffer is 7/8
    // full.
    case SOFTUART_CONFIG_RXLVL_7:
    {
        // Set the receive buffer level to 7/8 of the buffer length.
        pUART->usRxBufferLevel = (pUART->usRxBufferLen * 7) / 8;

        // This setting has been handled.
        break;
    }
    }
}

//*****************************************************************************
//! Sets the buffer level at which ``interrupts'' are generated.
//!
//! \param pUART specifies the SoftUART data structure.
//! \param ulTxLevel is the transmit buffer ``interrupt'' level, specified as
//! one of \b UART_FIFO_TX1_8, \b UART_FIFO_TX2_8, \b UART_FIFO_TX4_8,
//! \b UART_FIFO_TX6_8, or \b UART_FIFO_TX7_8.
//! \param ulRxLevel is the receive buffer ``interrupt'' level, specified as
//! one of \b UART_FIFO_RX1_8, \b UART_FIFO_RX2_8, \b UART_FIFO_RX4_8,
//! \b UART_FIFO_RX6_8, or \b UART_FIFO_RX7_8.
//!
//! This function sets the buffer level at which transmit and receive
//! ``interrupts'' are generated.
//!
//! \return None.
//*****************************************************************************
void
SoftUARTFIFOLevelSet(tSoftUART *pUART, unsigned long ulTxLevel,
                     unsigned long ulRxLevel)
{
    // Check the arguments.
    ASSERT((ulTxLevel == SOFTUART_FIFO_TX1_8) ||
           (ulTxLevel == SOFTUART_FIFO_TX2_8) ||
           (ulTxLevel == SOFTUART_FIFO_TX4_8) ||
           (ulTxLevel == SOFTUART_FIFO_TX6_8) ||
           (ulTxLevel == SOFTUART_FIFO_TX7_8));
    ASSERT((ulRxLevel == SOFTUART_FIFO_RX1_8) ||
           (ulRxLevel == SOFTUART_FIFO_RX2_8) ||
           (ulRxLevel == SOFTUART_FIFO_RX4_8) ||
           (ulRxLevel == SOFTUART_FIFO_RX6_8) ||
           (ulRxLevel == SOFTUART_FIFO_RX7_8));

    // Save the buffer "interrupt" levels.
    pUART->usConfig = ((pUART->usConfig & SOFTUART_CONFIG_BASE_M) |
                       ((ulTxLevel | ulRxLevel) << 8));

    // Compute the new buffer "interrupt" levels.
    SoftUARTTxLevelSet(pUART);
    SoftUARTRxLevelSet(pUART);
}

//*****************************************************************************
//! Gets the buffer level at which ``interrupts'' are generated.
//!
//! \param pUART specifies the SoftUART data structure.
//! \param pulTxLevel is a pointer to storage for the transmit buffer level,
//! returned as one of \b UART_FIFO_TX1_8, \b UART_FIFO_TX2_8,
//! \b UART_FIFO_TX4_8, \b UART_FIFO_TX6_8, or \b UART_FIFO_TX7_8.
//! \param pulRxLevel is a pointer to storage for the receive buffer level,
//! returned as one of \b UART_FIFO_RX1_8, \b UART_FIFO_RX2_8,
//! \b UART_FIFO_RX4_8, \b UART_FIFO_RX6_8, or \b UART_FIFO_RX7_8.
//!
//! This function gets the buffer level at which transmit and receive
//! ``interrupts'' are generated.
//!
//! \return None.
//*****************************************************************************
void
SoftUARTFIFOLevelGet(tSoftUART *pUART, unsigned long *pulTxLevel,
                     unsigned long *pulRxLevel)
{
    // Extract the transmit and receive buffer levels.
    *pulTxLevel = (pUART->usConfig & SOFTUART_CONFIG_TXLVL_M) >> 8;
    *pulRxLevel = (pUART->usConfig & SOFTUART_CONFIG_RXLVL_M) >> 8;
}

//*****************************************************************************
//! Gets the current configuration of a UART.
//!
//! \param pUART specifies the SoftUART data structure.
//! \param pulConfig is a pointer to storage for the data format.
//!
//! Returns the data format of the SoftUART.  The data format returned in
//! \e pulConfig is enumerated the same as the \e ulConfig parameter of
//! SoftUARTConfigSet().
//!
//! \return None.
//*****************************************************************************
void
SoftUARTConfigGet(tSoftUART *pUART, unsigned long *pulConfig)
{
    // Get the data format.
    *pulConfig = pUART->usConfig & SOFTUART_CONFIG_BASE_M;
}

//*****************************************************************************
//! Enables the SoftUART.
//!
//! \param pUART specifies the SoftUART data structure.
//!
//! This function enables the SoftUART, allowing data to be transmitted and
//! received.
//!
//! \return None.
//*****************************************************************************
void
SoftUARTEnable(tSoftUART *pUART)
{
    // Enable the SoftUART.
    pUART->ucFlags |= SOFTUART_FLAG_ENABLE;
}

//*****************************************************************************
//! Disables the SoftUART.
//!
//! \param pUART specifies the SoftUART data structure.
//!
//! This function disables the SoftUART after waiting for it to become idle.
//!
//! \return None.
//*****************************************************************************
void
SoftUARTDisable(tSoftUART *pUART)
{
    // Wait for end of TX.
    while(SoftUARTBusy(pUART))
    {
    }

    // Disable the SoftUART.
    pUART->ucFlags &= ~(SOFTUART_FLAG_ENABLE);
}

//*****************************************************************************
//! Determines if there are any characters in the receive buffer.
//!
//! \param pUART specifies the SoftUART data structure.
//!
//! 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.
//*****************************************************************************
tBoolean
SoftUARTCharsAvail(tSoftUART *pUART)
{
    // Return the availability of characters.
    return((pUART->usRxBufferRead == pUART->usRxBufferWrite) ? false : true);
}

//*****************************************************************************
//! Determines if there is any space in the transmit buffer.
//!
//! \param pUART specifies the SoftUART data structure.
//!
//! This function returns a flag indicating whether or not there is space
//! available in the transmit buffer.
//!
//! \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.
//*****************************************************************************
tBoolean
SoftUARTSpaceAvail(tSoftUART *pUART)
{
    unsigned short usTemp;

    // Determine the values of the write pointer once incremented.
    usTemp = pUART->usTxBufferWrite + 1;
    if(usTemp == pUART->usTxBufferLen)
    {
        usTemp = 0;
    }

    // Return the availability of space.
    return((pUART->usTxBufferRead == usTemp) ? false : true);
}

//*****************************************************************************
//! Handles the deassertion of the receive ``interrupts''.
//!
//! \param pUART specifies the SoftUART data structure.
//!
//! This function is used to determine when to deassert the receive
//! ``interrupt'' as a result of reading data from the receive buffer.
//!
//! \return None.
//*****************************************************************************
static void
SoftUARTRxReadInt(tSoftUART *pUART)
{
    unsigned long ulTemp;

    // Determine the number of characters in the receive buffer.
    if(pUART->usRxBufferWrite > pUART->usRxBufferRead)
    {
        ulTemp = pUART->usRxBufferWrite - pUART->usRxBufferRead;
    }
    else
    {
        ulTemp = (pUART->usRxBufferLen + pUART->usRxBufferWrite -
                  pUART->usRxBufferRead);
    }

    // See if the number of characters in the receive buffer have dropped below
    // the receive trigger level.
    if(ulTemp < pUART->usRxBufferLevel)
    {
        // Deassert the receive "interrupt".
        pUART->usIntStatus &= ~(SOFTUART_INT_RX);
    }

    // See if the receive buffer is now empty.
    if(ulTemp == 0)
    {
        // Deassert the receive timeout "interrupt".
        pUART->usIntStatus &= ~(SOFTUART_INT_RT);
    }
}

//*****************************************************************************
//! Receives a character from the specified port.
//!
//! \param pUART specifies the SoftUART data structure.
//!
//! Gets a character from the receive buffer for the specified port.
//!
//! \return Returns the character read from the specified port, cast as a
//! \e long.  A \b -1 isreturned if there are no characters present in the
//! receive buffer.  The SoftUARTCharsAvail() function should be called before
//! attempting to call this function.
//*****************************************************************************
long
SoftUARTCharGetNonBlocking(tSoftUART *pUART)
{
    long lTemp;

    // See if there are any characters in the receive buffer.
    if(pUART->usRxBufferRead != pUART->usRxBufferWrite)
    {
        // Read the next character.
        lTemp = pUART->pusRxBuffer[pUART->usRxBufferRead];
        pUART->usRxBufferRead++;
        if(pUART->usRxBufferRead == pUART->usRxBufferLen)
        {
            pUART->usRxBufferRead = 0;
        }

        // Deassert the receive "interrupt(s)" if appropriate.
        SoftUARTRxReadInt(pUART);

        // Set the receive status to match this character.
        pUART->ucRxStatus = ((pUART->ucRxStatus & SOFTUART_RXERROR_OVERRUN) |
                             ((lTemp >> 8) & ~(SOFTUART_RXERROR_OVERRUN)));

        // Return this character.
        return(lTemp);
    }
    else
    {
        // There are no characters, so return a failure.
        return(-1);
    }
}

//*****************************************************************************
//! Waits for a character from the specified port.
//!
//! \param pUART specifies the SoftUART data structure.
//!
//! Gets a character from the receive buffer for the specified port.  If there
//! are no characters available, this function waits until a character is
//! received before returning.
//!
//! \return Returns the character read from the specified port, cast as a
//! \e long.
//*****************************************************************************
long
SoftUARTCharGet(tSoftUART *pUART)
{
    long lTemp;

    // Wait until a char is available.
    while(pUART->usRxBufferRead ==
          *(volatile unsigned short *)(&(pUART->usRxBufferWrite)))
    {
    }

    // Read the next character.
    lTemp = pUART->pusRxBuffer[pUART->usRxBufferRead];
    pUART->usRxBufferRead++;
    if(pUART->usRxBufferRead == pUART->usRxBufferLen)
    {
        pUART->usRxBufferRead = 0;
    }

    // Deassert the receive "interrupt(s)" if appropriate.
    SoftUARTRxReadInt(pUART);

    // Set the receive status to match this character.
    pUART->ucRxStatus = ((pUART->ucRxStatus & SOFTUART_RXERROR_OVERRUN) |
                         ((lTemp >> 8) & ~(SOFTUART_RXERROR_OVERRUN)));

    // Return this character.
    return(lTemp);
}

//*****************************************************************************
//! Sends a character to the specified port.
//!
//! \param pUART specifies the SoftUART data structure.
//! \param ucData is the character to be transmitted.
//!
//! Writes the character \e ucData to the transmit buffer for the specified
//! port.  This function does not block, so if there is no space available,
//! then a \b false is returned, and the application must retry the function
//! later.
//!
//! \return Returns \b true if the character was successfully placed in the
//! transmit buffer or \b false if there was no space available in the
//! transmit buffer.
//*****************************************************************************
tBoolean
SoftUARTCharPutNonBlocking(tSoftUART *pUART, unsigned char ucData)
{
    unsigned short usTemp;

    // Determine the values of the write pointer once incremented.
    usTemp = pUART->usTxBufferWrite + 1;
    if(usTemp == pUART->usTxBufferLen)
    {
        usTemp = 0;
    }

    // See if there is space in the transmit buffer.
    if(usTemp != pUART->usTxBufferRead)
    {
        // Write this character to the transmit buffer.
        pUART->pucTxBuffer[pUART->usTxBufferWrite] = ucData;
        pUART->usTxBufferWrite = usTemp;

        // Success.
        return(true);
    }
    else
    {
        // There is no space in the transmit buffer, so return a failure.
        return(false);
    }
}

//*****************************************************************************
//! Waits to send a character from the specified port.
//!
//! \param pUART specifies the SoftUART data structure.
//! \param ucData is the character to be transmitted.
//!
//! Sends the character \e ucData to the transmit buffer for the specified
//! port.  If there is no space available in the transmit buffer, this function
//! waits until there is space available before returning.
//!
//! \return None.
//*****************************************************************************
void
SoftUARTCharPut(tSoftUART *pUART, unsigned char ucData)
{
    unsigned short usTemp;

    // Wait until space is available.
    usTemp = pUART->usTxBufferWrite + 1;
    if(usTemp == pUART->usTxBufferLen)
    {
        usTemp = 0;
    }
    while(usTemp == *(volatile unsigned short *)(&(pUART->usTxBufferRead)))
    {
    }

    // Send the char.
    pUART->pucTxBuffer[pUART->usTxBufferWrite] = ucData;
    pUART->usTxBufferWrite = usTemp;
}

//*****************************************************************************
//! Causes a BREAK to be sent.
//!
//! \param pUART specifies the SoftUART data structure.
//! \param bBreakState controls the output level.
//!
//! Calling this function with \e bBreakState set to \b true asserts a break
//! condition on the SoftUART.  Calling this function with \e bBreakState set
//! to \b false removes the break condition.  For proper transmission of a
//! break command, the break must be asserted for at least two complete frames.
//!
//! \return None.
//*****************************************************************************
void
SoftUARTBreakCtl(tSoftUART *pUART, tBoolean bBreakState)
{
    // Set the break condition as requested.
    if(bBreakState)
    {
        pUART->ucFlags |= SOFTUART_FLAG_TXBREAK;
    }
    else
    {
        pUART->ucFlags &= ~(SOFTUART_FLAG_TXBREAK);
    }
}

//*****************************************************************************
//! Determines whether the UART transmitter is busy or not.
//!
//! \param pUART specifies the SoftUART data structure.
//!
//! Allows the caller to determine whether all transmitted bytes have cleared
//! the transmitter hardware.  If \b false is returned, the transmit buffer is
//! empty and all bits of the last transmitted character, including all stop
//! bits, have left the hardware shift register.
//!
//! \return Returns \b true if the UART is transmitting or \b false if all
//! transmissions are complete.
//*****************************************************************************
tBoolean
SoftUARTBusy(tSoftUART *pUART)
{
    // Determine if the UART is busy.
    return(((pUART->ucTxState == SOFTUART_TXSTATE_IDLE) &&
            (((pUART->ucFlags & SOFTUART_FLAG_ENABLE) == 0) ||
             (pUART->usTxBufferRead == pUART->usTxBufferWrite))) ?
           false : true);
}

//*****************************************************************************
//! Enables individual SoftUART ``interrupt'' sources.
//!
//! \param pUART specifies the SoftUART data structure.
//! \param ulIntFlags is the bit mask of the ``interrupt'' sources to be
//! enabled.
//!
//! Enables the indicated SoftUART ``interrupt'' sources.  Only the sources
//! that are enabled can be reflected to the SoftUART callback.
//!
//! The \e ulIntFlags parameter is the logical OR of any of the following:
//!
//! - \b SOFTUART_INT_OE - Overrun Error ``interrupt''
//! - \b SOFTUART_INT_BE - Break Error ``interrupt''
//! - \b SOFTUART_INT_PE - Parity Error ``interrupt''
//! - \b SOFTUART_INT_FE - Framing Error ``interrupt''
//! - \b SOFTUART_INT_RT - Receive Timeout ``interrupt''
//! - \b SOFTUART_INT_TX - Transmit ``interrupt''
//! - \b SOFTUART_INT_RX - Receive ``interrupt''
//!
//! \return None.
//*****************************************************************************
void
SoftUARTIntEnable(tSoftUART *pUART, unsigned long ulIntFlags)
{
    // Enable the specified interrupts.
    pUART->usIntMask |= ulIntFlags;
}

//*****************************************************************************
//! Disables individual SoftUART ``interrupt'' sources.
//!
//! \param pUART specifies the SoftUART data structure.
//! \param ulIntFlags is the bit mask of the ``interrupt'' sources to be
//! disabled.
//!
//! Disables the indicated SoftUART ``interrupt'' sources.  Only the sources
//! that are enabled can be reflected to the SoftUART callback.
//!
//! The \e ulIntFlags parameter has the same definition as the \e ulIntFlags
//! parameter to SoftUARTIntEnable().
//!
//! \return None.
//*****************************************************************************
void
SoftUARTIntDisable(tSoftUART *pUART, unsigned long ulIntFlags)
{
    // Disable the specified interrupts.
    pUART->usIntMask &= ~(ulIntFlags);
}

//*****************************************************************************
//! Gets the current SoftUART ``interrupt'' status.
//!
//! \param pUART specifies the SoftUART data structure.
//! \param bMasked is \b false if the raw ``interrupt'' status is required and
//! \b true if the masked ``interrupt'' status is required.
//!
//! This returns the ``interrupt'' status for the SoftUART.  Either the raw
//! ``interrupt'' status or the status of ``interrupts'' that are allowed to
//! reflect to the SoftUART callback can be returned.
//!
//! \return Returns the current ``interrupt'' status, enumerated as a bit field
//! of values described in SoftUARTIntEnable().
//*****************************************************************************
unsigned long
SoftUARTIntStatus(tSoftUART *pUART, tBoolean bMasked)
{
    // Return either the interrupt status or the raw interrupt status as
    // requested.
    if(bMasked)
    {
        return(pUART->usIntStatus & pUART->usIntMask);
    }
    else
    {
        return(pUART->usIntStatus);
    }
}

//*****************************************************************************
//! Clears SoftUART ``interrupt'' sources.
//!
//! \param pUART specifies the SoftUART data structure.
//! \param ulIntFlags is a bit mask of the ``interrupt'' sources to be cleared.
//!
//! The specified SoftUART ``interrupt'' sources are cleared, so that they no
//! longer assert.  This function must be called in the callback function to
//! keep the ``interrupt'' from being recognized again immediately upon exit.
//!
//! The \e ulIntFlags parameter has the same definition as the \e ulIntFlags
//! parameter to SoftUARTIntEnable().
//!
//! \return None.
//*****************************************************************************
void
SoftUARTIntClear(tSoftUART *pUART, unsigned long ulIntFlags)
{
    // Clear the requested interrupt sources.
    pUART->usIntStatus &= ~(ulIntFlags);
}

//*****************************************************************************
//! Gets current receiver errors.
//!
//! \param pUART specifies the SoftUART data structure.
//!
//! This function returns the current state of each of the 4 receiver error
//! sources.  The returned errors are equivalent to the four error bits
//! returned via the previous call to SoftUARTCharGet() or
//! SoftUARTCharGetNonBlocking() with the exception that the overrun error is
//! set immediately when the overrun occurs rather than when a character is
//! next read.
//!
//! \return Returns a logical OR combination of the receiver error flags,
//! \b SOFTUART_RXERROR_FRAMING, \b SOFTUART_RXERROR_PARITY,
//! \b SOFTUART_RXERROR_BREAK and \b SOFTUART_RXERROR_OVERRUN.
//*****************************************************************************
unsigned long
SoftUARTRxErrorGet(tSoftUART *pUART)
{
    // Return the current value of the receive status.
    return(pUART->ucRxStatus);
}

//*****************************************************************************
//! Clears all reported receiver errors.
//!
//! \param pUART specifies the SoftUART data structure.
//!
//! This function is used to clear all receiver error conditions reported via
//! SoftUARTRxErrorGet().  If using the overrun, framing error, parity error or
//! break interrupts, this function must be called after clearing the interrupt
//! to ensure that later errors of the same type trigger another interrupt.
//!
//! \return None.
//*****************************************************************************
void
SoftUARTRxErrorClear(tSoftUART *pUART)
{
    // Clear any receive error status.
    pUART->ucRxStatus = 0;
}

//*****************************************************************************
//! Sets the callback used by the SoftUART module.
//!
//! \param pUART specifies the SoftUART data structure.
//! \param pfnCallback is a pointer to the callback function.
//!
//! This function sets the address of the callback function that is called when
//! there is an ``interrupt'' produced by the SoftUART module.
//!
//! \return None.
//*****************************************************************************
void
SoftUARTCallbackSet(tSoftUART *pUART, void (*pfnCallback)(void))
{
    // Save the callback function address.
    pUART->pfnIntCallback = pfnCallback;
}

//*****************************************************************************
//! Sets the GPIO pin to be used as the SoftUART Tx signal.
//!
//! \param pUART specifies the SoftUART data structure.
//! \param ulBase is the base address of the GPIO module.
//! \param ucPin is the bit-packed representation of the pin to use.
//!
//! This function sets the GPIO pin that is used when the SoftUART must assert
//! the Tx signal.
//!
//! The pin is specified using a bit-packed byte, where bit 0 of the byte
//! represents GPIO port pin 0, bit 1 represents GPIO port pin 1, and so on.
//!
//! \return None.
//*****************************************************************************
void
SoftUARTTxGPIOSet(tSoftUART *pUART, unsigned long ulBase, unsigned char ucPin)
{
    // Save the base address and pin for the Tx signal.
    if(ulBase == 0)
    {
        pUART->ulTxGPIO = 0;
    }
    else
    {
        pUART->ulTxGPIO = ulBase + (ucPin << 2);
    }
}

//*****************************************************************************
//! Sets the GPIO pin to be used as the SoftUART Rx signal.
//!
//! \param pUART specifies the SoftUART data structure.
//! \param ulBase is the base address of the GPIO module.
//! \param ucPin is the bit-packed representation of the pin to use.
//!
//! This function sets the GPIO pin that is used when the SoftUART must sample
//! the Rx signal.  If there is not a GPIO pin allocated for Rx, the SoftUART
//! module will not read data from the slave device.
//!
//! The pin is specified using a bit-packed byte, where bit 0 of the byte
//! represents GPIO port pin 0, bit 1 represents GPIO port pin 1, and so on.
//!
//! \return None.
//*****************************************************************************
void
SoftUARTRxGPIOSet(tSoftUART *pUART, unsigned long ulBase, unsigned char ucPin)
{
    // Save the base address and pin for the Rx signal.
    if(ulBase == 0)
    {
        pUART->ulRxGPIOPort = 0;
        pUART->ucRxPin = 0;
    }
    else
    {
        pUART->ulRxGPIOPort = ulBase;
        pUART->ucRxPin = ucPin;
    }
}

//*****************************************************************************
//! Sets the transmit buffer for a SoftUART module.
//!
//! \param pUART specifies the SoftUART data structure.
//! \param pucTxBuffer is the address of the transmit buffer.
//! \param usLen is the size, in 8-bit bytes, of the transmit buffer.
//!
//! This function sets the address and size of the transmit buffer.  It also
//! resets the read and write pointers, marking the transmit buffer as empty.
//!
//! \return None.
//*****************************************************************************
void
SoftUARTTxBufferSet(tSoftUART *pUART, unsigned char *pucTxBuffer,
                    unsigned short usLen)
{
    // Save the transmit buffer address and length.
    pUART->pucTxBuffer = pucTxBuffer;
    pUART->usTxBufferLen = usLen;

    // Reset the transmit buffer read and write pointers.
    pUART->usTxBufferRead = 0;
    pUART->usTxBufferWrite = 0;

    // Compute the new buffer "interrupt" level.
    SoftUARTTxLevelSet(pUART);
}

//*****************************************************************************
//! Sets the receive buffer for a SoftUART module.
//!
//! \param pUART specifies the SoftUART data structure.
//! \param pusRxBuffer is the address of the receive buffer.
//! \param usLen is the size, in 16-bit half-words, of the receive buffer.
//!
//! This function sets the address and size of the receive buffer.  It also
//! resets the read and write pointers, marking the receive buffer as empty.
//!
//! \return None.
//*****************************************************************************
void
SoftUARTRxBufferSet(tSoftUART *pUART, unsigned short *pusRxBuffer,
                    unsigned short usLen)
{
    // Save the receive buffer address and length.
    pUART->pusRxBuffer = pusRxBuffer;
    pUART->usRxBufferLen = usLen;

    // Reset the receive read and write pointers.
    pUART->usRxBufferRead = 0;
    pUART->usRxBufferWrite = 0;

    // Compute the new buffer "interrupt" level.
    SoftUARTRxLevelSet(pUART);
}

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



