Seger Real time terminal, use RTT viewer to view messages through the segger debugger instead of art
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 1.7.2