/* * Copyright 2017-2018, 2020 NXP * All rights reserved. * * * SPDX-License-Identifier: BSD-3-Clause * */ #include #include #if defined(__CC_ARM) || defined(__ARMCC_VERSION) #include #endif #include #include "fsl_debug_console.h" #include "fsl_adapter_uart.h" /*! @brief Keil: suppress ellipsis warning in va_arg usage below. */ #if defined(__CC_ARM) #pragma diag_suppress 1256 #endif /* __CC_ARM */ /******************************************************************************* * Definitions ******************************************************************************/ /*! @brief This definition is maximum line that debugconsole can scanf each time.*/ #define IO_MAXLINE 20U /*! @brief The overflow value.*/ #ifndef HUGE_VAL #define HUGE_VAL (99.e99) #endif /* HUGE_VAL */ /*! @brief State structure storing debug console. */ typedef struct DebugConsoleState { uint8_t uartHandleBuffer[HAL_UART_HANDLE_SIZE]; hal_uart_status_t (*putChar)(hal_uart_handle_t handle, const uint8_t *data, size_t length); /*!< put char function pointer */ hal_uart_status_t (*getChar)(hal_uart_handle_t handle, uint8_t *data, size_t length); /*!< get char function pointer */ serial_port_type_t type; /*!< The initialized port of the debug console. */ } debug_console_state_t; /*! @brief Type of KSDK printf function pointer. */ typedef int (*PUTCHAR_FUNC)(int a); #if PRINTF_ADVANCED_ENABLE /*! @brief Specification modifier flags for printf. */ enum _debugconsole_printf_flag { kPRINTF_Minus = 0x01U, /*!< Minus FLag. */ kPRINTF_Plus = 0x02U, /*!< Plus Flag. */ kPRINTF_Space = 0x04U, /*!< Space Flag. */ kPRINTF_Zero = 0x08U, /*!< Zero Flag. */ kPRINTF_Pound = 0x10U, /*!< Pound Flag. */ kPRINTF_LengthChar = 0x20U, /*!< Length: Char Flag. */ kPRINTF_LengthShortInt = 0x40U, /*!< Length: Short Int Flag. */ kPRINTF_LengthLongInt = 0x80U, /*!< Length: Long Int Flag. */ kPRINTF_LengthLongLongInt = 0x100U, /*!< Length: Long Long Int Flag. */ }; #endif /* PRINTF_ADVANCED_ENABLE */ /*! @brief Specification modifier flags for scanf. */ enum _debugconsole_scanf_flag { kSCANF_Suppress = 0x2U, /*!< Suppress Flag. */ kSCANF_DestMask = 0x7cU, /*!< Destination Mask. */ kSCANF_DestChar = 0x4U, /*!< Destination Char Flag. */ kSCANF_DestString = 0x8U, /*!< Destination String FLag. */ kSCANF_DestSet = 0x10U, /*!< Destination Set Flag. */ kSCANF_DestInt = 0x20U, /*!< Destination Int Flag. */ kSCANF_DestFloat = 0x30U, /*!< Destination Float Flag. */ kSCANF_LengthMask = 0x1f00U, /*!< Length Mask Flag. */ #if SCANF_ADVANCED_ENABLE kSCANF_LengthChar = 0x100U, /*!< Length Char Flag. */ kSCANF_LengthShortInt = 0x200U, /*!< Length ShortInt Flag. */ kSCANF_LengthLongInt = 0x400U, /*!< Length LongInt Flag. */ kSCANF_LengthLongLongInt = 0x800U, /*!< Length LongLongInt Flag. */ #endif /* SCANF_ADVANCED_ENABLE */ #if PRINTF_FLOAT_ENABLE kSCANF_LengthLongLongDouble = 0x1000U, /*!< Length LongLongDuoble Flag. */ #endif /*PRINTF_FLOAT_ENABLE */ kSCANF_TypeSinged = 0x2000U, /*!< TypeSinged Flag. */ }; /******************************************************************************* * Variables ******************************************************************************/ /*! @brief Debug UART state information. */ static debug_console_state_t s_debugConsole; /******************************************************************************* * Prototypes ******************************************************************************/ #if SDK_DEBUGCONSOLE static int DbgConsole_PrintfFormattedData(PUTCHAR_FUNC func_ptr, const char *fmt, va_list ap); static int DbgConsole_ScanfFormattedData(const char *line_ptr, char *format, va_list args_ptr); #endif /* SDK_DEBUGCONSOLE */ /******************************************************************************* * Code ******************************************************************************/ /*************Code for DbgConsole Init, Deinit, Printf, Scanf *******************************/ #if ((SDK_DEBUGCONSOLE == DEBUGCONSOLE_REDIRECT_TO_SDK) || defined(SDK_DEBUGCONSOLE_UART)) /* See fsl_debug_console.h for documentation of this function. */ status_t DbgConsole_Init(uint8_t instance, uint32_t baudRate, serial_port_type_t device, uint32_t clkSrcFreq) { hal_uart_config_t usrtConfig; if (kSerialPort_Uart != device) { return kStatus_Fail; } /* Set debug console to initialized to avoid duplicated initialized operation. */ s_debugConsole.type = device; usrtConfig.srcClock_Hz = clkSrcFreq; usrtConfig.baudRate_Bps = baudRate; usrtConfig.parityMode = kHAL_UartParityDisabled; usrtConfig.stopBitCount = kHAL_UartOneStopBit; usrtConfig.enableRx = 1U; usrtConfig.enableTx = 1U; usrtConfig.enableRxRTS = 0U; usrtConfig.enableTxCTS = 0U; usrtConfig.instance = instance; #if (defined(HAL_UART_ADAPTER_FIFO) && (HAL_UART_ADAPTER_FIFO > 0u)) usrtConfig.txFifoWatermark = 0U; usrtConfig.rxFifoWatermark = 0U; #endif /* Enable clock and initial UART module follow user configure structure. */ (void)HAL_UartInit((hal_uart_handle_t)&s_debugConsole.uartHandleBuffer[0], &usrtConfig); /* Set the function pointer for send and receive for this kind of device. */ s_debugConsole.putChar = HAL_UartSendBlocking; s_debugConsole.getChar = HAL_UartReceiveBlocking; return kStatus_Success; } /* See fsl_debug_console.h for documentation of this function. */ status_t DbgConsole_Deinit(void) { if (kSerialPort_None == s_debugConsole.type) { return kStatus_Success; } (void)HAL_UartDeinit((hal_uart_handle_t)&s_debugConsole.uartHandleBuffer[0]); s_debugConsole.type = kSerialPort_None; return kStatus_Success; } #endif /* DEBUGCONSOLE_REDIRECT_TO_SDK */ #if SDK_DEBUGCONSOLE /* See fsl_debug_console.h for documentation of this function. */ int DbgConsole_Printf(const char *fmt_s, ...) { va_list ap; int result; /* Do nothing if the debug UART is not initialized. */ if (kSerialPort_None == s_debugConsole.type) { return -1; } va_start(ap, fmt_s); result = DbgConsole_PrintfFormattedData(DbgConsole_Putchar, fmt_s, ap); va_end(ap); return result; } /* See fsl_debug_console.h for documentation of this function. */ int DbgConsole_Putchar(int ch) { /* Do nothing if the debug UART is not initialized. */ if (kSerialPort_None == s_debugConsole.type) { return -1; } (void)s_debugConsole.putChar((hal_uart_handle_t)&s_debugConsole.uartHandleBuffer[0], (uint8_t *)(&ch), 1); return 1; } /* See fsl_debug_console.h for documentation of this function. */ int DbgConsole_Scanf(char *fmt_ptr, ...) { /* Plus one to store end of string char */ char temp_buf[IO_MAXLINE + 1]; va_list ap; int32_t i; char result; /* Do nothing if the debug UART is not initialized. */ if (kSerialPort_None == s_debugConsole.type) { return -1; } va_start(ap, fmt_ptr); temp_buf[0] = '\0'; i = 0; while (true) { if (i >= (int32_t)IO_MAXLINE) { break; } result = (char)DbgConsole_Getchar(); temp_buf[i] = result; if ((result == '\r') || (result == '\n')) { /* End of Line. */ if (i == 0) { temp_buf[i] = '\0'; i = -1; } else { break; } } i++; } if ((i == (int32_t)IO_MAXLINE)) { temp_buf[i] = '\0'; } else { temp_buf[i + 1] = '\0'; } result = (char)DbgConsole_ScanfFormattedData(temp_buf, fmt_ptr, ap); va_end(ap); return (int)result; } /* See fsl_debug_console.h for documentation of this function. */ int DbgConsole_Getchar(void) { char ch; /* Do nothing if the debug UART is not initialized. */ if (kSerialPort_None == s_debugConsole.type) { return -1; } while (kStatus_HAL_UartSuccess != s_debugConsole.getChar((hal_uart_handle_t)&s_debugConsole.uartHandleBuffer[0], (uint8_t *)(&ch), 1)) { return -1; } return (int)ch; } /*************Code for process formatted data*******************************/ /*! * @brief Scanline function which ignores white spaces. * * @param[in] s The address of the string pointer to update. * @return String without white spaces. */ static uint32_t DbgConsole_ScanIgnoreWhiteSpace(const char **s) { uint8_t count = 0; char c; c = **s; while ((c == ' ') || (c == '\t') || (c == '\n') || (c == '\r') || (c == '\v') || (c == '\f')) { count++; (*s)++; c = **s; } return count; } /*! * @brief This function puts padding character. * * @param[in] c Padding character. * @param[in] curlen Length of current formatted string . * @param[in] width Width of expected formatted string. * @param[in] count Number of characters. * @param[in] func_ptr Function to put character out. */ static void DbgConsole_PrintfPaddingCharacter( char c, int32_t curlen, int32_t width, int32_t *count, PUTCHAR_FUNC func_ptr) { int32_t i; for (i = curlen; i < width; i++) { (void)func_ptr(c); (*count)++; } } /*! * @brief Converts a radix number to a string and return its length. * * @param[in] numstr Converted string of the number. * @param[in] nump Pointer to the number. * @param[in] neg Polarity of the number. * @param[in] radix The radix to be converted to. * @param[in] use_caps Used to identify %x/X output format. * @return Length of the converted string. */ static int32_t DbgConsole_ConvertRadixNumToString(char *numstr, void *nump, int32_t neg, int32_t radix, bool use_caps) { #if PRINTF_ADVANCED_ENABLE int64_t a; int64_t b; int64_t c; uint64_t ua; uint64_t ub; uint64_t uc; #else int32_t a; int32_t b; int32_t c; uint32_t ua; uint32_t ub; uint32_t uc; #endif /* PRINTF_ADVANCED_ENABLE */ int32_t nlen; char *nstrp; nlen = 0; nstrp = numstr; *nstrp++ = '\0'; if (0 != neg) { #if PRINTF_ADVANCED_ENABLE a = *(int64_t *)nump; #else a = *(int32_t *)nump; #endif /* PRINTF_ADVANCED_ENABLE */ if (a == 0) { *nstrp = '0'; ++nlen; return nlen; } while (a != 0) { #if PRINTF_ADVANCED_ENABLE b = (int64_t)a / (int64_t)radix; c = (int64_t)a - ((int64_t)b * (int64_t)radix); if (c < 0) { c = (int64_t)'0' - c; } #else b = a / radix; c = a - (b * radix); if (c < 0) { c = (int32_t)'0' - c; } #endif /* PRINTF_ADVANCED_ENABLE */ else { c = c + '0'; } a = b; *nstrp++ = (char)c; ++nlen; } } else { #if PRINTF_ADVANCED_ENABLE ua = *(uint64_t *)nump; #else ua = *(uint32_t *)nump; #endif /* PRINTF_ADVANCED_ENABLE */ if (ua == 0U) { *nstrp = '0'; ++nlen; return nlen; } while (ua != 0U) { #if PRINTF_ADVANCED_ENABLE ub = (uint64_t)ua / (uint64_t)radix; uc = (uint64_t)ua - ((uint64_t)ub * (uint64_t)radix); #else ub = ua / (uint32_t)radix; uc = ua - (ub * (uint32_t)radix); #endif /* PRINTF_ADVANCED_ENABLE */ if (uc < 10U) { uc = uc + '0'; } else { uc = uc - 10U + (use_caps ? 'A' : 'a'); } ua = ub; *nstrp++ = (char)uc; ++nlen; } } return nlen; } #if PRINTF_FLOAT_ENABLE /*! * @brief Converts a floating radix number to a string and return its length. * * @param[in] numstr Converted string of the number. * @param[in] nump Pointer to the number. * @param[in] radix The radix to be converted to. * @param[in] precision_width Specify the precision width. * @return Length of the converted string. */ static int32_t DbgConsole_ConvertFloatRadixNumToString(char *numstr, void *nump, int32_t radix, uint32_t precision_width) { int32_t a; int32_t b; int32_t c; uint32_t i; double fa; double dc; double fb; double r; double fractpart; double intpart; int32_t nlen; char *nstrp; nlen = 0; nstrp = numstr; *nstrp++ = '\0'; r = *(double *)nump; if (0.0 == r) { *nstrp = '0'; ++nlen; return nlen; } fractpart = modf((double)r, (double *)&intpart); /* Process fractional part. */ for (i = 0; i < precision_width; i++) { fractpart *= (double)radix; } if (r >= 0.0) { fa = fractpart + (double)0.5; if (fa >= pow((double)10, (double)precision_width)) { intpart++; } } else { fa = fractpart - (double)0.5; if (fa <= -pow((double)10, (double)precision_width)) { intpart--; } } for (i = 0; i < precision_width; i++) { fb = fa / (double)radix; dc = (fa - (double)(int64_t)fb * (double)radix); c = (int32_t)dc; if (c < 0) { c = (int32_t)'0' - c; } else { c = c + '0'; } fa = fb; *nstrp++ = (char)c; ++nlen; } *nstrp++ = (char)'.'; ++nlen; a = (int32_t)intpart; if (a == 0) { *nstrp++ = '0'; ++nlen; } else { while (a != 0) { b = (int32_t)a / (int32_t)radix; c = (int32_t)a - ((int32_t)b * (int32_t)radix); if (c < 0) { c = (int32_t)'0' - c; } else { c = c + '0'; } a = b; *nstrp++ = (char)c; ++nlen; } } return nlen; } #endif /* PRINTF_FLOAT_ENABLE */ /*! * @brief This function outputs its parameters according to a formatted string. * * @note I/O is performed by calling given function pointer using following * (*func_ptr)(c); * * @param[in] func_ptr Function to put character out. * @param[in] fmt_ptr Format string for printf. * @param[in] args_ptr Arguments to printf. * * @return Number of characters */ static int DbgConsole_PrintfFormattedData(PUTCHAR_FUNC func_ptr, const char *fmt, va_list ap) { /* va_list ap; */ const char *p; char c; char vstr[33]; char *vstrp = NULL; int32_t vlen = 0; bool done; int32_t count = 0; uint32_t field_width; uint32_t precision_width; char *sval; int32_t cval; bool use_caps; uint8_t radix = 0; #if PRINTF_ADVANCED_ENABLE uint32_t flags_used; char schar; bool dschar; int64_t ival; uint64_t uval = 0; bool valid_precision_width; #else int32_t ival; uint32_t uval = 0; #endif /* PRINTF_ADVANCED_ENABLE */ #if PRINTF_FLOAT_ENABLE double fval; #endif /* PRINTF_FLOAT_ENABLE */ /* Start parsing apart the format string and display appropriate formats and data. */ p = fmt; while (true) { if ('\0' == *p) { break; } c = *p; /* * All formats begin with a '%' marker. Special chars like * '\n' or '\t' are normally converted to the appropriate * character by the __compiler__. Thus, no need for this * routine to account for the '\' character. */ if (c != '%') { (void)func_ptr(c); count++; p++; /* By using 'continue', the next iteration of the loop is used, skipping the code that follows. */ continue; } use_caps = true; #if PRINTF_ADVANCED_ENABLE /* First check for specification modifier flags. */ flags_used = 0; done = false; while (!done) { switch (*++p) { case '-': flags_used |= (uint32_t)kPRINTF_Minus; break; case '+': flags_used |= (uint32_t)kPRINTF_Plus; break; case ' ': flags_used |= (uint32_t)kPRINTF_Space; break; case '0': flags_used |= (uint32_t)kPRINTF_Zero; break; case '#': flags_used |= (uint32_t)kPRINTF_Pound; break; default: /* We've gone one char too far. */ --p; done = true; break; } } #endif /* PRINTF_ADVANCED_ENABLE */ /* Next check for minimum field width. */ field_width = 0; done = false; while (!done) { c = *++p; if ((c >= '0') && (c <= '9')) { field_width = (field_width * 10U) + ((uint32_t)c - (uint32_t)'0'); } #if PRINTF_ADVANCED_ENABLE else if (c == '*') { field_width = (uint32_t)va_arg(ap, uint32_t); } #endif /* PRINTF_ADVANCED_ENABLE */ else { /* We've gone one char too far. */ --p; done = true; } } /* Next check for the width and precision field separator. */ #if (PRINTF_ADVANCED_ENABLE || PRINTF_FLOAT_ENABLE) precision_width = 6U; /* MISRA C-2012 Rule 2.2 */ #endif #if PRINTF_ADVANCED_ENABLE valid_precision_width = false; #endif /* PRINTF_ADVANCED_ENABLE */ if (*++p == '.') { /* Must get precision field width, if present. */ precision_width = 0U; done = false; while (!done) { c = *++p; if ((c >= '0') && (c <= '9')) { precision_width = (precision_width * 10U) + ((uint32_t)c - (uint32_t)'0'); #if PRINTF_ADVANCED_ENABLE valid_precision_width = true; #endif /* PRINTF_ADVANCED_ENABLE */ } #if PRINTF_ADVANCED_ENABLE else if (c == '*') { precision_width = (uint32_t)va_arg(ap, uint32_t); valid_precision_width = true; } #endif /* PRINTF_ADVANCED_ENABLE */ else { /* We've gone one char too far. */ --p; done = true; } } } else { /* We've gone one char too far. */ --p; } #if PRINTF_ADVANCED_ENABLE /* * Check for the length modifier. */ switch (/* c = */ *++p) { case 'h': if (*++p != 'h') { flags_used |= (uint32_t)kPRINTF_LengthShortInt; --p; } else { flags_used |= (uint32_t)kPRINTF_LengthChar; } break; case 'l': if (*++p != 'l') { flags_used |= (uint32_t)kPRINTF_LengthLongInt; --p; } else { flags_used |= (uint32_t)kPRINTF_LengthLongLongInt; } break; default: /* we've gone one char too far */ --p; break; } #endif /* PRINTF_ADVANCED_ENABLE */ /* Now we're ready to examine the format. */ c = *++p; { if ((c == 'd') || (c == 'i') || (c == 'f') || (c == 'F') || (c == 'x') || (c == 'X') || (c == 'o') || (c == 'b') || (c == 'p') || (c == 'u')) { if ((c == 'd') || (c == 'i')) { #if PRINTF_ADVANCED_ENABLE if (0U != (flags_used & (uint32_t)kPRINTF_LengthLongLongInt)) { ival = (int64_t)va_arg(ap, int64_t); } else #endif /* PRINTF_ADVANCED_ENABLE */ { ival = (int32_t)va_arg(ap, int32_t); } vlen = DbgConsole_ConvertRadixNumToString(vstr, &ival, 1, 10, use_caps); vstrp = &vstr[vlen]; #if PRINTF_ADVANCED_ENABLE if (ival < 0) { schar = '-'; ++vlen; } else { if (0U != (flags_used & (uint32_t)kPRINTF_Plus)) { schar = '+'; ++vlen; } else { if (0U != (flags_used & (uint32_t)kPRINTF_Space)) { schar = ' '; ++vlen; } else { schar = '\0'; } } } dschar = false; /* Do the ZERO pad. */ if (0U != (flags_used & (uint32_t)kPRINTF_Zero)) { if ('\0' != schar) { (void)func_ptr(schar); count++; } dschar = true; DbgConsole_PrintfPaddingCharacter('0', vlen, (int32_t)field_width, &count, func_ptr); vlen = (int32_t)field_width; } else { if (0U == (flags_used & (uint32_t)kPRINTF_Minus)) { DbgConsole_PrintfPaddingCharacter(' ', vlen, (int32_t)field_width, &count, func_ptr); if ('\0' != schar) { (void)func_ptr(schar); count++; } dschar = true; } } /* The string was built in reverse order, now display in correct order. */ if ((!dschar) && ('\0' != schar)) { (void)func_ptr(schar); count++; } #endif /* PRINTF_ADVANCED_ENABLE */ } #if PRINTF_FLOAT_ENABLE if ((c == 'f') || (c == 'F')) { fval = (double)va_arg(ap, double); vlen = DbgConsole_ConvertFloatRadixNumToString(vstr, &fval, 10, precision_width); vstrp = &vstr[vlen]; #if PRINTF_ADVANCED_ENABLE if (fval < 0.0) { schar = '-'; ++vlen; } else { if (0U != (flags_used & (uint32_t)kPRINTF_Plus)) { schar = '+'; ++vlen; } else { if (0U != (flags_used & (uint32_t)kPRINTF_Space)) { schar = ' '; ++vlen; } else { schar = '\0'; } } } dschar = false; if (0U != (flags_used & (uint32_t)kPRINTF_Zero)) { if ('\0' != schar) { (void)func_ptr(schar); count++; } dschar = true; DbgConsole_PrintfPaddingCharacter('0', vlen, (int32_t)field_width, &count, func_ptr); vlen = (int32_t)field_width; } else { if (0U == (flags_used & (uint32_t)kPRINTF_Minus)) { DbgConsole_PrintfPaddingCharacter(' ', vlen, (int32_t)field_width, &count, func_ptr); if (schar) { (void)func_ptr(schar); count++; } dschar = true; } } if ((!dschar) && schar) { (void)func_ptr(schar); count++; } #endif /* PRINTF_ADVANCED_ENABLE */ } #endif /* PRINTF_FLOAT_ENABLE */ if ((c == 'X') || (c == 'x')) { if (c == 'x') { use_caps = false; } #if PRINTF_ADVANCED_ENABLE if (0U != (flags_used & (uint32_t)kPRINTF_LengthLongLongInt)) { uval = (uint64_t)va_arg(ap, uint64_t); } else #endif /* PRINTF_ADVANCED_ENABLE */ { uval = (uint32_t)va_arg(ap, uint32_t); } vlen = DbgConsole_ConvertRadixNumToString(vstr, &uval, 0, 16, use_caps); vstrp = &vstr[vlen]; #if PRINTF_ADVANCED_ENABLE dschar = false; if (0U != (flags_used & (uint32_t)kPRINTF_Zero)) { if (0U != (flags_used & (uint32_t)kPRINTF_Pound)) { (void)func_ptr('0'); (void)func_ptr((use_caps ? 'X' : 'x')); count += 2; /*vlen += 2;*/ dschar = true; } DbgConsole_PrintfPaddingCharacter('0', vlen, (int32_t)field_width, &count, func_ptr); vlen = (int32_t)field_width; } else { if (0U == (flags_used & (uint32_t)kPRINTF_Pound)) { if (0U != (flags_used & (uint32_t)kPRINTF_Pound)) { vlen += 2; } DbgConsole_PrintfPaddingCharacter(' ', vlen, (int32_t)field_width, &count, func_ptr); if (0U != (flags_used & (uint32_t)kPRINTF_Pound)) { (void)func_ptr('0'); (void)func_ptr(use_caps ? 'X' : 'x'); count += 2; dschar = true; } } } if ((0U != (flags_used & (uint32_t)kPRINTF_Pound)) && (!dschar)) { (void)func_ptr('0'); (void)func_ptr(use_caps ? 'X' : 'x'); count += 2; vlen += 2; } #endif /* PRINTF_ADVANCED_ENABLE */ } if ((c == 'o') || (c == 'b') || (c == 'p') || (c == 'u')) { #if PRINTF_ADVANCED_ENABLE if (0U != (flags_used & (uint32_t)kPRINTF_LengthLongLongInt)) { uval = (uint64_t)va_arg(ap, uint64_t); } else #endif /* PRINTF_ADVANCED_ENABLE */ { uval = (uint32_t)va_arg(ap, uint32_t); } switch (c) { case 'o': radix = 8; break; case 'b': radix = 2; break; case 'p': radix = 16; break; case 'u': radix = 10; break; default: /* MISRA C-2012 Rule 16.4 */ break; } vlen = DbgConsole_ConvertRadixNumToString(vstr, &uval, 0, (int32_t)radix, use_caps); vstrp = &vstr[vlen]; #if PRINTF_ADVANCED_ENABLE if (0U != (flags_used & (uint32_t)kPRINTF_Zero)) { DbgConsole_PrintfPaddingCharacter('0', vlen, (int32_t)field_width, &count, func_ptr); vlen = (int32_t)field_width; } else { if (0U == (flags_used & (uint32_t)kPRINTF_Minus)) { DbgConsole_PrintfPaddingCharacter(' ', vlen, (int32_t)field_width, &count, func_ptr); } } #endif /* PRINTF_ADVANCED_ENABLE */ } #if !PRINTF_ADVANCED_ENABLE DbgConsole_PrintfPaddingCharacter(' ', vlen, (int32_t)field_width, &count, func_ptr); #endif /* !PRINTF_ADVANCED_ENABLE */ if (vstrp != NULL) { while ('\0' != *vstrp) { (void)func_ptr(*vstrp--); count++; } } #if PRINTF_ADVANCED_ENABLE if (0U != (flags_used & (uint32_t)kPRINTF_Minus)) { DbgConsole_PrintfPaddingCharacter(' ', vlen, (int32_t)field_width, &count, func_ptr); } #endif /* PRINTF_ADVANCED_ENABLE */ } else if (c == 'c') { cval = (int32_t)va_arg(ap, uint32_t); (void)func_ptr(cval); count++; } else if (c == 's') { sval = (char *)va_arg(ap, char *); if (NULL != sval) { #if PRINTF_ADVANCED_ENABLE if (valid_precision_width) { vlen = (int32_t)precision_width; } else { vlen = (int32_t)strlen(sval); } #else vlen = (int32_t)strlen(sval); #endif /* PRINTF_ADVANCED_ENABLE */ #if PRINTF_ADVANCED_ENABLE if (0U == (flags_used & (uint32_t)kPRINTF_Minus)) #endif /* PRINTF_ADVANCED_ENABLE */ { DbgConsole_PrintfPaddingCharacter(' ', vlen, (int32_t)field_width, &count, func_ptr); } #if PRINTF_ADVANCED_ENABLE if (valid_precision_width) { while (('\0' != *sval) && (vlen > 0)) { (void)func_ptr(*sval++); count++; vlen--; } /* In case that vlen sval is shorter than vlen */ vlen = (int32_t)precision_width - vlen; } else { #endif /* PRINTF_ADVANCED_ENABLE */ while ('\0' != *sval) { (void)func_ptr(*sval++); count++; } #if PRINTF_ADVANCED_ENABLE } #endif /* PRINTF_ADVANCED_ENABLE */ #if PRINTF_ADVANCED_ENABLE if (0U != (flags_used & (uint32_t)kPRINTF_Minus)) { DbgConsole_PrintfPaddingCharacter(' ', vlen, (int32_t)field_width, &count, func_ptr); } #endif /* PRINTF_ADVANCED_ENABLE */ } } else { (void)func_ptr(c); count++; } } p++; } return count; } /*! * @brief Converts an input line of ASCII characters based upon a provided * string format. * * @param[in] line_ptr The input line of ASCII data. * @param[in] format Format first points to the format string. * @param[in] args_ptr The list of parameters. * * @return Number of input items converted and assigned. * @retval IO_EOF When line_ptr is empty string "". */ static int DbgConsole_ScanfFormattedData(const char *line_ptr, char *format, va_list args_ptr) { uint8_t base; int8_t neg; /* Identifier for the format string. */ char *c = format; char temp; char *buf; /* Flag telling the conversion specification. */ uint32_t flag = 0; /* Filed width for the matching input streams. */ uint32_t field_width; /* How many arguments are assigned except the suppress. */ uint32_t nassigned = 0; bool match_failure = false; /* How many characters are read from the input streams. */ uint32_t n_decode = 0; int32_t val; const char *s; /* Identifier for the input string. */ const char *p = line_ptr; #if SCANF_FLOAT_ENABLE double fnum = 0.0; #endif /* SCANF_FLOAT_ENABLE */ /* Return EOF error before any conversion. */ if (*p == '\0') { return -1; } /* Decode directives. */ while (('\0' != (*c)) && ('\0' != (*p))) { /* Ignore all white-spaces in the format strings. */ if (0U != DbgConsole_ScanIgnoreWhiteSpace((const char **)(void *)&c)) { n_decode += DbgConsole_ScanIgnoreWhiteSpace(&p); } else if ((*c != '%') || ((*c == '%') && (*(c + 1) == '%'))) { /* Ordinary characters. */ c++; if (*p == *c) { n_decode++; p++; c++; } else { /* Match failure. Misalignment with C99, the unmatched characters need to be pushed back to stream. * However, it is deserted now. */ break; } } else { /* convernsion specification */ c++; /* Reset. */ flag = 0; field_width = 0; base = 0; /* Loop to get full conversion specification. */ while (('\0' != *c) && (0U == (flag & (uint32_t)kSCANF_DestMask))) { switch (*c) { #if SCANF_ADVANCED_ENABLE case '*': if (0U != (flag & (uint32_t)kSCANF_Suppress)) { /* Match failure. */ match_failure = true; break; } flag |= (uint32_t)kSCANF_Suppress; c++; break; case 'h': if (0U != (flag & (uint32_t)kSCANF_LengthMask)) { /* Match failure. */ match_failure = true; break; } if (c[1] == 'h') { flag |= (uint32_t)kSCANF_LengthChar; c++; } else { flag |= (uint32_t)kSCANF_LengthShortInt; } c++; break; case 'l': if (0U != (flag & (uint32_t)kSCANF_LengthMask)) { /* Match failure. */ match_failure = true; break; } if (c[1] == 'l') { flag |= (uint32_t)kSCANF_LengthLongLongInt; c++; } else { flag |= (uint32_t)kSCANF_LengthLongInt; } c++; break; #endif /* SCANF_ADVANCED_ENABLE */ #if SCANF_FLOAT_ENABLE case 'L': if (flag & (uint32_t)kSCANF_LengthMask) { /* Match failure. */ match_failure = true; break; } flag |= (uint32_t)kSCANF_LengthLongLongDouble; c++; break; #endif /* SCANF_FLOAT_ENABLE */ case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': if (0U != field_width) { /* Match failure. */ match_failure = true; break; } do { field_width = field_width * 10U + ((uint32_t)*c - (uint32_t)'0'); c++; } while ((*c >= '0') && (*c <= '9')); break; case 'd': base = 10; flag |= (uint32_t)kSCANF_TypeSinged; flag |= (uint32_t)kSCANF_DestInt; c++; break; case 'u': base = 10; flag |= (uint32_t)kSCANF_DestInt; c++; break; case 'o': base = 8; flag |= (uint32_t)kSCANF_DestInt; c++; break; case 'x': case 'X': base = 16; flag |= (uint32_t)kSCANF_DestInt; c++; break; case 'i': base = 0; flag |= (uint32_t)kSCANF_DestInt; c++; break; #if SCANF_FLOAT_ENABLE case 'a': case 'A': case 'e': case 'E': case 'f': case 'F': case 'g': case 'G': flag |= kSCANF_DestFloat; c++; break; #endif /* SCANF_FLOAT_ENABLE */ case 'c': flag |= (uint32_t)kSCANF_DestChar; if (0U == field_width) { field_width = 1; } c++; break; case 's': flag |= (uint32_t)kSCANF_DestString; c++; break; default: /* Match failure. */ match_failure = true; break; } /* Match failure. */ if (match_failure) { return (int)nassigned; } } if (0U == (flag & (uint32_t)kSCANF_DestMask)) { /* Format strings are exhausted. */ return (int)nassigned; } if (0U == field_width) { /* Large than length of a line. */ field_width = 99; } /* Matching strings in input streams and assign to argument. */ switch (flag & (uint32_t)kSCANF_DestMask) { case (uint32_t)kSCANF_DestChar: s = (const char *)p; buf = va_arg(args_ptr, char *); while (((field_width--) > 0U) && ('\0' != *p)) { if (0U == (flag & (uint32_t)kSCANF_Suppress)) { *buf++ = *p++; } else { p++; } n_decode++; } if ((0U == (flag & (uint32_t)kSCANF_Suppress)) && (s != p)) { nassigned++; } break; case (uint32_t)kSCANF_DestString: n_decode += DbgConsole_ScanIgnoreWhiteSpace(&p); s = p; buf = va_arg(args_ptr, char *); while ((field_width-- > 0U) && (*p != '\0') && (*p != ' ') && (*p != '\t') && (*p != '\n') && (*p != '\r') && (*p != '\v') && (*p != '\f')) { if (0U != (flag & (uint32_t)kSCANF_Suppress)) { p++; } else { *buf++ = *p++; } n_decode++; } if ((0U == (flag & (uint32_t)kSCANF_Suppress)) && (s != p)) { /* Add NULL to end of string. */ *buf = '\0'; nassigned++; } break; case (uint32_t)kSCANF_DestInt: n_decode += DbgConsole_ScanIgnoreWhiteSpace(&p); s = p; val = 0; if ((base == 0U) || (base == 16U)) { if ((s[0] == '0') && ((s[1] == 'x') || (s[1] == 'X'))) { base = 16U; if (field_width >= 1U) { p += 2; n_decode += 2U; field_width -= 2U; } } } if (base == 0U) { if (s[0] == '0') { base = 8U; } else { base = 10U; } } neg = 1; switch (*p) { case '-': neg = -1; n_decode++; p++; field_width--; break; case '+': neg = 1; n_decode++; p++; field_width--; break; default: /* MISRA C-2012 Rule 16.4 */ break; } while ((field_width-- > 0U) && (*p > '\0')) { if ((*p <= '9') && (*p >= '0')) { temp = *p - '0' + (char)0; } else if ((*p <= 'f') && (*p >= 'a')) { temp = *p - 'a' + (char)10; } else if ((*p <= 'F') && (*p >= 'A')) { temp = *p - 'A' + (char)10; } else { temp = (char)base; } if ((uint8_t)temp >= base) { break; } else { val = (int32_t)base * val + (int32_t)temp; } p++; n_decode++; } val *= neg; if (0U == (flag & (uint32_t)kSCANF_Suppress)) { #if SCANF_ADVANCED_ENABLE switch (flag & (uint32_t)kSCANF_LengthMask) { case (uint32_t)kSCANF_LengthChar: if (0U != (flag & (uint32_t)kSCANF_TypeSinged)) { *va_arg(args_ptr, signed char *) = (signed char)val; } else { *va_arg(args_ptr, unsigned char *) = (unsigned char)val; } break; case (uint32_t)kSCANF_LengthShortInt: if (0U != (flag & (uint32_t)kSCANF_TypeSinged)) { *va_arg(args_ptr, signed short *) = (signed short)val; } else { *va_arg(args_ptr, unsigned short *) = (unsigned short)val; } break; case (uint32_t)kSCANF_LengthLongInt: if (0U != (flag & (uint32_t)kSCANF_TypeSinged)) { *va_arg(args_ptr, signed long int *) = (signed long int)val; } else { *va_arg(args_ptr, unsigned long int *) = (unsigned long int)val; } break; case (uint32_t)kSCANF_LengthLongLongInt: if (0U != (flag & (uint32_t)kSCANF_TypeSinged)) { *va_arg(args_ptr, signed long long int *) = (signed long long int)val; } else { *va_arg(args_ptr, unsigned long long int *) = (unsigned long long int)val; } break; default: /* The default type is the type int. */ if (0U != (flag & (uint32_t)kSCANF_TypeSinged)) { *va_arg(args_ptr, signed int *) = (signed int)val; } else { *va_arg(args_ptr, unsigned int *) = (unsigned int)val; } break; } #else /* The default type is the type int. */ if (0U != (flag & (uint32_t)kSCANF_TypeSinged)) { *va_arg(args_ptr, signed int *) = (signed int)val; } else { *va_arg(args_ptr, unsigned int *) = (unsigned int)val; } #endif /* SCANF_ADVANCED_ENABLE */ nassigned++; } break; #if SCANF_FLOAT_ENABLE case (uint32_t)kSCANF_DestFloat: n_decode += DbgConsole_ScanIgnoreWhiteSpace(&p); fnum = strtod(p, (char **)&s); if ((fnum >= HUGE_VAL) || (fnum <= -HUGE_VAL)) { break; } n_decode += (int)(s) - (int)(p); p = s; if (0U == (flag & (uint32_t)kSCANF_Suppress)) { if (0U != (flag & (uint32_t)kSCANF_LengthLongLongDouble)) { *va_arg(args_ptr, double *) = fnum; } else { *va_arg(args_ptr, float *) = (float)fnum; } nassigned++; } break; #endif /* SCANF_FLOAT_ENABLE */ default: /* Match failure. */ match_failure = true; break; } /* Match failure. */ if (match_failure) { return (int)nassigned; } } } return (int)nassigned; } #endif /* SDK_DEBUGCONSOLE */ /*************Code to support toolchain's printf, scanf *******************************/ /* These function __write and __read is used to support IAR toolchain to printf and scanf*/ #if (defined(__ICCARM__)) #if defined(SDK_DEBUGCONSOLE_UART) #pragma weak __write size_t __write(int handle, const unsigned char *buffer, size_t size); size_t __write(int handle, const unsigned char *buffer, size_t size) { size_t ret; if (NULL == buffer) { /* * This means that we should flush internal buffers. Since we don't we just return. * (Remember, "handle" == -1 means that all handles should be flushed.) */ ret = (size_t)0; } else if ((handle != 1) && (handle != 2)) { /* This function only writes to "standard out" and "standard err" for all other file handles it returns failure. */ ret = (size_t)-1; } else if (kSerialPort_None == s_debugConsole.type) { /* Do nothing if the debug UART is not initialized. */ ret = (size_t)-1; } else { /* Send data. */ (void)s_debugConsole.putChar((hal_uart_handle_t)&s_debugConsole.uartHandleBuffer[0], buffer, size); ret = size; } return ret; } #pragma weak __read size_t __read(int handle, unsigned char *buffer, size_t size); size_t __read(int handle, unsigned char *buffer, size_t size) { size_t ret; /* This function only reads from "standard in", for all other file handles it returns failure. */ if (handle != 0) { ret = ((size_t)-1); } else if (kSerialPort_None == s_debugConsole.type) { /* Do nothing if the debug UART is not initialized. */ ret = ((size_t)-1); } else { /* Receive data. */ (void)s_debugConsole.getChar((hal_uart_handle_t)&s_debugConsole.uartHandleBuffer[0], buffer, size); ret = size; } return ret; } #endif /* SDK_DEBUGCONSOLE_UART */ /* support LPC Xpresso with RedLib */ #elif (defined(__REDLIB__)) #if (defined(SDK_DEBUGCONSOLE_UART)) int __attribute__((weak)) __sys_write(int handle, char *buffer, int size) { if (NULL == buffer) { /* return -1 if error. */ return -1; } /* This function only writes to "standard out" and "standard err" for all other file handles it returns failure. */ if ((handle != 1) && (handle != 2)) { return -1; } /* Do nothing if the debug UART is not initialized. */ if (kSerialPort_None == s_debugConsole.type) { return -1; } /* Send data. */ (void)s_debugConsole.putChar((hal_uart_handle_t)&s_debugConsole.uartHandleBuffer[0], (uint8_t *)buffer, size); return 0; } int __attribute__((weak)) __sys_readc(void) { char tmp; /* Do nothing if the debug UART is not initialized. */ if (kSerialPort_None == s_debugConsole.type) { return -1; } /* Receive data. */ s_debugConsole.getChar((hal_uart_handle_t)&s_debugConsole.uartHandleBuffer[0], (uint8_t *)&tmp, sizeof(tmp)); return tmp; } #endif /* SDK_DEBUGCONSOLE_UART */ /* These function fputc and fgetc is used to support KEIL toolchain to printf and scanf*/ #elif defined(__CC_ARM) || defined(__ARMCC_VERSION) #if defined(SDK_DEBUGCONSOLE_UART) #if defined(__CC_ARM) struct __FILE { int handle; /* * Whatever you require here. If the only file you are using is standard output using printf() for debugging, * no file handling is required. */ }; #endif /* FILE is typedef in stdio.h. */ #pragma weak __stdout #pragma weak __stdin FILE __stdout; FILE __stdin; #pragma weak fputc int fputc(int ch, FILE *f) { /* Do nothing if the debug UART is not initialized. */ if (kSerialPort_None == s_debugConsole.type) { return -1; } /* Send data. */ (void)s_debugConsole.putChar((hal_uart_handle_t)&s_debugConsole.uartHandleBuffer[0], (uint8_t *)(&ch), 1); return 1; } #pragma weak fgetc int fgetc(FILE *f) { char ch; /* Do nothing if the debug UART is not initialized. */ if (kSerialPort_None == s_debugConsole.type) { return -1; } /* Receive data. */ s_debugConsole.getChar((hal_uart_handle_t)&s_debugConsole.uartHandleBuffer[0], (uint8_t *)(&ch), 1); return ch; } /* * Terminate the program, passing a return code back to the user. * This function may not return. */ void _sys_exit(int returncode) { while (1) { } } /* * Writes a character to the output channel. This function is used * for last-resort error message output. */ void _ttywrch(int ch) { char ench = ch; /* Send data. */ s_debugConsole.putChar((hal_uart_handle_t)&s_debugConsole.uartHandleBuffer[0], (uint8_t *)(&ench), 1); } char *_sys_command_string(char *cmd, int len) { return (cmd); } #endif /* SDK_DEBUGCONSOLE_UART */ /* These function __write and __read is used to support ARM_GCC, KDS, Atollic toolchains to printf and scanf*/ #elif (defined(__GNUC__)) #if ((defined(__GNUC__) && (!defined(__MCUXPRESSO)) && (defined(SDK_DEBUGCONSOLE_UART))) || \ (defined(__MCUXPRESSO) && (defined(SDK_DEBUGCONSOLE_UART)))) int __attribute__((weak)) _write(int handle, char *buffer, int size); int __attribute__((weak)) _write(int handle, char *buffer, int size) { if (NULL == buffer) { /* return -1 if error. */ return -1; } /* This function only writes to "standard out" and "standard err" for all other file handles it returns failure. */ if ((handle != 1) && (handle != 2)) { return -1; } /* Do nothing if the debug UART is not initialized. */ if (kSerialPort_None == s_debugConsole.type) { return -1; } /* Send data. */ (void)s_debugConsole.putChar((hal_uart_handle_t)&s_debugConsole.uartHandleBuffer[0], (uint8_t *)buffer, size); return size; } int __attribute__((weak)) _read(int handle, char *buffer, int size); int __attribute__((weak)) _read(int handle, char *buffer, int size) { /* This function only reads from "standard in", for all other file handles it returns failure. */ if (handle != 0) { return -1; } /* Do nothing if the debug UART is not initialized. */ if (kSerialPort_None == s_debugConsole.type) { return -1; } /* Receive data. */ (void)s_debugConsole.getChar((hal_uart_handle_t)&s_debugConsole.uartHandleBuffer[0], (uint8_t *)buffer, size); return size; } #endif #endif /* __ICCARM__ */