1 /********************************************************************* 2 * SEGGER MICROCONTROLLER GmbH & Co. KG * 3 * Solutions for real time microcontroller applications * 4 ********************************************************************** 5 * * 6 * (c) 2014 - 2016 SEGGER Microcontroller GmbH & Co. KG * 7 * * 8 * www.segger.com Support: [email protected] * 9 * * 10 ********************************************************************** 11 * * 12 * SEGGER RTT * Real Time Transfer for embedded targets * 13 * * 14 ********************************************************************** 15 * * 16 * All rights reserved. * 17 * * 18 * SEGGER strongly recommends to not make any changes * 19 * to or modify the source code of this software in order to stay * 20 * compatible with the RTT protocol and J-Link. * 21 * * 22 * Redistribution and use in source and binary forms, with or * 23 * without modification, are permitted provided that the following * 24 * conditions are met: * 25 * * 26 * o Redistributions of source code must retain the above copyright * 27 * notice, this list of conditions and the following disclaimer. * 28 * * 29 * o Redistributions in binary form must reproduce the above * 30 * copyright notice, this list of conditions and the following * 31 * disclaimer in the documentation and/or other materials provided * 32 * with the distribution. * 33 * * 34 * o Neither the name of SEGGER Microcontroller GmbH & Co. KG * 35 * nor the names of its contributors may be used to endorse or * 36 * promote products derived from this software without specific * 37 * prior written permission. * 38 * * 39 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND * 40 * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * 41 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * 42 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * 43 * DISCLAIMED. IN NO EVENT SHALL SEGGER Microcontroller BE LIABLE FOR * 44 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * 45 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * 46 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * 47 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * 48 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * 49 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE * 50 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH * 51 * DAMAGE. * 52 * * 53 ********************************************************************** 54 ---------------------------END-OF-HEADER------------------------------ 55 File : SEGGER_RTT_printf.c 56 Purpose : Replacement for printf to write formatted data via RTT 57 Revision: $Rev: 4351 $ 58 ---------------------------------------------------------------------- 59 */ 60 #include "SEGGER_RTT.h" 61 #include "SEGGER_RTT_Conf.h" 62 63 /********************************************************************* 64 * 65 * Defines, configurable 66 * 67 ********************************************************************** 68 */ 69 70 #ifndef SEGGER_RTT_PRINTF_BUFFER_SIZE 71 #define SEGGER_RTT_PRINTF_BUFFER_SIZE (64) 72 #endif 73 74 #include <stdlib.h> 75 #include <stdarg.h> 76 77 78 #define FORMAT_FLAG_LEFT_JUSTIFY (1u << 0) 79 #define FORMAT_FLAG_PAD_ZERO (1u << 1) 80 #define FORMAT_FLAG_PRINT_SIGN (1u << 2) 81 #define FORMAT_FLAG_ALTERNATE (1u << 3) 82 83 /********************************************************************* 84 * 85 * Types 86 * 87 ********************************************************************** 88 */ 89 90 typedef struct { 91 char* pBuffer; 92 unsigned BufferSize; 93 unsigned Cnt; 94 95 int ReturnValue; 96 97 unsigned RTTBufferIndex; 98 } SEGGER_RTT_PRINTF_DESC; 99 100 /********************************************************************* 101 * 102 * Function prototypes 103 * 104 ********************************************************************** 105 */ 106 int SEGGER_RTT_vprintf(unsigned BufferIndex, const char * sFormat, va_list * pParamList); 107 108 /********************************************************************* 109 * 110 * Static code 111 * 112 ********************************************************************** 113 */ 114 /********************************************************************* 115 * 116 * _StoreChar 117 */ 118 static void _StoreChar(SEGGER_RTT_PRINTF_DESC * p, char c) { 119 unsigned Cnt; 120 121 Cnt = p->Cnt; 122 if ((Cnt + 1u) <= p->BufferSize) { 123 *(p->pBuffer + Cnt) = c; 124 p->Cnt = Cnt + 1u; 125 p->ReturnValue++; 126 } 127 // 128 // Write part of string, when the buffer is full 129 // 130 if (p->Cnt == p->BufferSize) { 131 if (SEGGER_RTT_Write(p->RTTBufferIndex, p->pBuffer, p->Cnt) != p->Cnt) { 132 p->ReturnValue = -1; 133 } else { 134 p->Cnt = 0u; 135 } 136 } 137 } 138 139 /********************************************************************* 140 * 141 * _PrintUnsigned 142 */ 143 static void _PrintUnsigned(SEGGER_RTT_PRINTF_DESC * pBufferDesc, unsigned v, unsigned Base, unsigned NumDigits, unsigned FieldWidth, unsigned FormatFlags) { 144 static const char _aV2C[16] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; 145 unsigned Div; 146 unsigned Digit; 147 unsigned Number; 148 unsigned Width; 149 char c; 150 151 Number = v; 152 Digit = 1u; 153 // 154 // Get actual field width 155 // 156 Width = 1u; 157 while (Number >= Base) { 158 Number = (Number / Base); 159 Width++; 160 } 161 if (NumDigits > Width) { 162 Width = NumDigits; 163 } 164 // 165 // Print leading chars if necessary 166 // 167 if ((FormatFlags & FORMAT_FLAG_LEFT_JUSTIFY) == 0u) { 168 if (FieldWidth != 0u) { 169 if (((FormatFlags & FORMAT_FLAG_PAD_ZERO) == FORMAT_FLAG_PAD_ZERO) && (NumDigits == 0u)) { 170 c = '0'; 171 } else { 172 c = ' '; 173 } 174 while ((FieldWidth != 0u) && (Width < FieldWidth)) { 175 FieldWidth--; 176 _StoreChar(pBufferDesc, c); 177 if (pBufferDesc->ReturnValue < 0) { 178 break; 179 } 180 } 181 } 182 } 183 if (pBufferDesc->ReturnValue >= 0) { 184 // 185 // Compute Digit. 186 // Loop until Digit has the value of the highest digit required. 187 // Example: If the output is 345 (Base 10), loop 2 times until Digit is 100. 188 // 189 while (1) { 190 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) 191 NumDigits--; 192 } else { 193 Div = v / Digit; 194 if (Div < Base) { // Is our divider big enough to extract the highest digit from value? => Done 195 break; 196 } 197 } 198 Digit *= Base; 199 } 200 // 201 // Output digits 202 // 203 do { 204 Div = v / Digit; 205 v -= Div * Digit; 206 _StoreChar(pBufferDesc, _aV2C[Div]); 207 if (pBufferDesc->ReturnValue < 0) { 208 break; 209 } 210 Digit /= Base; 211 } while (Digit); 212 // 213 // Print trailing spaces if necessary 214 // 215 if ((FormatFlags & FORMAT_FLAG_LEFT_JUSTIFY) == FORMAT_FLAG_LEFT_JUSTIFY) { 216 if (FieldWidth != 0u) { 217 while ((FieldWidth != 0u) && (Width < FieldWidth)) { 218 FieldWidth--; 219 _StoreChar(pBufferDesc, ' '); 220 if (pBufferDesc->ReturnValue < 0) { 221 break; 222 } 223 } 224 } 225 } 226 } 227 } 228 229 /********************************************************************* 230 * 231 * _PrintInt 232 */ 233 static void _PrintInt(SEGGER_RTT_PRINTF_DESC * pBufferDesc, int v, unsigned Base, unsigned NumDigits, unsigned FieldWidth, unsigned FormatFlags) { 234 unsigned Width; 235 int Number; 236 237 Number = (v < 0) ? -v : v; 238 239 // 240 // Get actual field width 241 // 242 Width = 1u; 243 while (Number >= (int)Base) { 244 Number = (Number / (int)Base); 245 Width++; 246 } 247 if (NumDigits > Width) { 248 Width = NumDigits; 249 } 250 if ((FieldWidth > 0u) && ((v < 0) || ((FormatFlags & FORMAT_FLAG_PRINT_SIGN) == FORMAT_FLAG_PRINT_SIGN))) { 251 FieldWidth--; 252 } 253 254 // 255 // Print leading spaces if necessary 256 // 257 if ((((FormatFlags & FORMAT_FLAG_PAD_ZERO) == 0u) || (NumDigits != 0u)) && ((FormatFlags & FORMAT_FLAG_LEFT_JUSTIFY) == 0u)) { 258 if (FieldWidth != 0u) { 259 while ((FieldWidth != 0u) && (Width < FieldWidth)) { 260 FieldWidth--; 261 _StoreChar(pBufferDesc, ' '); 262 if (pBufferDesc->ReturnValue < 0) { 263 break; 264 } 265 } 266 } 267 } 268 // 269 // Print sign if necessary 270 // 271 if (pBufferDesc->ReturnValue >= 0) { 272 if (v < 0) { 273 v = -v; 274 _StoreChar(pBufferDesc, '-'); 275 } else if ((FormatFlags & FORMAT_FLAG_PRINT_SIGN) == FORMAT_FLAG_PRINT_SIGN) { 276 _StoreChar(pBufferDesc, '+'); 277 } else { 278 279 } 280 if (pBufferDesc->ReturnValue >= 0) { 281 // 282 // Print leading zeros if necessary 283 // 284 if (((FormatFlags & FORMAT_FLAG_PAD_ZERO) == FORMAT_FLAG_PAD_ZERO) && ((FormatFlags & FORMAT_FLAG_LEFT_JUSTIFY) == 0u) && (NumDigits == 0u)) { 285 if (FieldWidth != 0u) { 286 while ((FieldWidth != 0u) && (Width < FieldWidth)) { 287 FieldWidth--; 288 _StoreChar(pBufferDesc, '0'); 289 if (pBufferDesc->ReturnValue < 0) { 290 break; 291 } 292 } 293 } 294 } 295 if (pBufferDesc->ReturnValue >= 0) { 296 // 297 // Print number without sign 298 // 299 _PrintUnsigned(pBufferDesc, (unsigned)v, Base, NumDigits, FieldWidth, FormatFlags); 300 } 301 } 302 } 303 } 304 305 /********************************************************************* 306 * 307 * Public code 308 * 309 ********************************************************************** 310 */ 311 /********************************************************************* 312 * 313 * SEGGER_RTT_vprintf 314 * 315 * Function description 316 * Stores a formatted string in SEGGER RTT control block. 317 * This data is read by the host. 318 * 319 * Parameters 320 * BufferIndex Index of "Up"-buffer to be used. (e.g. 0 for "Terminal") 321 * sFormat Pointer to format string 322 * pParamList Pointer to the list of arguments for the format string 323 * 324 * Return values 325 * >= 0: Number of bytes which have been stored in the "Up"-buffer. 326 * < 0: Error 327 */ 328 int SEGGER_RTT_vprintf(unsigned BufferIndex, const char * sFormat, va_list * pParamList) { 329 char c; 330 SEGGER_RTT_PRINTF_DESC BufferDesc; 331 int v; 332 unsigned NumDigits; 333 unsigned FormatFlags; 334 unsigned FieldWidth; 335 char acBuffer[SEGGER_RTT_PRINTF_BUFFER_SIZE]; 336 337 BufferDesc.pBuffer = acBuffer; 338 BufferDesc.BufferSize = SEGGER_RTT_PRINTF_BUFFER_SIZE; 339 BufferDesc.Cnt = 0u; 340 BufferDesc.RTTBufferIndex = BufferIndex; 341 BufferDesc.ReturnValue = 0; 342 343 do { 344 c = *sFormat; 345 sFormat++; 346 if (c == 0u) { 347 break; 348 } 349 if (c == '%') { 350 // 351 // Filter out flags 352 // 353 FormatFlags = 0u; 354 v = 1; 355 do { 356 c = *sFormat; 357 switch (c) { 358 case '-': FormatFlags |= FORMAT_FLAG_LEFT_JUSTIFY; sFormat++; break; 359 case '0': FormatFlags |= FORMAT_FLAG_PAD_ZERO; sFormat++; break; 360 case '+': FormatFlags |= FORMAT_FLAG_PRINT_SIGN; sFormat++; break; 361 case '#': FormatFlags |= FORMAT_FLAG_ALTERNATE; sFormat++; break; 362 default: v = 0; break; 363 } 364 } while (v); 365 // 366 // filter out field with 367 // 368 FieldWidth = 0u; 369 do { 370 c = *sFormat; 371 if ((c < '0') || (c > '9')) { 372 break; 373 } 374 sFormat++; 375 FieldWidth = (FieldWidth * 10u) + ((unsigned)c - '0'); 376 } while (1); 377 378 // 379 // Filter out precision (number of digits to display) 380 // 381 NumDigits = 0u; 382 c = *sFormat; 383 if (c == '.') { 384 sFormat++; 385 do { 386 c = *sFormat; 387 if ((c < '0') || (c > '9')) { 388 break; 389 } 390 sFormat++; 391 NumDigits = NumDigits * 10u + ((unsigned)c - '0'); 392 } while (1); 393 } 394 // 395 // Filter out length modifier 396 // 397 c = *sFormat; 398 do { 399 if ((c == 'l') || (c == 'h')) { 400 sFormat++; 401 c = *sFormat; 402 } else { 403 break; 404 } 405 } while (1); 406 // 407 // Handle specifiers 408 // 409 switch (c) { 410 case 'c': { 411 char c0; 412 v = va_arg(*pParamList, int); 413 c0 = (char)v; 414 _StoreChar(&BufferDesc, c0); 415 break; 416 } 417 case 'd': 418 v = va_arg(*pParamList, int); 419 _PrintInt(&BufferDesc, v, 10u, NumDigits, FieldWidth, FormatFlags); 420 break; 421 case 'u': 422 v = va_arg(*pParamList, int); 423 _PrintUnsigned(&BufferDesc, (unsigned)v, 10u, NumDigits, FieldWidth, FormatFlags); 424 break; 425 case 'x': 426 case 'X': 427 v = va_arg(*pParamList, int); 428 _PrintUnsigned(&BufferDesc, (unsigned)v, 16u, NumDigits, FieldWidth, FormatFlags); 429 break; 430 case 's': 431 { 432 const char * s = va_arg(*pParamList, const char *); 433 do { 434 c = *s; 435 s++; 436 if (c == '\0') { 437 break; 438 } 439 _StoreChar(&BufferDesc, c); 440 } while (BufferDesc.ReturnValue >= 0); 441 } 442 break; 443 case 'p': 444 v = va_arg(*pParamList, int); 445 _PrintUnsigned(&BufferDesc, (unsigned)v, 16u, 8u, 8u, 0u); 446 break; 447 case '%': 448 _StoreChar(&BufferDesc, '%'); 449 break; 450 default: 451 break; 452 } 453 sFormat++; 454 } else { 455 _StoreChar(&BufferDesc, c); 456 } 457 } while (BufferDesc.ReturnValue >= 0); 458 459 if (BufferDesc.ReturnValue > 0) { 460 // 461 // Write remaining data, if any 462 // 463 if (BufferDesc.Cnt != 0u) { 464 SEGGER_RTT_Write(BufferIndex, acBuffer, BufferDesc.Cnt); 465 } 466 BufferDesc.ReturnValue += (int)BufferDesc.Cnt; 467 } 468 return BufferDesc.ReturnValue; 469 } 470 471 /********************************************************************* 472 * 473 * SEGGER_RTT_printf 474 * 475 * Function description 476 * Stores a formatted string in SEGGER RTT control block. 477 * This data is read by the host. 478 * 479 * Parameters 480 * BufferIndex Index of "Up"-buffer to be used. (e.g. 0 for "Terminal") 481 * sFormat Pointer to format string, followed by the arguments for conversion 482 * 483 * Return values 484 * >= 0: Number of bytes which have been stored in the "Up"-buffer. 485 * < 0: Error 486 * 487 * Notes 488 * (1) Conversion specifications have following syntax: 489 * %[flags][FieldWidth][.Precision]ConversionSpecifier 490 * (2) Supported flags: 491 * -: Left justify within the field width 492 * +: Always print sign extension for signed conversions 493 * 0: Pad with 0 instead of spaces. Ignored when using '-'-flag or precision 494 * Supported conversion specifiers: 495 * c: Print the argument as one char 496 * d: Print the argument as a signed integer 497 * u: Print the argument as an unsigned integer 498 * x: Print the argument as an hexadecimal integer 499 * s: Print the string pointed to by the argument 500 * p: Print the argument as an 8-digit hexadecimal integer. (Argument shall be a pointer to void.) 501 */ 502 int SEGGER_RTT_printf(unsigned BufferIndex, const char * sFormat, ...) { 503 int r; 504 va_list ParamList; 505 506 va_start(ParamList, sFormat); 507 r = SEGGER_RTT_vprintf(BufferIndex, sFormat, &ParamList); 508 va_end(ParamList); 509 return r; 510 } 511 /*************************** End of file ****************************/ 512