BeRTOS
kdebug.c
Go to the documentation of this file.
00001 
00039 #include "cfg/cfg_debug.h"
00040 #include <cfg/macros.h> /* for BV() */
00041 #include <cfg/debug.h>
00042 #include <cfg/os.h>
00043 
00044 #include <cpu/attr.h>
00045 #include <cpu/types.h>
00046 
00047 #include <mware/formatwr.h> /* for _formatted_write() */
00048 #include <cpu/pgm.h>
00049 
00050 #ifdef _DEBUG
00051 
00052 #if CPU_HARVARD && !defined(_PROGMEM)
00053     #error This module build correctly only in program memory!
00054 #endif
00055 
00056 
00057 #if OS_HOSTED
00058     #include <unistd.h> // write()
00059 
00060     #define KDBG_WAIT_READY()      do { /*nop*/ } while(0)
00061     #define KDBG_WRITE_CHAR(c)     do { char __c = (c); write(STDERR_FILENO, &__c, sizeof(__c)); } while(0)
00062     #define KDBG_MASK_IRQ(old)     do { (void)(old); } while(0)
00063     #define KDBG_RESTORE_IRQ(old)  do { /*nop*/ } while(0)
00064     typedef char kdbg_irqsave_t; /* unused */
00065 
00066     #define kdbg_hw_init() do {} while (0) ///< Not needed
00067 
00068     #if CONFIG_KDEBUG_PORT == 666
00069         #error BITBANG debug console missing for this platform
00070     #endif
00071 #else
00072     #include CPU_CSOURCE(kdebug)
00073 #endif
00074 
00075 
00076 void kdbg_init(void)
00077 {
00078     /* Init debug hw */
00079     kdbg_hw_init();
00080     kputs("\n\n*** BeRTOS DBG START ***\n");
00081 }
00082 
00083 
00087 static void __kputchar(char c, UNUSED_ARG(void *, unused))
00088 {
00089     /* Poll while serial buffer is still busy */
00090     KDBG_WAIT_READY();
00091 
00092     /* Send '\n' as '\r\n' for dumb terminals */
00093     if (c == '\n')
00094     {
00095         KDBG_WRITE_CHAR('\r');
00096         KDBG_WAIT_READY();
00097     }
00098 
00099     KDBG_WRITE_CHAR(c);
00100 }
00101 
00102 
00103 void kputchar(char c)
00104 {
00105     /* Mask serial TX intr */
00106     kdbg_irqsave_t irqsave;
00107     KDBG_MASK_IRQ(irqsave);
00108 
00109     __kputchar(c, 0);
00110 
00111     /* Restore serial TX intr */
00112     KDBG_RESTORE_IRQ(irqsave);
00113 }
00114 
00115 
00116 static void PGM_FUNC(kvprintf)(const char * PGM_ATTR fmt, va_list ap)
00117 {
00118 #if CONFIG_PRINTF
00119     /* Mask serial TX intr */
00120     kdbg_irqsave_t irqsave;
00121     KDBG_MASK_IRQ(irqsave);
00122 
00123     PGM_FUNC(_formatted_write)(fmt, __kputchar, 0, ap);
00124 
00125     /* Restore serial TX intr */
00126     KDBG_RESTORE_IRQ(irqsave);
00127 #else
00128     /* A better than nothing printf() surrogate. */
00129     PGM_FUNC(kputs)(fmt);
00130 #endif /* CONFIG_PRINTF */
00131 }
00132 
00133 void PGM_FUNC(kprintf)(const char * PGM_ATTR fmt, ...)
00134 {
00135     va_list ap;
00136 
00137     va_start(ap, fmt);
00138     PGM_FUNC(kvprintf)(fmt, ap);
00139     va_end(ap);
00140 }
00141 
00142 void PGM_FUNC(kputs)(const char * PGM_ATTR str)
00143 {
00144     char c;
00145 
00146     /* Mask serial TX intr */
00147     kdbg_irqsave_t irqsave;
00148     KDBG_MASK_IRQ(irqsave);
00149 
00150     while ((c = PGM_READ_CHAR(str++)))
00151         __kputchar(c, 0);
00152 
00153     KDBG_RESTORE_IRQ(irqsave);
00154 }
00155 
00156 
00160 int kputnum(int num)
00161 {
00162     int output_len = 0;
00163     int divisor = 10000;
00164     int digit;
00165 
00166     do
00167     {
00168         digit = num / divisor;
00169         num %= divisor;
00170 
00171         if (digit || output_len || divisor == 1)
00172         {
00173             kputchar(digit + '0');
00174             ++output_len;
00175         }
00176     }
00177     while (divisor /= 10);
00178 
00179     return output_len;
00180 }
00181 
00182 
00183 static void klocation(const char * PGM_ATTR file, int line)
00184 {
00185     PGM_FUNC(kputs)(file);
00186     kputchar(':');
00187     kputnum(line);
00188     PGM_FUNC(kputs)(PGM_STR(": "));
00189 }
00190 
00191 int PGM_FUNC(__bassert)(const char * PGM_ATTR cond, const char * PGM_ATTR file, int line)
00192 {
00193     klocation(file, line);
00194     PGM_FUNC(kputs)(PGM_STR("Assertion failed: "));
00195     PGM_FUNC(kputs)(cond);
00196     kputchar('\n');
00197     BREAKPOINT;
00198     return 1;
00199 }
00200 
00201 /*
00202  * Unfortunately, there's no way to get __func__ in
00203  * program memory, so we waste quite a lot of RAM in
00204  * AVR and other Harvard processors.
00205  */
00206 void PGM_FUNC(__trace)(const char *name)
00207 {
00208     PGM_FUNC(kprintf)(PGM_STR("%s()\n"), name);
00209 }
00210 
00211 void PGM_FUNC(__tracemsg)(const char *name, const char * PGM_ATTR fmt, ...)
00212 {
00213     va_list ap;
00214 
00215     PGM_FUNC(kprintf)(PGM_STR("%s(): "), name);
00216     va_start(ap, fmt);
00217     PGM_FUNC(kvprintf)(fmt, ap);
00218     va_end(ap);
00219     kputchar('\n');
00220 }
00221 
00222 int PGM_FUNC(__invalid_ptr)(void *value, const char * PGM_ATTR name, const char * PGM_ATTR file, int line)
00223 {
00224     klocation(file, line);
00225     PGM_FUNC(kputs)(PGM_STR("Invalid ptr: "));
00226     PGM_FUNC(kputs)(name);
00227     #if CONFIG_PRINTF
00228         PGM_FUNC(kprintf)(PGM_STR(" = 0x%p\n"), value);
00229     #else
00230         (void)value;
00231         kputchar('\n');
00232     #endif
00233     return 1;
00234 }
00235 
00236 
00237 void __init_wall(long *wall, int size)
00238 {
00239     while(size--)
00240         *wall++ = WALL_VALUE;
00241 }
00242 
00243 
00244 int PGM_FUNC(__check_wall)(long *wall, int size, const char * PGM_ATTR name, const char * PGM_ATTR file, int line)
00245 {
00246     int i, fail = 0;
00247 
00248     for (i = 0; i < size; i++)
00249     {
00250         if (wall[i] != WALL_VALUE)
00251         {
00252             klocation(file, line);
00253             PGM_FUNC(kputs)(PGM_STR("Wall broken: "));
00254             PGM_FUNC(kputs)(name);
00255             #if CONFIG_PRINTF
00256                 PGM_FUNC(kprintf)(PGM_STR("[%d] (0x%p) = 0x%lx\n"), i, wall + i, wall[i]);
00257             #else
00258                 kputchar('\n');
00259             #endif
00260             fail = 1;
00261         }
00262     }
00263 
00264     return fail;
00265 }
00266 
00267 
00268 #if CONFIG_PRINTF
00269 
00273 void kdump(const void *_buf, size_t len)
00274 {
00275     const unsigned char *buf = (const unsigned char *)_buf;
00276 
00277     kprintf("Dumping buffer at addr [%p], %zu bytes", buf, len);
00278     size_t i=0;
00279     while (len--)
00280     {
00281         if ((i++ % 16) == 0)
00282             kputs("\n");
00283         kprintf("%02X ", *buf++);
00284     }
00285     kputchar('\n');
00286 }
00287 
00288 #endif /* CONFIG_PRINTF */
00289 
00290 #endif /* _DEBUG */