Subversion Repositories FlightCtrl

Rev

Rev 838 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
838 MikeW 1
// Die Funktion printf_P() unterliegt ihrer eigenen Lizenz und ist nicht von der Lizenz für den MikroKopter-Teil unterstellt
2
 
3
/*
4
Copyright (C) 1993 Free Software Foundation
5
 
6
This file is part of the GNU IO Library.  This library is free
7
software; you can redistribute it and/or modify it under the
8
terms of the GNU General Public License as published by the
9
Free Software Foundation; either version 2, or (at your option)
10
any later version.
11
 
12
This library is distributed in the hope that it will be useful,
13
but WITHOUT ANY WARRANTY; without even the implied warranty of
14
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
GNU General Public License for more details.
16
 
17
You should have received a copy of the GNU General Public License
18
along with this library; see the file COPYING.  If not, write to the Free
19
Software Foundation, 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
20
 
21
As a special exception, if you link this library with files
22
compiled with a GNU compiler to produce an executable, this does not cause
23
the resulting executable to be covered by the GNU General Public License.
24
This exception does not however invalidate any other reasons why
25
the executable file might be covered by the GNU General Public License. */
26
 
27
/*
28
 * Copyright (c) 1990 Regents of the University of California.
29
 * All rights reserved.
30
 *
31
 * Redistribution and use in source and binary forms, with or without
32
 * modification, are permitted provided that the following conditions
33
 * are met:
34
 * 1. Redistributions of source code must retain the above copyright
35
 *    notice, this list of conditions and the following disclaimer.
36
 * 2. Redistributions in binary form must reproduce the above copyright
37
 *    notice, this list of conditions and the following disclaimer in the
38
 *    documentation and/or other materials provided with the distribution.
39
 * 3. [rescinded 22 July 1999]
40
 * 4. Neither the name of the University nor the names of its contributors
41
 *    may be used to endorse or promote products derived from this software
42
 *    without specific prior written permission.
43
 *
44
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
45
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
46
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
47
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
48
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
49
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
50
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
51
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
52
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
53
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
54
 * SUCH DAMAGE.
55
 */
56
 
57
/******************************************************************************
58
 This file is a patched version of printf called _printf_P
59
 It is made to work with avr-gcc for Atmel AVR MCUs.
60
 There are some differences from standard printf:
61
        1. There is no floating point support (with fp the code is about 8K!)
62
        2. Return type is void
63
        3. Format string must be in program memory (by using macro printf this is
64
           done automaticaly)
65
        4. %n is not implemented (just remove the comment around it if you need it)
66
        5. If LIGHTPRINTF is defined, the code is about 550 bytes smaller and the
67
           folowing specifiers are disabled :
68
                space # * . - + p s o O
69
        6. A function void uart_sendchar(char c) is used for output. The UART must
70
                be initialized before using printf.
71
 
72
 Alexander Popov
73
 sasho@vip.orbitel.bg
74
******************************************************************************/
75
 
76
/*
77
 * Actual printf innards.
78
 *
79
 * This code is large and complicated...
80
 */
81
 
82
#include <string.h>
83
#ifdef __STDC__
84
#include <stdarg.h>
85
#else
86
#include <varargs.h>
87
#endif
88
 
89
#include "main.h"
90
 
91
 
92
//#define LIGHTPRINTF
93
char PrintZiel;
94
 
95
 
96
char Putchar(char zeichen)
97
{
98
  if(PrintZiel == OUT_LCD)
99
  {
966 MikeW 100
    DisplayBuff[DispPtr++] = zeichen; return(1);
838 MikeW 101
  }
102
  else if (PrintZiel == OUT_OSD)
103
  {
966 MikeW 104
    OSDBuff[OSDPtr++] = zeichen; return(1);
838 MikeW 105
  }
106
  else
107
  {
966 MikeW 108
    return(uart_putchar(zeichen));
838 MikeW 109
  }
110
}
111
 
112
 
113
void PRINT(const char * ptr, unsigned int len)
114
{
115
 for(;len;len--) Putchar(*ptr++);
116
}
117
 
118
void PRINTP(const char * ptr, unsigned int len)
119
{
120
 for(;len;len--) Putchar(pgm_read_byte(ptr++));
121
}
122
 
123
void PAD_SP(signed char howmany)
124
{
125
        for(;howmany>0;howmany--) Putchar(' ');
126
}
127
 
128
void PAD_0(signed char howmany)
129
{
130
        for(;howmany>0;howmany--) Putchar('0');
131
}
132
 
133
#define BUF             40
134
 
135
/*
136
 * Macros for converting digits to letters and vice versa
137
 */
138
#define to_digit(c)     ((c) - '0')
139
#define  is_digit(c)    ((c)<='9' && (c)>='0')
140
#define to_char(n)      ((n) + '0')
141
 
142
/*
143
 * Flags used during conversion.
144
 */
145
#define LONGINT         0x01            /* long integer */
146
#define LONGDBL         0x02            /* long double; unimplemented */
147
#define SHORTINT                0x04            /* short integer */
148
#define ALT                     0x08            /* alternate form */
149
#define LADJUST         0x10            /* left adjustment */
150
#define ZEROPAD         0x20            /* zero (as opposed to blank) pad */
151
#define HEXPREFIX       0x40            /* add 0x or 0X prefix */
152
 
153
void _printf_P (char ziel,char const *fmt0, ...)      /* Works with string from FLASH */
154
{
966 MikeW 155
        va_list ap;
838 MikeW 156
        register const char *fmt; /* format string */
157
        register char ch;       /* character from fmt */
158
        register int n;         /* handy integer (short term usage) */
159
        register char *cp;      /* handy char pointer (short term usage) */
160
        const char *fmark;      /* for remembering a place in fmt */
161
        register unsigned char flags;   /* flags as above */
162
        signed char width;              /* width from format (%8d), or 0 */
163
        signed char prec;               /* precision from format (%.3d), or -1 */
164
        char sign;                              /* sign prefix (' ', '+', '-', or \0) */
165
        unsigned long _ulong=0; /* integer arguments %[diouxX] */
166
#define OCT 8
167
#define DEC 10
168
#define HEX 16
169
        unsigned char base;             /* base for [diouxX] conversion */
170
        signed char dprec;              /* a copy of prec if [diouxX], 0 otherwise */
171
        signed char dpad;                       /* extra 0 padding needed for integers */
172
        signed char fieldsz;            /* field size expanded by sign, dpad etc */
173
        /* The initialization of 'size' is to suppress a warning that
174
           'size' might be used unitialized.  It seems gcc can't
175
           quite grok this spaghetti code ... */
176
        signed char size = 0;           /* size of converted field or string */
177
        char buf[BUF];          /* space for %c, %[diouxX], %[eEfgG] */
178
        char ox[2];                     /* space for 0x hex-prefix */
179
 
180
    PrintZiel = ziel;  // bestimmt, LCD oder UART
181
        va_start(ap, fmt0);
182
 
183
        fmt = fmt0;
184
 
185
        /*
186
         * Scan the format for conversions (`%' character).
187
         */
188
        for (;;) {
189
                for (fmark = fmt; (ch = pgm_read_byte(fmt)) != '\0' && ch != '%'; fmt++)
190
                        /* void */;
191
                if ((n = fmt - fmark) != 0) {
192
                        PRINTP(fmark, n);
193
                }
194
                if (ch == '\0')
195
                        goto done;
196
                fmt++;          /* skip over '%' */
197
 
198
                flags = 0;
199
                dprec = 0;
200
                width = 0;
201
                prec = -1;
202
                sign = '\0';
203
 
204
rflag:          ch = PRG_RDB(fmt++);
205
reswitch:
206
#ifdef LIGHTPRINTF
207
        if (ch=='o' || ch=='u' || (ch|0x20)=='x') {
208
#else
209
        if (ch=='u' || (ch|0x20)=='x') {
210
#endif
211
                if (flags&LONGINT) {
212
                        _ulong=va_arg(ap, unsigned long);
213
                } else {
214
                        register unsigned int _d;
215
                        _d=va_arg(ap, unsigned int);
216
                        _ulong = flags&SHORTINT ? (unsigned long)(unsigned short)_d : (unsigned long)_d;
217
                }
218
        }
219
 
220
#ifndef LIGHTPRINTF
221
                if(ch==' ') {
222
                        /*
223
                         * ``If the space and + flags both appear, the space
224
                         * flag will be ignored.''
225
                         *      -- ANSI X3J11
226
                         */
227
                        if (!sign)
228
                                sign = ' ';
229
                        goto rflag;
230
                } else if (ch=='#') {
231
                        flags |= ALT;
232
                        goto rflag;
233
                } else if (ch=='*'||ch=='-') {
234
                        if (ch=='*') {
235
                                /*
236
                                 * ``A negative field width argument is taken as a
237
                                 * - flag followed by a positive field width.''
238
                                 *      -- ANSI X3J11
239
                                 * They don't exclude field widths read from args.
240
                                 */
241
                                if ((width = va_arg(ap, int)) >= 0)
242
                                        goto rflag;
243
                                width = -width;
244
                        }
245
                        flags |= LADJUST;
246
                        flags &= ~ZEROPAD; /* '-' disables '0' */
247
                        goto rflag;
248
                } else if (ch=='+') {
249
                        sign = '+';
250
                        goto rflag;
251
                } else if (ch=='.') {
252
                        if ((ch = PRG_RDB(fmt++)) == '*') {
253
                                n = va_arg(ap, int);
254
                                prec = n < 0 ? -1 : n;
255
                                goto rflag;
256
                        }
257
                        n = 0;
258
                        while (is_digit(ch)) {
259
                                n = n*10 + to_digit(ch);
260
                                ch = PRG_RDB(fmt++);
261
                        }
262
                        prec = n < 0 ? -1 : n;
263
                        goto reswitch;
264
                } else
265
#endif /* LIGHTPRINTF */
266
                if (ch=='0') {
267
                        /*
268
                         * ``Note that 0 is taken as a flag, not as the
269
                         * beginning of a field width.''
270
                         *      -- ANSI X3J11
271
                         */
272
                        if (!(flags & LADJUST))
273
                            flags |= ZEROPAD; /* '-' disables '0' */
274
                        goto rflag;
275
                } else if (ch>='1' && ch<='9') {
276
                        n = 0;
277
                        do {
278
                                n = 10 * n + to_digit(ch);
279
                                ch = PRG_RDB(fmt++);
280
                        } while (is_digit(ch));
281
                        width = n;
282
                        goto reswitch;
283
                } else if (ch=='h') {
284
                        flags |= SHORTINT;
285
                        goto rflag;
286
                } else if (ch=='l') {
287
                        flags |= LONGINT;
288
                        goto rflag;
289
                } else if (ch=='c') {
290
                        *(cp = buf) = va_arg(ap, int);
291
                        size = 1;
292
                        sign = '\0';
293
                } else if (ch=='D'||ch=='d'||ch=='i') {
294
                        if(ch=='D')
295
                                flags |= LONGINT;
296
                        if (flags&LONGINT) {
297
                                _ulong=va_arg(ap, long);
298
                        } else {
299
                                register int _d;
300
                                _d=va_arg(ap, int);
301
                                _ulong = flags&SHORTINT ? (long)(short)_d : (long)_d;
302
                        }
303
 
304
                        if ((long)_ulong < 0) {
305
                                _ulong = -_ulong;
306
                                sign = '-';
307
                        }
308
                        base = DEC;
309
                        goto number;
310
                } else
311
/*             
312
                if (ch=='n') {
313
                        if (flags & LONGINT)
314
                                *va_arg(ap, long *) = ret;
315
                        else if (flags & SHORTINT)
316
                                *va_arg(ap, short *) = ret;
317
                        else
318
                                *va_arg(ap, int *) = ret;
319
                        continue;       // no output
320
                } else
321
*/
322
#ifndef LIGHTPRINTF                     
323
                if (ch=='O'||ch=='o') {
324
                        if (ch=='O')
325
                                flags |= LONGINT;
326
                        base = OCT;
327
                        goto nosign;
328
                } else if (ch=='p') {
329
                        /*
330
                         * ``The argument shall be a pointer to void.  The
331
                         * value of the pointer is converted to a sequence
332
                         * of printable characters, in an implementation-
333
                         * defined manner.''
334
                         *      -- ANSI X3J11
335
                         */
336
                        /* NOSTRICT */
337
                        _ulong = (unsigned int)va_arg(ap, void *);
338
                        base = HEX;
339
                        flags |= HEXPREFIX;
340
                        ch = 'x';
341
                        goto nosign;
342
                } else if (ch=='s') {  // print a string from RAM
343
                        if ((cp = va_arg(ap, char *)) == NULL) {
344
                                cp=buf;
345
                                cp[0] = '(';
346
                                cp[1] = 'n';
347
                                cp[2] = 'u';
348
                                cp[4] = cp[3] = 'l';
349
                                cp[5] = ')';
350
                                cp[6] = '\0';
351
                        }
352
                        if (prec >= 0) {
353
                                /*
354
                                 * can't use strlen; can only look for the
355
                                 * NUL in the first `prec' characters, and
356
                                 * strlen() will go further.
357
                                 */
358
                                char *p = (char*)memchr(cp, 0, prec);
359
 
360
                                if (p != NULL) {
361
                                        size = p - cp;
362
                                        if (size > prec)
363
                                                size = prec;
364
                                } else
365
                                        size = prec;
366
                        } else
367
                                size = strlen(cp);
368
                        sign = '\0';
369
                } else
370
#endif /* LIGHTPRINTF */                        
371
                if(ch=='U'||ch=='u') {
372
                        if (ch=='U')
373
                                flags |= LONGINT;
374
                        base = DEC;
375
                        goto nosign;
376
                } else if (ch=='X'||ch=='x') {
377
                        base = HEX;
378
                        /* leading 0x/X only if non-zero */
379
                        if (flags & ALT && _ulong != 0)
380
                                flags |= HEXPREFIX;
381
 
382
                        /* unsigned conversions */
383
nosign:                 sign = '\0';
384
                        /*
385
                         * ``... diouXx conversions ... if a precision is
386
                         * specified, the 0 flag will be ignored.''
387
                         *      -- ANSI X3J11
388
                         */
389
number: if ((dprec = prec) >= 0)
390
                                flags &= ~ZEROPAD;
391
 
392
                        /*
393
                         * ``The result of converting a zero value with an
394
                         * explicit precision of zero is no characters.''
395
                         *      -- ANSI X3J11
396
                         */
397
                        cp = buf + BUF;
398
                        if (_ulong != 0 || prec != 0) {
399
                                register unsigned char _d,notlastdigit;
400
                                do {
401
                                        notlastdigit=(_ulong>=base);
402
                                        _d = _ulong % base;
403
 
404
                                        if (_d<10) {
405
                                                _d+='0';
406
                                        } else {
407
                                                _d+='a'-10;
408
                                                if (ch=='X') _d&=~0x20;
409
                                        }
410
                                        *--cp=_d;
411
                                        _ulong /= base;
412
                                } while (notlastdigit);
413
#ifndef LIGHTPRINTF
414
                                // handle octal leading 0 
415
                                if (base==OCT && flags & ALT && *cp != '0')
416
                                        *--cp = '0';
417
#endif
418
                        }
419
 
420
                        size = buf + BUF - cp;
421
        } else {  //default
422
                /* "%?" prints ?, unless ? is NUL */
423
                        if (ch == '\0')
424
                                goto done;
425
                        /* pretend it was %c with argument ch */
426
                        cp = buf;
427
                        *cp = ch;
428
                        size = 1;
429
                        sign = '\0';
430
                }
431
 
432
                /*
433
                 * All reasonable formats wind up here.  At this point,
434
                 * `cp' points to a string which (if not flags&LADJUST)
435
                 * should be padded out to `width' places.  If
436
                 * flags&ZEROPAD, it should first be prefixed by any
437
                 * sign or other prefix; otherwise, it should be blank
438
                 * padded before the prefix is emitted.  After any
439
                 * left-hand padding and prefixing, emit zeroes
440
                 * required by a decimal [diouxX] precision, then print
441
                 * the string proper, then emit zeroes required by any
442
                 * leftover floating precision; finally, if LADJUST,
443
                 * pad with blanks.
444
                 */
445
 
446
                /*
447
                 * compute actual size, so we know how much to pad.
448
                 */
449
                fieldsz = size;
450
 
451
                dpad = dprec - size;
452
                if (dpad < 0)
453
                    dpad = 0;
454
 
455
                if (sign)
456
                        fieldsz++;
457
                else if (flags & HEXPREFIX)
458
                        fieldsz += 2;
459
                fieldsz += dpad;
460
 
461
                /* right-adjusting blank padding */
462
                if ((flags & (LADJUST|ZEROPAD)) == 0)
463
                        PAD_SP(width - fieldsz);
464
 
465
                /* prefix */
466
                if (sign) {
467
                        PRINT(&sign, 1);
468
                } else if (flags & HEXPREFIX) {
469
                        ox[0] = '0';
470
                        ox[1] = ch;
471
                        PRINT(ox, 2);
472
                }
473
 
474
                /* right-adjusting zero padding */
475
                if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD)
476
                        PAD_0(width - fieldsz);
477
 
478
                /* leading zeroes from decimal precision */
479
                PAD_0(dpad);
480
 
481
                /* the string or number proper */
482
                PRINT(cp, size);
483
 
484
                /* left-adjusting padding (always blank) */
485
                if (flags & LADJUST)
486
                        PAD_SP(width - fieldsz);
487
        }
488
done:
489
        va_end(ap);
490
}