source: trunk/firmware/SES/Drivers/RTT/SEGGER_RTT_printf.c@ 4

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