text: //*****************************************************************************
  //
  // uartstdio.c - Utility driver to provide simple UART console functions.
  //
  // Copyright (c) 2007-2013 Texas Instruments Incorporated.  All rights reserved.
  // Software License Agreement
  // 
  // Texas Instruments (TI) is supplying this software for use solely and
  // exclusively on TI's microcontroller products. The software is owned by
  // TI and/or its suppliers, and is protected under applicable copyright
  // laws. You may not combine this software with "viral" open-source
  // software in order to form a larger program.
  // 
  // THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
  // NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
  // NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  // A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
  // CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
  // DAMAGES, FOR ANY REASON WHATSOEVER.
  // 
  // This is part of revision 10636 of the Stellaris Firmware Development Package.
  //
  //*****************************************************************************
  
  #include <stdarg.h>
  #include "inc/hw_ints.h"
  #include "inc/hw_memmap.h"
  #include "inc/hw_types.h"
  #include "inc/hw_uart.h"
  #include "driverlib/debug.h"
  #include "driverlib/interrupt.h"
  #include "driverlib/rom.h"
  #include "driverlib/rom_map.h"
  #include "driverlib/sysctl.h"
  #include "driverlib/uart.h"
  #include "utils/uartstdio.h"
  
  //*****************************************************************************
  //
  //! \addtogroup uartstdio_api
  //! @{
  //
  //*****************************************************************************
  
  //*****************************************************************************
  //
  // If buffered mode is defined, set aside RX and TX buffers and read/write
  // pointers to control them.
  //
  //*****************************************************************************
  #ifdef UART_BUFFERED
  
  //*****************************************************************************
  //
  // This global controls whether or not we are echoing 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 tBoolean g_bDisableEcho;
  
  //*****************************************************************************
  //
  // Output ring buffer.  Buffer is full if g_ulUARTTxReadIndex is one ahead of
  // g_ulUARTTxWriteIndex.  Buffer is empty if the two indices are the same.
  //
  //*****************************************************************************
  static unsigned char g_pcUARTTxBuffer[UART_TX_BUFFER_SIZE];
  static volatile unsigned long g_ulUARTTxWriteIndex = 0;
  static volatile unsigned long g_ulUARTTxReadIndex = 0;
  
  //*****************************************************************************
  //
  // Input ring buffer.  Buffer is full if g_ulUARTTxReadIndex is one ahead of
  // g_ulUARTTxWriteIndex.  Buffer is empty if the two indices are the same.
  //
  //*****************************************************************************
  static unsigned char g_pcUARTRxBuffer[UART_RX_BUFFER_SIZE];
  static volatile unsigned long g_ulUARTRxWriteIndex = 0;
  static volatile unsigned long g_ulUARTRxReadIndex = 0;
  
  //*****************************************************************************
  //
  // Macros to determine number of free and used bytes in the transmit buffer.
  //
  //*****************************************************************************
  #define TX_BUFFER_USED          (GetBufferCount(&g_ulUARTTxReadIndex,  \
                                                  &g_ulUARTTxWriteIndex, \
                                                  UART_TX_BUFFER_SIZE))
  #define TX_BUFFER_FREE          (UART_TX_BUFFER_SIZE - TX_BUFFER_USED)
  #define TX_BUFFER_EMPTY         (IsBufferEmpty(&g_ulUARTTxReadIndex,   \
                                                 &g_ulUARTTxWriteIndex))
  #define TX_BUFFER_FULL          (IsBufferFull(&g_ulUARTTxReadIndex,  \
                                                &g_ulUARTTxWriteIndex, \
                                                UART_TX_BUFFER_SIZE))
  #define ADVANCE_TX_BUFFER_INDEX(Index) \
                                  (Index) = ((Index) + 1) % UART_TX_BUFFER_SIZE
  
  //*****************************************************************************
  //
  // Macros to determine number of free and used bytes in the receive buffer.
  //
  //*****************************************************************************
  #define RX_BUFFER_USED          (GetBufferCount(&g_ulUARTRxReadIndex,  \
                                                  &g_ulUARTRxWriteIndex, \
                                                  UART_RX_BUFFER_SIZE))
  #define RX_BUFFER_FREE          (UART_RX_BUFFER_SIZE - RX_BUFFER_USED)
  #define RX_BUFFER_EMPTY         (IsBufferEmpty(&g_ulUARTRxReadIndex,   \
                                                 &g_ulUARTRxWriteIndex))
  #define RX_BUFFER_FULL          (IsBufferFull(&g_ulUARTRxReadIndex,  \
                                                &g_ulUARTRxWriteIndex, \
                                                UART_RX_BUFFER_SIZE))
  #define ADVANCE_RX_BUFFER_INDEX(Index) \
                                  (Index) = ((Index) + 1) % UART_RX_BUFFER_SIZE
  #endif
  
  //*****************************************************************************
  //
  // The base address of the chosen UART.
  //
  //*****************************************************************************
  static unsigned long g_ulBase = 0;
  
  //*****************************************************************************
  //
  // A mapping from an integer between 0 and 15 to its ASCII character
  // equivalent.
  //
  //*****************************************************************************
  static const char * const g_pcHex = "0123456789abcdef";
  
  //*****************************************************************************
  //
  // The list of possible base addresses for the console UART.
  //
  //*****************************************************************************
  static const unsigned long g_ulUARTBase[3] =
  {
      UART0_BASE, UART1_BASE, UART2_BASE
  };
  
  #ifdef UART_BUFFERED
  //*****************************************************************************
  //
  // The list of possible interrupts for the console UART.
  //
  //*****************************************************************************
  static const unsigned long g_ulUARTInt[3] =
  {
      INT_UART0, INT_UART1, INT_UART2
  };
  
  //*****************************************************************************
  //
  // The port number in use.
  //
  //*****************************************************************************
  static unsigned long g_ulPortNum;
  #endif
  
  //*****************************************************************************
  //
  // The list of UART peripherals.
  //
  //*****************************************************************************
  static const unsigned long g_ulUARTPeriph[3] =
  {
      SYSCTL_PERIPH_UART0, SYSCTL_PERIPH_UART1, SYSCTL_PERIPH_UART2
  };
  
  //*****************************************************************************
  //
  //! Determines whether the ring buffer whose pointers and size are provided
  //! is full or not.
  //!
  //! \param pulRead points to the read index for the buffer.
  //! \param pulWrite points to the write index for the buffer.
  //! \param ulSize 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.
  //
  //*****************************************************************************
  #ifdef UART_BUFFERED
  static tBoolean
  IsBufferFull(volatile unsigned long *pulRead,
               volatile unsigned long *pulWrite, unsigned long ulSize)
  {
      unsigned long ulWrite;
      unsigned long ulRead;
  
      ulWrite = *pulWrite;
      ulRead = *pulRead;
  
      return((((ulWrite + 1) % ulSize) == ulRead) ? true : false);
  }
  #endif
  
  //*****************************************************************************
  //
  //! Determines whether the ring buffer whose pointers and size are provided
  //! is empty or not.
  //!
  //! \param pulRead points to the read index for the buffer.
  //! \param pulWrite 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.
  //
  //*****************************************************************************
  #ifdef UART_BUFFERED
  static tBoolean
  IsBufferEmpty(volatile unsigned long *pulRead,
                volatile unsigned long *pulWrite)
  {
      unsigned long ulWrite;
      unsigned long ulRead;
  
      ulWrite = *pulWrite;
      ulRead = *pulRead;
  
      return((ulWrite  == ulRead) ? true : false);
  }
  #endif
  
  //*****************************************************************************
  //
  //! Determines the number of bytes of data contained in a ring buffer.
  //!
  //! \param pulRead points to the read index for the buffer.
  //! \param pulWrite points to the write index for the buffer.
  //! \param ulSize 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.
  //
  //*****************************************************************************
  #ifdef UART_BUFFERED
  static unsigned long
  GetBufferCount(volatile unsigned long *pulRead,
                 volatile unsigned long *pulWrite, unsigned long ulSize)
  {
      unsigned long ulWrite;
      unsigned long ulRead;
  
      ulWrite = *pulWrite;
      ulRead = *pulRead;
  
      return((ulWrite >= ulRead) ? (ulWrite - ulRead) :
                                   (ulSize - (ulRead - ulWrite)));
  }
  #endif
  
  //*****************************************************************************
  //
  // Take as many bytes from the transmit buffer as we have space for and move
  // them into the UART transmit FIFO.
  //
  //*****************************************************************************
  #ifdef UART_BUFFERED
  static void
  UARTPrimeTransmit(unsigned long ulBase)
  {
      //
      // 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_ulUARTInt[g_ulPortNum]);
  
          //
          // Yes - take some characters out of the transmit buffer and feed
          // them to the UART transmit FIFO.
          //
          while(MAP_UARTSpaceAvail(ulBase) && !TX_BUFFER_EMPTY)
          {
              MAP_UARTCharPutNonBlocking(ulBase,
                                         g_pcUARTTxBuffer[g_ulUARTTxReadIndex]);
              ADVANCE_TX_BUFFER_INDEX(g_ulUARTTxReadIndex);
          }
  
          //
          // Reenable the UART interrupt.
          //
          MAP_IntEnable(g_ulUARTInt[g_ulPortNum]);
      }
  }
  #endif
  
  //*****************************************************************************
  //
  //! Configures the UART console.
  //!
  //! \param ulPortNum is the number of UART port to use for the serial console
  //! (0-2)
  //! \param ulBaud is the bit rate that the UART is to be configured to use.
  //! \param ulSrcClock 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 ulBaud 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: UARTprintf() 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
  UARTStdioConfig(unsigned long ulPortNum, unsigned long ulBaud,
                  unsigned long ulSrcClock)
  {
      //
      // Check the arguments.
      //
      ASSERT((ulPortNum == 0) || (ulPortNum == 1) ||
             (ulPortNum == 2));
  
  #ifdef UART_BUFFERED
      //
      // In buffered mode, we only allow a single instance to be opened.
      //
      ASSERT(g_ulBase == 0);
  #endif
  
      //
      // Check to make sure the UART peripheral is present.
      //
      if(!MAP_SysCtlPeripheralPresent(g_ulUARTPeriph[ulPortNum]))
      {
          return;
      }
  
      //
      // Select the base address of the UART.
      //
      g_ulBase = g_ulUARTBase[ulPortNum];
  
      //
      // Enable the UART peripheral for use.
      //
      MAP_SysCtlPeripheralEnable(g_ulUARTPeriph[ulPortNum]);
  
      //
      // Configure the UART for 115200, n, 8, 1
      //
      MAP_UARTConfigSetExpClk(g_ulBase, ulSrcClock, ulBaud,
                              (UART_CONFIG_PAR_NONE | UART_CONFIG_STOP_ONE |
                               UART_CONFIG_WLEN_8));
  
  #ifdef UART_BUFFERED
      //
      // Set the UART to interrupt whenever the TX FIFO is almost empty or
      // when any character is received.
      //
      MAP_UARTFIFOLevelSet(g_ulBase, UART_FIFO_TX1_8, UART_FIFO_RX1_8);
  
      //
      // Flush both the buffers.
      //
      UARTFlushRx();
      UARTFlushTx(true);
  
      //
      // Remember which interrupt we are dealing with.
      //
      g_ulPortNum = ulPortNum;
  
      //
      // 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(g_ulBase, 0xFFFFFFFF);
      MAP_UARTIntEnable(g_ulBase, UART_INT_RX | UART_INT_RT);
      MAP_IntEnable(g_ulUARTInt[ulPortNum]);
  #endif
  
      //
      // Enable the UART operation.
      //
      MAP_UARTEnable(g_ulBase);
  }
  
  //*****************************************************************************
  //
  //! Initializes the UART console.
  //!
  //! \param ulPortNum is the number of UART port to use for the serial console
  //! (0-2)
  //!
  //! This function will initialize the specified serial port to be used as a
  //! serial console.  The serial parameters will be set to 115200, 8-N-1.
  //! An application wishing to use a different baud rate may call
  //! UARTStdioInitExpClk() instead of this function.
  //!
  //! This function or UARTStdioInitExpClk() must be called prior to using any
  //! of the other UART console functions: UARTprintf() or UARTgets().  In order
  //! for this function to work correctly, SysCtlClockSet() must be called prior
  //! to calling this function.
  //!
  //! It is assumed that the caller has previously configured the relevant UART
  //! pins for operation as a UART rather than as GPIOs.
  //!
  //! \return None.
  //
  //*****************************************************************************
  void
  UARTStdioInit(unsigned long ulPortNum)
  {
      //
      // Pass this call on to the version of the function allowing the baud rate
      // to be specified.
      //
      UARTStdioConfig(ulPortNum, 115200, MAP_SysCtlClockGet());
  }
  
  //*****************************************************************************
  //
  //! Initializes the UART console and allows the baud rate to be selected.
  //!
  //! \param ulPortNum is the number of UART port to use for the serial console
  //! (0-2)
  //! \param ulBaud is the bit rate that the UART is to be configured to use.
  //!
  //! This function will initialize the specified serial port to be used as a
  //! serial console.  The serial parameters will be set to 8-N-1 and the bit
  //! rate set according to the value of the \e ulBaud parameter.
  //!
  //! This function or UARTStdioInit() must be called prior to using any of the
  //! other UART console functions: UARTprintf() or UARTgets().  In order for
  //! this function to work correctly, SysCtlClockSet() must be called prior to
  //! calling this function.  An application wishing to use 115,200 baud may call
  //! UARTStdioInit() instead of this function but should not call both
  //! functions.
  //!
  //! It is assumed that the caller has previously configured the relevant UART
  //! pins for operation as a UART rather than as GPIOs.
  //!
  //! \return None.
  //
  //*****************************************************************************
  void
  UARTStdioInitExpClk(unsigned long ulPortNum, unsigned long ulBaud)
  {
      UARTStdioConfig(ulPortNum, ulBaud, MAP_SysCtlClockGet());
  }
  
  //*****************************************************************************
  //
  //! Writes a string of characters to the UART output.
  //!
  //! \param pcBuf points to a buffer containing the string to transmit.
  //! \param ulLen 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 ulLen 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 ulLen 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
  UARTwrite(const char *pcBuf, unsigned long ulLen)
  {
  #ifdef UART_BUFFERED
      unsigned int uIdx;
  
      //
      // Check for valid arguments.
      //
      ASSERT(pcBuf != 0);
      ASSERT(g_ulBase != 0);
  
      //
      // Send the characters
      //
      for(uIdx = 0; uIdx < ulLen; 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_ulUARTTxWriteIndex] = '\r';
                  ADVANCE_TX_BUFFER_INDEX(g_ulUARTTxWriteIndex);
              }
              else
              {
                  //
                  // Buffer is full - discard remaining characters and return.
                  //
                  break;
              }
          }
  
          //
          // Send the character to the UART output.
          //
          if(!TX_BUFFER_FULL)
          {
              g_pcUARTTxBuffer[g_ulUARTTxWriteIndex] = pcBuf[uIdx];
              ADVANCE_TX_BUFFER_INDEX(g_ulUARTTxWriteIndex);
          }
          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)
      {
          UARTPrimeTransmit(g_ulBase);
          MAP_UARTIntEnable(g_ulBase, UART_INT_TX);
      }
  
      //
      // Return the number of characters written.
      //
      return(uIdx);
  #else
      unsigned int uIdx;
  
      //
      // Check for valid UART base address, and valid arguments.
      //
      ASSERT(g_ulBase != 0);
      ASSERT(pcBuf != 0);
  
      //
      // Send the characters
      //
      for(uIdx = 0; uIdx < ulLen; 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')
          {
              MAP_UARTCharPut(g_ulBase, '\r');
          }
  
          //
          // Send the character to the UART output.
          //
          MAP_UARTCharPut(g_ulBase, pcBuf[uIdx]);
      }
  
      //
      // Return the number of characters written.
      //
      return(uIdx);
  #endif
  }
  
  //*****************************************************************************
  //
  //! 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 ulLen 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
  UARTgets(char *pcBuf, unsigned long ulLen)
  {
  #ifdef UART_BUFFERED
      unsigned long ulCount = 0;
      char cChar;
  
      //
      // Check the arguments.
      //
      ASSERT(pcBuf != 0);
      ASSERT(ulLen != 0);
      ASSERT(g_ulBase != 0);
  
      //
      // Adjust the length back by 1 to leave space for the trailing
      // null terminator.
      //
      ulLen--;
  
      //
      // 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_ulUARTRxReadIndex];
              ADVANCE_RX_BUFFER_INDEX(g_ulUARTRxReadIndex);
  
              //
              // 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(ulCount < ulLen)
              {
                  //
                  // Store the character in the caller supplied buffer.
                  //
                  pcBuf[ulCount] = cChar;
  
                  //
                  // Increment the count of characters received.
                  //
                  ulCount++;
              }
          }
      }
  
      //
      // Add a null termination to the string.
      //
      pcBuf[ulCount] = 0;
  
      //
      // Return the count of chars in the buffer, not counting the trailing 0.
      //
      return(ulCount);
  #else
      unsigned long ulCount = 0;
      char cChar;
      static char bLastWasCR = 0;
  
      //
      // Check the arguments.
      //
      ASSERT(pcBuf != 0);
      ASSERT(ulLen != 0);
      ASSERT(g_ulBase != 0);
  
      //
      // Adjust the length back by 1 to leave space for the trailing
      // null terminator.
      //
      ulLen--;
  
      //
      // Process characters until a newline is received.
      //
      while(1)
      {
          //
          // Read the next character from the console.
          //
          cChar = MAP_UARTCharGet(g_ulBase);
  
          //
          // See if the backspace key was pressed.
          //
          if(cChar == '\b')
          {
              //
              // If there are any characters already in the buffer, then delete
              // the last.
              //
              if(ulCount)
              {
                  //
                  // Rub out the previous character.
                  //
                  UARTwrite("\b \b", 3);
  
                  //
                  // Decrement the number of characters in the buffer.
                  //
                  ulCount--;
              }
  
              //
              // Skip ahead to read the next character.
              //
              continue;
          }
  
          //
          // If this character is LF and last was CR, then just gobble up the
          // character because the EOL processing was taken care of with the CR.
          //
          if((cChar == '\n') && bLastWasCR)
          {
              bLastWasCR = 0;
              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 a LF which
              // should be paired with the CR.  So remember that a CR was
              // received.
              //
              if(cChar == '\r')
              {
                  bLastWasCR = 1;
              }
  
              //
              // 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(ulCount < ulLen)
          {
              //
              // Store the character in the caller supplied buffer.
              //
              pcBuf[ulCount] = cChar;
  
              //
              // Increment the count of characters received.
              //
              ulCount++;
  
              //
              // Reflect the character back to the user.
              //
              MAP_UARTCharPut(g_ulBase, cChar);
          }
      }
  
      //
      // Add a null termination to the string.
      //
      pcBuf[ulCount] = 0;
  
      //
      // Send a CRLF pair to the terminal to end the line.
      //
      UARTwrite("\r\n", 2);
  
      //
      // Return the count of chars in the buffer, not counting the trailing 0.
      //
      return(ulCount);
  #endif
  }
  
  //*****************************************************************************
  //
  //! 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
  UARTgetc(void)
  {
  #ifdef UART_BUFFERED
      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_ulUARTRxReadIndex];
      ADVANCE_RX_BUFFER_INDEX(g_ulUARTRxReadIndex);
  
      //
      // Return the character to the caller.
      //
      return(cChar);
  #else
      //
      // Block until a character is received by the UART then return it to
      // the caller.
      //
      return(MAP_UARTCharGet(g_ulBase));
  #endif
  }
  
  //*****************************************************************************
  //
  //! A simple UART based printf function supporting \%c, \%d, \%p, \%s, \%u,
  //! \%x, and \%X.
  //!
  //! \param pcString is the format string.
  //! \param ... are the optional arguments, which depend on the contents of the
  //! format string.
  //!
  //! This function is very similar to the C library <tt>fprintf()</tt> function.
  //! All of its output will be sent to the UART.  Only the following formatting
  //! characters are supported:
  //!
  //! - \%c to print a character
  //! - \%d or \%i to print a decimal value
  //! - \%s to print a string
  //! - \%u to print an unsigned decimal value
  //! - \%x to print a hexadecimal value using lower case letters
  //! - \%X to print a hexadecimal value using lower case letters (not upper case
  //! letters as would typically be used)
  //! - \%p to print a pointer as a hexadecimal value
  //! - \%\% to print out a \% character
  //!
  //! For \%s, \%d, \%i, \%u, \%p, \%x, and \%X, an optional number may reside
  //! between the \% and the format character, which specifies the minimum number
  //! of characters to use for that value; if preceded by a 0 then the extra
  //! characters will be filled with zeros instead of spaces.  For example,
  //! ``\%8d'' will use eight characters to print the decimal value with spaces
  //! added to reach eight; ``\%08d'' will use eight characters as well but will
  //! add zeroes instead of spaces.
  //!
  //! The type of the arguments after \e pcString must match the requirements of
  //! the format string.  For example, if an integer was passed where a string
  //! was expected, an error of some kind will most likely occur.
  //!
  //! \return None.
  //
  //*****************************************************************************
  void
  UARTprintf(const char *pcString, ...)
  {
      unsigned long ulIdx, ulValue, ulPos, ulCount, ulBase, ulNeg;
      char *pcStr, pcBuf[16], cFill;
      va_list vaArgP;
  
      //
      // Check the arguments.
      //
      ASSERT(pcString != 0);
  
      //
      // Start the varargs processing.
      //
      va_start(vaArgP, pcString);
  
      //
      // Loop while there are more characters in the string.
      //
      while(*pcString)
      {
          //
          // Find the first non-% character, or the end of the string.
          //
          for(ulIdx = 0; (pcString[ulIdx] != '%') && (pcString[ulIdx] != '\0');
              ulIdx++)
          {
          }
  
          //
          // Write this portion of the string.
          //
          UARTwrite(pcString, ulIdx);
  
          //
          // Skip the portion of the string that was written.
          //
          pcString += ulIdx;
  
          //
          // See if the next character is a %.
          //
          if(*pcString == '%')
          {
              //
              // Skip the %.
              //
              pcString++;
  
              //
              // Set the digit count to zero, and the fill character to space
              // (i.e. to the defaults).
              //
              ulCount = 0;
              cFill = ' ';
  
              //
              // It may be necessary to get back here to process more characters.
              // Goto's aren't pretty, but effective.  I feel extremely dirty for
              // using not one but two of the beasts.
              //
  again:
  
              //
              // Determine how to handle the next character.
              //
              switch(*pcString++)
              {
                  //
                  // Handle the digit characters.
                  //
                  case '0':
                  case '1':
                  case '2':
                  case '3':
                  case '4':
                  case '5':
                  case '6':
                  case '7':
                  case '8':
                  case '9':
                  {
                      //
                      // If this is a zero, and it is the first digit, then the
                      // fill character is a zero instead of a space.
                      //
                      if((pcString[-1] == '0') && (ulCount == 0))
                      {
                          cFill = '0';
                      }
  
                      //
                      // Update the digit count.
                      //
                      ulCount *= 10;
                      ulCount += pcString[-1] - '0';
  
                      //
                      // Get the next character.
                      //
                      goto again;
                  }
  
                  //
                  // Handle the %c command.
                  //
                  case 'c':
                  {
                      //
                      // Get the value from the varargs.
                      //
                      ulValue = va_arg(vaArgP, unsigned long);
  
                      //
                      // Print out the character.
                      //
                      UARTwrite((char *)&ulValue, 1);
  
                      //
                      // This command has been handled.
                      //
                      break;
                  }
  
                  //
                  // Handle the %d and %i commands.
                  //
                  case 'd':
                  case 'i':
                  {
                      //
                      // Get the value from the varargs.
                      //
                      ulValue = va_arg(vaArgP, unsigned long);
  
                      //
                      // Reset the buffer position.
                      //
                      ulPos = 0;
  
                      //
                      // If the value is negative, make it positive and indicate
                      // that a minus sign is needed.
                      //
                      if((long)ulValue < 0)
                      {
                          //
                          // Make the value positive.
                          //
                          ulValue = -(long)ulValue;
  
                          //
                          // Indicate that the value is negative.
                          //
                          ulNeg = 1;
                      }
                      else
                      {
                          //
                          // Indicate that the value is positive so that a minus
                          // sign isn't inserted.
                          //
                          ulNeg = 0;
                      }
  
                      //
                      // Set the base to 10.
                      //
                      ulBase = 10;
  
                      //
                      // Convert the value to ASCII.
                      //
                      goto convert;
                  }
  
                  //
                  // Handle the %s command.
                  //
                  case 's':
                  {
                      //
                      // Get the string pointer from the varargs.
                      //
                      pcStr = va_arg(vaArgP, char *);
  
                      //
                      // Determine the length of the string.
                      //
                      for(ulIdx = 0; pcStr[ulIdx] != '\0'; ulIdx++)
                      {
                      }
  
                      //
                      // Write the string.
                      //
                      UARTwrite(pcStr, ulIdx);
  
                      //
                      // Write any required padding spaces
                      //
                      if(ulCount > ulIdx)
                      {
                          ulCount -= ulIdx;
                          while(ulCount--)
                          {
                              UARTwrite(" ", 1);
                          }
                      }
                      //
                      // This command has been handled.
                      //
                      break;
                  }
  
                  //
                  // Handle the %u command.
                  //
                  case 'u':
                  {
                      //
                      // Get the value from the varargs.
                      //
                      ulValue = va_arg(vaArgP, unsigned long);
  
                      //
                      // Reset the buffer position.
                      //
                      ulPos = 0;
  
                      //
                      // Set the base to 10.
                      //
                      ulBase = 10;
  
                      //
                      // Indicate that the value is positive so that a minus sign
                      // isn't inserted.
                      //
                      ulNeg = 0;
  
                      //
                      // Convert the value to ASCII.
                      //
                      goto convert;
                  }
  
                  //
                  // Handle the %x and %X commands.  Note that they are treated
                  // identically; i.e. %X will use lower case letters for a-f
                  // instead of the upper case letters is should use.  We also
                  // alias %p to %x.
                  //
                  case 'x':
                  case 'X':
                  case 'p':
                  {
                      //
                      // Get the value from the varargs.
                      //
                      ulValue = va_arg(vaArgP, unsigned long);
  
                      //
                      // Reset the buffer position.
                      //
                      ulPos = 0;
  
                      //
                      // Set the base to 16.
                      //
                      ulBase = 16;
  
                      //
                      // Indicate that the value is positive so that a minus sign
                      // isn't inserted.
                      //
                      ulNeg = 0;
  
                      //
                      // Determine the number of digits in the string version of
                      // the value.
                      //
  convert:
                      for(ulIdx = 1;
                          (((ulIdx * ulBase) <= ulValue) &&
                           (((ulIdx * ulBase) / ulBase) == ulIdx));
                          ulIdx *= ulBase, ulCount--)
                      {
                      }
  
                      //
                      // If the value is negative, reduce the count of padding
                      // characters needed.
                      //
                      if(ulNeg)
                      {
                          ulCount--;
                      }
  
                      //
                      // If the value is negative and the value is padded with
                      // zeros, then place the minus sign before the padding.
                      //
                      if(ulNeg && (cFill == '0'))
                      {
                          //
                          // Place the minus sign in the output buffer.
                          //
                          pcBuf[ulPos++] = '-';
  
                          //
                          // The minus sign has been placed, so turn off the
                          // negative flag.
                          //
                          ulNeg = 0;
                      }
  
                      //
                      // Provide additional padding at the beginning of the
                      // string conversion if needed.
                      //
                      if((ulCount > 1) && (ulCount < 16))
                      {
                          for(ulCount--; ulCount; ulCount--)
                          {
                              pcBuf[ulPos++] = cFill;
                          }
                      }
  
                      //
                      // If the value is negative, then place the minus sign
                      // before the number.
                      //
                      if(ulNeg)
                      {
                          //
                          // Place the minus sign in the output buffer.
                          //
                          pcBuf[ulPos++] = '-';
                      }
  
                      //
                      // Convert the value into a string.
                      //
                      for(; ulIdx; ulIdx /= ulBase)
                      {
                          pcBuf[ulPos++] = g_pcHex[(ulValue / ulIdx) % ulBase];
                      }
  
                      //
                      // Write the string.
                      //
                      UARTwrite(pcBuf, ulPos);
  
                      //
                      // This command has been handled.
                      //
                      break;
                  }
  
                  //
                  // Handle the %% command.
                  //
                  case '%':
                  {
                      //
                      // Simply write a single %.
                      //
                      UARTwrite(pcString - 1, 1);
  
                      //
                      // This command has been handled.
                      //
                      break;
                  }
  
                  //
                  // Handle all other commands.
                  //
                  default:
                  {
                      //
                      // Indicate an error.
                      //
                      UARTwrite("ERROR", 5);
  
                      //
                      // This command has been handled.
                      //
                      break;
                  }
              }
          }
      }
  
      //
      // End the varargs processing.
      //
      va_end(vaArgP);
  }
  
  //*****************************************************************************
  //
  //! 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.
  //
  //*****************************************************************************
  #if defined(UART_BUFFERED) || defined(DOXYGEN)
  int
  UARTRxBytesAvail(void)
  {
      return(RX_BUFFER_USED);
  }
  #endif
  
  #if defined(UART_BUFFERED) || defined(DOXYGEN)
  //*****************************************************************************
  //
  //! 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
  UARTTxBytesFree(void)
  {
      return(TX_BUFFER_FREE);
  }
  #endif
  
  //*****************************************************************************
  //
  //! 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.
  //
  //*****************************************************************************
  #if defined(UART_BUFFERED) || defined(DOXYGEN)
  int
  UARTPeek(unsigned char ucChar)
  {
      int iCount;
      int iAvail;
      unsigned long ulReadIndex;
  
      //
      // How many characters are there in the receive buffer?
      //
      iAvail = (int)RX_BUFFER_USED;
      ulReadIndex = g_ulUARTRxReadIndex;
  
      //
      // Check all the unread characters looking for the one passed.
      //
      for(iCount = 0; iCount < iAvail; iCount++)
      {
          if(g_pcUARTRxBuffer[ulReadIndex] == 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(ulReadIndex);
          }
      }
  
      //
      // If we drop out of the loop, we didn't find the character in the receive
      // buffer.
      //
      return(-1);
  }
  #endif
  
  //*****************************************************************************
  //
  //! 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.
  //
  //*****************************************************************************
  #if defined(UART_BUFFERED) || defined(DOXYGEN)
  void
  UARTFlushRx(void)
  {
      unsigned long ulInt;
  
      //
      // Temporarily turn off interrupts.
      //
      ulInt = MAP_IntMasterDisable();
  
      //
      // Flush the receive buffer.
      //
      g_ulUARTRxReadIndex = 0;
      g_ulUARTRxWriteIndex = 0;
  
      //
      // If interrupts were enabled when we turned them off, turn them
      // back on again.
      //
      if(!ulInt)
      {
          MAP_IntMasterEnable();
      }
  }
  #endif
  
  //*****************************************************************************
  //
  //! 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
  //! UARTprintf() that is waiting to be transmitted.  On return, the transmit
  //! buffer will be empty.
  //!
  //! \return None.
  //
  //*****************************************************************************
  #if defined(UART_BUFFERED) || defined(DOXYGEN)
  void
  UARTFlushTx(tBoolean bDiscard)
  {
      unsigned long ulInt;
  
      //
      // Should the remaining data be discarded or transmitted?
      //
      if(bDiscard)
      {
          //
          // The remaining data should be discarded, so temporarily turn off
          // interrupts.
          //
          ulInt = MAP_IntMasterDisable();
  
          //
          // Flush the transmit buffer.
          //
          g_ulUARTTxReadIndex = 0;
          g_ulUARTTxWriteIndex = 0;
  
          //
          // If interrupts were enabled when we turned them off, turn them
          // back on again.
          //
          if(!ulInt)
          {
              MAP_IntMasterEnable();
          }
      }
      else
      {
          //
          // Wait for all remaining data to be transmitted before returning.
          //
          while(!TX_BUFFER_EMPTY)
          {
          }
      }
  }
  #endif
  
  //*****************************************************************************
  //
  //! 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.
  //
  //*****************************************************************************
  #if defined(UART_BUFFERED) || defined(DOXYGEN)
  void
  UARTEchoSet(tBoolean bEnable)
  {
      g_bDisableEcho = !bEnable;
  }
  #endif
  
  //*****************************************************************************
  //
  //! 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.
  //
  //*****************************************************************************
  #if defined(UART_BUFFERED) || defined(DOXYGEN)
  void
  UARTStdioIntHandler(void)
  {
      unsigned long ulInts;
      char cChar;
      long lChar;
      static tBoolean bLastWasCR = false;
  
      //
      // Get and clear the current interrupt source(s)
      //
      ulInts = MAP_UARTIntStatus(g_ulBase, true);
      MAP_UARTIntClear(g_ulBase, ulInts);
  
      //
      // Are we being interrupted because the TX FIFO has space available?
      //
      if(ulInts & UART_INT_TX)
      {
          //
          // Move as many bytes as we can into the transmit FIFO.
          //
          UARTPrimeTransmit(g_ulBase);
  
          //
          // If the output buffer is empty, turn off the transmit interrupt.
          //
          if(TX_BUFFER_EMPTY)
          {
              MAP_UARTIntDisable(g_ulBase, UART_INT_TX);
          }
      }
  
      //
      // Are we being interrupted due to a received character?
      //
      if(ulInts & (UART_INT_RX | UART_INT_RT))
      {
          //
          // Get all the available characters from the UART.
          //
          while(MAP_UARTCharsAvail(g_ulBase))
          {
              //
              // Read a character
              //
              lChar = MAP_UARTCharGetNonBlocking(g_ulBase);
              cChar = (unsigned char)(lChar & 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_ulUARTRxWriteIndex == 0)
                          {
                              g_ulUARTRxWriteIndex = UART_RX_BUFFER_SIZE - 1;
                          }
                          else
                          {
                              g_ulUARTRxWriteIndex--;
                          }
                      }
  
                      //
                      // 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_ulUARTRxWriteIndex] =
                      (unsigned char)(lChar & 0xFF);
                  ADVANCE_RX_BUFFER_INDEX(g_ulUARTRxWriteIndex);
  
                  //
                  // If echo is enabled, write the character to the transmit
                  // buffer so that the user gets some immediate feedback.
                  //
                  if(!g_bDisableEcho)
                  {
                      UARTwrite(&cChar, 1);
                  }
              }
          }
  
          //
          // If we wrote anything to the transmit buffer, make sure it actually
          // gets transmitted.
          //
          UARTPrimeTransmit(g_ulBase);
          MAP_UARTIntEnable(g_ulBase, UART_INT_TX);
      }
  }
  #endif
  
  //*****************************************************************************
  //
  // Close the Doxygen group.
  //! @}
  //
  //*****************************************************************************
  