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