Blame | Last modification | View Log | Download
/*! \file rprintf.c \brief printf routine and associated routines. *///*****************************************************************************//// File Name : 'rprintf.c'// Title : printf routine and associated routines// Author : Pascal Stang - Copyright (C) 2000-2002// Created : 2000.12.26// Revised : 2003.5.1// Version : 1.0// Target MCU : Atmel AVR series and other targets// Editor Tabs : 4//// NOTE: This code is currently below version 1.0, and therefore is considered// to be lacking in some functionality or documentation, or may not be fully// tested. Nonetheless, you can expect most functions to work.//// This code is distributed under the GNU Public License// which can be found at http://www.gnu.org/licenses/gpl.txt////*****************************************************************************#include <avr/pgmspace.h>//#include <string-avr.h>//#include <stdlib.h>#include <stdarg.h>#include "global.h"#include "rprintf.h"#ifndef TRUE#define TRUE -1#define FALSE 0#endif#define INF 32766 // maximum field size to print#define READMEMBYTE(a,char_ptr) ((a)?(pgm_read_byte(char_ptr)):(*char_ptr))#ifdef RPRINTF_COMPLEXstatic unsigned char buf[128];#endif// use this to store hex conversion in RAM//static char HexChars[] = "0123456789ABCDEF";// use this to store hex conversion in program memory//static prog_char HexChars[] = "0123456789ABCDEF";static char __attribute__ ((progmem)) HexChars[] = "0123456789ABCDEF";#define hexchar(x) pgm_read_byte( HexChars+((x)&0x0f) )//#define hexchar(x) ((((x)&0x0F)>9)?((x)+'A'-10):((x)+'0'))// function pointer to single character output routinestatic void (*rputchar)(unsigned char c);// *** rprintf initialization ***// you must call this function once and supply the character output// routine before using other functions in this libraryvoid rprintfInit(void (*putchar_func)(unsigned char c)){rputchar = putchar_func;}// *** rprintfChar ***// send a character/byte to the current output devicevoid rprintfChar(unsigned char c){// do LF -> CR/LF translationif(c == '\n')rputchar('\r');// send characterrputchar(c);}// *** rprintfStr ***// prints a null-terminated string stored in RAMvoid rprintfStr(char str[]){// send a string stored in RAM// check to make sure we have a good pointerif (!str) return;// print the string until a null-terminatorwhile (*str)rprintfChar(*str++);}// *** rprintfStrLen ***// prints a section of a string stored in RAM// begins printing at position indicated by <start>// prints number of characters indicated by <len>void rprintfStrLen(char str[], unsigned int start, unsigned int len){register int i=0;// check to make sure we have a good pointerif (!str) return;// spin through characters up to requested start// keep going as long as there's no nullwhile((i++<start) && (*str++));// for(i=0; i<start; i++)// {// // keep steping through string as long as there's no null// if(*str) str++;// }// then print exactly len charactersfor(i=0; i<len; i++){// print data out of the string as long as we haven't reached a null yet// at the null, start printing spacesif(*str)rprintfChar(*str++);elserprintfChar(' ');}}// *** rprintfProgStr ***// prints a null-terminated string stored in program ROMvoid rprintfProgStr(const prog_char str[]){// print a string stored in program memoryregister char c;// check to make sure we have a good pointerif (!str) return;// print the string until the null-terminatorwhile((c = pgm_read_byte(str++)))rprintfChar(c);}// *** rprintfCRLF ***// prints carriage return and line feedvoid rprintfCRLF(void){// print CR/LF//rprintfChar('\r');// LF -> CR/LF translation built-in to rprintfChar()rprintfChar('\n');}// *** rprintfu04 ***// prints an unsigned 4-bit number in hex (1 digit)void rprintfu04(unsigned char data){// print 4-bit hex value// char Character = data&0x0f;// if (Character>9)// Character+='A'-10;// else// Character+='0';rprintfChar(hexchar(data));}// *** rprintfu08 ***// prints an unsigned 8-bit number in hex (2 digits)void rprintfu08(unsigned char data){// print 8-bit hex valuerprintfu04(data>>4);rprintfu04(data);}// *** rprintfu16 ***// prints an unsigned 16-bit number in hex (4 digits)void rprintfu16(unsigned short data){// print 16-bit hex valuerprintfu08(data>>8);rprintfu08(data);}// *** rprintfu32 ***// prints an unsigned 32-bit number in hex (8 digits)void rprintfu32(unsigned long data){// print 32-bit hex valuerprintfu16(data>>16);rprintfu16(data);}// *** rprintfNum ***// special printf for numbers only// see formatting information below// Print the number "n" in the given "base"// using exactly "numDigits"// print +/- if signed flag "isSigned" is TRUE// use the character specified in "padchar" to pad extra characters//// Examples:// uartPrintfNum(10, 6, TRUE, ' ', 1234); --> " +1234"// uartPrintfNum(10, 6, FALSE, '0', 1234); --> "001234"// uartPrintfNum(16, 6, FALSE, '.', 0x5AA5); --> "..5AA5"void rprintfNum(char base, char numDigits, char isSigned, char padchar, long n){// define a global HexChars or use line below//static char HexChars[16] = "0123456789ABCDEF";char *p, buf[32];unsigned long x;unsigned char count;// prepare negative numberif( isSigned && (n < 0) ){x = -n;}else{x = n;}// setup little string buffercount = (numDigits-1)-(isSigned?1:0);p = buf + sizeof (buf);*--p = '\0';// force calculation of first digit// (to prevent zero from not printing at all!!!)*--p = hexchar(x%base); x /= base;// calculate remaining digitswhile(count--){if(x != 0){// calculate next digit*--p = hexchar(x%base); x /= base;}else{// no more digits left, pad out to desired length*--p = padchar;}}// apply signed notation if requestedif( isSigned ){if(n < 0){*--p = '-';}else if(n > 0){*--p = '+';}else{*--p = ' ';}}// print the string right-justifiedcount = numDigits;while(count--){rprintfChar(*p++);}}#ifdef RPRINTF_FLOAT// *** rprintfFloat ***// floating-point printvoid rprintfFloat(char numDigits, double x){unsigned char firstplace = FALSE;unsigned char negative;unsigned char i, digit;double place = 1.0;// save signnegative = (x<0);// convert to absolute valuex = (x>0)?(x):(-x);// find starting digit placefor(i=0; i<15; i++){if((x/place) < 10.0)break;elseplace *= 10.0;}// print polarity characterif(negative)rprintfChar('-');elserprintfChar('+');// print digitsfor(i=0; i<numDigits; i++){digit = (x/place);if(digit | firstplace | (place == 1.0)){firstplace = TRUE;rprintfChar(digit+0x30);}elserprintfChar(' ');if(place == 1.0){rprintfChar('.');}x -= (digit*place);place /= 10.0;}}#endif#ifdef RPRINTF_SIMPLE// *** rprintf1RamRom ***// called by rprintf() - does a simple printf (supports %d, %x, %c)// Supports:// %d - decimal// %x - hex// %c - characterint rprintf1RamRom(unsigned char stringInRom, const char *format, ...){// simple printf routine// define a global HexChars or use line below//static char HexChars[16] = "0123456789ABCDEF";char format_flag;unsigned int u_val, div_val, base;va_list ap;va_start(ap, format);for (;;){while ((format_flag = READMEMBYTE(stringInRom,format++) ) != '%'){ // Until '%' or '\0'if (!format_flag){va_end(ap);return(0);}rprintfChar(format_flag);}switch (format_flag = READMEMBYTE(stringInRom,format++) ){case 'c': format_flag = va_arg(ap,int);default: rprintfChar(format_flag); continue;case 'd': base = 10; div_val = 10000; goto CONVERSION_LOOP;// case 'x': base = 16; div_val = 0x10;case 'x': base = 16; div_val = 0x1000;CONVERSION_LOOP:u_val = va_arg(ap,int);if (format_flag == 'd'){if (((int)u_val) < 0){u_val = - u_val;rprintfChar('-');}while (div_val > 1 && div_val > u_val) div_val /= 10;}do{//rprintfChar(pgm_read_byte(HexChars+(u_val/div_val)));rprintfu04(u_val/div_val);u_val %= div_val;div_val /= base;} while (div_val);}}va_end(ap);}#endif#ifdef RPRINTF_COMPLEX// *** rprintf2RamRom ***// called by rprintf() - does a more powerful printf (supports %d, %u, %o, %x, %c, %s)// Supports:// %d - decimal// %u - unsigned decimal// %o - octal// %x - hex// %c - character// %s - strings// and the width,precision,padding modifiers// **this printf does not support floating point numbersint rprintf2RamRom(unsigned char stringInRom, const char *sfmt, ...){register unsigned char *f, *bp;register long l;register unsigned long u;register int i;register int fmt;register unsigned char pad = ' ';int flush_left = 0, f_width = 0, prec = INF, hash = 0, do_long = 0;int sign = 0;va_list ap;va_start(ap, sfmt);f = (unsigned char *) sfmt;for (; READMEMBYTE(stringInRom,f); f++){if (READMEMBYTE(stringInRom,f) != '%'){ // not a format character// then just output the charrprintfChar(READMEMBYTE(stringInRom,f));}else{f++; // if we have a "%" then skip itif (READMEMBYTE(stringInRom,f) == '-'){flush_left = 1; // minus: flush leftf++;}if (READMEMBYTE(stringInRom,f) == '0'|| READMEMBYTE(stringInRom,f) == '.'){// padding with 0 rather than blankpad = '0';f++;}if (READMEMBYTE(stringInRom,f) == '*'){ // field widthf_width = va_arg(ap, int);f++;}else if (Isdigit(READMEMBYTE(stringInRom,f))){f_width = atoiRamRom(stringInRom, (char *) f);while (Isdigit(READMEMBYTE(stringInRom,f)))f++; // skip the digits}if (READMEMBYTE(stringInRom,f) == '.'){ // precisionf++;if (READMEMBYTE(stringInRom,f) == '*'){prec = va_arg(ap, int);f++;}else if (Isdigit(READMEMBYTE(stringInRom,f))){prec = atoiRamRom(stringInRom, (char *) f);while (Isdigit(READMEMBYTE(stringInRom,f)))f++; // skip the digits}}if (READMEMBYTE(stringInRom,f) == '#'){ // alternate formhash = 1;f++;}if (READMEMBYTE(stringInRom,f) == 'l'){ // long formatdo_long = 1;f++;}fmt = READMEMBYTE(stringInRom,f);bp = buf;switch (fmt) { // do the formattingcase 'd': // 'd' signed decimalif (do_long)l = va_arg(ap, long);elsel = (long) (va_arg(ap, int));if (l < 0){sign = 1;l = -l;}do {*bp++ = l % 10 + '0';} while ((l /= 10) > 0);if (sign)*bp++ = '-';f_width = f_width - (bp - buf);if (!flush_left)while (f_width-- > 0)rprintfChar(pad);for (bp--; bp >= buf; bp--)rprintfChar(*bp);if (flush_left)while (f_width-- > 0)rprintfChar(' ');break;case 'o': // 'o' octal numbercase 'x': // 'x' hex numbercase 'u': // 'u' unsigned decimalif (do_long)u = va_arg(ap, unsigned long);elseu = (unsigned long) (va_arg(ap, unsigned));if (fmt == 'u'){ // unsigned decimaldo {*bp++ = u % 10 + '0';} while ((u /= 10) > 0);}else if (fmt == 'o'){ // octaldo {*bp++ = u % 8 + '0';} while ((u /= 8) > 0);if (hash)*bp++ = '0';}else if (fmt == 'x'){ // hexdo {i = u % 16;if (i < 10)*bp++ = i + '0';else*bp++ = i - 10 + 'a';} while ((u /= 16) > 0);if (hash){*bp++ = 'x';*bp++ = '0';}}i = f_width - (bp - buf);if (!flush_left)while (i-- > 0)rprintfChar(pad);for (bp--; bp >= buf; bp--)rprintfChar((int) (*bp));if (flush_left)while (i-- > 0)rprintfChar(' ');break;case 'c': // 'c' characteri = va_arg(ap, int);rprintfChar((int) (i));break;case 's': // 's' stringbp = va_arg(ap, unsigned char *);if (!bp)bp = (unsigned char *) "(nil)";f_width = f_width - strlen((char *) bp);if (!flush_left)while (f_width-- > 0)rprintfChar(pad);for (i = 0; *bp && i < prec; i++){rprintfChar(*bp);bp++;}if (flush_left)while (f_width-- > 0)rprintfChar(' ');break;case '%': // '%' characterrprintfChar('%');break;}flush_left = 0, f_width = 0, prec = INF, hash = 0, do_long = 0;sign = 0;pad = ' ';}}va_end(ap);return 0;}unsigned char Isdigit(char c){if((c >= 0x30) && (c <= 0x39))return TRUE;elsereturn FALSE;}int atoiRamRom(unsigned char stringInRom, char *str){int num = 0;;while(Isdigit(READMEMBYTE(stringInRom,str))){num *= 10;num += ((READMEMBYTE(stringInRom,str++)) - 0x30);}return num;}#endif//******************************************************************************// code below this line is commented out and can be ignored//******************************************************************************/*char* sprintf(const char *sfmt, ...){register unsigned char *f, *bp, *str;register long l;register unsigned long u;register int i;register int fmt;register unsigned char pad = ' ';int flush_left = 0, f_width = 0, prec = INF, hash = 0, do_long = 0;int sign = 0;va_list ap;va_start(ap, sfmt);str = bufstring;f = (unsigned char *) sfmt;for (; *f; f++){if (*f != '%'){ // not a format character*str++ = (*f); // then just output the char}else{f++; // if we have a "%" then skip itif (*f == '-'){flush_left = 1; // minus: flush leftf++;}if (*f == '0' || *f == '.'){// padding with 0 rather than blankpad = '0';f++;}if (*f == '*'){ // field widthf_width = va_arg(ap, int);f++;}else if (Isdigit(*f)){f_width = atoi((char *) f);while (Isdigit(*f))f++; // skip the digits}if (*f == '.'){ // precisionf++;if (*f == '*'){prec = va_arg(ap, int);f++;}else if (Isdigit(*f)){prec = atoi((char *) f);while (Isdigit(*f))f++; // skip the digits}}if (*f == '#'){ // alternate formhash = 1;f++;}if (*f == 'l'){ // long formatdo_long = 1;f++;}fmt = *f;bp = buf;switch (fmt) { // do the formattingcase 'd': // 'd' signed decimalif (do_long)l = va_arg(ap, long);elsel = (long) (va_arg(ap, int));if (l < 0){sign = 1;l = -l;}do {*bp++ = l % 10 + '0';} while ((l /= 10) > 0);if (sign)*bp++ = '-';f_width = f_width - (bp - buf);if (!flush_left)while (f_width-- > 0)*str++ = (pad);for (bp--; bp >= buf; bp--)*str++ = (*bp);if (flush_left)while (f_width-- > 0)*str++ = (' ');break;case 'o': // 'o' octal numbercase 'x': // 'x' hex numbercase 'u': // 'u' unsigned decimalif (do_long)u = va_arg(ap, unsigned long);elseu = (unsigned long) (va_arg(ap, unsigned));if (fmt == 'u'){ // unsigned decimaldo {*bp++ = u % 10 + '0';} while ((u /= 10) > 0);}else if (fmt == 'o'){ // octaldo {*bp++ = u % 8 + '0';} while ((u /= 8) > 0);if (hash)*bp++ = '0';}else if (fmt == 'x'){ // hexdo {i = u % 16;if (i < 10)*bp++ = i + '0';else*bp++ = i - 10 + 'a';} while ((u /= 16) > 0);if (hash){*bp++ = 'x';*bp++ = '0';}}i = f_width - (bp - buf);if (!flush_left)while (i-- > 0)*str++ = (pad);for (bp--; bp >= buf; bp--)*str++ = ((int) (*bp));if (flush_left)while (i-- > 0)*str++ = (' ');break;case 'c': // 'c' characteri = va_arg(ap, int);*str++ = ((int) (i));break;case 's': // 's' stringbp = va_arg(ap, unsigned char *);if (!bp)bp = (unsigned char *) "(nil)";f_width = f_width - strlen((char *) bp);if (!flush_left)while (f_width-- > 0)*str++ = (pad);for (i = 0; *bp && i < prec; i++){*str++ = (*bp);bp++;}if (flush_left)while (f_width-- > 0)*str++ = (' ');break;case '%': // '%' character*str++ = ('%');break;}flush_left = 0, f_width = 0, prec = INF, hash = 0, do_long = 0;sign = 0;pad = ' ';}}va_end(ap);// terminate string with null*str++ = '\0';return bufstring;}*/