1 /*========================================================================
5 // Infrastructure diagnostic output code
7 //========================================================================
8 //####ECOSGPLCOPYRIGHTBEGIN####
9 // -------------------------------------------
10 // This file is part of eCos, the Embedded Configurable Operating System.
11 // Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
12 // Copyright (C) 2002, 2004 Gary Thomas
14 // eCos is free software; you can redistribute it and/or modify it under
15 // the terms of the GNU General Public License as published by the Free
16 // Software Foundation; either version 2 or (at your option) any later version.
18 // eCos is distributed in the hope that it will be useful, but WITHOUT ANY
19 // WARRANTY; without even the implied warranty of MERCHANTABILITY or
20 // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
23 // You should have received a copy of the GNU General Public License along
24 // with eCos; if not, write to the Free Software Foundation, Inc.,
25 // 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
27 // As a special exception, if other files instantiate templates or use macros
28 // or inline functions from this file, or you compile this file and link it
29 // with other works to produce a work based on this file, this file does not
30 // by itself cause the resulting work to be covered by the GNU General Public
31 // License. However the source code for this file must still be made available
32 // in accordance with section (3) of the GNU General Public License.
34 // This exception does not invalidate any other reasons why a work based on
35 // this file might be covered by the GNU General Public License.
37 // Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
38 // at http://sources.redhat.com/ecos/ecos-license/
39 // -------------------------------------------
40 //####ECOSGPLCOPYRIGHTEND####
41 //========================================================================
42 //#####DESCRIPTIONBEGIN####
44 // Author(s): nickg,gthomas,jlarmour
47 // Purpose: Infrastructure diagnostic output
48 // Description: Implementations of infrastructure diagnostic routines.
50 //####DESCRIPTIONEND####
52 //======================================================================*/
54 #include <pkgconf/system.h>
55 #include <pkgconf/hal.h>
56 #include <pkgconf/infra.h>
58 #include <cyg/infra/cyg_type.h> // base types
60 #include <cyg/infra/diag.h> // HAL polled output
61 #include <cyg/hal/hal_arch.h> // architectural stuff for...
62 #include <cyg/hal/hal_intr.h> // interrupt control
63 #include <cyg/hal/hal_diag.h> // diagnostic output routines
68 #ifdef CYG_HAL_DIAG_LOCK_DATA_DEFN
69 CYG_HAL_DIAG_LOCK_DATA_DEFN;
72 /*----------------------------------------------------------------------*/
74 externC void diag_write_num(
75 cyg_uint32 n, /* number to write */
76 cyg_ucount8 base, /* radix to write to */
77 cyg_ucount8 sign, /* sign, '-' if -ve, '+' if +ve */
78 cyg_bool pfzero, /* prefix with zero ? */
79 cyg_ucount8 width /* min width of number */
82 class Cyg_dummy_diag_init_class {
84 Cyg_dummy_diag_init_class() {
89 // Initialize after HAL.
90 static Cyg_dummy_diag_init_class cyg_dummy_diag_init_obj
91 CYGBLD_ATTRIB_INIT_AFTER(CYG_INIT_HAL);
93 /*----------------------------------------------------------------------*/
94 /* Write single char to output */
96 externC void diag_write_char(char c)
98 /* Translate LF into CRLF */
102 HAL_DIAG_WRITE_CHAR('\r');
105 HAL_DIAG_WRITE_CHAR(c);
108 // Default wrapper function used by diag_printf
110 _diag_write_char(char c, void *param)
115 /*----------------------------------------------------------------------*/
116 /* Initialize. Call to pull in diag initializing constructor */
118 externC void diag_init(void)
123 // This routine is used to send characters during 'printf()' functions.
124 // It can be replaced by providing a replacement via diag_init_putc().
126 static void (*_putc)(char c, void *param) = _diag_write_char;
129 diag_init_putc(void (*putc)(char c, void *param))
134 /*----------------------------------------------------------------------*/
135 /* Write zero terminated string */
137 externC void diag_write_string(const char *psz)
139 while( *psz ) diag_write_char( *psz++ );
142 /*----------------------------------------------------------------------*/
143 /* Write decimal value */
145 externC void diag_write_dec( cyg_int32 n)
149 if( n < 0 ) n = -n, sign = '-';
152 diag_write_num( n, 10, sign, false, 0);
155 /*----------------------------------------------------------------------*/
156 /* Write hexadecimal value */
158 externC void diag_write_hex( cyg_uint32 n)
160 diag_write_num( n, 16, '+', false, 0);
163 /*----------------------------------------------------------------------*/
164 /* Generic number writing function */
165 /* The parameters determine what radix is used, the signed-ness of the */
166 /* number, its minimum width and whether it is zero or space filled on */
169 externC void diag_write_long_num(
170 cyg_uint64 n, /* number to write */
171 cyg_ucount8 base, /* radix to write to */
172 cyg_ucount8 sign, /* sign, '-' if -ve, '+' if +ve */
173 cyg_bool pfzero, /* prefix with zero ? */
174 cyg_ucount8 width /* min width of number */
179 char bufinit = pfzero?'0':' ';
180 const char *digits = "0123456789ABCDEF";
182 /* init buffer to padding char: space or zero */
183 for( bpos = 0; bpos < (cyg_count8)sizeof(buf); bpos++ ) buf[bpos] = bufinit;
185 /* Set pos to start */
188 /* construct digits into buffer in reverse order */
189 if( n == 0 ) buf[bpos++] = '0';
192 cyg_ucount8 d = n % base;
193 buf[bpos++] = digits[d];
197 /* set pos to width if less. */
198 if( (cyg_count8)width > bpos ) bpos = width;
200 /* set sign if negative. */
203 if( buf[bpos-1] == bufinit ) bpos--;
208 /* Now write it out in correct order. */
210 diag_write_char(buf[bpos--]);
213 externC void diag_write_num(
214 cyg_uint32 n, /* number to write */
215 cyg_ucount8 base, /* radix to write to */
216 cyg_ucount8 sign, /* sign, '-' if -ve, '+' if +ve */
217 cyg_bool pfzero, /* prefix with zero ? */
218 cyg_ucount8 width /* min width of number */
221 diag_write_long_num((long long)n, base, sign, pfzero, width);
224 /*----------------------------------------------------------------------*/
225 /* perform some simple sanity checks on a string to ensure that it */
226 /* consists of printable characters and is of reasonable length. */
228 static cyg_bool diag_check_string( const char *str )
230 cyg_bool result = true;
233 if( str == NULL ) return false;
235 for( s = str ; result && *s ; s++ )
239 /* Check for a reasonable length string. */
241 if( s-str > 2048 ) result = false;
243 /* We only really support CR, NL, tab and backspace at present.
244 * If we want to use other special chars, this test will
245 * have to be expanded. */
247 if( c == '\n' || c == '\r' || c == '\b' || c == '\t' )
250 /* Check for printable chars. This assumes ASCII */
252 if( c < ' ' || c > '~' )
260 /*----------------------------------------------------------------------*/
263 _cvt(unsigned long long val, char *buf, long radix, const char *digits)
274 *cp++ = digits[val % radix];
286 #define is_digit(c) ((c >= '0') && (c <= '9'))
289 _vprintf(void (*putc)(char c, void *param), void *param, const char *fmt, va_list ap)
291 char buf[sizeof(long long)*8];
294 int left_prec, right_prec, zero_fill, pad, pad_on_right,
295 i, islong, islonglong;
297 int res = 0, length = 0;
299 if (!diag_check_string(fmt)) {
300 diag_write_string("<Bad format string: ");
301 diag_write_hex((cyg_uint32)fmt);
302 diag_write_string(" :");
303 for( i = 0; i < 8; i++ ) {
304 diag_write_char(' ');
305 val = va_arg(ap, unsigned long);
308 diag_write_string(">\n");
311 while ((c = *fmt++) != '\0') {
314 left_prec = right_prec = pad_on_right = islong = islonglong = 0;
325 while (is_digit(c)) {
326 left_prec = (left_prec * 10) + (c - '0');
332 while (is_digit(c)) {
333 right_prec = (right_prec * 10) + (c - '0');
337 right_prec = left_prec;
345 // long long qualifier
352 islong = sizeof(size_t) == sizeof(long);
354 // Fetch value [numeric descriptors only]
367 val = va_arg(ap, long long);
369 val = (long long)va_arg(ap, long);
371 val = (long long)va_arg(ap, int);
373 if ((c == 'd') || (c == 'D')) {
379 // Mask to unsigned, sized quantity
381 val &= ((long long)1 << (sizeof(long) * 8)) - 1;
382 } else if (!islonglong) { // no need to mask longlong
383 val &= ((long long)1 << (sizeof(int) * 8)) - 1;
396 left_prec = sizeof(unsigned long)*2;
397 res += 2; // Account for "0x" leadin
409 length = _cvt(val, buf, 10, "0123456789");
413 length = _cvt(val, buf, 16, "0123456789abcdef");
416 length = _cvt(val, buf, 16, "0123456789ABCDEF");
423 cp = va_arg(ap, char *);
426 #if !CYGINT_ISO_CTYPE
427 #warning enable CYGINT_ISO_CTYPE to get sensible string output instead of bogus '<Not a string 0x...>' messages for unprintable characters
428 else if (!diag_check_string(cp)) {
429 diag_write_string("<Not a string: 0x");
430 diag_write_hex((cyg_uint32)cp);
435 while (cp[length] != '\0') length++;
439 c = va_arg(ap, int /*char*/);
446 if (left_prec == 0) {
448 length = sizeof(long long)*8;
450 length = sizeof(long)*8;
452 length = sizeof(int)*8;
454 for (i = 0; i < length-1; i++) {
455 buf[i] = ((val & ((long long)1<<i)) ? '1' : '.');
469 pad = left_prec - length;
476 (*putc)(sign, param);
490 (*putc)(sign, param);
493 while (length-- > 0) {
496 if (isprint(c) || isspace(c)) {
498 } else if (iscntrl(c)) {
499 (*putc)('\\', param);
502 (*putc)(c | 0x40, param);
504 int len = _cvt(c, buf, 16, "0123456789ABCDEF");
505 (*putc)('\\', param);
508 for (int i = 0; i < len; i++) {
509 (*putc)(buf[i], param);
537 _sputc(char c, void *param)
539 struct _sputc_info *info = (struct _sputc_info *)param;
541 if (info->len < info->max) {
549 diag_sprintf(char *buf, const char *fmt, ...)
553 struct _sputc_info info;
557 info.max = 1024; // Unlimited
559 ret = _vprintf(_sputc, (void *)&info, fmt, ap);
565 diag_snprintf(char *buf, size_t len, const char *fmt, ...)
569 struct _sputc_info info;
575 ret = _vprintf(_sputc, (void *)&info, fmt, ap);
581 diag_vsprintf(char *buf, const char *fmt, va_list ap)
584 struct _sputc_info info;
587 info.max = 1024; // Unlimited
589 ret = _vprintf(_sputc, (void *)&info, fmt, ap);
594 diag_printf(const char *fmt, ...)
600 ret = _vprintf(_putc, (void *)0, fmt, ap);
606 diag_vprintf(const char *fmt, va_list ap)
610 ret = _vprintf(_putc, (void *)0, fmt, ap);
615 diag_vdump_buf_with_offset(__printf_fun *pf,
621 if ((CYG_ADDRWORD)s > (CYG_ADDRWORD)p) {
622 s = (CYG_ADDRWORD)s - (CYG_ADDRWORD)p;
626 (*pf)("%08X: ", (CYG_ADDRWORD)p - (CYG_ADDRWORD)base);
630 for (i = 0; i < 16; i++) {
632 (*pf)("%02X ", p[i] & 0xFF);
636 if (i == 7) (*pf)(" ");
639 for (i = 0; i < 16; i++) {
642 if ((c < 0x20) || (c >= 0x7F)) c = '.';
655 diag_dump_buf_with_offset(cyg_uint8 *p,
659 diag_vdump_buf_with_offset(diag_printf, p, s, base);
663 diag_dump_buf(void *p, CYG_ADDRWORD s)
665 diag_dump_buf_with_offset((cyg_uint8 *)p, s, 0);
669 diag_dump_buf_with_offset_32bit(cyg_uint32 *p,
674 if ((CYG_ADDRWORD)s > (CYG_ADDRWORD)p) {
675 s = (CYG_ADDRWORD)s - (CYG_ADDRWORD)p;
679 diag_printf("%08X: ", (CYG_ADDRWORD)p - (CYG_ADDRWORD)base);
681 diag_printf("%08X: ", (CYG_ADDRWORD)p);
683 for (i = 0; i < 4; i++) {
685 diag_printf("%08X ", p[i] );
697 diag_dump_buf_32bit(void *p, CYG_ADDRWORD s)
699 diag_dump_buf_with_offset_32bit((cyg_uint32 *)p, s, 0);
703 diag_dump_buf_with_offset_16bit(cyg_uint16 *p,
708 if ((CYG_ADDRWORD)s > (CYG_ADDRWORD)p) {
709 s = (CYG_ADDRWORD)s - (CYG_ADDRWORD)p;
713 diag_printf("%08X: ", (CYG_ADDRWORD)p - (CYG_ADDRWORD)base);
715 diag_printf("%08X: ", (CYG_ADDRWORD)p);
717 for (i = 0; i < 8; i++) {
719 diag_printf("%04X ", p[i] );
720 if (i == 3) diag_printf(" ");
732 diag_dump_buf_16bit(void *p, CYG_ADDRWORD s)
734 diag_dump_buf_with_offset_16bit((cyg_uint16 *)p, s, 0);
737 /*-----------------------------------------------------------------------*/
738 /* EOF infra/diag.c */