Rev Author Line No. Line
1145 kaklik 1 /*! \file rprintf.c \brief printf routine and associated routines. */
2 //*****************************************************************************
3 //
4 // File Name : 'rprintf.c'
5 // Title : printf routine and associated routines
6 // Author : Pascal Stang - Copyright (C) 2000-2002
7 // Created : 2000.12.26
8 // Revised : 2003.5.1
9 // Version : 1.0
10 // Target MCU : Atmel AVR series and other targets
11 // Editor Tabs : 4
12 //
13 // NOTE: This code is currently below version 1.0, and therefore is considered
14 // to be lacking in some functionality or documentation, or may not be fully
15 // tested. Nonetheless, you can expect most functions to work.
16 //
17 // This code is distributed under the GNU Public License
18 // which can be found at http://www.gnu.org/licenses/gpl.txt
19 //
20 //*****************************************************************************
21  
22 #include <avr/pgmspace.h>
23 //#include <string-avr.h>
24 //#include <stdlib.h>
25 #include <stdarg.h>
26 #include "global.h"
27 #include "rprintf.h"
28  
29 #ifndef TRUE
30 #define TRUE -1
31 #define FALSE 0
32 #endif
33  
34 #define INF 32766 // maximum field size to print
35 #define READMEMBYTE(a,char_ptr) ((a)?(pgm_read_byte(char_ptr)):(*char_ptr))
36  
37 #ifdef RPRINTF_COMPLEX
38 static unsigned char buf[128];
39 #endif
40  
41 // use this to store hex conversion in RAM
42 //static char HexChars[] = "0123456789ABCDEF";
43 // use this to store hex conversion in program memory
44 //static prog_char HexChars[] = "0123456789ABCDEF";
45 static char __attribute__ ((progmem)) HexChars[] = "0123456789ABCDEF";
46  
47 #define hexchar(x) pgm_read_byte( HexChars+((x)&0x0f) )
48 //#define hexchar(x) ((((x)&0x0F)>9)?((x)+'A'-10):((x)+'0'))
49  
50 // function pointer to single character output routine
51 static void (*rputchar)(unsigned char c);
52  
53 // *** rprintf initialization ***
54 // you must call this function once and supply the character output
55 // routine before using other functions in this library
56 void rprintfInit(void (*putchar_func)(unsigned char c))
57 {
58 rputchar = putchar_func;
59 }
60  
61 // *** rprintfChar ***
62 // send a character/byte to the current output device
63 void rprintfChar(unsigned char c)
64 {
65 // do LF -> CR/LF translation
66 if(c == '\n')
67 rputchar('\r');
68 // send character
69 rputchar(c);
70 }
71  
72 // *** rprintfStr ***
73 // prints a null-terminated string stored in RAM
74 void rprintfStr(char str[])
75 {
76 // send a string stored in RAM
77 // check to make sure we have a good pointer
78 if (!str) return;
79  
80 // print the string until a null-terminator
81 while (*str)
82 rprintfChar(*str++);
83 }
84  
85 // *** rprintfStrLen ***
86 // prints a section of a string stored in RAM
87 // begins printing at position indicated by <start>
88 // prints number of characters indicated by <len>
89 void rprintfStrLen(char str[], unsigned int start, unsigned int len)
90 {
91 register int i=0;
92  
93 // check to make sure we have a good pointer
94 if (!str) return;
95 // spin through characters up to requested start
96 // keep going as long as there's no null
97 while((i++<start) && (*str++));
98 // for(i=0; i<start; i++)
99 // {
100 // // keep steping through string as long as there's no null
101 // if(*str) str++;
102 // }
103  
104 // then print exactly len characters
105 for(i=0; i<len; i++)
106 {
107 // print data out of the string as long as we haven't reached a null yet
108 // at the null, start printing spaces
109 if(*str)
110 rprintfChar(*str++);
111 else
112 rprintfChar(' ');
113 }
114  
115 }
116  
117 // *** rprintfProgStr ***
118 // prints a null-terminated string stored in program ROM
119 void rprintfProgStr(const prog_char str[])
120 {
121 // print a string stored in program memory
122 register char c;
123  
124 // check to make sure we have a good pointer
125 if (!str) return;
126  
127 // print the string until the null-terminator
128 while((c = pgm_read_byte(str++)))
129 rprintfChar(c);
130 }
131  
132 // *** rprintfCRLF ***
133 // prints carriage return and line feed
134 void rprintfCRLF(void)
135 {
136 // print CR/LF
137 //rprintfChar('\r');
138 // LF -> CR/LF translation built-in to rprintfChar()
139 rprintfChar('\n');
140 }
141  
142 // *** rprintfu04 ***
143 // prints an unsigned 4-bit number in hex (1 digit)
144 void rprintfu04(unsigned char data)
145 {
146 // print 4-bit hex value
147 // char Character = data&0x0f;
148 // if (Character>9)
149 // Character+='A'-10;
150 // else
151 // Character+='0';
152 rprintfChar(hexchar(data));
153 }
154  
155 // *** rprintfu08 ***
156 // prints an unsigned 8-bit number in hex (2 digits)
157 void rprintfu08(unsigned char data)
158 {
159 // print 8-bit hex value
160 rprintfu04(data>>4);
161 rprintfu04(data);
162 }
163  
164 // *** rprintfu16 ***
165 // prints an unsigned 16-bit number in hex (4 digits)
166 void rprintfu16(unsigned short data)
167 {
168 // print 16-bit hex value
169 rprintfu08(data>>8);
170 rprintfu08(data);
171 }
172  
173 // *** rprintfu32 ***
174 // prints an unsigned 32-bit number in hex (8 digits)
175 void rprintfu32(unsigned long data)
176 {
177 // print 32-bit hex value
178 rprintfu16(data>>16);
179 rprintfu16(data);
180 }
181  
182 // *** rprintfNum ***
183 // special printf for numbers only
184 // see formatting information below
185 // Print the number "n" in the given "base"
186 // using exactly "numDigits"
187 // print +/- if signed flag "isSigned" is TRUE
188 // use the character specified in "padchar" to pad extra characters
189 //
190 // Examples:
191 // uartPrintfNum(10, 6, TRUE, ' ', 1234); --> " +1234"
192 // uartPrintfNum(10, 6, FALSE, '0', 1234); --> "001234"
193 // uartPrintfNum(16, 6, FALSE, '.', 0x5AA5); --> "..5AA5"
194 void rprintfNum(char base, char numDigits, char isSigned, char padchar, long n)
195 {
196 // define a global HexChars or use line below
197 //static char HexChars[16] = "0123456789ABCDEF";
198 char *p, buf[32];
199 unsigned long x;
200 unsigned char count;
201  
202 // prepare negative number
203 if( isSigned && (n < 0) )
204 {
205 x = -n;
206 }
207 else
208 {
209 x = n;
210 }
211  
212 // setup little string buffer
213 count = (numDigits-1)-(isSigned?1:0);
214 p = buf + sizeof (buf);
215 *--p = '\0';
216  
217 // force calculation of first digit
218 // (to prevent zero from not printing at all!!!)
219 *--p = hexchar(x%base); x /= base;
220 // calculate remaining digits
221 while(count--)
222 {
223 if(x != 0)
224 {
225 // calculate next digit
226 *--p = hexchar(x%base); x /= base;
227 }
228 else
229 {
230 // no more digits left, pad out to desired length
231 *--p = padchar;
232 }
233 }
234  
235 // apply signed notation if requested
236 if( isSigned )
237 {
238 if(n < 0)
239 {
240 *--p = '-';
241 }
242 else if(n > 0)
243 {
244 *--p = '+';
245 }
246 else
247 {
248 *--p = ' ';
249 }
250 }
251  
252 // print the string right-justified
253 count = numDigits;
254 while(count--)
255 {
256 rprintfChar(*p++);
257 }
258 }
259  
260 #ifdef RPRINTF_FLOAT
261 // *** rprintfFloat ***
262 // floating-point print
263 void rprintfFloat(char numDigits, double x)
264 {
265 unsigned char firstplace = FALSE;
266 unsigned char negative;
267 unsigned char i, digit;
268 double place = 1.0;
269  
270 // save sign
271 negative = (x<0);
272 // convert to absolute value
273 x = (x>0)?(x):(-x);
274  
275 // find starting digit place
276 for(i=0; i<15; i++)
277 {
278 if((x/place) < 10.0)
279 break;
280 else
281 place *= 10.0;
282 }
283 // print polarity character
284 if(negative)
285 rprintfChar('-');
286 else
287 rprintfChar('+');
288  
289 // print digits
290 for(i=0; i<numDigits; i++)
291 {
292 digit = (x/place);
293  
294 if(digit | firstplace | (place == 1.0))
295 {
296 firstplace = TRUE;
297 rprintfChar(digit+0x30);
298 }
299 else
300 rprintfChar(' ');
301  
302 if(place == 1.0)
303 {
304 rprintfChar('.');
305 }
306  
307 x -= (digit*place);
308 place /= 10.0;
309 }
310 }
311 #endif
312  
313 #ifdef RPRINTF_SIMPLE
314 // *** rprintf1RamRom ***
315 // called by rprintf() - does a simple printf (supports %d, %x, %c)
316 // Supports:
317 // %d - decimal
318 // %x - hex
319 // %c - character
320 int rprintf1RamRom(unsigned char stringInRom, const char *format, ...)
321 {
322 // simple printf routine
323 // define a global HexChars or use line below
324 //static char HexChars[16] = "0123456789ABCDEF";
325 char format_flag;
326 unsigned int u_val, div_val, base;
327 va_list ap;
328  
329 va_start(ap, format);
330 for (;;)
331 {
332 while ((format_flag = READMEMBYTE(stringInRom,format++) ) != '%')
333 { // Until '%' or '\0'
334 if (!format_flag)
335 {
336 va_end(ap);
337 return(0);
338 }
339 rprintfChar(format_flag);
340 }
341  
342 switch (format_flag = READMEMBYTE(stringInRom,format++) )
343 {
344 case 'c': format_flag = va_arg(ap,int);
345 default: rprintfChar(format_flag); continue;
346 case 'd': base = 10; div_val = 10000; goto CONVERSION_LOOP;
347 // case 'x': base = 16; div_val = 0x10;
348 case 'x': base = 16; div_val = 0x1000;
349  
350 CONVERSION_LOOP:
351 u_val = va_arg(ap,int);
352 if (format_flag == 'd')
353 {
354 if (((int)u_val) < 0)
355 {
356 u_val = - u_val;
357 rprintfChar('-');
358 }
359 while (div_val > 1 && div_val > u_val) div_val /= 10;
360 }
361 do
362 {
363 //rprintfChar(pgm_read_byte(HexChars+(u_val/div_val)));
364 rprintfu04(u_val/div_val);
365 u_val %= div_val;
366 div_val /= base;
367 } while (div_val);
368 }
369 }
370 va_end(ap);
371 }
372 #endif
373  
374  
375 #ifdef RPRINTF_COMPLEX
376 // *** rprintf2RamRom ***
377 // called by rprintf() - does a more powerful printf (supports %d, %u, %o, %x, %c, %s)
378 // Supports:
379 // %d - decimal
380 // %u - unsigned decimal
381 // %o - octal
382 // %x - hex
383 // %c - character
384 // %s - strings
385 // and the width,precision,padding modifiers
386 // **this printf does not support floating point numbers
387 int rprintf2RamRom(unsigned char stringInRom, const char *sfmt, ...)
388 {
389 register unsigned char *f, *bp;
390 register long l;
391 register unsigned long u;
392 register int i;
393 register int fmt;
394 register unsigned char pad = ' ';
395 int flush_left = 0, f_width = 0, prec = INF, hash = 0, do_long = 0;
396 int sign = 0;
397  
398 va_list ap;
399 va_start(ap, sfmt);
400  
401 f = (unsigned char *) sfmt;
402  
403 for (; READMEMBYTE(stringInRom,f); f++)
404 {
405 if (READMEMBYTE(stringInRom,f) != '%')
406 { // not a format character
407 // then just output the char
408 rprintfChar(READMEMBYTE(stringInRom,f));
409 }
410 else
411 {
412 f++; // if we have a "%" then skip it
413 if (READMEMBYTE(stringInRom,f) == '-')
414 {
415 flush_left = 1; // minus: flush left
416 f++;
417 }
418 if (READMEMBYTE(stringInRom,f) == '0'
419 || READMEMBYTE(stringInRom,f) == '.')
420 {
421 // padding with 0 rather than blank
422 pad = '0';
423 f++;
424 }
425 if (READMEMBYTE(stringInRom,f) == '*')
426 { // field width
427 f_width = va_arg(ap, int);
428 f++;
429 }
430 else if (Isdigit(READMEMBYTE(stringInRom,f)))
431 {
432 f_width = atoiRamRom(stringInRom, (char *) f);
433 while (Isdigit(READMEMBYTE(stringInRom,f)))
434 f++; // skip the digits
435 }
436 if (READMEMBYTE(stringInRom,f) == '.')
437 { // precision
438 f++;
439 if (READMEMBYTE(stringInRom,f) == '*')
440 {
441 prec = va_arg(ap, int);
442 f++;
443 }
444 else if (Isdigit(READMEMBYTE(stringInRom,f)))
445 {
446 prec = atoiRamRom(stringInRom, (char *) f);
447 while (Isdigit(READMEMBYTE(stringInRom,f)))
448 f++; // skip the digits
449 }
450 }
451 if (READMEMBYTE(stringInRom,f) == '#')
452 { // alternate form
453 hash = 1;
454 f++;
455 }
456 if (READMEMBYTE(stringInRom,f) == 'l')
457 { // long format
458 do_long = 1;
459 f++;
460 }
461  
462 fmt = READMEMBYTE(stringInRom,f);
463 bp = buf;
464 switch (fmt) { // do the formatting
465 case 'd': // 'd' signed decimal
466 if (do_long)
467 l = va_arg(ap, long);
468 else
469 l = (long) (va_arg(ap, int));
470 if (l < 0)
471 {
472 sign = 1;
473 l = -l;
474 }
475 do {
476 *bp++ = l % 10 + '0';
477 } while ((l /= 10) > 0);
478 if (sign)
479 *bp++ = '-';
480 f_width = f_width - (bp - buf);
481 if (!flush_left)
482 while (f_width-- > 0)
483 rprintfChar(pad);
484 for (bp--; bp >= buf; bp--)
485 rprintfChar(*bp);
486 if (flush_left)
487 while (f_width-- > 0)
488 rprintfChar(' ');
489 break;
490 case 'o': // 'o' octal number
491 case 'x': // 'x' hex number
492 case 'u': // 'u' unsigned decimal
493 if (do_long)
494 u = va_arg(ap, unsigned long);
495 else
496 u = (unsigned long) (va_arg(ap, unsigned));
497 if (fmt == 'u')
498 { // unsigned decimal
499 do {
500 *bp++ = u % 10 + '0';
501 } while ((u /= 10) > 0);
502 }
503 else if (fmt == 'o')
504 { // octal
505 do {
506 *bp++ = u % 8 + '0';
507 } while ((u /= 8) > 0);
508 if (hash)
509 *bp++ = '0';
510 }
511 else if (fmt == 'x')
512 { // hex
513 do {
514 i = u % 16;
515 if (i < 10)
516 *bp++ = i + '0';
517 else
518 *bp++ = i - 10 + 'a';
519 } while ((u /= 16) > 0);
520 if (hash)
521 {
522 *bp++ = 'x';
523 *bp++ = '0';
524 }
525 }
526 i = f_width - (bp - buf);
527 if (!flush_left)
528 while (i-- > 0)
529 rprintfChar(pad);
530 for (bp--; bp >= buf; bp--)
531 rprintfChar((int) (*bp));
532 if (flush_left)
533 while (i-- > 0)
534 rprintfChar(' ');
535 break;
536 case 'c': // 'c' character
537 i = va_arg(ap, int);
538 rprintfChar((int) (i));
539 break;
540 case 's': // 's' string
541 bp = va_arg(ap, unsigned char *);
542 if (!bp)
543 bp = (unsigned char *) "(nil)";
544 f_width = f_width - strlen((char *) bp);
545 if (!flush_left)
546 while (f_width-- > 0)
547 rprintfChar(pad);
548 for (i = 0; *bp && i < prec; i++)
549 {
550 rprintfChar(*bp);
551 bp++;
552 }
553 if (flush_left)
554 while (f_width-- > 0)
555 rprintfChar(' ');
556 break;
557 case '%': // '%' character
558 rprintfChar('%');
559 break;
560 }
561 flush_left = 0, f_width = 0, prec = INF, hash = 0, do_long = 0;
562 sign = 0;
563 pad = ' ';
564 }
565 }
566  
567 va_end(ap);
568 return 0;
569 }
570  
571 unsigned char Isdigit(char c)
572 {
573 if((c >= 0x30) && (c <= 0x39))
574 return TRUE;
575 else
576 return FALSE;
577 }
578  
579 int atoiRamRom(unsigned char stringInRom, char *str)
580 {
581 int num = 0;;
582  
583 while(Isdigit(READMEMBYTE(stringInRom,str)))
584 {
585 num *= 10;
586 num += ((READMEMBYTE(stringInRom,str++)) - 0x30);
587 }
588 return num;
589 }
590  
591 #endif
592  
593 //******************************************************************************
594 // code below this line is commented out and can be ignored
595 //******************************************************************************
596 /*
597 char* sprintf(const char *sfmt, ...)
598 {
599 register unsigned char *f, *bp, *str;
600 register long l;
601 register unsigned long u;
602 register int i;
603 register int fmt;
604 register unsigned char pad = ' ';
605 int flush_left = 0, f_width = 0, prec = INF, hash = 0, do_long = 0;
606 int sign = 0;
607  
608 va_list ap;
609 va_start(ap, sfmt);
610  
611 str = bufstring;
612 f = (unsigned char *) sfmt;
613  
614 for (; *f; f++)
615 {
616 if (*f != '%')
617 { // not a format character
618 *str++ = (*f); // then just output the char
619 }
620 else
621 {
622 f++; // if we have a "%" then skip it
623 if (*f == '-')
624 {
625 flush_left = 1; // minus: flush left
626 f++;
627 }
628 if (*f == '0' || *f == '.')
629 {
630 // padding with 0 rather than blank
631 pad = '0';
632 f++;
633 }
634 if (*f == '*')
635 { // field width
636 f_width = va_arg(ap, int);
637 f++;
638 }
639 else if (Isdigit(*f))
640 {
641 f_width = atoi((char *) f);
642 while (Isdigit(*f))
643 f++; // skip the digits
644 }
645 if (*f == '.')
646 { // precision
647 f++;
648 if (*f == '*')
649 {
650 prec = va_arg(ap, int);
651 f++;
652 }
653 else if (Isdigit(*f))
654 {
655 prec = atoi((char *) f);
656 while (Isdigit(*f))
657 f++; // skip the digits
658 }
659 }
660 if (*f == '#')
661 { // alternate form
662 hash = 1;
663 f++;
664 }
665 if (*f == 'l')
666 { // long format
667 do_long = 1;
668 f++;
669 }
670  
671 fmt = *f;
672 bp = buf;
673 switch (fmt) { // do the formatting
674 case 'd': // 'd' signed decimal
675 if (do_long)
676 l = va_arg(ap, long);
677 else
678 l = (long) (va_arg(ap, int));
679 if (l < 0)
680 {
681 sign = 1;
682 l = -l;
683 }
684 do {
685 *bp++ = l % 10 + '0';
686 } while ((l /= 10) > 0);
687 if (sign)
688 *bp++ = '-';
689 f_width = f_width - (bp - buf);
690 if (!flush_left)
691 while (f_width-- > 0)
692 *str++ = (pad);
693 for (bp--; bp >= buf; bp--)
694 *str++ = (*bp);
695 if (flush_left)
696 while (f_width-- > 0)
697 *str++ = (' ');
698 break;
699 case 'o': // 'o' octal number
700 case 'x': // 'x' hex number
701 case 'u': // 'u' unsigned decimal
702 if (do_long)
703 u = va_arg(ap, unsigned long);
704 else
705 u = (unsigned long) (va_arg(ap, unsigned));
706 if (fmt == 'u')
707 { // unsigned decimal
708 do {
709 *bp++ = u % 10 + '0';
710 } while ((u /= 10) > 0);
711 }
712 else if (fmt == 'o')
713 { // octal
714 do {
715 *bp++ = u % 8 + '0';
716 } while ((u /= 8) > 0);
717 if (hash)
718 *bp++ = '0';
719 }
720 else if (fmt == 'x')
721 { // hex
722 do {
723 i = u % 16;
724 if (i < 10)
725 *bp++ = i + '0';
726 else
727 *bp++ = i - 10 + 'a';
728 } while ((u /= 16) > 0);
729 if (hash)
730 {
731 *bp++ = 'x';
732 *bp++ = '0';
733 }
734 }
735 i = f_width - (bp - buf);
736 if (!flush_left)
737 while (i-- > 0)
738 *str++ = (pad);
739 for (bp--; bp >= buf; bp--)
740 *str++ = ((int) (*bp));
741 if (flush_left)
742 while (i-- > 0)
743 *str++ = (' ');
744 break;
745 case 'c': // 'c' character
746 i = va_arg(ap, int);
747 *str++ = ((int) (i));
748 break;
749 case 's': // 's' string
750 bp = va_arg(ap, unsigned char *);
751 if (!bp)
752 bp = (unsigned char *) "(nil)";
753 f_width = f_width - strlen((char *) bp);
754 if (!flush_left)
755 while (f_width-- > 0)
756 *str++ = (pad);
757 for (i = 0; *bp && i < prec; i++)
758 {
759 *str++ = (*bp);
760 bp++;
761 }
762 if (flush_left)
763 while (f_width-- > 0)
764 *str++ = (' ');
765 break;
766 case '%': // '%' character
767 *str++ = ('%');
768 break;
769 }
770 flush_left = 0, f_width = 0, prec = INF, hash = 0, do_long = 0;
771 sign = 0;
772 pad = ' ';
773 }
774 }
775  
776 va_end(ap);
777 // terminate string with null
778 *str++ = '\0';
779 return bufstring;
780 }
781  
782 */