diff options
| author | Yuval Adam <yuv.adm@gmail.com> | 2012-10-29 23:06:01 +0200 |
|---|---|---|
| committer | Yuval Adam <yuv.adm@gmail.com> | 2012-10-29 23:06:01 +0200 |
| commit | 4ba8614c006f9828f0796c140bc3e13c9e67938c (patch) | |
| tree | ad204651c733250d27d20fce8820f9747c43c883 /utils/uartstdio.c | |
| parent | e018ceebed74b8223482bc9d1ed0b31c938381da (diff) | |
Added utils
Diffstat (limited to 'utils/uartstdio.c')
| -rw-r--r-- | utils/uartstdio.c | 1732 |
1 files changed, 1732 insertions, 0 deletions
diff --git a/utils/uartstdio.c b/utils/uartstdio.c new file mode 100644 index 0000000..ff2013f --- /dev/null +++ b/utils/uartstdio.c @@ -0,0 +1,1732 @@ +//*****************************************************************************
+//
+// uartstdio.c - Utility driver to provide simple UART console functions.
+//
+// Copyright (c) 2007-2012 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 9453 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.
+//! @}
+//
+//*****************************************************************************
|
