/* Cesar project {{{ * * Copyright (C) 2007 Spidcom * * <<>> * * }}} */ /** * \file lib/src/dbg.c * \brief Debug functions. * \ingroup lib */ #include "common/std.h" #include "hal/arch/arch.h" #include "hal/gpio/gpio.h" #include #include #include void (*dbg_fatal_cb[4]) (void); ARCH_STACK_DECLARE (dbg_stack); #if DEBUG # if CONFIG_DEBUG_FATAL_CATCH int dbg_fatal_try_level_; char dbg_fatal_text_[2048]; # endif void dbg_assert_fail (const char *assertion, const char *file, uint line, const char *function) { dbg_fatal (DBG_ASSERT_FMT_ "%s", file, line, function, assertion); } void dbg_assert_fail_terse (const char *message) { dbg_fatal ("%s", message); } void dbg_assert_print_fail (const char *fmt, ...) { va_list ap; va_start (ap, fmt); dbg_vfatal (fmt, ap); va_end (ap); } #endif /* DEBUG */ #if !DEBUG void dbg_fatal_blind (void) { dbg_fatal ("fatal error"); } #endif /* !DEBUG */ void dbg_fatal (const char *fmt, ...) { va_list ap; va_start (ap, fmt); dbg_vfatal (fmt, ap); va_end (ap); } static void dbg_vfatal_internal (const char *fmt, va_list ap) { static bool in_fatal = false; /* Stop system. */ arch_stop (); /* Signal on GPIOs. */ GPIO_SETUP (FATAL, GPIO_DIRECTION_OUT); GPIO_SET (FATAL, 0); GPIO_SETUP (FATAL_BLINK, GPIO_DIRECTION_OUT); GPIO_SET (FATAL_BLINK, 0); /* Complain for bad treatments. */ vfprintf (stderr, fmt, ap); fputc ('\n', stderr); if (!in_fatal) { in_fatal = true; uint i; bool cb_called = false; for (i = 0; i < COUNT (dbg_fatal_cb); i++) if (dbg_fatal_cb[i]) { dbg_fatal_cb[i] (); cb_called = true; } if (cb_called) { fputc ('>', stderr); vfprintf (stderr, fmt, ap); fputc ('\n', stderr); } in_fatal = false; } /* Signal on blinking GPIO. */ #if CONFIG_GPIO_FATAL_BLINK while (1) { /* No system available anymore, we are on our own. */ uint i; volatile uint dummy; for (i = 0; i < CONFIG_GPIO_FATAL_BLINK_DELAY; i++) dummy = 0; GPIO_TOGGLE (FATAL_BLINK); } #endif } void dbg_vfatal (const char *fmt, va_list ap) { #if DEBUG && CONFIG_DEBUG_FATAL_CATCH if (dbg_fatal_try_level_) { vsnprintf (dbg_fatal_text_, sizeof (dbg_fatal_text_), fmt, ap); try_throw (TRY_CODE_FATAL); } else #endif { arch_stack_call (dbg_stack, dbg_vfatal_internal, fmt, ap); arch_abort (); } }