Main Page | Modules | Data Structures | Directories | File List | Data Fields | Globals | Related Pages

rprintf.c

Go to the documentation of this file.
00001 /*! \file rprintf.c \brief printf routine and associated routines. */
00002 //*****************************************************************************
00003 //
00004 // File Name    : 'rprintf.c'
00005 // Title        : printf routine and associated routines
00006 // Author       : Pascal Stang - Copyright (C) 2000-2002
00007 // Created      : 2000.12.26
00008 // Revised      : 2003.5.1
00009 // Version      : 1.0
00010 // Target MCU   : Atmel AVR series and other targets
00011 // Editor Tabs  : 4
00012 //
00013 // NOTE: This code is currently below version 1.0, and therefore is considered
00014 // to be lacking in some functionality or documentation, or may not be fully
00015 // tested.  Nonetheless, you can expect most functions to work.
00016 //
00017 // This code is distributed under the GNU Public License
00018 //      which can be found at http://www.gnu.org/licenses/gpl.txt
00019 //
00020 //*****************************************************************************
00021 
00022 #include <avr/pgmspace.h>
00023 //#include <string-avr.h>
00024 //#include <stdlib.h>
00025 #include <stdarg.h>
00026 #include "global.h"
00027 #include "rprintf.h"
00028 
00029 #ifndef TRUE
00030     #define TRUE    -1
00031     #define FALSE   0
00032 #endif
00033 
00034 #define INF     32766   // maximum field size to print
00035 #define READMEMBYTE(a,char_ptr) ((a)?(pgm_read_byte(char_ptr)):(*char_ptr))
00036 
00037 #ifdef RPRINTF_COMPLEX
00038     static unsigned char buf[128];
00039 #endif
00040 
00041 // use this to store hex conversion in RAM
00042 //static char HexChars[] = "0123456789ABCDEF";
00043 // use this to store hex conversion in program memory
00044 //static prog_char HexChars[] = "0123456789ABCDEF";
00045 static char __attribute__ ((progmem)) HexChars[] = "0123456789ABCDEF";
00046 
00047 // function pointer to single character output routine
00048 static void (*rputchar)(unsigned char c);
00049 
00050 // *** rprintf initialization ***
00051 // you must call this function once and supply the character output
00052 // routine before using other functions in this library
00053 void rprintfInit(void (*putchar_func)(unsigned char c))
00054 {
00055     rputchar = putchar_func;
00056 }
00057 
00058 // *** rprintfChar ***
00059 // send a character/byte to the current output device
00060 inline void rprintfChar(unsigned char c)
00061 {
00062     // send character
00063     rputchar(c);
00064 }
00065 
00066 // *** rprintfStr ***
00067 // prints a null-terminated string stored in RAM
00068 void rprintfStr(char str[])
00069 {
00070     // send a string stored in RAM
00071     // check to make sure we have a good pointer
00072     if (!str) return;
00073 
00074     // print the string until a null-terminator
00075     while (*str)
00076         rprintfChar(*str++);
00077 }
00078 
00079 // *** rprintfStrLen ***
00080 // prints a section of a string stored in RAM
00081 // begins printing at position indicated by <start>
00082 // prints number of characters indicated by <len>
00083 void rprintfStrLen(char str[], unsigned int start, unsigned int len)
00084 {
00085     register int i=0;
00086 
00087     // check to make sure we have a good pointer
00088     if (!str) return;
00089     // spin through characters up to requested start
00090     // keep going as long as there's no null
00091     while((i++<start) && (*str++));
00092 //  for(i=0; i<start; i++)
00093 //  {
00094 //      // keep steping through string as long as there's no null
00095 //      if(*str) str++;
00096 //  }
00097 
00098     // then print exactly len characters
00099     for(i=0; i<len; i++)
00100     {
00101         // print data out of the string as long as we haven't reached a null yet
00102         // at the null, start printing spaces
00103         if(*str)
00104             rprintfChar(*str++);
00105         else
00106             rprintfChar(' ');
00107     }
00108 
00109 }
00110 
00111 // *** rprintfProgStr ***
00112 // prints a null-terminated string stored in program ROM
00113 void rprintfProgStr(const prog_char str[])
00114 {
00115     // print a string stored in program memory
00116     register char c;
00117 
00118     // check to make sure we have a good pointer
00119     if (!str) return;
00120     
00121     // print the string until the null-terminator
00122     while((c = pgm_read_byte(str++)))
00123         rprintfChar(c);
00124 }
00125 
00126 // *** rprintfCRLF ***
00127 // prints carriage return and line feed
00128 void rprintfCRLF(void)
00129 {
00130     // print CR/LF
00131     rprintfChar('\r');
00132     rprintfChar('\n');
00133 }
00134 
00135 // *** rprintfu04 ***
00136 // prints an unsigned 4-bit number in hex (1 digit)
00137 void rprintfu04(unsigned char data)
00138 {
00139     // print 4-bit hex value
00140 //  char Character = data&0x0f;
00141 //  if (Character>9)
00142 //      Character+='A'-10;
00143 //  else
00144 //      Character+='0';
00145     rprintfChar(pgm_read_byte( HexChars+(data&0x0f) ));
00146 }
00147 
00148 // *** rprintfu08 ***
00149 // prints an unsigned 8-bit number in hex (2 digits)
00150 void rprintfu08(unsigned char data)
00151 {
00152     // print 8-bit hex value
00153     rprintfu04(data>>4);
00154     rprintfu04(data);
00155 }
00156 
00157 // *** rprintfu16 ***
00158 // prints an unsigned 16-bit number in hex (4 digits)
00159 void rprintfu16(unsigned short data)
00160 {
00161     // print 16-bit hex value
00162     rprintfu08(data>>8);
00163     rprintfu08(data);
00164 }
00165 
00166 // *** rprintfu32 ***
00167 // prints an unsigned 32-bit number in hex (8 digits)
00168 void rprintfu32(unsigned long data)
00169 {
00170     // print 32-bit hex value
00171     rprintfu16(data>>16);
00172     rprintfu16(data);
00173 }
00174 
00175 // *** rprintfNum ***
00176 // special printf for numbers only
00177 // see formatting information below
00178 //  Print the number "n" in the given "base"
00179 //  using exactly "numDigits"
00180 //  print +/- if signed flag "isSigned" is TRUE
00181 //  use the character specified in "padchar" to pad extra characters
00182 //
00183 //  Examples:
00184 //  uartPrintfNum(10, 6,  TRUE, ' ',   1234);  -->  " +1234"
00185 //  uartPrintfNum(10, 6, FALSE, '0',   1234);  -->  "001234"
00186 //  uartPrintfNum(16, 6, FALSE, '.', 0x5AA5);  -->  "..5AA5"
00187 void rprintfNum(char base, char numDigits, char isSigned, char padchar, long n)
00188 {
00189     // define a global HexChars or use line below
00190     //static char HexChars[16] = "0123456789ABCDEF";
00191     char *p, buf[32];
00192     unsigned long x;
00193     unsigned char count;
00194 
00195     // prepare negative number
00196     if( isSigned && (n < 0) )
00197     {
00198         x = -n;
00199     }
00200     else
00201     {
00202         x = n;
00203     }
00204 
00205     // setup little string buffer
00206     count = (numDigits-1)-(isSigned?1:0);
00207     p = buf + sizeof (buf);
00208     *--p = '\0';
00209     
00210     // force calculation of first digit
00211     // (to prevent zero from not printing at all!!!)
00212     *--p = pgm_read_byte(HexChars + (x%base)); x /= base;
00213     // calculate remaining digits
00214     while(count--)
00215     {
00216         if(x != 0)
00217         {
00218             // calculate next digit
00219             *--p = pgm_read_byte(HexChars + (x%base)); x /= base;
00220         }
00221         else
00222         {
00223             // no more digits left, pad out to desired length
00224             *--p = padchar;
00225         }
00226     }
00227 
00228     // apply signed notation if requested
00229     if( isSigned )
00230     {
00231         if(n < 0)
00232         {
00233             *--p = '-';
00234         }
00235         else if(n > 0)
00236         {
00237             *--p = '+';
00238         }
00239         else
00240         {
00241             *--p = ' ';
00242         }
00243     }
00244 
00245     // print the string right-justified
00246     count = numDigits;
00247     while(count--)
00248     {
00249         rprintfChar(*p++);
00250     }
00251 }
00252 
00253 #ifdef RPRINTF_FLOAT
00254 // *** rprintfFloat ***
00255 // floating-point print
00256 void rprintfFloat(char numDigits, double x)
00257 {
00258     unsigned char firstplace = FALSE;
00259     unsigned char negative;
00260     unsigned char i, digit;
00261     double place = 1.0;
00262     
00263     // save sign
00264     negative = (x<0);
00265     // convert to absolute value
00266     x = (x>0)?(x):(-x);
00267     
00268     // find starting digit place
00269     for(i=0; i<15; i++)
00270     {
00271         if((x/place) < 10.0)
00272             break;
00273         else
00274             place *= 10.0;
00275     }
00276     // print polarity character
00277     if(negative)
00278         rprintfChar('-');
00279     else
00280         rprintfChar('+');
00281 
00282     // print digits
00283     for(i=0; i<numDigits; i++)
00284     {
00285         digit = (x/place);
00286 
00287         if(digit | firstplace | (place == 1.0))
00288         {
00289             firstplace = TRUE;
00290             rprintfChar(digit+0x30);
00291         }
00292         else
00293             rprintfChar(' ');
00294         
00295         if(place == 1.0)
00296         {
00297             rprintfChar('.');
00298         }
00299         
00300         x -= (digit*place);
00301         place /= 10.0;
00302     }
00303 }
00304 #endif
00305 
00306 #ifdef RPRINTF_SIMPLE
00307 // *** rprintf1RamRom ***
00308 // called by rprintf() - does a simple printf (supports %d, %x, %c)
00309 // Supports:
00310 // %d - decimal
00311 // %x - hex
00312 // %c - character
00313 int rprintf1RamRom(unsigned char stringInRom, const char *format, ...)
00314 {
00315     // simple printf routine
00316     // define a global HexChars or use line below
00317     //static char HexChars[16] = "0123456789ABCDEF";
00318     char format_flag;
00319     unsigned int u_val, div_val, base;
00320     va_list ap;
00321 
00322     va_start(ap, format);
00323     for (;;)
00324     {
00325         while ((format_flag = READMEMBYTE(stringInRom,format++) ) != '%')
00326         {   // Until '%' or '\0'
00327             if (!format_flag)
00328             {
00329                 va_end(ap);
00330                 return(0);
00331             }
00332             rprintfChar(format_flag);
00333         }
00334 
00335         switch (format_flag = READMEMBYTE(stringInRom,format++) )
00336         {
00337             case 'c': format_flag = va_arg(ap,int);
00338             default:  rprintfChar(format_flag); continue;
00339             case 'd': base = 10; div_val = 10000; goto CONVERSION_LOOP;
00340             case 'x': base = 16; div_val = 0x10;
00341 
00342             CONVERSION_LOOP:
00343             u_val = va_arg(ap,int);
00344             if (format_flag == 'd')
00345             {
00346                 if (((int)u_val) < 0)
00347                 {
00348                     u_val = - u_val;
00349                     rprintfChar('-');
00350                 }
00351                 while (div_val > 1 && div_val > u_val) div_val /= 10;
00352             }
00353             do
00354             {
00355                 rprintfChar(pgm_read_byte(HexChars+(u_val/div_val)));
00356                 u_val %= div_val;
00357                 div_val /= base;
00358             } while (div_val);
00359         }
00360     }
00361     va_end(ap);
00362 }
00363 #endif
00364 
00365 
00366 #ifdef RPRINTF_COMPLEX
00367 // *** rprintf2RamRom ***
00368 // called by rprintf() - does a more powerful printf (supports %d, %u, %o, %x, %c, %s)
00369 // Supports:
00370 // %d - decimal
00371 // %u - unsigned decimal
00372 // %o - octal
00373 // %x - hex
00374 // %c - character
00375 // %s - strings
00376 // and the width,precision,padding modifiers
00377 // **this printf does not support floating point numbers
00378 int rprintf2RamRom(unsigned char stringInRom, const char *sfmt, ...)
00379 {
00380     register unsigned char *f, *bp;
00381     register long l;
00382     register unsigned long u;
00383     register int i;
00384     register int fmt;
00385     register unsigned char pad = ' ';
00386     int flush_left = 0, f_width = 0, prec = INF, hash = 0, do_long = 0;
00387     int sign = 0;
00388 
00389     va_list ap;
00390     va_start(ap, sfmt);
00391 
00392     f = (unsigned char *) sfmt;
00393 
00394     for (; READMEMBYTE(stringInRom,f); f++)
00395     {
00396         if (READMEMBYTE(stringInRom,f) != '%')
00397         {   // not a format character
00398             // then just output the char
00399             rprintfChar(READMEMBYTE(stringInRom,f));
00400         }
00401         else 
00402         {
00403             f++;                        // if we have a "%" then skip it
00404             if (READMEMBYTE(stringInRom,f) == '-')
00405             {
00406                 flush_left = 1; // minus: flush left
00407                 f++;
00408             }
00409             if (READMEMBYTE(stringInRom,f) == '0'
00410                  || READMEMBYTE(stringInRom,f) == '.')
00411                 {
00412                     // padding with 0 rather than blank
00413                     pad = '0';
00414                     f++;
00415             }
00416             if (READMEMBYTE(stringInRom,f) == '*')
00417                 {   // field width
00418                     f_width = va_arg(ap, int);
00419                     f++;
00420             }
00421             else if (Isdigit(READMEMBYTE(stringInRom,f)))
00422                 {
00423                     f_width = atoiRamRom(stringInRom, (char *) f);
00424                     while (Isdigit(READMEMBYTE(stringInRom,f)))
00425                         f++;        // skip the digits
00426             }
00427             if (READMEMBYTE(stringInRom,f) == '.')
00428                 {   // precision
00429                     f++;
00430                     if (READMEMBYTE(stringInRom,f) == '*')
00431                     {
00432                         prec = va_arg(ap, int);
00433                         f++;
00434                     }
00435                     else if (Isdigit(READMEMBYTE(stringInRom,f)))
00436                     {
00437                         prec = atoiRamRom(stringInRom, (char *) f);
00438                         while (Isdigit(READMEMBYTE(stringInRom,f)))
00439                             f++;    // skip the digits
00440                     }
00441                 }
00442             if (READMEMBYTE(stringInRom,f) == '#')
00443                 {   // alternate form
00444                     hash = 1;
00445                     f++;
00446             }
00447             if (READMEMBYTE(stringInRom,f) == 'l')
00448                 {   // long format
00449                     do_long = 1;
00450                     f++;
00451             }
00452 
00453                 fmt = READMEMBYTE(stringInRom,f);
00454                 bp = buf;
00455                 switch (fmt) {      // do the formatting
00456                 case 'd':           // 'd' signed decimal
00457                     if (do_long)
00458                         l = va_arg(ap, long);
00459                     else
00460                         l = (long) (va_arg(ap, int));
00461                     if (l < 0)
00462                     {
00463                         sign = 1;
00464                         l = -l;
00465                     }
00466                     do  {
00467                         *bp++ = l % 10 + '0';
00468                     } while ((l /= 10) > 0);
00469                     if (sign)
00470                         *bp++ = '-';
00471                     f_width = f_width - (bp - buf);
00472                     if (!flush_left)
00473                         while (f_width-- > 0)
00474                             rprintfChar(pad);
00475                     for (bp--; bp >= buf; bp--)
00476                         rprintfChar(*bp);
00477                     if (flush_left)
00478                         while (f_width-- > 0)
00479                             rprintfChar(' ');
00480                     break;
00481             case 'o':           // 'o' octal number
00482             case 'x':           // 'x' hex number
00483             case 'u':           // 'u' unsigned decimal
00484                     if (do_long)
00485                         u = va_arg(ap, unsigned long);
00486                     else
00487                         u = (unsigned long) (va_arg(ap, unsigned));
00488                     if (fmt == 'u')
00489                     {   // unsigned decimal
00490                         do {
00491                             *bp++ = u % 10 + '0';
00492                         } while ((u /= 10) > 0);
00493                     }
00494                     else if (fmt == 'o')
00495                     {  // octal
00496                         do {
00497                             *bp++ = u % 8 + '0';
00498                         } while ((u /= 8) > 0);
00499                         if (hash)
00500                             *bp++ = '0';
00501                     }
00502                     else if (fmt == 'x')
00503                     {   // hex
00504                         do {
00505                             i = u % 16;
00506                             if (i < 10)
00507                                 *bp++ = i + '0';
00508                             else
00509                                 *bp++ = i - 10 + 'a';
00510                         } while ((u /= 16) > 0);
00511                         if (hash)
00512                         {
00513                             *bp++ = 'x';
00514                             *bp++ = '0';
00515                         }
00516                     }
00517                     i = f_width - (bp - buf);
00518                     if (!flush_left)
00519                         while (i-- > 0)
00520                             rprintfChar(pad);
00521                     for (bp--; bp >= buf; bp--)
00522                         rprintfChar((int) (*bp));
00523                     if (flush_left)
00524                         while (i-- > 0)
00525                             rprintfChar(' ');
00526                     break;
00527             case 'c':           // 'c' character
00528                     i = va_arg(ap, int);
00529                     rprintfChar((int) (i));
00530                     break;
00531             case 's':           // 's' string
00532                     bp = va_arg(ap, unsigned char *);
00533                     if (!bp)
00534                         bp = (unsigned char *) "(nil)";
00535                     f_width = f_width - strlen((char *) bp);
00536                     if (!flush_left)
00537                         while (f_width-- > 0)
00538                             rprintfChar(pad);
00539                     for (i = 0; *bp && i < prec; i++)
00540                     {
00541                         rprintfChar(*bp);
00542                         bp++;
00543                     }
00544                     if (flush_left)
00545                         while (f_width-- > 0)
00546                             rprintfChar(' ');
00547                     break;
00548             case '%':           // '%' character
00549                     rprintfChar('%');
00550                     break;
00551             }
00552             flush_left = 0, f_width = 0, prec = INF, hash = 0, do_long = 0;
00553             sign = 0;
00554             pad = ' ';
00555         }
00556     }
00557 
00558     va_end(ap);
00559     return 0;
00560 }
00561 
00562 unsigned char Isdigit(char c)
00563 {
00564     if((c >= 0x30) && (c <= 0x39))
00565         return TRUE;
00566     else
00567         return FALSE;
00568 }
00569 
00570 int atoiRamRom(unsigned char stringInRom, char *str)
00571 {
00572     int num = 0;;
00573 
00574     while(Isdigit(READMEMBYTE(stringInRom,str)))
00575     {
00576         num *= 10;
00577         num += ((READMEMBYTE(stringInRom,str++)) - 0x30);
00578     }
00579     return num;
00580 }
00581 
00582 #endif
00583 
00584 //******************************************************************************
00585 // code below this line is commented out and can be ignored
00586 //******************************************************************************
00587 /*
00588 char* sprintf(const char *sfmt, ...)
00589 {
00590     register unsigned char *f, *bp, *str;
00591     register long l;
00592     register unsigned long u;
00593     register int i;
00594     register int fmt;
00595     register unsigned char pad = ' ';
00596     int     flush_left = 0, f_width = 0, prec = INF, hash = 0, do_long = 0;
00597     int     sign = 0;
00598 
00599     va_list ap;
00600     va_start(ap, sfmt);
00601 
00602     str = bufstring;
00603     f = (unsigned char *) sfmt;
00604 
00605     for (; *f; f++)
00606     {
00607         if (*f != '%')
00608         {                               // not a format character
00609             *str++ = (*f);          // then just output the char
00610         }
00611         else 
00612         {
00613             f++;                        // if we have a "%" then skip it
00614             if (*f == '-')
00615             {
00616                 flush_left = 1; // minus: flush left
00617                 f++;
00618             }
00619             if (*f == '0' || *f == '.')
00620                 {
00621                     // padding with 0 rather than blank
00622                     pad = '0';
00623                     f++;
00624             }
00625             if (*f == '*')
00626                 {   // field width
00627                     f_width = va_arg(ap, int);
00628                     f++;
00629             }
00630             else if (Isdigit(*f))
00631                 {
00632                     f_width = atoi((char *) f);
00633                     while (Isdigit(*f))
00634                         f++;        // skip the digits
00635             }
00636             if (*f == '.')
00637                 {   // precision
00638                     f++;
00639                     if (*f == '*')
00640                     {
00641                         prec = va_arg(ap, int);
00642                         f++;
00643                     }
00644                     else if (Isdigit(*f))
00645                     {
00646                         prec = atoi((char *) f);
00647                         while (Isdigit(*f))
00648                             f++;    // skip the digits
00649                     }
00650                 }
00651             if (*f == '#')
00652                 {   // alternate form
00653                     hash = 1;
00654                     f++;
00655             }
00656             if (*f == 'l')
00657                 {   // long format
00658                     do_long = 1;
00659                     f++;
00660             }
00661 
00662                 fmt = *f;
00663                 bp = buf;
00664                 switch (fmt) {      // do the formatting
00665                 case 'd':           // 'd' signed decimal
00666                     if (do_long)
00667                         l = va_arg(ap, long);
00668                     else
00669                         l = (long) (va_arg(ap, int));
00670                     if (l < 0)
00671                     {
00672                         sign = 1;
00673                         l = -l;
00674                     }
00675                     do  {
00676                         *bp++ = l % 10 + '0';
00677                     } while ((l /= 10) > 0);
00678                     if (sign)
00679                         *bp++ = '-';
00680                     f_width = f_width - (bp - buf);
00681                     if (!flush_left)
00682                         while (f_width-- > 0)
00683                             *str++ = (pad);
00684                     for (bp--; bp >= buf; bp--)
00685                         *str++ = (*bp);
00686                     if (flush_left)
00687                         while (f_width-- > 0)
00688                             *str++ = (' ');
00689                     break;
00690             case 'o':           // 'o' octal number
00691             case 'x':           // 'x' hex number
00692             case 'u':           // 'u' unsigned decimal
00693                     if (do_long)
00694                         u = va_arg(ap, unsigned long);
00695                     else
00696                         u = (unsigned long) (va_arg(ap, unsigned));
00697                     if (fmt == 'u')
00698                     {   // unsigned decimal
00699                         do {
00700                             *bp++ = u % 10 + '0';
00701                         } while ((u /= 10) > 0);
00702                     }
00703                     else if (fmt == 'o')
00704                     {  // octal
00705                         do {
00706                             *bp++ = u % 8 + '0';
00707                         } while ((u /= 8) > 0);
00708                         if (hash)
00709                             *bp++ = '0';
00710                     }
00711                     else if (fmt == 'x')
00712                     {   // hex
00713                         do {
00714                             i = u % 16;
00715                             if (i < 10)
00716                                 *bp++ = i + '0';
00717                             else
00718                                 *bp++ = i - 10 + 'a';
00719                         } while ((u /= 16) > 0);
00720                         if (hash)
00721                         {
00722                             *bp++ = 'x';
00723                             *bp++ = '0';
00724                         }
00725                     }
00726                     i = f_width - (bp - buf);
00727                     if (!flush_left)
00728                         while (i-- > 0)
00729                             *str++ = (pad);
00730                     for (bp--; bp >= buf; bp--)
00731                         *str++ = ((int) (*bp));
00732                     if (flush_left)
00733                         while (i-- > 0)
00734                             *str++ = (' ');
00735                     break;
00736             case 'c':           // 'c' character
00737                     i = va_arg(ap, int);
00738                     *str++ = ((int) (i));
00739                     break;
00740             case 's':           // 's' string
00741                     bp = va_arg(ap, unsigned char *);
00742                     if (!bp)
00743                         bp = (unsigned char *) "(nil)";
00744                     f_width = f_width - strlen((char *) bp);
00745                     if (!flush_left)
00746                         while (f_width-- > 0)
00747                             *str++ = (pad);
00748                     for (i = 0; *bp && i < prec; i++)
00749                     {
00750                         *str++ = (*bp);
00751                         bp++;
00752                     }
00753                     if (flush_left)
00754                         while (f_width-- > 0)
00755                             *str++ = (' ');
00756                     break;
00757             case '%':           // '%' character
00758                     *str++ = ('%');
00759                     break;
00760             }
00761             flush_left = 0, f_width = 0, prec = INF, hash = 0, do_long = 0;
00762             sign = 0;
00763             pad = ' ';
00764         }
00765     }
00766 
00767     va_end(ap);
00768     // terminate string with null
00769     *str++ = '\0';
00770     return bufstring;
00771 }
00772 
00773 */

Generated on Tue Sep 20 03:11:43 2005 for Procyon AVRlib by  doxygen 1.4.2