1 | /**************************************************************************//*****
|
2 | * @file printf.c
|
3 | * @brief Implementation of several stdio.h methods, such as printf(),
|
4 | * sprintf() and so on. This reduces the memory footprint of the
|
5 | * binary when using those methods, compared to the libc implementation.
|
6 | ********************************************************************************/
|
7 | #include <stdio.h>
|
8 | #include <stdarg.h>
|
9 | #include <stm32f4xx_usart.h>
|
10 |
|
11 |
|
12 | /**
|
13 | * @brief Transmit a char, if you want to use printf(),
|
14 | * you need implement this function
|
15 | *
|
16 | * @param pStr Storage string.
|
17 | * @param c Character to write.
|
18 | */
|
19 | void PrintChar(char c)
|
20 | {
|
21 | if (c == '\n') {
|
22 | while (!(USART1->SR & 0x0080));
|
23 | USART1->DR = 0x0D;
|
24 | }
|
25 | while (!(USART1->SR & 0x0080));
|
26 | USART1->DR = (c & 0x1FF);
|
27 | }
|
28 |
|
29 | /** Maximum string size allowed (in bytes). */
|
30 | #define MAX_STRING_SIZE 100
|
31 |
|
32 |
|
33 | /** Required for proper compilation. */
|
34 | struct _reent r = {0, (FILE *) 0, (FILE *) 1, (FILE *) 0};
|
35 | //struct _reent *_impure_ptr = &r;
|
36 |
|
37 | /**
|
38 | * @brief Writes a character inside the given string. Returns 1.
|
39 | *
|
40 | * @param pStr Storage string.
|
41 | * @param c Character to write.
|
42 | */
|
43 | signed int PutChar(char *pStr, char c)
|
44 | {
|
45 | *pStr = c;
|
46 | return 1;
|
47 | }
|
48 |
|
49 |
|
50 | /**
|
51 | * @brief Writes a string inside the given string.
|
52 | *
|
53 | * @param pStr Storage string.
|
54 | * @param pSource Source string.
|
55 | * @return The size of the written
|
56 | */
|
57 | signed int PutString(char *pStr, const char *pSource)
|
58 | {
|
59 | signed int num = 0;
|
60 |
|
61 | while (*pSource != 0) {
|
62 |
|
63 | *pStr++ = *pSource++;
|
64 | num++;
|
65 | }
|
66 |
|
67 | return num;
|
68 | }
|
69 |
|
70 |
|
71 | /**
|
72 | * @brief Writes an unsigned int inside the given string, using the provided fill &
|
73 | * width parameters.
|
74 | *
|
75 | * @param pStr Storage string.
|
76 | * @param fill Fill character.
|
77 | * @param width Minimum integer width.
|
78 | * @param value Integer value.
|
79 | */
|
80 | signed int PutUnsignedInt(
|
81 | char *pStr,
|
82 | char fill,
|
83 | signed int width,
|
84 | unsigned int value)
|
85 | {
|
86 | signed int num = 0;
|
87 |
|
88 | /* Take current digit into account when calculating width */
|
89 | width--;
|
90 |
|
91 | /* Recursively write upper digits */
|
92 | if ((value / 10) > 0) {
|
93 |
|
94 | num = PutUnsignedInt(pStr, fill, width, value / 10);
|
95 | pStr += num;
|
96 | }
|
97 |
|
98 | /* Write filler characters */
|
99 | else {
|
100 |
|
101 | while (width > 0) {
|
102 |
|
103 | PutChar(pStr, fill);
|
104 | pStr++;
|
105 | num++;
|
106 | width--;
|
107 | }
|
108 | }
|
109 |
|
110 | /* Write lower digit */
|
111 | num += PutChar(pStr, (value % 10) + '0');
|
112 |
|
113 | return num;
|
114 | }
|
115 |
|
116 |
|
117 | /**
|
118 | * @brief Writes a signed int inside the given string, using the provided fill & width
|
119 | * parameters.
|
120 | *
|
121 | * @param pStr Storage string.
|
122 | * @param fill Fill character.
|
123 | * @param width Minimum integer width.
|
124 | * @param value Signed integer value.
|
125 | */
|
126 | signed int PutSignedInt(
|
127 | char *pStr,
|
128 | char fill,
|
129 | signed int width,
|
130 | signed int value)
|
131 | {
|
132 | signed int num = 0;
|
133 | unsigned int absolute;
|
134 |
|
135 | /* Compute absolute value */
|
136 | if (value < 0) {
|
137 |
|
138 | absolute = -value;
|
139 | }
|
140 | else {
|
141 |
|
142 | absolute = value;
|
143 | }
|
144 |
|
145 | /* Take current digit into account when calculating width */
|
146 | width--;
|
147 |
|
148 | /* Recursively write upper digits */
|
149 | if ((absolute / 10) > 0) {
|
150 |
|
151 | if (value < 0) {
|
152 |
|
153 | num = PutSignedInt(pStr, fill, width, -(absolute / 10));
|
154 | }
|
155 | else {
|
156 |
|
157 | num = PutSignedInt(pStr, fill, width, absolute / 10);
|
158 | }
|
159 | pStr += num;
|
160 | }
|
161 | else {
|
162 |
|
163 | /* Reserve space for sign */
|
164 | if (value < 0) {
|
165 |
|
166 | width--;
|
167 | }
|
168 |
|
169 | /* Write filler characters */
|
170 | while (width > 0) {
|
171 |
|
172 | PutChar(pStr, fill);
|
173 | pStr++;
|
174 | num++;
|
175 | width--;
|
176 | }
|
177 |
|
178 | /* Write sign */
|
179 | if (value < 0) {
|
180 |
|
181 | num += PutChar(pStr, '-');
|
182 | pStr++;
|
183 | }
|
184 | }
|
185 |
|
186 | /* Write lower digit */
|
187 | num += PutChar(pStr, (absolute % 10) + '0');
|
188 |
|
189 | return num;
|
190 | }
|
191 |
|
192 |
|
193 | /**
|
194 | * @brief Writes an hexadecimal value into a string, using the given fill, width &
|
195 | * capital parameters.
|
196 | *
|
197 | * @param pStr Storage string.
|
198 | * @param fill Fill character.
|
199 | * @param width Minimum integer width.
|
200 | * @param maj Indicates if the letters must be printed in lower- or upper-case.
|
201 | * @param value Hexadecimal value.
|
202 | *
|
203 | * @return The number of char written
|
204 | */
|
205 | signed int PutHexa(
|
206 | char *pStr,
|
207 | char fill,
|
208 | signed int width,
|
209 | unsigned char maj,
|
210 | unsigned int value)
|
211 | {
|
212 | signed int num = 0;
|
213 |
|
214 | /* Decrement width */
|
215 | width--;
|
216 |
|
217 | /* Recursively output upper digits */
|
218 | if ((value >> 4) > 0) {
|
219 |
|
220 | num += PutHexa(pStr, fill, width, maj, value >> 4);
|
221 | pStr += num;
|
222 | }
|
223 | /* Write filler chars */
|
224 | else {
|
225 |
|
226 | while (width > 0) {
|
227 |
|
228 | PutChar(pStr, fill);
|
229 | pStr++;
|
230 | num++;
|
231 | width--;
|
232 | }
|
233 | }
|
234 |
|
235 | /* Write current digit */
|
236 | if ((value & 0xF) < 10) {
|
237 |
|
238 | PutChar(pStr, (value & 0xF) + '0');
|
239 | }
|
240 | else if (maj) {
|
241 |
|
242 | PutChar(pStr, (value & 0xF) - 10 + 'A');
|
243 | }
|
244 | else {
|
245 |
|
246 | PutChar(pStr, (value & 0xF) - 10 + 'a');
|
247 | }
|
248 | num++;
|
249 |
|
250 | return num;
|
251 | }
|
252 |
|
253 |
|
254 |
|
255 | /* Global Functions ----------------------------------------------------------- */
|
256 |
|
257 |
|
258 | /**
|
259 | * @brief Stores the result of a formatted string into another string. Format
|
260 | * arguments are given in a va_list instance.
|
261 | *
|
262 | * @param pStr Destination string.
|
263 | * @param length Length of Destination string.
|
264 | * @param pFormat Format string.
|
265 | * @param ap Argument list.
|
266 | *
|
267 | * @return The number of characters written.
|
268 | */
|
269 | signed int vsnprintf(char *pStr, size_t length, const char *pFormat, va_list ap)
|
270 | {
|
271 | char fill;
|
272 | unsigned char width;
|
273 | signed int num = 0;
|
274 | signed int size = 0;
|
275 |
|
276 | /* Clear the string */
|
277 | if (pStr) {
|
278 |
|
279 | *pStr = 0;
|
280 | }
|
281 |
|
282 | /* Phase string */
|
283 | while (*pFormat != 0 && size < length) {
|
284 |
|
285 | /* Normal character */
|
286 | if (*pFormat != '%') {
|
287 |
|
288 | *pStr++ = *pFormat++;
|
289 | size++;
|
290 | }
|
291 | /* Escaped '%' */
|
292 | else if (*(pFormat+1) == '%') {
|
293 |
|
294 | *pStr++ = '%';
|
295 | pFormat += 2;
|
296 | size++;
|
297 | }
|
298 | /* Token delimiter */
|
299 | else {
|
300 |
|
301 | fill = ' ';
|
302 | width = 0;
|
303 | pFormat++;
|
304 |
|
305 | /* Parse filler */
|
306 | if (*pFormat == '0') {
|
307 |
|
308 | fill = '0';
|
309 | pFormat++;
|
310 | }
|
311 |
|
312 | /* Parse width */
|
313 | while ((*pFormat >= '0') && (*pFormat <= '9')) {
|
314 |
|
315 | width = (width*10) + *pFormat-'0';
|
316 | pFormat++;
|
317 | }
|
318 |
|
319 | /* Check if there is enough space */
|
320 | if (size + width > length) {
|
321 |
|
322 | width = length - size;
|
323 | }
|
324 |
|
325 | /* Parse type */
|
326 | switch (*pFormat) {
|
327 | case 'd':
|
328 | case 'i': num = PutSignedInt(pStr, fill, width, va_arg(ap, signed int)); break;
|
329 | case 'u': num = PutUnsignedInt(pStr, fill, width, va_arg(ap, unsigned int)); break;
|
330 | case 'x': num = PutHexa(pStr, fill, width, 0, va_arg(ap, unsigned int)); break;
|
331 | case 'X': num = PutHexa(pStr, fill, width, 1, va_arg(ap, unsigned int)); break;
|
332 | case 's': num = PutString(pStr, va_arg(ap, char *)); break;
|
333 | case 'c': num = PutChar(pStr, va_arg(ap, unsigned int)); break;
|
334 | default:
|
335 | return EOF;
|
336 | }
|
337 |
|
338 | pFormat++;
|
339 | pStr += num;
|
340 | size += num;
|
341 | }
|
342 | }
|
343 |
|
344 | /* NULL-terminated (final \0 is not counted) */
|
345 | if (size < length) {
|
346 |
|
347 | *pStr = 0;
|
348 | }
|
349 | else {
|
350 |
|
351 | *(--pStr) = 0;
|
352 | size--;
|
353 | }
|
354 |
|
355 | return size;
|
356 | }
|
357 |
|
358 |
|
359 | /**
|
360 | * @brief Stores the result of a formatted string into another string. Format
|
361 | * arguments are given in a va_list instance.
|
362 | *
|
363 | * @param pStr Destination string.
|
364 | * @param length Length of Destination string.
|
365 | * @param pFormat Format string.
|
366 | * @param ... Other arguments
|
367 | *
|
368 | * @return The number of characters written.
|
369 | */
|
370 | signed int snprintf(char *pString, size_t length, const char *pFormat, ...)
|
371 | {
|
372 | va_list ap;
|
373 | signed int rc;
|
374 |
|
375 | va_start(ap, pFormat);
|
376 | rc = vsnprintf(pString, length, pFormat, ap);
|
377 | va_end(ap);
|
378 |
|
379 | return rc;
|
380 | }
|
381 |
|
382 |
|
383 | /**
|
384 | * @brief Stores the result of a formatted string into another string. Format
|
385 | * arguments are given in a va_list instance.
|
386 | *
|
387 | * @param pString Destination string.
|
388 | * @param length Length of Destination string.
|
389 | * @param pFormat Format string.
|
390 | * @param ap Argument list.
|
391 | *
|
392 | * @return The number of characters written.
|
393 | */
|
394 | signed int vsprintf(char *pString, const char *pFormat, va_list ap)
|
395 | {
|
396 | return vsnprintf(pString, MAX_STRING_SIZE, pFormat, ap);
|
397 | }
|
398 |
|
399 | /**
|
400 | * @brief Outputs a formatted string on the given stream. Format arguments are given
|
401 | * in a va_list instance.
|
402 | *
|
403 | * @param pStream Output stream.
|
404 | * @param pFormat Format string
|
405 | * @param ap Argument list.
|
406 | */
|
407 | signed int vfprintf(FILE *pStream, const char *pFormat, va_list ap)
|
408 | {
|
409 | char pStr[MAX_STRING_SIZE];
|
410 | char pError[] = "stdio.c: increase MAX_STRING_SIZE\n\r";
|
411 |
|
412 | /* Write formatted string in buffer */
|
413 | if (vsprintf(pStr, pFormat, ap) >= MAX_STRING_SIZE) {
|
414 |
|
415 | fputs(pError, stderr);
|
416 | while (1); /* Increase MAX_STRING_SIZE */
|
417 | }
|
418 |
|
419 | /* Display string */
|
420 | return fputs(pStr, pStream);
|
421 | }
|
422 |
|
423 |
|
424 | /**
|
425 | * @brief Outputs a formatted string on the DBGU stream. Format arguments are given
|
426 | * in a va_list instance.
|
427 | *
|
428 | * @param pFormat Format string.
|
429 | * @param ap Argument list.
|
430 | */
|
431 | signed int vprintf(const char *pFormat, va_list ap)
|
432 | {
|
433 | return vfprintf(stdout, pFormat, ap);
|
434 | }
|
435 |
|
436 |
|
437 | /**
|
438 | * @brief Outputs a formatted string on the given stream, using a variable
|
439 | * number of arguments.
|
440 | *
|
441 | * @param pStream Output stream.
|
442 | * @param pFormat Format string.
|
443 | */
|
444 | signed int fprintf(FILE *pStream, const char *pFormat, ...)
|
445 | {
|
446 | va_list ap;
|
447 | signed int result;
|
448 |
|
449 | /* Forward call to vfprintf */
|
450 | va_start(ap, pFormat);
|
451 | result = vfprintf(pStream, pFormat, ap);
|
452 | va_end(ap);
|
453 |
|
454 | return result;
|
455 | }
|
456 |
|
457 |
|
458 | /**
|
459 | * @brief Outputs a formatted string on the DBGU stream, using a variable number of
|
460 | * arguments.
|
461 | *
|
462 | * @param pFormat Format string.
|
463 | */
|
464 | signed int printf(const char *pFormat, ...)
|
465 | {
|
466 | va_list ap;
|
467 | signed int result;
|
468 |
|
469 | /* Forward call to vprintf */
|
470 | va_start(ap, pFormat);
|
471 | result = vprintf(pFormat, ap);
|
472 | va_end(ap);
|
473 |
|
474 | return result;
|
475 | }
|
476 |
|
477 |
|
478 | /**
|
479 | * @brief Writes a formatted string inside another string.
|
480 | *
|
481 | * @param pStr torage string.
|
482 | * @param pFormat Format string.
|
483 | */
|
484 | signed int sprintf(char *pStr, const char *pFormat, ...)
|
485 | {
|
486 | va_list ap;
|
487 | signed int result;
|
488 |
|
489 | // Forward call to vsprintf
|
490 | va_start(ap, pFormat);
|
491 | result = vsprintf(pStr, pFormat, ap);
|
492 | va_end(ap);
|
493 |
|
494 | return result;
|
495 | }
|
496 |
|
497 |
|
498 | /**
|
499 | * @brief Outputs a string on stdout.
|
500 | *
|
501 | * @param pStr String to output.
|
502 | */
|
503 | signed int puts(const char *pStr)
|
504 | {
|
505 | return fputs(pStr, stdout);
|
506 | }
|
507 |
|
508 |
|
509 | /**
|
510 | * @brief Implementation of fputc using the DBGU as the standard output. Required
|
511 | * for printf().
|
512 | *
|
513 | * @param c Character to write.
|
514 | * @param pStream Output stream.
|
515 | * @param The character written if successful, or -1 if the output stream is
|
516 | * not stdout or stderr.
|
517 | */
|
518 | signed int fputc(signed int c, FILE *pStream)
|
519 | {
|
520 | if ((pStream == stdout) || (pStream == stderr)) {
|
521 |
|
522 | PrintChar(c);
|
523 |
|
524 | return c;
|
525 | }
|
526 | else {
|
527 |
|
528 | return EOF;
|
529 | }
|
530 | }
|
531 |
|
532 |
|
533 | /**
|
534 | * @brief Implementation of fputs using the DBGU as the standard output. Required
|
535 | * for printf().
|
536 | *
|
537 | * @param pStr String to write.
|
538 | * @param pStream Output stream.
|
539 | *
|
540 | * @return Number of characters written if successful, or -1 if the output
|
541 | * stream is not stdout or stderr.
|
542 | */
|
543 | signed int fputs(const char *pStr, FILE *pStream)
|
544 | {
|
545 | signed int num = 0;
|
546 |
|
547 | while (*pStr != 0) {
|
548 |
|
549 | if (fputc(*pStr, pStream) == -1) {
|
550 |
|
551 | return -1;
|
552 | }
|
553 | num++;
|
554 | pStr++;
|
555 | }
|
556 |
|
557 | return num;
|
558 | }
|
559 |
|
560 | /* --------------------------------- End Of File ------------------------------ */
|