//########################################################################### // // FILE: uartstdio.c // // TITLE: Utility driver to provide simple UART console functions. // //########################################################################### // $TI Release: F2837xD Support Library v3.05.00.00 $ // $Release Date: Tue Jun 26 03:15:23 CDT 2018 $ // $Copyright: // Copyright (C) 2013-2018 Texas Instruments Incorporated - http://www.ti.com/ // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions // are met: // // Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // // Redistributions in binary form must reproduce the above copyright // notice, this list of conditions and the following disclaimer in the // documentation and/or other materials provided with the // distribution. // // Neither the name of Texas Instruments Incorporated nor the names of // its contributors may be used to endorse or promote products derived // from this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // $ //########################################################################### // // Included Files // #include #include #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 bool g_bDisableEcho; // // Output ring buffer. Buffer is full if g_ui32UARTTxReadIndex is one ahead of // g_ui32UARTTxWriteIndex. Buffer is empty if the two indices are the same. // static unsigned char g_pcUARTTxBuffer[UART_TX_BUFFER_SIZE]; static volatile uint32_t g_ui32UARTTxWriteIndex = 0; static volatile uint32_t g_ui32UARTTxReadIndex = 0; // // Input ring buffer. Buffer is full if g_ui32UARTTxReadIndex is one ahead of // g_ui32UARTTxWriteIndex. Buffer is empty if the two indices are the same. // static unsigned char g_pcUARTRxBuffer[UART_RX_BUFFER_SIZE]; static volatile uint32_t g_ui32UARTRxWriteIndex = 0; static volatile uint32_t g_ui32UARTRxReadIndex = 0; // // Macros to determine number of free and used bytes in the transmit buffer. // #define TX_BUFFER_USED (GetBufferCount(&g_ui32UARTTxReadIndex, \ &g_ui32UARTTxWriteIndex, \ UART_TX_BUFFER_SIZE)) #define TX_BUFFER_FREE (UART_TX_BUFFER_SIZE - TX_BUFFER_USED) #define TX_BUFFER_EMPTY (IsBufferEmpty(&g_ui32UARTTxReadIndex, \ &g_ui32UARTTxWriteIndex)) #define TX_BUFFER_FULL (IsBufferFull(&g_ui32UARTTxReadIndex, \ &g_ui32UARTTxWriteIndex, \ 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_ui32UARTRxReadIndex, \ &g_ui32UARTRxWriteIndex, \ UART_RX_BUFFER_SIZE)) #define RX_BUFFER_FREE (UART_RX_BUFFER_SIZE - RX_BUFFER_USED) #define RX_BUFFER_EMPTY (IsBufferEmpty(&g_ui32UARTRxReadIndex, \ &g_ui32UARTRxWriteIndex)) #define RX_BUFFER_FULL (IsBufferFull(&g_ui32UARTRxReadIndex, \ &g_ui32UARTRxWriteIndex, \ 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 uint32_t g_ui32Base = 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 uint32_t g_ui32UARTBase[4] = { UARTA_BASE, UARTB_BASE, UARTC_BASE, UARTD_BASE }; #ifdef UART_BUFFERED // // The list of possible interrupts for the console UART. // static const uint32_t g_ui32UARTInt[3] = { INT_UART0, INT_UART1, INT_UART2 }; // // The port number in use. // static uint32_t g_ui32PortNum; #endif // // The list of UART peripherals. // static const uint32_t g_ui32UARTPeriph[3] = { SYSCTL_PERIPH_SCI1, SYSCTL_PERIPH_SCI2, SYSCTL_PERIPH_SCI3 }; //***************************************************************************** // //! Determines whether the ring buffer whose pointers and size are provided //! is full or not. //! //! \param pui32Read points to the read index for the buffer. //! \param pui32Write points to the write index for the buffer. //! \param ui32Size is the size of the buffer in bytes. //! //! This function is used to determine whether or not a given ring buffer is //! full. The structure of the code is specifically to ensure that we do not //! see warnings from the compiler related to the order of volatile accesses //! being undefined. //! //! \return Returns \b true if the buffer is full or \b false otherwise. // //***************************************************************************** #ifdef UART_BUFFERED static bool IsBufferFull(volatile uint32_t *pui32Read, volatile uint32_t *pui32Write, uint32_t ui32Size) { uint32_t ui32Write; uint32_t ui32Read; ui32Write = *pui32Write; ui32Read = *pui32Read; return((((ui32Write + 1) % ui32Size) == ui32Read) ? true : false); } #endif //***************************************************************************** // //! Determines whether the ring buffer whose pointers and size are provided //! is empty or not. //! //! \param pui32Read points to the read index for the buffer. //! \param pui32Write points to the write index for the buffer. //! //! This function is used to determine whether or not a given ring buffer is //! empty. The structure of the code is specifically to ensure that we do not //! see warnings from the compiler related to the order of volatile accesses //! being undefined. //! //! \return Returns \b true if the buffer is empty or \b false otherwise. // //***************************************************************************** #ifdef UART_BUFFERED static bool IsBufferEmpty(volatile uint32_t *pui32Read, volatile uint32_t *pui32Write) { uint32_t ui32Write; uint32_t ui32Read; ui32Write = *pui32Write; ui32Read = *pui32Read; return((ui32Write == ui32Read) ? true : false); } #endif //***************************************************************************** // //! Determines the number of bytes of data contained in a ring buffer. //! //! \param pui32Read points to the read index for the buffer. //! \param pui32Write points to the write index for the buffer. //! \param ui32Size is the size of the buffer in bytes. //! //! This function is used to determine how many bytes of data a given ring //! buffer currently contains. The structure of the code is specifically to //! ensure that we do not see warnings from the compiler related to the order //! of volatile accesses being undefined. //! //! \return Returns the number of bytes of data currently in the buffer. // //***************************************************************************** #ifdef UART_BUFFERED static uint32_t GetBufferCount(volatile uint32_t *pui32Read, volatile uint32_t *pui32Write, uint32_t ui32Size) { uint32_t ui32Write; uint32_t ui32Read; ui32Write = *pui32Write; ui32Read = *pui32Read; return((ui32Write >= ui32Read) ? (ui32Write - ui32Read) : (ui32Size - (ui32Read - ui32Write))); } #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(uint32_t ui32Base) { // // Do we have any data to transmit? // if(!TX_BUFFER_EMPTY) { // // Disable the UART interrupt. If we don't do this there is a race // condition which can cause the read index to be corrupted. // MAP_IntDisable(g_ui32UARTInt[g_ui32PortNum]); // // Yes - take some characters out of the transmit buffer and feed // them to the UART transmit FIFO. // while(MAP_UARTSpaceAvail(ui32Base) && !TX_BUFFER_EMPTY) { MAP_UARTCharPutNonBlocking(ui32Base, g_pcUARTTxBuffer[g_ui32UARTTxReadIndex]); ADVANCE_TX_BUFFER_INDEX(g_ui32UARTTxReadIndex); } // // Reenable the UART interrupt. // MAP_IntEnable(g_ui32UARTInt[g_ui32PortNum]); } } #endif //***************************************************************************** // //! Configures the UART console. //! //! \param ui32PortNum is the number of UART port to use for the serial console //! (0-2) //! \param ui32Baud is the bit rate that the UART is to be configured to use. //! \param ui32SrcClock is the frequency of the source clock for the UART //! module. //! //! This function will configure the specified serial port to be used as a //! serial console. The serial parameters are set to the baud rate //! specified by the \e ui32Baud parameter and use 8 bit, no parity, and 1 stop //! bit. //! //! This function must be called prior to using any of the other UART console //! functions: 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(uint32_t ui32PortNum, uint32_t ui32Baud, uint32_t ui32SrcClock) { // // Check the arguments. // ASSERT((ui32PortNum == 0) || (ui32PortNum == 1) || (ui32PortNum == 2)); #ifdef UART_BUFFERED // // In buffered mode, we only allow a single instance to be opened. // ASSERT(g_ui32Base == 0); #endif // // Check to make sure the UART peripheral is present. // if(!MAP_SysCtlPeripheralPresent(g_ui32UARTPeriph[ui32PortNum])) { return; } // // Select the base address of the UART. // g_ui32Base = g_ui32UARTBase[ui32PortNum]; // // Enable the UART peripheral for use. // MAP_SysCtlPeripheralEnable(g_ui32UARTPeriph[ui32PortNum]); // // Configure the UART for 115200, n, 8, 1 // MAP_UARTConfigSetExpClk(g_ui32Base, ui32SrcClock, ui32Baud, (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_ui32Base, UART_FIFO_TX1_8, UART_FIFO_RX1_8); // // Flush both the buffers. // UARTFlushRx(); UARTFlushTx(true); // // Remember which interrupt we are dealing with. // g_ui32PortNum = ui32PortNum; // // 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_ui32Base, 0xFFFFFFFF); MAP_UARTIntEnable(g_ui32Base, UART_INT_RX | UART_INT_RT); MAP_IntEnable(g_ui32UARTInt[ui32PortNum]); #endif // // Enable the UART operation. // MAP_UARTEnable(g_ui32Base); } //***************************************************************************** // //! Writes a string of characters to the UART output. //! //! \param pcBuf points to a buffer containing the string to transmit. //! \param ui32Len is the length of the string to transmit. //! //! This function will transmit the string to the UART output. The number of //! characters transmitted is determined by the \e ui32Len parameter. This //! function does no interpretation or translation of any characters. Since //! the output is sent to a UART, any LF (/n) characters encountered will be //! replaced with a CRLF pair. //! //! Besides using the \e ui32Len parameter to stop transmitting the string, if //! a null character (0) is encountered, then no more characters will be //! transmitted and the function will return. //! //! In non-buffered mode, this function is blocking and will not return until //! all the characters have been written to the output FIFO. In buffered mode, //! the characters are written to the UART transmit buffer and the call returns //! immediately. If insufficient space remains in the transmit buffer, //! additional characters are discarded. //! //! \return Returns the count of characters written. // //***************************************************************************** int UARTwrite(const char *pcBuf, uint32_t ui32Len) { #ifdef UART_BUFFERED unsigned int uIdx; // // Check for valid arguments. // ASSERT(pcBuf != 0); ASSERT(g_ui32Base != 0); // // Send the characters // for(uIdx = 0; uIdx < ui32Len; uIdx++) { // // If the character to the UART is \n, then add a \r before it so that // \n is translated to \n\r in the output. // if(pcBuf[uIdx] == '\n') { if(!TX_BUFFER_FULL) { g_pcUARTTxBuffer[g_ui32UARTTxWriteIndex] = '\r'; ADVANCE_TX_BUFFER_INDEX(g_ui32UARTTxWriteIndex); } else { // // Buffer is full - discard remaining characters and return. // break; } } // // Send the character to the UART output. // if(!TX_BUFFER_FULL) { g_pcUARTTxBuffer[g_ui32UARTTxWriteIndex] = pcBuf[uIdx]; ADVANCE_TX_BUFFER_INDEX(g_ui32UARTTxWriteIndex); } else { // // Buffer is full - discard remaining characters and return. // break; } } // // If we have anything in the buffer, make sure that the UART is set // up to transmit it. // if(!TX_BUFFER_EMPTY) { UARTPrimeTransmit(g_ui32Base); MAP_UARTIntEnable(g_ui32Base, 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_ui32Base != 0); ASSERT(pcBuf != 0); // // Send the characters // for(uIdx = 0; uIdx < ui32Len; uIdx++) { // // If the character to the UART is \n, then add a \r before it so that // \n is translated to \n\r in the output. // if(pcBuf[uIdx] == '\n') { MAP_UARTCharPut(g_ui32Base, '\r'); } // // Send the character to the UART output. // MAP_UARTCharPut(g_ui32Base, 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 ui32Len is the length of the buffer for storage of the string, //! including the trailing 0. //! //! This function will receive a string from the UART input and store the //! characters in the buffer pointed to by \e pcBuf. The characters will //! continue to be stored until a termination character is received. The //! termination characters are CR, LF, or ESC. A CRLF pair is treated as a //! single termination character. The termination characters are not stored in //! the string. The string will be terminated with a 0 and the function will //! return. //! //! In both buffered and unbuffered modes, this function will block until //! a termination character is received. If non-blocking operation is required //! in buffered mode, a call to UARTPeek() may be made to determine whether //! a termination character already exists in the receive buffer prior to //! calling UARTgets(). //! //! Since the string will be null terminated, the user must ensure that the //! buffer is sized to allow for the additional null character. //! //! \return Returns the count of characters that were stored, not including //! the trailing 0. // //***************************************************************************** int UARTgets(char *pcBuf, uint32_t ui32Len) { #ifdef UART_BUFFERED uint32_t ui32Count = 0; int8_t cChar; // // Check the arguments. // ASSERT(pcBuf != 0); ASSERT(ui32Len != 0); ASSERT(g_ui32Base != 0); // // Adjust the length back by 1 to leave space for the trailing // null terminator. // ui32Len--; // // Process characters until a newline is received. // while(1) { // // Read the next character from the receive buffer. // if(!RX_BUFFER_EMPTY) { cChar = g_pcUARTRxBuffer[g_ui32UARTRxReadIndex]; ADVANCE_RX_BUFFER_INDEX(g_ui32UARTRxReadIndex); // // See if a newline or escape character was received. // if((cChar == '\r') || (cChar == '\n') || (cChar == 0x1b)) { // // Stop processing the input and end the line. // break; } // // Process the received character as long as we are not at the end // of the buffer. If the end of the buffer has been reached then // all additional characters are ignored until a newline is // received. // if(ui32Count < ui32Len) { // // Store the character in the caller supplied buffer. // pcBuf[ui32Count] = cChar; // // Increment the count of characters received. // ui32Count++; } } } // // Add a null termination to the string. // pcBuf[ui32Count] = 0; // // Return the count of int8_ts in the buffer, not counting the trailing 0. // return(ui32Count); #else uint32_t ui32Count = 0; int8_t cChar; static int8_t bLastWasCR = 0; // // Check the arguments. // ASSERT(pcBuf != 0); ASSERT(ui32Len != 0); ASSERT(g_ui32Base != 0); // // Adjust the length back by 1 to leave space for the trailing // null terminator. // ui32Len--; // // Process characters until a newline is received. // while(1) { // // Read the next character from the console. // cChar = MAP_UARTCharGet(g_ui32Base); // // See if the backspace key was pressed. // if(cChar == '\b') { // // If there are any characters already in the buffer, then delete // the last. // if(ui32Count) { // // Rub out the previous character. // UARTwrite("\b \b", 3); // // Decrement the number of characters in the buffer. // ui32Count--; } // // 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(ui32Count < ui32Len) { // // Store the character in the caller supplied buffer. // pcBuf[ui32Count] = cChar; // // Increment the count of characters received. // ui32Count++; // // Reflect the character back to the user. // MAP_UARTCharPut(g_ui32Base, cChar); } } // // Add a null termination to the string. // pcBuf[ui32Count] = 0; // // Send a CRLF pair to the terminal to end the line. // UARTwrite("\r\n", 2); // // Return the count of int8_ts in the buffer, not counting the trailing 0. // return(ui32Count); #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_ui32UARTRxReadIndex]; ADVANCE_RX_BUFFER_INDEX(g_ui32UARTRxReadIndex); // // 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_ui32Base)); #endif } //***************************************************************************** // //! A simple UART based vprintf function supporting \%c, \%d, \%p, \%s, \%u, //! \%x, and \%X. //! //! \param pcString is the format string. //! \param vaArgP is a variable argument list pointer whose content will depend //! upon the format string passed in \e pcString. //! //! This function is very similar to the C library vprintf() 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 //! - \%l to print a long 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 in the variable arguments list 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 UARTvprintf(const char *pcString, va_list vaArgP) { uint32_t ui32Idx, ui32Value, ui32Pos, ui32Count, ui32Base, ui32Neg; char *pcStr, pcBuf[16], cFill; // // Check the arguments. // ASSERT(pcString != 0); // // Loop while there are more characters in the string. // while(*pcString) { // // Find the first non-% character, or the end of the string. // for(ui32Idx = 0; (pcString[ui32Idx] != '%') && (pcString[ui32Idx] != '\0'); ui32Idx++) { } // // Write this portion of the string. // UARTwrite(pcString, ui32Idx); // // Skip the portion of the string that was written. // pcString += ui32Idx; // // See if the next character is a %. // if(*pcString == '%') { // // Skip the %. // pcString++; // // Set the digit count to zero, and the fill character to space // (in other words, to the defaults). // ui32Count = 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') && (ui32Count == 0)) { cFill = '0'; } // // Update the digit count. // ui32Count *= 10; ui32Count += pcString[-1] - '0'; // // Get the next character. // goto again; } // // Handle the %c command. // case 'c': { // // Get the value from the varargs. // ui32Value = va_arg(vaArgP, uint32_t); // // Print out the character. // UARTwrite((char *)&ui32Value, 1); // // This command has been handled. // break; } // // Handle the %d and %i commands. // case 'd': case 'i': { // // Get the value from the varargs. // ui32Value = va_arg(vaArgP, uint16_t); // // Reset the buffer position. // ui32Pos = 0; // // If the value is negative, make it positive and indicate // that a minus sign is needed. // if((int32_t)ui32Value < 0) { // // Make the value positive. // ui32Value = -(int32_t)ui32Value; // // Indicate that the value is negative. // ui32Neg = 1; } else { // // Indicate that the value is positive so that a minus // sign isn't inserted. // ui32Neg = 0; } // // Set the base to 10. // ui32Base = 10; // // Convert the value to ASCII. // goto convert; } // // Handle the %l command. // case 'l': { // // Get the value from the varargs. // ui32Value = va_arg(vaArgP, uint32_t); // // Reset the buffer position. // ui32Pos = 0; // // If the value is negative, make it positive and indicate // that a minus sign is needed. // if((int32_t)ui32Value < 0) { // // Make the value positive. // ui32Value = -(int32_t)ui32Value; // // Indicate that the value is negative. // ui32Neg = 1; } else { // // Indicate that the value is positive so that a minus // sign isn't inserted. // ui32Neg = 0; } // // Set the base to 10. // ui32Base = 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(ui32Idx = 0; pcStr[ui32Idx] != '\0'; ui32Idx++) { } // // Write the string. // UARTwrite(pcStr, ui32Idx); // // Write any required padding spaces // if(ui32Count > ui32Idx) { ui32Count -= ui32Idx; while(ui32Count--) { UARTwrite(" ", 1); } } // // This command has been handled. // break; } // // Handle the %u command. // case 'u': { // // Get the value from the varargs. // ui32Value = va_arg(vaArgP, uint32_t); // // Reset the buffer position. // ui32Pos = 0; // // Set the base to 10. // ui32Base = 10; // // Indicate that the value is positive so that a minus sign // isn't inserted. // ui32Neg = 0; // // Convert the value to ASCII. // goto convert; } // // Handle the %x and %X commands. Note that they are treated // identically; in other words, %X will use lower case letters // for a-f instead of the upper case letters it should use. We // also alias %p to %x. // case 'x': case 'X': case 'p': { // // Get the value from the varargs. // ui32Value = va_arg(vaArgP, uint32_t); // // Reset the buffer position. // ui32Pos = 0; // // Set the base to 16. // ui32Base = 16; // // Indicate that the value is positive so that a minus sign // isn't inserted. // ui32Neg = 0; // // Determine the number of digits in the string version of // the value. // convert: for(ui32Idx = 1; (((ui32Idx * ui32Base) <= ui32Value) && (((ui32Idx * ui32Base) / ui32Base) == ui32Idx)); ui32Idx *= ui32Base, ui32Count--) { } // // If the value is negative, reduce the count of padding // characters needed. // if(ui32Neg) { ui32Count--; } // // If the value is negative and the value is padded with // zeros, then place the minus sign before the padding. // if(ui32Neg && (cFill == '0')) { // // Place the minus sign in the output buffer. // pcBuf[ui32Pos++] = '-'; // // The minus sign has been placed, so turn off the // negative flag. // ui32Neg = 0; } // // Provide additional padding at the beginning of the // string conversion if needed. // if((ui32Count > 1) && (ui32Count < 16)) { for(ui32Count--; ui32Count; ui32Count--) { pcBuf[ui32Pos++] = cFill; } } // // If the value is negative, then place the minus sign // before the number. // if(ui32Neg) { // // Place the minus sign in the output buffer. // pcBuf[ui32Pos++] = '-'; } // // Convert the value into a string. // for(; ui32Idx; ui32Idx /= ui32Base) { pcBuf[ui32Pos++] = g_pcHex[(ui32Value / ui32Idx) % ui32Base]; } // // Write the string. // UARTwrite(pcBuf, ui32Pos); // // 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; } } } } } //***************************************************************************** // //! 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, ...) { va_list vaArgP; // // Start the varargs processing. // va_start(vaArgP, pcString); UARTvprintf(pcString, vaArgP); // // We're finished with the varargs now. // 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; uint32_t ui32ReadIndex; // // How many characters are there in the receive buffer? // iAvail = (int)RX_BUFFER_USED; ui32ReadIndex = g_ui32UARTRxReadIndex; // // Check all the unread characters looking for the one passed. // for(iCount = 0; iCount < iAvail; iCount++) { if(g_pcUARTRxBuffer[ui32ReadIndex] == ucChar) { // // We found it so return the index // return(iCount); } else { // // This one didn't match so move on to the next character. // ADVANCE_RX_BUFFER_INDEX(ui32ReadIndex); } } // // If we drop out of the loop, we didn't find the character in the receive // buffer. // return(-1); } #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) { uint32_t ui32Int; // // Temporarily turn off interrupts. // ui32Int = MAP_IntMasterDisable(); // // Flush the receive buffer. // g_ui32UARTRxReadIndex = 0; g_ui32UARTRxWriteIndex = 0; // // If interrupts were enabled when we turned them off, turn them // back on again. // if(!ui32Int) { MAP_IntMasterEnable(); } } #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(bool bDiscard) { uint32_t ui32Int; // // Should the remaining data be discarded or transmitted? // if(bDiscard) { // // The remaining data should be discarded, so temporarily turn off // interrupts. // ui32Int = MAP_IntMasterDisable(); // // Flush the transmit buffer. // g_ui32UARTTxReadIndex = 0; g_ui32UARTTxWriteIndex = 0; // // If interrupts were enabled when we turned them off, turn them // back on again. // if(!ui32Int) { MAP_IntMasterEnable(); } } else { // // Wait for all remaining data to be transmitted before returning. // while(!TX_BUFFER_EMPTY) { } } } #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(bool 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) { uint32_t ui32Ints; int8_t cChar; int32_t i32Char; static bool bLastWasCR = false; // // Get and clear the current interrupt source(s) // ui32Ints = MAP_UARTIntStatus(g_ui32Base, true); MAP_UARTIntClear(g_ui32Base, ui32Ints); // // Are we being interrupted because the TX FIFO has space available? // if(ui32Ints & UART_INT_TX) { // // Move as many bytes as we can into the transmit FIFO. // UARTPrimeTransmit(g_ui32Base); // // If the output buffer is empty, turn off the transmit interrupt. // if(TX_BUFFER_EMPTY) { MAP_UARTIntDisable(g_ui32Base, UART_INT_TX); } } // // Are we being interrupted due to a received character? // if(ui32Ints & (UART_INT_RX | UART_INT_RT)) { // // Get all the available characters from the UART. // while(MAP_UARTCharsAvail(g_ui32Base)) { // // Read a character // i32Char = MAP_UARTCharGetNonBlocking(g_ui32Base); cChar = (unsigned char)(i32Char & 0xFF); // // If echo is disabled, we skip the various text filtering // operations that would typically be required when supporting a // command line. // if(!g_bDisableEcho) { // // Handle backspace by erasing the last character in the // buffer. // if(cChar == '\b') { // // If there are any characters already in the buffer, then // delete the last. // if(!RX_BUFFER_EMPTY) { // // Rub out the previous character on the users // terminal. // UARTwrite("\b \b", 3); // // Decrement the number of characters in the buffer. // if(g_ui32UARTRxWriteIndex == 0) { g_ui32UARTRxWriteIndex = UART_RX_BUFFER_SIZE - 1; } else { g_ui32UARTRxWriteIndex--; } } // // Skip ahead to read the next character. // continue; } // // If this character is LF and last was CR, then just gobble up // the character since we already echoed the previous CR and we // don't want to store 2 characters in the buffer if we don't // need to. // if((cChar == '\n') && bLastWasCR) { bLastWasCR = false; continue; } // // See if a newline or escape character was received. // if((cChar == '\r') || (cChar == '\n') || (cChar == 0x1b)) { // // If the character is a CR, then it may be followed by an // LF which should be paired with the CR. So remember that // a CR was received. // if(cChar == '\r') { bLastWasCR = 1; } // // Regardless of the line termination character received, // put a CR in the receive buffer as a marker telling // UARTgets() where the line ends. We also send an // additional LF to ensure that the local terminal echo // receives both CR and LF. // cChar = '\r'; UARTwrite("\n", 1); } } // // If there is space in the receive buffer, put the character // there, otherwise throw it away. // if(!RX_BUFFER_FULL) { // // Store the new character in the receive buffer // g_pcUARTRxBuffer[g_ui32UARTRxWriteIndex] = (unsigned char)(i32Char & 0xFF); ADVANCE_RX_BUFFER_INDEX(g_ui32UARTRxWriteIndex); // // If echo is enabled, write the character to the transmit // buffer so that the user gets some immediate feedback. // if(!g_bDisableEcho) { UARTwrite((const char *)&cChar, 1); } } } // // If we wrote anything to the transmit buffer, make sure it actually // gets transmitted. // UARTPrimeTransmit(g_ui32Base); MAP_UARTIntEnable(g_ui32Base, UART_INT_TX); } } #endif //***************************************************************************** // // Close the Doxygen group. //! @} // //***************************************************************************** // // End of file //