Main Page   Data Structures   File List   Data Fields   Globals  

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

Generated on Tue Feb 4 20:18:37 2003 for Procyon AVRlib by doxygen1.3-rc2