Subversion Repositories svnkaklik

Rev

Go to most recent revision | Details | Last modification | View Log

Rev Author Line No. Line
507 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
*/