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