Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependents: 3_Test_AFE 1_Test_Flash_ADC_RTT
SEGGER_RTT_printf.c
00001 /********************************************************************* 00002 * SEGGER Microcontroller GmbH * 00003 * The Embedded Experts * 00004 ********************************************************************** 00005 * * 00006 * (c) 1995 - 2019 SEGGER Microcontroller GmbH * 00007 * * 00008 * www.segger.com Support: support@segger.com * 00009 * * 00010 ********************************************************************** 00011 * * 00012 * SEGGER RTT * Real Time Transfer for embedded targets * 00013 * * 00014 ********************************************************************** 00015 * * 00016 * All rights reserved. * 00017 * * 00018 * SEGGER strongly recommends to not make any changes * 00019 * to or modify the source code of this software in order to stay * 00020 * compatible with the RTT protocol and J-Link. * 00021 * * 00022 * Redistribution and use in source and binary forms, with or * 00023 * without modification, are permitted provided that the following * 00024 * conditions are met: * 00025 * * 00026 * o Redistributions of source code must retain the above copyright * 00027 * notice, this list of conditions and the following disclaimer. * 00028 * * 00029 * o Redistributions in binary form must reproduce the above * 00030 * copyright notice, this list of conditions and the following * 00031 * disclaimer in the documentation and/or other materials provided * 00032 * with the distribution. * 00033 * * 00034 * o Neither the name of SEGGER Microcontroller GmbH * 00035 * nor the names of its contributors may be used to endorse or * 00036 * promote products derived from this software without specific * 00037 * prior written permission. * 00038 * * 00039 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND * 00040 * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * 00041 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * 00042 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * 00043 * DISCLAIMED. IN NO EVENT SHALL SEGGER Microcontroller BE LIABLE FOR * 00044 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * 00045 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * 00046 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * 00047 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * 00048 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * 00049 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE * 00050 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH * 00051 * DAMAGE. * 00052 * * 00053 ********************************************************************** 00054 * * 00055 * RTT version: 6.44i * 00056 * * 00057 ********************************************************************** 00058 ---------------------------END-OF-HEADER------------------------------ 00059 File : SEGGER_RTT_printf.c 00060 Purpose : Replacement for printf to write formatted data via RTT 00061 Revision: Rev: 12360 00062 ---------------------------------------------------------------------- 00063 */ 00064 #include "SEGGER_RTT.h" 00065 #include "SEGGER_RTT_Conf.h" 00066 00067 /********************************************************************* 00068 * 00069 * Defines, configurable 00070 * 00071 ********************************************************************** 00072 */ 00073 00074 #ifndef SEGGER_RTT_PRINTF_BUFFER_SIZE 00075 #define SEGGER_RTT_PRINTF_BUFFER_SIZE (64) 00076 #endif 00077 00078 #include <stdlib.h> 00079 #include <stdarg.h> 00080 00081 00082 #define FORMAT_FLAG_LEFT_JUSTIFY (1u << 0) 00083 #define FORMAT_FLAG_PAD_ZERO (1u << 1) 00084 #define FORMAT_FLAG_PRINT_SIGN (1u << 2) 00085 #define FORMAT_FLAG_ALTERNATE (1u << 3) 00086 00087 /********************************************************************* 00088 * 00089 * Types 00090 * 00091 ********************************************************************** 00092 */ 00093 00094 typedef struct { 00095 char* pBuffer; 00096 unsigned BufferSize; 00097 unsigned Cnt; 00098 00099 int ReturnValue; 00100 00101 unsigned RTTBufferIndex; 00102 } SEGGER_RTT_PRINTF_DESC; 00103 00104 /********************************************************************* 00105 * 00106 * Function prototypes 00107 * 00108 ********************************************************************** 00109 */ 00110 00111 /********************************************************************* 00112 * 00113 * Static code 00114 * 00115 ********************************************************************** 00116 */ 00117 /********************************************************************* 00118 * 00119 * _StoreChar 00120 */ 00121 static void _StoreChar(SEGGER_RTT_PRINTF_DESC * p, char c) { 00122 unsigned Cnt; 00123 00124 Cnt = p->Cnt; 00125 if ((Cnt + 1u) <= p->BufferSize) { 00126 *(p->pBuffer + Cnt) = c; 00127 p->Cnt = Cnt + 1u; 00128 p->ReturnValue++; 00129 } 00130 // 00131 // Write part of string, when the buffer is full 00132 // 00133 if (p->Cnt == p->BufferSize) { 00134 if (SEGGER_RTT_Write(p->RTTBufferIndex, p->pBuffer, p->Cnt) != p->Cnt) { 00135 p->ReturnValue = -1; 00136 } else { 00137 p->Cnt = 0u; 00138 } 00139 } 00140 } 00141 00142 /********************************************************************* 00143 * 00144 * _PrintUnsigned 00145 */ 00146 static void _PrintUnsigned(SEGGER_RTT_PRINTF_DESC * pBufferDesc, unsigned v, unsigned Base, unsigned NumDigits, unsigned FieldWidth, unsigned FormatFlags) { 00147 static const char _aV2C[16] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; 00148 unsigned Div; 00149 unsigned Digit; 00150 unsigned Number; 00151 unsigned Width; 00152 char c; 00153 00154 Number = v; 00155 Digit = 1u; 00156 // 00157 // Get actual field width 00158 // 00159 Width = 1u; 00160 while (Number >= Base) { 00161 Number = (Number / Base); 00162 Width++; 00163 } 00164 if (NumDigits > Width) { 00165 Width = NumDigits; 00166 } 00167 // 00168 // Print leading chars if necessary 00169 // 00170 if ((FormatFlags & FORMAT_FLAG_LEFT_JUSTIFY) == 0u) { 00171 if (FieldWidth != 0u) { 00172 if (((FormatFlags & FORMAT_FLAG_PAD_ZERO) == FORMAT_FLAG_PAD_ZERO) && (NumDigits == 0u)) { 00173 c = '0'; 00174 } else { 00175 c = ' '; 00176 } 00177 while ((FieldWidth != 0u) && (Width < FieldWidth)) { 00178 FieldWidth--; 00179 _StoreChar(pBufferDesc, c); 00180 if (pBufferDesc->ReturnValue < 0) { 00181 break; 00182 } 00183 } 00184 } 00185 } 00186 if (pBufferDesc->ReturnValue >= 0) { 00187 // 00188 // Compute Digit. 00189 // Loop until Digit has the value of the highest digit required. 00190 // Example: If the output is 345 (Base 10), loop 2 times until Digit is 100. 00191 // 00192 while (1) { 00193 if (NumDigits > 1u) { // User specified a min number of digits to print? => Make sure we loop at least that often, before checking anything else (> 1 check avoids problems with NumDigits being signed / unsigned) 00194 NumDigits--; 00195 } else { 00196 Div = v / Digit; 00197 if (Div < Base) { // Is our divider big enough to extract the highest digit from value? => Done 00198 break; 00199 } 00200 } 00201 Digit *= Base; 00202 } 00203 // 00204 // Output digits 00205 // 00206 do { 00207 Div = v / Digit; 00208 v -= Div * Digit; 00209 _StoreChar(pBufferDesc, _aV2C[Div]); 00210 if (pBufferDesc->ReturnValue < 0) { 00211 break; 00212 } 00213 Digit /= Base; 00214 } while (Digit); 00215 // 00216 // Print trailing spaces if necessary 00217 // 00218 if ((FormatFlags & FORMAT_FLAG_LEFT_JUSTIFY) == FORMAT_FLAG_LEFT_JUSTIFY) { 00219 if (FieldWidth != 0u) { 00220 while ((FieldWidth != 0u) && (Width < FieldWidth)) { 00221 FieldWidth--; 00222 _StoreChar(pBufferDesc, ' '); 00223 if (pBufferDesc->ReturnValue < 0) { 00224 break; 00225 } 00226 } 00227 } 00228 } 00229 } 00230 } 00231 00232 /********************************************************************* 00233 * 00234 * _PrintInt 00235 */ 00236 static void _PrintInt(SEGGER_RTT_PRINTF_DESC * pBufferDesc, int v, unsigned Base, unsigned NumDigits, unsigned FieldWidth, unsigned FormatFlags) { 00237 unsigned Width; 00238 int Number; 00239 00240 Number = (v < 0) ? -v : v; 00241 00242 // 00243 // Get actual field width 00244 // 00245 Width = 1u; 00246 while (Number >= (int)Base) { 00247 Number = (Number / (int)Base); 00248 Width++; 00249 } 00250 if (NumDigits > Width) { 00251 Width = NumDigits; 00252 } 00253 if ((FieldWidth > 0u) && ((v < 0) || ((FormatFlags & FORMAT_FLAG_PRINT_SIGN) == FORMAT_FLAG_PRINT_SIGN))) { 00254 FieldWidth--; 00255 } 00256 00257 // 00258 // Print leading spaces if necessary 00259 // 00260 if ((((FormatFlags & FORMAT_FLAG_PAD_ZERO) == 0u) || (NumDigits != 0u)) && ((FormatFlags & FORMAT_FLAG_LEFT_JUSTIFY) == 0u)) { 00261 if (FieldWidth != 0u) { 00262 while ((FieldWidth != 0u) && (Width < FieldWidth)) { 00263 FieldWidth--; 00264 _StoreChar(pBufferDesc, ' '); 00265 if (pBufferDesc->ReturnValue < 0) { 00266 break; 00267 } 00268 } 00269 } 00270 } 00271 // 00272 // Print sign if necessary 00273 // 00274 if (pBufferDesc->ReturnValue >= 0) { 00275 if (v < 0) { 00276 v = -v; 00277 _StoreChar(pBufferDesc, '-'); 00278 } else if ((FormatFlags & FORMAT_FLAG_PRINT_SIGN) == FORMAT_FLAG_PRINT_SIGN) { 00279 _StoreChar(pBufferDesc, '+'); 00280 } else { 00281 00282 } 00283 if (pBufferDesc->ReturnValue >= 0) { 00284 // 00285 // Print leading zeros if necessary 00286 // 00287 if (((FormatFlags & FORMAT_FLAG_PAD_ZERO) == FORMAT_FLAG_PAD_ZERO) && ((FormatFlags & FORMAT_FLAG_LEFT_JUSTIFY) == 0u) && (NumDigits == 0u)) { 00288 if (FieldWidth != 0u) { 00289 while ((FieldWidth != 0u) && (Width < FieldWidth)) { 00290 FieldWidth--; 00291 _StoreChar(pBufferDesc, '0'); 00292 if (pBufferDesc->ReturnValue < 0) { 00293 break; 00294 } 00295 } 00296 } 00297 } 00298 if (pBufferDesc->ReturnValue >= 0) { 00299 // 00300 // Print number without sign 00301 // 00302 _PrintUnsigned(pBufferDesc, (unsigned)v, Base, NumDigits, FieldWidth, FormatFlags); 00303 } 00304 } 00305 } 00306 } 00307 00308 /********************************************************************* 00309 * 00310 * Public code 00311 * 00312 ********************************************************************** 00313 */ 00314 /********************************************************************* 00315 * 00316 * SEGGER_RTT_vprintf 00317 * 00318 * Function description 00319 * Stores a formatted string in SEGGER RTT control block. 00320 * This data is read by the host. 00321 * 00322 * Parameters 00323 * BufferIndex Index of "Up"-buffer to be used. (e.g. 0 for "Terminal") 00324 * sFormat Pointer to format string 00325 * pParamList Pointer to the list of arguments for the format string 00326 * 00327 * Return values 00328 * >= 0: Number of bytes which have been stored in the "Up"-buffer. 00329 * < 0: Error 00330 */ 00331 int SEGGER_RTT_vprintf(unsigned BufferIndex, const char * sFormat, va_list * pParamList) { 00332 char c; 00333 SEGGER_RTT_PRINTF_DESC BufferDesc; 00334 int v; 00335 unsigned NumDigits; 00336 unsigned FormatFlags; 00337 unsigned FieldWidth; 00338 char acBuffer[SEGGER_RTT_PRINTF_BUFFER_SIZE]; 00339 00340 BufferDesc.pBuffer = acBuffer; 00341 BufferDesc.BufferSize = SEGGER_RTT_PRINTF_BUFFER_SIZE; 00342 BufferDesc.Cnt = 0u; 00343 BufferDesc.RTTBufferIndex = BufferIndex; 00344 BufferDesc.ReturnValue = 0; 00345 00346 do { 00347 c = *sFormat; 00348 sFormat++; 00349 if (c == 0u) { 00350 break; 00351 } 00352 if (c == '%') { 00353 // 00354 // Filter out flags 00355 // 00356 FormatFlags = 0u; 00357 v = 1; 00358 do { 00359 c = *sFormat; 00360 switch (c) { 00361 case '-': FormatFlags |= FORMAT_FLAG_LEFT_JUSTIFY; sFormat++; break; 00362 case '0': FormatFlags |= FORMAT_FLAG_PAD_ZERO; sFormat++; break; 00363 case '+': FormatFlags |= FORMAT_FLAG_PRINT_SIGN; sFormat++; break; 00364 case '#': FormatFlags |= FORMAT_FLAG_ALTERNATE; sFormat++; break; 00365 default: v = 0; break; 00366 } 00367 } while (v); 00368 // 00369 // filter out field with 00370 // 00371 FieldWidth = 0u; 00372 do { 00373 c = *sFormat; 00374 if ((c < '0') || (c > '9')) { 00375 break; 00376 } 00377 sFormat++; 00378 FieldWidth = (FieldWidth * 10u) + ((unsigned)c - '0'); 00379 } while (1); 00380 00381 // 00382 // Filter out precision (number of digits to display) 00383 // 00384 NumDigits = 0u; 00385 c = *sFormat; 00386 if (c == '.') { 00387 sFormat++; 00388 do { 00389 c = *sFormat; 00390 if ((c < '0') || (c > '9')) { 00391 break; 00392 } 00393 sFormat++; 00394 NumDigits = NumDigits * 10u + ((unsigned)c - '0'); 00395 } while (1); 00396 } 00397 // 00398 // Filter out length modifier 00399 // 00400 c = *sFormat; 00401 do { 00402 if ((c == 'l') || (c == 'h')) { 00403 sFormat++; 00404 c = *sFormat; 00405 } else { 00406 break; 00407 } 00408 } while (1); 00409 // 00410 // Handle specifiers 00411 // 00412 switch (c) { 00413 case 'c': { 00414 char c0; 00415 v = va_arg(*pParamList, int); 00416 c0 = (char)v; 00417 _StoreChar(&BufferDesc, c0); 00418 break; 00419 } 00420 case 'd': 00421 v = va_arg(*pParamList, int); 00422 _PrintInt(&BufferDesc, v, 10u, NumDigits, FieldWidth, FormatFlags); 00423 break; 00424 case 'u': 00425 v = va_arg(*pParamList, int); 00426 _PrintUnsigned(&BufferDesc, (unsigned)v, 10u, NumDigits, FieldWidth, FormatFlags); 00427 break; 00428 case 'x': 00429 case 'X': 00430 v = va_arg(*pParamList, int); 00431 _PrintUnsigned(&BufferDesc, (unsigned)v, 16u, NumDigits, FieldWidth, FormatFlags); 00432 break; 00433 case 's': 00434 { 00435 const char * s = va_arg(*pParamList, const char *); 00436 do { 00437 c = *s; 00438 s++; 00439 if (c == '\0') { 00440 break; 00441 } 00442 _StoreChar(&BufferDesc, c); 00443 } while (BufferDesc.ReturnValue >= 0); 00444 } 00445 break; 00446 case 'p': 00447 v = va_arg(*pParamList, int); 00448 _PrintUnsigned(&BufferDesc, (unsigned)v, 16u, 8u, 8u, 0u); 00449 break; 00450 case '%': 00451 _StoreChar(&BufferDesc, '%'); 00452 break; 00453 default: 00454 break; 00455 } 00456 sFormat++; 00457 } else { 00458 _StoreChar(&BufferDesc, c); 00459 } 00460 } while (BufferDesc.ReturnValue >= 0); 00461 00462 if (BufferDesc.ReturnValue > 0) { 00463 // 00464 // Write remaining data, if any 00465 // 00466 if (BufferDesc.Cnt != 0u) { 00467 SEGGER_RTT_Write(BufferIndex, acBuffer, BufferDesc.Cnt); 00468 } 00469 BufferDesc.ReturnValue += (int)BufferDesc.Cnt; 00470 } 00471 return BufferDesc.ReturnValue; 00472 } 00473 00474 /********************************************************************* 00475 * 00476 * SEGGER_RTT_printf 00477 * 00478 * Function description 00479 * Stores a formatted string in SEGGER RTT control block. 00480 * This data is read by the host. 00481 * 00482 * Parameters 00483 * BufferIndex Index of "Up"-buffer to be used. (e.g. 0 for "Terminal") 00484 * sFormat Pointer to format string, followed by the arguments for conversion 00485 * 00486 * Return values 00487 * >= 0: Number of bytes which have been stored in the "Up"-buffer. 00488 * < 0: Error 00489 * 00490 * Notes 00491 * (1) Conversion specifications have following syntax: 00492 * %[flags][FieldWidth][.Precision]ConversionSpecifier 00493 * (2) Supported flags: 00494 * -: Left justify within the field width 00495 * +: Always print sign extension for signed conversions 00496 * 0: Pad with 0 instead of spaces. Ignored when using '-'-flag or precision 00497 * Supported conversion specifiers: 00498 * c: Print the argument as one char 00499 * d: Print the argument as a signed integer 00500 * u: Print the argument as an unsigned integer 00501 * x: Print the argument as an hexadecimal integer 00502 * s: Print the string pointed to by the argument 00503 * p: Print the argument as an 8-digit hexadecimal integer. (Argument shall be a pointer to void.) 00504 */ 00505 int SEGGER_RTT_printf(unsigned BufferIndex, const char * sFormat, ...) { 00506 int r; 00507 va_list ParamList; 00508 00509 va_start(ParamList, sFormat); 00510 r = SEGGER_RTT_vprintf(BufferIndex, sFormat, &ParamList); 00511 va_end(ParamList); 00512 return r; 00513 } 00514 /*************************** End of file ****************************/
Generated on Tue Jul 12 2022 22:00:51 by
1.7.2