diff --git a/examples/linux/assert/main.cpp b/examples/linux/assert/main.cpp index 2e2aac484..2ad7ad013 100644 --- a/examples/linux/assert/main.cpp +++ b/examples/linux/assert/main.cpp @@ -1,10 +1,55 @@ #include +#include + +enum +{ + CAN_OK = 0, + CAN_ERROR_INIT_TIMEOUT, + CAN_ERROR_RX_MAILBOX_FULL, + CAN_ERROR_TX_MAILBOX_FULL +}; + +static const char * error_stringify(uint8_t error) +// XPCC_MODULE_ERROR_STRINGIFY("Can")(uint8_t error) +{ + switch (error) + { + case CAN_ERROR_INIT_TIMEOUT: + return "init.timeout"; + case CAN_ERROR_RX_MAILBOX_FULL: + return "rx.full"; + case CAN_ERROR_TX_MAILBOX_FULL: + return "tx.full"; + default: + return "unknown"; + } +} + +__attribute__((section(XPCC_MODULE_ERROR_NAME_LINKER_SECTION), used)) +const xpcc_module_error_stringify_t +module_error_stringify = {"Can", error_stringify}; + +xpcc_extern_c uint8_t xpcc_get_module_id_from_stringify(const xpcc_module_error_stringify_t * const module); +static inline uint8_t module_id() { return xpcc_get_module_id_from_stringify(&module_error_stringify); } + +namespace CanModule +{ + uint8_t id() + { + return module_id(); + } + + xpcc_error_t create_error(uint8_t error) + { + return {id(), error}; + } +} static xpcc::Abandonment -test_assertion_handler(const char *id) +test_assertion_handler(xpcc_error_t error) { - if (strncmp(id, "iobuffer", 8) == 0) - return xpcc::Abandonment::Ignore; + if (error.module == CanModule::id()) + return xpcc::Abandonment::Fail; return xpcc::Abandonment::DontCare; } XPCC_ASSERTION_HANDLER(test_assertion_handler); @@ -13,11 +58,7 @@ XPCC_ASSERTION_HANDLER(test_assertion_handler); int main() { - xpcc_assert(true, "can.init"); - - xpcc_assert_debug(false, "iobuffer.full"); - - xpcc_assert(false, "uart.init"); + xpcc_assert(false, CanModule::create_error(CAN_ERROR_INIT_TIMEOUT)); return 0; } diff --git a/src/xpcc/architecture/interface/assert.hpp b/src/xpcc/architecture/interface/assert.hpp index 1694f889b..74e48d292 100644 --- a/src/xpcc/architecture/interface/assert.hpp +++ b/src/xpcc/architecture/interface/assert.hpp @@ -13,6 +13,7 @@ #include #include #include +#include "error.hpp" /** * @ingroup interface @@ -37,7 +38,8 @@ Abandonment : uint8_t Fail = Bit2 ///< This failure is reason for abandonment }; -using AssertionHandler = Abandonment (*)(const char * identifier); +/// @ingroup assert +using AssertionHandler = Abandonment (*)(xpcc_error_t error); } // namespace xpcc @@ -66,9 +68,9 @@ using AssertionHandler = Abandonment (*)(const char * identifier); extern "C" { -void xpcc_assert(bool condition, const char * identifier); +void xpcc_assert(bool condition, xpcc_error_t error); -void xpcc_abandon(const char * identifier); +void xpcc_abandon(xpcc_error_t error); } diff --git a/src/xpcc/architecture/interface/error.hpp b/src/xpcc/architecture/interface/error.hpp new file mode 100644 index 000000000..6bd73644f --- /dev/null +++ b/src/xpcc/architecture/interface/error.hpp @@ -0,0 +1,70 @@ +// coding: utf-8 +/* Copyright (c) 2016, Roboterclub Aachen e.V. + * All Rights Reserved. + * + * The file is part of the xpcc library and is released under the 3-clause BSD + * license. See the file `LICENSE` for the full license governing this code. + */ +// ---------------------------------------------------------------------------- + +#ifndef XPCC_ERROR_HPP +#define XPCC_ERROR_HPP + +#include +#include + +/** + * @ingroup interface + * @defgroup error Errors + * + * Errors at runtime + * + * @see driver + * @author Niklas Hauser + */ + +#if defined XPCC__CPU_ARM || defined XPCC__CPU_AVR +# define XPCC_MODULE_ERROR_NAME_LINKER_SECTION ".errorname" +#elif defined XPCC__OS_OSX +# define XPCC_MODULE_ERROR_NAME_LINKER_SECTION "__DATA,xpcc_errorname" +#elif defined XPCC__OS_LINUX +# define XPCC_MODULE_ERROR_NAME_LINKER_SECTION "xpcc_errorname" +#endif + +xpcc_extern_c_begin + +typedef struct +{ + uint8_t module; + uint8_t error; +} xpcc_error_t; + +typedef struct +{ + const char * module_name; + const char * (*stringify)(uint8_t error); +} xpcc_module_error_stringify_t; + +const char * xpcc_error_module(xpcc_error_t error); +const char * xpcc_error_stringify(xpcc_error_t error); + +xpcc_extern_c_end + +#ifdef XPCC_ERROR_LINKER_SECTION +# define XPCC_MODULE_ERROR_STRINGIFY(module_name) \ + static const char * error_stringify(xpcc_error_t); \ + \ + __attribute__((section(XPCC_MODULE_ERROR_NAME_LINKER_SECTION), used)) \ + static const xpcc_module_error_stringify_t \ + module_error_stringify = {module_name, error_stringify}; \ + \ + xpcc_extern_c uint8_t xpcc_get_module_id_from_stringify(const xpcc_module_error_stringify_t * module); \ + static inline uint8_t module_id() { return xpcc_get_module_id_from_stringify(&module_error_stringify); } \ + \ + const char * error_stringify +#else +# define XPCC_MODULE_ERROR_STRINGIFY(module_name) \ + const char * error_stringify +#endif + +#endif // XPCC_ASSERT_HPP diff --git a/src/xpcc/architecture/platform/driver/core/cortex/linkerscript/stm32_dccm.ld.in b/src/xpcc/architecture/platform/driver/core/cortex/linkerscript/stm32_dccm.ld.in index 7ffe5d053..dda96a869 100644 --- a/src/xpcc/architecture/platform/driver/core/cortex/linkerscript/stm32_dccm.ld.in +++ b/src/xpcc/architecture/platform/driver/core/cortex/linkerscript/stm32_dccm.ld.in @@ -323,6 +323,12 @@ SECTIONS __assertion_table_end = .; . = ALIGN (4); + /* Module error names. */ + __errorname_table_start = .; + KEEP(*(.error_modname)) + __errorname_table_end = .; + . = ALIGN (4); + /* Position independent code will call non-static functions via the * Procedure Linkage Table or PLT. This PLT does not exist in .o files. * In a .o file, use of the PLT is indicated by a special relocation. diff --git a/src/xpcc/architecture/platform/driver/core/hosted/assert.cpp b/src/xpcc/architecture/platform/driver/core/hosted/assert.cpp index 40691f6cc..a7a11da79 100644 --- a/src/xpcc/architecture/platform/driver/core/hosted/assert.cpp +++ b/src/xpcc/architecture/platform/driver/core/hosted/assert.cpp @@ -24,7 +24,7 @@ extern AssertionHandler __assertion_table_end __asm("__stop_xpcc_assertion"); extern "C" { -void xpcc_assert(bool condition, const char *identifier) +void xpcc_assert(bool condition, xpcc_error_t error) { if (!condition) { @@ -33,21 +33,21 @@ void xpcc_assert(bool condition, const char *identifier) AssertionHandler * handler = &__assertion_table_start; for (; handler < &__assertion_table_end; handler++) { - state |= (uint8_t) (*handler)(identifier); + state |= (uint8_t) (*handler)(error); } if (state == (uint8_t) Abandonment::DontCare or state & (uint8_t) Abandonment::Fail) { - xpcc_abandon(identifier); + xpcc_abandon(error); } } } -void xpcc_abandon(const char *identifier) __attribute__((weak)); -void xpcc_abandon(const char *identifier) +void xpcc_abandon(xpcc_error_t error) __attribute__((weak)); +void xpcc_abandon(xpcc_error_t error) { - XPCC_LOG_ERROR << "Assertion '" << identifier << "' failed! Abandoning." << xpcc::endl; + XPCC_LOG_ERROR << "Module '" << xpcc_error_module(error) << "' failed assertion '" << xpcc_error_stringify(error) << "'! Abandoning." << xpcc::endl; exit(1); } diff --git a/src/xpcc/architecture/platform/driver/core/hosted/error.cpp b/src/xpcc/architecture/platform/driver/core/hosted/error.cpp new file mode 100644 index 000000000..763cb7c63 --- /dev/null +++ b/src/xpcc/architecture/platform/driver/core/hosted/error.cpp @@ -0,0 +1,47 @@ +// coding: utf-8 +/* Copyright (c) 2016, Roboterclub Aachen e.V. + * All Rights Reserved. + * + * The file is part of the xpcc library and is released under the 3-clause BSD + * license. See the file `LICENSE` for the full license governing this code. + */ +// ---------------------------------------------------------------------------- + +#include +#include +#include + +#ifdef XPCC__OS_OSX +extern xpcc_module_error_stringify_t __errorname_table_start __asm("section$start$__DATA$xpcc_errorname"); +extern xpcc_module_error_stringify_t __errorname_table_end __asm("section$end$__DATA$xpcc_errorname"); +#else +extern xpcc_module_error_stringify_t __errorname_table_start __asm("__start_xpcc_errorname"); +extern xpcc_module_error_stringify_t __errorname_table_end __asm("__stop_xpcc_errorname"); +#endif + +extern "C" { + +static uint8_t number_of_error_modules = 0; + +uint8_t xpcc_get_module_id_from_stringify(const xpcc_module_error_stringify_t * const module) +{ + number_of_error_modules = &__errorname_table_end - &__errorname_table_start; + + if (module < &__errorname_table_start || &__errorname_table_end <= module) return -1; + return (module - &__errorname_table_start); +} + +const char * xpcc_error_module(xpcc_error_t error) +{ + if (error.module >= number_of_error_modules) return "Invalid"; + + return (&__errorname_table_start)[error.module].module_name; +} +const char * xpcc_error_stringify(xpcc_error_t error) +{ + if (error.module >= number_of_error_modules) return "Invalid"; + if (error.error == 0) return "Ok"; + return (&__errorname_table_start)[error.module].stringify(error.error); +} + +} diff --git a/src/xpcc/architecture/utils.hpp b/src/xpcc/architecture/utils.hpp index dd95421d9..0ee807116 100644 --- a/src/xpcc/architecture/utils.hpp +++ b/src/xpcc/architecture/utils.hpp @@ -114,10 +114,20 @@ #define XPCC_CONCAT5_(a,b,c,d,e) XPCC_CONCAT5__(a,b,c,d,e) #define XPCC_CONCAT5__(a,b,c,d,e) a ## b ## c ## d ## e + #ifdef __cplusplus + # define xpcc_extern_c extern "C" + # define xpcc_extern_c_begin extern "C" { + # define xpcc_extern_c_end } + #else + # define xpcc_extern_c extern + # define xpcc_extern_c_begin + # define xpcc_extern_c_end + #endif #if defined(XPCC__COMPILER_GCC) || defined(XPCC__COMPILER_CLANG) # define xpcc_always_inline inline __attribute__((always_inline)) # define xpcc_unused __attribute__((unused)) + # define xpcc_used __attribute__((used)) # define xpcc_weak __attribute__((weak)) # define xpcc_aligned(n) __attribute__((aligned(n))) # define xpcc_packed __attribute__((packed)) @@ -129,6 +139,7 @@ #else # define xpcc_always_inline inline # define xpcc_unused + # define xpcc_used # define xpcc_weak # define xpcc_aligned(n) # define xpcc_packed