Appiko
SEGGER_RTT_printf.c
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: 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 * 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 ****************************/