1 /*
2  * Copyright (C) 2008-2009 SVOX AG, Baslerstr. 30, 8048 Zuerich, Switzerland
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 /**
17  *
18  * @file picodbg.h
19  *
20  * Provides functions and macros to debug the Pico system and to trace
21  * the execution of its code.
22  *
23  * Copyright (C) 2008-2009 SVOX AG, Baslerstr. 30, 8048 Zuerich, Switzerland
24  * All rights reserved.
25  *
26  * History:
27  * - 2009-04-20 -- initial version
28  */
29 
30 /**
31  * @addtogroup picodbg
32  * ---------------------------------------------------\n
33  * <b> Pico Debug Support </b>\n
34  * ---------------------------------------------------\n
35  * GENERAL REMARKS
36  * ---------------
37  * This module provides a set of macros to help debug the Pico system.
38  * The usage of macros allows for completely removing debug code from
39  * the binaries delivered to customers. To enable diagnostic output
40  * the preprocessor symbol PICO_DEBUG has to be defined.
41  *
42  * By using global variables (to store the current log level etc.)
43  * this module violates a basic Pico design principle!
44  *
45  * Justification:\n
46  * - going without global data would reduce the functionality
47  *   of this module considerably (e.g., log level could not be
48  *   changed at runtime etc.)
49  * - at the moment, the only known system interdicting global
50  *   variables is Symbian; but even there global variables are
51  *   possible by using thread-local storage
52  * - allocating global data on the heap would require to pass
53  *   a handle to this memory block to all routines of this
54  *   module which in turn implies that _every_ function in the
55  *   Pico system would require a pointer to some global data;
56  *   obviously, this would be very awkward
57  *
58  * Furthermore, this module uses the non-standardized but handy
59  * __FUNCTION__ macro. It expands to the name of the enclosing
60  * function. For compilers not supporting this macro simply
61  * define __FUNCTION__ as an empty string.
62  *
63  *
64  * INITIALIZATION/TERMINATION\n
65  * --------------------------\n
66  * Before using any debug macros, this module has to be initialized
67  * by calling PICODBG_INITIALIZE(). If the routines are not needed
68  * anymore, PICODBG_TERMINATE() has to be called to terminate the
69  * module (e.g., to close the log file).
70  *
71  *
72  * TRACING\n
73  * -------\n
74  * Each tracing message is associated with a log level which describes
75  * its severity. The following levels are supported:
76  * - Trace - Very detailed log messages, potentially of a high
77  *            frequency and volume
78  * - Debug - Less detailed and/or less frequent debugging messages
79  * - Info  - Informational messages
80  * - Warn  - Warnings which don't appear to the Pico user
81  * - Error - Error messages
82  *
83  * Tracing messages can use the well-known printf format specification.
84  * But because variadic macros (macros with a variable no. arguments)
85  * are not commonly supported by compilers a little trick is used
86  * which requires the format string and its arguments to be enclosed
87  * in double parenthesis:
88  *
89  * - PICODBG_INFO(("hello, world!"));
90  * - PICODBG_TRACE(("argc=%d", argc));
91  *    ...
92  *
93  * Each tracing message is expected to be a single line of text. Some
94  * contextual information (e.g., log level, time and date, source file
95  * and line number) and a newline are automatically added. The output
96  * format can be customized by a call to PICODBG_SET_OUTPUT_FORMAT().
97  *
98  * Sample output:
99  *    - *** info|2008-04-03|14:51:36|dbgdemo.c(15)|hello world
100  *    - *** trace|2008-04-03|14:51:36|dbgdemo.c(16)|argc=2
101  *    - ...
102  *
103  * To compose a tracing message line consisting of, e.g. the elements
104  * of an array, on the Info level two additional macros shown in the
105  * following example are provided:
106  *
107  *    PICODBG_INFO_CTX();\n
108  *    for (i = 0; i < len; i++)\n
109  *        ...some calc with arr and i\n
110  *        PICODBG_INFO_MSG((" %d", arr[i]));\n
111  *    }\n
112  *    PICODBG_INFO_MSG(("\n"));\n
113  *
114  * Colored output of tracing messages helps to capture severe problems
115  * quickly. This feature is supported on the Windows platform and on
116  * platforms supporting ANSI escape codes. PICODBG_ENABLE_COLORS() lets
117  * you turn on and off colored output.
118  *
119  *
120  * FILTERING\n
121  * ---------\n
122  * By calling PICODBG_SET_LOG_LEVEL() the log level may be changed at
123  * any time to increase/decrease the amount of debugging output.
124  *
125  * By calling PICODBG_SET_LOG_FILTERFN() the log filter may be changed
126  * at any time to change the source file name being used as filter for
127  * log messages (ie. only tracing info of the specified file will be
128  * logged). To disable the file name based filter set the filter file
129  * name to an empty string.
130  *
131  * Future version of this module might provide further filtering
132  * possibilities (e.g., filtering based on function names * etc.).
133  *
134  *
135  * LOGGING\n
136  * -------\n
137  * By default, tracing messages are output to the console (stderr).
138  * This allows for separating diagnostic output from other console
139  * output to stdout. In addition, tracing messages may be saved to
140  * a file by calling PICODBG_SET_LOG_FILE().
141  * Currently, file output is the only additional output target; but
142  * on embedded systems, more output targets may be required (e.g.,
143  * sending output to a serial port or over the network).
144  *
145  *
146  * ASSERTIONS\n
147  * ----------\n
148  * To support the 'design/programming by contract' paradigm, this
149  * module also provides assertions. PICODBG_ASSERT(expr) evualuates
150  * an expression and, when the result is false, prints a diagnostic
151  * message and aborts the program.
152  *
153  *
154  * FUTURE EXTENSIONS\n
155  * -----------------\n
156  * - advanced tracing functions to dump complex data
157  * - debug memory allocation that can be used to assist in
158  *   finding memory problems
159  */
160 
161 
162 #if !defined(__PICODBG_H__)
163 #define __PICODBG_H__
164 
165 #ifdef __cplusplus
166 extern "C" {
167 #endif
168 #if 0
169 }
170 #endif
171 
172 
173 /* Not all compilers support the __FUNCTION__ macro */
174 #if !defined(__FUNCTION__) && !defined(__GNUC__)
175 #define __FUNCTION__ ""
176 #endif
177 
178 
179 /* Log levels sorted by severity */
180 #define PICODBG_LOG_LEVEL_ERROR     1
181 #define PICODBG_LOG_LEVEL_WARN      2
182 #define PICODBG_LOG_LEVEL_INFO      3
183 #define PICODBG_LOG_LEVEL_DEBUG     4
184 #define PICODBG_LOG_LEVEL_TRACE     5
185 
186 /* Output format flags */
187 #define PICODBG_SHOW_LEVEL          0x0001
188 #define PICODBG_SHOW_DATE           0x0002
189 #define PICODBG_SHOW_TIME           0x0004
190 #define PICODBG_SHOW_SRCNAME        0x0008
191 #define PICODBG_SHOW_SRCLINE        0x0010
192 #define PICODBG_SHOW_SRCALL         (PICODBG_SHOW_SRCNAME | PICODBG_SHOW_SRCLINE)
193 #define PICODBG_SHOW_FUNCTION       0x0020
194 #define PICODBG_SHOW_POS            (PICODBG_SHOW_SRCALL | PICODBG_SHOW_FUNCTION)
195 
196 /* definition of PICO_DEBUG enables debugging code */
197 #if defined(PICO_DEBUG)
198 
199 #define PICODBG_INITIALIZE(level) \
200     picodbg_initialize(level)
201 
202 #define PICODBG_TERMINATE() \
203     picodbg_terminate()
204 
205 #define PICODBG_SET_LOG_LEVEL(level) \
206     picodbg_setLogLevel(level)
207 
208 #define PICODBG_SET_LOG_FILTERFN(name) \
209     picodbg_setLogFilterFN(name)
210 
211 #define PICODBG_SET_LOG_FILE(name) \
212     picodbg_setLogFile(name)
213 
214 #define PICODBG_ENABLE_COLORS(flag) \
215     picodbg_enableColors(flag)
216 
217 #define PICODBG_SET_OUTPUT_FORMAT(format) \
218     picodbg_setOutputFormat(format)
219 
220 
221 #define PICODBG_ASSERT(expr) \
222     for (;!(expr);picodbg_assert(__FILE__, __LINE__, __FUNCTION__, #expr))
223 
224 #define PICODBG_ASSERT_RANGE(val, min, max) \
225     PICODBG_ASSERT(((val) >= (min)) && ((val) <= (max)))
226 
227 
228 #define PICODBG_LOG(level, msg) \
229     picodbg_log(level, 1,  __FILE__, __LINE__, __FUNCTION__, picodbg_varargs msg)
230 
231 #define PICODBG_ERROR(msg) \
232     PICODBG_LOG(PICODBG_LOG_LEVEL_ERROR, msg)
233 
234 #define PICODBG_WARN(msg) \
235     PICODBG_LOG(PICODBG_LOG_LEVEL_WARN, msg)
236 
237 #define PICODBG_INFO(msg) \
238     PICODBG_LOG(PICODBG_LOG_LEVEL_INFO, msg)
239 
240 #define PICODBG_DEBUG(msg) \
241     PICODBG_LOG(PICODBG_LOG_LEVEL_DEBUG, msg)
242 
243 #define PICODBG_TRACE(msg) \
244     PICODBG_LOG(PICODBG_LOG_LEVEL_TRACE, msg)
245 
246 
247 #define PICODBG_INFO_CTX() \
248     picodbg_log(PICODBG_LOG_LEVEL_INFO, 0, __FILE__, __LINE__, __FUNCTION__, "")
249 
250 #define PICODBG_INFO_MSG(msg) \
251     picodbg_log_msg(PICODBG_LOG_LEVEL_INFO, __FILE__, picodbg_varargs msg)
252 
253 #define PICODBG_INFO_MSG_F(filterfn, msg) \
254     picodbg_log_msg(PICODBG_LOG_LEVEL_INFO, (const char *)filterfn, picodbg_varargs msg)
255 
256 
257 
258 /* helper routines; should NOT be used directly! */
259 
260 void picodbg_initialize(int level);
261 void picodbg_terminate();
262 
263 void picodbg_setLogLevel(int level);
264 void picodbg_setLogFilterFN(const char *name);
265 void picodbg_setLogFile(const char *name);
266 void picodbg_enableColors(int flag);
267 void picodbg_setOutputFormat(unsigned int format);
268 
269 const char *picodbg_varargs(const char *format, ...);
270 
271 void picodbg_log(int level, int donewline, const char *file, int line,
272                  const char *func, const char *msg);
273 void picodbg_assert(const char *file, int line, const char *func,
274                     const char *expr);
275 
276 void picodbg_log_msg(int level, const char *file, const char *msg);
277 
278 
279 #else  /* release version; omit debugging code */
280 
281 #define PICODBG_INITIALIZE(level)
282 #define PICODBG_TERMINATE()
283 #define PICODBG_SET_LOG_LEVEL(level)
284 #define PICODBG_SET_LOG_FILTERFN(name)
285 #define PICODBG_SET_LOG_FILE(name)
286 #define PICODBG_ENABLE_COLORS(flag)
287 #define PICODBG_SET_OUTPUT_FORMAT(format)
288 
289 #define PICODBG_ASSERT(expr)
290 #define PICODBG_ASSERT_RANGE(val, min, max)
291 
292 #define PICODBG_LOG(level, msg)
293 #define PICODBG_ERROR(msg)
294 #define PICODBG_WARN(msg)
295 #define PICODBG_INFO(msg)
296 #define PICODBG_DEBUG(msg)
297 #define PICODBG_TRACE(msg)
298 
299 #define PICODBG_INFO_CTX()
300 #define PICODBG_INFO_MSG(msg)
301 #define PICODBG_INFO_MSG_F(filterfn, msg)
302 
303 
304 #endif /* defined(PICO_DEBUG) */
305 
306 #ifdef __cplusplus
307 }
308 #endif
309 
310 
311 #endif /* !defined(__PICODBG_H__) */
312