Rename myself
[bertos.git] / bertos / drv / kdebug.c
1 /**
2  * \file
3  * <!--
4  * This file is part of BeRTOS.
5  *
6  * Bertos is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
19  *
20  * As a special exception, you may use this file as part of a free software
21  * library without restriction.  Specifically, if other files instantiate
22  * templates or use macros or inline functions from this file, or you compile
23  * this file and link it with other files to produce an executable, this
24  * file does not by itself cause the resulting executable to be covered by
25  * the GNU General Public License.  This exception does not however
26  * invalidate any other reasons why the executable file might be covered by
27  * the GNU General Public License.
28  *
29  * Copyright 2003, 2004, 2005, 2006, 2007 Develer S.r.l. (http://www.develer.com/)
30  * Copyright 2000, 2001, 2002 Bernie Innocenti <bernie@codewiz.org>
31  *
32  * -->
33  *
34  * \brief General pourpose debug support for embedded systems (implementation).
35  *
36  * \version $Id$
37  * \author Bernie Innocenti <bernie@codewiz.org>
38  * \author Stefano Fedrigo <aleph@develer.com>
39  */
40
41 #include "cfg/cfg_debug.h"
42 #include <cfg/macros.h> /* for BV() */
43 #include <cfg/debug.h>
44 #include <cfg/os.h>
45
46 #include <cpu/irq.h>
47 #include <cpu/attr.h>
48 #include <cpu/types.h>
49
50 #include <mware/formatwr.h> /* for _formatted_write() */
51 #include <mware/pgm.h>
52
53 #ifdef _DEBUG
54
55 #if CPU_HARVARD && !defined(_PROGMEM)
56         #error This module build correctly only in program memory!
57 #endif
58
59
60 #if OS_HOSTED
61         #include <stdio.h>
62         #define KDBG_WAIT_READY()      do { /*nop*/ } while(0)
63         #define KDBG_WRITE_CHAR(c)     putc((c), stderr)
64         #define KDBG_MASK_IRQ(old)     do { (void)(old); } while(0)
65         #define KDBG_RESTORE_IRQ(old)  do { /*nop*/ } while(0)
66         typedef char kdbg_irqsave_t; /* unused */
67
68         #define kdbg_hw_init() do {} while (0) ///< Not needed
69
70         #if CONFIG_KDEBUG_PORT == 666
71                 #error BITBANG debug console missing for this platform
72         #endif
73 #else
74         #include CPU_CSOURCE(kdebug)
75 #endif
76
77
78 void kdbg_init(void)
79 {
80         /* Init debug hw */
81         kdbg_hw_init();
82         kputs("\n\n*** BeRTOS DBG START ***\n");
83 }
84
85
86 /**
87  * Output one character to the debug console
88  */
89 static void __kputchar(char c, UNUSED_ARG(void *, unused))
90 {
91         /* Poll while serial buffer is still busy */
92         KDBG_WAIT_READY();
93
94         /* Send '\n' as '\r\n' for dumb terminals */
95         if (c == '\n')
96         {
97                 KDBG_WRITE_CHAR('\r');
98                 KDBG_WAIT_READY();
99         }
100
101         KDBG_WRITE_CHAR(c);
102 }
103
104
105 void kputchar(char c)
106 {
107         /* Mask serial TX intr */
108         kdbg_irqsave_t irqsave;
109         KDBG_MASK_IRQ(irqsave);
110
111         __kputchar(c, 0);
112
113         /* Restore serial TX intr */
114         KDBG_RESTORE_IRQ(irqsave);
115 }
116
117
118 static void PGM_FUNC(kvprintf)(const char * PGM_ATTR fmt, va_list ap)
119 {
120 #if CONFIG_PRINTF
121         /* Mask serial TX intr */
122         kdbg_irqsave_t irqsave;
123         KDBG_MASK_IRQ(irqsave);
124
125         PGM_FUNC(_formatted_write)(fmt, __kputchar, 0, ap);
126
127         /* Restore serial TX intr */
128         KDBG_RESTORE_IRQ(irqsave);
129 #else
130         /* A better than nothing printf() surrogate. */
131         PGM_FUNC(kputs)(fmt);
132 #endif /* CONFIG_PRINTF */
133 }
134
135 void PGM_FUNC(kprintf)(const char * PGM_ATTR fmt, ...)
136 {
137         va_list ap;
138
139         va_start(ap, fmt);
140         PGM_FUNC(kvprintf)(fmt, ap);
141         va_end(ap);
142 }
143
144 void PGM_FUNC(kputs)(const char * PGM_ATTR str)
145 {
146         char c;
147
148         /* Mask serial TX intr */
149         kdbg_irqsave_t irqsave;
150         KDBG_MASK_IRQ(irqsave);
151
152         while ((c = PGM_READ_CHAR(str++)))
153                 __kputchar(c, 0);
154
155         KDBG_RESTORE_IRQ(irqsave);
156 }
157
158
159 /**
160  * Cheap function to print small integers without using printf().
161  */
162 int kputnum(int num)
163 {
164         int output_len = 0;
165         int divisor = 10000;
166         int digit;
167
168         do
169         {
170                 digit = num / divisor;
171                 num %= divisor;
172
173                 if (digit || output_len || divisor == 1)
174                 {
175                         kputchar(digit + '0');
176                         ++output_len;
177                 }
178         }
179         while (divisor /= 10);
180
181         return output_len;
182 }
183
184
185 static void klocation(const char * PGM_ATTR file, int line)
186 {
187         PGM_FUNC(kputs)(file);
188         kputchar(':');
189         kputnum(line);
190         PGM_FUNC(kputs)(PGM_STR(": "));
191 }
192
193 int PGM_FUNC(__bassert)(const char * PGM_ATTR cond, const char * PGM_ATTR file, int line)
194 {
195         klocation(file, line);
196         PGM_FUNC(kputs)(PGM_STR("Assertion failed: "));
197         PGM_FUNC(kputs)(cond);
198         kputchar('\n');
199         BREAKPOINT;
200         return 1;
201 }
202
203 /*
204  * Unfortunately, there's no way to get __func__ in
205  * program memory, so we waste quite a lot of RAM in
206  * AVR and other Harvard processors.
207  */
208 void PGM_FUNC(__trace)(const char *name)
209 {
210         PGM_FUNC(kprintf)(PGM_STR("%s()\n"), name);
211 }
212
213 void PGM_FUNC(__tracemsg)(const char *name, const char * PGM_ATTR fmt, ...)
214 {
215         va_list ap;
216
217         PGM_FUNC(kprintf)(PGM_STR("%s(): "), name);
218         va_start(ap, fmt);
219         PGM_FUNC(kvprintf)(fmt, ap);
220         va_end(ap);
221         kputchar('\n');
222 }
223
224 int PGM_FUNC(__invalid_ptr)(void *value, const char * PGM_ATTR name, const char * PGM_ATTR file, int line)
225 {
226         klocation(file, line);
227         PGM_FUNC(kputs)(PGM_STR("Invalid ptr: "));
228         PGM_FUNC(kputs)(name);
229         #if CONFIG_PRINTF
230                 PGM_FUNC(kprintf)(PGM_STR(" = 0x%p\n"), value);
231         #else
232                 (void)value;
233                 kputchar('\n');
234         #endif
235         return 1;
236 }
237
238
239 void __init_wall(long *wall, int size)
240 {
241         while(size--)
242                 *wall++ = WALL_VALUE;
243 }
244
245
246 int PGM_FUNC(__check_wall)(long *wall, int size, const char * PGM_ATTR name, const char * PGM_ATTR file, int line)
247 {
248         int i, fail = 0;
249
250         for (i = 0; i < size; i++)
251         {
252                 if (wall[i] != WALL_VALUE)
253                 {
254                         klocation(file, line);
255                         PGM_FUNC(kputs)(PGM_STR("Wall broken: "));
256                         PGM_FUNC(kputs)(name);
257                         #if CONFIG_PRINTF
258                                 PGM_FUNC(kprintf)(PGM_STR("[%d] (0x%p) = 0x%lx\n"), i, wall + i, wall[i]);
259                         #else
260                                 kputchar('\n');
261                         #endif
262                         fail = 1;
263                 }
264         }
265
266         return fail;
267 }
268
269
270 #if CONFIG_PRINTF
271
272 /**
273  * Dump binary data in hex
274  */
275 void kdump(const void *_buf, size_t len)
276 {
277         const unsigned char *buf = (const unsigned char *)_buf;
278
279         while (len--)
280                 kprintf("%02X", *buf++);
281         kputchar('\n');
282 }
283
284 #endif /* CONFIG_PRINTF */
285
286 #endif /* _DEBUG */