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_uint64 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 */
101 HAL_DIAG_WRITE_CHAR('\r');
104 HAL_DIAG_WRITE_CHAR(c);
107 // Default wrapper function used by diag_printf
109 _diag_write_char(char c, void *param)
114 /*----------------------------------------------------------------------*/
115 /* Initialize. Call to pull in diag initializing constructor */
117 externC void diag_init(void)
122 // This routine is used to send characters during 'printf()' functions.
123 // It can be replaced by providing a replacement via diag_init_putc().
125 static void (*_putc)(char c, void *param) = _diag_write_char;
128 diag_init_putc(void (*putc)(char c, void *param))
133 /*----------------------------------------------------------------------*/
134 /* Write zero terminated string */
136 externC void diag_write_string(const char *psz)
139 diag_write_char(*psz++);
142 /*----------------------------------------------------------------------*/
143 /* Write decimal value */
145 externC void diag_write_dec(cyg_int32 n)
154 diag_write_num(n, 10, sign, false, 0);
157 /*----------------------------------------------------------------------*/
158 /* Write hexadecimal value */
160 externC void diag_write_hex(cyg_uint32 n)
162 diag_write_num(n, 16, '+', false, 0);
165 /*----------------------------------------------------------------------*/
166 /* Generic number writing function */
167 /* The parameters determine what radix is used, the signed-ness of the */
168 /* number, its minimum width and whether it is zero or space filled on */
171 externC void diag_write_long_num(
172 cyg_uint64 n, /* number to write */
173 cyg_ucount8 base, /* radix to write to */
174 cyg_ucount8 sign, /* sign, '-' if -ve, '+' if +ve */
175 cyg_bool pfzero, /* prefix with zero ? */
176 cyg_ucount8 width /* min width of number */
181 char bufinit = pfzero?'0':' ';
182 const char *digits = "0123456789ABCDEF";
184 /* init buffer to padding char: space or zero */
185 for (bpos = 0; bpos < (cyg_count8)sizeof(buf); bpos++)
188 /* Set pos to start */
191 /* construct digits into buffer in reverse order */
196 cyg_ucount8 d = n % base;
197 buf[bpos++] = digits[d];
201 /* set pos to width if less. */
202 if ((cyg_count8)width > bpos)
205 /* set sign if negative. */
207 if (buf[bpos-1] == bufinit) bpos--;
213 /* Now write it out in correct order. */
215 diag_write_char(buf[bpos--]);
218 externC void diag_write_num(
219 cyg_uint64 n, /* number to write */
220 cyg_ucount8 base, /* radix to write to */
221 cyg_ucount8 sign, /* sign, '-' if -ve, '+' if +ve */
222 cyg_bool pfzero, /* prefix with zero ? */
223 cyg_ucount8 width /* min width of number */
226 diag_write_long_num(n, base, sign, pfzero, width);
229 /*----------------------------------------------------------------------*/
230 /* perform some simple sanity checks on a string to ensure that it */
231 /* consists of printable characters and is of reasonable length. */
233 static cyg_bool diag_check_string(const char *str)
235 cyg_bool result = true;
241 for (s = str ; result && *s ; s++) {
244 /* Check for a reasonable length string. */
248 /* We only really support CR, NL, tab and backspace at present.
249 * If we want to use other special chars, this test will
250 * have to be expanded. */
251 if (c == '\n' || c == '\r' || c == '\b' || c == '\t')
254 /* Check for printable chars. This assumes ASCII */
255 if (c < ' ' || c > '~')
262 /*----------------------------------------------------------------------*/
265 _cvt(unsigned long long val, char *buf, long radix, const char *digits)
276 *cp++ = digits[val % radix];
288 #define is_digit(c) ((c >= '0') && (c <= '9'))
291 _vprintf(void (*putc)(char c, void *param), void *param, const char *fmt, va_list ap)
293 char buf[sizeof(long long) * 8];
295 const char *cp = buf;
296 int left_prec, right_prec, zero_fill, pad, pad_on_right,
297 i, islong, islonglong;
299 int res = 0, length = 0;
301 if (!diag_check_string(fmt)) {
302 diag_write_string("<Bad format string: ");
303 diag_write_hex((cyg_uint32)fmt);
304 diag_write_string(" :");
305 for (i = 0; i < 8; i++) {
306 diag_write_char(' ');
307 val = va_arg(ap, unsigned long);
310 diag_write_string(">\n");
313 while ((c = *fmt++) != '\0') {
316 left_prec = right_prec = pad_on_right = islong = islonglong = 0;
327 while (is_digit(c)) {
328 left_prec = (left_prec * 10) + (c - '0');
334 while (is_digit(c)) {
335 right_prec = (right_prec * 10) + (c - '0');
339 right_prec = left_prec;
347 // long long qualifier
354 islong = sizeof(size_t) == sizeof(long);
356 // Fetch value [numeric descriptors only]
369 val = va_arg(ap, long long);
371 val = (long long)va_arg(ap, long);
373 val = (long long)va_arg(ap, int);
375 if ((c == 'd') || (c == 'D')) {
381 // Mask to unsigned, sized quantity
383 // no need to mask longlong
385 val &= ((long long)1 << (sizeof(long) * 8)) - 1;
387 val &= ((long long)1 << (sizeof(int) * 8)) - 1;
400 left_prec = sizeof(unsigned long) * 2;
401 res += 2; // Account for "0x" leadin
413 length = _cvt(val, buf, 10, "0123456789");
417 length = _cvt(val, buf, 16, "0123456789abcdef");
420 length = _cvt(val, buf, 16, "0123456789ABCDEF");
427 cp = va_arg(ap, char *);
430 #if !CYGINT_ISO_CTYPE
431 #warning enable CYGINT_ISO_CTYPE to get sensible string output instead of bogus '<Not a string 0x...>' messages for unprintable characters
432 else if (!diag_check_string(cp)) {
433 diag_write_string("<Not a string: 0x");
434 diag_write_hex((cyg_uint32)cp);
439 while (cp[length] != '\0') length++;
443 c = va_arg(ap, int /*char*/);
450 if (left_prec == 0) {
452 length = sizeof(long long) * 8;
454 length = sizeof(long) * 8;
456 length = sizeof(int) * 8;
458 for (i = 0; i < length-1; i++) {
459 buf[i] = ((val & (1LL << i)) ? '1' : '.');
473 pad = left_prec - length;
497 while (length-- > 0) {
500 if (isprint(c) || isspace(c)) {
502 } else if (iscntrl(c)) {
506 putc(c | 0x40, param);
508 int len = _cvt(c, buf, 16, "0123456789ABCDEF");
512 for (int i = 0; i < len; i++) {
541 _sputc(char c, void *param)
543 struct _sputc_info *info = (struct _sputc_info *)param;
545 if (info->len < info->max) {
553 diag_sprintf(char *buf, const char *fmt, ...)
557 struct _sputc_info info;
561 info.max = 1024; // Unlimited
563 ret = _vprintf(_sputc, &info, fmt, ap);
569 diag_snprintf(char *buf, size_t len, const char *fmt, ...)
573 struct _sputc_info info;
579 ret = _vprintf(_sputc, &info, fmt, ap);
585 diag_vsprintf(char *buf, const char *fmt, va_list ap)
588 struct _sputc_info info;
591 info.max = 1024; // Unlimited
593 ret = _vprintf(_sputc, &info, fmt, ap);
598 diag_printf(const char *fmt, ...)
604 ret = _vprintf(_putc, NULL, fmt, ap);
610 diag_vprintf(const char *fmt, va_list ap)
614 ret = _vprintf(_putc, NULL, fmt, ap);
619 diag_vdump_buf_with_offset(__printf_fun *pf, void *_p, CYG_ADDRWORD s,
623 cyg_uint8 *p = (cyg_uint8 *)_p;
625 if (s > (CYG_ADDRWORD)p) {
626 s = s - (CYG_ADDRWORD)p;
629 pf("%08X: ", (CYG_ADDRWORD)p - (CYG_ADDRWORD)base);
630 for (i = 0; i < 16; i++) {
640 for (i = 0; i < 16; i++) {
643 if ((c < 0x20) || (c >= 0x7F)) c = '.';
656 diag_dump_buf_with_offset(void *p, CYG_ADDRWORD s, void *base)
658 diag_vdump_buf_with_offset(diag_printf, p, s, base);
662 diag_dump_buf(void *p, CYG_ADDRWORD s)
664 diag_dump_buf_with_offset(p, s, 0);
668 diag_dump_buf_with_offset_32bit(void *_p, CYG_ADDRWORD s,
672 cyg_uint32 *p = (cyg_uint32 *)_p;
674 if ((CYG_ADDRWORD)s > (CYG_ADDRWORD)p) {
675 s = (CYG_ADDRWORD)s - (CYG_ADDRWORD)p;
678 diag_printf("%08X: ", (CYG_ADDRWORD)p - (CYG_ADDRWORD)base);
679 for (i = 0; i < 4; i++) {
680 if (i < (int)s / 4) {
681 diag_printf("%08X ", p[i]);
693 diag_dump_buf_32bit(void *p, CYG_ADDRWORD s)
695 diag_dump_buf_with_offset_32bit(p, s, 0);
699 diag_dump_buf_with_offset_16bit(void *_p, CYG_ADDRWORD s,
703 cyg_uint16 * p = (cyg_uint16 *)_p;
705 if ((CYG_ADDRWORD)s > (CYG_ADDRWORD)p) {
706 s = (CYG_ADDRWORD)s - (CYG_ADDRWORD)p;
709 diag_printf("%08X: ", (CYG_ADDRWORD)p - (CYG_ADDRWORD)base);
710 for (i = 0; i < 8; i++) {
711 if (i < (int)s / 2) {
712 diag_printf("%04X ", p[i]);
713 if (i == 3) diag_printf(" ");
725 diag_dump_buf_16bit(void *p, CYG_ADDRWORD s)
727 diag_dump_buf_with_offset_16bit(p, s, 0);
730 /*-----------------------------------------------------------------------*/
731 /* EOF infra/diag.c */