//############################################################################## // // FILE: scistdio.c // // TITLE: Utility driver to provide simple SCI console functions. // //############################################################################## // // $Release Date: $ // $Copyright: // Copyright (C) 2013-2023 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 "scistdio.h" //****************************************************************************** // //! \addtogroup SCIstdio_api //! @{ // //****************************************************************************** // // The base address of the chosen SCI. // 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"; //****************************************************************************** // //! Configures the SCI console. //! //! \param base is the base address of SCI. //! \param ui32Baud is the bit rate that the SCI is to be configured to use. //! \param ui32SrcClock is the frequency of the source clock for the SCI //! module. //! //! 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 SCI console //! functions: SCIprintf() or SCIgets(). This function assumes that the //! caller has previously configured the relevant SCI pins for operation as a //! SCI rather than as GPIOs. //! //! \return None. // //****************************************************************************** void SCIStdioConfig(uint32_t base, uint32_t ui32Baud, uint32_t ui32SrcClock) { // // Select the base address of the SCI. // g_ui32Base = base; // // Configure the SCI for 115200, n, 8, 1 // SCI_setConfig(g_ui32Base, ui32SrcClock, ui32Baud, (SCI_CONFIG_PAR_NONE | SCI_CONFIG_STOP_ONE | SCI_CONFIG_WLEN_8)); } //****************************************************************************** // //! Writes a string of characters to the SCI 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 SCI 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 SCI, 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 SCI 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 SCIwrite(const char *pcBuf, uint32_t ui32Len) { unsigned int uIdx; // // Check for valid SCI 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 SCI is \n, then add a \r before it so that // \n is translated to \n\r in the output. // if(pcBuf[uIdx] == '\n') { SCI_writeCharBlockingNonFIFO(g_ui32Base, '\r'); } // // Send the character to the SCI output. // SCI_writeCharBlockingNonFIFO(g_ui32Base, pcBuf[uIdx]); } // // Return the number of characters written. // return(uIdx); } //***************************************************************************** // //! A simple SCI 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 SCI. 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 SCIvprintf(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. // SCIwrite(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. // SCIwrite((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, 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 %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. // SCIwrite(pcStr, ui32Idx); // // Write any required padding spaces // if(ui32Count > ui32Idx) { ui32Count -= ui32Idx; while(ui32Count--) { SCIwrite(" ", 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. // SCIwrite(pcBuf, ui32Pos); // // This command has been handled. // break; } // // Handle the %% command. // case '%': { // // Simply write a single %. // SCIwrite(pcString - 1, 1); // // This command has been handled. // break; } // // Handle all other commands. // default: { // // Indicate an error. // SCIwrite("ERROR", 5); // // This command has been handled. // break; } } } } } //***************************************************************************** // //! A simple SCI 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 SCI. 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 SCIprintf(const char *pcString, ...) { va_list vaArgP; // // Start the varargs processing. // va_start(vaArgP, pcString); SCIvprintf(pcString, vaArgP); // // We're finished with the varargs now. // va_end(vaArgP); } //***************************************************************************** // // Close the Doxygen group. //! @} // //***************************************************************************** // // End of file //