//***************************************************************************** // // 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 #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 fprintf() 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. //! @} // //*****************************************************************************