RTT Debugger Library
Dependents: BREAK_SENSOR_LED MPU9250_simple MPU9250_tap_better Sensor_tap_BLE ... more
SEGGER_RTT_printf.c
00001 /********************************************************************* 00002 * SEGGER MICROCONTROLLER GmbH & Co. KG * 00003 * Solutions for real time microcontroller applications * 00004 ********************************************************************** 00005 * * 00006 * (c) 2014-2014 SEGGER Microcontroller GmbH & Co. KG * 00007 * * 00008 * Internet: www.segger.com Support: support@segger.com * 00009 * * 00010 ********************************************************************** 00011 ---------------------------------------------------------------------- 00012 File : SEGGER_RTT_printf.c 00013 Date : 17 Dec 2014 00014 Purpose : Replacement for printf to write formatted data via RTT 00015 ---------------------------END-OF-HEADER------------------------------ 00016 */ 00017 #include "SEGGER_RTT.h" 00018 #include "SEGGER_RTT_Conf.h" 00019 00020 /********************************************************************* 00021 * 00022 * Defines, configurable 00023 * 00024 ********************************************************************** 00025 */ 00026 00027 #ifndef SEGGER_RTT_PRINTF_BUFFER_SIZE 00028 #define SEGGER_RTT_PRINTF_BUFFER_SIZE (64) 00029 #endif 00030 00031 #include <stdlib.h> 00032 #include <stdarg.h> 00033 00034 00035 #define FORMAT_FLAG_LEFT_JUSTIFY (1 << 0) 00036 #define FORMAT_FLAG_PAD_ZERO (1 << 1) 00037 #define FORMAT_FLAG_PRINT_SIGN (1 << 2) 00038 #define FORMAT_FLAG_ALTERNATE (1 << 3) 00039 00040 /********************************************************************* 00041 * 00042 * Types 00043 * 00044 ********************************************************************** 00045 */ 00046 00047 typedef struct { 00048 char* pBuffer; 00049 int BufferSize; 00050 int Cnt; 00051 00052 int ReturnValue; 00053 00054 unsigned RTTBufferIndex; 00055 } SEGGER_RTT_PRINTF_DESC; 00056 00057 /********************************************************************* 00058 * 00059 * Function prototypes 00060 * 00061 ********************************************************************** 00062 */ 00063 int SEGGER_RTT_vprintf(unsigned BufferIndex, const char * sFormat, va_list * pParamList); 00064 00065 /********************************************************************* 00066 * 00067 * Static code 00068 * 00069 ********************************************************************** 00070 */ 00071 /********************************************************************* 00072 * 00073 * _StoreChar 00074 */ 00075 static void _StoreChar(SEGGER_RTT_PRINTF_DESC * p, char c) { 00076 int Cnt; 00077 00078 Cnt = p->Cnt; 00079 if ((Cnt + 1) <= p->BufferSize) { 00080 *(p->pBuffer + Cnt) = c; 00081 p->Cnt = Cnt + 1; 00082 p->ReturnValue++; 00083 } 00084 // 00085 // Write part of string, when the buffer is full 00086 // 00087 if (p->Cnt == p->BufferSize) { 00088 if (SEGGER_RTT_Write(p->RTTBufferIndex, p->pBuffer, p->Cnt) != p->Cnt) { 00089 p->ReturnValue = -1; 00090 } else { 00091 p->Cnt = 0; 00092 } 00093 } 00094 } 00095 00096 /********************************************************************* 00097 * 00098 * _PrintUnsigned 00099 */ 00100 static void _PrintUnsigned(SEGGER_RTT_PRINTF_DESC * pBufferDesc, unsigned v, unsigned Base, int NumDigits, unsigned FieldWidth, unsigned FormatFlags) { 00101 static const char _aV2C[16] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; 00102 unsigned Div; 00103 unsigned Digit = 1; 00104 unsigned Number; 00105 unsigned Width; 00106 char c; 00107 00108 Number = v; 00109 00110 // 00111 // Get actual field width 00112 // 00113 Width = 1; 00114 while (Number >= Base) { 00115 Number = (Number / Base); 00116 Width++; 00117 } 00118 if ((unsigned)NumDigits > Width) { 00119 Width = NumDigits; 00120 } 00121 // 00122 // Print leading chars if necessary 00123 // 00124 if ((FormatFlags & FORMAT_FLAG_LEFT_JUSTIFY) == 0) { 00125 if (FieldWidth != 0) { 00126 if (((FormatFlags & FORMAT_FLAG_PAD_ZERO) == FORMAT_FLAG_PAD_ZERO) && (NumDigits == 0)) { 00127 c = '0'; 00128 } else { 00129 c = ' '; 00130 } 00131 while ((FieldWidth != 0) && (Width < FieldWidth--)) { 00132 _StoreChar(pBufferDesc, c); 00133 if (pBufferDesc->ReturnValue < 0) { 00134 return; 00135 } 00136 } 00137 } 00138 } 00139 // 00140 // Count how many digits are required by precision 00141 // 00142 while (((v / Digit) >= Base) | (NumDigits-- > 1)) { 00143 Digit *= Base; 00144 } 00145 // 00146 // Output digits 00147 // 00148 do { 00149 Div = v / Digit; 00150 v -= Div * Digit; 00151 _StoreChar(pBufferDesc, _aV2C[Div]); 00152 if (pBufferDesc->ReturnValue < 0) { 00153 break; 00154 } 00155 Digit /= Base; 00156 } while (Digit); 00157 // 00158 // Print trailing spaces if necessary 00159 // 00160 if ((FormatFlags & FORMAT_FLAG_LEFT_JUSTIFY) == FORMAT_FLAG_LEFT_JUSTIFY) { 00161 if (FieldWidth != 0) { 00162 while ((FieldWidth != 0) && (Width < FieldWidth--)) { 00163 _StoreChar(pBufferDesc, ' '); 00164 if (pBufferDesc->ReturnValue < 0) { 00165 return; 00166 } 00167 } 00168 } 00169 } 00170 } 00171 00172 /********************************************************************* 00173 * 00174 * _PrintInt 00175 */ 00176 static void _PrintInt(SEGGER_RTT_PRINTF_DESC * pBufferDesc, int v, unsigned Base, unsigned NumDigits, unsigned FieldWidth, unsigned FormatFlags) { 00177 unsigned Width; 00178 unsigned Number; 00179 00180 Number = (v < 0) ? -v : v; 00181 00182 // 00183 // Get actual field width 00184 // 00185 Width = 1; 00186 while (Number >= Base) { 00187 Number = (Number / Base); 00188 Width++; 00189 } 00190 if (NumDigits > Width) { 00191 Width = NumDigits; 00192 } 00193 if ((FieldWidth > 0) && ((v < 0) || ((FormatFlags & FORMAT_FLAG_PRINT_SIGN) == FORMAT_FLAG_PRINT_SIGN))) { 00194 FieldWidth--; 00195 } 00196 00197 // 00198 // Print leading spaces if necessary 00199 // 00200 if ((((FormatFlags & FORMAT_FLAG_PAD_ZERO) == 0) || (NumDigits != 0)) && ((FormatFlags & FORMAT_FLAG_LEFT_JUSTIFY) == 0)) { 00201 if (FieldWidth != 0) { 00202 while ((FieldWidth != 0) && (Width < FieldWidth--)) { 00203 _StoreChar(pBufferDesc, ' '); 00204 if (pBufferDesc->ReturnValue < 0) { 00205 return; 00206 } 00207 } 00208 } 00209 } 00210 // 00211 // Print sign if necessary 00212 // 00213 if (v < 0) { 00214 v = -v; 00215 _StoreChar(pBufferDesc, '-'); 00216 if (pBufferDesc->ReturnValue < 0) { 00217 return; 00218 } 00219 } else if ((FormatFlags & FORMAT_FLAG_PRINT_SIGN) == FORMAT_FLAG_PRINT_SIGN) { 00220 _StoreChar(pBufferDesc, '+'); 00221 if (pBufferDesc->ReturnValue < 0) { 00222 return; 00223 } 00224 } 00225 // 00226 // Print leading zeros if necessary 00227 // 00228 if (((FormatFlags & FORMAT_FLAG_PAD_ZERO) == FORMAT_FLAG_PAD_ZERO) && ((FormatFlags & FORMAT_FLAG_LEFT_JUSTIFY) == 0) && (NumDigits == 0)) { 00229 if (FieldWidth != 0) { 00230 while ((FieldWidth != 0) && (Width < FieldWidth--)) { 00231 _StoreChar(pBufferDesc, '0'); 00232 if (pBufferDesc->ReturnValue < 0) { 00233 return; 00234 } 00235 } 00236 } 00237 } 00238 00239 // 00240 // Print number without sign 00241 // 00242 _PrintUnsigned(pBufferDesc, v, Base, NumDigits, FieldWidth, FormatFlags); 00243 } 00244 00245 /********************************************************************* 00246 * 00247 * Public code 00248 * 00249 ********************************************************************** 00250 */ 00251 /********************************************************************* 00252 * 00253 * SEGGER_RTT_vprintf 00254 * 00255 * Function description 00256 * Stores a formatted string in SEGGER RTT control block. 00257 * This data is read by the host. 00258 * 00259 * Parameters 00260 * BufferIndex Index of "Up"-buffer to be used. (e.g. 0 for "Terminal") 00261 * sFormat Pointer to format string 00262 * pParamList Pointer to the list of arguments for the format string 00263 * 00264 * Return values 00265 * >= 0: Number of bytes which have been stored in the "Up"-buffer. 00266 * < 0: Error 00267 */ 00268 int SEGGER_RTT_vprintf(unsigned BufferIndex, const char * sFormat, va_list * pParamList) { 00269 char c; 00270 SEGGER_RTT_PRINTF_DESC BufferDesc; 00271 int v; 00272 unsigned NumDigits; 00273 unsigned FormatFlags; 00274 unsigned FieldWidth; 00275 char acBuffer[SEGGER_RTT_PRINTF_BUFFER_SIZE]; 00276 00277 BufferDesc.pBuffer = acBuffer; 00278 BufferDesc.BufferSize = SEGGER_RTT_PRINTF_BUFFER_SIZE; 00279 BufferDesc.Cnt = 0; 00280 BufferDesc.RTTBufferIndex = BufferIndex; 00281 BufferDesc.ReturnValue = 0; 00282 00283 do { 00284 c = *sFormat++; 00285 if (c == 0) { 00286 break; 00287 } 00288 if (c == '%') { 00289 // 00290 // Filter out flags 00291 // 00292 FormatFlags = 0; 00293 do { 00294 c = *sFormat; 00295 switch (c) { 00296 case '-': FormatFlags |= FORMAT_FLAG_LEFT_JUSTIFY; sFormat++; break; 00297 case '0': FormatFlags |= FORMAT_FLAG_PAD_ZERO; sFormat++; break; 00298 case '+': FormatFlags |= FORMAT_FLAG_PRINT_SIGN; sFormat++; break; 00299 case '#': FormatFlags |= FORMAT_FLAG_ALTERNATE; sFormat++; break; 00300 default: goto FilterFieldWidth; break; 00301 } 00302 } while (1); 00303 // 00304 // filter out field with 00305 // 00306 FilterFieldWidth: 00307 FieldWidth = 0; 00308 do { 00309 c = *sFormat; 00310 if (c < '0' || c > '9') { 00311 break; 00312 } 00313 sFormat++; 00314 FieldWidth = FieldWidth * 10 + (c - '0'); 00315 } while (1); 00316 00317 // 00318 // Filter out precision (number of digits to display) 00319 // 00320 NumDigits = 0; 00321 c = *sFormat; 00322 if (c == '.') { 00323 sFormat++; 00324 do { 00325 c = *sFormat; 00326 if (c < '0' || c > '9') { 00327 break; 00328 } 00329 sFormat++; 00330 NumDigits = NumDigits * 10 + (c - '0'); 00331 } while (1); 00332 } 00333 // 00334 // Filter out length modifier 00335 // 00336 c = *sFormat; 00337 do { 00338 if (c == 'l' || c == 'h') { 00339 c = *sFormat++; 00340 continue; 00341 } 00342 break; 00343 } while (1); 00344 // 00345 // Handle specifiers 00346 // 00347 switch (c) { 00348 case 'c': { 00349 char c0; 00350 v = va_arg(*pParamList, int); 00351 c0 = (char)v; 00352 _StoreChar(&BufferDesc, c0); 00353 break; 00354 } 00355 case 'd': 00356 v = va_arg(*pParamList, int); 00357 _PrintInt(&BufferDesc, v, 10, NumDigits, FieldWidth, FormatFlags); 00358 break; 00359 case 'u': 00360 v = va_arg(*pParamList, int); 00361 _PrintUnsigned(&BufferDesc, v, 10, NumDigits, FieldWidth, FormatFlags); 00362 break; 00363 case 'x': 00364 case 'X': 00365 v = va_arg(*pParamList, int); 00366 _PrintUnsigned(&BufferDesc, v, 16, NumDigits, FieldWidth, FormatFlags); 00367 break; 00368 case 's': 00369 { 00370 const char * s = va_arg(*pParamList, const char *); 00371 do { 00372 c = *s++; 00373 if (c == 0) { 00374 break; 00375 } 00376 _StoreChar(&BufferDesc, c); 00377 } while (BufferDesc.ReturnValue >= 0); 00378 } 00379 break; 00380 case 'p': 00381 v = va_arg(*pParamList, int); 00382 _PrintUnsigned(&BufferDesc, v, 16, 8, 8, 0); 00383 break; 00384 case '%': 00385 _StoreChar(&BufferDesc, '%'); 00386 break; 00387 } 00388 sFormat++; 00389 } else { 00390 _StoreChar(&BufferDesc, c); 00391 } 00392 } while (BufferDesc.ReturnValue >= 0); 00393 00394 if (BufferDesc.ReturnValue > 0) { 00395 // 00396 // Write remaining data, if any 00397 // 00398 if (BufferDesc.Cnt != 0) { 00399 SEGGER_RTT_Write(BufferIndex, acBuffer, BufferDesc.Cnt); 00400 } 00401 BufferDesc.ReturnValue += BufferDesc.Cnt; 00402 } 00403 return BufferDesc.ReturnValue; 00404 } 00405 00406 /********************************************************************* 00407 * 00408 * SEGGER_RTT_printf 00409 * 00410 * Function description 00411 * Stores a formatted string in SEGGER RTT control block. 00412 * This data is read by the host. 00413 * 00414 * Parameters 00415 * BufferIndex Index of "Up"-buffer to be used. (e.g. 0 for "Terminal") 00416 * sFormat Pointer to format string, followed by the arguments for conversion 00417 * 00418 * Return values 00419 * >= 0: Number of bytes which have been stored in the "Up"-buffer. 00420 * < 0: Error 00421 * 00422 * Notes 00423 * (1) Conversion specifications have following syntax: 00424 * %[flags][FieldWidth][.Precision]ConversionSpecifier 00425 * (2) Supported flags: 00426 * -: Left justify within the field width 00427 * +: Always print sign extension for signed conversions 00428 * 0: Pad with 0 instead of spaces. Ignored when using '-'-flag or precision 00429 * Supported conversion specifiers: 00430 * c: Print the argument as one char 00431 * d: Print the argument as a signed integer 00432 * u: Print the argument as an unsigned integer 00433 * x: Print the argument as an hexadecimal integer 00434 * s: Print the string pointed to by the argument 00435 * p: Print the argument as an 8-digit hexadecimal integer. (Argument shall be a pointer to void.) 00436 */ 00437 int SEGGER_RTT_printf(unsigned BufferIndex, const char * sFormat, ...) { 00438 va_list ParamList; 00439 00440 va_start(ParamList, sFormat); 00441 return SEGGER_RTT_vprintf(BufferIndex, sFormat, &ParamList); 00442 } 00443 /*************************** End of file ****************************/
Generated on Wed Jul 13 2022 19:38:22 by 1.7.2