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