commit b309b7514c6a2fd20003006f5ff08370007ca8b5
Author: Thomas Schöpping <tschoepp@cit-ec.uni-bielefeld.de>
Date:   Mon Sep 17 16:27:08 2018 +0200

    All contents of the os/ folder has been moved one directory up.

diff --git a/amiroos.h b/amiroos.h
new file mode 100644
index 0000000..74ccb53
--- /dev/null
+++ b/amiroos.h
@@ -0,0 +1,85 @@
+/*
+AMiRo-OS is an operating system designed for the Autonomous Mini Robot (AMiRo) platform.
+Copyright (C) 2016..2018  Thomas Schöpping et al.
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _AMIROOS_H_
+#define _AMIROOS_H_
+
+/**
+ * @brief   AMiRo-OS identification macro.
+ */
+#define _AMIRO_OS_
+
+/**
+ * @name   AMiRo-OS version and relase information.
+ * @{
+ */
+
+/**
+ * @brief   The type of this version.
+ * @note    Is one of "pre-alpha", "alpha", "beta", "release candidate", "release".
+ */
+#define AMIROOS_RELEASE_TYPE          "beta"
+
+/**
+ * @brief   The operating system major version.
+ * @note    Changes of the major version imply incompatibilities.
+ */
+#define AMIROOS_VERSION_MAJOR         2
+
+/**
+ * @brief   The operating system minor version.
+ * @note    A higher minor version implies new functionalty, but all old interfaces are still available.
+ */
+#define AMIROOS_VERSION_MINOR         0
+
+/**
+ * @brief   The operating system patch level.
+ */
+#define AMIROOS_VERSION_PATCH         0
+
+/** @} */
+
+/* subsystems headers */
+#include <aosconf.h>
+#include <hal.h>
+#if defined(HAL_USE_QEI) && (HAL_USE_QEI == TRUE)
+#include <hal_qei.h>
+#endif
+#include <ch.h>
+
+/* configuration check */
+#if !defined(_AMIRO_OS_CFG_)
+#error "invalid AMiRo-OS configuration file"
+#endif
+#if (_AMIRO_OS_CFG_VERSION_MAJOR_ != AMIROOS_VERSION_MAJOR) || (_AMIRO_OS_CFG_VERSION_MINOR_ < AMIROOS_VERSION_MINOR)
+#error "incompatible AMiRo-OS configuration file"
+#endif
+#include "core/inc/aos_confcheck.h"
+
+/* core headers */
+#include "core/inc/aos_debug.h"
+#include <core/inc/aos_iostream.h>
+#include "core/inc/aos_shell.h"
+#include "core/inc/aos_system.h"
+#include "core/inc/aos_thread.h"
+#include "core/inc/aos_time.h"
+#include "core/inc/aos_timer.h"
+#include "core/inc/aos_types.h"
+#include "core/inc/aos_unittest.h"
+
+#endif /* _AMIROOS_H_ */
diff --git a/core/core.mk b/core/core.mk
new file mode 100644
index 0000000..9bc01a8
--- /dev/null
+++ b/core/core.mk
@@ -0,0 +1,44 @@
+################################################################################
+# AMiRo-OS is an operating system designed for the Autonomous Mini Robot       #
+# (AMiRo) platform.                                                            #
+# Copyright (C) 2016..2018  Thomas Schöpping et al.                            #
+#                                                                              #
+# This program is free software: you can redistribute it and/or modify         #
+# it under the terms of the GNU General Public License as published by         #
+# the Free Software Foundation, either version 3 of the License, or            #
+# (at your option) any later version.                                          #
+#                                                                              #
+# This program is distributed in the hope that it will be useful,              #
+# but WITHOUT ANY WARRANTY; without even the implied warranty of               #
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the                #
+# GNU General Public License for more details.                                 #
+#                                                                              #
+# You should have received a copy of the GNU General Public License            #
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.        #
+#                                                                              #
+# This research/work was supported by the Cluster of Excellence Cognitive      #
+# Interaction Technology 'CITEC' (EXC 277) at Bielefeld University, which is   #
+# funded by the German Research Foundation (DFG).                              #
+################################################################################
+
+
+
+# absolute path to this directory
+AMIROOS_CORE_DIR := $(dir $(lastword $(MAKEFILE_LIST)))
+
+# include paths
+AMIROOSCOREINC = $(AMIROOS_CORE_DIR)inc
+
+# C source files
+AMIROOSCORECSRC = $(AMIROOS_CORE_DIR)src/aos_debug.c \
+                  $(AMIROOS_CORE_DIR)src/aos_iostream.c \
+                  $(AMIROOS_CORE_DIR)src/aos_shell.c \
+                  $(AMIROOS_CORE_DIR)src/aos_system.c \
+                  $(AMIROOS_CORE_DIR)src/aos_thread.c \
+                  $(AMIROOS_CORE_DIR)src/aos_time.c \
+                  $(AMIROOS_CORE_DIR)src/aos_timer.c \
+                  $(AMIROOS_CORE_DIR)src/aos_unittest.c
+
+# C++ source files
+AMIROOSCORECPPSRC = $(AMIROOS_CORE_DIR)src/aos_main.cpp
+
diff --git a/core/inc/aos_confcheck.h b/core/inc/aos_confcheck.h
new file mode 100644
index 0000000..bf16754
--- /dev/null
+++ b/core/inc/aos_confcheck.h
@@ -0,0 +1,113 @@
+/*
+AMiRo-OS is an operating system designed for the Autonomous Mini Robot (AMiRo) platform.
+Copyright (C) 2016..2018  Thomas Schöpping et al.
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @file    aos_confcheck.h
+ * @brief   Header that checks whether all necessary configurations are correct.
+ *
+ * @addtogroup aos_system
+ * @{
+ */
+
+#ifndef _AMIROOS_CONFCHECK_H_
+#define _AMIROOS_CONFCHECK_H_
+
+#include <aosconf.h>
+
+/*
+ * Kernel parameters and options
+ */
+
+#ifndef AMIROOS_CFG_DBG
+  #error "AMIROOS_CFG_DBG not defined in aosconf.h"
+#endif
+
+#ifndef AMIROOS_CFG_TESTS_ENABLE
+  #error "AMIROOS_CFG_TESTS_ENABLE not defined in aosconf.h"
+#endif
+
+#ifndef AMIROOS_CFG_PROFILE
+  #error "AMIROOS_CFG_PROFILE not defined in aosconf.h"
+#endif
+
+#ifndef AMIROOS_CFG_MAIN_LOOP_TIMEOUT
+  #error "AMIROOS_CFG_MAIN_LOOP_TIMEOUT not defined in aosconf.h"
+#endif
+
+/*
+ * SSSP parameters and options
+ */
+
+#ifndef AMIROOS_CFG_SSSP_MASTER
+  #error "AMIROOS_CFG_SSSP_MASTER not defined in aosconf.h"
+#endif
+
+#ifndef AMIROOS_CFG_SSSP_STACK_START
+  #error "AMIROOS_CFG_SSSP_STACK_START not defined in aosconf.h"
+#endif
+
+#ifndef AMIROOS_CFG_SSSP_STACK_END
+  #error "AMIROOS_CFG_SSSP_STACK_END not defined in aosconf.h"
+#endif
+
+#if (AMIROOS_CFG_SSSP_STACK_START == true) && (AMIROOS_CFG_SSSP_STACK_END == true)
+  #warning "AMIROOS_CFG_SSSP_STACK_START and AMIROOS_CFG_SSSP_STACK_END both enabled in aosconf.h"
+  #if (AMIROOS_CFG_SSSP_MASTER != true)
+    #error "AMIROOS_CFG_SSSP_MASTER must be enabled in this case"
+  #endif
+#endif
+
+#ifndef AMIROOS_CFG_SSSP_SIGNALDELAY
+  #error "AMIROOS_CFG_SSSP_SIGNALDELAY not defined in aosconf.h"
+#endif
+
+#ifndef AMIROOS_CFG_SSSP_SYSSYNCPERIOD
+  #error "AMIROOS_CFG_SSSP_SYSSYNCPERIOD not defined in aosconf.h"
+#endif
+
+/*
+ * System shell options
+ */
+
+#ifndef AMIROOS_CFG_SHELL_ENABLE
+  #error "AMIROOS_CFG_SHELL_ENABLE not defined in aosconf.h"
+#endif
+
+#if (AMIROOS_CFG_SHELL_ENABLE == true)
+
+  #ifndef AMIROOS_CFG_SHELL_STACKSIZE
+    #error "AMIROOS_CFG_SHELL_STACKSIZE not defined in aosconf.h"
+  #endif
+
+  #ifndef AMIROOS_CFG_SHELL_THREADPRIO
+    #error "AMIROOS_CFG_SHELL_THREADPRIO not defined in aosconf.h"
+  #endif
+
+  #ifndef AMIROOS_CFG_SHELL_LINEWIDTH
+    #error "AMIROOS_CFG_SHELL_LINEWIDTH not defined in aosconf.h"
+  #endif
+
+  #ifndef AMIROOS_CFG_SHELL_MAXARGS
+    #error "AMIROOS_CFG_SHELL_MAXARGS not defined in aosconf.h"
+  #endif
+
+#endif /* AMIROOS_CFG_SHELL_ENABLE == true */
+
+#endif /* _AMIROOS_CONFCHECK_H_ */
+
+/** @} */
diff --git a/core/inc/aos_debug.h b/core/inc/aos_debug.h
new file mode 100644
index 0000000..56a33ba
--- /dev/null
+++ b/core/inc/aos_debug.h
@@ -0,0 +1,103 @@
+/*
+AMiRo-OS is an operating system designed for the Autonomous Mini Robot (AMiRo) platform.
+Copyright (C) 2016..2018  Thomas Schöpping et al.
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @file    aos_debug.h
+ * @brief   Macros used for debugging.
+ *
+ * @addtogroup aos_debug
+ * @{
+ */
+
+#ifndef _AMIROOS_DEBUG_H_
+#define _AMIROOS_DEBUG_H_
+
+#include <aosconf.h>
+#include <ch.h>
+
+#if (AMIROOS_CFG_DBG == true) || defined(__DOXYGEN__)
+
+/**
+ * @brief   Function parameters check.
+ * @details If the condition check fails, the kernel panics and halts.
+ *
+ * @param[in] c The condition to be verified to be true.
+ */
+#define aosDbgCheck(c)                chDbgCheck(c)
+
+/**
+ * @brief   Condition assertion.
+ * @details If the condition check fails, the kernel panics with a message and halts.
+ * @note    As a limitation of ChibiOS, the remark string is not currently used.
+ *
+ * @param[in] c The condition to be verified to be true.
+ */
+#define aosDbgAssert(c)               chDbgAssert(c, "__FILE__(__LINE__): aosDbgAssert failed")
+
+/**
+ * @brief   Condition assertion.
+ * @details If the condition check fails, the kernel panics with a message and halts.
+ * @note    As a limitation of ChibiOS, the remark string is not currently used.
+ *
+ * @param[in] c The condition to be verified to be true.
+ * @param[in] r A custom remark string.
+ */
+#define aosDbgAssertMsg(c, r) {                           \
+  (void)r;                                                \
+  chDbgAssert(c, r);                                      \
+}
+
+/**
+ * @brief   Printf function for messages only printed in debug builds.
+ *
+ * @param[in] fmt   Formatted string to print.
+ */
+#define aosDbgPrintf(fmt, ...)           chprintf((BaseSequentialStream*)&aos.iostream, fmt, ##__VA_ARGS__)
+
+#else /* (AMIROOS_CFG_DBG != true) */
+
+#define aosDbgCheck(c) {                                  \
+  (void)(c);                                              \
+  }
+
+#define aosDbgAssert(c) {                                 \
+  (void)(c);                                              \
+}
+
+#define aosDbgAssertMsg(c, r) {                           \
+  (void)(c);                                              \
+  (void)(r);                                              \
+}
+
+#define aosDbgPrintf(fmt, ...) {                          \
+  (void)(fmt);                                            \
+}
+
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+  void aosPrintHaltErrorCode(const char* reason);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _AMIROOS_DEBUG_H_ */
+
+/** @} */
diff --git a/core/inc/aos_iostream.h b/core/inc/aos_iostream.h
new file mode 100644
index 0000000..2c71571
--- /dev/null
+++ b/core/inc/aos_iostream.h
@@ -0,0 +1,146 @@
+/*
+AMiRo-OS is an operating system designed for the Autonomous Mini Robot (AMiRo) platform.
+Copyright (C) 2016..2018  Thomas Schöpping et al.
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @file    aos_iostream.h
+ * @brief   Stream and channel macros and structures.
+ *
+ * @addtogroup aos_stream
+ * @{
+ */
+
+#ifndef _AMIROOS_IOSTREAM_H_
+#define _AMIROOS_IOSTREAM_H_
+
+#include <hal.h>
+#include <aos_types.h>
+#include <stdarg.h>
+
+
+
+/**
+ * @brief   Channel flag to indicate whether the channel is attached to a stream.
+ */
+#define AOS_IOCHANNEL_ATTACHED                  (1 << 0)
+
+/**
+ * @brief   Channel flag to indicate whether the channel is set as input.
+ */
+#define AOS_IOCHANNEL_INPUT_ENABLE              (1 << 1)
+
+/**
+ * @brief   Channel flag to indicate whether the channel is set as output.
+ */
+#define AOS_IOCHANNEL_OUTPUT_ENABLE             (1 << 2)
+
+/*
+ * forward definitions
+ */
+typedef struct aos_iochannel AosIOChannel;
+typedef struct aos_ostream AosIOStream;
+
+/**
+ * @brief   AosI=Channel specific methods.
+ */
+#define _aos_iochannel_methods                                              \
+  _base_asynchronous_channel_methods
+
+/**
+ * @brief   AosIOChannel specific data.
+ */
+#define _aos_iochannel_data                                                 \
+  /* pointer to a BaseAsynchronousChannel object */                         \
+  BaseAsynchronousChannel* asyncchannel;                                    \
+  /* pointer to the next channel in a AosIOStream */                        \
+  AosIOChannel* next;                                                       \
+  /* flags related to the channel */                                        \
+  uint8_t flags;
+
+/**
+ * @extends BaseAsynchronousChannelVMT
+ *
+ * @brief   AosIOChannel virtual methods table.
+ */
+struct AosIOChannelVMT {
+  _aos_iochannel_methods
+};
+
+/**
+ * @extends BaseAsynchronousChannel
+ *
+ * @brief   I/O Channel class.
+ * @details This class implements an asynchronous I/O channel.
+ */
+struct aos_iochannel {
+  /** @brief Virtual Methods Table. */
+  const struct AosIOChannelVMT* vmt;
+  _aos_iochannel_data
+};
+
+/**
+ * @brief   AosIOStream methods.
+ */
+#define _aos_iostream_methods                                               \
+  _base_sequential_stream_methods
+
+/**
+ * @brief   AosIOStream data.
+ */
+#define _aos_iostream_data                                                  \
+  /* Pointer to the first channel in a list. */                             \
+  AosIOChannel* channel;
+
+/**
+ * @extends BaseSequentialStream
+ *
+ * @brief   AosIOStream virtual methods table.
+ */
+struct AosIOStreamVMT {
+  _aos_iostream_methods
+};
+
+/**
+ * @extends BaseSequentialStream
+ *
+ * @brief   I/O Stream class.
+ * @details This class implements an base sequential stream.
+ * @todo    So far only output but no input is supported.
+ */
+struct aos_ostream {
+  const struct AosIOStreamVMT* vmt;
+  _aos_iostream_data
+};
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+  void aosIOStreamInit(AosIOStream* stream);
+  void aosIOChannelInit(AosIOChannel* channel, BaseAsynchronousChannel* asyncchannel);
+  void aosIOStreamAddChannel(AosIOStream* stream, AosIOChannel* channel);
+  aos_status_t aosIOStreamRemoveChannel(AosIOStream* stream, AosIOChannel* channel);
+  void aosIOChannelInputEnable(AosIOChannel* channel);
+  void aosIOChannelInputDisable(AosIOChannel* channel);
+  void aosIOChannelOutputEnable(AosIOChannel* channel);
+  void aosIOChannelOutputDisable(AosIOChannel* channel);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _AMIROOS_IOSTREAM_H_ */
+
+/** @} */
diff --git a/core/inc/aos_shell.h b/core/inc/aos_shell.h
new file mode 100644
index 0000000..07d2128
--- /dev/null
+++ b/core/inc/aos_shell.h
@@ -0,0 +1,376 @@
+/*
+AMiRo-OS is an operating system designed for the Autonomous Mini Robot (AMiRo) platform.
+Copyright (C) 2016..2018  Thomas Schöpping et al.
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @file    aos_shell.h
+ * @brief   Shell macros and structures.
+ *
+ * @addtogroup aos_shell
+ * @{
+ */
+
+#ifndef _AMIROOS_SHELL_H_
+#define _AMIROOS_SHELL_H_
+
+#include <aosconf.h>
+#if (AMIROOS_CFG_SHELL_ENABLE == true)
+#include <hal.h>
+#include <aos_types.h>
+
+/**
+ * @brief   Shell event flag that is emitted when the thread starts.
+ */
+#define AOS_SHELL_EVTFLAG_START                   ((eventflags_t)(1 << 0))
+
+/**
+ * @brief   Shell event flag that is emitted when a command is executed.
+ */
+#define AOS_SHELL_EVTFLAG_EXEC                    ((eventflags_t)(1 << 1))
+
+/**
+ * @brief   Shell event flag that is emitted when a command execution finished.
+ */
+#define AOS_SHELL_EVTFLAG_DONE                    ((eventflags_t)(1 << 2))
+
+/**
+ * @brief   Shell event flag that is emitted when the shread stops.
+ */
+#define AOS_SHELL_EVTFLAG_EXIT                    ((eventflags_t)(1 << 3))
+
+/**
+ * @brief   Shell event flag that is emitted when an I/O error occurred.
+ */
+#define AOS_SHELL_EVTFLAG_IOERROR                 ((eventflags_t)(1 << 4))
+
+/**
+ * @brief   Shell input configuration for replacing content by user input.
+ */
+#define AOS_SHELL_CONFIG_INPUT_OVERWRITE          (1 << 0)
+
+/**
+ * @brief   Shell prompt configuration print a minimalistic prompt.
+ */
+#define AOS_SHELL_CONFIG_PROMPT_MINIMAL           (1 << 1)
+
+/**
+ * @brief   Shell prompt configuration to additionally print the system uptime with the prompt.
+ */
+#define AOS_SHELL_CONFIG_PROMPT_UPTIME            (1 << 2)
+
+/**
+ * @brief   Shell prompt configuration to additionally print the date and time with the prompt.
+ */
+#define AOS_SHELL_CONFIG_PROMPT_DATETIME          (2 << 2)
+
+/**
+ * @brief   Shell prompt configuration to additionally print the system uptime with the prompt.
+ */
+#define AOS_SHELL_CONFIG_MATCH_CASE               (1 << 4)
+
+/**
+ * @brief   Shell I/O channel flag whether the channel is attached to a list.
+ */
+#define AOS_SHELLCHANNEL_ATTACHED                 (1 << 0)
+
+/**
+ * @brief   Shell I/O channel flag whether the channel is enabled as input.
+ */
+#define AOS_SHELLCHANNEL_INPUT_ENABLED            (1 << 1)
+
+/**
+ * @brief   Shell I/O channel flag whether the channel is enabled as output.
+ */
+#define AOS_SHELLCHANNEL_OUTPUT_ENABLED           (1 << 2)
+
+/*
+ * forward definitions
+ */
+typedef struct aos_shellchannel AosShellChannel;
+typedef struct aos_shellstream AosShellStream;
+
+/**
+ * @brief   AosShellChannel specific methods.
+ */
+#define _aos_shell_channel_methods                                          \
+  _base_asynchronous_channel_methods
+
+/**
+ * @brief   AosShellChannel specific data.
+ */
+#define _aos_shell_channel_data                                             \
+  /* pointer to a BaseAsynchronousChannel object */                         \
+  BaseAsynchronousChannel* asyncchannel;                                    \
+  /* event listener for the associated BaseAsynchronousChannel */           \
+  event_listener_t listener;                                                \
+  /* pointer to the next chennal in a AosShellStream */                     \
+  AosShellChannel* next;                                                    \
+  /* flags related to the channel */                                        \
+  uint8_t flags;
+
+/**
+ * @extends BaseAsynchronousChannelVMT
+ *
+ * @brief   AosShellChannel virtual methods table.
+ */
+struct AosShellChannelVMT {
+  _aos_shell_channel_methods
+};
+
+/**
+ * @extends BaseAsynchronousChannel
+ *
+ * @brief   Shell channel class.
+ * @details This class implements an asynchronous I/O channel.
+ */
+struct aos_shellchannel {
+  /** @brief Virtual Methods Table. */
+  const struct AosShellChannelVMT* vmt;
+  _aos_shell_channel_data
+};
+
+/**
+ * @brief   AosShellStream methods.
+ */
+#define _aos_shellstream_methods                                            \
+  _base_sequential_stream_methods
+
+/**
+ * @brief   AosShellStream data.
+ */
+#define _aos_shellstream_data                                               \
+  /* Pointer to the first channel in a list. */                             \
+  AosShellChannel* channel;
+
+/**
+ * @extends BaseSequentialStream
+ *
+ * @brief   AosShellStream virtual methods table.
+ */
+struct AosShellStreamVMT {
+  _aos_shellstream_methods
+};
+
+/**
+ * @extends BaseSequentialStream
+ *
+ * @brief   Shell Stream class.
+ * @details This class implements an base sequential stream.
+ * @todo    So far only output but no input is supported.
+ */
+struct aos_shellstream {
+  const struct AosShellStreamVMT* vmt;
+  _aos_shellstream_data
+};
+
+/**
+ * @brief   Shell command calback type.
+ */
+typedef int (*aos_shellcmdcb_t)(BaseSequentialStream* stream, int argc, char* argv[]);
+
+/**
+ * @brief   Shell command structure.
+ */
+typedef struct aos_shellcommand {
+  /**
+   * @brief   Command name.
+   */
+  const char* name;
+
+  /**
+   * @brief   Callback function.
+   */
+  aos_shellcmdcb_t callback;
+
+  /**
+   * @brief   Pointer to next command in a singly linked list.
+   */
+  struct aos_shellcommand* next;
+
+} aos_shellcommand_t;
+
+/**
+ * @brief   Execution status of a shell command.
+ */
+typedef struct aos_shellexecstatus {
+  /**
+   * @brief   Pointer to the command that was executed.
+   */
+  aos_shellcommand_t* command;
+
+  /**
+   * @brief   Return value of the executed command.
+   */
+  int retval;
+} aos_shellexecstatus_t;
+
+/**
+ * @brief   Enumerator to encode shell actions.
+ */
+typedef enum aos_shellaction {
+  AOS_SHELL_ACTION_NONE,
+  AOS_SHELL_ACTION_READCHAR,
+  AOS_SHELL_ACTION_AUTOFILL,
+  AOS_SHELL_ACTION_SUGGEST,
+  AOS_SHELL_ACTION_INSERTTOGGLE,
+  AOS_SHELL_ACTION_DELETEFORWARD,
+  AOS_SHELL_ACTION_DELETEBACKWARD,
+  AOS_SHELL_ACTION_RECALLLAST,
+  AOS_SHELL_ACTION_CLEAR,
+  AOS_SHELL_ACTION_CURSOR2START,
+  AOS_SHELL_ACTION_CURSOR2END,
+  AOS_SHELL_ACTION_CURSORLEFT,
+  AOS_SHELL_ACTION_CURSORRIGHT,
+  AOS_SHELL_ACTION_EXECUTE,
+  AOS_SHELL_ACTION_ESCSTART,
+} aos_shellaction_t;
+
+/**
+ * @brief   Shell structure.
+ */
+typedef struct aos_shell {
+  /**
+   * @brief   Pointer to the thread object.
+   */
+  thread_t* thread;
+
+  /**
+   * @brief   Event source.
+   */
+  event_source_t eventSource;
+
+  /**
+   * @brief   Struct for OS related events
+   */
+  struct {
+    /**
+     * @brief   Pointer to the OS' event source.
+     */
+    event_source_t* eventSource;
+
+    /**
+     * @brief   Listener for OS related events.
+     */
+    event_listener_t eventListener;
+  } os;
+
+  /**
+     * @brief   Pointer to the first I/O channel.
+     */
+  AosShellStream stream;
+
+  /**
+   * @brief   String to printed as prompt.
+   */
+  const char* prompt;
+
+  /**
+   * @brief   Pointer to the first element of the singly linked list of commands.
+   * @details Commands are ordered alphabetically in the list.
+   */
+  aos_shellcommand_t* commands;
+
+  /**
+   * @brief   Execution status of the most recent command.
+   */
+  aos_shellexecstatus_t execstatus;
+
+  /**
+   * @brief   Input buffer.
+   */
+  char* line;
+
+  /**
+   * @brief   Size of the input buffer.
+   */
+  size_t linesize;
+
+  /**
+   * @brief   Structure containing data for internal input parsing.
+   */
+  struct {
+    /**
+     * @brief   The last action executed by the shell.
+     */
+    aos_shellaction_t lastaction;
+
+    /**
+     * @brief   Number of character in the current escape sequence.
+     */
+    uint8_t escp;
+
+    /**
+     * @brief   Buffer to store an escape sequence.
+     */
+    char escseq[5];
+
+    /**
+     * @brief   Current curso position.
+     */
+    size_t cursorpos;
+
+    /**
+     * @brief   Current line width.
+     */
+    size_t lineend;
+
+    /**
+     * @brief   Flag whether there was input since the prompt was printed the last time.
+     */
+    bool noinput;
+  } inputdata;
+
+  /**
+   * @brief   Argument buffer.
+   */
+  char** arglist;
+
+  /**
+   * @brief   Size of the argument buffer.
+   */
+  size_t arglistsize;
+
+  /**
+   * @brief   Configuration flags.
+   */
+  uint8_t config;
+} aos_shell_t;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+  void aosShellInit(aos_shell_t* shell, event_source_t* oseventsource, const char* prompt, char* line, size_t linesize, char** arglist, size_t arglistsize);
+  void aosShellStreamInit(AosShellStream* stream);
+  void aosShellChannelInit(AosShellChannel* channel, BaseAsynchronousChannel* asyncchannel);
+  aos_status_t aosShellAddCommand(aos_shell_t* shell, aos_shellcommand_t* cmd);
+  aos_status_t aosShellRemoveCommand(aos_shell_t* shell, char* cmd, aos_shellcommand_t** removed);
+  void aosShellStreamAddChannel(AosShellStream* stream, AosShellChannel* channel);
+  aos_status_t aosShellStreamRemoveChannel(AosShellStream* stream, AosShellChannel* channel);
+  void aosShellChannelInputEnable(AosShellChannel* channel);
+  void aosShellChannelInputDisable( AosShellChannel* channel);
+  void aosShellChannelOutputEnable(AosShellChannel* channel);
+  void aosShellChannelOutputDisable(AosShellChannel* channel);
+  THD_FUNCTION(aosShellThread, shell);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* AMIROOS_CFG_SHELL_ENABLE == true */
+
+#endif /* _AMIROOS_SHELL_H_ */
+
+/** @} */
diff --git a/core/inc/aos_system.h b/core/inc/aos_system.h
new file mode 100644
index 0000000..dbba08c
--- /dev/null
+++ b/core/inc/aos_system.h
@@ -0,0 +1,224 @@
+/*
+AMiRo-OS is an operating system designed for the Autonomous Mini Robot (AMiRo) platform.
+Copyright (C) 2016..2018  Thomas Schöpping et al.
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @file    aos_system.h
+ * @brief   System macros and structures.
+ *
+ * @addtogroup aos_system
+ * @{
+ */
+
+#ifndef _AMIROOS_SYSTEM_H_
+#define _AMIROOS_SYSTEM_H_
+
+#include <aos_iostream.h>
+#include <amiro-lld.h>
+#include <aos_shell.h>
+#include <aos_time.h>
+#include <chprintf.h>
+
+/**
+ * @brief   Resolution of the system time measurement.
+ */
+#define AOS_SYSTEM_TIME_RESOLUTION              ((MICROSECONDS_PER_SECOND + CH_CFG_ST_FREQUENCY - 1) / CH_CFG_ST_FREQUENCY)
+
+/**
+ * @brief   System event flag which is emitted when a shutdown was initiated.
+ */
+#define AOS_SYSTEM_EVENTFLAGS_SHUTDOWN          (eventflags_t)(1 << 0)
+
+/**
+ * @brief   System event flag which is emitted when a shutdown to transportation mode was initiated.
+ */
+#define AOS_SYSTEM_EVENTFLAGS_TRANSPORTATION    (AOS_SYSTEM_EVENTFLAGS_SHUTDOWN | (eventflags_t)(1 << 1))
+
+/**
+ * @brief   System event flag which is emitted when a shutdown to deepsleep mode was initiated.
+ */
+#define AOS_SYSTEM_EVENTFLAGS_DEEPSLEEP         (AOS_SYSTEM_EVENTFLAGS_SHUTDOWN | (eventflags_t)(1 << 2))
+
+/**
+ * @brief   System event flag which is emitted when a shutdown to hibernate mode was initiated.
+ */
+#define AOS_SYSTEM_EVENTFLAGS_HIBERNATE         (AOS_SYSTEM_EVENTFLAGS_SHUTDOWN | (eventflags_t)(1 << 3))
+
+/**
+ * @brief   System event flag which is emitted when a system restart was initiated.
+ */
+#define AOS_SYSTEM_EVENTFLAGS_RESTART           (AOS_SYSTEM_EVENTFLAGS_SHUTDOWN | (eventflags_t)(1 << 4))
+
+/**
+ * @brief   Major version of the implemented SSSP.
+ */
+#define AOS_SYSTEM_SSSP_VERSION_MAJOR           1
+
+/**
+ * @brief   Minor version of the implemented SSSP.
+ */
+#define AOS_SYSTEM_SSSP_VERSION_MINOR           4
+
+/**
+ * @brief   Timeout delay according to SSSP.
+ * @details SSSP defines timeouts to be ten times longer than the signal delay time.
+ */
+#define AOS_SYSTEM_SSSP_TIMEOUT                 (10 * AMIROOS_CFG_SSSP_SIGNALDELAY)
+
+/**
+ * @brief   Enumerator to identify shutdown types.
+ */
+typedef enum aos_shutdown {
+  AOS_SHUTDOWN_NONE,            /**< Default value if no shutdown action was initiated */
+  AOS_SHUTDOWN_PASSIVE,         /**< Passive shutdown (initiated by another module). */
+  AOS_SHUTDOWN_HIBERNATE,       /**< Active shutdown to hibernate mode. */
+  AOS_SHUTDOWN_DEEPSLEEP,       /**< Active shutdown to deepsleep mode. */
+  AOS_SHUTDOWN_TRANSPORTATION,  /**< Active shutdown to transportation mode. */
+  AOS_SHUTDOWN_RESTART,         /**< Active saystem restart request. */
+} aos_shutdown_t;
+
+/**
+ * @brief   Enumerator of the several stages of SSSP.
+ */
+typedef enum aos_ssspstage {
+  AOS_SSSP_STARTUP_1_1  = 0x10, /**< Identifier of SSSP startup phase stage 1-1. */
+  AOS_SSSP_STARTUP_1_2  = 0x11, /**< Identifier of SSSP startup phase stage 1-2. */
+  AOS_SSSP_STARTUP_1_3  = 0x12, /**< Identifier of SSSP startup phase stage 1-3. */
+  AOS_SSSP_STARTUP_2_1  = 0x14, /**< Identifier of SSSP startup phase stage 2-1. */
+  AOS_SSSP_STARTUP_2_2  = 0x15, /**< Identifier of SSSP startup phase stage 2-2. */
+  AOS_SSSP_STARTUP_3_1  = 0x18, /**< Identifier of SSSP startup phase stage 3-1. */
+  AOS_SSSP_STARTUP_3_2  = 0x19, /**< Identifier of SSSP startup phase stage 3-2. */
+  AOS_SSSP_STARTUP_3_3  = 0x1A, /**< Identifier of SSSP startup phase stage 3-3. */
+  AOS_SSSP_STARTUP_3_4  = 0x1B, /**< Identifier of SSSP startup phase stage 3-4. */
+  AOS_SSSP_OPERATION    = 0x20, /**< Identifier of SSSP operation pahse. */
+  AOS_SSSP_SHUTDOWN_1_1 = 0x30, /**< Identifier of SSSP shutdown phase stage 1-1. */
+  AOS_SSSP_SHUTDOWN_1_2 = 0x31, /**< Identifier of SSSP shutdown phase stage 1-2. */
+  AOS_SSSP_SHUTDOWN_1_3 = 0x32, /**< Identifier of SSSP shutdown phase stage 1-3. */
+  AOS_SSSP_SHUTDOWN_2_1 = 0x34, /**< Identifier of SSSP shutdown phase stage 2-1. */
+  AOS_SSSP_SHUTDOWN_2_2 = 0x35, /**< Identifier of SSSP shutdown phase stage 2-2. */
+  AOS_SSSP_SHUTDOWN_3   = 0x38, /**< Identifier of SSSP shutdown phase stage 3. */
+} aos_ssspstage_t;
+
+/**
+ * @brief   Type to represent module IDs.
+ */
+typedef uint16_t aos_ssspmoduleid_t;
+
+/**
+ * @brief   AMiRo-OS base system structure.
+ */
+typedef struct aos_system {
+
+  /**
+   * @brief   SSSP relevant data.
+   */
+  struct {
+    /**
+     * @brief   Current SSSP stage of the system.
+     */
+    aos_ssspstage_t stage;
+
+    /**
+     * @brief   Module identifier.
+     * @details A value of 0 indicates an uninitialized ID.
+     *          The vlaues 0 and ~0 are reserved und must not be set.
+     */
+    aos_ssspmoduleid_t moduleId;
+  } sssp;
+
+  /**
+   * @brief   System I/O stream.
+   */
+  AosIOStream iostream;
+
+  /**
+   * @brief   Event structure.
+   */
+  struct {
+
+    /**
+     * @brief   I/O event source.
+     */
+    event_source_t io;
+
+    /**
+     * @brief   OS event source.
+     */
+    event_source_t os;
+  } events;
+
+#if (AMIROOS_CFG_SHELL_ENABLE == true) || defined(__DOXYGEN__)
+  /**
+   * @brief   Pointer to the shell object.
+   */
+  aos_shell_t shell;
+#endif
+
+} aos_system_t;
+
+/**
+ * @brief   Global system object.
+ */
+extern aos_system_t aos;
+
+/**
+ * @brief   Printf function that uses the default system I/O stream.
+ *
+ * @param[in] fmt   Formatted string to print.
+ */
+#define aosprintf(fmt, ...)                     chprintf((BaseSequentialStream*)&aos.iostream, fmt, ##__VA_ARGS__)
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+#if (AMIROOS_CFG_SHELL_ENABLE == true)
+  void aosSysInit(const char* shellPrompt);
+#else
+  void aosSysInit(void);
+#endif
+  void aosSysStart(void);
+  eventmask_t aosSysSsspStartupOsInitSyncCheck(event_listener_t* syncEvtListener);
+  void aosSysGetUptimeX(aos_timestamp_t* ut);
+  void aosSysGetDateTime(struct tm* dt);
+  void aosSysSetDateTime(struct tm* dt);
+  void aosSysShutdownInit(aos_shutdown_t shutdown);
+  void aosSysStop(void);
+  void aosSysDeinit(void);
+  void aosSysShutdownFinal(aos_shutdown_t shutdown);
+#ifdef __cplusplus
+}
+#endif
+
+/**
+ * @brief   Retrieves the system uptime.
+ *
+ * @param[out] ut   The system uptime.
+ */
+static inline void aosSysGetUptime(aos_timestamp_t* ut)
+{
+  aosDbgCheck(ut != NULL);
+
+  chSysLock();
+  aosSysGetUptimeX(ut);
+  chSysUnlock();
+
+  return;
+}
+
+#endif /* _AMIROOS_SYSTEM_H_ */
+
+/** @} */
diff --git a/core/inc/aos_thread.h b/core/inc/aos_thread.h
new file mode 100644
index 0000000..7568b49
--- /dev/null
+++ b/core/inc/aos_thread.h
@@ -0,0 +1,242 @@
+/*
+AMiRo-OS is an operating system designed for the Autonomous Mini Robot (AMiRo) platform.
+Copyright (C) 2016..2018  Thomas Schöpping et al.
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @file    aos_thread.h
+ * @brief   Thread macros and inline functions.
+ *
+ * @addtogroup aos_threads
+ * @{
+ */
+
+#ifndef _AMIROOS_THREAD_H_
+#define _AMIROOS_THREAD_H_
+
+#include <aos_time.h>
+#include <aos_system.h>
+
+/**
+ * @brief   Minimum thread priority.
+ */
+#define AOS_THD_LOWPRIO_MIN           ((tprio_t)(LOWPRIO))
+
+/**
+ * @brief   Maximum priority for background threads.
+ */
+#define AOS_THD_LOWPRIO_MAX           ((tprio_t)(LOWPRIO + ((NORMALPRIO - LOWPRIO) / 2)))
+
+/**
+ * @brief   Minimum priority for normal/standard threads.
+ */
+#define AOS_THD_NORMALPRIO_MIN        ((tprio_t)(AOS_THD_LOWPRIO_MAX + 1))
+
+/**
+ * @brief   Maximum priority for normal/standard threads.
+ */
+#define AOS_THD_NORMALPRIO_MAX        ((tprio_t)(NORMALPRIO))
+
+/**
+ * @brief   Minimum priority for important threads.
+ */
+#define AOS_THD_HIGHPRIO_MIN          ((tprio_t)(NORMALPRIO + 1))
+
+/**
+ * @brief   Maximum priority for important threads.
+ */
+#define AOS_THD_HIGHPRIO_MAX          ((tprio_t)(NORMALPRIO + ((HIGHPRIO - NORMALPRIO) / 2)))
+
+/**
+ * @brief   Minimum priority for real-time threads.
+ */
+#define AOS_THD_RTPRIO_MIN            ((tprio_t)(AOS_THD_HIGHPRIO_MAX + 1))
+
+/**
+ * @brief   Maximum priority for real-time threads.
+ */
+#define AOS_THD_RTPRIO_MAX            ((tprio_t)(HIGHPRIO - 1))
+
+/**
+ * @brief   Priority for the system control thread.
+ */
+#define AOS_THD_CTRLPRIO              ((tprio_t)(HIGHPRIO))
+
+/**
+ * @brief   Maximum timeframe that can be slept in system ticks.
+ */
+#define AOS_THD_MAX_SLEEP_ST          TIME_MAX_INTERVAL
+
+/**
+ * @brief   Maximum timeframe that can be slept in seconds.
+ */
+#define AOS_THD_MAX_SLEEP_S           (chTimeI2S(AOS_THD_MAX_SLEEP_ST) - 1)
+
+/**
+ * @brief   Maximum timeframe that can be slept in milliseconds.
+ */
+#define AOS_THD_MAX_SLEEP_MS          (chTimeI2MS(AOS_THD_MAX_SLEEP_ST) - 1)
+
+/**
+ * @brief   Maximum timeframe that can be slept in microseconds.
+ */
+#define AOS_THD_MAX_SLEEP_US          (chTimeI2US(AOS_THD_MAX_SLEEP_ST) - 1)
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+  void aosThdSleepUntilS(const aos_timestamp_t* t);
+#ifdef __cplusplus
+}
+#endif
+
+/**
+ * @brief   Lets the calling thread sleep the specified amount of microseconds.
+ *
+ * @param[in] us    Time to sleep in microseconds.
+ */
+static inline void aosThdUSleepS(const aos_interval_t us)
+{
+  aos_timestamp_t ut;
+
+  aosSysGetUptimeX(&ut);
+  ut += us;
+  aosThdSleepUntilS(&ut);
+
+  return;
+}
+
+/**
+ * @brief   Lets the calling thread sleep the specified amount of milliseconds.
+ *
+ * @param[in] ms    Time to sleep in milliseconds.
+ */
+static inline void aosThdMSleepS(const uint32_t ms)
+{
+  aos_timestamp_t ut;
+
+  aosSysGetUptimeX(&ut);
+  ut += (aos_timestamp_t)ms * MICROSECONDS_PER_MILLISECOND;
+  aosThdSleepUntilS(&ut);
+
+  return;
+}
+
+/**
+ * @brief   Lets the calling thread sleep the specified amount of seconds.
+ *
+ * @param[in] s     Time to sleep in seconds.
+ */
+static inline void aosThdSSleepS(const uint32_t s)
+{
+  aos_timestamp_t ut;
+
+  aosSysGetUptimeX(&ut);
+  ut += (aos_timestamp_t)s * MICROSECONDS_PER_SECOND;
+  aosThdSleepUntilS(&ut);
+
+  return;
+}
+
+/**
+ * @brief   Lets the calling thread sleep the specified amount of seconds.
+ *
+ * @param[in] s     Time to sleep in seconds.
+ */
+static inline void aosThdSleepS(const float s)
+{
+  aos_timestamp_t ut;
+
+  aosSysGetUptimeX(&ut);
+  ut += (aos_timestamp_t)(s * MICROSECONDS_PER_SECOND);
+  aosThdSleepUntilS(&ut);
+
+  return;
+}
+
+/**
+ * @brief   Lets the calling thread sleep the specified amount of microseconds.
+ *
+ * @param[in] us    Time to sleep in microseconds.
+ */
+static inline void aosThdUSleep(const uint32_t us)
+{
+  chSysLock();
+  aosThdUSleepS(us);
+  chSysUnlock();
+
+  return;
+}
+
+/**
+ * @brief   Lets the calling thread sleep the specified amount of milliseconds.
+ *
+ * @param[in] ms    Time to sleep in milliseconds.
+ */
+static inline void aosThdMSleep(const uint32_t ms)
+{
+  chSysLock();
+  aosThdMSleepS(ms);
+  chSysUnlock();
+
+  return;
+}
+
+/**
+ * @brief   Lets the calling thread sleep the specified amount of seconds.
+ *
+ * @param[in] s     Time to sleep in seconds.
+ */
+static inline void aosThdSSleep(const uint32_t s)
+{
+  chSysLock();
+  aosThdSSleepS(s);
+  chSysUnlock();
+
+  return;
+}
+
+/**
+ * @brief   Lets the calling thread sleep the specified amount of seconds.
+ *
+ * @param[in] s     Time to sleep in seconds.
+ */
+static inline void aosThdSleep(const float s)
+{
+  chSysLock();
+  aosThdSleepS(s);
+  chSysUnlock();
+
+  return;
+}
+
+/**
+ * @brief   Lets the calling thread sleep until the specifide system uptime.
+ *
+ * @param[in] t     Deadline until the thread will sleep.
+ */
+static inline void aosThdSleepUntil(const aos_timestamp_t* t)
+{
+  chSysLock();
+  aosThdSleepUntilS(t);
+  chSysUnlock();
+
+  return;
+}
+
+#endif /* _AMIROOS_THREAD_H_ */
+
+/** @} */
diff --git a/core/inc/aos_time.h b/core/inc/aos_time.h
new file mode 100644
index 0000000..284af13
--- /dev/null
+++ b/core/inc/aos_time.h
@@ -0,0 +1,225 @@
+/*
+AMiRo-OS is an operating system designed for the Autonomous Mini Robot (AMiRo) platform.
+Copyright (C) 2016..2018  Thomas Schöpping et al.
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY) without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/.
+*/
+
+/**
+ * @file    aos_time.h
+ * @brief   Time related constants and data types.
+ *
+ * @addtogroup aos_time
+ * @{
+ */
+
+#ifndef _AMIROOS_TIME_H_
+#define _AMIROOS_TIME_H_
+
+#include <stdint.h>
+
+/**
+ * @brief   Generic time to represent long time frames at high precision.
+ * @note    By definition the temporal resolution is 1us.
+ */
+typedef uint64_t aos_timestamp_t;
+
+/**
+ * @brief   generic time to represent medium length time frames at high precision.
+ * @note    By definition the temporal resolution is 1us.
+ */
+typedef uint32_t aos_interval_t;
+
+/**
+ * @brief   Generic time to represent long time frames at high precision.
+ * @note    By definition the temporal resolution is 1us.
+ */
+typedef aos_timestamp_t aos_longinterval_t;
+
+#define MICROSECONDS_PER_MICROSECOND  ((uint8_t)  (1))
+#define MILLISECONDS_PER_MILLISECOND  ((uint8_t)  (1))
+#define SECONDS_PER_SECOND            ((uint8_t)  (1))
+#define MINUTES_PER_MINUTE            ((uint8_t)  (1))
+#define HOURS_PER_HOUR                ((uint8_t)  (1))
+#define DAYS_PER_DAY                  ((uint8_t)  (1))
+#define WEEKS_PER_WEEK                ((uint8_t)  (1))
+#define MONTHS_PER_MONTH              ((uint8_t)  (1))
+#define YEARS_PER_YEAR                ((uint8_t)  (1))
+#define DECADES_PER_DECADE            ((uint8_t)  (1))
+#define CENTURIES_PER_CENTURY         ((uint8_t)  (1))
+#define MILLENIUMS_PER_MILLENIUM      ((uint8_t)  (1))
+
+#define MICROSECONDS_PER_MILLISECOND  ((uint16_t) (1000))
+#define MILLISECONDS_PER_SECOND       ((uint16_t) (1000))
+#define SECONDS_PER_MINUTE            ((uint8_t)  (60))
+#define MINUTES_PER_HOUR              ((uint8_t)  (60))
+#define HOURS_PER_DAY                 ((uint8_t)  (24))
+#define DAYS_PER_WEEK                 ((uint8_t)  (7))
+#define DAYS_PER_YEAR                 ((float)    (365.25f))
+#define MONTHS_PER_YEAR               ((uint8_t)  (12))
+#define YEARS_PER_DECADE              ((uint8_t)  (10))
+#define DECADES_PER_CENTURY           ((uint8_t)  (10))
+#define CENTURIES_PER_MILLENIUM       ((uint8_t)  (10))
+
+#define MICROSECONDS_PER_SECOND       ((uint32_t) ((uint32_t)MICROSECONDS_PER_MILLISECOND * (uint32_t)MILLISECONDS_PER_SECOND))
+#define MILLISECONDS_PER_MINUTE       ((uint16_t) ((uint16_t)MILLISECONDS_PER_SECOND * (uint16_t)SECONDS_PER_MINUTE))
+#define SECONDS_PER_HOUR              ((uint16_t) ((uint16_t)SECONDS_PER_MINUTE * (uint16_t)MINUTES_PER_HOUR))
+#define MINUTES_PER_DAY               ((uint16_t) ((uint16_t)MINUTES_PER_HOUR * (uint16_t)HOURS_PER_DAY))
+#define HOURS_PER_WEEK                ((uint8_t)  (HOURS_PER_DAY * DAYS_PER_WEEK))
+#define HOURS_PER_YEAR                ((uint16_t) ((float)HOURS_PER_DAY * DAYS_PER_YEAR))
+#define DAYS_PER_MONTH                ((float)    (DAYS_PER_YEAR / (float)MONTHS_PER_YEAR))
+#define DAYS_PER_DECADE               ((float)    (DAYS_PER_YEAR * (float)YEARS_PER_DECADE))
+#define WEEKS_PER_YEAR                ((float)    (DAYS_PER_YEAR / (float)DAYS_PER_WEEK))
+#define MONTHS_PER_DECADE             ((uint8_t)  (MONTHS_PER_YEAR * YEARS_PER_DECADE))
+#define YEARS_PER_CENTURY             ((uint8_t)  (YEARS_PER_DECADE * DECADES_PER_CENTURY))
+#define DECADES_PER_MILLENIUM         ((uint8_t)  (DECADES_PER_CENTURY * CENTURIES_PER_MILLENIUM))
+
+#define MICROSECONDS_PER_MINUTE       ((uint32_t) ((uint32_t)MICROSECONDS_PER_MILLISECOND * (uint32_t)MILLISECONDS_PER_MINUTE))
+#define MILLISECONDS_PER_HOUR         ((uint32_t) ((uint32_t)MILLISECONDS_PER_SECOND * (uint32_t)SECONDS_PER_HOUR))
+#define SECONDS_PER_DAY               ((uint32_t) ((uint32_t)SECONDS_PER_MINUTE * (uint32_t)MINUTES_PER_DAY))
+#define MINUTES_PER_WEEK              ((uint16_t) ((uint16_t)MINUTES_PER_HOUR * (uint16_t)HOURS_PER_WEEK))
+#define HOURS_PER_MONTH               ((float)    ((float)HOURS_PER_DAY * DAYS_PER_MONTH))
+#define HOURS_PER_DECADE              ((uint32_t) ((float)HOURS_PER_DAY * DAYS_PER_DECADE))
+#define MINUTES_PER_YEAR              ((uint32_t) ((uint32_t)MINUTES_PER_HOUR * (uint32_t)HOURS_PER_YEAR))
+#define DAYS_PER_CENTURY              ((uint16_t) (DAYS_PER_YEAR * (float)YEARS_PER_CENTURY))
+#define WEEKS_PER_MONTH               ((float)    (DAYS_PER_MONTH / (float)DAYS_PER_WEEK))
+#define WEEKS_PER_DECADE              ((float)    (DAYS_PER_DECADE / (float)DAYS_PER_WEEK))
+#define MONTHS_PER_CENTURY            ((uint16_t) ((uint16_t)MONTHS_PER_YEAR * (uint16_t)YEARS_PER_CENTURY))
+#define YEARS_PER_MILLENIUM           ((uint16_t) ((uint16_t)YEARS_PER_DECADE * (uint16_t)DECADES_PER_MILLENIUM))
+
+#define MICROSECONDS_PER_HOUR         ((uint32_t) ((uint32_t)MICROSECONDS_PER_MILLISECOND * MILLISECONDS_PER_HOUR))
+#define MILLISECONDS_PER_DAY          ((uint32_t) ((uint32_t)MILLISECONDS_PER_SECOND * SECONDS_PER_DAY))
+#define SECONDS_PER_WEEK              ((uint32_t) (SECONDS_PER_MINUTE * (uint32_t)MINUTES_PER_WEEK))
+#define SECONDS_PER_YEAR              ((uint32_t) (SECONDS_PER_MINUTE * MINUTES_PER_YEAR))
+#define MINUTES_PER_MONTH             ((uint16_t) ((float)MINUTES_PER_HOUR * HOURS_PER_MONTH))
+#define MINUTES_PER_DECADE            ((uint32_t) ((uint32_t)MINUTES_PER_HOUR * HOURS_PER_DECADE))
+#define HOURS_PER_CENTURY             ((uint32_t) ((uint32_t)HOURS_PER_DAY * (uint32_t)DAYS_PER_CENTURY))
+#define DAYS_PER_MILLENIUM            ((uint32_t) (DAYS_PER_YEAR * (float)YEARS_PER_MILLENIUM))
+#define WEEKS_PER_CENTURY             ((float)    ((float)DAYS_PER_CENTURY / (float)DAYS_PER_WEEK))
+#define MONTHS_PER_MILLENIUM          ((uint16_t) ((uint16_t)MONTHS_PER_YEAR * YEARS_PER_MILLENIUM))
+
+#define MICROSECONDS_PER_DAY          ((uint64_t) ((uint64_t)MICROSECONDS_PER_MILLISECOND * (uint64_t)MILLISECONDS_PER_DAY))
+#define MILLISECONDS_PER_WEEK         ((uint32_t) ((uint32_t)MILLISECONDS_PER_SECOND * SECONDS_PER_WEEK))
+#define MILLISECONDS_PER_YEAR         ((uint64_t) ((uint64_t)MILLISECONDS_PER_SECOND * (uint64_t)SECONDS_PER_YEAR))
+#define SECONDS_PER_MONTH             ((uint32_t) ((uint32_t)SECONDS_PER_MINUTE * (uint32_t)MINUTES_PER_MONTH))
+#define SECONDS_PER_DECADE            ((uint32_t) ((uint32_t)SECONDS_PER_MINUTE * MINUTES_PER_DECADE))
+#define MINUTES_PER_CENTURY           ((uint32_t) ((uint32_t)MINUTES_PER_HOUR * HOURS_PER_CENTURY))
+#define HOURS_PER_MILLENIUM           ((uint32_t) ((uint32_t)HOURS_PER_DAY * DAYS_PER_MILLENIUM))
+#define WEEKS_PER_MILLENIUM           ((float)    ((float)DAYS_PER_MILLENIUM / (float)DAYS_PER_WEEK))
+
+#define MICROSECONDS_PER_WEEK         ((uint64_t) ((uint64_t)MICROSECONDS_PER_MILLISECOND * (uint64_t)MILLISECONDS_PER_WEEK))
+#define MICROSECONDS_PER_YEAR         ((uint64_t) ((uint64_t)MICROSECONDS_PER_MILLISECOND * MILLISECONDS_PER_YEAR))
+#define MILLISECONDS_PER_MONTH        ((uint32_t) ((uint32_t)MILLISECONDS_PER_SECOND * SECONDS_PER_MONTH))
+#define MILLISECONDS_PER_DECADE       ((uint64_t) ((uint64_t)MILLISECONDS_PER_SECOND * (uint64_t)SECONDS_PER_DECADE))
+#define SECONDS_PER_CENTURY           ((uint32_t) (SECONDS_PER_MINUTE * MINUTES_PER_CENTURY))
+#define MINUTES_PER_MILLENIUM         ((uint32_t) ((uint32_t)MINUTES_PER_HOUR * HOURS_PER_MILLENIUM))
+
+#define MICROSECONDS_PER_MONTH        ((uint64_t) ((uint64_t)MICROSECONDS_PER_MILLISECOND * (uint64_t)MILLISECONDS_PER_MONTH))
+#define MICROSECONDS_PER_DECADE       ((uint64_t) ((uint64_t)MICROSECONDS_PER_MILLISECOND * MILLISECONDS_PER_DECADE))
+#define MILLISECONDS_PER_CENTURY      ((uint64_t) ((uint64_t)MILLISECONDS_PER_SECOND * (uint64_t)SECONDS_PER_CENTURY))
+#define SECONDS_PER_MILLENIUM         ((uint64_t) ((uint64_t)SECONDS_PER_MINUTE * (uint64_t)MINUTES_PER_MILLENIUM))
+
+#define MICROSECONDS_PER_CENTURY      ((uint64_t) ((uint64_t)MICROSECONDS_PER_MILLISECOND * MILLISECONDS_PER_CENTURY))
+#define MILLISECONDS_PER_MILLENIUM    ((uint64_t) ((uint64_t)MILLISECONDS_PER_SECOND * SECONDS_PER_MILLENIUM))
+
+#define MICROSECONDS_PER_MILLENIUM    ((uint64_t) ((uint64_t)MICROSECONDS_PER_MILLISECOND * MILLISECONDS_PER_MILLENIUM))
+
+#define MILLISECONDS_PER_MICROSECOND  ((float)MILLISECONDS_PER_MILLISECOND / (float)MICROSECONDS_PER_MILLISECOND)
+
+#define SECONDS_PER_MICROSECOND       ((float)SECONDS_PER_SECOND / (float)MICROSECONDS_PER_SECOND)
+#define SECONDS_PER_MILLISECOND       ((float)SECONDS_PER_SECOND / (float)MILLISECONDS_PER_SECOND)
+
+#define MINUTES_PER_MICROSECOND       ((float)MINUTES_PER_MINUTE / (float)MICROSECONDS_PER_MINUTE)
+#define MINUTES_PER_MILLISECOND       ((float)MINUTES_PER_MINUTE / (float)MILLISECONDS_PER_MINUTE)
+#define MINUTES_PER_SECOND            ((float)MINUTES_PER_MINUTE / (float)SECONDS_PER_MINUTE)
+
+#define HOURS_PER_MICROSECOND         ((float)HOURS_PER_HOUR / (float)MICROSECONDS_PER_HOUR)
+#define HOURS_PER_MILLISECOND         ((float)HOURS_PER_HOUR / (float)MILLISECONDS_PER_HOUR)
+#define HOURS_PER_SECOND              ((float)HOURS_PER_HOUR / (float)SECONDS_PER_HOUR)
+#define HOURS_PER_MINUTE              ((float)HOURS_PER_HOUR / (float)MINUTES_PER_HOUR)
+
+#define DAYS_PER_MICROSECOND          ((float)DAYS_PER_DAY / (float)MICROSECONDS_PER_DAY)
+#define DAYS_PER_MILLISECOND          ((float)DAYS_PER_DAY / (float)MILLISECONDS_PER_DAY)
+#define DAYS_PER_SECOND               ((float)DAYS_PER_DAY / (float)SECONDS_PER_DAY)
+#define DAYS_PER_MINUTE               ((float)DAYS_PER_DAY / (float)MINUTES_PER_DAY)
+#define DAYS_PER_HOUR                 ((float)DAYS_PER_DAY / (float)HOURS_PER_DAY)
+
+#define WEEKS_PER_MICROSECOND         ((float)WEEKS_PER_WEEK / (float)MICROSECONDS_PER_WEEK)
+#define WEEKS_PER_MILLISECOND         ((float)WEEKS_PER_WEEK / (float)MILLISECONDS_PER_WEEK)
+#define WEEKS_PER_SECOND              ((float)WEEKS_PER_WEEK / (float)SECONDS_PER_WEEK)
+#define WEEKS_PER_MINUTE              ((float)WEEKS_PER_WEEK / (float)MINUTES_PER_WEEK)
+#define WEEKS_PER_HOUR                ((float)WEEKS_PER_WEEK / (float)HOURS_PER_WEEK)
+#define WEEKS_PER_DAY                 ((float)WEEKS_PER_WEEK / (float)DAYS_PER_WEEK)
+
+#define MONTHS_PER_MICROSECOND        ((float)MONTHS_PER_MONTH / (float)MICROSECONDS_PER_MONTH)
+#define MONTHS_PER_MILLISECOND        ((float)MONTHS_PER_MONTH / (float)MILLISECONDS_PER_MONTH)
+#define MONTHS_PER_SECOND             ((float)MONTHS_PER_MONTH / (float)SECONDS_PER_MONTH)
+#define MONTHS_PER_MINUTE             ((float)MONTHS_PER_MONTH / (float)MINUTES_PER_MONTH)
+#define MONTHS_PER_HOUR               ((float)MONTHS_PER_MONTH / (float)HOURS_PER_MONTH)
+#define MONTHS_PER_DAY                ((float)MONTHS_PER_MONTH / (float)DAYS_PER_MONTH)
+#define MONTHS_PER_WEEK               ((float)MONTHS_PER_MONTH / (float)WEEKS_PER_MONTH)
+
+#define YEARS_PER_MICROSECOND         ((float)YEARS_PER_YEAR / (float)MICROSECONDS_PER_YEAR)
+#define YEARS_PER_MILLISECOND         ((float)YEARS_PER_YEAR / (float)MILLISECONDS_PER_YEAR)
+#define YEARS_PER_SECOND              ((float)YEARS_PER_YEAR / (float)SECONDS_PER_YEAR)
+#define YEARS_PER_MINUTE              ((float)YEARS_PER_YEAR / (float)MINUTES_PER_YEAR)
+#define YEARS_PER_HOUR                ((float)YEARS_PER_YEAR / (float)HOURS_PER_YEAR)
+#define YEARS_PER_DAY                 ((float)YEARS_PER_YEAR / (float)DAYS_PER_YEAR)
+#define YEARS_PER_WEEK                ((float)YEARS_PER_YEAR / (float)WEEKS_PER_YEAR)
+#define YEARS_PER_MONTH               ((float)YEARS_PER_YEAR / (float)MONTHS_PER_YEAR)
+
+#define DECADES_PER_MICROSECOND       ((float)DECADES_PER_DECADE / (float)MICROSECONDS_PER_DECADE)
+#define DECADES_PER_MILLISECOND       ((float)DECADES_PER_DECADE / (float)MILLISECONDS_PER_DECADE)
+#define DECADES_PER_SECOND            ((float)DECADES_PER_DECADE / (float)SECONDS_PER_DECADE)
+#define DECADES_PER_MINUTE            ((float)DECADES_PER_DECADE / (float)MINUTES_PER_DECADE)
+#define DECADES_PER_HOUR              ((float)DECADES_PER_DECADE / (float)HOURS_PER_DECADE)
+#define DECADES_PER_DAY               ((float)DECADES_PER_DECADE / (float)DAYS_PER_DECADE)
+#define DECADES_PER_WEEK              ((float)DECADES_PER_DECADE / (float)WEEKS_PER_DECADE)
+#define DECADES_PER_MONTH             ((float)DECADES_PER_DECADE / (float)MONTHS_PER_DECADE)
+#define DECADES_PER_YEAR              ((float)DECADES_PER_DECADE / (float)YEARS_PER_DECADE)
+
+#define CENTURIES_PER_MICROSECOND     ((float)CENTURIES_PER_CENTURY / (float)MICROSECONDS_PER_CENTURY)
+#define CENTURIES_PER_MILLISECOND     ((float)CENTURIES_PER_CENTURY / (float)MILLISECONDS_PER_CENTURY)
+#define CENTURIES_PER_SECOND          ((float)CENTURIES_PER_CENTURY / (float)SECONDS_PER_CENTURY)
+#define CENTURIES_PER_MINUTE          ((float)CENTURIES_PER_CENTURY / (float)MINUTES_PER_CENTURY)
+#define CENTURIES_PER_HOUR            ((float)CENTURIES_PER_CENTURY / (float)HOURS_PER_CENTURY)
+#define CENTURIES_PER_DAY             ((float)CENTURIES_PER_CENTURY / (float)DAYS_PER_CENTURY)
+#define CENTURIES_PER_WEEK            ((float)CENTURIES_PER_CENTURY / (float)WEEKS_PER_CENTURY)
+#define CENTURIES_PER_MONTH           ((float)CENTURIES_PER_CENTURY / (float)MONTHS_PER_CENTURY)
+#define CENTURIES_PER_YEAR            ((float)CENTURIES_PER_CENTURY / (float)YEARS_PER_CENTURY)
+#define CENTURIES_PER_DECADE          ((float)CENTURIES_PER_CENTURY / (float)DECADES_PER_CENTURY)
+
+#define MILLENIUMS_PER_MICROSECOND    ((float)MILLENIUMS_PER_MILLENIUM / (float)MICROSECONDS_PER_MILLENIUM)
+#define MILLENIUMS_PER_MILLISECOND    ((float)MILLENIUMS_PER_MILLENIUM / (float)MILLISECONDS_PER_MILLENIUM)
+#define MILLENIUMS_PER_SECOND         ((float)MILLENIUMS_PER_MILLENIUM / (float)SECONDS_PER_MILLENIUM)
+#define MILLENIUMS_PER_MINUTE         ((float)MILLENIUMS_PER_MILLENIUM / (float)MINUTES_PER_MILLENIUM)
+#define MILLENIUMS_PER_HOUR           ((float)MILLENIUMS_PER_MILLENIUM / (float)HOURS_PER_MILLENIUM)
+#define MILLENIUMS_PER_DAY            ((float)MILLENIUMS_PER_MILLENIUM / (float)DAYS_PER_MILLENIUM)
+#define MILLENIUMS_PER_WEEK           ((float)MILLENIUMS_PER_MILLENIUM / (float)WEEKS_PER_MILLENIUM)
+#define MILLENIUMS_PER_MONTH          ((float)MILLENIUMS_PER_MILLENIUM / (float)MONTHS_PER_MILLENIUM)
+#define MILLENIUMS_PER_YEAR           ((float)MILLENIUMS_PER_MILLENIUM / (float)YEARS_PER_MILLENIUM)
+#define MILLENIUMS_PER_DECADE         ((float)MILLENIUMS_PER_MILLENIUM / (float)DECADES_PER_MILLENIUM)
+#define MILLENIUMS_PER_CENTURY        ((float)MILLENIUMS_PER_MILLENIUM / (float)CENTURIES_PER_MILLENIUM)
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+  uint8_t aosTimeDayOfWeekFromDate(const uint16_t day, const uint8_t month, const uint16_t year);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _AMIROOS_TIME_H_ */
+
+/** @} */
diff --git a/core/inc/aos_timer.h b/core/inc/aos_timer.h
new file mode 100644
index 0000000..495c741
--- /dev/null
+++ b/core/inc/aos_timer.h
@@ -0,0 +1,260 @@
+/*
+AMiRo-OS is an operating system designed for the Autonomous Mini Robot (AMiRo) platform.
+Copyright (C) 2016..2018  Thomas Schöpping et al.
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @file    aos_timer.h
+ * @brief   Timer macros and structures.
+ *
+ * @addtogroup aos_timers
+ * @{
+ */
+
+#ifndef _AMIROOS_TIMER_H_
+#define _AMIROOS_TIMER_H_
+
+#include <ch.h>
+#include <aos_time.h>
+
+/**
+ * @brief   Maximum timer interval that can be set in system ticks.
+ */
+#define AOS_TIMER_MAX_INTERVAL_ST     TIME_MAX_INTERVAL
+
+/**
+ * @brief   Maximum timer interval that can be set in seconds.
+ */
+#define AOS_TIMER_MAX_INTERVAL_S      (chTimeI2S(AOS_TIMER_MAX_INTERVAL_ST) - 1)
+
+/**
+ * @brief   Maximum timer interval that can be set in milliseconds.
+ */
+#define AOS_TIMER_MAX_INTERVAL_MS     (chTimeI2MS(AOS_TIMER_MAX_INTERVAL_ST) - 1)
+
+/**
+ * @brief   Maximum timer interval that can be set in microseconds.
+ */
+#define AOS_TIMER_MAX_INTERVAL_US     (chTimeI2US(AOS_TIMER_MAX_INTERVAL_ST) - 1)
+
+/**
+ * @brief   Timer stucture.
+ */
+typedef struct aos_timer {
+  /**
+   * @brief   ChibiOS virtual timer.
+   */
+  virtual_timer_t vt;
+
+  /**
+   * @brief   Time to wake up.
+   */
+  aos_timestamp_t wkuptime;
+
+  /**
+   * @brief   Pointer to a callback function.
+   */
+  vtfunc_t callback;
+
+  /**
+   * @brief   Pointer to a parameter for the callback function.
+   */
+  void* cbparam;
+} aos_timer_t;
+
+/**
+ * @brief   Periodic timer structure.
+ */
+typedef struct aos_periodictimer {
+  /**
+   * @brief   AMiRo-OS timer.
+   */
+  aos_timer_t timer;
+
+  /**
+   * @brief   Period interval.
+   */
+  aos_longinterval_t interval;
+
+  /**
+   * @brief   Pointer to a callback function.
+   */
+  vtfunc_t callback;
+
+  /**
+   * @brief   Pointer to a parameter for the callback function.
+   */
+  void* cbparam;
+} aos_periodictimer_t;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+  void aosTimerInit(aos_timer_t* timer);
+  void aosTimerSetAbsoluteI(aos_timer_t* timer, aos_timestamp_t* uptime, vtfunc_t cb, void* par);
+  void aosTimerSetIntervalI(aos_timer_t* timer, aos_interval_t offset, vtfunc_t cb, void* par);
+  void aosTimerSetLongIntervalI(aos_timer_t* timer, aos_longinterval_t* offset, vtfunc_t cb, void* par);
+  void aosPeriodicTimerInit(aos_periodictimer_t* ptimer);
+  void aosPeriodicTimerSetI(aos_periodictimer_t* ptimer, aos_interval_t interval, vtfunc_t cb, void* par);
+  void aosPeriodicTimerSetLongI(aos_periodictimer_t* ptimer, aos_longinterval_t* interval, vtfunc_t cb, void* par);
+#ifdef __cplusplus
+}
+#endif
+
+/**
+ * @brief   Set timer to fire at an absolute system time.
+ *
+ * @param[in] timer   Pointer to the timer to set.
+ * @param[in] uptime  Pointer to the absolute uptime for the timer to fire.
+ * @param[in] cb      Pointer to a callback function to be called.
+ * @param[in] par     Pointer to a parameter fpr the callback function (may be NULL).
+ */
+static inline void aosTimerSetAbsolute(aos_timer_t* timer, aos_timestamp_t* uptime, vtfunc_t cb, void* par)
+{
+  chSysLock();
+  aosTimerSetAbsoluteI(timer, uptime, cb, par);
+  chSysUnlock();
+
+  return;
+}
+
+/**
+ * @brief   Set timer to fire after a relative interval.
+ *
+ * @param[in] timer   Pointer to the timer to set.
+ * @param[in] offset  Relative interval to set for the timer to fire.
+ * @param[in] cb      Pointer to a callback function to be called.
+ * @param[in] par     Pointer to a parameter fpr the callback function (may be NULL).
+ */
+static inline void aosTimerSetInterval(aos_timer_t* timer, aos_interval_t offset, vtfunc_t cb, void* par)
+{
+  chSysLock();
+  aosTimerSetIntervalI(timer, offset, cb, par);
+  chSysUnlock();
+}
+
+/**
+ * @brief   Set timer to fire after a long relative interval.
+ *
+ * @param[in] timer   Pointer to the timer to set.
+ * @param[in] offset  Pointer to a long interval value to set for the timer to fire.
+ * @param[in] cb      Pointer to a callback function to be called.
+ * @param[in] par     Pointer to a parameter fpr the callback function (may be NULL).
+ */
+static inline void aosTimerSetLongInterval(aos_timer_t* timer, aos_longinterval_t* offset, vtfunc_t cb, void* par)
+{
+  chSysLock();
+  aosTimerSetLongIntervalI(timer, offset, cb, par);
+  chSysUnlock();
+}
+
+/**
+ * @brief   Reset a timer.
+ *
+ * @param[in] timer   Pointer to the timer to reset.
+ */
+static inline void aosTimerResetI(aos_timer_t* timer)
+{
+  chVTResetI(&(timer->vt));
+
+  return;
+}
+
+/**
+ * @brief   Reset a timer.
+ *
+ * @param[in] timer   Pointer to the timer to reset.
+ */
+static inline void aosTimerReset(aos_timer_t* timer)
+{
+  chSysLock();
+  aosTimerResetI(timer);
+  chSysUnlock();
+
+  return;
+}
+
+/**
+ * @brief   Determine whether a timer is armed.
+ *
+ * @param[in] timer   Pointer to the timer to check.
+ *
+ * @return    true if the timer is armed, false otherwise.
+ */
+static inline bool aosTimerIsArmedI(aos_timer_t* timer)
+{
+  return chVTIsArmedI(&(timer->vt));
+}
+
+/**
+ * @brief   Determine whether a timer is armed.
+ *
+ * @param[in] timer   Pointer to the timer to check.
+ *
+ * @return    true if the timer is armed, false otherwise.
+ */
+static inline bool aosTimerIsArmed(aos_timer_t* timer)
+{
+  bool b;
+
+  chSysLock();
+  b = aosTimerIsArmedI(timer);
+  chSysUnlock();
+
+  return b;
+}
+
+/**
+ * @brief   Set a periodic timer to fire in the specified interval.
+ *
+ * @param[in] ptimer    Pointer to the periodic timer to set.
+ * @param[in] interval  Interval for the periodic timer to fire,
+ * @param[in] cb        Pointer to a callback function to be called.
+ *                      In contrast to other callback functions, this get called from an already ISR locked context.
+ *                      This it may not contain any chSysLockX() or chSysUnlockX() calls.
+ * @param[in] par       Pointer to a parameter for the callback function (may be NULL).
+ */
+static inline void aosPeriodicTimerSet(aos_periodictimer_t *ptimer, aos_interval_t interval, vtfunc_t cb, void *par)
+{
+  chSysLock();
+  aosPeriodicTimerSetI(ptimer, interval, cb, par);
+  chSysUnlock();
+
+  return;
+}
+
+/**
+ * @brief   Set a periodic timer to fire in the specified interval.
+ *
+ * @param[in] ptimer    Pointer to the periodic timer to set.
+ * @param[in] interval  Pointer to a long interval value for the periodic timer to fire,
+ * @param[in] cb        Pointer to a callback function to be called.
+ *                      In contrast to other callback functions, this get called from an already ISR locked context.
+ *                      This it may not contain any chSysLockX() or chSysUnlockX() calls.
+ * @param[in] par       Pointer to a parameter for the callback function (may be NULL).
+ */
+static inline void aosPeriodicTimerSetLong(aos_periodictimer_t* ptimer, aos_longinterval_t* interval, vtfunc_t cb, void* par)
+{
+  chSysLock();
+  aosPeriodicTimerSetLongI(ptimer, interval, cb, par);
+  chSysUnlock();
+
+  return;
+}
+
+#endif /* _AMIROOS_TIMER_H_ */
+
+/** @} */
diff --git a/core/inc/aos_types.h b/core/inc/aos_types.h
new file mode 100644
index 0000000..4154884
--- /dev/null
+++ b/core/inc/aos_types.h
@@ -0,0 +1,44 @@
+/*
+AMiRo-OS is an operating system designed for the Autonomous Mini Robot (AMiRo) platform.
+Copyright (C) 2016..2018  Thomas Schöpping et al.
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @file    aos_types.h
+ * @brief   Data types used throughout AMiRo-OS
+ *
+ * @addtogroup aos_types
+ * @{
+ */
+
+#ifndef _AMIROOS_TYPES_H_
+#define _AMIROOS_TYPES_H_
+
+/**
+ * @brief   Error codes used in AMiRo-OS.
+ */
+typedef enum {
+  AOS_OK = 0,                 /**< No error, success. */
+  AOS_SUCCESS = 0,            /**< No error, success */
+  AOS_WARNING = 1,            /**< No error, but a warning occurred */
+  AOS_INVALID_ARGUMENTS = 2,  /**< No error, but given arguments are invalid */
+  AOS_ERROR = 0x80,           /**< An error occurred */
+  AOS_FAILURE = 0x80,         /**< An error occurred */
+} aos_status_t;
+
+#endif /* _AMIROOS_TYPES_H_ */
+
+/** @} */
diff --git a/core/inc/aos_unittest.h b/core/inc/aos_unittest.h
new file mode 100644
index 0000000..3900bac
--- /dev/null
+++ b/core/inc/aos_unittest.h
@@ -0,0 +1,117 @@
+/*
+AMiRo-OS is an operating system designed for the Autonomous Mini Robot (AMiRo) platform.
+Copyright (C) 2016..2018  Thomas Schöpping et al.
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @file    aos_unittest.h
+ * @brief   Unittest structures.
+ *
+ * @addtogroup aos_unittests
+ * @{
+ */
+
+#ifndef _AMIROOS_UNITTEST_H_
+#define _AMIROOS_UNITTEST_H_
+
+#include <aosconf.h>
+#if (AMIROOS_CFG_TESTS_ENABLE == true) || defined(__DOXYGEN__)
+#include <hal.h>
+#include <aos_shell.h>
+
+/*
+ * Forward declarations.
+ */
+typedef struct aos_unittest aos_unittest_t;
+typedef struct aos_utresult aos_utresult_t;
+
+/**
+ * @brief   Unit test interface function definition.
+ *
+ * @param[in] stream  The stream to use for printing messages.
+ * @param[in] ut      The object to run the test on.
+ *
+ * @return    A result containing the number of passed and failed tests.
+ */
+typedef aos_utresult_t (*aos_utfunction_t)(BaseSequentialStream* stream, aos_unittest_t* ut);
+
+/**
+ * @brief   Unit test result struct.
+ */
+struct aos_utresult {
+  /**
+   * @brief   Number of passed tests.
+   */
+  uint32_t passed;
+
+  /**
+   * @brief   Number of failed tests.
+   */
+  uint32_t failed;
+};
+
+/**
+ * @brief   Unit test definition struct.
+ */
+struct aos_unittest {
+  /**
+   * @brief   Name of the unit test.
+   */
+  const char* name;
+
+  /**
+   * @brief   Further information about the test.
+   */
+  const char* info;
+
+  /**
+   * @brief   Callback function to run that executes the unit test.
+   */
+  aos_utfunction_t testfunc;
+
+  /**
+   * @brief   Shell command to add to an shell command list.
+   */
+  aos_shellcommand_t shellcmd;
+
+  /**
+   * @brief   Further test specific data.
+   */
+  void* data;
+};
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+  uint32_t aosUtResultTotal(aos_utresult_t* result);
+  float aosUtResultRatio(aos_utresult_t* result);
+  void aosUtResultPrintSummary(BaseSequentialStream* stream, aos_utresult_t* result, char* heading);
+  void aosUtObjectInit(aos_unittest_t* ut, char* name, char* info, aos_utfunction_t func, void* data, char* shellname, aos_shellcmdcb_t shellcb);
+  aos_utresult_t aosUtRun(BaseSequentialStream* stream, aos_unittest_t* ut, char* note);
+  void aosUtPassed(BaseSequentialStream* stream, aos_utresult_t* result);
+  void aosUtPassedMsg(BaseSequentialStream* stream, aos_utresult_t* result, const char* fmt, ...);
+  void aosUtFailed(BaseSequentialStream* stream, aos_utresult_t* result);
+  void aosUtFailedMsg(BaseSequentialStream* stream, aos_utresult_t* result, const char* fmt, ...);
+  void aosUtInfoMsg(BaseSequentialStream* stream, const char* fmt, ...);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* AMIROOS_CFG_TESTS_ENABLE == true */
+
+#endif /* _AMIROOS_UNITTEST_H_ */
+
+/** @} */
diff --git a/core/src/aos_debug.c b/core/src/aos_debug.c
new file mode 100644
index 0000000..f4e5dbe
--- /dev/null
+++ b/core/src/aos_debug.c
@@ -0,0 +1,140 @@
+/*
+AMiRo-OS is an operating system designed for the Autonomous Mini Robot (AMiRo) platform.
+Copyright (C) 2016..2018  Thomas Schöpping et al.
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @file    aos_debug.c
+ * @brief   Functions necessary to print an error on system halt.
+ *
+ * @addtogroup aos_debug
+ * @{
+ */
+
+#include <aos_debug.h>
+
+#include <hal.h>
+
+/*
+ * System_halt
+ * ChibiOS error code (see chdebug.c)
+ *
+ *            - SV#1, misplaced @p chSysDisable().
+ *            - SV#2, misplaced @p chSysSuspend()
+ *            - SV#3, misplaced @p chSysEnable().
+ *            - SV#4, misplaced @p chSysLock().
+ *            - SV#5, misplaced @p chSysUnlock().
+ *            - SV#6, misplaced @p chSysLockFromIsr().
+ *            - SV#7, misplaced @p chSysUnlockFromIsr().
+ *            - SV#8, misplaced @p CH_IRQ_PROLOGUE().
+ *            - SV#9, misplaced @p CH_IRQ_EPILOGUE().
+ *            - SV#10, misplaced I-class function.
+ *            - SV#11, misplaced S-class function.
+ */
+
+#if ((CH_DBG_SYSTEM_STATE_CHECK == TRUE) && (HAL_USE_SERIAL == TRUE)) || defined(__DOXYGEN__)
+
+/**
+ * @brief   Actively waits for the serial driver to be empty.
+ */
+static inline void _serialWaitForEmpty(SerialDriver* sdp) {
+  while (!((sdp->usart->SR) & USART_SR_TC)) {
+    continue;
+  }
+  return;
+}
+
+/**
+ * @brief   Prints the specified string without suspending the thread.
+ *
+ * @param[in] str   The string to print.
+ *
+ * @return          The number of characters printed.
+ */
+static inline unsigned int _printString(SerialDriver* sdp, const char* str)
+{
+  unsigned int i = 0;
+  while (str[i] != '\0') {
+    sdp->usart->DR = str[i];
+    _serialWaitForEmpty(sdp);
+    ++i;
+  }
+  return i;
+}
+
+/**
+ * @brief   Prints the specified string to the given serial stream.
+ *
+ * @param[in] sdp       serial stream to print to
+ * @param[in] reason    string to print
+ */
+static void _printError(SerialDriver* sdp, const char* reason)
+{
+  if (sdp->state != SD_STOP && sdp->state != SD_READY) {
+    sd_lld_start(sdp, NULL);
+    sdp->state = SD_READY;
+  }
+  if (sdp->state == SD_READY) {
+    _printString(sdp, "\nSystem halt! error code / function name: ");
+    _printString(sdp, reason);
+    _printString(sdp, "\n");
+  }
+
+  return;
+}
+
+#endif /* ((CH_DBG_SYSTEM_STATE_CHECK == TRUE) && (HAL_USE_SERIAL == TRUE)) || defined(__DOXYGEN__) */
+
+/**
+ * @brief   Prints an error message.
+ *
+ * @param[in] reason  The string to print.
+ */
+void aosPrintHaltErrorCode(const char* reason)
+{
+#if (CH_DBG_SYSTEM_STATE_CHECK == TRUE) && (HAL_USE_SERIAL == TRUE)
+  #if STM32_SERIAL_USE_USART1
+  _printError(&SD1, reason);
+  #endif
+  #if STM32_SERIAL_USE_USART2
+  _printError(&SD2, reason);
+  #endif
+  #if STM32_SERIAL_USE_USART3
+  _printError(&SD3, reason);
+  #endif
+  #if STM32_SERIAL_USE_UART4
+  _printError(&SD4, reason);
+  #endif
+  #if STM32_SERIAL_USE_UART5
+  _printError(&SD5, reason);
+  #endif
+  #if STM32_SERIAL_USE_USART6
+  _printError(&SD6, reason);
+  #endif
+  #if STM32_SERIAL_USE_UART7
+  _printError(&SD7, reason);
+  #endif
+  #if STM32_SERIAL_USE_UART8
+  _printError(&SD8, reason);
+  #endif
+#else
+  (void)reason;
+#endif /* (CH_DBG_SYSTEM_STATE_CHECK == TRUE) && (HAL_USE_SERIAL == TRUE) */
+
+  return;
+}
+
+/** @} */
diff --git a/core/src/aos_iostream.c b/core/src/aos_iostream.c
new file mode 100644
index 0000000..548eae2
--- /dev/null
+++ b/core/src/aos_iostream.c
@@ -0,0 +1,388 @@
+/*
+AMiRo-OS is an operating system designed for the Autonomous Mini Robot (AMiRo) platform.
+Copyright (C) 2016..2018  Thomas Schöpping et al.
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @file    aos_iostream.c
+ * @brief   Stream and channel code.
+ * @details Implementation of the aos_ostrem and aos_iochannel.
+ *
+ * @addtogroup aos_stream
+ * @{
+ */
+
+#include <aos_iostream.h>
+
+#include <aos_debug.h>
+#include <chprintf.h>
+
+/**
+ * @brief   Implementation of the BaseAsynchronousChannel write() method (inherited from BaseSequentialStream).
+ */
+static size_t _channelwrite(void *instance, const uint8_t *bp, size_t n)
+{
+  if (((AosIOChannel*)instance)->flags & AOS_IOCHANNEL_OUTPUT_ENABLE) {
+    return streamWrite(((AosIOChannel*)instance)->asyncchannel, bp, n);
+  } else {
+    return 0;
+  }
+}
+
+/**
+ * @brief   Implementation of the BaseAsynchronousChannel read() method (inherited from BaseSequentialStream).
+ */
+static size_t _channelread(void *instance, uint8_t *bp, size_t n)
+{
+  if (((AosIOChannel*)instance)->flags & AOS_IOCHANNEL_INPUT_ENABLE) {
+    return streamRead(((AosIOChannel*)instance)->asyncchannel, bp, n);
+  } else {
+    return 0;
+  }
+}
+
+/**
+ * @brief   Implementation of the BaseAsynchronousChannel put() method (inherited from BaseSequentialStream).
+ */
+static msg_t _channelput(void *instance, uint8_t b)
+{
+  if (((AosIOChannel*)instance)->flags & AOS_IOCHANNEL_OUTPUT_ENABLE) {
+    return streamPut(((AosIOChannel*)instance)->asyncchannel, b);
+  } else {
+    return MSG_RESET;
+  }
+}
+
+/**
+ * @brief   Implementation of the BaseAsynchronousChannel get() method (inherited from BaseSequentialStream).
+ */
+static msg_t _channelget(void *instance)
+{
+  if (((AosIOChannel*)instance)->flags & AOS_IOCHANNEL_INPUT_ENABLE) {
+    return streamGet(((AosIOChannel*)instance)->asyncchannel);
+  } else {
+    return MSG_RESET;
+  }
+}
+
+/**
+ * @brief   Implementation of the BaseAsynchronousChannel putt() method.
+ */
+static msg_t _channelputt(void *instance, uint8_t b, sysinterval_t time)
+{
+  if (((AosIOChannel*)instance)->flags & AOS_IOCHANNEL_OUTPUT_ENABLE) {
+    return chnPutTimeout(((AosIOChannel*)instance)->asyncchannel, b, time);
+  } else {
+    return MSG_RESET;
+  }
+}
+
+/**
+ * @brief   Implementation of the BaseAsynchronousChannel gett() method.
+ */
+static msg_t _channelgett(void *instance, sysinterval_t time)
+{
+  if (((AosIOChannel*)instance)->flags & AOS_IOCHANNEL_INPUT_ENABLE) {
+    return chnGetTimeout(((AosIOChannel*)instance)->asyncchannel, time);
+  } else {
+    return MSG_RESET;
+  }
+}
+
+/**
+ * @brief   Implementation of the BaseAsynchronousChannel writet() method.
+ */
+static size_t _channelwritet(void *instance, const uint8_t *bp, size_t n, sysinterval_t time)
+{
+  if (((AosIOChannel*)instance)->flags & AOS_IOCHANNEL_OUTPUT_ENABLE) {
+    return chnWriteTimeout(((AosIOChannel*)instance)->asyncchannel, bp, n, time);
+  } else {
+    return 0;
+  }
+}
+
+/**
+ * @brief   Implementation of the BaseAsynchronousChannel readt() method.
+ */
+static size_t _channelreadt(void *instance, uint8_t *bp, size_t n, sysinterval_t time)
+{
+  if (((AosIOChannel*)instance)->flags & AOS_IOCHANNEL_INPUT_ENABLE) {
+    return chnReadTimeout(((AosIOChannel*)instance)->asyncchannel, bp, n, time);
+  } else {
+    return 0;
+  }
+}
+
+/**
+ * @brief   Implementation of the BaseAsynchronousChannel ctl() method.
+ */
+static msg_t _channelctl(void *instance, unsigned int operation, void *arg)
+{
+  if (((AosIOChannel*)instance)->flags & AOS_IOCHANNEL_OUTPUT_ENABLE) {
+    return chnControl(((AosIOChannel*)instance)->asyncchannel, operation, arg);
+  } else {
+    return MSG_OK;
+  }
+}
+
+/**
+ * @brief   Virtual methods table for all AosIOChannel objects.
+ */
+static const struct AosIOChannelVMT _channelvmt = {
+  (size_t) 0,
+  _channelwrite,
+  _channelread,
+  _channelput,
+  _channelget,
+  _channelputt,
+  _channelgett,
+  _channelwritet,
+  _channelreadt,
+  _channelctl,
+};
+
+/**
+ * @brief   Implementation of the BaseSequentialStream write() method.
+ */
+static size_t _streamwrite(void *instance, const uint8_t *bp, size_t n)
+{
+  aosDbgCheck(instance != NULL);
+
+  // local variables
+  AosIOChannel* channel = ((AosIOStream*)instance)->channel;
+  size_t bytes;
+  size_t maxbytes = 0;
+
+  // iterate through the list of channels
+  while (channel != NULL) {
+    bytes = streamWrite(channel, bp, n);
+    maxbytes = (bytes > maxbytes) ? bytes : maxbytes;
+    channel = channel->next;
+  }
+
+  return maxbytes;
+}
+
+/**
+ * @brief   Implementation of the BaseSequentialStream read() method.
+ */
+static size_t _stremread(void *instance, uint8_t *bp, size_t n)
+{
+  (void)instance;
+  (void)bp;
+  (void)n;
+
+  return 0;
+}
+
+/**
+ * @brief   Implementation of the BaseSequentialStream put() method.
+ */
+static msg_t _streamput(void *instance, uint8_t b)
+{
+  aosDbgCheck(instance != NULL);
+
+  // local variables
+  AosIOChannel* channel = ((AosIOStream*)instance)->channel;
+  msg_t ret = MSG_OK;
+
+  // iterate through the list of channels
+  while (channel != NULL) {
+    msg_t ret_ = streamPut(channel, b);
+    ret = (ret_ < ret) ? ret_ : ret;
+    channel = channel->next;
+  }
+
+  return ret;
+}
+
+/**
+ * @brief   Implementation of the BaseSequentialStream get() method.
+ */
+static msg_t _streamget(void *instance)
+{
+  (void)instance;
+
+  return 0;
+}
+
+/**
+ * @brief   Virtual methods table for all AosIOStream objects.
+ */
+static const struct AosIOStreamVMT _streamvmt = {
+  (size_t) 0,
+  _streamwrite,
+  _stremread,
+  _streamput,
+  _streamget,
+};
+
+/**
+ * @brief   Initializes an aos_iostream_t object.
+ *
+ * @param[in] stream    Th aos_iostream_t object to initialize.
+ */
+void aosIOStreamInit(AosIOStream* stream)
+{
+  aosDbgCheck(stream != NULL);
+
+  stream->vmt = &_streamvmt;
+  stream->channel = NULL;
+
+  return;
+}
+
+/**
+ * @brief   Initializes an aos_iostream_channel_t object.
+ *
+ * @param[in] channel       The aos_iostream_channel_t to initialize.
+ * @param[in] asyncchannel  The BaseAsynchronousChannel object to associate with te channel.
+ */
+void aosIOChannelInit(AosIOChannel *channel, BaseAsynchronousChannel *asyncchannel)
+{
+  aosDbgCheck(channel != NULL);
+  aosDbgCheck(asyncchannel != NULL);
+
+  channel->vmt = &_channelvmt;
+  channel->asyncchannel = asyncchannel;
+  channel->next = NULL;
+  channel->flags = 0;
+
+  return;
+}
+
+/**
+ * @brief   Adds a channel to a stream.
+ *
+ * @param[in] stream    The stream to be expanded.
+ * @param[in] channel   The channel to be added.
+ */
+void aosIOStreamAddChannel(AosIOStream *stream, AosIOChannel* channel)
+{
+  aosDbgCheck(stream != NULL);
+  aosDbgCheck(channel != NULL && channel->asyncchannel != NULL && channel->next == NULL && (channel->flags & AOS_IOCHANNEL_ATTACHED) == 0);
+
+  // prepend the new channel
+  chSysLock();
+  channel->flags |= AOS_IOCHANNEL_ATTACHED;
+  channel->next = stream->channel;
+  stream->channel = channel;
+  chSysUnlock();
+
+  return;
+}
+
+/**
+ * @brief   Removes a channel from a stream.
+ *
+ * @param[in] stream        The stream to remove the channel from.
+ * @param[in] asyncchannel  The BaseAsynchronousChannel to remove.
+ * @param[out] removed      Pointer to the removed aos_iostream_channel_t.
+ * @return
+ */
+aos_status_t aosIOStreamRemoveChannel(AosIOStream* stream, AosIOChannel* channel)
+{
+  aosDbgCheck(stream != NULL);
+  aosDbgCheck(channel != NULL);
+
+  // local variables
+  AosIOChannel* prev = NULL;
+  AosIOChannel* curr = stream->channel;
+
+  // iterate through the list and search for the specified channel
+  while (curr != NULL) {
+    // if the channel was found, remove it
+    if (curr == channel) {
+      chSysLock();
+      // special case: the first channel matches (prev is NULL)
+      if (prev == NULL) {
+        stream->channel = curr->next;
+      } else {
+        prev->next = curr->next;
+      }
+      curr->next = NULL;
+      curr->flags &= ~AOS_IOCHANNEL_ATTACHED;
+      chSysUnlock();
+      return AOS_SUCCESS;
+    }
+    // iterate to the next channel
+    else {
+      prev = curr;
+      curr = curr->next;
+    }
+  }
+
+  // if the channel was not found, return an error
+  return AOS_ERROR;
+}
+
+/**
+ * @brief   Enable input for a AosIOChannel.
+ *
+ * @param[in] channel   The AosIOChannel to enable as input.
+ */
+void aosIOChannelInputEnable(AosIOChannel* channel)
+{
+  aosDbgCheck(channel != NULL);
+
+  channel->flags |= AOS_IOCHANNEL_INPUT_ENABLE;
+
+  return;
+}
+
+/**
+ * @brief   Disable input for a AosIOChannel.
+ *
+ * @param[in] channel   The AosIOChannel to disable as input.
+ */
+void aosIOChannelInputDisable(AosIOChannel* channel)
+{
+  aosDbgCheck(channel != NULL);
+
+  channel->flags &= ~AOS_IOCHANNEL_INPUT_ENABLE;
+
+  return;
+}
+
+/**
+ * @brief   Enable output for a AosIOChannel.
+ *
+ * @param[in] channel   The AosIOChannel to enable as output.
+ */
+void aosIOChannelOutputEnable(AosIOChannel* channel)
+{
+  aosDbgCheck(channel != NULL);
+
+  channel->flags |= AOS_IOCHANNEL_OUTPUT_ENABLE;
+
+  return;
+}
+
+/**
+ * @brief   Disable output for a AosIOChannel.
+ *
+ * @param[in] channel   The AosIOChannel to disable as output.
+ */
+void aosIOChannelOutputDisable(AosIOChannel* channel)
+{
+  aosDbgCheck(channel != NULL);
+
+  channel->flags &= ~AOS_IOCHANNEL_OUTPUT_ENABLE;
+
+  return;
+}
+
+/** @} */
diff --git a/core/src/aos_main.cpp b/core/src/aos_main.cpp
new file mode 100644
index 0000000..68ab754
--- /dev/null
+++ b/core/src/aos_main.cpp
@@ -0,0 +1,1280 @@
+/*
+AMiRo-OS is an operating system designed for the Autonomous Mini Robot (AMiRo) platform.
+Copyright (C) 2016..2018  Thomas Schöpping et al.
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @file    aos_main.cpp
+ * @brief   Main function.
+ * @details Main function with SSSP and initialization,
+ *          extendable via hooks.
+ *
+ * @addtogroup aos_system
+ * @{
+ */
+
+#include <amiroos.h>
+#include <module.h>
+
+/*
+ * hook to add further includes
+ */
+#if defined(AMIROOS_CFG_MAIN_EXTRA_INCLUDE_HEADER)
+#include AMIROOS_CFG_MAIN_EXTRA_INCLUDE_HEADER
+#endif
+
+/**
+ * @brief   Event mask to identify I/O events.
+ */
+#define IOEVENT_MASK                            EVENT_MASK(0)
+
+/**
+ * @brief   Event mask to identify OS events.
+ */
+#define OSEVENT_MASK                            EVENT_MASK(1)
+
+/**
+ * @brief   Event mask to idetify CAN events.
+ */
+#define CANEVENT_MASK                           EVENT_MASK(2)
+
+/**
+ * @brief   Event mask to idetify timeout events.
+ */
+#define TIMEOUTEVENT_MASK                       EVENT_MASK(3)
+
+/**
+ * @brief   Event mask to idetify signal delay events.
+ */
+#define DELAYEVENT_MASK                         EVENT_MASK(4)
+
+/**
+ * @brief   CAN message identifier for initialization of the SSSP stack initialization sequence.
+ */
+#define SSSP_STACKINIT_CANMSGID_INIT            0x003
+
+/**
+ * @brief   CAN message identifier for transmitting module IDs during the SSSP stack initialization sequence.
+ */
+#define SSSP_STACKINIT_CANMSGID_MODULEID        0x002
+
+/**
+ * @brief   CAN message identifier for abortion of the SSSP stack initialization sequence.
+ */
+#define SSSP_STACKINIT_CANMSGID_ABORT           0x001
+
+/**
+ * @brief   CAN message identifier for calender synchronization message.
+ */
+#define CALENDERSYNC_CANMSGID                   0x004
+
+/**
+ * @brief   Listener object for I/O events.
+ */
+static event_listener_t _eventListenerIO;
+
+/**
+ * @brief   Listener object for OS events.
+ */
+static event_listener_t _eventListenerOS;
+
+#if defined(MODULE_HAL_PROGIF) || defined(__DOXYGEN__)
+/**
+ * @brief   I/O channel for the programmer interface.
+ */
+static AosIOChannel _stdiochannel;
+
+#if (AMIROOS_CFG_SHELL_ENABLE == true) || defined(__DOXYGEN__)
+/**
+ * @brief   I/O shell channel for the programmer interface.
+ */
+static AosShellChannel _stdshellchannel;
+#endif
+#endif
+
+/*
+ * hook to add further static variables
+ */
+#if defined(AMIROOS_CFG_MAIN_EXTRA_STATIC_VARIABLES)
+AMIROOS_CFG_MAIN_EXTRA_STATIC_VARIABLES
+#endif
+
+/**
+ * @brief   Prints an error message about an unexpected event.
+ *
+ * @param[in] mask    The event mask.
+ * @param[in] flags   The event flags.
+ */
+static inline void _unexpectedEventError(const eventmask_t mask, const eventflags_t flags)
+{
+#if (AMIROOS_CFG_DBG == true)
+  aosprintf("CTRL: unexpected/unknown event received. mask: 0x%08X; flags: 0x%08X\n", mask, flags);
+#else
+  (void)(mask);
+  (void)(flags);
+#endif
+  return;
+}
+
+/**
+ * @brief   Callback function to be used during SSSP stack initialization sequence.
+ *
+ * @param[in] par   A pointer to an @p event_source_t to be fired.
+ */
+static void _ssspTimerCallback(void* par)
+{
+  aosDbgCheck(par != NULL);
+
+  chSysLockFromISR();
+  chEvtBroadcastI((event_source_t*)par);
+  chSysUnlockFromISR();
+
+  return;
+}
+
+/**
+ * @brief   Helper function to serialize data.
+ *
+ * @param[out]  dst   Pointer to the output buffer.
+ * @param[in]   src   Data to be serialized.
+ * @param[in]   n     Number of bytes to serialize.
+ */
+inline void _serialize(uint8_t* dst, const uint64_t src, const uint8_t n)
+{
+  aosDbgCheck(dst != NULL);
+  aosDbgCheck(n > 0 && n <= 8);
+
+  for (uint8_t byte = 0; byte < n; ++byte) {
+    dst[byte] = (uint8_t)((src >> (byte * 8)) & 0xFF);
+  }
+
+  return;
+}
+
+/**
+ * @brief   Helper function to deserialize data.
+ *
+ * @param[in] src   Pointer to the buffer of data to be deserialzed.
+ * @param[in] n     Number of bytes to deserialize.
+ *
+ * @return    The deserialized 32 bit data.
+ */
+inline uint64_t _deserialize(uint8_t* src, const uint8_t n)
+{
+  aosDbgCheck(src != NULL);
+  aosDbgCheck(n > 0 && n <= 8);
+
+  uint64_t result = 0;
+  for (uint8_t byte = 0; byte < n; ++byte) {
+    result |= ((uint64_t)src[byte]) << (byte * 8);
+  }
+
+  return result;
+}
+
+/**
+ * @brief   Converter function to encode a TM value to a single unsigned 64 bit integer.
+ *
+ * @details Contents of the TM struct are mapped as follows:
+ *            bits  |63     62|61      53|52    50|49         26|25     22|21     17|16     12|11      6|5       0|
+ *            #bits |       2 |        9 |      3 |          24 |       4 |       5 |       5 |       6 |       6 |
+ *            value |   isdst |     yday |   wday |        year |     mon |    mday |    hour |     min |     sec |
+ *            range | special | [0, 365] | [0, 6] | [1900, ...] | [0, 11] | [1, 31] | [0, 23] | [0, 59] | [0, 61] |
+ *          The Daylight Saving Time Flag (isdsst) is encoded as follows:
+ *            DST not in effect         -> 0
+ *            DST in effect             -> 1
+ *            no information available  -> 2
+ *
+ * @param[in] src   Pointer to the TM struct to encode.
+ *
+ * @return  An unsigned 64 bit integer, which holds the encoded time value.
+ */
+inline uint64_t _TM2U64(struct tm* src)
+{
+  aosDbgCheck(src != NULL);
+
+  return (((uint64_t)(src->tm_sec  & 0x0000003F) << (0))               |
+          ((uint64_t)(src->tm_min  & 0x0000003F) << (6))               |
+          ((uint64_t)(src->tm_hour & 0x0000001F) << (12))              |
+          ((uint64_t)(src->tm_mday & 0x0000001F) << (17))              |
+          ((uint64_t)(src->tm_mon  & 0x0000000F) << (22))              |
+          ((uint64_t)(src->tm_year & 0x00FFFFFF) << (26))              |
+          ((uint64_t)(src->tm_wday & 0x00000007) << (50))              |
+          ((uint64_t)(src->tm_yday & 0x000001FF) << (53))              |
+          ((uint64_t)((src->tm_isdst == 0) ? 0 : (src->tm_isdst > 0) ? 1 : 2) << (62)));
+}
+
+/**
+ * @brief   Converter functiomn to retrieve the encoded TM value from an unsigned 64 bit integer.
+ *
+ * @details For information on the encoding, please refer to @p _TM2U64 function.
+ *
+ * @param[out] dst  The TM struct to fill with the decoded values.
+ * @param[in]  src  Unsigned 64 bit integer holding the encoded TM value.
+ */
+inline void _U642TM(struct tm* dst, const uint64_t src)
+{
+  aosDbgCheck(dst != NULL);
+
+  dst->tm_sec  = (src >> 0)  & 0x0000003F;
+  dst->tm_min  = (src >> 6)  & 0x0000003F;
+  dst->tm_hour = (src >> 12) & 0x0000001F;
+  dst->tm_mday = (src >> 17) & 0x0000001F;
+  dst->tm_mon  = (src >> 22) & 0x0000000F;
+  dst->tm_year = (src >> 26) & 0x00FFFFFF;
+  dst->tm_wday = (src >> 50) & 0x00000007;
+  dst->tm_yday = (src >> 53) & 0x000001FF;
+  dst->tm_isdst = (((src >> 62) & 0x03) == 0) ? 0 : (((src >> 62) & 0x03) > 0) ? 1 : -1;
+
+  return;
+}
+
+/**
+ * @brief   Implementation of the SSSP module stack initialization sequence (startup phase 3).
+ *
+ * @return Shutdown value.
+ * @retval AOS_SHUTDOWN_NONE      No shutdown signal received
+ * @retval AOS_SHUTDOWN_PASSIVE   Shutdown signal received.
+ */
+aos_shutdown_t _ssspModuleStackInitialization(void)
+{
+  // local types
+  /**
+   * @brief   States for the internal state machine to implement SSSP startup stage 3.
+   */
+  typedef enum {
+    STAGE_3_1,                  /**< Initiation of SSSP startup stage 3. */
+    STAGE_3_2,                  /**< Starting the sequence and broadcasting the first ID. */
+    STAGE_3_3_WAITFORFIRSTID,   /**< Waiting for first ID after initiation. */
+    STAGE_3_3_WAITFORIDORSIG,   /**< Waiting for next ID or activation of neighbor signal. */
+    STAGE_3_3_WAITFORID,        /**< Waiting for next ID (after the module has set its own ID). */
+    STAGE_3_4_FINISH,           /**< Successful finish of stage 3. */
+    STAGE_3_4_ABORT_ACTIVE,     /**< Aborting stage 3 (active). */
+    STAGE_3_4_ABORT,            /**< Aborting stage 3 (passive). */
+  } sssp_modulestackinitstage_t;
+
+  typedef struct {
+    bool loop     : 1;
+    bool wfe      : 1;
+    bool wfe_next : 1;
+  } flags_t;
+
+  // local variables
+  aos_shutdown_t shutdown = AOS_SHUTDOWN_NONE;
+  sssp_modulestackinitstage_t stage = STAGE_3_1;
+  eventmask_t eventmask = 0;
+  eventflags_t ioflags;
+  event_source_t eventSourceTimeout;
+  event_source_t eventSourceDelay;
+  event_listener_t eventListenerTimeout;
+  event_listener_t eventListenerDelay;
+  event_listener_t eventListenerCan;
+  virtual_timer_t timerTimeout;
+  virtual_timer_t timerDelay;
+  CANTxFrame canTxFrame;
+  CANRxFrame canRxFrame;
+#if (AMIROOS_CFG_SSSP_STACK_START != true) || (AMIROOS_CFG_DBG == true)
+  aos_ssspmoduleid_t lastid = 0;
+#endif
+  flags_t flags;
+
+  // initialize local varibles
+  chEvtObjectInit(&eventSourceTimeout);
+  chEvtObjectInit(&eventSourceDelay);
+  chVTObjectInit(&timerTimeout);
+  chVTObjectInit(&timerDelay);
+  canTxFrame.RTR = CAN_RTR_DATA;
+  canTxFrame.IDE = CAN_IDE_STD;
+  flags.loop = true;
+  flags.wfe = false; // do not wait for events in the initial iteration of the FSM loop
+  flags.wfe_next = true;
+
+  // initialize system variables
+  aos.sssp.stage = AOS_SSSP_STARTUP_3_1;
+  aos.sssp.moduleId = 0;
+
+  // listen to events (timout, delay, CAN receive)
+  chEvtRegisterMask(&eventSourceTimeout, &eventListenerTimeout, TIMEOUTEVENT_MASK);
+  chEvtRegisterMask(&eventSourceDelay, &eventListenerDelay, DELAYEVENT_MASK);
+  chEvtRegisterMask(&MODULE_HAL_CAN.rxfull_event, &eventListenerCan, CANEVENT_MASK);
+
+  /*
+   * FSM in a loop.
+   *
+   * This is a fully event-based FSM for the module stack initialization
+   * sequence, defined by SSSP as startup stage 3. There are five different
+   * events that can occur at this point:
+   *  I/O events: The input level of an input pin has changed. Such events must
+   *              be handled differently depending on the current state. Most
+   *              of the time, however, such events can be ignored.
+   *  OS events:  Such events are only available after this stage completed and
+   *              thus should never occur. However, there is an optional hook
+   *              to handle such events, nevertheless.
+   *  CAN events: At least one CAN message was received. Note that this event
+   *              will only fire again if all input buffers have been cleared.
+   *  timeouts:   If some module does not support the sequence of there is any
+   *              issue, such a case is detected via timeouts and must be
+   *              handled accordingly (see abort state). In some cases, it is
+   *              possible that a timeout event occurres 'simultaneously' with
+   *              some other event. This can be caused by several timing issues
+   *              and is a valid situation. As a result, any other events
+   *              should be handled before the timeout event. If the other
+   *              events are expected and valid, this implementation requires
+   *              the timeout event flag to be cleared explicitely. Otherwise
+   *              it is evaluated at the end of each iteration of the loop.
+   *  delays:     Depending on the current state, delays are required by SSSP
+   *              for timing of the sequential activation of signals.
+   */
+  aosDbgPrintf("SSSP stack initialization sequence:\n");
+  while (flags.loop) {
+#if (AMIROOS_CFG_DBG == true)
+    switch (stage) {
+      case STAGE_3_1:
+        aosDbgPrintf(">>> 3-1\n");
+        break;
+      case STAGE_3_2:
+        aosDbgPrintf(">>> 3-2\n");
+        break;
+      case STAGE_3_3_WAITFORFIRSTID:
+        aosDbgPrintf(">>> 3-3 (1st ID)\n");
+        break;
+      case STAGE_3_3_WAITFORIDORSIG:
+        aosDbgPrintf(">>> 3-3 (ID/sig)\n");
+        break;
+      case STAGE_3_3_WAITFORID:
+        aosDbgPrintf(">>> 3-3 (ID)\n");
+        break;
+      case STAGE_3_4_FINISH:
+        aosDbgPrintf(">>> 3-4 (finish)\n");
+        break;
+      case STAGE_3_4_ABORT_ACTIVE:
+        aosDbgPrintf(">>> 3-4 (active abort)\n");
+        break;
+      case STAGE_3_4_ABORT:
+        aosDbgPrintf(">>> 3-4 (abort)\n");
+        break;
+    }
+#endif
+
+    // reset wfe flag for the next iteration
+    flags.wfe_next = true;
+
+    // waiting for events may be skipped
+    if (flags.wfe) {
+      // wait for any event to occur
+      aosDbgPrintf("WFE...");
+      eventmask = chEvtWaitAnyTimeout(ALL_EVENTS, chTimeUS2I(AOS_SYSTEM_SSSP_TIMEOUT));
+      aosDbgPrintf("\t0x%08X", eventmask);
+    } else {
+      aosDbgPrintf("WFE skipped");
+    }
+    aos_timestamp_t uptime;
+    aosSysGetUptime(&uptime);
+    aosDbgPrintf("\t%04ums\n", (uint32_t)(uptime / 1000));
+
+    /*
+     * execute some general tasks and high priority events
+     */
+    // no event occurred at all
+    if ((flags.wfe) && (eventmask == 0)) {
+      aosDbgPrintf("ERR: no evt\n");
+      // enforce timeout event
+      chEvtBroadcast(&eventSourceTimeout);
+      continue;
+    }
+    // if an IO event occurred
+    if (eventmask & _eventListenerIO.events) {
+      ioflags = chEvtGetAndClearFlags(&_eventListenerIO);
+      aosDbgPrintf("INFO: IO evt (0x%08X)\n", ioflags);
+      // a power-down event occurred
+      if (ioflags & MODULE_SSSP_EVENTFLAGS_PD) {
+        aosDbgPrintf("PD evt\n");
+        // deactivate S and UP
+        apalControlGpioSet(&moduleSsspGpioSync, APAL_GPIO_OFF);
+  #if (AMIROOS_CFG_SSSP_STACK_END != true)
+        apalControlGpioSet(&moduleSsspGpioUp, APAL_GPIO_OFF);
+  #endif
+        // set shutdown flag and exit the loop
+        shutdown = AOS_SHUTDOWN_PASSIVE;
+        break;
+      }
+      // the S signal was deactivated
+      if (ioflags & MODULE_SSSP_EVENTFLAGS_SYNC) {
+        apalControlGpioState_t sstate;
+        apalControlGpioGet(&moduleSsspGpioSync, &sstate);
+        if (sstate == APAL_GPIO_OFF) {
+          aosDbgPrintf("-S evt\n");
+          // either finish or abort
+          if ((stage == STAGE_3_3_WAITFORID) && (aos.sssp.moduleId != 0)) {
+            stage = STAGE_3_4_FINISH;
+          } else if (stage != STAGE_3_4_ABORT) {
+            stage = STAGE_3_4_ABORT_ACTIVE;
+          }
+        }
+      }
+    }
+    // an OS event occurred
+    if (eventmask & _eventListenerOS.events) {
+      aosDbgPrintf("WARN: OS evt\n");
+      // get the flags
+      eventflags_t oseventflags = chEvtGetAndClearFlags(&_eventListenerOS);
+      // there should be no OS events at this point
+#ifdef MODULE_SSSP_STARTUP_3_OSEVENT_HOOK
+      MODULE_SSSP_STARTUP_3_OSEVENT_HOOK(eventmask, eventflags);
+#else
+      _unexpectedEventError(eventmask, oseventflags);
+#endif
+    }
+    // if a CAN event occurred
+    if ((eventmask & eventListenerCan.events)) {
+      // fetch message
+      if (flags.wfe) {
+        canReceiveTimeout(&MODULE_HAL_CAN, CAN_ANY_MAILBOX, &canRxFrame, TIME_IMMEDIATE);
+        aosDbgPrintf("CAN <- 0x%03X\n", canRxFrame.SID);
+      }
+      // identify and handle abort messgaes
+      if (canRxFrame.SID == SSSP_STACKINIT_CANMSGID_ABORT) {
+        stage = STAGE_3_4_ABORT;
+      }
+      // warn if a unexpected message was received
+      else if ((canRxFrame.SID != SSSP_STACKINIT_CANMSGID_INIT) &&
+               (canRxFrame.SID != SSSP_STACKINIT_CANMSGID_MODULEID)) {
+        aosDbgPrintf("WARN: unknown msg\n");
+      }
+      // any further pending messages are fetched at the end of the loop
+    }
+    // if a timeout event occurred
+    if (eventmask & eventListenerTimeout.events) {
+      // is handled at the end of the loop (or must be cleared by FSM)
+    }
+    // if a delay event occurred
+    if (eventmask & eventListenerDelay.events) {
+      // is handled by FSM
+    }
+
+    /*
+     * this is the actual FSM
+     */
+    switch (stage) {
+      case STAGE_3_1:
+      {
+        aos.sssp.stage = AOS_SSSP_STARTUP_3_1;
+
+        // there was no event at all (skipped wfe)
+        if (eventmask == 0 && flags.wfe == false) {
+#if (AMIROOS_CFG_SSSP_MASTER == true)
+          // initialize the stage by transmitting an according CAN message
+          aosDbgPrintf("CAN -> init\n");
+          canTxFrame.DLC = 0;
+          canTxFrame.SID = SSSP_STACKINIT_CANMSGID_INIT;
+          if (canTransmitTimeout(&MODULE_HAL_CAN, CAN_ANY_MAILBOX, &canTxFrame, TIME_IMMEDIATE) != MSG_OK) {
+            chEvtBroadcast(&eventSourceTimeout);
+            break;
+          }
+          // activate S
+          aosDbgPrintf("S+\n");
+          apalControlGpioSet(&moduleSsspGpioSync, APAL_GPIO_ON);
+#if (AMIROOS_CFG_SSSP_STACK_START == true)
+          // proceed immediately
+          stage = STAGE_3_2;
+          flags.wfe_next = false;
+#else
+          // set the timeout timer
+          chVTSet(&timerTimeout, chTimeUS2I(AOS_SYSTEM_SSSP_TIMEOUT), _ssspTimerCallback, &eventSourceTimeout);
+          // proceed
+          stage = STAGE_3_3_WAITFORFIRSTID;
+#endif
+#else
+          // set the timeout timer
+          chVTSet(&timerTimeout, chTimeUS2I(AOS_SYSTEM_SSSP_TIMEOUT), _ssspTimerCallback, &eventSourceTimeout);
+#endif
+        }
+
+#if (AMIROOS_CFG_SSSP_MASTER != true)
+        // a CAN message was received
+        else if (eventmask & eventListenerCan.events) {
+          // if an initiation message was received
+          if (canRxFrame.DLC == 0 &&
+              canRxFrame.RTR == CAN_RTR_DATA &&
+              canRxFrame.IDE == CAN_IDE_STD &&
+              canRxFrame.SID == SSSP_STACKINIT_CANMSGID_INIT) {
+            aosDbgPrintf("init msg\n");
+            // reset the timeout timer and clear pending flags
+            chVTReset(&timerTimeout);
+            chEvtWaitAnyTimeout(eventListenerTimeout.events, TIME_IMMEDIATE);
+            eventmask &= ~(eventListenerTimeout.events);
+            // activate S
+            aosDbgPrintf("S+\n");
+            apalControlGpioSet(&moduleSsspGpioSync, APAL_GPIO_ON);
+#if (AMIROOS_CFG_SSSP_STACK_START == true)
+            // proceed
+            stage = STAGE_3_2;
+            flags.wfe_next = false;
+#else
+            // set the timeout timer
+            chVTSet(&timerTimeout, chTimeUS2I(AOS_SYSTEM_SSSP_TIMEOUT), _ssspTimerCallback, &eventSourceTimeout);
+            // proceed
+            stage = STAGE_3_3_WAITFORFIRSTID;
+#endif
+          }
+        }
+#endif
+
+        break;
+      } /* end of STAGE_3_1 */
+
+      case STAGE_3_2:
+      {
+#if (AMIROOS_CFG_SSSP_STACK_START == true)
+        aos.sssp.stage = AOS_SSSP_STARTUP_3_2;
+
+        // if this stage was just entered
+        if (flags.wfe == false) {
+          // set the module ID
+          aos.sssp.moduleId = 1;
+          // broadcast module ID
+          aosDbgPrintf("CAN -> ID (%u)\n", aos.sssp.moduleId);
+          canTxFrame.DLC = 4;
+          canTxFrame.SID = SSSP_STACKINIT_CANMSGID_MODULEID;
+          _serialize(canTxFrame.data8, aos.sssp.moduleId, 4);
+          if (canTransmitTimeout(&MODULE_HAL_CAN, CAN_ANY_MAILBOX, &canTxFrame, TIME_IMMEDIATE) != MSG_OK) {
+            chEvtBroadcast(&eventSourceTimeout);
+            break;
+          }
+#if (AMIROOS_CFG_SSSP_STACK_START != true) || (AMIROOS_CFG_DBG == true)
+          lastid = aos.sssp.moduleId;
+#endif
+#if (AMIROOS_CFG_SSSP_STACK_END == true)
+          // sequence is already over
+          // deactivate S
+          aosDbgPrintf("S-\n");
+          apalControlGpioSet(&moduleSsspGpioSync, APAL_GPIO_OFF);
+          // proceed
+          stage = STAGE_3_3_WAITFORID;
+#else
+          // set the delay timer so the UP signal is activated later
+          chVTSet(&timerDelay, chTimeUS2I(AMIROOS_CFG_SSSP_SIGNALDELAY), _ssspTimerCallback, &eventSourceDelay);
+#endif
+        }
+
+        // if a delay event occurred
+        if (eventmask & eventListenerDelay.events) {
+          // activate UP
+          aosDbgPrintf("UP+\n");
+          apalControlGpioSet(&moduleSsspGpioUp, APAL_GPIO_ON);
+          // deactivate S
+          aosDbgPrintf("S-\n");
+          apalControlGpioSet(&moduleSsspGpioSync, APAL_GPIO_OFF);
+          // explicitely clear timeout event flag
+          chEvtWaitAnyTimeout(eventListenerTimeout.events, TIME_IMMEDIATE);
+          eventmask &= ~(eventListenerTimeout.events);
+          // proceed
+          stage = STAGE_3_3_WAITFORID;
+        }
+#endif
+
+        break;
+      } /* end of STAGE_3_2 */
+
+      case STAGE_3_3_WAITFORFIRSTID:
+      {
+#if (AMIROOS_CFG_SSSP_STACK_START != true)
+        aos.sssp.stage = AOS_SSSP_STARTUP_3_3;
+
+        // a CAN message was received
+        if (eventmask & eventListenerCan.events) {
+          // if an ID message was received
+          if (canRxFrame.DLC == 4 &&
+              canRxFrame.RTR == CAN_RTR_DATA &&
+              canRxFrame.IDE == CAN_IDE_STD &&
+              canRxFrame.SID == SSSP_STACKINIT_CANMSGID_MODULEID) {
+            aosDbgPrintf("ID (%u)\n", (uint32_t)_deserialize(canRxFrame.data8, 4));
+            // validate received ID
+            if (lastid < _deserialize(canRxFrame.data8, 4)) {
+              // store received ID
+              lastid = _deserialize(canRxFrame.data8, 4);
+              // restart timeout timer
+              chVTSet(&timerTimeout, chTimeUS2I(AOS_SYSTEM_SSSP_TIMEOUT), _ssspTimerCallback, &eventSourceTimeout);
+              // proceed
+              stage = STAGE_3_3_WAITFORIDORSIG;
+            } else {
+              aosDbgPrintf("ERR: invalid ID\n");
+              // abort
+              stage = STAGE_3_4_ABORT_ACTIVE;
+              flags.wfe_next = false;
+            }
+            // explicitely clear timeout event flag
+            chEvtWaitAnyTimeout(eventListenerTimeout.events, TIME_IMMEDIATE);
+            eventmask &= ~(eventListenerTimeout.events);
+          }
+        }
+#endif
+        break;
+      } /* end of STAGE_3_3_WAITFORFIRSTID */
+
+      case STAGE_3_3_WAITFORIDORSIG:
+      {
+#if (AMIROOS_CFG_SSSP_STACK_START != true)
+        aos.sssp.stage = AOS_SSSP_STARTUP_3_3;
+
+        // a CAN message was received
+        if (eventmask & eventListenerCan.events) {
+          // if an ID message was received
+          if (canRxFrame.DLC == 4 &&
+              canRxFrame.RTR == CAN_RTR_DATA &&
+              canRxFrame.IDE == CAN_IDE_STD &&
+              canRxFrame.SID == SSSP_STACKINIT_CANMSGID_MODULEID) {
+            aosDbgPrintf("ID (%u)\n", (uint32_t)_deserialize(canRxFrame.data8, 4));
+            // validate received ID
+            if (lastid < _deserialize(canRxFrame.data8, 4)) {
+              // store received ID
+              lastid = _deserialize(canRxFrame.data8, 4);
+              // restart timeout timer
+              chVTSet(&timerTimeout, chTimeUS2I(AOS_SYSTEM_SSSP_TIMEOUT), _ssspTimerCallback, &eventSourceTimeout);
+            } else {
+              aosDbgPrintf("ERR: invalid ID\n");
+              // abort
+              stage = STAGE_3_4_ABORT_ACTIVE;
+              flags.wfe_next = false;
+            }
+            // explicitely clear timeout event flag
+            chEvtWaitAnyTimeout(eventListenerTimeout.events, TIME_IMMEDIATE);
+            eventmask &= ~(eventListenerTimeout.events);
+          }
+        }
+
+        // if an IO event was received (DN signal)
+        if ((eventmask & _eventListenerIO.events) && (ioflags & MODULE_SSSP_EVENTFLAGS_DN)) {
+          aosDbgPrintf("DN <-\n");
+          // reset timeout timer
+          chVTReset(&timerTimeout);
+          chEvtWaitAnyTimeout(eventListenerTimeout.events, TIME_IMMEDIATE);
+          eventmask &= ~(eventListenerTimeout.events);
+          // increment and broadcast ID
+          aos.sssp.moduleId = lastid + 1;
+          aosDbgPrintf("CAN -> ID (%u)\n", aos.sssp.moduleId);
+          canTxFrame.DLC = 4;
+          canTxFrame.SID = SSSP_STACKINIT_CANMSGID_MODULEID;
+          _serialize(canTxFrame.data8, aos.sssp.moduleId, 4);
+          if (canTransmitTimeout(&MODULE_HAL_CAN, CAN_ANY_MAILBOX, &canTxFrame, TIME_IMMEDIATE) != MSG_OK) {
+            chEvtBroadcast(&eventSourceTimeout);
+            break;
+          }
+          // set delay timer
+          chVTSet(&timerDelay, chTimeUS2I(AMIROOS_CFG_SSSP_SIGNALDELAY), _ssspTimerCallback, &eventSourceDelay);
+        }
+
+        // if a delay event occurred
+        if (eventmask & eventListenerDelay.events) {
+#if (AMIROOS_CFG_SSSP_STACK_END != true)
+          // activate UP
+          aosDbgPrintf("UP+\n");
+          apalControlGpioSet(&moduleSsspGpioUp, APAL_GPIO_ON);
+#endif
+          // deactivate S
+          aosDbgPrintf("S-\n");
+          apalControlGpioSet(&moduleSsspGpioSync, APAL_GPIO_OFF);
+          // reset the timeout timer
+          chVTSet(&timerTimeout, chTimeUS2I(AOS_SYSTEM_SSSP_TIMEOUT), _ssspTimerCallback, &eventSourceTimeout);
+          chEvtWaitAnyTimeout(eventListenerTimeout.events, TIME_IMMEDIATE);
+          eventmask &= ~(eventListenerTimeout.events);
+          // proceed
+          stage = STAGE_3_3_WAITFORID;
+        }
+#endif
+
+        break;
+      } /* end of STAGE_3_3_WAITFORIDORSIG */
+
+      case STAGE_3_3_WAITFORID:
+      {
+        aos.sssp.stage = AOS_SSSP_STARTUP_3_3;
+
+#if (AMIROOS_CFG_SSSP_STACK_END != true)
+        // a CAN message was received
+        if (eventmask & eventListenerCan.events) {
+          // if an ID message was received
+          if (canRxFrame.DLC == 4 &&
+              canRxFrame.RTR == CAN_RTR_DATA &&
+              canRxFrame.IDE == CAN_IDE_STD &&
+              canRxFrame.SID == SSSP_STACKINIT_CANMSGID_MODULEID) {
+#if (AMIROOS_CFG_SSSP_STACK_START != true) || (AMIROOS_CFG_DBG == true)
+            // Plausibility of the received ID is not checked at this point but is done by other modules still in a previous stage.
+            lastid = _deserialize(canRxFrame.data8, 4);
+            aosDbgPrintf("ID (%u)\n", lastid);
+#endif
+            // restart timeout timer
+            chVTSet(&timerTimeout, chTimeUS2I(AOS_SYSTEM_SSSP_TIMEOUT), _ssspTimerCallback, &eventSourceTimeout);
+            chEvtWaitAnyTimeout(eventListenerTimeout.events, TIME_IMMEDIATE);
+            eventmask &= ~(eventListenerTimeout.events);
+          }
+        }
+#endif
+
+        break;
+      } /* end of STAGE_3_3_WAITFORID */
+
+      case STAGE_3_4_FINISH:
+      {
+        aos.sssp.stage = AOS_SSSP_STARTUP_3_4;
+
+        // if an IO event was received (S signal)
+        if ((eventmask & _eventListenerIO.events) && (ioflags & MODULE_SSSP_EVENTFLAGS_SYNC)) {
+          // reset the timeout timer
+          chVTReset(&timerTimeout);
+          chEvtWaitAnyTimeout(eventListenerTimeout.events, TIME_IMMEDIATE);
+          eventmask &= ~(eventListenerTimeout.events);
+          //set the delay timer
+          chVTSet(&timerDelay, chTimeUS2I(AOS_SYSTEM_SSSP_TIMEOUT), _ssspTimerCallback, &eventSourceDelay);
+        }
+
+        // if a CAN event was received
+        if (eventmask & eventListenerCan.events) {
+          // if an abort message was received
+          if (canRxFrame.SID == SSSP_STACKINIT_CANMSGID_ABORT) {
+            aosDbgPrintf("abort msg\n");
+            // reset the delay timer
+            chVTReset(&timerDelay);
+            chEvtWaitAnyTimeout(eventListenerDelay.events, TIME_IMMEDIATE);
+            eventmask &= ~(eventListenerDelay.events);
+            // proceed
+            stage = STAGE_3_4_ABORT;
+          }
+        }
+
+        // if a delay timer event occurred
+        if (eventmask & eventListenerDelay.events) {
+          aosDbgPrintf("sequence sucessful\n");
+          // sequence finished sucessfully
+          flags.loop = false;
+        }
+
+        break;
+      } /* end of STAGE_3_4_FINISH */
+
+      case STAGE_3_4_ABORT_ACTIVE:
+      {
+        aos.sssp.stage = AOS_SSSP_STARTUP_3_4;
+
+        // emit abort message
+        canTxFrame.DLC = 0;
+        canTxFrame.SID = SSSP_STACKINIT_CANMSGID_ABORT;
+        canTransmitTimeout(&MODULE_HAL_CAN, CAN_ANY_MAILBOX, &canTxFrame, TIME_INFINITE);
+        aosDbgPrintf("CAN -> abort\n");
+        // clear timeout flag
+        eventmask &= ~(eventListenerTimeout.events);
+        // proceed immediately
+        stage = STAGE_3_4_ABORT;
+        flags.wfe_next = false;
+        break;
+      } /* end of STAGE_3_4_ABORT_ACTIVE */
+
+      case STAGE_3_4_ABORT:
+      {
+        aos.sssp.stage = AOS_SSSP_STARTUP_3_4;
+
+        // deactivate S
+        aosDbgPrintf("S-\n");
+        apalControlGpioSet(&moduleSsspGpioSync, APAL_GPIO_OFF);
+        // invalidate module ID
+        aos.sssp.moduleId = 0;
+
+        // if an IO event was received (S signal)
+        if ((eventmask & _eventListenerIO.events) && (ioflags & MODULE_SSSP_EVENTFLAGS_SYNC)) {
+          aosDbgPrintf("sequence aborted\n");
+          // exit the sequence
+          flags.loop = false;
+        }
+
+        break;
+      } /* end of STAGE_3_4_ABORT */
+    }
+
+    // fetch pending CAN message (if any)
+    if ((eventmask & eventListenerCan.events) && (canReceiveTimeout(&MODULE_HAL_CAN, CAN_ANY_MAILBOX, &canRxFrame, TIME_IMMEDIATE) == MSG_OK)) {
+      aosDbgPrintf("CAN <- 0x%03X\n", canRxFrame.SID);
+      flags.wfe_next = false;
+    }
+
+    // handle unhandled timeout events
+    if (eventmask & eventListenerTimeout.events) {
+      aosDbgPrintf("ERR: timeout evt\n");
+      // abort
+      flags.wfe_next = false;
+      stage = STAGE_3_4_ABORT_ACTIVE;
+    }
+
+    // apply wfe value for next iteration
+    flags.wfe = flags.wfe_next;
+  } /* end of FSM loop */
+  aosDbgPrintf("\n");
+
+  // unregister all events (timeout, delay, CAN receive)
+  chEvtUnregister(&eventSourceTimeout, &eventListenerTimeout);
+  chEvtUnregister(&eventSourceDelay, &eventListenerDelay);
+  chEvtUnregister(&MODULE_HAL_CAN.rxfull_event, &eventListenerCan);
+  // clear any pending events (timeout, delay, CAN receive)
+  chEvtWaitAllTimeout(TIMEOUTEVENT_MASK | DELAYEVENT_MASK | CANEVENT_MASK, TIME_IMMEDIATE);
+
+  // reset all control signals
+#if (AMIROOS_CFG_SSSP_STACK_END != true)
+  apalControlGpioSet(&moduleSsspGpioUp, APAL_GPIO_OFF);
+#endif
+  apalControlGpioSet(&moduleSsspGpioSync, APAL_GPIO_OFF);
+
+  return shutdown;
+}
+
+/**
+ * @brief   Application entry point.
+ */
+int main(void)
+{
+  // local variables
+  eventmask_t eventmask = 0;
+  eventflags_t eventflags = 0;
+  aos_shutdown_t shutdown = AOS_SHUTDOWN_NONE;
+#if defined(AMIROOS_CFG_MAIN_EXTRA_THREAD_VARIABLES)
+  AMIROOS_CFG_MAIN_EXTRA_THREAD_VARIABLES
+#endif
+
+  /*
+   * ##########################################################################
+   * # system initialization                                                  #
+   * ##########################################################################
+   */
+
+#if defined(AMIROOS_CFG_MAIN_INIT_HOOK_0)
+#if defined(AMIROOS_CFG_MAIN_INIT_HOOK_0_ARGS)
+  AMIROOS_CFG_MAIN_INIT_HOOK_0(AMIROOS_CFG_MAIN_INIT_HOOK_0_ARGS);
+#else
+  AMIROOS_CFG_MAIN_INIT_HOOK_0();
+#endif
+#endif
+
+  /* hardware, kernel, and operating system initialization */
+  // ChibiOS/HAL and custom hal additions (if any)
+  halInit();
+#ifdef MODULE_INIT_HAL_EXTRA
+  MODULE_INIT_HAL_EXTRA();
+#endif
+
+#if defined(AMIROOS_CFG_MAIN_INIT_HOOK_1)
+#if defined(AMIROOS_CFG_MAIN_INIT_HOOK_1_ARGS)
+  AMIROOS_CFG_MAIN_INIT_HOOK_1(AMIROOS_CFG_MAIN_INIT_HOOK_1_ARGS);
+#else
+  AMIROOS_CFG_MAIN_INIT_HOOK_1();
+#endif
+#endif
+
+  // ChibiOS/RT kernel and custom kernel additions (if any)
+  chSysInit();
+#ifdef MODULE_INIT_KERNEL_EXTRA
+  MODULE_INIT_KERNEL_EXTRA();
+#endif
+
+#if defined(AMIROOS_CFG_MAIN_INIT_HOOK_2)
+#if defined(AMIROOS_CFG_MAIN_INIT_HOOK_2_ARGS)
+  AMIROOS_CFG_MAIN_INIT_HOOK_2(AMIROOS_CFG_MAIN_INIT_HOOK_2_ARGS);
+#else
+  AMIROOS_CFG_MAIN_INIT_HOOK_2();
+#endif
+#endif
+
+  // AMiRo-OS and custom OS additions (if any)
+#if (AMIROOS_CFG_SHELL_ENABLE == true)
+  aosSysInit(moduleShellPrompt);
+#else
+  aosSysInit();
+#endif
+#ifdef MODULE_INIT_OS_EXTRA
+  MODULE_INIT_OS_EXTRA();
+#endif
+
+#if defined(AMIROOS_CFG_MAIN_INIT_HOOK_3)
+#if defined(AMIROOS_CFG_MAIN_INIT_HOOK_3_ARGS)
+  AMIROOS_CFG_MAIN_INIT_HOOK_3(AMIROOS_CFG_MAIN_INIT_HOOK_3_ARGS);
+#else
+  AMIROOS_CFG_MAIN_INIT_HOOK_3();
+#endif
+#endif
+
+#if (AMIROOS_CFG_TESTS_ENABLE == true)
+#if defined(MODULE_INIT_TESTS)
+  MODULE_INIT_TESTS();
+#else
+  #warning "MODULE_INIT_TESTS not defined"
+#endif
+#endif
+
+#if defined(AMIROOS_CFG_MAIN_INIT_HOOK_4)
+#if defined(AMIROOS_CFG_MAIN_INIT_HOOK_4_ARGS)
+  AMIROOS_CFG_MAIN_INIT_HOOK_4(AMIROOS_CFG_MAIN_INIT_HOOK_4_ARGS);
+#else
+  AMIROOS_CFG_MAIN_INIT_HOOK_4();
+#endif
+#endif
+
+  /* event associations */
+#if (AMIROOS_CFG_SSSP_STACK_START == true) && (AMIROOS_CFG_SSSP_STACK_END == true)
+  chEvtRegisterMaskWithFlags(&aos.events.io, &_eventListenerIO, IOEVENT_MASK, MODULE_SSSP_EVENTFLAGS_PD | MODULE_SSSP_EVENTFLAGS_SYNC);
+#elif (AMIROOS_CFG_SSSP_STACK_START == true)
+  chEvtRegisterMaskWithFlags(&aos.events.io, &_eventListenerIO, IOEVENT_MASK, MODULE_SSSP_EVENTFLAGS_PD | MODULE_SSSP_EVENTFLAGS_SYNC | MODULE_SSSP_EVENTFLAGS_UP);
+#elif (AMIROOS_CFG_SSSP_STACK_END == true)
+  chEvtRegisterMaskWithFlags(&aos.events.io, &_eventListenerIO, IOEVENT_MASK, MODULE_SSSP_EVENTFLAGS_PD | MODULE_SSSP_EVENTFLAGS_SYNC | MODULE_SSSP_EVENTFLAGS_DN);
+#else
+  chEvtRegisterMaskWithFlags(&aos.events.io, &_eventListenerIO, IOEVENT_MASK, MODULE_SSSP_EVENTFLAGS_PD | MODULE_SSSP_EVENTFLAGS_SYNC | MODULE_SSSP_EVENTFLAGS_DN | MODULE_SSSP_EVENTFLAGS_UP);
+#endif
+  chEvtRegisterMask(&aos.events.os, &_eventListenerOS, OSEVENT_MASK);
+
+#if defined(AMIROOS_CFG_MAIN_INIT_HOOK_5)
+#if defined(AMIROOS_CFG_MAIN_INIT_HOOK_5_ARGS)
+  AMIROOS_CFG_MAIN_INIT_HOOK_5(AMIROOS_CFG_MAIN_INIT_HOOK_5_ARGS);
+#else
+  AMIROOS_CFG_MAIN_INIT_HOOK_5();
+#endif
+#endif
+
+  /* periphery communication initialization */
+  // CAN (mandatory)
+  canStart(&MODULE_HAL_CAN, &moduleHalCanConfig);
+  // module specific initialization (if any)
+#ifdef MODULE_INIT_PERIPHERY_COMM
+  MODULE_INIT_PERIPHERY_COMM();
+#endif
+  // user interface (if any)
+#ifdef MODULE_HAL_PROGIF
+  aosIOChannelInit(&_stdiochannel, (BaseAsynchronousChannel*)&MODULE_HAL_PROGIF);
+  aosIOChannelOutputEnable(&_stdiochannel);
+  aosIOStreamAddChannel(&aos.iostream, &_stdiochannel);
+#if (AMIROOS_CFG_SHELL_ENABLE == true)
+  aosShellChannelInit(&_stdshellchannel, (BaseAsynchronousChannel*)&MODULE_HAL_PROGIF);
+  aosShellChannelInputEnable(&_stdshellchannel);
+  aosShellChannelOutputEnable(&_stdshellchannel);
+  aosShellStreamAddChannel(&aos.shell.stream, &_stdshellchannel);
+#endif
+#endif
+
+#if defined(AMIROOS_CFG_MAIN_INIT_HOOK_6)
+#if defined(AMIROOS_CFG_MAIN_INIT_HOOK_6_ARGS)
+  AMIROOS_CFG_MAIN_INIT_HOOK_6(AMIROOS_CFG_MAIN_INIT_HOOK_6_ARGS);
+#else
+  AMIROOS_CFG_MAIN_INIT_HOOK_6();
+#endif
+#endif
+
+  /* module is ready -> print welcome prompt */
+  aosprintf("\n");
+  aosprintf("######################################################################\n");
+  aosprintf("# AMiRo-OS is an operating system designed for the Autonomous Mini   #\n");
+  aosprintf("# Robot (AMiRo) platform.                                            #\n");
+  aosprintf("# Copyright (C) 2016..2018  Thomas Schöpping et al.                  #\n");
+  aosprintf("#                                                                    #\n");
+  aosprintf("# This is free software; see the source for copying conditions.      #\n");
+  aosprintf("# There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR  #\n");
+  aosprintf("# A PARTICULAR PURPOSE.                                              #\n");
+  aosprintf("# The development of this software was supported by the Excellence   #\n");
+  aosprintf("# Cluster EXC 227 Cognitive Interaction Technology. The Excellence   #\n");
+  aosprintf("# Cluster EXC 227 is a grant of the Deutsche Forschungsgemeinschaft  #\n");
+  aosprintf("# (DFG) in the context of the German Excellence Initiative.          #\n");
+  aosprintf("######################################################################\n");
+  aosprintf("\n");
+
+#if defined(AMIROOS_CFG_MAIN_INIT_HOOK_7)
+#if defined(AMIROOS_CFG_MAIN_INIT_HOOK_7_ARGS)
+  AMIROOS_CFG_MAIN_INIT_HOOK_7(AMIROOS_CFG_MAIN_INIT_HOOK_7_ARGS);
+#else
+  AMIROOS_CFG_MAIN_INIT_HOOK_7();
+#endif
+#endif
+
+  /* SSSP startup OS synchronization phase (end of startup stage 2) */
+  while ((shutdown == AOS_SHUTDOWN_NONE) && (eventmask = aosSysSsspStartupOsInitSyncCheck(&_eventListenerIO)) != 0) {
+    /*
+     * This code is executed if the received event was not about the SYS_SYNC control signal.
+     * The returned event could be caused by any listener (not only the argument).
+     */
+    // IO event
+    if (eventmask & _eventListenerIO.events) {
+      eventflags = chEvtGetAndClearFlags(&_eventListenerIO);
+      // PD event
+      if (eventflags & MODULE_SSSP_EVENTFLAGS_PD) {
+        shutdown = AOS_SHUTDOWN_PASSIVE;
+      } else {
+#ifdef MODULE_SSSP_STARTUP_2_2_IOEVENT_HOOK
+        MODULE_SSSP_STARTUP_2_2_IOEVENT_HOOK(eventmask, eventflags);
+#else
+        // ignore any other IO events
+#endif
+      }
+    }
+    // OS event
+    else if (eventmask & _eventListenerOS.events) {
+      eventflags = chEvtGetAndClearFlags(&_eventListenerOS);
+      _unexpectedEventError(eventmask, eventflags);
+    }
+    // unknown event
+    else {
+      _unexpectedEventError(eventmask, 0);
+    }
+  }
+
+  /*
+   * There must be no delays at this point, thus no hook is allowed.
+   */
+
+  /* SSSP startup stage 3 (module stack initialization) */
+  if (shutdown == AOS_SHUTDOWN_NONE) {
+    shutdown = _ssspModuleStackInitialization();
+  }
+
+  /*
+   * There must be no delays at this point, thus no hook is allowed.
+   */
+
+  /* snychronize calendars */
+  if (shutdown == AOS_SHUTDOWN_NONE) {
+#if (AMIROOS_CFG_SSSP_MASTER == true)
+    CANTxFrame frame;
+    struct tm t;
+    uint64_t encoded;
+
+    frame.DLC = 8;
+    frame.RTR = CAN_RTR_DATA;
+    frame.IDE = CAN_IDE_STD;
+    frame.SID = CALENDERSYNC_CANMSGID;
+
+    aosDbgPrintf("transmitting current date/time...\t");
+    // get current date & time
+    aosSysGetDateTime(&t);
+    // encode
+    encoded = _TM2U64(&t);
+    // serialize
+    _serialize(frame.data8, encoded, 8);
+    // transmit
+    canTransmitTimeout(&MODULE_HAL_CAN, CAN_ANY_MAILBOX, &frame, TIME_IMMEDIATE);
+
+    aosDbgPrintf("done\n");
+#else
+    CANRxFrame frame;
+    uint64_t encoded;
+    struct tm t;
+
+    aosDbgPrintf("receiving current date/time...\t");
+    // receive message
+    if (canReceiveTimeout(&MODULE_HAL_CAN, CAN_ANY_MAILBOX, &frame, chTimeUS2I(AOS_SYSTEM_SSSP_TIMEOUT)) == MSG_OK) {
+      // validate message
+      if (frame.DLC == 8 &&
+          frame.RTR == CAN_RTR_DATA &&
+          frame.IDE == CAN_IDE_STD &&
+          frame.SID == CALENDERSYNC_CANMSGID) {
+        // deserialize
+        encoded = _deserialize(frame.data8, 8);
+        // decode
+        _U642TM(&t, encoded);
+        // set current date & time
+        aosSysSetDateTime(&t);
+        aosDbgPrintf("success\n");
+      } else {
+        aosDbgPrintf("fail (invalid message)\n");
+      }
+    } else {
+      aosDbgPrintf("fail (timeout)\n");
+    }
+#endif
+    aosDbgPrintf("\n");
+  }
+
+#if defined(AMIROOS_CFG_MAIN_INIT_HOOK_8)
+#if defined(AMIROOS_CFG_MAIN_INIT_HOOK_8_ARGS)
+  AMIROOS_CFG_MAIN_INIT_HOOK_8(AMIROOS_CFG_MAIN_INIT_HOOK_8_ARGS);
+#else
+  AMIROOS_CFG_MAIN_INIT_HOOK_8();
+#endif
+#endif
+
+  /* completely start AMiRo-OS */
+  if (shutdown == AOS_SHUTDOWN_NONE) {
+    aosSysStart();
+  }
+
+#if defined(AMIROOS_CFG_MAIN_INIT_HOOK_9)
+#if defined(AMIROOS_CFG_MAIN_INIT_HOOK_9_ARGS)
+  AMIROOS_CFG_MAIN_INIT_HOOK_9(AMIROOS_CFG_MAIN_INIT_HOOK_9_ARGS);
+#else
+  AMIROOS_CFG_MAIN_INIT_HOOK_9();
+#endif
+#endif
+
+  /*
+   * ##########################################################################
+   * # infinite loop                                                          #
+   * ##########################################################################
+   */
+
+  // sleep until a shutdown event is received
+  while (shutdown == AOS_SHUTDOWN_NONE) {
+    // wait for an event
+#if (AMIROOS_CFG_MAIN_LOOP_TIMEOUT != 0)
+    eventmask = chEvtWaitOneTimeout(ALL_EVENTS, chTimeUS2I(AMIROOS_CFG_MAIN_LOOP_TIMEOUT));
+#else
+    eventmask = chEvtWaitOne(ALL_EVENTS);
+#endif
+
+#if defined(AMIROOS_CFG_MAIN_LOOP_HOOK_0)
+#if defined(AMIROOS_CFG_MAIN_LOOP_HOOK_0_ARGS)
+    AMIROOS_CFG_MAIN_LOOP_HOOK_0(AMIROOS_CFG_MAIN_LOOP_HOOK_0_ARGS);
+#else
+    AMIROOS_CFG_MAIN_LOOP_HOOK_0();
+#endif
+#endif
+
+    switch (eventmask) {
+      // if this was an I/O event
+      case IOEVENT_MASK:
+        // evaluate flags
+        eventflags = chEvtGetAndClearFlags(&_eventListenerIO);
+        // PD event
+        if (eventflags & MODULE_SSSP_EVENTFLAGS_PD) {
+          shutdown = AOS_SHUTDOWN_PASSIVE;
+        }
+        // all other events
+#ifdef MODULE_MAIN_LOOP_IO_EVENT
+        else {
+          MODULE_MAIN_LOOP_IO_EVENT(eventmask, eventflags);
+        }
+#endif
+        break;
+
+      // if this was an OS event
+      case OSEVENT_MASK:
+        // evaluate flags
+        eventflags = chEvtGetAndClearFlags(&_eventListenerOS);
+        switch (eventflags) {
+          case AOS_SYSTEM_EVENTFLAGS_HIBERNATE:
+            shutdown = AOS_SHUTDOWN_HIBERNATE;
+            break;
+          case AOS_SYSTEM_EVENTFLAGS_DEEPSLEEP:
+            shutdown = AOS_SHUTDOWN_DEEPSLEEP;
+            break;
+          case AOS_SYSTEM_EVENTFLAGS_TRANSPORTATION:
+            shutdown = AOS_SHUTDOWN_TRANSPORTATION;
+            break;
+          case AOS_SYSTEM_EVENTFLAGS_RESTART:
+            shutdown = AOS_SHUTDOWN_RESTART;
+            break;
+          default:
+            _unexpectedEventError(eventmask, eventflags);
+            break;
+        }
+        break;
+
+      // if this was any other event (should be impossible to occur)
+      default:
+        eventflags = 0;
+        _unexpectedEventError(eventmask, eventflags);
+        break;
+    }
+
+#if defined(AMIROOS_CFG_MAIN_LOOP_HOOK_1)
+#if defined(AMIROOS_CFG_MAIN_LOOP_HOOK_1_ARGS)
+    AMIROOS_CFG_MAIN_LOOP_HOOK_1(AMIROOS_CFG_MAIN_LOOP_HOOK_1_ARGS);
+#else
+    AMIROOS_CFG_MAIN_LOOP_HOOK_1();
+#endif
+#endif
+  }
+
+  /*
+   * ##########################################################################
+   * # system shutdown                                                        #
+   * ##########################################################################
+   */
+
+#if defined(AMIROOS_CFG_MAIN_SHUTDOWN_HOOK_0)
+#if defined(AMIROOS_CFG_MAIN_SHUTDOWN_HOOK_0_ARGS)
+    AMIROOS_CFG_MAIN_SHUTDOWN_HOOK_0(AMIROOS_CFG_MAIN_SHUTDOWN_HOOK_0_ARGS);
+#else
+    AMIROOS_CFG_MAIN_SHUTDOWN_HOOK_0();
+#endif
+#endif
+
+  // initialize/acknowledge shutdown
+  aosSysShutdownInit(shutdown);
+
+#if defined(AMIROOS_CFG_MAIN_SHUTDOWN_HOOK_1)
+#if defined(AMIROOS_CFG_MAIN_SHUTDOWN_HOOK_1_ARGS)
+    AMIROOS_CFG_MAIN_SHUTDOWN_HOOK_1(AMIROOS_CFG_MAIN_SHUTDOWN_HOOK_1_ARGS);
+#else
+    AMIROOS_CFG_MAIN_SHUTDOWN_HOOK_1();
+#endif
+#endif
+
+  // stop system threads
+  aosSysStop();
+
+#if defined(AMIROOS_CFG_MAIN_SHUTDOWN_HOOK_2)
+#if defined(AMIROOS_CFG_MAIN_SHUTDOWN_HOOK_2_ARGS)
+    AMIROOS_CFG_MAIN_SHUTDOWN_HOOK_2(AMIROOS_CFG_MAIN_SHUTDOWN_HOOK_2_ARGS);
+#else
+    AMIROOS_CFG_MAIN_SHUTDOWN_HOOK_2();
+#endif
+#endif
+
+  // deinitialize system
+  aosSysDeinit();
+
+#if defined(AMIROOS_CFG_MAIN_SHUTDOWN_HOOK_3)
+#if defined(AMIROOS_CFG_MAIN_SHUTDOWN_HOOK_3_ARGS)
+    AMIROOS_CFG_MAIN_SHUTDOWN_HOOK_3(AMIROOS_CFG_MAIN_SHUTDOWN_HOOK_3_ARGS);
+#else
+    AMIROOS_CFG_MAIN_SHUTDOWN_HOOK_3();
+#endif
+#endif
+
+  /* stop all periphery communication */
+  // CAN (mandatory)
+  canStop(&MODULE_HAL_CAN);
+#ifdef MODULE_SHUTDOWN_PERIPHERY_COMM
+  MODULE_SHUTDOWN_PERIPHERY_COMM();
+#endif
+
+#if defined(AMIROOS_CFG_MAIN_SHUTDOWN_HOOK_4)
+#if defined(AMIROOS_CFG_MAIN_SHUTDOWN_HOOK_4_ARGS)
+    AMIROOS_CFG_MAIN_SHUTDOWN_HOOK_4(AMIROOS_CFG_MAIN_SHUTDOWN_HOOK_4_ARGS);
+#else
+    AMIROOS_CFG_MAIN_SHUTDOWN_HOOK_4();
+#endif
+#endif
+
+  // finally hand over to bootloader
+  aosSysShutdownFinal(shutdown);
+
+  /*
+   * ##########################################################################
+   * # after shutdown/restart                                                 #
+   * ##########################################################################
+   *
+   * NOTE: This code will not be executed, since the bootloader callbacks will stop/restart the MCU.
+   *       It is included nevertheless for the sake of completeness and to explicitely indicate,
+   *       which subsystems should NOT be shut down.
+   */
+
+  // return an error, since this code should not be executed
+  return -1;
+}
+
+/** @} */
diff --git a/core/src/aos_shell.c b/core/src/aos_shell.c
new file mode 100644
index 0000000..00e10f0
--- /dev/null
+++ b/core/src/aos_shell.c
@@ -0,0 +1,1532 @@
+/*
+AMiRo-OS is an operating system designed for the Autonomous Mini Robot (AMiRo) platform.
+Copyright (C) 2016..2018  Thomas Schöpping et al.
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @file    aos_shell.c
+ * @brief   Shell code.
+ * @details Shell code as well as shell related channels and streams.
+ *
+ * @addtogroup aos_shell
+ * @{
+ */
+
+#include <aos_shell.h>
+
+#if (AMIROOS_CFG_SHELL_ENABLE == true)
+#include <aos_debug.h>
+#include <aos_time.h>
+#include <aos_system.h>
+#include <string.h>
+
+/**
+ * @brief   Event mask to be set on OS related events.
+ */
+#define AOS_SHELL_EVENTMASK_OS                  EVENT_MASK(0)
+
+/**
+ * @brief   Event mask to be set on a input event.
+ */
+#define AOS_SHELL_EVENTMASK_INPUT               EVENT_MASK(1)
+
+/**
+ * @brief   Implementation of the BaseAsynchronous write() method (inherited from BaseSequentialStream).
+ */
+static size_t _channelwrite(void *instance, const uint8_t *bp, size_t n)
+{
+  if (((AosShellChannel*)instance)->flags & AOS_SHELLCHANNEL_OUTPUT_ENABLED) {
+    return streamWrite(((AosShellChannel*)instance)->asyncchannel, bp, n);
+  } else {
+    return 0;
+  }
+}
+
+/**
+ * @brief   Implementation of the BaseAsynchronous read() method (inherited from BaseSequentialStream).
+ */
+static size_t _channelread(void *instance, uint8_t *bp, size_t n)
+{
+  if (((AosShellChannel*)instance)->flags & AOS_SHELLCHANNEL_INPUT_ENABLED) {
+    return streamRead(((AosShellChannel*)instance)->asyncchannel, bp, n);
+  } else {
+    return 0;
+  }
+}
+
+/**
+ * @brief   Implementation of the BaseAsynchronous put() method (inherited from BaseSequentialStream).
+ */
+static msg_t _channelput(void *instance, uint8_t b)
+{
+  if (((AosShellChannel*)instance)->flags & AOS_SHELLCHANNEL_OUTPUT_ENABLED) {
+    return streamPut(((AosShellChannel*)instance)->asyncchannel, b);
+  } else {
+    return MSG_RESET;
+  }
+}
+
+/**
+ * @brief   Implementation of the BaseAsynchronous get() method (inherited from BaseSequentialStream).
+ */
+static msg_t _channelget(void *instance)
+{
+  if (((AosShellChannel*)instance)->flags & AOS_SHELLCHANNEL_INPUT_ENABLED) {
+    return streamGet(((AosShellChannel*)instance)->asyncchannel);
+  } else {
+    return MSG_RESET;
+  }
+}
+
+/**
+ * @brief   Implementation of the BaseAsynchronous putt() method.
+ */
+static msg_t _channelputt(void *instance, uint8_t b, sysinterval_t time)
+{
+  if (((AosShellChannel*)instance)->flags & AOS_SHELLCHANNEL_OUTPUT_ENABLED) {
+    return chnPutTimeout(((AosShellChannel*)instance)->asyncchannel, b, time);
+  } else {
+    return MSG_RESET;
+  }
+}
+
+/**
+ * @brief   Implementation of the BaseAsynchronous gett() method.
+ */
+static msg_t _channelgett(void *instance, sysinterval_t time)
+{
+  if (((AosShellChannel*)instance)->flags & AOS_SHELLCHANNEL_INPUT_ENABLED) {
+    return chnGetTimeout(((AosShellChannel*)instance)->asyncchannel, time);
+  } else {
+    return MSG_RESET;
+  }
+}
+
+/**
+ * @brief   Implementation of the BaseAsynchronous writet() method.
+ */
+static size_t _channelwritet(void *instance, const uint8_t *bp, size_t n, sysinterval_t time)
+{
+  if (((AosShellChannel*)instance)->flags & AOS_SHELLCHANNEL_OUTPUT_ENABLED) {
+    return chnWriteTimeout(((AosShellChannel*)instance)->asyncchannel, bp, n, time);
+  } else {
+    return 0;
+  }
+}
+
+/**
+ * @brief   Implementation of the BaseAsynchronous readt() method.
+ */
+static size_t _channelreadt(void *instance, uint8_t *bp, size_t n, sysinterval_t time)
+{
+  if (((AosShellChannel*)instance)->flags & AOS_SHELLCHANNEL_INPUT_ENABLED) {
+    return chnReadTimeout(((AosShellChannel*)instance)->asyncchannel, bp, n, time);
+  } else {
+    return 0;
+  }
+}
+
+/**
+ * @brief   Implementation of the BaseAsynchronousChannel ctl() method.
+ */
+static msg_t _channelctl(void *instance, unsigned int operation, void *arg) {
+  (void) instance;
+
+  switch (operation) {
+  case CHN_CTL_NOP:
+    osalDbgCheck(arg == NULL);
+    break;
+  case CHN_CTL_INVALID:
+    osalDbgAssert(false, "invalid CTL operation");
+    break;
+  default:
+    break;
+  }
+  return MSG_OK;
+}
+
+static const struct AosShellChannelVMT _channelvmt = {
+  (size_t) 0,
+  _channelwrite,
+  _channelread,
+  _channelput,
+  _channelget,
+  _channelputt,
+  _channelgett,
+  _channelwritet,
+  _channelreadt,
+  _channelctl,
+};
+
+static size_t _streamwrite(void *instance, const uint8_t *bp, size_t n)
+{
+  aosDbgCheck(instance != NULL);
+
+  // local variables
+  AosShellChannel* channel = ((AosShellStream*)instance)->channel;
+  size_t bytes;
+  size_t maxbytes = 0;
+
+  // iterate through the list of channels
+  while (channel != NULL) {
+    bytes = streamWrite(channel, bp, n);
+    maxbytes = (bytes > maxbytes) ? bytes : maxbytes;
+    channel = channel->next;
+  }
+
+  return maxbytes;
+}
+
+static size_t _stremread(void *instance, uint8_t *bp, size_t n)
+{
+  (void)instance;
+  (void)bp;
+  (void)n;
+
+  return 0;
+}
+
+static msg_t _streamput(void *instance, uint8_t b)
+{
+  aosDbgCheck(instance != NULL);
+
+  // local variables
+  AosShellChannel* channel = ((AosShellStream*)instance)->channel;
+  msg_t ret = MSG_OK;
+
+  // iterate through the list of channels
+  while (channel != NULL) {
+    msg_t ret_ = streamPut(channel, b);
+    ret = (ret_ < ret) ? ret_ : ret;
+    channel = channel->next;
+  }
+
+  return ret;
+}
+
+static msg_t _streamget(void *instance)
+{
+  (void)instance;
+
+  return 0;
+}
+
+static const struct AosShellStreamVMT _streamvmt = {
+  (size_t) 0,
+  _streamwrite,
+  _stremread,
+  _streamput,
+  _streamget,
+};
+
+/**
+ * @brief   Enumerator of special keyboard keys.
+ */
+typedef enum special_key {
+  KEY_UNKNOWN,      /**< any/unknow key */
+  KEY_AMBIGUOUS,    /**< key is ambiguous */
+  KEY_TAB,          /**< tabulator key */
+  KEY_ESCAPE,       /**< escape key */
+  KEY_BACKSPACE,    /**< backspace key */
+  KEY_INSERT,       /**< insert key */
+  KEY_DELETE,       /**< delete key */
+  KEY_HOME,         /**< home key */
+  KEY_END,          /**< end key */
+  KEY_PAGE_UP,      /**< page up key */
+  KEY_PAGE_DOWN,    /**< page down key */
+  KEY_ARROW_UP,     /**< arrow up key */
+  KEY_ARROW_DOWN,   /**< arrow down key */
+  KEY_ARROW_LEFT,   /**< arrow left key */
+  KEY_ARROW_RIGHT,  /**< arrow right key */
+} special_key_t;
+
+/**
+ * @brief   Enumerator for case (in)sensitive character matching.
+ */
+typedef enum charmatch {
+  CHAR_MATCH_NOT    = 0,  /**< Characters do not match at all. */
+  CHAR_MATCH_NCASE  = 1,  /**< Characters would match case insensitive. */
+  CHAR_MATCH_CASE   = 2,  /**< Characters do match with case. */
+} charmatch_t;
+
+/**
+ * @brief   Print the shell prompt
+ * @details Depending on the configuration flags, the system uptime is printed before the prompt string.
+ *
+ * @param[in] shell   Pointer to the shell object.
+ */
+static void _printPrompt(aos_shell_t* shell)
+{
+  aosDbgCheck(shell != NULL);
+
+  // print some time informattion before prompt if configured
+  if (shell->config & (AOS_SHELL_CONFIG_PROMPT_UPTIME | AOS_SHELL_CONFIG_PROMPT_DATETIME)) {
+    // printf the system uptime
+    if ((shell->config & (AOS_SHELL_CONFIG_PROMPT_UPTIME | AOS_SHELL_CONFIG_PROMPT_DATETIME)) == AOS_SHELL_CONFIG_PROMPT_UPTIME) {
+      // get current system uptime
+      aos_timestamp_t uptime;
+      aosSysGetUptime(&uptime);
+
+      chprintf((BaseSequentialStream*)&shell->stream, "[%01u:%02u:%02u:%02u:%03u:%03u] ",
+               (uint32_t)(uptime / MICROSECONDS_PER_DAY),
+               (uint8_t)(uptime % MICROSECONDS_PER_DAY / MICROSECONDS_PER_HOUR),
+               (uint8_t)(uptime % MICROSECONDS_PER_HOUR / MICROSECONDS_PER_MINUTE),
+               (uint8_t)(uptime % MICROSECONDS_PER_MINUTE / MICROSECONDS_PER_SECOND),
+               (uint16_t)(uptime % MICROSECONDS_PER_SECOND / MICROSECONDS_PER_MILLISECOND),
+               (uint16_t)(uptime % MICROSECONDS_PER_MILLISECOND / MICROSECONDS_PER_MICROSECOND));
+    }
+    else if ((shell->config & (AOS_SHELL_CONFIG_PROMPT_UPTIME | AOS_SHELL_CONFIG_PROMPT_DATETIME)) == AOS_SHELL_CONFIG_PROMPT_DATETIME) {
+      // get current RTC time
+      struct tm dt;
+      aosSysGetDateTime(&dt);
+      chprintf((BaseSequentialStream*)&shell->stream, "[%02u-%02u-%04u|%02u:%02u:%02u] ",
+               dt.tm_mday,
+               dt.tm_mon + 1,
+               dt.tm_year + 1900,
+               dt.tm_hour,
+               dt.tm_min,
+               dt.tm_sec);
+    }
+    else {
+      aosDbgAssert(false);
+    }
+  }
+
+  // print the actual prompt string
+  if (shell->prompt && !(shell->config & AOS_SHELL_CONFIG_PROMPT_MINIMAL)) {
+    chprintf((BaseSequentialStream*)&shell->stream, "%s$ ", shell->prompt);
+  } else {
+    chprintf((BaseSequentialStream*)&shell->stream, "%>$ ");
+  }
+
+  return;
+}
+
+/**
+ * @brief   Interprete a escape sequence
+ *
+ * @param[in] seq   Character sequence to interprete.
+ *                  Must be terminated by NUL byte.
+ *
+ * @return          A @p special_key value.
+ */
+static special_key_t _interpreteEscapeSequence(const char seq[])
+{
+  // local variables
+  bool ambiguous = false;
+  int cmp = 0;
+
+  // TAB
+  /* not supported yet; use "\x09" instead */
+
+  // BACKSPACE
+  /* not supported yet; use "\x08" instead */
+
+  // ESCAPE
+  cmp = strcmp(seq, "\x1B");
+  if (cmp == 0) {
+    return KEY_ESCAPE;
+  } else {
+    ambiguous |= (cmp < 0);
+  }
+
+  // INSERT
+  cmp = strcmp(seq, "\x1B\x5B\x32\x7E");
+  if (cmp == 0) {
+    return KEY_INSERT;
+  } else {
+    ambiguous |= (cmp < 0);
+  }
+
+  // DELETE
+  cmp = strcmp(seq, "\x1B\x5B\x33\x7E");
+  if (cmp == 0) {
+    return KEY_DELETE;
+  } else {
+    ambiguous |= (cmp < 0);
+  }
+
+  // HOME
+  cmp = strcmp(seq, "\x1B\x4F\x48");
+  if (cmp == 0) {
+    return KEY_HOME;
+  } else {
+    ambiguous |= (cmp < 0);
+  }
+
+  // END
+  cmp = strcmp(seq, "\x1B\x4F\x46");
+  if (cmp == 0) {
+    return KEY_END;
+  } else {
+    ambiguous |= (cmp < 0);
+  }
+
+  // PAGE UP
+  cmp = strcmp(seq, "\x1B\x5B\x35\x7E");
+  if (cmp == 0) {
+    return KEY_PAGE_UP;
+  } else {
+    ambiguous |= (cmp < 0);
+  }
+
+  // PAGE DOWN
+  cmp = strcmp(seq, "\x1B\x5B\x36\x7E");
+  if (cmp == 0) {
+    return KEY_PAGE_DOWN;
+  } else {
+    ambiguous |= (cmp < 0);
+  }
+
+  // ARROW UP
+  cmp = strcmp(seq, "\x1B\x5B\x41");
+  if (cmp == 0) {
+    return KEY_ARROW_UP;
+  } else {
+    ambiguous |= (cmp < 0);
+  }
+
+  // ARROW DOWN
+  cmp = strcmp(seq, "\x1B\x5B\x42");
+  if (cmp == 0) {
+    return KEY_ARROW_DOWN;
+  } else {
+    ambiguous |= (cmp < 0);
+  }
+
+  // ARROW LEFT
+  cmp = strcmp(seq, "\x1B\x5B\x44");
+  if (cmp == 0) {
+    return KEY_ARROW_LEFT;
+  } else {
+    ambiguous |= (cmp < 0);
+  }
+
+  // ARROW RIGHT
+  cmp = strcmp(seq, "\x1B\x5B\x43");
+  if (cmp == 0) {
+    return KEY_ARROW_RIGHT;
+  } else {
+    ambiguous |= (cmp < 0);
+  }
+
+  return ambiguous ? KEY_AMBIGUOUS : KEY_UNKNOWN;
+}
+
+/**
+ * @brief   Move the cursor in the terminal
+ *
+ * @param[in] shell   Pointer to the shell object.
+ * @param[in] from    Starting position of the cursor.
+ * @param[in] to      Target position to move the cursor to.
+ *
+ * @return            The number of positions moved.
+ */
+static int _moveCursor(aos_shell_t* shell, const size_t from, const size_t to)
+{
+  aosDbgCheck(shell != NULL);
+
+  // local variables
+  size_t pos = from;
+
+  // move cursor left by printing backspaces
+  while (pos > to) {
+    streamPut(&shell->stream, '\b');
+    --pos;
+  }
+
+  // move cursor right by printing line content
+  while (pos < to) {
+    streamPut(&shell->stream, shell->line[pos]);
+    ++pos;
+  }
+
+  return (int)pos - (int)from;
+}
+
+/**
+ * @brief   Print content of the shell line
+ *
+ * @param[in] shell   Pointer to the shell object.
+ * @param[in] from    First position to start printing from.
+ * @param[in] to      Position after the last character to print.
+ *
+ * @return            Number of characters printed.
+ */
+static inline size_t _printLine(aos_shell_t* shell, const size_t from, const size_t to)
+{
+  aosDbgCheck(shell != NULL);
+
+  // local variables
+  size_t cnt;
+
+  for (cnt = 0; from + cnt < to; ++cnt) {
+    streamPut(&shell->stream, shell->line[from + cnt]);
+  }
+
+  return cnt;
+}
+
+/**
+ * @brief   Compare two characters.
+ *
+ * @param[in] lhs       First character to compare.
+ * @param[in] rhs       Second character to compare.
+ *
+ * @return              How well the characters match.
+ */
+static inline charmatch_t _charcmp(char lhs, char rhs)
+{
+  // if lhs is a upper case letter and rhs is a lower case letter
+  if (lhs >= 'A' && lhs <= 'Z' && rhs >= 'a' && rhs <= 'z') {
+    return (lhs == (rhs - 'a' + 'A')) ? CHAR_MATCH_NCASE : CHAR_MATCH_NOT;
+  }
+  // if lhs is a lower case letter and rhs is a upper case letter
+  else if (lhs >= 'a' && lhs <= 'z' && rhs >= 'A' && rhs <= 'Z') {
+    return ((lhs - 'a' + 'A') == rhs) ? CHAR_MATCH_NCASE : CHAR_MATCH_NOT;
+  }
+  // default
+  else {
+    return (lhs == rhs) ? CHAR_MATCH_CASE : CHAR_MATCH_NOT;
+  }
+}
+
+/**
+ * @brief   Maps an character from ASCII to a modified custom encoding.
+ * @details The custom character encoding is very similar to ASCII and has the following structure:
+ *          0x00=NULL ... 0x40='@' (identically to ASCII)
+ *          0x4A='a'; 0x4B='A'; 0x4C='b'; 0x4D='B' ... 0x73='z'; 0x74='Z' (custom letter order)
+ *          0x75='[' ... 0x7A='`' (0x5B..0x60 is ASCII)
+ *          0x7B='{' ... 0x7F=DEL (identically to ASCII)
+ *
+ * @param[in] c   Character to map to the custom encoding.
+ *
+ * @return    The customly encoded character.
+ */
+static inline char _mapAscii2Custom(const char c)
+{
+  if (c >= 'A' && c <= 'Z') {
+    return ((c - 'A') * 2) + 'A' + 1;
+  } else if (c > 'Z' && c < 'a') {
+    return c + ('z' - 'a') + 1;
+  } else if (c >= 'a' && c <= 'z') {
+    return ((c - 'a') * 2) + 'A';
+  } else {
+    return c;
+  }
+}
+
+/**
+ * @brief   Compares two strings wrt letter case.
+ * @details Comparisson uses a custom character encoding or mapping.
+ *          See @p _mapAscii2Custom for details.
+ *
+ * @param[in] str1    First string to compare.
+ * @param[in] str2    Second string to compare.
+ * @param[in] cs      Flag indicating whether comparison shall be case sensitive.
+ * @param[in,out] n   Maximum number of character to compare (in) and number of matching characters (out).
+ *                    If a null pointer is specified, this parameter is ignored.
+ *                    If the value pointed to is zero, comarison will not be limited.
+ * @param[out] m      Optional indicator whether there was at least one case mismatch.
+ *
+ * @return      Integer value indicating the relationship between the strings.
+ * @retval <0   The first character that does not match has a lower value in str1 than in str2.
+ * @retval  0   The contents of both strings are equal.
+ * @retval >0   The first character that does not match has a greater value in str1 than in str2.
+ */
+static int _strccmp(const char *str1, const char *str2, bool cs, size_t* n, charmatch_t* m)
+{
+  aosDbgCheck(str1 != NULL);
+  aosDbgCheck(str2 != NULL);
+
+  // initialize variables
+  if (m) {
+    *m = CHAR_MATCH_NOT;
+  }
+  size_t i = 0;
+
+  // iterate through the strings
+  while ((n == NULL) || (*n == 0) || (*n > 0 && i < *n)) {
+    // break on NUL
+    if (str1[i] == '\0' || str2[i] == '\0') {
+      if (n) {
+        *n = i;
+      }
+      break;
+    }
+    // compare character
+    const charmatch_t match = _charcmp(str1[i], str2[i]);
+    if ((match == CHAR_MATCH_CASE) || (!cs && match == CHAR_MATCH_NCASE)) {
+      if (m != NULL && *m != CHAR_MATCH_NCASE) {
+        *m = match;
+      }
+      ++i;
+    } else {
+      if (n) {
+        *n = i;
+      }
+      break;
+    }
+  }
+
+  return _mapAscii2Custom(str1[i]) - _mapAscii2Custom(str2[i]);
+}
+
+static aos_status_t _readChannel(aos_shell_t* shell, AosShellChannel* channel, size_t* n)
+{
+  aosDbgCheck(shell != NULL);
+  aosDbgCheck(channel != NULL);
+  aosDbgCheck(n != NULL);
+
+  // local variables
+  aos_shellaction_t action = AOS_SHELL_ACTION_NONE;
+  char c;
+  special_key_t key;
+
+  // initialize output variables
+  *n = 0;
+
+  // read character by character from the channel
+  while (chnReadTimeout(channel, (uint8_t*)&c, 1, TIME_IMMEDIATE)) {
+    key = KEY_UNKNOWN;
+
+    // parse escape sequence
+    if (shell->inputdata.escp > 0) {
+      shell->inputdata.escseq[shell->inputdata.escp] = c;
+      ++shell->inputdata.escp;
+      key = _interpreteEscapeSequence(shell->inputdata.escseq);
+      if (key == KEY_AMBIGUOUS) {
+        // read next byte to resolve ambiguity
+        continue;
+      } else {
+        /*
+         * If the escape sequence could either be parsed sucessfully
+         * or there is no match (KEY_UNKNOWN),
+         * reset the sequence variable and interprete key/character
+         */
+        shell->inputdata.escp = 0;
+        memset(shell->inputdata.escseq, '\0', sizeof(shell->inputdata.escseq)*sizeof(shell->inputdata.escseq[0]));
+      }
+    }
+
+    /* interprete keys or character */
+    {
+      // default
+      action = AOS_SHELL_ACTION_NONE;
+
+      // printable character
+      if (key == KEY_UNKNOWN && c >= '\x20' && c <= '\x7E') {
+        action = AOS_SHELL_ACTION_READCHAR;
+      }
+
+      // tab key or character
+      else if (key == KEY_TAB || c == '\x09') {
+        /*
+         * pressing tab once applies auto fill
+         * pressing tab a second time prints suggestions
+         */
+        if (shell->inputdata.lastaction == AOS_SHELL_ACTION_AUTOFILL || shell->inputdata.lastaction == AOS_SHELL_ACTION_SUGGEST) {
+          action = AOS_SHELL_ACTION_SUGGEST;
+        } else {
+          action = AOS_SHELL_ACTION_AUTOFILL;
+        }
+      }
+
+      // INS key
+      else if (key == KEY_INSERT) {
+        action = AOS_SHELL_ACTION_INSERTTOGGLE;
+      }
+
+      // DEL key or character
+      else if (key == KEY_DELETE || c == '\x7F') {
+        // ignore if cursor is at very right
+        if (shell->inputdata.cursorpos < shell->inputdata.lineend) {
+          action = AOS_SHELL_ACTION_DELETEFORWARD;
+        }
+      }
+
+      // backspace key or character
+      else if (key == KEY_BACKSPACE || c == '\x08') {
+        // ignore if cursor is at very left
+        if (shell->inputdata.cursorpos > 0) {
+          action = AOS_SHELL_ACTION_DELETEBACKWARD;
+        }
+      }
+
+      // 'page up' of 'arrow up' key
+      else if (key == KEY_PAGE_UP || key == KEY_ARROW_UP) {
+        // ignore if there was some input
+        if (shell->inputdata.noinput) {
+          action = AOS_SHELL_ACTION_RECALLLAST;
+        }
+      }
+
+      // 'page down' key, 'arrow done' key, 'end of test' character or 'end of transmission' character
+      else if (key == KEY_PAGE_DOWN || key == KEY_ARROW_DOWN || c == '\x03' || c == '\x03') {
+        // ignore if line is empty
+        if (shell->inputdata.lineend > 0) {
+          action = AOS_SHELL_ACTION_CLEAR;
+        }
+      }
+
+      // 'home' key
+      else if (key == KEY_HOME) {
+        // ignore if cursor is very left
+        if (shell->inputdata.cursorpos > 0) {
+          action = AOS_SHELL_ACTION_CURSOR2START;
+        }
+      }
+
+      // 'end' key
+      else if (key == KEY_END) {
+        // ignore if cursos is very right
+        if (shell->inputdata.cursorpos < shell->inputdata.lineend) {
+          action = AOS_SHELL_ACTION_CURSOR2END;
+        }
+      }
+
+      // 'arrow left' key
+      else if (key == KEY_ARROW_LEFT) {
+        // ignore if cursor is very left
+        if (shell->inputdata.cursorpos > 0) {
+          action = AOS_SHELL_ACTION_CURSORLEFT;
+        }
+      }
+
+      // 'arrow right' key
+      else if (key == KEY_ARROW_RIGHT) {
+        // irgnore if cursor is very right
+        if (shell->inputdata.cursorpos < shell->inputdata.lineend) {
+          action = AOS_SHELL_ACTION_CURSORRIGHT;
+        }
+      }
+
+      // carriage return ('\r') or line feed ('\n') character
+      else if (c == '\x0D' || c == '\x0A') {
+        action = AOS_SHELL_ACTION_EXECUTE;
+      }
+
+      // ESC key or [ESCAPE] character
+      else if (key == KEY_ESCAPE || c == '\x1B') {
+        action = AOS_SHELL_ACTION_ESCSTART;
+      }
+    }
+
+    /* handle function */
+    switch (action) {
+      case AOS_SHELL_ACTION_READCHAR:
+      {
+        // line is full
+        if (shell->inputdata.lineend + 1 >= shell->linesize) {
+          _moveCursor(shell, shell->inputdata.cursorpos, shell->inputdata.lineend);
+          chprintf((BaseSequentialStream*)&shell->stream, "\n\tmaximum line width reached\n");
+          _printPrompt(shell);
+          _printLine(shell, 0, shell->inputdata.lineend);
+          _moveCursor(shell, shell->inputdata.lineend, shell->inputdata.cursorpos);
+        }
+        // read character
+        else {
+          // clear old line content on first input
+          if (shell->inputdata.noinput) {
+            memset(shell->line, '\0', shell->linesize);
+            shell->inputdata.noinput = false;
+          }
+          // overwrite content
+          if (shell->config & AOS_SHELL_CONFIG_INPUT_OVERWRITE) {
+            shell->line[shell->inputdata.cursorpos] = c;
+            ++shell->inputdata.cursorpos;
+            shell->inputdata.lineend = (shell->inputdata.cursorpos > shell->inputdata.lineend) ? shell->inputdata.cursorpos : shell->inputdata.lineend;
+            streamPut(&shell->stream, (uint8_t)c);
+          }
+          // insert character
+          else {
+            memmove(&(shell->line[shell->inputdata.cursorpos+1]), &(shell->line[shell->inputdata.cursorpos]), shell->inputdata.lineend - shell->inputdata.cursorpos);
+            shell->line[shell->inputdata.cursorpos] = c;
+            ++shell->inputdata.lineend;
+            _printLine(shell, shell->inputdata.cursorpos, shell->inputdata.lineend);
+            ++shell->inputdata.cursorpos;
+            _moveCursor(shell, shell->inputdata.lineend, shell->inputdata.cursorpos);
+          }
+        }
+        break;
+      }
+
+      case AOS_SHELL_ACTION_AUTOFILL:
+      {
+        const char* fill = shell->line;
+        size_t cmatch = shell->inputdata.cursorpos;
+        charmatch_t matchlevel = CHAR_MATCH_NOT;
+        size_t n;
+        // iterate through command list
+        for (aos_shellcommand_t* cmd = shell->commands; cmd != NULL; cmd = cmd->next) {
+          // compare current match with command
+          n = cmatch;
+          charmatch_t mlvl = CHAR_MATCH_NOT;
+          _strccmp(fill, cmd->name, shell->config & AOS_SHELL_CONFIG_MATCH_CASE, (n == 0) ? NULL : &n, &mlvl);
+          const int cmp = (n < cmatch) ?
+                            (n - cmatch) :
+                            (cmd->name[n] != '\0') ?
+                              strlen(cmd->name) - n :
+                              0;
+          // if an exact match was found
+          if (cmatch + cmp == shell->inputdata.cursorpos) {
+            cmatch = shell->inputdata.cursorpos;
+            fill = cmd->name;
+            // break the loop only if there are no case mismatches with the input
+            n = shell->inputdata.cursorpos;
+            _strccmp(fill, shell->line, false, &n, &mlvl);
+            if (mlvl == CHAR_MATCH_CASE) {
+              break;
+            }
+          }
+          // if a not exact match was found
+          else if (cmatch + cmp > shell->inputdata.cursorpos) {
+            // if this is the first one
+            if (fill == shell->line) {
+              cmatch += cmp;
+              fill = cmd->name;
+            }
+            // if this is a worse one
+            else if ((cmp < 0) || (cmp == 0 && mlvl == CHAR_MATCH_CASE)) {
+              cmatch += cmp;
+            }
+          }
+          // non matching commands are ignored
+          else {}
+        }
+        // evaluate if there are case mismatches
+        n = cmatch;
+        _strccmp(shell->line, fill, shell->config & AOS_SHELL_CONFIG_MATCH_CASE, &n, &matchlevel);
+        // print the auto fill if any
+        if (cmatch > shell->inputdata.cursorpos || (cmatch == shell->inputdata.cursorpos && matchlevel == CHAR_MATCH_NCASE)) {
+          shell->inputdata.noinput = false;
+          // limit auto fill so it will not overflow the line width
+          if (shell->inputdata.lineend + (cmatch - shell->inputdata.cursorpos) > shell->linesize) {
+            cmatch = shell->linesize - shell->inputdata.lineend + shell->inputdata.cursorpos;
+          }
+          // move trailing memory further in the line
+          memmove(&(shell->line[cmatch]), &(shell->line[shell->inputdata.cursorpos]), shell->inputdata.lineend - shell->inputdata.cursorpos);
+          shell->inputdata.lineend += cmatch - shell->inputdata.cursorpos;
+          // if there was no incorrect case when matching
+          if (matchlevel == CHAR_MATCH_CASE) {
+            // insert fill command name to line
+            memcpy(&(shell->line[shell->inputdata.cursorpos]), &(fill[shell->inputdata.cursorpos]), cmatch - shell->inputdata.cursorpos);
+            // print the output
+            _printLine(shell, shell->inputdata.cursorpos, shell->inputdata.lineend);
+          } else {
+            // overwrite line with fill command name
+            memcpy(shell->line, fill, cmatch);
+            // reprint the whole line
+            _moveCursor(shell, shell->inputdata.cursorpos, 0);
+            _printLine(shell, 0, shell->inputdata.lineend);
+          }
+          // move cursor to the end of the matching sequence
+          shell->inputdata.cursorpos = cmatch;
+          _moveCursor(shell, shell->inputdata.lineend, shell->inputdata.cursorpos);
+        }
+        break;
+      }
+
+      case AOS_SHELL_ACTION_SUGGEST:
+      {
+        unsigned int matches = 0;
+        // iterate through command list
+        for (aos_shellcommand_t* cmd = shell->commands; cmd != NULL; cmd = cmd->next) {
+          // compare line content with command, excpet if cursorpos=0
+          size_t i = shell->inputdata.cursorpos;
+          if (shell->inputdata.cursorpos > 0) {
+            _strccmp(shell->line, cmd->name, true, &i, NULL);
+          }
+          const int cmp = (i < shell->inputdata.cursorpos) ?
+                            (i - shell->inputdata.cursorpos) :
+                            (cmd->name[i] != '\0') ?
+                              strlen(cmd->name) - i :
+                              0;
+          // if a match was found
+          if (cmp > 0) {
+            // if this is the first one
+            if (matches == 0) {
+              _moveCursor(shell, shell->inputdata.cursorpos, shell->inputdata.lineend);
+              streamPut(&shell->stream, '\n');
+            }
+            // print the command
+            chprintf((BaseSequentialStream*)&shell->stream, "\t%s\n", cmd->name);
+            ++matches;
+          }
+        }
+        // reprint the prompt and line if any matches have been found
+        if (matches > 0) {
+          _printPrompt(shell);
+          _printLine(shell, 0, shell->inputdata.lineend);
+          _moveCursor(shell, shell->inputdata.lineend, shell->inputdata.cursorpos);
+          shell->inputdata.noinput = false;
+        }
+        break;
+      }
+
+      case AOS_SHELL_ACTION_INSERTTOGGLE:
+      {
+        if (shell->config & AOS_SHELL_CONFIG_INPUT_OVERWRITE) {
+          shell->config &= ~AOS_SHELL_CONFIG_INPUT_OVERWRITE;
+        } else {
+          shell->config |= AOS_SHELL_CONFIG_INPUT_OVERWRITE;
+        }
+        break;
+      }
+
+      case AOS_SHELL_ACTION_DELETEFORWARD:
+      {
+        --shell->inputdata.lineend;
+        memmove(&(shell->line[shell->inputdata.cursorpos]), &(shell->line[shell->inputdata.cursorpos+1]), shell->inputdata.lineend - shell->inputdata.cursorpos);
+        _printLine(shell, shell->inputdata.cursorpos, shell->inputdata.lineend);
+        streamPut(&shell->stream, ' ');
+        _moveCursor(shell, shell->inputdata.lineend + 1, shell->inputdata.cursorpos);
+        break;
+      }
+
+      case AOS_SHELL_ACTION_DELETEBACKWARD:
+      {
+        --shell->inputdata.cursorpos;
+        memmove(&(shell->line[shell->inputdata.cursorpos]), &(shell->line[shell->inputdata.cursorpos+1]), shell->inputdata.lineend - shell->inputdata.cursorpos);
+        --shell->inputdata.lineend;
+        shell->line[shell->inputdata.lineend] = '\0';
+        _moveCursor(shell, shell->inputdata.cursorpos + 1, shell->inputdata.cursorpos);
+        _printLine(shell, shell->inputdata.cursorpos, shell->inputdata.lineend);
+        streamPut(&shell->stream, ' ');
+        _moveCursor(shell, shell->inputdata.lineend+1, shell->inputdata.cursorpos);
+        break;
+      }
+
+      case AOS_SHELL_ACTION_RECALLLAST:
+      {
+        // replace any intermediate NUL bytes with spaces
+        shell->inputdata.lineend = 0;
+        size_t nul_start = 0;
+        size_t nul_end = 0;
+        // search line for a NUL byte
+        while (nul_start < shell->linesize) {
+          if (shell->line[nul_start] == '\0') {
+            nul_end = nul_start + 1;
+            // keep searcjing for a byte that is not NUL
+            while (nul_end < shell->linesize) {
+              if (shell->line[nul_end] != '\0') {
+                // an intermediate NUL sequence was found
+                memset(&(shell->line[nul_start]), ' ', nul_end - nul_start);
+                shell->inputdata.lineend = nul_end + 1;
+                break;
+              } else {
+                ++nul_end;
+              }
+            }
+            nul_start = nul_end + 1;
+          } else {
+            ++shell->inputdata.lineend;
+            ++nul_start;
+          }
+        }
+        shell->inputdata.cursorpos = shell->inputdata.lineend;
+        // print the line
+        shell->inputdata.noinput = _printLine(shell, 0, shell->inputdata.lineend) == 0;
+        break;
+      }
+
+      case AOS_SHELL_ACTION_CLEAR:
+      {
+        // clear output
+        _moveCursor(shell, shell->inputdata.cursorpos, 0);
+        for (shell->inputdata.cursorpos = 0; shell->inputdata.cursorpos < shell->inputdata.lineend; ++shell->inputdata.cursorpos) {
+          streamPut(&shell->stream, ' ');
+        }
+        _moveCursor(shell, shell->inputdata.lineend, 0);
+        shell->inputdata.cursorpos = 0;
+        shell->inputdata.lineend = 0;
+        shell->inputdata.noinput = true;
+        break;
+      }
+
+      case AOS_SHELL_ACTION_CURSOR2START:
+      {
+        _moveCursor(shell, shell->inputdata.cursorpos, 0);
+        shell->inputdata.cursorpos = 0;
+        break;
+      }
+
+      case AOS_SHELL_ACTION_CURSOR2END:
+      {
+        _moveCursor(shell, shell->inputdata.cursorpos, shell->inputdata.lineend);
+        shell->inputdata.cursorpos = shell->inputdata.lineend;
+        break;
+      }
+
+      case AOS_SHELL_ACTION_CURSORLEFT:
+      {
+        _moveCursor(shell, shell->inputdata.cursorpos, shell->inputdata.cursorpos-1);
+        --shell->inputdata.cursorpos;
+        break;
+      }
+
+      case AOS_SHELL_ACTION_CURSORRIGHT:
+      {
+        _moveCursor(shell, shell->inputdata.cursorpos, shell->inputdata.cursorpos+1);
+        ++shell->inputdata.cursorpos;
+        break;
+      }
+
+      case AOS_SHELL_ACTION_EXECUTE:
+      {
+        streamPut(&shell->stream, '\n');
+        // set the number of read bytes and return
+        if (!shell->inputdata.noinput) {
+          *n = shell->linesize - shell->inputdata.lineend;
+          // fill the remainder of the line with NUL bytes
+          memset(&(shell->line[shell->inputdata.lineend]), '\0', *n);
+          // reset static variables
+          shell->inputdata.noinput = true;
+        }
+        return AOS_SUCCESS;
+        break;
+      }
+
+      case AOS_SHELL_ACTION_ESCSTART:
+      {
+        shell->inputdata.escseq[0] = c;
+        ++shell->inputdata.escp;
+        break;
+      }
+
+      case AOS_SHELL_ACTION_NONE:
+      default:
+      {
+        // do nothing (ignore input) and read next byte
+        continue;
+        break;
+      }
+    } /* end of switch */
+
+    shell->inputdata.lastaction = action;
+  } /* end of while */
+
+  // no more data could be read from the channel
+  return AOS_WARNING;
+}
+
+/**
+ * @brief   Parses the content of the input buffer (line) to separate arguments.
+ *
+ * @param[in] shell   Pointer to the shell object.
+ *
+ * @return            Number of arguments found.
+ */
+static size_t _parseArguments(aos_shell_t* shell)
+{
+  aosDbgCheck(shell != NULL);
+
+  /*
+   * States for a very small FSM.
+   */
+  typedef enum {
+    START,
+    SPACE,
+    TEXT,
+    END,
+  } state_t;
+
+  // local variables
+  state_t state = START;
+  size_t arg = 0;
+
+  // iterate through the line
+  for (char* c = shell->line; c < shell->line + shell->linesize; ++c) {
+    // terminate at first NUL byte
+    if (*c == '\0') {
+      state = END;
+      break;
+    }
+    // spaces become NUL bytes
+    else if (*c == ' ') {
+      *c = '\0';
+      state = SPACE;
+    }
+    // handle non-NUL bytes
+    else {
+      switch (state) {
+        case START:
+        case SPACE:
+          // ignore too many arguments
+          if (arg < shell->arglistsize) {
+            shell->arglist[arg] = c;
+          }
+          ++arg;
+          break;
+        case TEXT:
+        case END:
+        default:
+          break;
+      }
+      state = TEXT;
+    }
+  }
+
+  // set all remaining argument pointers to NULL
+  for (size_t a = arg; a < shell->arglistsize; ++a) {
+    shell->arglist[a] = NULL;
+  }
+
+  return arg;
+}
+
+/**
+ * @brief   Initializes a shell object with the specified parameters.
+ *
+ * @param[in] shell         Pointer to the shell object.
+ * @param[in] stream        I/O stream to use.
+ * @param[in] prompt        Prompt line to print (NULL = use default prompt).
+ * @param[in] line          Pointer to the input buffer.
+ * @param[in] linesize      Size of the input buffer.
+ * @param[in] arglist       Pointer to the argument buffer.
+ * @param[in] arglistsize   Size of te argument buffer.
+ */
+void aosShellInit(aos_shell_t* shell, event_source_t* oseventsource,  const char* prompt, char* line, size_t linesize, char** arglist, size_t arglistsize)
+{
+  aosDbgCheck(shell != NULL);
+  aosDbgCheck(oseventsource != NULL);
+  aosDbgCheck(line != NULL);
+  aosDbgCheck(arglist != NULL);
+
+  // set parameters
+  shell->thread = NULL;
+  chEvtObjectInit(&shell->eventSource);
+  shell->os.eventSource = oseventsource;
+  aosShellStreamInit(&shell->stream);
+  shell->prompt = prompt;
+  shell->commands = NULL;
+  shell->execstatus.command = NULL;
+  shell->execstatus.retval = 0;
+  shell->line = line;
+  shell->linesize = linesize;
+  shell->inputdata.lastaction = AOS_SHELL_ACTION_NONE;
+  shell->inputdata.escp = 0;
+  memset(shell->inputdata.escseq, '\0', sizeof(shell->inputdata.escseq)*sizeof(shell->inputdata.escseq[0]));
+  shell->inputdata.cursorpos = 0;
+  shell->inputdata.lineend = 0;
+  shell->inputdata.noinput = true;
+  shell->arglist = arglist;
+  shell->arglistsize = arglistsize;
+  shell->config = 0x00;
+
+  // initialize arrays
+  memset(shell->line, '\0', shell->linesize);
+  for (size_t a = 0; a < shell->arglistsize; ++a) {
+    shell->arglist[a] = NULL;
+  }
+
+  return;
+}
+
+/**
+ * @brief   Initialize an AosShellStream object.
+ *
+ * @param[in] stream  The AosShellStrem to initialize.
+ */
+void aosShellStreamInit(AosShellStream* stream)
+{
+  aosDbgCheck(stream != NULL);
+
+  stream->vmt = &_streamvmt;
+  stream->channel = NULL;
+
+  return;
+}
+
+/**
+ * @brief   Initialize an AosShellChannel object with the specified parameters.
+ *
+ * @param[in] channel       The AosShellChannel to initialize.
+ * @param[in] asyncchannel  An BaseAsynchronousChannel this AosShellChannel is associated with.
+ */
+void aosShellChannelInit(AosShellChannel* channel, BaseAsynchronousChannel* asyncchannel)
+{
+  aosDbgCheck(channel != NULL);
+  aosDbgCheck(asyncchannel != NULL);
+
+  channel->vmt = &_channelvmt;
+  channel->asyncchannel = asyncchannel;
+  channel->listener.wflags = 0;
+  channel->next = NULL;
+  channel->flags = 0;
+
+  return;
+}
+
+/**
+ * @brief   Inserts a command to the shells list of commands.
+ *
+ * @param[in] shell   Pointer to the shell object.
+ * @param[in] cmd     Pointer to the command to add.
+ *
+ * @return            A status value.
+ * @retval AOS_SUCCESS  The command was added successfully.
+ * @retval AOS_ERROR    Another command with identical name already exists.
+ */
+aos_status_t aosShellAddCommand(aos_shell_t *shell, aos_shellcommand_t *cmd)
+{
+  aosDbgCheck(shell != NULL);
+  aosDbgCheck(cmd != NULL);
+  aosDbgCheck(cmd->name != NULL && strlen(cmd->name) > 0 && strchr(cmd->name, ' ') == NULL && strchr(cmd->name, '\t') == NULL);
+  aosDbgCheck(cmd->callback != NULL);
+  aosDbgCheck(cmd->next == NULL);
+
+  aos_shellcommand_t* prev = NULL;
+  aos_shellcommand_t** curr = &(shell->commands);
+
+  // insert the command to the list wrt lexographical order (exception: lower case characters preceed upper their uppercase counterparts)
+  while (*curr != NULL) {
+    // iterate through the list as long as the command names are 'smaller'
+    const int cmp = _strccmp((*curr)->name, cmd->name, true, NULL, NULL);
+    if (cmp < 0) {
+      prev = *curr;
+      curr = &((*curr)->next);
+      continue;
+    }
+    // error if the command already exists
+    else if (cmp == 0) {
+      return AOS_ERROR;
+    }
+    // insert the command as soon as a 'larger' name was found
+    else /* if (cmpval > 0) */ {
+      cmd->next = *curr;
+      // special case: the first command is larger
+      if (prev == NULL) {
+        shell->commands = cmd;
+      } else {
+        prev->next = cmd;
+      }
+      return AOS_SUCCESS;
+    }
+  }
+  // the end of the list has been reached
+
+  // append the command
+  *curr = cmd;
+  return AOS_SUCCESS;
+}
+
+/**
+ * @brief   Removes a command from the shells list of commands.
+ *
+ * @param[in] shell     Pointer to the shell object.
+ * @param[in] cmd       Name of the command to removde.
+ * @param[out] removed  Optional pointer to the command that was removed.
+ *
+ * @return              A status value.
+ * @retval AOS_SUCCESS  The command was removed successfully.
+ * @retval AOS_ERROR    The command name was not found.
+ */
+aos_status_t aosShellRemoveCommand(aos_shell_t *shell, char *cmd, aos_shellcommand_t **removed)
+{
+  aosDbgCheck(shell != NULL);
+  aosDbgCheck(cmd != NULL && strlen(cmd) > 0);
+
+  aos_shellcommand_t* prev = NULL;
+  aos_shellcommand_t** curr = &(shell->commands);
+
+  // iterate through the list and seach for the specified command name
+  while (curr != NULL) {
+    const int cmpval = strcmp((*curr)->name, cmd);
+    // iterate through the list as long as the command names are 'smaller'
+    if (cmpval < 0) {
+      prev = *curr;
+      curr = &((*curr)->next);
+      continue;
+    }
+    // remove the command when found
+    else if (cmpval == 0) {
+      // special case: the first command matches
+      if (prev == NULL) {
+        shell->commands = (*curr)->next;
+      } else {
+        prev->next = (*curr)->next;
+      }
+      (*curr)->next = NULL;
+      // set the optional output argument
+      if (removed != NULL) {
+        *removed = *curr;
+      }
+      return AOS_SUCCESS;
+    }
+    // break the loop if the command names are 'larger'
+    else /* if (cmpval > 0) */ {
+      break;
+    }
+  }
+
+  // if the command was not found, return an error
+  return AOS_ERROR;
+}
+
+/**
+ * @brief   Add a channel to a AosShellStream.
+ *
+ * @param[in] stream    The AosShellStream to extend.
+ * @param[in] channel   The channel to be added to the stream.
+ */
+void aosShellStreamAddChannel(AosShellStream* stream, AosShellChannel* channel)
+{
+  aosDbgCheck(stream != NULL);
+  aosDbgCheck(channel != NULL && channel->asyncchannel != NULL && channel->next == NULL && (channel->flags & AOS_SHELLCHANNEL_ATTACHED) == 0);
+
+  // prepend the new channel
+  chSysLock();
+  channel->flags |= AOS_SHELLCHANNEL_ATTACHED;
+  channel->next = stream->channel;
+  stream->channel = channel;
+  chSysUnlock();
+
+  return;
+}
+
+/**
+ * @brief   Remove a channel from an AosShellStream.
+ *
+ * @param[in] stream    The AosShellStream to modify.
+ * @param[in] channel   The channel to remove.
+ * @return
+ */
+aos_status_t aosShellStreamRemoveChannel(AosShellStream* stream, AosShellChannel* channel)
+{
+  aosDbgCheck(stream != NULL);
+  aosDbgCheck(channel != NULL && channel->asyncchannel != NULL && channel->flags & AOS_SHELLCHANNEL_ATTACHED);
+
+  // local varibales
+  AosShellChannel* prev = NULL;
+  AosShellChannel* curr = stream->channel;
+
+  // iterate through the list and search for the specified channel
+  while (curr != NULL) {
+    // if the channel was found
+    if (curr == channel) {
+      chSysLock();
+      // special case: the first channel matches (prev is NULL)
+      if (prev == NULL) {
+        stream->channel = curr->next;
+      } else {
+        prev->next = channel->next;
+      }
+      curr->next = NULL;
+      curr->flags &= ~AOS_SHELLCHANNEL_ATTACHED;
+      chSysUnlock();
+      return AOS_SUCCESS;
+    }
+  }
+
+  // if the channel was not found, return an error
+  return AOS_ERROR;
+}
+
+/**
+ * @brief   Enable a AosSheööChannel as input.
+ *
+ * @param[in] channel   The channel to enable as input.
+ */
+void aosShellChannelInputEnable(AosShellChannel* channel)
+{
+  aosDbgCheck(channel != NULL && channel->asyncchannel != NULL);
+
+  chSysLock();
+  channel->listener.wflags |= CHN_INPUT_AVAILABLE;
+  channel->flags |= AOS_SHELLCHANNEL_INPUT_ENABLED;
+  chSysUnlock();
+
+  return;
+}
+
+/**
+ * @brief   Disable a AosSheööChannel as input.
+ *
+ * @param[in] channel   The channel to disable as input.
+ */
+void aosShellChannelInputDisable( AosShellChannel* channel)
+{
+  aosDbgCheck(channel != NULL && channel->asyncchannel != NULL);
+
+  chSysLock();
+  channel->listener.wflags &= ~CHN_INPUT_AVAILABLE;
+  channel->flags &= ~AOS_SHELLCHANNEL_INPUT_ENABLED;
+  chSysUnlock();
+
+  return;
+}
+
+/**
+ * @brief   Enable a AosSheööChannel as output.
+ *
+ * @param[in] channel   The channel to enable as output.
+ */
+void aosShellChannelOutputEnable(AosShellChannel* channel)
+{
+  aosDbgCheck(channel != NULL && channel->asyncchannel != NULL);
+
+  channel->flags |= AOS_SHELLCHANNEL_OUTPUT_ENABLED;
+
+  return;
+}
+
+/**
+ * @brief   Disable a AosSheööChannel as output.
+ *
+ * @param[in] channel   The channel to disable as output.
+ */
+void aosShellChannelOutputDisable(AosShellChannel* channel)
+{
+  aosDbgCheck(channel != NULL && channel->asyncchannel != NULL);
+
+  channel->flags &= ~AOS_SHELLCHANNEL_OUTPUT_ENABLED;
+
+  return;
+}
+
+/**
+ * @brief   Thread main function.
+ *
+ * @param[in] aosShellThread    Name of the function;
+ * @param[in] shell             Pointer to the shell object.
+ */
+THD_FUNCTION(aosShellThread, shell)
+{
+  aosDbgCheck(shell != NULL);
+
+  // local variables
+  eventmask_t eventmask;
+  eventflags_t eventflags;
+  AosShellChannel* channel;
+  aos_status_t readeval;
+  size_t nchars = 0;
+  size_t nargs = 0;
+  aos_shellcommand_t* cmd;
+
+
+  // register OS related events
+  chEvtRegisterMask(((aos_shell_t*)shell)->os.eventSource, &(((aos_shell_t*)shell)->os.eventListener), AOS_SHELL_EVENTMASK_OS);
+  // register events to all input channels
+  for (channel = ((aos_shell_t*)shell)->stream.channel; channel != NULL; channel = channel->next) {
+    chEvtRegisterMaskWithFlags(&(channel->asyncchannel->event), &(channel->listener), AOS_SHELL_EVENTMASK_INPUT, channel->listener.wflags);
+  }
+
+  // fire start event
+  chEvtBroadcastFlags(&(((aos_shell_t*)shell)->eventSource), AOS_SHELL_EVTFLAG_START);
+
+  // print the prompt for the first time
+  _printPrompt((aos_shell_t*)shell);
+
+  // enter thread loop
+  while (!chThdShouldTerminateX()) {
+    // wait for event and handle it accordingly
+    eventmask = chEvtWaitOne(ALL_EVENTS);
+
+    // handle event
+    switch (eventmask) {
+
+      // OS related events
+      case AOS_SHELL_EVENTMASK_OS:
+      {
+        eventflags = chEvtGetAndClearFlags(&((aos_shell_t*)shell)->os.eventListener);
+        // handle shutdown/restart events
+        if (eventflags & AOS_SYSTEM_EVENTFLAGS_SHUTDOWN) {
+          chThdTerminate(((aos_shell_t*)shell)->thread);
+        } else {
+          // print an error message
+          chprintf((BaseSequentialStream*)&((aos_shell_t*)shell)->stream, "\nERROR: unknown OS event received (0x%08X)\n", eventflags);
+        }
+        break;
+      }
+
+      // input events
+      case AOS_SHELL_EVENTMASK_INPUT:
+      {
+        // check and handle all channels
+        channel = ((aos_shell_t*)shell)->stream.channel;
+        while (channel != NULL) {
+          eventflags = chEvtGetAndClearFlags(&channel->listener);
+          // if there is new input
+          if (eventflags & CHN_INPUT_AVAILABLE) {
+            // read input from channel
+            readeval = _readChannel((aos_shell_t*)shell, channel, &nchars);
+            // parse input line to argument list only if the input shall be executed
+            nargs = (readeval == AOS_SUCCESS && nchars > 0) ? _parseArguments((aos_shell_t*)shell) : 0;
+            // check number of arguments
+            if (nargs > ((aos_shell_t*)shell)->arglistsize) {
+              // error too many arguments
+              chprintf((BaseSequentialStream*)&((aos_shell_t*)shell)->stream, "\ttoo many arguments\n");
+            } else if (nargs > 0) {
+              // search command list for arg[0] and execute callback
+              cmd = ((aos_shell_t*)shell)->commands;
+              while (cmd != NULL) {
+                if (strcmp(((aos_shell_t*)shell)->arglist[0], cmd->name) == 0) {
+                  ((aos_shell_t*)shell)->execstatus.command = cmd;
+                  chEvtBroadcastFlags(&(((aos_shell_t*)shell)->eventSource), AOS_SHELL_EVTFLAG_EXEC);
+                  ((aos_shell_t*)shell)->execstatus.retval = cmd->callback((BaseSequentialStream*)&((aos_shell_t*)shell)->stream, nargs, ((aos_shell_t*)shell)->arglist);
+                  chEvtBroadcastFlags(&(((aos_shell_t*)shell)->eventSource), AOS_SHELL_EVTFLAG_DONE);
+                  // notify if the command was not successful
+                  if (((aos_shell_t*)shell)->execstatus.retval != 0) {
+                    chprintf((BaseSequentialStream*)&((aos_shell_t*)shell)->stream, "command returned exit status %d\n", ((aos_shell_t*)shell)->execstatus.retval);
+                  }
+                  break;
+                }
+                cmd = cmd->next;
+              } /* end of while */
+
+              // if no matching command was found, print an error
+              if (cmd == NULL) {
+                chprintf((BaseSequentialStream*)&((aos_shell_t*)shell)->stream, "%s: command not found\n", ((aos_shell_t*)shell)->arglist[0]);
+              }
+            }
+
+            // reset some internal variables and eprint a new prompt
+            if (readeval == AOS_SUCCESS && !chThdShouldTerminateX()) {
+              ((aos_shell_t*)shell)->inputdata.cursorpos = 0;
+              ((aos_shell_t*)shell)->inputdata.lineend = 0;
+              _printPrompt((aos_shell_t*)shell);
+            }
+          }
+
+          // iterate to next channel
+          channel = channel->next;
+        }
+        break;
+      }
+
+      // other events
+      default:
+      {
+        // print an error message
+        chprintf((BaseSequentialStream*)&((aos_shell_t*)shell)->stream, "\nSHELL: ERROR: unknown event received (0x%08X)\n", eventmask);
+        break;
+      }
+
+    } /* end of switch */
+
+  } /* end of while */
+
+  // fire event and exit the thread
+  chSysLock();
+  chEvtBroadcastFlagsI(&(((aos_shell_t*)shell)->eventSource), AOS_SHELL_EVTFLAG_EXIT);
+  chThdExitS(MSG_OK);
+  // no chSysUnlock() required since the thread has been terminated an all waiting threads have been woken up
+}
+
+#endif /* AMIROOS_CFG_SHELL_ENABLE == true */
+
+/** @} */
diff --git a/core/src/aos_system.c b/core/src/aos_system.c
new file mode 100644
index 0000000..ff44afb
--- /dev/null
+++ b/core/src/aos_system.c
@@ -0,0 +1,1048 @@
+/*
+AMiRo-OS is an operating system designed for the Autonomous Mini Robot (AMiRo) platform.
+Copyright (C) 2016..2018  Thomas Schöpping et al.
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @file    aos_system.c
+ * @brief   System code.
+ * @details Contains system initialization and shutdown routines
+ *          and system shell commands.
+ *
+ * @addtogroup aos_system
+ * @{
+ */
+
+#include <aos_system.h>
+
+#include <amiroos.h>
+#include <amiroblt.h>
+#include <module.h>
+#include <string.h>
+#include <stdlib.h>
+#if (AMIROOS_CFG_TESTS_ENABLE == true)
+#include <ch_test.h>
+#include <rt_test_root.h>
+#endif
+
+/**
+ * @brief   Period of the system timer.
+ */
+#define SYSTIMER_PERIOD               (TIME_MAX_SYSTIME - CH_CFG_ST_TIMEDELTA)
+
+/**
+ * @brief   Width of the printable system info text.
+ */
+#define SYSTEM_INFO_WIDTH             70
+
+/**
+ * @brief   Width of the name column of the system info table.
+ */
+#define SYSTEM_INFO_NAMEWIDTH         14
+
+/* forward declarations */
+static void _printSystemInfo(BaseSequentialStream* stream);
+#if (AMIROOS_CFG_SHELL_ENABLE == true)
+static int _shellcmd_configcb(BaseSequentialStream* stream, int argc, char* argv[]);
+static int _shellcmd_infocb(BaseSequentialStream* stream, int argc, char* argv[]);
+static int _shellcmd_shutdowncb(BaseSequentialStream* stream, int argc, char* argv[]);
+#endif /* AMIROOS_CFG_SHELL_ENABLE == true */
+#if (AMIROOS_CFG_TESTS_ENABLE == true)
+static int _shellcmd_kerneltestcb(BaseSequentialStream* stream, int argc, char* argv[]);
+#endif /* AMIROOS_CFG_TESTS_ENABLE == true */
+
+/**
+ * @brief   Timer to accumulate system uptime.
+ */
+static virtual_timer_t _systimer;
+
+/**
+ * @brief   Accumulated system uptime.
+ */
+static aos_timestamp_t _uptime;
+
+/**
+ * @brief   Timer register value of last accumulation.
+ */
+static systime_t _synctime;
+
+#if (AMIROOS_CFG_SSSP_MASTER == true) || defined(__DOXYGEN__)
+/**
+ * @brief   Timer to drive the SYS_SYNC signal for system wide time synchronization according to SSSP.
+ */
+static virtual_timer_t _syssynctimer;
+
+/**
+ * @brief   Last uptime of system wide time synchronization.
+ */
+static aos_timestamp_t _syssynctime;
+#endif
+
+#if ((AMIROOS_CFG_SSSP_MASTER != true) && (AMIROOS_CFG_PROFILE == true)) || defined(__DOXYGEN__)
+/**
+ * @brief   Offset between local clock and system wide synchronization signal.
+ */
+static float _syssyncskew;
+
+/**
+ * @brief   Weighting factor for the low-pass filter used for calculating the @p _syssyncskew value.
+ */
+#define SYSTEM_SYSSYNCSKEW_LPFACTOR   (0.1f / AOS_SYSTEM_TIME_RESOLUTION)
+#endif
+
+#if (AMIROOS_CFG_SHELL_ENABLE == true) || defined(__DOXYGEN__)
+/**
+ * @brief   Shell thread working area.
+ */
+THD_WORKING_AREA(_shell_wa, AMIROOS_CFG_SHELL_STACKSIZE);
+
+/**
+ * @brief   Shell input buffer.
+ */
+static char _shell_line[AMIROOS_CFG_SHELL_LINEWIDTH];
+
+/**
+ * @brief   Shell argument buffer.
+ */
+static char* _shell_arglist[AMIROOS_CFG_SHELL_MAXARGS];
+
+/**
+ * @brief   Shell command to retrieve system information.
+ */
+static aos_shellcommand_t _shellcmd_info = {
+  /* name     */ "module:info",
+  /* callback */ _shellcmd_infocb,
+  /* next     */ NULL,
+};
+
+/**
+ * @brief   Shell command to set or retrieve system configuration.
+ */
+static aos_shellcommand_t _shellcmd_config = {
+  /* name     */ "module:config",
+  /* callback */ _shellcmd_configcb,
+  /* next     */ NULL,
+};
+
+/**
+ * @brief   Shell command to shutdown the system.
+ */
+static aos_shellcommand_t _shellcmd_shutdown = {
+  /* name     */ "system:shutdown",
+  /* callback */ _shellcmd_shutdowncb,
+  /* next     */ NULL,
+};
+#endif /* AMIROOS_CFG_SHELL_ENABLE == true */
+
+#if (AMIROOS_CFG_TESTS_ENABLE == true) || defined(__DOXYGEN__)
+/**
+ * @brief   Shell kommand to run a test of the ChibiOS/RT kernel.
+ */
+static aos_shellcommand_t _shellcmd_kerneltest = {
+  /* name     */ "kernel:test",
+  /* callback */ _shellcmd_kerneltestcb,
+  /* next     */ NULL,
+};
+#endif /* AMIROOS_CFG_TESTS_ENABLE == true */
+
+/**
+ * @brief   Global system object.
+ */
+aos_system_t aos;
+
+/**
+ * @brief   Print a separator line.
+ *
+ * @param[in] stream    Stream to print to or NULL to print to all system streams.
+ * @param[in] c         Character to use.
+ * @param[in] n         Length of the separator line.
+ *
+ * @return  Number of characters printed.
+ */
+static unsigned int _printSystemInfoSeparator(BaseSequentialStream* stream, const char c, const unsigned int n)
+{
+  aosDbgCheck(stream != NULL);
+
+  // print the specified character n times
+  for (unsigned int i = 0; i < n; ++i) {
+    streamPut(stream, c);
+  }
+  streamPut(stream, '\n');
+
+  return n+1;
+}
+
+/**
+ * @brief   Print a system information line.
+ * @details Prints a system information line with the following format:
+ *            "<name>[spaces]fmt"
+ *          The combined width of "<name>[spaces]" can be specified in order to align <fmt> on multiple lines.
+ *          Note that there is not trailing newline added implicitely.
+ *
+ * @param[in] stream      Stream to print to or NULL to print to all system streams.
+ * @param[in] name        Name of the entry/line.
+ * @param[in] namewidth   Width of the name column.
+ * @param[in] fmt         Formatted string of information content.
+ *
+ * @return  Number of characters printed.
+ */
+static unsigned int _printSystemInfoLine(BaseSequentialStream* stream, const char* name, const unsigned int namewidth, const char* fmt, ...)
+{
+  aosDbgCheck(stream != NULL);
+  aosDbgCheck(name != NULL);
+
+  unsigned int n = 0;
+  va_list ap;
+
+  va_start(ap, fmt);
+  n += chprintf(stream, name);
+  while (n < namewidth) {
+    streamPut(stream, ' ');
+    ++n;
+  }
+  n += chvprintf(stream, fmt, ap);
+  va_end(ap);
+
+  streamPut(stream, '\n');
+  ++n;
+
+  return n;
+}
+
+/**
+ * @brief   Prints information about the system.
+ *
+ * @param[in] stream    Stream to print to.
+ */
+static void _printSystemInfo(BaseSequentialStream* stream)
+{
+  aosDbgCheck(stream != NULL);
+
+  // local variables
+  struct tm dt;
+  aosSysGetDateTime(&dt);
+
+  // print static information about module and operating system
+  _printSystemInfoSeparator(stream, '=', SYSTEM_INFO_WIDTH);
+  _printSystemInfoLine(stream, "Module", SYSTEM_INFO_NAMEWIDTH, "%s (v%s)", BOARD_NAME, BOARD_VERSION);
+#ifdef PLATFORM_NAME
+  _printSystemInfoLine(stream, "Platform", SYSTEM_INFO_NAMEWIDTH, "%s", PLATFORM_NAME);
+#endif
+#ifdef PORT_CORE_VARIANT_NAME
+  _printSystemInfoLine(stream, "Core Variant", SYSTEM_INFO_NAMEWIDTH, "%s", PORT_CORE_VARIANT_NAME);
+#endif
+  _printSystemInfoLine(stream, "Architecture", SYSTEM_INFO_NAMEWIDTH, "%s", PORT_ARCHITECTURE_NAME);
+  _printSystemInfoSeparator(stream, '-', SYSTEM_INFO_WIDTH);
+  _printSystemInfoLine(stream, "AMiRo-OS" , SYSTEM_INFO_NAMEWIDTH, "%u.%u.%u %s (SSSP %u.%u)", AMIROOS_VERSION_MAJOR, AMIROOS_VERSION_MINOR, AMIROOS_VERSION_PATCH, AMIROOS_RELEASE_TYPE, AOS_SYSTEM_SSSP_VERSION_MAJOR, AOS_SYSTEM_SSSP_VERSION_MINOR);
+  _printSystemInfoLine(stream, "AMiRo-LLD" , SYSTEM_INFO_NAMEWIDTH, "%u.%u.%u %s (periphAL %u.%u)", AMIRO_LLD_VERSION_MAJOR, AMIRO_LLD_VERSION_MINOR, AMIRO_LLD_VERSION_PATCH, AMIRO_LLD_RELEASE_TYPE, PERIPHAL_VERSION_MAJOR, PERIPHAL_VERSION_MINOR);
+  _printSystemInfoLine(stream, "ChibiOS/RT" , SYSTEM_INFO_NAMEWIDTH, "%u.%u.%u %s", CH_KERNEL_MAJOR, CH_KERNEL_MINOR, CH_KERNEL_PATCH, (CH_KERNEL_STABLE == 1) ? "stable" : "non-stable");
+  _printSystemInfoLine(stream, "ChibiOS/HAL", SYSTEM_INFO_NAMEWIDTH, "%u.%u.%u %s", CH_HAL_MAJOR, CH_HAL_MINOR, CH_HAL_PATCH, (CH_HAL_STABLE == 1) ? "stable" : "non-stable");
+  _printSystemInfoLine(stream, "build type", SYSTEM_INFO_NAMEWIDTH,"%s", (AMIROOS_CFG_DBG == true) ? "debug" : "release");
+  _printSystemInfoLine(stream, "Compiler" , SYSTEM_INFO_NAMEWIDTH, "%s %u.%u.%u", "GCC", __GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__); // TODO: support other compilers than GCC
+  _printSystemInfoLine(stream, "Compiled" , SYSTEM_INFO_NAMEWIDTH, "%s - %s", __DATE__, __TIME__);
+
+  // print static information about the bootloader
+  _printSystemInfoSeparator(stream, '-', SYSTEM_INFO_WIDTH);
+  if (BL_CALLBACK_TABLE_ADDRESS->magicNumber == BL_MAGIC_NUMBER) {
+    _printSystemInfoLine(stream, "AMiRo-BLT", SYSTEM_INFO_NAMEWIDTH, "%u.%u.%u %s (SSSP %u.%u)", BL_CALLBACK_TABLE_ADDRESS->vBootloader.major, BL_CALLBACK_TABLE_ADDRESS->vBootloader.minor, BL_CALLBACK_TABLE_ADDRESS->vBootloader.patch,
+                         (BL_CALLBACK_TABLE_ADDRESS->vBootloader.identifier == BL_VERSION_ID_AMiRoBLT_Release) ? "stable" :
+                         (BL_CALLBACK_TABLE_ADDRESS->vBootloader.identifier == BL_VERSION_ID_AMiRoBLT_ReleaseCandidate) ? "release candidate" :
+                         (BL_CALLBACK_TABLE_ADDRESS->vBootloader.identifier == BL_VERSION_ID_AMiRoBLT_Beta) ? "beta" :
+                         (BL_CALLBACK_TABLE_ADDRESS->vBootloader.identifier == BL_VERSION_ID_AMiRoBLT_Alpha) ? "alpha" :
+                         (BL_CALLBACK_TABLE_ADDRESS->vBootloader.identifier == BL_VERSION_ID_AMiRoBLT_PreAlpha) ? "pre-alpha" :
+                         "<release type unknown>",
+                         BL_CALLBACK_TABLE_ADDRESS->vSSSP.major, BL_CALLBACK_TABLE_ADDRESS->vSSSP.minor);
+    if (BL_CALLBACK_TABLE_ADDRESS->vSSSP.major != AOS_SYSTEM_SSSP_VERSION_MAJOR) {
+      if (stream) {
+        chprintf(stream, "WARNING: Bootloader and AMiRo-OS implement incompatible SSSP versions!\n");
+      } else {
+        aosprintf("WARNING: Bootloader and AMiRo-OS implement incompatible SSSP versions!\n");
+      }
+    }
+    _printSystemInfoLine(stream, "Compiler", SYSTEM_INFO_NAMEWIDTH, "%s %u.%u.%u", (BL_CALLBACK_TABLE_ADDRESS->vCompiler.identifier == BL_VERSION_ID_GCC) ? "GCC" : "<compiler unknown>", BL_CALLBACK_TABLE_ADDRESS->vCompiler.major, BL_CALLBACK_TABLE_ADDRESS->vCompiler.minor, BL_CALLBACK_TABLE_ADDRESS->vCompiler.patch); // TODO: support other compilers than GCC
+  } else {
+    if (stream) {
+      chprintf(stream, "Bootloader incompatible or not available.\n");
+    } else {
+      aosprintf("Bootloader incompatible or not available.\n");
+    }
+  }
+
+  // print dynamic information about the module
+  _printSystemInfoSeparator(stream, '-', SYSTEM_INFO_WIDTH);
+  if (aos.sssp.moduleId != 0) {
+    _printSystemInfoLine(stream, "Module ID", SYSTEM_INFO_NAMEWIDTH, "%u", aos.sssp.moduleId);
+  } else {
+    _printSystemInfoLine(stream, "Module ID", SYSTEM_INFO_NAMEWIDTH, "not available");
+  }
+  _printSystemInfoLine(stream, "Date", SYSTEM_INFO_NAMEWIDTH, "%s %02u-%02u-%04u", (dt.tm_wday == 0) ? "Sunday" : (dt.tm_wday == 1) ? "Monday" : (dt.tm_wday == 2) ? "Tuesday" : (dt.tm_wday == 3) ? "Wednesday" : (dt.tm_wday == 4) ? "Thursday" : (dt.tm_wday == 5) ? "Friday" : "Saturday",
+                       dt.tm_mday,
+                       dt.tm_mon + 1,
+                       dt.tm_year + 1900);
+  _printSystemInfoLine(stream, "Time", SYSTEM_INFO_NAMEWIDTH, "%02u:%02u:%02u", dt.tm_hour, dt.tm_min, dt.tm_sec);
+
+  _printSystemInfoSeparator(stream, '=', SYSTEM_INFO_WIDTH);
+
+  return;
+}
+
+#if (AMIROOS_CFG_SHELL_ENABLE == true) || defined(__DOXYGEN__)
+/**
+ * @brief   Callback function for the system:config shell command.
+ *
+ * @param[in] stream    The I/O stream to use.
+ * @param[in] argc      Number of arguments.
+ * @param[in] argv      List of pointers to the arguments.
+ *
+ * @return              An exit status.
+ * @retval  AOS_OK                  The command was executed successfuly.
+ * @retval  AOS_INVALID_ARGUMENTS   There was an issue with the arguemnts.
+ */
+static int _shellcmd_configcb(BaseSequentialStream* stream, int argc, char* argv[])
+{
+  aosDbgCheck(stream != NULL);
+
+  // local variables
+  int retval = AOS_INVALID_ARGUMENTS;
+
+  // if there are additional arguments
+  if (argc > 1) {
+    // if the user wants to set or retrieve the shell configuration
+    if (strcmp(argv[1], "--shell") == 0) {
+      // if the user wants to modify the shell configuration
+      if (argc > 2) {
+        // if the user wants to modify the prompt
+        if (strcmp(argv[2], "prompt") == 0) {
+          // there must be a further argument
+          if (argc > 3) {
+            // handle the option
+            if (strcmp(argv[3], "text") == 0) {
+              aos.shell.config &= ~AOS_SHELL_CONFIG_PROMPT_MINIMAL;
+              retval = AOS_OK;
+            }
+            else if (strcmp(argv[3], "minimal") == 0) {
+              aos.shell.config |= AOS_SHELL_CONFIG_PROMPT_MINIMAL;
+              retval = AOS_OK;
+            }
+            else if (strcmp(argv[3], "notime") == 0) {
+              aos.shell.config &= ~(AOS_SHELL_CONFIG_PROMPT_UPTIME | AOS_SHELL_CONFIG_PROMPT_DATETIME);
+              retval = AOS_OK;
+            }
+            else if (strcmp(argv[3], "uptime") == 0) {
+              aos.shell.config &= ~AOS_SHELL_CONFIG_PROMPT_DATETIME;
+              aos.shell.config |= AOS_SHELL_CONFIG_PROMPT_UPTIME;
+              retval = AOS_OK;
+            }
+            else if (strcmp(argv[3], "date&time") == 0) {
+              aos.shell.config &= ~AOS_SHELL_CONFIG_PROMPT_UPTIME;
+              aos.shell.config |= AOS_SHELL_CONFIG_PROMPT_DATETIME;
+              retval = AOS_OK;
+            }
+            else {
+              chprintf(stream, "unknown option '%s'\n", argv[3]);
+              return AOS_INVALID_ARGUMENTS;
+            }
+          }
+        }
+        // if the user wants to modify the string matching
+        else if (strcmp(argv[2], "match") == 0) {
+          // there must be a further argument
+          if (argc > 3) {
+            if (strcmp(argv[3], "casesensitive") == 0) {
+              aos.shell.config |= AOS_SHELL_CONFIG_MATCH_CASE;
+              retval = AOS_OK;
+            }
+            else if (strcmp(argv[3], "caseinsensitive") == 0) {
+              aos.shell.config &= ~AOS_SHELL_CONFIG_MATCH_CASE;
+              retval = AOS_OK;
+            }
+          }
+        }
+      }
+      // if the user wants to retrieve the shell configuration
+      else {
+        chprintf(stream, "current shell configuration:\n");
+        chprintf(stream, "  prompt text:   %s\n",
+                 (aos.shell.prompt != NULL) ? aos.shell.prompt : "n/a");
+        char time[10];
+        switch (aos.shell.config & (AOS_SHELL_CONFIG_PROMPT_UPTIME | AOS_SHELL_CONFIG_PROMPT_DATETIME)) {
+          case AOS_SHELL_CONFIG_PROMPT_UPTIME:
+            strcpy(time, "uptime"); break;
+          case AOS_SHELL_CONFIG_PROMPT_DATETIME:
+            strcpy(time, "date&time"); break;
+          default:
+            strcpy(time, "no time"); break;
+        }
+        chprintf(stream, "  prompt style:  %s, %s\n",
+                 (aos.shell.config & AOS_SHELL_CONFIG_PROMPT_MINIMAL) ? "minimal" : "text",
+                 time);
+        chprintf(stream, "  input method:  %s\n",
+                 (aos.shell.config & AOS_SHELL_CONFIG_INPUT_OVERWRITE) ? "replace" : "insert");
+        chprintf(stream, "  text matching: %s\n",
+                 (aos.shell.config & AOS_SHELL_CONFIG_MATCH_CASE) ? "case sensitive" : "case insensitive");
+        retval = AOS_OK;
+      }
+    }
+    // if the user wants to configure the date or time
+    else if (strcmp(argv[1], "--date&time") == 0 && argc == 4) {
+      struct tm dt;
+      aosSysGetDateTime(&dt);
+      unsigned int val = atoi(argv[3]);
+      if (strcmp(argv[2], "year") == 0) {
+        dt.tm_year = val - 1900;
+      }
+      else if (strcmp(argv[2], "month") == 0 && val <= 12) {
+        dt.tm_mon = val - 1;
+      }
+      else if (strcmp(argv[2], "day") == 0 && val <= 31) {
+        dt.tm_mday = val;
+      }
+      else if (strcmp(argv[2], "hour") == 0 && val < 24) {
+        dt.tm_hour = val;
+      }
+      else if (strcmp(argv[2], "minute") == 0 && val < 60) {
+        dt.tm_min = val;
+      }
+      else if (strcmp(argv[2], "second") == 0 && val < 60) {
+        dt.tm_sec = val;
+      }
+      else {
+        chprintf(stream, "unknown option '%s' or value '%s'\n", argv[2], argv[3]);
+        return AOS_INVALID_ARGUMENTS;
+      }
+      dt.tm_wday = aosTimeDayOfWeekFromDate(dt.tm_mday, dt.tm_mon+1, dt.tm_year+1900) % 7;
+      aosSysSetDateTime(&dt);
+
+      // read and print new date and time
+      aosSysGetDateTime(&dt);
+      chprintf(stream, "date/time set to %02u:%02u:%02u @ %02u-%02u-%04u\n",
+               dt.tm_hour, dt.tm_min, dt.tm_sec,
+               dt.tm_mday, dt.tm_mon+1, dt.tm_year+1900);
+
+      retval = AOS_OK;
+    }
+  }
+
+  // print help, if required
+  if (retval == AOS_INVALID_ARGUMENTS) {
+    chprintf(stream, "Usage: %s OPTION\n", argv[0]);
+    chprintf(stream, "Options:\n");
+    chprintf(stream, "  --help\n");
+    chprintf(stream, "    Print this help text.\n");
+    chprintf(stream, "  --shell [OPT [VAL]]\n");
+    chprintf(stream, "    Set or retrieve shell configuration.\n");
+    chprintf(stream, "    Possible OPTs and VALs are:\n");
+    chprintf(stream, "      prompt text|minimal|uptime|date&time|notime\n");
+    chprintf(stream, "        Configures the prompt.\n");
+    chprintf(stream, "      match casesensitive|caseinsenitive\n");
+    chprintf(stream, "        Configures string matching.\n");
+    chprintf(stream, "  --date&time OPT VAL\n");
+    chprintf(stream, "    Set the date/time value of OPT to VAL.\n");
+    chprintf(stream, "    Possible OPTs are:\n");
+    chprintf(stream, "      year\n");
+    chprintf(stream, "      month\n");
+    chprintf(stream, "      day\n");
+    chprintf(stream, "      hour\n");
+    chprintf(stream, "      minute\n");
+    chprintf(stream, "      second\n");
+  }
+
+  return (argc > 1 && strcmp(argv[1], "--help") == 0) ? AOS_OK : retval;
+}
+
+/**
+ * @brief   Callback function for the system:info shell command.
+ *
+ * @param[in] stream    The I/O stream to use.
+ * @param[in] argc      Number of arguments.
+ * @param[in] argv      List of pointers to the arguments.
+ *
+ * @return            An exit status.
+ * @retval  AOS_OK    The command was executed successfully.
+ */
+static int _shellcmd_infocb(BaseSequentialStream* stream, int argc, char* argv[])
+{
+  aosDbgCheck(stream != NULL);
+
+  (void)argc;
+  (void)argv;
+
+  // print system information
+  _printSystemInfo(stream);
+
+  // print time measurement precision
+  chprintf(stream, "module time resolution: %uus\n", AOS_SYSTEM_TIME_RESOLUTION);
+
+  // print system uptime
+  aos_timestamp_t uptime;
+  aosSysGetUptime(&uptime);
+  chprintf(stream, "The system is running for\n");
+  chprintf(stream, "%10u days\n", (uint32_t)(uptime / MICROSECONDS_PER_DAY));
+  chprintf(stream, "%10u hours\n", (uint8_t)(uptime % MICROSECONDS_PER_DAY / MICROSECONDS_PER_HOUR));
+  chprintf(stream, "%10u minutes\n", (uint8_t)(uptime % MICROSECONDS_PER_HOUR / MICROSECONDS_PER_MINUTE));
+  chprintf(stream, "%10u seconds\n", (uint8_t)(uptime % MICROSECONDS_PER_MINUTE / MICROSECONDS_PER_SECOND));
+  chprintf(stream, "%10u milliseconds\n", (uint16_t)(uptime % MICROSECONDS_PER_SECOND / MICROSECONDS_PER_MILLISECOND));
+  chprintf(stream, "%10u microseconds\n", (uint16_t)(uptime % MICROSECONDS_PER_MILLISECOND / MICROSECONDS_PER_MICROSECOND));
+#if (AMIROOS_CFG_SSSP_MASTER != true) && (AMIROOS_CFG_PROFILE == true)
+  chprintf(stream, "SSSP synchronization offset: %.3fus per %uus\n", _syssyncskew, AMIROOS_CFG_SSSP_SYSSYNCPERIOD);
+#endif
+  _printSystemInfoSeparator(stream, '=', SYSTEM_INFO_WIDTH);
+
+  return AOS_OK;
+}
+
+/**
+ * @brief   Callback function for the sytem:shutdown shell command.
+ *
+ * @param[in] stream    The I/O stream to use.
+ * @param[in] argc      Number of arguments.
+ * @param[in] argv      List of pointers to the arguments.
+ *
+ * @return              An exit status.
+ * @retval  AOS_OK                  The command was executed successfully.
+ * @retval  AOS_INVALID_ARGUMENTS   There was an issue with the arguments.
+ */
+static int _shellcmd_shutdowncb(BaseSequentialStream* stream, int argc, char* argv[])
+{
+  aosDbgCheck(stream != NULL);
+
+  // print help text
+  if (argc != 2 || strcmp(argv[1], "--help") == 0) {
+    chprintf(stream, "Usage: %s OPTION\n", argv[0]);
+    chprintf(stream, "Options:\n");
+    chprintf(stream, "  --help\n");
+    chprintf(stream, "    Print this help text.\n");
+    chprintf(stream, "  --hibernate, -h\n");
+    chprintf(stream, "    Shutdown to hibernate mode.\n");
+    chprintf(stream, "    Least energy saving, but allows charging via pins.\n");
+    chprintf(stream, "  --deepsleep, -d\n");
+    chprintf(stream, "    Shutdown to deepsleep mode.\n");
+    chprintf(stream, "    Minimum energy consumption while allowing charging via plug.\n");
+    chprintf(stream, "  --transportation, -t\n");
+    chprintf(stream, "    Shutdown to transportation mode.\n");
+    chprintf(stream, "    Minimum energy consumption with all interrupts disabled (no charging).\n");
+    chprintf(stream, "  --restart, -r\n");
+    chprintf(stream, "    Shutdown and restart system.\n");
+
+    return (argc != 2) ? AOS_INVALID_ARGUMENTS : AOS_OK;
+  }
+  // handle argument
+  else {
+    if (strcmp(argv[1], "-h") == 0 || strcmp(argv[1], "--hibernate") == 0) {
+      chEvtBroadcastFlags(&aos.events.os, AOS_SYSTEM_EVENTFLAGS_HIBERNATE);
+      chThdTerminate(currp);
+      return AOS_OK;
+    }
+    else if (strcmp(argv[1], "-d") == 0 || strcmp(argv[1], "--deepsleep") == 0) {
+      chEvtBroadcastFlags(&aos.events.os, AOS_SYSTEM_EVENTFLAGS_DEEPSLEEP);
+      chThdTerminate(currp);
+      return AOS_OK;
+    }
+    else if (strcmp(argv[1], "-t") == 0 || strcmp(argv[1], "--transportation") == 0) {
+      chEvtBroadcastFlags(&aos.events.os, AOS_SYSTEM_EVENTFLAGS_TRANSPORTATION);
+      chThdTerminate(currp);
+      return AOS_OK;
+    }
+    else if (strcmp(argv[1], "-r") == 0 || strcmp(argv[1], "--restart") == 0) {
+      chEvtBroadcastFlags(&aos.events.os, AOS_SYSTEM_EVENTFLAGS_RESTART);
+      chThdTerminate(currp);
+      return AOS_OK;
+    }
+    else {
+      chprintf(stream, "unknown argument %s\n", argv[1]);
+      return AOS_INVALID_ARGUMENTS;
+    }
+  }
+}
+#endif /* AMIROOS_CFG_SHELL_ENABLE == true */
+
+#if (AMIROOS_CFG_TESTS_ENABLE == true) || defined(__DOXYGEN__)
+/**
+ * @brief   Callback function for the kernel:test shell command.
+ *
+ * @param[in] stream    The I/O stream to use.
+ * @param[in] argc      Number of arguments.
+ * @param[in] argv      List of pointers to the arguments.
+ *
+ * @return      An exit status.
+ */
+static int _shellcmd_kerneltestcb(BaseSequentialStream* stream, int argc, char* argv[])
+{
+  aosDbgCheck(stream != NULL);
+
+  (void)argc;
+  (void)argv;
+
+  msg_t retval = test_execute(stream, &rt_test_suite);
+
+  return retval;
+}
+#endif /* AMIROOS_CFG_TESTS_ENABLE == true */
+
+/**
+ * @brief   Generic callback function for GPIO interrupts.
+ *
+ * @param[in] args   Pointer to the GPIO pad identifier.
+ */
+static void _intCallback(void* args)
+{
+  aosDbgCheck((args != NULL) && (*((iopadid_t*)args) < sizeof(eventflags_t) * 8));
+
+  chSysLockFromISR();
+  chEvtBroadcastFlagsI(&aos.events.io, (eventflags_t)1 << *((iopadid_t*)args));
+  chSysUnlockFromISR();
+
+  return;
+}
+
+#if (AMIROOS_CFG_SSSP_MASTER != true) || defined(__DOXYGEN__)
+/**
+ * @brief   Callback function for the Sync signal interrupt.
+ *
+ * @param[in] args   Pointer to the GPIO pad identifier.
+ */
+static void _signalSyncCallback(void *args)
+{
+  aosDbgCheck((args != NULL) && (*((iopadid_t*)args) < sizeof(eventflags_t) * 8));
+
+  apalControlGpioState_t s_state;
+  aos_timestamp_t uptime;
+
+  chSysLockFromISR();
+  // if the system is in operation phase
+  if (aos.sssp.stage == AOS_SSSP_OPERATION) {
+    // read signal S
+    apalControlGpioGet(&moduleSsspGpioSync, &s_state);
+    // if S was toggled from on to off
+    if (s_state == APAL_GPIO_OFF) {
+      // get current uptime
+      aosSysGetUptimeX(&uptime);
+      // align the uptime with the synchronization period
+      if (uptime % AMIROOS_CFG_SSSP_SYSSYNCPERIOD < AMIROOS_CFG_SSSP_SYSSYNCPERIOD / 2) {
+        _uptime -= uptime % AMIROOS_CFG_SSSP_SYSSYNCPERIOD;
+#if (AMIROOS_CFG_PROFILE == true)
+        _syssyncskew = ((1.0f - SYSTEM_SYSSYNCSKEW_LPFACTOR) * _syssyncskew) + (SYSTEM_SYSSYNCSKEW_LPFACTOR * (uptime % AMIROOS_CFG_SSSP_SYSSYNCPERIOD));
+#endif
+      } else {
+        _uptime += AMIROOS_CFG_SSSP_SYSSYNCPERIOD - (uptime % AMIROOS_CFG_SSSP_SYSSYNCPERIOD);
+#if (AMIROOS_CFG_PROFILE == true)
+        _syssyncskew = ((1.0f - SYSTEM_SYSSYNCSKEW_LPFACTOR) * _syssyncskew) - (SYSTEM_SYSSYNCSKEW_LPFACTOR * (AMIROOS_CFG_SSSP_SYSSYNCPERIOD - (uptime % AMIROOS_CFG_SSSP_SYSSYNCPERIOD)));
+#endif
+      }
+    }
+  }
+  // broadcast event
+  chEvtBroadcastFlagsI(&aos.events.io, (eventflags_t)1 << *((iopadid_t*)args));
+  chSysUnlockFromISR();
+
+  return;
+}
+#endif
+
+/**
+ * @brief   Callback function for the uptime accumulation timer.
+ *
+ * @param[in] par   Generic parameter.
+ */
+static void _uptimeCallback(void* par)
+{
+  (void)par;
+
+  chSysLockFromISR();
+  // read current time in system ticks
+  register const systime_t st = chVTGetSystemTimeX();
+  // update the uptime variables
+  _uptime += chTimeI2US(chTimeDiffX(_synctime, st));
+  _synctime = st;
+  // enable the timer again
+  chVTSetI(&_systimer, SYSTIMER_PERIOD, &_uptimeCallback, NULL);
+  chSysUnlockFromISR();
+
+  return;
+}
+
+#if (AMIROOS_CFG_SSSP_MASTER == true) || defined (__DOXYGEN__)
+/**
+ * @brief   Periodic system synchronization callback function.
+ * @details Toggles the SYS_SYNC signal and reconfigures the system synchronization timer.
+ *
+ * @param[in] par   Unuesed parameters.
+ */
+static void _sysSyncTimerCallback(void* par)
+{
+  (void)par;
+
+  apalControlGpioState_t s_state;
+  aos_timestamp_t uptime;
+
+  chSysLockFromISR();
+  // toggle and read signal S
+  apalGpioToggle(moduleSsspGpioSync.gpio);
+  apalControlGpioGet(&moduleSsspGpioSync, &s_state);
+  // if S was toggled from off to on
+  if (s_state == APAL_GPIO_ON) {
+    // reconfigure the timer precisely, because the logically falling edge (next interrupt) snychronizes the system time
+    _syssynctime += AMIROOS_CFG_SSSP_SYSSYNCPERIOD;
+    aosSysGetUptimeX(&uptime);
+    chVTSetI(&_syssynctimer, chTimeUS2I(_syssynctime - uptime), _sysSyncTimerCallback, NULL);
+  }
+  // if S was toggled from on to off
+  else /* if (s_state == APAL_GPIO_OFF) */ {
+    // reconfigure the timer (lazy)
+    chVTSetI(&_syssynctimer, chTimeUS2I(AMIROOS_CFG_SSSP_SYSSYNCPERIOD / 2), _sysSyncTimerCallback, NULL);
+  }
+  chSysUnlockFromISR();
+
+  return;
+}
+#endif
+
+/**
+ * @brief   AMiRo-OS system initialization.
+ * @note    Must be called from the system control thread (usually main thread).
+ *
+ * @param[in] shellPrompt   String to be printed as prompt of the system shell.
+ */
+#if (AMIROOS_CFG_SHELL_ENABLE == true) || defined(__DOXYGEN__)
+void aosSysInit(const char* shellPrompt)
+#else
+void aosSysInit(void)
+#endif
+{
+  /* set control thread to maximum priority */
+  chThdSetPriority(AOS_THD_CTRLPRIO);
+
+  /* set local variables */
+  chVTObjectInit(&_systimer);
+  _synctime = 0;
+  _uptime = 0;
+#if (AMIROOS_CFG_SSSP_MASTER == true)
+  chVTObjectInit(&_syssynctimer);
+  _syssynctime = 0;
+#endif
+#if (AMIROOS_CFG_SSSP_MASTER != true) && (AMIROOS_CFG_PROFILE == true)
+  _syssyncskew = 0.0f;
+#endif
+
+  /* initialize aos configuration */
+  aos.sssp.stage = AOS_SSSP_STARTUP_2_1;
+  aos.sssp.moduleId = 0;
+  aosIOStreamInit(&aos.iostream);
+  chEvtObjectInit(&aos.events.io);
+  chEvtObjectInit(&aos.events.os);
+
+  /* interrupt setup */
+  // PD signal
+  palSetPadCallback(moduleSsspGpioPd.gpio->port, moduleSsspGpioPd.gpio->pad, _intCallback, &moduleSsspGpioPd.gpio->pad);
+  palEnablePadEvent(moduleSsspGpioPd.gpio->port, moduleSsspGpioPd.gpio->pad, APAL2CH_EDGE(moduleSsspGpioPd.meta.edge));
+  // SYNC signal
+#if (AMIROOS_CFG_SSSP_MASTER == true)
+  palSetPadCallback(moduleSsspGpioSync.gpio->port, moduleSsspGpioSync.gpio->pad, _intCallback, &moduleSsspGpioSync.gpio->pad);
+#else
+  palSetPadCallback(moduleSsspGpioSync.gpio->port, moduleSsspGpioSync.gpio->pad, _signalSyncCallback, &moduleSsspGpioSync.gpio->pad);
+#endif
+  palEnablePadEvent(moduleSsspGpioSync.gpio->port, moduleSsspGpioSync.gpio->pad, APAL2CH_EDGE(moduleSsspGpioSync.meta.edge));
+#if (AMIROOS_CFG_SSSP_STACK_START != true)
+  // DN signal
+  palSetPadCallback(moduleSsspGpioDn.gpio->port, moduleSsspGpioDn.gpio->pad, _intCallback, &moduleSsspGpioDn.gpio->pad);
+  palEnablePadEvent(moduleSsspGpioDn.gpio->port, moduleSsspGpioDn.gpio->pad, APAL2CH_EDGE(moduleSsspGpioDn.meta.edge));
+#endif
+#if (AMIROOS_CFG_SSSP_STACK_END != true)
+  // UP signal
+  palSetPadCallback(moduleSsspGpioUp.gpio->port, moduleSsspGpioUp.gpio->pad, _intCallback, &moduleSsspGpioUp.gpio->pad);
+  palEnablePadEvent(moduleSsspGpioUp.gpio->port, moduleSsspGpioUp.gpio->pad, APAL2CH_EDGE(moduleSsspGpioUp.meta.edge));
+#endif
+#ifdef MODULE_INIT_INTERRUPTS
+  // further interrupt signals
+  MODULE_INIT_INTERRUPTS();
+#endif
+
+#if (AMIROOS_CFG_SHELL_ENABLE == true)
+  /* init shell */
+  aosShellInit(&aos.shell,
+               &aos.events.os,
+               shellPrompt,
+               _shell_line,
+               AMIROOS_CFG_SHELL_LINEWIDTH,
+               _shell_arglist,
+               AMIROOS_CFG_SHELL_MAXARGS);
+  // add system commands
+  aosShellAddCommand(&aos.shell, &_shellcmd_config);
+  aosShellAddCommand(&aos.shell, &_shellcmd_info);
+  aosShellAddCommand(&aos.shell, &_shellcmd_shutdown);
+#if (AMIROOS_CFG_TESTS_ENABLE == true)
+  aosShellAddCommand(&aos.shell, &_shellcmd_kerneltest);
+#endif
+#endif
+
+  return;
+}
+
+/**
+ * @brief   Starts the system and all system threads.
+ */
+inline void aosSysStart(void)
+{
+  // update the system SSSP stage
+  aos.sssp.stage = AOS_SSSP_OPERATION;
+
+#if (AMIROOS_CFG_SSSP_MASTER == true)
+  {
+    chSysLock();
+    // start the system synchronization counter
+    // The first iteration of the timer is set to the next 'center' of a 'slice'.
+    aos_timestamp_t t;
+    aosSysGetUptimeX(&t);
+    t = AMIROOS_CFG_SSSP_SYSSYNCPERIOD - (t % AMIROOS_CFG_SSSP_SYSSYNCPERIOD);
+    chVTSetI(&_syssynctimer, chTimeUS2I((t > (AMIROOS_CFG_SSSP_SYSSYNCPERIOD / 2)) ? (t - (AMIROOS_CFG_SSSP_SYSSYNCPERIOD / 2)) : (t + (AMIROOS_CFG_SSSP_SYSSYNCPERIOD / 2))), _sysSyncTimerCallback, NULL);
+    chSysUnlock();
+  }
+#endif
+
+  // print system information;
+  _printSystemInfo((BaseSequentialStream*)&aos.iostream);
+  aosprintf("\n");
+
+#if (AMIROOS_CFG_SHELL_ENABLE == true)
+  // start system shell thread
+  aos.shell.thread = chThdCreateStatic(_shell_wa, sizeof(_shell_wa), AMIROOS_CFG_SHELL_THREADPRIO, aosShellThread, &aos.shell);
+#endif
+
+  return;
+}
+
+/**
+ * @brief   Implements the SSSP startup synchronization step.
+ *
+ * @param[in] syncEvtListener   Event listener that receives the Sync event.
+ *
+ * @return    If another event that the listener is interested in was received, its mask is returned.
+ *            Otherwise an empty mask (0) is returned.
+ */
+eventmask_t aosSysSsspStartupOsInitSyncCheck(event_listener_t* syncEvtListener)
+{
+  aosDbgCheck(syncEvtListener != NULL);
+
+  // local variables
+  eventmask_t m;
+  eventflags_t f;
+  apalControlGpioState_t s;
+
+  // update the system SSSP stage
+  aos.sssp.stage = AOS_SSSP_STARTUP_2_2;
+
+  // deactivate the sync signal to indicate that the module is ready (SSSPv1 stage 2.1 of startup phase)
+  apalControlGpioSet(&moduleSsspGpioSync, APAL_GPIO_OFF);
+
+  // wait for any event to occur (do not apply any filter in order not to miss any event)
+  m = chEvtWaitOne(ALL_EVENTS);
+  f = chEvtGetAndClearFlags(syncEvtListener);
+  apalControlGpioGet(&moduleSsspGpioSync, &s);
+
+  // if the event was a system event,
+  //   and it was fired because of the SysSync control signal,
+  //   and the SysSync control signal has been deactivated
+  if (m & syncEvtListener->events &&
+      f == MODULE_SSSP_EVENTFLAGS_SYNC &&
+      s == APAL_GPIO_OFF) {
+    chSysLock();
+    // start the uptime counter
+    _synctime = chVTGetSystemTimeX();
+    _uptime = 0;
+    chVTSetI(&_systimer, SYSTIMER_PERIOD, &_uptimeCallback, NULL);
+    chSysUnlock();
+
+    return 0;
+  }
+  // an unexpected event occurred
+  else {
+    // reassign the flags to the event and return the event mask
+    syncEvtListener->flags |= f;
+    return m;
+  }
+}
+
+/**
+ * @brief   Retrieves the system uptime.
+ *
+ * @param[out] ut   The system uptime.
+ */
+inline void aosSysGetUptimeX(aos_timestamp_t* ut)
+{
+  aosDbgCheck(ut != NULL);
+
+  *ut = _uptime + chTimeI2US(chTimeDiffX(_synctime, chVTGetSystemTimeX()));
+
+  return;
+}
+
+/**
+ * @brief   retrieves the date and time from the MCU clock.
+ *
+ * @param[out] td   The date and time.
+ */
+void aosSysGetDateTime(struct tm* dt)
+{
+  aosDbgCheck(dt != NULL);
+
+  RTCDateTime rtc;
+  rtcGetTime(&MODULE_HAL_RTC, &rtc);
+  rtcConvertDateTimeToStructTm(&rtc, dt, NULL);
+
+  return;
+}
+
+/**
+ * @brief   set the date and time of the MCU clock.
+ *
+ * @param[in] dt    The date and time to set.
+ */
+void aosSysSetDateTime(struct tm* dt)
+{
+  aosDbgCheck(dt != NULL);
+
+  RTCDateTime rtc;
+  rtcConvertStructTmToDateTime(dt, 0, &rtc);
+  rtcSetTime(&MODULE_HAL_RTC, &rtc);
+
+  return;
+}
+
+/**
+ * @brief   Initializes/Acknowledges a system shutdown/restart request.
+ * @note    This functions should be called from the thread with highest priority.
+ *
+ * @param[in] shutdown    Type of shutdown.
+ */
+void aosSysShutdownInit(aos_shutdown_t shutdown)
+{
+  // check arguments
+  aosDbgCheck(shutdown != AOS_SHUTDOWN_NONE);
+
+#if (AMIROOS_CFG_SSSP_MASTER == true)
+  // deactivate the system synchronization timer
+  chVTReset(&_syssynctimer);
+#endif
+
+  // update the system SSSP stage
+  aos.sssp.stage = AOS_SSSP_SHUTDOWN_1_1;
+
+  // activate the SYS_PD control signal only, if this module initiated the shutdown
+  chSysLock();
+  if (shutdown != AOS_SHUTDOWN_PASSIVE) {
+    apalControlGpioSet(&moduleSsspGpioPd, APAL_GPIO_ON);
+  }
+  // activate the SYS_SYNC signal
+  apalControlGpioSet(&moduleSsspGpioSync, APAL_GPIO_ON);
+  chSysUnlock();
+
+  switch (shutdown) {
+    case AOS_SHUTDOWN_PASSIVE:
+      chEvtBroadcastFlags(&aos.events.os, AOS_SYSTEM_EVENTFLAGS_SHUTDOWN);
+      aosprintf("shutdown request received...\n");
+      break;
+    case AOS_SHUTDOWN_HIBERNATE:
+      chEvtBroadcastFlags(&aos.events.os, AOS_SYSTEM_EVENTFLAGS_HIBERNATE);
+      aosprintf("shutdown to hibernate mode...\n");
+      break;
+    case AOS_SHUTDOWN_DEEPSLEEP:
+      chEvtBroadcastFlags(&aos.events.os, AOS_SYSTEM_EVENTFLAGS_DEEPSLEEP);
+      aosprintf("shutdown to deepsleep mode...\n");
+      break;
+    case AOS_SHUTDOWN_TRANSPORTATION:
+      chEvtBroadcastFlags(&aos.events.os, AOS_SYSTEM_EVENTFLAGS_TRANSPORTATION);
+      aosprintf("shutdown to transportation mode...\n");
+      break;
+    case AOS_SHUTDOWN_RESTART:
+      chEvtBroadcastFlags(&aos.events.os, AOS_SYSTEM_EVENTFLAGS_RESTART);
+      aosprintf("restarting system...\n");
+      break;
+   // must never occur
+   case AOS_SHUTDOWN_NONE:
+   default:
+      break;
+  }
+
+  // update the system SSSP stage
+  aos.sssp.stage = AOS_SSSP_SHUTDOWN_1_2;
+
+  return;
+}
+
+/**
+ * @brief   Stops the system and all related threads (not the thread this function is called from).
+ */
+void aosSysStop(void)
+{
+#if (AMIROOS_CFG_SHELL_ENABLE == true)
+  chThdWait(aos.shell.thread);
+#endif
+
+  return;
+}
+
+/**
+ * @brief   Deinitialize all system variables.
+ */
+void aosSysDeinit(void)
+{
+  return;
+}
+
+/**
+ * @brief   Finally shuts down the system and calls the bootloader callback function.
+ * @note    This function should be called from the thtead with highest priority.
+ *
+ * @param[in] shutdown    Type of shutdown.
+ */
+void aosSysShutdownFinal(aos_shutdown_t shutdown)
+{
+  // check arguments
+  aosDbgCheck(shutdown != AOS_SHUTDOWN_NONE);
+
+  // disable all interrupts
+  irqDeinit();
+
+  // update the system SSSP stage
+  aos.sssp.stage = AOS_SSSP_SHUTDOWN_1_3;
+
+  // call bootloader callback depending on arguments
+  switch (shutdown) {
+    case AOS_SHUTDOWN_PASSIVE:
+      BL_CALLBACK_TABLE_ADDRESS->cbHandleShutdownRequest();
+      break;
+    case AOS_SHUTDOWN_HIBERNATE:
+      BL_CALLBACK_TABLE_ADDRESS->cbShutdownHibernate();
+      break;
+    case AOS_SHUTDOWN_DEEPSLEEP:
+      BL_CALLBACK_TABLE_ADDRESS->cbShutdownDeepsleep();
+      break;
+    case AOS_SHUTDOWN_TRANSPORTATION:
+      BL_CALLBACK_TABLE_ADDRESS->cbShutdownTransportation();
+      break;
+    case AOS_SHUTDOWN_RESTART:
+      BL_CALLBACK_TABLE_ADDRESS->cbShutdownRestart();
+      break;
+    // must never occur
+    case AOS_SHUTDOWN_NONE:
+    default:
+      break;
+  }
+
+  return;
+}
+
+/** @} */
diff --git a/core/src/aos_thread.c b/core/src/aos_thread.c
new file mode 100644
index 0000000..05c1668
--- /dev/null
+++ b/core/src/aos_thread.c
@@ -0,0 +1,60 @@
+/*
+AMiRo-OS is an operating system designed for the Autonomous Mini Robot (AMiRo) platform.
+Copyright (C) 2016..2018  Thomas Schöpping et al.
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @file    aos_thread.c
+ * @brief   Thread code.
+ *
+ * @addtogroup aos_threads
+ * @{
+ */
+
+#include <aos_thread.h>
+
+/**
+ * @brief   Lets the calling thread sleep until the specifide system uptime.
+ *
+ * @param[in] t     Deadline until the thread will sleep.
+ */
+void aosThdSleepUntilS(const aos_timestamp_t* t)
+{
+  aosDbgCheck(t != NULL);
+
+  aos_timestamp_t uptime;
+
+  // get the current system uptime
+  aosSysGetUptimeX(&uptime);
+
+  // while the remaining time is too long, it must be split into multiple sleeps
+  while ( (*t > uptime) && ((*t - uptime) > AOS_THD_MAX_SLEEP_US) ) {
+    chThdSleepS(chTimeUS2I(AOS_THD_MAX_SLEEP_US));
+    aosSysGetUptimeX(&uptime);
+  }
+
+  // sleep the remaining time
+  if (*t > uptime) {
+    sysinterval_t rest = chTimeUS2I(*t - uptime);
+    if (rest > TIME_IMMEDIATE) {
+      chThdSleepS(rest);
+    }
+  }
+
+  return;
+}
+
+/** @} */
diff --git a/core/src/aos_time.c b/core/src/aos_time.c
new file mode 100644
index 0000000..e637810
--- /dev/null
+++ b/core/src/aos_time.c
@@ -0,0 +1,60 @@
+/*
+AMiRo-OS is an operating system designed for the Autonomous Mini Robot (AMiRo) platform.
+Copyright (C) 2016..2018  Thomas Schöpping et al.
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @file    aos_time.c
+ * @brief   Time related function implementations.
+ *
+ * @addtogroup aos_time
+ * @{
+ */
+
+#include <aos_time.h>
+
+#include <aos_debug.h>
+#include <aos_system.h>
+
+/**
+ * @brief   Calculates the day of week from a specified date.
+ *
+ * @param[in] day     The day of the date.
+ * @param[in] month   The month of the daste.
+ * @param[in] year    The year of the date.
+ *
+ * @return    The day of week depending on the date represented in ISO format (1 = Monday to 7 = Sunday).
+ */
+uint8_t aosTimeDayOfWeekFromDate(const uint16_t day, const uint8_t month, const uint16_t year)
+{
+  aosDbgCheck(day >= 1 && day <= 31);
+  aosDbgCheck(month >= 1 && month <= 12);
+
+  /*
+   * Implementation of Zeller's congruence for Gregorian calender.
+   * See https://en.wikipedia.org/wiki/Zeller%27s_congruence for details.
+   */
+  const uint32_t q = day;
+  const uint32_t m = (month >= 3) ? month : month + 12;
+  const uint32_t K = year % 100;
+  const uint32_t J = year / 100;
+
+  const uint32_t h = (q + ((13 * (m + 1)) / 5) + K + (K / 4) + (J / 4) - (2 * J)) % 7;
+
+  return ((h + 5) % 7) + 1;
+}
+
+/** @} */
diff --git a/core/src/aos_timer.c b/core/src/aos_timer.c
new file mode 100644
index 0000000..1a7a4fc
--- /dev/null
+++ b/core/src/aos_timer.c
@@ -0,0 +1,296 @@
+/*
+AMiRo-OS is an operating system designed for the Autonomous Mini Robot (AMiRo) platform.
+Copyright (C) 2016..2018  Thomas Schöpping et al.
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @file    aos_timer.c
+ * @brief   Timer code.
+ * @details Implementation of aos_timer_t and aos_periodictimer_t functions.
+ *
+ * @addtogroup aos_timers
+ * @{
+ */
+
+#include <aos_timer.h>
+
+#include <aos_system.h>
+
+/*
+ * Forward declarations.
+ */
+static inline void _setupTimer(aos_timer_t* timer);
+static inline void _setupPeriodicTimer(aos_periodictimer_t* ptimer);
+static void _intermediateCb(void* timer);
+static void _fireCb(void* timer);
+static void _periodicCb(void* ptimer);
+
+/**
+ * @brief   Setup a timer according to its configuration.
+ *
+ * @param[in] timer   Pointer to the timer to setup.
+ */
+static inline void _setupTimer(aos_timer_t* timer)
+{
+  aos_timestamp_t uptime;
+
+  // get current system uptime
+  aosSysGetUptimeX(&uptime);
+
+  // if the wakeup time is more than TIME_IMMEDIATE in the future
+  if ( (timer->wkuptime > uptime) && ((timer->wkuptime - uptime) > TIME_IMMEDIATE) ) {
+    // split the time delta if necessary
+    if ((timer->wkuptime - uptime) > AOS_TIMER_MAX_INTERVAL_US) {
+      chVTSetI(&(timer->vt), chTimeUS2I(AOS_TIMER_MAX_INTERVAL_US), _intermediateCb, timer);
+    } else {
+      chVTSetI(&(timer->vt), chTimeUS2I(timer->wkuptime - uptime), _fireCb, timer);
+    }
+  } else {
+    vtfunc_t fn = timer->callback;
+    timer->callback = NULL;
+    fn(timer->cbparam);
+  }
+
+  return;
+}
+
+/**
+ * @brief   Setup a periodic timer according to its configuration.
+ *
+ * @param[in] ptimer  Pointer to the periodic timer to setup.
+ */
+static inline void _setupPeriodicTimer(aos_periodictimer_t *ptimer)
+{
+  // if the periodic timer is being initialized
+  if (ptimer->timer.wkuptime == 0) {
+    aos_timestamp_t uptime;
+
+    // get current system uptime
+    aosSysGetUptimeX(&uptime);
+    ptimer->timer.wkuptime = uptime + ptimer->interval;
+  }
+  // if the peridic timer is reactivated after it has fired
+  else {
+    ptimer->timer.wkuptime += ptimer->interval;
+  }
+
+  // set the callback and parameters
+  ptimer->timer.callback = _periodicCb;
+  ptimer->timer.cbparam = ptimer;
+
+  // setup the timer
+  _setupTimer(&(ptimer->timer));
+
+  return;
+}
+
+/**
+ * @brief   Callback function for intermediate interrupts.
+ * @details This is required if the desired time to fire is too far in the future so that the interval must be split.
+ *
+ * @param[in] timer   Pointer to a aos_timer_t to reactivate.
+ */
+static void _intermediateCb(void* timer)
+{
+  chSysLockFromISR();
+  _setupTimer((aos_timer_t*)timer);
+  chSysUnlockFromISR();
+}
+
+/**
+ * @brief   Callback function for the final fire event of the timer.
+ *
+ * @param[in] timer   Pointer to a aos_timer_t to call its callback.
+ */
+static void _fireCb(void *timer)
+{
+  chSysLockFromISR();
+  ((aos_timer_t*)timer)->callback(((aos_timer_t*)timer)->cbparam);
+  chSysUnlockFromISR();
+}
+
+/**
+ * @brief   Callback function for periodic timer interrupts.
+ * @details This function calls the original callback and reenables the timer afterwards.
+ *
+ * @param[in] ptimer  Pointer to a aos_periodictimer_t to reactivate.
+ */
+static void _periodicCb(void* ptimer)
+{
+  ((aos_periodictimer_t*)ptimer)->callback(((aos_periodictimer_t*)ptimer)->cbparam);
+  _setupPeriodicTimer((aos_periodictimer_t*)ptimer);
+}
+
+/**
+ * @brief   Initialize a aos_timer_t object.
+ *
+ * @param[in] timer   The timer to initialize.
+ */
+void aosTimerInit(aos_timer_t* timer)
+{
+  aosDbgAssert(timer != NULL);
+
+  chVTObjectInit(&(timer->vt));
+  timer->wkuptime = 0;
+  timer->callback = NULL;
+  timer->cbparam = NULL;
+
+  return;
+}
+
+/**
+ * @brief   Set timer to fire at an absolute system time.
+ *
+ * @param[in] timer   Pointer to the timer to set.
+ * @param[in] uptime  Pointer to the absolute system time for the timer to fire.
+ * @param[in] cb      Pointer to a callback function to be called.
+ *                    In contrast to ChibiOS callback functions, this gets called from an already ISR locked context.
+ *                    Thus it may not contain any chSysLockX() or chSysUnlockX() calls and so forth.
+ * @param[in] par     Pointer to a parameter fpr the callback function (may be NULL).
+ */
+void aosTimerSetAbsoluteI(aos_timer_t *timer, aos_timestamp_t *uptime, vtfunc_t cb, void *par)
+{
+  aosDbgCheck(timer != NULL);
+  aosDbgCheck(uptime != NULL);
+  aosDbgCheck(cb != NULL);
+
+  timer->wkuptime = *uptime;
+  timer->callback = cb;
+  timer->cbparam = par;
+  _setupTimer(timer);
+
+  return;
+}
+
+/**
+ * @brief   Set timer to fire after a relative interval.
+ *
+ * @param[in] timer   Pointer to the timer to set.
+ * @param[in] offset  Relative interval to set for the timer to fire.
+ * @param[in] cb      Pointer to a callback function to be called.
+ *                    In contrast to ChibiOS callback functions, this gets called from an already ISR locked context.
+ *                    Thus it may not contain any chSysLockX() or chSysUnlockX() calls and so forth.
+ * @param[in] par     Pointer to a parameter for the callback function (may be NULL).
+ */
+void aosTimerSetIntervalI(aos_timer_t *timer, aos_interval_t offset, vtfunc_t cb, void *par)
+{
+  aosDbgCheck(timer != NULL);
+  aosDbgCheck(cb != NULL);
+
+  aos_timestamp_t uptime;
+
+  aosSysGetUptimeX(&uptime);
+  timer->wkuptime = uptime + offset;
+  timer->callback = cb;
+  timer->cbparam = par;
+  _setupTimer(timer);
+
+  return;
+}
+
+/**
+ * @brief   Set timer to fire after a long relative interval.
+ *
+ * @param[in] timer   Pointer to the timer to set.
+ * @param[in] offset  Pointer to a long interval value to set for the timer to fire.
+ * @param[in] cb      Pointer to a callback function to be called.
+ *                    In contrast to ChibiOS callback functions, this gets called from an already ISR locked context.
+ *                    Thus it may not contain any chSysLockX() or chSysUnlockX() calls and so forth.
+ * @param[in] par     Pointer to a parameter for the callback function (may be NULL).
+ */
+void aosTimerSetLongIntervalI(aos_timer_t *timer, aos_longinterval_t *offset, vtfunc_t cb, void *par)
+{
+  aosDbgCheck(timer != NULL);
+  aosDbgCheck(offset != NULL);
+  aosDbgCheck(cb != NULL);
+
+  aos_timestamp_t uptime;
+
+  aosSysGetUptimeX(&uptime);
+  timer->wkuptime = uptime + *offset;
+  timer->callback = cb;
+  timer->cbparam = par;
+  _setupTimer(timer);
+
+  return;
+}
+
+/**
+ * @brief   Initialize a aos_periodictimer_t object.
+ *
+ * @param[in] timer   The periodic timer to initialize.
+ */
+void aosPeriodicTimerInit(aos_periodictimer_t *ptimer)
+{
+  aosDbgAssert(ptimer != NULL);
+
+  aosTimerInit(&(ptimer->timer));
+  ptimer->interval = 0;
+
+  return;
+}
+
+/**
+ * @brief   Set a periodic timer to fire in the specified interval.
+ *
+ * @param[in] ptimer    Pointer to the periodic timer to set.
+ * @param[in] interval  Interval for the periodic timer to fire,
+ * @param[in] cb        Pointer to a callback function to be called.
+ *                      In contrast to ChibiOS callback functions, this gets called from an already ISR locked context.
+ *                      Thus it may not contain any chSysLockX() or chSysUnlockX() calls and so forth.
+ * @param[in] par       Pointer to a parameter for the callback function (may be NULL).
+ */
+void aosPeriodicTimerSetI(aos_periodictimer_t* ptimer, aos_interval_t interval, vtfunc_t cb, void* par)
+{
+  aosDbgCheck(ptimer != NULL);
+  aosDbgCheck(interval > TIME_IMMEDIATE);
+  aosDbgCheck(cb != NULL);
+
+  ptimer->timer.wkuptime = 0;
+  ptimer->interval = interval;
+  ptimer->callback = cb;
+  ptimer->cbparam = par;
+  _setupPeriodicTimer(ptimer);
+
+  return;
+}
+
+/**
+ * @brief   Set a periodic timer to fire in the specified interval.
+ *
+ * @param[in] ptimer    Pointer to the periodic timer to set.
+ * @param[in] interval  Pointer to a long interval value for the periodic timer to fire,
+ * @param[in] cb        Pointer to a callback function to be called.
+ *                      In contrast to other callback functions, this get called from an already ISR locked context.
+ *                      This it may not contain any chSysLockX() or chSysUnlockX() calls.
+ * @param[in] par       Pointer to a parameter for the callback function (may be NULL).
+ */
+void aosPeriodicTimerSetLongI(aos_periodictimer_t* ptimer, aos_longinterval_t* interval, vtfunc_t cb, void* par)
+{
+  aosDbgCheck(ptimer != NULL);
+  aosDbgCheck(*interval > TIME_IMMEDIATE);
+  aosDbgCheck(cb != NULL);
+
+  ptimer->timer.wkuptime = 0;
+  ptimer->interval = *interval;
+  ptimer->callback = cb;
+  ptimer->cbparam = par;
+  _setupPeriodicTimer(ptimer);
+
+  return;
+}
+
+/** @} */
diff --git a/core/src/aos_unittest.c b/core/src/aos_unittest.c
new file mode 100644
index 0000000..8dd8fa3
--- /dev/null
+++ b/core/src/aos_unittest.c
@@ -0,0 +1,276 @@
+/*
+AMiRo-OS is an operating system designed for the Autonomous Mini Robot (AMiRo) platform.
+Copyright (C) 2016..2018  Thomas Schöpping et al.
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @file    aos_unittest.c
+ * @brief   Unittest code.
+ * @details Functions to initialize and run unittests, 
+ *          as well as utility functions to be used in unittests.
+ *
+ * @addtogroup aos_unittests
+ * @{
+ */
+
+#include <aos_unittest.h>
+
+#if (AMIROOS_CFG_TESTS_ENABLE == true) || defined(__DOXYGEN__)
+#include <aos_debug.h>
+#include <chprintf.h>
+#include <string.h>
+
+/**
+ * @brief   Retrieve the total number of tests (passed and failed).
+ *
+ * @param[in] result    The result object to evaluate.
+ *
+ * @return  Number of total tests executed.
+ */
+inline uint32_t aosUtResultTotal(aos_utresult_t *result)
+{
+  aosDbgCheck(result != NULL);
+
+  return result->passed + result->failed;
+}
+
+/**
+ * @brief   Retrieve the ratio of passed tests.
+ *
+ * @param[in] result    The result object to evaluate.
+ *
+ * @return  Ratio of passed tests to total tests as float in range [0, 1].
+ */
+inline float aosUtResultRatio(aos_utresult_t *result)
+{
+  aosDbgCheck(result != NULL);
+
+  if (aosUtResultTotal(result) > 0) {
+    return (float)result->passed / (float)aosUtResultTotal(result);
+  } else {
+    return 1.0f;
+  }
+}
+
+/**
+ * @brief   Print the summary of a test.
+ * @details The summary consists of:
+ *          - total numer of tests executed
+ *          - absolute number of passed tests
+ *          - absolute number of failed tests
+ *          - relative ratio of passed tests
+ *
+ * @param[in] stream    Stream to print the result to.
+ * @param[in] result    Result to evaluate and print.
+ * @param[in] heading   Optional heading (defaults to "summary").
+ */
+void aosUtResultPrintSummary(BaseSequentialStream *stream, aos_utresult_t *result, char* heading)
+{
+  aosDbgCheck(stream != NULL);
+  aosDbgCheck(result != NULL);
+
+  chprintf(stream, "%s:\n", (heading != NULL) ? heading : "summary");
+  chprintf(stream, "\ttotal:  %3u\n", aosUtResultTotal(result));
+  chprintf(stream, "\tpassed: %3u\n", result->passed);
+  chprintf(stream, "\tfailed: %3u\n", result->failed);
+  chprintf(stream, "\tratio:  %3u%%\n", (uint8_t)(aosUtResultRatio(result) * 100.0f));
+
+  return;
+}
+
+/**
+ * @brief   Initialize a unit test object.
+ *
+ * @param[in] ut          The unit test object to initialize.
+ * @param[in] name        name of the unit test.
+ * @param[in] info        Optional information string.
+ * @param[in] func        Unit test calback function.
+ * @param[in] data        Optional data for the unit test.
+ * @param[in] shellname   Name of the shell command
+ * @param[in] shellcb     Callback for the shell command.
+ */
+void aosUtObjectInit(aos_unittest_t* ut, char* name, char* info, aos_utfunction_t func, void* data, char* shellname, aos_shellcmdcb_t shellcb)
+{
+  aosDbgCheck(ut != NULL);
+  aosDbgCheck(name != NULL && strlen(name) > 0);
+  aosDbgCheck(func != NULL);
+  aosDbgCheck(shellname != NULL && strlen(shellname) > 0);
+  aosDbgCheck(shellcb != NULL);
+
+  ut->name = name;
+  ut->info = info;
+  ut->testfunc = func;
+  ut->shellcmd.name = shellname;
+  ut->shellcmd.callback = shellcb;
+  ut->shellcmd.next = NULL;
+  ut->data = data;
+
+  return;
+}
+
+/**
+ * @brief   Run an unit test.
+ *
+ * @param[in] stream  A stream for printing messages.
+ * @param[in] ut      Unit test to execute.
+ * @param[in] note    Optional note string.
+ *
+ * @return    Result of the test.
+ */
+aos_utresult_t aosUtRun(BaseSequentialStream *stream, aos_unittest_t *ut, char *note)
+{
+  aosDbgCheck(stream != NULL);
+  aosDbgCheck(ut != NULL);
+
+  // print name heading
+  {
+    chprintf(stream, "\n");
+    const int nchars = chprintf(stream, "%s unit test\n", ut->name);
+    for (int c = 0; c < nchars-1; ++c) {
+      chprintf(stream, "=");
+    }
+    chprintf(stream, "\n");
+  }
+
+  // print info (if any)
+  if (ut->info != NULL) {
+    chprintf(stream, "info: %s\n", ut->info);
+  }
+  // print note (if any)
+  if (note != NULL) {
+    chprintf(stream, "note: %s\n", note);
+  }
+  chprintf(stream, "\n");
+
+  // run test
+  aos_utresult_t result = ut->testfunc(stream, ut);
+
+  // print summary
+  aosUtResultPrintSummary(stream, &result, NULL);
+
+  return result;
+}
+
+/**
+ * @brief   Helper function for passed tests.
+ * @details Prints a message that the test was passed and modifies the result accordigly.
+ *
+ * @param[in] stream      Stream to print the message to.
+ * @param[in,out] result  Result object to modify.
+ */
+void aosUtPassed(BaseSequentialStream *stream, aos_utresult_t* result)
+{
+  aosDbgCheck(stream != NULL);
+  aosDbgCheck(result != NULL);
+
+  ++result->passed;
+  chprintf(stream, "\tPASSED\n");
+  chprintf(stream, "\n");
+
+  return;
+}
+
+/**
+ * @brief   Helper function for passed tests.
+ * @details Prints a message that the test was passed, an additional custom message, and modifies the result accordigly.
+ *
+ * @param[in] stream      Stream to print the message to.
+ * @param[in,out] result  Result object to modify.
+ * @param[in] fmt         Formatted message string.
+ */
+void aosUtPassedMsg(BaseSequentialStream *stream, aos_utresult_t* result, const char *fmt, ...)
+{
+  aosDbgCheck(stream != NULL);
+  aosDbgCheck(result != NULL);
+
+  va_list ap;
+
+  ++result->passed;
+  chprintf(stream, "\tPASSED\t");
+  va_start(ap, fmt);
+  chvprintf(stream, fmt, ap);
+  va_end(ap);
+  chprintf(stream, "\n");
+
+  return;
+}
+
+/**
+ * @brief   Helper function for failed tests.
+ * @details Prints a message that the test was failed and modifies the result accordigly.
+ *
+ * @param[in] stream      Stream to print the message to.
+ * @param[in,out] result  Result object to modify.
+ */
+void aosUtFailed(BaseSequentialStream *stream, aos_utresult_t* result)
+{
+  aosDbgCheck(stream != NULL);
+  aosDbgCheck(result != NULL);
+
+  ++result->failed;
+  chprintf(stream, "\tFAILED\n");
+  chprintf(stream, "\n");
+
+  return;
+}
+
+/**
+ * @brief   Helper function for failed tests.
+ * @details Prints a message that the test was failed, an additional custom message, and modifies the result accordigly.
+ *
+ * @param[in] stream      Stream to print the message to.
+ * @param[in,out] result  Result object to modify.
+ * @param[in] fmt         Formatted message string.
+ */
+void aosUtFailedMsg(BaseSequentialStream *stream, aos_utresult_t* result, const char *fmt, ...)
+{
+  aosDbgCheck(stream != NULL);
+  aosDbgCheck(result != NULL);
+
+  va_list ap;
+
+  ++result->failed;
+  chprintf(stream, "\tFAILED\t");
+  va_start(ap, fmt);
+  chvprintf(stream, fmt, ap);
+  va_end(ap);
+  chprintf(stream, "\n");
+
+  return;
+}
+
+/**
+ * @brief   Helper function for information messages.
+ *
+ * @param[in] stream  Strean to rpint the message to.
+ * @param[in] fmt     Formatted message string.
+ */
+void aosUtInfoMsg(BaseSequentialStream* stream, const char* fmt, ...)
+{
+  aosDbgCheck(stream != NULL);
+
+  va_list ap;
+  va_start(ap, fmt);
+  chvprintf(stream, fmt, ap);
+  va_end(ap);
+  chprintf(stream, "\n");
+
+  return;
+}
+
+#endif /* AMIROOS_CFG_TESTS_ENABLE == true */
+
+/** @} */
diff --git a/modules/DiWheelDrive_1-1/Makefile b/modules/DiWheelDrive_1-1/Makefile
index 766bf42..3a04da5 100644
--- a/modules/DiWheelDrive_1-1/Makefile
+++ b/modules/DiWheelDrive_1-1/Makefile
@@ -118,7 +118,7 @@ PROJECT := $(patsubst $(abspath $(dir $(abspath $(lastword $(MAKEFILE_LIST))))..
 # Imported source files and paths
 include ../../kernel/kernel.mk
 CHIBIOS := $(AMIROOS_KERNEL)
-AMIROOS = ../../os
+AMIROOS = ../../
 # Startup files
 include $(CHIBIOS)/os/common/startup/ARMCMx/compilers/GCC/mk/startup_stm32f1xx.mk
 # HAL-OSAL files
diff --git a/modules/LightRing_1-0/Makefile b/modules/LightRing_1-0/Makefile
index 766bf42..3a04da5 100644
--- a/modules/LightRing_1-0/Makefile
+++ b/modules/LightRing_1-0/Makefile
@@ -118,7 +118,7 @@ PROJECT := $(patsubst $(abspath $(dir $(abspath $(lastword $(MAKEFILE_LIST))))..
 # Imported source files and paths
 include ../../kernel/kernel.mk
 CHIBIOS := $(AMIROOS_KERNEL)
-AMIROOS = ../../os
+AMIROOS = ../../
 # Startup files
 include $(CHIBIOS)/os/common/startup/ARMCMx/compilers/GCC/mk/startup_stm32f1xx.mk
 # HAL-OSAL files
diff --git a/modules/PowerManagement_1-1/Makefile b/modules/PowerManagement_1-1/Makefile
index 9ef4d80..0836551 100644
--- a/modules/PowerManagement_1-1/Makefile
+++ b/modules/PowerManagement_1-1/Makefile
@@ -118,7 +118,7 @@ PROJECT := $(patsubst $(abspath $(dir $(abspath $(lastword $(MAKEFILE_LIST))))..
 # Imported source files and paths
 include ../../kernel/kernel.mk
 CHIBIOS := $(AMIROOS_KERNEL)
-AMIROOS = ../../os
+AMIROOS = ../../
 # Startup files
 include $(CHIBIOS)/os/common/startup/ARMCMx/compilers/GCC/mk/startup_stm32f4xx.mk
 # HAL-OSAL files
diff --git a/os/amiroos.h b/os/amiroos.h
deleted file mode 100644
index 74ccb53..0000000
--- a/os/amiroos.h
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
-AMiRo-OS is an operating system designed for the Autonomous Mini Robot (AMiRo) platform.
-Copyright (C) 2016..2018  Thomas Schöpping et al.
-
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program.  If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#ifndef _AMIROOS_H_
-#define _AMIROOS_H_
-
-/**
- * @brief   AMiRo-OS identification macro.
- */
-#define _AMIRO_OS_
-
-/**
- * @name   AMiRo-OS version and relase information.
- * @{
- */
-
-/**
- * @brief   The type of this version.
- * @note    Is one of "pre-alpha", "alpha", "beta", "release candidate", "release".
- */
-#define AMIROOS_RELEASE_TYPE          "beta"
-
-/**
- * @brief   The operating system major version.
- * @note    Changes of the major version imply incompatibilities.
- */
-#define AMIROOS_VERSION_MAJOR         2
-
-/**
- * @brief   The operating system minor version.
- * @note    A higher minor version implies new functionalty, but all old interfaces are still available.
- */
-#define AMIROOS_VERSION_MINOR         0
-
-/**
- * @brief   The operating system patch level.
- */
-#define AMIROOS_VERSION_PATCH         0
-
-/** @} */
-
-/* subsystems headers */
-#include <aosconf.h>
-#include <hal.h>
-#if defined(HAL_USE_QEI) && (HAL_USE_QEI == TRUE)
-#include <hal_qei.h>
-#endif
-#include <ch.h>
-
-/* configuration check */
-#if !defined(_AMIRO_OS_CFG_)
-#error "invalid AMiRo-OS configuration file"
-#endif
-#if (_AMIRO_OS_CFG_VERSION_MAJOR_ != AMIROOS_VERSION_MAJOR) || (_AMIRO_OS_CFG_VERSION_MINOR_ < AMIROOS_VERSION_MINOR)
-#error "incompatible AMiRo-OS configuration file"
-#endif
-#include "core/inc/aos_confcheck.h"
-
-/* core headers */
-#include "core/inc/aos_debug.h"
-#include <core/inc/aos_iostream.h>
-#include "core/inc/aos_shell.h"
-#include "core/inc/aos_system.h"
-#include "core/inc/aos_thread.h"
-#include "core/inc/aos_time.h"
-#include "core/inc/aos_timer.h"
-#include "core/inc/aos_types.h"
-#include "core/inc/aos_unittest.h"
-
-#endif /* _AMIROOS_H_ */
diff --git a/os/core/core.mk b/os/core/core.mk
deleted file mode 100644
index 9bc01a8..0000000
--- a/os/core/core.mk
+++ /dev/null
@@ -1,44 +0,0 @@
-################################################################################
-# AMiRo-OS is an operating system designed for the Autonomous Mini Robot       #
-# (AMiRo) platform.                                                            #
-# Copyright (C) 2016..2018  Thomas Schöpping et al.                            #
-#                                                                              #
-# This program is free software: you can redistribute it and/or modify         #
-# it under the terms of the GNU General Public License as published by         #
-# the Free Software Foundation, either version 3 of the License, or            #
-# (at your option) any later version.                                          #
-#                                                                              #
-# This program is distributed in the hope that it will be useful,              #
-# but WITHOUT ANY WARRANTY; without even the implied warranty of               #
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the                #
-# GNU General Public License for more details.                                 #
-#                                                                              #
-# You should have received a copy of the GNU General Public License            #
-# along with this program.  If not, see <http://www.gnu.org/licenses/>.        #
-#                                                                              #
-# This research/work was supported by the Cluster of Excellence Cognitive      #
-# Interaction Technology 'CITEC' (EXC 277) at Bielefeld University, which is   #
-# funded by the German Research Foundation (DFG).                              #
-################################################################################
-
-
-
-# absolute path to this directory
-AMIROOS_CORE_DIR := $(dir $(lastword $(MAKEFILE_LIST)))
-
-# include paths
-AMIROOSCOREINC = $(AMIROOS_CORE_DIR)inc
-
-# C source files
-AMIROOSCORECSRC = $(AMIROOS_CORE_DIR)src/aos_debug.c \
-                  $(AMIROOS_CORE_DIR)src/aos_iostream.c \
-                  $(AMIROOS_CORE_DIR)src/aos_shell.c \
-                  $(AMIROOS_CORE_DIR)src/aos_system.c \
-                  $(AMIROOS_CORE_DIR)src/aos_thread.c \
-                  $(AMIROOS_CORE_DIR)src/aos_time.c \
-                  $(AMIROOS_CORE_DIR)src/aos_timer.c \
-                  $(AMIROOS_CORE_DIR)src/aos_unittest.c
-
-# C++ source files
-AMIROOSCORECPPSRC = $(AMIROOS_CORE_DIR)src/aos_main.cpp
-
diff --git a/os/core/inc/aos_confcheck.h b/os/core/inc/aos_confcheck.h
deleted file mode 100644
index bf16754..0000000
--- a/os/core/inc/aos_confcheck.h
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
-AMiRo-OS is an operating system designed for the Autonomous Mini Robot (AMiRo) platform.
-Copyright (C) 2016..2018  Thomas Schöpping et al.
-
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program.  If not, see <http://www.gnu.org/licenses/>.
-*/
-
-/**
- * @file    aos_confcheck.h
- * @brief   Header that checks whether all necessary configurations are correct.
- *
- * @addtogroup aos_system
- * @{
- */
-
-#ifndef _AMIROOS_CONFCHECK_H_
-#define _AMIROOS_CONFCHECK_H_
-
-#include <aosconf.h>
-
-/*
- * Kernel parameters and options
- */
-
-#ifndef AMIROOS_CFG_DBG
-  #error "AMIROOS_CFG_DBG not defined in aosconf.h"
-#endif
-
-#ifndef AMIROOS_CFG_TESTS_ENABLE
-  #error "AMIROOS_CFG_TESTS_ENABLE not defined in aosconf.h"
-#endif
-
-#ifndef AMIROOS_CFG_PROFILE
-  #error "AMIROOS_CFG_PROFILE not defined in aosconf.h"
-#endif
-
-#ifndef AMIROOS_CFG_MAIN_LOOP_TIMEOUT
-  #error "AMIROOS_CFG_MAIN_LOOP_TIMEOUT not defined in aosconf.h"
-#endif
-
-/*
- * SSSP parameters and options
- */
-
-#ifndef AMIROOS_CFG_SSSP_MASTER
-  #error "AMIROOS_CFG_SSSP_MASTER not defined in aosconf.h"
-#endif
-
-#ifndef AMIROOS_CFG_SSSP_STACK_START
-  #error "AMIROOS_CFG_SSSP_STACK_START not defined in aosconf.h"
-#endif
-
-#ifndef AMIROOS_CFG_SSSP_STACK_END
-  #error "AMIROOS_CFG_SSSP_STACK_END not defined in aosconf.h"
-#endif
-
-#if (AMIROOS_CFG_SSSP_STACK_START == true) && (AMIROOS_CFG_SSSP_STACK_END == true)
-  #warning "AMIROOS_CFG_SSSP_STACK_START and AMIROOS_CFG_SSSP_STACK_END both enabled in aosconf.h"
-  #if (AMIROOS_CFG_SSSP_MASTER != true)
-    #error "AMIROOS_CFG_SSSP_MASTER must be enabled in this case"
-  #endif
-#endif
-
-#ifndef AMIROOS_CFG_SSSP_SIGNALDELAY
-  #error "AMIROOS_CFG_SSSP_SIGNALDELAY not defined in aosconf.h"
-#endif
-
-#ifndef AMIROOS_CFG_SSSP_SYSSYNCPERIOD
-  #error "AMIROOS_CFG_SSSP_SYSSYNCPERIOD not defined in aosconf.h"
-#endif
-
-/*
- * System shell options
- */
-
-#ifndef AMIROOS_CFG_SHELL_ENABLE
-  #error "AMIROOS_CFG_SHELL_ENABLE not defined in aosconf.h"
-#endif
-
-#if (AMIROOS_CFG_SHELL_ENABLE == true)
-
-  #ifndef AMIROOS_CFG_SHELL_STACKSIZE
-    #error "AMIROOS_CFG_SHELL_STACKSIZE not defined in aosconf.h"
-  #endif
-
-  #ifndef AMIROOS_CFG_SHELL_THREADPRIO
-    #error "AMIROOS_CFG_SHELL_THREADPRIO not defined in aosconf.h"
-  #endif
-
-  #ifndef AMIROOS_CFG_SHELL_LINEWIDTH
-    #error "AMIROOS_CFG_SHELL_LINEWIDTH not defined in aosconf.h"
-  #endif
-
-  #ifndef AMIROOS_CFG_SHELL_MAXARGS
-    #error "AMIROOS_CFG_SHELL_MAXARGS not defined in aosconf.h"
-  #endif
-
-#endif /* AMIROOS_CFG_SHELL_ENABLE == true */
-
-#endif /* _AMIROOS_CONFCHECK_H_ */
-
-/** @} */
diff --git a/os/core/inc/aos_debug.h b/os/core/inc/aos_debug.h
deleted file mode 100644
index 56a33ba..0000000
--- a/os/core/inc/aos_debug.h
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
-AMiRo-OS is an operating system designed for the Autonomous Mini Robot (AMiRo) platform.
-Copyright (C) 2016..2018  Thomas Schöpping et al.
-
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program.  If not, see <http://www.gnu.org/licenses/>.
-*/
-
-/**
- * @file    aos_debug.h
- * @brief   Macros used for debugging.
- *
- * @addtogroup aos_debug
- * @{
- */
-
-#ifndef _AMIROOS_DEBUG_H_
-#define _AMIROOS_DEBUG_H_
-
-#include <aosconf.h>
-#include <ch.h>
-
-#if (AMIROOS_CFG_DBG == true) || defined(__DOXYGEN__)
-
-/**
- * @brief   Function parameters check.
- * @details If the condition check fails, the kernel panics and halts.
- *
- * @param[in] c The condition to be verified to be true.
- */
-#define aosDbgCheck(c)                chDbgCheck(c)
-
-/**
- * @brief   Condition assertion.
- * @details If the condition check fails, the kernel panics with a message and halts.
- * @note    As a limitation of ChibiOS, the remark string is not currently used.
- *
- * @param[in] c The condition to be verified to be true.
- */
-#define aosDbgAssert(c)               chDbgAssert(c, "__FILE__(__LINE__): aosDbgAssert failed")
-
-/**
- * @brief   Condition assertion.
- * @details If the condition check fails, the kernel panics with a message and halts.
- * @note    As a limitation of ChibiOS, the remark string is not currently used.
- *
- * @param[in] c The condition to be verified to be true.
- * @param[in] r A custom remark string.
- */
-#define aosDbgAssertMsg(c, r) {                           \
-  (void)r;                                                \
-  chDbgAssert(c, r);                                      \
-}
-
-/**
- * @brief   Printf function for messages only printed in debug builds.
- *
- * @param[in] fmt   Formatted string to print.
- */
-#define aosDbgPrintf(fmt, ...)           chprintf((BaseSequentialStream*)&aos.iostream, fmt, ##__VA_ARGS__)
-
-#else /* (AMIROOS_CFG_DBG != true) */
-
-#define aosDbgCheck(c) {                                  \
-  (void)(c);                                              \
-  }
-
-#define aosDbgAssert(c) {                                 \
-  (void)(c);                                              \
-}
-
-#define aosDbgAssertMsg(c, r) {                           \
-  (void)(c);                                              \
-  (void)(r);                                              \
-}
-
-#define aosDbgPrintf(fmt, ...) {                          \
-  (void)(fmt);                                            \
-}
-
-#endif
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-  void aosPrintHaltErrorCode(const char* reason);
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* _AMIROOS_DEBUG_H_ */
-
-/** @} */
diff --git a/os/core/inc/aos_iostream.h b/os/core/inc/aos_iostream.h
deleted file mode 100644
index 2c71571..0000000
--- a/os/core/inc/aos_iostream.h
+++ /dev/null
@@ -1,146 +0,0 @@
-/*
-AMiRo-OS is an operating system designed for the Autonomous Mini Robot (AMiRo) platform.
-Copyright (C) 2016..2018  Thomas Schöpping et al.
-
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program.  If not, see <http://www.gnu.org/licenses/>.
-*/
-
-/**
- * @file    aos_iostream.h
- * @brief   Stream and channel macros and structures.
- *
- * @addtogroup aos_stream
- * @{
- */
-
-#ifndef _AMIROOS_IOSTREAM_H_
-#define _AMIROOS_IOSTREAM_H_
-
-#include <hal.h>
-#include <aos_types.h>
-#include <stdarg.h>
-
-
-
-/**
- * @brief   Channel flag to indicate whether the channel is attached to a stream.
- */
-#define AOS_IOCHANNEL_ATTACHED                  (1 << 0)
-
-/**
- * @brief   Channel flag to indicate whether the channel is set as input.
- */
-#define AOS_IOCHANNEL_INPUT_ENABLE              (1 << 1)
-
-/**
- * @brief   Channel flag to indicate whether the channel is set as output.
- */
-#define AOS_IOCHANNEL_OUTPUT_ENABLE             (1 << 2)
-
-/*
- * forward definitions
- */
-typedef struct aos_iochannel AosIOChannel;
-typedef struct aos_ostream AosIOStream;
-
-/**
- * @brief   AosI=Channel specific methods.
- */
-#define _aos_iochannel_methods                                              \
-  _base_asynchronous_channel_methods
-
-/**
- * @brief   AosIOChannel specific data.
- */
-#define _aos_iochannel_data                                                 \
-  /* pointer to a BaseAsynchronousChannel object */                         \
-  BaseAsynchronousChannel* asyncchannel;                                    \
-  /* pointer to the next channel in a AosIOStream */                        \
-  AosIOChannel* next;                                                       \
-  /* flags related to the channel */                                        \
-  uint8_t flags;
-
-/**
- * @extends BaseAsynchronousChannelVMT
- *
- * @brief   AosIOChannel virtual methods table.
- */
-struct AosIOChannelVMT {
-  _aos_iochannel_methods
-};
-
-/**
- * @extends BaseAsynchronousChannel
- *
- * @brief   I/O Channel class.
- * @details This class implements an asynchronous I/O channel.
- */
-struct aos_iochannel {
-  /** @brief Virtual Methods Table. */
-  const struct AosIOChannelVMT* vmt;
-  _aos_iochannel_data
-};
-
-/**
- * @brief   AosIOStream methods.
- */
-#define _aos_iostream_methods                                               \
-  _base_sequential_stream_methods
-
-/**
- * @brief   AosIOStream data.
- */
-#define _aos_iostream_data                                                  \
-  /* Pointer to the first channel in a list. */                             \
-  AosIOChannel* channel;
-
-/**
- * @extends BaseSequentialStream
- *
- * @brief   AosIOStream virtual methods table.
- */
-struct AosIOStreamVMT {
-  _aos_iostream_methods
-};
-
-/**
- * @extends BaseSequentialStream
- *
- * @brief   I/O Stream class.
- * @details This class implements an base sequential stream.
- * @todo    So far only output but no input is supported.
- */
-struct aos_ostream {
-  const struct AosIOStreamVMT* vmt;
-  _aos_iostream_data
-};
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-  void aosIOStreamInit(AosIOStream* stream);
-  void aosIOChannelInit(AosIOChannel* channel, BaseAsynchronousChannel* asyncchannel);
-  void aosIOStreamAddChannel(AosIOStream* stream, AosIOChannel* channel);
-  aos_status_t aosIOStreamRemoveChannel(AosIOStream* stream, AosIOChannel* channel);
-  void aosIOChannelInputEnable(AosIOChannel* channel);
-  void aosIOChannelInputDisable(AosIOChannel* channel);
-  void aosIOChannelOutputEnable(AosIOChannel* channel);
-  void aosIOChannelOutputDisable(AosIOChannel* channel);
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* _AMIROOS_IOSTREAM_H_ */
-
-/** @} */
diff --git a/os/core/inc/aos_shell.h b/os/core/inc/aos_shell.h
deleted file mode 100644
index 07d2128..0000000
--- a/os/core/inc/aos_shell.h
+++ /dev/null
@@ -1,376 +0,0 @@
-/*
-AMiRo-OS is an operating system designed for the Autonomous Mini Robot (AMiRo) platform.
-Copyright (C) 2016..2018  Thomas Schöpping et al.
-
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program.  If not, see <http://www.gnu.org/licenses/>.
-*/
-
-/**
- * @file    aos_shell.h
- * @brief   Shell macros and structures.
- *
- * @addtogroup aos_shell
- * @{
- */
-
-#ifndef _AMIROOS_SHELL_H_
-#define _AMIROOS_SHELL_H_
-
-#include <aosconf.h>
-#if (AMIROOS_CFG_SHELL_ENABLE == true)
-#include <hal.h>
-#include <aos_types.h>
-
-/**
- * @brief   Shell event flag that is emitted when the thread starts.
- */
-#define AOS_SHELL_EVTFLAG_START                   ((eventflags_t)(1 << 0))
-
-/**
- * @brief   Shell event flag that is emitted when a command is executed.
- */
-#define AOS_SHELL_EVTFLAG_EXEC                    ((eventflags_t)(1 << 1))
-
-/**
- * @brief   Shell event flag that is emitted when a command execution finished.
- */
-#define AOS_SHELL_EVTFLAG_DONE                    ((eventflags_t)(1 << 2))
-
-/**
- * @brief   Shell event flag that is emitted when the shread stops.
- */
-#define AOS_SHELL_EVTFLAG_EXIT                    ((eventflags_t)(1 << 3))
-
-/**
- * @brief   Shell event flag that is emitted when an I/O error occurred.
- */
-#define AOS_SHELL_EVTFLAG_IOERROR                 ((eventflags_t)(1 << 4))
-
-/**
- * @brief   Shell input configuration for replacing content by user input.
- */
-#define AOS_SHELL_CONFIG_INPUT_OVERWRITE          (1 << 0)
-
-/**
- * @brief   Shell prompt configuration print a minimalistic prompt.
- */
-#define AOS_SHELL_CONFIG_PROMPT_MINIMAL           (1 << 1)
-
-/**
- * @brief   Shell prompt configuration to additionally print the system uptime with the prompt.
- */
-#define AOS_SHELL_CONFIG_PROMPT_UPTIME            (1 << 2)
-
-/**
- * @brief   Shell prompt configuration to additionally print the date and time with the prompt.
- */
-#define AOS_SHELL_CONFIG_PROMPT_DATETIME          (2 << 2)
-
-/**
- * @brief   Shell prompt configuration to additionally print the system uptime with the prompt.
- */
-#define AOS_SHELL_CONFIG_MATCH_CASE               (1 << 4)
-
-/**
- * @brief   Shell I/O channel flag whether the channel is attached to a list.
- */
-#define AOS_SHELLCHANNEL_ATTACHED                 (1 << 0)
-
-/**
- * @brief   Shell I/O channel flag whether the channel is enabled as input.
- */
-#define AOS_SHELLCHANNEL_INPUT_ENABLED            (1 << 1)
-
-/**
- * @brief   Shell I/O channel flag whether the channel is enabled as output.
- */
-#define AOS_SHELLCHANNEL_OUTPUT_ENABLED           (1 << 2)
-
-/*
- * forward definitions
- */
-typedef struct aos_shellchannel AosShellChannel;
-typedef struct aos_shellstream AosShellStream;
-
-/**
- * @brief   AosShellChannel specific methods.
- */
-#define _aos_shell_channel_methods                                          \
-  _base_asynchronous_channel_methods
-
-/**
- * @brief   AosShellChannel specific data.
- */
-#define _aos_shell_channel_data                                             \
-  /* pointer to a BaseAsynchronousChannel object */                         \
-  BaseAsynchronousChannel* asyncchannel;                                    \
-  /* event listener for the associated BaseAsynchronousChannel */           \
-  event_listener_t listener;                                                \
-  /* pointer to the next chennal in a AosShellStream */                     \
-  AosShellChannel* next;                                                    \
-  /* flags related to the channel */                                        \
-  uint8_t flags;
-
-/**
- * @extends BaseAsynchronousChannelVMT
- *
- * @brief   AosShellChannel virtual methods table.
- */
-struct AosShellChannelVMT {
-  _aos_shell_channel_methods
-};
-
-/**
- * @extends BaseAsynchronousChannel
- *
- * @brief   Shell channel class.
- * @details This class implements an asynchronous I/O channel.
- */
-struct aos_shellchannel {
-  /** @brief Virtual Methods Table. */
-  const struct AosShellChannelVMT* vmt;
-  _aos_shell_channel_data
-};
-
-/**
- * @brief   AosShellStream methods.
- */
-#define _aos_shellstream_methods                                            \
-  _base_sequential_stream_methods
-
-/**
- * @brief   AosShellStream data.
- */
-#define _aos_shellstream_data                                               \
-  /* Pointer to the first channel in a list. */                             \
-  AosShellChannel* channel;
-
-/**
- * @extends BaseSequentialStream
- *
- * @brief   AosShellStream virtual methods table.
- */
-struct AosShellStreamVMT {
-  _aos_shellstream_methods
-};
-
-/**
- * @extends BaseSequentialStream
- *
- * @brief   Shell Stream class.
- * @details This class implements an base sequential stream.
- * @todo    So far only output but no input is supported.
- */
-struct aos_shellstream {
-  const struct AosShellStreamVMT* vmt;
-  _aos_shellstream_data
-};
-
-/**
- * @brief   Shell command calback type.
- */
-typedef int (*aos_shellcmdcb_t)(BaseSequentialStream* stream, int argc, char* argv[]);
-
-/**
- * @brief   Shell command structure.
- */
-typedef struct aos_shellcommand {
-  /**
-   * @brief   Command name.
-   */
-  const char* name;
-
-  /**
-   * @brief   Callback function.
-   */
-  aos_shellcmdcb_t callback;
-
-  /**
-   * @brief   Pointer to next command in a singly linked list.
-   */
-  struct aos_shellcommand* next;
-
-} aos_shellcommand_t;
-
-/**
- * @brief   Execution status of a shell command.
- */
-typedef struct aos_shellexecstatus {
-  /**
-   * @brief   Pointer to the command that was executed.
-   */
-  aos_shellcommand_t* command;
-
-  /**
-   * @brief   Return value of the executed command.
-   */
-  int retval;
-} aos_shellexecstatus_t;
-
-/**
- * @brief   Enumerator to encode shell actions.
- */
-typedef enum aos_shellaction {
-  AOS_SHELL_ACTION_NONE,
-  AOS_SHELL_ACTION_READCHAR,
-  AOS_SHELL_ACTION_AUTOFILL,
-  AOS_SHELL_ACTION_SUGGEST,
-  AOS_SHELL_ACTION_INSERTTOGGLE,
-  AOS_SHELL_ACTION_DELETEFORWARD,
-  AOS_SHELL_ACTION_DELETEBACKWARD,
-  AOS_SHELL_ACTION_RECALLLAST,
-  AOS_SHELL_ACTION_CLEAR,
-  AOS_SHELL_ACTION_CURSOR2START,
-  AOS_SHELL_ACTION_CURSOR2END,
-  AOS_SHELL_ACTION_CURSORLEFT,
-  AOS_SHELL_ACTION_CURSORRIGHT,
-  AOS_SHELL_ACTION_EXECUTE,
-  AOS_SHELL_ACTION_ESCSTART,
-} aos_shellaction_t;
-
-/**
- * @brief   Shell structure.
- */
-typedef struct aos_shell {
-  /**
-   * @brief   Pointer to the thread object.
-   */
-  thread_t* thread;
-
-  /**
-   * @brief   Event source.
-   */
-  event_source_t eventSource;
-
-  /**
-   * @brief   Struct for OS related events
-   */
-  struct {
-    /**
-     * @brief   Pointer to the OS' event source.
-     */
-    event_source_t* eventSource;
-
-    /**
-     * @brief   Listener for OS related events.
-     */
-    event_listener_t eventListener;
-  } os;
-
-  /**
-     * @brief   Pointer to the first I/O channel.
-     */
-  AosShellStream stream;
-
-  /**
-   * @brief   String to printed as prompt.
-   */
-  const char* prompt;
-
-  /**
-   * @brief   Pointer to the first element of the singly linked list of commands.
-   * @details Commands are ordered alphabetically in the list.
-   */
-  aos_shellcommand_t* commands;
-
-  /**
-   * @brief   Execution status of the most recent command.
-   */
-  aos_shellexecstatus_t execstatus;
-
-  /**
-   * @brief   Input buffer.
-   */
-  char* line;
-
-  /**
-   * @brief   Size of the input buffer.
-   */
-  size_t linesize;
-
-  /**
-   * @brief   Structure containing data for internal input parsing.
-   */
-  struct {
-    /**
-     * @brief   The last action executed by the shell.
-     */
-    aos_shellaction_t lastaction;
-
-    /**
-     * @brief   Number of character in the current escape sequence.
-     */
-    uint8_t escp;
-
-    /**
-     * @brief   Buffer to store an escape sequence.
-     */
-    char escseq[5];
-
-    /**
-     * @brief   Current curso position.
-     */
-    size_t cursorpos;
-
-    /**
-     * @brief   Current line width.
-     */
-    size_t lineend;
-
-    /**
-     * @brief   Flag whether there was input since the prompt was printed the last time.
-     */
-    bool noinput;
-  } inputdata;
-
-  /**
-   * @brief   Argument buffer.
-   */
-  char** arglist;
-
-  /**
-   * @brief   Size of the argument buffer.
-   */
-  size_t arglistsize;
-
-  /**
-   * @brief   Configuration flags.
-   */
-  uint8_t config;
-} aos_shell_t;
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-  void aosShellInit(aos_shell_t* shell, event_source_t* oseventsource, const char* prompt, char* line, size_t linesize, char** arglist, size_t arglistsize);
-  void aosShellStreamInit(AosShellStream* stream);
-  void aosShellChannelInit(AosShellChannel* channel, BaseAsynchronousChannel* asyncchannel);
-  aos_status_t aosShellAddCommand(aos_shell_t* shell, aos_shellcommand_t* cmd);
-  aos_status_t aosShellRemoveCommand(aos_shell_t* shell, char* cmd, aos_shellcommand_t** removed);
-  void aosShellStreamAddChannel(AosShellStream* stream, AosShellChannel* channel);
-  aos_status_t aosShellStreamRemoveChannel(AosShellStream* stream, AosShellChannel* channel);
-  void aosShellChannelInputEnable(AosShellChannel* channel);
-  void aosShellChannelInputDisable( AosShellChannel* channel);
-  void aosShellChannelOutputEnable(AosShellChannel* channel);
-  void aosShellChannelOutputDisable(AosShellChannel* channel);
-  THD_FUNCTION(aosShellThread, shell);
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* AMIROOS_CFG_SHELL_ENABLE == true */
-
-#endif /* _AMIROOS_SHELL_H_ */
-
-/** @} */
diff --git a/os/core/inc/aos_system.h b/os/core/inc/aos_system.h
deleted file mode 100644
index dbba08c..0000000
--- a/os/core/inc/aos_system.h
+++ /dev/null
@@ -1,224 +0,0 @@
-/*
-AMiRo-OS is an operating system designed for the Autonomous Mini Robot (AMiRo) platform.
-Copyright (C) 2016..2018  Thomas Schöpping et al.
-
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program.  If not, see <http://www.gnu.org/licenses/>.
-*/
-
-/**
- * @file    aos_system.h
- * @brief   System macros and structures.
- *
- * @addtogroup aos_system
- * @{
- */
-
-#ifndef _AMIROOS_SYSTEM_H_
-#define _AMIROOS_SYSTEM_H_
-
-#include <aos_iostream.h>
-#include <amiro-lld.h>
-#include <aos_shell.h>
-#include <aos_time.h>
-#include <chprintf.h>
-
-/**
- * @brief   Resolution of the system time measurement.
- */
-#define AOS_SYSTEM_TIME_RESOLUTION              ((MICROSECONDS_PER_SECOND + CH_CFG_ST_FREQUENCY - 1) / CH_CFG_ST_FREQUENCY)
-
-/**
- * @brief   System event flag which is emitted when a shutdown was initiated.
- */
-#define AOS_SYSTEM_EVENTFLAGS_SHUTDOWN          (eventflags_t)(1 << 0)
-
-/**
- * @brief   System event flag which is emitted when a shutdown to transportation mode was initiated.
- */
-#define AOS_SYSTEM_EVENTFLAGS_TRANSPORTATION    (AOS_SYSTEM_EVENTFLAGS_SHUTDOWN | (eventflags_t)(1 << 1))
-
-/**
- * @brief   System event flag which is emitted when a shutdown to deepsleep mode was initiated.
- */
-#define AOS_SYSTEM_EVENTFLAGS_DEEPSLEEP         (AOS_SYSTEM_EVENTFLAGS_SHUTDOWN | (eventflags_t)(1 << 2))
-
-/**
- * @brief   System event flag which is emitted when a shutdown to hibernate mode was initiated.
- */
-#define AOS_SYSTEM_EVENTFLAGS_HIBERNATE         (AOS_SYSTEM_EVENTFLAGS_SHUTDOWN | (eventflags_t)(1 << 3))
-
-/**
- * @brief   System event flag which is emitted when a system restart was initiated.
- */
-#define AOS_SYSTEM_EVENTFLAGS_RESTART           (AOS_SYSTEM_EVENTFLAGS_SHUTDOWN | (eventflags_t)(1 << 4))
-
-/**
- * @brief   Major version of the implemented SSSP.
- */
-#define AOS_SYSTEM_SSSP_VERSION_MAJOR           1
-
-/**
- * @brief   Minor version of the implemented SSSP.
- */
-#define AOS_SYSTEM_SSSP_VERSION_MINOR           4
-
-/**
- * @brief   Timeout delay according to SSSP.
- * @details SSSP defines timeouts to be ten times longer than the signal delay time.
- */
-#define AOS_SYSTEM_SSSP_TIMEOUT                 (10 * AMIROOS_CFG_SSSP_SIGNALDELAY)
-
-/**
- * @brief   Enumerator to identify shutdown types.
- */
-typedef enum aos_shutdown {
-  AOS_SHUTDOWN_NONE,            /**< Default value if no shutdown action was initiated */
-  AOS_SHUTDOWN_PASSIVE,         /**< Passive shutdown (initiated by another module). */
-  AOS_SHUTDOWN_HIBERNATE,       /**< Active shutdown to hibernate mode. */
-  AOS_SHUTDOWN_DEEPSLEEP,       /**< Active shutdown to deepsleep mode. */
-  AOS_SHUTDOWN_TRANSPORTATION,  /**< Active shutdown to transportation mode. */
-  AOS_SHUTDOWN_RESTART,         /**< Active saystem restart request. */
-} aos_shutdown_t;
-
-/**
- * @brief   Enumerator of the several stages of SSSP.
- */
-typedef enum aos_ssspstage {
-  AOS_SSSP_STARTUP_1_1  = 0x10, /**< Identifier of SSSP startup phase stage 1-1. */
-  AOS_SSSP_STARTUP_1_2  = 0x11, /**< Identifier of SSSP startup phase stage 1-2. */
-  AOS_SSSP_STARTUP_1_3  = 0x12, /**< Identifier of SSSP startup phase stage 1-3. */
-  AOS_SSSP_STARTUP_2_1  = 0x14, /**< Identifier of SSSP startup phase stage 2-1. */
-  AOS_SSSP_STARTUP_2_2  = 0x15, /**< Identifier of SSSP startup phase stage 2-2. */
-  AOS_SSSP_STARTUP_3_1  = 0x18, /**< Identifier of SSSP startup phase stage 3-1. */
-  AOS_SSSP_STARTUP_3_2  = 0x19, /**< Identifier of SSSP startup phase stage 3-2. */
-  AOS_SSSP_STARTUP_3_3  = 0x1A, /**< Identifier of SSSP startup phase stage 3-3. */
-  AOS_SSSP_STARTUP_3_4  = 0x1B, /**< Identifier of SSSP startup phase stage 3-4. */
-  AOS_SSSP_OPERATION    = 0x20, /**< Identifier of SSSP operation pahse. */
-  AOS_SSSP_SHUTDOWN_1_1 = 0x30, /**< Identifier of SSSP shutdown phase stage 1-1. */
-  AOS_SSSP_SHUTDOWN_1_2 = 0x31, /**< Identifier of SSSP shutdown phase stage 1-2. */
-  AOS_SSSP_SHUTDOWN_1_3 = 0x32, /**< Identifier of SSSP shutdown phase stage 1-3. */
-  AOS_SSSP_SHUTDOWN_2_1 = 0x34, /**< Identifier of SSSP shutdown phase stage 2-1. */
-  AOS_SSSP_SHUTDOWN_2_2 = 0x35, /**< Identifier of SSSP shutdown phase stage 2-2. */
-  AOS_SSSP_SHUTDOWN_3   = 0x38, /**< Identifier of SSSP shutdown phase stage 3. */
-} aos_ssspstage_t;
-
-/**
- * @brief   Type to represent module IDs.
- */
-typedef uint16_t aos_ssspmoduleid_t;
-
-/**
- * @brief   AMiRo-OS base system structure.
- */
-typedef struct aos_system {
-
-  /**
-   * @brief   SSSP relevant data.
-   */
-  struct {
-    /**
-     * @brief   Current SSSP stage of the system.
-     */
-    aos_ssspstage_t stage;
-
-    /**
-     * @brief   Module identifier.
-     * @details A value of 0 indicates an uninitialized ID.
-     *          The vlaues 0 and ~0 are reserved und must not be set.
-     */
-    aos_ssspmoduleid_t moduleId;
-  } sssp;
-
-  /**
-   * @brief   System I/O stream.
-   */
-  AosIOStream iostream;
-
-  /**
-   * @brief   Event structure.
-   */
-  struct {
-
-    /**
-     * @brief   I/O event source.
-     */
-    event_source_t io;
-
-    /**
-     * @brief   OS event source.
-     */
-    event_source_t os;
-  } events;
-
-#if (AMIROOS_CFG_SHELL_ENABLE == true) || defined(__DOXYGEN__)
-  /**
-   * @brief   Pointer to the shell object.
-   */
-  aos_shell_t shell;
-#endif
-
-} aos_system_t;
-
-/**
- * @brief   Global system object.
- */
-extern aos_system_t aos;
-
-/**
- * @brief   Printf function that uses the default system I/O stream.
- *
- * @param[in] fmt   Formatted string to print.
- */
-#define aosprintf(fmt, ...)                     chprintf((BaseSequentialStream*)&aos.iostream, fmt, ##__VA_ARGS__)
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-#if (AMIROOS_CFG_SHELL_ENABLE == true)
-  void aosSysInit(const char* shellPrompt);
-#else
-  void aosSysInit(void);
-#endif
-  void aosSysStart(void);
-  eventmask_t aosSysSsspStartupOsInitSyncCheck(event_listener_t* syncEvtListener);
-  void aosSysGetUptimeX(aos_timestamp_t* ut);
-  void aosSysGetDateTime(struct tm* dt);
-  void aosSysSetDateTime(struct tm* dt);
-  void aosSysShutdownInit(aos_shutdown_t shutdown);
-  void aosSysStop(void);
-  void aosSysDeinit(void);
-  void aosSysShutdownFinal(aos_shutdown_t shutdown);
-#ifdef __cplusplus
-}
-#endif
-
-/**
- * @brief   Retrieves the system uptime.
- *
- * @param[out] ut   The system uptime.
- */
-static inline void aosSysGetUptime(aos_timestamp_t* ut)
-{
-  aosDbgCheck(ut != NULL);
-
-  chSysLock();
-  aosSysGetUptimeX(ut);
-  chSysUnlock();
-
-  return;
-}
-
-#endif /* _AMIROOS_SYSTEM_H_ */
-
-/** @} */
diff --git a/os/core/inc/aos_thread.h b/os/core/inc/aos_thread.h
deleted file mode 100644
index 7568b49..0000000
--- a/os/core/inc/aos_thread.h
+++ /dev/null
@@ -1,242 +0,0 @@
-/*
-AMiRo-OS is an operating system designed for the Autonomous Mini Robot (AMiRo) platform.
-Copyright (C) 2016..2018  Thomas Schöpping et al.
-
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program.  If not, see <http://www.gnu.org/licenses/>.
-*/
-
-/**
- * @file    aos_thread.h
- * @brief   Thread macros and inline functions.
- *
- * @addtogroup aos_threads
- * @{
- */
-
-#ifndef _AMIROOS_THREAD_H_
-#define _AMIROOS_THREAD_H_
-
-#include <aos_time.h>
-#include <aos_system.h>
-
-/**
- * @brief   Minimum thread priority.
- */
-#define AOS_THD_LOWPRIO_MIN           ((tprio_t)(LOWPRIO))
-
-/**
- * @brief   Maximum priority for background threads.
- */
-#define AOS_THD_LOWPRIO_MAX           ((tprio_t)(LOWPRIO + ((NORMALPRIO - LOWPRIO) / 2)))
-
-/**
- * @brief   Minimum priority for normal/standard threads.
- */
-#define AOS_THD_NORMALPRIO_MIN        ((tprio_t)(AOS_THD_LOWPRIO_MAX + 1))
-
-/**
- * @brief   Maximum priority for normal/standard threads.
- */
-#define AOS_THD_NORMALPRIO_MAX        ((tprio_t)(NORMALPRIO))
-
-/**
- * @brief   Minimum priority for important threads.
- */
-#define AOS_THD_HIGHPRIO_MIN          ((tprio_t)(NORMALPRIO + 1))
-
-/**
- * @brief   Maximum priority for important threads.
- */
-#define AOS_THD_HIGHPRIO_MAX          ((tprio_t)(NORMALPRIO + ((HIGHPRIO - NORMALPRIO) / 2)))
-
-/**
- * @brief   Minimum priority for real-time threads.
- */
-#define AOS_THD_RTPRIO_MIN            ((tprio_t)(AOS_THD_HIGHPRIO_MAX + 1))
-
-/**
- * @brief   Maximum priority for real-time threads.
- */
-#define AOS_THD_RTPRIO_MAX            ((tprio_t)(HIGHPRIO - 1))
-
-/**
- * @brief   Priority for the system control thread.
- */
-#define AOS_THD_CTRLPRIO              ((tprio_t)(HIGHPRIO))
-
-/**
- * @brief   Maximum timeframe that can be slept in system ticks.
- */
-#define AOS_THD_MAX_SLEEP_ST          TIME_MAX_INTERVAL
-
-/**
- * @brief   Maximum timeframe that can be slept in seconds.
- */
-#define AOS_THD_MAX_SLEEP_S           (chTimeI2S(AOS_THD_MAX_SLEEP_ST) - 1)
-
-/**
- * @brief   Maximum timeframe that can be slept in milliseconds.
- */
-#define AOS_THD_MAX_SLEEP_MS          (chTimeI2MS(AOS_THD_MAX_SLEEP_ST) - 1)
-
-/**
- * @brief   Maximum timeframe that can be slept in microseconds.
- */
-#define AOS_THD_MAX_SLEEP_US          (chTimeI2US(AOS_THD_MAX_SLEEP_ST) - 1)
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-  void aosThdSleepUntilS(const aos_timestamp_t* t);
-#ifdef __cplusplus
-}
-#endif
-
-/**
- * @brief   Lets the calling thread sleep the specified amount of microseconds.
- *
- * @param[in] us    Time to sleep in microseconds.
- */
-static inline void aosThdUSleepS(const aos_interval_t us)
-{
-  aos_timestamp_t ut;
-
-  aosSysGetUptimeX(&ut);
-  ut += us;
-  aosThdSleepUntilS(&ut);
-
-  return;
-}
-
-/**
- * @brief   Lets the calling thread sleep the specified amount of milliseconds.
- *
- * @param[in] ms    Time to sleep in milliseconds.
- */
-static inline void aosThdMSleepS(const uint32_t ms)
-{
-  aos_timestamp_t ut;
-
-  aosSysGetUptimeX(&ut);
-  ut += (aos_timestamp_t)ms * MICROSECONDS_PER_MILLISECOND;
-  aosThdSleepUntilS(&ut);
-
-  return;
-}
-
-/**
- * @brief   Lets the calling thread sleep the specified amount of seconds.
- *
- * @param[in] s     Time to sleep in seconds.
- */
-static inline void aosThdSSleepS(const uint32_t s)
-{
-  aos_timestamp_t ut;
-
-  aosSysGetUptimeX(&ut);
-  ut += (aos_timestamp_t)s * MICROSECONDS_PER_SECOND;
-  aosThdSleepUntilS(&ut);
-
-  return;
-}
-
-/**
- * @brief   Lets the calling thread sleep the specified amount of seconds.
- *
- * @param[in] s     Time to sleep in seconds.
- */
-static inline void aosThdSleepS(const float s)
-{
-  aos_timestamp_t ut;
-
-  aosSysGetUptimeX(&ut);
-  ut += (aos_timestamp_t)(s * MICROSECONDS_PER_SECOND);
-  aosThdSleepUntilS(&ut);
-
-  return;
-}
-
-/**
- * @brief   Lets the calling thread sleep the specified amount of microseconds.
- *
- * @param[in] us    Time to sleep in microseconds.
- */
-static inline void aosThdUSleep(const uint32_t us)
-{
-  chSysLock();
-  aosThdUSleepS(us);
-  chSysUnlock();
-
-  return;
-}
-
-/**
- * @brief   Lets the calling thread sleep the specified amount of milliseconds.
- *
- * @param[in] ms    Time to sleep in milliseconds.
- */
-static inline void aosThdMSleep(const uint32_t ms)
-{
-  chSysLock();
-  aosThdMSleepS(ms);
-  chSysUnlock();
-
-  return;
-}
-
-/**
- * @brief   Lets the calling thread sleep the specified amount of seconds.
- *
- * @param[in] s     Time to sleep in seconds.
- */
-static inline void aosThdSSleep(const uint32_t s)
-{
-  chSysLock();
-  aosThdSSleepS(s);
-  chSysUnlock();
-
-  return;
-}
-
-/**
- * @brief   Lets the calling thread sleep the specified amount of seconds.
- *
- * @param[in] s     Time to sleep in seconds.
- */
-static inline void aosThdSleep(const float s)
-{
-  chSysLock();
-  aosThdSleepS(s);
-  chSysUnlock();
-
-  return;
-}
-
-/**
- * @brief   Lets the calling thread sleep until the specifide system uptime.
- *
- * @param[in] t     Deadline until the thread will sleep.
- */
-static inline void aosThdSleepUntil(const aos_timestamp_t* t)
-{
-  chSysLock();
-  aosThdSleepUntilS(t);
-  chSysUnlock();
-
-  return;
-}
-
-#endif /* _AMIROOS_THREAD_H_ */
-
-/** @} */
diff --git a/os/core/inc/aos_time.h b/os/core/inc/aos_time.h
deleted file mode 100644
index 284af13..0000000
--- a/os/core/inc/aos_time.h
+++ /dev/null
@@ -1,225 +0,0 @@
-/*
-AMiRo-OS is an operating system designed for the Autonomous Mini Robot (AMiRo) platform.
-Copyright (C) 2016..2018  Thomas Schöpping et al.
-
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY) without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program.  If not, see <http://www.gnu.org/licenses/.
-*/
-
-/**
- * @file    aos_time.h
- * @brief   Time related constants and data types.
- *
- * @addtogroup aos_time
- * @{
- */
-
-#ifndef _AMIROOS_TIME_H_
-#define _AMIROOS_TIME_H_
-
-#include <stdint.h>
-
-/**
- * @brief   Generic time to represent long time frames at high precision.
- * @note    By definition the temporal resolution is 1us.
- */
-typedef uint64_t aos_timestamp_t;
-
-/**
- * @brief   generic time to represent medium length time frames at high precision.
- * @note    By definition the temporal resolution is 1us.
- */
-typedef uint32_t aos_interval_t;
-
-/**
- * @brief   Generic time to represent long time frames at high precision.
- * @note    By definition the temporal resolution is 1us.
- */
-typedef aos_timestamp_t aos_longinterval_t;
-
-#define MICROSECONDS_PER_MICROSECOND  ((uint8_t)  (1))
-#define MILLISECONDS_PER_MILLISECOND  ((uint8_t)  (1))
-#define SECONDS_PER_SECOND            ((uint8_t)  (1))
-#define MINUTES_PER_MINUTE            ((uint8_t)  (1))
-#define HOURS_PER_HOUR                ((uint8_t)  (1))
-#define DAYS_PER_DAY                  ((uint8_t)  (1))
-#define WEEKS_PER_WEEK                ((uint8_t)  (1))
-#define MONTHS_PER_MONTH              ((uint8_t)  (1))
-#define YEARS_PER_YEAR                ((uint8_t)  (1))
-#define DECADES_PER_DECADE            ((uint8_t)  (1))
-#define CENTURIES_PER_CENTURY         ((uint8_t)  (1))
-#define MILLENIUMS_PER_MILLENIUM      ((uint8_t)  (1))
-
-#define MICROSECONDS_PER_MILLISECOND  ((uint16_t) (1000))
-#define MILLISECONDS_PER_SECOND       ((uint16_t) (1000))
-#define SECONDS_PER_MINUTE            ((uint8_t)  (60))
-#define MINUTES_PER_HOUR              ((uint8_t)  (60))
-#define HOURS_PER_DAY                 ((uint8_t)  (24))
-#define DAYS_PER_WEEK                 ((uint8_t)  (7))
-#define DAYS_PER_YEAR                 ((float)    (365.25f))
-#define MONTHS_PER_YEAR               ((uint8_t)  (12))
-#define YEARS_PER_DECADE              ((uint8_t)  (10))
-#define DECADES_PER_CENTURY           ((uint8_t)  (10))
-#define CENTURIES_PER_MILLENIUM       ((uint8_t)  (10))
-
-#define MICROSECONDS_PER_SECOND       ((uint32_t) ((uint32_t)MICROSECONDS_PER_MILLISECOND * (uint32_t)MILLISECONDS_PER_SECOND))
-#define MILLISECONDS_PER_MINUTE       ((uint16_t) ((uint16_t)MILLISECONDS_PER_SECOND * (uint16_t)SECONDS_PER_MINUTE))
-#define SECONDS_PER_HOUR              ((uint16_t) ((uint16_t)SECONDS_PER_MINUTE * (uint16_t)MINUTES_PER_HOUR))
-#define MINUTES_PER_DAY               ((uint16_t) ((uint16_t)MINUTES_PER_HOUR * (uint16_t)HOURS_PER_DAY))
-#define HOURS_PER_WEEK                ((uint8_t)  (HOURS_PER_DAY * DAYS_PER_WEEK))
-#define HOURS_PER_YEAR                ((uint16_t) ((float)HOURS_PER_DAY * DAYS_PER_YEAR))
-#define DAYS_PER_MONTH                ((float)    (DAYS_PER_YEAR / (float)MONTHS_PER_YEAR))
-#define DAYS_PER_DECADE               ((float)    (DAYS_PER_YEAR * (float)YEARS_PER_DECADE))
-#define WEEKS_PER_YEAR                ((float)    (DAYS_PER_YEAR / (float)DAYS_PER_WEEK))
-#define MONTHS_PER_DECADE             ((uint8_t)  (MONTHS_PER_YEAR * YEARS_PER_DECADE))
-#define YEARS_PER_CENTURY             ((uint8_t)  (YEARS_PER_DECADE * DECADES_PER_CENTURY))
-#define DECADES_PER_MILLENIUM         ((uint8_t)  (DECADES_PER_CENTURY * CENTURIES_PER_MILLENIUM))
-
-#define MICROSECONDS_PER_MINUTE       ((uint32_t) ((uint32_t)MICROSECONDS_PER_MILLISECOND * (uint32_t)MILLISECONDS_PER_MINUTE))
-#define MILLISECONDS_PER_HOUR         ((uint32_t) ((uint32_t)MILLISECONDS_PER_SECOND * (uint32_t)SECONDS_PER_HOUR))
-#define SECONDS_PER_DAY               ((uint32_t) ((uint32_t)SECONDS_PER_MINUTE * (uint32_t)MINUTES_PER_DAY))
-#define MINUTES_PER_WEEK              ((uint16_t) ((uint16_t)MINUTES_PER_HOUR * (uint16_t)HOURS_PER_WEEK))
-#define HOURS_PER_MONTH               ((float)    ((float)HOURS_PER_DAY * DAYS_PER_MONTH))
-#define HOURS_PER_DECADE              ((uint32_t) ((float)HOURS_PER_DAY * DAYS_PER_DECADE))
-#define MINUTES_PER_YEAR              ((uint32_t) ((uint32_t)MINUTES_PER_HOUR * (uint32_t)HOURS_PER_YEAR))
-#define DAYS_PER_CENTURY              ((uint16_t) (DAYS_PER_YEAR * (float)YEARS_PER_CENTURY))
-#define WEEKS_PER_MONTH               ((float)    (DAYS_PER_MONTH / (float)DAYS_PER_WEEK))
-#define WEEKS_PER_DECADE              ((float)    (DAYS_PER_DECADE / (float)DAYS_PER_WEEK))
-#define MONTHS_PER_CENTURY            ((uint16_t) ((uint16_t)MONTHS_PER_YEAR * (uint16_t)YEARS_PER_CENTURY))
-#define YEARS_PER_MILLENIUM           ((uint16_t) ((uint16_t)YEARS_PER_DECADE * (uint16_t)DECADES_PER_MILLENIUM))
-
-#define MICROSECONDS_PER_HOUR         ((uint32_t) ((uint32_t)MICROSECONDS_PER_MILLISECOND * MILLISECONDS_PER_HOUR))
-#define MILLISECONDS_PER_DAY          ((uint32_t) ((uint32_t)MILLISECONDS_PER_SECOND * SECONDS_PER_DAY))
-#define SECONDS_PER_WEEK              ((uint32_t) (SECONDS_PER_MINUTE * (uint32_t)MINUTES_PER_WEEK))
-#define SECONDS_PER_YEAR              ((uint32_t) (SECONDS_PER_MINUTE * MINUTES_PER_YEAR))
-#define MINUTES_PER_MONTH             ((uint16_t) ((float)MINUTES_PER_HOUR * HOURS_PER_MONTH))
-#define MINUTES_PER_DECADE            ((uint32_t) ((uint32_t)MINUTES_PER_HOUR * HOURS_PER_DECADE))
-#define HOURS_PER_CENTURY             ((uint32_t) ((uint32_t)HOURS_PER_DAY * (uint32_t)DAYS_PER_CENTURY))
-#define DAYS_PER_MILLENIUM            ((uint32_t) (DAYS_PER_YEAR * (float)YEARS_PER_MILLENIUM))
-#define WEEKS_PER_CENTURY             ((float)    ((float)DAYS_PER_CENTURY / (float)DAYS_PER_WEEK))
-#define MONTHS_PER_MILLENIUM          ((uint16_t) ((uint16_t)MONTHS_PER_YEAR * YEARS_PER_MILLENIUM))
-
-#define MICROSECONDS_PER_DAY          ((uint64_t) ((uint64_t)MICROSECONDS_PER_MILLISECOND * (uint64_t)MILLISECONDS_PER_DAY))
-#define MILLISECONDS_PER_WEEK         ((uint32_t) ((uint32_t)MILLISECONDS_PER_SECOND * SECONDS_PER_WEEK))
-#define MILLISECONDS_PER_YEAR         ((uint64_t) ((uint64_t)MILLISECONDS_PER_SECOND * (uint64_t)SECONDS_PER_YEAR))
-#define SECONDS_PER_MONTH             ((uint32_t) ((uint32_t)SECONDS_PER_MINUTE * (uint32_t)MINUTES_PER_MONTH))
-#define SECONDS_PER_DECADE            ((uint32_t) ((uint32_t)SECONDS_PER_MINUTE * MINUTES_PER_DECADE))
-#define MINUTES_PER_CENTURY           ((uint32_t) ((uint32_t)MINUTES_PER_HOUR * HOURS_PER_CENTURY))
-#define HOURS_PER_MILLENIUM           ((uint32_t) ((uint32_t)HOURS_PER_DAY * DAYS_PER_MILLENIUM))
-#define WEEKS_PER_MILLENIUM           ((float)    ((float)DAYS_PER_MILLENIUM / (float)DAYS_PER_WEEK))
-
-#define MICROSECONDS_PER_WEEK         ((uint64_t) ((uint64_t)MICROSECONDS_PER_MILLISECOND * (uint64_t)MILLISECONDS_PER_WEEK))
-#define MICROSECONDS_PER_YEAR         ((uint64_t) ((uint64_t)MICROSECONDS_PER_MILLISECOND * MILLISECONDS_PER_YEAR))
-#define MILLISECONDS_PER_MONTH        ((uint32_t) ((uint32_t)MILLISECONDS_PER_SECOND * SECONDS_PER_MONTH))
-#define MILLISECONDS_PER_DECADE       ((uint64_t) ((uint64_t)MILLISECONDS_PER_SECOND * (uint64_t)SECONDS_PER_DECADE))
-#define SECONDS_PER_CENTURY           ((uint32_t) (SECONDS_PER_MINUTE * MINUTES_PER_CENTURY))
-#define MINUTES_PER_MILLENIUM         ((uint32_t) ((uint32_t)MINUTES_PER_HOUR * HOURS_PER_MILLENIUM))
-
-#define MICROSECONDS_PER_MONTH        ((uint64_t) ((uint64_t)MICROSECONDS_PER_MILLISECOND * (uint64_t)MILLISECONDS_PER_MONTH))
-#define MICROSECONDS_PER_DECADE       ((uint64_t) ((uint64_t)MICROSECONDS_PER_MILLISECOND * MILLISECONDS_PER_DECADE))
-#define MILLISECONDS_PER_CENTURY      ((uint64_t) ((uint64_t)MILLISECONDS_PER_SECOND * (uint64_t)SECONDS_PER_CENTURY))
-#define SECONDS_PER_MILLENIUM         ((uint64_t) ((uint64_t)SECONDS_PER_MINUTE * (uint64_t)MINUTES_PER_MILLENIUM))
-
-#define MICROSECONDS_PER_CENTURY      ((uint64_t) ((uint64_t)MICROSECONDS_PER_MILLISECOND * MILLISECONDS_PER_CENTURY))
-#define MILLISECONDS_PER_MILLENIUM    ((uint64_t) ((uint64_t)MILLISECONDS_PER_SECOND * SECONDS_PER_MILLENIUM))
-
-#define MICROSECONDS_PER_MILLENIUM    ((uint64_t) ((uint64_t)MICROSECONDS_PER_MILLISECOND * MILLISECONDS_PER_MILLENIUM))
-
-#define MILLISECONDS_PER_MICROSECOND  ((float)MILLISECONDS_PER_MILLISECOND / (float)MICROSECONDS_PER_MILLISECOND)
-
-#define SECONDS_PER_MICROSECOND       ((float)SECONDS_PER_SECOND / (float)MICROSECONDS_PER_SECOND)
-#define SECONDS_PER_MILLISECOND       ((float)SECONDS_PER_SECOND / (float)MILLISECONDS_PER_SECOND)
-
-#define MINUTES_PER_MICROSECOND       ((float)MINUTES_PER_MINUTE / (float)MICROSECONDS_PER_MINUTE)
-#define MINUTES_PER_MILLISECOND       ((float)MINUTES_PER_MINUTE / (float)MILLISECONDS_PER_MINUTE)
-#define MINUTES_PER_SECOND            ((float)MINUTES_PER_MINUTE / (float)SECONDS_PER_MINUTE)
-
-#define HOURS_PER_MICROSECOND         ((float)HOURS_PER_HOUR / (float)MICROSECONDS_PER_HOUR)
-#define HOURS_PER_MILLISECOND         ((float)HOURS_PER_HOUR / (float)MILLISECONDS_PER_HOUR)
-#define HOURS_PER_SECOND              ((float)HOURS_PER_HOUR / (float)SECONDS_PER_HOUR)
-#define HOURS_PER_MINUTE              ((float)HOURS_PER_HOUR / (float)MINUTES_PER_HOUR)
-
-#define DAYS_PER_MICROSECOND          ((float)DAYS_PER_DAY / (float)MICROSECONDS_PER_DAY)
-#define DAYS_PER_MILLISECOND          ((float)DAYS_PER_DAY / (float)MILLISECONDS_PER_DAY)
-#define DAYS_PER_SECOND               ((float)DAYS_PER_DAY / (float)SECONDS_PER_DAY)
-#define DAYS_PER_MINUTE               ((float)DAYS_PER_DAY / (float)MINUTES_PER_DAY)
-#define DAYS_PER_HOUR                 ((float)DAYS_PER_DAY / (float)HOURS_PER_DAY)
-
-#define WEEKS_PER_MICROSECOND         ((float)WEEKS_PER_WEEK / (float)MICROSECONDS_PER_WEEK)
-#define WEEKS_PER_MILLISECOND         ((float)WEEKS_PER_WEEK / (float)MILLISECONDS_PER_WEEK)
-#define WEEKS_PER_SECOND              ((float)WEEKS_PER_WEEK / (float)SECONDS_PER_WEEK)
-#define WEEKS_PER_MINUTE              ((float)WEEKS_PER_WEEK / (float)MINUTES_PER_WEEK)
-#define WEEKS_PER_HOUR                ((float)WEEKS_PER_WEEK / (float)HOURS_PER_WEEK)
-#define WEEKS_PER_DAY                 ((float)WEEKS_PER_WEEK / (float)DAYS_PER_WEEK)
-
-#define MONTHS_PER_MICROSECOND        ((float)MONTHS_PER_MONTH / (float)MICROSECONDS_PER_MONTH)
-#define MONTHS_PER_MILLISECOND        ((float)MONTHS_PER_MONTH / (float)MILLISECONDS_PER_MONTH)
-#define MONTHS_PER_SECOND             ((float)MONTHS_PER_MONTH / (float)SECONDS_PER_MONTH)
-#define MONTHS_PER_MINUTE             ((float)MONTHS_PER_MONTH / (float)MINUTES_PER_MONTH)
-#define MONTHS_PER_HOUR               ((float)MONTHS_PER_MONTH / (float)HOURS_PER_MONTH)
-#define MONTHS_PER_DAY                ((float)MONTHS_PER_MONTH / (float)DAYS_PER_MONTH)
-#define MONTHS_PER_WEEK               ((float)MONTHS_PER_MONTH / (float)WEEKS_PER_MONTH)
-
-#define YEARS_PER_MICROSECOND         ((float)YEARS_PER_YEAR / (float)MICROSECONDS_PER_YEAR)
-#define YEARS_PER_MILLISECOND         ((float)YEARS_PER_YEAR / (float)MILLISECONDS_PER_YEAR)
-#define YEARS_PER_SECOND              ((float)YEARS_PER_YEAR / (float)SECONDS_PER_YEAR)
-#define YEARS_PER_MINUTE              ((float)YEARS_PER_YEAR / (float)MINUTES_PER_YEAR)
-#define YEARS_PER_HOUR                ((float)YEARS_PER_YEAR / (float)HOURS_PER_YEAR)
-#define YEARS_PER_DAY                 ((float)YEARS_PER_YEAR / (float)DAYS_PER_YEAR)
-#define YEARS_PER_WEEK                ((float)YEARS_PER_YEAR / (float)WEEKS_PER_YEAR)
-#define YEARS_PER_MONTH               ((float)YEARS_PER_YEAR / (float)MONTHS_PER_YEAR)
-
-#define DECADES_PER_MICROSECOND       ((float)DECADES_PER_DECADE / (float)MICROSECONDS_PER_DECADE)
-#define DECADES_PER_MILLISECOND       ((float)DECADES_PER_DECADE / (float)MILLISECONDS_PER_DECADE)
-#define DECADES_PER_SECOND            ((float)DECADES_PER_DECADE / (float)SECONDS_PER_DECADE)
-#define DECADES_PER_MINUTE            ((float)DECADES_PER_DECADE / (float)MINUTES_PER_DECADE)
-#define DECADES_PER_HOUR              ((float)DECADES_PER_DECADE / (float)HOURS_PER_DECADE)
-#define DECADES_PER_DAY               ((float)DECADES_PER_DECADE / (float)DAYS_PER_DECADE)
-#define DECADES_PER_WEEK              ((float)DECADES_PER_DECADE / (float)WEEKS_PER_DECADE)
-#define DECADES_PER_MONTH             ((float)DECADES_PER_DECADE / (float)MONTHS_PER_DECADE)
-#define DECADES_PER_YEAR              ((float)DECADES_PER_DECADE / (float)YEARS_PER_DECADE)
-
-#define CENTURIES_PER_MICROSECOND     ((float)CENTURIES_PER_CENTURY / (float)MICROSECONDS_PER_CENTURY)
-#define CENTURIES_PER_MILLISECOND     ((float)CENTURIES_PER_CENTURY / (float)MILLISECONDS_PER_CENTURY)
-#define CENTURIES_PER_SECOND          ((float)CENTURIES_PER_CENTURY / (float)SECONDS_PER_CENTURY)
-#define CENTURIES_PER_MINUTE          ((float)CENTURIES_PER_CENTURY / (float)MINUTES_PER_CENTURY)
-#define CENTURIES_PER_HOUR            ((float)CENTURIES_PER_CENTURY / (float)HOURS_PER_CENTURY)
-#define CENTURIES_PER_DAY             ((float)CENTURIES_PER_CENTURY / (float)DAYS_PER_CENTURY)
-#define CENTURIES_PER_WEEK            ((float)CENTURIES_PER_CENTURY / (float)WEEKS_PER_CENTURY)
-#define CENTURIES_PER_MONTH           ((float)CENTURIES_PER_CENTURY / (float)MONTHS_PER_CENTURY)
-#define CENTURIES_PER_YEAR            ((float)CENTURIES_PER_CENTURY / (float)YEARS_PER_CENTURY)
-#define CENTURIES_PER_DECADE          ((float)CENTURIES_PER_CENTURY / (float)DECADES_PER_CENTURY)
-
-#define MILLENIUMS_PER_MICROSECOND    ((float)MILLENIUMS_PER_MILLENIUM / (float)MICROSECONDS_PER_MILLENIUM)
-#define MILLENIUMS_PER_MILLISECOND    ((float)MILLENIUMS_PER_MILLENIUM / (float)MILLISECONDS_PER_MILLENIUM)
-#define MILLENIUMS_PER_SECOND         ((float)MILLENIUMS_PER_MILLENIUM / (float)SECONDS_PER_MILLENIUM)
-#define MILLENIUMS_PER_MINUTE         ((float)MILLENIUMS_PER_MILLENIUM / (float)MINUTES_PER_MILLENIUM)
-#define MILLENIUMS_PER_HOUR           ((float)MILLENIUMS_PER_MILLENIUM / (float)HOURS_PER_MILLENIUM)
-#define MILLENIUMS_PER_DAY            ((float)MILLENIUMS_PER_MILLENIUM / (float)DAYS_PER_MILLENIUM)
-#define MILLENIUMS_PER_WEEK           ((float)MILLENIUMS_PER_MILLENIUM / (float)WEEKS_PER_MILLENIUM)
-#define MILLENIUMS_PER_MONTH          ((float)MILLENIUMS_PER_MILLENIUM / (float)MONTHS_PER_MILLENIUM)
-#define MILLENIUMS_PER_YEAR           ((float)MILLENIUMS_PER_MILLENIUM / (float)YEARS_PER_MILLENIUM)
-#define MILLENIUMS_PER_DECADE         ((float)MILLENIUMS_PER_MILLENIUM / (float)DECADES_PER_MILLENIUM)
-#define MILLENIUMS_PER_CENTURY        ((float)MILLENIUMS_PER_MILLENIUM / (float)CENTURIES_PER_MILLENIUM)
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-  uint8_t aosTimeDayOfWeekFromDate(const uint16_t day, const uint8_t month, const uint16_t year);
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* _AMIROOS_TIME_H_ */
-
-/** @} */
diff --git a/os/core/inc/aos_timer.h b/os/core/inc/aos_timer.h
deleted file mode 100644
index 495c741..0000000
--- a/os/core/inc/aos_timer.h
+++ /dev/null
@@ -1,260 +0,0 @@
-/*
-AMiRo-OS is an operating system designed for the Autonomous Mini Robot (AMiRo) platform.
-Copyright (C) 2016..2018  Thomas Schöpping et al.
-
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program.  If not, see <http://www.gnu.org/licenses/>.
-*/
-
-/**
- * @file    aos_timer.h
- * @brief   Timer macros and structures.
- *
- * @addtogroup aos_timers
- * @{
- */
-
-#ifndef _AMIROOS_TIMER_H_
-#define _AMIROOS_TIMER_H_
-
-#include <ch.h>
-#include <aos_time.h>
-
-/**
- * @brief   Maximum timer interval that can be set in system ticks.
- */
-#define AOS_TIMER_MAX_INTERVAL_ST     TIME_MAX_INTERVAL
-
-/**
- * @brief   Maximum timer interval that can be set in seconds.
- */
-#define AOS_TIMER_MAX_INTERVAL_S      (chTimeI2S(AOS_TIMER_MAX_INTERVAL_ST) - 1)
-
-/**
- * @brief   Maximum timer interval that can be set in milliseconds.
- */
-#define AOS_TIMER_MAX_INTERVAL_MS     (chTimeI2MS(AOS_TIMER_MAX_INTERVAL_ST) - 1)
-
-/**
- * @brief   Maximum timer interval that can be set in microseconds.
- */
-#define AOS_TIMER_MAX_INTERVAL_US     (chTimeI2US(AOS_TIMER_MAX_INTERVAL_ST) - 1)
-
-/**
- * @brief   Timer stucture.
- */
-typedef struct aos_timer {
-  /**
-   * @brief   ChibiOS virtual timer.
-   */
-  virtual_timer_t vt;
-
-  /**
-   * @brief   Time to wake up.
-   */
-  aos_timestamp_t wkuptime;
-
-  /**
-   * @brief   Pointer to a callback function.
-   */
-  vtfunc_t callback;
-
-  /**
-   * @brief   Pointer to a parameter for the callback function.
-   */
-  void* cbparam;
-} aos_timer_t;
-
-/**
- * @brief   Periodic timer structure.
- */
-typedef struct aos_periodictimer {
-  /**
-   * @brief   AMiRo-OS timer.
-   */
-  aos_timer_t timer;
-
-  /**
-   * @brief   Period interval.
-   */
-  aos_longinterval_t interval;
-
-  /**
-   * @brief   Pointer to a callback function.
-   */
-  vtfunc_t callback;
-
-  /**
-   * @brief   Pointer to a parameter for the callback function.
-   */
-  void* cbparam;
-} aos_periodictimer_t;
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-  void aosTimerInit(aos_timer_t* timer);
-  void aosTimerSetAbsoluteI(aos_timer_t* timer, aos_timestamp_t* uptime, vtfunc_t cb, void* par);
-  void aosTimerSetIntervalI(aos_timer_t* timer, aos_interval_t offset, vtfunc_t cb, void* par);
-  void aosTimerSetLongIntervalI(aos_timer_t* timer, aos_longinterval_t* offset, vtfunc_t cb, void* par);
-  void aosPeriodicTimerInit(aos_periodictimer_t* ptimer);
-  void aosPeriodicTimerSetI(aos_periodictimer_t* ptimer, aos_interval_t interval, vtfunc_t cb, void* par);
-  void aosPeriodicTimerSetLongI(aos_periodictimer_t* ptimer, aos_longinterval_t* interval, vtfunc_t cb, void* par);
-#ifdef __cplusplus
-}
-#endif
-
-/**
- * @brief   Set timer to fire at an absolute system time.
- *
- * @param[in] timer   Pointer to the timer to set.
- * @param[in] uptime  Pointer to the absolute uptime for the timer to fire.
- * @param[in] cb      Pointer to a callback function to be called.
- * @param[in] par     Pointer to a parameter fpr the callback function (may be NULL).
- */
-static inline void aosTimerSetAbsolute(aos_timer_t* timer, aos_timestamp_t* uptime, vtfunc_t cb, void* par)
-{
-  chSysLock();
-  aosTimerSetAbsoluteI(timer, uptime, cb, par);
-  chSysUnlock();
-
-  return;
-}
-
-/**
- * @brief   Set timer to fire after a relative interval.
- *
- * @param[in] timer   Pointer to the timer to set.
- * @param[in] offset  Relative interval to set for the timer to fire.
- * @param[in] cb      Pointer to a callback function to be called.
- * @param[in] par     Pointer to a parameter fpr the callback function (may be NULL).
- */
-static inline void aosTimerSetInterval(aos_timer_t* timer, aos_interval_t offset, vtfunc_t cb, void* par)
-{
-  chSysLock();
-  aosTimerSetIntervalI(timer, offset, cb, par);
-  chSysUnlock();
-}
-
-/**
- * @brief   Set timer to fire after a long relative interval.
- *
- * @param[in] timer   Pointer to the timer to set.
- * @param[in] offset  Pointer to a long interval value to set for the timer to fire.
- * @param[in] cb      Pointer to a callback function to be called.
- * @param[in] par     Pointer to a parameter fpr the callback function (may be NULL).
- */
-static inline void aosTimerSetLongInterval(aos_timer_t* timer, aos_longinterval_t* offset, vtfunc_t cb, void* par)
-{
-  chSysLock();
-  aosTimerSetLongIntervalI(timer, offset, cb, par);
-  chSysUnlock();
-}
-
-/**
- * @brief   Reset a timer.
- *
- * @param[in] timer   Pointer to the timer to reset.
- */
-static inline void aosTimerResetI(aos_timer_t* timer)
-{
-  chVTResetI(&(timer->vt));
-
-  return;
-}
-
-/**
- * @brief   Reset a timer.
- *
- * @param[in] timer   Pointer to the timer to reset.
- */
-static inline void aosTimerReset(aos_timer_t* timer)
-{
-  chSysLock();
-  aosTimerResetI(timer);
-  chSysUnlock();
-
-  return;
-}
-
-/**
- * @brief   Determine whether a timer is armed.
- *
- * @param[in] timer   Pointer to the timer to check.
- *
- * @return    true if the timer is armed, false otherwise.
- */
-static inline bool aosTimerIsArmedI(aos_timer_t* timer)
-{
-  return chVTIsArmedI(&(timer->vt));
-}
-
-/**
- * @brief   Determine whether a timer is armed.
- *
- * @param[in] timer   Pointer to the timer to check.
- *
- * @return    true if the timer is armed, false otherwise.
- */
-static inline bool aosTimerIsArmed(aos_timer_t* timer)
-{
-  bool b;
-
-  chSysLock();
-  b = aosTimerIsArmedI(timer);
-  chSysUnlock();
-
-  return b;
-}
-
-/**
- * @brief   Set a periodic timer to fire in the specified interval.
- *
- * @param[in] ptimer    Pointer to the periodic timer to set.
- * @param[in] interval  Interval for the periodic timer to fire,
- * @param[in] cb        Pointer to a callback function to be called.
- *                      In contrast to other callback functions, this get called from an already ISR locked context.
- *                      This it may not contain any chSysLockX() or chSysUnlockX() calls.
- * @param[in] par       Pointer to a parameter for the callback function (may be NULL).
- */
-static inline void aosPeriodicTimerSet(aos_periodictimer_t *ptimer, aos_interval_t interval, vtfunc_t cb, void *par)
-{
-  chSysLock();
-  aosPeriodicTimerSetI(ptimer, interval, cb, par);
-  chSysUnlock();
-
-  return;
-}
-
-/**
- * @brief   Set a periodic timer to fire in the specified interval.
- *
- * @param[in] ptimer    Pointer to the periodic timer to set.
- * @param[in] interval  Pointer to a long interval value for the periodic timer to fire,
- * @param[in] cb        Pointer to a callback function to be called.
- *                      In contrast to other callback functions, this get called from an already ISR locked context.
- *                      This it may not contain any chSysLockX() or chSysUnlockX() calls.
- * @param[in] par       Pointer to a parameter for the callback function (may be NULL).
- */
-static inline void aosPeriodicTimerSetLong(aos_periodictimer_t* ptimer, aos_longinterval_t* interval, vtfunc_t cb, void* par)
-{
-  chSysLock();
-  aosPeriodicTimerSetLongI(ptimer, interval, cb, par);
-  chSysUnlock();
-
-  return;
-}
-
-#endif /* _AMIROOS_TIMER_H_ */
-
-/** @} */
diff --git a/os/core/inc/aos_types.h b/os/core/inc/aos_types.h
deleted file mode 100644
index 4154884..0000000
--- a/os/core/inc/aos_types.h
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
-AMiRo-OS is an operating system designed for the Autonomous Mini Robot (AMiRo) platform.
-Copyright (C) 2016..2018  Thomas Schöpping et al.
-
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program.  If not, see <http://www.gnu.org/licenses/>.
-*/
-
-/**
- * @file    aos_types.h
- * @brief   Data types used throughout AMiRo-OS
- *
- * @addtogroup aos_types
- * @{
- */
-
-#ifndef _AMIROOS_TYPES_H_
-#define _AMIROOS_TYPES_H_
-
-/**
- * @brief   Error codes used in AMiRo-OS.
- */
-typedef enum {
-  AOS_OK = 0,                 /**< No error, success. */
-  AOS_SUCCESS = 0,            /**< No error, success */
-  AOS_WARNING = 1,            /**< No error, but a warning occurred */
-  AOS_INVALID_ARGUMENTS = 2,  /**< No error, but given arguments are invalid */
-  AOS_ERROR = 0x80,           /**< An error occurred */
-  AOS_FAILURE = 0x80,         /**< An error occurred */
-} aos_status_t;
-
-#endif /* _AMIROOS_TYPES_H_ */
-
-/** @} */
diff --git a/os/core/inc/aos_unittest.h b/os/core/inc/aos_unittest.h
deleted file mode 100644
index 3900bac..0000000
--- a/os/core/inc/aos_unittest.h
+++ /dev/null
@@ -1,117 +0,0 @@
-/*
-AMiRo-OS is an operating system designed for the Autonomous Mini Robot (AMiRo) platform.
-Copyright (C) 2016..2018  Thomas Schöpping et al.
-
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program.  If not, see <http://www.gnu.org/licenses/>.
-*/
-
-/**
- * @file    aos_unittest.h
- * @brief   Unittest structures.
- *
- * @addtogroup aos_unittests
- * @{
- */
-
-#ifndef _AMIROOS_UNITTEST_H_
-#define _AMIROOS_UNITTEST_H_
-
-#include <aosconf.h>
-#if (AMIROOS_CFG_TESTS_ENABLE == true) || defined(__DOXYGEN__)
-#include <hal.h>
-#include <aos_shell.h>
-
-/*
- * Forward declarations.
- */
-typedef struct aos_unittest aos_unittest_t;
-typedef struct aos_utresult aos_utresult_t;
-
-/**
- * @brief   Unit test interface function definition.
- *
- * @param[in] stream  The stream to use for printing messages.
- * @param[in] ut      The object to run the test on.
- *
- * @return    A result containing the number of passed and failed tests.
- */
-typedef aos_utresult_t (*aos_utfunction_t)(BaseSequentialStream* stream, aos_unittest_t* ut);
-
-/**
- * @brief   Unit test result struct.
- */
-struct aos_utresult {
-  /**
-   * @brief   Number of passed tests.
-   */
-  uint32_t passed;
-
-  /**
-   * @brief   Number of failed tests.
-   */
-  uint32_t failed;
-};
-
-/**
- * @brief   Unit test definition struct.
- */
-struct aos_unittest {
-  /**
-   * @brief   Name of the unit test.
-   */
-  const char* name;
-
-  /**
-   * @brief   Further information about the test.
-   */
-  const char* info;
-
-  /**
-   * @brief   Callback function to run that executes the unit test.
-   */
-  aos_utfunction_t testfunc;
-
-  /**
-   * @brief   Shell command to add to an shell command list.
-   */
-  aos_shellcommand_t shellcmd;
-
-  /**
-   * @brief   Further test specific data.
-   */
-  void* data;
-};
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-  uint32_t aosUtResultTotal(aos_utresult_t* result);
-  float aosUtResultRatio(aos_utresult_t* result);
-  void aosUtResultPrintSummary(BaseSequentialStream* stream, aos_utresult_t* result, char* heading);
-  void aosUtObjectInit(aos_unittest_t* ut, char* name, char* info, aos_utfunction_t func, void* data, char* shellname, aos_shellcmdcb_t shellcb);
-  aos_utresult_t aosUtRun(BaseSequentialStream* stream, aos_unittest_t* ut, char* note);
-  void aosUtPassed(BaseSequentialStream* stream, aos_utresult_t* result);
-  void aosUtPassedMsg(BaseSequentialStream* stream, aos_utresult_t* result, const char* fmt, ...);
-  void aosUtFailed(BaseSequentialStream* stream, aos_utresult_t* result);
-  void aosUtFailedMsg(BaseSequentialStream* stream, aos_utresult_t* result, const char* fmt, ...);
-  void aosUtInfoMsg(BaseSequentialStream* stream, const char* fmt, ...);
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* AMIROOS_CFG_TESTS_ENABLE == true */
-
-#endif /* _AMIROOS_UNITTEST_H_ */
-
-/** @} */
diff --git a/os/core/src/aos_debug.c b/os/core/src/aos_debug.c
deleted file mode 100644
index f4e5dbe..0000000
--- a/os/core/src/aos_debug.c
+++ /dev/null
@@ -1,140 +0,0 @@
-/*
-AMiRo-OS is an operating system designed for the Autonomous Mini Robot (AMiRo) platform.
-Copyright (C) 2016..2018  Thomas Schöpping et al.
-
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program.  If not, see <http://www.gnu.org/licenses/>.
-*/
-
-/**
- * @file    aos_debug.c
- * @brief   Functions necessary to print an error on system halt.
- *
- * @addtogroup aos_debug
- * @{
- */
-
-#include <aos_debug.h>
-
-#include <hal.h>
-
-/*
- * System_halt
- * ChibiOS error code (see chdebug.c)
- *
- *            - SV#1, misplaced @p chSysDisable().
- *            - SV#2, misplaced @p chSysSuspend()
- *            - SV#3, misplaced @p chSysEnable().
- *            - SV#4, misplaced @p chSysLock().
- *            - SV#5, misplaced @p chSysUnlock().
- *            - SV#6, misplaced @p chSysLockFromIsr().
- *            - SV#7, misplaced @p chSysUnlockFromIsr().
- *            - SV#8, misplaced @p CH_IRQ_PROLOGUE().
- *            - SV#9, misplaced @p CH_IRQ_EPILOGUE().
- *            - SV#10, misplaced I-class function.
- *            - SV#11, misplaced S-class function.
- */
-
-#if ((CH_DBG_SYSTEM_STATE_CHECK == TRUE) && (HAL_USE_SERIAL == TRUE)) || defined(__DOXYGEN__)
-
-/**
- * @brief   Actively waits for the serial driver to be empty.
- */
-static inline void _serialWaitForEmpty(SerialDriver* sdp) {
-  while (!((sdp->usart->SR) & USART_SR_TC)) {
-    continue;
-  }
-  return;
-}
-
-/**
- * @brief   Prints the specified string without suspending the thread.
- *
- * @param[in] str   The string to print.
- *
- * @return          The number of characters printed.
- */
-static inline unsigned int _printString(SerialDriver* sdp, const char* str)
-{
-  unsigned int i = 0;
-  while (str[i] != '\0') {
-    sdp->usart->DR = str[i];
-    _serialWaitForEmpty(sdp);
-    ++i;
-  }
-  return i;
-}
-
-/**
- * @brief   Prints the specified string to the given serial stream.
- *
- * @param[in] sdp       serial stream to print to
- * @param[in] reason    string to print
- */
-static void _printError(SerialDriver* sdp, const char* reason)
-{
-  if (sdp->state != SD_STOP && sdp->state != SD_READY) {
-    sd_lld_start(sdp, NULL);
-    sdp->state = SD_READY;
-  }
-  if (sdp->state == SD_READY) {
-    _printString(sdp, "\nSystem halt! error code / function name: ");
-    _printString(sdp, reason);
-    _printString(sdp, "\n");
-  }
-
-  return;
-}
-
-#endif /* ((CH_DBG_SYSTEM_STATE_CHECK == TRUE) && (HAL_USE_SERIAL == TRUE)) || defined(__DOXYGEN__) */
-
-/**
- * @brief   Prints an error message.
- *
- * @param[in] reason  The string to print.
- */
-void aosPrintHaltErrorCode(const char* reason)
-{
-#if (CH_DBG_SYSTEM_STATE_CHECK == TRUE) && (HAL_USE_SERIAL == TRUE)
-  #if STM32_SERIAL_USE_USART1
-  _printError(&SD1, reason);
-  #endif
-  #if STM32_SERIAL_USE_USART2
-  _printError(&SD2, reason);
-  #endif
-  #if STM32_SERIAL_USE_USART3
-  _printError(&SD3, reason);
-  #endif
-  #if STM32_SERIAL_USE_UART4
-  _printError(&SD4, reason);
-  #endif
-  #if STM32_SERIAL_USE_UART5
-  _printError(&SD5, reason);
-  #endif
-  #if STM32_SERIAL_USE_USART6
-  _printError(&SD6, reason);
-  #endif
-  #if STM32_SERIAL_USE_UART7
-  _printError(&SD7, reason);
-  #endif
-  #if STM32_SERIAL_USE_UART8
-  _printError(&SD8, reason);
-  #endif
-#else
-  (void)reason;
-#endif /* (CH_DBG_SYSTEM_STATE_CHECK == TRUE) && (HAL_USE_SERIAL == TRUE) */
-
-  return;
-}
-
-/** @} */
diff --git a/os/core/src/aos_iostream.c b/os/core/src/aos_iostream.c
deleted file mode 100644
index 548eae2..0000000
--- a/os/core/src/aos_iostream.c
+++ /dev/null
@@ -1,388 +0,0 @@
-/*
-AMiRo-OS is an operating system designed for the Autonomous Mini Robot (AMiRo) platform.
-Copyright (C) 2016..2018  Thomas Schöpping et al.
-
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program.  If not, see <http://www.gnu.org/licenses/>.
-*/
-
-/**
- * @file    aos_iostream.c
- * @brief   Stream and channel code.
- * @details Implementation of the aos_ostrem and aos_iochannel.
- *
- * @addtogroup aos_stream
- * @{
- */
-
-#include <aos_iostream.h>
-
-#include <aos_debug.h>
-#include <chprintf.h>
-
-/**
- * @brief   Implementation of the BaseAsynchronousChannel write() method (inherited from BaseSequentialStream).
- */
-static size_t _channelwrite(void *instance, const uint8_t *bp, size_t n)
-{
-  if (((AosIOChannel*)instance)->flags & AOS_IOCHANNEL_OUTPUT_ENABLE) {
-    return streamWrite(((AosIOChannel*)instance)->asyncchannel, bp, n);
-  } else {
-    return 0;
-  }
-}
-
-/**
- * @brief   Implementation of the BaseAsynchronousChannel read() method (inherited from BaseSequentialStream).
- */
-static size_t _channelread(void *instance, uint8_t *bp, size_t n)
-{
-  if (((AosIOChannel*)instance)->flags & AOS_IOCHANNEL_INPUT_ENABLE) {
-    return streamRead(((AosIOChannel*)instance)->asyncchannel, bp, n);
-  } else {
-    return 0;
-  }
-}
-
-/**
- * @brief   Implementation of the BaseAsynchronousChannel put() method (inherited from BaseSequentialStream).
- */
-static msg_t _channelput(void *instance, uint8_t b)
-{
-  if (((AosIOChannel*)instance)->flags & AOS_IOCHANNEL_OUTPUT_ENABLE) {
-    return streamPut(((AosIOChannel*)instance)->asyncchannel, b);
-  } else {
-    return MSG_RESET;
-  }
-}
-
-/**
- * @brief   Implementation of the BaseAsynchronousChannel get() method (inherited from BaseSequentialStream).
- */
-static msg_t _channelget(void *instance)
-{
-  if (((AosIOChannel*)instance)->flags & AOS_IOCHANNEL_INPUT_ENABLE) {
-    return streamGet(((AosIOChannel*)instance)->asyncchannel);
-  } else {
-    return MSG_RESET;
-  }
-}
-
-/**
- * @brief   Implementation of the BaseAsynchronousChannel putt() method.
- */
-static msg_t _channelputt(void *instance, uint8_t b, sysinterval_t time)
-{
-  if (((AosIOChannel*)instance)->flags & AOS_IOCHANNEL_OUTPUT_ENABLE) {
-    return chnPutTimeout(((AosIOChannel*)instance)->asyncchannel, b, time);
-  } else {
-    return MSG_RESET;
-  }
-}
-
-/**
- * @brief   Implementation of the BaseAsynchronousChannel gett() method.
- */
-static msg_t _channelgett(void *instance, sysinterval_t time)
-{
-  if (((AosIOChannel*)instance)->flags & AOS_IOCHANNEL_INPUT_ENABLE) {
-    return chnGetTimeout(((AosIOChannel*)instance)->asyncchannel, time);
-  } else {
-    return MSG_RESET;
-  }
-}
-
-/**
- * @brief   Implementation of the BaseAsynchronousChannel writet() method.
- */
-static size_t _channelwritet(void *instance, const uint8_t *bp, size_t n, sysinterval_t time)
-{
-  if (((AosIOChannel*)instance)->flags & AOS_IOCHANNEL_OUTPUT_ENABLE) {
-    return chnWriteTimeout(((AosIOChannel*)instance)->asyncchannel, bp, n, time);
-  } else {
-    return 0;
-  }
-}
-
-/**
- * @brief   Implementation of the BaseAsynchronousChannel readt() method.
- */
-static size_t _channelreadt(void *instance, uint8_t *bp, size_t n, sysinterval_t time)
-{
-  if (((AosIOChannel*)instance)->flags & AOS_IOCHANNEL_INPUT_ENABLE) {
-    return chnReadTimeout(((AosIOChannel*)instance)->asyncchannel, bp, n, time);
-  } else {
-    return 0;
-  }
-}
-
-/**
- * @brief   Implementation of the BaseAsynchronousChannel ctl() method.
- */
-static msg_t _channelctl(void *instance, unsigned int operation, void *arg)
-{
-  if (((AosIOChannel*)instance)->flags & AOS_IOCHANNEL_OUTPUT_ENABLE) {
-    return chnControl(((AosIOChannel*)instance)->asyncchannel, operation, arg);
-  } else {
-    return MSG_OK;
-  }
-}
-
-/**
- * @brief   Virtual methods table for all AosIOChannel objects.
- */
-static const struct AosIOChannelVMT _channelvmt = {
-  (size_t) 0,
-  _channelwrite,
-  _channelread,
-  _channelput,
-  _channelget,
-  _channelputt,
-  _channelgett,
-  _channelwritet,
-  _channelreadt,
-  _channelctl,
-};
-
-/**
- * @brief   Implementation of the BaseSequentialStream write() method.
- */
-static size_t _streamwrite(void *instance, const uint8_t *bp, size_t n)
-{
-  aosDbgCheck(instance != NULL);
-
-  // local variables
-  AosIOChannel* channel = ((AosIOStream*)instance)->channel;
-  size_t bytes;
-  size_t maxbytes = 0;
-
-  // iterate through the list of channels
-  while (channel != NULL) {
-    bytes = streamWrite(channel, bp, n);
-    maxbytes = (bytes > maxbytes) ? bytes : maxbytes;
-    channel = channel->next;
-  }
-
-  return maxbytes;
-}
-
-/**
- * @brief   Implementation of the BaseSequentialStream read() method.
- */
-static size_t _stremread(void *instance, uint8_t *bp, size_t n)
-{
-  (void)instance;
-  (void)bp;
-  (void)n;
-
-  return 0;
-}
-
-/**
- * @brief   Implementation of the BaseSequentialStream put() method.
- */
-static msg_t _streamput(void *instance, uint8_t b)
-{
-  aosDbgCheck(instance != NULL);
-
-  // local variables
-  AosIOChannel* channel = ((AosIOStream*)instance)->channel;
-  msg_t ret = MSG_OK;
-
-  // iterate through the list of channels
-  while (channel != NULL) {
-    msg_t ret_ = streamPut(channel, b);
-    ret = (ret_ < ret) ? ret_ : ret;
-    channel = channel->next;
-  }
-
-  return ret;
-}
-
-/**
- * @brief   Implementation of the BaseSequentialStream get() method.
- */
-static msg_t _streamget(void *instance)
-{
-  (void)instance;
-
-  return 0;
-}
-
-/**
- * @brief   Virtual methods table for all AosIOStream objects.
- */
-static const struct AosIOStreamVMT _streamvmt = {
-  (size_t) 0,
-  _streamwrite,
-  _stremread,
-  _streamput,
-  _streamget,
-};
-
-/**
- * @brief   Initializes an aos_iostream_t object.
- *
- * @param[in] stream    Th aos_iostream_t object to initialize.
- */
-void aosIOStreamInit(AosIOStream* stream)
-{
-  aosDbgCheck(stream != NULL);
-
-  stream->vmt = &_streamvmt;
-  stream->channel = NULL;
-
-  return;
-}
-
-/**
- * @brief   Initializes an aos_iostream_channel_t object.
- *
- * @param[in] channel       The aos_iostream_channel_t to initialize.
- * @param[in] asyncchannel  The BaseAsynchronousChannel object to associate with te channel.
- */
-void aosIOChannelInit(AosIOChannel *channel, BaseAsynchronousChannel *asyncchannel)
-{
-  aosDbgCheck(channel != NULL);
-  aosDbgCheck(asyncchannel != NULL);
-
-  channel->vmt = &_channelvmt;
-  channel->asyncchannel = asyncchannel;
-  channel->next = NULL;
-  channel->flags = 0;
-
-  return;
-}
-
-/**
- * @brief   Adds a channel to a stream.
- *
- * @param[in] stream    The stream to be expanded.
- * @param[in] channel   The channel to be added.
- */
-void aosIOStreamAddChannel(AosIOStream *stream, AosIOChannel* channel)
-{
-  aosDbgCheck(stream != NULL);
-  aosDbgCheck(channel != NULL && channel->asyncchannel != NULL && channel->next == NULL && (channel->flags & AOS_IOCHANNEL_ATTACHED) == 0);
-
-  // prepend the new channel
-  chSysLock();
-  channel->flags |= AOS_IOCHANNEL_ATTACHED;
-  channel->next = stream->channel;
-  stream->channel = channel;
-  chSysUnlock();
-
-  return;
-}
-
-/**
- * @brief   Removes a channel from a stream.
- *
- * @param[in] stream        The stream to remove the channel from.
- * @param[in] asyncchannel  The BaseAsynchronousChannel to remove.
- * @param[out] removed      Pointer to the removed aos_iostream_channel_t.
- * @return
- */
-aos_status_t aosIOStreamRemoveChannel(AosIOStream* stream, AosIOChannel* channel)
-{
-  aosDbgCheck(stream != NULL);
-  aosDbgCheck(channel != NULL);
-
-  // local variables
-  AosIOChannel* prev = NULL;
-  AosIOChannel* curr = stream->channel;
-
-  // iterate through the list and search for the specified channel
-  while (curr != NULL) {
-    // if the channel was found, remove it
-    if (curr == channel) {
-      chSysLock();
-      // special case: the first channel matches (prev is NULL)
-      if (prev == NULL) {
-        stream->channel = curr->next;
-      } else {
-        prev->next = curr->next;
-      }
-      curr->next = NULL;
-      curr->flags &= ~AOS_IOCHANNEL_ATTACHED;
-      chSysUnlock();
-      return AOS_SUCCESS;
-    }
-    // iterate to the next channel
-    else {
-      prev = curr;
-      curr = curr->next;
-    }
-  }
-
-  // if the channel was not found, return an error
-  return AOS_ERROR;
-}
-
-/**
- * @brief   Enable input for a AosIOChannel.
- *
- * @param[in] channel   The AosIOChannel to enable as input.
- */
-void aosIOChannelInputEnable(AosIOChannel* channel)
-{
-  aosDbgCheck(channel != NULL);
-
-  channel->flags |= AOS_IOCHANNEL_INPUT_ENABLE;
-
-  return;
-}
-
-/**
- * @brief   Disable input for a AosIOChannel.
- *
- * @param[in] channel   The AosIOChannel to disable as input.
- */
-void aosIOChannelInputDisable(AosIOChannel* channel)
-{
-  aosDbgCheck(channel != NULL);
-
-  channel->flags &= ~AOS_IOCHANNEL_INPUT_ENABLE;
-
-  return;
-}
-
-/**
- * @brief   Enable output for a AosIOChannel.
- *
- * @param[in] channel   The AosIOChannel to enable as output.
- */
-void aosIOChannelOutputEnable(AosIOChannel* channel)
-{
-  aosDbgCheck(channel != NULL);
-
-  channel->flags |= AOS_IOCHANNEL_OUTPUT_ENABLE;
-
-  return;
-}
-
-/**
- * @brief   Disable output for a AosIOChannel.
- *
- * @param[in] channel   The AosIOChannel to disable as output.
- */
-void aosIOChannelOutputDisable(AosIOChannel* channel)
-{
-  aosDbgCheck(channel != NULL);
-
-  channel->flags &= ~AOS_IOCHANNEL_OUTPUT_ENABLE;
-
-  return;
-}
-
-/** @} */
diff --git a/os/core/src/aos_main.cpp b/os/core/src/aos_main.cpp
deleted file mode 100644
index 68ab754..0000000
--- a/os/core/src/aos_main.cpp
+++ /dev/null
@@ -1,1280 +0,0 @@
-/*
-AMiRo-OS is an operating system designed for the Autonomous Mini Robot (AMiRo) platform.
-Copyright (C) 2016..2018  Thomas Schöpping et al.
-
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program.  If not, see <http://www.gnu.org/licenses/>.
-*/
-
-/**
- * @file    aos_main.cpp
- * @brief   Main function.
- * @details Main function with SSSP and initialization,
- *          extendable via hooks.
- *
- * @addtogroup aos_system
- * @{
- */
-
-#include <amiroos.h>
-#include <module.h>
-
-/*
- * hook to add further includes
- */
-#if defined(AMIROOS_CFG_MAIN_EXTRA_INCLUDE_HEADER)
-#include AMIROOS_CFG_MAIN_EXTRA_INCLUDE_HEADER
-#endif
-
-/**
- * @brief   Event mask to identify I/O events.
- */
-#define IOEVENT_MASK                            EVENT_MASK(0)
-
-/**
- * @brief   Event mask to identify OS events.
- */
-#define OSEVENT_MASK                            EVENT_MASK(1)
-
-/**
- * @brief   Event mask to idetify CAN events.
- */
-#define CANEVENT_MASK                           EVENT_MASK(2)
-
-/**
- * @brief   Event mask to idetify timeout events.
- */
-#define TIMEOUTEVENT_MASK                       EVENT_MASK(3)
-
-/**
- * @brief   Event mask to idetify signal delay events.
- */
-#define DELAYEVENT_MASK                         EVENT_MASK(4)
-
-/**
- * @brief   CAN message identifier for initialization of the SSSP stack initialization sequence.
- */
-#define SSSP_STACKINIT_CANMSGID_INIT            0x003
-
-/**
- * @brief   CAN message identifier for transmitting module IDs during the SSSP stack initialization sequence.
- */
-#define SSSP_STACKINIT_CANMSGID_MODULEID        0x002
-
-/**
- * @brief   CAN message identifier for abortion of the SSSP stack initialization sequence.
- */
-#define SSSP_STACKINIT_CANMSGID_ABORT           0x001
-
-/**
- * @brief   CAN message identifier for calender synchronization message.
- */
-#define CALENDERSYNC_CANMSGID                   0x004
-
-/**
- * @brief   Listener object for I/O events.
- */
-static event_listener_t _eventListenerIO;
-
-/**
- * @brief   Listener object for OS events.
- */
-static event_listener_t _eventListenerOS;
-
-#if defined(MODULE_HAL_PROGIF) || defined(__DOXYGEN__)
-/**
- * @brief   I/O channel for the programmer interface.
- */
-static AosIOChannel _stdiochannel;
-
-#if (AMIROOS_CFG_SHELL_ENABLE == true) || defined(__DOXYGEN__)
-/**
- * @brief   I/O shell channel for the programmer interface.
- */
-static AosShellChannel _stdshellchannel;
-#endif
-#endif
-
-/*
- * hook to add further static variables
- */
-#if defined(AMIROOS_CFG_MAIN_EXTRA_STATIC_VARIABLES)
-AMIROOS_CFG_MAIN_EXTRA_STATIC_VARIABLES
-#endif
-
-/**
- * @brief   Prints an error message about an unexpected event.
- *
- * @param[in] mask    The event mask.
- * @param[in] flags   The event flags.
- */
-static inline void _unexpectedEventError(const eventmask_t mask, const eventflags_t flags)
-{
-#if (AMIROOS_CFG_DBG == true)
-  aosprintf("CTRL: unexpected/unknown event received. mask: 0x%08X; flags: 0x%08X\n", mask, flags);
-#else
-  (void)(mask);
-  (void)(flags);
-#endif
-  return;
-}
-
-/**
- * @brief   Callback function to be used during SSSP stack initialization sequence.
- *
- * @param[in] par   A pointer to an @p event_source_t to be fired.
- */
-static void _ssspTimerCallback(void* par)
-{
-  aosDbgCheck(par != NULL);
-
-  chSysLockFromISR();
-  chEvtBroadcastI((event_source_t*)par);
-  chSysUnlockFromISR();
-
-  return;
-}
-
-/**
- * @brief   Helper function to serialize data.
- *
- * @param[out]  dst   Pointer to the output buffer.
- * @param[in]   src   Data to be serialized.
- * @param[in]   n     Number of bytes to serialize.
- */
-inline void _serialize(uint8_t* dst, const uint64_t src, const uint8_t n)
-{
-  aosDbgCheck(dst != NULL);
-  aosDbgCheck(n > 0 && n <= 8);
-
-  for (uint8_t byte = 0; byte < n; ++byte) {
-    dst[byte] = (uint8_t)((src >> (byte * 8)) & 0xFF);
-  }
-
-  return;
-}
-
-/**
- * @brief   Helper function to deserialize data.
- *
- * @param[in] src   Pointer to the buffer of data to be deserialzed.
- * @param[in] n     Number of bytes to deserialize.
- *
- * @return    The deserialized 32 bit data.
- */
-inline uint64_t _deserialize(uint8_t* src, const uint8_t n)
-{
-  aosDbgCheck(src != NULL);
-  aosDbgCheck(n > 0 && n <= 8);
-
-  uint64_t result = 0;
-  for (uint8_t byte = 0; byte < n; ++byte) {
-    result |= ((uint64_t)src[byte]) << (byte * 8);
-  }
-
-  return result;
-}
-
-/**
- * @brief   Converter function to encode a TM value to a single unsigned 64 bit integer.
- *
- * @details Contents of the TM struct are mapped as follows:
- *            bits  |63     62|61      53|52    50|49         26|25     22|21     17|16     12|11      6|5       0|
- *            #bits |       2 |        9 |      3 |          24 |       4 |       5 |       5 |       6 |       6 |
- *            value |   isdst |     yday |   wday |        year |     mon |    mday |    hour |     min |     sec |
- *            range | special | [0, 365] | [0, 6] | [1900, ...] | [0, 11] | [1, 31] | [0, 23] | [0, 59] | [0, 61] |
- *          The Daylight Saving Time Flag (isdsst) is encoded as follows:
- *            DST not in effect         -> 0
- *            DST in effect             -> 1
- *            no information available  -> 2
- *
- * @param[in] src   Pointer to the TM struct to encode.
- *
- * @return  An unsigned 64 bit integer, which holds the encoded time value.
- */
-inline uint64_t _TM2U64(struct tm* src)
-{
-  aosDbgCheck(src != NULL);
-
-  return (((uint64_t)(src->tm_sec  & 0x0000003F) << (0))               |
-          ((uint64_t)(src->tm_min  & 0x0000003F) << (6))               |
-          ((uint64_t)(src->tm_hour & 0x0000001F) << (12))              |
-          ((uint64_t)(src->tm_mday & 0x0000001F) << (17))              |
-          ((uint64_t)(src->tm_mon  & 0x0000000F) << (22))              |
-          ((uint64_t)(src->tm_year & 0x00FFFFFF) << (26))              |
-          ((uint64_t)(src->tm_wday & 0x00000007) << (50))              |
-          ((uint64_t)(src->tm_yday & 0x000001FF) << (53))              |
-          ((uint64_t)((src->tm_isdst == 0) ? 0 : (src->tm_isdst > 0) ? 1 : 2) << (62)));
-}
-
-/**
- * @brief   Converter functiomn to retrieve the encoded TM value from an unsigned 64 bit integer.
- *
- * @details For information on the encoding, please refer to @p _TM2U64 function.
- *
- * @param[out] dst  The TM struct to fill with the decoded values.
- * @param[in]  src  Unsigned 64 bit integer holding the encoded TM value.
- */
-inline void _U642TM(struct tm* dst, const uint64_t src)
-{
-  aosDbgCheck(dst != NULL);
-
-  dst->tm_sec  = (src >> 0)  & 0x0000003F;
-  dst->tm_min  = (src >> 6)  & 0x0000003F;
-  dst->tm_hour = (src >> 12) & 0x0000001F;
-  dst->tm_mday = (src >> 17) & 0x0000001F;
-  dst->tm_mon  = (src >> 22) & 0x0000000F;
-  dst->tm_year = (src >> 26) & 0x00FFFFFF;
-  dst->tm_wday = (src >> 50) & 0x00000007;
-  dst->tm_yday = (src >> 53) & 0x000001FF;
-  dst->tm_isdst = (((src >> 62) & 0x03) == 0) ? 0 : (((src >> 62) & 0x03) > 0) ? 1 : -1;
-
-  return;
-}
-
-/**
- * @brief   Implementation of the SSSP module stack initialization sequence (startup phase 3).
- *
- * @return Shutdown value.
- * @retval AOS_SHUTDOWN_NONE      No shutdown signal received
- * @retval AOS_SHUTDOWN_PASSIVE   Shutdown signal received.
- */
-aos_shutdown_t _ssspModuleStackInitialization(void)
-{
-  // local types
-  /**
-   * @brief   States for the internal state machine to implement SSSP startup stage 3.
-   */
-  typedef enum {
-    STAGE_3_1,                  /**< Initiation of SSSP startup stage 3. */
-    STAGE_3_2,                  /**< Starting the sequence and broadcasting the first ID. */
-    STAGE_3_3_WAITFORFIRSTID,   /**< Waiting for first ID after initiation. */
-    STAGE_3_3_WAITFORIDORSIG,   /**< Waiting for next ID or activation of neighbor signal. */
-    STAGE_3_3_WAITFORID,        /**< Waiting for next ID (after the module has set its own ID). */
-    STAGE_3_4_FINISH,           /**< Successful finish of stage 3. */
-    STAGE_3_4_ABORT_ACTIVE,     /**< Aborting stage 3 (active). */
-    STAGE_3_4_ABORT,            /**< Aborting stage 3 (passive). */
-  } sssp_modulestackinitstage_t;
-
-  typedef struct {
-    bool loop     : 1;
-    bool wfe      : 1;
-    bool wfe_next : 1;
-  } flags_t;
-
-  // local variables
-  aos_shutdown_t shutdown = AOS_SHUTDOWN_NONE;
-  sssp_modulestackinitstage_t stage = STAGE_3_1;
-  eventmask_t eventmask = 0;
-  eventflags_t ioflags;
-  event_source_t eventSourceTimeout;
-  event_source_t eventSourceDelay;
-  event_listener_t eventListenerTimeout;
-  event_listener_t eventListenerDelay;
-  event_listener_t eventListenerCan;
-  virtual_timer_t timerTimeout;
-  virtual_timer_t timerDelay;
-  CANTxFrame canTxFrame;
-  CANRxFrame canRxFrame;
-#if (AMIROOS_CFG_SSSP_STACK_START != true) || (AMIROOS_CFG_DBG == true)
-  aos_ssspmoduleid_t lastid = 0;
-#endif
-  flags_t flags;
-
-  // initialize local varibles
-  chEvtObjectInit(&eventSourceTimeout);
-  chEvtObjectInit(&eventSourceDelay);
-  chVTObjectInit(&timerTimeout);
-  chVTObjectInit(&timerDelay);
-  canTxFrame.RTR = CAN_RTR_DATA;
-  canTxFrame.IDE = CAN_IDE_STD;
-  flags.loop = true;
-  flags.wfe = false; // do not wait for events in the initial iteration of the FSM loop
-  flags.wfe_next = true;
-
-  // initialize system variables
-  aos.sssp.stage = AOS_SSSP_STARTUP_3_1;
-  aos.sssp.moduleId = 0;
-
-  // listen to events (timout, delay, CAN receive)
-  chEvtRegisterMask(&eventSourceTimeout, &eventListenerTimeout, TIMEOUTEVENT_MASK);
-  chEvtRegisterMask(&eventSourceDelay, &eventListenerDelay, DELAYEVENT_MASK);
-  chEvtRegisterMask(&MODULE_HAL_CAN.rxfull_event, &eventListenerCan, CANEVENT_MASK);
-
-  /*
-   * FSM in a loop.
-   *
-   * This is a fully event-based FSM for the module stack initialization
-   * sequence, defined by SSSP as startup stage 3. There are five different
-   * events that can occur at this point:
-   *  I/O events: The input level of an input pin has changed. Such events must
-   *              be handled differently depending on the current state. Most
-   *              of the time, however, such events can be ignored.
-   *  OS events:  Such events are only available after this stage completed and
-   *              thus should never occur. However, there is an optional hook
-   *              to handle such events, nevertheless.
-   *  CAN events: At least one CAN message was received. Note that this event
-   *              will only fire again if all input buffers have been cleared.
-   *  timeouts:   If some module does not support the sequence of there is any
-   *              issue, such a case is detected via timeouts and must be
-   *              handled accordingly (see abort state). In some cases, it is
-   *              possible that a timeout event occurres 'simultaneously' with
-   *              some other event. This can be caused by several timing issues
-   *              and is a valid situation. As a result, any other events
-   *              should be handled before the timeout event. If the other
-   *              events are expected and valid, this implementation requires
-   *              the timeout event flag to be cleared explicitely. Otherwise
-   *              it is evaluated at the end of each iteration of the loop.
-   *  delays:     Depending on the current state, delays are required by SSSP
-   *              for timing of the sequential activation of signals.
-   */
-  aosDbgPrintf("SSSP stack initialization sequence:\n");
-  while (flags.loop) {
-#if (AMIROOS_CFG_DBG == true)
-    switch (stage) {
-      case STAGE_3_1:
-        aosDbgPrintf(">>> 3-1\n");
-        break;
-      case STAGE_3_2:
-        aosDbgPrintf(">>> 3-2\n");
-        break;
-      case STAGE_3_3_WAITFORFIRSTID:
-        aosDbgPrintf(">>> 3-3 (1st ID)\n");
-        break;
-      case STAGE_3_3_WAITFORIDORSIG:
-        aosDbgPrintf(">>> 3-3 (ID/sig)\n");
-        break;
-      case STAGE_3_3_WAITFORID:
-        aosDbgPrintf(">>> 3-3 (ID)\n");
-        break;
-      case STAGE_3_4_FINISH:
-        aosDbgPrintf(">>> 3-4 (finish)\n");
-        break;
-      case STAGE_3_4_ABORT_ACTIVE:
-        aosDbgPrintf(">>> 3-4 (active abort)\n");
-        break;
-      case STAGE_3_4_ABORT:
-        aosDbgPrintf(">>> 3-4 (abort)\n");
-        break;
-    }
-#endif
-
-    // reset wfe flag for the next iteration
-    flags.wfe_next = true;
-
-    // waiting for events may be skipped
-    if (flags.wfe) {
-      // wait for any event to occur
-      aosDbgPrintf("WFE...");
-      eventmask = chEvtWaitAnyTimeout(ALL_EVENTS, chTimeUS2I(AOS_SYSTEM_SSSP_TIMEOUT));
-      aosDbgPrintf("\t0x%08X", eventmask);
-    } else {
-      aosDbgPrintf("WFE skipped");
-    }
-    aos_timestamp_t uptime;
-    aosSysGetUptime(&uptime);
-    aosDbgPrintf("\t%04ums\n", (uint32_t)(uptime / 1000));
-
-    /*
-     * execute some general tasks and high priority events
-     */
-    // no event occurred at all
-    if ((flags.wfe) && (eventmask == 0)) {
-      aosDbgPrintf("ERR: no evt\n");
-      // enforce timeout event
-      chEvtBroadcast(&eventSourceTimeout);
-      continue;
-    }
-    // if an IO event occurred
-    if (eventmask & _eventListenerIO.events) {
-      ioflags = chEvtGetAndClearFlags(&_eventListenerIO);
-      aosDbgPrintf("INFO: IO evt (0x%08X)\n", ioflags);
-      // a power-down event occurred
-      if (ioflags & MODULE_SSSP_EVENTFLAGS_PD) {
-        aosDbgPrintf("PD evt\n");
-        // deactivate S and UP
-        apalControlGpioSet(&moduleSsspGpioSync, APAL_GPIO_OFF);
-  #if (AMIROOS_CFG_SSSP_STACK_END != true)
-        apalControlGpioSet(&moduleSsspGpioUp, APAL_GPIO_OFF);
-  #endif
-        // set shutdown flag and exit the loop
-        shutdown = AOS_SHUTDOWN_PASSIVE;
-        break;
-      }
-      // the S signal was deactivated
-      if (ioflags & MODULE_SSSP_EVENTFLAGS_SYNC) {
-        apalControlGpioState_t sstate;
-        apalControlGpioGet(&moduleSsspGpioSync, &sstate);
-        if (sstate == APAL_GPIO_OFF) {
-          aosDbgPrintf("-S evt\n");
-          // either finish or abort
-          if ((stage == STAGE_3_3_WAITFORID) && (aos.sssp.moduleId != 0)) {
-            stage = STAGE_3_4_FINISH;
-          } else if (stage != STAGE_3_4_ABORT) {
-            stage = STAGE_3_4_ABORT_ACTIVE;
-          }
-        }
-      }
-    }
-    // an OS event occurred
-    if (eventmask & _eventListenerOS.events) {
-      aosDbgPrintf("WARN: OS evt\n");
-      // get the flags
-      eventflags_t oseventflags = chEvtGetAndClearFlags(&_eventListenerOS);
-      // there should be no OS events at this point
-#ifdef MODULE_SSSP_STARTUP_3_OSEVENT_HOOK
-      MODULE_SSSP_STARTUP_3_OSEVENT_HOOK(eventmask, eventflags);
-#else
-      _unexpectedEventError(eventmask, oseventflags);
-#endif
-    }
-    // if a CAN event occurred
-    if ((eventmask & eventListenerCan.events)) {
-      // fetch message
-      if (flags.wfe) {
-        canReceiveTimeout(&MODULE_HAL_CAN, CAN_ANY_MAILBOX, &canRxFrame, TIME_IMMEDIATE);
-        aosDbgPrintf("CAN <- 0x%03X\n", canRxFrame.SID);
-      }
-      // identify and handle abort messgaes
-      if (canRxFrame.SID == SSSP_STACKINIT_CANMSGID_ABORT) {
-        stage = STAGE_3_4_ABORT;
-      }
-      // warn if a unexpected message was received
-      else if ((canRxFrame.SID != SSSP_STACKINIT_CANMSGID_INIT) &&
-               (canRxFrame.SID != SSSP_STACKINIT_CANMSGID_MODULEID)) {
-        aosDbgPrintf("WARN: unknown msg\n");
-      }
-      // any further pending messages are fetched at the end of the loop
-    }
-    // if a timeout event occurred
-    if (eventmask & eventListenerTimeout.events) {
-      // is handled at the end of the loop (or must be cleared by FSM)
-    }
-    // if a delay event occurred
-    if (eventmask & eventListenerDelay.events) {
-      // is handled by FSM
-    }
-
-    /*
-     * this is the actual FSM
-     */
-    switch (stage) {
-      case STAGE_3_1:
-      {
-        aos.sssp.stage = AOS_SSSP_STARTUP_3_1;
-
-        // there was no event at all (skipped wfe)
-        if (eventmask == 0 && flags.wfe == false) {
-#if (AMIROOS_CFG_SSSP_MASTER == true)
-          // initialize the stage by transmitting an according CAN message
-          aosDbgPrintf("CAN -> init\n");
-          canTxFrame.DLC = 0;
-          canTxFrame.SID = SSSP_STACKINIT_CANMSGID_INIT;
-          if (canTransmitTimeout(&MODULE_HAL_CAN, CAN_ANY_MAILBOX, &canTxFrame, TIME_IMMEDIATE) != MSG_OK) {
-            chEvtBroadcast(&eventSourceTimeout);
-            break;
-          }
-          // activate S
-          aosDbgPrintf("S+\n");
-          apalControlGpioSet(&moduleSsspGpioSync, APAL_GPIO_ON);
-#if (AMIROOS_CFG_SSSP_STACK_START == true)
-          // proceed immediately
-          stage = STAGE_3_2;
-          flags.wfe_next = false;
-#else
-          // set the timeout timer
-          chVTSet(&timerTimeout, chTimeUS2I(AOS_SYSTEM_SSSP_TIMEOUT), _ssspTimerCallback, &eventSourceTimeout);
-          // proceed
-          stage = STAGE_3_3_WAITFORFIRSTID;
-#endif
-#else
-          // set the timeout timer
-          chVTSet(&timerTimeout, chTimeUS2I(AOS_SYSTEM_SSSP_TIMEOUT), _ssspTimerCallback, &eventSourceTimeout);
-#endif
-        }
-
-#if (AMIROOS_CFG_SSSP_MASTER != true)
-        // a CAN message was received
-        else if (eventmask & eventListenerCan.events) {
-          // if an initiation message was received
-          if (canRxFrame.DLC == 0 &&
-              canRxFrame.RTR == CAN_RTR_DATA &&
-              canRxFrame.IDE == CAN_IDE_STD &&
-              canRxFrame.SID == SSSP_STACKINIT_CANMSGID_INIT) {
-            aosDbgPrintf("init msg\n");
-            // reset the timeout timer and clear pending flags
-            chVTReset(&timerTimeout);
-            chEvtWaitAnyTimeout(eventListenerTimeout.events, TIME_IMMEDIATE);
-            eventmask &= ~(eventListenerTimeout.events);
-            // activate S
-            aosDbgPrintf("S+\n");
-            apalControlGpioSet(&moduleSsspGpioSync, APAL_GPIO_ON);
-#if (AMIROOS_CFG_SSSP_STACK_START == true)
-            // proceed
-            stage = STAGE_3_2;
-            flags.wfe_next = false;
-#else
-            // set the timeout timer
-            chVTSet(&timerTimeout, chTimeUS2I(AOS_SYSTEM_SSSP_TIMEOUT), _ssspTimerCallback, &eventSourceTimeout);
-            // proceed
-            stage = STAGE_3_3_WAITFORFIRSTID;
-#endif
-          }
-        }
-#endif
-
-        break;
-      } /* end of STAGE_3_1 */
-
-      case STAGE_3_2:
-      {
-#if (AMIROOS_CFG_SSSP_STACK_START == true)
-        aos.sssp.stage = AOS_SSSP_STARTUP_3_2;
-
-        // if this stage was just entered
-        if (flags.wfe == false) {
-          // set the module ID
-          aos.sssp.moduleId = 1;
-          // broadcast module ID
-          aosDbgPrintf("CAN -> ID (%u)\n", aos.sssp.moduleId);
-          canTxFrame.DLC = 4;
-          canTxFrame.SID = SSSP_STACKINIT_CANMSGID_MODULEID;
-          _serialize(canTxFrame.data8, aos.sssp.moduleId, 4);
-          if (canTransmitTimeout(&MODULE_HAL_CAN, CAN_ANY_MAILBOX, &canTxFrame, TIME_IMMEDIATE) != MSG_OK) {
-            chEvtBroadcast(&eventSourceTimeout);
-            break;
-          }
-#if (AMIROOS_CFG_SSSP_STACK_START != true) || (AMIROOS_CFG_DBG == true)
-          lastid = aos.sssp.moduleId;
-#endif
-#if (AMIROOS_CFG_SSSP_STACK_END == true)
-          // sequence is already over
-          // deactivate S
-          aosDbgPrintf("S-\n");
-          apalControlGpioSet(&moduleSsspGpioSync, APAL_GPIO_OFF);
-          // proceed
-          stage = STAGE_3_3_WAITFORID;
-#else
-          // set the delay timer so the UP signal is activated later
-          chVTSet(&timerDelay, chTimeUS2I(AMIROOS_CFG_SSSP_SIGNALDELAY), _ssspTimerCallback, &eventSourceDelay);
-#endif
-        }
-
-        // if a delay event occurred
-        if (eventmask & eventListenerDelay.events) {
-          // activate UP
-          aosDbgPrintf("UP+\n");
-          apalControlGpioSet(&moduleSsspGpioUp, APAL_GPIO_ON);
-          // deactivate S
-          aosDbgPrintf("S-\n");
-          apalControlGpioSet(&moduleSsspGpioSync, APAL_GPIO_OFF);
-          // explicitely clear timeout event flag
-          chEvtWaitAnyTimeout(eventListenerTimeout.events, TIME_IMMEDIATE);
-          eventmask &= ~(eventListenerTimeout.events);
-          // proceed
-          stage = STAGE_3_3_WAITFORID;
-        }
-#endif
-
-        break;
-      } /* end of STAGE_3_2 */
-
-      case STAGE_3_3_WAITFORFIRSTID:
-      {
-#if (AMIROOS_CFG_SSSP_STACK_START != true)
-        aos.sssp.stage = AOS_SSSP_STARTUP_3_3;
-
-        // a CAN message was received
-        if (eventmask & eventListenerCan.events) {
-          // if an ID message was received
-          if (canRxFrame.DLC == 4 &&
-              canRxFrame.RTR == CAN_RTR_DATA &&
-              canRxFrame.IDE == CAN_IDE_STD &&
-              canRxFrame.SID == SSSP_STACKINIT_CANMSGID_MODULEID) {
-            aosDbgPrintf("ID (%u)\n", (uint32_t)_deserialize(canRxFrame.data8, 4));
-            // validate received ID
-            if (lastid < _deserialize(canRxFrame.data8, 4)) {
-              // store received ID
-              lastid = _deserialize(canRxFrame.data8, 4);
-              // restart timeout timer
-              chVTSet(&timerTimeout, chTimeUS2I(AOS_SYSTEM_SSSP_TIMEOUT), _ssspTimerCallback, &eventSourceTimeout);
-              // proceed
-              stage = STAGE_3_3_WAITFORIDORSIG;
-            } else {
-              aosDbgPrintf("ERR: invalid ID\n");
-              // abort
-              stage = STAGE_3_4_ABORT_ACTIVE;
-              flags.wfe_next = false;
-            }
-            // explicitely clear timeout event flag
-            chEvtWaitAnyTimeout(eventListenerTimeout.events, TIME_IMMEDIATE);
-            eventmask &= ~(eventListenerTimeout.events);
-          }
-        }
-#endif
-        break;
-      } /* end of STAGE_3_3_WAITFORFIRSTID */
-
-      case STAGE_3_3_WAITFORIDORSIG:
-      {
-#if (AMIROOS_CFG_SSSP_STACK_START != true)
-        aos.sssp.stage = AOS_SSSP_STARTUP_3_3;
-
-        // a CAN message was received
-        if (eventmask & eventListenerCan.events) {
-          // if an ID message was received
-          if (canRxFrame.DLC == 4 &&
-              canRxFrame.RTR == CAN_RTR_DATA &&
-              canRxFrame.IDE == CAN_IDE_STD &&
-              canRxFrame.SID == SSSP_STACKINIT_CANMSGID_MODULEID) {
-            aosDbgPrintf("ID (%u)\n", (uint32_t)_deserialize(canRxFrame.data8, 4));
-            // validate received ID
-            if (lastid < _deserialize(canRxFrame.data8, 4)) {
-              // store received ID
-              lastid = _deserialize(canRxFrame.data8, 4);
-              // restart timeout timer
-              chVTSet(&timerTimeout, chTimeUS2I(AOS_SYSTEM_SSSP_TIMEOUT), _ssspTimerCallback, &eventSourceTimeout);
-            } else {
-              aosDbgPrintf("ERR: invalid ID\n");
-              // abort
-              stage = STAGE_3_4_ABORT_ACTIVE;
-              flags.wfe_next = false;
-            }
-            // explicitely clear timeout event flag
-            chEvtWaitAnyTimeout(eventListenerTimeout.events, TIME_IMMEDIATE);
-            eventmask &= ~(eventListenerTimeout.events);
-          }
-        }
-
-        // if an IO event was received (DN signal)
-        if ((eventmask & _eventListenerIO.events) && (ioflags & MODULE_SSSP_EVENTFLAGS_DN)) {
-          aosDbgPrintf("DN <-\n");
-          // reset timeout timer
-          chVTReset(&timerTimeout);
-          chEvtWaitAnyTimeout(eventListenerTimeout.events, TIME_IMMEDIATE);
-          eventmask &= ~(eventListenerTimeout.events);
-          // increment and broadcast ID
-          aos.sssp.moduleId = lastid + 1;
-          aosDbgPrintf("CAN -> ID (%u)\n", aos.sssp.moduleId);
-          canTxFrame.DLC = 4;
-          canTxFrame.SID = SSSP_STACKINIT_CANMSGID_MODULEID;
-          _serialize(canTxFrame.data8, aos.sssp.moduleId, 4);
-          if (canTransmitTimeout(&MODULE_HAL_CAN, CAN_ANY_MAILBOX, &canTxFrame, TIME_IMMEDIATE) != MSG_OK) {
-            chEvtBroadcast(&eventSourceTimeout);
-            break;
-          }
-          // set delay timer
-          chVTSet(&timerDelay, chTimeUS2I(AMIROOS_CFG_SSSP_SIGNALDELAY), _ssspTimerCallback, &eventSourceDelay);
-        }
-
-        // if a delay event occurred
-        if (eventmask & eventListenerDelay.events) {
-#if (AMIROOS_CFG_SSSP_STACK_END != true)
-          // activate UP
-          aosDbgPrintf("UP+\n");
-          apalControlGpioSet(&moduleSsspGpioUp, APAL_GPIO_ON);
-#endif
-          // deactivate S
-          aosDbgPrintf("S-\n");
-          apalControlGpioSet(&moduleSsspGpioSync, APAL_GPIO_OFF);
-          // reset the timeout timer
-          chVTSet(&timerTimeout, chTimeUS2I(AOS_SYSTEM_SSSP_TIMEOUT), _ssspTimerCallback, &eventSourceTimeout);
-          chEvtWaitAnyTimeout(eventListenerTimeout.events, TIME_IMMEDIATE);
-          eventmask &= ~(eventListenerTimeout.events);
-          // proceed
-          stage = STAGE_3_3_WAITFORID;
-        }
-#endif
-
-        break;
-      } /* end of STAGE_3_3_WAITFORIDORSIG */
-
-      case STAGE_3_3_WAITFORID:
-      {
-        aos.sssp.stage = AOS_SSSP_STARTUP_3_3;
-
-#if (AMIROOS_CFG_SSSP_STACK_END != true)
-        // a CAN message was received
-        if (eventmask & eventListenerCan.events) {
-          // if an ID message was received
-          if (canRxFrame.DLC == 4 &&
-              canRxFrame.RTR == CAN_RTR_DATA &&
-              canRxFrame.IDE == CAN_IDE_STD &&
-              canRxFrame.SID == SSSP_STACKINIT_CANMSGID_MODULEID) {
-#if (AMIROOS_CFG_SSSP_STACK_START != true) || (AMIROOS_CFG_DBG == true)
-            // Plausibility of the received ID is not checked at this point but is done by other modules still in a previous stage.
-            lastid = _deserialize(canRxFrame.data8, 4);
-            aosDbgPrintf("ID (%u)\n", lastid);
-#endif
-            // restart timeout timer
-            chVTSet(&timerTimeout, chTimeUS2I(AOS_SYSTEM_SSSP_TIMEOUT), _ssspTimerCallback, &eventSourceTimeout);
-            chEvtWaitAnyTimeout(eventListenerTimeout.events, TIME_IMMEDIATE);
-            eventmask &= ~(eventListenerTimeout.events);
-          }
-        }
-#endif
-
-        break;
-      } /* end of STAGE_3_3_WAITFORID */
-
-      case STAGE_3_4_FINISH:
-      {
-        aos.sssp.stage = AOS_SSSP_STARTUP_3_4;
-
-        // if an IO event was received (S signal)
-        if ((eventmask & _eventListenerIO.events) && (ioflags & MODULE_SSSP_EVENTFLAGS_SYNC)) {
-          // reset the timeout timer
-          chVTReset(&timerTimeout);
-          chEvtWaitAnyTimeout(eventListenerTimeout.events, TIME_IMMEDIATE);
-          eventmask &= ~(eventListenerTimeout.events);
-          //set the delay timer
-          chVTSet(&timerDelay, chTimeUS2I(AOS_SYSTEM_SSSP_TIMEOUT), _ssspTimerCallback, &eventSourceDelay);
-        }
-
-        // if a CAN event was received
-        if (eventmask & eventListenerCan.events) {
-          // if an abort message was received
-          if (canRxFrame.SID == SSSP_STACKINIT_CANMSGID_ABORT) {
-            aosDbgPrintf("abort msg\n");
-            // reset the delay timer
-            chVTReset(&timerDelay);
-            chEvtWaitAnyTimeout(eventListenerDelay.events, TIME_IMMEDIATE);
-            eventmask &= ~(eventListenerDelay.events);
-            // proceed
-            stage = STAGE_3_4_ABORT;
-          }
-        }
-
-        // if a delay timer event occurred
-        if (eventmask & eventListenerDelay.events) {
-          aosDbgPrintf("sequence sucessful\n");
-          // sequence finished sucessfully
-          flags.loop = false;
-        }
-
-        break;
-      } /* end of STAGE_3_4_FINISH */
-
-      case STAGE_3_4_ABORT_ACTIVE:
-      {
-        aos.sssp.stage = AOS_SSSP_STARTUP_3_4;
-
-        // emit abort message
-        canTxFrame.DLC = 0;
-        canTxFrame.SID = SSSP_STACKINIT_CANMSGID_ABORT;
-        canTransmitTimeout(&MODULE_HAL_CAN, CAN_ANY_MAILBOX, &canTxFrame, TIME_INFINITE);
-        aosDbgPrintf("CAN -> abort\n");
-        // clear timeout flag
-        eventmask &= ~(eventListenerTimeout.events);
-        // proceed immediately
-        stage = STAGE_3_4_ABORT;
-        flags.wfe_next = false;
-        break;
-      } /* end of STAGE_3_4_ABORT_ACTIVE */
-
-      case STAGE_3_4_ABORT:
-      {
-        aos.sssp.stage = AOS_SSSP_STARTUP_3_4;
-
-        // deactivate S
-        aosDbgPrintf("S-\n");
-        apalControlGpioSet(&moduleSsspGpioSync, APAL_GPIO_OFF);
-        // invalidate module ID
-        aos.sssp.moduleId = 0;
-
-        // if an IO event was received (S signal)
-        if ((eventmask & _eventListenerIO.events) && (ioflags & MODULE_SSSP_EVENTFLAGS_SYNC)) {
-          aosDbgPrintf("sequence aborted\n");
-          // exit the sequence
-          flags.loop = false;
-        }
-
-        break;
-      } /* end of STAGE_3_4_ABORT */
-    }
-
-    // fetch pending CAN message (if any)
-    if ((eventmask & eventListenerCan.events) && (canReceiveTimeout(&MODULE_HAL_CAN, CAN_ANY_MAILBOX, &canRxFrame, TIME_IMMEDIATE) == MSG_OK)) {
-      aosDbgPrintf("CAN <- 0x%03X\n", canRxFrame.SID);
-      flags.wfe_next = false;
-    }
-
-    // handle unhandled timeout events
-    if (eventmask & eventListenerTimeout.events) {
-      aosDbgPrintf("ERR: timeout evt\n");
-      // abort
-      flags.wfe_next = false;
-      stage = STAGE_3_4_ABORT_ACTIVE;
-    }
-
-    // apply wfe value for next iteration
-    flags.wfe = flags.wfe_next;
-  } /* end of FSM loop */
-  aosDbgPrintf("\n");
-
-  // unregister all events (timeout, delay, CAN receive)
-  chEvtUnregister(&eventSourceTimeout, &eventListenerTimeout);
-  chEvtUnregister(&eventSourceDelay, &eventListenerDelay);
-  chEvtUnregister(&MODULE_HAL_CAN.rxfull_event, &eventListenerCan);
-  // clear any pending events (timeout, delay, CAN receive)
-  chEvtWaitAllTimeout(TIMEOUTEVENT_MASK | DELAYEVENT_MASK | CANEVENT_MASK, TIME_IMMEDIATE);
-
-  // reset all control signals
-#if (AMIROOS_CFG_SSSP_STACK_END != true)
-  apalControlGpioSet(&moduleSsspGpioUp, APAL_GPIO_OFF);
-#endif
-  apalControlGpioSet(&moduleSsspGpioSync, APAL_GPIO_OFF);
-
-  return shutdown;
-}
-
-/**
- * @brief   Application entry point.
- */
-int main(void)
-{
-  // local variables
-  eventmask_t eventmask = 0;
-  eventflags_t eventflags = 0;
-  aos_shutdown_t shutdown = AOS_SHUTDOWN_NONE;
-#if defined(AMIROOS_CFG_MAIN_EXTRA_THREAD_VARIABLES)
-  AMIROOS_CFG_MAIN_EXTRA_THREAD_VARIABLES
-#endif
-
-  /*
-   * ##########################################################################
-   * # system initialization                                                  #
-   * ##########################################################################
-   */
-
-#if defined(AMIROOS_CFG_MAIN_INIT_HOOK_0)
-#if defined(AMIROOS_CFG_MAIN_INIT_HOOK_0_ARGS)
-  AMIROOS_CFG_MAIN_INIT_HOOK_0(AMIROOS_CFG_MAIN_INIT_HOOK_0_ARGS);
-#else
-  AMIROOS_CFG_MAIN_INIT_HOOK_0();
-#endif
-#endif
-
-  /* hardware, kernel, and operating system initialization */
-  // ChibiOS/HAL and custom hal additions (if any)
-  halInit();
-#ifdef MODULE_INIT_HAL_EXTRA
-  MODULE_INIT_HAL_EXTRA();
-#endif
-
-#if defined(AMIROOS_CFG_MAIN_INIT_HOOK_1)
-#if defined(AMIROOS_CFG_MAIN_INIT_HOOK_1_ARGS)
-  AMIROOS_CFG_MAIN_INIT_HOOK_1(AMIROOS_CFG_MAIN_INIT_HOOK_1_ARGS);
-#else
-  AMIROOS_CFG_MAIN_INIT_HOOK_1();
-#endif
-#endif
-
-  // ChibiOS/RT kernel and custom kernel additions (if any)
-  chSysInit();
-#ifdef MODULE_INIT_KERNEL_EXTRA
-  MODULE_INIT_KERNEL_EXTRA();
-#endif
-
-#if defined(AMIROOS_CFG_MAIN_INIT_HOOK_2)
-#if defined(AMIROOS_CFG_MAIN_INIT_HOOK_2_ARGS)
-  AMIROOS_CFG_MAIN_INIT_HOOK_2(AMIROOS_CFG_MAIN_INIT_HOOK_2_ARGS);
-#else
-  AMIROOS_CFG_MAIN_INIT_HOOK_2();
-#endif
-#endif
-
-  // AMiRo-OS and custom OS additions (if any)
-#if (AMIROOS_CFG_SHELL_ENABLE == true)
-  aosSysInit(moduleShellPrompt);
-#else
-  aosSysInit();
-#endif
-#ifdef MODULE_INIT_OS_EXTRA
-  MODULE_INIT_OS_EXTRA();
-#endif
-
-#if defined(AMIROOS_CFG_MAIN_INIT_HOOK_3)
-#if defined(AMIROOS_CFG_MAIN_INIT_HOOK_3_ARGS)
-  AMIROOS_CFG_MAIN_INIT_HOOK_3(AMIROOS_CFG_MAIN_INIT_HOOK_3_ARGS);
-#else
-  AMIROOS_CFG_MAIN_INIT_HOOK_3();
-#endif
-#endif
-
-#if (AMIROOS_CFG_TESTS_ENABLE == true)
-#if defined(MODULE_INIT_TESTS)
-  MODULE_INIT_TESTS();
-#else
-  #warning "MODULE_INIT_TESTS not defined"
-#endif
-#endif
-
-#if defined(AMIROOS_CFG_MAIN_INIT_HOOK_4)
-#if defined(AMIROOS_CFG_MAIN_INIT_HOOK_4_ARGS)
-  AMIROOS_CFG_MAIN_INIT_HOOK_4(AMIROOS_CFG_MAIN_INIT_HOOK_4_ARGS);
-#else
-  AMIROOS_CFG_MAIN_INIT_HOOK_4();
-#endif
-#endif
-
-  /* event associations */
-#if (AMIROOS_CFG_SSSP_STACK_START == true) && (AMIROOS_CFG_SSSP_STACK_END == true)
-  chEvtRegisterMaskWithFlags(&aos.events.io, &_eventListenerIO, IOEVENT_MASK, MODULE_SSSP_EVENTFLAGS_PD | MODULE_SSSP_EVENTFLAGS_SYNC);
-#elif (AMIROOS_CFG_SSSP_STACK_START == true)
-  chEvtRegisterMaskWithFlags(&aos.events.io, &_eventListenerIO, IOEVENT_MASK, MODULE_SSSP_EVENTFLAGS_PD | MODULE_SSSP_EVENTFLAGS_SYNC | MODULE_SSSP_EVENTFLAGS_UP);
-#elif (AMIROOS_CFG_SSSP_STACK_END == true)
-  chEvtRegisterMaskWithFlags(&aos.events.io, &_eventListenerIO, IOEVENT_MASK, MODULE_SSSP_EVENTFLAGS_PD | MODULE_SSSP_EVENTFLAGS_SYNC | MODULE_SSSP_EVENTFLAGS_DN);
-#else
-  chEvtRegisterMaskWithFlags(&aos.events.io, &_eventListenerIO, IOEVENT_MASK, MODULE_SSSP_EVENTFLAGS_PD | MODULE_SSSP_EVENTFLAGS_SYNC | MODULE_SSSP_EVENTFLAGS_DN | MODULE_SSSP_EVENTFLAGS_UP);
-#endif
-  chEvtRegisterMask(&aos.events.os, &_eventListenerOS, OSEVENT_MASK);
-
-#if defined(AMIROOS_CFG_MAIN_INIT_HOOK_5)
-#if defined(AMIROOS_CFG_MAIN_INIT_HOOK_5_ARGS)
-  AMIROOS_CFG_MAIN_INIT_HOOK_5(AMIROOS_CFG_MAIN_INIT_HOOK_5_ARGS);
-#else
-  AMIROOS_CFG_MAIN_INIT_HOOK_5();
-#endif
-#endif
-
-  /* periphery communication initialization */
-  // CAN (mandatory)
-  canStart(&MODULE_HAL_CAN, &moduleHalCanConfig);
-  // module specific initialization (if any)
-#ifdef MODULE_INIT_PERIPHERY_COMM
-  MODULE_INIT_PERIPHERY_COMM();
-#endif
-  // user interface (if any)
-#ifdef MODULE_HAL_PROGIF
-  aosIOChannelInit(&_stdiochannel, (BaseAsynchronousChannel*)&MODULE_HAL_PROGIF);
-  aosIOChannelOutputEnable(&_stdiochannel);
-  aosIOStreamAddChannel(&aos.iostream, &_stdiochannel);
-#if (AMIROOS_CFG_SHELL_ENABLE == true)
-  aosShellChannelInit(&_stdshellchannel, (BaseAsynchronousChannel*)&MODULE_HAL_PROGIF);
-  aosShellChannelInputEnable(&_stdshellchannel);
-  aosShellChannelOutputEnable(&_stdshellchannel);
-  aosShellStreamAddChannel(&aos.shell.stream, &_stdshellchannel);
-#endif
-#endif
-
-#if defined(AMIROOS_CFG_MAIN_INIT_HOOK_6)
-#if defined(AMIROOS_CFG_MAIN_INIT_HOOK_6_ARGS)
-  AMIROOS_CFG_MAIN_INIT_HOOK_6(AMIROOS_CFG_MAIN_INIT_HOOK_6_ARGS);
-#else
-  AMIROOS_CFG_MAIN_INIT_HOOK_6();
-#endif
-#endif
-
-  /* module is ready -> print welcome prompt */
-  aosprintf("\n");
-  aosprintf("######################################################################\n");
-  aosprintf("# AMiRo-OS is an operating system designed for the Autonomous Mini   #\n");
-  aosprintf("# Robot (AMiRo) platform.                                            #\n");
-  aosprintf("# Copyright (C) 2016..2018  Thomas Schöpping et al.                  #\n");
-  aosprintf("#                                                                    #\n");
-  aosprintf("# This is free software; see the source for copying conditions.      #\n");
-  aosprintf("# There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR  #\n");
-  aosprintf("# A PARTICULAR PURPOSE.                                              #\n");
-  aosprintf("# The development of this software was supported by the Excellence   #\n");
-  aosprintf("# Cluster EXC 227 Cognitive Interaction Technology. The Excellence   #\n");
-  aosprintf("# Cluster EXC 227 is a grant of the Deutsche Forschungsgemeinschaft  #\n");
-  aosprintf("# (DFG) in the context of the German Excellence Initiative.          #\n");
-  aosprintf("######################################################################\n");
-  aosprintf("\n");
-
-#if defined(AMIROOS_CFG_MAIN_INIT_HOOK_7)
-#if defined(AMIROOS_CFG_MAIN_INIT_HOOK_7_ARGS)
-  AMIROOS_CFG_MAIN_INIT_HOOK_7(AMIROOS_CFG_MAIN_INIT_HOOK_7_ARGS);
-#else
-  AMIROOS_CFG_MAIN_INIT_HOOK_7();
-#endif
-#endif
-
-  /* SSSP startup OS synchronization phase (end of startup stage 2) */
-  while ((shutdown == AOS_SHUTDOWN_NONE) && (eventmask = aosSysSsspStartupOsInitSyncCheck(&_eventListenerIO)) != 0) {
-    /*
-     * This code is executed if the received event was not about the SYS_SYNC control signal.
-     * The returned event could be caused by any listener (not only the argument).
-     */
-    // IO event
-    if (eventmask & _eventListenerIO.events) {
-      eventflags = chEvtGetAndClearFlags(&_eventListenerIO);
-      // PD event
-      if (eventflags & MODULE_SSSP_EVENTFLAGS_PD) {
-        shutdown = AOS_SHUTDOWN_PASSIVE;
-      } else {
-#ifdef MODULE_SSSP_STARTUP_2_2_IOEVENT_HOOK
-        MODULE_SSSP_STARTUP_2_2_IOEVENT_HOOK(eventmask, eventflags);
-#else
-        // ignore any other IO events
-#endif
-      }
-    }
-    // OS event
-    else if (eventmask & _eventListenerOS.events) {
-      eventflags = chEvtGetAndClearFlags(&_eventListenerOS);
-      _unexpectedEventError(eventmask, eventflags);
-    }
-    // unknown event
-    else {
-      _unexpectedEventError(eventmask, 0);
-    }
-  }
-
-  /*
-   * There must be no delays at this point, thus no hook is allowed.
-   */
-
-  /* SSSP startup stage 3 (module stack initialization) */
-  if (shutdown == AOS_SHUTDOWN_NONE) {
-    shutdown = _ssspModuleStackInitialization();
-  }
-
-  /*
-   * There must be no delays at this point, thus no hook is allowed.
-   */
-
-  /* snychronize calendars */
-  if (shutdown == AOS_SHUTDOWN_NONE) {
-#if (AMIROOS_CFG_SSSP_MASTER == true)
-    CANTxFrame frame;
-    struct tm t;
-    uint64_t encoded;
-
-    frame.DLC = 8;
-    frame.RTR = CAN_RTR_DATA;
-    frame.IDE = CAN_IDE_STD;
-    frame.SID = CALENDERSYNC_CANMSGID;
-
-    aosDbgPrintf("transmitting current date/time...\t");
-    // get current date & time
-    aosSysGetDateTime(&t);
-    // encode
-    encoded = _TM2U64(&t);
-    // serialize
-    _serialize(frame.data8, encoded, 8);
-    // transmit
-    canTransmitTimeout(&MODULE_HAL_CAN, CAN_ANY_MAILBOX, &frame, TIME_IMMEDIATE);
-
-    aosDbgPrintf("done\n");
-#else
-    CANRxFrame frame;
-    uint64_t encoded;
-    struct tm t;
-
-    aosDbgPrintf("receiving current date/time...\t");
-    // receive message
-    if (canReceiveTimeout(&MODULE_HAL_CAN, CAN_ANY_MAILBOX, &frame, chTimeUS2I(AOS_SYSTEM_SSSP_TIMEOUT)) == MSG_OK) {
-      // validate message
-      if (frame.DLC == 8 &&
-          frame.RTR == CAN_RTR_DATA &&
-          frame.IDE == CAN_IDE_STD &&
-          frame.SID == CALENDERSYNC_CANMSGID) {
-        // deserialize
-        encoded = _deserialize(frame.data8, 8);
-        // decode
-        _U642TM(&t, encoded);
-        // set current date & time
-        aosSysSetDateTime(&t);
-        aosDbgPrintf("success\n");
-      } else {
-        aosDbgPrintf("fail (invalid message)\n");
-      }
-    } else {
-      aosDbgPrintf("fail (timeout)\n");
-    }
-#endif
-    aosDbgPrintf("\n");
-  }
-
-#if defined(AMIROOS_CFG_MAIN_INIT_HOOK_8)
-#if defined(AMIROOS_CFG_MAIN_INIT_HOOK_8_ARGS)
-  AMIROOS_CFG_MAIN_INIT_HOOK_8(AMIROOS_CFG_MAIN_INIT_HOOK_8_ARGS);
-#else
-  AMIROOS_CFG_MAIN_INIT_HOOK_8();
-#endif
-#endif
-
-  /* completely start AMiRo-OS */
-  if (shutdown == AOS_SHUTDOWN_NONE) {
-    aosSysStart();
-  }
-
-#if defined(AMIROOS_CFG_MAIN_INIT_HOOK_9)
-#if defined(AMIROOS_CFG_MAIN_INIT_HOOK_9_ARGS)
-  AMIROOS_CFG_MAIN_INIT_HOOK_9(AMIROOS_CFG_MAIN_INIT_HOOK_9_ARGS);
-#else
-  AMIROOS_CFG_MAIN_INIT_HOOK_9();
-#endif
-#endif
-
-  /*
-   * ##########################################################################
-   * # infinite loop                                                          #
-   * ##########################################################################
-   */
-
-  // sleep until a shutdown event is received
-  while (shutdown == AOS_SHUTDOWN_NONE) {
-    // wait for an event
-#if (AMIROOS_CFG_MAIN_LOOP_TIMEOUT != 0)
-    eventmask = chEvtWaitOneTimeout(ALL_EVENTS, chTimeUS2I(AMIROOS_CFG_MAIN_LOOP_TIMEOUT));
-#else
-    eventmask = chEvtWaitOne(ALL_EVENTS);
-#endif
-
-#if defined(AMIROOS_CFG_MAIN_LOOP_HOOK_0)
-#if defined(AMIROOS_CFG_MAIN_LOOP_HOOK_0_ARGS)
-    AMIROOS_CFG_MAIN_LOOP_HOOK_0(AMIROOS_CFG_MAIN_LOOP_HOOK_0_ARGS);
-#else
-    AMIROOS_CFG_MAIN_LOOP_HOOK_0();
-#endif
-#endif
-
-    switch (eventmask) {
-      // if this was an I/O event
-      case IOEVENT_MASK:
-        // evaluate flags
-        eventflags = chEvtGetAndClearFlags(&_eventListenerIO);
-        // PD event
-        if (eventflags & MODULE_SSSP_EVENTFLAGS_PD) {
-          shutdown = AOS_SHUTDOWN_PASSIVE;
-        }
-        // all other events
-#ifdef MODULE_MAIN_LOOP_IO_EVENT
-        else {
-          MODULE_MAIN_LOOP_IO_EVENT(eventmask, eventflags);
-        }
-#endif
-        break;
-
-      // if this was an OS event
-      case OSEVENT_MASK:
-        // evaluate flags
-        eventflags = chEvtGetAndClearFlags(&_eventListenerOS);
-        switch (eventflags) {
-          case AOS_SYSTEM_EVENTFLAGS_HIBERNATE:
-            shutdown = AOS_SHUTDOWN_HIBERNATE;
-            break;
-          case AOS_SYSTEM_EVENTFLAGS_DEEPSLEEP:
-            shutdown = AOS_SHUTDOWN_DEEPSLEEP;
-            break;
-          case AOS_SYSTEM_EVENTFLAGS_TRANSPORTATION:
-            shutdown = AOS_SHUTDOWN_TRANSPORTATION;
-            break;
-          case AOS_SYSTEM_EVENTFLAGS_RESTART:
-            shutdown = AOS_SHUTDOWN_RESTART;
-            break;
-          default:
-            _unexpectedEventError(eventmask, eventflags);
-            break;
-        }
-        break;
-
-      // if this was any other event (should be impossible to occur)
-      default:
-        eventflags = 0;
-        _unexpectedEventError(eventmask, eventflags);
-        break;
-    }
-
-#if defined(AMIROOS_CFG_MAIN_LOOP_HOOK_1)
-#if defined(AMIROOS_CFG_MAIN_LOOP_HOOK_1_ARGS)
-    AMIROOS_CFG_MAIN_LOOP_HOOK_1(AMIROOS_CFG_MAIN_LOOP_HOOK_1_ARGS);
-#else
-    AMIROOS_CFG_MAIN_LOOP_HOOK_1();
-#endif
-#endif
-  }
-
-  /*
-   * ##########################################################################
-   * # system shutdown                                                        #
-   * ##########################################################################
-   */
-
-#if defined(AMIROOS_CFG_MAIN_SHUTDOWN_HOOK_0)
-#if defined(AMIROOS_CFG_MAIN_SHUTDOWN_HOOK_0_ARGS)
-    AMIROOS_CFG_MAIN_SHUTDOWN_HOOK_0(AMIROOS_CFG_MAIN_SHUTDOWN_HOOK_0_ARGS);
-#else
-    AMIROOS_CFG_MAIN_SHUTDOWN_HOOK_0();
-#endif
-#endif
-
-  // initialize/acknowledge shutdown
-  aosSysShutdownInit(shutdown);
-
-#if defined(AMIROOS_CFG_MAIN_SHUTDOWN_HOOK_1)
-#if defined(AMIROOS_CFG_MAIN_SHUTDOWN_HOOK_1_ARGS)
-    AMIROOS_CFG_MAIN_SHUTDOWN_HOOK_1(AMIROOS_CFG_MAIN_SHUTDOWN_HOOK_1_ARGS);
-#else
-    AMIROOS_CFG_MAIN_SHUTDOWN_HOOK_1();
-#endif
-#endif
-
-  // stop system threads
-  aosSysStop();
-
-#if defined(AMIROOS_CFG_MAIN_SHUTDOWN_HOOK_2)
-#if defined(AMIROOS_CFG_MAIN_SHUTDOWN_HOOK_2_ARGS)
-    AMIROOS_CFG_MAIN_SHUTDOWN_HOOK_2(AMIROOS_CFG_MAIN_SHUTDOWN_HOOK_2_ARGS);
-#else
-    AMIROOS_CFG_MAIN_SHUTDOWN_HOOK_2();
-#endif
-#endif
-
-  // deinitialize system
-  aosSysDeinit();
-
-#if defined(AMIROOS_CFG_MAIN_SHUTDOWN_HOOK_3)
-#if defined(AMIROOS_CFG_MAIN_SHUTDOWN_HOOK_3_ARGS)
-    AMIROOS_CFG_MAIN_SHUTDOWN_HOOK_3(AMIROOS_CFG_MAIN_SHUTDOWN_HOOK_3_ARGS);
-#else
-    AMIROOS_CFG_MAIN_SHUTDOWN_HOOK_3();
-#endif
-#endif
-
-  /* stop all periphery communication */
-  // CAN (mandatory)
-  canStop(&MODULE_HAL_CAN);
-#ifdef MODULE_SHUTDOWN_PERIPHERY_COMM
-  MODULE_SHUTDOWN_PERIPHERY_COMM();
-#endif
-
-#if defined(AMIROOS_CFG_MAIN_SHUTDOWN_HOOK_4)
-#if defined(AMIROOS_CFG_MAIN_SHUTDOWN_HOOK_4_ARGS)
-    AMIROOS_CFG_MAIN_SHUTDOWN_HOOK_4(AMIROOS_CFG_MAIN_SHUTDOWN_HOOK_4_ARGS);
-#else
-    AMIROOS_CFG_MAIN_SHUTDOWN_HOOK_4();
-#endif
-#endif
-
-  // finally hand over to bootloader
-  aosSysShutdownFinal(shutdown);
-
-  /*
-   * ##########################################################################
-   * # after shutdown/restart                                                 #
-   * ##########################################################################
-   *
-   * NOTE: This code will not be executed, since the bootloader callbacks will stop/restart the MCU.
-   *       It is included nevertheless for the sake of completeness and to explicitely indicate,
-   *       which subsystems should NOT be shut down.
-   */
-
-  // return an error, since this code should not be executed
-  return -1;
-}
-
-/** @} */
diff --git a/os/core/src/aos_shell.c b/os/core/src/aos_shell.c
deleted file mode 100644
index 00e10f0..0000000
--- a/os/core/src/aos_shell.c
+++ /dev/null
@@ -1,1532 +0,0 @@
-/*
-AMiRo-OS is an operating system designed for the Autonomous Mini Robot (AMiRo) platform.
-Copyright (C) 2016..2018  Thomas Schöpping et al.
-
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program.  If not, see <http://www.gnu.org/licenses/>.
-*/
-
-/**
- * @file    aos_shell.c
- * @brief   Shell code.
- * @details Shell code as well as shell related channels and streams.
- *
- * @addtogroup aos_shell
- * @{
- */
-
-#include <aos_shell.h>
-
-#if (AMIROOS_CFG_SHELL_ENABLE == true)
-#include <aos_debug.h>
-#include <aos_time.h>
-#include <aos_system.h>
-#include <string.h>
-
-/**
- * @brief   Event mask to be set on OS related events.
- */
-#define AOS_SHELL_EVENTMASK_OS                  EVENT_MASK(0)
-
-/**
- * @brief   Event mask to be set on a input event.
- */
-#define AOS_SHELL_EVENTMASK_INPUT               EVENT_MASK(1)
-
-/**
- * @brief   Implementation of the BaseAsynchronous write() method (inherited from BaseSequentialStream).
- */
-static size_t _channelwrite(void *instance, const uint8_t *bp, size_t n)
-{
-  if (((AosShellChannel*)instance)->flags & AOS_SHELLCHANNEL_OUTPUT_ENABLED) {
-    return streamWrite(((AosShellChannel*)instance)->asyncchannel, bp, n);
-  } else {
-    return 0;
-  }
-}
-
-/**
- * @brief   Implementation of the BaseAsynchronous read() method (inherited from BaseSequentialStream).
- */
-static size_t _channelread(void *instance, uint8_t *bp, size_t n)
-{
-  if (((AosShellChannel*)instance)->flags & AOS_SHELLCHANNEL_INPUT_ENABLED) {
-    return streamRead(((AosShellChannel*)instance)->asyncchannel, bp, n);
-  } else {
-    return 0;
-  }
-}
-
-/**
- * @brief   Implementation of the BaseAsynchronous put() method (inherited from BaseSequentialStream).
- */
-static msg_t _channelput(void *instance, uint8_t b)
-{
-  if (((AosShellChannel*)instance)->flags & AOS_SHELLCHANNEL_OUTPUT_ENABLED) {
-    return streamPut(((AosShellChannel*)instance)->asyncchannel, b);
-  } else {
-    return MSG_RESET;
-  }
-}
-
-/**
- * @brief   Implementation of the BaseAsynchronous get() method (inherited from BaseSequentialStream).
- */
-static msg_t _channelget(void *instance)
-{
-  if (((AosShellChannel*)instance)->flags & AOS_SHELLCHANNEL_INPUT_ENABLED) {
-    return streamGet(((AosShellChannel*)instance)->asyncchannel);
-  } else {
-    return MSG_RESET;
-  }
-}
-
-/**
- * @brief   Implementation of the BaseAsynchronous putt() method.
- */
-static msg_t _channelputt(void *instance, uint8_t b, sysinterval_t time)
-{
-  if (((AosShellChannel*)instance)->flags & AOS_SHELLCHANNEL_OUTPUT_ENABLED) {
-    return chnPutTimeout(((AosShellChannel*)instance)->asyncchannel, b, time);
-  } else {
-    return MSG_RESET;
-  }
-}
-
-/**
- * @brief   Implementation of the BaseAsynchronous gett() method.
- */
-static msg_t _channelgett(void *instance, sysinterval_t time)
-{
-  if (((AosShellChannel*)instance)->flags & AOS_SHELLCHANNEL_INPUT_ENABLED) {
-    return chnGetTimeout(((AosShellChannel*)instance)->asyncchannel, time);
-  } else {
-    return MSG_RESET;
-  }
-}
-
-/**
- * @brief   Implementation of the BaseAsynchronous writet() method.
- */
-static size_t _channelwritet(void *instance, const uint8_t *bp, size_t n, sysinterval_t time)
-{
-  if (((AosShellChannel*)instance)->flags & AOS_SHELLCHANNEL_OUTPUT_ENABLED) {
-    return chnWriteTimeout(((AosShellChannel*)instance)->asyncchannel, bp, n, time);
-  } else {
-    return 0;
-  }
-}
-
-/**
- * @brief   Implementation of the BaseAsynchronous readt() method.
- */
-static size_t _channelreadt(void *instance, uint8_t *bp, size_t n, sysinterval_t time)
-{
-  if (((AosShellChannel*)instance)->flags & AOS_SHELLCHANNEL_INPUT_ENABLED) {
-    return chnReadTimeout(((AosShellChannel*)instance)->asyncchannel, bp, n, time);
-  } else {
-    return 0;
-  }
-}
-
-/**
- * @brief   Implementation of the BaseAsynchronousChannel ctl() method.
- */
-static msg_t _channelctl(void *instance, unsigned int operation, void *arg) {
-  (void) instance;
-
-  switch (operation) {
-  case CHN_CTL_NOP:
-    osalDbgCheck(arg == NULL);
-    break;
-  case CHN_CTL_INVALID:
-    osalDbgAssert(false, "invalid CTL operation");
-    break;
-  default:
-    break;
-  }
-  return MSG_OK;
-}
-
-static const struct AosShellChannelVMT _channelvmt = {
-  (size_t) 0,
-  _channelwrite,
-  _channelread,
-  _channelput,
-  _channelget,
-  _channelputt,
-  _channelgett,
-  _channelwritet,
-  _channelreadt,
-  _channelctl,
-};
-
-static size_t _streamwrite(void *instance, const uint8_t *bp, size_t n)
-{
-  aosDbgCheck(instance != NULL);
-
-  // local variables
-  AosShellChannel* channel = ((AosShellStream*)instance)->channel;
-  size_t bytes;
-  size_t maxbytes = 0;
-
-  // iterate through the list of channels
-  while (channel != NULL) {
-    bytes = streamWrite(channel, bp, n);
-    maxbytes = (bytes > maxbytes) ? bytes : maxbytes;
-    channel = channel->next;
-  }
-
-  return maxbytes;
-}
-
-static size_t _stremread(void *instance, uint8_t *bp, size_t n)
-{
-  (void)instance;
-  (void)bp;
-  (void)n;
-
-  return 0;
-}
-
-static msg_t _streamput(void *instance, uint8_t b)
-{
-  aosDbgCheck(instance != NULL);
-
-  // local variables
-  AosShellChannel* channel = ((AosShellStream*)instance)->channel;
-  msg_t ret = MSG_OK;
-
-  // iterate through the list of channels
-  while (channel != NULL) {
-    msg_t ret_ = streamPut(channel, b);
-    ret = (ret_ < ret) ? ret_ : ret;
-    channel = channel->next;
-  }
-
-  return ret;
-}
-
-static msg_t _streamget(void *instance)
-{
-  (void)instance;
-
-  return 0;
-}
-
-static const struct AosShellStreamVMT _streamvmt = {
-  (size_t) 0,
-  _streamwrite,
-  _stremread,
-  _streamput,
-  _streamget,
-};
-
-/**
- * @brief   Enumerator of special keyboard keys.
- */
-typedef enum special_key {
-  KEY_UNKNOWN,      /**< any/unknow key */
-  KEY_AMBIGUOUS,    /**< key is ambiguous */
-  KEY_TAB,          /**< tabulator key */
-  KEY_ESCAPE,       /**< escape key */
-  KEY_BACKSPACE,    /**< backspace key */
-  KEY_INSERT,       /**< insert key */
-  KEY_DELETE,       /**< delete key */
-  KEY_HOME,         /**< home key */
-  KEY_END,          /**< end key */
-  KEY_PAGE_UP,      /**< page up key */
-  KEY_PAGE_DOWN,    /**< page down key */
-  KEY_ARROW_UP,     /**< arrow up key */
-  KEY_ARROW_DOWN,   /**< arrow down key */
-  KEY_ARROW_LEFT,   /**< arrow left key */
-  KEY_ARROW_RIGHT,  /**< arrow right key */
-} special_key_t;
-
-/**
- * @brief   Enumerator for case (in)sensitive character matching.
- */
-typedef enum charmatch {
-  CHAR_MATCH_NOT    = 0,  /**< Characters do not match at all. */
-  CHAR_MATCH_NCASE  = 1,  /**< Characters would match case insensitive. */
-  CHAR_MATCH_CASE   = 2,  /**< Characters do match with case. */
-} charmatch_t;
-
-/**
- * @brief   Print the shell prompt
- * @details Depending on the configuration flags, the system uptime is printed before the prompt string.
- *
- * @param[in] shell   Pointer to the shell object.
- */
-static void _printPrompt(aos_shell_t* shell)
-{
-  aosDbgCheck(shell != NULL);
-
-  // print some time informattion before prompt if configured
-  if (shell->config & (AOS_SHELL_CONFIG_PROMPT_UPTIME | AOS_SHELL_CONFIG_PROMPT_DATETIME)) {
-    // printf the system uptime
-    if ((shell->config & (AOS_SHELL_CONFIG_PROMPT_UPTIME | AOS_SHELL_CONFIG_PROMPT_DATETIME)) == AOS_SHELL_CONFIG_PROMPT_UPTIME) {
-      // get current system uptime
-      aos_timestamp_t uptime;
-      aosSysGetUptime(&uptime);
-
-      chprintf((BaseSequentialStream*)&shell->stream, "[%01u:%02u:%02u:%02u:%03u:%03u] ",
-               (uint32_t)(uptime / MICROSECONDS_PER_DAY),
-               (uint8_t)(uptime % MICROSECONDS_PER_DAY / MICROSECONDS_PER_HOUR),
-               (uint8_t)(uptime % MICROSECONDS_PER_HOUR / MICROSECONDS_PER_MINUTE),
-               (uint8_t)(uptime % MICROSECONDS_PER_MINUTE / MICROSECONDS_PER_SECOND),
-               (uint16_t)(uptime % MICROSECONDS_PER_SECOND / MICROSECONDS_PER_MILLISECOND),
-               (uint16_t)(uptime % MICROSECONDS_PER_MILLISECOND / MICROSECONDS_PER_MICROSECOND));
-    }
-    else if ((shell->config & (AOS_SHELL_CONFIG_PROMPT_UPTIME | AOS_SHELL_CONFIG_PROMPT_DATETIME)) == AOS_SHELL_CONFIG_PROMPT_DATETIME) {
-      // get current RTC time
-      struct tm dt;
-      aosSysGetDateTime(&dt);
-      chprintf((BaseSequentialStream*)&shell->stream, "[%02u-%02u-%04u|%02u:%02u:%02u] ",
-               dt.tm_mday,
-               dt.tm_mon + 1,
-               dt.tm_year + 1900,
-               dt.tm_hour,
-               dt.tm_min,
-               dt.tm_sec);
-    }
-    else {
-      aosDbgAssert(false);
-    }
-  }
-
-  // print the actual prompt string
-  if (shell->prompt && !(shell->config & AOS_SHELL_CONFIG_PROMPT_MINIMAL)) {
-    chprintf((BaseSequentialStream*)&shell->stream, "%s$ ", shell->prompt);
-  } else {
-    chprintf((BaseSequentialStream*)&shell->stream, "%>$ ");
-  }
-
-  return;
-}
-
-/**
- * @brief   Interprete a escape sequence
- *
- * @param[in] seq   Character sequence to interprete.
- *                  Must be terminated by NUL byte.
- *
- * @return          A @p special_key value.
- */
-static special_key_t _interpreteEscapeSequence(const char seq[])
-{
-  // local variables
-  bool ambiguous = false;
-  int cmp = 0;
-
-  // TAB
-  /* not supported yet; use "\x09" instead */
-
-  // BACKSPACE
-  /* not supported yet; use "\x08" instead */
-
-  // ESCAPE
-  cmp = strcmp(seq, "\x1B");
-  if (cmp == 0) {
-    return KEY_ESCAPE;
-  } else {
-    ambiguous |= (cmp < 0);
-  }
-
-  // INSERT
-  cmp = strcmp(seq, "\x1B\x5B\x32\x7E");
-  if (cmp == 0) {
-    return KEY_INSERT;
-  } else {
-    ambiguous |= (cmp < 0);
-  }
-
-  // DELETE
-  cmp = strcmp(seq, "\x1B\x5B\x33\x7E");
-  if (cmp == 0) {
-    return KEY_DELETE;
-  } else {
-    ambiguous |= (cmp < 0);
-  }
-
-  // HOME
-  cmp = strcmp(seq, "\x1B\x4F\x48");
-  if (cmp == 0) {
-    return KEY_HOME;
-  } else {
-    ambiguous |= (cmp < 0);
-  }
-
-  // END
-  cmp = strcmp(seq, "\x1B\x4F\x46");
-  if (cmp == 0) {
-    return KEY_END;
-  } else {
-    ambiguous |= (cmp < 0);
-  }
-
-  // PAGE UP
-  cmp = strcmp(seq, "\x1B\x5B\x35\x7E");
-  if (cmp == 0) {
-    return KEY_PAGE_UP;
-  } else {
-    ambiguous |= (cmp < 0);
-  }
-
-  // PAGE DOWN
-  cmp = strcmp(seq, "\x1B\x5B\x36\x7E");
-  if (cmp == 0) {
-    return KEY_PAGE_DOWN;
-  } else {
-    ambiguous |= (cmp < 0);
-  }
-
-  // ARROW UP
-  cmp = strcmp(seq, "\x1B\x5B\x41");
-  if (cmp == 0) {
-    return KEY_ARROW_UP;
-  } else {
-    ambiguous |= (cmp < 0);
-  }
-
-  // ARROW DOWN
-  cmp = strcmp(seq, "\x1B\x5B\x42");
-  if (cmp == 0) {
-    return KEY_ARROW_DOWN;
-  } else {
-    ambiguous |= (cmp < 0);
-  }
-
-  // ARROW LEFT
-  cmp = strcmp(seq, "\x1B\x5B\x44");
-  if (cmp == 0) {
-    return KEY_ARROW_LEFT;
-  } else {
-    ambiguous |= (cmp < 0);
-  }
-
-  // ARROW RIGHT
-  cmp = strcmp(seq, "\x1B\x5B\x43");
-  if (cmp == 0) {
-    return KEY_ARROW_RIGHT;
-  } else {
-    ambiguous |= (cmp < 0);
-  }
-
-  return ambiguous ? KEY_AMBIGUOUS : KEY_UNKNOWN;
-}
-
-/**
- * @brief   Move the cursor in the terminal
- *
- * @param[in] shell   Pointer to the shell object.
- * @param[in] from    Starting position of the cursor.
- * @param[in] to      Target position to move the cursor to.
- *
- * @return            The number of positions moved.
- */
-static int _moveCursor(aos_shell_t* shell, const size_t from, const size_t to)
-{
-  aosDbgCheck(shell != NULL);
-
-  // local variables
-  size_t pos = from;
-
-  // move cursor left by printing backspaces
-  while (pos > to) {
-    streamPut(&shell->stream, '\b');
-    --pos;
-  }
-
-  // move cursor right by printing line content
-  while (pos < to) {
-    streamPut(&shell->stream, shell->line[pos]);
-    ++pos;
-  }
-
-  return (int)pos - (int)from;
-}
-
-/**
- * @brief   Print content of the shell line
- *
- * @param[in] shell   Pointer to the shell object.
- * @param[in] from    First position to start printing from.
- * @param[in] to      Position after the last character to print.
- *
- * @return            Number of characters printed.
- */
-static inline size_t _printLine(aos_shell_t* shell, const size_t from, const size_t to)
-{
-  aosDbgCheck(shell != NULL);
-
-  // local variables
-  size_t cnt;
-
-  for (cnt = 0; from + cnt < to; ++cnt) {
-    streamPut(&shell->stream, shell->line[from + cnt]);
-  }
-
-  return cnt;
-}
-
-/**
- * @brief   Compare two characters.
- *
- * @param[in] lhs       First character to compare.
- * @param[in] rhs       Second character to compare.
- *
- * @return              How well the characters match.
- */
-static inline charmatch_t _charcmp(char lhs, char rhs)
-{
-  // if lhs is a upper case letter and rhs is a lower case letter
-  if (lhs >= 'A' && lhs <= 'Z' && rhs >= 'a' && rhs <= 'z') {
-    return (lhs == (rhs - 'a' + 'A')) ? CHAR_MATCH_NCASE : CHAR_MATCH_NOT;
-  }
-  // if lhs is a lower case letter and rhs is a upper case letter
-  else if (lhs >= 'a' && lhs <= 'z' && rhs >= 'A' && rhs <= 'Z') {
-    return ((lhs - 'a' + 'A') == rhs) ? CHAR_MATCH_NCASE : CHAR_MATCH_NOT;
-  }
-  // default
-  else {
-    return (lhs == rhs) ? CHAR_MATCH_CASE : CHAR_MATCH_NOT;
-  }
-}
-
-/**
- * @brief   Maps an character from ASCII to a modified custom encoding.
- * @details The custom character encoding is very similar to ASCII and has the following structure:
- *          0x00=NULL ... 0x40='@' (identically to ASCII)
- *          0x4A='a'; 0x4B='A'; 0x4C='b'; 0x4D='B' ... 0x73='z'; 0x74='Z' (custom letter order)
- *          0x75='[' ... 0x7A='`' (0x5B..0x60 is ASCII)
- *          0x7B='{' ... 0x7F=DEL (identically to ASCII)
- *
- * @param[in] c   Character to map to the custom encoding.
- *
- * @return    The customly encoded character.
- */
-static inline char _mapAscii2Custom(const char c)
-{
-  if (c >= 'A' && c <= 'Z') {
-    return ((c - 'A') * 2) + 'A' + 1;
-  } else if (c > 'Z' && c < 'a') {
-    return c + ('z' - 'a') + 1;
-  } else if (c >= 'a' && c <= 'z') {
-    return ((c - 'a') * 2) + 'A';
-  } else {
-    return c;
-  }
-}
-
-/**
- * @brief   Compares two strings wrt letter case.
- * @details Comparisson uses a custom character encoding or mapping.
- *          See @p _mapAscii2Custom for details.
- *
- * @param[in] str1    First string to compare.
- * @param[in] str2    Second string to compare.
- * @param[in] cs      Flag indicating whether comparison shall be case sensitive.
- * @param[in,out] n   Maximum number of character to compare (in) and number of matching characters (out).
- *                    If a null pointer is specified, this parameter is ignored.
- *                    If the value pointed to is zero, comarison will not be limited.
- * @param[out] m      Optional indicator whether there was at least one case mismatch.
- *
- * @return      Integer value indicating the relationship between the strings.
- * @retval <0   The first character that does not match has a lower value in str1 than in str2.
- * @retval  0   The contents of both strings are equal.
- * @retval >0   The first character that does not match has a greater value in str1 than in str2.
- */
-static int _strccmp(const char *str1, const char *str2, bool cs, size_t* n, charmatch_t* m)
-{
-  aosDbgCheck(str1 != NULL);
-  aosDbgCheck(str2 != NULL);
-
-  // initialize variables
-  if (m) {
-    *m = CHAR_MATCH_NOT;
-  }
-  size_t i = 0;
-
-  // iterate through the strings
-  while ((n == NULL) || (*n == 0) || (*n > 0 && i < *n)) {
-    // break on NUL
-    if (str1[i] == '\0' || str2[i] == '\0') {
-      if (n) {
-        *n = i;
-      }
-      break;
-    }
-    // compare character
-    const charmatch_t match = _charcmp(str1[i], str2[i]);
-    if ((match == CHAR_MATCH_CASE) || (!cs && match == CHAR_MATCH_NCASE)) {
-      if (m != NULL && *m != CHAR_MATCH_NCASE) {
-        *m = match;
-      }
-      ++i;
-    } else {
-      if (n) {
-        *n = i;
-      }
-      break;
-    }
-  }
-
-  return _mapAscii2Custom(str1[i]) - _mapAscii2Custom(str2[i]);
-}
-
-static aos_status_t _readChannel(aos_shell_t* shell, AosShellChannel* channel, size_t* n)
-{
-  aosDbgCheck(shell != NULL);
-  aosDbgCheck(channel != NULL);
-  aosDbgCheck(n != NULL);
-
-  // local variables
-  aos_shellaction_t action = AOS_SHELL_ACTION_NONE;
-  char c;
-  special_key_t key;
-
-  // initialize output variables
-  *n = 0;
-
-  // read character by character from the channel
-  while (chnReadTimeout(channel, (uint8_t*)&c, 1, TIME_IMMEDIATE)) {
-    key = KEY_UNKNOWN;
-
-    // parse escape sequence
-    if (shell->inputdata.escp > 0) {
-      shell->inputdata.escseq[shell->inputdata.escp] = c;
-      ++shell->inputdata.escp;
-      key = _interpreteEscapeSequence(shell->inputdata.escseq);
-      if (key == KEY_AMBIGUOUS) {
-        // read next byte to resolve ambiguity
-        continue;
-      } else {
-        /*
-         * If the escape sequence could either be parsed sucessfully
-         * or there is no match (KEY_UNKNOWN),
-         * reset the sequence variable and interprete key/character
-         */
-        shell->inputdata.escp = 0;
-        memset(shell->inputdata.escseq, '\0', sizeof(shell->inputdata.escseq)*sizeof(shell->inputdata.escseq[0]));
-      }
-    }
-
-    /* interprete keys or character */
-    {
-      // default
-      action = AOS_SHELL_ACTION_NONE;
-
-      // printable character
-      if (key == KEY_UNKNOWN && c >= '\x20' && c <= '\x7E') {
-        action = AOS_SHELL_ACTION_READCHAR;
-      }
-
-      // tab key or character
-      else if (key == KEY_TAB || c == '\x09') {
-        /*
-         * pressing tab once applies auto fill
-         * pressing tab a second time prints suggestions
-         */
-        if (shell->inputdata.lastaction == AOS_SHELL_ACTION_AUTOFILL || shell->inputdata.lastaction == AOS_SHELL_ACTION_SUGGEST) {
-          action = AOS_SHELL_ACTION_SUGGEST;
-        } else {
-          action = AOS_SHELL_ACTION_AUTOFILL;
-        }
-      }
-
-      // INS key
-      else if (key == KEY_INSERT) {
-        action = AOS_SHELL_ACTION_INSERTTOGGLE;
-      }
-
-      // DEL key or character
-      else if (key == KEY_DELETE || c == '\x7F') {
-        // ignore if cursor is at very right
-        if (shell->inputdata.cursorpos < shell->inputdata.lineend) {
-          action = AOS_SHELL_ACTION_DELETEFORWARD;
-        }
-      }
-
-      // backspace key or character
-      else if (key == KEY_BACKSPACE || c == '\x08') {
-        // ignore if cursor is at very left
-        if (shell->inputdata.cursorpos > 0) {
-          action = AOS_SHELL_ACTION_DELETEBACKWARD;
-        }
-      }
-
-      // 'page up' of 'arrow up' key
-      else if (key == KEY_PAGE_UP || key == KEY_ARROW_UP) {
-        // ignore if there was some input
-        if (shell->inputdata.noinput) {
-          action = AOS_SHELL_ACTION_RECALLLAST;
-        }
-      }
-
-      // 'page down' key, 'arrow done' key, 'end of test' character or 'end of transmission' character
-      else if (key == KEY_PAGE_DOWN || key == KEY_ARROW_DOWN || c == '\x03' || c == '\x03') {
-        // ignore if line is empty
-        if (shell->inputdata.lineend > 0) {
-          action = AOS_SHELL_ACTION_CLEAR;
-        }
-      }
-
-      // 'home' key
-      else if (key == KEY_HOME) {
-        // ignore if cursor is very left
-        if (shell->inputdata.cursorpos > 0) {
-          action = AOS_SHELL_ACTION_CURSOR2START;
-        }
-      }
-
-      // 'end' key
-      else if (key == KEY_END) {
-        // ignore if cursos is very right
-        if (shell->inputdata.cursorpos < shell->inputdata.lineend) {
-          action = AOS_SHELL_ACTION_CURSOR2END;
-        }
-      }
-
-      // 'arrow left' key
-      else if (key == KEY_ARROW_LEFT) {
-        // ignore if cursor is very left
-        if (shell->inputdata.cursorpos > 0) {
-          action = AOS_SHELL_ACTION_CURSORLEFT;
-        }
-      }
-
-      // 'arrow right' key
-      else if (key == KEY_ARROW_RIGHT) {
-        // irgnore if cursor is very right
-        if (shell->inputdata.cursorpos < shell->inputdata.lineend) {
-          action = AOS_SHELL_ACTION_CURSORRIGHT;
-        }
-      }
-
-      // carriage return ('\r') or line feed ('\n') character
-      else if (c == '\x0D' || c == '\x0A') {
-        action = AOS_SHELL_ACTION_EXECUTE;
-      }
-
-      // ESC key or [ESCAPE] character
-      else if (key == KEY_ESCAPE || c == '\x1B') {
-        action = AOS_SHELL_ACTION_ESCSTART;
-      }
-    }
-
-    /* handle function */
-    switch (action) {
-      case AOS_SHELL_ACTION_READCHAR:
-      {
-        // line is full
-        if (shell->inputdata.lineend + 1 >= shell->linesize) {
-          _moveCursor(shell, shell->inputdata.cursorpos, shell->inputdata.lineend);
-          chprintf((BaseSequentialStream*)&shell->stream, "\n\tmaximum line width reached\n");
-          _printPrompt(shell);
-          _printLine(shell, 0, shell->inputdata.lineend);
-          _moveCursor(shell, shell->inputdata.lineend, shell->inputdata.cursorpos);
-        }
-        // read character
-        else {
-          // clear old line content on first input
-          if (shell->inputdata.noinput) {
-            memset(shell->line, '\0', shell->linesize);
-            shell->inputdata.noinput = false;
-          }
-          // overwrite content
-          if (shell->config & AOS_SHELL_CONFIG_INPUT_OVERWRITE) {
-            shell->line[shell->inputdata.cursorpos] = c;
-            ++shell->inputdata.cursorpos;
-            shell->inputdata.lineend = (shell->inputdata.cursorpos > shell->inputdata.lineend) ? shell->inputdata.cursorpos : shell->inputdata.lineend;
-            streamPut(&shell->stream, (uint8_t)c);
-          }
-          // insert character
-          else {
-            memmove(&(shell->line[shell->inputdata.cursorpos+1]), &(shell->line[shell->inputdata.cursorpos]), shell->inputdata.lineend - shell->inputdata.cursorpos);
-            shell->line[shell->inputdata.cursorpos] = c;
-            ++shell->inputdata.lineend;
-            _printLine(shell, shell->inputdata.cursorpos, shell->inputdata.lineend);
-            ++shell->inputdata.cursorpos;
-            _moveCursor(shell, shell->inputdata.lineend, shell->inputdata.cursorpos);
-          }
-        }
-        break;
-      }
-
-      case AOS_SHELL_ACTION_AUTOFILL:
-      {
-        const char* fill = shell->line;
-        size_t cmatch = shell->inputdata.cursorpos;
-        charmatch_t matchlevel = CHAR_MATCH_NOT;
-        size_t n;
-        // iterate through command list
-        for (aos_shellcommand_t* cmd = shell->commands; cmd != NULL; cmd = cmd->next) {
-          // compare current match with command
-          n = cmatch;
-          charmatch_t mlvl = CHAR_MATCH_NOT;
-          _strccmp(fill, cmd->name, shell->config & AOS_SHELL_CONFIG_MATCH_CASE, (n == 0) ? NULL : &n, &mlvl);
-          const int cmp = (n < cmatch) ?
-                            (n - cmatch) :
-                            (cmd->name[n] != '\0') ?
-                              strlen(cmd->name) - n :
-                              0;
-          // if an exact match was found
-          if (cmatch + cmp == shell->inputdata.cursorpos) {
-            cmatch = shell->inputdata.cursorpos;
-            fill = cmd->name;
-            // break the loop only if there are no case mismatches with the input
-            n = shell->inputdata.cursorpos;
-            _strccmp(fill, shell->line, false, &n, &mlvl);
-            if (mlvl == CHAR_MATCH_CASE) {
-              break;
-            }
-          }
-          // if a not exact match was found
-          else if (cmatch + cmp > shell->inputdata.cursorpos) {
-            // if this is the first one
-            if (fill == shell->line) {
-              cmatch += cmp;
-              fill = cmd->name;
-            }
-            // if this is a worse one
-            else if ((cmp < 0) || (cmp == 0 && mlvl == CHAR_MATCH_CASE)) {
-              cmatch += cmp;
-            }
-          }
-          // non matching commands are ignored
-          else {}
-        }
-        // evaluate if there are case mismatches
-        n = cmatch;
-        _strccmp(shell->line, fill, shell->config & AOS_SHELL_CONFIG_MATCH_CASE, &n, &matchlevel);
-        // print the auto fill if any
-        if (cmatch > shell->inputdata.cursorpos || (cmatch == shell->inputdata.cursorpos && matchlevel == CHAR_MATCH_NCASE)) {
-          shell->inputdata.noinput = false;
-          // limit auto fill so it will not overflow the line width
-          if (shell->inputdata.lineend + (cmatch - shell->inputdata.cursorpos) > shell->linesize) {
-            cmatch = shell->linesize - shell->inputdata.lineend + shell->inputdata.cursorpos;
-          }
-          // move trailing memory further in the line
-          memmove(&(shell->line[cmatch]), &(shell->line[shell->inputdata.cursorpos]), shell->inputdata.lineend - shell->inputdata.cursorpos);
-          shell->inputdata.lineend += cmatch - shell->inputdata.cursorpos;
-          // if there was no incorrect case when matching
-          if (matchlevel == CHAR_MATCH_CASE) {
-            // insert fill command name to line
-            memcpy(&(shell->line[shell->inputdata.cursorpos]), &(fill[shell->inputdata.cursorpos]), cmatch - shell->inputdata.cursorpos);
-            // print the output
-            _printLine(shell, shell->inputdata.cursorpos, shell->inputdata.lineend);
-          } else {
-            // overwrite line with fill command name
-            memcpy(shell->line, fill, cmatch);
-            // reprint the whole line
-            _moveCursor(shell, shell->inputdata.cursorpos, 0);
-            _printLine(shell, 0, shell->inputdata.lineend);
-          }
-          // move cursor to the end of the matching sequence
-          shell->inputdata.cursorpos = cmatch;
-          _moveCursor(shell, shell->inputdata.lineend, shell->inputdata.cursorpos);
-        }
-        break;
-      }
-
-      case AOS_SHELL_ACTION_SUGGEST:
-      {
-        unsigned int matches = 0;
-        // iterate through command list
-        for (aos_shellcommand_t* cmd = shell->commands; cmd != NULL; cmd = cmd->next) {
-          // compare line content with command, excpet if cursorpos=0
-          size_t i = shell->inputdata.cursorpos;
-          if (shell->inputdata.cursorpos > 0) {
-            _strccmp(shell->line, cmd->name, true, &i, NULL);
-          }
-          const int cmp = (i < shell->inputdata.cursorpos) ?
-                            (i - shell->inputdata.cursorpos) :
-                            (cmd->name[i] != '\0') ?
-                              strlen(cmd->name) - i :
-                              0;
-          // if a match was found
-          if (cmp > 0) {
-            // if this is the first one
-            if (matches == 0) {
-              _moveCursor(shell, shell->inputdata.cursorpos, shell->inputdata.lineend);
-              streamPut(&shell->stream, '\n');
-            }
-            // print the command
-            chprintf((BaseSequentialStream*)&shell->stream, "\t%s\n", cmd->name);
-            ++matches;
-          }
-        }
-        // reprint the prompt and line if any matches have been found
-        if (matches > 0) {
-          _printPrompt(shell);
-          _printLine(shell, 0, shell->inputdata.lineend);
-          _moveCursor(shell, shell->inputdata.lineend, shell->inputdata.cursorpos);
-          shell->inputdata.noinput = false;
-        }
-        break;
-      }
-
-      case AOS_SHELL_ACTION_INSERTTOGGLE:
-      {
-        if (shell->config & AOS_SHELL_CONFIG_INPUT_OVERWRITE) {
-          shell->config &= ~AOS_SHELL_CONFIG_INPUT_OVERWRITE;
-        } else {
-          shell->config |= AOS_SHELL_CONFIG_INPUT_OVERWRITE;
-        }
-        break;
-      }
-
-      case AOS_SHELL_ACTION_DELETEFORWARD:
-      {
-        --shell->inputdata.lineend;
-        memmove(&(shell->line[shell->inputdata.cursorpos]), &(shell->line[shell->inputdata.cursorpos+1]), shell->inputdata.lineend - shell->inputdata.cursorpos);
-        _printLine(shell, shell->inputdata.cursorpos, shell->inputdata.lineend);
-        streamPut(&shell->stream, ' ');
-        _moveCursor(shell, shell->inputdata.lineend + 1, shell->inputdata.cursorpos);
-        break;
-      }
-
-      case AOS_SHELL_ACTION_DELETEBACKWARD:
-      {
-        --shell->inputdata.cursorpos;
-        memmove(&(shell->line[shell->inputdata.cursorpos]), &(shell->line[shell->inputdata.cursorpos+1]), shell->inputdata.lineend - shell->inputdata.cursorpos);
-        --shell->inputdata.lineend;
-        shell->line[shell->inputdata.lineend] = '\0';
-        _moveCursor(shell, shell->inputdata.cursorpos + 1, shell->inputdata.cursorpos);
-        _printLine(shell, shell->inputdata.cursorpos, shell->inputdata.lineend);
-        streamPut(&shell->stream, ' ');
-        _moveCursor(shell, shell->inputdata.lineend+1, shell->inputdata.cursorpos);
-        break;
-      }
-
-      case AOS_SHELL_ACTION_RECALLLAST:
-      {
-        // replace any intermediate NUL bytes with spaces
-        shell->inputdata.lineend = 0;
-        size_t nul_start = 0;
-        size_t nul_end = 0;
-        // search line for a NUL byte
-        while (nul_start < shell->linesize) {
-          if (shell->line[nul_start] == '\0') {
-            nul_end = nul_start + 1;
-            // keep searcjing for a byte that is not NUL
-            while (nul_end < shell->linesize) {
-              if (shell->line[nul_end] != '\0') {
-                // an intermediate NUL sequence was found
-                memset(&(shell->line[nul_start]), ' ', nul_end - nul_start);
-                shell->inputdata.lineend = nul_end + 1;
-                break;
-              } else {
-                ++nul_end;
-              }
-            }
-            nul_start = nul_end + 1;
-          } else {
-            ++shell->inputdata.lineend;
-            ++nul_start;
-          }
-        }
-        shell->inputdata.cursorpos = shell->inputdata.lineend;
-        // print the line
-        shell->inputdata.noinput = _printLine(shell, 0, shell->inputdata.lineend) == 0;
-        break;
-      }
-
-      case AOS_SHELL_ACTION_CLEAR:
-      {
-        // clear output
-        _moveCursor(shell, shell->inputdata.cursorpos, 0);
-        for (shell->inputdata.cursorpos = 0; shell->inputdata.cursorpos < shell->inputdata.lineend; ++shell->inputdata.cursorpos) {
-          streamPut(&shell->stream, ' ');
-        }
-        _moveCursor(shell, shell->inputdata.lineend, 0);
-        shell->inputdata.cursorpos = 0;
-        shell->inputdata.lineend = 0;
-        shell->inputdata.noinput = true;
-        break;
-      }
-
-      case AOS_SHELL_ACTION_CURSOR2START:
-      {
-        _moveCursor(shell, shell->inputdata.cursorpos, 0);
-        shell->inputdata.cursorpos = 0;
-        break;
-      }
-
-      case AOS_SHELL_ACTION_CURSOR2END:
-      {
-        _moveCursor(shell, shell->inputdata.cursorpos, shell->inputdata.lineend);
-        shell->inputdata.cursorpos = shell->inputdata.lineend;
-        break;
-      }
-
-      case AOS_SHELL_ACTION_CURSORLEFT:
-      {
-        _moveCursor(shell, shell->inputdata.cursorpos, shell->inputdata.cursorpos-1);
-        --shell->inputdata.cursorpos;
-        break;
-      }
-
-      case AOS_SHELL_ACTION_CURSORRIGHT:
-      {
-        _moveCursor(shell, shell->inputdata.cursorpos, shell->inputdata.cursorpos+1);
-        ++shell->inputdata.cursorpos;
-        break;
-      }
-
-      case AOS_SHELL_ACTION_EXECUTE:
-      {
-        streamPut(&shell->stream, '\n');
-        // set the number of read bytes and return
-        if (!shell->inputdata.noinput) {
-          *n = shell->linesize - shell->inputdata.lineend;
-          // fill the remainder of the line with NUL bytes
-          memset(&(shell->line[shell->inputdata.lineend]), '\0', *n);
-          // reset static variables
-          shell->inputdata.noinput = true;
-        }
-        return AOS_SUCCESS;
-        break;
-      }
-
-      case AOS_SHELL_ACTION_ESCSTART:
-      {
-        shell->inputdata.escseq[0] = c;
-        ++shell->inputdata.escp;
-        break;
-      }
-
-      case AOS_SHELL_ACTION_NONE:
-      default:
-      {
-        // do nothing (ignore input) and read next byte
-        continue;
-        break;
-      }
-    } /* end of switch */
-
-    shell->inputdata.lastaction = action;
-  } /* end of while */
-
-  // no more data could be read from the channel
-  return AOS_WARNING;
-}
-
-/**
- * @brief   Parses the content of the input buffer (line) to separate arguments.
- *
- * @param[in] shell   Pointer to the shell object.
- *
- * @return            Number of arguments found.
- */
-static size_t _parseArguments(aos_shell_t* shell)
-{
-  aosDbgCheck(shell != NULL);
-
-  /*
-   * States for a very small FSM.
-   */
-  typedef enum {
-    START,
-    SPACE,
-    TEXT,
-    END,
-  } state_t;
-
-  // local variables
-  state_t state = START;
-  size_t arg = 0;
-
-  // iterate through the line
-  for (char* c = shell->line; c < shell->line + shell->linesize; ++c) {
-    // terminate at first NUL byte
-    if (*c == '\0') {
-      state = END;
-      break;
-    }
-    // spaces become NUL bytes
-    else if (*c == ' ') {
-      *c = '\0';
-      state = SPACE;
-    }
-    // handle non-NUL bytes
-    else {
-      switch (state) {
-        case START:
-        case SPACE:
-          // ignore too many arguments
-          if (arg < shell->arglistsize) {
-            shell->arglist[arg] = c;
-          }
-          ++arg;
-          break;
-        case TEXT:
-        case END:
-        default:
-          break;
-      }
-      state = TEXT;
-    }
-  }
-
-  // set all remaining argument pointers to NULL
-  for (size_t a = arg; a < shell->arglistsize; ++a) {
-    shell->arglist[a] = NULL;
-  }
-
-  return arg;
-}
-
-/**
- * @brief   Initializes a shell object with the specified parameters.
- *
- * @param[in] shell         Pointer to the shell object.
- * @param[in] stream        I/O stream to use.
- * @param[in] prompt        Prompt line to print (NULL = use default prompt).
- * @param[in] line          Pointer to the input buffer.
- * @param[in] linesize      Size of the input buffer.
- * @param[in] arglist       Pointer to the argument buffer.
- * @param[in] arglistsize   Size of te argument buffer.
- */
-void aosShellInit(aos_shell_t* shell, event_source_t* oseventsource,  const char* prompt, char* line, size_t linesize, char** arglist, size_t arglistsize)
-{
-  aosDbgCheck(shell != NULL);
-  aosDbgCheck(oseventsource != NULL);
-  aosDbgCheck(line != NULL);
-  aosDbgCheck(arglist != NULL);
-
-  // set parameters
-  shell->thread = NULL;
-  chEvtObjectInit(&shell->eventSource);
-  shell->os.eventSource = oseventsource;
-  aosShellStreamInit(&shell->stream);
-  shell->prompt = prompt;
-  shell->commands = NULL;
-  shell->execstatus.command = NULL;
-  shell->execstatus.retval = 0;
-  shell->line = line;
-  shell->linesize = linesize;
-  shell->inputdata.lastaction = AOS_SHELL_ACTION_NONE;
-  shell->inputdata.escp = 0;
-  memset(shell->inputdata.escseq, '\0', sizeof(shell->inputdata.escseq)*sizeof(shell->inputdata.escseq[0]));
-  shell->inputdata.cursorpos = 0;
-  shell->inputdata.lineend = 0;
-  shell->inputdata.noinput = true;
-  shell->arglist = arglist;
-  shell->arglistsize = arglistsize;
-  shell->config = 0x00;
-
-  // initialize arrays
-  memset(shell->line, '\0', shell->linesize);
-  for (size_t a = 0; a < shell->arglistsize; ++a) {
-    shell->arglist[a] = NULL;
-  }
-
-  return;
-}
-
-/**
- * @brief   Initialize an AosShellStream object.
- *
- * @param[in] stream  The AosShellStrem to initialize.
- */
-void aosShellStreamInit(AosShellStream* stream)
-{
-  aosDbgCheck(stream != NULL);
-
-  stream->vmt = &_streamvmt;
-  stream->channel = NULL;
-
-  return;
-}
-
-/**
- * @brief   Initialize an AosShellChannel object with the specified parameters.
- *
- * @param[in] channel       The AosShellChannel to initialize.
- * @param[in] asyncchannel  An BaseAsynchronousChannel this AosShellChannel is associated with.
- */
-void aosShellChannelInit(AosShellChannel* channel, BaseAsynchronousChannel* asyncchannel)
-{
-  aosDbgCheck(channel != NULL);
-  aosDbgCheck(asyncchannel != NULL);
-
-  channel->vmt = &_channelvmt;
-  channel->asyncchannel = asyncchannel;
-  channel->listener.wflags = 0;
-  channel->next = NULL;
-  channel->flags = 0;
-
-  return;
-}
-
-/**
- * @brief   Inserts a command to the shells list of commands.
- *
- * @param[in] shell   Pointer to the shell object.
- * @param[in] cmd     Pointer to the command to add.
- *
- * @return            A status value.
- * @retval AOS_SUCCESS  The command was added successfully.
- * @retval AOS_ERROR    Another command with identical name already exists.
- */
-aos_status_t aosShellAddCommand(aos_shell_t *shell, aos_shellcommand_t *cmd)
-{
-  aosDbgCheck(shell != NULL);
-  aosDbgCheck(cmd != NULL);
-  aosDbgCheck(cmd->name != NULL && strlen(cmd->name) > 0 && strchr(cmd->name, ' ') == NULL && strchr(cmd->name, '\t') == NULL);
-  aosDbgCheck(cmd->callback != NULL);
-  aosDbgCheck(cmd->next == NULL);
-
-  aos_shellcommand_t* prev = NULL;
-  aos_shellcommand_t** curr = &(shell->commands);
-
-  // insert the command to the list wrt lexographical order (exception: lower case characters preceed upper their uppercase counterparts)
-  while (*curr != NULL) {
-    // iterate through the list as long as the command names are 'smaller'
-    const int cmp = _strccmp((*curr)->name, cmd->name, true, NULL, NULL);
-    if (cmp < 0) {
-      prev = *curr;
-      curr = &((*curr)->next);
-      continue;
-    }
-    // error if the command already exists
-    else if (cmp == 0) {
-      return AOS_ERROR;
-    }
-    // insert the command as soon as a 'larger' name was found
-    else /* if (cmpval > 0) */ {
-      cmd->next = *curr;
-      // special case: the first command is larger
-      if (prev == NULL) {
-        shell->commands = cmd;
-      } else {
-        prev->next = cmd;
-      }
-      return AOS_SUCCESS;
-    }
-  }
-  // the end of the list has been reached
-
-  // append the command
-  *curr = cmd;
-  return AOS_SUCCESS;
-}
-
-/**
- * @brief   Removes a command from the shells list of commands.
- *
- * @param[in] shell     Pointer to the shell object.
- * @param[in] cmd       Name of the command to removde.
- * @param[out] removed  Optional pointer to the command that was removed.
- *
- * @return              A status value.
- * @retval AOS_SUCCESS  The command was removed successfully.
- * @retval AOS_ERROR    The command name was not found.
- */
-aos_status_t aosShellRemoveCommand(aos_shell_t *shell, char *cmd, aos_shellcommand_t **removed)
-{
-  aosDbgCheck(shell != NULL);
-  aosDbgCheck(cmd != NULL && strlen(cmd) > 0);
-
-  aos_shellcommand_t* prev = NULL;
-  aos_shellcommand_t** curr = &(shell->commands);
-
-  // iterate through the list and seach for the specified command name
-  while (curr != NULL) {
-    const int cmpval = strcmp((*curr)->name, cmd);
-    // iterate through the list as long as the command names are 'smaller'
-    if (cmpval < 0) {
-      prev = *curr;
-      curr = &((*curr)->next);
-      continue;
-    }
-    // remove the command when found
-    else if (cmpval == 0) {
-      // special case: the first command matches
-      if (prev == NULL) {
-        shell->commands = (*curr)->next;
-      } else {
-        prev->next = (*curr)->next;
-      }
-      (*curr)->next = NULL;
-      // set the optional output argument
-      if (removed != NULL) {
-        *removed = *curr;
-      }
-      return AOS_SUCCESS;
-    }
-    // break the loop if the command names are 'larger'
-    else /* if (cmpval > 0) */ {
-      break;
-    }
-  }
-
-  // if the command was not found, return an error
-  return AOS_ERROR;
-}
-
-/**
- * @brief   Add a channel to a AosShellStream.
- *
- * @param[in] stream    The AosShellStream to extend.
- * @param[in] channel   The channel to be added to the stream.
- */
-void aosShellStreamAddChannel(AosShellStream* stream, AosShellChannel* channel)
-{
-  aosDbgCheck(stream != NULL);
-  aosDbgCheck(channel != NULL && channel->asyncchannel != NULL && channel->next == NULL && (channel->flags & AOS_SHELLCHANNEL_ATTACHED) == 0);
-
-  // prepend the new channel
-  chSysLock();
-  channel->flags |= AOS_SHELLCHANNEL_ATTACHED;
-  channel->next = stream->channel;
-  stream->channel = channel;
-  chSysUnlock();
-
-  return;
-}
-
-/**
- * @brief   Remove a channel from an AosShellStream.
- *
- * @param[in] stream    The AosShellStream to modify.
- * @param[in] channel   The channel to remove.
- * @return
- */
-aos_status_t aosShellStreamRemoveChannel(AosShellStream* stream, AosShellChannel* channel)
-{
-  aosDbgCheck(stream != NULL);
-  aosDbgCheck(channel != NULL && channel->asyncchannel != NULL && channel->flags & AOS_SHELLCHANNEL_ATTACHED);
-
-  // local varibales
-  AosShellChannel* prev = NULL;
-  AosShellChannel* curr = stream->channel;
-
-  // iterate through the list and search for the specified channel
-  while (curr != NULL) {
-    // if the channel was found
-    if (curr == channel) {
-      chSysLock();
-      // special case: the first channel matches (prev is NULL)
-      if (prev == NULL) {
-        stream->channel = curr->next;
-      } else {
-        prev->next = channel->next;
-      }
-      curr->next = NULL;
-      curr->flags &= ~AOS_SHELLCHANNEL_ATTACHED;
-      chSysUnlock();
-      return AOS_SUCCESS;
-    }
-  }
-
-  // if the channel was not found, return an error
-  return AOS_ERROR;
-}
-
-/**
- * @brief   Enable a AosSheööChannel as input.
- *
- * @param[in] channel   The channel to enable as input.
- */
-void aosShellChannelInputEnable(AosShellChannel* channel)
-{
-  aosDbgCheck(channel != NULL && channel->asyncchannel != NULL);
-
-  chSysLock();
-  channel->listener.wflags |= CHN_INPUT_AVAILABLE;
-  channel->flags |= AOS_SHELLCHANNEL_INPUT_ENABLED;
-  chSysUnlock();
-
-  return;
-}
-
-/**
- * @brief   Disable a AosSheööChannel as input.
- *
- * @param[in] channel   The channel to disable as input.
- */
-void aosShellChannelInputDisable( AosShellChannel* channel)
-{
-  aosDbgCheck(channel != NULL && channel->asyncchannel != NULL);
-
-  chSysLock();
-  channel->listener.wflags &= ~CHN_INPUT_AVAILABLE;
-  channel->flags &= ~AOS_SHELLCHANNEL_INPUT_ENABLED;
-  chSysUnlock();
-
-  return;
-}
-
-/**
- * @brief   Enable a AosSheööChannel as output.
- *
- * @param[in] channel   The channel to enable as output.
- */
-void aosShellChannelOutputEnable(AosShellChannel* channel)
-{
-  aosDbgCheck(channel != NULL && channel->asyncchannel != NULL);
-
-  channel->flags |= AOS_SHELLCHANNEL_OUTPUT_ENABLED;
-
-  return;
-}
-
-/**
- * @brief   Disable a AosSheööChannel as output.
- *
- * @param[in] channel   The channel to disable as output.
- */
-void aosShellChannelOutputDisable(AosShellChannel* channel)
-{
-  aosDbgCheck(channel != NULL && channel->asyncchannel != NULL);
-
-  channel->flags &= ~AOS_SHELLCHANNEL_OUTPUT_ENABLED;
-
-  return;
-}
-
-/**
- * @brief   Thread main function.
- *
- * @param[in] aosShellThread    Name of the function;
- * @param[in] shell             Pointer to the shell object.
- */
-THD_FUNCTION(aosShellThread, shell)
-{
-  aosDbgCheck(shell != NULL);
-
-  // local variables
-  eventmask_t eventmask;
-  eventflags_t eventflags;
-  AosShellChannel* channel;
-  aos_status_t readeval;
-  size_t nchars = 0;
-  size_t nargs = 0;
-  aos_shellcommand_t* cmd;
-
-
-  // register OS related events
-  chEvtRegisterMask(((aos_shell_t*)shell)->os.eventSource, &(((aos_shell_t*)shell)->os.eventListener), AOS_SHELL_EVENTMASK_OS);
-  // register events to all input channels
-  for (channel = ((aos_shell_t*)shell)->stream.channel; channel != NULL; channel = channel->next) {
-    chEvtRegisterMaskWithFlags(&(channel->asyncchannel->event), &(channel->listener), AOS_SHELL_EVENTMASK_INPUT, channel->listener.wflags);
-  }
-
-  // fire start event
-  chEvtBroadcastFlags(&(((aos_shell_t*)shell)->eventSource), AOS_SHELL_EVTFLAG_START);
-
-  // print the prompt for the first time
-  _printPrompt((aos_shell_t*)shell);
-
-  // enter thread loop
-  while (!chThdShouldTerminateX()) {
-    // wait for event and handle it accordingly
-    eventmask = chEvtWaitOne(ALL_EVENTS);
-
-    // handle event
-    switch (eventmask) {
-
-      // OS related events
-      case AOS_SHELL_EVENTMASK_OS:
-      {
-        eventflags = chEvtGetAndClearFlags(&((aos_shell_t*)shell)->os.eventListener);
-        // handle shutdown/restart events
-        if (eventflags & AOS_SYSTEM_EVENTFLAGS_SHUTDOWN) {
-          chThdTerminate(((aos_shell_t*)shell)->thread);
-        } else {
-          // print an error message
-          chprintf((BaseSequentialStream*)&((aos_shell_t*)shell)->stream, "\nERROR: unknown OS event received (0x%08X)\n", eventflags);
-        }
-        break;
-      }
-
-      // input events
-      case AOS_SHELL_EVENTMASK_INPUT:
-      {
-        // check and handle all channels
-        channel = ((aos_shell_t*)shell)->stream.channel;
-        while (channel != NULL) {
-          eventflags = chEvtGetAndClearFlags(&channel->listener);
-          // if there is new input
-          if (eventflags & CHN_INPUT_AVAILABLE) {
-            // read input from channel
-            readeval = _readChannel((aos_shell_t*)shell, channel, &nchars);
-            // parse input line to argument list only if the input shall be executed
-            nargs = (readeval == AOS_SUCCESS && nchars > 0) ? _parseArguments((aos_shell_t*)shell) : 0;
-            // check number of arguments
-            if (nargs > ((aos_shell_t*)shell)->arglistsize) {
-              // error too many arguments
-              chprintf((BaseSequentialStream*)&((aos_shell_t*)shell)->stream, "\ttoo many arguments\n");
-            } else if (nargs > 0) {
-              // search command list for arg[0] and execute callback
-              cmd = ((aos_shell_t*)shell)->commands;
-              while (cmd != NULL) {
-                if (strcmp(((aos_shell_t*)shell)->arglist[0], cmd->name) == 0) {
-                  ((aos_shell_t*)shell)->execstatus.command = cmd;
-                  chEvtBroadcastFlags(&(((aos_shell_t*)shell)->eventSource), AOS_SHELL_EVTFLAG_EXEC);
-                  ((aos_shell_t*)shell)->execstatus.retval = cmd->callback((BaseSequentialStream*)&((aos_shell_t*)shell)->stream, nargs, ((aos_shell_t*)shell)->arglist);
-                  chEvtBroadcastFlags(&(((aos_shell_t*)shell)->eventSource), AOS_SHELL_EVTFLAG_DONE);
-                  // notify if the command was not successful
-                  if (((aos_shell_t*)shell)->execstatus.retval != 0) {
-                    chprintf((BaseSequentialStream*)&((aos_shell_t*)shell)->stream, "command returned exit status %d\n", ((aos_shell_t*)shell)->execstatus.retval);
-                  }
-                  break;
-                }
-                cmd = cmd->next;
-              } /* end of while */
-
-              // if no matching command was found, print an error
-              if (cmd == NULL) {
-                chprintf((BaseSequentialStream*)&((aos_shell_t*)shell)->stream, "%s: command not found\n", ((aos_shell_t*)shell)->arglist[0]);
-              }
-            }
-
-            // reset some internal variables and eprint a new prompt
-            if (readeval == AOS_SUCCESS && !chThdShouldTerminateX()) {
-              ((aos_shell_t*)shell)->inputdata.cursorpos = 0;
-              ((aos_shell_t*)shell)->inputdata.lineend = 0;
-              _printPrompt((aos_shell_t*)shell);
-            }
-          }
-
-          // iterate to next channel
-          channel = channel->next;
-        }
-        break;
-      }
-
-      // other events
-      default:
-      {
-        // print an error message
-        chprintf((BaseSequentialStream*)&((aos_shell_t*)shell)->stream, "\nSHELL: ERROR: unknown event received (0x%08X)\n", eventmask);
-        break;
-      }
-
-    } /* end of switch */
-
-  } /* end of while */
-
-  // fire event and exit the thread
-  chSysLock();
-  chEvtBroadcastFlagsI(&(((aos_shell_t*)shell)->eventSource), AOS_SHELL_EVTFLAG_EXIT);
-  chThdExitS(MSG_OK);
-  // no chSysUnlock() required since the thread has been terminated an all waiting threads have been woken up
-}
-
-#endif /* AMIROOS_CFG_SHELL_ENABLE == true */
-
-/** @} */
diff --git a/os/core/src/aos_system.c b/os/core/src/aos_system.c
deleted file mode 100644
index ff44afb..0000000
--- a/os/core/src/aos_system.c
+++ /dev/null
@@ -1,1048 +0,0 @@
-/*
-AMiRo-OS is an operating system designed for the Autonomous Mini Robot (AMiRo) platform.
-Copyright (C) 2016..2018  Thomas Schöpping et al.
-
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program.  If not, see <http://www.gnu.org/licenses/>.
-*/
-
-/**
- * @file    aos_system.c
- * @brief   System code.
- * @details Contains system initialization and shutdown routines
- *          and system shell commands.
- *
- * @addtogroup aos_system
- * @{
- */
-
-#include <aos_system.h>
-
-#include <amiroos.h>
-#include <amiroblt.h>
-#include <module.h>
-#include <string.h>
-#include <stdlib.h>
-#if (AMIROOS_CFG_TESTS_ENABLE == true)
-#include <ch_test.h>
-#include <rt_test_root.h>
-#endif
-
-/**
- * @brief   Period of the system timer.
- */
-#define SYSTIMER_PERIOD               (TIME_MAX_SYSTIME - CH_CFG_ST_TIMEDELTA)
-
-/**
- * @brief   Width of the printable system info text.
- */
-#define SYSTEM_INFO_WIDTH             70
-
-/**
- * @brief   Width of the name column of the system info table.
- */
-#define SYSTEM_INFO_NAMEWIDTH         14
-
-/* forward declarations */
-static void _printSystemInfo(BaseSequentialStream* stream);
-#if (AMIROOS_CFG_SHELL_ENABLE == true)
-static int _shellcmd_configcb(BaseSequentialStream* stream, int argc, char* argv[]);
-static int _shellcmd_infocb(BaseSequentialStream* stream, int argc, char* argv[]);
-static int _shellcmd_shutdowncb(BaseSequentialStream* stream, int argc, char* argv[]);
-#endif /* AMIROOS_CFG_SHELL_ENABLE == true */
-#if (AMIROOS_CFG_TESTS_ENABLE == true)
-static int _shellcmd_kerneltestcb(BaseSequentialStream* stream, int argc, char* argv[]);
-#endif /* AMIROOS_CFG_TESTS_ENABLE == true */
-
-/**
- * @brief   Timer to accumulate system uptime.
- */
-static virtual_timer_t _systimer;
-
-/**
- * @brief   Accumulated system uptime.
- */
-static aos_timestamp_t _uptime;
-
-/**
- * @brief   Timer register value of last accumulation.
- */
-static systime_t _synctime;
-
-#if (AMIROOS_CFG_SSSP_MASTER == true) || defined(__DOXYGEN__)
-/**
- * @brief   Timer to drive the SYS_SYNC signal for system wide time synchronization according to SSSP.
- */
-static virtual_timer_t _syssynctimer;
-
-/**
- * @brief   Last uptime of system wide time synchronization.
- */
-static aos_timestamp_t _syssynctime;
-#endif
-
-#if ((AMIROOS_CFG_SSSP_MASTER != true) && (AMIROOS_CFG_PROFILE == true)) || defined(__DOXYGEN__)
-/**
- * @brief   Offset between local clock and system wide synchronization signal.
- */
-static float _syssyncskew;
-
-/**
- * @brief   Weighting factor for the low-pass filter used for calculating the @p _syssyncskew value.
- */
-#define SYSTEM_SYSSYNCSKEW_LPFACTOR   (0.1f / AOS_SYSTEM_TIME_RESOLUTION)
-#endif
-
-#if (AMIROOS_CFG_SHELL_ENABLE == true) || defined(__DOXYGEN__)
-/**
- * @brief   Shell thread working area.
- */
-THD_WORKING_AREA(_shell_wa, AMIROOS_CFG_SHELL_STACKSIZE);
-
-/**
- * @brief   Shell input buffer.
- */
-static char _shell_line[AMIROOS_CFG_SHELL_LINEWIDTH];
-
-/**
- * @brief   Shell argument buffer.
- */
-static char* _shell_arglist[AMIROOS_CFG_SHELL_MAXARGS];
-
-/**
- * @brief   Shell command to retrieve system information.
- */
-static aos_shellcommand_t _shellcmd_info = {
-  /* name     */ "module:info",
-  /* callback */ _shellcmd_infocb,
-  /* next     */ NULL,
-};
-
-/**
- * @brief   Shell command to set or retrieve system configuration.
- */
-static aos_shellcommand_t _shellcmd_config = {
-  /* name     */ "module:config",
-  /* callback */ _shellcmd_configcb,
-  /* next     */ NULL,
-};
-
-/**
- * @brief   Shell command to shutdown the system.
- */
-static aos_shellcommand_t _shellcmd_shutdown = {
-  /* name     */ "system:shutdown",
-  /* callback */ _shellcmd_shutdowncb,
-  /* next     */ NULL,
-};
-#endif /* AMIROOS_CFG_SHELL_ENABLE == true */
-
-#if (AMIROOS_CFG_TESTS_ENABLE == true) || defined(__DOXYGEN__)
-/**
- * @brief   Shell kommand to run a test of the ChibiOS/RT kernel.
- */
-static aos_shellcommand_t _shellcmd_kerneltest = {
-  /* name     */ "kernel:test",
-  /* callback */ _shellcmd_kerneltestcb,
-  /* next     */ NULL,
-};
-#endif /* AMIROOS_CFG_TESTS_ENABLE == true */
-
-/**
- * @brief   Global system object.
- */
-aos_system_t aos;
-
-/**
- * @brief   Print a separator line.
- *
- * @param[in] stream    Stream to print to or NULL to print to all system streams.
- * @param[in] c         Character to use.
- * @param[in] n         Length of the separator line.
- *
- * @return  Number of characters printed.
- */
-static unsigned int _printSystemInfoSeparator(BaseSequentialStream* stream, const char c, const unsigned int n)
-{
-  aosDbgCheck(stream != NULL);
-
-  // print the specified character n times
-  for (unsigned int i = 0; i < n; ++i) {
-    streamPut(stream, c);
-  }
-  streamPut(stream, '\n');
-
-  return n+1;
-}
-
-/**
- * @brief   Print a system information line.
- * @details Prints a system information line with the following format:
- *            "<name>[spaces]fmt"
- *          The combined width of "<name>[spaces]" can be specified in order to align <fmt> on multiple lines.
- *          Note that there is not trailing newline added implicitely.
- *
- * @param[in] stream      Stream to print to or NULL to print to all system streams.
- * @param[in] name        Name of the entry/line.
- * @param[in] namewidth   Width of the name column.
- * @param[in] fmt         Formatted string of information content.
- *
- * @return  Number of characters printed.
- */
-static unsigned int _printSystemInfoLine(BaseSequentialStream* stream, const char* name, const unsigned int namewidth, const char* fmt, ...)
-{
-  aosDbgCheck(stream != NULL);
-  aosDbgCheck(name != NULL);
-
-  unsigned int n = 0;
-  va_list ap;
-
-  va_start(ap, fmt);
-  n += chprintf(stream, name);
-  while (n < namewidth) {
-    streamPut(stream, ' ');
-    ++n;
-  }
-  n += chvprintf(stream, fmt, ap);
-  va_end(ap);
-
-  streamPut(stream, '\n');
-  ++n;
-
-  return n;
-}
-
-/**
- * @brief   Prints information about the system.
- *
- * @param[in] stream    Stream to print to.
- */
-static void _printSystemInfo(BaseSequentialStream* stream)
-{
-  aosDbgCheck(stream != NULL);
-
-  // local variables
-  struct tm dt;
-  aosSysGetDateTime(&dt);
-
-  // print static information about module and operating system
-  _printSystemInfoSeparator(stream, '=', SYSTEM_INFO_WIDTH);
-  _printSystemInfoLine(stream, "Module", SYSTEM_INFO_NAMEWIDTH, "%s (v%s)", BOARD_NAME, BOARD_VERSION);
-#ifdef PLATFORM_NAME
-  _printSystemInfoLine(stream, "Platform", SYSTEM_INFO_NAMEWIDTH, "%s", PLATFORM_NAME);
-#endif
-#ifdef PORT_CORE_VARIANT_NAME
-  _printSystemInfoLine(stream, "Core Variant", SYSTEM_INFO_NAMEWIDTH, "%s", PORT_CORE_VARIANT_NAME);
-#endif
-  _printSystemInfoLine(stream, "Architecture", SYSTEM_INFO_NAMEWIDTH, "%s", PORT_ARCHITECTURE_NAME);
-  _printSystemInfoSeparator(stream, '-', SYSTEM_INFO_WIDTH);
-  _printSystemInfoLine(stream, "AMiRo-OS" , SYSTEM_INFO_NAMEWIDTH, "%u.%u.%u %s (SSSP %u.%u)", AMIROOS_VERSION_MAJOR, AMIROOS_VERSION_MINOR, AMIROOS_VERSION_PATCH, AMIROOS_RELEASE_TYPE, AOS_SYSTEM_SSSP_VERSION_MAJOR, AOS_SYSTEM_SSSP_VERSION_MINOR);
-  _printSystemInfoLine(stream, "AMiRo-LLD" , SYSTEM_INFO_NAMEWIDTH, "%u.%u.%u %s (periphAL %u.%u)", AMIRO_LLD_VERSION_MAJOR, AMIRO_LLD_VERSION_MINOR, AMIRO_LLD_VERSION_PATCH, AMIRO_LLD_RELEASE_TYPE, PERIPHAL_VERSION_MAJOR, PERIPHAL_VERSION_MINOR);
-  _printSystemInfoLine(stream, "ChibiOS/RT" , SYSTEM_INFO_NAMEWIDTH, "%u.%u.%u %s", CH_KERNEL_MAJOR, CH_KERNEL_MINOR, CH_KERNEL_PATCH, (CH_KERNEL_STABLE == 1) ? "stable" : "non-stable");
-  _printSystemInfoLine(stream, "ChibiOS/HAL", SYSTEM_INFO_NAMEWIDTH, "%u.%u.%u %s", CH_HAL_MAJOR, CH_HAL_MINOR, CH_HAL_PATCH, (CH_HAL_STABLE == 1) ? "stable" : "non-stable");
-  _printSystemInfoLine(stream, "build type", SYSTEM_INFO_NAMEWIDTH,"%s", (AMIROOS_CFG_DBG == true) ? "debug" : "release");
-  _printSystemInfoLine(stream, "Compiler" , SYSTEM_INFO_NAMEWIDTH, "%s %u.%u.%u", "GCC", __GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__); // TODO: support other compilers than GCC
-  _printSystemInfoLine(stream, "Compiled" , SYSTEM_INFO_NAMEWIDTH, "%s - %s", __DATE__, __TIME__);
-
-  // print static information about the bootloader
-  _printSystemInfoSeparator(stream, '-', SYSTEM_INFO_WIDTH);
-  if (BL_CALLBACK_TABLE_ADDRESS->magicNumber == BL_MAGIC_NUMBER) {
-    _printSystemInfoLine(stream, "AMiRo-BLT", SYSTEM_INFO_NAMEWIDTH, "%u.%u.%u %s (SSSP %u.%u)", BL_CALLBACK_TABLE_ADDRESS->vBootloader.major, BL_CALLBACK_TABLE_ADDRESS->vBootloader.minor, BL_CALLBACK_TABLE_ADDRESS->vBootloader.patch,
-                         (BL_CALLBACK_TABLE_ADDRESS->vBootloader.identifier == BL_VERSION_ID_AMiRoBLT_Release) ? "stable" :
-                         (BL_CALLBACK_TABLE_ADDRESS->vBootloader.identifier == BL_VERSION_ID_AMiRoBLT_ReleaseCandidate) ? "release candidate" :
-                         (BL_CALLBACK_TABLE_ADDRESS->vBootloader.identifier == BL_VERSION_ID_AMiRoBLT_Beta) ? "beta" :
-                         (BL_CALLBACK_TABLE_ADDRESS->vBootloader.identifier == BL_VERSION_ID_AMiRoBLT_Alpha) ? "alpha" :
-                         (BL_CALLBACK_TABLE_ADDRESS->vBootloader.identifier == BL_VERSION_ID_AMiRoBLT_PreAlpha) ? "pre-alpha" :
-                         "<release type unknown>",
-                         BL_CALLBACK_TABLE_ADDRESS->vSSSP.major, BL_CALLBACK_TABLE_ADDRESS->vSSSP.minor);
-    if (BL_CALLBACK_TABLE_ADDRESS->vSSSP.major != AOS_SYSTEM_SSSP_VERSION_MAJOR) {
-      if (stream) {
-        chprintf(stream, "WARNING: Bootloader and AMiRo-OS implement incompatible SSSP versions!\n");
-      } else {
-        aosprintf("WARNING: Bootloader and AMiRo-OS implement incompatible SSSP versions!\n");
-      }
-    }
-    _printSystemInfoLine(stream, "Compiler", SYSTEM_INFO_NAMEWIDTH, "%s %u.%u.%u", (BL_CALLBACK_TABLE_ADDRESS->vCompiler.identifier == BL_VERSION_ID_GCC) ? "GCC" : "<compiler unknown>", BL_CALLBACK_TABLE_ADDRESS->vCompiler.major, BL_CALLBACK_TABLE_ADDRESS->vCompiler.minor, BL_CALLBACK_TABLE_ADDRESS->vCompiler.patch); // TODO: support other compilers than GCC
-  } else {
-    if (stream) {
-      chprintf(stream, "Bootloader incompatible or not available.\n");
-    } else {
-      aosprintf("Bootloader incompatible or not available.\n");
-    }
-  }
-
-  // print dynamic information about the module
-  _printSystemInfoSeparator(stream, '-', SYSTEM_INFO_WIDTH);
-  if (aos.sssp.moduleId != 0) {
-    _printSystemInfoLine(stream, "Module ID", SYSTEM_INFO_NAMEWIDTH, "%u", aos.sssp.moduleId);
-  } else {
-    _printSystemInfoLine(stream, "Module ID", SYSTEM_INFO_NAMEWIDTH, "not available");
-  }
-  _printSystemInfoLine(stream, "Date", SYSTEM_INFO_NAMEWIDTH, "%s %02u-%02u-%04u", (dt.tm_wday == 0) ? "Sunday" : (dt.tm_wday == 1) ? "Monday" : (dt.tm_wday == 2) ? "Tuesday" : (dt.tm_wday == 3) ? "Wednesday" : (dt.tm_wday == 4) ? "Thursday" : (dt.tm_wday == 5) ? "Friday" : "Saturday",
-                       dt.tm_mday,
-                       dt.tm_mon + 1,
-                       dt.tm_year + 1900);
-  _printSystemInfoLine(stream, "Time", SYSTEM_INFO_NAMEWIDTH, "%02u:%02u:%02u", dt.tm_hour, dt.tm_min, dt.tm_sec);
-
-  _printSystemInfoSeparator(stream, '=', SYSTEM_INFO_WIDTH);
-
-  return;
-}
-
-#if (AMIROOS_CFG_SHELL_ENABLE == true) || defined(__DOXYGEN__)
-/**
- * @brief   Callback function for the system:config shell command.
- *
- * @param[in] stream    The I/O stream to use.
- * @param[in] argc      Number of arguments.
- * @param[in] argv      List of pointers to the arguments.
- *
- * @return              An exit status.
- * @retval  AOS_OK                  The command was executed successfuly.
- * @retval  AOS_INVALID_ARGUMENTS   There was an issue with the arguemnts.
- */
-static int _shellcmd_configcb(BaseSequentialStream* stream, int argc, char* argv[])
-{
-  aosDbgCheck(stream != NULL);
-
-  // local variables
-  int retval = AOS_INVALID_ARGUMENTS;
-
-  // if there are additional arguments
-  if (argc > 1) {
-    // if the user wants to set or retrieve the shell configuration
-    if (strcmp(argv[1], "--shell") == 0) {
-      // if the user wants to modify the shell configuration
-      if (argc > 2) {
-        // if the user wants to modify the prompt
-        if (strcmp(argv[2], "prompt") == 0) {
-          // there must be a further argument
-          if (argc > 3) {
-            // handle the option
-            if (strcmp(argv[3], "text") == 0) {
-              aos.shell.config &= ~AOS_SHELL_CONFIG_PROMPT_MINIMAL;
-              retval = AOS_OK;
-            }
-            else if (strcmp(argv[3], "minimal") == 0) {
-              aos.shell.config |= AOS_SHELL_CONFIG_PROMPT_MINIMAL;
-              retval = AOS_OK;
-            }
-            else if (strcmp(argv[3], "notime") == 0) {
-              aos.shell.config &= ~(AOS_SHELL_CONFIG_PROMPT_UPTIME | AOS_SHELL_CONFIG_PROMPT_DATETIME);
-              retval = AOS_OK;
-            }
-            else if (strcmp(argv[3], "uptime") == 0) {
-              aos.shell.config &= ~AOS_SHELL_CONFIG_PROMPT_DATETIME;
-              aos.shell.config |= AOS_SHELL_CONFIG_PROMPT_UPTIME;
-              retval = AOS_OK;
-            }
-            else if (strcmp(argv[3], "date&time") == 0) {
-              aos.shell.config &= ~AOS_SHELL_CONFIG_PROMPT_UPTIME;
-              aos.shell.config |= AOS_SHELL_CONFIG_PROMPT_DATETIME;
-              retval = AOS_OK;
-            }
-            else {
-              chprintf(stream, "unknown option '%s'\n", argv[3]);
-              return AOS_INVALID_ARGUMENTS;
-            }
-          }
-        }
-        // if the user wants to modify the string matching
-        else if (strcmp(argv[2], "match") == 0) {
-          // there must be a further argument
-          if (argc > 3) {
-            if (strcmp(argv[3], "casesensitive") == 0) {
-              aos.shell.config |= AOS_SHELL_CONFIG_MATCH_CASE;
-              retval = AOS_OK;
-            }
-            else if (strcmp(argv[3], "caseinsensitive") == 0) {
-              aos.shell.config &= ~AOS_SHELL_CONFIG_MATCH_CASE;
-              retval = AOS_OK;
-            }
-          }
-        }
-      }
-      // if the user wants to retrieve the shell configuration
-      else {
-        chprintf(stream, "current shell configuration:\n");
-        chprintf(stream, "  prompt text:   %s\n",
-                 (aos.shell.prompt != NULL) ? aos.shell.prompt : "n/a");
-        char time[10];
-        switch (aos.shell.config & (AOS_SHELL_CONFIG_PROMPT_UPTIME | AOS_SHELL_CONFIG_PROMPT_DATETIME)) {
-          case AOS_SHELL_CONFIG_PROMPT_UPTIME:
-            strcpy(time, "uptime"); break;
-          case AOS_SHELL_CONFIG_PROMPT_DATETIME:
-            strcpy(time, "date&time"); break;
-          default:
-            strcpy(time, "no time"); break;
-        }
-        chprintf(stream, "  prompt style:  %s, %s\n",
-                 (aos.shell.config & AOS_SHELL_CONFIG_PROMPT_MINIMAL) ? "minimal" : "text",
-                 time);
-        chprintf(stream, "  input method:  %s\n",
-                 (aos.shell.config & AOS_SHELL_CONFIG_INPUT_OVERWRITE) ? "replace" : "insert");
-        chprintf(stream, "  text matching: %s\n",
-                 (aos.shell.config & AOS_SHELL_CONFIG_MATCH_CASE) ? "case sensitive" : "case insensitive");
-        retval = AOS_OK;
-      }
-    }
-    // if the user wants to configure the date or time
-    else if (strcmp(argv[1], "--date&time") == 0 && argc == 4) {
-      struct tm dt;
-      aosSysGetDateTime(&dt);
-      unsigned int val = atoi(argv[3]);
-      if (strcmp(argv[2], "year") == 0) {
-        dt.tm_year = val - 1900;
-      }
-      else if (strcmp(argv[2], "month") == 0 && val <= 12) {
-        dt.tm_mon = val - 1;
-      }
-      else if (strcmp(argv[2], "day") == 0 && val <= 31) {
-        dt.tm_mday = val;
-      }
-      else if (strcmp(argv[2], "hour") == 0 && val < 24) {
-        dt.tm_hour = val;
-      }
-      else if (strcmp(argv[2], "minute") == 0 && val < 60) {
-        dt.tm_min = val;
-      }
-      else if (strcmp(argv[2], "second") == 0 && val < 60) {
-        dt.tm_sec = val;
-      }
-      else {
-        chprintf(stream, "unknown option '%s' or value '%s'\n", argv[2], argv[3]);
-        return AOS_INVALID_ARGUMENTS;
-      }
-      dt.tm_wday = aosTimeDayOfWeekFromDate(dt.tm_mday, dt.tm_mon+1, dt.tm_year+1900) % 7;
-      aosSysSetDateTime(&dt);
-
-      // read and print new date and time
-      aosSysGetDateTime(&dt);
-      chprintf(stream, "date/time set to %02u:%02u:%02u @ %02u-%02u-%04u\n",
-               dt.tm_hour, dt.tm_min, dt.tm_sec,
-               dt.tm_mday, dt.tm_mon+1, dt.tm_year+1900);
-
-      retval = AOS_OK;
-    }
-  }
-
-  // print help, if required
-  if (retval == AOS_INVALID_ARGUMENTS) {
-    chprintf(stream, "Usage: %s OPTION\n", argv[0]);
-    chprintf(stream, "Options:\n");
-    chprintf(stream, "  --help\n");
-    chprintf(stream, "    Print this help text.\n");
-    chprintf(stream, "  --shell [OPT [VAL]]\n");
-    chprintf(stream, "    Set or retrieve shell configuration.\n");
-    chprintf(stream, "    Possible OPTs and VALs are:\n");
-    chprintf(stream, "      prompt text|minimal|uptime|date&time|notime\n");
-    chprintf(stream, "        Configures the prompt.\n");
-    chprintf(stream, "      match casesensitive|caseinsenitive\n");
-    chprintf(stream, "        Configures string matching.\n");
-    chprintf(stream, "  --date&time OPT VAL\n");
-    chprintf(stream, "    Set the date/time value of OPT to VAL.\n");
-    chprintf(stream, "    Possible OPTs are:\n");
-    chprintf(stream, "      year\n");
-    chprintf(stream, "      month\n");
-    chprintf(stream, "      day\n");
-    chprintf(stream, "      hour\n");
-    chprintf(stream, "      minute\n");
-    chprintf(stream, "      second\n");
-  }
-
-  return (argc > 1 && strcmp(argv[1], "--help") == 0) ? AOS_OK : retval;
-}
-
-/**
- * @brief   Callback function for the system:info shell command.
- *
- * @param[in] stream    The I/O stream to use.
- * @param[in] argc      Number of arguments.
- * @param[in] argv      List of pointers to the arguments.
- *
- * @return            An exit status.
- * @retval  AOS_OK    The command was executed successfully.
- */
-static int _shellcmd_infocb(BaseSequentialStream* stream, int argc, char* argv[])
-{
-  aosDbgCheck(stream != NULL);
-
-  (void)argc;
-  (void)argv;
-
-  // print system information
-  _printSystemInfo(stream);
-
-  // print time measurement precision
-  chprintf(stream, "module time resolution: %uus\n", AOS_SYSTEM_TIME_RESOLUTION);
-
-  // print system uptime
-  aos_timestamp_t uptime;
-  aosSysGetUptime(&uptime);
-  chprintf(stream, "The system is running for\n");
-  chprintf(stream, "%10u days\n", (uint32_t)(uptime / MICROSECONDS_PER_DAY));
-  chprintf(stream, "%10u hours\n", (uint8_t)(uptime % MICROSECONDS_PER_DAY / MICROSECONDS_PER_HOUR));
-  chprintf(stream, "%10u minutes\n", (uint8_t)(uptime % MICROSECONDS_PER_HOUR / MICROSECONDS_PER_MINUTE));
-  chprintf(stream, "%10u seconds\n", (uint8_t)(uptime % MICROSECONDS_PER_MINUTE / MICROSECONDS_PER_SECOND));
-  chprintf(stream, "%10u milliseconds\n", (uint16_t)(uptime % MICROSECONDS_PER_SECOND / MICROSECONDS_PER_MILLISECOND));
-  chprintf(stream, "%10u microseconds\n", (uint16_t)(uptime % MICROSECONDS_PER_MILLISECOND / MICROSECONDS_PER_MICROSECOND));
-#if (AMIROOS_CFG_SSSP_MASTER != true) && (AMIROOS_CFG_PROFILE == true)
-  chprintf(stream, "SSSP synchronization offset: %.3fus per %uus\n", _syssyncskew, AMIROOS_CFG_SSSP_SYSSYNCPERIOD);
-#endif
-  _printSystemInfoSeparator(stream, '=', SYSTEM_INFO_WIDTH);
-
-  return AOS_OK;
-}
-
-/**
- * @brief   Callback function for the sytem:shutdown shell command.
- *
- * @param[in] stream    The I/O stream to use.
- * @param[in] argc      Number of arguments.
- * @param[in] argv      List of pointers to the arguments.
- *
- * @return              An exit status.
- * @retval  AOS_OK                  The command was executed successfully.
- * @retval  AOS_INVALID_ARGUMENTS   There was an issue with the arguments.
- */
-static int _shellcmd_shutdowncb(BaseSequentialStream* stream, int argc, char* argv[])
-{
-  aosDbgCheck(stream != NULL);
-
-  // print help text
-  if (argc != 2 || strcmp(argv[1], "--help") == 0) {
-    chprintf(stream, "Usage: %s OPTION\n", argv[0]);
-    chprintf(stream, "Options:\n");
-    chprintf(stream, "  --help\n");
-    chprintf(stream, "    Print this help text.\n");
-    chprintf(stream, "  --hibernate, -h\n");
-    chprintf(stream, "    Shutdown to hibernate mode.\n");
-    chprintf(stream, "    Least energy saving, but allows charging via pins.\n");
-    chprintf(stream, "  --deepsleep, -d\n");
-    chprintf(stream, "    Shutdown to deepsleep mode.\n");
-    chprintf(stream, "    Minimum energy consumption while allowing charging via plug.\n");
-    chprintf(stream, "  --transportation, -t\n");
-    chprintf(stream, "    Shutdown to transportation mode.\n");
-    chprintf(stream, "    Minimum energy consumption with all interrupts disabled (no charging).\n");
-    chprintf(stream, "  --restart, -r\n");
-    chprintf(stream, "    Shutdown and restart system.\n");
-
-    return (argc != 2) ? AOS_INVALID_ARGUMENTS : AOS_OK;
-  }
-  // handle argument
-  else {
-    if (strcmp(argv[1], "-h") == 0 || strcmp(argv[1], "--hibernate") == 0) {
-      chEvtBroadcastFlags(&aos.events.os, AOS_SYSTEM_EVENTFLAGS_HIBERNATE);
-      chThdTerminate(currp);
-      return AOS_OK;
-    }
-    else if (strcmp(argv[1], "-d") == 0 || strcmp(argv[1], "--deepsleep") == 0) {
-      chEvtBroadcastFlags(&aos.events.os, AOS_SYSTEM_EVENTFLAGS_DEEPSLEEP);
-      chThdTerminate(currp);
-      return AOS_OK;
-    }
-    else if (strcmp(argv[1], "-t") == 0 || strcmp(argv[1], "--transportation") == 0) {
-      chEvtBroadcastFlags(&aos.events.os, AOS_SYSTEM_EVENTFLAGS_TRANSPORTATION);
-      chThdTerminate(currp);
-      return AOS_OK;
-    }
-    else if (strcmp(argv[1], "-r") == 0 || strcmp(argv[1], "--restart") == 0) {
-      chEvtBroadcastFlags(&aos.events.os, AOS_SYSTEM_EVENTFLAGS_RESTART);
-      chThdTerminate(currp);
-      return AOS_OK;
-    }
-    else {
-      chprintf(stream, "unknown argument %s\n", argv[1]);
-      return AOS_INVALID_ARGUMENTS;
-    }
-  }
-}
-#endif /* AMIROOS_CFG_SHELL_ENABLE == true */
-
-#if (AMIROOS_CFG_TESTS_ENABLE == true) || defined(__DOXYGEN__)
-/**
- * @brief   Callback function for the kernel:test shell command.
- *
- * @param[in] stream    The I/O stream to use.
- * @param[in] argc      Number of arguments.
- * @param[in] argv      List of pointers to the arguments.
- *
- * @return      An exit status.
- */
-static int _shellcmd_kerneltestcb(BaseSequentialStream* stream, int argc, char* argv[])
-{
-  aosDbgCheck(stream != NULL);
-
-  (void)argc;
-  (void)argv;
-
-  msg_t retval = test_execute(stream, &rt_test_suite);
-
-  return retval;
-}
-#endif /* AMIROOS_CFG_TESTS_ENABLE == true */
-
-/**
- * @brief   Generic callback function for GPIO interrupts.
- *
- * @param[in] args   Pointer to the GPIO pad identifier.
- */
-static void _intCallback(void* args)
-{
-  aosDbgCheck((args != NULL) && (*((iopadid_t*)args) < sizeof(eventflags_t) * 8));
-
-  chSysLockFromISR();
-  chEvtBroadcastFlagsI(&aos.events.io, (eventflags_t)1 << *((iopadid_t*)args));
-  chSysUnlockFromISR();
-
-  return;
-}
-
-#if (AMIROOS_CFG_SSSP_MASTER != true) || defined(__DOXYGEN__)
-/**
- * @brief   Callback function for the Sync signal interrupt.
- *
- * @param[in] args   Pointer to the GPIO pad identifier.
- */
-static void _signalSyncCallback(void *args)
-{
-  aosDbgCheck((args != NULL) && (*((iopadid_t*)args) < sizeof(eventflags_t) * 8));
-
-  apalControlGpioState_t s_state;
-  aos_timestamp_t uptime;
-
-  chSysLockFromISR();
-  // if the system is in operation phase
-  if (aos.sssp.stage == AOS_SSSP_OPERATION) {
-    // read signal S
-    apalControlGpioGet(&moduleSsspGpioSync, &s_state);
-    // if S was toggled from on to off
-    if (s_state == APAL_GPIO_OFF) {
-      // get current uptime
-      aosSysGetUptimeX(&uptime);
-      // align the uptime with the synchronization period
-      if (uptime % AMIROOS_CFG_SSSP_SYSSYNCPERIOD < AMIROOS_CFG_SSSP_SYSSYNCPERIOD / 2) {
-        _uptime -= uptime % AMIROOS_CFG_SSSP_SYSSYNCPERIOD;
-#if (AMIROOS_CFG_PROFILE == true)
-        _syssyncskew = ((1.0f - SYSTEM_SYSSYNCSKEW_LPFACTOR) * _syssyncskew) + (SYSTEM_SYSSYNCSKEW_LPFACTOR * (uptime % AMIROOS_CFG_SSSP_SYSSYNCPERIOD));
-#endif
-      } else {
-        _uptime += AMIROOS_CFG_SSSP_SYSSYNCPERIOD - (uptime % AMIROOS_CFG_SSSP_SYSSYNCPERIOD);
-#if (AMIROOS_CFG_PROFILE == true)
-        _syssyncskew = ((1.0f - SYSTEM_SYSSYNCSKEW_LPFACTOR) * _syssyncskew) - (SYSTEM_SYSSYNCSKEW_LPFACTOR * (AMIROOS_CFG_SSSP_SYSSYNCPERIOD - (uptime % AMIROOS_CFG_SSSP_SYSSYNCPERIOD)));
-#endif
-      }
-    }
-  }
-  // broadcast event
-  chEvtBroadcastFlagsI(&aos.events.io, (eventflags_t)1 << *((iopadid_t*)args));
-  chSysUnlockFromISR();
-
-  return;
-}
-#endif
-
-/**
- * @brief   Callback function for the uptime accumulation timer.
- *
- * @param[in] par   Generic parameter.
- */
-static void _uptimeCallback(void* par)
-{
-  (void)par;
-
-  chSysLockFromISR();
-  // read current time in system ticks
-  register const systime_t st = chVTGetSystemTimeX();
-  // update the uptime variables
-  _uptime += chTimeI2US(chTimeDiffX(_synctime, st));
-  _synctime = st;
-  // enable the timer again
-  chVTSetI(&_systimer, SYSTIMER_PERIOD, &_uptimeCallback, NULL);
-  chSysUnlockFromISR();
-
-  return;
-}
-
-#if (AMIROOS_CFG_SSSP_MASTER == true) || defined (__DOXYGEN__)
-/**
- * @brief   Periodic system synchronization callback function.
- * @details Toggles the SYS_SYNC signal and reconfigures the system synchronization timer.
- *
- * @param[in] par   Unuesed parameters.
- */
-static void _sysSyncTimerCallback(void* par)
-{
-  (void)par;
-
-  apalControlGpioState_t s_state;
-  aos_timestamp_t uptime;
-
-  chSysLockFromISR();
-  // toggle and read signal S
-  apalGpioToggle(moduleSsspGpioSync.gpio);
-  apalControlGpioGet(&moduleSsspGpioSync, &s_state);
-  // if S was toggled from off to on
-  if (s_state == APAL_GPIO_ON) {
-    // reconfigure the timer precisely, because the logically falling edge (next interrupt) snychronizes the system time
-    _syssynctime += AMIROOS_CFG_SSSP_SYSSYNCPERIOD;
-    aosSysGetUptimeX(&uptime);
-    chVTSetI(&_syssynctimer, chTimeUS2I(_syssynctime - uptime), _sysSyncTimerCallback, NULL);
-  }
-  // if S was toggled from on to off
-  else /* if (s_state == APAL_GPIO_OFF) */ {
-    // reconfigure the timer (lazy)
-    chVTSetI(&_syssynctimer, chTimeUS2I(AMIROOS_CFG_SSSP_SYSSYNCPERIOD / 2), _sysSyncTimerCallback, NULL);
-  }
-  chSysUnlockFromISR();
-
-  return;
-}
-#endif
-
-/**
- * @brief   AMiRo-OS system initialization.
- * @note    Must be called from the system control thread (usually main thread).
- *
- * @param[in] shellPrompt   String to be printed as prompt of the system shell.
- */
-#if (AMIROOS_CFG_SHELL_ENABLE == true) || defined(__DOXYGEN__)
-void aosSysInit(const char* shellPrompt)
-#else
-void aosSysInit(void)
-#endif
-{
-  /* set control thread to maximum priority */
-  chThdSetPriority(AOS_THD_CTRLPRIO);
-
-  /* set local variables */
-  chVTObjectInit(&_systimer);
-  _synctime = 0;
-  _uptime = 0;
-#if (AMIROOS_CFG_SSSP_MASTER == true)
-  chVTObjectInit(&_syssynctimer);
-  _syssynctime = 0;
-#endif
-#if (AMIROOS_CFG_SSSP_MASTER != true) && (AMIROOS_CFG_PROFILE == true)
-  _syssyncskew = 0.0f;
-#endif
-
-  /* initialize aos configuration */
-  aos.sssp.stage = AOS_SSSP_STARTUP_2_1;
-  aos.sssp.moduleId = 0;
-  aosIOStreamInit(&aos.iostream);
-  chEvtObjectInit(&aos.events.io);
-  chEvtObjectInit(&aos.events.os);
-
-  /* interrupt setup */
-  // PD signal
-  palSetPadCallback(moduleSsspGpioPd.gpio->port, moduleSsspGpioPd.gpio->pad, _intCallback, &moduleSsspGpioPd.gpio->pad);
-  palEnablePadEvent(moduleSsspGpioPd.gpio->port, moduleSsspGpioPd.gpio->pad, APAL2CH_EDGE(moduleSsspGpioPd.meta.edge));
-  // SYNC signal
-#if (AMIROOS_CFG_SSSP_MASTER == true)
-  palSetPadCallback(moduleSsspGpioSync.gpio->port, moduleSsspGpioSync.gpio->pad, _intCallback, &moduleSsspGpioSync.gpio->pad);
-#else
-  palSetPadCallback(moduleSsspGpioSync.gpio->port, moduleSsspGpioSync.gpio->pad, _signalSyncCallback, &moduleSsspGpioSync.gpio->pad);
-#endif
-  palEnablePadEvent(moduleSsspGpioSync.gpio->port, moduleSsspGpioSync.gpio->pad, APAL2CH_EDGE(moduleSsspGpioSync.meta.edge));
-#if (AMIROOS_CFG_SSSP_STACK_START != true)
-  // DN signal
-  palSetPadCallback(moduleSsspGpioDn.gpio->port, moduleSsspGpioDn.gpio->pad, _intCallback, &moduleSsspGpioDn.gpio->pad);
-  palEnablePadEvent(moduleSsspGpioDn.gpio->port, moduleSsspGpioDn.gpio->pad, APAL2CH_EDGE(moduleSsspGpioDn.meta.edge));
-#endif
-#if (AMIROOS_CFG_SSSP_STACK_END != true)
-  // UP signal
-  palSetPadCallback(moduleSsspGpioUp.gpio->port, moduleSsspGpioUp.gpio->pad, _intCallback, &moduleSsspGpioUp.gpio->pad);
-  palEnablePadEvent(moduleSsspGpioUp.gpio->port, moduleSsspGpioUp.gpio->pad, APAL2CH_EDGE(moduleSsspGpioUp.meta.edge));
-#endif
-#ifdef MODULE_INIT_INTERRUPTS
-  // further interrupt signals
-  MODULE_INIT_INTERRUPTS();
-#endif
-
-#if (AMIROOS_CFG_SHELL_ENABLE == true)
-  /* init shell */
-  aosShellInit(&aos.shell,
-               &aos.events.os,
-               shellPrompt,
-               _shell_line,
-               AMIROOS_CFG_SHELL_LINEWIDTH,
-               _shell_arglist,
-               AMIROOS_CFG_SHELL_MAXARGS);
-  // add system commands
-  aosShellAddCommand(&aos.shell, &_shellcmd_config);
-  aosShellAddCommand(&aos.shell, &_shellcmd_info);
-  aosShellAddCommand(&aos.shell, &_shellcmd_shutdown);
-#if (AMIROOS_CFG_TESTS_ENABLE == true)
-  aosShellAddCommand(&aos.shell, &_shellcmd_kerneltest);
-#endif
-#endif
-
-  return;
-}
-
-/**
- * @brief   Starts the system and all system threads.
- */
-inline void aosSysStart(void)
-{
-  // update the system SSSP stage
-  aos.sssp.stage = AOS_SSSP_OPERATION;
-
-#if (AMIROOS_CFG_SSSP_MASTER == true)
-  {
-    chSysLock();
-    // start the system synchronization counter
-    // The first iteration of the timer is set to the next 'center' of a 'slice'.
-    aos_timestamp_t t;
-    aosSysGetUptimeX(&t);
-    t = AMIROOS_CFG_SSSP_SYSSYNCPERIOD - (t % AMIROOS_CFG_SSSP_SYSSYNCPERIOD);
-    chVTSetI(&_syssynctimer, chTimeUS2I((t > (AMIROOS_CFG_SSSP_SYSSYNCPERIOD / 2)) ? (t - (AMIROOS_CFG_SSSP_SYSSYNCPERIOD / 2)) : (t + (AMIROOS_CFG_SSSP_SYSSYNCPERIOD / 2))), _sysSyncTimerCallback, NULL);
-    chSysUnlock();
-  }
-#endif
-
-  // print system information;
-  _printSystemInfo((BaseSequentialStream*)&aos.iostream);
-  aosprintf("\n");
-
-#if (AMIROOS_CFG_SHELL_ENABLE == true)
-  // start system shell thread
-  aos.shell.thread = chThdCreateStatic(_shell_wa, sizeof(_shell_wa), AMIROOS_CFG_SHELL_THREADPRIO, aosShellThread, &aos.shell);
-#endif
-
-  return;
-}
-
-/**
- * @brief   Implements the SSSP startup synchronization step.
- *
- * @param[in] syncEvtListener   Event listener that receives the Sync event.
- *
- * @return    If another event that the listener is interested in was received, its mask is returned.
- *            Otherwise an empty mask (0) is returned.
- */
-eventmask_t aosSysSsspStartupOsInitSyncCheck(event_listener_t* syncEvtListener)
-{
-  aosDbgCheck(syncEvtListener != NULL);
-
-  // local variables
-  eventmask_t m;
-  eventflags_t f;
-  apalControlGpioState_t s;
-
-  // update the system SSSP stage
-  aos.sssp.stage = AOS_SSSP_STARTUP_2_2;
-
-  // deactivate the sync signal to indicate that the module is ready (SSSPv1 stage 2.1 of startup phase)
-  apalControlGpioSet(&moduleSsspGpioSync, APAL_GPIO_OFF);
-
-  // wait for any event to occur (do not apply any filter in order not to miss any event)
-  m = chEvtWaitOne(ALL_EVENTS);
-  f = chEvtGetAndClearFlags(syncEvtListener);
-  apalControlGpioGet(&moduleSsspGpioSync, &s);
-
-  // if the event was a system event,
-  //   and it was fired because of the SysSync control signal,
-  //   and the SysSync control signal has been deactivated
-  if (m & syncEvtListener->events &&
-      f == MODULE_SSSP_EVENTFLAGS_SYNC &&
-      s == APAL_GPIO_OFF) {
-    chSysLock();
-    // start the uptime counter
-    _synctime = chVTGetSystemTimeX();
-    _uptime = 0;
-    chVTSetI(&_systimer, SYSTIMER_PERIOD, &_uptimeCallback, NULL);
-    chSysUnlock();
-
-    return 0;
-  }
-  // an unexpected event occurred
-  else {
-    // reassign the flags to the event and return the event mask
-    syncEvtListener->flags |= f;
-    return m;
-  }
-}
-
-/**
- * @brief   Retrieves the system uptime.
- *
- * @param[out] ut   The system uptime.
- */
-inline void aosSysGetUptimeX(aos_timestamp_t* ut)
-{
-  aosDbgCheck(ut != NULL);
-
-  *ut = _uptime + chTimeI2US(chTimeDiffX(_synctime, chVTGetSystemTimeX()));
-
-  return;
-}
-
-/**
- * @brief   retrieves the date and time from the MCU clock.
- *
- * @param[out] td   The date and time.
- */
-void aosSysGetDateTime(struct tm* dt)
-{
-  aosDbgCheck(dt != NULL);
-
-  RTCDateTime rtc;
-  rtcGetTime(&MODULE_HAL_RTC, &rtc);
-  rtcConvertDateTimeToStructTm(&rtc, dt, NULL);
-
-  return;
-}
-
-/**
- * @brief   set the date and time of the MCU clock.
- *
- * @param[in] dt    The date and time to set.
- */
-void aosSysSetDateTime(struct tm* dt)
-{
-  aosDbgCheck(dt != NULL);
-
-  RTCDateTime rtc;
-  rtcConvertStructTmToDateTime(dt, 0, &rtc);
-  rtcSetTime(&MODULE_HAL_RTC, &rtc);
-
-  return;
-}
-
-/**
- * @brief   Initializes/Acknowledges a system shutdown/restart request.
- * @note    This functions should be called from the thread with highest priority.
- *
- * @param[in] shutdown    Type of shutdown.
- */
-void aosSysShutdownInit(aos_shutdown_t shutdown)
-{
-  // check arguments
-  aosDbgCheck(shutdown != AOS_SHUTDOWN_NONE);
-
-#if (AMIROOS_CFG_SSSP_MASTER == true)
-  // deactivate the system synchronization timer
-  chVTReset(&_syssynctimer);
-#endif
-
-  // update the system SSSP stage
-  aos.sssp.stage = AOS_SSSP_SHUTDOWN_1_1;
-
-  // activate the SYS_PD control signal only, if this module initiated the shutdown
-  chSysLock();
-  if (shutdown != AOS_SHUTDOWN_PASSIVE) {
-    apalControlGpioSet(&moduleSsspGpioPd, APAL_GPIO_ON);
-  }
-  // activate the SYS_SYNC signal
-  apalControlGpioSet(&moduleSsspGpioSync, APAL_GPIO_ON);
-  chSysUnlock();
-
-  switch (shutdown) {
-    case AOS_SHUTDOWN_PASSIVE:
-      chEvtBroadcastFlags(&aos.events.os, AOS_SYSTEM_EVENTFLAGS_SHUTDOWN);
-      aosprintf("shutdown request received...\n");
-      break;
-    case AOS_SHUTDOWN_HIBERNATE:
-      chEvtBroadcastFlags(&aos.events.os, AOS_SYSTEM_EVENTFLAGS_HIBERNATE);
-      aosprintf("shutdown to hibernate mode...\n");
-      break;
-    case AOS_SHUTDOWN_DEEPSLEEP:
-      chEvtBroadcastFlags(&aos.events.os, AOS_SYSTEM_EVENTFLAGS_DEEPSLEEP);
-      aosprintf("shutdown to deepsleep mode...\n");
-      break;
-    case AOS_SHUTDOWN_TRANSPORTATION:
-      chEvtBroadcastFlags(&aos.events.os, AOS_SYSTEM_EVENTFLAGS_TRANSPORTATION);
-      aosprintf("shutdown to transportation mode...\n");
-      break;
-    case AOS_SHUTDOWN_RESTART:
-      chEvtBroadcastFlags(&aos.events.os, AOS_SYSTEM_EVENTFLAGS_RESTART);
-      aosprintf("restarting system...\n");
-      break;
-   // must never occur
-   case AOS_SHUTDOWN_NONE:
-   default:
-      break;
-  }
-
-  // update the system SSSP stage
-  aos.sssp.stage = AOS_SSSP_SHUTDOWN_1_2;
-
-  return;
-}
-
-/**
- * @brief   Stops the system and all related threads (not the thread this function is called from).
- */
-void aosSysStop(void)
-{
-#if (AMIROOS_CFG_SHELL_ENABLE == true)
-  chThdWait(aos.shell.thread);
-#endif
-
-  return;
-}
-
-/**
- * @brief   Deinitialize all system variables.
- */
-void aosSysDeinit(void)
-{
-  return;
-}
-
-/**
- * @brief   Finally shuts down the system and calls the bootloader callback function.
- * @note    This function should be called from the thtead with highest priority.
- *
- * @param[in] shutdown    Type of shutdown.
- */
-void aosSysShutdownFinal(aos_shutdown_t shutdown)
-{
-  // check arguments
-  aosDbgCheck(shutdown != AOS_SHUTDOWN_NONE);
-
-  // disable all interrupts
-  irqDeinit();
-
-  // update the system SSSP stage
-  aos.sssp.stage = AOS_SSSP_SHUTDOWN_1_3;
-
-  // call bootloader callback depending on arguments
-  switch (shutdown) {
-    case AOS_SHUTDOWN_PASSIVE:
-      BL_CALLBACK_TABLE_ADDRESS->cbHandleShutdownRequest();
-      break;
-    case AOS_SHUTDOWN_HIBERNATE:
-      BL_CALLBACK_TABLE_ADDRESS->cbShutdownHibernate();
-      break;
-    case AOS_SHUTDOWN_DEEPSLEEP:
-      BL_CALLBACK_TABLE_ADDRESS->cbShutdownDeepsleep();
-      break;
-    case AOS_SHUTDOWN_TRANSPORTATION:
-      BL_CALLBACK_TABLE_ADDRESS->cbShutdownTransportation();
-      break;
-    case AOS_SHUTDOWN_RESTART:
-      BL_CALLBACK_TABLE_ADDRESS->cbShutdownRestart();
-      break;
-    // must never occur
-    case AOS_SHUTDOWN_NONE:
-    default:
-      break;
-  }
-
-  return;
-}
-
-/** @} */
diff --git a/os/core/src/aos_thread.c b/os/core/src/aos_thread.c
deleted file mode 100644
index 05c1668..0000000
--- a/os/core/src/aos_thread.c
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
-AMiRo-OS is an operating system designed for the Autonomous Mini Robot (AMiRo) platform.
-Copyright (C) 2016..2018  Thomas Schöpping et al.
-
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program.  If not, see <http://www.gnu.org/licenses/>.
-*/
-
-/**
- * @file    aos_thread.c
- * @brief   Thread code.
- *
- * @addtogroup aos_threads
- * @{
- */
-
-#include <aos_thread.h>
-
-/**
- * @brief   Lets the calling thread sleep until the specifide system uptime.
- *
- * @param[in] t     Deadline until the thread will sleep.
- */
-void aosThdSleepUntilS(const aos_timestamp_t* t)
-{
-  aosDbgCheck(t != NULL);
-
-  aos_timestamp_t uptime;
-
-  // get the current system uptime
-  aosSysGetUptimeX(&uptime);
-
-  // while the remaining time is too long, it must be split into multiple sleeps
-  while ( (*t > uptime) && ((*t - uptime) > AOS_THD_MAX_SLEEP_US) ) {
-    chThdSleepS(chTimeUS2I(AOS_THD_MAX_SLEEP_US));
-    aosSysGetUptimeX(&uptime);
-  }
-
-  // sleep the remaining time
-  if (*t > uptime) {
-    sysinterval_t rest = chTimeUS2I(*t - uptime);
-    if (rest > TIME_IMMEDIATE) {
-      chThdSleepS(rest);
-    }
-  }
-
-  return;
-}
-
-/** @} */
diff --git a/os/core/src/aos_time.c b/os/core/src/aos_time.c
deleted file mode 100644
index e637810..0000000
--- a/os/core/src/aos_time.c
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
-AMiRo-OS is an operating system designed for the Autonomous Mini Robot (AMiRo) platform.
-Copyright (C) 2016..2018  Thomas Schöpping et al.
-
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program.  If not, see <http://www.gnu.org/licenses/>.
-*/
-
-/**
- * @file    aos_time.c
- * @brief   Time related function implementations.
- *
- * @addtogroup aos_time
- * @{
- */
-
-#include <aos_time.h>
-
-#include <aos_debug.h>
-#include <aos_system.h>
-
-/**
- * @brief   Calculates the day of week from a specified date.
- *
- * @param[in] day     The day of the date.
- * @param[in] month   The month of the daste.
- * @param[in] year    The year of the date.
- *
- * @return    The day of week depending on the date represented in ISO format (1 = Monday to 7 = Sunday).
- */
-uint8_t aosTimeDayOfWeekFromDate(const uint16_t day, const uint8_t month, const uint16_t year)
-{
-  aosDbgCheck(day >= 1 && day <= 31);
-  aosDbgCheck(month >= 1 && month <= 12);
-
-  /*
-   * Implementation of Zeller's congruence for Gregorian calender.
-   * See https://en.wikipedia.org/wiki/Zeller%27s_congruence for details.
-   */
-  const uint32_t q = day;
-  const uint32_t m = (month >= 3) ? month : month + 12;
-  const uint32_t K = year % 100;
-  const uint32_t J = year / 100;
-
-  const uint32_t h = (q + ((13 * (m + 1)) / 5) + K + (K / 4) + (J / 4) - (2 * J)) % 7;
-
-  return ((h + 5) % 7) + 1;
-}
-
-/** @} */
diff --git a/os/core/src/aos_timer.c b/os/core/src/aos_timer.c
deleted file mode 100644
index 1a7a4fc..0000000
--- a/os/core/src/aos_timer.c
+++ /dev/null
@@ -1,296 +0,0 @@
-/*
-AMiRo-OS is an operating system designed for the Autonomous Mini Robot (AMiRo) platform.
-Copyright (C) 2016..2018  Thomas Schöpping et al.
-
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program.  If not, see <http://www.gnu.org/licenses/>.
-*/
-
-/**
- * @file    aos_timer.c
- * @brief   Timer code.
- * @details Implementation of aos_timer_t and aos_periodictimer_t functions.
- *
- * @addtogroup aos_timers
- * @{
- */
-
-#include <aos_timer.h>
-
-#include <aos_system.h>
-
-/*
- * Forward declarations.
- */
-static inline void _setupTimer(aos_timer_t* timer);
-static inline void _setupPeriodicTimer(aos_periodictimer_t* ptimer);
-static void _intermediateCb(void* timer);
-static void _fireCb(void* timer);
-static void _periodicCb(void* ptimer);
-
-/**
- * @brief   Setup a timer according to its configuration.
- *
- * @param[in] timer   Pointer to the timer to setup.
- */
-static inline void _setupTimer(aos_timer_t* timer)
-{
-  aos_timestamp_t uptime;
-
-  // get current system uptime
-  aosSysGetUptimeX(&uptime);
-
-  // if the wakeup time is more than TIME_IMMEDIATE in the future
-  if ( (timer->wkuptime > uptime) && ((timer->wkuptime - uptime) > TIME_IMMEDIATE) ) {
-    // split the time delta if necessary
-    if ((timer->wkuptime - uptime) > AOS_TIMER_MAX_INTERVAL_US) {
-      chVTSetI(&(timer->vt), chTimeUS2I(AOS_TIMER_MAX_INTERVAL_US), _intermediateCb, timer);
-    } else {
-      chVTSetI(&(timer->vt), chTimeUS2I(timer->wkuptime - uptime), _fireCb, timer);
-    }
-  } else {
-    vtfunc_t fn = timer->callback;
-    timer->callback = NULL;
-    fn(timer->cbparam);
-  }
-
-  return;
-}
-
-/**
- * @brief   Setup a periodic timer according to its configuration.
- *
- * @param[in] ptimer  Pointer to the periodic timer to setup.
- */
-static inline void _setupPeriodicTimer(aos_periodictimer_t *ptimer)
-{
-  // if the periodic timer is being initialized
-  if (ptimer->timer.wkuptime == 0) {
-    aos_timestamp_t uptime;
-
-    // get current system uptime
-    aosSysGetUptimeX(&uptime);
-    ptimer->timer.wkuptime = uptime + ptimer->interval;
-  }
-  // if the peridic timer is reactivated after it has fired
-  else {
-    ptimer->timer.wkuptime += ptimer->interval;
-  }
-
-  // set the callback and parameters
-  ptimer->timer.callback = _periodicCb;
-  ptimer->timer.cbparam = ptimer;
-
-  // setup the timer
-  _setupTimer(&(ptimer->timer));
-
-  return;
-}
-
-/**
- * @brief   Callback function for intermediate interrupts.
- * @details This is required if the desired time to fire is too far in the future so that the interval must be split.
- *
- * @param[in] timer   Pointer to a aos_timer_t to reactivate.
- */
-static void _intermediateCb(void* timer)
-{
-  chSysLockFromISR();
-  _setupTimer((aos_timer_t*)timer);
-  chSysUnlockFromISR();
-}
-
-/**
- * @brief   Callback function for the final fire event of the timer.
- *
- * @param[in] timer   Pointer to a aos_timer_t to call its callback.
- */
-static void _fireCb(void *timer)
-{
-  chSysLockFromISR();
-  ((aos_timer_t*)timer)->callback(((aos_timer_t*)timer)->cbparam);
-  chSysUnlockFromISR();
-}
-
-/**
- * @brief   Callback function for periodic timer interrupts.
- * @details This function calls the original callback and reenables the timer afterwards.
- *
- * @param[in] ptimer  Pointer to a aos_periodictimer_t to reactivate.
- */
-static void _periodicCb(void* ptimer)
-{
-  ((aos_periodictimer_t*)ptimer)->callback(((aos_periodictimer_t*)ptimer)->cbparam);
-  _setupPeriodicTimer((aos_periodictimer_t*)ptimer);
-}
-
-/**
- * @brief   Initialize a aos_timer_t object.
- *
- * @param[in] timer   The timer to initialize.
- */
-void aosTimerInit(aos_timer_t* timer)
-{
-  aosDbgAssert(timer != NULL);
-
-  chVTObjectInit(&(timer->vt));
-  timer->wkuptime = 0;
-  timer->callback = NULL;
-  timer->cbparam = NULL;
-
-  return;
-}
-
-/**
- * @brief   Set timer to fire at an absolute system time.
- *
- * @param[in] timer   Pointer to the timer to set.
- * @param[in] uptime  Pointer to the absolute system time for the timer to fire.
- * @param[in] cb      Pointer to a callback function to be called.
- *                    In contrast to ChibiOS callback functions, this gets called from an already ISR locked context.
- *                    Thus it may not contain any chSysLockX() or chSysUnlockX() calls and so forth.
- * @param[in] par     Pointer to a parameter fpr the callback function (may be NULL).
- */
-void aosTimerSetAbsoluteI(aos_timer_t *timer, aos_timestamp_t *uptime, vtfunc_t cb, void *par)
-{
-  aosDbgCheck(timer != NULL);
-  aosDbgCheck(uptime != NULL);
-  aosDbgCheck(cb != NULL);
-
-  timer->wkuptime = *uptime;
-  timer->callback = cb;
-  timer->cbparam = par;
-  _setupTimer(timer);
-
-  return;
-}
-
-/**
- * @brief   Set timer to fire after a relative interval.
- *
- * @param[in] timer   Pointer to the timer to set.
- * @param[in] offset  Relative interval to set for the timer to fire.
- * @param[in] cb      Pointer to a callback function to be called.
- *                    In contrast to ChibiOS callback functions, this gets called from an already ISR locked context.
- *                    Thus it may not contain any chSysLockX() or chSysUnlockX() calls and so forth.
- * @param[in] par     Pointer to a parameter for the callback function (may be NULL).
- */
-void aosTimerSetIntervalI(aos_timer_t *timer, aos_interval_t offset, vtfunc_t cb, void *par)
-{
-  aosDbgCheck(timer != NULL);
-  aosDbgCheck(cb != NULL);
-
-  aos_timestamp_t uptime;
-
-  aosSysGetUptimeX(&uptime);
-  timer->wkuptime = uptime + offset;
-  timer->callback = cb;
-  timer->cbparam = par;
-  _setupTimer(timer);
-
-  return;
-}
-
-/**
- * @brief   Set timer to fire after a long relative interval.
- *
- * @param[in] timer   Pointer to the timer to set.
- * @param[in] offset  Pointer to a long interval value to set for the timer to fire.
- * @param[in] cb      Pointer to a callback function to be called.
- *                    In contrast to ChibiOS callback functions, this gets called from an already ISR locked context.
- *                    Thus it may not contain any chSysLockX() or chSysUnlockX() calls and so forth.
- * @param[in] par     Pointer to a parameter for the callback function (may be NULL).
- */
-void aosTimerSetLongIntervalI(aos_timer_t *timer, aos_longinterval_t *offset, vtfunc_t cb, void *par)
-{
-  aosDbgCheck(timer != NULL);
-  aosDbgCheck(offset != NULL);
-  aosDbgCheck(cb != NULL);
-
-  aos_timestamp_t uptime;
-
-  aosSysGetUptimeX(&uptime);
-  timer->wkuptime = uptime + *offset;
-  timer->callback = cb;
-  timer->cbparam = par;
-  _setupTimer(timer);
-
-  return;
-}
-
-/**
- * @brief   Initialize a aos_periodictimer_t object.
- *
- * @param[in] timer   The periodic timer to initialize.
- */
-void aosPeriodicTimerInit(aos_periodictimer_t *ptimer)
-{
-  aosDbgAssert(ptimer != NULL);
-
-  aosTimerInit(&(ptimer->timer));
-  ptimer->interval = 0;
-
-  return;
-}
-
-/**
- * @brief   Set a periodic timer to fire in the specified interval.
- *
- * @param[in] ptimer    Pointer to the periodic timer to set.
- * @param[in] interval  Interval for the periodic timer to fire,
- * @param[in] cb        Pointer to a callback function to be called.
- *                      In contrast to ChibiOS callback functions, this gets called from an already ISR locked context.
- *                      Thus it may not contain any chSysLockX() or chSysUnlockX() calls and so forth.
- * @param[in] par       Pointer to a parameter for the callback function (may be NULL).
- */
-void aosPeriodicTimerSetI(aos_periodictimer_t* ptimer, aos_interval_t interval, vtfunc_t cb, void* par)
-{
-  aosDbgCheck(ptimer != NULL);
-  aosDbgCheck(interval > TIME_IMMEDIATE);
-  aosDbgCheck(cb != NULL);
-
-  ptimer->timer.wkuptime = 0;
-  ptimer->interval = interval;
-  ptimer->callback = cb;
-  ptimer->cbparam = par;
-  _setupPeriodicTimer(ptimer);
-
-  return;
-}
-
-/**
- * @brief   Set a periodic timer to fire in the specified interval.
- *
- * @param[in] ptimer    Pointer to the periodic timer to set.
- * @param[in] interval  Pointer to a long interval value for the periodic timer to fire,
- * @param[in] cb        Pointer to a callback function to be called.
- *                      In contrast to other callback functions, this get called from an already ISR locked context.
- *                      This it may not contain any chSysLockX() or chSysUnlockX() calls.
- * @param[in] par       Pointer to a parameter for the callback function (may be NULL).
- */
-void aosPeriodicTimerSetLongI(aos_periodictimer_t* ptimer, aos_longinterval_t* interval, vtfunc_t cb, void* par)
-{
-  aosDbgCheck(ptimer != NULL);
-  aosDbgCheck(*interval > TIME_IMMEDIATE);
-  aosDbgCheck(cb != NULL);
-
-  ptimer->timer.wkuptime = 0;
-  ptimer->interval = *interval;
-  ptimer->callback = cb;
-  ptimer->cbparam = par;
-  _setupPeriodicTimer(ptimer);
-
-  return;
-}
-
-/** @} */
diff --git a/os/core/src/aos_unittest.c b/os/core/src/aos_unittest.c
deleted file mode 100644
index 8dd8fa3..0000000
--- a/os/core/src/aos_unittest.c
+++ /dev/null
@@ -1,276 +0,0 @@
-/*
-AMiRo-OS is an operating system designed for the Autonomous Mini Robot (AMiRo) platform.
-Copyright (C) 2016..2018  Thomas Schöpping et al.
-
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program.  If not, see <http://www.gnu.org/licenses/>.
-*/
-
-/**
- * @file    aos_unittest.c
- * @brief   Unittest code.
- * @details Functions to initialize and run unittests, 
- *          as well as utility functions to be used in unittests.
- *
- * @addtogroup aos_unittests
- * @{
- */
-
-#include <aos_unittest.h>
-
-#if (AMIROOS_CFG_TESTS_ENABLE == true) || defined(__DOXYGEN__)
-#include <aos_debug.h>
-#include <chprintf.h>
-#include <string.h>
-
-/**
- * @brief   Retrieve the total number of tests (passed and failed).
- *
- * @param[in] result    The result object to evaluate.
- *
- * @return  Number of total tests executed.
- */
-inline uint32_t aosUtResultTotal(aos_utresult_t *result)
-{
-  aosDbgCheck(result != NULL);
-
-  return result->passed + result->failed;
-}
-
-/**
- * @brief   Retrieve the ratio of passed tests.
- *
- * @param[in] result    The result object to evaluate.
- *
- * @return  Ratio of passed tests to total tests as float in range [0, 1].
- */
-inline float aosUtResultRatio(aos_utresult_t *result)
-{
-  aosDbgCheck(result != NULL);
-
-  if (aosUtResultTotal(result) > 0) {
-    return (float)result->passed / (float)aosUtResultTotal(result);
-  } else {
-    return 1.0f;
-  }
-}
-
-/**
- * @brief   Print the summary of a test.
- * @details The summary consists of:
- *          - total numer of tests executed
- *          - absolute number of passed tests
- *          - absolute number of failed tests
- *          - relative ratio of passed tests
- *
- * @param[in] stream    Stream to print the result to.
- * @param[in] result    Result to evaluate and print.
- * @param[in] heading   Optional heading (defaults to "summary").
- */
-void aosUtResultPrintSummary(BaseSequentialStream *stream, aos_utresult_t *result, char* heading)
-{
-  aosDbgCheck(stream != NULL);
-  aosDbgCheck(result != NULL);
-
-  chprintf(stream, "%s:\n", (heading != NULL) ? heading : "summary");
-  chprintf(stream, "\ttotal:  %3u\n", aosUtResultTotal(result));
-  chprintf(stream, "\tpassed: %3u\n", result->passed);
-  chprintf(stream, "\tfailed: %3u\n", result->failed);
-  chprintf(stream, "\tratio:  %3u%%\n", (uint8_t)(aosUtResultRatio(result) * 100.0f));
-
-  return;
-}
-
-/**
- * @brief   Initialize a unit test object.
- *
- * @param[in] ut          The unit test object to initialize.
- * @param[in] name        name of the unit test.
- * @param[in] info        Optional information string.
- * @param[in] func        Unit test calback function.
- * @param[in] data        Optional data for the unit test.
- * @param[in] shellname   Name of the shell command
- * @param[in] shellcb     Callback for the shell command.
- */
-void aosUtObjectInit(aos_unittest_t* ut, char* name, char* info, aos_utfunction_t func, void* data, char* shellname, aos_shellcmdcb_t shellcb)
-{
-  aosDbgCheck(ut != NULL);
-  aosDbgCheck(name != NULL && strlen(name) > 0);
-  aosDbgCheck(func != NULL);
-  aosDbgCheck(shellname != NULL && strlen(shellname) > 0);
-  aosDbgCheck(shellcb != NULL);
-
-  ut->name = name;
-  ut->info = info;
-  ut->testfunc = func;
-  ut->shellcmd.name = shellname;
-  ut->shellcmd.callback = shellcb;
-  ut->shellcmd.next = NULL;
-  ut->data = data;
-
-  return;
-}
-
-/**
- * @brief   Run an unit test.
- *
- * @param[in] stream  A stream for printing messages.
- * @param[in] ut      Unit test to execute.
- * @param[in] note    Optional note string.
- *
- * @return    Result of the test.
- */
-aos_utresult_t aosUtRun(BaseSequentialStream *stream, aos_unittest_t *ut, char *note)
-{
-  aosDbgCheck(stream != NULL);
-  aosDbgCheck(ut != NULL);
-
-  // print name heading
-  {
-    chprintf(stream, "\n");
-    const int nchars = chprintf(stream, "%s unit test\n", ut->name);
-    for (int c = 0; c < nchars-1; ++c) {
-      chprintf(stream, "=");
-    }
-    chprintf(stream, "\n");
-  }
-
-  // print info (if any)
-  if (ut->info != NULL) {
-    chprintf(stream, "info: %s\n", ut->info);
-  }
-  // print note (if any)
-  if (note != NULL) {
-    chprintf(stream, "note: %s\n", note);
-  }
-  chprintf(stream, "\n");
-
-  // run test
-  aos_utresult_t result = ut->testfunc(stream, ut);
-
-  // print summary
-  aosUtResultPrintSummary(stream, &result, NULL);
-
-  return result;
-}
-
-/**
- * @brief   Helper function for passed tests.
- * @details Prints a message that the test was passed and modifies the result accordigly.
- *
- * @param[in] stream      Stream to print the message to.
- * @param[in,out] result  Result object to modify.
- */
-void aosUtPassed(BaseSequentialStream *stream, aos_utresult_t* result)
-{
-  aosDbgCheck(stream != NULL);
-  aosDbgCheck(result != NULL);
-
-  ++result->passed;
-  chprintf(stream, "\tPASSED\n");
-  chprintf(stream, "\n");
-
-  return;
-}
-
-/**
- * @brief   Helper function for passed tests.
- * @details Prints a message that the test was passed, an additional custom message, and modifies the result accordigly.
- *
- * @param[in] stream      Stream to print the message to.
- * @param[in,out] result  Result object to modify.
- * @param[in] fmt         Formatted message string.
- */
-void aosUtPassedMsg(BaseSequentialStream *stream, aos_utresult_t* result, const char *fmt, ...)
-{
-  aosDbgCheck(stream != NULL);
-  aosDbgCheck(result != NULL);
-
-  va_list ap;
-
-  ++result->passed;
-  chprintf(stream, "\tPASSED\t");
-  va_start(ap, fmt);
-  chvprintf(stream, fmt, ap);
-  va_end(ap);
-  chprintf(stream, "\n");
-
-  return;
-}
-
-/**
- * @brief   Helper function for failed tests.
- * @details Prints a message that the test was failed and modifies the result accordigly.
- *
- * @param[in] stream      Stream to print the message to.
- * @param[in,out] result  Result object to modify.
- */
-void aosUtFailed(BaseSequentialStream *stream, aos_utresult_t* result)
-{
-  aosDbgCheck(stream != NULL);
-  aosDbgCheck(result != NULL);
-
-  ++result->failed;
-  chprintf(stream, "\tFAILED\n");
-  chprintf(stream, "\n");
-
-  return;
-}
-
-/**
- * @brief   Helper function for failed tests.
- * @details Prints a message that the test was failed, an additional custom message, and modifies the result accordigly.
- *
- * @param[in] stream      Stream to print the message to.
- * @param[in,out] result  Result object to modify.
- * @param[in] fmt         Formatted message string.
- */
-void aosUtFailedMsg(BaseSequentialStream *stream, aos_utresult_t* result, const char *fmt, ...)
-{
-  aosDbgCheck(stream != NULL);
-  aosDbgCheck(result != NULL);
-
-  va_list ap;
-
-  ++result->failed;
-  chprintf(stream, "\tFAILED\t");
-  va_start(ap, fmt);
-  chvprintf(stream, fmt, ap);
-  va_end(ap);
-  chprintf(stream, "\n");
-
-  return;
-}
-
-/**
- * @brief   Helper function for information messages.
- *
- * @param[in] stream  Strean to rpint the message to.
- * @param[in] fmt     Formatted message string.
- */
-void aosUtInfoMsg(BaseSequentialStream* stream, const char* fmt, ...)
-{
-  aosDbgCheck(stream != NULL);
-
-  va_list ap;
-  va_start(ap, fmt);
-  chvprintf(stream, fmt, ap);
-  va_end(ap);
-  chprintf(stream, "\n");
-
-  return;
-}
-
-#endif /* AMIROOS_CFG_TESTS_ENABLE == true */
-
-/** @} */
diff --git a/os/doc/Doxyfile b/os/doc/Doxyfile
deleted file mode 100644
index c9f5c29..0000000
--- a/os/doc/Doxyfile
+++ /dev/null
@@ -1,2479 +0,0 @@
-# Doxyfile 1.8.11
-
-# This file describes the settings to be used by the documentation system
-# doxygen (www.doxygen.org) for a project.
-#
-# All text after a double hash (##) is considered a comment and is placed in
-# front of the TAG it is preceding.
-#
-# All text after a single hash (#) is considered a comment and will be ignored.
-# The format is:
-# TAG = value [value, ...]
-# For lists, items can also be appended using:
-# TAG += value [value, ...]
-# Values that contain spaces should be placed between quotes (\" \").
-
-#---------------------------------------------------------------------------
-# Project related configuration options
-#---------------------------------------------------------------------------
-
-# This tag specifies the encoding used for all characters in the config file
-# that follow. The default is UTF-8 which is also the encoding used for all text
-# before the first occurrence of this tag. Doxygen uses libiconv (or the iconv
-# built into libc) for the transcoding. See http://www.gnu.org/software/libiconv
-# for the list of possible encodings.
-# The default value is: UTF-8.
-
-DOXYFILE_ENCODING      = UTF-8
-
-# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by
-# double-quotes, unless you are using Doxywizard) that should identify the
-# project for which the documentation is generated. This name is used in the
-# title of most generated pages and in a few other places.
-# The default value is: My Project.
-
-PROJECT_NAME           = AMiRo-OS
-
-# The PROJECT_NUMBER tag can be used to enter a project or revision number. This
-# could be handy for archiving the generated documentation or if some version
-# control system is used.
-
-PROJECT_NUMBER         = 
-
-# Using the PROJECT_BRIEF tag one can provide an optional one line description
-# for a project that appears at the top of each page and should give viewer a
-# quick idea about the purpose of the project. Keep the description short.
-
-PROJECT_BRIEF          = 
-
-# With the PROJECT_LOGO tag one can specify a logo or an icon that is included
-# in the documentation. The maximum height of the logo should not exceed 55
-# pixels and the maximum width should not exceed 200 pixels. Doxygen will copy
-# the logo to the output directory.
-
-PROJECT_LOGO           = 
-
-# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path
-# into which the generated documentation will be written. If a relative path is
-# entered, it will be relative to the location where doxygen was started. If
-# left blank the current directory will be used.
-
-OUTPUT_DIRECTORY       = 
-
-# If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub-
-# directories (in 2 levels) under the output directory of each output format and
-# will distribute the generated files over these directories. Enabling this
-# option can be useful when feeding doxygen a huge amount of source files, where
-# putting all generated files in the same directory would otherwise causes
-# performance problems for the file system.
-# The default value is: NO.
-
-CREATE_SUBDIRS         = NO
-
-# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII
-# characters to appear in the names of generated files. If set to NO, non-ASCII
-# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode
-# U+3044.
-# The default value is: NO.
-
-ALLOW_UNICODE_NAMES    = NO
-
-# The OUTPUT_LANGUAGE tag is used to specify the language in which all
-# documentation generated by doxygen is written. Doxygen will use this
-# information to generate all constant output in the proper language.
-# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese,
-# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States),
-# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian,
-# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages),
-# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian,
-# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian,
-# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish,
-# Ukrainian and Vietnamese.
-# The default value is: English.
-
-OUTPUT_LANGUAGE        = English
-
-# If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member
-# descriptions after the members that are listed in the file and class
-# documentation (similar to Javadoc). Set to NO to disable this.
-# The default value is: YES.
-
-BRIEF_MEMBER_DESC      = YES
-
-# If the REPEAT_BRIEF tag is set to YES, doxygen will prepend the brief
-# description of a member or function before the detailed description
-#
-# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
-# brief descriptions will be completely suppressed.
-# The default value is: YES.
-
-REPEAT_BRIEF           = YES
-
-# This tag implements a quasi-intelligent brief description abbreviator that is
-# used to form the text in various listings. Each string in this list, if found
-# as the leading text of the brief description, will be stripped from the text
-# and the result, after processing the whole list, is used as the annotated
-# text. Otherwise, the brief description is used as-is. If left blank, the
-# following values are used ($name is automatically replaced with the name of
-# the entity):The $name class, The $name widget, The $name file, is, provides,
-# specifies, contains, represents, a, an and the.
-
-ABBREVIATE_BRIEF       = "The $name class" \
-                         "The $name widget" \
-                         "The $name file" \
-                         is \
-                         provides \
-                         specifies \
-                         contains \
-                         represents \
-                         a \
-                         an \
-                         the
-
-# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
-# doxygen will generate a detailed section even if there is only a brief
-# description.
-# The default value is: NO.
-
-ALWAYS_DETAILED_SEC    = NO
-
-# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
-# inherited members of a class in the documentation of that class as if those
-# members were ordinary class members. Constructors, destructors and assignment
-# operators of the base classes will not be shown.
-# The default value is: NO.
-
-INLINE_INHERITED_MEMB  = NO
-
-# If the FULL_PATH_NAMES tag is set to YES, doxygen will prepend the full path
-# before files name in the file list and in the header files. If set to NO the
-# shortest path that makes the file name unique will be used
-# The default value is: YES.
-
-FULL_PATH_NAMES        = YES
-
-# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path.
-# Stripping is only done if one of the specified strings matches the left-hand
-# part of the path. The tag can be used to show relative paths in the file list.
-# If left blank the directory from which doxygen is run is used as the path to
-# strip.
-#
-# Note that you can specify absolute paths here, but also relative paths, which
-# will be relative from the directory where doxygen is started.
-# This tag requires that the tag FULL_PATH_NAMES is set to YES.
-
-STRIP_FROM_PATH        = 
-
-# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the
-# path mentioned in the documentation of a class, which tells the reader which
-# header file to include in order to use a class. If left blank only the name of
-# the header file containing the class definition is used. Otherwise one should
-# specify the list of include paths that are normally passed to the compiler
-# using the -I flag.
-
-STRIP_FROM_INC_PATH    = 
-
-# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but
-# less readable) file names. This can be useful is your file systems doesn't
-# support long names like on DOS, Mac, or CD-ROM.
-# The default value is: NO.
-
-SHORT_NAMES            = NO
-
-# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the
-# first line (until the first dot) of a Javadoc-style comment as the brief
-# description. If set to NO, the Javadoc-style will behave just like regular Qt-
-# style comments (thus requiring an explicit @brief command for a brief
-# description.)
-# The default value is: NO.
-
-JAVADOC_AUTOBRIEF      = NO
-
-# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first
-# line (until the first dot) of a Qt-style comment as the brief description. If
-# set to NO, the Qt-style will behave just like regular Qt-style comments (thus
-# requiring an explicit \brief command for a brief description.)
-# The default value is: NO.
-
-QT_AUTOBRIEF           = NO
-
-# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a
-# multi-line C++ special comment block (i.e. a block of //! or /// comments) as
-# a brief description. This used to be the default behavior. The new default is
-# to treat a multi-line C++ comment block as a detailed description. Set this
-# tag to YES if you prefer the old behavior instead.
-#
-# Note that setting this tag to YES also means that rational rose comments are
-# not recognized any more.
-# The default value is: NO.
-
-MULTILINE_CPP_IS_BRIEF = NO
-
-# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the
-# documentation from any documented member that it re-implements.
-# The default value is: YES.
-
-INHERIT_DOCS           = YES
-
-# If the SEPARATE_MEMBER_PAGES tag is set to YES then doxygen will produce a new
-# page for each member. If set to NO, the documentation of a member will be part
-# of the file/class/namespace that contains it.
-# The default value is: NO.
-
-SEPARATE_MEMBER_PAGES  = NO
-
-# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen
-# uses this value to replace tabs by spaces in code fragments.
-# Minimum value: 1, maximum value: 16, default value: 4.
-
-TAB_SIZE               = 4
-
-# This tag can be used to specify a number of aliases that act as commands in
-# the documentation. An alias has the form:
-# name=value
-# For example adding
-# "sideeffect=@par Side Effects:\n"
-# will allow you to put the command \sideeffect (or @sideeffect) in the
-# documentation, which will result in a user-defined paragraph with heading
-# "Side Effects:". You can put \n's in the value part of an alias to insert
-# newlines.
-
-ALIASES                = 
-
-# This tag can be used to specify a number of word-keyword mappings (TCL only).
-# A mapping has the form "name=value". For example adding "class=itcl::class"
-# will allow you to use the command class in the itcl::class meaning.
-
-TCL_SUBST              = 
-
-# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources
-# only. Doxygen will then generate output that is more tailored for C. For
-# instance, some of the names that are used will be different. The list of all
-# members will be omitted, etc.
-# The default value is: NO.
-
-OPTIMIZE_OUTPUT_FOR_C  = YES
-
-# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or
-# Python sources only. Doxygen will then generate output that is more tailored
-# for that language. For instance, namespaces will be presented as packages,
-# qualified scopes will look different, etc.
-# The default value is: NO.
-
-OPTIMIZE_OUTPUT_JAVA   = NO
-
-# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
-# sources. Doxygen will then generate output that is tailored for Fortran.
-# The default value is: NO.
-
-OPTIMIZE_FOR_FORTRAN   = NO
-
-# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
-# sources. Doxygen will then generate output that is tailored for VHDL.
-# The default value is: NO.
-
-OPTIMIZE_OUTPUT_VHDL   = NO
-
-# Doxygen selects the parser to use depending on the extension of the files it
-# parses. With this tag you can assign which parser to use for a given
-# extension. Doxygen has a built-in mapping, but you can override or extend it
-# using this tag. The format is ext=language, where ext is a file extension, and
-# language is one of the parsers supported by doxygen: IDL, Java, Javascript,
-# C#, C, C++, D, PHP, Objective-C, Python, Fortran (fixed format Fortran:
-# FortranFixed, free formatted Fortran: FortranFree, unknown formatted Fortran:
-# Fortran. In the later case the parser tries to guess whether the code is fixed
-# or free formatted code, this is the default for Fortran type files), VHDL. For
-# instance to make doxygen treat .inc files as Fortran files (default is PHP),
-# and .f files as C (default is Fortran), use: inc=Fortran f=C.
-#
-# Note: For files without extension you can use no_extension as a placeholder.
-#
-# Note that for custom extensions you also need to set FILE_PATTERNS otherwise
-# the files are not read by doxygen.
-
-EXTENSION_MAPPING      = 
-
-# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments
-# according to the Markdown format, which allows for more readable
-# documentation. See http://daringfireball.net/projects/markdown/ for details.
-# The output of markdown processing is further processed by doxygen, so you can
-# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in
-# case of backward compatibilities issues.
-# The default value is: YES.
-
-MARKDOWN_SUPPORT       = YES
-
-# When enabled doxygen tries to link words that correspond to documented
-# classes, or namespaces to their corresponding documentation. Such a link can
-# be prevented in individual cases by putting a % sign in front of the word or
-# globally by setting AUTOLINK_SUPPORT to NO.
-# The default value is: YES.
-
-AUTOLINK_SUPPORT       = YES
-
-# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
-# to include (a tag file for) the STL sources as input, then you should set this
-# tag to YES in order to let doxygen match functions declarations and
-# definitions whose arguments contain STL classes (e.g. func(std::string);
-# versus func(std::string) {}). This also make the inheritance and collaboration
-# diagrams that involve STL classes more complete and accurate.
-# The default value is: NO.
-
-BUILTIN_STL_SUPPORT    = NO
-
-# If you use Microsoft's C++/CLI language, you should set this option to YES to
-# enable parsing support.
-# The default value is: NO.
-
-CPP_CLI_SUPPORT        = NO
-
-# Set the SIP_SUPPORT tag to YES if your project consists of sip (see:
-# http://www.riverbankcomputing.co.uk/software/sip/intro) sources only. Doxygen
-# will parse them like normal C++ but will assume all classes use public instead
-# of private inheritance when no explicit protection keyword is present.
-# The default value is: NO.
-
-SIP_SUPPORT            = NO
-
-# For Microsoft's IDL there are propget and propput attributes to indicate
-# getter and setter methods for a property. Setting this option to YES will make
-# doxygen to replace the get and set methods by a property in the documentation.
-# This will only work if the methods are indeed getting or setting a simple
-# type. If this is not the case, or you want to show the methods anyway, you
-# should set this option to NO.
-# The default value is: YES.
-
-IDL_PROPERTY_SUPPORT   = YES
-
-# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
-# tag is set to YES then doxygen will reuse the documentation of the first
-# member in the group (if any) for the other members of the group. By default
-# all members of a group must be documented explicitly.
-# The default value is: NO.
-
-DISTRIBUTE_GROUP_DOC   = NO
-
-# If one adds a struct or class to a group and this option is enabled, then also
-# any nested class or struct is added to the same group. By default this option
-# is disabled and one has to add nested compounds explicitly via \ingroup.
-# The default value is: NO.
-
-GROUP_NESTED_COMPOUNDS = NO
-
-# Set the SUBGROUPING tag to YES to allow class member groups of the same type
-# (for instance a group of public functions) to be put as a subgroup of that
-# type (e.g. under the Public Functions section). Set it to NO to prevent
-# subgrouping. Alternatively, this can be done per class using the
-# \nosubgrouping command.
-# The default value is: YES.
-
-SUBGROUPING            = YES
-
-# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions
-# are shown inside the group in which they are included (e.g. using \ingroup)
-# instead of on a separate page (for HTML and Man pages) or section (for LaTeX
-# and RTF).
-#
-# Note that this feature does not work in combination with
-# SEPARATE_MEMBER_PAGES.
-# The default value is: NO.
-
-INLINE_GROUPED_CLASSES = NO
-
-# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions
-# with only public data fields or simple typedef fields will be shown inline in
-# the documentation of the scope in which they are defined (i.e. file,
-# namespace, or group documentation), provided this scope is documented. If set
-# to NO, structs, classes, and unions are shown on a separate page (for HTML and
-# Man pages) or section (for LaTeX and RTF).
-# The default value is: NO.
-
-INLINE_SIMPLE_STRUCTS  = NO
-
-# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or
-# enum is documented as struct, union, or enum with the name of the typedef. So
-# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
-# with name TypeT. When disabled the typedef will appear as a member of a file,
-# namespace, or class. And the struct will be named TypeS. This can typically be
-# useful for C code in case the coding convention dictates that all compound
-# types are typedef'ed and only the typedef is referenced, never the tag name.
-# The default value is: NO.
-
-TYPEDEF_HIDES_STRUCT   = NO
-
-# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This
-# cache is used to resolve symbols given their name and scope. Since this can be
-# an expensive process and often the same symbol appears multiple times in the
-# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small
-# doxygen will become slower. If the cache is too large, memory is wasted. The
-# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range
-# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536
-# symbols. At the end of a run doxygen will report the cache usage and suggest
-# the optimal cache size from a speed point of view.
-# Minimum value: 0, maximum value: 9, default value: 0.
-
-LOOKUP_CACHE_SIZE      = 0
-
-#---------------------------------------------------------------------------
-# Build related configuration options
-#---------------------------------------------------------------------------
-
-# If the EXTRACT_ALL tag is set to YES, doxygen will assume all entities in
-# documentation are documented, even if no documentation was available. Private
-# class members and static file members will be hidden unless the
-# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES.
-# Note: This will also disable the warnings about undocumented members that are
-# normally produced when WARNINGS is set to YES.
-# The default value is: NO.
-
-EXTRACT_ALL            = YES
-
-# If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will
-# be included in the documentation.
-# The default value is: NO.
-
-EXTRACT_PRIVATE        = NO
-
-# If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal
-# scope will be included in the documentation.
-# The default value is: NO.
-
-EXTRACT_PACKAGE        = NO
-
-# If the EXTRACT_STATIC tag is set to YES, all static members of a file will be
-# included in the documentation.
-# The default value is: NO.
-
-EXTRACT_STATIC         = NO
-
-# If the EXTRACT_LOCAL_CLASSES tag is set to YES, classes (and structs) defined
-# locally in source files will be included in the documentation. If set to NO,
-# only classes defined in header files are included. Does not have any effect
-# for Java sources.
-# The default value is: YES.
-
-EXTRACT_LOCAL_CLASSES  = YES
-
-# This flag is only useful for Objective-C code. If set to YES, local methods,
-# which are defined in the implementation section but not in the interface are
-# included in the documentation. If set to NO, only methods in the interface are
-# included.
-# The default value is: NO.
-
-EXTRACT_LOCAL_METHODS  = NO
-
-# If this flag is set to YES, the members of anonymous namespaces will be
-# extracted and appear in the documentation as a namespace called
-# 'anonymous_namespace{file}', where file will be replaced with the base name of
-# the file that contains the anonymous namespace. By default anonymous namespace
-# are hidden.
-# The default value is: NO.
-
-EXTRACT_ANON_NSPACES   = NO
-
-# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all
-# undocumented members inside documented classes or files. If set to NO these
-# members will be included in the various overviews, but no documentation
-# section is generated. This option has no effect if EXTRACT_ALL is enabled.
-# The default value is: NO.
-
-HIDE_UNDOC_MEMBERS     = NO
-
-# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all
-# undocumented classes that are normally visible in the class hierarchy. If set
-# to NO, these classes will be included in the various overviews. This option
-# has no effect if EXTRACT_ALL is enabled.
-# The default value is: NO.
-
-HIDE_UNDOC_CLASSES     = NO
-
-# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend
-# (class|struct|union) declarations. If set to NO, these declarations will be
-# included in the documentation.
-# The default value is: NO.
-
-HIDE_FRIEND_COMPOUNDS  = NO
-
-# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any
-# documentation blocks found inside the body of a function. If set to NO, these
-# blocks will be appended to the function's detailed documentation block.
-# The default value is: NO.
-
-HIDE_IN_BODY_DOCS      = NO
-
-# The INTERNAL_DOCS tag determines if documentation that is typed after a
-# \internal command is included. If the tag is set to NO then the documentation
-# will be excluded. Set it to YES to include the internal documentation.
-# The default value is: NO.
-
-INTERNAL_DOCS          = NO
-
-# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file
-# names in lower-case letters. If set to YES, upper-case letters are also
-# allowed. This is useful if you have classes or files whose names only differ
-# in case and if your file system supports case sensitive file names. Windows
-# and Mac users are advised to set this option to NO.
-# The default value is: system dependent.
-
-CASE_SENSE_NAMES       = NO
-
-# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with
-# their full class and namespace scopes in the documentation. If set to YES, the
-# scope will be hidden.
-# The default value is: NO.
-
-HIDE_SCOPE_NAMES       = YES
-
-# If the HIDE_COMPOUND_REFERENCE tag is set to NO (default) then doxygen will
-# append additional text to a page's title, such as Class Reference. If set to
-# YES the compound reference will be hidden.
-# The default value is: NO.
-
-HIDE_COMPOUND_REFERENCE= NO
-
-# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of
-# the files that are included by a file in the documentation of that file.
-# The default value is: YES.
-
-SHOW_INCLUDE_FILES     = YES
-
-# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each
-# grouped member an include statement to the documentation, telling the reader
-# which file to include in order to use the member.
-# The default value is: NO.
-
-SHOW_GROUPED_MEMB_INC  = NO
-
-# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include
-# files with double quotes in the documentation rather than with sharp brackets.
-# The default value is: NO.
-
-FORCE_LOCAL_INCLUDES   = NO
-
-# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the
-# documentation for inline members.
-# The default value is: YES.
-
-INLINE_INFO            = YES
-
-# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the
-# (detailed) documentation of file and class members alphabetically by member
-# name. If set to NO, the members will appear in declaration order.
-# The default value is: YES.
-
-SORT_MEMBER_DOCS       = YES
-
-# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief
-# descriptions of file, namespace and class members alphabetically by member
-# name. If set to NO, the members will appear in declaration order. Note that
-# this will also influence the order of the classes in the class list.
-# The default value is: NO.
-
-SORT_BRIEF_DOCS        = NO
-
-# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the
-# (brief and detailed) documentation of class members so that constructors and
-# destructors are listed first. If set to NO the constructors will appear in the
-# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS.
-# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief
-# member documentation.
-# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting
-# detailed member documentation.
-# The default value is: NO.
-
-SORT_MEMBERS_CTORS_1ST = NO
-
-# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy
-# of group names into alphabetical order. If set to NO the group names will
-# appear in their defined order.
-# The default value is: NO.
-
-SORT_GROUP_NAMES       = NO
-
-# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by
-# fully-qualified names, including namespaces. If set to NO, the class list will
-# be sorted only by class name, not including the namespace part.
-# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
-# Note: This option applies only to the class list, not to the alphabetical
-# list.
-# The default value is: NO.
-
-SORT_BY_SCOPE_NAME     = NO
-
-# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper
-# type resolution of all parameters of a function it will reject a match between
-# the prototype and the implementation of a member function even if there is
-# only one candidate or it is obvious which candidate to choose by doing a
-# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still
-# accept a match between prototype and implementation in such cases.
-# The default value is: NO.
-
-STRICT_PROTO_MATCHING  = NO
-
-# The GENERATE_TODOLIST tag can be used to enable (YES) or disable (NO) the todo
-# list. This list is created by putting \todo commands in the documentation.
-# The default value is: YES.
-
-GENERATE_TODOLIST      = YES
-
-# The GENERATE_TESTLIST tag can be used to enable (YES) or disable (NO) the test
-# list. This list is created by putting \test commands in the documentation.
-# The default value is: YES.
-
-GENERATE_TESTLIST      = YES
-
-# The GENERATE_BUGLIST tag can be used to enable (YES) or disable (NO) the bug
-# list. This list is created by putting \bug commands in the documentation.
-# The default value is: YES.
-
-GENERATE_BUGLIST       = YES
-
-# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or disable (NO)
-# the deprecated list. This list is created by putting \deprecated commands in
-# the documentation.
-# The default value is: YES.
-
-GENERATE_DEPRECATEDLIST= YES
-
-# The ENABLED_SECTIONS tag can be used to enable conditional documentation
-# sections, marked by \if <section_label> ... \endif and \cond <section_label>
-# ... \endcond blocks.
-
-ENABLED_SECTIONS       = 
-
-# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the
-# initial value of a variable or macro / define can have for it to appear in the
-# documentation. If the initializer consists of more lines than specified here
-# it will be hidden. Use a value of 0 to hide initializers completely. The
-# appearance of the value of individual variables and macros / defines can be
-# controlled using \showinitializer or \hideinitializer command in the
-# documentation regardless of this setting.
-# Minimum value: 0, maximum value: 10000, default value: 30.
-
-MAX_INITIALIZER_LINES  = 30
-
-# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at
-# the bottom of the documentation of classes and structs. If set to YES, the
-# list will mention the files that were used to generate the documentation.
-# The default value is: YES.
-
-SHOW_USED_FILES        = YES
-
-# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This
-# will remove the Files entry from the Quick Index and from the Folder Tree View
-# (if specified).
-# The default value is: YES.
-
-SHOW_FILES             = YES
-
-# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces
-# page. This will remove the Namespaces entry from the Quick Index and from the
-# Folder Tree View (if specified).
-# The default value is: YES.
-
-SHOW_NAMESPACES        = YES
-
-# The FILE_VERSION_FILTER tag can be used to specify a program or script that
-# doxygen should invoke to get the current version for each file (typically from
-# the version control system). Doxygen will invoke the program by executing (via
-# popen()) the command command input-file, where command is the value of the
-# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided
-# by doxygen. Whatever the program writes to standard output is used as the file
-# version. For an example see the documentation.
-
-FILE_VERSION_FILTER    = 
-
-# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed
-# by doxygen. The layout file controls the global structure of the generated
-# output files in an output format independent way. To create the layout file
-# that represents doxygen's defaults, run doxygen with the -l option. You can
-# optionally specify a file name after the option, if omitted DoxygenLayout.xml
-# will be used as the name of the layout file.
-#
-# Note that if you run doxygen from a directory containing a file called
-# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE
-# tag is left empty.
-
-LAYOUT_FILE            = 
-
-# The CITE_BIB_FILES tag can be used to specify one or more bib files containing
-# the reference definitions. This must be a list of .bib files. The .bib
-# extension is automatically appended if omitted. This requires the bibtex tool
-# to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info.
-# For LaTeX the style of the bibliography can be controlled using
-# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the
-# search path. See also \cite for info how to create references.
-
-CITE_BIB_FILES         = 
-
-#---------------------------------------------------------------------------
-# Configuration options related to warning and progress messages
-#---------------------------------------------------------------------------
-
-# The QUIET tag can be used to turn on/off the messages that are generated to
-# standard output by doxygen. If QUIET is set to YES this implies that the
-# messages are off.
-# The default value is: NO.
-
-QUIET                  = NO
-
-# The WARNINGS tag can be used to turn on/off the warning messages that are
-# generated to standard error (stderr) by doxygen. If WARNINGS is set to YES
-# this implies that the warnings are on.
-#
-# Tip: Turn warnings on while writing the documentation.
-# The default value is: YES.
-
-WARNINGS               = YES
-
-# If the WARN_IF_UNDOCUMENTED tag is set to YES then doxygen will generate
-# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag
-# will automatically be disabled.
-# The default value is: YES.
-
-WARN_IF_UNDOCUMENTED   = YES
-
-# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for
-# potential errors in the documentation, such as not documenting some parameters
-# in a documented function, or documenting parameters that don't exist or using
-# markup commands wrongly.
-# The default value is: YES.
-
-WARN_IF_DOC_ERROR      = YES
-
-# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that
-# are documented, but have no documentation for their parameters or return
-# value. If set to NO, doxygen will only warn about wrong or incomplete
-# parameter documentation, but not about the absence of documentation.
-# The default value is: NO.
-
-WARN_NO_PARAMDOC       = NO
-
-# If the WARN_AS_ERROR tag is set to YES then doxygen will immediately stop when
-# a warning is encountered.
-# The default value is: NO.
-
-WARN_AS_ERROR          = NO
-
-# The WARN_FORMAT tag determines the format of the warning messages that doxygen
-# can produce. The string should contain the $file, $line, and $text tags, which
-# will be replaced by the file and line number from which the warning originated
-# and the warning text. Optionally the format may contain $version, which will
-# be replaced by the version of the file (if it could be obtained via
-# FILE_VERSION_FILTER)
-# The default value is: $file:$line: $text.
-
-WARN_FORMAT            = "$file:$line: $text"
-
-# The WARN_LOGFILE tag can be used to specify a file to which warning and error
-# messages should be written. If left blank the output is written to standard
-# error (stderr).
-
-WARN_LOGFILE           = 
-
-#---------------------------------------------------------------------------
-# Configuration options related to the input files
-#---------------------------------------------------------------------------
-
-# The INPUT tag is used to specify the files and/or directories that contain
-# documented source files. You may enter file names like myfile.cpp or
-# directories like /usr/src/myproject. Separate the files or directories with
-# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING
-# Note: If this tag is empty the current directory is searched.
-
-INPUT                  = ../core/
-
-# This tag can be used to specify the character encoding of the source files
-# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
-# libiconv (or the iconv built into libc) for the transcoding. See the libiconv
-# documentation (see: http://www.gnu.org/software/libiconv) for the list of
-# possible encodings.
-# The default value is: UTF-8.
-
-INPUT_ENCODING         = UTF-8
-
-# If the value of the INPUT tag contains directories, you can use the
-# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and
-# *.h) to filter out the source-files in the directories.
-#
-# Note that for custom extensions or not directly supported extensions you also
-# need to set EXTENSION_MAPPING for the extension otherwise the files are not
-# read by doxygen.
-#
-# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp,
-# *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h,
-# *.hh, *.hxx, *.hpp, *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc,
-# *.m, *.markdown, *.md, *.mm, *.dox, *.py, *.pyw, *.f90, *.f, *.for, *.tcl,
-# *.vhd, *.vhdl, *.ucf, *.qsf, *.as and *.js.
-
-FILE_PATTERNS          = *.c \
-                         *.cc \
-                         *.cxx \
-                         *.cpp \
-                         *.c++ \
-                         *.java \
-                         *.ii \
-                         *.ixx \
-                         *.ipp \
-                         *.i++ \
-                         *.inl \
-                         *.idl \
-                         *.ddl \
-                         *.odl \
-                         *.h \
-                         *.hh \
-                         *.hxx \
-                         *.hpp \
-                         *.h++ \
-                         *.cs \
-                         *.d \
-                         *.php \
-                         *.php4 \
-                         *.php5 \
-                         *.phtml \
-                         *.inc \
-                         *.m \
-                         *.markdown \
-                         *.md \
-                         *.mm \
-                         *.dox \
-                         *.py \
-                         *.pyw \
-                         *.f90 \
-                         *.f \
-                         *.for \
-                         *.tcl \
-                         *.vhd \
-                         *.vhdl \
-                         *.ucf \
-                         *.qsf \
-                         *.as \
-                         *.js
-
-# The RECURSIVE tag can be used to specify whether or not subdirectories should
-# be searched for input files as well.
-# The default value is: NO.
-
-RECURSIVE              = YES
-
-# The EXCLUDE tag can be used to specify files and/or directories that should be
-# excluded from the INPUT source files. This way you can easily exclude a
-# subdirectory from a directory tree whose root is specified with the INPUT tag.
-#
-# Note that relative paths are relative to the directory from which doxygen is
-# run.
-
-EXCLUDE                = 
-
-# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
-# directories that are symbolic links (a Unix file system feature) are excluded
-# from the input.
-# The default value is: NO.
-
-EXCLUDE_SYMLINKS       = NO
-
-# If the value of the INPUT tag contains directories, you can use the
-# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
-# certain files from those directories.
-#
-# Note that the wildcards are matched against the file with absolute path, so to
-# exclude all test directories for example use the pattern */test/*
-
-EXCLUDE_PATTERNS       = 
-
-# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
-# (namespaces, classes, functions, etc.) that should be excluded from the
-# output. The symbol name can be a fully qualified name, a word, or if the
-# wildcard * is used, a substring. Examples: ANamespace, AClass,
-# AClass::ANamespace, ANamespace::*Test
-#
-# Note that the wildcards are matched against the file with absolute path, so to
-# exclude all test directories use the pattern */test/*
-
-EXCLUDE_SYMBOLS        = 
-
-# The EXAMPLE_PATH tag can be used to specify one or more files or directories
-# that contain example code fragments that are included (see the \include
-# command).
-
-EXAMPLE_PATH           = 
-
-# If the value of the EXAMPLE_PATH tag contains directories, you can use the
-# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and
-# *.h) to filter out the source-files in the directories. If left blank all
-# files are included.
-
-EXAMPLE_PATTERNS       = *
-
-# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
-# searched for input files to be used with the \include or \dontinclude commands
-# irrespective of the value of the RECURSIVE tag.
-# The default value is: NO.
-
-EXAMPLE_RECURSIVE      = NO
-
-# The IMAGE_PATH tag can be used to specify one or more files or directories
-# that contain images that are to be included in the documentation (see the
-# \image command).
-
-IMAGE_PATH             = 
-
-# The INPUT_FILTER tag can be used to specify a program that doxygen should
-# invoke to filter for each input file. Doxygen will invoke the filter program
-# by executing (via popen()) the command:
-#
-# <filter> <input-file>
-#
-# where <filter> is the value of the INPUT_FILTER tag, and <input-file> is the
-# name of an input file. Doxygen will then use the output that the filter
-# program writes to standard output. If FILTER_PATTERNS is specified, this tag
-# will be ignored.
-#
-# Note that the filter must not add or remove lines; it is applied before the
-# code is scanned, but not when the output code is generated. If lines are added
-# or removed, the anchors will not be placed correctly.
-#
-# Note that for custom extensions or not directly supported extensions you also
-# need to set EXTENSION_MAPPING for the extension otherwise the files are not
-# properly processed by doxygen.
-
-INPUT_FILTER           = 
-
-# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
-# basis. Doxygen will compare the file name with each pattern and apply the
-# filter if there is a match. The filters are a list of the form: pattern=filter
-# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how
-# filters are used. If the FILTER_PATTERNS tag is empty or if none of the
-# patterns match the file name, INPUT_FILTER is applied.
-#
-# Note that for custom extensions or not directly supported extensions you also
-# need to set EXTENSION_MAPPING for the extension otherwise the files are not
-# properly processed by doxygen.
-
-FILTER_PATTERNS        = 
-
-# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
-# INPUT_FILTER) will also be used to filter the input files that are used for
-# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES).
-# The default value is: NO.
-
-FILTER_SOURCE_FILES    = NO
-
-# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file
-# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and
-# it is also possible to disable source filtering for a specific pattern using
-# *.ext= (so without naming a filter).
-# This tag requires that the tag FILTER_SOURCE_FILES is set to YES.
-
-FILTER_SOURCE_PATTERNS = 
-
-# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that
-# is part of the input, its contents will be placed on the main page
-# (index.html). This can be useful if you have a project on for instance GitHub
-# and want to reuse the introduction page also for the doxygen output.
-
-USE_MDFILE_AS_MAINPAGE = 
-
-#---------------------------------------------------------------------------
-# Configuration options related to source browsing
-#---------------------------------------------------------------------------
-
-# If the SOURCE_BROWSER tag is set to YES then a list of source files will be
-# generated. Documented entities will be cross-referenced with these sources.
-#
-# Note: To get rid of all source code in the generated output, make sure that
-# also VERBATIM_HEADERS is set to NO.
-# The default value is: NO.
-
-SOURCE_BROWSER         = NO
-
-# Setting the INLINE_SOURCES tag to YES will include the body of functions,
-# classes and enums directly into the documentation.
-# The default value is: NO.
-
-INLINE_SOURCES         = NO
-
-# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any
-# special comment blocks from generated source code fragments. Normal C, C++ and
-# Fortran comments will always remain visible.
-# The default value is: YES.
-
-STRIP_CODE_COMMENTS    = YES
-
-# If the REFERENCED_BY_RELATION tag is set to YES then for each documented
-# function all documented functions referencing it will be listed.
-# The default value is: NO.
-
-REFERENCED_BY_RELATION = NO
-
-# If the REFERENCES_RELATION tag is set to YES then for each documented function
-# all documented entities called/used by that function will be listed.
-# The default value is: NO.
-
-REFERENCES_RELATION    = NO
-
-# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set
-# to YES then the hyperlinks from functions in REFERENCES_RELATION and
-# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will
-# link to the documentation.
-# The default value is: YES.
-
-REFERENCES_LINK_SOURCE = YES
-
-# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the
-# source code will show a tooltip with additional information such as prototype,
-# brief description and links to the definition and documentation. Since this
-# will make the HTML file larger and loading of large files a bit slower, you
-# can opt to disable this feature.
-# The default value is: YES.
-# This tag requires that the tag SOURCE_BROWSER is set to YES.
-
-SOURCE_TOOLTIPS        = YES
-
-# If the USE_HTAGS tag is set to YES then the references to source code will
-# point to the HTML generated by the htags(1) tool instead of doxygen built-in
-# source browser. The htags tool is part of GNU's global source tagging system
-# (see http://www.gnu.org/software/global/global.html). You will need version
-# 4.8.6 or higher.
-#
-# To use it do the following:
-# - Install the latest version of global
-# - Enable SOURCE_BROWSER and USE_HTAGS in the config file
-# - Make sure the INPUT points to the root of the source tree
-# - Run doxygen as normal
-#
-# Doxygen will invoke htags (and that will in turn invoke gtags), so these
-# tools must be available from the command line (i.e. in the search path).
-#
-# The result: instead of the source browser generated by doxygen, the links to
-# source code will now point to the output of htags.
-# The default value is: NO.
-# This tag requires that the tag SOURCE_BROWSER is set to YES.
-
-USE_HTAGS              = NO
-
-# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a
-# verbatim copy of the header file for each class for which an include is
-# specified. Set to NO to disable this.
-# See also: Section \class.
-# The default value is: YES.
-
-VERBATIM_HEADERS       = YES
-
-# If the CLANG_ASSISTED_PARSING tag is set to YES then doxygen will use the
-# clang parser (see: http://clang.llvm.org/) for more accurate parsing at the
-# cost of reduced performance. This can be particularly helpful with template
-# rich C++ code for which doxygen's built-in parser lacks the necessary type
-# information.
-# Note: The availability of this option depends on whether or not doxygen was
-# generated with the -Duse-libclang=ON option for CMake.
-# The default value is: NO.
-
-CLANG_ASSISTED_PARSING = NO
-
-# If clang assisted parsing is enabled you can provide the compiler with command
-# line options that you would normally use when invoking the compiler. Note that
-# the include paths will already be set by doxygen for the files and directories
-# specified with INPUT and INCLUDE_PATH.
-# This tag requires that the tag CLANG_ASSISTED_PARSING is set to YES.
-
-CLANG_OPTIONS          = 
-
-#---------------------------------------------------------------------------
-# Configuration options related to the alphabetical class index
-#---------------------------------------------------------------------------
-
-# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all
-# compounds will be generated. Enable this if the project contains a lot of
-# classes, structs, unions or interfaces.
-# The default value is: YES.
-
-ALPHABETICAL_INDEX     = YES
-
-# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in
-# which the alphabetical index list will be split.
-# Minimum value: 1, maximum value: 20, default value: 5.
-# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
-
-COLS_IN_ALPHA_INDEX    = 5
-
-# In case all classes in a project start with a common prefix, all classes will
-# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag
-# can be used to specify a prefix (or a list of prefixes) that should be ignored
-# while generating the index headers.
-# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
-
-IGNORE_PREFIX          = 
-
-#---------------------------------------------------------------------------
-# Configuration options related to the HTML output
-#---------------------------------------------------------------------------
-
-# If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output
-# The default value is: YES.
-
-GENERATE_HTML          = YES
-
-# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a
-# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
-# it.
-# The default directory is: html.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-HTML_OUTPUT            = html
-
-# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each
-# generated HTML page (for example: .htm, .php, .asp).
-# The default value is: .html.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-HTML_FILE_EXTENSION    = .html
-
-# The HTML_HEADER tag can be used to specify a user-defined HTML header file for
-# each generated HTML page. If the tag is left blank doxygen will generate a
-# standard header.
-#
-# To get valid HTML the header file that includes any scripts and style sheets
-# that doxygen needs, which is dependent on the configuration options used (e.g.
-# the setting GENERATE_TREEVIEW). It is highly recommended to start with a
-# default header using
-# doxygen -w html new_header.html new_footer.html new_stylesheet.css
-# YourConfigFile
-# and then modify the file new_header.html. See also section "Doxygen usage"
-# for information on how to generate the default header that doxygen normally
-# uses.
-# Note: The header is subject to change so you typically have to regenerate the
-# default header when upgrading to a newer version of doxygen. For a description
-# of the possible markers and block names see the documentation.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-HTML_HEADER            = 
-
-# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each
-# generated HTML page. If the tag is left blank doxygen will generate a standard
-# footer. See HTML_HEADER for more information on how to generate a default
-# footer and what special commands can be used inside the footer. See also
-# section "Doxygen usage" for information on how to generate the default footer
-# that doxygen normally uses.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-HTML_FOOTER            = 
-
-# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style
-# sheet that is used by each HTML page. It can be used to fine-tune the look of
-# the HTML output. If left blank doxygen will generate a default style sheet.
-# See also section "Doxygen usage" for information on how to generate the style
-# sheet that doxygen normally uses.
-# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as
-# it is more robust and this tag (HTML_STYLESHEET) will in the future become
-# obsolete.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-HTML_STYLESHEET        = 
-
-# The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined
-# cascading style sheets that are included after the standard style sheets
-# created by doxygen. Using this option one can overrule certain style aspects.
-# This is preferred over using HTML_STYLESHEET since it does not replace the
-# standard style sheet and is therefore more robust against future updates.
-# Doxygen will copy the style sheet files to the output directory.
-# Note: The order of the extra style sheet files is of importance (e.g. the last
-# style sheet in the list overrules the setting of the previous ones in the
-# list). For an example see the documentation.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-HTML_EXTRA_STYLESHEET  = 
-
-# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or
-# other source files which should be copied to the HTML output directory. Note
-# that these files will be copied to the base HTML output directory. Use the
-# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these
-# files. In the HTML_STYLESHEET file, use the file name only. Also note that the
-# files will be copied as-is; there are no commands or markers available.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-HTML_EXTRA_FILES       = 
-
-# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen
-# will adjust the colors in the style sheet and background images according to
-# this color. Hue is specified as an angle on a colorwheel, see
-# http://en.wikipedia.org/wiki/Hue for more information. For instance the value
-# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300
-# purple, and 360 is red again.
-# Minimum value: 0, maximum value: 359, default value: 220.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-HTML_COLORSTYLE_HUE    = 220
-
-# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors
-# in the HTML output. For a value of 0 the output will use grayscales only. A
-# value of 255 will produce the most vivid colors.
-# Minimum value: 0, maximum value: 255, default value: 100.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-HTML_COLORSTYLE_SAT    = 100
-
-# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the
-# luminance component of the colors in the HTML output. Values below 100
-# gradually make the output lighter, whereas values above 100 make the output
-# darker. The value divided by 100 is the actual gamma applied, so 80 represents
-# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not
-# change the gamma.
-# Minimum value: 40, maximum value: 240, default value: 80.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-HTML_COLORSTYLE_GAMMA  = 80
-
-# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML
-# page will contain the date and time when the page was generated. Setting this
-# to YES can help to show when doxygen was last run and thus if the
-# documentation is up to date.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-HTML_TIMESTAMP         = NO
-
-# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
-# documentation will contain sections that can be hidden and shown after the
-# page has loaded.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-HTML_DYNAMIC_SECTIONS  = NO
-
-# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries
-# shown in the various tree structured indices initially; the user can expand
-# and collapse entries dynamically later on. Doxygen will expand the tree to
-# such a level that at most the specified number of entries are visible (unless
-# a fully collapsed tree already exceeds this amount). So setting the number of
-# entries 1 will produce a full collapsed tree by default. 0 is a special value
-# representing an infinite number of entries and will result in a full expanded
-# tree by default.
-# Minimum value: 0, maximum value: 9999, default value: 100.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-HTML_INDEX_NUM_ENTRIES = 100
-
-# If the GENERATE_DOCSET tag is set to YES, additional index files will be
-# generated that can be used as input for Apple's Xcode 3 integrated development
-# environment (see: http://developer.apple.com/tools/xcode/), introduced with
-# OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a
-# Makefile in the HTML output directory. Running make will produce the docset in
-# that directory and running make install will install the docset in
-# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at
-# startup. See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html
-# for more information.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-GENERATE_DOCSET        = NO
-
-# This tag determines the name of the docset feed. A documentation feed provides
-# an umbrella under which multiple documentation sets from a single provider
-# (such as a company or product suite) can be grouped.
-# The default value is: Doxygen generated docs.
-# This tag requires that the tag GENERATE_DOCSET is set to YES.
-
-DOCSET_FEEDNAME        = "Doxygen generated docs"
-
-# This tag specifies a string that should uniquely identify the documentation
-# set bundle. This should be a reverse domain-name style string, e.g.
-# com.mycompany.MyDocSet. Doxygen will append .docset to the name.
-# The default value is: org.doxygen.Project.
-# This tag requires that the tag GENERATE_DOCSET is set to YES.
-
-DOCSET_BUNDLE_ID       = org.doxygen.Project
-
-# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify
-# the documentation publisher. This should be a reverse domain-name style
-# string, e.g. com.mycompany.MyDocSet.documentation.
-# The default value is: org.doxygen.Publisher.
-# This tag requires that the tag GENERATE_DOCSET is set to YES.
-
-DOCSET_PUBLISHER_ID    = org.doxygen.Publisher
-
-# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher.
-# The default value is: Publisher.
-# This tag requires that the tag GENERATE_DOCSET is set to YES.
-
-DOCSET_PUBLISHER_NAME  = Publisher
-
-# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three
-# additional HTML index files: index.hhp, index.hhc, and index.hhk. The
-# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop
-# (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on
-# Windows.
-#
-# The HTML Help Workshop contains a compiler that can convert all HTML output
-# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML
-# files are now used as the Windows 98 help format, and will replace the old
-# Windows help format (.hlp) on all Windows platforms in the future. Compressed
-# HTML files also contain an index, a table of contents, and you can search for
-# words in the documentation. The HTML workshop also contains a viewer for
-# compressed HTML files.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-GENERATE_HTMLHELP      = NO
-
-# The CHM_FILE tag can be used to specify the file name of the resulting .chm
-# file. You can add a path in front of the file if the result should not be
-# written to the html output directory.
-# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
-
-CHM_FILE               = 
-
-# The HHC_LOCATION tag can be used to specify the location (absolute path
-# including file name) of the HTML help compiler (hhc.exe). If non-empty,
-# doxygen will try to run the HTML help compiler on the generated index.hhp.
-# The file has to be specified with full path.
-# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
-
-HHC_LOCATION           = 
-
-# The GENERATE_CHI flag controls if a separate .chi index file is generated
-# (YES) or that it should be included in the master .chm file (NO).
-# The default value is: NO.
-# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
-
-GENERATE_CHI           = NO
-
-# The CHM_INDEX_ENCODING is used to encode HtmlHelp index (hhk), content (hhc)
-# and project file content.
-# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
-
-CHM_INDEX_ENCODING     = 
-
-# The BINARY_TOC flag controls whether a binary table of contents is generated
-# (YES) or a normal table of contents (NO) in the .chm file. Furthermore it
-# enables the Previous and Next buttons.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
-
-BINARY_TOC             = NO
-
-# The TOC_EXPAND flag can be set to YES to add extra items for group members to
-# the table of contents of the HTML help documentation and to the tree view.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
-
-TOC_EXPAND             = NO
-
-# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and
-# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that
-# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help
-# (.qch) of the generated HTML documentation.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-GENERATE_QHP           = NO
-
-# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify
-# the file name of the resulting .qch file. The path specified is relative to
-# the HTML output folder.
-# This tag requires that the tag GENERATE_QHP is set to YES.
-
-QCH_FILE               = 
-
-# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help
-# Project output. For more information please see Qt Help Project / Namespace
-# (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#namespace).
-# The default value is: org.doxygen.Project.
-# This tag requires that the tag GENERATE_QHP is set to YES.
-
-QHP_NAMESPACE          = org.doxygen.Project
-
-# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt
-# Help Project output. For more information please see Qt Help Project / Virtual
-# Folders (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#virtual-
-# folders).
-# The default value is: doc.
-# This tag requires that the tag GENERATE_QHP is set to YES.
-
-QHP_VIRTUAL_FOLDER     = doc
-
-# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom
-# filter to add. For more information please see Qt Help Project / Custom
-# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
-# filters).
-# This tag requires that the tag GENERATE_QHP is set to YES.
-
-QHP_CUST_FILTER_NAME   = 
-
-# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the
-# custom filter to add. For more information please see Qt Help Project / Custom
-# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
-# filters).
-# This tag requires that the tag GENERATE_QHP is set to YES.
-
-QHP_CUST_FILTER_ATTRS  = 
-
-# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this
-# project's filter section matches. Qt Help Project / Filter Attributes (see:
-# http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes).
-# This tag requires that the tag GENERATE_QHP is set to YES.
-
-QHP_SECT_FILTER_ATTRS  = 
-
-# The QHG_LOCATION tag can be used to specify the location of Qt's
-# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the
-# generated .qhp file.
-# This tag requires that the tag GENERATE_QHP is set to YES.
-
-QHG_LOCATION           = 
-
-# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be
-# generated, together with the HTML files, they form an Eclipse help plugin. To
-# install this plugin and make it available under the help contents menu in
-# Eclipse, the contents of the directory containing the HTML and XML files needs
-# to be copied into the plugins directory of eclipse. The name of the directory
-# within the plugins directory should be the same as the ECLIPSE_DOC_ID value.
-# After copying Eclipse needs to be restarted before the help appears.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-GENERATE_ECLIPSEHELP   = NO
-
-# A unique identifier for the Eclipse help plugin. When installing the plugin
-# the directory name containing the HTML and XML files should also have this
-# name. Each documentation set should have its own identifier.
-# The default value is: org.doxygen.Project.
-# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES.
-
-ECLIPSE_DOC_ID         = org.doxygen.Project
-
-# If you want full control over the layout of the generated HTML pages it might
-# be necessary to disable the index and replace it with your own. The
-# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top
-# of each HTML page. A value of NO enables the index and the value YES disables
-# it. Since the tabs in the index contain the same information as the navigation
-# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-DISABLE_INDEX          = NO
-
-# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
-# structure should be generated to display hierarchical information. If the tag
-# value is set to YES, a side panel will be generated containing a tree-like
-# index structure (just like the one that is generated for HTML Help). For this
-# to work a browser that supports JavaScript, DHTML, CSS and frames is required
-# (i.e. any modern browser). Windows users are probably better off using the
-# HTML help feature. Via custom style sheets (see HTML_EXTRA_STYLESHEET) one can
-# further fine-tune the look of the index. As an example, the default style
-# sheet generated by doxygen has an example that shows how to put an image at
-# the root of the tree instead of the PROJECT_NAME. Since the tree basically has
-# the same information as the tab index, you could consider setting
-# DISABLE_INDEX to YES when enabling this option.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-GENERATE_TREEVIEW      = NO
-
-# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that
-# doxygen will group on one line in the generated HTML documentation.
-#
-# Note that a value of 0 will completely suppress the enum values from appearing
-# in the overview section.
-# Minimum value: 0, maximum value: 20, default value: 4.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-ENUM_VALUES_PER_LINE   = 4
-
-# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used
-# to set the initial width (in pixels) of the frame in which the tree is shown.
-# Minimum value: 0, maximum value: 1500, default value: 250.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-TREEVIEW_WIDTH         = 250
-
-# If the EXT_LINKS_IN_WINDOW option is set to YES, doxygen will open links to
-# external symbols imported via tag files in a separate window.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-EXT_LINKS_IN_WINDOW    = NO
-
-# Use this tag to change the font size of LaTeX formulas included as images in
-# the HTML documentation. When you change the font size after a successful
-# doxygen run you need to manually remove any form_*.png images from the HTML
-# output directory to force them to be regenerated.
-# Minimum value: 8, maximum value: 50, default value: 10.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-FORMULA_FONTSIZE       = 10
-
-# Use the FORMULA_TRANPARENT tag to determine whether or not the images
-# generated for formulas are transparent PNGs. Transparent PNGs are not
-# supported properly for IE 6.0, but are supported on all modern browsers.
-#
-# Note that when changing this option you need to delete any form_*.png files in
-# the HTML output directory before the changes have effect.
-# The default value is: YES.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-FORMULA_TRANSPARENT    = YES
-
-# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see
-# http://www.mathjax.org) which uses client side Javascript for the rendering
-# instead of using pre-rendered bitmaps. Use this if you do not have LaTeX
-# installed or if you want to formulas look prettier in the HTML output. When
-# enabled you may also need to install MathJax separately and configure the path
-# to it using the MATHJAX_RELPATH option.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-USE_MATHJAX            = NO
-
-# When MathJax is enabled you can set the default output format to be used for
-# the MathJax output. See the MathJax site (see:
-# http://docs.mathjax.org/en/latest/output.html) for more details.
-# Possible values are: HTML-CSS (which is slower, but has the best
-# compatibility), NativeMML (i.e. MathML) and SVG.
-# The default value is: HTML-CSS.
-# This tag requires that the tag USE_MATHJAX is set to YES.
-
-MATHJAX_FORMAT         = HTML-CSS
-
-# When MathJax is enabled you need to specify the location relative to the HTML
-# output directory using the MATHJAX_RELPATH option. The destination directory
-# should contain the MathJax.js script. For instance, if the mathjax directory
-# is located at the same level as the HTML output directory, then
-# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax
-# Content Delivery Network so you can quickly see the result without installing
-# MathJax. However, it is strongly recommended to install a local copy of
-# MathJax from http://www.mathjax.org before deployment.
-# The default value is: http://cdn.mathjax.org/mathjax/latest.
-# This tag requires that the tag USE_MATHJAX is set to YES.
-
-MATHJAX_RELPATH        = http://cdn.mathjax.org/mathjax/latest
-
-# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax
-# extension names that should be enabled during MathJax rendering. For example
-# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols
-# This tag requires that the tag USE_MATHJAX is set to YES.
-
-MATHJAX_EXTENSIONS     = 
-
-# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces
-# of code that will be used on startup of the MathJax code. See the MathJax site
-# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an
-# example see the documentation.
-# This tag requires that the tag USE_MATHJAX is set to YES.
-
-MATHJAX_CODEFILE       = 
-
-# When the SEARCHENGINE tag is enabled doxygen will generate a search box for
-# the HTML output. The underlying search engine uses javascript and DHTML and
-# should work on any modern browser. Note that when using HTML help
-# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET)
-# there is already a search function so this one should typically be disabled.
-# For large projects the javascript based search engine can be slow, then
-# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to
-# search using the keyboard; to jump to the search box use <access key> + S
-# (what the <access key> is depends on the OS and browser, but it is typically
-# <CTRL>, <ALT>/<option>, or both). Inside the search box use the <cursor down
-# key> to jump into the search results window, the results can be navigated
-# using the <cursor keys>. Press <Enter> to select an item or <escape> to cancel
-# the search. The filter options can be selected when the cursor is inside the
-# search box by pressing <Shift>+<cursor down>. Also here use the <cursor keys>
-# to select a filter and <Enter> or <escape> to activate or cancel the filter
-# option.
-# The default value is: YES.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-SEARCHENGINE           = YES
-
-# When the SERVER_BASED_SEARCH tag is enabled the search engine will be
-# implemented using a web server instead of a web client using Javascript. There
-# are two flavors of web server based searching depending on the EXTERNAL_SEARCH
-# setting. When disabled, doxygen will generate a PHP script for searching and
-# an index file used by the script. When EXTERNAL_SEARCH is enabled the indexing
-# and searching needs to be provided by external tools. See the section
-# "External Indexing and Searching" for details.
-# The default value is: NO.
-# This tag requires that the tag SEARCHENGINE is set to YES.
-
-SERVER_BASED_SEARCH    = NO
-
-# When EXTERNAL_SEARCH tag is enabled doxygen will no longer generate the PHP
-# script for searching. Instead the search results are written to an XML file
-# which needs to be processed by an external indexer. Doxygen will invoke an
-# external search engine pointed to by the SEARCHENGINE_URL option to obtain the
-# search results.
-#
-# Doxygen ships with an example indexer (doxyindexer) and search engine
-# (doxysearch.cgi) which are based on the open source search engine library
-# Xapian (see: http://xapian.org/).
-#
-# See the section "External Indexing and Searching" for details.
-# The default value is: NO.
-# This tag requires that the tag SEARCHENGINE is set to YES.
-
-EXTERNAL_SEARCH        = NO
-
-# The SEARCHENGINE_URL should point to a search engine hosted by a web server
-# which will return the search results when EXTERNAL_SEARCH is enabled.
-#
-# Doxygen ships with an example indexer (doxyindexer) and search engine
-# (doxysearch.cgi) which are based on the open source search engine library
-# Xapian (see: http://xapian.org/). See the section "External Indexing and
-# Searching" for details.
-# This tag requires that the tag SEARCHENGINE is set to YES.
-
-SEARCHENGINE_URL       = 
-
-# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed
-# search data is written to a file for indexing by an external tool. With the
-# SEARCHDATA_FILE tag the name of this file can be specified.
-# The default file is: searchdata.xml.
-# This tag requires that the tag SEARCHENGINE is set to YES.
-
-SEARCHDATA_FILE        = searchdata.xml
-
-# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the
-# EXTERNAL_SEARCH_ID tag can be used as an identifier for the project. This is
-# useful in combination with EXTRA_SEARCH_MAPPINGS to search through multiple
-# projects and redirect the results back to the right project.
-# This tag requires that the tag SEARCHENGINE is set to YES.
-
-EXTERNAL_SEARCH_ID     = 
-
-# The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through doxygen
-# projects other than the one defined by this configuration file, but that are
-# all added to the same external search index. Each project needs to have a
-# unique id set via EXTERNAL_SEARCH_ID. The search mapping then maps the id of
-# to a relative location where the documentation can be found. The format is:
-# EXTRA_SEARCH_MAPPINGS = tagname1=loc1 tagname2=loc2 ...
-# This tag requires that the tag SEARCHENGINE is set to YES.
-
-EXTRA_SEARCH_MAPPINGS  = 
-
-#---------------------------------------------------------------------------
-# Configuration options related to the LaTeX output
-#---------------------------------------------------------------------------
-
-# If the GENERATE_LATEX tag is set to YES, doxygen will generate LaTeX output.
-# The default value is: YES.
-
-GENERATE_LATEX         = YES
-
-# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. If a
-# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
-# it.
-# The default directory is: latex.
-# This tag requires that the tag GENERATE_LATEX is set to YES.
-
-LATEX_OUTPUT           = latex
-
-# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
-# invoked.
-#
-# Note that when enabling USE_PDFLATEX this option is only used for generating
-# bitmaps for formulas in the HTML output, but not in the Makefile that is
-# written to the output directory.
-# The default file is: latex.
-# This tag requires that the tag GENERATE_LATEX is set to YES.
-
-LATEX_CMD_NAME         = latex
-
-# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to generate
-# index for LaTeX.
-# The default file is: makeindex.
-# This tag requires that the tag GENERATE_LATEX is set to YES.
-
-MAKEINDEX_CMD_NAME     = makeindex
-
-# If the COMPACT_LATEX tag is set to YES, doxygen generates more compact LaTeX
-# documents. This may be useful for small projects and may help to save some
-# trees in general.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_LATEX is set to YES.
-
-COMPACT_LATEX          = NO
-
-# The PAPER_TYPE tag can be used to set the paper type that is used by the
-# printer.
-# Possible values are: a4 (210 x 297 mm), letter (8.5 x 11 inches), legal (8.5 x
-# 14 inches) and executive (7.25 x 10.5 inches).
-# The default value is: a4.
-# This tag requires that the tag GENERATE_LATEX is set to YES.
-
-PAPER_TYPE             = a4
-
-# The EXTRA_PACKAGES tag can be used to specify one or more LaTeX package names
-# that should be included in the LaTeX output. The package can be specified just
-# by its name or with the correct syntax as to be used with the LaTeX
-# \usepackage command. To get the times font for instance you can specify :
-# EXTRA_PACKAGES=times or EXTRA_PACKAGES={times}
-# To use the option intlimits with the amsmath package you can specify:
-# EXTRA_PACKAGES=[intlimits]{amsmath}
-# If left blank no extra packages will be included.
-# This tag requires that the tag GENERATE_LATEX is set to YES.
-
-EXTRA_PACKAGES         = 
-
-# The LATEX_HEADER tag can be used to specify a personal LaTeX header for the
-# generated LaTeX document. The header should contain everything until the first
-# chapter. If it is left blank doxygen will generate a standard header. See
-# section "Doxygen usage" for information on how to let doxygen write the
-# default header to a separate file.
-#
-# Note: Only use a user-defined header if you know what you are doing! The
-# following commands have a special meaning inside the header: $title,
-# $datetime, $date, $doxygenversion, $projectname, $projectnumber,
-# $projectbrief, $projectlogo. Doxygen will replace $title with the empty
-# string, for the replacement values of the other commands the user is referred
-# to HTML_HEADER.
-# This tag requires that the tag GENERATE_LATEX is set to YES.
-
-LATEX_HEADER           = 
-
-# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for the
-# generated LaTeX document. The footer should contain everything after the last
-# chapter. If it is left blank doxygen will generate a standard footer. See
-# LATEX_HEADER for more information on how to generate a default footer and what
-# special commands can be used inside the footer.
-#
-# Note: Only use a user-defined footer if you know what you are doing!
-# This tag requires that the tag GENERATE_LATEX is set to YES.
-
-LATEX_FOOTER           = 
-
-# The LATEX_EXTRA_STYLESHEET tag can be used to specify additional user-defined
-# LaTeX style sheets that are included after the standard style sheets created
-# by doxygen. Using this option one can overrule certain style aspects. Doxygen
-# will copy the style sheet files to the output directory.
-# Note: The order of the extra style sheet files is of importance (e.g. the last
-# style sheet in the list overrules the setting of the previous ones in the
-# list).
-# This tag requires that the tag GENERATE_LATEX is set to YES.
-
-LATEX_EXTRA_STYLESHEET = 
-
-# The LATEX_EXTRA_FILES tag can be used to specify one or more extra images or
-# other source files which should be copied to the LATEX_OUTPUT output
-# directory. Note that the files will be copied as-is; there are no commands or
-# markers available.
-# This tag requires that the tag GENERATE_LATEX is set to YES.
-
-LATEX_EXTRA_FILES      = 
-
-# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated is
-# prepared for conversion to PDF (using ps2pdf or pdflatex). The PDF file will
-# contain links (just like the HTML output) instead of page references. This
-# makes the output suitable for online browsing using a PDF viewer.
-# The default value is: YES.
-# This tag requires that the tag GENERATE_LATEX is set to YES.
-
-PDF_HYPERLINKS         = YES
-
-# If the USE_PDFLATEX tag is set to YES, doxygen will use pdflatex to generate
-# the PDF file directly from the LaTeX files. Set this option to YES, to get a
-# higher quality PDF documentation.
-# The default value is: YES.
-# This tag requires that the tag GENERATE_LATEX is set to YES.
-
-USE_PDFLATEX           = YES
-
-# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \batchmode
-# command to the generated LaTeX files. This will instruct LaTeX to keep running
-# if errors occur, instead of asking the user for help. This option is also used
-# when generating formulas in HTML.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_LATEX is set to YES.
-
-LATEX_BATCHMODE        = NO
-
-# If the LATEX_HIDE_INDICES tag is set to YES then doxygen will not include the
-# index chapters (such as File Index, Compound Index, etc.) in the output.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_LATEX is set to YES.
-
-LATEX_HIDE_INDICES     = NO
-
-# If the LATEX_SOURCE_CODE tag is set to YES then doxygen will include source
-# code with syntax highlighting in the LaTeX output.
-#
-# Note that which sources are shown also depends on other settings such as
-# SOURCE_BROWSER.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_LATEX is set to YES.
-
-LATEX_SOURCE_CODE      = NO
-
-# The LATEX_BIB_STYLE tag can be used to specify the style to use for the
-# bibliography, e.g. plainnat, or ieeetr. See
-# http://en.wikipedia.org/wiki/BibTeX and \cite for more info.
-# The default value is: plain.
-# This tag requires that the tag GENERATE_LATEX is set to YES.
-
-LATEX_BIB_STYLE        = plain
-
-# If the LATEX_TIMESTAMP tag is set to YES then the footer of each generated
-# page will contain the date and time when the page was generated. Setting this
-# to NO can help when comparing the output of multiple runs.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_LATEX is set to YES.
-
-LATEX_TIMESTAMP        = NO
-
-#---------------------------------------------------------------------------
-# Configuration options related to the RTF output
-#---------------------------------------------------------------------------
-
-# If the GENERATE_RTF tag is set to YES, doxygen will generate RTF output. The
-# RTF output is optimized for Word 97 and may not look too pretty with other RTF
-# readers/editors.
-# The default value is: NO.
-
-GENERATE_RTF           = NO
-
-# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. If a
-# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
-# it.
-# The default directory is: rtf.
-# This tag requires that the tag GENERATE_RTF is set to YES.
-
-RTF_OUTPUT             = rtf
-
-# If the COMPACT_RTF tag is set to YES, doxygen generates more compact RTF
-# documents. This may be useful for small projects and may help to save some
-# trees in general.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_RTF is set to YES.
-
-COMPACT_RTF            = NO
-
-# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated will
-# contain hyperlink fields. The RTF file will contain links (just like the HTML
-# output) instead of page references. This makes the output suitable for online
-# browsing using Word or some other Word compatible readers that support those
-# fields.
-#
-# Note: WordPad (write) and others do not support links.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_RTF is set to YES.
-
-RTF_HYPERLINKS         = NO
-
-# Load stylesheet definitions from file. Syntax is similar to doxygen's config
-# file, i.e. a series of assignments. You only have to provide replacements,
-# missing definitions are set to their default value.
-#
-# See also section "Doxygen usage" for information on how to generate the
-# default style sheet that doxygen normally uses.
-# This tag requires that the tag GENERATE_RTF is set to YES.
-
-RTF_STYLESHEET_FILE    = 
-
-# Set optional variables used in the generation of an RTF document. Syntax is
-# similar to doxygen's config file. A template extensions file can be generated
-# using doxygen -e rtf extensionFile.
-# This tag requires that the tag GENERATE_RTF is set to YES.
-
-RTF_EXTENSIONS_FILE    = 
-
-# If the RTF_SOURCE_CODE tag is set to YES then doxygen will include source code
-# with syntax highlighting in the RTF output.
-#
-# Note that which sources are shown also depends on other settings such as
-# SOURCE_BROWSER.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_RTF is set to YES.
-
-RTF_SOURCE_CODE        = NO
-
-#---------------------------------------------------------------------------
-# Configuration options related to the man page output
-#---------------------------------------------------------------------------
-
-# If the GENERATE_MAN tag is set to YES, doxygen will generate man pages for
-# classes and files.
-# The default value is: NO.
-
-GENERATE_MAN           = NO
-
-# The MAN_OUTPUT tag is used to specify where the man pages will be put. If a
-# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
-# it. A directory man3 will be created inside the directory specified by
-# MAN_OUTPUT.
-# The default directory is: man.
-# This tag requires that the tag GENERATE_MAN is set to YES.
-
-MAN_OUTPUT             = man
-
-# The MAN_EXTENSION tag determines the extension that is added to the generated
-# man pages. In case the manual section does not start with a number, the number
-# 3 is prepended. The dot (.) at the beginning of the MAN_EXTENSION tag is
-# optional.
-# The default value is: .3.
-# This tag requires that the tag GENERATE_MAN is set to YES.
-
-MAN_EXTENSION          = .3
-
-# The MAN_SUBDIR tag determines the name of the directory created within
-# MAN_OUTPUT in which the man pages are placed. If defaults to man followed by
-# MAN_EXTENSION with the initial . removed.
-# This tag requires that the tag GENERATE_MAN is set to YES.
-
-MAN_SUBDIR             = 
-
-# If the MAN_LINKS tag is set to YES and doxygen generates man output, then it
-# will generate one additional man file for each entity documented in the real
-# man page(s). These additional files only source the real man page, but without
-# them the man command would be unable to find the correct page.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_MAN is set to YES.
-
-MAN_LINKS              = NO
-
-#---------------------------------------------------------------------------
-# Configuration options related to the XML output
-#---------------------------------------------------------------------------
-
-# If the GENERATE_XML tag is set to YES, doxygen will generate an XML file that
-# captures the structure of the code including all documentation.
-# The default value is: NO.
-
-GENERATE_XML           = NO
-
-# The XML_OUTPUT tag is used to specify where the XML pages will be put. If a
-# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
-# it.
-# The default directory is: xml.
-# This tag requires that the tag GENERATE_XML is set to YES.
-
-XML_OUTPUT             = xml
-
-# If the XML_PROGRAMLISTING tag is set to YES, doxygen will dump the program
-# listings (including syntax highlighting and cross-referencing information) to
-# the XML output. Note that enabling this will significantly increase the size
-# of the XML output.
-# The default value is: YES.
-# This tag requires that the tag GENERATE_XML is set to YES.
-
-XML_PROGRAMLISTING     = YES
-
-#---------------------------------------------------------------------------
-# Configuration options related to the DOCBOOK output
-#---------------------------------------------------------------------------
-
-# If the GENERATE_DOCBOOK tag is set to YES, doxygen will generate Docbook files
-# that can be used to generate PDF.
-# The default value is: NO.
-
-GENERATE_DOCBOOK       = NO
-
-# The DOCBOOK_OUTPUT tag is used to specify where the Docbook pages will be put.
-# If a relative path is entered the value of OUTPUT_DIRECTORY will be put in
-# front of it.
-# The default directory is: docbook.
-# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
-
-DOCBOOK_OUTPUT         = docbook
-
-# If the DOCBOOK_PROGRAMLISTING tag is set to YES, doxygen will include the
-# program listings (including syntax highlighting and cross-referencing
-# information) to the DOCBOOK output. Note that enabling this will significantly
-# increase the size of the DOCBOOK output.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
-
-DOCBOOK_PROGRAMLISTING = NO
-
-#---------------------------------------------------------------------------
-# Configuration options for the AutoGen Definitions output
-#---------------------------------------------------------------------------
-
-# If the GENERATE_AUTOGEN_DEF tag is set to YES, doxygen will generate an
-# AutoGen Definitions (see http://autogen.sf.net) file that captures the
-# structure of the code including all documentation. Note that this feature is
-# still experimental and incomplete at the moment.
-# The default value is: NO.
-
-GENERATE_AUTOGEN_DEF   = NO
-
-#---------------------------------------------------------------------------
-# Configuration options related to the Perl module output
-#---------------------------------------------------------------------------
-
-# If the GENERATE_PERLMOD tag is set to YES, doxygen will generate a Perl module
-# file that captures the structure of the code including all documentation.
-#
-# Note that this feature is still experimental and incomplete at the moment.
-# The default value is: NO.
-
-GENERATE_PERLMOD       = NO
-
-# If the PERLMOD_LATEX tag is set to YES, doxygen will generate the necessary
-# Makefile rules, Perl scripts and LaTeX code to be able to generate PDF and DVI
-# output from the Perl module output.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_PERLMOD is set to YES.
-
-PERLMOD_LATEX          = NO
-
-# If the PERLMOD_PRETTY tag is set to YES, the Perl module output will be nicely
-# formatted so it can be parsed by a human reader. This is useful if you want to
-# understand what is going on. On the other hand, if this tag is set to NO, the
-# size of the Perl module output will be much smaller and Perl will parse it
-# just the same.
-# The default value is: YES.
-# This tag requires that the tag GENERATE_PERLMOD is set to YES.
-
-PERLMOD_PRETTY         = YES
-
-# The names of the make variables in the generated doxyrules.make file are
-# prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. This is useful
-# so different doxyrules.make files included by the same Makefile don't
-# overwrite each other's variables.
-# This tag requires that the tag GENERATE_PERLMOD is set to YES.
-
-PERLMOD_MAKEVAR_PREFIX = 
-
-#---------------------------------------------------------------------------
-# Configuration options related to the preprocessor
-#---------------------------------------------------------------------------
-
-# If the ENABLE_PREPROCESSING tag is set to YES, doxygen will evaluate all
-# C-preprocessor directives found in the sources and include files.
-# The default value is: YES.
-
-ENABLE_PREPROCESSING   = YES
-
-# If the MACRO_EXPANSION tag is set to YES, doxygen will expand all macro names
-# in the source code. If set to NO, only conditional compilation will be
-# performed. Macro expansion can be done in a controlled way by setting
-# EXPAND_ONLY_PREDEF to YES.
-# The default value is: NO.
-# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
-
-MACRO_EXPANSION        = NO
-
-# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES then
-# the macro expansion is limited to the macros specified with the PREDEFINED and
-# EXPAND_AS_DEFINED tags.
-# The default value is: NO.
-# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
-
-EXPAND_ONLY_PREDEF     = NO
-
-# If the SEARCH_INCLUDES tag is set to YES, the include files in the
-# INCLUDE_PATH will be searched if a #include is found.
-# The default value is: YES.
-# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
-
-SEARCH_INCLUDES        = YES
-
-# The INCLUDE_PATH tag can be used to specify one or more directories that
-# contain include files that are not input files but should be processed by the
-# preprocessor.
-# This tag requires that the tag SEARCH_INCLUDES is set to YES.
-
-INCLUDE_PATH           = 
-
-# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
-# patterns (like *.h and *.hpp) to filter out the header-files in the
-# directories. If left blank, the patterns specified with FILE_PATTERNS will be
-# used.
-# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
-
-INCLUDE_FILE_PATTERNS  = 
-
-# The PREDEFINED tag can be used to specify one or more macro names that are
-# defined before the preprocessor is started (similar to the -D option of e.g.
-# gcc). The argument of the tag is a list of macros of the form: name or
-# name=definition (no spaces). If the definition and the "=" are omitted, "=1"
-# is assumed. To prevent a macro definition from being undefined via #undef or
-# recursively expanded use the := operator instead of the = operator.
-# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
-
-PREDEFINED             = 
-
-# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this
-# tag can be used to specify a list of macro names that should be expanded. The
-# macro definition that is found in the sources will be used. Use the PREDEFINED
-# tag if you want to use a different macro definition that overrules the
-# definition found in the source code.
-# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
-
-EXPAND_AS_DEFINED      = 
-
-# If the SKIP_FUNCTION_MACROS tag is set to YES then doxygen's preprocessor will
-# remove all references to function-like macros that are alone on a line, have
-# an all uppercase name, and do not end with a semicolon. Such function macros
-# are typically used for boiler-plate code, and will confuse the parser if not
-# removed.
-# The default value is: YES.
-# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
-
-SKIP_FUNCTION_MACROS   = YES
-
-#---------------------------------------------------------------------------
-# Configuration options related to external references
-#---------------------------------------------------------------------------
-
-# The TAGFILES tag can be used to specify one or more tag files. For each tag
-# file the location of the external documentation should be added. The format of
-# a tag file without this location is as follows:
-# TAGFILES = file1 file2 ...
-# Adding location for the tag files is done as follows:
-# TAGFILES = file1=loc1 "file2 = loc2" ...
-# where loc1 and loc2 can be relative or absolute paths or URLs. See the
-# section "Linking to external documentation" for more information about the use
-# of tag files.
-# Note: Each tag file must have a unique name (where the name does NOT include
-# the path). If a tag file is not located in the directory in which doxygen is
-# run, you must also specify the path to the tagfile here.
-
-TAGFILES               = 
-
-# When a file name is specified after GENERATE_TAGFILE, doxygen will create a
-# tag file that is based on the input files it reads. See section "Linking to
-# external documentation" for more information about the usage of tag files.
-
-GENERATE_TAGFILE       = 
-
-# If the ALLEXTERNALS tag is set to YES, all external class will be listed in
-# the class index. If set to NO, only the inherited external classes will be
-# listed.
-# The default value is: NO.
-
-ALLEXTERNALS           = NO
-
-# If the EXTERNAL_GROUPS tag is set to YES, all external groups will be listed
-# in the modules index. If set to NO, only the current project's groups will be
-# listed.
-# The default value is: YES.
-
-EXTERNAL_GROUPS        = YES
-
-# If the EXTERNAL_PAGES tag is set to YES, all external pages will be listed in
-# the related pages index. If set to NO, only the current project's pages will
-# be listed.
-# The default value is: YES.
-
-EXTERNAL_PAGES         = YES
-
-# The PERL_PATH should be the absolute path and name of the perl script
-# interpreter (i.e. the result of 'which perl').
-# The default file (with absolute path) is: /usr/bin/perl.
-
-PERL_PATH              = /usr/bin/perl
-
-#---------------------------------------------------------------------------
-# Configuration options related to the dot tool
-#---------------------------------------------------------------------------
-
-# If the CLASS_DIAGRAMS tag is set to YES, doxygen will generate a class diagram
-# (in HTML and LaTeX) for classes with base or super classes. Setting the tag to
-# NO turns the diagrams off. Note that this option also works with HAVE_DOT
-# disabled, but it is recommended to install and use dot, since it yields more
-# powerful graphs.
-# The default value is: YES.
-
-CLASS_DIAGRAMS         = YES
-
-# You can define message sequence charts within doxygen comments using the \msc
-# command. Doxygen will then run the mscgen tool (see:
-# http://www.mcternan.me.uk/mscgen/)) to produce the chart and insert it in the
-# documentation. The MSCGEN_PATH tag allows you to specify the directory where
-# the mscgen tool resides. If left empty the tool is assumed to be found in the
-# default search path.
-
-MSCGEN_PATH            = 
-
-# You can include diagrams made with dia in doxygen documentation. Doxygen will
-# then run dia to produce the diagram and insert it in the documentation. The
-# DIA_PATH tag allows you to specify the directory where the dia binary resides.
-# If left empty dia is assumed to be found in the default search path.
-
-DIA_PATH               = 
-
-# If set to YES the inheritance and collaboration graphs will hide inheritance
-# and usage relations if the target is undocumented or is not a class.
-# The default value is: YES.
-
-HIDE_UNDOC_RELATIONS   = YES
-
-# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
-# available from the path. This tool is part of Graphviz (see:
-# http://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent
-# Bell Labs. The other options in this section have no effect if this option is
-# set to NO
-# The default value is: YES.
-
-HAVE_DOT               = NO
-
-# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is allowed
-# to run in parallel. When set to 0 doxygen will base this on the number of
-# processors available in the system. You can set it explicitly to a value
-# larger than 0 to get control over the balance between CPU load and processing
-# speed.
-# Minimum value: 0, maximum value: 32, default value: 0.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-DOT_NUM_THREADS        = 0
-
-# When you want a differently looking font in the dot files that doxygen
-# generates you can specify the font name using DOT_FONTNAME. You need to make
-# sure dot is able to find the font, which can be done by putting it in a
-# standard location or by setting the DOTFONTPATH environment variable or by
-# setting DOT_FONTPATH to the directory containing the font.
-# The default value is: Helvetica.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-DOT_FONTNAME           = Helvetica
-
-# The DOT_FONTSIZE tag can be used to set the size (in points) of the font of
-# dot graphs.
-# Minimum value: 4, maximum value: 24, default value: 10.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-DOT_FONTSIZE           = 10
-
-# By default doxygen will tell dot to use the default font as specified with
-# DOT_FONTNAME. If you specify a different font using DOT_FONTNAME you can set
-# the path where dot can find it using this tag.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-DOT_FONTPATH           = 
-
-# If the CLASS_GRAPH tag is set to YES then doxygen will generate a graph for
-# each documented class showing the direct and indirect inheritance relations.
-# Setting this tag to YES will force the CLASS_DIAGRAMS tag to NO.
-# The default value is: YES.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-CLASS_GRAPH            = YES
-
-# If the COLLABORATION_GRAPH tag is set to YES then doxygen will generate a
-# graph for each documented class showing the direct and indirect implementation
-# dependencies (inheritance, containment, and class references variables) of the
-# class with other documented classes.
-# The default value is: YES.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-COLLABORATION_GRAPH    = YES
-
-# If the GROUP_GRAPHS tag is set to YES then doxygen will generate a graph for
-# groups, showing the direct groups dependencies.
-# The default value is: YES.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-GROUP_GRAPHS           = YES
-
-# If the UML_LOOK tag is set to YES, doxygen will generate inheritance and
-# collaboration diagrams in a style similar to the OMG's Unified Modeling
-# Language.
-# The default value is: NO.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-UML_LOOK               = NO
-
-# If the UML_LOOK tag is enabled, the fields and methods are shown inside the
-# class node. If there are many fields or methods and many nodes the graph may
-# become too big to be useful. The UML_LIMIT_NUM_FIELDS threshold limits the
-# number of items for each type to make the size more manageable. Set this to 0
-# for no limit. Note that the threshold may be exceeded by 50% before the limit
-# is enforced. So when you set the threshold to 10, up to 15 fields may appear,
-# but if the number exceeds 15, the total amount of fields shown is limited to
-# 10.
-# Minimum value: 0, maximum value: 100, default value: 10.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-UML_LIMIT_NUM_FIELDS   = 10
-
-# If the TEMPLATE_RELATIONS tag is set to YES then the inheritance and
-# collaboration graphs will show the relations between templates and their
-# instances.
-# The default value is: NO.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-TEMPLATE_RELATIONS     = NO
-
-# If the INCLUDE_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are set to
-# YES then doxygen will generate a graph for each documented file showing the
-# direct and indirect include dependencies of the file with other documented
-# files.
-# The default value is: YES.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-INCLUDE_GRAPH          = YES
-
-# If the INCLUDED_BY_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are
-# set to YES then doxygen will generate a graph for each documented file showing
-# the direct and indirect include dependencies of the file with other documented
-# files.
-# The default value is: YES.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-INCLUDED_BY_GRAPH      = YES
-
-# If the CALL_GRAPH tag is set to YES then doxygen will generate a call
-# dependency graph for every global function or class method.
-#
-# Note that enabling this option will significantly increase the time of a run.
-# So in most cases it will be better to enable call graphs for selected
-# functions only using the \callgraph command. Disabling a call graph can be
-# accomplished by means of the command \hidecallgraph.
-# The default value is: NO.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-CALL_GRAPH             = NO
-
-# If the CALLER_GRAPH tag is set to YES then doxygen will generate a caller
-# dependency graph for every global function or class method.
-#
-# Note that enabling this option will significantly increase the time of a run.
-# So in most cases it will be better to enable caller graphs for selected
-# functions only using the \callergraph command. Disabling a caller graph can be
-# accomplished by means of the command \hidecallergraph.
-# The default value is: NO.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-CALLER_GRAPH           = NO
-
-# If the GRAPHICAL_HIERARCHY tag is set to YES then doxygen will graphical
-# hierarchy of all classes instead of a textual one.
-# The default value is: YES.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-GRAPHICAL_HIERARCHY    = YES
-
-# If the DIRECTORY_GRAPH tag is set to YES then doxygen will show the
-# dependencies a directory has on other directories in a graphical way. The
-# dependency relations are determined by the #include relations between the
-# files in the directories.
-# The default value is: YES.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-DIRECTORY_GRAPH        = YES
-
-# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
-# generated by dot. For an explanation of the image formats see the section
-# output formats in the documentation of the dot tool (Graphviz (see:
-# http://www.graphviz.org/)).
-# Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order
-# to make the SVG files visible in IE 9+ (other browsers do not have this
-# requirement).
-# Possible values are: png, png:cairo, png:cairo:cairo, png:cairo:gd, png:gd,
-# png:gd:gd, jpg, jpg:cairo, jpg:cairo:gd, jpg:gd, jpg:gd:gd, gif, gif:cairo,
-# gif:cairo:gd, gif:gd, gif:gd:gd, svg, png:gd, png:gd:gd, png:cairo,
-# png:cairo:gd, png:cairo:cairo, png:cairo:gdiplus, png:gdiplus and
-# png:gdiplus:gdiplus.
-# The default value is: png.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-DOT_IMAGE_FORMAT       = png
-
-# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to
-# enable generation of interactive SVG images that allow zooming and panning.
-#
-# Note that this requires a modern browser other than Internet Explorer. Tested
-# and working are Firefox, Chrome, Safari, and Opera.
-# Note: For IE 9+ you need to set HTML_FILE_EXTENSION to xhtml in order to make
-# the SVG files visible. Older versions of IE do not have SVG support.
-# The default value is: NO.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-INTERACTIVE_SVG        = NO
-
-# The DOT_PATH tag can be used to specify the path where the dot tool can be
-# found. If left blank, it is assumed the dot tool can be found in the path.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-DOT_PATH               = 
-
-# The DOTFILE_DIRS tag can be used to specify one or more directories that
-# contain dot files that are included in the documentation (see the \dotfile
-# command).
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-DOTFILE_DIRS           = 
-
-# The MSCFILE_DIRS tag can be used to specify one or more directories that
-# contain msc files that are included in the documentation (see the \mscfile
-# command).
-
-MSCFILE_DIRS           = 
-
-# The DIAFILE_DIRS tag can be used to specify one or more directories that
-# contain dia files that are included in the documentation (see the \diafile
-# command).
-
-DIAFILE_DIRS           = 
-
-# When using plantuml, the PLANTUML_JAR_PATH tag should be used to specify the
-# path where java can find the plantuml.jar file. If left blank, it is assumed
-# PlantUML is not used or called during a preprocessing step. Doxygen will
-# generate a warning when it encounters a \startuml command in this case and
-# will not generate output for the diagram.
-
-PLANTUML_JAR_PATH      = 
-
-# When using plantuml, the specified paths are searched for files specified by
-# the !include statement in a plantuml block.
-
-PLANTUML_INCLUDE_PATH  = 
-
-# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of nodes
-# that will be shown in the graph. If the number of nodes in a graph becomes
-# larger than this value, doxygen will truncate the graph, which is visualized
-# by representing a node as a red box. Note that doxygen if the number of direct
-# children of the root node in a graph is already larger than
-# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note that
-# the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
-# Minimum value: 0, maximum value: 10000, default value: 50.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-DOT_GRAPH_MAX_NODES    = 50
-
-# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the graphs
-# generated by dot. A depth value of 3 means that only nodes reachable from the
-# root by following a path via at most 3 edges will be shown. Nodes that lay
-# further from the root node will be omitted. Note that setting this option to 1
-# or 2 may greatly reduce the computation time needed for large code bases. Also
-# note that the size of a graph can be further restricted by
-# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
-# Minimum value: 0, maximum value: 1000, default value: 0.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-MAX_DOT_GRAPH_DEPTH    = 0
-
-# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
-# background. This is disabled by default, because dot on Windows does not seem
-# to support this out of the box.
-#
-# Warning: Depending on the platform used, enabling this option may lead to
-# badly anti-aliased labels on the edges of a graph (i.e. they become hard to
-# read).
-# The default value is: NO.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-DOT_TRANSPARENT        = NO
-
-# Set the DOT_MULTI_TARGETS tag to YES to allow dot to generate multiple output
-# files in one run (i.e. multiple -o and -T options on the command line). This
-# makes dot run faster, but since only newer versions of dot (>1.8.10) support
-# this, this feature is disabled by default.
-# The default value is: NO.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-DOT_MULTI_TARGETS      = NO
-
-# If the GENERATE_LEGEND tag is set to YES doxygen will generate a legend page
-# explaining the meaning of the various boxes and arrows in the dot generated
-# graphs.
-# The default value is: YES.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-GENERATE_LEGEND        = YES
-
-# If the DOT_CLEANUP tag is set to YES, doxygen will remove the intermediate dot
-# files that are used to generate the various graphs.
-# The default value is: YES.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-DOT_CLEANUP            = YES
diff --git a/os/unittests/lld/inc/ut_lld_adc.h b/os/unittests/lld/inc/ut_lld_adc.h
deleted file mode 100644
index b3cae14..0000000
--- a/os/unittests/lld/inc/ut_lld_adc.h
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
-AMiRo-OS is an operating system designed for the Autonomous Mini Robot (AMiRo) platform.
-Copyright (C) 2016..2018  Thomas Schöpping et al.
-
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program.  If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#ifndef _AMIROOS_UT_LLD_ADC_H_
-#define _AMIROOS_UT_LLD_ADC_H_
-
-#include <aos_unittest.h>
-
-#if ((AMIROOS_CFG_TESTS_ENABLE == true) && (HAL_USE_ADC == TRUE))|| defined(__DOXYGEN__)
-
-/**
- * @brief   Custom data structure for the unit test.
- */
-typedef struct {
-  /**
-   * @brief   Pointer to the driver to use.
-   */
-  ADCDriver* driver;
-
-  /**
-   * @brief   Pointer to the conversion group to use.
-   */
-  ADCConversionGroup* convgroup;
-} ut_adcdata_t;
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-  aos_utresult_t utAdcFunc(BaseSequentialStream* stream, aos_unittest_t* ut);
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* (AMIROOS_CFG_TESTS_ENABLE == true) && (HAL_USE_ADC == TRUE) */
-
-#endif /* _AMIROOS_UT_LLD_ADC_H_ */
diff --git a/os/unittests/lld/src/ut_lld_adc.c b/os/unittests/lld/src/ut_lld_adc.c
deleted file mode 100644
index 05721f7..0000000
--- a/os/unittests/lld/src/ut_lld_adc.c
+++ /dev/null
@@ -1,156 +0,0 @@
-/*
-AMiRo-OS is an operating system designed for the Autonomous Mini Robot (AMiRo) platform.
-Copyright (C) 2016..2018  Thomas Schöpping et al.
-
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program.  If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#include <ut_lld_adc.h>
-
-#if ((AMIROOS_CFG_TESTS_ENABLE == true) && (HAL_USE_ADC == TRUE))|| defined(__DOXYGEN__)
-
-#include <aos_debug.h>
-#include <aos_thread.h>
-#include <chprintf.h>
-
-/**
- * @brief   Event mask of the ADC analog watchdog event.
- */
-#define _adcWdgEventmask                        EVENT_MASK(31)
-
-/**
- * @brief   ADC analog watchdog threshold (9.0V).
- */
-#define _adcWdgThreshold                        (uint16_t)(9.0f / 5.0f / 3.3f * ((1 << 12) - 1) + 0.5f)
-
-/**
- * @brief   Pointer to the thread listening for an ADC analog watchdog event.
- */
-static thread_t* _listener;
-
-/**
- * @brief   Helper function to convert ADC sample value to volts.
- *
- * @param[in] adc   ADC sample value.
- *
- * @return          Converted value in volts.
- */
-static inline float _adc2volt(adcsample_t adc) {
-  return (float)adc / ((1 << 12) - 1) * 3.3f * 5.0f;
-}
-
-/**
- * @brief   ADC analog watchdog callback function.
- *
- * @param[in] adcp  ADC driver.
- * @param[in] err   ADC error value.
- */
-static void _adcAwdCb(ADCDriver* adcp, adcerror_t err)
-{
-  (void)adcp;
-
-  if (err == ADC_ERR_WATCHDOG) {
-    chSysLockFromISR();
-    if (_listener != NULL) {
-      chEvtSignalI(_listener, _adcWdgEventmask);
-      _listener = NULL;
-    }
-    chSysUnlockFromISR();
-  }
-
-  return;
-}
-
-/**
- * @brief   ADC unit test function.
- *
- * @param[in] stream  Stream for input/output.
- * @param[in] ut      Unit test object.
- *
- * @return            Unit test result value.
- */
-aos_utresult_t utAdcFunc(BaseSequentialStream* stream, aos_unittest_t* ut)
-{
-  aosDbgCheck(ut->data != NULL && ((ut_adcdata_t*)(ut->data))->driver != NULL && ((ut_adcdata_t*)(ut->data))->convgroup != NULL);
-
-  // local variables
-  aos_utresult_t result = {0, 0};
-  adcsample_t buffer[1] = {0};
-  bool wdgpassed = false;
-  eventmask_t eventmask = 0;
-  ADCConversionGroup conversionGroup = *(((ut_adcdata_t*)(ut->data))->convgroup);
-  conversionGroup.circular = true;
-  conversionGroup.end_cb = NULL;
-  conversionGroup.end_cb = NULL;
-  conversionGroup.htr = ADC_HTR_HT;
-  conversionGroup.ltr = 0;
-
-  chprintf(stream, "reading voltage for five seconds...\n");
-  adcStartConversion(((ut_adcdata_t*)(ut->data))->driver, &conversionGroup, buffer, 1);
-  for (uint8_t s = 0; s < 5; ++s) {
-    aosThdSSleep(1);
-    chprintf(stream, "\tVSYS = %fV\n", _adc2volt(buffer[0]));
-  }
-  adcStopConversion(((ut_adcdata_t*)(ut->data))->driver);
-  if (buffer[0] != 0) {
-    aosUtPassed(stream, &result);
-  } else {
-    aosUtFailed(stream, &result);
-  }
-
-  chprintf(stream, "detecting external power...\n");
-  conversionGroup.error_cb = _adcAwdCb;
-  conversionGroup.htr = _adcWdgThreshold;
-  conversionGroup.ltr = _adcWdgThreshold;
-  _listener = chThdGetSelfX();
-  adcStartConversion(((ut_adcdata_t*)(ut->data))->driver, &conversionGroup, buffer, 1);
-  eventmask = chEvtWaitOneTimeout(_adcWdgEventmask, chTimeS2I(5));
-  if (eventmask == _adcWdgEventmask) {
-    aosUtPassedMsg(stream, &result, "%fV %c 9V\n", _adc2volt(buffer[0]), (buffer[0] > _adcWdgThreshold) ? '>' : '<');
-    wdgpassed = true;
-  } else {
-    adcStopConversion(((ut_adcdata_t*)(ut->data))->driver);
-    aosUtFailed(stream, &result);
-    wdgpassed = false;
-  }
-
-  if (wdgpassed) {
-    for (uint8_t i = 0; i < 2; ++i) {
-      if (buffer[0] > _adcWdgThreshold) {
-        chprintf(stream, "Remove external power within ten seconds.\n");
-        conversionGroup.htr = ADC_HTR_HT;
-        conversionGroup.ltr = _adcWdgThreshold;
-      } else {
-        chprintf(stream, "Connect external power within ten seconds.\n");
-        conversionGroup.htr = _adcWdgThreshold;
-        conversionGroup.ltr = 0;
-      }
-      aosThdMSleep(100); // wait some time so the ADC wil trigger again immediately due to noise
-      _listener = chThdGetSelfX();
-      adcStartConversion(((ut_adcdata_t*)(ut->data))->driver, &conversionGroup, buffer, 1);
-      eventmask = chEvtWaitOneTimeout(_adcWdgEventmask, chTimeS2I(10));
-      if (eventmask == _adcWdgEventmask) {
-        aosUtPassedMsg(stream, &result, "%fV %c 9V\n", _adc2volt(buffer[0]), (buffer[0] > _adcWdgThreshold) ? '>' : '<');
-      } else {
-        adcStopConversion(((ut_adcdata_t*)(ut->data))->driver);
-        aosUtFailed(stream, &result);
-        break;
-      }
-    }
-  }
-
-  return result;
-}
-
-#endif /* (AMIROOS_CFG_TESTS_ENABLE == true) && (HAL_USE_ADC == TRUE) */
diff --git a/os/unittests/periphery-lld/inc/ut_alld_a3906.h b/os/unittests/periphery-lld/inc/ut_alld_a3906.h
deleted file mode 100644
index 3eaef77..0000000
--- a/os/unittests/periphery-lld/inc/ut_alld_a3906.h
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
-AMiRo-OS is an operating system designed for the Autonomous Mini Robot (AMiRo) platform.
-Copyright (C) 2016..2018  Thomas Schöpping et al.
-
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program.  If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#ifndef _AMIROOS_UT_ALLD_A3906_H_
-#define _AMIROOS_UT_ALLD_A3906_H_
-
-#include <aos_unittest.h>
-#include <amiro-lld.h>
-
-#if ((AMIROOS_CFG_TESTS_ENABLE == true) && defined(AMIROLLD_CFG_USE_A3906)) || defined(__DOXYGEN__)
-
-#include <alld_a3906.h>
-
-/**
- * @brief   Custom data structure for the unit test.
- */
-typedef struct {
-  /**
-   * @brief   Pointer to the driver to use.
-   */
-  A3906Driver* driver;
-
-  /**
-   * @brief   PWM driver information.
-   */
-  struct {
-    /**
-     * @brief   The PWM driver to use.
-     */
-    apalPWMDriver_t* driver;
-
-    /**
-     * @brief   PWM channel information.
-     */
-    struct {
-      /**
-     * @brief   PWM channel for the left wheel forward direction.
-     */
-      apalPWMchannel_t left_forward;
-
-      /**
-     * @brief   PWM channel for the left wheel backward direction.
-     */
-      apalPWMchannel_t left_backward;
-
-      /**
-     * @brief   PWM channel for the right wheel forward direction.
-     */
-      apalPWMchannel_t right_forward;
-
-      /**
-     * @brief   PWM channel for the right wheel backward direction.
-     */
-      apalPWMchannel_t right_backward;
-    } channel;
-  } pwm;
-
-  /**
-   * @brief   QEI driver information
-   */
-  struct {
-    /**
-     * @brief   QEI driver for the left wheel.
-     */
-    apalQEIDriver_t* left;
-
-    /**
-     * @brief   QEI driver for the right wheel.
-     */
-    apalQEIDriver_t* right;
-
-    /**
-     * @brief   QEI increments per wheel revolution.
-     */
-    apalQEICount_t increments_per_revolution;
-  } qei;
-
-  /**
-   * @brief   Wheel diameter in m.
-   */
-  float wheel_diameter;
-
-  /**
-   * @brief   Timeout value (in us).
-   */
-  apalTime_t timeout;
-} ut_a3906data_t;
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-  aos_utresult_t utAlldA3906Func(BaseSequentialStream* stream, aos_unittest_t* ut);
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* (AMIROOS_CFG_TESTS_ENABLE == true) && defined(AMIROLLD_CFG_USE_A3906) */
-
-#endif /* _AMIROOS_UT_ALLD_A3906_H_ */
diff --git a/os/unittests/periphery-lld/inc/ut_alld_at24c01bn-sh-b.h b/os/unittests/periphery-lld/inc/ut_alld_at24c01bn-sh-b.h
deleted file mode 100644
index 1ed579e..0000000
--- a/os/unittests/periphery-lld/inc/ut_alld_at24c01bn-sh-b.h
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
-AMiRo-OS is an operating system designed for the Autonomous Mini Robot (AMiRo) platform.
-Copyright (C) 2016..2018  Thomas Schöpping et al.
-
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program.  If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#ifndef _AMIROOS_UT_ALLD_AT24C01BN_H_
-#define _AMIROOS_UT_ALLD_AT24C01BN_H_
-
-#include <aos_unittest.h>
-#include <amiro-lld.h>
-
-#if ((AMIROOS_CFG_TESTS_ENABLE == true) && defined(AMIROLLD_CFG_USE_AT24C01BN)) || defined(__DOXYGEN__)
-
-#include <alld_at24c01bn-sh-b.h>
-
-/**
- * @brief   Custom data structure for the unit test.
- */
-typedef struct {
-  /**
-   * @brief   Pointer to the driver to use.
-   */
-  AT24C01BNDriver* driver;
-
-  /**
-   * @brief   Timeout value (in us).
-   */
-  apalTime_t timeout;
-} ut_at24c01bndata_t;
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-  aos_utresult_t utAlldAt24c01bnFunc(BaseSequentialStream* stream, aos_unittest_t* ut);
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* (AMIROOS_CFG_TESTS_ENABLE == true) && defined(AMIROLLD_CFG_USE_AT24C01BN) */
-
-#endif /* _AMIROOS_UT_ALLD_AT24C01BN_H_ */
diff --git a/os/unittests/periphery-lld/inc/ut_alld_bq24103a.h b/os/unittests/periphery-lld/inc/ut_alld_bq24103a.h
deleted file mode 100644
index 889ce22..0000000
--- a/os/unittests/periphery-lld/inc/ut_alld_bq24103a.h
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
-AMiRo-OS is an operating system designed for the Autonomous Mini Robot (AMiRo) platform.
-Copyright (C) 2016..2018  Thomas Schöpping et al.
-
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program.  If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#ifndef _AMIROOS_UT_ALLD_BQ24103A_H_
-#define _AMIROOS_UT_ALLD_BQ24103A_H_
-
-#include <aos_unittest.h>
-#include <amiro-lld.h>
-
-#if ((AMIROOS_CFG_TESTS_ENABLE == true) && defined(AMIROLLD_CFG_USE_BQ24103A)) || defined(__DOXYGEN__)
-
-#include <alld_bq24103a.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-  aos_utresult_t utAlldBq24103aFunc(BaseSequentialStream* stream, aos_unittest_t* ut);
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* (AMIROOS_CFG_TESTS_ENABLE == true) && defined(AMIROLLD_CFG_USE_BQ24103A) */
-
-#endif /* _AMIROOS_UT_ALLD_BQ24103A_H_ */
diff --git a/os/unittests/periphery-lld/inc/ut_alld_bq27500.h b/os/unittests/periphery-lld/inc/ut_alld_bq27500.h
deleted file mode 100644
index 9818639..0000000
--- a/os/unittests/periphery-lld/inc/ut_alld_bq27500.h
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
-AMiRo-OS is an operating system designed for the Autonomous Mini Robot (AMiRo) platform.
-Copyright (C) 2016..2018  Thomas Schöpping et al.
-
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program.  If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#ifndef _AMIROOS_UT_ALLD_BQ27500_H_
-#define _AMIROOS_UT_ALLD_BQ27500_H_
-
-#include <aos_unittest.h>
-#include <amiro-lld.h>
-
-#if ((AMIROOS_CFG_TESTS_ENABLE == true) && defined(AMIROLLD_CFG_USE_BQ27500)) || defined(__DOXYGEN__)
-
-#include <alld_bq27500.h>
-
-/**
- * @brief   Custom data structure for the unit test.
- */
-typedef struct {
-  /**
-   * @brief   Pointer to the driver to use.
-   */
-  BQ27500Driver *driver;
-
-  /**
-   * @brief   Timeout value (in us);
-   */
-  apalTime_t timeout;
-} ut_bq27500data_t;
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-  aos_utresult_t utAlldBq27500Func(BaseSequentialStream* stream, aos_unittest_t* ut);
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* (AMIROOS_CFG_TESTS_ENABLE == true) && defined(AMIROLLD_CFG_USE_BQ27500) */
-
-#endif /* _AMIROOS_UT_ALLD_BQ27500_H_ */
-
diff --git a/os/unittests/periphery-lld/inc/ut_alld_bq27500_bq24103a.h b/os/unittests/periphery-lld/inc/ut_alld_bq27500_bq24103a.h
deleted file mode 100644
index 58836ce..0000000
--- a/os/unittests/periphery-lld/inc/ut_alld_bq27500_bq24103a.h
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
-AMiRo-OS is an operating system designed for the Autonomous Mini Robot (AMiRo) platform.
-Copyright (C) 2016..2018  Thomas Schöpping et al.
-
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program.  If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#ifndef _AMIROOS_UT_ALLD_BQ27500_BQ24193A_H_
-#define _AMIROOS_UT_ALLD_BQ27500_BQ24193A_H_
-
-#include <aos_unittest.h>
-#include <amiro-lld.h>
-
-#if ((AMIROOS_CFG_TESTS_ENABLE == true) && defined(AMIROLLD_CFG_USE_BQ27500) && defined(AMIROLLD_CFG_USE_BQ24103A)) || defined(__DOXYGEN__)
-
-#include <alld_bq27500.h>
-#include <alld_bq24103a.h>
-
-/**
- * @brief   Custom data structure for the unit test.
- */
-typedef struct {
-  /**
-   * @brief   BQ27500 driver to use.
-   */
-  BQ27500Driver* bq27500;
-
-  /**
-   * @brief   BQ24103A driver to use.
-   */
-  BQ24103ADriver* bq24103a;
-
-  /**
-   * @brief   Timeout value (in us).
-   */
-  apalTime_t timeout;
-} ut_bq27500bq24103adata_t;
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-  aos_utresult_t utAlldBq27500Bq24103aFunc(BaseSequentialStream* stream, aos_unittest_t* ut);
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* (AMIROOS_CFG_TESTS_ENABLE == true) && defined(AMIROLLD_CFG_USE_BQ27500) && defined(AMIROLLD_CFG_USE_BQ24103A) */
-
-#endif /* _AMIROOS_UT_ALLD_BQ27500_BQ24193A_H_ */
diff --git a/os/unittests/periphery-lld/inc/ut_alld_dw1000.h b/os/unittests/periphery-lld/inc/ut_alld_dw1000.h
deleted file mode 100755
index 43f98eb..0000000
--- a/os/unittests/periphery-lld/inc/ut_alld_dw1000.h
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
-AMiRo-OS is an operating system designed for the Autonomous Mini Robot (AMiRo) platform.
-Copyright (C) 2016..2018  Thomas Schöpping et al.
-
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program.  If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#ifndef _AMIROOS_UT_DW1000_LLD_HPP_
-#define _AMIROOS_UT_DW1000_LLD_HPP_
-
-#include <aos_unittest.h>
-#include <amiro-lld.h>
-
-#if ((AMIROOS_CFG_TESTS_ENABLE == true) && defined(AMIROLLD_CFG_USE_DW1000)) || defined(__DOXYGEN__)
-
-#include <alld_dw1000.h>
-//#include <deca_instance.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-  aos_utresult_t utAlldDw1000Func(BaseSequentialStream* stream, aos_unittest_t* ut);
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* (AMIROOS_CFG_TESTS_ENABLE == true) && defined(AMIROLLD_CFG_USE_DW1000) */
-
-#endif /* _AMIROOS_UT_DW1000_LLD_HPP_ */
diff --git a/os/unittests/periphery-lld/inc/ut_alld_hmc5883l.h b/os/unittests/periphery-lld/inc/ut_alld_hmc5883l.h
deleted file mode 100644
index e478c2f..0000000
--- a/os/unittests/periphery-lld/inc/ut_alld_hmc5883l.h
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
-AMiRo-OS is an operating system designed for the Autonomous Mini Robot (AMiRo) platform.
-Copyright (C) 2016..2018  Thomas Schöpping et al.
-
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program.  If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#ifndef _AMIROOS_UT_HMC5883L_LLD_HPP_
-#define _AMIROOS_UT_HMC5883L_LLD_HPP_
-
-#include <aos_unittest.h>
-#include <amiro-lld.h>
-
-#if ((AMIROOS_CFG_TESTS_ENABLE == true) && defined(AMIROLLD_CFG_USE_HMC5883L)) || defined(__DOXYGEN__)
-
-#include <alld_hmc5883l.h>
-
-/**
- * @brief   Constum data structure for this unit test.
- */
-typedef struct {
-  /**
-   * @brief   HMC5338L driver to use.
-   */
-  HMC5883LDriver* driver;
-
-  /**
-   * @brief   Event source for certain tests.
-   */
-  event_source_t *drdyEvtSrc;
-
-  /**
-   * @brief   Event flags to watch.
-   */
-  eventflags_t evtflags;
-
-  /**
-   * @brief   Timeout value in microseconds.
-   */
-  apalTime_t timeout;
-} ut_hmc5883ldata_t;
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-  aos_utresult_t utAlldHmc5883lFunc(BaseSequentialStream* stream, aos_unittest_t* ut);
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* (AMIROOS_CFG_TESTS_ENABLE == true) && defined(AMIROLLD_CFG_USE_HMC5883L) */
-
-
-#endif /* _AMIROOS_UT_HMC5883L_LLD_HPP_ */
diff --git a/os/unittests/periphery-lld/inc/ut_alld_ina219.h b/os/unittests/periphery-lld/inc/ut_alld_ina219.h
deleted file mode 100644
index c386e5f..0000000
--- a/os/unittests/periphery-lld/inc/ut_alld_ina219.h
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
-AMiRo-OS is an operating system designed for the Autonomous Mini Robot (AMiRo) platform.
-Copyright (C) 2016..2018  Thomas Schöpping et al.
-
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program.  If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#ifndef _AMIROOS_UT_INA219_LLD_HPP_
-#define _AMIROOS_UT_INA219_LLD_HPP_
-
-#include <aos_unittest.h>
-#include <amiro-lld.h>
-
-#if ((AMIROOS_CFG_TESTS_ENABLE == true) && defined(AMIROLLD_CFG_USE_INA219)) || defined(__DOXYGEN__)
-
-#include <alld_ina219.h>
-
-/**
- * @brief   Custom data structure for the unit test.
- */
-typedef struct {
-  /**
-   * @brief   INA219 driver to use.
-   */
-  INA219Driver *inad;
-
-  /**
-   * @brief   Expected voltage to be measured.
-   */
-  float v_expected;
-
-  /**
-   * @brief   Tolerance (relative) of measurement.
-   */
-  float tolerance;
-
-  /**
-   * @brief   Timeout delay for certain tests.
-   */
-  apalTime_t timeout;
-} ut_ina219data_t;
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-  aos_utresult_t utAlldIna219Func(BaseSequentialStream* stream, aos_unittest_t* ut);
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* (AMIROOS_CFG_TESTS_ENABLE == true) && defined(AMIROLLD_CFG_USE_INA219) */
-
-#endif /* _AMIROOS_UT_INA219_LLD_HPP_ */
diff --git a/os/unittests/periphery-lld/inc/ut_alld_l3g4200d.h b/os/unittests/periphery-lld/inc/ut_alld_l3g4200d.h
deleted file mode 100644
index ff55790..0000000
--- a/os/unittests/periphery-lld/inc/ut_alld_l3g4200d.h
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
-AMiRo-OS is an operating system designed for the Autonomous Mini Robot (AMiRo) platform.
-Copyright (C) 2016..2018  Thomas Schöpping et al.
-
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program.  If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#ifndef _AMIROOS_UT_L3G4200D_LLD_HPP_
-#define _AMIROOS_UT_L3G4200D_LLD_HPP_
-
-#include <aos_unittest.h>
-#include <amiro-lld.h>
-
-#if ((AMIROOS_CFG_TESTS_ENABLE == true) && defined(AMIROLLD_CFG_USE_L3G4200D)) || defined(__DOXYGEN__)
-
-#include <alld_l3g4200d.h>
-
-/**
- * @brief   Custom data structure for the unit test.
- */
-typedef struct {
-  /**
-   * @brief   L3G4200D driver to use.
-   */
-  L3G4200DDriver *l3gd;
-
-  /**
-   * @brief   SPI configuratoin.
-   */
-  SPIConfig *spiconf;
-
-  /**
-   * @brief   Event source for certain tests.
-   */
-  event_source_t *src;
-
-  /**
-   * @brief   Event flags to watch.
-   */
-  eventflags_t evtflags;
-} ut_l3g4200ddata_t;
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-  aos_utresult_t utAlldL3g4200dFunc(BaseSequentialStream* stream, aos_unittest_t* ut);
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* (AMIROOS_CFG_TESTS_ENABLE == true) && defined(AMIROLLD_CFG_USE_L3G4200D) */
-
-#endif /* _AMIROOS_UT_L3G4200D_LLD_HPP_ */
-
diff --git a/os/unittests/periphery-lld/inc/ut_alld_led.h b/os/unittests/periphery-lld/inc/ut_alld_led.h
deleted file mode 100644
index d8a3e21..0000000
--- a/os/unittests/periphery-lld/inc/ut_alld_led.h
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
-AMiRo-OS is an operating system designed for the Autonomous Mini Robot (AMiRo) platform.
-Copyright (C) 2016..2018  Thomas Schöpping et al.
-
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program.  If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#ifndef _AMIROOS_UT_ALLD_LED_H_
-#define _AMIROOS_UT_ALLD_LED_H_
-
-#include <aos_unittest.h>
-#include <amiro-lld.h>
-
-#if ((AMIROOS_CFG_TESTS_ENABLE == true) && defined(AMIROLLD_CFG_USE_LED)) || defined(__DOXYGEN__)
-
-#include <alld_led.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-  aos_utresult_t utAlldLedFunc(BaseSequentialStream* stream, aos_unittest_t* ut);
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* (AMIROOS_CFG_TESTS_ENABLE == true) && defined(AMIROLLD_CFG_USE_LED) */
-
-#endif /* _AMIROOS_UT_ALLD_LED_H_ */
diff --git a/os/unittests/periphery-lld/inc/ut_alld_lis331dlh.h b/os/unittests/periphery-lld/inc/ut_alld_lis331dlh.h
deleted file mode 100644
index 41152f4..0000000
--- a/os/unittests/periphery-lld/inc/ut_alld_lis331dlh.h
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
-AMiRo-OS is an operating system designed for the Autonomous Mini Robot (AMiRo) platform.
-Copyright (C) 2016..2018  Thomas Schöpping et al.
-
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program.  If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#ifndef _AMIROOS_UT_LIS331DLH_LLD_HPP_
-#define _AMIROOS_UT_LIS331DLH_LLD_HPP_
-
-#include <aos_unittest.h>
-#include <amiro-lld.h>
-
-#if ((AMIROOS_CFG_TESTS_ENABLE == true) && defined(AMIROLLD_CFG_USE_LIS331DLH)) || defined(__DOXYGEN__)
-
-#include <alld_lis331dlh.h>
-
-/**
- * @brief   Custom data structure for the unit test.
- */
-typedef struct {
-  /**
-   * @brief   Accelerometer driver to use.
-   */
-  LIS331DLHDriver *lisd;
-
-  /**
-   * @brief   SPI configuratoin.
-   */
-  SPIConfig *spiconf;
-
-  /**
-   * @brief   Event source for certain tests.
-   */
-  event_source_t *src;
-
-  /**
-   * @brief   Event flags to watch.
-   */
-  eventflags_t evtflags;
-} ut_lis331dlhdata_t;
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-  aos_utresult_t utAlldLis331dlhFunc(BaseSequentialStream* stream, aos_unittest_t* ut);
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* (AMIROOS_CFG_TESTS_ENABLE == true) && defined(AMIROLLD_CFG_USE_LIS331DLH) */
-
-#endif /* _AMIROOS_UT_LIS331DLH_LLD_HPP_ */
-
diff --git a/os/unittests/periphery-lld/inc/ut_alld_ltc4412.h b/os/unittests/periphery-lld/inc/ut_alld_ltc4412.h
deleted file mode 100644
index 9a68766..0000000
--- a/os/unittests/periphery-lld/inc/ut_alld_ltc4412.h
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
-AMiRo-OS is an operating system designed for the Autonomous Mini Robot (AMiRo) platform.
-Copyright (C) 2016..2018  Thomas Schöpping et al.
-
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program.  If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#ifndef _AMIROOS_UT_ALLD_LTC4412_H_
-#define _AMIROOS_UT_ALLD_LTC4412_H_
-
-#include <aos_unittest.h>
-#include <amiro-lld.h>
-
-#if ((AMIROOS_CFG_TESTS_ENABLE == true) && defined(AMIROLLD_CFG_USE_LTC4412)) || defined(__DOXYGEN__)
-
-#include <alld_ltc4412.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-  aos_utresult_t utAlldLtc4412Func(BaseSequentialStream* stream, aos_unittest_t* ut);
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* (AMIROOS_CFG_TESTS_ENABLE == true) && defined(AMIROLLD_CFG_USE_LTC4412) */
-
-#endif /* _AMIROOS_UT_ALLD_LTC4412_H_ */
diff --git a/os/unittests/periphery-lld/inc/ut_alld_mpr121.h b/os/unittests/periphery-lld/inc/ut_alld_mpr121.h
deleted file mode 100644
index 019d521..0000000
--- a/os/unittests/periphery-lld/inc/ut_alld_mpr121.h
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
-AMiRo-OS is an operating system designed for the Autonomous Mini Robot (AMiRo) platform.
-Copyright (C) 2016..2018  Thomas Schöpping et al.
-
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program.  If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#ifndef _AMIROOS_UT_ALLD_MPR121_H_
-#define _AMIROOS_UT_ALLD_MPR121_H_
-
-#include <aos_unittest.h>
-#include <amiro-lld.h>
-
-#if ((AMIROOS_CFG_TESTS_ENABLE == true) && defined(AMIROLLD_CFG_USE_MPR121)) || defined(__DOXYGEN__)
-
-#include <alld_mpr121.h>
-
-/**
- * @brief   Custom data structure for the unit test.
- */
-typedef struct {
-  /**
-   * @brief   Pointer to the MPR121 driver to use.
-   */
-  MPR121Driver* mprd;
-
-  /**
-   * @brief   Timeout value (in us).
-   */
-  apalTime_t timeout;
-
-  /**
-   * @brief   Event source to listen to.
-   */
-  event_source_t* evtsource;
-
-  /**
-   * @brief   Event flags to watch.
-   */
-  eventflags_t evtflags;
-} ut_mpr121data_t;
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-  aos_utresult_t utAlldMpr121Func(BaseSequentialStream* stream, aos_unittest_t* ut);
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* (AMIROOS_CFG_TESTS_ENABLE == true) && defined(AMIROLLD_CFG_USE_MPR121) */
-
-#endif /* _AMIROOS_UT_ALLD_MPR121_H_ */
diff --git a/os/unittests/periphery-lld/inc/ut_alld_pca9544a.h b/os/unittests/periphery-lld/inc/ut_alld_pca9544a.h
deleted file mode 100644
index 08e153c..0000000
--- a/os/unittests/periphery-lld/inc/ut_alld_pca9544a.h
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
-AMiRo-OS is an operating system designed for the Autonomous Mini Robot (AMiRo) platform.
-Copyright (C) 2016..2018  Thomas Schöpping et al.
-
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program.  If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#ifndef _AMIROOS_UT_ALLD_PCA9544A_H_
-#define _AMIROOS_UT_ALLD_PCA9544A_H_
-
-#include <aos_unittest.h>
-#include <amiro-lld.h>
-
-#if ((AMIROOS_CFG_TESTS_ENABLE == true) && defined(AMIROLLD_CFG_USE_PCA9544A)) || defined(__DOXYGEN__)
-
-#include <alld_pca9544a.h>
-
-/**
- * @brief   Custom data structure for the unit test.
- */
-typedef struct {
-  /**
-   * @brief   Pointer to the driver to use.
-   */
-  PCA9544ADriver *driver;
-
-  /**
-   * @brief   Timeout for bus communication.
-   */
-  apalTime_t timeout;
-} ut_pca9544adata_t;
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-  aos_utresult_t utAlldPca9544aFunc(BaseSequentialStream* stream, aos_unittest_t* ut);
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* (AMIROOS_CFG_TESTS_ENABLE == true) && defined(AMIROLLD_CFG_USE_PCA9544A) */
-
-#endif /* _AMIROOS_UT_ALLD_PCA9544A_H_ */
-
-
diff --git a/os/unittests/periphery-lld/inc/ut_alld_pklcs1212e4001.h b/os/unittests/periphery-lld/inc/ut_alld_pklcs1212e4001.h
deleted file mode 100644
index 9fc35c9..0000000
--- a/os/unittests/periphery-lld/inc/ut_alld_pklcs1212e4001.h
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
-AMiRo-OS is an operating system designed for the Autonomous Mini Robot (AMiRo) platform.
-Copyright (C) 2016..2018  Thomas Schöpping et al.
-
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program.  If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#ifndef _AMIROOS_UT_ALLD_PKLCS1212E4001_H_
-#define _AMIROOS_UT_ALLD_PKLCS1212E4001_H_
-
-#include <aos_unittest.h>
-#include <amiro-lld.h>
-
-#if ((AMIROOS_CFG_TESTS_ENABLE == true) && defined(AMIROLLD_CFG_USE_PKLCS1212E4001)) || defined(__DOXYGEN__)
-
-#include <alld_pklcs1212e4001.h>
-
-/**
- * @brief   Custom data structure for the unit test.
- */
-typedef struct {
-  /**
-   * @brief   Pointer to the PWM driver.
-   */
-  apalPWMDriver_t* driver;
-
-  /**
-   * @brief   PWM channel to use.
-   */
-  apalPWMchannel_t channel;
-} ut_pklcs1212e4001_t;
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-  aos_utresult_t utAlldPklcs1212e4001Func(BaseSequentialStream* stream, aos_unittest_t* ut);
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* (AMIROOS_CFG_TESTS_ENABLE == true) && defined(AMIROLLD_CFG_USE_PKLCS1212E4001) */
-
-#endif /* _AMIROOS_UT_ALLD_PKLCS1212E4001_H_ */
diff --git a/os/unittests/periphery-lld/inc/ut_alld_tlc5947.h b/os/unittests/periphery-lld/inc/ut_alld_tlc5947.h
deleted file mode 100644
index 5c31bdc..0000000
--- a/os/unittests/periphery-lld/inc/ut_alld_tlc5947.h
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
-AMiRo-OS is an operating system designed for the Autonomous Mini Robot (AMiRo) platform.
-Copyright (C) 2016..2018  Thomas Schöpping et al.
-
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program.  If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#ifndef _AMIROOS_UT_ALLD_TLC5947_H_
-#define _AMIROOS_UT_ALLD_TLC5947_H_
-
-#include <aos_unittest.h>
-#include <amiro-lld.h>
-
-#if ((AMIROOS_CFG_TESTS_ENABLE == true) && defined(AMIROLLD_CFG_USE_TLC5947)) || defined(__DOXYGEN__)
-
-#include <alld_tlc5947.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-  aos_utresult_t utAlldTlc5947Func(BaseSequentialStream* stream, aos_unittest_t* ut);
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* (AMIROOS_CFG_TESTS_ENABLE == true) && defined(AMIROLLD_CFG_USE_TLC5947) */
-
-#endif /* _AMIROOS_UT_ALLD_TLC5947_H_ */
diff --git a/os/unittests/periphery-lld/inc/ut_alld_tps2051bdbv.h b/os/unittests/periphery-lld/inc/ut_alld_tps2051bdbv.h
deleted file mode 100644
index 10e1e38..0000000
--- a/os/unittests/periphery-lld/inc/ut_alld_tps2051bdbv.h
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
-AMiRo-OS is an operating system designed for the Autonomous Mini Robot (AMiRo) platform.
-Copyright (C) 2016..2018  Thomas Schöpping et al.
-
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program.  If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#ifndef _AMIROOS_UT_ALLD_TPS2051BDBV_H_
-#define _AMIROOS_UT_ALLD_TPS2051BDBV_H_
-
-#include <aos_unittest.h>
-#include <amiro-lld.h>
-
-#if ((AMIROOS_CFG_TESTS_ENABLE == true) && defined(AMIROLLD_CFG_USE_TPS2051BDBV)) || defined(__DOXYGEN__)
-
-#include <alld_tps2051bdbv.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-  aos_utresult_t utAlldTps2051bdbvFunc(BaseSequentialStream* stream, aos_unittest_t* ut);
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* (AMIROOS_CFG_TESTS_ENABLE == true) && defined(AMIROLLD_CFG_USE_TPS2051BDBV) */
-
-#endif /* _AMIROOS_UT_ALLD_TPS2051BDBV_H_ */
diff --git a/os/unittests/periphery-lld/inc/ut_alld_tps62113.h b/os/unittests/periphery-lld/inc/ut_alld_tps62113.h
deleted file mode 100644
index 9915ea4..0000000
--- a/os/unittests/periphery-lld/inc/ut_alld_tps62113.h
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
-AMiRo-OS is an operating system designed for the Autonomous Mini Robot (AMiRo) platform.
-Copyright (C) 2016..2018  Thomas Schöpping et al.
-
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program.  If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#ifndef _AMIROOS_UT_ALLD_TPS62113_H_
-#define _AMIROOS_UT_ALLD_TPS62113_H_
-
-#include <aos_unittest.h>
-#include <amiro-lld.h>
-
-#if ((AMIROOS_CFG_TESTS_ENABLE == true) && defined(AMIROLLD_CFG_USE_TPS62113)) || defined(__DOXYGEN__)
-
-#include <alld_tps62113.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-  aos_utresult_t utAlldTps62113Func(BaseSequentialStream* stream, aos_unittest_t* ut);
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* (AMIROOS_CFG_TESTS_ENABLE == true) && defined(AMIROLLD_CFG_USE_TPS62113) */
-
-#endif /* _AMIROOS_UT_ALLD_TPS62113_H_ */
-
diff --git a/os/unittests/periphery-lld/inc/ut_alld_tps62113_ina219.h b/os/unittests/periphery-lld/inc/ut_alld_tps62113_ina219.h
deleted file mode 100644
index 034fd82..0000000
--- a/os/unittests/periphery-lld/inc/ut_alld_tps62113_ina219.h
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
-AMiRo-OS is an operating system designed for the Autonomous Mini Robot (AMiRo) platform.
-Copyright (C) 2016..2018  Thomas Schöpping et al.
-
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program.  If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#ifndef _AMIROOS_UT_ALLD_TPS62113_INA219_H_
-#define _AMIROOS_UT_ALLD_TPS62113_INA219_H_
-
-#include <aos_unittest.h>
-#include <amiro-lld.h>
-
-#if ((AMIROOS_CFG_TESTS_ENABLE == true) && defined(AMIROLLD_CFG_USE_TPS62113) && defined(AMIROLLD_CFG_USE_INA219)) || defined(__DOXYGEN__)
-
-#include <alld_tps62113.h>
-#include <alld_ina219.h>
-
-/**
- * @brief   Custom data structure for the unit test.
- */
-typedef struct {
-  /**
-   * @brief   TPS62113 driver to use.
-   */
-  TPS62113Driver* tps62113;
-
-  /**
-   * @brief   INA219 driver to use.
-   */
-  INA219Driver* ina219;
-
-  /**
-   * @brief   Timeout value (in us).
-   */
-  apalTime_t timeout;
-} ut_tps62113ina219data_t;
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-  aos_utresult_t utAlldTps62113Ina219Func(BaseSequentialStream* stream, aos_unittest_t* ut);
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* (AMIROOS_CFG_TESTS_ENABLE == true) && defined(AMIROLLD_CFG_USE_TPS62113) && defined(AMIROLLD_CFG_USE_INA219) */
-
-#endif /* _AMIROOS_UT_ALLD_TPS62113_INA219_H_ */
diff --git a/os/unittests/periphery-lld/inc/ut_alld_vcnl4020.h b/os/unittests/periphery-lld/inc/ut_alld_vcnl4020.h
deleted file mode 100644
index 4c0c37f..0000000
--- a/os/unittests/periphery-lld/inc/ut_alld_vcnl4020.h
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
-AMiRo-OS is an operating system designed for the Autonomous Mini Robot (AMiRo) platform.
-Copyright (C) 2016..2018  Thomas Schöpping et al.
-
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program.  If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#ifndef _AMIROOS_UT_VCNL4020_LLD_HPP_
-#define _AMIROOS_UT_VCNL4020_LLD_HPP_
-
-#include <aos_unittest.h>
-#include <amiro-lld.h>
-
-#if ((AMIROOS_CFG_TESTS_ENABLE == true) && defined(AMIROLLD_CFG_USE_VCNL4020)) || defined(__DOXYGEN__)
-
-#include <alld_vcnl4020.h>
-
-/**
- * @brief   Custom data structure for the unit test.
- */
-typedef struct {
-  /**
-   * @brief   VCNL4020 driver to use.
-   */
-  VCNL4020Driver *vcnld;
-
-  /**
-   * @brief   Timeout for certain tests.
-   */
-  apalTime_t timeout;
-
-  /**
-   * @brief   Event source to listen to.
-   */
-  event_source_t* evtsource;
-
-  /**
-   * @brief   Event flags to watch.
-   */
-  eventflags_t evtflags;
-} ut_vcnl4020data_t;
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-  aos_utresult_t utAlldVcnl4020Func(BaseSequentialStream* stream, aos_unittest_t* ut);
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* (AMIROOS_CFG_TESTS_ENABLE == true) && defined(AMIROLLD_CFG_USE_VCNL4020) */
-
-#endif /* _AMIROOS_UT_VCNL4020_LLD_HPP_ */
-
-
diff --git a/os/unittests/periphery-lld/module.h b/os/unittests/periphery-lld/module.h
deleted file mode 100755
index d6ba3e9..0000000
--- a/os/unittests/periphery-lld/module.h
+++ /dev/null
@@ -1,397 +0,0 @@
-/*
-AMiRo-OS is an operating system designed for the Autonomous Mini Robot (AMiRo) platform.
-Copyright (C) 2016..2018  Thomas Schöpping et al.
-
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program.  If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#ifndef _AMIROOS_MODULE_H_
-#define _AMIROOS_MODULE_H_
-
-/*===========================================================================*/
-/**
- * @name Module specific functions
- * @{
- */
-/*===========================================================================*/
-
-static void _alld_dw1000_callback(void* args);
-
-/** @} */
-
-/*===========================================================================*/
-/**
- * @name ChibiOS/HAL configuration
- * @{
- */
-/*===========================================================================*/
-#include <hal.h>
-
-/**
- * @brief   CAN driver to use.
- */
-#define MODULE_HAL_CAN                          CAND1
-
-/**
- * @brief   Configuration for the CAN driver.
- */
-extern CANConfig moduleHalCanConfig;
-
-/**
- * @brief   I2C driver to access the EEPROM.
- */
-#define MODULE_HAL_I2C_EEPROM                   I2CD2
-
-/**
- * @brief   Configuration for the EEPROM I2C driver.
- */
-extern I2CConfig moduleHalI2cEepromConfig;
-
-/**
- * @brief   Serial driver of the programmer interface.
- */
-#define MODULE_HAL_PROGIF                       SD1
-
-/**
- * @brief   Configuration for the programmer serial interface driver.
- */
-extern SerialConfig moduleHalProgIfConfig;
-
-/**
- * @brief   SPI interface driver for the motion sensors (gyroscope and accelerometer).
- */
-#define MODULE_HAL_SPI_LIGHT                    SPID1
-
-/**
- * @brief   SPI interface driver for UWB Module.
- */
-#define MODULE_HAL_SPI_UWB                      SPID2
-
-/**
- * @brief   Configuration for the SPI interface driver to communicate with the LED driver.
- */
-extern SPIConfig moduleHalSpiLightConfig;
-
-/**
- * @brief   Configuration for the SPI interface driver to communicate with the LED driver.
- */
-extern SPIConfig moduleHalSpiUWBConfig;
-
-/**
- * @brief   Real-Time Clock driver.
- */
-#define MODULE_HAL_RTC                          RTCD1
-
-/** @} */
-
-/*===========================================================================*/
-/**
- * @name GPIO definitions
- * @{
- */
-/*===========================================================================*/
-#include <amiro-lld.h>
-
-/**
- * @brief   LIGHT_BANK output signal GPIO.
- */
-extern apalControlGpio_t moduleGpioLightBlank;
-
-/**
- * @brief   LASER_EN output signal GPIO.
- */
-extern apalControlGpio_t moduleGpioLaserEn;
-
-/**
- * @brief   LASER_OC input signal GPIO.
- */
-extern apalControlGpio_t moduleGpioLaserOc;
-
-/**
- * @brief   SYS_UART_DN bidirectional signal GPIO.
- */
-extern apalControlGpio_t moduleGpioSysUartDn;
-
-/**
- * @brief   WL_GDO2 input signal GPIO.
- */
-extern apalControlGpio_t moduleGpioWlGdo2;
-
-/**
- * @brief   WL_GDO0 input signal GPIO.
- */
-extern apalControlGpio_t moduleGpioWlGdo0;
-
-/**
- * @brief   LIGHT_XLAT output signal GPIO.
- */
-extern apalControlGpio_t moduleGpioLightXlat;
-
-/**
- * @brief   SYS_PD bidirectional signal GPIO.
- */
-extern apalControlGpio_t moduleGpioSysPd;
-
-/**
- * @brief   SYS_SYNC bidirectional signal GPIO.
- */
-extern apalControlGpio_t moduleGpioSysSync;
-
-/** @} */
-
-/*===========================================================================*/
-/**
- * @name AMiRo-OS core configurations
- * @{
- */
-/*===========================================================================*/
-
-/**
- * @brief   Event flag to be set on a LASER_OC interrupt.
- */
-#define MODULE_OS_IOEVENTFLAGS_LASEROC          ((eventflags_t)1 << GPIOB_LASER_OC_N)
-
-/**
- * @brief   Event flag to be set on a SYS_UART_DN interrupt.
- */
-#define MODULE_OS_IOEVENTFLAGS_SYSUARTDN        ((eventflags_t)1 << GPIOB_SYS_UART_DN)
-
-/**
- * @brief   Event flag to be set on a WL_GDO2 interrupt.
- */
-#define MODULE_OS_IOEVENTFLAGS_WLGDO2           ((eventflags_t)1 << GPIOB_WL_GDO2)
-
-/**
- * @brief   Event flag to be set on a WL_GDO0 interrupt.
- */
-#define MODULE_OS_IOEVENTFLAGS_WLGDO0           ((eventflags_t)1 << GPIOB_WL_GDO0)
-
-/**
- * @brief   Event flag to be set on a SYS_PD interrupt.
- */
-#define MODULE_OS_IOEVENTFLAGS_SYSPD            ((eventflags_t)1 << GPIOC_SYS_PD_N)
-
-/**
- * @brief   Event flag to be set on a SYS_SYNC interrupt.
- */
-#define MODULE_OS_IOEVENTFLAGS_SYSSYNC          ((eventflags_t)1 << GPIOD_SYS_INT_N)
-
-#if (AMIROOS_CFG_SHELL_ENABLE == true) || defined(__DOXYGEN__)
-/**
- * @brief   Shell prompt text.
- */
-extern const char* moduleShellPrompt;
-#endif
-
-
-
-
-/**
- * @brief   Interrupt initialization macro.
- * @note    SSSP related interrupt signals are already initialized in 'aos_system.c'.
- */
-#define MODULE_INIT_INTERRUPTS() {                                            \
-  /* LASER_OC */                                                              \
-  palSetPadCallback(moduleGpioLaserOc.gpio->port, moduleGpioLaserOc.gpio->pad, _intCallback, &moduleGpioLaserOc.gpio->pad); \
-  palEnablePadEvent(moduleGpioLaserOc.gpio->port, moduleGpioLaserOc.gpio->pad, APAL2CH_EDGE(moduleGpioLaserOc.meta.edge));  \
-  /* WL_GDO2 */                                                               \
-  palSetPadCallback(moduleGpioWlGdo2.gpio->port, moduleGpioWlGdo2.gpio->pad, _alld_dw1000_callback, &moduleGpioWlGdo2.gpio->pad);  \
-  palEnablePadEvent(moduleGpioWlGdo2.gpio->port, moduleGpioWlGdo2.gpio->pad, APAL2CH_EDGE(moduleGpioWlGdo2.meta.edge));   \
-  /* WL_GDO0 */                                                               \
-  palSetPadCallback(moduleGpioWlGdo0.gpio->port, moduleGpioWlGdo0.gpio->pad, _alld_dw1000_callback, &moduleGpioWlGdo0.gpio->pad);  \
-  /*palEnablePadEvent(moduleGpioWlGdo0.gpio->port, moduleGpioWlGdo0.gpio->pad, APAL2CH_EDGE(moduleGpioWlGdo0.meta.edge)); // this is broken for some reason*/   \
-}
-
-/**
- * @brief   Unit test initialization hook.
- */
-#define MODULE_INIT_TESTS() {                                                 \
-  /* add unit-test shell commands */                                          \
-  aosShellAddCommand(&aos.shell, &moduleUtAlldAt24c01bn.shellcmd);            \
-  aosShellAddCommand(&aos.shell, &moduleUtAlldTlc5947.shellcmd);              \
-  aosShellAddCommand(&aos.shell, &moduleUtAlldTps2051bdbv.shellcmd);          \
-  aosShellAddCommand(&aos.shell, &moduleUtAlldDw1000.shellcmd);                \
-}
-
-/**
- * @brief   Periphery communication interfaces initialization hook.
- */
-#define MODULE_INIT_PERIPHERY_COMM() {                                        \
-  /* serial driver */                                                         \
-  sdStart(&MODULE_HAL_PROGIF, &moduleHalProgIfConfig);                        \
-  /* I2C */                                                                   \
-  moduleHalI2cEepromConfig.clock_speed = (AT24C01BN_LLD_I2C_MAXFREQUENCY < moduleHalI2cEepromConfig.clock_speed) ? AT24C01BN_LLD_I2C_MAXFREQUENCY : moduleHalI2cEepromConfig.clock_speed; \
-  moduleHalI2cEepromConfig.duty_cycle = (moduleHalI2cEepromConfig.clock_speed <= 100000) ? STD_DUTY_CYCLE : FAST_DUTY_CYCLE_2;  \
-  i2cStart(&MODULE_HAL_I2C_EEPROM, &moduleHalI2cEepromConfig);                \
-  /* SPI */                                                                   \
-  spiStart(&MODULE_HAL_SPI_LIGHT, &moduleHalSpiLightConfig);                  \
-  spiStart(&MODULE_HAL_SPI_UWB, &moduleHalSpiUWBConfig);                      \
-}
-
-/**
- * @brief   Periphery communication interface deinitialization hook.
- */
-#define MODULE_SHUTDOWN_PERIPHERY_COMM() {                                    \
-  /* SPI */                                                                   \
-  spiStop(&MODULE_HAL_SPI_LIGHT);                                             \
-  spiStop(&MODULE_HAL_SPI_UWB);                                               \
-  /* I2C */                                                                   \
-  i2cStop(&MODULE_HAL_I2C_EEPROM);                                            \
-  /* don't stop the serial driver so messages can still be printed */         \
-}
-
-/** @} */
-
-/*===========================================================================*/
-/**
- * @name Startup Shutdown Synchronization Protocol (SSSP)
- * @{
- */
-/*===========================================================================*/
-
-/**
- * @brief   PD signal GPIO.
- */
-#define moduleSsspGpioPd                        moduleGpioSysPd
-
-/**
- * @brief   SYNC signal GPIO.
- */
-#define moduleSsspGpioSync                      moduleGpioSysSync
-
-/**
- * @brief   DN signal GPIO.
- */
-#define moduleSsspGpioDn                        moduleGpioSysUartDn
-
-/**
- * @brief   Event flags for PD signal events.
- */
-#define MODULE_SSSP_EVENTFLAGS_PD               MODULE_OS_IOEVENTFLAGS_SYSPD
-
-/**
- * @brief   Event flags for SYNC signal events.
- */
-#define MODULE_SSSP_EVENTFLAGS_SYNC             MODULE_OS_IOEVENTFLAGS_SYSSYNC
-
-/**
- * @brief   Event flags for DN signal events.
- */
-#define MODULE_SSSP_EVENTFLAGS_DN               MODULE_OS_IOEVENTFLAGS_SYSUARTDN
-
-/** @} */
-
-/*===========================================================================*/
-/**
- * @name Low-level drivers
- * @{
- */
-/*===========================================================================*/
-#include <alld_at24c01bn-sh-b.h>
-#include <alld_tlc5947.h>
-#include <alld_tps2051bdbv.h>
-#include <alld_dw1000.h>
-
-/**
- * @brief   EEPROM driver.
- */
-extern AT24C01BNDriver moduleLldEeprom;
-
-/**
- * @brief   LED PWM driver.
- */
-extern TLC5947Driver moduleLldLedPwm;
-
-/**
- * @brief   Power switch driver for the laser supply power.
- */
-extern TPS2051BDriver moduleLldPowerSwitchLaser;
-
-/**
- * @brief   DW1000 driver for UWB.
- */
-extern DW1000Driver moduleLldDW1000;
-
-
-
-
-/*! ------------------------------------------------------------------------------------------------------------------
- * Function: _alld_dw1000_callback()
- *
- * Low level abstract function to handle 'reset' adn 'irq' interrupt from DW1000
- * Expects arg to be of iopadid_t* type, used to distinguish between irq or reset signal
- */
-static void _alld_dw1000_callback(void* args) {
-
-    aosDbgCheck(true);
-
-
-    chSysLockFromISR();
-    if ((*(iopadid_t*) args) == moduleLldDW1000.gpio_reset->pad)
-    {
-        // dw1000 external indicate reset done
-    }
-    else if ((*(iopadid_t*) args) == moduleLldDW1000.gpio_exti->pad)
-    {
-        dwt_isr();
-    }
-    else
-    {
-        return;
-    }
-    chSysUnlockFromISR();
-
-}
-
-
-/** @} */
-
-/*===========================================================================*/
-/**
- * @name Unit tests (UT)
- * @{
- */
-/*===========================================================================*/
-#if (AMIROOS_CFG_TESTS_ENABLE == true) || defined(__DOXYGEN__)
-#include <ut_alld_at24c01bn-sh-b.h>
-#include <ut_alld_tlc5947.h>
-#include <ut_alld_tps2051bdbv.h>
-#include <ut_alld_dw1000.h>
-
-/**
- * @brief   EEPROM unit test object.
- */
-extern aos_unittest_t moduleUtAlldAt24c01bn;
-
-/**
- * @brief   LED PWM driver unit test object.
- */
-extern aos_unittest_t moduleUtAlldTlc5947;
-
-/**
- * @brief   Current-limited power switch (Laser output)
- */
-extern aos_unittest_t moduleUtAlldTps2051bdbv;
-
-/**
- * @brief   DW1000 unit test object.
- */
-extern aos_unittest_t moduleUtAlldDw1000;
-
-
-#endif /* AMIROOS_CFG_TESTS_ENABLE == true */
-
-/** @} */
-
-#endif /* _AMIROOS_MODULE_H_ */
diff --git a/os/unittests/periphery-lld/src/ut_alld_a3906.c b/os/unittests/periphery-lld/src/ut_alld_a3906.c
deleted file mode 100644
index f4bbe3f..0000000
--- a/os/unittests/periphery-lld/src/ut_alld_a3906.c
+++ /dev/null
@@ -1,259 +0,0 @@
-/*
-AMiRo-OS is an operating system designed for the Autonomous Mini Robot (AMiRo) platform.
-Copyright (C) 2016..2018  Thomas Schöpping et al.
-
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program.  If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#include <ut_alld_a3906.h>
-
-#if ((AMIROOS_CFG_TESTS_ENABLE == true) && defined(AMIROLLD_CFG_USE_A3906)) || defined(__DOXYGEN__)
-
-#include <aos_debug.h>
-#include <chprintf.h>
-#include <alld_a3906.h>
-#include <aos_thread.h>
-#include <stdlib.h>
-#include <math.h>
-
-/**
- * @brief   Interval to poll QEI in certain tests.
- */
-#define QEI_POLL_INTERVAL_MS          100
-
-/**
- * @brief   Threshold for QEI differences.
- * @details Differences smaller tahn or equal to this value are neglected (interpreted as zero).
- */
-#define QEI_DIFF_THRESHOLD            4
-
-/**
- * @brief   Enumerator to distinguish between left and right wheel.
- */
-typedef enum {
-  WHEEL_LEFT    = 0,  /**< left wheel identifier */
-  WHEEL_RIGHT   = 1,  /**< right wheel identifier */
-} wheel_t;
-
-/**
- * @brief   Enumerator to distinguish directions.
- */
-typedef enum {
-  DIRECTION_FORWARD   = 0,  /**< forward direction identifier */
-  DIRECTION_BACKWARD  = 1,  /**< backward direction identifier */
-} direction_t;
-
-/**
- * @brief   helper function to test each wheel and direction separately.
- *
- * @param[in] stream      Stream for input/output.
- * @param[in] data        Unit test meta data.
- * @param[in] wheel       Wheel to test.
- * @param[in] direction   Direction to test.
- * @param[in,out] result  Result variable to modify.
- */
-void _wheelDirectionTest(BaseSequentialStream* stream, ut_a3906data_t* data, wheel_t wheel, direction_t direction, aos_utresult_t* result)
-{
-  // local variables
-  uint32_t status;
-  bool qei_valid;
-  apalQEICount_t qei_count[2];
-  apalQEIDirection_t qei_direction;
-  uint32_t timeout_counter;
-
-  chprintf(stream, "%s wheel %s...\n", (wheel == WHEEL_LEFT) ? "left" : "right", (direction == DIRECTION_FORWARD) ? "forward" : "backward");
-  qei_valid = false;
-  status = apalQEIGetPosition((wheel == WHEEL_LEFT) ? data->qei.left : data->qei.right, &qei_count[0]);
-  // increase PWM incrementally and read QEI data
-  for (apalPWMwidth_t pwm_width = APAL_PWM_WIDTH_MIN; pwm_width < APAL_PWM_WIDTH_MAX; ++pwm_width) {
-    status |= a3906_lld_set_pwm(data->pwm.driver, (wheel == WHEEL_LEFT) ?
-                                  ((direction == DIRECTION_FORWARD) ? data->pwm.channel.left_forward : data->pwm.channel.left_backward) :
-                                  ((direction == DIRECTION_FORWARD) ? data->pwm.channel.right_forward : data->pwm.channel.right_backward),
-                                pwm_width);
-    status |= apalQEIGetPosition((wheel == WHEEL_LEFT) ? data->qei.left : data->qei.right, &qei_count[1]);
-    qei_valid = qei_valid || (qei_count[0] != qei_count[1]);
-    aosThdUSleep(5 * MICROSECONDS_PER_SECOND / (APAL_PWM_WIDTH_MAX - APAL_PWM_WIDTH_MIN));
-    qei_count[0] = qei_count[1];
-  }
-  status |= qei_valid ? 0x00 : 0x10;
-  status |= apalQEIGetDirection((wheel == WHEEL_LEFT) ? data->qei.left : data->qei.right, &qei_direction);
-  status |= (qei_direction == ((direction == DIRECTION_FORWARD) ? APAL_QEI_DIRECTION_UP : APAL_QEI_DIRECTION_DOWN)) ? 0x00 : 0x20;
-
-  // let the wheel spin free until it stops
-  status |= a3906_lld_set_pwm(data->pwm.driver, (wheel == WHEEL_LEFT) ?
-                                ((direction == DIRECTION_FORWARD) ? data->pwm.channel.left_forward : data->pwm.channel.left_backward) :
-                                ((direction == DIRECTION_FORWARD) ? data->pwm.channel.right_forward : data->pwm.channel.right_backward),
-                              0);
-  qei_count[0] = 0;
-  qei_count[1] = 0;
-  timeout_counter = 0;
-  do {
-    status |= apalQEIGetPosition((wheel == WHEEL_LEFT) ? data->qei.left : data->qei.right, &qei_count[0]);
-    aosThdMSleep(1);
-    status |= apalQEIGetPosition((wheel == WHEEL_LEFT) ? data->qei.left : data->qei.right, &qei_count[1]);
-    ++timeout_counter;
-  } while ((qei_count[0] != qei_count[1]) && (timeout_counter * MICROSECONDS_PER_MILLISECOND <= data->timeout));
-  status |= (timeout_counter * MICROSECONDS_PER_MILLISECOND > data->timeout) ? APAL_STATUS_TIMEOUT : 0x00;
-
-  // report result
-  if (status == APAL_STATUS_SUCCESS) {
-    aosUtPassed(stream, result);
-  } else {
-    aosUtFailedMsg(stream, result, "0x%08X\n", status);
-  }
-
-  return;
-}
-
-/**
- * @brief   A3905 unit test function.
- *
- * @param[in] stream  Stream for input/output.
- * @param[in] ut      Unit test object.
- *
- * @return            Unit test result value.
- */
-aos_utresult_t utAlldA3906Func(BaseSequentialStream* stream, aos_unittest_t* ut)
-{
-  aosDbgCheck((ut->data != NULL) &&
-              (((ut_a3906data_t*)ut->data)->driver != NULL) &&
-              (((ut_a3906data_t*)ut->data)->pwm.driver != NULL) &&
-              (((ut_a3906data_t*)ut->data)->qei.left != NULL) &&
-              (((ut_a3906data_t*)ut->data)->qei.right != NULL));
-
-
-
-  // local variables
-  aos_utresult_t result = {0, 0};
-  uint32_t status = 0;
-  a3906_lld_power_t power_state;
-  apalQEICount_t qei_count[2][2];
-  apalQEICount_t qei_range[2];
-  uint32_t timeout_counter;
-  apalQEICount_t qei_increments[2][2];
-  uint32_t stable_counter;
-  apalQEICount_t qei_increments_diff[2];
-
-  chprintf(stream, "enable power...\n");
-  power_state = A3906_LLD_POWER_ON;
-  status = a3906_lld_set_power(((ut_a3906data_t*)ut->data)->driver, power_state);
-  status |= a3906_lld_get_power(((ut_a3906data_t*)ut->data)->driver, &power_state);
-  status |= (power_state != A3906_LLD_POWER_ON) ? 0x10 : 0x00;
-  if (status == APAL_STATUS_SUCCESS) {
-    aosUtPassed(stream, &result);
-  } else {
-    aosUtFailedMsg(stream, &result, "0x%08X\n", status);
-  }
-
-  _wheelDirectionTest(stream, (ut_a3906data_t*)ut->data, WHEEL_LEFT, DIRECTION_FORWARD, &result);
-
-  _wheelDirectionTest(stream, (ut_a3906data_t*)ut->data, WHEEL_LEFT, DIRECTION_BACKWARD, &result);
-
-  _wheelDirectionTest(stream, (ut_a3906data_t*)ut->data, WHEEL_RIGHT, DIRECTION_FORWARD, &result);
-
-  _wheelDirectionTest(stream, (ut_a3906data_t*)ut->data, WHEEL_RIGHT, DIRECTION_BACKWARD, &result);
-
-  chprintf(stream, "both wheels full speed forward...\n");
-  status = APAL_STATUS_SUCCESS;
-  status |= a3906_lld_set_pwm(((ut_a3906data_t*)ut->data)->pwm.driver, ((ut_a3906data_t*)ut->data)->pwm.channel.left_forward, APAL_PWM_WIDTH_MAX);
-  status |= a3906_lld_set_pwm(((ut_a3906data_t*)ut->data)->pwm.driver, ((ut_a3906data_t*)ut->data)->pwm.channel.right_forward, APAL_PWM_WIDTH_MAX);
-  aosThdMSleep(100);
-  qei_count[WHEEL_LEFT][0] = 0;
-  qei_count[WHEEL_LEFT][1] = 0;
-  qei_count[WHEEL_RIGHT][0] = 0;
-  qei_count[WHEEL_RIGHT][1] = 0;
-  status |= apalQEIGetRange(((ut_a3906data_t*)ut->data)->qei.left, &qei_range[WHEEL_LEFT]);
-  status |= apalQEIGetRange(((ut_a3906data_t*)ut->data)->qei.right, &qei_range[WHEEL_RIGHT]);
-  timeout_counter = 0;
-  qei_increments[WHEEL_LEFT][0] = 0;
-  qei_increments[WHEEL_LEFT][1] = 0;
-  qei_increments[WHEEL_RIGHT][0] = 0;
-  qei_increments[WHEEL_RIGHT][1] = 0;
-  stable_counter = 0;
-  do {
-    status |= apalQEIGetPosition(((ut_a3906data_t*)ut->data)->qei.left, &qei_count[WHEEL_LEFT][0]);
-    status |= apalQEIGetPosition(((ut_a3906data_t*)ut->data)->qei.right, &qei_count[WHEEL_RIGHT][0]);
-    aosThdMSleep(QEI_POLL_INTERVAL_MS);
-    status |= apalQEIGetPosition(((ut_a3906data_t*)ut->data)->qei.left, &qei_count[WHEEL_LEFT][1]);
-    status |= apalQEIGetPosition(((ut_a3906data_t*)ut->data)->qei.right, &qei_count[WHEEL_RIGHT][1]);
-    timeout_counter += QEI_POLL_INTERVAL_MS;
-    qei_increments[WHEEL_LEFT][0] = qei_increments[WHEEL_LEFT][1];
-    qei_increments[WHEEL_LEFT][1] = (qei_count[WHEEL_LEFT][1] > qei_count[WHEEL_LEFT][0]) ? (qei_count[WHEEL_LEFT][1] - qei_count[WHEEL_LEFT][0]) : (qei_count[WHEEL_LEFT][1] + (qei_range[WHEEL_LEFT] - qei_count[WHEEL_LEFT][0]));
-    qei_increments[WHEEL_RIGHT][0] = qei_increments[WHEEL_RIGHT][1];
-    qei_increments[WHEEL_RIGHT][1] = (qei_count[WHEEL_RIGHT][1] > qei_count[WHEEL_RIGHT][0]) ? (qei_count[WHEEL_RIGHT][1] - qei_count[WHEEL_RIGHT][0]) : (qei_count[WHEEL_RIGHT][1] + (qei_range[WHEEL_RIGHT] - qei_count[WHEEL_RIGHT][0]));
-    qei_increments_diff[WHEEL_LEFT] = abs((int32_t)(qei_increments[WHEEL_LEFT][0]) - (int32_t)qei_increments[WHEEL_LEFT][1]);
-    qei_increments_diff[WHEEL_RIGHT] = abs((int32_t)(qei_increments[WHEEL_RIGHT][0]) - (int32_t)qei_increments[WHEEL_RIGHT][1]);
-    stable_counter = (qei_increments_diff[WHEEL_LEFT] <= QEI_DIFF_THRESHOLD && qei_increments_diff[WHEEL_RIGHT] < QEI_DIFF_THRESHOLD) ? stable_counter+1 : 0;
-  } while((stable_counter * QEI_POLL_INTERVAL_MS < MILLISECONDS_PER_SECOND) && (timeout_counter * MICROSECONDS_PER_MILLISECOND <= ((ut_a3906data_t*)ut->data)->timeout));
-  status |= (timeout_counter * MICROSECONDS_PER_MILLISECOND > ((ut_a3906data_t*)ut->data)->timeout) ? APAL_STATUS_TIMEOUT : 0x00;
-  if (status == APAL_STATUS_SUCCESS) {
-    aosUtPassed(stream, &result);
-    const float tps[2] = {qei_increments[WHEEL_LEFT][1] * ((float)MILLISECONDS_PER_SECOND / (float)QEI_POLL_INTERVAL_MS),
-                          qei_increments[WHEEL_RIGHT][1] * ((float)MILLISECONDS_PER_SECOND / (float)QEI_POLL_INTERVAL_MS)};
-    const float rpm[2] = {tps[WHEEL_LEFT] * SECONDS_PER_MINUTE / (float)(((ut_a3906data_t*)ut->data)->qei.increments_per_revolution),
-                          tps[WHEEL_RIGHT] * SECONDS_PER_MINUTE / (float)(((ut_a3906data_t*)ut->data)->qei.increments_per_revolution)};
-    const float velocity[2] = {tps[WHEEL_LEFT] / (float)(((ut_a3906data_t*)ut->data)->qei.increments_per_revolution) * ((ut_a3906data_t*)ut->data)->wheel_diameter * acos(-1),
-                               tps[WHEEL_RIGHT] / (float)(((ut_a3906data_t*)ut->data)->qei.increments_per_revolution) * ((ut_a3906data_t*)ut->data)->wheel_diameter * acos(-1)};
-    chprintf(stream, "left wheel:\n");
-    chprintf(stream, "\t%f tps\n", tps[WHEEL_LEFT]);
-    chprintf(stream, "\t%f RPM\n", rpm[WHEEL_LEFT]);
-    chprintf(stream, "\t%f m/s\n", velocity[WHEEL_LEFT]);
-    chprintf(stream, "right wheel:\n");
-    chprintf(stream, "\t%f tps\n", tps[WHEEL_RIGHT]);
-    chprintf(stream, "\t%f RPM\n", rpm[WHEEL_RIGHT]);
-    chprintf(stream, "\t%f m/s\n", velocity[WHEEL_RIGHT]);
-    chprintf(stream, "\n");
-  } else {
-    aosUtFailedMsg(stream, &result, "0x%08X\n", status);
-  }
-
-  chprintf(stream, "disable power... \n");
-  power_state = A3906_LLD_POWER_OFF;
-  status = a3906_lld_set_power(((ut_a3906data_t*)ut->data)->driver, power_state);
-  status |= a3906_lld_get_power(((ut_a3906data_t*)ut->data)->driver, &power_state);
-  status |= (power_state != A3906_LLD_POWER_OFF) ? 0x10 : 0x00;
-  qei_count[WHEEL_LEFT][0] = 0;
-  qei_count[WHEEL_LEFT][1] = 0;
-  qei_count[WHEEL_RIGHT][0] = 0;
-  qei_count[WHEEL_RIGHT][1] = 0;
-  timeout_counter = 0;
-  stable_counter = 0;
-  do {
-    status |= apalQEIGetPosition(((ut_a3906data_t*)ut->data)->qei.left, &qei_count[WHEEL_LEFT][0]);
-    status |= apalQEIGetPosition(((ut_a3906data_t*)ut->data)->qei.right, &qei_count[WHEEL_RIGHT][0]);
-    aosThdMSleep(1);
-    status |= apalQEIGetPosition(((ut_a3906data_t*)ut->data)->qei.left, &qei_count[WHEEL_LEFT][1]);
-    status |= apalQEIGetPosition(((ut_a3906data_t*)ut->data)->qei.right, &qei_count[WHEEL_RIGHT][1]);
-    ++timeout_counter;
-    stable_counter = (qei_count[WHEEL_LEFT][0] == qei_count[WHEEL_LEFT][1] && qei_count[WHEEL_RIGHT][0] == qei_count[WHEEL_RIGHT][1]) ? stable_counter+1 : 0;
-  } while((stable_counter < 100) && (timeout_counter * MICROSECONDS_PER_MILLISECOND <= ((ut_a3906data_t*)ut->data)->timeout));
-  status |= (timeout_counter * MICROSECONDS_PER_MILLISECOND > ((ut_a3906data_t*)ut->data)->timeout) ? APAL_STATUS_TIMEOUT : 0x00;
-  if (status == APAL_STATUS_SUCCESS) {
-    aosUtPassed(stream, &result);
-  } else {
-    aosUtFailedMsg(stream, &result, "0x%08X\n", status);
-  }
-
-  // stop the PWM
-  a3906_lld_set_pwm(((ut_a3906data_t*)ut->data)->pwm.driver, ((ut_a3906data_t*)ut->data)->pwm.channel.left_forward, APAL_PWM_WIDTH_OFF);
-  a3906_lld_set_pwm(((ut_a3906data_t*)ut->data)->pwm.driver, ((ut_a3906data_t*)ut->data)->pwm.channel.left_backward, APAL_PWM_WIDTH_OFF);
-  a3906_lld_set_pwm(((ut_a3906data_t*)ut->data)->pwm.driver, ((ut_a3906data_t*)ut->data)->pwm.channel.right_forward, APAL_PWM_WIDTH_OFF);
-  a3906_lld_set_pwm(((ut_a3906data_t*)ut->data)->pwm.driver, ((ut_a3906data_t*)ut->data)->pwm.channel.right_backward, APAL_PWM_WIDTH_OFF);
-
-  aosUtInfoMsg(stream,"driver object memory footprint: %u bytes\n", sizeof(A3906Driver));
-
-  return result;
-}
-
-#endif /* (AMIROOS_CFG_TESTS_ENABLE == true) && defined(AMIROLLD_CFG_USE_A3906) */
diff --git a/os/unittests/periphery-lld/src/ut_alld_at24c01bn-sh-b.c b/os/unittests/periphery-lld/src/ut_alld_at24c01bn-sh-b.c
deleted file mode 100644
index a841ba0..0000000
--- a/os/unittests/periphery-lld/src/ut_alld_at24c01bn-sh-b.c
+++ /dev/null
@@ -1,205 +0,0 @@
-/*
-AMiRo-OS is an operating system designed for the Autonomous Mini Robot (AMiRo) platform.
-Copyright (C) 2016..2018  Thomas Schöpping et al.
-
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program.  If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#include <ut_alld_at24c01bn-sh-b.h>
-
-#if ((AMIROOS_CFG_TESTS_ENABLE == true) && defined(AMIROLLD_CFG_USE_AT24C01BN)) || defined(__DOXYGEN__)
-
-#include <aos_debug.h>
-#include <chprintf.h>
-
-/**
- * @brief   EEPROM address for page write/read access.
- */
-#define _pageAddress                  (AT24C01BN_LLD_SIZE_BYTES - 2*AT24C01BN_LLD_PAGE_SIZE_BYTES)
-
-/**
- * @brief   EEPROM address for byte write/read access.
- */
-#define _byteAddress                  (_pageAddress + AT24C01BN_LLD_PAGE_SIZE_BYTES - 1)
-
-/**
- * @brief   Offset for overflow tests.
- */
-#define _overflowOffset               3
-
-/**
- * @brief   EEPROM address for page write/read access with overflow.
- */
-#define _overflowAddress              (_pageAddress + _overflowOffset)
-
-/**
- * @brief   Test data byte.
- */
-#define _bytedata                     0xA5
-
-/**
- * @brief   AT24C01BN-SH-B unit test function.
- *
- * @param[in] stream  Stream for inout/outout.
- * @param[in] ut      Unit test object.
- *
- * @return            Unit test result value.
- */
-aos_utresult_t utAlldAt24c01bnFunc(BaseSequentialStream* stream, aos_unittest_t* ut)
-{
-  aosDbgCheck(ut->data != NULL && ((ut_at24c01bndata_t*)(ut->data))->driver != NULL);
-
-  // local variables
-  aos_utresult_t result = {0, 0};
-  uint32_t status = 0;
-  uint8_t page_data[AT24C01BN_LLD_PAGE_SIZE_BYTES];
-  uint8_t original_data[AT24C01BN_LLD_PAGE_SIZE_BYTES];
-  uint8_t read_data[AT24C01BN_LLD_PAGE_SIZE_BYTES];
-  size_t errors = 0;
-  for (size_t dataIdx = 0; dataIdx < AT24C01BN_LLD_PAGE_SIZE_BYTES; ++dataIdx) {
-    page_data[dataIdx] = dataIdx;
-  }
-
-  chprintf(stream, "reading byte...\n");
-  status = at24c01bn_lld_read(((ut_at24c01bndata_t*)(ut->data))->driver, _byteAddress, original_data, 1, ((ut_at24c01bndata_t*)(ut->data))->timeout);
-  if (status == APAL_STATUS_SUCCESS || status == APAL_STATUS_WARNING) {
-    aosUtPassed(stream, &result);
-  } else {
-    aosUtFailedMsg(stream, &result, "0x%08X\n", status);
-  }
-
-  chprintf(stream, "writing byte...\n");
-  status = at24c01bn_lld_write_byte(((ut_at24c01bndata_t*)(ut->data))->driver, _byteAddress, _bytedata, ((ut_at24c01bndata_t*)(ut->data))->timeout);
-  while (at24c01bn_lld_poll_ack(((ut_at24c01bndata_t*)(ut->data))->driver, ((ut_at24c01bndata_t*)(ut->data))->timeout) == APAL_STATUS_FAILURE) {
-    continue;
-  }
-  status |= at24c01bn_lld_read(((ut_at24c01bndata_t*)(ut->data))->driver, _byteAddress, &read_data[0], 1, ((ut_at24c01bndata_t*)(ut->data))->timeout);
-  status |= (read_data[0] == _bytedata) ? 0x00 : 0x20;
-  status = at24c01bn_lld_write_byte(((ut_at24c01bndata_t*)(ut->data))->driver, _byteAddress, (uint8_t)~_bytedata, ((ut_at24c01bndata_t*)(ut->data))->timeout);
-  while (at24c01bn_lld_poll_ack(((ut_at24c01bndata_t*)(ut->data))->driver, ((ut_at24c01bndata_t*)(ut->data))->timeout) == APAL_STATUS_FAILURE) {
-    continue;
-  }
-  status |= at24c01bn_lld_read(((ut_at24c01bndata_t*)(ut->data))->driver, _byteAddress, &read_data[1], 1, ((ut_at24c01bndata_t*)(ut->data))->timeout);
-  status |= (read_data[1] == (uint8_t)~_bytedata) ? 0x00 : 0x40;
-  status |= at24c01bn_lld_write_byte(((ut_at24c01bndata_t*)(ut->data))->driver, _byteAddress, original_data[0], ((ut_at24c01bndata_t*)(ut->data))->timeout);
-  while (at24c01bn_lld_poll_ack(((ut_at24c01bndata_t*)(ut->data))->driver, ((ut_at24c01bndata_t*)(ut->data))->timeout) == APAL_STATUS_FAILURE) {
-    continue;
-  }
-  status |= at24c01bn_lld_read(((ut_at24c01bndata_t*)(ut->data))->driver, _byteAddress, &read_data[2], 1, ((ut_at24c01bndata_t*)(ut->data))->timeout);
-  status |= (read_data[2] == original_data[0]) ? 0x00 : 0x80;
-  if (status == APAL_STATUS_SUCCESS || status == APAL_STATUS_WARNING) {
-    aosUtPassed(stream, &result);
-  } else {
-    aosUtFailedMsg(stream, &result, "0x%08X\n", status);
-  }
-
-  chprintf(stream, "reading page...\n");
-  status = at24c01bn_lld_read(((ut_at24c01bndata_t*)(ut->data))->driver, _pageAddress, original_data, AT24C01BN_LLD_PAGE_SIZE_BYTES, ((ut_at24c01bndata_t*)(ut->data))->timeout);
-  if (status == APAL_STATUS_SUCCESS) {
-    aosUtPassed(stream, &result);
-  } else {
-    aosUtFailedMsg(stream, &result, "0x%08X\n", status);
-  }
-
-  chprintf(stream, "writing page...\n");
-  status = at24c01bn_lld_write_page(((ut_at24c01bndata_t*)(ut->data))->driver, _pageAddress, page_data, AT24C01BN_LLD_PAGE_SIZE_BYTES, ((ut_at24c01bndata_t*)(ut->data))->timeout);
-  while (at24c01bn_lld_poll_ack(((ut_at24c01bndata_t*)(ut->data))->driver, ((ut_at24c01bndata_t*)(ut->data))->timeout) == APAL_STATUS_FAILURE) {
-    continue;
-  }
-  status |= at24c01bn_lld_read(((ut_at24c01bndata_t*)(ut->data))->driver, _pageAddress, read_data, AT24C01BN_LLD_PAGE_SIZE_BYTES, ((ut_at24c01bndata_t*)(ut->data))->timeout);
-  errors = 0;
-  for (size_t dataIdx = 0; dataIdx < AT24C01BN_LLD_PAGE_SIZE_BYTES; dataIdx++) {
-    if (read_data[dataIdx] != page_data[dataIdx]) {
-      ++errors;
-    }
-  }
-  if (status == APAL_STATUS_OK && errors == 0) {
-    aosUtPassed(stream, &result);
-  } else {
-    aosUtFailedMsg(stream, &result, "0x%08X; %u\n", status, errors);
-  }
-
-  chprintf(stream, "reading page at current address...\n");
-  // set address counter to UT_ALLD_AT24C01BN_PAGE_ADDRESS
-  status = at24c01bn_lld_read(((ut_at24c01bndata_t*)(ut->data))->driver, _pageAddress-1, read_data, 1, ((ut_at24c01bndata_t*)(ut->data))->timeout);
-  if (status == APAL_STATUS_WARNING) {
-    // on STM32F1 platform the address gets incremented by 2 after reading
-    status = at24c01bn_lld_read(((ut_at24c01bndata_t*)(ut->data))->driver, _pageAddress-2, read_data, 1, ((ut_at24c01bndata_t*)(ut->data))->timeout);
-  }
-  // read page from the current address
-  status = at24c01bn_lld_read_current_address(((ut_at24c01bndata_t*)(ut->data))->driver, read_data, AT24C01BN_LLD_PAGE_SIZE_BYTES, ((ut_at24c01bndata_t*)(ut->data))->timeout);
-  errors = 0;
-  for (uint8_t dataIdx = 0; dataIdx < 8; dataIdx++) {
-    if (read_data[dataIdx] != page_data[dataIdx]) {
-      ++errors;
-    }
-  }
-  if (status == APAL_STATUS_OK && errors == 0) {
-    aosUtPassed(stream, &result);
-  } else {
-    aosUtFailedMsg(stream, &result, "0x%08X; %u\n", status, errors);
-  }
-
-  chprintf(stream, "writing page with overflow (7 bytes)...\n");
-  status = at24c01bn_lld_write_page(((ut_at24c01bndata_t*)(ut->data))->driver, _overflowAddress, page_data, AT24C01BN_LLD_PAGE_SIZE_BYTES-1, ((ut_at24c01bndata_t*)(ut->data))->timeout);
-  while (at24c01bn_lld_poll_ack(((ut_at24c01bndata_t*)(ut->data))->driver, ((ut_at24c01bndata_t*)(ut->data))->timeout) == APAL_STATUS_FAILURE) {
-    continue;
-  }
-  status |= at24c01bn_lld_read(((ut_at24c01bndata_t*)(ut->data))->driver, _overflowAddress, read_data, AT24C01BN_LLD_PAGE_SIZE_BYTES-_overflowOffset, ((ut_at24c01bndata_t*)(ut->data))->timeout);
-  status |= at24c01bn_lld_read(((ut_at24c01bndata_t*)(ut->data))->driver, _overflowAddress-_overflowOffset, read_data+(AT24C01BN_LLD_PAGE_SIZE_BYTES-_overflowOffset), _overflowOffset-1, ((ut_at24c01bndata_t*)(ut->data))->timeout);
-  errors = 0;
-  for (uint8_t dataIdx = 0; dataIdx < AT24C01BN_LLD_PAGE_SIZE_BYTES-1; dataIdx++) {
-    if (read_data[dataIdx] != page_data[dataIdx]) {
-      ++errors;
-    }
-  }
-  if (status == APAL_STATUS_OK && errors == 0) {
-    aosUtPassed(stream, &result);
-  } else {
-    aosUtFailedMsg(stream, &result, "0x%08X; %u\n", status, errors);
-  }
-
-  chprintf(stream, "writing page with overflow (8 bytes)...\n");
-  status = at24c01bn_lld_write_page(((ut_at24c01bndata_t*)(ut->data))->driver, _overflowAddress, page_data, AT24C01BN_LLD_PAGE_SIZE_BYTES, ((ut_at24c01bndata_t*)(ut->data))->timeout);
-  while (at24c01bn_lld_poll_ack(((ut_at24c01bndata_t*)(ut->data))->driver, ((ut_at24c01bndata_t*)(ut->data))->timeout) == APAL_STATUS_FAILURE) {
-    continue;
-  }
-  status |= at24c01bn_lld_read(((ut_at24c01bndata_t*)(ut->data))->driver, _overflowAddress, read_data, AT24C01BN_LLD_PAGE_SIZE_BYTES-_overflowOffset, ((ut_at24c01bndata_t*)(ut->data))->timeout);
-  status |= at24c01bn_lld_read(((ut_at24c01bndata_t*)(ut->data))->driver, _overflowAddress-_overflowOffset, read_data+(AT24C01BN_LLD_PAGE_SIZE_BYTES-_overflowOffset), _overflowOffset, ((ut_at24c01bndata_t*)(ut->data))->timeout);
-  errors = 0;
-  for (uint8_t dataIdx = 0; dataIdx < AT24C01BN_LLD_PAGE_SIZE_BYTES; dataIdx++) {
-    if (read_data[dataIdx] != page_data[dataIdx]) {
-      ++errors;
-    }
-  }
-  if (status == APAL_STATUS_OK && errors == 0) {
-    aosUtPassed(stream, &result);
-  } else {
-    aosUtFailedMsg(stream, &result, "0x%08X; %u\n", status, errors);
-  }
-
-  chprintf(stream, "write back original data...\n");
-  status = at24c01bn_lld_write_page(((ut_at24c01bndata_t*)(ut->data))->driver, _pageAddress, original_data, AT24C01BN_LLD_PAGE_SIZE_BYTES, ((ut_at24c01bndata_t*)(ut->data))->timeout);
-  if (status == APAL_STATUS_SUCCESS) {
-    aosUtPassed(stream, &result);
-  } else {
-    aosUtFailedMsg(stream, &result, "0x%08X\n", status);
-  }
-
-  aosUtInfoMsg(stream,"driver object memory footprint: %u bytes\n", sizeof(AT24C01BNDriver));
-
-  return result;
-}
-
-#endif /* (AMIROOS_CFG_TESTS_ENABLE == true) && defined(AMIROLLD_CFG_USE_AT24C01BN) */
diff --git a/os/unittests/periphery-lld/src/ut_alld_bq24103a.c b/os/unittests/periphery-lld/src/ut_alld_bq24103a.c
deleted file mode 100644
index 42a5ba0..0000000
--- a/os/unittests/periphery-lld/src/ut_alld_bq24103a.c
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
-AMiRo-OS is an operating system designed for the Autonomous Mini Robot (AMiRo) platform.
-Copyright (C) 2016..2018  Thomas Schöpping et al.
-
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program.  If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#include <ut_alld_bq24103a.h>
-
-#if ((AMIROOS_CFG_TESTS_ENABLE == true) && defined(AMIROLLD_CFG_USE_BQ24103A)) || defined(__DOXYGEN__)
-
-#include <aos_debug.h>
-#include <chprintf.h>
-#include <aos_thread.h>
-#include <alld_bq24103a.h>
-
-aos_utresult_t utAlldBq24103aFunc(BaseSequentialStream* stream, aos_unittest_t* ut)
-{
-  aosDbgCheck(ut->data != NULL);
-
-  // local variables
-  aos_utresult_t result = {0, 0};
-  uint32_t status;
-  bq24103a_lld_enable_t en[3];
-  bq24103a_lld_charge_state_t charge;
-
-  chprintf(stream, "read enable pin...\n");
-  status = bq24103a_lld_get_enabled((BQ24103ADriver*)ut->data, &en[0]);
-  chprintf(stream, "\t\tcurrently %s\n", (en[0] == BQ24103A_LLD_ENABLED) ? "enabled" : "disabled");
-  if(status == APAL_STATUS_SUCCESS){
-    aosUtPassed(stream, &result);
-  } else {
-    aosUtFailedMsg(stream, &result, "0x%08X\n", status);
-  }
-
-  chprintf(stream, "write enable pin...\n");
-  status = bq24103a_lld_set_enabled((BQ24103ADriver*)ut->data, (en[0] == BQ24103A_LLD_ENABLED) ? BQ24103A_LLD_DISABLED : BQ24103A_LLD_ENABLED);
-  aosThdMSleep(1);
-  status |= bq24103a_lld_get_enabled((BQ24103ADriver*)ut->data, &en[1]);
-  status |= bq24103a_lld_set_enabled((BQ24103ADriver*)ut->data, en[0]);
-  aosThdMSleep(1);
-  status |= bq24103a_lld_get_enabled((BQ24103ADriver*)ut->data, &en[2]);
-  if(status == APAL_STATUS_SUCCESS && en[0] != en[1] && en[0] == en[2] && en[1] != en[2]){
-    aosUtPassed(stream, &result);
-  } else {
-    aosUtFailedMsg(stream, &result, "0x%08X, %u-%u\n", status, en[1], en[2]);
-  }
-
-  chprintf(stream, "read status pin...\n");
-  aosThdMSleep(500);
-  status = bq24103a_lld_get_charge_status((BQ24103ADriver*)ut->data, &charge);
-  chprintf(stream, "\t\tcharge status: %scharging\n", (charge == BQ24103A_LLD_CHARGING) ? "" : "not ");
-  if (status == APAL_STATUS_SUCCESS) {
-    aosUtPassed(stream, &result);
-  } else {
-    aosUtFailedMsg(stream, &result, "0x%08X\n", status);
-  }
-
-  aosUtInfoMsg(stream,"driver object memory footprint: %u bytes\n", sizeof(BQ24103ADriver));
-
-  return result;
-}
-
-#endif /* (AMIROOS_CFG_TESTS_ENABLE == true) && defined(AMIROLLD_CFG_USE_BQ24103A) */
diff --git a/os/unittests/periphery-lld/src/ut_alld_bq27500.c b/os/unittests/periphery-lld/src/ut_alld_bq27500.c
deleted file mode 100644
index 6fad31f..0000000
--- a/os/unittests/periphery-lld/src/ut_alld_bq27500.c
+++ /dev/null
@@ -1,305 +0,0 @@
-/*
-AMiRo-OS is an operating system designed for the Autonomous Mini Robot (AMiRo) platform.
-Copyright (C) 2016..2018  Thomas Schöpping et al.
-
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program.  If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#include <ut_alld_bq27500.h>
-
-#if ((AMIROOS_CFG_TESTS_ENABLE == true) && defined(AMIROLLD_CFG_USE_BQ27500)) || defined(__DOXYGEN__)
-
-#include <string.h>
-#include <aos_debug.h>
-#include <chprintf.h>
-#include <aos_thread.h>
-#include <alld_bq27500.h>
-
-aos_utresult_t utAlldBq27500Func(BaseSequentialStream* stream, aos_unittest_t* ut)
-{
-  aosDbgCheck(ut->data != NULL && ((ut_bq27500data_t*)(ut->data))->driver != NULL);
-
-  // local variables
-  aos_utresult_t result = {0, 0};
-  uint32_t status;
-  bq27500_lld_batlow_t bl;
-  bq27500_lld_batgood_t bg;
-  uint16_t dst;
-  bq27500_lld_flags_t flags;
-  uint16_t subdata = 0;
-  uint8_t original_length;
-  char original_name[8+1];
-  uint8_t val = 0x00;
-  uint8_t block[32];
-  char new_name[] = "test";
-  uint8_t new_lenght;
-  char name[8+1] = {'\0'};
-  uint8_t sum = 0;
-  bool success;
-  bool success2;
-
-  chprintf(stream, "read battery low gpio...\n");
-  status = bq27500_lld_read_batlow(((ut_bq27500data_t*)ut->data)->driver, &bl);
-  chprintf(stream, "\t\tbattery low: 0x%X\n", bl);
-  if (status == APAL_STATUS_SUCCESS) {
-    aosUtPassed(stream, &result);
-  } else {
-    aosUtFailedMsg(stream, &result, "0x%08X\n", status);
-  }
-
-  chprintf(stream, "read battery good gpio...\n");
-  status = bq27500_lld_read_batgood(((ut_bq27500data_t*)ut->data)->driver, &bg);
-  chprintf(stream, "\t\tbattery good: 0x%X\n", bg);
-  if (status == APAL_STATUS_SUCCESS) {
-    aosUtPassed(stream, &result);
-  } else {
-    aosUtFailedMsg(stream, &result, "0x%08X\n", status);
-  }
-
-  chprintf(stream, "std command FLAGS...\n");
-  status = bq27500_lld_std_command(((ut_bq27500data_t*)ut->data)->driver, BQ27500_LLD_STD_CMD_Flags, &flags.value, ((ut_bq27500data_t*)ut->data)->timeout);
-  chprintf(stream, "\t\tflags: 0x%04X\n", flags.value);
-  chprintf(stream, "\t\tbattery detected: 0x%X\n", flags.content.bat_det);
-  chprintf(stream, "\t\tbattery fully charged: 0x%X\n", flags.content.fc);
-  if (status == APAL_STATUS_SUCCESS) {
-    aosUtPassed(stream, &result);
-  } else {
-    aosUtFailedMsg(stream, &result, "0x%08X\n", status);
-  }
-
-  chprintf(stream, "std command CTNL...\n");
-  status = bq27500_lld_std_command(((ut_bq27500data_t*)ut->data)->driver, BQ27500_LLD_STD_CMD_Control, &dst, ((ut_bq27500data_t*)ut->data)->timeout);
-  if (status == APAL_STATUS_SUCCESS) {
-    aosUtPassed(stream, &result);
-  } else {
-    aosUtFailedMsg(stream, &result, "0x%08X\n", status);
-  }
-
-  chprintf(stream, "sub command: CTRL Status...\n");
-  aosThdMSleep(5);
-  status = bq27500_lld_sub_command_call(((ut_bq27500data_t*)ut->data)->driver, BQ27500_LLD_SUB_CMD_CONTROL_STATUS, ((ut_bq27500data_t*)ut->data)->timeout);
-  aosThdMSleep(5);
-  status |= bq27500_lld_std_command(((ut_bq27500data_t*)ut->data)->driver, BQ27500_LLD_STD_CMD_Control, &dst, ((ut_bq27500data_t*)ut->data)->timeout);
-  aosThdMSleep(5);
-  bq27500_lld_control_status_t ctrl;
-  status |= bq27500_lld_sub_command_read(((ut_bq27500data_t*)ut->data)->driver, &ctrl.value, ((ut_bq27500data_t*)ut->data)->timeout);
-  chprintf(stream, "\t\tdst: 0x%X\n", ctrl.value);
-  chprintf(stream, "\t\tsleep: 0x%X\n", ctrl.content.sleep);
-  chprintf(stream, "\t\thibernate: 0x%X\n", ctrl.content.hibernate);
-  if (status == APAL_STATUS_SUCCESS) {
-    aosUtPassed(stream, &result);
-  } else {
-    aosUtFailedMsg(stream, &result, "0x%08X\n", status);
-  }
-
-  chprintf(stream, "sub command: firmware version...\n");
-  status = bq27500_lld_sub_command_call(((ut_bq27500data_t*)ut->data)->driver, BQ27500_LLD_SUB_CMD_FW_VERSION, ((ut_bq27500data_t*)ut->data)->timeout);
-  aosThdMSleep(1);
-  bq27500_lld_version_t version;
-  status |= bq27500_lld_sub_command_read(((ut_bq27500data_t*)ut->data)->driver, &version.value, ((ut_bq27500data_t*)ut->data)->timeout);
-  chprintf(stream, "\t\tfirmware version: %X%X-%X%X\n", version.content.major_high, version.content.major_low, version.content.minor_high, version.content.minor_low);
-  if (status == APAL_STATUS_SUCCESS) {
-    aosUtPassed(stream, &result);
-  } else {
-    aosUtFailedMsg(stream, &result, "0x%08X\n", status);
-  }
-
-  chprintf(stream, "sub command: hardware version...\n");
-  status = bq27500_lld_sub_command_call(((ut_bq27500data_t*)ut->data)->driver, BQ27500_LLD_SUB_CMD_HW_VERSION, ((ut_bq27500data_t*)ut->data)->timeout);
-  aosThdMSleep(1);
-  status |= bq27500_lld_sub_command_read(((ut_bq27500data_t*)ut->data)->driver, &version.value, ((ut_bq27500data_t*)ut->data)->timeout);
-  chprintf(stream, "\t\thardware version: %X%X-%X%X\n", version.content.major_high, version.content.major_low, version.content.minor_high, version.content.minor_low);
-  if (status == APAL_STATUS_SUCCESS) {
-    aosUtPassed(stream, &result);
-  } else {
-    aosUtFailedMsg(stream, &result, "0x%08X\n", status);
-  }
-
-  chprintf(stream, "ext command: device name length...\n");
-  status = bq27500_lld_ext_command(((ut_bq27500data_t*)ut->data)->driver, BQ27500_LLD_EXT_CMD_DeviceNameLength, BQ27500_LLD_EXT_CMD_READ, &original_length, 1, 0, ((ut_bq27500data_t*)ut->data)->timeout);
-  chprintf(stream, "\t\tdevice name length: %d \n", original_length);
-  if (status == APAL_STATUS_SUCCESS && original_length <= 8) {
-    aosUtPassed(stream, &result);
-  } else {
-    aosUtFailedMsg(stream, &result, "0x%08X\n", status);
-    original_length = 8;
-  }
-
-  chprintf(stream, "ext command: device name (read)...\n");
-  status = bq27500_lld_ext_command(((ut_bq27500data_t*)ut->data)->driver, BQ27500_LLD_EXT_CMD_DeviceName, BQ27500_LLD_EXT_CMD_READ, (uint8_t*)original_name, original_length, 0, ((ut_bq27500data_t*)ut->data)->timeout);
-  original_name[original_length] = '\0';
-  chprintf(stream, "\t\tdevice name: %s\n", original_name);
-  if (status == APAL_STATUS_SUCCESS) {
-    aosUtPassed(stream, &result);
-  } else {
-    aosUtFailedMsg(stream, &result, "0x%08X\n", status);
-  }
-
-  chprintf(stream, "battery info std commands...\n");
-  status = bq27500_lld_std_command(((ut_bq27500data_t*)ut->data)->driver, BQ27500_LLD_STD_CMD_Temperatur, &dst, ((ut_bq27500data_t*)ut->data)->timeout);
-  chprintf(stream, "\t\ttemperature: %fK (%fC) \n", (float)dst/10.0f, (float)dst/10.0f-273.5f);
-  status |= bq27500_lld_std_command(((ut_bq27500data_t*)ut->data)->driver, BQ27500_LLD_STD_CMD_FullAvailableCapacity, &dst, ((ut_bq27500data_t*)ut->data)->timeout);
-  chprintf(stream, "\t\tfull available capacity: %umAh \n", dst);
-  status |= bq27500_lld_std_command(((ut_bq27500data_t*)ut->data)->driver, BQ27500_LLD_STD_CMD_FullChargeCapacity, &dst, ((ut_bq27500data_t*)ut->data)->timeout);
-  chprintf(stream, "\t\tfull charge capacity: %umAh \n", dst);
-  status |= bq27500_lld_std_command(((ut_bq27500data_t*)ut->data)->driver, BQ27500_LLD_STD_CMD_RemainingCapacity, &dst, ((ut_bq27500data_t*)ut->data)->timeout);
-  chprintf(stream, "\t\tremaining capacity: %umAh \n", dst);
-  status |= bq27500_lld_std_command(((ut_bq27500data_t*)ut->data)->driver, BQ27500_LLD_STD_CMD_Voltage, &dst, ((ut_bq27500data_t*)ut->data)->timeout);
-  chprintf(stream, "\t\tvoltage: %umV \n", dst);
-  status |= bq27500_lld_std_command(((ut_bq27500data_t*)ut->data)->driver, BQ27500_LLD_STD_CMD_AverageCurrent, &dst, ((ut_bq27500data_t*)ut->data)->timeout);
-  chprintf(stream, "\t\taverage current: %dmA \n", (int8_t)dst);
-  status |= bq27500_lld_std_command(((ut_bq27500data_t*)ut->data)->driver, BQ27500_LLD_STD_CMD_AveragePower, &dst, ((ut_bq27500data_t*)ut->data)->timeout);
-  chprintf(stream, "\t\taverage power: %dmW \n", (int8_t)dst);
-  status |= bq27500_lld_std_command(((ut_bq27500data_t*)ut->data)->driver, BQ27500_LLD_STD_CMD_TimeToFull, &dst, ((ut_bq27500data_t*)ut->data)->timeout);
-  if (dst != (uint16_t)~0) {
-    chprintf(stream, "\t\ttime to full: %umin \n", dst);
-  } else {
-    chprintf(stream, "\t\ttime to full: (not charging) \n", dst);
-  }
-  status |= bq27500_lld_std_command(((ut_bq27500data_t*)ut->data)->driver, BQ27500_LLD_STD_CMD_TimeToEmpty, &dst, ((ut_bq27500data_t*)ut->data)->timeout);
-  if (dst != (uint16_t)~0) {
-    chprintf(stream, "\t\ttime to empty: %umin \n", dst);
-  } else {
-    chprintf(stream, "\t\ttime to empty: (not discharging) \n", dst);
-  }
-  if (status == APAL_STATUS_SUCCESS) {
-    aosUtPassed(stream, &result);
-  } else {
-    aosUtFailedMsg(stream, &result, "0x%08X\n", status);
-  }
-
-  chprintf(stream, "check sealed state...\n");
-  status = bq27500_lld_std_command(((ut_bq27500data_t*)ut->data)->driver, BQ27500_LLD_STD_CMD_Control, &dst, ((ut_bq27500data_t*)ut->data)->timeout);
-  status |= bq27500_lld_sub_command_call(((ut_bq27500data_t*)ut->data)->driver, BQ27500_LLD_SUB_CMD_CONTROL_STATUS, ((ut_bq27500data_t*)ut->data)->timeout);
-  aosThdMSleep(1);
-  status |= bq27500_lld_sub_command_read(((ut_bq27500data_t*)ut->data)->driver, &ctrl.value, ((ut_bq27500data_t*)ut->data)->timeout);
-  chprintf(stream, "\t\tsealed: 0x%X\n", ctrl.content.ss);
-  chprintf(stream, "\t\tfull access sealed: 0x%X\n", ctrl.content.fas);
-  if (status == APAL_STATUS_SUCCESS) {
-    aosUtPassed(stream, &result);
-  } else {
-    aosUtFailedMsg(stream, &result, "0x%08X\n", status);
-  }
-
-  chprintf(stream, "unseale...\n");
-  status = bq27500_lld_send_ctnl_data(((ut_bq27500data_t*)ut->data)->driver, BQ27500_LLD_DEFAULT_UNSEAL_KEY1, ((ut_bq27500data_t*)ut->data)->timeout);
-  aosThdMSleep(50);
-  status |= bq27500_lld_send_ctnl_data(((ut_bq27500data_t*)ut->data)->driver, BQ27500_LLD_DEFAULT_UNSEAL_KEY0, ((ut_bq27500data_t*)ut->data)->timeout);
-  aosThdMSleep(50);
-  status |= bq27500_lld_sub_command_call(((ut_bq27500data_t*)ut->data)->driver, BQ27500_LLD_SUB_CMD_CONTROL_STATUS, ((ut_bq27500data_t*)ut->data)->timeout);
-  aosThdMSleep(50);
-  status |= bq27500_lld_std_command(((ut_bq27500data_t*)ut->data)->driver, BQ27500_LLD_STD_CMD_Control, &dst, ((ut_bq27500data_t*)ut->data)->timeout);
-  status |= bq27500_lld_sub_command_read(((ut_bq27500data_t*)ut->data)->driver, &ctrl.value, ((ut_bq27500data_t*)ut->data)->timeout);
-  if (status == APAL_STATUS_SUCCESS && ctrl.content.ss == 0x0) {
-    aosUtPassed(stream, &result);
-  } else {
-    aosUtFailedMsg(stream, &result, "0x%08X\n", status);
-  }
-
-  chprintf(stream, "read device name from data flash...\n");
-  status = bq27500_lld_ext_command(((ut_bq27500data_t*)ut->data)->driver, BQ27500_LLD_EXT_CMD_BlockDataControl, BQ27500_LLD_EXT_CMD_WRITE, &val, 1, 0, ((ut_bq27500data_t*)ut->data)->timeout);
-  aosThdMSleep(50);
-  val = 0x30;
-  status |= bq27500_lld_ext_command(((ut_bq27500data_t*)ut->data)->driver, BQ27500_LLD_EXT_CMD_DataFlashClass, BQ27500_LLD_EXT_CMD_WRITE, &val, 1, 0, ((ut_bq27500data_t*)ut->data)->timeout);
-  aosThdMSleep(50);
-  val = 0;
-  status |= bq27500_lld_ext_command(((ut_bq27500data_t*)ut->data)->driver, BQ27500_LLD_EXT_CMD_DataFlashBlock, BQ27500_LLD_EXT_CMD_WRITE, &val, 1, 0, ((ut_bq27500data_t*)ut->data)->timeout);
-  aosThdMSleep(50);
-  status |= bq27500_lld_ext_command(((ut_bq27500data_t*)ut->data)->driver, BQ27500_LLD_EXT_CMD_BlockData, BQ27500_LLD_EXT_CMD_READ, (uint8_t*)block, original_length, 13, ((ut_bq27500data_t*)ut->data)->timeout);
-  block[original_length] = '\0';
-  chprintf(stream, "\t\tdevice name: %s\n", block);
-  if (status == APAL_STATUS_SUCCESS && (strcmp((char*)block, (char*)original_name) == 0)) {
-    aosUtPassed(stream, &result);
-  } else {
-    chprintf(stream, "\t\tread data: ");
-    for (uint8_t blockIdx = 0; blockIdx < original_length; blockIdx++) {
-      chprintf(stream, "0x%02X\n", block[blockIdx]);
-    }
-    aosUtFailedMsg(stream, &result, "0x%08X\n", status);
-  }
-
-  chprintf(stream, "change device name in data flash to \"test\"...\n");
-  status = bq27500_lld_ext_command(((ut_bq27500data_t*)ut->data)->driver, BQ27500_LLD_EXT_CMD_BlockData, BQ27500_LLD_EXT_CMD_WRITE, (uint8_t*)new_name, 5, 13, ((ut_bq27500data_t*)ut->data)->timeout);
-  aosThdMSleep(50);
-  status |= bq27500_lld_ext_command(((ut_bq27500data_t*)ut->data)->driver, BQ27500_LLD_EXT_CMD_BlockData, BQ27500_LLD_EXT_CMD_READ, (uint8_t*)block, 32, 0, ((ut_bq27500data_t*)ut->data)->timeout);
-  // compute blockdata checksum
-  status |= bq27500_lld_compute_blockdata_checksum(block, &sum);
-  // write checksum to BlockDataChecksum, triggering the write of BlackData
-  status |= bq27500_lld_ext_command(((ut_bq27500data_t*)ut->data)->driver, BQ27500_LLD_EXT_CMD_BlockDataCheckSum, BQ27500_LLD_EXT_CMD_WRITE, &sum, 1, 0, ((ut_bq27500data_t*)ut->data)->timeout);
-  aosThdMSleep(50);
-  status |= bq27500_lld_ext_command(((ut_bq27500data_t*)ut->data)->driver, BQ27500_LLD_EXT_CMD_DeviceNameLength, BQ27500_LLD_EXT_CMD_READ, &new_lenght, 1, 0, ((ut_bq27500data_t*)ut->data)->timeout);
-  aosThdMSleep(50);
-  // read out device name, to see if changing it was successfull
-  status |= bq27500_lld_ext_command(((ut_bq27500data_t*)ut->data)->driver, BQ27500_LLD_EXT_CMD_DeviceName, BQ27500_LLD_EXT_CMD_READ, (uint8_t*)name, new_lenght, 0, ((ut_bq27500data_t*)ut->data)->timeout);
-  name[new_lenght] = '\0';
-  chprintf(stream, "\t\tdevice name: %s\n", name);
-  success = (strcmp(name, new_name) == 0);
-
-  // change device name back to original name
-  val = 0x00;
-  status = bq27500_lld_ext_command(((ut_bq27500data_t*)ut->data)->driver, BQ27500_LLD_EXT_CMD_BlockDataControl, BQ27500_LLD_EXT_CMD_WRITE, &val, 1, 0, ((ut_bq27500data_t*)ut->data)->timeout);
-  aosThdMSleep(50);
-  val = 0x30;
-  status |= bq27500_lld_ext_command(((ut_bq27500data_t*)ut->data)->driver, BQ27500_LLD_EXT_CMD_DataFlashClass, BQ27500_LLD_EXT_CMD_WRITE, &val, 1, 0, ((ut_bq27500data_t*)ut->data)->timeout);
-  aosThdMSleep(50);
-  val = 0;
-  status |= bq27500_lld_ext_command(((ut_bq27500data_t*)ut->data)->driver, BQ27500_LLD_EXT_CMD_DataFlashBlock, BQ27500_LLD_EXT_CMD_WRITE, &val, 1, 0, ((ut_bq27500data_t*)ut->data)->timeout);
-  aosThdMSleep(50);
-  status |= bq27500_lld_ext_command(((ut_bq27500data_t*)ut->data)->driver, BQ27500_LLD_EXT_CMD_BlockData, BQ27500_LLD_EXT_CMD_WRITE, (uint8_t*)original_name, 7, 13, ((ut_bq27500data_t*)ut->data)->timeout);
-  aosThdMSleep(50);
-  status |= bq27500_lld_ext_command(((ut_bq27500data_t*)ut->data)->driver, BQ27500_LLD_EXT_CMD_BlockData, BQ27500_LLD_EXT_CMD_READ, (uint8_t*)block, 32, 0, ((ut_bq27500data_t*)ut->data)->timeout);
-  // compute blockdata checksum
-  sum = 0;
-  status |= bq27500_lld_compute_blockdata_checksum(block, &sum);
-  // write checksum to BlockDataChecksum, triggering the write of BlackData
-  status |= bq27500_lld_ext_command(((ut_bq27500data_t*)ut->data)->driver, BQ27500_LLD_EXT_CMD_BlockDataCheckSum, BQ27500_LLD_EXT_CMD_WRITE, &sum, 1, 0, ((ut_bq27500data_t*)ut->data)->timeout);
-  aosThdMSleep(1000);
-  status |= bq27500_lld_ext_command(((ut_bq27500data_t*)ut->data)->driver, BQ27500_LLD_EXT_CMD_DeviceNameLength, BQ27500_LLD_EXT_CMD_READ, &original_length, 1, 0, ((ut_bq27500data_t*)ut->data)->timeout);
-  aosThdMSleep(50);
-  // read device name, to see if changing it back to the original name was successfull
-  status |= bq27500_lld_ext_command(((ut_bq27500data_t*)ut->data)->driver, BQ27500_LLD_EXT_CMD_DeviceName, BQ27500_LLD_EXT_CMD_READ, (uint8_t*)name, original_length, 0, ((ut_bq27500data_t*)ut->data)->timeout);
-  success2 = (strcmp(name, original_name) == 0);
-  name[original_length] = '\0';
-  chprintf(stream, "\t\tchanged back to name: %s, original_name: %s\n", name, original_name);
-  if (status == APAL_STATUS_OK && ((success && success2) || (ctrl.content.sleep == 0))) {
-    aosUtPassed(stream, &result);
-  } else {
-    aosUtFailedMsg(stream, &result, "0x%08X, changing: 0x%X - changing back: 0x%X\n", status, success, success2);
-  }
-
-  chprintf(stream, "seal...\n");
-  status = bq27500_lld_std_command(((ut_bq27500data_t*)ut->data)->driver, BQ27500_LLD_STD_CMD_Control, &dst, ((ut_bq27500data_t*)ut->data)->timeout);
-  aosThdMSleep(50);
-  status |= bq27500_lld_sub_command_call(((ut_bq27500data_t*)ut->data)->driver, BQ27500_LLD_SUB_CMD_SEALED, ((ut_bq27500data_t*)ut->data)->timeout);
-  aosThdMSleep(50);
-  status |= bq27500_lld_std_command(((ut_bq27500data_t*)ut->data)->driver, BQ27500_LLD_STD_CMD_Control, &dst, ((ut_bq27500data_t*)ut->data)->timeout);
-  aosThdMSleep(50);
-  status |= bq27500_lld_sub_command_call(((ut_bq27500data_t*)ut->data)->driver, BQ27500_LLD_SUB_CMD_CONTROL_STATUS, ((ut_bq27500data_t*)ut->data)->timeout);
-  aosThdMSleep(50);
-  status |= bq27500_lld_sub_command_read(((ut_bq27500data_t*)ut->data)->driver, &ctrl.value, ((ut_bq27500data_t*)ut->data)->timeout);
-  if (status == APAL_STATUS_SUCCESS && ctrl.content.ss == 0x1) {
-    aosUtPassed(stream, &result);
-  } else {
-    chprintf(stream, "\tfailed (0x%X)\n", status);
-    aosUtFailedMsg(stream, &result, "0x%08X, ctrl 0x%X\n", status, subdata);
-    ++result.failed;
-  }
-
-  aosUtInfoMsg(stream,"driver object memory footprint: %u bytes\n", sizeof(BQ27500Driver));
-
-  return result;
-}
-
-#endif /* (AMIROOS_CFG_TESTS_ENABLE == true) && defined(AMIROLLD_CFG_USE_BQ27500) */
-
diff --git a/os/unittests/periphery-lld/src/ut_alld_bq27500_bq24103a.c b/os/unittests/periphery-lld/src/ut_alld_bq27500_bq24103a.c
deleted file mode 100644
index f5dbfde..0000000
--- a/os/unittests/periphery-lld/src/ut_alld_bq27500_bq24103a.c
+++ /dev/null
@@ -1,134 +0,0 @@
-/*
-AMiRo-OS is an operating system designed for the Autonomous Mini Robot (AMiRo) platform.
-Copyright (C) 2016..2018  Thomas Schöpping et al.
-
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program.  If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#include <ut_alld_bq27500_bq24103a.h>
-
-#if ((AMIROOS_CFG_TESTS_ENABLE == true) && defined(AMIROLLD_CFG_USE_BQ27500) && defined(AMIROLLD_CFG_USE_BQ24103A)) || defined(__DOXYGEN__)
-
-#include <aos_debug.h>
-#include <chprintf.h>
-#include <aos_thread.h>
-
-aos_utresult_t utAlldBq27500Bq24103aFunc(BaseSequentialStream *stream, aos_unittest_t *ut)
-{
-  aosDbgCheck(ut->data != NULL && ((ut_bq27500bq24103adata_t*)ut->data)->bq27500 != NULL && ((ut_bq27500bq24103adata_t*)ut->data)->bq24103a != NULL);
-
-  // local variables
-  aos_utresult_t result = {0, 0};
-  uint32_t status;
-  uint16_t dst;
-  bq27500_lld_flags_t flags;
-  bq27500_lld_batgood_t bg;
-  bq24103a_lld_enable_t charger_enabled;
-  uint32_t sleeptime_s;
-  bq24103a_lld_charge_state_t charge;
-
-  chprintf(stream, "check for battery...\n");
-  status = bq27500_lld_std_command(((ut_bq27500bq24103adata_t*)ut->data)->bq27500, BQ27500_LLD_STD_CMD_Flags, &dst, ((ut_bq27500bq24103adata_t*)ut->data)->timeout);
-  flags.value = dst;
-  chprintf(stream, "\t\tbattery detected: %s\n", flags.content.bat_det ? "yes" : "no");
-  chprintf(stream, "\t\tbattery fully charged: %s\n", flags.content.fc ? "yes" : "no");
-  status |= bq27500_lld_read_batgood(((ut_bq27500bq24103adata_t*)ut->data)->bq27500, &bg);
-  chprintf(stream, "\t\tbattery good: %s\n", (bg == BQ27500_LLD_BATTERY_GOOD) ? "yes" : "no");
-  if (status == APAL_STATUS_SUCCESS) {
-    if (!flags.content.bat_det) {
-      aosUtPassedMsg(stream, &result, "no battery detected, aborting\n");
-      return result;
-    } else if (!bg) {
-      aosUtPassedMsg(stream, &result, "battery damaged, aborting\n");
-      return result;
-    } else {
-      aosUtPassed(stream, &result);
-    }
-  } else {
-    aosUtFailedMsg(stream, &result, "0x%08X; aborting\n", status);
-    return result;
-  }
-
-  chprintf(stream, "get current charger setting...\n");
-  status = bq24103a_lld_get_enabled(((ut_bq27500bq24103adata_t*)ut->data)->bq24103a, &charger_enabled);
-  if (status == APAL_STATUS_SUCCESS) {
-    aosUtPassedMsg(stream, &result, "currently %s\n", (charger_enabled == BQ24103A_LLD_ENABLED) ? "enabled" : "disabled");
-  } else {
-    aosUtFailedMsg(stream, &result, "0x%08X\n", status);
-  }
-
-  // disable/enable charger
-  for (uint8_t iteration = 0; iteration < 2; ++iteration) {
-    if (charger_enabled == BQ24103A_LLD_ENABLED) {
-      sleeptime_s = 120;
-      chprintf(stream, "disable charger...\n");
-      status = bq24103a_lld_set_enabled(((ut_bq27500bq24103adata_t*)ut->data)->bq24103a, BQ24103A_LLD_DISABLED);
-      aosThdSSleep(1);
-      status |= bq24103a_lld_get_enabled(((ut_bq27500bq24103adata_t*)ut->data)->bq24103a, &charger_enabled);
-      status |= (charger_enabled == BQ24103A_LLD_DISABLED) ? 0x0000 : 0x0100;
-      for (uint32_t s = 0; s < sleeptime_s; ++s) {
-        int nchars = chprintf(stream, "%us / %us", s, sleeptime_s);
-        aosThdSSleep(1);
-        for (int c = 0; c < nchars; ++c) {
-          chprintf(stream, "\b \b");
-        }
-      }
-      status |= bq24103a_lld_get_charge_status(((ut_bq27500bq24103adata_t*)ut->data)->bq24103a, &charge);
-      chprintf(stream, "\t\tcharge status: %scharging\n", (charge == BQ24103A_LLD_CHARGING) ? "" : "not ");
-      status |= bq27500_lld_std_command(((ut_bq27500bq24103adata_t*)ut->data)->bq27500, BQ27500_LLD_STD_CMD_TimeToFull, &dst, ((ut_bq27500bq24103adata_t*)ut->data)->timeout);
-      if (status == APAL_STATUS_SUCCESS) {
-        if (dst == 0xFFFF || dst == 0) {
-          aosUtPassedMsg(stream, &result, "battery %sfull\n", flags.content.fc ? "" : "not ");
-        } else {
-          aosUtFailedMsg(stream, &result, "battery %sfull but charging (TTF = %umin)\n", flags.content.fc ? "" : "not ", dst);
-        }
-      } else {
-        aosUtFailedMsg(stream, &result, "0x%08X\n", status);
-      }
-    }
-    else { /* charger_enabled != BQ24103A_LLD_ENABLED */
-      sleeptime_s = 90;
-      chprintf(stream, "enable charger...\n");
-      status = bq24103a_lld_set_enabled(((ut_bq27500bq24103adata_t*)ut->data)->bq24103a, BQ24103A_LLD_ENABLED);
-      aosThdSSleep(1);
-      status |= bq24103a_lld_get_enabled(((ut_bq27500bq24103adata_t*)ut->data)->bq24103a, &charger_enabled);
-      status |= (charger_enabled == BQ24103A_LLD_ENABLED) ? 0x0000 : 0x0100;
-      for (uint32_t s = 0; s < sleeptime_s; ++s) {
-        int nchars = chprintf(stream, "%us / %us", s, sleeptime_s);
-        aosThdSSleep(1);
-        for (int c = 0; c < nchars; ++c) {
-          chprintf(stream, "\b \b");
-        }
-      }
-      status |= bq24103a_lld_get_charge_status(((ut_bq27500bq24103adata_t*)ut->data)->bq24103a, &charge);
-      chprintf(stream, "\t\tcharge status: %scharging\n", (charge == BQ24103A_LLD_CHARGING) ? "" : "not ");
-      status |= bq27500_lld_std_command(((ut_bq27500bq24103adata_t*)ut->data)->bq27500, BQ27500_LLD_STD_CMD_TimeToFull, &dst, ((ut_bq27500bq24103adata_t*)ut->data)->timeout);
-      if (status == APAL_STATUS_SUCCESS) {
-        if (((dst == 0xFFFF || dst == 0) && flags.content.fc) || (!(dst == 0xFFFF || dst == 0) && !flags.content.fc)) {
-          aosUtPassedMsg(stream, &result, "battery %sfull and %scharging (TTF = %umin)\n", flags.content.fc ? "" : "not ", (dst != 0xFFFF || dst != 0) ? "" : "not ", dst);
-        } else {
-          aosUtFailedMsg(stream, &result, "battery %sfull and %scharging (TTF = %umin)\n", flags.content.fc ? "" : "not ", (dst != 0xFFFF || dst != 0) ? "" : "not ", dst);
-        }
-      } else {
-        aosUtFailedMsg(stream, &result, "0x%08X\n", status);
-      }
-    }
-
-    bq24103a_lld_get_enabled(((ut_bq27500bq24103adata_t*)ut->data)->bq24103a, &charger_enabled);
-  }
-
-  return result;
-}
-
-#endif /* (AMIROOS_CFG_TESTS_ENABLE == true) && defined(AMIROLLD_CFG_USE_BQ27500) && defined(AMIROLLD_CFG_USE_BQ24103A) */
diff --git a/os/unittests/periphery-lld/src/ut_alld_dw1000.c b/os/unittests/periphery-lld/src/ut_alld_dw1000.c
deleted file mode 100755
index f17071b..0000000
--- a/os/unittests/periphery-lld/src/ut_alld_dw1000.c
+++ /dev/null
@@ -1,142 +0,0 @@
-/*
-AMiRo-OS is an operating system designed for the Autonomous Mini Robot (AMiRo) platform.
-Copyright (C) 2016..2018  Thomas Schöpping et al.
-
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program.  If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#include <ut_alld_dw1000.h>
-
-#if ((AMIROOS_CFG_TESTS_ENABLE == true) && defined(AMIROLLD_CFG_USE_DW1000)) || defined(__DOXYGEN__)
-
-#include <aos_debug.h>
-#include <chprintf.h>
-#include <aos_thread.h>
-// No unit testing! -> Contains the Deca Demo Application
-#include <deca_instance.h>
-#include <alld_dw1000.h>
-#include <alld_dw1000_regs.h>
-#include <math.h>
-
-
-aos_utresult_t utAlldDw1000Func(BaseSequentialStream* stream, aos_unittest_t* ut) {
-
-    aosDbgCheck(ut->data != NULL);
-
-    aos_utresult_t result = {0, 0};
-
-    chprintf(stream, "init DW1000...\n");
-    dwt_initialise(DWT_LOADUCODE, (DW1000Driver*) ut->data);
-    chprintf(stream, "device ID should be: 0xDECA0130\nget device ID...\n");
-    uint32_t actual_deviceId = dwt_readdevid();
-    chprintf(stream, "actual device ID is: 0x%x\n", actual_deviceId);
-    aosThdMSleep(1);
-
-    if (actual_deviceId == DWT_DEVICE_ID){
-      aosUtPassed(stream, &result);
-    } else {
-      aosUtFailed(stream, &result);
-    }
-
-    /*chprintf(stream, "write-read test...\n");
-    uint32_t testvalue = 0x0A;
-    uint16_t panid = 0x00;
-
-    dwt_readfromdevice(PANADR_ID, PANADR_PAN_ID_OFFSET, 2, (uint8_t*) &panid);
-    chprintf(stream, "value PANADR register before write: %x\n", panid);
-    chprintf(stream, "write 0x%x to PANADR register...\n", testvalue);
-    dwt_setpanid(testvalue);
-    dwt_readfromdevice(PANADR_ID, PANADR_PAN_ID_OFFSET, 2, (uint8_t*) &panid);
-
-    chprintf(stream, "PANADR register is now: 0x%x\n", panid);
-
-    if (panid == testvalue){
-      aosUtPassed(stream, &result);
-    } else {
-      aosUtFailed(stream, &result);
-    }
-*/
-
-    dwt_setleds(0x03);
-
-    // RUN DECA-DEMO
-
-    instanceConfig_t chConfig;
-    chConfig.channelNumber = 2;            // channel
-    chConfig.preambleCode = 4;             // preambleCode
-    chConfig.pulseRepFreq = DWT_PRF_16M;   // prf
-    chConfig.dataRate = DWT_BR_6M8;        // datarate
-    chConfig.preambleLen = DWT_PLEN_128;   // preambleLength
-    chConfig.pacSize = DWT_PAC8;           // pacSize
-    chConfig.nsSFD = 0;                    // non-standard SFD
-    chConfig.sfdTO = (129 + 8 - 8);        // SFD timeout
-
-    sfConfig_t sfConfig;
-    sfConfig.slotDuration_ms = (10);        //slot duration in milliseconds (NOTE: the ranging exchange must be able to complete in this time
-                                            //e.g. tag sends a poll, 4 anchors send responses and tag sends the final + processing time
-    sfConfig.numSlots = (10);               //number of slots in the superframe (8 tag slots and 2 used for anchor to anchor ranging),
-    sfConfig.sfPeriod_ms = (10*10);         //in ms => 100 ms frame means 10 Hz location rate
-    sfConfig.tagPeriod_ms = (10*10);        //tag period in ms (sleep time + ranging time)
-    sfConfig.pollTxToFinalTxDly_us = (2500); //poll to final delay in microseconds (needs to be adjusted according to lengths of ranging frames)
-
-    //TODO Disable EXTI IRQ
-    //port_DisableEXT_IRQ();
-
-    // inittestapplication
-    // dwt_softreset(); // already done in instance_init()
-
-    // Set this instance mode (tag/anchor)
-    (void) instance_init(TAG, (DW1000Driver*) ut->data);
-    //int err = instance_init(TAG, (DW1000Driver*) ut->data);
-    (void) instance_readdeviceid();
-    //uint32_t deca_dev_id = instance_readdeviceid();
-
-    // TAG ID 0
-    instance_set_16bit_address(0);
-    // simulate DECA config Mode 2 (DIP 1100000)
-    instance_config(&chConfig, &sfConfig) ;
-
-    //TODO Enable EXTI IRQ
-    //port_EnableEXT_IRQ();
-
-    // Start Ranging
-
-    chprintf(stream, "start ranging...\n");
-
-
-    while(1) {
-        //int n = 0;
-        instance_data_t* inst = instance_get_local_structure_ptr(0);
-
-        int monitor_local = inst->monitor ;
-        int txdiff = (chVTGetSystemTimeX() - inst->timeofTx);
-
-        tag_run();
-        //if delayed TX scheduled but did not happen after expected time then it has failed... (has to be < slot period)
-        //if anchor just go into RX and wait for next message from tags/anchors
-        //if tag handle as a timeout
-        if( (monitor_local == 1) && ( txdiff > inst->slotDuration_ms) )  {
-            inst->wait4ack = 0;
-            tag_process_rx_timeout(inst);
-            inst->monitor = 0;
-        }
-    }
-
-    (void) instance_newrange();
-    //int rx = instance_newrange();
-
-    return result;
-}
-
-#endif /* (AMIROOS_CFG_TESTS_ENABLE == true) && defined(AMIROLLD_CFG_USE_DW1000) */
diff --git a/os/unittests/periphery-lld/src/ut_alld_hmc5883l.c b/os/unittests/periphery-lld/src/ut_alld_hmc5883l.c
deleted file mode 100644
index eb4b7ca..0000000
--- a/os/unittests/periphery-lld/src/ut_alld_hmc5883l.c
+++ /dev/null
@@ -1,195 +0,0 @@
-/*
-AMiRo-OS is an operating system designed for the Autonomous Mini Robot (AMiRo) platform.
-Copyright (C) 2016..2018  Thomas Schöpping et al.
-
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program.  If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#include <ut_alld_hmc5883l.h>
-
-#if ((AMIROOS_CFG_TESTS_ENABLE == true) && defined(AMIROLLD_CFG_USE_HMC5883L)) || defined(__DOXYGEN__)
-
-#include <aos_debug.h>
-#include <chprintf.h>
-#include <alld_hmc5883l.h>
-#include <aos_thread.h>
-#include <aos_system.h>
-
-/**
- * @brief   HMC5338L unit test function.
- *
- * @param[in] stream  Stream for intput/output.
- * @param[in] ut      Unit test object.
- *
- * @return            Unit test result value.
- */
-aos_utresult_t utAlldHmc5883lFunc(BaseSequentialStream* stream, aos_unittest_t* ut)
-{
-  aosDbgCheck(ut->data != NULL && (((ut_hmc5883ldata_t*)(ut->data))->drdyEvtSrc != NULL));
-
-  // local variables
-  aos_utresult_t result = {0, 0};
-  uint32_t status;
-  uint8_t rxbuffer[3];
-  uint8_t data;
-  uint8_t conf = 0x70;
-  hmc5883l_lld_config_t cfg;
-  uint16_t mdata[3];
-  uint8_t state;
-  eventmask_t event_mask = 0;
-  event_listener_t el;
-  uint16_t data_reads = 0;
-  aos_timestamp_t start;
-  aos_timestamp_t t;
-
-  chprintf(stream, "check ID...\n");
-  status = hmc5883l_lld_check(((ut_hmc5883ldata_t*)ut->data)->driver, rxbuffer, 3, ((ut_hmc5883ldata_t*)ut->data)->timeout);
-  if (status == APAL_STATUS_SUCCESS && rxbuffer[0] == HMC5883L_LLD_IDENTIFICATION_A
-                                   && rxbuffer[1] == HMC5883L_LLD_IDENTIFICATION_B
-                                   && rxbuffer[2] == HMC5883L_LLD_IDENTIFICATION_C) {
-    aosUtPassed(stream, &result);
-  } else {
-    chprintf(stream, "\tfailed\n");
-    ++result.failed;
-    chprintf(stream, "\t\tstatus: %d, idA: %d, idB: %d, idC: %d\n", status, rxbuffer[0], rxbuffer[1], rxbuffer[2]);
-    chprintf(stream, "\t\texpected idA: %d, idB: %d, idC: %d\n", HMC5883L_LLD_IDENTIFICATION_A, HMC5883L_LLD_IDENTIFICATION_B, HMC5883L_LLD_IDENTIFICATION_C);
-  }
-
-  chprintf(stream, "read register...\n");
-  status = hmc5883l_lld_read_register(((ut_hmc5883ldata_t*)ut->data)->driver, HMC5883L_LLD_REGISTER_IDENTIFICATION_A, &data, 1, ((ut_hmc5883ldata_t*)ut->data)->timeout);
-  if ((status == APAL_STATUS_OK || status == APAL_STATUS_WARNING) && data == HMC5883L_LLD_IDENTIFICATION_A) {
-    aosUtPassed(stream, &result);
-  } else {
-    aosUtFailedMsg(stream, &result, "0x%08X\n", status);
-  }
-
-  chprintf(stream, "write register...\n");
-  status = hmc5883l_lld_write_register(((ut_hmc5883ldata_t*)ut->data)->driver, HMC5883L_LLD_REGISTER_CONFIG_A, &conf, 1, ((ut_hmc5883ldata_t*)ut->data)->timeout);
-  status |= hmc5883l_lld_read_register(((ut_hmc5883ldata_t*)ut->data)->driver, HMC5883L_LLD_REGISTER_CONFIG_A, &data, 1, ((ut_hmc5883ldata_t*)ut->data)->timeout);
-  if ((status == APAL_STATUS_SUCCESS || status == APAL_STATUS_WARNING) && data == 0x70) {
-    aosUtPassed(stream, &result);
-  } else {
-    aosUtFailedMsg(stream, &result, "0x%08X\n, data: d", status, data);
-  }
-
-  chprintf(stream, "read configuration\n");
-  status = hmc5883l_lld_read_config(((ut_hmc5883ldata_t*)ut->data)->driver, &cfg, ((ut_hmc5883ldata_t*)ut->data)->timeout);
-  if (status == APAL_STATUS_SUCCESS) {
-    aosUtPassed(stream, &result);
-  } else {
-    aosUtFailedMsg(stream, &result, "0x%08X\n", status);
-  }
-
-  chprintf(stream, "write configuration\n");
-  cfg.avg = HMC5883L_LLD_AVG1;
-  cfg.outrate = HMC5883L_LLD_75_HZ;
-  cfg.mbias = HMC5883L_LLD_MB_NORMAL;
-  cfg.gain = HMC5883L_LLD_GN_0_GA;
-  cfg.highspeed = HMC5883L_LLD_HS_DISABLE;
-  cfg.mode = HMC5883L_LLD_MM_CONTINUOUS;
-  status = hmc5883l_lld_write_config(((ut_hmc5883ldata_t*)ut->data)->driver, cfg, ((ut_hmc5883ldata_t*)ut->data)->timeout);
-  status |= hmc5883l_lld_read_config(((ut_hmc5883ldata_t*)ut->data)->driver, &cfg, ((ut_hmc5883ldata_t*)ut->data)->timeout);
-  if (status == APAL_STATUS_OK &&
-      cfg.avg == HMC5883L_LLD_AVG1 &&
-      cfg.outrate == HMC5883L_LLD_75_HZ &&
-      cfg.mbias == HMC5883L_LLD_MB_NORMAL &&
-      cfg.gain == HMC5883L_LLD_GN_0_GA &&
-      cfg.highspeed == HMC5883L_LLD_HS_DISABLE &&
-      cfg.mode == HMC5883L_LLD_MM_CONTINUOUS) {
-    aosUtPassed(stream, &result);
-  } else {
-    aosUtFailedMsg(stream, &result, "0x%08X\n", status);
-  }
-
-  chprintf(stream, "read all data for five seconds...\n");
-  status = hmc5883l_lld_set_register(((ut_hmc5883ldata_t*)ut->data)->driver,HMC5883L_LLD_REGISTER_MODE,HMC5883L_LLD_MM_CONTINUOUS,((ut_hmc5883ldata_t*)ut->data)->timeout);
-  for (uint8_t i = 0; i < 5; ++i) {
-    status |= hmc5883l_lld_read_data(((ut_hmc5883ldata_t*)ut->data)->driver, mdata, ((ut_hmc5883ldata_t*)ut->data)->timeout);
-    chprintf(stream, "\t\tX = 0x%04X\tY = 0x%04X\tZ = 0x%04X\n",mdata[0],mdata[1],mdata[2]);
-    aosThdSSleep(1);
-  }
-  if (status == APAL_STATUS_OK) {
-    aosUtPassed(stream, &result);
-  } else {
-    aosUtFailedMsg(stream, &result, "0x%08X\n", status);
-  }
-
-  chprintf(stream, "read status...\n");
-  status = hmc5883l_lld_read_lock(((ut_hmc5883ldata_t*)ut->data)->driver, &state, ((ut_hmc5883ldata_t*)ut->data)->timeout);
-  chprintf(stream, "\t\tsensor lock: %d\n", state);
-  status |= hmc5883l_lld_read_rdy(((ut_hmc5883ldata_t*)ut->data)->driver, &state, ((ut_hmc5883ldata_t*)ut->data)->timeout);
-  chprintf(stream, "\t\tsensor rdy: %d\n", state);
-  status |= hmc5883l_lld_read_status(((ut_hmc5883ldata_t*)ut->data)->driver, &state, ((ut_hmc5883ldata_t*)ut->data)->timeout);
-  chprintf(stream, "\t\tsensor status: %d\n", state);
-  if (status == APAL_STATUS_OK || status == APAL_STATUS_WARNING) {
-    aosUtPassed(stream, &result);
-  } else {
-    aosUtFailedMsg(stream, &result, "0x%08X\n", status);
-  }
-
-  chprintf(stream, "interrupt (partial data read)...\n");
-  chEvtRegister(((ut_hmc5883ldata_t*)ut->data)->drdyEvtSrc, &el, 0);
-  status = hmc5883l_lld_write_config(((ut_hmc5883ldata_t*)ut->data)->driver, cfg, ((ut_hmc5883ldata_t*)ut->data)->timeout);
-  aosThdSSleep(1);
-  status |= hmc5883l_lld_read_data(((ut_hmc5883ldata_t*)ut->data)->driver, mdata, ((ut_hmc5883ldata_t*)ut->data)->timeout);
-  aosThdMSleep(10);
-  event_mask = chEvtWaitOneTimeout(EVENT_MASK(0), TIME_IMMEDIATE);
-  status |= hmc5883l_lld_read_register(((ut_hmc5883ldata_t*)ut->data)->driver, HMC5883L_LLD_REGISTER_DATA_OUT_X_MSB, &data, 1, ((ut_hmc5883ldata_t*)ut->data)->timeout);
-  aosThdMSleep(10);
-  status |= hmc5883l_lld_read_register(((ut_hmc5883ldata_t*)ut->data)->driver, HMC5883L_LLD_REGISTER_DATA_OUT_X_LSB, &data, 1, ((ut_hmc5883ldata_t*)ut->data)->timeout);
-  aosThdMSleep(10);
-  event_mask = chEvtWaitOneTimeout(EVENT_MASK(0), TIME_IMMEDIATE);
-  chprintf(stream, "\t\teventmask = 0x%08X (should be 0)\n", event_mask);
-  if (event_mask != EVENT_MASK(0)) {
-    aosUtPassed(stream, &result);
-  } else {
-    aosUtFailed(stream, &result);
-  }
-
-  chprintf(stream, "interrupt (full data read)...\n");
-  status |= hmc5883l_lld_read_data(((ut_hmc5883ldata_t*)ut->data)->driver, mdata, ((ut_hmc5883ldata_t*)ut->data)->timeout);
-  event_mask = chEvtWaitOneTimeout(EVENT_MASK(0), chTimeUS2I(100 * MICROSECONDS_PER_MILLISECOND));
-  chprintf(stream, "\t\teventmask = 0x%08X (should be 1)\n", event_mask);
-  if (event_mask == EVENT_MASK(0)) {
-    aosUtPassed(stream, &result);
-  } else {
-    aosUtFailed(stream, &result);
-  }
-
-  chprintf(stream, "read data based on interrupt...\n");
-  status = hmc5883l_lld_read_config(((ut_hmc5883ldata_t*)ut->data)->driver, &cfg, ((ut_hmc5883ldata_t*)ut->data)->timeout);
-  uint8_t mode = HMC5883L_LLD_MM_SINGLE;
-  cfg.mode = mode;
-  status |= hmc5883l_lld_write_config(((ut_hmc5883ldata_t*)ut->data)->driver, cfg, ((ut_hmc5883ldata_t*)ut->data)->timeout);
-  aosSysGetUptime(&start);
-  aosSysGetUptime(&t);
-  status |= hmc5883l_lld_read_data(((ut_hmc5883ldata_t*)ut->data)->driver, mdata, ((ut_hmc5883ldata_t*)ut->data)->timeout);
-  while (t - start < MICROSECONDS_PER_SECOND) {
-    event_mask = chEvtWaitOneTimeout(EVENT_MASK(0), chTimeUS2I(1000));
-    if (event_mask == EVENT_MASK(0)) {
-      status |= hmc5883l_lld_read_data(((ut_hmc5883ldata_t*)ut->data)->driver, mdata, ((ut_hmc5883ldata_t*)ut->data)->timeout);
-      data_reads++;
-      status = hmc5883l_lld_write_register(((ut_hmc5883ldata_t*)ut->data)->driver, HMC5883L_LLD_REGISTER_CONFIG_A+2, &mode, 1, ((ut_hmc5883ldata_t*)ut->data)->timeout);
-    }
-    aosSysGetUptime(&t);
-  }
-  chEvtUnregister(((ut_hmc5883ldata_t*)ut->data)->drdyEvtSrc, &el);
-  aosUtInfoMsg(stream,"Read data %u times in a second\n", data_reads);
-
-  aosUtInfoMsg(stream,"driver object memory footprint: %u bytes\n", sizeof(HMC5883LDriver));
-
-  return result;
-}
-
-#endif /* (AMIROOS_CFG_TESTS_ENABLE == true) && defined(AMIROLLD_CFG_USE_HMC5883L) */
diff --git a/os/unittests/periphery-lld/src/ut_alld_ina219.c b/os/unittests/periphery-lld/src/ut_alld_ina219.c
deleted file mode 100644
index 06d0470..0000000
--- a/os/unittests/periphery-lld/src/ut_alld_ina219.c
+++ /dev/null
@@ -1,169 +0,0 @@
-/*
-AMiRo-OS is an operating system designed for the Autonomous Mini Robot (AMiRo) platform.
-Copyright (C) 2016..2018  Thomas Schöpping et al.
-
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program.  If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#include <ut_alld_ina219.h>
-
-#if ((AMIROOS_CFG_TESTS_ENABLE == true) && defined(AMIROLLD_CFG_USE_INA219)) || defined(__DOXYGEN__)
-
-#include <aos_debug.h>
-#include <chprintf.h>
-#include <aos_thread.h>
-#include <alld_ina219.h>
-#include <math.h>
-
-aos_utresult_t utAlldIna219Func(BaseSequentialStream* stream, aos_unittest_t* ut)
-{
-  aosDbgCheck(ut->data != NULL && ((ut_ina219data_t*)(ut->data))->inad != NULL);
-
-  // local variables
-  aos_utresult_t result = {0, 0};
-  uint32_t status;
-  uint16_t data[6];
-  uint16_t write_data = 0x1011;
-  uint16_t new_data[6];
-  uint16_t reset_data;
-  uint16_t test_calib = 0;
-  int16_t usensor_data = 0;
-  uint16_t busready = 0;
-  uint32_t power = 0;
-  int32_t shunt;
-  uint32_t bus;
-
-  chprintf(stream, "read registers...\n");
-  status = ina219_lld_read_register(((ut_ina219data_t*)ut->data)->inad, INA219_LLD_REGISTER_CONFIGURATION, data, 6, ((ut_ina219data_t*)ut->data)->timeout);
-  if (status == APAL_STATUS_SUCCESS) {
-    aosUtPassed(stream, &result);
-  } else {
-    aosUtFailed(stream, &result);
-  }
-
-  chprintf(stream, "write registers...\n");
-  status = ina219_lld_write_register(((ut_ina219data_t*)ut->data)->inad, INA219_LLD_REGISTER_CONFIGURATION, &write_data, 1, ((ut_ina219data_t*)ut->data)->timeout);
-  status |= ina219_lld_read_register(((ut_ina219data_t*)ut->data)->inad, INA219_LLD_REGISTER_CONFIGURATION, new_data, 6, ((ut_ina219data_t*)ut->data)->timeout);
-  if (status == APAL_STATUS_SUCCESS && new_data[0] == write_data) {
-    uint8_t errors = 0;
-    for (uint8_t dataIdx = 1; dataIdx < 6; dataIdx++) {
-      if (new_data[dataIdx] != data[dataIdx]) {
-        ++errors;
-      }
-    }
-    if (errors == 0) {
-      aosUtPassed(stream, &result);
-    } else {
-      aosUtFailed(stream, &result);
-    }
-  } else {
-    aosUtFailed(stream, &result);
-  }
-
-  chprintf(stream, "reset...\n");
-  status = ina219_lld_reset(((ut_ina219data_t*)ut->data)->inad, ((ut_ina219data_t*)ut->data)->timeout);
-  status |= ina219_lld_read_register(((ut_ina219data_t*)ut->data)->inad, INA219_LLD_REGISTER_CONFIGURATION, &reset_data, 1, ((ut_ina219data_t*)ut->data)->timeout);
-  if (status == APAL_STATUS_SUCCESS && reset_data == 0x399F) {
-    aosUtPassed(stream, &result);
-  } else {
-    chprintf(stream, "\tfailed\n");
-    ++result.failed;
-  }
-
-  chprintf(stream, "read config...\n");
-  ina219_lld_cfg_t ina_config;
-  status = ina219_lld_read_config(((ut_ina219data_t*)ut->data)->inad, &ina_config, ((ut_ina219data_t*)ut->data)->timeout);
-  if (status == APAL_STATUS_SUCCESS) {
-    aosUtPassed(stream, &result);
-  } else {
-    aosUtFailed(stream, &result);
-  }
-
-  chprintf(stream, "write config...\n");
-  ina_config.data = 0x7FFu;
-  status = ina219_lld_write_config(((ut_ina219data_t*)ut->data)->inad, ina_config, ((ut_ina219data_t*)ut->data)->timeout);
-  if (status == APAL_STATUS_SUCCESS) {
-    aosUtPassed(stream, &result);
-  } else {
-    aosUtFailed(stream, &result);
-  }
-
-
-  chprintf(stream, "calibrate...\n");
-  ina219_lld_calib_input_t calib_in;
-  calib_in.shunt_resistance_0 = 0.1;
-  calib_in.max_expected_current_A = 0.075;
-  calib_in.current_lsb_uA = 10;
-  calib_in.cfg_reg = ina_config;
-  ina219_lld_calib_output_t calib_out;
-  status = ina219_lld_calibration(((ut_ina219data_t*)ut->data)->inad, &calib_in, &calib_out);
-  status |= ina219_lld_write_calibration(((ut_ina219data_t*)ut->data)->inad, calib_out.calibration & 0xFFFEu, ((ut_ina219data_t*)ut->data)->timeout);
-  status |= ina219_lld_write_calibration(((ut_ina219data_t*)ut->data)->inad, 0xA000, ((ut_ina219data_t*)ut->data)->timeout);
-  ina219_lld_cfg_t test_config;
-  ((ut_ina219data_t*)ut->data)->inad->current_lsb_uA = 0xA;
-  status |= ina219_lld_read_config(((ut_ina219data_t*)ut->data)->inad, &test_config, ((ut_ina219data_t*)ut->data)->timeout);
-  status |= ina219_lld_read_calibration(((ut_ina219data_t*)ut->data)->inad, &test_calib, ((ut_ina219data_t*)ut->data)->timeout);
-  while (!busready || power == 0) {
-    aosThdMSleep(20);
-    status |= ina219_lld_bus_conversion_ready(((ut_ina219data_t*)ut->data)->inad, &busready, ((ut_ina219data_t*)ut->data)->timeout);
-    status |= ina219_lld_read_power(((ut_ina219data_t*)ut->data)->inad, &power, ((ut_ina219data_t*)ut->data)->timeout);
-  }
-  if (status == APAL_STATUS_SUCCESS) {
-    aosUtPassed(stream, &result);
-  } else {
-    aosUtFailed(stream, &result);
-  }
-
-  chprintf(stream, "read shunt voltage...\n");
-  status = ina219_lld_read_shunt_voltage(((ut_ina219data_t*)ut->data)->inad, &shunt, ((ut_ina219data_t*)ut->data)->timeout);
-  chprintf(stream, "\t\tshunt voltage: %fV\n", (float)shunt/1000000.f);
-  if (status == APAL_STATUS_SUCCESS) {
-    aosUtPassed(stream, &result);
-  } else {
-    aosUtFailed(stream, &result);
-  }
-
-  chprintf(stream, "read bus voltage (%u%% tolerance)...\n", (uint8_t)(((ut_ina219data_t*)ut->data)->tolerance * 100.f + 0.5f));
-  status = ina219_lld_read_bus_voltage(((ut_ina219data_t*)ut->data)->inad, &bus, ((ut_ina219data_t*)ut->data)->timeout);
-  chprintf(stream, "\t\tbus voltage: %fV\n", (float)bus/1000000.f);
-  if ((status == APAL_STATUS_SUCCESS) && (fabs(((float)bus/1000000.f) - ((ut_ina219data_t*)ut->data)->v_expected) < ((ut_ina219data_t*)ut->data)->v_expected * ((ut_ina219data_t*)ut->data)->tolerance)) {
-    aosUtPassed(stream, &result);
-  } else {
-    aosUtFailed(stream, &result);
-  }
-
-  chprintf(stream, "read power...\n");
-  status = ina219_lld_read_power(((ut_ina219data_t*)ut->data)->inad, &power, ((ut_ina219data_t*)ut->data)->timeout);
-  chprintf(stream, "\t\tpower: %fW\n", (float)(power)/1000000.f);
-  if (status == APAL_STATUS_SUCCESS) {
-    aosUtPassed(stream, &result);
-  } else {
-    aosUtFailed(stream, &result);
-  }
-
-  chprintf(stream, "read current...\n");
-  status = ina219_lld_read_current(((ut_ina219data_t*)ut->data)->inad, &usensor_data, ((ut_ina219data_t*)ut->data)->timeout);
-  chprintf(stream, "\t\tcurrent: %fA\n", (float)(usensor_data)/1000000.f);
-  if (status == APAL_STATUS_SUCCESS) {
-    aosUtPassed(stream, &result);
-  } else {
-    aosUtFailed(stream, &result);
-  }
-
-  aosUtInfoMsg(stream, "driver object memory footprint: %u bytes\n", sizeof(INA219Driver));
-
-  return result;
-}
-
-#endif /* (AMIROOS_CFG_TESTS_ENABLE == true) && defined(AMIROLLD_CFG_USE_INA219) */
diff --git a/os/unittests/periphery-lld/src/ut_alld_l3g4200d.c b/os/unittests/periphery-lld/src/ut_alld_l3g4200d.c
deleted file mode 100644
index bbca210..0000000
--- a/os/unittests/periphery-lld/src/ut_alld_l3g4200d.c
+++ /dev/null
@@ -1,269 +0,0 @@
-/*
-AMiRo-OS is an operating system designed for the Autonomous Mini Robot (AMiRo) platform.
-Copyright (C) 2016..2018  Thomas Schöpping et al.
-
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program.  If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#include <ut_alld_l3g4200d.h>
-
-#if ((AMIROOS_CFG_TESTS_ENABLE == true) && defined(AMIROLLD_CFG_USE_L3G4200D)) || defined(__DOXYGEN__)
-
-#include <aos_debug.h>
-#include <chprintf.h>
-#include <aos_thread.h>
-#include <alld_l3g4200d.h>
-
-/**
- * @brief   L3G4200D unit test function.
- *
- * @param[in] stream  Stream for input/output.
- * @param[in] ut      Unit test object.
- *
- * @return            Unit test result value.
- */
-aos_utresult_t utAlldL3g4200dFunc(BaseSequentialStream* stream, aos_unittest_t* ut)
-{
-  aosDbgCheck(ut->data != NULL && ((ut_l3g4200ddata_t*)(ut->data)) != NULL);
-
-  // local variables
-  aos_utresult_t result = {0, 0};
-  uint32_t status;
-  uint8_t data = 0;
-  uint8_t write_data[5];
-  uint8_t read_data[5];
-  int16_t sdata[3];
-  uint8_t status_reg;
-  eventmask_t event_mask;
-  bool success = false;
-  uint8_t fifo = 0x5F;
-  event_listener_t el;
-
-  for (uint8_t dataIdx = 0; dataIdx < 4; dataIdx++) {
-    write_data[dataIdx] = (dataIdx+1)*11;
-  }
-  write_data[4] = 0;
-
-  chprintf(stream, "check identity...\n");
-  status = l3g4200d_lld_read_register(((ut_l3g4200ddata_t*)(ut->data))->l3gd, L3G4200D_LLD_REGISTER_WHO_AM_I, &data, 1);
-  if(status == APAL_STATUS_SUCCESS && data == L3G4200D_LLD_WHO_AM_I){
-    aosUtPassed(stream, &result);
-  } else {
-    aosUtFailedMsg(stream, &result, "0x%08X, data: %d\n", status, data);
-  }
-
-  chprintf(stream, "write register...\n");
-  status = l3g4200d_lld_write_register(((ut_l3g4200ddata_t*)(ut->data))->l3gd, L3G4200D_LLD_REGISTER_CTRL_REG1, write_data, 1);
-  if (status == APAL_STATUS_SUCCESS) {
-    aosUtPassed(stream, &result);
-  } else {
-    aosUtFailed(stream, &result);
-  }
-
-  chprintf(stream, "read register...\n");
-  status = l3g4200d_lld_read_register(((ut_l3g4200ddata_t*)(ut->data))->l3gd, L3G4200D_LLD_REGISTER_CTRL_REG1, &data, 1);
-  if (status == APAL_STATUS_SUCCESS && data == write_data[0]) {
-    aosUtPassed(stream, &result);
-  } else {
-    aosUtFailedMsg(stream, &result, "0x%08X, data: %d\n", status, data);
-  }
-
-  chprintf(stream, "write multiple registers...\n");
-  status = l3g4200d_lld_write_register(((ut_l3g4200ddata_t*)(ut->data))->l3gd, L3G4200D_LLD_REGISTER_CTRL_REG1, write_data, 5);
-  if (status == APAL_STATUS_SUCCESS) {
-    aosUtPassed(stream, &result);
-  } else {
-    aosUtFailed(stream, &result);
-  }
-
-  chprintf(stream, "read multiple registers...\n");
-  status = l3g4200d_lld_read_register(((ut_l3g4200ddata_t*)(ut->data))->l3gd, L3G4200D_LLD_REGISTER_CTRL_REG1, read_data, 5);
-  uint8_t errors = 0;
-  for (uint8_t dataIdx = 0; dataIdx < 5; dataIdx++) {
-    if (read_data[dataIdx] != write_data[dataIdx]) {
-      ++errors;
-    }
-  }
-  if (status == APAL_STATUS_SUCCESS && errors == 0) {
-    aosUtPassed(stream, &result);
-  } else {
-    for (uint8_t dataIdx = 0; dataIdx < 5; dataIdx++) {
-      chprintf(stream, "\t\tStatus: %d, CTRL_REG%d: %d, write_data: %d\n", status, dataIdx+1, read_data[dataIdx], write_data[dataIdx]);
-    }
-    aosUtFailedMsg(stream, &result, "0x%08X, errors: %d\n", status, errors);
-  }
-
-  chprintf(stream, "read config...\n");
-  l3g4200d_lld_cfg_t cfg;
-  status = l3g4200d_lld_read_config(((ut_l3g4200ddata_t*)(ut->data))->l3gd, &cfg);
-  if (status == APAL_STATUS_SUCCESS) {
-    aosUtPassed(stream, &result);
-  } else {
-    aosUtFailed(stream, &result);
-  }
-
-  chprintf(stream, "write config...\n");
-  cfg.registers.ctrl_reg1 = L3G4200D_LLD_PD | L3G4200D_LLD_DR_100_HZ | L3G4200D_LLD_BW_12_5 | L3G4200D_LLD_ZEN | L3G4200D_LLD_YEN | L3G4200D_LLD_XEN;
-  //cfg.registers.ctrl_reg1 = L3G4200D_LLD_PD | L3G4200D_LLD_DR_800_HZ | L3G4200D_LLD_BW_20 | L3G4200D_LLD_ZEN | L3G4200D_LLD_YEN | L3G4200D_LLD_XEN;
-  cfg.registers.ctrl_reg3 = 0x07;
-  cfg.registers.ctrl_reg5 |= L3G4200D_LLD_FIFO_EN;
-  status = l3g4200d_lld_write_config(((ut_l3g4200ddata_t*)(ut->data))->l3gd, cfg);
-  uint8_t reg1 = cfg.data[0];
-  status |= l3g4200d_lld_read_config(((ut_l3g4200ddata_t*)(ut->data))->l3gd, &cfg);
-  if (status == APAL_STATUS_SUCCESS && cfg.data[0] == reg1) {
-    aosUtPassed(stream, &result);
-  } else {
-    aosUtFailed(stream, &result);
-  }
-
-  chprintf(stream, "read gyro data for five seconds...\n");
-  status = APAL_STATUS_OK;
-  for (uint8_t i = 0; i < 5; ++i) {
-    status |= l3g4200d_lld_read_all_data(((ut_l3g4200ddata_t*)(ut->data))->l3gd, sdata, &cfg);
-    chprintf(stream, "\t\tX = %6d\tY = %6d\tZ = %6d\n", sdata[0], sdata[1], sdata[2]);
-    aosThdSSleep(1);
-  }
-  if (status == APAL_STATUS_SUCCESS) {
-    aosUtPassed(stream, &result);
-  } else {
-    aosUtFailed(stream, &result);
-  }
-
-  chprintf(stream, "read X axis for five seconds...\n");
-  status = APAL_STATUS_SUCCESS;
-  for (uint32_t i = 0; i <= 5; i++) {
-    status |= l3g4200d_lld_read_data(((ut_l3g4200ddata_t*)(ut->data))->l3gd, &(sdata[0]), L3G4200D_LLD_X_AXIS, &cfg);
-    chprintf(stream, "\t\tX = %6d\n", sdata[0]);
-    aosThdSSleep(1);
-  }
-  if (status == APAL_STATUS_SUCCESS) {
-    aosUtPassed(stream, &result);
-  } else {
-    aosUtFailed(stream, &result);
-  }
-
-  chprintf(stream, "read Y axis for five seconds...\n");
-  status = APAL_STATUS_SUCCESS;
-  for (uint32_t i = 0; i <= 5; i++) {
-    status |= l3g4200d_lld_read_data(((ut_l3g4200ddata_t*)(ut->data))->l3gd, &(sdata[0]), L3G4200D_LLD_Y_AXIS, &cfg);
-    chprintf(stream, "\t\tY = %6d\n", sdata[0]);
-    aosThdSSleep(1);
-  }
-  if (status == APAL_STATUS_SUCCESS) {
-    aosUtPassed(stream, &result);
-  } else {
-    aosUtFailed(stream, &result);
-  }
-
-  chprintf(stream, "read Z axis for five seconds...\n");
-  status = APAL_STATUS_SUCCESS;
-  for (uint32_t i = 0; i <= 5; i++) {
-    status |= l3g4200d_lld_read_data(((ut_l3g4200ddata_t*)(ut->data))->l3gd, &(sdata[0]), L3G4200D_LLD_Z_AXIS, &cfg);
-    chprintf(stream, "\t\tZ = %6d\n", sdata[0]);
-    aosThdSSleep(1);
-  }
-  if (status == APAL_STATUS_SUCCESS) {
-    aosUtPassed(stream, &result);
-  } else {
-    aosUtFailed(stream, &result);
-  }
-  aosThdMSleep(10);
-
-  chprintf(stream, "read status register...\n");
-  status = l3g4200d_lld_read_status_register(((ut_l3g4200ddata_t*)(ut->data))->l3gd, &status_reg);
-  if (status == APAL_STATUS_SUCCESS) {
-    aosUtPassed(stream, &result);
-  } else {
-    aosUtFailed(stream, &result);
-  }
-
-  chprintf(stream, "read interrupt config...\n");
-  l3g4200d_lld_int_cfg_t int_cfg;
-  status = l3g4200d_lld_read_int_config(((ut_l3g4200ddata_t*)(ut->data))->l3gd, &int_cfg);
-  if (status == APAL_STATUS_SUCCESS) {
-    aosUtPassed(stream, &result);
-  } else {
-    aosUtFailed(stream, &result);
-  }
-
-  chprintf(stream, "write interrupt config...\n");
-  int_cfg.registers.int1_tsh_xh = 10;
-  status = l3g4200d_lld_write_int_config(((ut_l3g4200ddata_t*)(ut->data))->l3gd, int_cfg);
-  l3g4200d_lld_int_cfg_t int_cfg2;
-  status |= l3g4200d_lld_read_int_config(((ut_l3g4200ddata_t*)(ut->data))->l3gd, &int_cfg2);
-  if (status == APAL_STATUS_SUCCESS && int_cfg.registers.int1_tsh_xh == 10) {
-    aosUtPassed(stream, &result);
-  } else {
-    aosUtFailed(stream, &result);
-  }
-
-  chprintf(stream, "interrupt test: read fifo until empty...\n");
-  chEvtRegister(((ut_l3g4200ddata_t*)(ut->data))->src, &el, 0);
-  status = l3g4200d_lld_write_fifo_ctrl_register(((ut_l3g4200ddata_t*)(ut->data))->l3gd,fifo);
-  fifo = 0;
-  status |= l3g4200d_lld_read_fifo_ctrl_register(((ut_l3g4200ddata_t*)(ut->data))->l3gd,&fifo);
-  status |= l3g4200d_lld_read_all_data(((ut_l3g4200ddata_t*)(ut->data))->l3gd, sdata, &cfg);
-  chEvtGetAndClearFlags(&el);
-  aosThdSSleep(1);
-  chEvtGetAndClearFlags(&el);
-  success = false;
-  for (uint8_t i = 0; i < 200; i++) {
-    status |= l3g4200d_lld_read_all_data(((ut_l3g4200ddata_t*)(ut->data))->l3gd, sdata, &cfg);
-    event_mask = chEvtWaitAnyTimeout(~0, TIME_IMMEDIATE);
-    status |= l3g4200d_lld_read_fifo_src_register(((ut_l3g4200ddata_t*)(ut->data))->l3gd,&fifo);
-    if (event_mask != 0 && ((fifo & L3G4200D_LLD_EMPTY) || fifo == 0)) {
-      success = true;
-      break;
-    }
-    aosThdMSleep(1);
-  }
-  if (status == APAL_STATUS_SUCCESS && success) {
-    aosUtPassed(stream, &result);
-  } else {
-    aosUtFailed(stream, &result);
-  }
-
-  fifo = 0x4A;
-  status |= l3g4200d_lld_write_fifo_ctrl_register(((ut_l3g4200ddata_t*)(ut->data))->l3gd,fifo);
-  cfg.registers.ctrl_reg1 = L3G4200D_LLD_PD | L3G4200D_LLD_DR_800_HZ | L3G4200D_LLD_BW_20 | L3G4200D_LLD_ZEN | L3G4200D_LLD_YEN | L3G4200D_LLD_XEN;
-  cfg.registers.ctrl_reg3 = 0x04;
-  status |= l3g4200d_lld_write_config(((ut_l3g4200ddata_t*)(ut->data))->l3gd, cfg);
-  chprintf(stream, "interrupt test: wait until wtm reached...\n");
-  for (uint8_t i = 0; i < 200; i++) {
-    status |= l3g4200d_lld_read_all_data(((ut_l3g4200ddata_t*)(ut->data))->l3gd, sdata, &cfg);
-    event_mask = chEvtWaitAnyTimeout(~0, TIME_IMMEDIATE);
-    status |= l3g4200d_lld_read_fifo_src_register(((ut_l3g4200ddata_t*)(ut->data))->l3gd,&fifo);
-    if (event_mask != 0 && (fifo & L3G4200D_LLD_WTM)) {
-      success = true;
-      break;
-    }
-    aosThdMSleep(10);
-  }
-  if (status == APAL_STATUS_SUCCESS && success) {
-    aosUtPassed(stream, &result);
-  } else {
-    aosUtFailed(stream, &result);
-  }
-
-  chEvtUnregister(((ut_l3g4200ddata_t*)(ut->data))->src, &el);
-  aosThdMSleep(10);
-
-  aosUtInfoMsg(stream, "driver object memory footprint: %u bytes\n", sizeof(L3G4200DDriver));
-
-  return result;
-}
-
-#endif /* (AMIROOS_CFG_TESTS_ENABLE == true) && defined(AMIROLLD_CFG_USE_L3G4200D) */
-
-
diff --git a/os/unittests/periphery-lld/src/ut_alld_led.c b/os/unittests/periphery-lld/src/ut_alld_led.c
deleted file mode 100644
index 53ac634..0000000
--- a/os/unittests/periphery-lld/src/ut_alld_led.c
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
-AMiRo-OS is an operating system designed for the Autonomous Mini Robot (AMiRo) platform.
-Copyright (C) 2016..2018  Thomas Schöpping et al.
-
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program.  If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#include <ut_alld_led.h>
-
-#if ((AMIROOS_CFG_TESTS_ENABLE == true) && defined(AMIROLLD_CFG_USE_LED)) || defined(__DOXYGEN__)
-
-#include <aos_debug.h>
-#include <chprintf.h>
-#include <alld_led.h>
-#include <aos_thread.h>
-
-/**
- * @brief   LED unit test function.
- *
- * @param[in] stream  Stream for input/output.
- * @param[in] ut      Unit test object.
- *
- * @return            Unit test result value.
- */
-aos_utresult_t utAlldLedFunc(BaseSequentialStream* stream, aos_unittest_t* ut)
-{
-  aosDbgCheck(ut->data != NULL);
-
-  // local variables
-  aos_utresult_t result = {0, 0};
-  uint32_t status = AOS_OK;
-
-  chprintf(stream, "lighting up for two seconds...\n");
-  led_lld_state_t state = LED_LLD_STATE_ON;
-  status = led_lld_set((LEDDriver*)ut->data, state);
-  aosThdSSleep(2);
-  status |= led_lld_get((LEDDriver*)ut->data, &state);
-  if (status == APAL_STATUS_OK && state == LED_LLD_STATE_ON) {
-    aosUtPassed(stream, &result);
-  } else {
-    aosUtFailed(stream, &result);
-  }
-
-  chprintf(stream, "turning off for two seconds...\n");
-  state = LED_LLD_STATE_OFF;
-  status = led_lld_set((LEDDriver*)ut->data, state);
-  aosThdSSleep(2);
-  status |= led_lld_get((LEDDriver*)ut->data, &state);
-  if (status == APAL_STATUS_OK && state == LED_LLD_STATE_OFF) {
-    aosUtPassed(stream, &result);
-  } else {
-    aosUtFailed(stream, &result);
-  }
-
-  chprintf(stream, "toggling for two seconds...\n");
-  status = led_lld_set((LEDDriver*)ut->data, LED_LLD_STATE_ON);
-  for (uint32_t i = 0; i < 2000/100; ++i) {
-    status |= led_lld_toggle((LEDDriver*)ut->data);
-    status |= led_lld_get((LEDDriver*)ut->data, &state);
-    status |= ((uint8_t)state != (i & 0x01u)) ? APAL_STATUS_ERROR : APAL_STATUS_OK;
-    aosThdMSleep(100);
-  }
-  status = led_lld_set((LEDDriver*)ut->data, LED_LLD_STATE_OFF);
-  if (status == APAL_STATUS_OK) {
-    aosUtPassed(stream, &result);
-  } else {
-    aosUtFailed(stream, &result);
-  }
-
-  aosUtInfoMsg(stream,"driver object memory footprint: %u bytes\n", sizeof(LEDDriver));
-
-  return result;
-}
-
-#endif /* (AMIROOS_CFG_TESTS_ENABLE == true) && defined(AMIROLLD_CFG_USE_LED) */
diff --git a/os/unittests/periphery-lld/src/ut_alld_lis331dlh.c b/os/unittests/periphery-lld/src/ut_alld_lis331dlh.c
deleted file mode 100644
index 56378fa..0000000
--- a/os/unittests/periphery-lld/src/ut_alld_lis331dlh.c
+++ /dev/null
@@ -1,236 +0,0 @@
-/*
-AMiRo-OS is an operating system designed for the Autonomous Mini Robot (AMiRo) platform.
-Copyright (C) 2016..2018  Thomas Schöpping et al.
-
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program.  If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#include <ut_alld_lis331dlh.h>
-
-#if ((AMIROOS_CFG_TESTS_ENABLE == true) && defined(AMIROLLD_CFG_USE_LIS331DLH)) || defined(__DOXYGEN__)
-
-#include <aos_debug.h>
-#include <chprintf.h>
-#include <aos_thread.h>
-#include <alld_lis331dlh.h>
-
-/**
- * @brief   LIS331DLH unit test function.
- *
- * @param[in] stream  Stream for input/output.
- * @param[in] ut      Unit test object.
- *
- * @return            Unit test result value.
- */
-aos_utresult_t utAlldLis331dlhFunc(BaseSequentialStream* stream, aos_unittest_t* ut)
-{
-  aosDbgCheck(ut->data != NULL && ((ut_lis331dlhdata_t*)(ut->data)) != NULL);
-
-  // local variables
-  aos_utresult_t result = {0, 0};
-  uint32_t status;
-  uint8_t data = 0;
-  uint8_t write_data[5];
-  uint8_t read_data[5];
-  uint8_t errors = 0;
-  uint8_t reg1;
-  int16_t sdata[3];
-  uint8_t status_reg;
-  lis331dlh_lld_int_cfg_t intcfg;
-  event_listener_t el;
-  eventmask_t event_mask;
-  uint8_t success = 0;
-
-  for (uint8_t dataIdx = 0; dataIdx < 4; dataIdx++) {
-    write_data[dataIdx] = (dataIdx+1)*11;
-  }
-  write_data[4] = 0;
-
-  chprintf(stream, "check identity...\n");
-  status = lis331dlh_lld_read_register(((ut_lis331dlhdata_t*)(ut->data))->lisd, LIS331DLH_LLD_REGISTER_WHO_AM_I, &data, 1);
-  if (status == APAL_STATUS_SUCCESS &&
-      data == LIS331DLH_LLD_WHO_AM_I) {
-    aosUtPassed(stream, &result);
-  } else {
-    chprintf(stream, "\tfailed\n");
-    aosUtFailedMsg(stream, &result, "0x%08X, data: %d\n", status, data);
-    ++result.failed;
-  }
-
-  chprintf(stream, "write register...\n");
-  status = lis331dlh_lld_write_register(((ut_lis331dlhdata_t*)(ut->data))->lisd, LIS331DLH_LLD_REGISTER_CTRL_REG1, write_data, 1);
-  if (status == APAL_STATUS_SUCCESS) {
-    aosUtPassed(stream, &result);
-  } else {
-    aosUtFailed(stream, &result);
-  }
-
-  chprintf(stream, "read register...\n");
-  status = lis331dlh_lld_read_register(((ut_lis331dlhdata_t*)(ut->data))->lisd, LIS331DLH_LLD_REGISTER_CTRL_REG1, &data, 1);
-  if (status == APAL_STATUS_SUCCESS && data == write_data[0]) {
-    aosUtPassed(stream, &result);
-  } else {
-    chprintf(stream, "\tfailed\n");
-    aosUtFailedMsg(stream, &result, "0x%08X, data: %d\n", status, data);
-    ++result.failed;
-  }
-
-  chprintf(stream, "write multiple registers...\n");
-  status = lis331dlh_lld_write_register(((ut_lis331dlhdata_t*)(ut->data))->lisd, LIS331DLH_LLD_REGISTER_CTRL_REG1, write_data, 5);
-  if (status == APAL_STATUS_SUCCESS) {
-    aosUtPassed(stream, &result);
-  } else {
-    aosUtFailed(stream, &result);
-  }
-
-  chprintf(stream, "read multiple registers...\n");
-  status = lis331dlh_lld_read_register(((ut_lis331dlhdata_t*)(ut->data))->lisd, LIS331DLH_LLD_REGISTER_CTRL_REG1, read_data, 5);
-  for (uint8_t dataIdx = 0; dataIdx < 5; dataIdx++) {
-    if (read_data[dataIdx] != write_data[dataIdx]) {
-      ++errors;
-    }
-  }
-  if (status == APAL_STATUS_SUCCESS &&
-      errors == 0) {
-    aosUtPassed(stream, &result);
-  } else {
-    chprintf(stream, "\tfailed\n");
-    for (uint8_t dataIdx = 0; dataIdx < 5; dataIdx++) {
-      chprintf(stream, "\t\tStatus: %d, CTRL_REG%d: %d, write_data: %d\n", status, dataIdx+1, read_data[dataIdx], write_data[dataIdx]);
-    }
-    aosUtFailedMsg(stream, &result, "0x%08X, errors: %d\n", status, errors);
-  }
-
-  chprintf(stream, "read config...\n");
-  lis331dlh_lld_cfg_t cfg;
-  status = lis331dlh_lld_read_config(((ut_lis331dlhdata_t*)(ut->data))->lisd, &cfg);
-  if (status == APAL_STATUS_SUCCESS) {
-    aosUtPassed(stream, &result);
-  } else {
-    aosUtFailed(stream, &result);
-  }
-
-  chprintf(stream, "write config...\n");
-  cfg.registers.ctrl_reg1 = LIS331DLH_LLD_PM_ODR |
-      LIS331DLH_LLD_DR_1000HZ_780LP |
-      LIS331DLH_LLD_X_AXIS_ENABLE |
-      LIS331DLH_LLD_Y_AXIS_ENABLE |
-      LIS331DLH_LLD_Z_AXIS_ENABLE;
-  cfg.registers.ctrl_reg3 = 0x00;
-  status = lis331dlh_lld_write_config(((ut_lis331dlhdata_t*)(ut->data))->lisd, &cfg);
-  reg1 = cfg.data[0];
-  lis331dlh_lld_read_config(((ut_lis331dlhdata_t*)(ut->data))->lisd, &cfg);
-  if (status == APAL_STATUS_SUCCESS && cfg.data[0] == reg1) {
-    aosUtPassed(stream, &result);
-  } else {
-    aosUtFailed(stream, &result);
-  }
-
-  chprintf(stream, "read acceleration for five seconds...\n");
-  status = APAL_STATUS_SUCCESS;
-  for (uint8_t i = 0; i < 5; ++i) {
-    status |= lis331dlh_lld_read_all_data(((ut_lis331dlhdata_t*)(ut->data))->lisd, sdata, &cfg);
-    chprintf(stream, "\t\tX = %6d\tY = %6d\tZ = %6d\n", sdata[0], sdata[1], sdata[2]);
-    aosThdSSleep(1);
-  }
-  if (status == APAL_STATUS_SUCCESS) {
-    aosUtPassed(stream, &result);
-  } else {
-    aosUtFailed(stream, &result);
-  }
-
-  chprintf(stream, "read X acceleration for five seconds...\n");
-  status = APAL_STATUS_SUCCESS;
-  for (uint8_t i = 0; i < 5; ++i) {
-    status |= lis331dlh_lld_read_data(((ut_lis331dlhdata_t*)(ut->data))->lisd, &(sdata[0]), LIS331DLH_LLD_X_AXIS, &cfg);
-    chprintf(stream, "\t\tX = %6d\n", sdata[0]);
-    aosThdSSleep(1);
-  }
-  if (status == APAL_STATUS_SUCCESS) {
-    aosUtPassed(stream, &result);
-  } else {
-    aosUtFailed(stream, &result);
-  }
-
-  chprintf(stream, "read Y acceleration for five seconds...\n");
-  status = APAL_STATUS_SUCCESS;
-  for (uint8_t i = 0; i < 5; ++i) {
-    status |= lis331dlh_lld_read_data(((ut_lis331dlhdata_t*)(ut->data))->lisd, &(sdata[0]), LIS331DLH_LLD_Y_AXIS, &cfg);
-    chprintf(stream, "\t\tY = %6d\n", sdata[0]);
-    aosThdSSleep(1);
-  }
-  if (status == APAL_STATUS_SUCCESS) {
-    aosUtPassed(stream, &result);
-  } else {
-    aosUtFailed(stream, &result);
-  }
-
-  chprintf(stream, "read Z acceleration for five seconds...\n");
-  status = APAL_STATUS_SUCCESS;
-  for (uint8_t i = 0; i < 5; ++i) {
-    status |= lis331dlh_lld_read_data(((ut_lis331dlhdata_t*)(ut->data))->lisd, &(sdata[0]), LIS331DLH_LLD_Z_AXIS, &cfg);
-    chprintf(stream, "\t\tZ = %6d\n", sdata[0]);
-    aosThdSSleep(1);
-  }
-  if (status == APAL_STATUS_SUCCESS) {
-    aosUtPassed(stream, &result);
-  } else {
-    aosUtFailed(stream, &result);
-  }
-
-  chprintf(stream, "read status register...\n");
-  status = lis331dlh_lld_read_status_register(((ut_lis331dlhdata_t*)(ut->data))->lisd, &status_reg);
-  if (status == APAL_STATUS_SUCCESS) {
-    aosUtPassed(stream, &result);
-  } else {
-    aosUtFailed(stream, &result);
-  }
-
-  chprintf(stream, "interrupt...\n");
-  intcfg.cfg_reg = LIS331DLH_LLD_INT_CFG_X_HIGH_ENABLE | LIS331DLH_LLD_INT_CFG_Y_HIGH_ENABLE | LIS331DLH_LLD_INT_CFG_Z_HIGH_ENABLE;
-  intcfg.threshold = 10;
-  intcfg.duration = 1;
-  lis331dlh_lld_write_int_config(((ut_lis331dlhdata_t*)(ut->data))->lisd, &intcfg, LIS331DLH_LLD_INT1);
-  aosThdSSleep(1);
-  chEvtRegister(((ut_lis331dlhdata_t*)(ut->data))->src, &el, 3);
-  chprintf(stream, "\t\tmove the AMiRo now to generate interrupts\n");
-  aosThdSSleep(1);
-  for (uint8_t i = 0; i < 10; i++) {
-    event_mask = chEvtWaitOneTimeout(EVENT_MASK(3), TIME_IMMEDIATE);
-    status |= lis331dlh_lld_read_all_data(((ut_lis331dlhdata_t*)(ut->data))->lisd, sdata, &cfg);
-    status = lis331dlh_lld_read_register(((ut_lis331dlhdata_t*)(ut->data))->lisd, LIS331DLH_LLD_REGISTER_INT1_SOURCE, &data, 1);
-    eventflags_t flags = chEvtGetAndClearFlags(&el);
-    if (event_mask == EVENT_MASK(3) && (flags & ((ut_lis331dlhdata_t*)(ut->data))->evtflags)) {
-      ++success;
-      chprintf(stream, "\t\tX = %6d INTERRUPT\n", sdata[0]);
-    } else {
-      chprintf(stream, "\t\tX = %6d\n", sdata[0]);
-    }
-    aosThdSSleep(1);
-  }
-  event_mask = chEvtWaitOneTimeout(EVENT_MASK(3), TIME_IMMEDIATE);
-  chEvtUnregister(((ut_lis331dlhdata_t*)(ut->data))->src, &el);
-  if (status == APAL_STATUS_SUCCESS && success > 0) {
-    aosUtPassed(stream, &result);
-  } else {
-    aosUtFailed(stream, &result);
-  }
-
-  aosUtInfoMsg(stream, "driver object memory footprint: %u bytes\n", sizeof(LIS331DLHDriver));
-
-  return result;
-}
-
-#endif /* (AMIROOS_CFG_TESTS_ENABLE == true) && defined(AMIROLLD_CFG_USE_LIS331DLH) */
-
diff --git a/os/unittests/periphery-lld/src/ut_alld_ltc4412.c b/os/unittests/periphery-lld/src/ut_alld_ltc4412.c
deleted file mode 100644
index 40ee37f..0000000
--- a/os/unittests/periphery-lld/src/ut_alld_ltc4412.c
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
-AMiRo-OS is an operating system designed for the Autonomous Mini Robot (AMiRo) platform.
-Copyright (C) 2016..2018  Thomas Schöpping et al.
-
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program.  If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#include <ut_alld_ltc4412.h>
-
-#if ((AMIROOS_CFG_TESTS_ENABLE == true) && defined(AMIROLLD_CFG_USE_LTC4412)) || defined(__DOXYGEN__)
-
-#include <aos_debug.h>
-#include <chprintf.h>
-#include <aos_thread.h>
-#include <alld_ltc4412.h>
-
-aos_utresult_t utAlldLtc4412Func(BaseSequentialStream* stream, aos_unittest_t* ut)
-{
-  aosDbgCheck(ut->data != NULL);
-
-  // local variables
-  aos_utresult_t result = {0,0};
-  uint32_t status;
-
-  chprintf(stream, "read ctrl pin... \n");
-  ltc4412_lld_ctrl_t ctrl;
-  status = ltc4412_lld_get_ctrl((LTC4412Driver*)ut->data, &ctrl);
-  if(status == APAL_STATUS_SUCCESS){
-    aosUtPassed(stream, &result);
-  } else {
-    aosUtFailedMsg(stream, &result, "0x%08X\n", status);
-  }
-
-  chprintf(stream, "write ctrl pin... \n");
-  status = ltc4412_lld_set_ctrl((LTC4412Driver*)ut->data, LTC4412_LLD_CTRL_ACTIVE);
-  status |= ltc4412_lld_get_ctrl((LTC4412Driver*)ut->data, &ctrl);
-  if (status == APAL_STATUS_SUCCESS && ctrl == LTC4412_LLD_CTRL_ACTIVE) {
-    aosUtPassed(stream, &result);
-  } else {
-    aosUtFailedMsg(stream, &result, "0x%08X\n", status);
-  }
-
-  chprintf(stream, "read stat pin... \n");
-  ltc4412_lld_stat_t stat;
-  status = ltc4412_lld_get_stat((LTC4412Driver*)ut->data, &stat);
-  if(status == APAL_STATUS_SUCCESS){
-    aosUtPassed(stream, &result);
-  } else {
-    aosUtFailedMsg(stream, &result, "0x%08X\n", status);
-  }
-
-  aosUtInfoMsg(stream,"driver object memory footprint: %u bytes\n", sizeof(LTC4412Driver));
-
-  return result;
-}
-
-#endif /* (AMIROOS_CFG_TESTS_ENABLE == true) && defined(AMIROLLD_CFG_USE_LTC4412) */
diff --git a/os/unittests/periphery-lld/src/ut_alld_mpr121.c b/os/unittests/periphery-lld/src/ut_alld_mpr121.c
deleted file mode 100644
index 2e5e30f..0000000
--- a/os/unittests/periphery-lld/src/ut_alld_mpr121.c
+++ /dev/null
@@ -1,165 +0,0 @@
-/*
-AMiRo-OS is an operating system designed for the Autonomous Mini Robot (AMiRo) platform.
-Copyright (C) 2016..2018  Thomas Schöpping et al.
-
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program.  If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#include <ut_alld_mpr121.h>
-
-#if ((AMIROOS_CFG_TESTS_ENABLE == true) && defined(AMIROLLD_CFG_USE_MPR121)) || defined(__DOXYGEN__)
-
-#include <aos_debug.h>
-#include <chprintf.h>
-#include <aos_thread.h>
-#include <amiroos.h>
-
-#define INTERRUPT_EVENT_ID            1
-
-aos_utresult_t utAlldMpr121Func(BaseSequentialStream* stream, aos_unittest_t* ut)
-{
-  aosDbgCheck(ut->data != NULL && ((ut_mpr121data_t*)ut->data)->mprd != NULL);
-
-  // local variables
-  aos_utresult_t result = {0, 0};
-  uint32_t status;
-  mpr121_lld_config_t cfg;
-  uint8_t data, wdata, rdata;
-  uint16_t edata[4];
-  uint8_t tstate = 0;
-  event_listener_t event_listener;
-  aos_timestamp_t tstart, tcurrent, tend;
-
-  chprintf(stream, "soft reset...\n");
-  status = mpr121_lld_soft_reset(((ut_mpr121data_t*)ut->data)->mprd, ((ut_mpr121data_t*)ut->data)->timeout);
-  status |= mpr121_lld_read_config(((ut_mpr121data_t*)ut->data)->mprd, &cfg, ((ut_mpr121data_t*)ut->data)->timeout);
-  if (status == APAL_STATUS_SUCCESS && cfg.registers.ele_config == 0) {
-    aosUtPassed(stream, &result);
-  } else {
-    aosUtFailedMsg(stream, &result, "0x%08X\n", status);
-  }
-
-  chprintf(stream, "read register...\n");
-  status = mpr121_lld_read_register(((ut_mpr121data_t*)ut->data)->mprd, MPR121_LLD_REGISTER_CONFIG_2, 0, 1, &data, ((ut_mpr121data_t*)ut->data)->timeout);
-  chprintf(stream, "\t\tdata: 0x%02X\n", data);
-  if (status == APAL_STATUS_SUCCESS && data == (MPR121_LLD_CDT_0_5 | MPR121_LLD_ESI_16)) {
-    aosUtPassed(stream, &result);
-  } else {
-    aosUtFailedMsg(stream, &result, "0x%08X\n", status);
-  }
-
-  chprintf(stream, "write register...\n");
-  wdata = MPR121_LLD_CDT_32 | MPR121_LLD_SFI_10 | MPR121_LLD_ESI_16;
-  status = mpr121_lld_write_register(((ut_mpr121data_t*)ut->data)->mprd, MPR121_LLD_REGISTER_CONFIG_2, 0, 1, &wdata, ((ut_mpr121data_t*)ut->data)->timeout);
-  aosThdMSleep(500);
-  status |= mpr121_lld_read_register(((ut_mpr121data_t*)ut->data)->mprd, MPR121_LLD_REGISTER_CONFIG_2, 0, 1, &rdata, ((ut_mpr121data_t*)ut->data)->timeout);
-  chprintf(stream, "\t\tdata: 0x%02X\n", rdata);
-  status |= mpr121_lld_write_register(((ut_mpr121data_t*)ut->data)->mprd, MPR121_LLD_REGISTER_CONFIG_2, 0, 1, &data, ((ut_mpr121data_t*)ut->data)->timeout);
-  if (status == APAL_STATUS_SUCCESS && rdata == wdata) {
-    aosUtPassed(stream, &result);
-  } else {
-    aosUtFailedMsg(stream, &result, "0x%08X\n", status);
-  }
-
-  chprintf(stream, "read config...\n");
-  status = mpr121_lld_read_config(((ut_mpr121data_t*)ut->data)->mprd, &cfg, ((ut_mpr121data_t*)ut->data)->timeout);
-  if (status == APAL_STATUS_SUCCESS && cfg.registers.config_1 == 0x10 && cfg.registers.config_2 == 0x24) {
-    aosUtPassed(stream, &result);
-  } else {
-    chprintf(stream, "\t\tconfig 1: 0x%02X\n", cfg.registers.config_1);
-    chprintf(stream, "\t\tconfig 2: 0x%02X\n", cfg.registers.config_2);
-    mpr121_lld_read_register(((ut_mpr121data_t*)ut->data)->mprd, MPR121_LLD_REGISTER_CONFIG_1, 0, 1, &rdata, ((ut_mpr121data_t*)ut->data)->timeout);
-    chprintf(stream, "\t\tconfig 1: 0x%02X\n", rdata);
-    mpr121_lld_read_register(((ut_mpr121data_t*)ut->data)->mprd, MPR121_LLD_REGISTER_CONFIG_2, 0, 1, &rdata, ((ut_mpr121data_t*)ut->data)->timeout);
-    chprintf(stream, "\t\tconfig 2: 0x%02X\n", rdata);
-    for (uint8_t valueIdx = 0; valueIdx < 8; valueIdx++) {
-      chprintf(stream, "\t\tdata %d: 0x%02X\n", valueIdx, cfg.values[valueIdx]);
-    }
-    chprintf(stream, "ele_config: 0x%02X\n", cfg.registers.ele_config);
-    chprintf(stream, "config_1: 0x%02X\n", cfg.registers.config_1);
-    chprintf(stream, "config_2: 0x%02X\n", cfg.registers.config_2);
-    chprintf(stream, "target_level: 0x%02X\n", cfg.registers.target_level);
-    chprintf(stream, "low_side_limit: 0x%02X\n", cfg.registers.low_side_limit);
-    chprintf(stream, "up_side_limit: 0x%02X\n", cfg.registers.up_side_limit);
-    chprintf(stream, "auto_config_2: 0x%02X\n", cfg.registers.auto_config_2);
-    chprintf(stream, "auto_config_1: 0x%02X\n", cfg.registers.auto_config_1);
-    aosUtFailedMsg(stream, &result, "0x%08X\n", status);
-  }
-
-  chprintf(stream, "write config...\n");
-  cfg.registers.ele_config = MPR121_LLD_CL_ON_ALL | MPR121_LLD_ELEPROX_0 | 4;
-  cfg.registers.config_1 = MPR121_LLD_FFI_18 | 16;
-  cfg.registers.config_2 = MPR121_LLD_CDT_1 | MPR121_LLD_SFI_10 | MPR121_LLD_ESI_32;
-  cfg.registers.up_side_limit = 0x96u;
-  cfg.registers.low_side_limit = 0x58u;
-  cfg.registers.target_level = 0x68u;
-  cfg.registers.auto_config_1 = MPR121_LLD_FFI_18 | MPR121_LLD_RETRY_2 | MPR121_LLD_BVA_ON_ALL | MPR121_LLD_AC_RECONF_EN;
-  status = mpr121_lld_write_config(((ut_mpr121data_t*)ut->data)->mprd, cfg, ((ut_mpr121data_t*)ut->data)->timeout);
-  aosThdMSleep(500);
-  status |= mpr121_lld_read_config(((ut_mpr121data_t*)ut->data)->mprd, &cfg, ((ut_mpr121data_t*)ut->data)->timeout);
-  if (status == APAL_STATUS_SUCCESS && cfg.registers.up_side_limit == 0x96u) {
-    aosUtPassed(stream, &result);
-  } else {
-    aosUtFailedMsg(stream, &result, "0x%08X\n", status);
-  }
-
-  chprintf(stream, "read filtered data for ten seconds...\n");
-  chprintf(stream, "(values should change if you touch the sensors now)\n");
-  for (uint8_t i = 0; i < 10; i++) {
-    status = mpr121_lld_read_filtered_data(((ut_mpr121data_t*)ut->data)->mprd, 0, 4, edata, ((ut_mpr121data_t*)ut->data)->timeout);
-    chprintf(stream, "\t\t0x%04X | 0x%04X | 0x%04X | 0x%04X\n", edata[0], edata[1], edata[2], edata[3]);
-    aosThdSSleep(1);
-  }
-  if (status == APAL_STATUS_SUCCESS) {
-    aosUtPassed(stream, &result);
-  } else {
-    aosUtFailedMsg(stream, &result, "0x%08X\n", status);
-  }
-
-  chprintf(stream, "test interrupts...\n");
-  status = AOS_OK;
-  chEvtRegister(((ut_mpr121data_t*)ut->data)->evtsource, &event_listener, INTERRUPT_EVENT_ID);
-  aosSysGetUptime(&tstart);
-  tend = tstart + (30 * MICROSECONDS_PER_SECOND);
-  do {
-    aosSysGetUptime(&tcurrent);
-    const aos_timestamp_t ttimeout = MICROSECONDS_PER_SECOND - ((tcurrent - tstart) % MICROSECONDS_PER_SECOND);
-    const eventmask_t emask = chEvtWaitOneTimeout(EVENT_MASK(INTERRUPT_EVENT_ID), chTimeUS2I(ttimeout));
-    const eventflags_t eflags = chEvtGetAndClearFlags(&event_listener);
-    if (emask == EVENT_MASK(INTERRUPT_EVENT_ID) && eflags == ((ut_mpr121data_t*)ut->data)->evtflags) {
-      // interrupt detected
-      status |= mpr121_lld_read_register(((ut_mpr121data_t*)ut->data)->mprd, MPR121_LLD_REGISTER_TOUCH_STATUS, 0, 1, &tstate, ((ut_mpr121data_t*)ut->data)->timeout);
-      chprintf(stream, "\t\tinterrupt detected\n");
-      chprintf(stream, "\t\ttstate: %X %X %X %X\n", tstate & 1, (tstate >> 1) & 1, (tstate >> 2) & 1, (tstate >> 3) & 1);
-    }
-    else if (emask == 0) {
-      // timeout
-      status |= mpr121_lld_read_register(((ut_mpr121data_t*)ut->data)->mprd, MPR121_LLD_REGISTER_TOUCH_STATUS, 0, 1, &tstate, ((ut_mpr121data_t*)ut->data)->timeout);
-      chprintf(stream, "\t\ttstate: %X %X %X %X\n", tstate & 1, (tstate >> 1) & 1, (tstate >> 2) & 1, (tstate >> 3) & 1);
-    }
-    aosSysGetUptime(&tcurrent);
-  } while (tcurrent < tend);
-  chEvtUnregister(((ut_mpr121data_t*)ut->data)->evtsource, &event_listener);
-  if (status == APAL_STATUS_SUCCESS) {
-    aosUtPassed(stream, &result);
-  } else {
-    aosUtFailedMsg(stream, &result, "0x%08X\n", status);
-  }
-
-  aosUtInfoMsg(stream,"driver object memory footprint: %u bytes\n", sizeof(MPR121Driver));
-
-  return result;
-}
-
-#endif /* (AMIROOS_CFG_TESTS_ENABLE == true) && defined(AMIROLLD_CFG_USE_MPR121) */
diff --git a/os/unittests/periphery-lld/src/ut_alld_pca9544a.c b/os/unittests/periphery-lld/src/ut_alld_pca9544a.c
deleted file mode 100644
index 827f557..0000000
--- a/os/unittests/periphery-lld/src/ut_alld_pca9544a.c
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
-AMiRo-OS is an operating system designed for the Autonomous Mini Robot (AMiRo) platform.
-Copyright (C) 2016..2018  Thomas Schöpping et al.
-
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program.  If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#include <ut_alld_pca9544a.h>
-
-#if ((AMIROOS_CFG_TESTS_ENABLE == true) && defined(AMIROLLD_CFG_USE_PCA9544A)) || defined(__DOXYGEN__)
-
-#include <aos_debug.h>
-#include <chprintf.h>
-#include <aos_thread.h>
-#include <alld_pca9544a.h>
-
-aos_utresult_t utAlldPca9544aFunc(BaseSequentialStream* stream, aos_unittest_t* ut)
-{
-  aosDbgCheck(ut->data != NULL && ((ut_pca9544adata_t*)ut->data)->driver != NULL);
-
-  // local variables
-  aos_utresult_t result = {0,0};
-  uint32_t status;
-  uint8_t ctrlreg;
-  pca9544a_lld_intstatus_t interrupt;
-  pca9544a_lld_chid_t channel;
-  uint8_t test_mask = 0x00u;
-
-  chprintf(stream, "reading control register...\n");
-  status = pca9544a_lld_read(((ut_pca9544adata_t*)ut->data)->driver, &ctrlreg, ((ut_pca9544adata_t*)ut->data)->timeout);
-  if (status == APAL_STATUS_OK || status == APAL_STATUS_WARNING) {
-    aosUtPassed(stream, &result);
-  } else {
-    aosUtFailedMsg(stream, &result, "0x%08X\n", status);
-  }
-
-  chprintf(stream, "writing control register...\n");
-  status = APAL_STATUS_OK;
-  status |= pca9544a_lld_write(((ut_pca9544adata_t*)ut->data)->driver, (uint8_t)(PCA9544A_LLD_CTRLREG_EN), ((ut_pca9544adata_t*)ut->data)->timeout);
-  status |= pca9544a_lld_read(((ut_pca9544adata_t*)ut->data)->driver, &ctrlreg, ((ut_pca9544adata_t*)ut->data)->timeout);
-  if ((status == APAL_STATUS_OK  || status == APAL_STATUS_WARNING) && ctrlreg == PCA9544A_LLD_CTRLREG_EN) {
-    aosUtPassed(stream, &result);
-  } else {
-    aosUtFailedMsg(stream, &result, "0x%08X, 0x%X\n", status, ctrlreg);
-  }
-
-  chprintf(stream, "reading interrupt status...\n");
-  status = pca9544a_lld_getintstatus(((ut_pca9544adata_t*)ut->data)->driver, &interrupt, ((ut_pca9544adata_t*)ut->data)->timeout);
-  if (status == APAL_STATUS_OK || status == APAL_STATUS_WARNING) {
-    aosUtPassedMsg(stream, &result, "0x%08X\n", interrupt);
-  } else {
-    aosUtFailedMsg(stream, &result, "0x%08X\n", status);
-  }
-
-  chprintf(stream, "reading current channel...\n");
-  status = pca9544a_lld_getcurrentchannel(((ut_pca9544adata_t*)ut->data)->driver, &channel, ((ut_pca9544adata_t*)ut->data)->timeout);
-  if (status == APAL_STATUS_OK || status == APAL_STATUS_WARNING) {
-    aosUtPassedMsg(stream, &result, "0x%08X\n", channel);
-  } else {
-    aosUtFailedMsg(stream, &result, "0x%08X\n", status);
-  }
-
-  chprintf(stream, "setting current channel...\n");
-  status = APAL_STATUS_OK;
-  status |= pca9544a_lld_setchannel(((ut_pca9544adata_t*)ut->data)->driver, PCA9544A_LLD_CH0, ((ut_pca9544adata_t*)ut->data)->timeout);
-  status |= pca9544a_lld_getcurrentchannel(((ut_pca9544adata_t*)ut->data)->driver, &channel, ((ut_pca9544adata_t*)ut->data)->timeout);
-  test_mask |= (channel != PCA9544A_LLD_CH0) ? 0x01u : 0x00u;
-  status |= pca9544a_lld_setchannel(((ut_pca9544adata_t*)ut->data)->driver, PCA9544A_LLD_CH1, ((ut_pca9544adata_t*)ut->data)->timeout);
-  status |= pca9544a_lld_getcurrentchannel(((ut_pca9544adata_t*)ut->data)->driver, &channel, ((ut_pca9544adata_t*)ut->data)->timeout);
-  test_mask |= (channel != PCA9544A_LLD_CH1) ? 0x02u : 0x00u;
-  status |= pca9544a_lld_setchannel(((ut_pca9544adata_t*)ut->data)->driver, PCA9544A_LLD_CH2, ((ut_pca9544adata_t*)ut->data)->timeout);
-  status |= pca9544a_lld_getcurrentchannel(((ut_pca9544adata_t*)ut->data)->driver, &channel, ((ut_pca9544adata_t*)ut->data)->timeout);
-  test_mask |= (channel != PCA9544A_LLD_CH2) ? 0x04u : 0x00u;
-  status |= pca9544a_lld_setchannel(((ut_pca9544adata_t*)ut->data)->driver, PCA9544A_LLD_CH3, ((ut_pca9544adata_t*)ut->data)->timeout);
-  status |= pca9544a_lld_getcurrentchannel(((ut_pca9544adata_t*)ut->data)->driver, &channel, ((ut_pca9544adata_t*)ut->data)->timeout);
-  test_mask |= (channel != PCA9544A_LLD_CH3) ? 0x08u : 0x00u;
-  status |= pca9544a_lld_setchannel(((ut_pca9544adata_t*)ut->data)->driver, PCA9544A_LLD_CH_NONE, ((ut_pca9544adata_t*)ut->data)->timeout);
-  status |= pca9544a_lld_getcurrentchannel(((ut_pca9544adata_t*)ut->data)->driver, &channel, ((ut_pca9544adata_t*)ut->data)->timeout);
-  test_mask |= (channel != PCA9544A_LLD_CH_NONE) ? 0x10u : 0x00u;
-  if ((status == APAL_STATUS_OK || status == APAL_STATUS_WARNING) && test_mask == 0x00u) {
-    aosUtPassed(stream, &result);
-  } else {
-    aosUtFailedMsg(stream, &result, "0x%08X, 0x%X\n", status, test_mask);
-  }
-
-  aosUtInfoMsg(stream,"driver object memory footprint: %u bytes\n", sizeof(PCA9544ADriver));
-
-  return result;
-}
-
-#endif /* (AMIROOS_CFG_TESTS_ENABLE == true) && defined(AMIROLLD_CFG_USE_PCA9544A) */
-
diff --git a/os/unittests/periphery-lld/src/ut_alld_pklcs1212e4001.c b/os/unittests/periphery-lld/src/ut_alld_pklcs1212e4001.c
deleted file mode 100644
index 33d2a6a..0000000
--- a/os/unittests/periphery-lld/src/ut_alld_pklcs1212e4001.c
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
-AMiRo-OS is an operating system designed for the Autonomous Mini Robot (AMiRo) platform.
-Copyright (C) 2016..2018  Thomas Schöpping et al.
-
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program.  If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#include <ut_alld_pklcs1212e4001.h>
-
-#if ((AMIROOS_CFG_TESTS_ENABLE == true) && defined(AMIROLLD_CFG_USE_PKLCS1212E4001)) || defined(__DOXYGEN__)
-
-#include <aos_debug.h>
-#include <chprintf.h>
-#include <aos_thread.h>
-
-aos_utresult_t utAlldPklcs1212e4001Func(BaseSequentialStream* stream, aos_unittest_t* ut)
-{
-  aosDbgCheck(ut->data != NULL && ((ut_pklcs1212e4001_t*)ut->data)->driver != NULL);
-
-  // local variables
-  aos_utresult_t result = {0, 0};
-  uint32_t status;
-
-  chprintf(stream, "checking PWM configuration...\n");
-  status = pklcs1212e4001_lld_checkPWMconfiguration(((ut_pklcs1212e4001_t*)ut->data)->driver);
-  if (status == APAL_STATUS_OK) {
-    aosUtPassed(stream, &result);
-  } else {
-    aosUtFailedMsg(stream, &result, "0x%08X\n", status);
-    // abort at this point
-    return result;
-  }
-
-  chprintf(stream, "buzzing for one second...\n");
-  status = pklcs1212e4001_lld_enable(((ut_pklcs1212e4001_t*)ut->data)->driver, ((ut_pklcs1212e4001_t*)ut->data)->channel, true);
-  aosThdSSleep(1);
-  status |= pklcs1212e4001_lld_enable(((ut_pklcs1212e4001_t*)ut->data)->driver, ((ut_pklcs1212e4001_t*)ut->data)->channel, false);
-  if (status == APAL_STATUS_OK) {
-    aosUtPassed(stream, &result);
-  } else {
-    aosUtFailedMsg(stream, &result, "0x%08X\n", status);
-  }
-
-  return result;
-}
-
-#endif /* (AMIROOS_CFG_TESTS_ENABLE == true) && defined(AMIROLLD_CFG_USE_PKLCS1212E4001) */
diff --git a/os/unittests/periphery-lld/src/ut_alld_tlc5947.c b/os/unittests/periphery-lld/src/ut_alld_tlc5947.c
deleted file mode 100644
index deb93a3..0000000
--- a/os/unittests/periphery-lld/src/ut_alld_tlc5947.c
+++ /dev/null
@@ -1,178 +0,0 @@
-/*
-AMiRo-OS is an operating system designed for the Autonomous Mini Robot (AMiRo) platform.
-Copyright (C) 2016..2018  Thomas Schöpping et al.
-
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program.  If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#include <ut_alld_tlc5947.h>
-
-#if ((AMIROOS_CFG_TESTS_ENABLE == true) && defined(AMIROLLD_CFG_USE_TLC5947)) || defined(__DOXYGEN__)
-
-#include <aos_debug.h>
-#include <chprintf.h>
-#include <alld_tlc5947.h>
-#include <string.h>
-#include <aos_thread.h>
-
-/**
- * @brief   TLC9547 unit test function
- *
- * @param[in] stream  Stream for input/output.
- * @param[in] ut      Unit test object.
- *
- * @return            Unit test result value.
- */
-aos_utresult_t utAlldTlc5947Func(BaseSequentialStream *stream, aos_unittest_t *ut)
-{
-  aosDbgCheck(ut->data != NULL);
-
-  // local variables
-  aos_utresult_t result = {0, 0};
-  uint32_t status = 0;
-  tlc5947_lld_blank_t blank;
-  tlc5947_lld_buffer_t buffer;
-
-  chprintf(stream, "reading blank pin...\n");
-  status = tlc5947_lld_getBlank((TLC5947Driver*)ut->data, &blank);
-  if (status == APAL_STATUS_OK) {
-    aosUtPassedMsg(stream, &result, "blank is %s\n", (blank == TLC5947_LLD_BLANK_ENABLE) ? "enabled" : "disabled");
-  } else {
-    aosUtFailedMsg(stream, &result, "0x%08X\n", status);
-  }
-
-  // enabling/disabling blank pin
-  for (uint8_t i = 0; i < 2; ++i) {
-    blank = (blank == TLC5947_LLD_BLANK_ENABLE) ? TLC5947_LLD_BLANK_DISABLE : TLC5947_LLD_BLANK_ENABLE;
-    tlc5947_lld_blank_t blank_after = (blank == TLC5947_LLD_BLANK_ENABLE) ? TLC5947_LLD_BLANK_DISABLE : TLC5947_LLD_BLANK_ENABLE;
-    chprintf(stream, "%s blank pin...\n", (blank == TLC5947_LLD_BLANK_ENABLE) ? "enabling" : "disabling");
-    status = tlc5947_lld_setBlank((TLC5947Driver*)ut->data, blank);
-    status |= tlc5947_lld_getBlank((TLC5947Driver*)ut->data, &blank_after);
-    if (status == APAL_STATUS_OK && blank_after == blank) {
-      aosUtPassed(stream, &result);
-    } else {
-      aosUtFailedMsg(stream, &result, "0x%08X\n", status);
-    }
-  }
-
-  chprintf(stream, "setting all black and dimming white...\n");
-  status = tlc5947_lld_setBlank((TLC5947Driver*)ut->data, TLC5947_LLD_BLANK_ENABLE);
-  memset(buffer.data, 0, TLC5947_LLD_BUFFER_SIZE);
-  status |= tlc5947_lld_write((TLC5947Driver*)ut->data, &buffer);
-  status |= tlc5947_lld_update((TLC5947Driver*)ut->data);
-  status |= tlc5947_lld_setBlank((TLC5947Driver*)ut->data, TLC5947_LLD_BLANK_DISABLE);
-  for (uint8_t bit = 0; bit < TLC5947_LLD_PWM_RESOLUTION_BITS; ++bit) {
-    for (uint8_t channel = 0; channel < TLC5947_LLD_NUM_CHANNELS; ++channel) {
-      tlc5947_lld_setBuffer(&buffer, channel, (1 << (bit+1)) - 1);
-    }
-    status |= tlc5947_lld_write((TLC5947Driver*)ut->data, &buffer);
-    status |= tlc5947_lld_update((TLC5947Driver*)ut->data);
-    aosThdMSleep(100);
-  }
-  if (status == APAL_STATUS_OK) {
-    aosUtPassed(stream, &result);
-  } else {
-    aosUtFailedMsg(stream, &result, "0x%08X\n", status);
-  }
-
-  chprintf(stream, "NOT dimming black again...\n");
-  status = APAL_STATUS_OK;
-  for (uint8_t bit = TLC5947_LLD_PWM_RESOLUTION_BITS; bit > 0; --bit) {
-    for (uint8_t channel = 0; channel < TLC5947_LLD_NUM_CHANNELS; ++channel) {
-      tlc5947_lld_setBuffer(&buffer, channel, (1 << bit) - 1);
-    }
-    status |= tlc5947_lld_setBlank((TLC5947Driver*)ut->data, TLC5947_LLD_BLANK_ENABLE);
-    status |= tlc5947_lld_write((TLC5947Driver*)ut->data, &buffer);
-    status |= tlc5947_lld_setBlank((TLC5947Driver*)ut->data, TLC5947_LLD_BLANK_ENABLE);
-    // Grayscale data is not updated this time (tlc5947_lld_update() not called).
-    // TODO: For some reason the PWMs are updated nevertheless.
-    aosThdMSleep(100);
-  }
-  status |= tlc5947_lld_setBlank((TLC5947Driver*)ut->data, TLC5947_LLD_BLANK_ENABLE);
-  if (status == APAL_STATUS_OK) {
-    aosUtPassed(stream, &result);
-  } else {
-    aosUtFailedMsg(stream, &result, "0x%08X\n", status);
-  }
-
-  chprintf(stream, "setting each channel incrementally...\n");
-  status = APAL_STATUS_OK;
-  memset(buffer.data, 0, TLC5947_LLD_BUFFER_SIZE);
-  status |= tlc5947_lld_write((TLC5947Driver*)ut->data, &buffer);
-  status |= tlc5947_lld_update((TLC5947Driver*)ut->data);
-  status |= tlc5947_lld_setBlank((TLC5947Driver*)ut->data, TLC5947_LLD_BLANK_DISABLE);
-  for (uint8_t channel = 0; channel < TLC5947_LLD_NUM_CHANNELS; ++channel) {
-    uint16_t value = 0x0000u;
-    for (uint8_t byte = 0; byte < 3; ++byte) {
-      switch (byte) {
-        case 0:
-          value |= 0x00Fu;
-          break;
-        case 1:
-          value |= 0x0F0u;
-          break;
-        case 2:
-          value |= 0xF00u;
-          break;
-      }
-      tlc5947_lld_setBuffer(&buffer, channel, value);
-      status |= tlc5947_lld_write((TLC5947Driver*)ut->data, &buffer);
-      status |= tlc5947_lld_update((TLC5947Driver*)ut->data);
-      aosThdSleep(1.0f / 3.0f);
-      tlc5947_lld_setBuffer(&buffer, channel, 0);
-    }
-  }
-  if (status == APAL_STATUS_OK) {
-    aosUtPassed(stream, &result);
-  } else {
-    aosUtFailedMsg(stream, &result, "0x%08X\n", status);
-  }
-
-  chprintf(stream, "setting one color after another...\n");
-  status = APAL_STATUS_OK;
-  for (int8_t color = 0; color < 3; ++color) {
-    for (uint8_t channel = color; channel < TLC5947_LLD_NUM_CHANNELS; channel += 3) {
-      const uint16_t val = 0xAF5u; // some deterministic value with high entropy
-      tlc5947_lld_setBuffer(&buffer, channel, val);
-      status |= tlc5947_lld_write((TLC5947Driver*)ut->data, &buffer);
-      status |= tlc5947_lld_update((TLC5947Driver*)ut->data);
-      status |= (tlc5947_lld_getBuffer(&buffer, channel) != val) ? (1 << 31) : 0;
-      if (status != APAL_STATUS_OK) {
-        break;
-      } else {
-        aosThdSleep(1.0f / 8.0f);
-      }
-    }
-    for (uint8_t channel = 0; channel < TLC5947_LLD_NUM_CHANNELS; ++channel) {
-      tlc5947_lld_setBuffer(&buffer, channel, 0);
-    }
-  }
-  if (status == APAL_STATUS_OK) {
-    aosUtPassed(stream, &result);
-  } else {
-    aosUtFailedMsg(stream, &result, "0x%08X\n", status);
-  }
-
-  // turn LEDs off
-  tlc5947_lld_setBlank((TLC5947Driver*)ut->data, TLC5947_LLD_BLANK_ENABLE);
-  memset(buffer.data, 0, TLC5947_LLD_BUFFER_SIZE);
-  tlc5947_lld_write((TLC5947Driver*)ut->data, &buffer);
-  tlc5947_lld_update((TLC5947Driver*)ut->data);
-
-  aosUtInfoMsg(stream, "driver object memory footprint: %u bytes\n", sizeof(TLC5947Driver));
-
-  return result;
-}
-
-#endif /* (AMIROOS_CFG_TESTS_ENABLE == true) && defined(AMIROLLD_CFG_USE_TLC5947) */
diff --git a/os/unittests/periphery-lld/src/ut_alld_tps2051bdbv.c b/os/unittests/periphery-lld/src/ut_alld_tps2051bdbv.c
deleted file mode 100644
index ca74611..0000000
--- a/os/unittests/periphery-lld/src/ut_alld_tps2051bdbv.c
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
-AMiRo-OS is an operating system designed for the Autonomous Mini Robot (AMiRo) platform.
-Copyright (C) 2016..2018  Thomas Schöpping et al.
-
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program.  If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#include <ut_alld_tps2051bdbv.h>
-
-#if ((AMIROOS_CFG_TESTS_ENABLE == true) && defined(AMIROLLD_CFG_USE_TPS2051BDBV)) || defined(__DOXYGEN__)
-
-#include <aos_debug.h>
-#include <chprintf.h>
-
-/**
- * @brief   TPS2051BDBV unit test function.
- *
- * @param[in] stream  Stream for input/output.
- * @param[in] ut      Unit test object.
- *
- * @return            Unit test result value.
- */
-aos_utresult_t utAlldTps2051bdbvFunc(BaseSequentialStream* stream, aos_unittest_t* ut)
-{
-  aosDbgCheck(ut->data != NULL);
-
-  // local variables
-  aos_utresult_t result = {0, 0};
-  uint32_t status = AOS_OK;
-  tps2051b_lld_enable_t en;
-  tps2051b_lld_overcurrent_t oc;
-
-  chprintf(stream, "write laser enable...\n");
-  status = tps2051b_lld_set_enable((TPS2051BDriver*)ut->data, TPS2051B_LLD_ENABLE);
-  if (status == APAL_STATUS_SUCCESS) {
-    aosUtPassed(stream, &result);
-  } else {
-    aosUtFailed(stream, &result);
-  }
-
-  chprintf(stream, "read laser enable...\n");
-  status = tps2051b_lld_read_enable((TPS2051BDriver*)ut->data, &en);
-  if (status == APAL_STATUS_SUCCESS && en == TPS2051B_LLD_ENABLE) {
-    aosUtPassed(stream, &result);
-  } else {
-    aosUtFailed(stream, &result);
-  }
-
-  chprintf(stream, "read laser oc...\n");
-  status = tps2051b_lld_read_overcurrent((TPS2051BDriver*)ut->data, &oc);
-  if (status == APAL_STATUS_SUCCESS && oc == TPS2051B_LLD_NO_OVERCURRENT) {
-    aosUtPassed(stream, &result);
-  } else {
-    aosUtFailed(stream, &result);
-  }
-
-  chprintf(stream, "disable laser...\n");
-  status = tps2051b_lld_set_enable((TPS2051BDriver*)ut->data, TPS2051B_LLD_DISABLE);
-  if (status == APAL_STATUS_SUCCESS) {
-    aosUtPassed(stream, &result);
-  } else {
-    aosUtFailed(stream, &result);
-  }
-
-  aosUtInfoMsg(stream,"driver object memory footprint: %u bytes\n", sizeof(TPS2051BDriver));
-
-  return result;
-}
-
-#endif /* (AMIROOS_CFG_TESTS_ENABLE == true) && defined(AMIROLLD_CFG_USE_TPS2051BDBV) */
diff --git a/os/unittests/periphery-lld/src/ut_alld_tps62113.c b/os/unittests/periphery-lld/src/ut_alld_tps62113.c
deleted file mode 100644
index 403579e..0000000
--- a/os/unittests/periphery-lld/src/ut_alld_tps62113.c
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
-AMiRo-OS is an operating system designed for the Autonomous Mini Robot (AMiRo) platform.
-Copyright (C) 2016..2018  Thomas Schöpping et al.
-
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program.  If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#include <ut_alld_tps62113.h>
-
-#if ((AMIROOS_CFG_TESTS_ENABLE == true) && defined(AMIROLLD_CFG_USE_TPS62113)) || defined(__DOXYGEN__)
-
-#include <aos_debug.h>
-#include <chprintf.h>
-#include <aos_thread.h>
-#include <alld_tps62113.h>
-
-aos_utresult_t utAlldTps62113Func(BaseSequentialStream* stream, aos_unittest_t* ut)
-{
-  aosDbgCheck(ut->data != NULL);
-
-  // local variables
-  aos_utresult_t result = {0,0};
-  uint32_t status;
-  tps62113_lld_power_en_t power;
-
-  chprintf(stream, "read pin... \n");
-  status = tps62113_lld_get_power_en((TPS62113Driver*)ut->data, &power);
-  if(status == APAL_STATUS_SUCCESS){
-    aosUtPassed(stream, &result);
-  } else {
-    aosUtFailedMsg(stream, &result, "0x%08X\n", status);
-  }
-
-  chprintf(stream, "write pin... \n");
-  status = tps62113_lld_set_power_en((TPS62113Driver*)ut->data, TPS62113_LLD_POWER_ENABLED);
-  status |= tps62113_lld_get_power_en((TPS62113Driver*)ut->data, &power);
-  if(status == APAL_STATUS_SUCCESS && power == TPS62113_LLD_POWER_ENABLED){
-    aosUtPassed(stream, &result);
-  } else {
-    aosUtFailedMsg(stream, &result, "0x%08X\n", status);
-  }
-
-  aosUtInfoMsg(stream,"driver object memory footprint: %u bytes\n", sizeof(TPS62113Driver));
-
-  return result;
-}
-
-#endif /* (AMIROOS_CFG_TESTS_ENABLE == true) && defined(AMIROLLD_CFG_USE_TPS62113) */
-
-
diff --git a/os/unittests/periphery-lld/src/ut_alld_tps62113_ina219.c b/os/unittests/periphery-lld/src/ut_alld_tps62113_ina219.c
deleted file mode 100644
index 7ce0035..0000000
--- a/os/unittests/periphery-lld/src/ut_alld_tps62113_ina219.c
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
-AMiRo-OS is an operating system designed for the Autonomous Mini Robot (AMiRo) platform.
-Copyright (C) 2016..2018  Thomas Schöpping et al.
-
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program.  If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#include <ut_alld_tps62113_ina219.h>
-
-#if ((AMIROOS_CFG_TESTS_ENABLE == true) && defined(AMIROLLD_CFG_USE_TPS62113) && defined(AMIROLLD_CFG_USE_INA219)) || defined(__DOXYGEN__)
-
-#include <aos_debug.h>
-#include <chprintf.h>
-#include <aos_thread.h>
-
-aos_utresult_t utAlldTps62113Ina219Func(BaseSequentialStream *stream, aos_unittest_t *ut)
-{
-  aosDbgCheck(ut->data != NULL && ((ut_tps62113ina219data_t*)ut->data)->tps62113 != NULL && ((ut_tps62113ina219data_t*)ut->data)->ina219 != NULL);
-
-  // local variables
-  aos_utresult_t result = {0, 0};
-  uint32_t status;
-  tps62113_lld_power_en_t power;
-  uint32_t v_buson, v_busoff;
-
-  chprintf(stream, "read pin... \n");
-  status = tps62113_lld_get_power_en(((ut_tps62113ina219data_t*)ut->data)->tps62113, &power);
-  aosThdSSleep(1);
-  status |= ina219_lld_read_bus_voltage(((ut_tps62113ina219data_t*)ut->data)->ina219, &v_buson, ((ut_tps62113ina219data_t*)ut->data)->timeout);
-  if (status == APAL_STATUS_SUCCESS && power == TPS62113_LLD_POWER_ENABLED) {
-    aosUtPassedMsg(stream, &result, "enabled, %fV\n", (float)v_buson / 1000000.0f);
-  } else {
-    aosUtFailedMsg(stream, &result, "0x%08X\n", status);
-  }
-
-  chprintf(stream, "write pin... \n");
-  status = tps62113_lld_set_power_en(((ut_tps62113ina219data_t*)ut->data)->tps62113, TPS62113_LLD_POWER_DISABLED);
-  status |= tps62113_lld_get_power_en(((ut_tps62113ina219data_t*)ut->data)->tps62113, &power);
-  aosThdSSleep(1);
-  status |= ina219_lld_read_bus_voltage(((ut_tps62113ina219data_t*)ut->data)->ina219, &v_busoff, ((ut_tps62113ina219data_t*)ut->data)->timeout);
-  status |= tps62113_lld_set_power_en(((ut_tps62113ina219data_t*)ut->data)->tps62113, TPS62113_LLD_POWER_ENABLED);
-  if (status == APAL_STATUS_SUCCESS && power == TPS62113_LLD_POWER_DISABLED) {
-    chprintf(stream, "\tdisabled, %fV\n", (float)v_busoff / 1000000.0f);
-    if (v_buson > v_busoff) {
-      aosUtPassed(stream, &result);
-    } else {
-      aosUtFailedMsg(stream, &result, "on: %fV; off: %fV\n", (float)v_buson / 1000000.0f, (float)v_busoff / 1000000.0f);
-    }
-  } else {
-    aosUtFailedMsg(stream, &result, "0x%08X\n", status);
-  }
-
-  return result;
-}
-
-#endif /* (AMIROOS_CFG_TESTS_ENABLE == true) && defined(AMIROLLD_CFG_USE_TPS62113) && defined(AMIROLLD_CFG_USE_INA219) */
diff --git a/os/unittests/periphery-lld/src/ut_alld_vcnl4020.c b/os/unittests/periphery-lld/src/ut_alld_vcnl4020.c
deleted file mode 100644
index fc3c674..0000000
--- a/os/unittests/periphery-lld/src/ut_alld_vcnl4020.c
+++ /dev/null
@@ -1,226 +0,0 @@
-/*
-AMiRo-OS is an operating system designed for the Autonomous Mini Robot (AMiRo) platform.
-Copyright (C) 2016..2018  Thomas Schöpping et al.
-
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program.  If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#include <ut_alld_vcnl4020.h>
-
-#if ((AMIROOS_CFG_TESTS_ENABLE == true) && defined(AMIROLLD_CFG_USE_VCNL4020)) || defined(__DOXYGEN__)
-
-#include <aos_debug.h>
-#include <chprintf.h>
-#include <aos_thread.h>
-#include <alld_vcnl4020.h>
-#include <amiroos.h>
-
-#define INTERRUPT_EVENT_ID            1
-
-#define INTERRUPT_THRESHOLD           0x2000
-
-aos_utresult_t utAlldVcnl4020Func(BaseSequentialStream* stream, aos_unittest_t* ut)
-{
-  aosDbgCheck((ut->data != NULL) &&
-              (((ut_vcnl4020data_t*)(ut->data))->vcnld != NULL) &&
-              (((ut_vcnl4020data_t*)(ut->data))->evtsource != NULL));
-
-  // local variables
-  aos_utresult_t result = {0, 0};
-  uint32_t status;
-  uint8_t reg_buf[4];
-  uint8_t* reg_8 = (uint8_t*)(reg_buf);
-  uint16_t* reg_16 = (uint16_t*)(reg_buf);
-  event_listener_t event_listener;
-  aos_timestamp_t tcurrent, tend;
-
-  chprintf(stream, "reading register...\n");
-  status = vcnl4020_lld_readreg(((ut_vcnl4020data_t*)(ut->data))->vcnld, VCNL4020_LLD_REGADDR_IDREV, &reg_8[0], ((ut_vcnl4020data_t*)(ut->data))->timeout);
-  if ((status == APAL_STATUS_OK || status == APAL_STATUS_WARNING) && reg_8[0] == 0x21u) {
-    aosUtPassed(stream, &result);
-  } else {
-    aosUtFailedMsg(stream, &result, "0x%08X; 0x%08X\n", status, reg_8[0]);
-  }
-
-  chprintf(stream, "writing register...\n");
-  status = vcnl4020_lld_writereg(((ut_vcnl4020data_t*)(ut->data))->vcnld, VCNL4020_LLD_REGADDR_PROXRATE, VCNL4020_LLD_PROXRATEREG_250_HZ, ((ut_vcnl4020data_t*)(ut->data))->timeout);
-  status |= vcnl4020_lld_readreg(((ut_vcnl4020data_t*)(ut->data))->vcnld, VCNL4020_LLD_REGADDR_PROXRATE, &reg_8[0], ((ut_vcnl4020data_t*)(ut->data))->timeout);
-  status |= (reg_8[0] == VCNL4020_LLD_PROXRATEREG_250_HZ) ? 0x0000 : 0x0100;
-  status |= vcnl4020_lld_writereg(((ut_vcnl4020data_t*)(ut->data))->vcnld, VCNL4020_LLD_REGADDR_CMD, (VCNL4020_LLD_CMDREG_ALSEN | VCNL4020_LLD_CMDREG_PROXEN | VCNL4020_LLD_CMDREG_SELFTIMED), ((ut_vcnl4020data_t*)(ut->data))->timeout);
-  status |= vcnl4020_lld_readreg(((ut_vcnl4020data_t*)(ut->data))->vcnld, VCNL4020_LLD_REGADDR_CMD, &reg_8[0], ((ut_vcnl4020data_t*)(ut->data))->timeout);
-  status |= (reg_8[0] & (VCNL4020_LLD_CMDREG_ALSEN | VCNL4020_LLD_CMDREG_PROXEN | VCNL4020_LLD_CMDREG_SELFTIMED)) ? 0x0000 : 0x0200;
-
-  if (status == APAL_STATUS_OK || status == APAL_STATUS_WARNING) {
-    aosUtPassed(stream, &result);
-  } else {
-    aosUtFailedMsg(stream, &result, "0x%08X, 0x%02X\n", status, reg_8[0]);
-  }
-
-  chprintf(stream, "reading ambient light for ten seconds...\n");
-  status = APAL_STATUS_OK;
-  for (uint8_t i = 0; i < 10; ++i) {
-    aosThdSSleep(1);
-    status |= vcnl4020_lld_readals(((ut_vcnl4020data_t*)(ut->data))->vcnld, &reg_16[0], ((ut_vcnl4020data_t*)(ut->data))->timeout);
-    chprintf(stream, "\t\tambient light: 0x%04X\n", reg_16[0]);
-  }
-  status |= (reg_16[0] == 0x0000) ? 0x10 : 0x00;
-  if (status == APAL_STATUS_OK) {
-    aosUtPassed(stream, &result);
-  } else {
-    aosUtFailedMsg(stream, &result, "0x%08X\n", status);
-  }
-
-  chprintf(stream, "reading proximity for ten seconds...\n");
-  status = APAL_STATUS_OK;
-  for (uint8_t i = 0; i < 10; ++i) {
-    aosThdSSleep(1);
-    status |= vcnl4020_lld_readprox(((ut_vcnl4020data_t*)(ut->data))->vcnld, &reg_16[1], ((ut_vcnl4020data_t*)(ut->data))->timeout);
-    chprintf(stream, "\t\tproximity: 0x%04X\n", reg_16[1]);
-  }
-  status |= (reg_16[1] == 0x0000) ? 0x10 : 0x00;
-  if (status == APAL_STATUS_OK) {
-    aosUtPassed(stream, &result);
-  } else {
-    aosUtFailedMsg(stream, &result, "0x%08X\n", status);
-  }
-
-  chprintf(stream, "reading ambient light and proximity for ten seconds...\n");
-  status = APAL_STATUS_OK;
-  for (uint8_t i = 0; i < 10; ++i) {
-    aosThdSSleep(1);
-    status |= vcnl4020_lld_readalsandprox(((ut_vcnl4020data_t*)(ut->data))->vcnld, &reg_16[0], &reg_16[1], ((ut_vcnl4020data_t*)(ut->data))->timeout);
-    chprintf(stream, "\t\tambient light: 0x%04X\tproximity: 0x%04X\n", reg_16[0], reg_16[1]);
-  }
-  status |= (reg_16[0] == 0x0000 || reg_16[1] == 0x0000) ? 0x10 : 0x00;
-  if (status == APAL_STATUS_OK) {
-    aosUtPassed(stream, &result);
-  } else {
-    aosUtFailedMsg(stream, &result, "0x%08X\n", status);
-  }
-
-  chprintf(stream, "reading low threshold register...\n");
-  status = vcnl4020_lld_readlth(((ut_vcnl4020data_t*)(ut->data))->vcnld, &reg_16[0], ((ut_vcnl4020data_t*)(ut->data))->timeout);
-  if (status == APAL_STATUS_OK) {
-    aosUtPassed(stream, &result);
-  } else {
-    aosUtFailedMsg(stream, &result, "0x%08X\n", status);
-  }
-
-  chprintf(stream, "reading high threshold register...\n");
-  status = vcnl4020_lld_readhth(((ut_vcnl4020data_t*)(ut->data))->vcnld, &reg_16[1], ((ut_vcnl4020data_t*)(ut->data))->timeout);
-  if (status == APAL_STATUS_OK) {
-    aosUtPassedMsg(stream, &result, "0x%04X\n", reg_16[1]);
-  } else {
-    aosUtFailedMsg(stream, &result, "0x%08X\n", status);
-  }
-
-  chprintf(stream, "reading both threshold registers...\n");
-  status = vcnl4020_lld_readth(((ut_vcnl4020data_t*)(ut->data))->vcnld, &reg_16[0], &reg_16[1], ((ut_vcnl4020data_t*)(ut->data))->timeout);
-  if (status == APAL_STATUS_OK) {
-    aosUtPassedMsg(stream, &result, "low: 0x%04X; high: 0x%04X\n", reg_16[0], reg_16[1]);
-  } else {
-    aosUtFailedMsg(stream, &result, "0x%08X\n", status);
-  }
-
-  chprintf(stream, "writing low threshold register...\n");
-  status = vcnl4020_lld_writelth(((ut_vcnl4020data_t*)(ut->data))->vcnld, 0xFFFFu, ((ut_vcnl4020data_t*)(ut->data))->timeout);
-  status |= vcnl4020_lld_readlth(((ut_vcnl4020data_t*)(ut->data))->vcnld, &reg_16[0], ((ut_vcnl4020data_t*)(ut->data))->timeout);
-  if (status == APAL_STATUS_OK && reg_16[0] == 0xFFFFu) {
-    aosUtPassed(stream, &result);
-  } else {
-    aosUtFailedMsg(stream, &result, "0x%08X, 0x%04X\n", status, reg_16[0]);
-  }
-
-  chprintf(stream, "writing high threshold register...\n");
-  status = vcnl4020_lld_writehth(((ut_vcnl4020data_t*)(ut->data))->vcnld, 0xFFFFu, ((ut_vcnl4020data_t*)(ut->data))->timeout);
-  status |= vcnl4020_lld_readhth(((ut_vcnl4020data_t*)(ut->data))->vcnld, &reg_16[1], ((ut_vcnl4020data_t*)(ut->data))->timeout);
-  if (status == APAL_STATUS_OK && reg_16[1] == 0xFFFFu) {
-    aosUtPassed(stream, &result);
-  } else {
-    aosUtFailedMsg(stream, &result, "0x%08X, 0x%04X\n", status, reg_16[1]);
-  }
-
-  chprintf(stream, "writing both threshold registers...\n");
-  status = vcnl4020_lld_writeth(((ut_vcnl4020data_t*)(ut->data))->vcnld, 0x5555u, 0xAAAAu, ((ut_vcnl4020data_t*)(ut->data))->timeout);
-  status |= vcnl4020_lld_readth(((ut_vcnl4020data_t*)(ut->data))->vcnld, &reg_16[0], &reg_16[1], ((ut_vcnl4020data_t*)(ut->data))->timeout);
-  if (status == APAL_STATUS_OK && reg_16[0] == 0x5555u && reg_16[1] == 0xAAAAu) {
-    aosUtPassed(stream, &result);
-  } else {
-    aosUtFailedMsg(stream, &result, "0x%08X, 0x%04X, 0x%04X\n", status, reg_16[0], reg_16[1]);
-  }
-
-  chprintf(stream, "test interrupts...\n");
-  chprintf(stream, "(thresholds are 0x%04X and 0x%04X)\n", 0, INTERRUPT_THRESHOLD);
-  chEvtRegister(((ut_vcnl4020data_t*)(ut->data))->evtsource, &event_listener, INTERRUPT_EVENT_ID);
-  aosSysGetUptime(&tend);
-  tend += 30 * MICROSECONDS_PER_SECOND;
-  status = vcnl4020_lld_writeth(((ut_vcnl4020data_t*)(ut->data))->vcnld, 0x0000, INTERRUPT_THRESHOLD, ((ut_vcnl4020data_t*)(ut->data))->timeout);
-  status |= vcnl4020_lld_writereg(((ut_vcnl4020data_t*)(ut->data))->vcnld, VCNL4020_LLD_REGADDR_INTCTRL, VCNL4020_LLD_INTCTRLREG_THRES_EN, ((ut_vcnl4020data_t*)(ut->data))->timeout);
-  do {
-    // read proximity data, interrupt event information and interrupt status
-    const eventmask_t emask = chEvtWaitOneTimeout(EVENT_MASK(INTERRUPT_EVENT_ID), chTimeUS2I(10*MICROSECONDS_PER_MILLISECOND));
-    const eventflags_t eflags = chEvtGetAndClearFlags(&event_listener);
-    status |= vcnl4020_lld_readprox(((ut_vcnl4020data_t*)(ut->data))->vcnld, &reg_16[0], ((ut_vcnl4020data_t*)(ut->data))->timeout);
-    status |= vcnl4020_lld_readreg(((ut_vcnl4020data_t*)(ut->data))->vcnld, VCNL4020_LLD_REGADDR_INTSTATUS, &reg_8[2], ((ut_vcnl4020data_t*)(ut->data))->timeout);
-    if (emask == EVENT_MASK(INTERRUPT_EVENT_ID) &&
-        eflags == ((ut_vcnl4020data_t*)(ut->data))->evtflags &&
-        reg_8[2] == VCNL4020_LLD_INTSTATUSREG_THHIGH) {
-      // true positive (correct case)
-      chprintf(stream, "\t\tinterrupt detected: prox = 0x%04X\n", reg_16[0]);
-      aosThdMSleep(100);
-    }
-    else if (emask != EVENT_MASK(INTERRUPT_EVENT_ID) &&
-             eflags != ((ut_vcnl4020data_t*)(ut->data))->evtflags &&
-             reg_8[2] != VCNL4020_LLD_INTSTATUSREG_THHIGH) {
-      // true negative (correct case)
-      // do nothing, just keep on looping
-    }
-    else if (emask == EVENT_MASK(INTERRUPT_EVENT_ID) &&
-             eflags == ((ut_vcnl4020data_t*)(ut->data))->evtflags &&
-             reg_8[2] != 0 ) {
-      // false positive
-      status |= 0x1000;
-      chprintf(stream, "\t\tfalse positive: intstatus = 0x%02X; prox = 0x%04X\n", reg_8[2], reg_16[0]);
-    }
-    else if (emask != EVENT_MASK(INTERRUPT_EVENT_ID) &&
-             eflags != ((ut_vcnl4020data_t*)(ut->data))->evtflags &&
-             reg_8[2] == 0) {
-      // false negative
-      status |= 0x2000;
-      chprintf(stream, "\t\tfalse negative: intstatus = 0x%02X; prox = 0x%04X\n", reg_8[2], reg_16[0]);
-    } // any other events are just ignored
-    // reset interrupt status
-    if (reg_8[2] != 0) {
-      status |= vcnl4020_lld_writereg(((ut_vcnl4020data_t*)(ut->data))->vcnld, VCNL4020_LLD_REGADDR_INTSTATUS, reg_8[2], ((ut_vcnl4020data_t*)(ut->data))->timeout);
-    }
-    aosSysGetUptime(&tcurrent);
-  } while (tcurrent < tend);
-  chEvtUnregister(((ut_vcnl4020data_t*)(ut->data))->evtsource, &event_listener);
-  status |= vcnl4020_lld_writereg(((ut_vcnl4020data_t*)(ut->data))->vcnld, VCNL4020_LLD_REGADDR_INTCTRL, 0, ((ut_vcnl4020data_t*)(ut->data))->timeout);
-  status |= vcnl4020_lld_readreg(((ut_vcnl4020data_t*)(ut->data))->vcnld, VCNL4020_LLD_REGADDR_INTSTATUS, &reg_8[2], ((ut_vcnl4020data_t*)(ut->data))->timeout);
-  status |= vcnl4020_lld_writereg(((ut_vcnl4020data_t*)(ut->data))->vcnld, VCNL4020_LLD_REGADDR_INTSTATUS, reg_8[2], ((ut_vcnl4020data_t*)(ut->data))->timeout);
-  if (status == APAL_STATUS_SUCCESS || status == APAL_STATUS_WARNING) {
-    aosUtPassed(stream, &result);
-  } else {
-    aosUtFailedMsg(stream, &result, "0x%08X\n", status);
-  }
-
-  aosUtInfoMsg(stream, "driver object memory footprint: %u bytes\n", sizeof(VCNL4020Driver));
-
-  return result;
-}
-
-#endif /* (AMIROOS_CFG_TESTS_ENABLE == true) && defined(AMIROLLD_CFG_USE_VCNL4020) */
-
-
diff --git a/os/unittests/unittests.mk b/os/unittests/unittests.mk
deleted file mode 100644
index 332aa91..0000000
--- a/os/unittests/unittests.mk
+++ /dev/null
@@ -1,55 +0,0 @@
-################################################################################
-# AMiRo-OS is an operating system designed for the Autonomous Mini Robot       #
-# (AMiRo) platform.                                                            #
-# Copyright (C) 2016..2018  Thomas Schöpping et al.                            #
-#                                                                              #
-# This program is free software: you can redistribute it and/or modify         #
-# it under the terms of the GNU General Public License as published by         #
-# the Free Software Foundation, either version 3 of the License, or            #
-# (at your option) any later version.                                          #
-#                                                                              #
-# This program is distributed in the hope that it will be useful,              #
-# but WITHOUT ANY WARRANTY; without even the implied warranty of               #
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the                #
-# GNU General Public License for more details.                                 #
-#                                                                              #
-# You should have received a copy of the GNU General Public License            #
-# along with this program.  If not, see <http://www.gnu.org/licenses/>.        #
-#                                                                              #
-# This research/work was supported by the Cluster of Excellence Cognitive      #
-# Interaction Technology 'CITEC' (EXC 277) at Bielefeld University, which is   #
-# funded by the German Research Foundation (DFG).                              #
-################################################################################
-
-
-
-# absolute path to this directory
-UNITTESTS_DIR := $(dir $(lastword $(MAKEFILE_LIST)))
-
-# include path
-UNITTESTSINC = $(UNITTESTS_DIR)lld/inc \
-               $(UNITTESTS_DIR)periphery-lld/inc
-
-# C sources
-UNITTESTSCSRC = $(UNITTESTS_DIR)lld/src/ut_lld_adc.c \
-                $(UNITTESTS_DIR)periphery-lld/src/ut_alld_a3906.c \
-                $(UNITTESTS_DIR)periphery-lld/src/ut_alld_at24c01bn-sh-b.c \
-                $(UNITTESTS_DIR)periphery-lld/src/ut_alld_bq24103a.c \
-                $(UNITTESTS_DIR)periphery-lld/src/ut_alld_bq27500.c \
-                $(UNITTESTS_DIR)periphery-lld/src/ut_alld_bq27500_bq24103a.c \
-                $(UNITTESTS_DIR)periphery-lld/src/ut_alld_hmc5883l.c \
-                $(UNITTESTS_DIR)periphery-lld/src/ut_alld_ina219.c \
-                $(UNITTESTS_DIR)periphery-lld/src/ut_alld_l3g4200d.c \
-                $(UNITTESTS_DIR)periphery-lld/src/ut_alld_led.c \
-                $(UNITTESTS_DIR)periphery-lld/src/ut_alld_lis331dlh.c \
-                $(UNITTESTS_DIR)periphery-lld/src/ut_alld_ltc4412.c \
-                $(UNITTESTS_DIR)periphery-lld/src/ut_alld_mpr121.c \
-                $(UNITTESTS_DIR)periphery-lld/src/ut_alld_pca9544a.c \
-                $(UNITTESTS_DIR)periphery-lld/src/ut_alld_pklcs1212e4001.c \
-                $(UNITTESTS_DIR)periphery-lld/src/ut_alld_tlc5947.c \
-                $(UNITTESTS_DIR)periphery-lld/src/ut_alld_tps2051bdbv.c \
-                $(UNITTESTS_DIR)periphery-lld/src/ut_alld_tps62113.c \
-                $(UNITTESTS_DIR)periphery-lld/src/ut_alld_tps62113_ina219.c \
-                $(UNITTESTS_DIR)periphery-lld/src/ut_alld_vcnl4020.c \
-                $(UNITTESTS_DIR)periphery-lld/src/ut_alld_dw1000.c
-
diff --git a/unittests/lld/inc/ut_lld_adc.h b/unittests/lld/inc/ut_lld_adc.h
new file mode 100644
index 0000000..b3cae14
--- /dev/null
+++ b/unittests/lld/inc/ut_lld_adc.h
@@ -0,0 +1,51 @@
+/*
+AMiRo-OS is an operating system designed for the Autonomous Mini Robot (AMiRo) platform.
+Copyright (C) 2016..2018  Thomas Schöpping et al.
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _AMIROOS_UT_LLD_ADC_H_
+#define _AMIROOS_UT_LLD_ADC_H_
+
+#include <aos_unittest.h>
+
+#if ((AMIROOS_CFG_TESTS_ENABLE == true) && (HAL_USE_ADC == TRUE))|| defined(__DOXYGEN__)
+
+/**
+ * @brief   Custom data structure for the unit test.
+ */
+typedef struct {
+  /**
+   * @brief   Pointer to the driver to use.
+   */
+  ADCDriver* driver;
+
+  /**
+   * @brief   Pointer to the conversion group to use.
+   */
+  ADCConversionGroup* convgroup;
+} ut_adcdata_t;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+  aos_utresult_t utAdcFunc(BaseSequentialStream* stream, aos_unittest_t* ut);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* (AMIROOS_CFG_TESTS_ENABLE == true) && (HAL_USE_ADC == TRUE) */
+
+#endif /* _AMIROOS_UT_LLD_ADC_H_ */
diff --git a/unittests/lld/src/ut_lld_adc.c b/unittests/lld/src/ut_lld_adc.c
new file mode 100644
index 0000000..05721f7
--- /dev/null
+++ b/unittests/lld/src/ut_lld_adc.c
@@ -0,0 +1,156 @@
+/*
+AMiRo-OS is an operating system designed for the Autonomous Mini Robot (AMiRo) platform.
+Copyright (C) 2016..2018  Thomas Schöpping et al.
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <ut_lld_adc.h>
+
+#if ((AMIROOS_CFG_TESTS_ENABLE == true) && (HAL_USE_ADC == TRUE))|| defined(__DOXYGEN__)
+
+#include <aos_debug.h>
+#include <aos_thread.h>
+#include <chprintf.h>
+
+/**
+ * @brief   Event mask of the ADC analog watchdog event.
+ */
+#define _adcWdgEventmask                        EVENT_MASK(31)
+
+/**
+ * @brief   ADC analog watchdog threshold (9.0V).
+ */
+#define _adcWdgThreshold                        (uint16_t)(9.0f / 5.0f / 3.3f * ((1 << 12) - 1) + 0.5f)
+
+/**
+ * @brief   Pointer to the thread listening for an ADC analog watchdog event.
+ */
+static thread_t* _listener;
+
+/**
+ * @brief   Helper function to convert ADC sample value to volts.
+ *
+ * @param[in] adc   ADC sample value.
+ *
+ * @return          Converted value in volts.
+ */
+static inline float _adc2volt(adcsample_t adc) {
+  return (float)adc / ((1 << 12) - 1) * 3.3f * 5.0f;
+}
+
+/**
+ * @brief   ADC analog watchdog callback function.
+ *
+ * @param[in] adcp  ADC driver.
+ * @param[in] err   ADC error value.
+ */
+static void _adcAwdCb(ADCDriver* adcp, adcerror_t err)
+{
+  (void)adcp;
+
+  if (err == ADC_ERR_WATCHDOG) {
+    chSysLockFromISR();
+    if (_listener != NULL) {
+      chEvtSignalI(_listener, _adcWdgEventmask);
+      _listener = NULL;
+    }
+    chSysUnlockFromISR();
+  }
+
+  return;
+}
+
+/**
+ * @brief   ADC unit test function.
+ *
+ * @param[in] stream  Stream for input/output.
+ * @param[in] ut      Unit test object.
+ *
+ * @return            Unit test result value.
+ */
+aos_utresult_t utAdcFunc(BaseSequentialStream* stream, aos_unittest_t* ut)
+{
+  aosDbgCheck(ut->data != NULL && ((ut_adcdata_t*)(ut->data))->driver != NULL && ((ut_adcdata_t*)(ut->data))->convgroup != NULL);
+
+  // local variables
+  aos_utresult_t result = {0, 0};
+  adcsample_t buffer[1] = {0};
+  bool wdgpassed = false;
+  eventmask_t eventmask = 0;
+  ADCConversionGroup conversionGroup = *(((ut_adcdata_t*)(ut->data))->convgroup);
+  conversionGroup.circular = true;
+  conversionGroup.end_cb = NULL;
+  conversionGroup.end_cb = NULL;
+  conversionGroup.htr = ADC_HTR_HT;
+  conversionGroup.ltr = 0;
+
+  chprintf(stream, "reading voltage for five seconds...\n");
+  adcStartConversion(((ut_adcdata_t*)(ut->data))->driver, &conversionGroup, buffer, 1);
+  for (uint8_t s = 0; s < 5; ++s) {
+    aosThdSSleep(1);
+    chprintf(stream, "\tVSYS = %fV\n", _adc2volt(buffer[0]));
+  }
+  adcStopConversion(((ut_adcdata_t*)(ut->data))->driver);
+  if (buffer[0] != 0) {
+    aosUtPassed(stream, &result);
+  } else {
+    aosUtFailed(stream, &result);
+  }
+
+  chprintf(stream, "detecting external power...\n");
+  conversionGroup.error_cb = _adcAwdCb;
+  conversionGroup.htr = _adcWdgThreshold;
+  conversionGroup.ltr = _adcWdgThreshold;
+  _listener = chThdGetSelfX();
+  adcStartConversion(((ut_adcdata_t*)(ut->data))->driver, &conversionGroup, buffer, 1);
+  eventmask = chEvtWaitOneTimeout(_adcWdgEventmask, chTimeS2I(5));
+  if (eventmask == _adcWdgEventmask) {
+    aosUtPassedMsg(stream, &result, "%fV %c 9V\n", _adc2volt(buffer[0]), (buffer[0] > _adcWdgThreshold) ? '>' : '<');
+    wdgpassed = true;
+  } else {
+    adcStopConversion(((ut_adcdata_t*)(ut->data))->driver);
+    aosUtFailed(stream, &result);
+    wdgpassed = false;
+  }
+
+  if (wdgpassed) {
+    for (uint8_t i = 0; i < 2; ++i) {
+      if (buffer[0] > _adcWdgThreshold) {
+        chprintf(stream, "Remove external power within ten seconds.\n");
+        conversionGroup.htr = ADC_HTR_HT;
+        conversionGroup.ltr = _adcWdgThreshold;
+      } else {
+        chprintf(stream, "Connect external power within ten seconds.\n");
+        conversionGroup.htr = _adcWdgThreshold;
+        conversionGroup.ltr = 0;
+      }
+      aosThdMSleep(100); // wait some time so the ADC wil trigger again immediately due to noise
+      _listener = chThdGetSelfX();
+      adcStartConversion(((ut_adcdata_t*)(ut->data))->driver, &conversionGroup, buffer, 1);
+      eventmask = chEvtWaitOneTimeout(_adcWdgEventmask, chTimeS2I(10));
+      if (eventmask == _adcWdgEventmask) {
+        aosUtPassedMsg(stream, &result, "%fV %c 9V\n", _adc2volt(buffer[0]), (buffer[0] > _adcWdgThreshold) ? '>' : '<');
+      } else {
+        adcStopConversion(((ut_adcdata_t*)(ut->data))->driver);
+        aosUtFailed(stream, &result);
+        break;
+      }
+    }
+  }
+
+  return result;
+}
+
+#endif /* (AMIROOS_CFG_TESTS_ENABLE == true) && (HAL_USE_ADC == TRUE) */
diff --git a/unittests/periphery-lld/inc/ut_alld_a3906.h b/unittests/periphery-lld/inc/ut_alld_a3906.h
new file mode 100644
index 0000000..3eaef77
--- /dev/null
+++ b/unittests/periphery-lld/inc/ut_alld_a3906.h
@@ -0,0 +1,114 @@
+/*
+AMiRo-OS is an operating system designed for the Autonomous Mini Robot (AMiRo) platform.
+Copyright (C) 2016..2018  Thomas Schöpping et al.
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _AMIROOS_UT_ALLD_A3906_H_
+#define _AMIROOS_UT_ALLD_A3906_H_
+
+#include <aos_unittest.h>
+#include <amiro-lld.h>
+
+#if ((AMIROOS_CFG_TESTS_ENABLE == true) && defined(AMIROLLD_CFG_USE_A3906)) || defined(__DOXYGEN__)
+
+#include <alld_a3906.h>
+
+/**
+ * @brief   Custom data structure for the unit test.
+ */
+typedef struct {
+  /**
+   * @brief   Pointer to the driver to use.
+   */
+  A3906Driver* driver;
+
+  /**
+   * @brief   PWM driver information.
+   */
+  struct {
+    /**
+     * @brief   The PWM driver to use.
+     */
+    apalPWMDriver_t* driver;
+
+    /**
+     * @brief   PWM channel information.
+     */
+    struct {
+      /**
+     * @brief   PWM channel for the left wheel forward direction.
+     */
+      apalPWMchannel_t left_forward;
+
+      /**
+     * @brief   PWM channel for the left wheel backward direction.
+     */
+      apalPWMchannel_t left_backward;
+
+      /**
+     * @brief   PWM channel for the right wheel forward direction.
+     */
+      apalPWMchannel_t right_forward;
+
+      /**
+     * @brief   PWM channel for the right wheel backward direction.
+     */
+      apalPWMchannel_t right_backward;
+    } channel;
+  } pwm;
+
+  /**
+   * @brief   QEI driver information
+   */
+  struct {
+    /**
+     * @brief   QEI driver for the left wheel.
+     */
+    apalQEIDriver_t* left;
+
+    /**
+     * @brief   QEI driver for the right wheel.
+     */
+    apalQEIDriver_t* right;
+
+    /**
+     * @brief   QEI increments per wheel revolution.
+     */
+    apalQEICount_t increments_per_revolution;
+  } qei;
+
+  /**
+   * @brief   Wheel diameter in m.
+   */
+  float wheel_diameter;
+
+  /**
+   * @brief   Timeout value (in us).
+   */
+  apalTime_t timeout;
+} ut_a3906data_t;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+  aos_utresult_t utAlldA3906Func(BaseSequentialStream* stream, aos_unittest_t* ut);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* (AMIROOS_CFG_TESTS_ENABLE == true) && defined(AMIROLLD_CFG_USE_A3906) */
+
+#endif /* _AMIROOS_UT_ALLD_A3906_H_ */
diff --git a/unittests/periphery-lld/inc/ut_alld_at24c01bn-sh-b.h b/unittests/periphery-lld/inc/ut_alld_at24c01bn-sh-b.h
new file mode 100644
index 0000000..1ed579e
--- /dev/null
+++ b/unittests/periphery-lld/inc/ut_alld_at24c01bn-sh-b.h
@@ -0,0 +1,54 @@
+/*
+AMiRo-OS is an operating system designed for the Autonomous Mini Robot (AMiRo) platform.
+Copyright (C) 2016..2018  Thomas Schöpping et al.
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _AMIROOS_UT_ALLD_AT24C01BN_H_
+#define _AMIROOS_UT_ALLD_AT24C01BN_H_
+
+#include <aos_unittest.h>
+#include <amiro-lld.h>
+
+#if ((AMIROOS_CFG_TESTS_ENABLE == true) && defined(AMIROLLD_CFG_USE_AT24C01BN)) || defined(__DOXYGEN__)
+
+#include <alld_at24c01bn-sh-b.h>
+
+/**
+ * @brief   Custom data structure for the unit test.
+ */
+typedef struct {
+  /**
+   * @brief   Pointer to the driver to use.
+   */
+  AT24C01BNDriver* driver;
+
+  /**
+   * @brief   Timeout value (in us).
+   */
+  apalTime_t timeout;
+} ut_at24c01bndata_t;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+  aos_utresult_t utAlldAt24c01bnFunc(BaseSequentialStream* stream, aos_unittest_t* ut);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* (AMIROOS_CFG_TESTS_ENABLE == true) && defined(AMIROLLD_CFG_USE_AT24C01BN) */
+
+#endif /* _AMIROOS_UT_ALLD_AT24C01BN_H_ */
diff --git a/unittests/periphery-lld/inc/ut_alld_bq24103a.h b/unittests/periphery-lld/inc/ut_alld_bq24103a.h
new file mode 100644
index 0000000..889ce22
--- /dev/null
+++ b/unittests/periphery-lld/inc/ut_alld_bq24103a.h
@@ -0,0 +1,39 @@
+/*
+AMiRo-OS is an operating system designed for the Autonomous Mini Robot (AMiRo) platform.
+Copyright (C) 2016..2018  Thomas Schöpping et al.
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _AMIROOS_UT_ALLD_BQ24103A_H_
+#define _AMIROOS_UT_ALLD_BQ24103A_H_
+
+#include <aos_unittest.h>
+#include <amiro-lld.h>
+
+#if ((AMIROOS_CFG_TESTS_ENABLE == true) && defined(AMIROLLD_CFG_USE_BQ24103A)) || defined(__DOXYGEN__)
+
+#include <alld_bq24103a.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+  aos_utresult_t utAlldBq24103aFunc(BaseSequentialStream* stream, aos_unittest_t* ut);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* (AMIROOS_CFG_TESTS_ENABLE == true) && defined(AMIROLLD_CFG_USE_BQ24103A) */
+
+#endif /* _AMIROOS_UT_ALLD_BQ24103A_H_ */
diff --git a/unittests/periphery-lld/inc/ut_alld_bq27500.h b/unittests/periphery-lld/inc/ut_alld_bq27500.h
new file mode 100644
index 0000000..9818639
--- /dev/null
+++ b/unittests/periphery-lld/inc/ut_alld_bq27500.h
@@ -0,0 +1,55 @@
+/*
+AMiRo-OS is an operating system designed for the Autonomous Mini Robot (AMiRo) platform.
+Copyright (C) 2016..2018  Thomas Schöpping et al.
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _AMIROOS_UT_ALLD_BQ27500_H_
+#define _AMIROOS_UT_ALLD_BQ27500_H_
+
+#include <aos_unittest.h>
+#include <amiro-lld.h>
+
+#if ((AMIROOS_CFG_TESTS_ENABLE == true) && defined(AMIROLLD_CFG_USE_BQ27500)) || defined(__DOXYGEN__)
+
+#include <alld_bq27500.h>
+
+/**
+ * @brief   Custom data structure for the unit test.
+ */
+typedef struct {
+  /**
+   * @brief   Pointer to the driver to use.
+   */
+  BQ27500Driver *driver;
+
+  /**
+   * @brief   Timeout value (in us);
+   */
+  apalTime_t timeout;
+} ut_bq27500data_t;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+  aos_utresult_t utAlldBq27500Func(BaseSequentialStream* stream, aos_unittest_t* ut);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* (AMIROOS_CFG_TESTS_ENABLE == true) && defined(AMIROLLD_CFG_USE_BQ27500) */
+
+#endif /* _AMIROOS_UT_ALLD_BQ27500_H_ */
+
diff --git a/unittests/periphery-lld/inc/ut_alld_bq27500_bq24103a.h b/unittests/periphery-lld/inc/ut_alld_bq27500_bq24103a.h
new file mode 100644
index 0000000..58836ce
--- /dev/null
+++ b/unittests/periphery-lld/inc/ut_alld_bq27500_bq24103a.h
@@ -0,0 +1,60 @@
+/*
+AMiRo-OS is an operating system designed for the Autonomous Mini Robot (AMiRo) platform.
+Copyright (C) 2016..2018  Thomas Schöpping et al.
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _AMIROOS_UT_ALLD_BQ27500_BQ24193A_H_
+#define _AMIROOS_UT_ALLD_BQ27500_BQ24193A_H_
+
+#include <aos_unittest.h>
+#include <amiro-lld.h>
+
+#if ((AMIROOS_CFG_TESTS_ENABLE == true) && defined(AMIROLLD_CFG_USE_BQ27500) && defined(AMIROLLD_CFG_USE_BQ24103A)) || defined(__DOXYGEN__)
+
+#include <alld_bq27500.h>
+#include <alld_bq24103a.h>
+
+/**
+ * @brief   Custom data structure for the unit test.
+ */
+typedef struct {
+  /**
+   * @brief   BQ27500 driver to use.
+   */
+  BQ27500Driver* bq27500;
+
+  /**
+   * @brief   BQ24103A driver to use.
+   */
+  BQ24103ADriver* bq24103a;
+
+  /**
+   * @brief   Timeout value (in us).
+   */
+  apalTime_t timeout;
+} ut_bq27500bq24103adata_t;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+  aos_utresult_t utAlldBq27500Bq24103aFunc(BaseSequentialStream* stream, aos_unittest_t* ut);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* (AMIROOS_CFG_TESTS_ENABLE == true) && defined(AMIROLLD_CFG_USE_BQ27500) && defined(AMIROLLD_CFG_USE_BQ24103A) */
+
+#endif /* _AMIROOS_UT_ALLD_BQ27500_BQ24193A_H_ */
diff --git a/unittests/periphery-lld/inc/ut_alld_dw1000.h b/unittests/periphery-lld/inc/ut_alld_dw1000.h
new file mode 100755
index 0000000..43f98eb
--- /dev/null
+++ b/unittests/periphery-lld/inc/ut_alld_dw1000.h
@@ -0,0 +1,40 @@
+/*
+AMiRo-OS is an operating system designed for the Autonomous Mini Robot (AMiRo) platform.
+Copyright (C) 2016..2018  Thomas Schöpping et al.
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _AMIROOS_UT_DW1000_LLD_HPP_
+#define _AMIROOS_UT_DW1000_LLD_HPP_
+
+#include <aos_unittest.h>
+#include <amiro-lld.h>
+
+#if ((AMIROOS_CFG_TESTS_ENABLE == true) && defined(AMIROLLD_CFG_USE_DW1000)) || defined(__DOXYGEN__)
+
+#include <alld_dw1000.h>
+//#include <deca_instance.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+  aos_utresult_t utAlldDw1000Func(BaseSequentialStream* stream, aos_unittest_t* ut);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* (AMIROOS_CFG_TESTS_ENABLE == true) && defined(AMIROLLD_CFG_USE_DW1000) */
+
+#endif /* _AMIROOS_UT_DW1000_LLD_HPP_ */
diff --git a/unittests/periphery-lld/inc/ut_alld_hmc5883l.h b/unittests/periphery-lld/inc/ut_alld_hmc5883l.h
new file mode 100644
index 0000000..e478c2f
--- /dev/null
+++ b/unittests/periphery-lld/inc/ut_alld_hmc5883l.h
@@ -0,0 +1,65 @@
+/*
+AMiRo-OS is an operating system designed for the Autonomous Mini Robot (AMiRo) platform.
+Copyright (C) 2016..2018  Thomas Schöpping et al.
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _AMIROOS_UT_HMC5883L_LLD_HPP_
+#define _AMIROOS_UT_HMC5883L_LLD_HPP_
+
+#include <aos_unittest.h>
+#include <amiro-lld.h>
+
+#if ((AMIROOS_CFG_TESTS_ENABLE == true) && defined(AMIROLLD_CFG_USE_HMC5883L)) || defined(__DOXYGEN__)
+
+#include <alld_hmc5883l.h>
+
+/**
+ * @brief   Constum data structure for this unit test.
+ */
+typedef struct {
+  /**
+   * @brief   HMC5338L driver to use.
+   */
+  HMC5883LDriver* driver;
+
+  /**
+   * @brief   Event source for certain tests.
+   */
+  event_source_t *drdyEvtSrc;
+
+  /**
+   * @brief   Event flags to watch.
+   */
+  eventflags_t evtflags;
+
+  /**
+   * @brief   Timeout value in microseconds.
+   */
+  apalTime_t timeout;
+} ut_hmc5883ldata_t;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+  aos_utresult_t utAlldHmc5883lFunc(BaseSequentialStream* stream, aos_unittest_t* ut);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* (AMIROOS_CFG_TESTS_ENABLE == true) && defined(AMIROLLD_CFG_USE_HMC5883L) */
+
+
+#endif /* _AMIROOS_UT_HMC5883L_LLD_HPP_ */
diff --git a/unittests/periphery-lld/inc/ut_alld_ina219.h b/unittests/periphery-lld/inc/ut_alld_ina219.h
new file mode 100644
index 0000000..c386e5f
--- /dev/null
+++ b/unittests/periphery-lld/inc/ut_alld_ina219.h
@@ -0,0 +1,64 @@
+/*
+AMiRo-OS is an operating system designed for the Autonomous Mini Robot (AMiRo) platform.
+Copyright (C) 2016..2018  Thomas Schöpping et al.
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _AMIROOS_UT_INA219_LLD_HPP_
+#define _AMIROOS_UT_INA219_LLD_HPP_
+
+#include <aos_unittest.h>
+#include <amiro-lld.h>
+
+#if ((AMIROOS_CFG_TESTS_ENABLE == true) && defined(AMIROLLD_CFG_USE_INA219)) || defined(__DOXYGEN__)
+
+#include <alld_ina219.h>
+
+/**
+ * @brief   Custom data structure for the unit test.
+ */
+typedef struct {
+  /**
+   * @brief   INA219 driver to use.
+   */
+  INA219Driver *inad;
+
+  /**
+   * @brief   Expected voltage to be measured.
+   */
+  float v_expected;
+
+  /**
+   * @brief   Tolerance (relative) of measurement.
+   */
+  float tolerance;
+
+  /**
+   * @brief   Timeout delay for certain tests.
+   */
+  apalTime_t timeout;
+} ut_ina219data_t;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+  aos_utresult_t utAlldIna219Func(BaseSequentialStream* stream, aos_unittest_t* ut);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* (AMIROOS_CFG_TESTS_ENABLE == true) && defined(AMIROLLD_CFG_USE_INA219) */
+
+#endif /* _AMIROOS_UT_INA219_LLD_HPP_ */
diff --git a/unittests/periphery-lld/inc/ut_alld_l3g4200d.h b/unittests/periphery-lld/inc/ut_alld_l3g4200d.h
new file mode 100644
index 0000000..ff55790
--- /dev/null
+++ b/unittests/periphery-lld/inc/ut_alld_l3g4200d.h
@@ -0,0 +1,65 @@
+/*
+AMiRo-OS is an operating system designed for the Autonomous Mini Robot (AMiRo) platform.
+Copyright (C) 2016..2018  Thomas Schöpping et al.
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _AMIROOS_UT_L3G4200D_LLD_HPP_
+#define _AMIROOS_UT_L3G4200D_LLD_HPP_
+
+#include <aos_unittest.h>
+#include <amiro-lld.h>
+
+#if ((AMIROOS_CFG_TESTS_ENABLE == true) && defined(AMIROLLD_CFG_USE_L3G4200D)) || defined(__DOXYGEN__)
+
+#include <alld_l3g4200d.h>
+
+/**
+ * @brief   Custom data structure for the unit test.
+ */
+typedef struct {
+  /**
+   * @brief   L3G4200D driver to use.
+   */
+  L3G4200DDriver *l3gd;
+
+  /**
+   * @brief   SPI configuratoin.
+   */
+  SPIConfig *spiconf;
+
+  /**
+   * @brief   Event source for certain tests.
+   */
+  event_source_t *src;
+
+  /**
+   * @brief   Event flags to watch.
+   */
+  eventflags_t evtflags;
+} ut_l3g4200ddata_t;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+  aos_utresult_t utAlldL3g4200dFunc(BaseSequentialStream* stream, aos_unittest_t* ut);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* (AMIROOS_CFG_TESTS_ENABLE == true) && defined(AMIROLLD_CFG_USE_L3G4200D) */
+
+#endif /* _AMIROOS_UT_L3G4200D_LLD_HPP_ */
+
diff --git a/unittests/periphery-lld/inc/ut_alld_led.h b/unittests/periphery-lld/inc/ut_alld_led.h
new file mode 100644
index 0000000..d8a3e21
--- /dev/null
+++ b/unittests/periphery-lld/inc/ut_alld_led.h
@@ -0,0 +1,39 @@
+/*
+AMiRo-OS is an operating system designed for the Autonomous Mini Robot (AMiRo) platform.
+Copyright (C) 2016..2018  Thomas Schöpping et al.
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _AMIROOS_UT_ALLD_LED_H_
+#define _AMIROOS_UT_ALLD_LED_H_
+
+#include <aos_unittest.h>
+#include <amiro-lld.h>
+
+#if ((AMIROOS_CFG_TESTS_ENABLE == true) && defined(AMIROLLD_CFG_USE_LED)) || defined(__DOXYGEN__)
+
+#include <alld_led.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+  aos_utresult_t utAlldLedFunc(BaseSequentialStream* stream, aos_unittest_t* ut);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* (AMIROOS_CFG_TESTS_ENABLE == true) && defined(AMIROLLD_CFG_USE_LED) */
+
+#endif /* _AMIROOS_UT_ALLD_LED_H_ */
diff --git a/unittests/periphery-lld/inc/ut_alld_lis331dlh.h b/unittests/periphery-lld/inc/ut_alld_lis331dlh.h
new file mode 100644
index 0000000..41152f4
--- /dev/null
+++ b/unittests/periphery-lld/inc/ut_alld_lis331dlh.h
@@ -0,0 +1,65 @@
+/*
+AMiRo-OS is an operating system designed for the Autonomous Mini Robot (AMiRo) platform.
+Copyright (C) 2016..2018  Thomas Schöpping et al.
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _AMIROOS_UT_LIS331DLH_LLD_HPP_
+#define _AMIROOS_UT_LIS331DLH_LLD_HPP_
+
+#include <aos_unittest.h>
+#include <amiro-lld.h>
+
+#if ((AMIROOS_CFG_TESTS_ENABLE == true) && defined(AMIROLLD_CFG_USE_LIS331DLH)) || defined(__DOXYGEN__)
+
+#include <alld_lis331dlh.h>
+
+/**
+ * @brief   Custom data structure for the unit test.
+ */
+typedef struct {
+  /**
+   * @brief   Accelerometer driver to use.
+   */
+  LIS331DLHDriver *lisd;
+
+  /**
+   * @brief   SPI configuratoin.
+   */
+  SPIConfig *spiconf;
+
+  /**
+   * @brief   Event source for certain tests.
+   */
+  event_source_t *src;
+
+  /**
+   * @brief   Event flags to watch.
+   */
+  eventflags_t evtflags;
+} ut_lis331dlhdata_t;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+  aos_utresult_t utAlldLis331dlhFunc(BaseSequentialStream* stream, aos_unittest_t* ut);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* (AMIROOS_CFG_TESTS_ENABLE == true) && defined(AMIROLLD_CFG_USE_LIS331DLH) */
+
+#endif /* _AMIROOS_UT_LIS331DLH_LLD_HPP_ */
+
diff --git a/unittests/periphery-lld/inc/ut_alld_ltc4412.h b/unittests/periphery-lld/inc/ut_alld_ltc4412.h
new file mode 100644
index 0000000..9a68766
--- /dev/null
+++ b/unittests/periphery-lld/inc/ut_alld_ltc4412.h
@@ -0,0 +1,39 @@
+/*
+AMiRo-OS is an operating system designed for the Autonomous Mini Robot (AMiRo) platform.
+Copyright (C) 2016..2018  Thomas Schöpping et al.
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _AMIROOS_UT_ALLD_LTC4412_H_
+#define _AMIROOS_UT_ALLD_LTC4412_H_
+
+#include <aos_unittest.h>
+#include <amiro-lld.h>
+
+#if ((AMIROOS_CFG_TESTS_ENABLE == true) && defined(AMIROLLD_CFG_USE_LTC4412)) || defined(__DOXYGEN__)
+
+#include <alld_ltc4412.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+  aos_utresult_t utAlldLtc4412Func(BaseSequentialStream* stream, aos_unittest_t* ut);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* (AMIROOS_CFG_TESTS_ENABLE == true) && defined(AMIROLLD_CFG_USE_LTC4412) */
+
+#endif /* _AMIROOS_UT_ALLD_LTC4412_H_ */
diff --git a/unittests/periphery-lld/inc/ut_alld_mpr121.h b/unittests/periphery-lld/inc/ut_alld_mpr121.h
new file mode 100644
index 0000000..019d521
--- /dev/null
+++ b/unittests/periphery-lld/inc/ut_alld_mpr121.h
@@ -0,0 +1,64 @@
+/*
+AMiRo-OS is an operating system designed for the Autonomous Mini Robot (AMiRo) platform.
+Copyright (C) 2016..2018  Thomas Schöpping et al.
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _AMIROOS_UT_ALLD_MPR121_H_
+#define _AMIROOS_UT_ALLD_MPR121_H_
+
+#include <aos_unittest.h>
+#include <amiro-lld.h>
+
+#if ((AMIROOS_CFG_TESTS_ENABLE == true) && defined(AMIROLLD_CFG_USE_MPR121)) || defined(__DOXYGEN__)
+
+#include <alld_mpr121.h>
+
+/**
+ * @brief   Custom data structure for the unit test.
+ */
+typedef struct {
+  /**
+   * @brief   Pointer to the MPR121 driver to use.
+   */
+  MPR121Driver* mprd;
+
+  /**
+   * @brief   Timeout value (in us).
+   */
+  apalTime_t timeout;
+
+  /**
+   * @brief   Event source to listen to.
+   */
+  event_source_t* evtsource;
+
+  /**
+   * @brief   Event flags to watch.
+   */
+  eventflags_t evtflags;
+} ut_mpr121data_t;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+  aos_utresult_t utAlldMpr121Func(BaseSequentialStream* stream, aos_unittest_t* ut);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* (AMIROOS_CFG_TESTS_ENABLE == true) && defined(AMIROLLD_CFG_USE_MPR121) */
+
+#endif /* _AMIROOS_UT_ALLD_MPR121_H_ */
diff --git a/unittests/periphery-lld/inc/ut_alld_pca9544a.h b/unittests/periphery-lld/inc/ut_alld_pca9544a.h
new file mode 100644
index 0000000..08e153c
--- /dev/null
+++ b/unittests/periphery-lld/inc/ut_alld_pca9544a.h
@@ -0,0 +1,56 @@
+/*
+AMiRo-OS is an operating system designed for the Autonomous Mini Robot (AMiRo) platform.
+Copyright (C) 2016..2018  Thomas Schöpping et al.
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _AMIROOS_UT_ALLD_PCA9544A_H_
+#define _AMIROOS_UT_ALLD_PCA9544A_H_
+
+#include <aos_unittest.h>
+#include <amiro-lld.h>
+
+#if ((AMIROOS_CFG_TESTS_ENABLE == true) && defined(AMIROLLD_CFG_USE_PCA9544A)) || defined(__DOXYGEN__)
+
+#include <alld_pca9544a.h>
+
+/**
+ * @brief   Custom data structure for the unit test.
+ */
+typedef struct {
+  /**
+   * @brief   Pointer to the driver to use.
+   */
+  PCA9544ADriver *driver;
+
+  /**
+   * @brief   Timeout for bus communication.
+   */
+  apalTime_t timeout;
+} ut_pca9544adata_t;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+  aos_utresult_t utAlldPca9544aFunc(BaseSequentialStream* stream, aos_unittest_t* ut);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* (AMIROOS_CFG_TESTS_ENABLE == true) && defined(AMIROLLD_CFG_USE_PCA9544A) */
+
+#endif /* _AMIROOS_UT_ALLD_PCA9544A_H_ */
+
+
diff --git a/unittests/periphery-lld/inc/ut_alld_pklcs1212e4001.h b/unittests/periphery-lld/inc/ut_alld_pklcs1212e4001.h
new file mode 100644
index 0000000..9fc35c9
--- /dev/null
+++ b/unittests/periphery-lld/inc/ut_alld_pklcs1212e4001.h
@@ -0,0 +1,54 @@
+/*
+AMiRo-OS is an operating system designed for the Autonomous Mini Robot (AMiRo) platform.
+Copyright (C) 2016..2018  Thomas Schöpping et al.
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _AMIROOS_UT_ALLD_PKLCS1212E4001_H_
+#define _AMIROOS_UT_ALLD_PKLCS1212E4001_H_
+
+#include <aos_unittest.h>
+#include <amiro-lld.h>
+
+#if ((AMIROOS_CFG_TESTS_ENABLE == true) && defined(AMIROLLD_CFG_USE_PKLCS1212E4001)) || defined(__DOXYGEN__)
+
+#include <alld_pklcs1212e4001.h>
+
+/**
+ * @brief   Custom data structure for the unit test.
+ */
+typedef struct {
+  /**
+   * @brief   Pointer to the PWM driver.
+   */
+  apalPWMDriver_t* driver;
+
+  /**
+   * @brief   PWM channel to use.
+   */
+  apalPWMchannel_t channel;
+} ut_pklcs1212e4001_t;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+  aos_utresult_t utAlldPklcs1212e4001Func(BaseSequentialStream* stream, aos_unittest_t* ut);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* (AMIROOS_CFG_TESTS_ENABLE == true) && defined(AMIROLLD_CFG_USE_PKLCS1212E4001) */
+
+#endif /* _AMIROOS_UT_ALLD_PKLCS1212E4001_H_ */
diff --git a/unittests/periphery-lld/inc/ut_alld_tlc5947.h b/unittests/periphery-lld/inc/ut_alld_tlc5947.h
new file mode 100644
index 0000000..5c31bdc
--- /dev/null
+++ b/unittests/periphery-lld/inc/ut_alld_tlc5947.h
@@ -0,0 +1,39 @@
+/*
+AMiRo-OS is an operating system designed for the Autonomous Mini Robot (AMiRo) platform.
+Copyright (C) 2016..2018  Thomas Schöpping et al.
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _AMIROOS_UT_ALLD_TLC5947_H_
+#define _AMIROOS_UT_ALLD_TLC5947_H_
+
+#include <aos_unittest.h>
+#include <amiro-lld.h>
+
+#if ((AMIROOS_CFG_TESTS_ENABLE == true) && defined(AMIROLLD_CFG_USE_TLC5947)) || defined(__DOXYGEN__)
+
+#include <alld_tlc5947.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+  aos_utresult_t utAlldTlc5947Func(BaseSequentialStream* stream, aos_unittest_t* ut);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* (AMIROOS_CFG_TESTS_ENABLE == true) && defined(AMIROLLD_CFG_USE_TLC5947) */
+
+#endif /* _AMIROOS_UT_ALLD_TLC5947_H_ */
diff --git a/unittests/periphery-lld/inc/ut_alld_tps2051bdbv.h b/unittests/periphery-lld/inc/ut_alld_tps2051bdbv.h
new file mode 100644
index 0000000..10e1e38
--- /dev/null
+++ b/unittests/periphery-lld/inc/ut_alld_tps2051bdbv.h
@@ -0,0 +1,39 @@
+/*
+AMiRo-OS is an operating system designed for the Autonomous Mini Robot (AMiRo) platform.
+Copyright (C) 2016..2018  Thomas Schöpping et al.
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _AMIROOS_UT_ALLD_TPS2051BDBV_H_
+#define _AMIROOS_UT_ALLD_TPS2051BDBV_H_
+
+#include <aos_unittest.h>
+#include <amiro-lld.h>
+
+#if ((AMIROOS_CFG_TESTS_ENABLE == true) && defined(AMIROLLD_CFG_USE_TPS2051BDBV)) || defined(__DOXYGEN__)
+
+#include <alld_tps2051bdbv.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+  aos_utresult_t utAlldTps2051bdbvFunc(BaseSequentialStream* stream, aos_unittest_t* ut);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* (AMIROOS_CFG_TESTS_ENABLE == true) && defined(AMIROLLD_CFG_USE_TPS2051BDBV) */
+
+#endif /* _AMIROOS_UT_ALLD_TPS2051BDBV_H_ */
diff --git a/unittests/periphery-lld/inc/ut_alld_tps62113.h b/unittests/periphery-lld/inc/ut_alld_tps62113.h
new file mode 100644
index 0000000..9915ea4
--- /dev/null
+++ b/unittests/periphery-lld/inc/ut_alld_tps62113.h
@@ -0,0 +1,40 @@
+/*
+AMiRo-OS is an operating system designed for the Autonomous Mini Robot (AMiRo) platform.
+Copyright (C) 2016..2018  Thomas Schöpping et al.
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _AMIROOS_UT_ALLD_TPS62113_H_
+#define _AMIROOS_UT_ALLD_TPS62113_H_
+
+#include <aos_unittest.h>
+#include <amiro-lld.h>
+
+#if ((AMIROOS_CFG_TESTS_ENABLE == true) && defined(AMIROLLD_CFG_USE_TPS62113)) || defined(__DOXYGEN__)
+
+#include <alld_tps62113.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+  aos_utresult_t utAlldTps62113Func(BaseSequentialStream* stream, aos_unittest_t* ut);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* (AMIROOS_CFG_TESTS_ENABLE == true) && defined(AMIROLLD_CFG_USE_TPS62113) */
+
+#endif /* _AMIROOS_UT_ALLD_TPS62113_H_ */
+
diff --git a/unittests/periphery-lld/inc/ut_alld_tps62113_ina219.h b/unittests/periphery-lld/inc/ut_alld_tps62113_ina219.h
new file mode 100644
index 0000000..034fd82
--- /dev/null
+++ b/unittests/periphery-lld/inc/ut_alld_tps62113_ina219.h
@@ -0,0 +1,60 @@
+/*
+AMiRo-OS is an operating system designed for the Autonomous Mini Robot (AMiRo) platform.
+Copyright (C) 2016..2018  Thomas Schöpping et al.
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _AMIROOS_UT_ALLD_TPS62113_INA219_H_
+#define _AMIROOS_UT_ALLD_TPS62113_INA219_H_
+
+#include <aos_unittest.h>
+#include <amiro-lld.h>
+
+#if ((AMIROOS_CFG_TESTS_ENABLE == true) && defined(AMIROLLD_CFG_USE_TPS62113) && defined(AMIROLLD_CFG_USE_INA219)) || defined(__DOXYGEN__)
+
+#include <alld_tps62113.h>
+#include <alld_ina219.h>
+
+/**
+ * @brief   Custom data structure for the unit test.
+ */
+typedef struct {
+  /**
+   * @brief   TPS62113 driver to use.
+   */
+  TPS62113Driver* tps62113;
+
+  /**
+   * @brief   INA219 driver to use.
+   */
+  INA219Driver* ina219;
+
+  /**
+   * @brief   Timeout value (in us).
+   */
+  apalTime_t timeout;
+} ut_tps62113ina219data_t;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+  aos_utresult_t utAlldTps62113Ina219Func(BaseSequentialStream* stream, aos_unittest_t* ut);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* (AMIROOS_CFG_TESTS_ENABLE == true) && defined(AMIROLLD_CFG_USE_TPS62113) && defined(AMIROLLD_CFG_USE_INA219) */
+
+#endif /* _AMIROOS_UT_ALLD_TPS62113_INA219_H_ */
diff --git a/unittests/periphery-lld/inc/ut_alld_vcnl4020.h b/unittests/periphery-lld/inc/ut_alld_vcnl4020.h
new file mode 100644
index 0000000..4c0c37f
--- /dev/null
+++ b/unittests/periphery-lld/inc/ut_alld_vcnl4020.h
@@ -0,0 +1,66 @@
+/*
+AMiRo-OS is an operating system designed for the Autonomous Mini Robot (AMiRo) platform.
+Copyright (C) 2016..2018  Thomas Schöpping et al.
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _AMIROOS_UT_VCNL4020_LLD_HPP_
+#define _AMIROOS_UT_VCNL4020_LLD_HPP_
+
+#include <aos_unittest.h>
+#include <amiro-lld.h>
+
+#if ((AMIROOS_CFG_TESTS_ENABLE == true) && defined(AMIROLLD_CFG_USE_VCNL4020)) || defined(__DOXYGEN__)
+
+#include <alld_vcnl4020.h>
+
+/**
+ * @brief   Custom data structure for the unit test.
+ */
+typedef struct {
+  /**
+   * @brief   VCNL4020 driver to use.
+   */
+  VCNL4020Driver *vcnld;
+
+  /**
+   * @brief   Timeout for certain tests.
+   */
+  apalTime_t timeout;
+
+  /**
+   * @brief   Event source to listen to.
+   */
+  event_source_t* evtsource;
+
+  /**
+   * @brief   Event flags to watch.
+   */
+  eventflags_t evtflags;
+} ut_vcnl4020data_t;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+  aos_utresult_t utAlldVcnl4020Func(BaseSequentialStream* stream, aos_unittest_t* ut);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* (AMIROOS_CFG_TESTS_ENABLE == true) && defined(AMIROLLD_CFG_USE_VCNL4020) */
+
+#endif /* _AMIROOS_UT_VCNL4020_LLD_HPP_ */
+
+
diff --git a/unittests/periphery-lld/module.h b/unittests/periphery-lld/module.h
new file mode 100755
index 0000000..d6ba3e9
--- /dev/null
+++ b/unittests/periphery-lld/module.h
@@ -0,0 +1,397 @@
+/*
+AMiRo-OS is an operating system designed for the Autonomous Mini Robot (AMiRo) platform.
+Copyright (C) 2016..2018  Thomas Schöpping et al.
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _AMIROOS_MODULE_H_
+#define _AMIROOS_MODULE_H_
+
+/*===========================================================================*/
+/**
+ * @name Module specific functions
+ * @{
+ */
+/*===========================================================================*/
+
+static void _alld_dw1000_callback(void* args);
+
+/** @} */
+
+/*===========================================================================*/
+/**
+ * @name ChibiOS/HAL configuration
+ * @{
+ */
+/*===========================================================================*/
+#include <hal.h>
+
+/**
+ * @brief   CAN driver to use.
+ */
+#define MODULE_HAL_CAN                          CAND1
+
+/**
+ * @brief   Configuration for the CAN driver.
+ */
+extern CANConfig moduleHalCanConfig;
+
+/**
+ * @brief   I2C driver to access the EEPROM.
+ */
+#define MODULE_HAL_I2C_EEPROM                   I2CD2
+
+/**
+ * @brief   Configuration for the EEPROM I2C driver.
+ */
+extern I2CConfig moduleHalI2cEepromConfig;
+
+/**
+ * @brief   Serial driver of the programmer interface.
+ */
+#define MODULE_HAL_PROGIF                       SD1
+
+/**
+ * @brief   Configuration for the programmer serial interface driver.
+ */
+extern SerialConfig moduleHalProgIfConfig;
+
+/**
+ * @brief   SPI interface driver for the motion sensors (gyroscope and accelerometer).
+ */
+#define MODULE_HAL_SPI_LIGHT                    SPID1
+
+/**
+ * @brief   SPI interface driver for UWB Module.
+ */
+#define MODULE_HAL_SPI_UWB                      SPID2
+
+/**
+ * @brief   Configuration for the SPI interface driver to communicate with the LED driver.
+ */
+extern SPIConfig moduleHalSpiLightConfig;
+
+/**
+ * @brief   Configuration for the SPI interface driver to communicate with the LED driver.
+ */
+extern SPIConfig moduleHalSpiUWBConfig;
+
+/**
+ * @brief   Real-Time Clock driver.
+ */
+#define MODULE_HAL_RTC                          RTCD1
+
+/** @} */
+
+/*===========================================================================*/
+/**
+ * @name GPIO definitions
+ * @{
+ */
+/*===========================================================================*/
+#include <amiro-lld.h>
+
+/**
+ * @brief   LIGHT_BANK output signal GPIO.
+ */
+extern apalControlGpio_t moduleGpioLightBlank;
+
+/**
+ * @brief   LASER_EN output signal GPIO.
+ */
+extern apalControlGpio_t moduleGpioLaserEn;
+
+/**
+ * @brief   LASER_OC input signal GPIO.
+ */
+extern apalControlGpio_t moduleGpioLaserOc;
+
+/**
+ * @brief   SYS_UART_DN bidirectional signal GPIO.
+ */
+extern apalControlGpio_t moduleGpioSysUartDn;
+
+/**
+ * @brief   WL_GDO2 input signal GPIO.
+ */
+extern apalControlGpio_t moduleGpioWlGdo2;
+
+/**
+ * @brief   WL_GDO0 input signal GPIO.
+ */
+extern apalControlGpio_t moduleGpioWlGdo0;
+
+/**
+ * @brief   LIGHT_XLAT output signal GPIO.
+ */
+extern apalControlGpio_t moduleGpioLightXlat;
+
+/**
+ * @brief   SYS_PD bidirectional signal GPIO.
+ */
+extern apalControlGpio_t moduleGpioSysPd;
+
+/**
+ * @brief   SYS_SYNC bidirectional signal GPIO.
+ */
+extern apalControlGpio_t moduleGpioSysSync;
+
+/** @} */
+
+/*===========================================================================*/
+/**
+ * @name AMiRo-OS core configurations
+ * @{
+ */
+/*===========================================================================*/
+
+/**
+ * @brief   Event flag to be set on a LASER_OC interrupt.
+ */
+#define MODULE_OS_IOEVENTFLAGS_LASEROC          ((eventflags_t)1 << GPIOB_LASER_OC_N)
+
+/**
+ * @brief   Event flag to be set on a SYS_UART_DN interrupt.
+ */
+#define MODULE_OS_IOEVENTFLAGS_SYSUARTDN        ((eventflags_t)1 << GPIOB_SYS_UART_DN)
+
+/**
+ * @brief   Event flag to be set on a WL_GDO2 interrupt.
+ */
+#define MODULE_OS_IOEVENTFLAGS_WLGDO2           ((eventflags_t)1 << GPIOB_WL_GDO2)
+
+/**
+ * @brief   Event flag to be set on a WL_GDO0 interrupt.
+ */
+#define MODULE_OS_IOEVENTFLAGS_WLGDO0           ((eventflags_t)1 << GPIOB_WL_GDO0)
+
+/**
+ * @brief   Event flag to be set on a SYS_PD interrupt.
+ */
+#define MODULE_OS_IOEVENTFLAGS_SYSPD            ((eventflags_t)1 << GPIOC_SYS_PD_N)
+
+/**
+ * @brief   Event flag to be set on a SYS_SYNC interrupt.
+ */
+#define MODULE_OS_IOEVENTFLAGS_SYSSYNC          ((eventflags_t)1 << GPIOD_SYS_INT_N)
+
+#if (AMIROOS_CFG_SHELL_ENABLE == true) || defined(__DOXYGEN__)
+/**
+ * @brief   Shell prompt text.
+ */
+extern const char* moduleShellPrompt;
+#endif
+
+
+
+
+/**
+ * @brief   Interrupt initialization macro.
+ * @note    SSSP related interrupt signals are already initialized in 'aos_system.c'.
+ */
+#define MODULE_INIT_INTERRUPTS() {                                            \
+  /* LASER_OC */                                                              \
+  palSetPadCallback(moduleGpioLaserOc.gpio->port, moduleGpioLaserOc.gpio->pad, _intCallback, &moduleGpioLaserOc.gpio->pad); \
+  palEnablePadEvent(moduleGpioLaserOc.gpio->port, moduleGpioLaserOc.gpio->pad, APAL2CH_EDGE(moduleGpioLaserOc.meta.edge));  \
+  /* WL_GDO2 */                                                               \
+  palSetPadCallback(moduleGpioWlGdo2.gpio->port, moduleGpioWlGdo2.gpio->pad, _alld_dw1000_callback, &moduleGpioWlGdo2.gpio->pad);  \
+  palEnablePadEvent(moduleGpioWlGdo2.gpio->port, moduleGpioWlGdo2.gpio->pad, APAL2CH_EDGE(moduleGpioWlGdo2.meta.edge));   \
+  /* WL_GDO0 */                                                               \
+  palSetPadCallback(moduleGpioWlGdo0.gpio->port, moduleGpioWlGdo0.gpio->pad, _alld_dw1000_callback, &moduleGpioWlGdo0.gpio->pad);  \
+  /*palEnablePadEvent(moduleGpioWlGdo0.gpio->port, moduleGpioWlGdo0.gpio->pad, APAL2CH_EDGE(moduleGpioWlGdo0.meta.edge)); // this is broken for some reason*/   \
+}
+
+/**
+ * @brief   Unit test initialization hook.
+ */
+#define MODULE_INIT_TESTS() {                                                 \
+  /* add unit-test shell commands */                                          \
+  aosShellAddCommand(&aos.shell, &moduleUtAlldAt24c01bn.shellcmd);            \
+  aosShellAddCommand(&aos.shell, &moduleUtAlldTlc5947.shellcmd);              \
+  aosShellAddCommand(&aos.shell, &moduleUtAlldTps2051bdbv.shellcmd);          \
+  aosShellAddCommand(&aos.shell, &moduleUtAlldDw1000.shellcmd);                \
+}
+
+/**
+ * @brief   Periphery communication interfaces initialization hook.
+ */
+#define MODULE_INIT_PERIPHERY_COMM() {                                        \
+  /* serial driver */                                                         \
+  sdStart(&MODULE_HAL_PROGIF, &moduleHalProgIfConfig);                        \
+  /* I2C */                                                                   \
+  moduleHalI2cEepromConfig.clock_speed = (AT24C01BN_LLD_I2C_MAXFREQUENCY < moduleHalI2cEepromConfig.clock_speed) ? AT24C01BN_LLD_I2C_MAXFREQUENCY : moduleHalI2cEepromConfig.clock_speed; \
+  moduleHalI2cEepromConfig.duty_cycle = (moduleHalI2cEepromConfig.clock_speed <= 100000) ? STD_DUTY_CYCLE : FAST_DUTY_CYCLE_2;  \
+  i2cStart(&MODULE_HAL_I2C_EEPROM, &moduleHalI2cEepromConfig);                \
+  /* SPI */                                                                   \
+  spiStart(&MODULE_HAL_SPI_LIGHT, &moduleHalSpiLightConfig);                  \
+  spiStart(&MODULE_HAL_SPI_UWB, &moduleHalSpiUWBConfig);                      \
+}
+
+/**
+ * @brief   Periphery communication interface deinitialization hook.
+ */
+#define MODULE_SHUTDOWN_PERIPHERY_COMM() {                                    \
+  /* SPI */                                                                   \
+  spiStop(&MODULE_HAL_SPI_LIGHT);                                             \
+  spiStop(&MODULE_HAL_SPI_UWB);                                               \
+  /* I2C */                                                                   \
+  i2cStop(&MODULE_HAL_I2C_EEPROM);                                            \
+  /* don't stop the serial driver so messages can still be printed */         \
+}
+
+/** @} */
+
+/*===========================================================================*/
+/**
+ * @name Startup Shutdown Synchronization Protocol (SSSP)
+ * @{
+ */
+/*===========================================================================*/
+
+/**
+ * @brief   PD signal GPIO.
+ */
+#define moduleSsspGpioPd                        moduleGpioSysPd
+
+/**
+ * @brief   SYNC signal GPIO.
+ */
+#define moduleSsspGpioSync                      moduleGpioSysSync
+
+/**
+ * @brief   DN signal GPIO.
+ */
+#define moduleSsspGpioDn                        moduleGpioSysUartDn
+
+/**
+ * @brief   Event flags for PD signal events.
+ */
+#define MODULE_SSSP_EVENTFLAGS_PD               MODULE_OS_IOEVENTFLAGS_SYSPD
+
+/**
+ * @brief   Event flags for SYNC signal events.
+ */
+#define MODULE_SSSP_EVENTFLAGS_SYNC             MODULE_OS_IOEVENTFLAGS_SYSSYNC
+
+/**
+ * @brief   Event flags for DN signal events.
+ */
+#define MODULE_SSSP_EVENTFLAGS_DN               MODULE_OS_IOEVENTFLAGS_SYSUARTDN
+
+/** @} */
+
+/*===========================================================================*/
+/**
+ * @name Low-level drivers
+ * @{
+ */
+/*===========================================================================*/
+#include <alld_at24c01bn-sh-b.h>
+#include <alld_tlc5947.h>
+#include <alld_tps2051bdbv.h>
+#include <alld_dw1000.h>
+
+/**
+ * @brief   EEPROM driver.
+ */
+extern AT24C01BNDriver moduleLldEeprom;
+
+/**
+ * @brief   LED PWM driver.
+ */
+extern TLC5947Driver moduleLldLedPwm;
+
+/**
+ * @brief   Power switch driver for the laser supply power.
+ */
+extern TPS2051BDriver moduleLldPowerSwitchLaser;
+
+/**
+ * @brief   DW1000 driver for UWB.
+ */
+extern DW1000Driver moduleLldDW1000;
+
+
+
+
+/*! ------------------------------------------------------------------------------------------------------------------
+ * Function: _alld_dw1000_callback()
+ *
+ * Low level abstract function to handle 'reset' adn 'irq' interrupt from DW1000
+ * Expects arg to be of iopadid_t* type, used to distinguish between irq or reset signal
+ */
+static void _alld_dw1000_callback(void* args) {
+
+    aosDbgCheck(true);
+
+
+    chSysLockFromISR();
+    if ((*(iopadid_t*) args) == moduleLldDW1000.gpio_reset->pad)
+    {
+        // dw1000 external indicate reset done
+    }
+    else if ((*(iopadid_t*) args) == moduleLldDW1000.gpio_exti->pad)
+    {
+        dwt_isr();
+    }
+    else
+    {
+        return;
+    }
+    chSysUnlockFromISR();
+
+}
+
+
+/** @} */
+
+/*===========================================================================*/
+/**
+ * @name Unit tests (UT)
+ * @{
+ */
+/*===========================================================================*/
+#if (AMIROOS_CFG_TESTS_ENABLE == true) || defined(__DOXYGEN__)
+#include <ut_alld_at24c01bn-sh-b.h>
+#include <ut_alld_tlc5947.h>
+#include <ut_alld_tps2051bdbv.h>
+#include <ut_alld_dw1000.h>
+
+/**
+ * @brief   EEPROM unit test object.
+ */
+extern aos_unittest_t moduleUtAlldAt24c01bn;
+
+/**
+ * @brief   LED PWM driver unit test object.
+ */
+extern aos_unittest_t moduleUtAlldTlc5947;
+
+/**
+ * @brief   Current-limited power switch (Laser output)
+ */
+extern aos_unittest_t moduleUtAlldTps2051bdbv;
+
+/**
+ * @brief   DW1000 unit test object.
+ */
+extern aos_unittest_t moduleUtAlldDw1000;
+
+
+#endif /* AMIROOS_CFG_TESTS_ENABLE == true */
+
+/** @} */
+
+#endif /* _AMIROOS_MODULE_H_ */
diff --git a/unittests/periphery-lld/src/ut_alld_a3906.c b/unittests/periphery-lld/src/ut_alld_a3906.c
new file mode 100644
index 0000000..f4bbe3f
--- /dev/null
+++ b/unittests/periphery-lld/src/ut_alld_a3906.c
@@ -0,0 +1,259 @@
+/*
+AMiRo-OS is an operating system designed for the Autonomous Mini Robot (AMiRo) platform.
+Copyright (C) 2016..2018  Thomas Schöpping et al.
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <ut_alld_a3906.h>
+
+#if ((AMIROOS_CFG_TESTS_ENABLE == true) && defined(AMIROLLD_CFG_USE_A3906)) || defined(__DOXYGEN__)
+
+#include <aos_debug.h>
+#include <chprintf.h>
+#include <alld_a3906.h>
+#include <aos_thread.h>
+#include <stdlib.h>
+#include <math.h>
+
+/**
+ * @brief   Interval to poll QEI in certain tests.
+ */
+#define QEI_POLL_INTERVAL_MS          100
+
+/**
+ * @brief   Threshold for QEI differences.
+ * @details Differences smaller tahn or equal to this value are neglected (interpreted as zero).
+ */
+#define QEI_DIFF_THRESHOLD            4
+
+/**
+ * @brief   Enumerator to distinguish between left and right wheel.
+ */
+typedef enum {
+  WHEEL_LEFT    = 0,  /**< left wheel identifier */
+  WHEEL_RIGHT   = 1,  /**< right wheel identifier */
+} wheel_t;
+
+/**
+ * @brief   Enumerator to distinguish directions.
+ */
+typedef enum {
+  DIRECTION_FORWARD   = 0,  /**< forward direction identifier */
+  DIRECTION_BACKWARD  = 1,  /**< backward direction identifier */
+} direction_t;
+
+/**
+ * @brief   helper function to test each wheel and direction separately.
+ *
+ * @param[in] stream      Stream for input/output.
+ * @param[in] data        Unit test meta data.
+ * @param[in] wheel       Wheel to test.
+ * @param[in] direction   Direction to test.
+ * @param[in,out] result  Result variable to modify.
+ */
+void _wheelDirectionTest(BaseSequentialStream* stream, ut_a3906data_t* data, wheel_t wheel, direction_t direction, aos_utresult_t* result)
+{
+  // local variables
+  uint32_t status;
+  bool qei_valid;
+  apalQEICount_t qei_count[2];
+  apalQEIDirection_t qei_direction;
+  uint32_t timeout_counter;
+
+  chprintf(stream, "%s wheel %s...\n", (wheel == WHEEL_LEFT) ? "left" : "right", (direction == DIRECTION_FORWARD) ? "forward" : "backward");
+  qei_valid = false;
+  status = apalQEIGetPosition((wheel == WHEEL_LEFT) ? data->qei.left : data->qei.right, &qei_count[0]);
+  // increase PWM incrementally and read QEI data
+  for (apalPWMwidth_t pwm_width = APAL_PWM_WIDTH_MIN; pwm_width < APAL_PWM_WIDTH_MAX; ++pwm_width) {
+    status |= a3906_lld_set_pwm(data->pwm.driver, (wheel == WHEEL_LEFT) ?
+                                  ((direction == DIRECTION_FORWARD) ? data->pwm.channel.left_forward : data->pwm.channel.left_backward) :
+                                  ((direction == DIRECTION_FORWARD) ? data->pwm.channel.right_forward : data->pwm.channel.right_backward),
+                                pwm_width);
+    status |= apalQEIGetPosition((wheel == WHEEL_LEFT) ? data->qei.left : data->qei.right, &qei_count[1]);
+    qei_valid = qei_valid || (qei_count[0] != qei_count[1]);
+    aosThdUSleep(5 * MICROSECONDS_PER_SECOND / (APAL_PWM_WIDTH_MAX - APAL_PWM_WIDTH_MIN));
+    qei_count[0] = qei_count[1];
+  }
+  status |= qei_valid ? 0x00 : 0x10;
+  status |= apalQEIGetDirection((wheel == WHEEL_LEFT) ? data->qei.left : data->qei.right, &qei_direction);
+  status |= (qei_direction == ((direction == DIRECTION_FORWARD) ? APAL_QEI_DIRECTION_UP : APAL_QEI_DIRECTION_DOWN)) ? 0x00 : 0x20;
+
+  // let the wheel spin free until it stops
+  status |= a3906_lld_set_pwm(data->pwm.driver, (wheel == WHEEL_LEFT) ?
+                                ((direction == DIRECTION_FORWARD) ? data->pwm.channel.left_forward : data->pwm.channel.left_backward) :
+                                ((direction == DIRECTION_FORWARD) ? data->pwm.channel.right_forward : data->pwm.channel.right_backward),
+                              0);
+  qei_count[0] = 0;
+  qei_count[1] = 0;
+  timeout_counter = 0;
+  do {
+    status |= apalQEIGetPosition((wheel == WHEEL_LEFT) ? data->qei.left : data->qei.right, &qei_count[0]);
+    aosThdMSleep(1);
+    status |= apalQEIGetPosition((wheel == WHEEL_LEFT) ? data->qei.left : data->qei.right, &qei_count[1]);
+    ++timeout_counter;
+  } while ((qei_count[0] != qei_count[1]) && (timeout_counter * MICROSECONDS_PER_MILLISECOND <= data->timeout));
+  status |= (timeout_counter * MICROSECONDS_PER_MILLISECOND > data->timeout) ? APAL_STATUS_TIMEOUT : 0x00;
+
+  // report result
+  if (status == APAL_STATUS_SUCCESS) {
+    aosUtPassed(stream, result);
+  } else {
+    aosUtFailedMsg(stream, result, "0x%08X\n", status);
+  }
+
+  return;
+}
+
+/**
+ * @brief   A3905 unit test function.
+ *
+ * @param[in] stream  Stream for input/output.
+ * @param[in] ut      Unit test object.
+ *
+ * @return            Unit test result value.
+ */
+aos_utresult_t utAlldA3906Func(BaseSequentialStream* stream, aos_unittest_t* ut)
+{
+  aosDbgCheck((ut->data != NULL) &&
+              (((ut_a3906data_t*)ut->data)->driver != NULL) &&
+              (((ut_a3906data_t*)ut->data)->pwm.driver != NULL) &&
+              (((ut_a3906data_t*)ut->data)->qei.left != NULL) &&
+              (((ut_a3906data_t*)ut->data)->qei.right != NULL));
+
+
+
+  // local variables
+  aos_utresult_t result = {0, 0};
+  uint32_t status = 0;
+  a3906_lld_power_t power_state;
+  apalQEICount_t qei_count[2][2];
+  apalQEICount_t qei_range[2];
+  uint32_t timeout_counter;
+  apalQEICount_t qei_increments[2][2];
+  uint32_t stable_counter;
+  apalQEICount_t qei_increments_diff[2];
+
+  chprintf(stream, "enable power...\n");
+  power_state = A3906_LLD_POWER_ON;
+  status = a3906_lld_set_power(((ut_a3906data_t*)ut->data)->driver, power_state);
+  status |= a3906_lld_get_power(((ut_a3906data_t*)ut->data)->driver, &power_state);
+  status |= (power_state != A3906_LLD_POWER_ON) ? 0x10 : 0x00;
+  if (status == APAL_STATUS_SUCCESS) {
+    aosUtPassed(stream, &result);
+  } else {
+    aosUtFailedMsg(stream, &result, "0x%08X\n", status);
+  }
+
+  _wheelDirectionTest(stream, (ut_a3906data_t*)ut->data, WHEEL_LEFT, DIRECTION_FORWARD, &result);
+
+  _wheelDirectionTest(stream, (ut_a3906data_t*)ut->data, WHEEL_LEFT, DIRECTION_BACKWARD, &result);
+
+  _wheelDirectionTest(stream, (ut_a3906data_t*)ut->data, WHEEL_RIGHT, DIRECTION_FORWARD, &result);
+
+  _wheelDirectionTest(stream, (ut_a3906data_t*)ut->data, WHEEL_RIGHT, DIRECTION_BACKWARD, &result);
+
+  chprintf(stream, "both wheels full speed forward...\n");
+  status = APAL_STATUS_SUCCESS;
+  status |= a3906_lld_set_pwm(((ut_a3906data_t*)ut->data)->pwm.driver, ((ut_a3906data_t*)ut->data)->pwm.channel.left_forward, APAL_PWM_WIDTH_MAX);
+  status |= a3906_lld_set_pwm(((ut_a3906data_t*)ut->data)->pwm.driver, ((ut_a3906data_t*)ut->data)->pwm.channel.right_forward, APAL_PWM_WIDTH_MAX);
+  aosThdMSleep(100);
+  qei_count[WHEEL_LEFT][0] = 0;
+  qei_count[WHEEL_LEFT][1] = 0;
+  qei_count[WHEEL_RIGHT][0] = 0;
+  qei_count[WHEEL_RIGHT][1] = 0;
+  status |= apalQEIGetRange(((ut_a3906data_t*)ut->data)->qei.left, &qei_range[WHEEL_LEFT]);
+  status |= apalQEIGetRange(((ut_a3906data_t*)ut->data)->qei.right, &qei_range[WHEEL_RIGHT]);
+  timeout_counter = 0;
+  qei_increments[WHEEL_LEFT][0] = 0;
+  qei_increments[WHEEL_LEFT][1] = 0;
+  qei_increments[WHEEL_RIGHT][0] = 0;
+  qei_increments[WHEEL_RIGHT][1] = 0;
+  stable_counter = 0;
+  do {
+    status |= apalQEIGetPosition(((ut_a3906data_t*)ut->data)->qei.left, &qei_count[WHEEL_LEFT][0]);
+    status |= apalQEIGetPosition(((ut_a3906data_t*)ut->data)->qei.right, &qei_count[WHEEL_RIGHT][0]);
+    aosThdMSleep(QEI_POLL_INTERVAL_MS);
+    status |= apalQEIGetPosition(((ut_a3906data_t*)ut->data)->qei.left, &qei_count[WHEEL_LEFT][1]);
+    status |= apalQEIGetPosition(((ut_a3906data_t*)ut->data)->qei.right, &qei_count[WHEEL_RIGHT][1]);
+    timeout_counter += QEI_POLL_INTERVAL_MS;
+    qei_increments[WHEEL_LEFT][0] = qei_increments[WHEEL_LEFT][1];
+    qei_increments[WHEEL_LEFT][1] = (qei_count[WHEEL_LEFT][1] > qei_count[WHEEL_LEFT][0]) ? (qei_count[WHEEL_LEFT][1] - qei_count[WHEEL_LEFT][0]) : (qei_count[WHEEL_LEFT][1] + (qei_range[WHEEL_LEFT] - qei_count[WHEEL_LEFT][0]));
+    qei_increments[WHEEL_RIGHT][0] = qei_increments[WHEEL_RIGHT][1];
+    qei_increments[WHEEL_RIGHT][1] = (qei_count[WHEEL_RIGHT][1] > qei_count[WHEEL_RIGHT][0]) ? (qei_count[WHEEL_RIGHT][1] - qei_count[WHEEL_RIGHT][0]) : (qei_count[WHEEL_RIGHT][1] + (qei_range[WHEEL_RIGHT] - qei_count[WHEEL_RIGHT][0]));
+    qei_increments_diff[WHEEL_LEFT] = abs((int32_t)(qei_increments[WHEEL_LEFT][0]) - (int32_t)qei_increments[WHEEL_LEFT][1]);
+    qei_increments_diff[WHEEL_RIGHT] = abs((int32_t)(qei_increments[WHEEL_RIGHT][0]) - (int32_t)qei_increments[WHEEL_RIGHT][1]);
+    stable_counter = (qei_increments_diff[WHEEL_LEFT] <= QEI_DIFF_THRESHOLD && qei_increments_diff[WHEEL_RIGHT] < QEI_DIFF_THRESHOLD) ? stable_counter+1 : 0;
+  } while((stable_counter * QEI_POLL_INTERVAL_MS < MILLISECONDS_PER_SECOND) && (timeout_counter * MICROSECONDS_PER_MILLISECOND <= ((ut_a3906data_t*)ut->data)->timeout));
+  status |= (timeout_counter * MICROSECONDS_PER_MILLISECOND > ((ut_a3906data_t*)ut->data)->timeout) ? APAL_STATUS_TIMEOUT : 0x00;
+  if (status == APAL_STATUS_SUCCESS) {
+    aosUtPassed(stream, &result);
+    const float tps[2] = {qei_increments[WHEEL_LEFT][1] * ((float)MILLISECONDS_PER_SECOND / (float)QEI_POLL_INTERVAL_MS),
+                          qei_increments[WHEEL_RIGHT][1] * ((float)MILLISECONDS_PER_SECOND / (float)QEI_POLL_INTERVAL_MS)};
+    const float rpm[2] = {tps[WHEEL_LEFT] * SECONDS_PER_MINUTE / (float)(((ut_a3906data_t*)ut->data)->qei.increments_per_revolution),
+                          tps[WHEEL_RIGHT] * SECONDS_PER_MINUTE / (float)(((ut_a3906data_t*)ut->data)->qei.increments_per_revolution)};
+    const float velocity[2] = {tps[WHEEL_LEFT] / (float)(((ut_a3906data_t*)ut->data)->qei.increments_per_revolution) * ((ut_a3906data_t*)ut->data)->wheel_diameter * acos(-1),
+                               tps[WHEEL_RIGHT] / (float)(((ut_a3906data_t*)ut->data)->qei.increments_per_revolution) * ((ut_a3906data_t*)ut->data)->wheel_diameter * acos(-1)};
+    chprintf(stream, "left wheel:\n");
+    chprintf(stream, "\t%f tps\n", tps[WHEEL_LEFT]);
+    chprintf(stream, "\t%f RPM\n", rpm[WHEEL_LEFT]);
+    chprintf(stream, "\t%f m/s\n", velocity[WHEEL_LEFT]);
+    chprintf(stream, "right wheel:\n");
+    chprintf(stream, "\t%f tps\n", tps[WHEEL_RIGHT]);
+    chprintf(stream, "\t%f RPM\n", rpm[WHEEL_RIGHT]);
+    chprintf(stream, "\t%f m/s\n", velocity[WHEEL_RIGHT]);
+    chprintf(stream, "\n");
+  } else {
+    aosUtFailedMsg(stream, &result, "0x%08X\n", status);
+  }
+
+  chprintf(stream, "disable power... \n");
+  power_state = A3906_LLD_POWER_OFF;
+  status = a3906_lld_set_power(((ut_a3906data_t*)ut->data)->driver, power_state);
+  status |= a3906_lld_get_power(((ut_a3906data_t*)ut->data)->driver, &power_state);
+  status |= (power_state != A3906_LLD_POWER_OFF) ? 0x10 : 0x00;
+  qei_count[WHEEL_LEFT][0] = 0;
+  qei_count[WHEEL_LEFT][1] = 0;
+  qei_count[WHEEL_RIGHT][0] = 0;
+  qei_count[WHEEL_RIGHT][1] = 0;
+  timeout_counter = 0;
+  stable_counter = 0;
+  do {
+    status |= apalQEIGetPosition(((ut_a3906data_t*)ut->data)->qei.left, &qei_count[WHEEL_LEFT][0]);
+    status |= apalQEIGetPosition(((ut_a3906data_t*)ut->data)->qei.right, &qei_count[WHEEL_RIGHT][0]);
+    aosThdMSleep(1);
+    status |= apalQEIGetPosition(((ut_a3906data_t*)ut->data)->qei.left, &qei_count[WHEEL_LEFT][1]);
+    status |= apalQEIGetPosition(((ut_a3906data_t*)ut->data)->qei.right, &qei_count[WHEEL_RIGHT][1]);
+    ++timeout_counter;
+    stable_counter = (qei_count[WHEEL_LEFT][0] == qei_count[WHEEL_LEFT][1] && qei_count[WHEEL_RIGHT][0] == qei_count[WHEEL_RIGHT][1]) ? stable_counter+1 : 0;
+  } while((stable_counter < 100) && (timeout_counter * MICROSECONDS_PER_MILLISECOND <= ((ut_a3906data_t*)ut->data)->timeout));
+  status |= (timeout_counter * MICROSECONDS_PER_MILLISECOND > ((ut_a3906data_t*)ut->data)->timeout) ? APAL_STATUS_TIMEOUT : 0x00;
+  if (status == APAL_STATUS_SUCCESS) {
+    aosUtPassed(stream, &result);
+  } else {
+    aosUtFailedMsg(stream, &result, "0x%08X\n", status);
+  }
+
+  // stop the PWM
+  a3906_lld_set_pwm(((ut_a3906data_t*)ut->data)->pwm.driver, ((ut_a3906data_t*)ut->data)->pwm.channel.left_forward, APAL_PWM_WIDTH_OFF);
+  a3906_lld_set_pwm(((ut_a3906data_t*)ut->data)->pwm.driver, ((ut_a3906data_t*)ut->data)->pwm.channel.left_backward, APAL_PWM_WIDTH_OFF);
+  a3906_lld_set_pwm(((ut_a3906data_t*)ut->data)->pwm.driver, ((ut_a3906data_t*)ut->data)->pwm.channel.right_forward, APAL_PWM_WIDTH_OFF);
+  a3906_lld_set_pwm(((ut_a3906data_t*)ut->data)->pwm.driver, ((ut_a3906data_t*)ut->data)->pwm.channel.right_backward, APAL_PWM_WIDTH_OFF);
+
+  aosUtInfoMsg(stream,"driver object memory footprint: %u bytes\n", sizeof(A3906Driver));
+
+  return result;
+}
+
+#endif /* (AMIROOS_CFG_TESTS_ENABLE == true) && defined(AMIROLLD_CFG_USE_A3906) */
diff --git a/unittests/periphery-lld/src/ut_alld_at24c01bn-sh-b.c b/unittests/periphery-lld/src/ut_alld_at24c01bn-sh-b.c
new file mode 100644
index 0000000..a841ba0
--- /dev/null
+++ b/unittests/periphery-lld/src/ut_alld_at24c01bn-sh-b.c
@@ -0,0 +1,205 @@
+/*
+AMiRo-OS is an operating system designed for the Autonomous Mini Robot (AMiRo) platform.
+Copyright (C) 2016..2018  Thomas Schöpping et al.
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <ut_alld_at24c01bn-sh-b.h>
+
+#if ((AMIROOS_CFG_TESTS_ENABLE == true) && defined(AMIROLLD_CFG_USE_AT24C01BN)) || defined(__DOXYGEN__)
+
+#include <aos_debug.h>
+#include <chprintf.h>
+
+/**
+ * @brief   EEPROM address for page write/read access.
+ */
+#define _pageAddress                  (AT24C01BN_LLD_SIZE_BYTES - 2*AT24C01BN_LLD_PAGE_SIZE_BYTES)
+
+/**
+ * @brief   EEPROM address for byte write/read access.
+ */
+#define _byteAddress                  (_pageAddress + AT24C01BN_LLD_PAGE_SIZE_BYTES - 1)
+
+/**
+ * @brief   Offset for overflow tests.
+ */
+#define _overflowOffset               3
+
+/**
+ * @brief   EEPROM address for page write/read access with overflow.
+ */
+#define _overflowAddress              (_pageAddress + _overflowOffset)
+
+/**
+ * @brief   Test data byte.
+ */
+#define _bytedata                     0xA5
+
+/**
+ * @brief   AT24C01BN-SH-B unit test function.
+ *
+ * @param[in] stream  Stream for inout/outout.
+ * @param[in] ut      Unit test object.
+ *
+ * @return            Unit test result value.
+ */
+aos_utresult_t utAlldAt24c01bnFunc(BaseSequentialStream* stream, aos_unittest_t* ut)
+{
+  aosDbgCheck(ut->data != NULL && ((ut_at24c01bndata_t*)(ut->data))->driver != NULL);
+
+  // local variables
+  aos_utresult_t result = {0, 0};
+  uint32_t status = 0;
+  uint8_t page_data[AT24C01BN_LLD_PAGE_SIZE_BYTES];
+  uint8_t original_data[AT24C01BN_LLD_PAGE_SIZE_BYTES];
+  uint8_t read_data[AT24C01BN_LLD_PAGE_SIZE_BYTES];
+  size_t errors = 0;
+  for (size_t dataIdx = 0; dataIdx < AT24C01BN_LLD_PAGE_SIZE_BYTES; ++dataIdx) {
+    page_data[dataIdx] = dataIdx;
+  }
+
+  chprintf(stream, "reading byte...\n");
+  status = at24c01bn_lld_read(((ut_at24c01bndata_t*)(ut->data))->driver, _byteAddress, original_data, 1, ((ut_at24c01bndata_t*)(ut->data))->timeout);
+  if (status == APAL_STATUS_SUCCESS || status == APAL_STATUS_WARNING) {
+    aosUtPassed(stream, &result);
+  } else {
+    aosUtFailedMsg(stream, &result, "0x%08X\n", status);
+  }
+
+  chprintf(stream, "writing byte...\n");
+  status = at24c01bn_lld_write_byte(((ut_at24c01bndata_t*)(ut->data))->driver, _byteAddress, _bytedata, ((ut_at24c01bndata_t*)(ut->data))->timeout);
+  while (at24c01bn_lld_poll_ack(((ut_at24c01bndata_t*)(ut->data))->driver, ((ut_at24c01bndata_t*)(ut->data))->timeout) == APAL_STATUS_FAILURE) {
+    continue;
+  }
+  status |= at24c01bn_lld_read(((ut_at24c01bndata_t*)(ut->data))->driver, _byteAddress, &read_data[0], 1, ((ut_at24c01bndata_t*)(ut->data))->timeout);
+  status |= (read_data[0] == _bytedata) ? 0x00 : 0x20;
+  status = at24c01bn_lld_write_byte(((ut_at24c01bndata_t*)(ut->data))->driver, _byteAddress, (uint8_t)~_bytedata, ((ut_at24c01bndata_t*)(ut->data))->timeout);
+  while (at24c01bn_lld_poll_ack(((ut_at24c01bndata_t*)(ut->data))->driver, ((ut_at24c01bndata_t*)(ut->data))->timeout) == APAL_STATUS_FAILURE) {
+    continue;
+  }
+  status |= at24c01bn_lld_read(((ut_at24c01bndata_t*)(ut->data))->driver, _byteAddress, &read_data[1], 1, ((ut_at24c01bndata_t*)(ut->data))->timeout);
+  status |= (read_data[1] == (uint8_t)~_bytedata) ? 0x00 : 0x40;
+  status |= at24c01bn_lld_write_byte(((ut_at24c01bndata_t*)(ut->data))->driver, _byteAddress, original_data[0], ((ut_at24c01bndata_t*)(ut->data))->timeout);
+  while (at24c01bn_lld_poll_ack(((ut_at24c01bndata_t*)(ut->data))->driver, ((ut_at24c01bndata_t*)(ut->data))->timeout) == APAL_STATUS_FAILURE) {
+    continue;
+  }
+  status |= at24c01bn_lld_read(((ut_at24c01bndata_t*)(ut->data))->driver, _byteAddress, &read_data[2], 1, ((ut_at24c01bndata_t*)(ut->data))->timeout);
+  status |= (read_data[2] == original_data[0]) ? 0x00 : 0x80;
+  if (status == APAL_STATUS_SUCCESS || status == APAL_STATUS_WARNING) {
+    aosUtPassed(stream, &result);
+  } else {
+    aosUtFailedMsg(stream, &result, "0x%08X\n", status);
+  }
+
+  chprintf(stream, "reading page...\n");
+  status = at24c01bn_lld_read(((ut_at24c01bndata_t*)(ut->data))->driver, _pageAddress, original_data, AT24C01BN_LLD_PAGE_SIZE_BYTES, ((ut_at24c01bndata_t*)(ut->data))->timeout);
+  if (status == APAL_STATUS_SUCCESS) {
+    aosUtPassed(stream, &result);
+  } else {
+    aosUtFailedMsg(stream, &result, "0x%08X\n", status);
+  }
+
+  chprintf(stream, "writing page...\n");
+  status = at24c01bn_lld_write_page(((ut_at24c01bndata_t*)(ut->data))->driver, _pageAddress, page_data, AT24C01BN_LLD_PAGE_SIZE_BYTES, ((ut_at24c01bndata_t*)(ut->data))->timeout);
+  while (at24c01bn_lld_poll_ack(((ut_at24c01bndata_t*)(ut->data))->driver, ((ut_at24c01bndata_t*)(ut->data))->timeout) == APAL_STATUS_FAILURE) {
+    continue;
+  }
+  status |= at24c01bn_lld_read(((ut_at24c01bndata_t*)(ut->data))->driver, _pageAddress, read_data, AT24C01BN_LLD_PAGE_SIZE_BYTES, ((ut_at24c01bndata_t*)(ut->data))->timeout);
+  errors = 0;
+  for (size_t dataIdx = 0; dataIdx < AT24C01BN_LLD_PAGE_SIZE_BYTES; dataIdx++) {
+    if (read_data[dataIdx] != page_data[dataIdx]) {
+      ++errors;
+    }
+  }
+  if (status == APAL_STATUS_OK && errors == 0) {
+    aosUtPassed(stream, &result);
+  } else {
+    aosUtFailedMsg(stream, &result, "0x%08X; %u\n", status, errors);
+  }
+
+  chprintf(stream, "reading page at current address...\n");
+  // set address counter to UT_ALLD_AT24C01BN_PAGE_ADDRESS
+  status = at24c01bn_lld_read(((ut_at24c01bndata_t*)(ut->data))->driver, _pageAddress-1, read_data, 1, ((ut_at24c01bndata_t*)(ut->data))->timeout);
+  if (status == APAL_STATUS_WARNING) {
+    // on STM32F1 platform the address gets incremented by 2 after reading
+    status = at24c01bn_lld_read(((ut_at24c01bndata_t*)(ut->data))->driver, _pageAddress-2, read_data, 1, ((ut_at24c01bndata_t*)(ut->data))->timeout);
+  }
+  // read page from the current address
+  status = at24c01bn_lld_read_current_address(((ut_at24c01bndata_t*)(ut->data))->driver, read_data, AT24C01BN_LLD_PAGE_SIZE_BYTES, ((ut_at24c01bndata_t*)(ut->data))->timeout);
+  errors = 0;
+  for (uint8_t dataIdx = 0; dataIdx < 8; dataIdx++) {
+    if (read_data[dataIdx] != page_data[dataIdx]) {
+      ++errors;
+    }
+  }
+  if (status == APAL_STATUS_OK && errors == 0) {
+    aosUtPassed(stream, &result);
+  } else {
+    aosUtFailedMsg(stream, &result, "0x%08X; %u\n", status, errors);
+  }
+
+  chprintf(stream, "writing page with overflow (7 bytes)...\n");
+  status = at24c01bn_lld_write_page(((ut_at24c01bndata_t*)(ut->data))->driver, _overflowAddress, page_data, AT24C01BN_LLD_PAGE_SIZE_BYTES-1, ((ut_at24c01bndata_t*)(ut->data))->timeout);
+  while (at24c01bn_lld_poll_ack(((ut_at24c01bndata_t*)(ut->data))->driver, ((ut_at24c01bndata_t*)(ut->data))->timeout) == APAL_STATUS_FAILURE) {
+    continue;
+  }
+  status |= at24c01bn_lld_read(((ut_at24c01bndata_t*)(ut->data))->driver, _overflowAddress, read_data, AT24C01BN_LLD_PAGE_SIZE_BYTES-_overflowOffset, ((ut_at24c01bndata_t*)(ut->data))->timeout);
+  status |= at24c01bn_lld_read(((ut_at24c01bndata_t*)(ut->data))->driver, _overflowAddress-_overflowOffset, read_data+(AT24C01BN_LLD_PAGE_SIZE_BYTES-_overflowOffset), _overflowOffset-1, ((ut_at24c01bndata_t*)(ut->data))->timeout);
+  errors = 0;
+  for (uint8_t dataIdx = 0; dataIdx < AT24C01BN_LLD_PAGE_SIZE_BYTES-1; dataIdx++) {
+    if (read_data[dataIdx] != page_data[dataIdx]) {
+      ++errors;
+    }
+  }
+  if (status == APAL_STATUS_OK && errors == 0) {
+    aosUtPassed(stream, &result);
+  } else {
+    aosUtFailedMsg(stream, &result, "0x%08X; %u\n", status, errors);
+  }
+
+  chprintf(stream, "writing page with overflow (8 bytes)...\n");
+  status = at24c01bn_lld_write_page(((ut_at24c01bndata_t*)(ut->data))->driver, _overflowAddress, page_data, AT24C01BN_LLD_PAGE_SIZE_BYTES, ((ut_at24c01bndata_t*)(ut->data))->timeout);
+  while (at24c01bn_lld_poll_ack(((ut_at24c01bndata_t*)(ut->data))->driver, ((ut_at24c01bndata_t*)(ut->data))->timeout) == APAL_STATUS_FAILURE) {
+    continue;
+  }
+  status |= at24c01bn_lld_read(((ut_at24c01bndata_t*)(ut->data))->driver, _overflowAddress, read_data, AT24C01BN_LLD_PAGE_SIZE_BYTES-_overflowOffset, ((ut_at24c01bndata_t*)(ut->data))->timeout);
+  status |= at24c01bn_lld_read(((ut_at24c01bndata_t*)(ut->data))->driver, _overflowAddress-_overflowOffset, read_data+(AT24C01BN_LLD_PAGE_SIZE_BYTES-_overflowOffset), _overflowOffset, ((ut_at24c01bndata_t*)(ut->data))->timeout);
+  errors = 0;
+  for (uint8_t dataIdx = 0; dataIdx < AT24C01BN_LLD_PAGE_SIZE_BYTES; dataIdx++) {
+    if (read_data[dataIdx] != page_data[dataIdx]) {
+      ++errors;
+    }
+  }
+  if (status == APAL_STATUS_OK && errors == 0) {
+    aosUtPassed(stream, &result);
+  } else {
+    aosUtFailedMsg(stream, &result, "0x%08X; %u\n", status, errors);
+  }
+
+  chprintf(stream, "write back original data...\n");
+  status = at24c01bn_lld_write_page(((ut_at24c01bndata_t*)(ut->data))->driver, _pageAddress, original_data, AT24C01BN_LLD_PAGE_SIZE_BYTES, ((ut_at24c01bndata_t*)(ut->data))->timeout);
+  if (status == APAL_STATUS_SUCCESS) {
+    aosUtPassed(stream, &result);
+  } else {
+    aosUtFailedMsg(stream, &result, "0x%08X\n", status);
+  }
+
+  aosUtInfoMsg(stream,"driver object memory footprint: %u bytes\n", sizeof(AT24C01BNDriver));
+
+  return result;
+}
+
+#endif /* (AMIROOS_CFG_TESTS_ENABLE == true) && defined(AMIROLLD_CFG_USE_AT24C01BN) */
diff --git a/unittests/periphery-lld/src/ut_alld_bq24103a.c b/unittests/periphery-lld/src/ut_alld_bq24103a.c
new file mode 100644
index 0000000..42a5ba0
--- /dev/null
+++ b/unittests/periphery-lld/src/ut_alld_bq24103a.c
@@ -0,0 +1,75 @@
+/*
+AMiRo-OS is an operating system designed for the Autonomous Mini Robot (AMiRo) platform.
+Copyright (C) 2016..2018  Thomas Schöpping et al.
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <ut_alld_bq24103a.h>
+
+#if ((AMIROOS_CFG_TESTS_ENABLE == true) && defined(AMIROLLD_CFG_USE_BQ24103A)) || defined(__DOXYGEN__)
+
+#include <aos_debug.h>
+#include <chprintf.h>
+#include <aos_thread.h>
+#include <alld_bq24103a.h>
+
+aos_utresult_t utAlldBq24103aFunc(BaseSequentialStream* stream, aos_unittest_t* ut)
+{
+  aosDbgCheck(ut->data != NULL);
+
+  // local variables
+  aos_utresult_t result = {0, 0};
+  uint32_t status;
+  bq24103a_lld_enable_t en[3];
+  bq24103a_lld_charge_state_t charge;
+
+  chprintf(stream, "read enable pin...\n");
+  status = bq24103a_lld_get_enabled((BQ24103ADriver*)ut->data, &en[0]);
+  chprintf(stream, "\t\tcurrently %s\n", (en[0] == BQ24103A_LLD_ENABLED) ? "enabled" : "disabled");
+  if(status == APAL_STATUS_SUCCESS){
+    aosUtPassed(stream, &result);
+  } else {
+    aosUtFailedMsg(stream, &result, "0x%08X\n", status);
+  }
+
+  chprintf(stream, "write enable pin...\n");
+  status = bq24103a_lld_set_enabled((BQ24103ADriver*)ut->data, (en[0] == BQ24103A_LLD_ENABLED) ? BQ24103A_LLD_DISABLED : BQ24103A_LLD_ENABLED);
+  aosThdMSleep(1);
+  status |= bq24103a_lld_get_enabled((BQ24103ADriver*)ut->data, &en[1]);
+  status |= bq24103a_lld_set_enabled((BQ24103ADriver*)ut->data, en[0]);
+  aosThdMSleep(1);
+  status |= bq24103a_lld_get_enabled((BQ24103ADriver*)ut->data, &en[2]);
+  if(status == APAL_STATUS_SUCCESS && en[0] != en[1] && en[0] == en[2] && en[1] != en[2]){
+    aosUtPassed(stream, &result);
+  } else {
+    aosUtFailedMsg(stream, &result, "0x%08X, %u-%u\n", status, en[1], en[2]);
+  }
+
+  chprintf(stream, "read status pin...\n");
+  aosThdMSleep(500);
+  status = bq24103a_lld_get_charge_status((BQ24103ADriver*)ut->data, &charge);
+  chprintf(stream, "\t\tcharge status: %scharging\n", (charge == BQ24103A_LLD_CHARGING) ? "" : "not ");
+  if (status == APAL_STATUS_SUCCESS) {
+    aosUtPassed(stream, &result);
+  } else {
+    aosUtFailedMsg(stream, &result, "0x%08X\n", status);
+  }
+
+  aosUtInfoMsg(stream,"driver object memory footprint: %u bytes\n", sizeof(BQ24103ADriver));
+
+  return result;
+}
+
+#endif /* (AMIROOS_CFG_TESTS_ENABLE == true) && defined(AMIROLLD_CFG_USE_BQ24103A) */
diff --git a/unittests/periphery-lld/src/ut_alld_bq27500.c b/unittests/periphery-lld/src/ut_alld_bq27500.c
new file mode 100644
index 0000000..6fad31f
--- /dev/null
+++ b/unittests/periphery-lld/src/ut_alld_bq27500.c
@@ -0,0 +1,305 @@
+/*
+AMiRo-OS is an operating system designed for the Autonomous Mini Robot (AMiRo) platform.
+Copyright (C) 2016..2018  Thomas Schöpping et al.
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <ut_alld_bq27500.h>
+
+#if ((AMIROOS_CFG_TESTS_ENABLE == true) && defined(AMIROLLD_CFG_USE_BQ27500)) || defined(__DOXYGEN__)
+
+#include <string.h>
+#include <aos_debug.h>
+#include <chprintf.h>
+#include <aos_thread.h>
+#include <alld_bq27500.h>
+
+aos_utresult_t utAlldBq27500Func(BaseSequentialStream* stream, aos_unittest_t* ut)
+{
+  aosDbgCheck(ut->data != NULL && ((ut_bq27500data_t*)(ut->data))->driver != NULL);
+
+  // local variables
+  aos_utresult_t result = {0, 0};
+  uint32_t status;
+  bq27500_lld_batlow_t bl;
+  bq27500_lld_batgood_t bg;
+  uint16_t dst;
+  bq27500_lld_flags_t flags;
+  uint16_t subdata = 0;
+  uint8_t original_length;
+  char original_name[8+1];
+  uint8_t val = 0x00;
+  uint8_t block[32];
+  char new_name[] = "test";
+  uint8_t new_lenght;
+  char name[8+1] = {'\0'};
+  uint8_t sum = 0;
+  bool success;
+  bool success2;
+
+  chprintf(stream, "read battery low gpio...\n");
+  status = bq27500_lld_read_batlow(((ut_bq27500data_t*)ut->data)->driver, &bl);
+  chprintf(stream, "\t\tbattery low: 0x%X\n", bl);
+  if (status == APAL_STATUS_SUCCESS) {
+    aosUtPassed(stream, &result);
+  } else {
+    aosUtFailedMsg(stream, &result, "0x%08X\n", status);
+  }
+
+  chprintf(stream, "read battery good gpio...\n");
+  status = bq27500_lld_read_batgood(((ut_bq27500data_t*)ut->data)->driver, &bg);
+  chprintf(stream, "\t\tbattery good: 0x%X\n", bg);
+  if (status == APAL_STATUS_SUCCESS) {
+    aosUtPassed(stream, &result);
+  } else {
+    aosUtFailedMsg(stream, &result, "0x%08X\n", status);
+  }
+
+  chprintf(stream, "std command FLAGS...\n");
+  status = bq27500_lld_std_command(((ut_bq27500data_t*)ut->data)->driver, BQ27500_LLD_STD_CMD_Flags, &flags.value, ((ut_bq27500data_t*)ut->data)->timeout);
+  chprintf(stream, "\t\tflags: 0x%04X\n", flags.value);
+  chprintf(stream, "\t\tbattery detected: 0x%X\n", flags.content.bat_det);
+  chprintf(stream, "\t\tbattery fully charged: 0x%X\n", flags.content.fc);
+  if (status == APAL_STATUS_SUCCESS) {
+    aosUtPassed(stream, &result);
+  } else {
+    aosUtFailedMsg(stream, &result, "0x%08X\n", status);
+  }
+
+  chprintf(stream, "std command CTNL...\n");
+  status = bq27500_lld_std_command(((ut_bq27500data_t*)ut->data)->driver, BQ27500_LLD_STD_CMD_Control, &dst, ((ut_bq27500data_t*)ut->data)->timeout);
+  if (status == APAL_STATUS_SUCCESS) {
+    aosUtPassed(stream, &result);
+  } else {
+    aosUtFailedMsg(stream, &result, "0x%08X\n", status);
+  }
+
+  chprintf(stream, "sub command: CTRL Status...\n");
+  aosThdMSleep(5);
+  status = bq27500_lld_sub_command_call(((ut_bq27500data_t*)ut->data)->driver, BQ27500_LLD_SUB_CMD_CONTROL_STATUS, ((ut_bq27500data_t*)ut->data)->timeout);
+  aosThdMSleep(5);
+  status |= bq27500_lld_std_command(((ut_bq27500data_t*)ut->data)->driver, BQ27500_LLD_STD_CMD_Control, &dst, ((ut_bq27500data_t*)ut->data)->timeout);
+  aosThdMSleep(5);
+  bq27500_lld_control_status_t ctrl;
+  status |= bq27500_lld_sub_command_read(((ut_bq27500data_t*)ut->data)->driver, &ctrl.value, ((ut_bq27500data_t*)ut->data)->timeout);
+  chprintf(stream, "\t\tdst: 0x%X\n", ctrl.value);
+  chprintf(stream, "\t\tsleep: 0x%X\n", ctrl.content.sleep);
+  chprintf(stream, "\t\thibernate: 0x%X\n", ctrl.content.hibernate);
+  if (status == APAL_STATUS_SUCCESS) {
+    aosUtPassed(stream, &result);
+  } else {
+    aosUtFailedMsg(stream, &result, "0x%08X\n", status);
+  }
+
+  chprintf(stream, "sub command: firmware version...\n");
+  status = bq27500_lld_sub_command_call(((ut_bq27500data_t*)ut->data)->driver, BQ27500_LLD_SUB_CMD_FW_VERSION, ((ut_bq27500data_t*)ut->data)->timeout);
+  aosThdMSleep(1);
+  bq27500_lld_version_t version;
+  status |= bq27500_lld_sub_command_read(((ut_bq27500data_t*)ut->data)->driver, &version.value, ((ut_bq27500data_t*)ut->data)->timeout);
+  chprintf(stream, "\t\tfirmware version: %X%X-%X%X\n", version.content.major_high, version.content.major_low, version.content.minor_high, version.content.minor_low);
+  if (status == APAL_STATUS_SUCCESS) {
+    aosUtPassed(stream, &result);
+  } else {
+    aosUtFailedMsg(stream, &result, "0x%08X\n", status);
+  }
+
+  chprintf(stream, "sub command: hardware version...\n");
+  status = bq27500_lld_sub_command_call(((ut_bq27500data_t*)ut->data)->driver, BQ27500_LLD_SUB_CMD_HW_VERSION, ((ut_bq27500data_t*)ut->data)->timeout);
+  aosThdMSleep(1);
+  status |= bq27500_lld_sub_command_read(((ut_bq27500data_t*)ut->data)->driver, &version.value, ((ut_bq27500data_t*)ut->data)->timeout);
+  chprintf(stream, "\t\thardware version: %X%X-%X%X\n", version.content.major_high, version.content.major_low, version.content.minor_high, version.content.minor_low);
+  if (status == APAL_STATUS_SUCCESS) {
+    aosUtPassed(stream, &result);
+  } else {
+    aosUtFailedMsg(stream, &result, "0x%08X\n", status);
+  }
+
+  chprintf(stream, "ext command: device name length...\n");
+  status = bq27500_lld_ext_command(((ut_bq27500data_t*)ut->data)->driver, BQ27500_LLD_EXT_CMD_DeviceNameLength, BQ27500_LLD_EXT_CMD_READ, &original_length, 1, 0, ((ut_bq27500data_t*)ut->data)->timeout);
+  chprintf(stream, "\t\tdevice name length: %d \n", original_length);
+  if (status == APAL_STATUS_SUCCESS && original_length <= 8) {
+    aosUtPassed(stream, &result);
+  } else {
+    aosUtFailedMsg(stream, &result, "0x%08X\n", status);
+    original_length = 8;
+  }
+
+  chprintf(stream, "ext command: device name (read)...\n");
+  status = bq27500_lld_ext_command(((ut_bq27500data_t*)ut->data)->driver, BQ27500_LLD_EXT_CMD_DeviceName, BQ27500_LLD_EXT_CMD_READ, (uint8_t*)original_name, original_length, 0, ((ut_bq27500data_t*)ut->data)->timeout);
+  original_name[original_length] = '\0';
+  chprintf(stream, "\t\tdevice name: %s\n", original_name);
+  if (status == APAL_STATUS_SUCCESS) {
+    aosUtPassed(stream, &result);
+  } else {
+    aosUtFailedMsg(stream, &result, "0x%08X\n", status);
+  }
+
+  chprintf(stream, "battery info std commands...\n");
+  status = bq27500_lld_std_command(((ut_bq27500data_t*)ut->data)->driver, BQ27500_LLD_STD_CMD_Temperatur, &dst, ((ut_bq27500data_t*)ut->data)->timeout);
+  chprintf(stream, "\t\ttemperature: %fK (%fC) \n", (float)dst/10.0f, (float)dst/10.0f-273.5f);
+  status |= bq27500_lld_std_command(((ut_bq27500data_t*)ut->data)->driver, BQ27500_LLD_STD_CMD_FullAvailableCapacity, &dst, ((ut_bq27500data_t*)ut->data)->timeout);
+  chprintf(stream, "\t\tfull available capacity: %umAh \n", dst);
+  status |= bq27500_lld_std_command(((ut_bq27500data_t*)ut->data)->driver, BQ27500_LLD_STD_CMD_FullChargeCapacity, &dst, ((ut_bq27500data_t*)ut->data)->timeout);
+  chprintf(stream, "\t\tfull charge capacity: %umAh \n", dst);
+  status |= bq27500_lld_std_command(((ut_bq27500data_t*)ut->data)->driver, BQ27500_LLD_STD_CMD_RemainingCapacity, &dst, ((ut_bq27500data_t*)ut->data)->timeout);
+  chprintf(stream, "\t\tremaining capacity: %umAh \n", dst);
+  status |= bq27500_lld_std_command(((ut_bq27500data_t*)ut->data)->driver, BQ27500_LLD_STD_CMD_Voltage, &dst, ((ut_bq27500data_t*)ut->data)->timeout);
+  chprintf(stream, "\t\tvoltage: %umV \n", dst);
+  status |= bq27500_lld_std_command(((ut_bq27500data_t*)ut->data)->driver, BQ27500_LLD_STD_CMD_AverageCurrent, &dst, ((ut_bq27500data_t*)ut->data)->timeout);
+  chprintf(stream, "\t\taverage current: %dmA \n", (int8_t)dst);
+  status |= bq27500_lld_std_command(((ut_bq27500data_t*)ut->data)->driver, BQ27500_LLD_STD_CMD_AveragePower, &dst, ((ut_bq27500data_t*)ut->data)->timeout);
+  chprintf(stream, "\t\taverage power: %dmW \n", (int8_t)dst);
+  status |= bq27500_lld_std_command(((ut_bq27500data_t*)ut->data)->driver, BQ27500_LLD_STD_CMD_TimeToFull, &dst, ((ut_bq27500data_t*)ut->data)->timeout);
+  if (dst != (uint16_t)~0) {
+    chprintf(stream, "\t\ttime to full: %umin \n", dst);
+  } else {
+    chprintf(stream, "\t\ttime to full: (not charging) \n", dst);
+  }
+  status |= bq27500_lld_std_command(((ut_bq27500data_t*)ut->data)->driver, BQ27500_LLD_STD_CMD_TimeToEmpty, &dst, ((ut_bq27500data_t*)ut->data)->timeout);
+  if (dst != (uint16_t)~0) {
+    chprintf(stream, "\t\ttime to empty: %umin \n", dst);
+  } else {
+    chprintf(stream, "\t\ttime to empty: (not discharging) \n", dst);
+  }
+  if (status == APAL_STATUS_SUCCESS) {
+    aosUtPassed(stream, &result);
+  } else {
+    aosUtFailedMsg(stream, &result, "0x%08X\n", status);
+  }
+
+  chprintf(stream, "check sealed state...\n");
+  status = bq27500_lld_std_command(((ut_bq27500data_t*)ut->data)->driver, BQ27500_LLD_STD_CMD_Control, &dst, ((ut_bq27500data_t*)ut->data)->timeout);
+  status |= bq27500_lld_sub_command_call(((ut_bq27500data_t*)ut->data)->driver, BQ27500_LLD_SUB_CMD_CONTROL_STATUS, ((ut_bq27500data_t*)ut->data)->timeout);
+  aosThdMSleep(1);
+  status |= bq27500_lld_sub_command_read(((ut_bq27500data_t*)ut->data)->driver, &ctrl.value, ((ut_bq27500data_t*)ut->data)->timeout);
+  chprintf(stream, "\t\tsealed: 0x%X\n", ctrl.content.ss);
+  chprintf(stream, "\t\tfull access sealed: 0x%X\n", ctrl.content.fas);
+  if (status == APAL_STATUS_SUCCESS) {
+    aosUtPassed(stream, &result);
+  } else {
+    aosUtFailedMsg(stream, &result, "0x%08X\n", status);
+  }
+
+  chprintf(stream, "unseale...\n");
+  status = bq27500_lld_send_ctnl_data(((ut_bq27500data_t*)ut->data)->driver, BQ27500_LLD_DEFAULT_UNSEAL_KEY1, ((ut_bq27500data_t*)ut->data)->timeout);
+  aosThdMSleep(50);
+  status |= bq27500_lld_send_ctnl_data(((ut_bq27500data_t*)ut->data)->driver, BQ27500_LLD_DEFAULT_UNSEAL_KEY0, ((ut_bq27500data_t*)ut->data)->timeout);
+  aosThdMSleep(50);
+  status |= bq27500_lld_sub_command_call(((ut_bq27500data_t*)ut->data)->driver, BQ27500_LLD_SUB_CMD_CONTROL_STATUS, ((ut_bq27500data_t*)ut->data)->timeout);
+  aosThdMSleep(50);
+  status |= bq27500_lld_std_command(((ut_bq27500data_t*)ut->data)->driver, BQ27500_LLD_STD_CMD_Control, &dst, ((ut_bq27500data_t*)ut->data)->timeout);
+  status |= bq27500_lld_sub_command_read(((ut_bq27500data_t*)ut->data)->driver, &ctrl.value, ((ut_bq27500data_t*)ut->data)->timeout);
+  if (status == APAL_STATUS_SUCCESS && ctrl.content.ss == 0x0) {
+    aosUtPassed(stream, &result);
+  } else {
+    aosUtFailedMsg(stream, &result, "0x%08X\n", status);
+  }
+
+  chprintf(stream, "read device name from data flash...\n");
+  status = bq27500_lld_ext_command(((ut_bq27500data_t*)ut->data)->driver, BQ27500_LLD_EXT_CMD_BlockDataControl, BQ27500_LLD_EXT_CMD_WRITE, &val, 1, 0, ((ut_bq27500data_t*)ut->data)->timeout);
+  aosThdMSleep(50);
+  val = 0x30;
+  status |= bq27500_lld_ext_command(((ut_bq27500data_t*)ut->data)->driver, BQ27500_LLD_EXT_CMD_DataFlashClass, BQ27500_LLD_EXT_CMD_WRITE, &val, 1, 0, ((ut_bq27500data_t*)ut->data)->timeout);
+  aosThdMSleep(50);
+  val = 0;
+  status |= bq27500_lld_ext_command(((ut_bq27500data_t*)ut->data)->driver, BQ27500_LLD_EXT_CMD_DataFlashBlock, BQ27500_LLD_EXT_CMD_WRITE, &val, 1, 0, ((ut_bq27500data_t*)ut->data)->timeout);
+  aosThdMSleep(50);
+  status |= bq27500_lld_ext_command(((ut_bq27500data_t*)ut->data)->driver, BQ27500_LLD_EXT_CMD_BlockData, BQ27500_LLD_EXT_CMD_READ, (uint8_t*)block, original_length, 13, ((ut_bq27500data_t*)ut->data)->timeout);
+  block[original_length] = '\0';
+  chprintf(stream, "\t\tdevice name: %s\n", block);
+  if (status == APAL_STATUS_SUCCESS && (strcmp((char*)block, (char*)original_name) == 0)) {
+    aosUtPassed(stream, &result);
+  } else {
+    chprintf(stream, "\t\tread data: ");
+    for (uint8_t blockIdx = 0; blockIdx < original_length; blockIdx++) {
+      chprintf(stream, "0x%02X\n", block[blockIdx]);
+    }
+    aosUtFailedMsg(stream, &result, "0x%08X\n", status);
+  }
+
+  chprintf(stream, "change device name in data flash to \"test\"...\n");
+  status = bq27500_lld_ext_command(((ut_bq27500data_t*)ut->data)->driver, BQ27500_LLD_EXT_CMD_BlockData, BQ27500_LLD_EXT_CMD_WRITE, (uint8_t*)new_name, 5, 13, ((ut_bq27500data_t*)ut->data)->timeout);
+  aosThdMSleep(50);
+  status |= bq27500_lld_ext_command(((ut_bq27500data_t*)ut->data)->driver, BQ27500_LLD_EXT_CMD_BlockData, BQ27500_LLD_EXT_CMD_READ, (uint8_t*)block, 32, 0, ((ut_bq27500data_t*)ut->data)->timeout);
+  // compute blockdata checksum
+  status |= bq27500_lld_compute_blockdata_checksum(block, &sum);
+  // write checksum to BlockDataChecksum, triggering the write of BlackData
+  status |= bq27500_lld_ext_command(((ut_bq27500data_t*)ut->data)->driver, BQ27500_LLD_EXT_CMD_BlockDataCheckSum, BQ27500_LLD_EXT_CMD_WRITE, &sum, 1, 0, ((ut_bq27500data_t*)ut->data)->timeout);
+  aosThdMSleep(50);
+  status |= bq27500_lld_ext_command(((ut_bq27500data_t*)ut->data)->driver, BQ27500_LLD_EXT_CMD_DeviceNameLength, BQ27500_LLD_EXT_CMD_READ, &new_lenght, 1, 0, ((ut_bq27500data_t*)ut->data)->timeout);
+  aosThdMSleep(50);
+  // read out device name, to see if changing it was successfull
+  status |= bq27500_lld_ext_command(((ut_bq27500data_t*)ut->data)->driver, BQ27500_LLD_EXT_CMD_DeviceName, BQ27500_LLD_EXT_CMD_READ, (uint8_t*)name, new_lenght, 0, ((ut_bq27500data_t*)ut->data)->timeout);
+  name[new_lenght] = '\0';
+  chprintf(stream, "\t\tdevice name: %s\n", name);
+  success = (strcmp(name, new_name) == 0);
+
+  // change device name back to original name
+  val = 0x00;
+  status = bq27500_lld_ext_command(((ut_bq27500data_t*)ut->data)->driver, BQ27500_LLD_EXT_CMD_BlockDataControl, BQ27500_LLD_EXT_CMD_WRITE, &val, 1, 0, ((ut_bq27500data_t*)ut->data)->timeout);
+  aosThdMSleep(50);
+  val = 0x30;
+  status |= bq27500_lld_ext_command(((ut_bq27500data_t*)ut->data)->driver, BQ27500_LLD_EXT_CMD_DataFlashClass, BQ27500_LLD_EXT_CMD_WRITE, &val, 1, 0, ((ut_bq27500data_t*)ut->data)->timeout);
+  aosThdMSleep(50);
+  val = 0;
+  status |= bq27500_lld_ext_command(((ut_bq27500data_t*)ut->data)->driver, BQ27500_LLD_EXT_CMD_DataFlashBlock, BQ27500_LLD_EXT_CMD_WRITE, &val, 1, 0, ((ut_bq27500data_t*)ut->data)->timeout);
+  aosThdMSleep(50);
+  status |= bq27500_lld_ext_command(((ut_bq27500data_t*)ut->data)->driver, BQ27500_LLD_EXT_CMD_BlockData, BQ27500_LLD_EXT_CMD_WRITE, (uint8_t*)original_name, 7, 13, ((ut_bq27500data_t*)ut->data)->timeout);
+  aosThdMSleep(50);
+  status |= bq27500_lld_ext_command(((ut_bq27500data_t*)ut->data)->driver, BQ27500_LLD_EXT_CMD_BlockData, BQ27500_LLD_EXT_CMD_READ, (uint8_t*)block, 32, 0, ((ut_bq27500data_t*)ut->data)->timeout);
+  // compute blockdata checksum
+  sum = 0;
+  status |= bq27500_lld_compute_blockdata_checksum(block, &sum);
+  // write checksum to BlockDataChecksum, triggering the write of BlackData
+  status |= bq27500_lld_ext_command(((ut_bq27500data_t*)ut->data)->driver, BQ27500_LLD_EXT_CMD_BlockDataCheckSum, BQ27500_LLD_EXT_CMD_WRITE, &sum, 1, 0, ((ut_bq27500data_t*)ut->data)->timeout);
+  aosThdMSleep(1000);
+  status |= bq27500_lld_ext_command(((ut_bq27500data_t*)ut->data)->driver, BQ27500_LLD_EXT_CMD_DeviceNameLength, BQ27500_LLD_EXT_CMD_READ, &original_length, 1, 0, ((ut_bq27500data_t*)ut->data)->timeout);
+  aosThdMSleep(50);
+  // read device name, to see if changing it back to the original name was successfull
+  status |= bq27500_lld_ext_command(((ut_bq27500data_t*)ut->data)->driver, BQ27500_LLD_EXT_CMD_DeviceName, BQ27500_LLD_EXT_CMD_READ, (uint8_t*)name, original_length, 0, ((ut_bq27500data_t*)ut->data)->timeout);
+  success2 = (strcmp(name, original_name) == 0);
+  name[original_length] = '\0';
+  chprintf(stream, "\t\tchanged back to name: %s, original_name: %s\n", name, original_name);
+  if (status == APAL_STATUS_OK && ((success && success2) || (ctrl.content.sleep == 0))) {
+    aosUtPassed(stream, &result);
+  } else {
+    aosUtFailedMsg(stream, &result, "0x%08X, changing: 0x%X - changing back: 0x%X\n", status, success, success2);
+  }
+
+  chprintf(stream, "seal...\n");
+  status = bq27500_lld_std_command(((ut_bq27500data_t*)ut->data)->driver, BQ27500_LLD_STD_CMD_Control, &dst, ((ut_bq27500data_t*)ut->data)->timeout);
+  aosThdMSleep(50);
+  status |= bq27500_lld_sub_command_call(((ut_bq27500data_t*)ut->data)->driver, BQ27500_LLD_SUB_CMD_SEALED, ((ut_bq27500data_t*)ut->data)->timeout);
+  aosThdMSleep(50);
+  status |= bq27500_lld_std_command(((ut_bq27500data_t*)ut->data)->driver, BQ27500_LLD_STD_CMD_Control, &dst, ((ut_bq27500data_t*)ut->data)->timeout);
+  aosThdMSleep(50);
+  status |= bq27500_lld_sub_command_call(((ut_bq27500data_t*)ut->data)->driver, BQ27500_LLD_SUB_CMD_CONTROL_STATUS, ((ut_bq27500data_t*)ut->data)->timeout);
+  aosThdMSleep(50);
+  status |= bq27500_lld_sub_command_read(((ut_bq27500data_t*)ut->data)->driver, &ctrl.value, ((ut_bq27500data_t*)ut->data)->timeout);
+  if (status == APAL_STATUS_SUCCESS && ctrl.content.ss == 0x1) {
+    aosUtPassed(stream, &result);
+  } else {
+    chprintf(stream, "\tfailed (0x%X)\n", status);
+    aosUtFailedMsg(stream, &result, "0x%08X, ctrl 0x%X\n", status, subdata);
+    ++result.failed;
+  }
+
+  aosUtInfoMsg(stream,"driver object memory footprint: %u bytes\n", sizeof(BQ27500Driver));
+
+  return result;
+}
+
+#endif /* (AMIROOS_CFG_TESTS_ENABLE == true) && defined(AMIROLLD_CFG_USE_BQ27500) */
+
diff --git a/unittests/periphery-lld/src/ut_alld_bq27500_bq24103a.c b/unittests/periphery-lld/src/ut_alld_bq27500_bq24103a.c
new file mode 100644
index 0000000..f5dbfde
--- /dev/null
+++ b/unittests/periphery-lld/src/ut_alld_bq27500_bq24103a.c
@@ -0,0 +1,134 @@
+/*
+AMiRo-OS is an operating system designed for the Autonomous Mini Robot (AMiRo) platform.
+Copyright (C) 2016..2018  Thomas Schöpping et al.
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <ut_alld_bq27500_bq24103a.h>
+
+#if ((AMIROOS_CFG_TESTS_ENABLE == true) && defined(AMIROLLD_CFG_USE_BQ27500) && defined(AMIROLLD_CFG_USE_BQ24103A)) || defined(__DOXYGEN__)
+
+#include <aos_debug.h>
+#include <chprintf.h>
+#include <aos_thread.h>
+
+aos_utresult_t utAlldBq27500Bq24103aFunc(BaseSequentialStream *stream, aos_unittest_t *ut)
+{
+  aosDbgCheck(ut->data != NULL && ((ut_bq27500bq24103adata_t*)ut->data)->bq27500 != NULL && ((ut_bq27500bq24103adata_t*)ut->data)->bq24103a != NULL);
+
+  // local variables
+  aos_utresult_t result = {0, 0};
+  uint32_t status;
+  uint16_t dst;
+  bq27500_lld_flags_t flags;
+  bq27500_lld_batgood_t bg;
+  bq24103a_lld_enable_t charger_enabled;
+  uint32_t sleeptime_s;
+  bq24103a_lld_charge_state_t charge;
+
+  chprintf(stream, "check for battery...\n");
+  status = bq27500_lld_std_command(((ut_bq27500bq24103adata_t*)ut->data)->bq27500, BQ27500_LLD_STD_CMD_Flags, &dst, ((ut_bq27500bq24103adata_t*)ut->data)->timeout);
+  flags.value = dst;
+  chprintf(stream, "\t\tbattery detected: %s\n", flags.content.bat_det ? "yes" : "no");
+  chprintf(stream, "\t\tbattery fully charged: %s\n", flags.content.fc ? "yes" : "no");
+  status |= bq27500_lld_read_batgood(((ut_bq27500bq24103adata_t*)ut->data)->bq27500, &bg);
+  chprintf(stream, "\t\tbattery good: %s\n", (bg == BQ27500_LLD_BATTERY_GOOD) ? "yes" : "no");
+  if (status == APAL_STATUS_SUCCESS) {
+    if (!flags.content.bat_det) {
+      aosUtPassedMsg(stream, &result, "no battery detected, aborting\n");
+      return result;
+    } else if (!bg) {
+      aosUtPassedMsg(stream, &result, "battery damaged, aborting\n");
+      return result;
+    } else {
+      aosUtPassed(stream, &result);
+    }
+  } else {
+    aosUtFailedMsg(stream, &result, "0x%08X; aborting\n", status);
+    return result;
+  }
+
+  chprintf(stream, "get current charger setting...\n");
+  status = bq24103a_lld_get_enabled(((ut_bq27500bq24103adata_t*)ut->data)->bq24103a, &charger_enabled);
+  if (status == APAL_STATUS_SUCCESS) {
+    aosUtPassedMsg(stream, &result, "currently %s\n", (charger_enabled == BQ24103A_LLD_ENABLED) ? "enabled" : "disabled");
+  } else {
+    aosUtFailedMsg(stream, &result, "0x%08X\n", status);
+  }
+
+  // disable/enable charger
+  for (uint8_t iteration = 0; iteration < 2; ++iteration) {
+    if (charger_enabled == BQ24103A_LLD_ENABLED) {
+      sleeptime_s = 120;
+      chprintf(stream, "disable charger...\n");
+      status = bq24103a_lld_set_enabled(((ut_bq27500bq24103adata_t*)ut->data)->bq24103a, BQ24103A_LLD_DISABLED);
+      aosThdSSleep(1);
+      status |= bq24103a_lld_get_enabled(((ut_bq27500bq24103adata_t*)ut->data)->bq24103a, &charger_enabled);
+      status |= (charger_enabled == BQ24103A_LLD_DISABLED) ? 0x0000 : 0x0100;
+      for (uint32_t s = 0; s < sleeptime_s; ++s) {
+        int nchars = chprintf(stream, "%us / %us", s, sleeptime_s);
+        aosThdSSleep(1);
+        for (int c = 0; c < nchars; ++c) {
+          chprintf(stream, "\b \b");
+        }
+      }
+      status |= bq24103a_lld_get_charge_status(((ut_bq27500bq24103adata_t*)ut->data)->bq24103a, &charge);
+      chprintf(stream, "\t\tcharge status: %scharging\n", (charge == BQ24103A_LLD_CHARGING) ? "" : "not ");
+      status |= bq27500_lld_std_command(((ut_bq27500bq24103adata_t*)ut->data)->bq27500, BQ27500_LLD_STD_CMD_TimeToFull, &dst, ((ut_bq27500bq24103adata_t*)ut->data)->timeout);
+      if (status == APAL_STATUS_SUCCESS) {
+        if (dst == 0xFFFF || dst == 0) {
+          aosUtPassedMsg(stream, &result, "battery %sfull\n", flags.content.fc ? "" : "not ");
+        } else {
+          aosUtFailedMsg(stream, &result, "battery %sfull but charging (TTF = %umin)\n", flags.content.fc ? "" : "not ", dst);
+        }
+      } else {
+        aosUtFailedMsg(stream, &result, "0x%08X\n", status);
+      }
+    }
+    else { /* charger_enabled != BQ24103A_LLD_ENABLED */
+      sleeptime_s = 90;
+      chprintf(stream, "enable charger...\n");
+      status = bq24103a_lld_set_enabled(((ut_bq27500bq24103adata_t*)ut->data)->bq24103a, BQ24103A_LLD_ENABLED);
+      aosThdSSleep(1);
+      status |= bq24103a_lld_get_enabled(((ut_bq27500bq24103adata_t*)ut->data)->bq24103a, &charger_enabled);
+      status |= (charger_enabled == BQ24103A_LLD_ENABLED) ? 0x0000 : 0x0100;
+      for (uint32_t s = 0; s < sleeptime_s; ++s) {
+        int nchars = chprintf(stream, "%us / %us", s, sleeptime_s);
+        aosThdSSleep(1);
+        for (int c = 0; c < nchars; ++c) {
+          chprintf(stream, "\b \b");
+        }
+      }
+      status |= bq24103a_lld_get_charge_status(((ut_bq27500bq24103adata_t*)ut->data)->bq24103a, &charge);
+      chprintf(stream, "\t\tcharge status: %scharging\n", (charge == BQ24103A_LLD_CHARGING) ? "" : "not ");
+      status |= bq27500_lld_std_command(((ut_bq27500bq24103adata_t*)ut->data)->bq27500, BQ27500_LLD_STD_CMD_TimeToFull, &dst, ((ut_bq27500bq24103adata_t*)ut->data)->timeout);
+      if (status == APAL_STATUS_SUCCESS) {
+        if (((dst == 0xFFFF || dst == 0) && flags.content.fc) || (!(dst == 0xFFFF || dst == 0) && !flags.content.fc)) {
+          aosUtPassedMsg(stream, &result, "battery %sfull and %scharging (TTF = %umin)\n", flags.content.fc ? "" : "not ", (dst != 0xFFFF || dst != 0) ? "" : "not ", dst);
+        } else {
+          aosUtFailedMsg(stream, &result, "battery %sfull and %scharging (TTF = %umin)\n", flags.content.fc ? "" : "not ", (dst != 0xFFFF || dst != 0) ? "" : "not ", dst);
+        }
+      } else {
+        aosUtFailedMsg(stream, &result, "0x%08X\n", status);
+      }
+    }
+
+    bq24103a_lld_get_enabled(((ut_bq27500bq24103adata_t*)ut->data)->bq24103a, &charger_enabled);
+  }
+
+  return result;
+}
+
+#endif /* (AMIROOS_CFG_TESTS_ENABLE == true) && defined(AMIROLLD_CFG_USE_BQ27500) && defined(AMIROLLD_CFG_USE_BQ24103A) */
diff --git a/unittests/periphery-lld/src/ut_alld_dw1000.c b/unittests/periphery-lld/src/ut_alld_dw1000.c
new file mode 100755
index 0000000..f17071b
--- /dev/null
+++ b/unittests/periphery-lld/src/ut_alld_dw1000.c
@@ -0,0 +1,142 @@
+/*
+AMiRo-OS is an operating system designed for the Autonomous Mini Robot (AMiRo) platform.
+Copyright (C) 2016..2018  Thomas Schöpping et al.
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <ut_alld_dw1000.h>
+
+#if ((AMIROOS_CFG_TESTS_ENABLE == true) && defined(AMIROLLD_CFG_USE_DW1000)) || defined(__DOXYGEN__)
+
+#include <aos_debug.h>
+#include <chprintf.h>
+#include <aos_thread.h>
+// No unit testing! -> Contains the Deca Demo Application
+#include <deca_instance.h>
+#include <alld_dw1000.h>
+#include <alld_dw1000_regs.h>
+#include <math.h>
+
+
+aos_utresult_t utAlldDw1000Func(BaseSequentialStream* stream, aos_unittest_t* ut) {
+
+    aosDbgCheck(ut->data != NULL);
+
+    aos_utresult_t result = {0, 0};
+
+    chprintf(stream, "init DW1000...\n");
+    dwt_initialise(DWT_LOADUCODE, (DW1000Driver*) ut->data);
+    chprintf(stream, "device ID should be: 0xDECA0130\nget device ID...\n");
+    uint32_t actual_deviceId = dwt_readdevid();
+    chprintf(stream, "actual device ID is: 0x%x\n", actual_deviceId);
+    aosThdMSleep(1);
+
+    if (actual_deviceId == DWT_DEVICE_ID){
+      aosUtPassed(stream, &result);
+    } else {
+      aosUtFailed(stream, &result);
+    }
+
+    /*chprintf(stream, "write-read test...\n");
+    uint32_t testvalue = 0x0A;
+    uint16_t panid = 0x00;
+
+    dwt_readfromdevice(PANADR_ID, PANADR_PAN_ID_OFFSET, 2, (uint8_t*) &panid);
+    chprintf(stream, "value PANADR register before write: %x\n", panid);
+    chprintf(stream, "write 0x%x to PANADR register...\n", testvalue);
+    dwt_setpanid(testvalue);
+    dwt_readfromdevice(PANADR_ID, PANADR_PAN_ID_OFFSET, 2, (uint8_t*) &panid);
+
+    chprintf(stream, "PANADR register is now: 0x%x\n", panid);
+
+    if (panid == testvalue){
+      aosUtPassed(stream, &result);
+    } else {
+      aosUtFailed(stream, &result);
+    }
+*/
+
+    dwt_setleds(0x03);
+
+    // RUN DECA-DEMO
+
+    instanceConfig_t chConfig;
+    chConfig.channelNumber = 2;            // channel
+    chConfig.preambleCode = 4;             // preambleCode
+    chConfig.pulseRepFreq = DWT_PRF_16M;   // prf
+    chConfig.dataRate = DWT_BR_6M8;        // datarate
+    chConfig.preambleLen = DWT_PLEN_128;   // preambleLength
+    chConfig.pacSize = DWT_PAC8;           // pacSize
+    chConfig.nsSFD = 0;                    // non-standard SFD
+    chConfig.sfdTO = (129 + 8 - 8);        // SFD timeout
+
+    sfConfig_t sfConfig;
+    sfConfig.slotDuration_ms = (10);        //slot duration in milliseconds (NOTE: the ranging exchange must be able to complete in this time
+                                            //e.g. tag sends a poll, 4 anchors send responses and tag sends the final + processing time
+    sfConfig.numSlots = (10);               //number of slots in the superframe (8 tag slots and 2 used for anchor to anchor ranging),
+    sfConfig.sfPeriod_ms = (10*10);         //in ms => 100 ms frame means 10 Hz location rate
+    sfConfig.tagPeriod_ms = (10*10);        //tag period in ms (sleep time + ranging time)
+    sfConfig.pollTxToFinalTxDly_us = (2500); //poll to final delay in microseconds (needs to be adjusted according to lengths of ranging frames)
+
+    //TODO Disable EXTI IRQ
+    //port_DisableEXT_IRQ();
+
+    // inittestapplication
+    // dwt_softreset(); // already done in instance_init()
+
+    // Set this instance mode (tag/anchor)
+    (void) instance_init(TAG, (DW1000Driver*) ut->data);
+    //int err = instance_init(TAG, (DW1000Driver*) ut->data);
+    (void) instance_readdeviceid();
+    //uint32_t deca_dev_id = instance_readdeviceid();
+
+    // TAG ID 0
+    instance_set_16bit_address(0);
+    // simulate DECA config Mode 2 (DIP 1100000)
+    instance_config(&chConfig, &sfConfig) ;
+
+    //TODO Enable EXTI IRQ
+    //port_EnableEXT_IRQ();
+
+    // Start Ranging
+
+    chprintf(stream, "start ranging...\n");
+
+
+    while(1) {
+        //int n = 0;
+        instance_data_t* inst = instance_get_local_structure_ptr(0);
+
+        int monitor_local = inst->monitor ;
+        int txdiff = (chVTGetSystemTimeX() - inst->timeofTx);
+
+        tag_run();
+        //if delayed TX scheduled but did not happen after expected time then it has failed... (has to be < slot period)
+        //if anchor just go into RX and wait for next message from tags/anchors
+        //if tag handle as a timeout
+        if( (monitor_local == 1) && ( txdiff > inst->slotDuration_ms) )  {
+            inst->wait4ack = 0;
+            tag_process_rx_timeout(inst);
+            inst->monitor = 0;
+        }
+    }
+
+    (void) instance_newrange();
+    //int rx = instance_newrange();
+
+    return result;
+}
+
+#endif /* (AMIROOS_CFG_TESTS_ENABLE == true) && defined(AMIROLLD_CFG_USE_DW1000) */
diff --git a/unittests/periphery-lld/src/ut_alld_hmc5883l.c b/unittests/periphery-lld/src/ut_alld_hmc5883l.c
new file mode 100644
index 0000000..eb4b7ca
--- /dev/null
+++ b/unittests/periphery-lld/src/ut_alld_hmc5883l.c
@@ -0,0 +1,195 @@
+/*
+AMiRo-OS is an operating system designed for the Autonomous Mini Robot (AMiRo) platform.
+Copyright (C) 2016..2018  Thomas Schöpping et al.
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <ut_alld_hmc5883l.h>
+
+#if ((AMIROOS_CFG_TESTS_ENABLE == true) && defined(AMIROLLD_CFG_USE_HMC5883L)) || defined(__DOXYGEN__)
+
+#include <aos_debug.h>
+#include <chprintf.h>
+#include <alld_hmc5883l.h>
+#include <aos_thread.h>
+#include <aos_system.h>
+
+/**
+ * @brief   HMC5338L unit test function.
+ *
+ * @param[in] stream  Stream for intput/output.
+ * @param[in] ut      Unit test object.
+ *
+ * @return            Unit test result value.
+ */
+aos_utresult_t utAlldHmc5883lFunc(BaseSequentialStream* stream, aos_unittest_t* ut)
+{
+  aosDbgCheck(ut->data != NULL && (((ut_hmc5883ldata_t*)(ut->data))->drdyEvtSrc != NULL));
+
+  // local variables
+  aos_utresult_t result = {0, 0};
+  uint32_t status;
+  uint8_t rxbuffer[3];
+  uint8_t data;
+  uint8_t conf = 0x70;
+  hmc5883l_lld_config_t cfg;
+  uint16_t mdata[3];
+  uint8_t state;
+  eventmask_t event_mask = 0;
+  event_listener_t el;
+  uint16_t data_reads = 0;
+  aos_timestamp_t start;
+  aos_timestamp_t t;
+
+  chprintf(stream, "check ID...\n");
+  status = hmc5883l_lld_check(((ut_hmc5883ldata_t*)ut->data)->driver, rxbuffer, 3, ((ut_hmc5883ldata_t*)ut->data)->timeout);
+  if (status == APAL_STATUS_SUCCESS && rxbuffer[0] == HMC5883L_LLD_IDENTIFICATION_A
+                                   && rxbuffer[1] == HMC5883L_LLD_IDENTIFICATION_B
+                                   && rxbuffer[2] == HMC5883L_LLD_IDENTIFICATION_C) {
+    aosUtPassed(stream, &result);
+  } else {
+    chprintf(stream, "\tfailed\n");
+    ++result.failed;
+    chprintf(stream, "\t\tstatus: %d, idA: %d, idB: %d, idC: %d\n", status, rxbuffer[0], rxbuffer[1], rxbuffer[2]);
+    chprintf(stream, "\t\texpected idA: %d, idB: %d, idC: %d\n", HMC5883L_LLD_IDENTIFICATION_A, HMC5883L_LLD_IDENTIFICATION_B, HMC5883L_LLD_IDENTIFICATION_C);
+  }
+
+  chprintf(stream, "read register...\n");
+  status = hmc5883l_lld_read_register(((ut_hmc5883ldata_t*)ut->data)->driver, HMC5883L_LLD_REGISTER_IDENTIFICATION_A, &data, 1, ((ut_hmc5883ldata_t*)ut->data)->timeout);
+  if ((status == APAL_STATUS_OK || status == APAL_STATUS_WARNING) && data == HMC5883L_LLD_IDENTIFICATION_A) {
+    aosUtPassed(stream, &result);
+  } else {
+    aosUtFailedMsg(stream, &result, "0x%08X\n", status);
+  }
+
+  chprintf(stream, "write register...\n");
+  status = hmc5883l_lld_write_register(((ut_hmc5883ldata_t*)ut->data)->driver, HMC5883L_LLD_REGISTER_CONFIG_A, &conf, 1, ((ut_hmc5883ldata_t*)ut->data)->timeout);
+  status |= hmc5883l_lld_read_register(((ut_hmc5883ldata_t*)ut->data)->driver, HMC5883L_LLD_REGISTER_CONFIG_A, &data, 1, ((ut_hmc5883ldata_t*)ut->data)->timeout);
+  if ((status == APAL_STATUS_SUCCESS || status == APAL_STATUS_WARNING) && data == 0x70) {
+    aosUtPassed(stream, &result);
+  } else {
+    aosUtFailedMsg(stream, &result, "0x%08X\n, data: d", status, data);
+  }
+
+  chprintf(stream, "read configuration\n");
+  status = hmc5883l_lld_read_config(((ut_hmc5883ldata_t*)ut->data)->driver, &cfg, ((ut_hmc5883ldata_t*)ut->data)->timeout);
+  if (status == APAL_STATUS_SUCCESS) {
+    aosUtPassed(stream, &result);
+  } else {
+    aosUtFailedMsg(stream, &result, "0x%08X\n", status);
+  }
+
+  chprintf(stream, "write configuration\n");
+  cfg.avg = HMC5883L_LLD_AVG1;
+  cfg.outrate = HMC5883L_LLD_75_HZ;
+  cfg.mbias = HMC5883L_LLD_MB_NORMAL;
+  cfg.gain = HMC5883L_LLD_GN_0_GA;
+  cfg.highspeed = HMC5883L_LLD_HS_DISABLE;
+  cfg.mode = HMC5883L_LLD_MM_CONTINUOUS;
+  status = hmc5883l_lld_write_config(((ut_hmc5883ldata_t*)ut->data)->driver, cfg, ((ut_hmc5883ldata_t*)ut->data)->timeout);
+  status |= hmc5883l_lld_read_config(((ut_hmc5883ldata_t*)ut->data)->driver, &cfg, ((ut_hmc5883ldata_t*)ut->data)->timeout);
+  if (status == APAL_STATUS_OK &&
+      cfg.avg == HMC5883L_LLD_AVG1 &&
+      cfg.outrate == HMC5883L_LLD_75_HZ &&
+      cfg.mbias == HMC5883L_LLD_MB_NORMAL &&
+      cfg.gain == HMC5883L_LLD_GN_0_GA &&
+      cfg.highspeed == HMC5883L_LLD_HS_DISABLE &&
+      cfg.mode == HMC5883L_LLD_MM_CONTINUOUS) {
+    aosUtPassed(stream, &result);
+  } else {
+    aosUtFailedMsg(stream, &result, "0x%08X\n", status);
+  }
+
+  chprintf(stream, "read all data for five seconds...\n");
+  status = hmc5883l_lld_set_register(((ut_hmc5883ldata_t*)ut->data)->driver,HMC5883L_LLD_REGISTER_MODE,HMC5883L_LLD_MM_CONTINUOUS,((ut_hmc5883ldata_t*)ut->data)->timeout);
+  for (uint8_t i = 0; i < 5; ++i) {
+    status |= hmc5883l_lld_read_data(((ut_hmc5883ldata_t*)ut->data)->driver, mdata, ((ut_hmc5883ldata_t*)ut->data)->timeout);
+    chprintf(stream, "\t\tX = 0x%04X\tY = 0x%04X\tZ = 0x%04X\n",mdata[0],mdata[1],mdata[2]);
+    aosThdSSleep(1);
+  }
+  if (status == APAL_STATUS_OK) {
+    aosUtPassed(stream, &result);
+  } else {
+    aosUtFailedMsg(stream, &result, "0x%08X\n", status);
+  }
+
+  chprintf(stream, "read status...\n");
+  status = hmc5883l_lld_read_lock(((ut_hmc5883ldata_t*)ut->data)->driver, &state, ((ut_hmc5883ldata_t*)ut->data)->timeout);
+  chprintf(stream, "\t\tsensor lock: %d\n", state);
+  status |= hmc5883l_lld_read_rdy(((ut_hmc5883ldata_t*)ut->data)->driver, &state, ((ut_hmc5883ldata_t*)ut->data)->timeout);
+  chprintf(stream, "\t\tsensor rdy: %d\n", state);
+  status |= hmc5883l_lld_read_status(((ut_hmc5883ldata_t*)ut->data)->driver, &state, ((ut_hmc5883ldata_t*)ut->data)->timeout);
+  chprintf(stream, "\t\tsensor status: %d\n", state);
+  if (status == APAL_STATUS_OK || status == APAL_STATUS_WARNING) {
+    aosUtPassed(stream, &result);
+  } else {
+    aosUtFailedMsg(stream, &result, "0x%08X\n", status);
+  }
+
+  chprintf(stream, "interrupt (partial data read)...\n");
+  chEvtRegister(((ut_hmc5883ldata_t*)ut->data)->drdyEvtSrc, &el, 0);
+  status = hmc5883l_lld_write_config(((ut_hmc5883ldata_t*)ut->data)->driver, cfg, ((ut_hmc5883ldata_t*)ut->data)->timeout);
+  aosThdSSleep(1);
+  status |= hmc5883l_lld_read_data(((ut_hmc5883ldata_t*)ut->data)->driver, mdata, ((ut_hmc5883ldata_t*)ut->data)->timeout);
+  aosThdMSleep(10);
+  event_mask = chEvtWaitOneTimeout(EVENT_MASK(0), TIME_IMMEDIATE);
+  status |= hmc5883l_lld_read_register(((ut_hmc5883ldata_t*)ut->data)->driver, HMC5883L_LLD_REGISTER_DATA_OUT_X_MSB, &data, 1, ((ut_hmc5883ldata_t*)ut->data)->timeout);
+  aosThdMSleep(10);
+  status |= hmc5883l_lld_read_register(((ut_hmc5883ldata_t*)ut->data)->driver, HMC5883L_LLD_REGISTER_DATA_OUT_X_LSB, &data, 1, ((ut_hmc5883ldata_t*)ut->data)->timeout);
+  aosThdMSleep(10);
+  event_mask = chEvtWaitOneTimeout(EVENT_MASK(0), TIME_IMMEDIATE);
+  chprintf(stream, "\t\teventmask = 0x%08X (should be 0)\n", event_mask);
+  if (event_mask != EVENT_MASK(0)) {
+    aosUtPassed(stream, &result);
+  } else {
+    aosUtFailed(stream, &result);
+  }
+
+  chprintf(stream, "interrupt (full data read)...\n");
+  status |= hmc5883l_lld_read_data(((ut_hmc5883ldata_t*)ut->data)->driver, mdata, ((ut_hmc5883ldata_t*)ut->data)->timeout);
+  event_mask = chEvtWaitOneTimeout(EVENT_MASK(0), chTimeUS2I(100 * MICROSECONDS_PER_MILLISECOND));
+  chprintf(stream, "\t\teventmask = 0x%08X (should be 1)\n", event_mask);
+  if (event_mask == EVENT_MASK(0)) {
+    aosUtPassed(stream, &result);
+  } else {
+    aosUtFailed(stream, &result);
+  }
+
+  chprintf(stream, "read data based on interrupt...\n");
+  status = hmc5883l_lld_read_config(((ut_hmc5883ldata_t*)ut->data)->driver, &cfg, ((ut_hmc5883ldata_t*)ut->data)->timeout);
+  uint8_t mode = HMC5883L_LLD_MM_SINGLE;
+  cfg.mode = mode;
+  status |= hmc5883l_lld_write_config(((ut_hmc5883ldata_t*)ut->data)->driver, cfg, ((ut_hmc5883ldata_t*)ut->data)->timeout);
+  aosSysGetUptime(&start);
+  aosSysGetUptime(&t);
+  status |= hmc5883l_lld_read_data(((ut_hmc5883ldata_t*)ut->data)->driver, mdata, ((ut_hmc5883ldata_t*)ut->data)->timeout);
+  while (t - start < MICROSECONDS_PER_SECOND) {
+    event_mask = chEvtWaitOneTimeout(EVENT_MASK(0), chTimeUS2I(1000));
+    if (event_mask == EVENT_MASK(0)) {
+      status |= hmc5883l_lld_read_data(((ut_hmc5883ldata_t*)ut->data)->driver, mdata, ((ut_hmc5883ldata_t*)ut->data)->timeout);
+      data_reads++;
+      status = hmc5883l_lld_write_register(((ut_hmc5883ldata_t*)ut->data)->driver, HMC5883L_LLD_REGISTER_CONFIG_A+2, &mode, 1, ((ut_hmc5883ldata_t*)ut->data)->timeout);
+    }
+    aosSysGetUptime(&t);
+  }
+  chEvtUnregister(((ut_hmc5883ldata_t*)ut->data)->drdyEvtSrc, &el);
+  aosUtInfoMsg(stream,"Read data %u times in a second\n", data_reads);
+
+  aosUtInfoMsg(stream,"driver object memory footprint: %u bytes\n", sizeof(HMC5883LDriver));
+
+  return result;
+}
+
+#endif /* (AMIROOS_CFG_TESTS_ENABLE == true) && defined(AMIROLLD_CFG_USE_HMC5883L) */
diff --git a/unittests/periphery-lld/src/ut_alld_ina219.c b/unittests/periphery-lld/src/ut_alld_ina219.c
new file mode 100644
index 0000000..06d0470
--- /dev/null
+++ b/unittests/periphery-lld/src/ut_alld_ina219.c
@@ -0,0 +1,169 @@
+/*
+AMiRo-OS is an operating system designed for the Autonomous Mini Robot (AMiRo) platform.
+Copyright (C) 2016..2018  Thomas Schöpping et al.
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <ut_alld_ina219.h>
+
+#if ((AMIROOS_CFG_TESTS_ENABLE == true) && defined(AMIROLLD_CFG_USE_INA219)) || defined(__DOXYGEN__)
+
+#include <aos_debug.h>
+#include <chprintf.h>
+#include <aos_thread.h>
+#include <alld_ina219.h>
+#include <math.h>
+
+aos_utresult_t utAlldIna219Func(BaseSequentialStream* stream, aos_unittest_t* ut)
+{
+  aosDbgCheck(ut->data != NULL && ((ut_ina219data_t*)(ut->data))->inad != NULL);
+
+  // local variables
+  aos_utresult_t result = {0, 0};
+  uint32_t status;
+  uint16_t data[6];
+  uint16_t write_data = 0x1011;
+  uint16_t new_data[6];
+  uint16_t reset_data;
+  uint16_t test_calib = 0;
+  int16_t usensor_data = 0;
+  uint16_t busready = 0;
+  uint32_t power = 0;
+  int32_t shunt;
+  uint32_t bus;
+
+  chprintf(stream, "read registers...\n");
+  status = ina219_lld_read_register(((ut_ina219data_t*)ut->data)->inad, INA219_LLD_REGISTER_CONFIGURATION, data, 6, ((ut_ina219data_t*)ut->data)->timeout);
+  if (status == APAL_STATUS_SUCCESS) {
+    aosUtPassed(stream, &result);
+  } else {
+    aosUtFailed(stream, &result);
+  }
+
+  chprintf(stream, "write registers...\n");
+  status = ina219_lld_write_register(((ut_ina219data_t*)ut->data)->inad, INA219_LLD_REGISTER_CONFIGURATION, &write_data, 1, ((ut_ina219data_t*)ut->data)->timeout);
+  status |= ina219_lld_read_register(((ut_ina219data_t*)ut->data)->inad, INA219_LLD_REGISTER_CONFIGURATION, new_data, 6, ((ut_ina219data_t*)ut->data)->timeout);
+  if (status == APAL_STATUS_SUCCESS && new_data[0] == write_data) {
+    uint8_t errors = 0;
+    for (uint8_t dataIdx = 1; dataIdx < 6; dataIdx++) {
+      if (new_data[dataIdx] != data[dataIdx]) {
+        ++errors;
+      }
+    }
+    if (errors == 0) {
+      aosUtPassed(stream, &result);
+    } else {
+      aosUtFailed(stream, &result);
+    }
+  } else {
+    aosUtFailed(stream, &result);
+  }
+
+  chprintf(stream, "reset...\n");
+  status = ina219_lld_reset(((ut_ina219data_t*)ut->data)->inad, ((ut_ina219data_t*)ut->data)->timeout);
+  status |= ina219_lld_read_register(((ut_ina219data_t*)ut->data)->inad, INA219_LLD_REGISTER_CONFIGURATION, &reset_data, 1, ((ut_ina219data_t*)ut->data)->timeout);
+  if (status == APAL_STATUS_SUCCESS && reset_data == 0x399F) {
+    aosUtPassed(stream, &result);
+  } else {
+    chprintf(stream, "\tfailed\n");
+    ++result.failed;
+  }
+
+  chprintf(stream, "read config...\n");
+  ina219_lld_cfg_t ina_config;
+  status = ina219_lld_read_config(((ut_ina219data_t*)ut->data)->inad, &ina_config, ((ut_ina219data_t*)ut->data)->timeout);
+  if (status == APAL_STATUS_SUCCESS) {
+    aosUtPassed(stream, &result);
+  } else {
+    aosUtFailed(stream, &result);
+  }
+
+  chprintf(stream, "write config...\n");
+  ina_config.data = 0x7FFu;
+  status = ina219_lld_write_config(((ut_ina219data_t*)ut->data)->inad, ina_config, ((ut_ina219data_t*)ut->data)->timeout);
+  if (status == APAL_STATUS_SUCCESS) {
+    aosUtPassed(stream, &result);
+  } else {
+    aosUtFailed(stream, &result);
+  }
+
+
+  chprintf(stream, "calibrate...\n");
+  ina219_lld_calib_input_t calib_in;
+  calib_in.shunt_resistance_0 = 0.1;
+  calib_in.max_expected_current_A = 0.075;
+  calib_in.current_lsb_uA = 10;
+  calib_in.cfg_reg = ina_config;
+  ina219_lld_calib_output_t calib_out;
+  status = ina219_lld_calibration(((ut_ina219data_t*)ut->data)->inad, &calib_in, &calib_out);
+  status |= ina219_lld_write_calibration(((ut_ina219data_t*)ut->data)->inad, calib_out.calibration & 0xFFFEu, ((ut_ina219data_t*)ut->data)->timeout);
+  status |= ina219_lld_write_calibration(((ut_ina219data_t*)ut->data)->inad, 0xA000, ((ut_ina219data_t*)ut->data)->timeout);
+  ina219_lld_cfg_t test_config;
+  ((ut_ina219data_t*)ut->data)->inad->current_lsb_uA = 0xA;
+  status |= ina219_lld_read_config(((ut_ina219data_t*)ut->data)->inad, &test_config, ((ut_ina219data_t*)ut->data)->timeout);
+  status |= ina219_lld_read_calibration(((ut_ina219data_t*)ut->data)->inad, &test_calib, ((ut_ina219data_t*)ut->data)->timeout);
+  while (!busready || power == 0) {
+    aosThdMSleep(20);
+    status |= ina219_lld_bus_conversion_ready(((ut_ina219data_t*)ut->data)->inad, &busready, ((ut_ina219data_t*)ut->data)->timeout);
+    status |= ina219_lld_read_power(((ut_ina219data_t*)ut->data)->inad, &power, ((ut_ina219data_t*)ut->data)->timeout);
+  }
+  if (status == APAL_STATUS_SUCCESS) {
+    aosUtPassed(stream, &result);
+  } else {
+    aosUtFailed(stream, &result);
+  }
+
+  chprintf(stream, "read shunt voltage...\n");
+  status = ina219_lld_read_shunt_voltage(((ut_ina219data_t*)ut->data)->inad, &shunt, ((ut_ina219data_t*)ut->data)->timeout);
+  chprintf(stream, "\t\tshunt voltage: %fV\n", (float)shunt/1000000.f);
+  if (status == APAL_STATUS_SUCCESS) {
+    aosUtPassed(stream, &result);
+  } else {
+    aosUtFailed(stream, &result);
+  }
+
+  chprintf(stream, "read bus voltage (%u%% tolerance)...\n", (uint8_t)(((ut_ina219data_t*)ut->data)->tolerance * 100.f + 0.5f));
+  status = ina219_lld_read_bus_voltage(((ut_ina219data_t*)ut->data)->inad, &bus, ((ut_ina219data_t*)ut->data)->timeout);
+  chprintf(stream, "\t\tbus voltage: %fV\n", (float)bus/1000000.f);
+  if ((status == APAL_STATUS_SUCCESS) && (fabs(((float)bus/1000000.f) - ((ut_ina219data_t*)ut->data)->v_expected) < ((ut_ina219data_t*)ut->data)->v_expected * ((ut_ina219data_t*)ut->data)->tolerance)) {
+    aosUtPassed(stream, &result);
+  } else {
+    aosUtFailed(stream, &result);
+  }
+
+  chprintf(stream, "read power...\n");
+  status = ina219_lld_read_power(((ut_ina219data_t*)ut->data)->inad, &power, ((ut_ina219data_t*)ut->data)->timeout);
+  chprintf(stream, "\t\tpower: %fW\n", (float)(power)/1000000.f);
+  if (status == APAL_STATUS_SUCCESS) {
+    aosUtPassed(stream, &result);
+  } else {
+    aosUtFailed(stream, &result);
+  }
+
+  chprintf(stream, "read current...\n");
+  status = ina219_lld_read_current(((ut_ina219data_t*)ut->data)->inad, &usensor_data, ((ut_ina219data_t*)ut->data)->timeout);
+  chprintf(stream, "\t\tcurrent: %fA\n", (float)(usensor_data)/1000000.f);
+  if (status == APAL_STATUS_SUCCESS) {
+    aosUtPassed(stream, &result);
+  } else {
+    aosUtFailed(stream, &result);
+  }
+
+  aosUtInfoMsg(stream, "driver object memory footprint: %u bytes\n", sizeof(INA219Driver));
+
+  return result;
+}
+
+#endif /* (AMIROOS_CFG_TESTS_ENABLE == true) && defined(AMIROLLD_CFG_USE_INA219) */
diff --git a/unittests/periphery-lld/src/ut_alld_l3g4200d.c b/unittests/periphery-lld/src/ut_alld_l3g4200d.c
new file mode 100644
index 0000000..bbca210
--- /dev/null
+++ b/unittests/periphery-lld/src/ut_alld_l3g4200d.c
@@ -0,0 +1,269 @@
+/*
+AMiRo-OS is an operating system designed for the Autonomous Mini Robot (AMiRo) platform.
+Copyright (C) 2016..2018  Thomas Schöpping et al.
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <ut_alld_l3g4200d.h>
+
+#if ((AMIROOS_CFG_TESTS_ENABLE == true) && defined(AMIROLLD_CFG_USE_L3G4200D)) || defined(__DOXYGEN__)
+
+#include <aos_debug.h>
+#include <chprintf.h>
+#include <aos_thread.h>
+#include <alld_l3g4200d.h>
+
+/**
+ * @brief   L3G4200D unit test function.
+ *
+ * @param[in] stream  Stream for input/output.
+ * @param[in] ut      Unit test object.
+ *
+ * @return            Unit test result value.
+ */
+aos_utresult_t utAlldL3g4200dFunc(BaseSequentialStream* stream, aos_unittest_t* ut)
+{
+  aosDbgCheck(ut->data != NULL && ((ut_l3g4200ddata_t*)(ut->data)) != NULL);
+
+  // local variables
+  aos_utresult_t result = {0, 0};
+  uint32_t status;
+  uint8_t data = 0;
+  uint8_t write_data[5];
+  uint8_t read_data[5];
+  int16_t sdata[3];
+  uint8_t status_reg;
+  eventmask_t event_mask;
+  bool success = false;
+  uint8_t fifo = 0x5F;
+  event_listener_t el;
+
+  for (uint8_t dataIdx = 0; dataIdx < 4; dataIdx++) {
+    write_data[dataIdx] = (dataIdx+1)*11;
+  }
+  write_data[4] = 0;
+
+  chprintf(stream, "check identity...\n");
+  status = l3g4200d_lld_read_register(((ut_l3g4200ddata_t*)(ut->data))->l3gd, L3G4200D_LLD_REGISTER_WHO_AM_I, &data, 1);
+  if(status == APAL_STATUS_SUCCESS && data == L3G4200D_LLD_WHO_AM_I){
+    aosUtPassed(stream, &result);
+  } else {
+    aosUtFailedMsg(stream, &result, "0x%08X, data: %d\n", status, data);
+  }
+
+  chprintf(stream, "write register...\n");
+  status = l3g4200d_lld_write_register(((ut_l3g4200ddata_t*)(ut->data))->l3gd, L3G4200D_LLD_REGISTER_CTRL_REG1, write_data, 1);
+  if (status == APAL_STATUS_SUCCESS) {
+    aosUtPassed(stream, &result);
+  } else {
+    aosUtFailed(stream, &result);
+  }
+
+  chprintf(stream, "read register...\n");
+  status = l3g4200d_lld_read_register(((ut_l3g4200ddata_t*)(ut->data))->l3gd, L3G4200D_LLD_REGISTER_CTRL_REG1, &data, 1);
+  if (status == APAL_STATUS_SUCCESS && data == write_data[0]) {
+    aosUtPassed(stream, &result);
+  } else {
+    aosUtFailedMsg(stream, &result, "0x%08X, data: %d\n", status, data);
+  }
+
+  chprintf(stream, "write multiple registers...\n");
+  status = l3g4200d_lld_write_register(((ut_l3g4200ddata_t*)(ut->data))->l3gd, L3G4200D_LLD_REGISTER_CTRL_REG1, write_data, 5);
+  if (status == APAL_STATUS_SUCCESS) {
+    aosUtPassed(stream, &result);
+  } else {
+    aosUtFailed(stream, &result);
+  }
+
+  chprintf(stream, "read multiple registers...\n");
+  status = l3g4200d_lld_read_register(((ut_l3g4200ddata_t*)(ut->data))->l3gd, L3G4200D_LLD_REGISTER_CTRL_REG1, read_data, 5);
+  uint8_t errors = 0;
+  for (uint8_t dataIdx = 0; dataIdx < 5; dataIdx++) {
+    if (read_data[dataIdx] != write_data[dataIdx]) {
+      ++errors;
+    }
+  }
+  if (status == APAL_STATUS_SUCCESS && errors == 0) {
+    aosUtPassed(stream, &result);
+  } else {
+    for (uint8_t dataIdx = 0; dataIdx < 5; dataIdx++) {
+      chprintf(stream, "\t\tStatus: %d, CTRL_REG%d: %d, write_data: %d\n", status, dataIdx+1, read_data[dataIdx], write_data[dataIdx]);
+    }
+    aosUtFailedMsg(stream, &result, "0x%08X, errors: %d\n", status, errors);
+  }
+
+  chprintf(stream, "read config...\n");
+  l3g4200d_lld_cfg_t cfg;
+  status = l3g4200d_lld_read_config(((ut_l3g4200ddata_t*)(ut->data))->l3gd, &cfg);
+  if (status == APAL_STATUS_SUCCESS) {
+    aosUtPassed(stream, &result);
+  } else {
+    aosUtFailed(stream, &result);
+  }
+
+  chprintf(stream, "write config...\n");
+  cfg.registers.ctrl_reg1 = L3G4200D_LLD_PD | L3G4200D_LLD_DR_100_HZ | L3G4200D_LLD_BW_12_5 | L3G4200D_LLD_ZEN | L3G4200D_LLD_YEN | L3G4200D_LLD_XEN;
+  //cfg.registers.ctrl_reg1 = L3G4200D_LLD_PD | L3G4200D_LLD_DR_800_HZ | L3G4200D_LLD_BW_20 | L3G4200D_LLD_ZEN | L3G4200D_LLD_YEN | L3G4200D_LLD_XEN;
+  cfg.registers.ctrl_reg3 = 0x07;
+  cfg.registers.ctrl_reg5 |= L3G4200D_LLD_FIFO_EN;
+  status = l3g4200d_lld_write_config(((ut_l3g4200ddata_t*)(ut->data))->l3gd, cfg);
+  uint8_t reg1 = cfg.data[0];
+  status |= l3g4200d_lld_read_config(((ut_l3g4200ddata_t*)(ut->data))->l3gd, &cfg);
+  if (status == APAL_STATUS_SUCCESS && cfg.data[0] == reg1) {
+    aosUtPassed(stream, &result);
+  } else {
+    aosUtFailed(stream, &result);
+  }
+
+  chprintf(stream, "read gyro data for five seconds...\n");
+  status = APAL_STATUS_OK;
+  for (uint8_t i = 0; i < 5; ++i) {
+    status |= l3g4200d_lld_read_all_data(((ut_l3g4200ddata_t*)(ut->data))->l3gd, sdata, &cfg);
+    chprintf(stream, "\t\tX = %6d\tY = %6d\tZ = %6d\n", sdata[0], sdata[1], sdata[2]);
+    aosThdSSleep(1);
+  }
+  if (status == APAL_STATUS_SUCCESS) {
+    aosUtPassed(stream, &result);
+  } else {
+    aosUtFailed(stream, &result);
+  }
+
+  chprintf(stream, "read X axis for five seconds...\n");
+  status = APAL_STATUS_SUCCESS;
+  for (uint32_t i = 0; i <= 5; i++) {
+    status |= l3g4200d_lld_read_data(((ut_l3g4200ddata_t*)(ut->data))->l3gd, &(sdata[0]), L3G4200D_LLD_X_AXIS, &cfg);
+    chprintf(stream, "\t\tX = %6d\n", sdata[0]);
+    aosThdSSleep(1);
+  }
+  if (status == APAL_STATUS_SUCCESS) {
+    aosUtPassed(stream, &result);
+  } else {
+    aosUtFailed(stream, &result);
+  }
+
+  chprintf(stream, "read Y axis for five seconds...\n");
+  status = APAL_STATUS_SUCCESS;
+  for (uint32_t i = 0; i <= 5; i++) {
+    status |= l3g4200d_lld_read_data(((ut_l3g4200ddata_t*)(ut->data))->l3gd, &(sdata[0]), L3G4200D_LLD_Y_AXIS, &cfg);
+    chprintf(stream, "\t\tY = %6d\n", sdata[0]);
+    aosThdSSleep(1);
+  }
+  if (status == APAL_STATUS_SUCCESS) {
+    aosUtPassed(stream, &result);
+  } else {
+    aosUtFailed(stream, &result);
+  }
+
+  chprintf(stream, "read Z axis for five seconds...\n");
+  status = APAL_STATUS_SUCCESS;
+  for (uint32_t i = 0; i <= 5; i++) {
+    status |= l3g4200d_lld_read_data(((ut_l3g4200ddata_t*)(ut->data))->l3gd, &(sdata[0]), L3G4200D_LLD_Z_AXIS, &cfg);
+    chprintf(stream, "\t\tZ = %6d\n", sdata[0]);
+    aosThdSSleep(1);
+  }
+  if (status == APAL_STATUS_SUCCESS) {
+    aosUtPassed(stream, &result);
+  } else {
+    aosUtFailed(stream, &result);
+  }
+  aosThdMSleep(10);
+
+  chprintf(stream, "read status register...\n");
+  status = l3g4200d_lld_read_status_register(((ut_l3g4200ddata_t*)(ut->data))->l3gd, &status_reg);
+  if (status == APAL_STATUS_SUCCESS) {
+    aosUtPassed(stream, &result);
+  } else {
+    aosUtFailed(stream, &result);
+  }
+
+  chprintf(stream, "read interrupt config...\n");
+  l3g4200d_lld_int_cfg_t int_cfg;
+  status = l3g4200d_lld_read_int_config(((ut_l3g4200ddata_t*)(ut->data))->l3gd, &int_cfg);
+  if (status == APAL_STATUS_SUCCESS) {
+    aosUtPassed(stream, &result);
+  } else {
+    aosUtFailed(stream, &result);
+  }
+
+  chprintf(stream, "write interrupt config...\n");
+  int_cfg.registers.int1_tsh_xh = 10;
+  status = l3g4200d_lld_write_int_config(((ut_l3g4200ddata_t*)(ut->data))->l3gd, int_cfg);
+  l3g4200d_lld_int_cfg_t int_cfg2;
+  status |= l3g4200d_lld_read_int_config(((ut_l3g4200ddata_t*)(ut->data))->l3gd, &int_cfg2);
+  if (status == APAL_STATUS_SUCCESS && int_cfg.registers.int1_tsh_xh == 10) {
+    aosUtPassed(stream, &result);
+  } else {
+    aosUtFailed(stream, &result);
+  }
+
+  chprintf(stream, "interrupt test: read fifo until empty...\n");
+  chEvtRegister(((ut_l3g4200ddata_t*)(ut->data))->src, &el, 0);
+  status = l3g4200d_lld_write_fifo_ctrl_register(((ut_l3g4200ddata_t*)(ut->data))->l3gd,fifo);
+  fifo = 0;
+  status |= l3g4200d_lld_read_fifo_ctrl_register(((ut_l3g4200ddata_t*)(ut->data))->l3gd,&fifo);
+  status |= l3g4200d_lld_read_all_data(((ut_l3g4200ddata_t*)(ut->data))->l3gd, sdata, &cfg);
+  chEvtGetAndClearFlags(&el);
+  aosThdSSleep(1);
+  chEvtGetAndClearFlags(&el);
+  success = false;
+  for (uint8_t i = 0; i < 200; i++) {
+    status |= l3g4200d_lld_read_all_data(((ut_l3g4200ddata_t*)(ut->data))->l3gd, sdata, &cfg);
+    event_mask = chEvtWaitAnyTimeout(~0, TIME_IMMEDIATE);
+    status |= l3g4200d_lld_read_fifo_src_register(((ut_l3g4200ddata_t*)(ut->data))->l3gd,&fifo);
+    if (event_mask != 0 && ((fifo & L3G4200D_LLD_EMPTY) || fifo == 0)) {
+      success = true;
+      break;
+    }
+    aosThdMSleep(1);
+  }
+  if (status == APAL_STATUS_SUCCESS && success) {
+    aosUtPassed(stream, &result);
+  } else {
+    aosUtFailed(stream, &result);
+  }
+
+  fifo = 0x4A;
+  status |= l3g4200d_lld_write_fifo_ctrl_register(((ut_l3g4200ddata_t*)(ut->data))->l3gd,fifo);
+  cfg.registers.ctrl_reg1 = L3G4200D_LLD_PD | L3G4200D_LLD_DR_800_HZ | L3G4200D_LLD_BW_20 | L3G4200D_LLD_ZEN | L3G4200D_LLD_YEN | L3G4200D_LLD_XEN;
+  cfg.registers.ctrl_reg3 = 0x04;
+  status |= l3g4200d_lld_write_config(((ut_l3g4200ddata_t*)(ut->data))->l3gd, cfg);
+  chprintf(stream, "interrupt test: wait until wtm reached...\n");
+  for (uint8_t i = 0; i < 200; i++) {
+    status |= l3g4200d_lld_read_all_data(((ut_l3g4200ddata_t*)(ut->data))->l3gd, sdata, &cfg);
+    event_mask = chEvtWaitAnyTimeout(~0, TIME_IMMEDIATE);
+    status |= l3g4200d_lld_read_fifo_src_register(((ut_l3g4200ddata_t*)(ut->data))->l3gd,&fifo);
+    if (event_mask != 0 && (fifo & L3G4200D_LLD_WTM)) {
+      success = true;
+      break;
+    }
+    aosThdMSleep(10);
+  }
+  if (status == APAL_STATUS_SUCCESS && success) {
+    aosUtPassed(stream, &result);
+  } else {
+    aosUtFailed(stream, &result);
+  }
+
+  chEvtUnregister(((ut_l3g4200ddata_t*)(ut->data))->src, &el);
+  aosThdMSleep(10);
+
+  aosUtInfoMsg(stream, "driver object memory footprint: %u bytes\n", sizeof(L3G4200DDriver));
+
+  return result;
+}
+
+#endif /* (AMIROOS_CFG_TESTS_ENABLE == true) && defined(AMIROLLD_CFG_USE_L3G4200D) */
+
+
diff --git a/unittests/periphery-lld/src/ut_alld_led.c b/unittests/periphery-lld/src/ut_alld_led.c
new file mode 100644
index 0000000..53ac634
--- /dev/null
+++ b/unittests/periphery-lld/src/ut_alld_led.c
@@ -0,0 +1,86 @@
+/*
+AMiRo-OS is an operating system designed for the Autonomous Mini Robot (AMiRo) platform.
+Copyright (C) 2016..2018  Thomas Schöpping et al.
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <ut_alld_led.h>
+
+#if ((AMIROOS_CFG_TESTS_ENABLE == true) && defined(AMIROLLD_CFG_USE_LED)) || defined(__DOXYGEN__)
+
+#include <aos_debug.h>
+#include <chprintf.h>
+#include <alld_led.h>
+#include <aos_thread.h>
+
+/**
+ * @brief   LED unit test function.
+ *
+ * @param[in] stream  Stream for input/output.
+ * @param[in] ut      Unit test object.
+ *
+ * @return            Unit test result value.
+ */
+aos_utresult_t utAlldLedFunc(BaseSequentialStream* stream, aos_unittest_t* ut)
+{
+  aosDbgCheck(ut->data != NULL);
+
+  // local variables
+  aos_utresult_t result = {0, 0};
+  uint32_t status = AOS_OK;
+
+  chprintf(stream, "lighting up for two seconds...\n");
+  led_lld_state_t state = LED_LLD_STATE_ON;
+  status = led_lld_set((LEDDriver*)ut->data, state);
+  aosThdSSleep(2);
+  status |= led_lld_get((LEDDriver*)ut->data, &state);
+  if (status == APAL_STATUS_OK && state == LED_LLD_STATE_ON) {
+    aosUtPassed(stream, &result);
+  } else {
+    aosUtFailed(stream, &result);
+  }
+
+  chprintf(stream, "turning off for two seconds...\n");
+  state = LED_LLD_STATE_OFF;
+  status = led_lld_set((LEDDriver*)ut->data, state);
+  aosThdSSleep(2);
+  status |= led_lld_get((LEDDriver*)ut->data, &state);
+  if (status == APAL_STATUS_OK && state == LED_LLD_STATE_OFF) {
+    aosUtPassed(stream, &result);
+  } else {
+    aosUtFailed(stream, &result);
+  }
+
+  chprintf(stream, "toggling for two seconds...\n");
+  status = led_lld_set((LEDDriver*)ut->data, LED_LLD_STATE_ON);
+  for (uint32_t i = 0; i < 2000/100; ++i) {
+    status |= led_lld_toggle((LEDDriver*)ut->data);
+    status |= led_lld_get((LEDDriver*)ut->data, &state);
+    status |= ((uint8_t)state != (i & 0x01u)) ? APAL_STATUS_ERROR : APAL_STATUS_OK;
+    aosThdMSleep(100);
+  }
+  status = led_lld_set((LEDDriver*)ut->data, LED_LLD_STATE_OFF);
+  if (status == APAL_STATUS_OK) {
+    aosUtPassed(stream, &result);
+  } else {
+    aosUtFailed(stream, &result);
+  }
+
+  aosUtInfoMsg(stream,"driver object memory footprint: %u bytes\n", sizeof(LEDDriver));
+
+  return result;
+}
+
+#endif /* (AMIROOS_CFG_TESTS_ENABLE == true) && defined(AMIROLLD_CFG_USE_LED) */
diff --git a/unittests/periphery-lld/src/ut_alld_lis331dlh.c b/unittests/periphery-lld/src/ut_alld_lis331dlh.c
new file mode 100644
index 0000000..56378fa
--- /dev/null
+++ b/unittests/periphery-lld/src/ut_alld_lis331dlh.c
@@ -0,0 +1,236 @@
+/*
+AMiRo-OS is an operating system designed for the Autonomous Mini Robot (AMiRo) platform.
+Copyright (C) 2016..2018  Thomas Schöpping et al.
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <ut_alld_lis331dlh.h>
+
+#if ((AMIROOS_CFG_TESTS_ENABLE == true) && defined(AMIROLLD_CFG_USE_LIS331DLH)) || defined(__DOXYGEN__)
+
+#include <aos_debug.h>
+#include <chprintf.h>
+#include <aos_thread.h>
+#include <alld_lis331dlh.h>
+
+/**
+ * @brief   LIS331DLH unit test function.
+ *
+ * @param[in] stream  Stream for input/output.
+ * @param[in] ut      Unit test object.
+ *
+ * @return            Unit test result value.
+ */
+aos_utresult_t utAlldLis331dlhFunc(BaseSequentialStream* stream, aos_unittest_t* ut)
+{
+  aosDbgCheck(ut->data != NULL && ((ut_lis331dlhdata_t*)(ut->data)) != NULL);
+
+  // local variables
+  aos_utresult_t result = {0, 0};
+  uint32_t status;
+  uint8_t data = 0;
+  uint8_t write_data[5];
+  uint8_t read_data[5];
+  uint8_t errors = 0;
+  uint8_t reg1;
+  int16_t sdata[3];
+  uint8_t status_reg;
+  lis331dlh_lld_int_cfg_t intcfg;
+  event_listener_t el;
+  eventmask_t event_mask;
+  uint8_t success = 0;
+
+  for (uint8_t dataIdx = 0; dataIdx < 4; dataIdx++) {
+    write_data[dataIdx] = (dataIdx+1)*11;
+  }
+  write_data[4] = 0;
+
+  chprintf(stream, "check identity...\n");
+  status = lis331dlh_lld_read_register(((ut_lis331dlhdata_t*)(ut->data))->lisd, LIS331DLH_LLD_REGISTER_WHO_AM_I, &data, 1);
+  if (status == APAL_STATUS_SUCCESS &&
+      data == LIS331DLH_LLD_WHO_AM_I) {
+    aosUtPassed(stream, &result);
+  } else {
+    chprintf(stream, "\tfailed\n");
+    aosUtFailedMsg(stream, &result, "0x%08X, data: %d\n", status, data);
+    ++result.failed;
+  }
+
+  chprintf(stream, "write register...\n");
+  status = lis331dlh_lld_write_register(((ut_lis331dlhdata_t*)(ut->data))->lisd, LIS331DLH_LLD_REGISTER_CTRL_REG1, write_data, 1);
+  if (status == APAL_STATUS_SUCCESS) {
+    aosUtPassed(stream, &result);
+  } else {
+    aosUtFailed(stream, &result);
+  }
+
+  chprintf(stream, "read register...\n");
+  status = lis331dlh_lld_read_register(((ut_lis331dlhdata_t*)(ut->data))->lisd, LIS331DLH_LLD_REGISTER_CTRL_REG1, &data, 1);
+  if (status == APAL_STATUS_SUCCESS && data == write_data[0]) {
+    aosUtPassed(stream, &result);
+  } else {
+    chprintf(stream, "\tfailed\n");
+    aosUtFailedMsg(stream, &result, "0x%08X, data: %d\n", status, data);
+    ++result.failed;
+  }
+
+  chprintf(stream, "write multiple registers...\n");
+  status = lis331dlh_lld_write_register(((ut_lis331dlhdata_t*)(ut->data))->lisd, LIS331DLH_LLD_REGISTER_CTRL_REG1, write_data, 5);
+  if (status == APAL_STATUS_SUCCESS) {
+    aosUtPassed(stream, &result);
+  } else {
+    aosUtFailed(stream, &result);
+  }
+
+  chprintf(stream, "read multiple registers...\n");
+  status = lis331dlh_lld_read_register(((ut_lis331dlhdata_t*)(ut->data))->lisd, LIS331DLH_LLD_REGISTER_CTRL_REG1, read_data, 5);
+  for (uint8_t dataIdx = 0; dataIdx < 5; dataIdx++) {
+    if (read_data[dataIdx] != write_data[dataIdx]) {
+      ++errors;
+    }
+  }
+  if (status == APAL_STATUS_SUCCESS &&
+      errors == 0) {
+    aosUtPassed(stream, &result);
+  } else {
+    chprintf(stream, "\tfailed\n");
+    for (uint8_t dataIdx = 0; dataIdx < 5; dataIdx++) {
+      chprintf(stream, "\t\tStatus: %d, CTRL_REG%d: %d, write_data: %d\n", status, dataIdx+1, read_data[dataIdx], write_data[dataIdx]);
+    }
+    aosUtFailedMsg(stream, &result, "0x%08X, errors: %d\n", status, errors);
+  }
+
+  chprintf(stream, "read config...\n");
+  lis331dlh_lld_cfg_t cfg;
+  status = lis331dlh_lld_read_config(((ut_lis331dlhdata_t*)(ut->data))->lisd, &cfg);
+  if (status == APAL_STATUS_SUCCESS) {
+    aosUtPassed(stream, &result);
+  } else {
+    aosUtFailed(stream, &result);
+  }
+
+  chprintf(stream, "write config...\n");
+  cfg.registers.ctrl_reg1 = LIS331DLH_LLD_PM_ODR |
+      LIS331DLH_LLD_DR_1000HZ_780LP |
+      LIS331DLH_LLD_X_AXIS_ENABLE |
+      LIS331DLH_LLD_Y_AXIS_ENABLE |
+      LIS331DLH_LLD_Z_AXIS_ENABLE;
+  cfg.registers.ctrl_reg3 = 0x00;
+  status = lis331dlh_lld_write_config(((ut_lis331dlhdata_t*)(ut->data))->lisd, &cfg);
+  reg1 = cfg.data[0];
+  lis331dlh_lld_read_config(((ut_lis331dlhdata_t*)(ut->data))->lisd, &cfg);
+  if (status == APAL_STATUS_SUCCESS && cfg.data[0] == reg1) {
+    aosUtPassed(stream, &result);
+  } else {
+    aosUtFailed(stream, &result);
+  }
+
+  chprintf(stream, "read acceleration for five seconds...\n");
+  status = APAL_STATUS_SUCCESS;
+  for (uint8_t i = 0; i < 5; ++i) {
+    status |= lis331dlh_lld_read_all_data(((ut_lis331dlhdata_t*)(ut->data))->lisd, sdata, &cfg);
+    chprintf(stream, "\t\tX = %6d\tY = %6d\tZ = %6d\n", sdata[0], sdata[1], sdata[2]);
+    aosThdSSleep(1);
+  }
+  if (status == APAL_STATUS_SUCCESS) {
+    aosUtPassed(stream, &result);
+  } else {
+    aosUtFailed(stream, &result);
+  }
+
+  chprintf(stream, "read X acceleration for five seconds...\n");
+  status = APAL_STATUS_SUCCESS;
+  for (uint8_t i = 0; i < 5; ++i) {
+    status |= lis331dlh_lld_read_data(((ut_lis331dlhdata_t*)(ut->data))->lisd, &(sdata[0]), LIS331DLH_LLD_X_AXIS, &cfg);
+    chprintf(stream, "\t\tX = %6d\n", sdata[0]);
+    aosThdSSleep(1);
+  }
+  if (status == APAL_STATUS_SUCCESS) {
+    aosUtPassed(stream, &result);
+  } else {
+    aosUtFailed(stream, &result);
+  }
+
+  chprintf(stream, "read Y acceleration for five seconds...\n");
+  status = APAL_STATUS_SUCCESS;
+  for (uint8_t i = 0; i < 5; ++i) {
+    status |= lis331dlh_lld_read_data(((ut_lis331dlhdata_t*)(ut->data))->lisd, &(sdata[0]), LIS331DLH_LLD_Y_AXIS, &cfg);
+    chprintf(stream, "\t\tY = %6d\n", sdata[0]);
+    aosThdSSleep(1);
+  }
+  if (status == APAL_STATUS_SUCCESS) {
+    aosUtPassed(stream, &result);
+  } else {
+    aosUtFailed(stream, &result);
+  }
+
+  chprintf(stream, "read Z acceleration for five seconds...\n");
+  status = APAL_STATUS_SUCCESS;
+  for (uint8_t i = 0; i < 5; ++i) {
+    status |= lis331dlh_lld_read_data(((ut_lis331dlhdata_t*)(ut->data))->lisd, &(sdata[0]), LIS331DLH_LLD_Z_AXIS, &cfg);
+    chprintf(stream, "\t\tZ = %6d\n", sdata[0]);
+    aosThdSSleep(1);
+  }
+  if (status == APAL_STATUS_SUCCESS) {
+    aosUtPassed(stream, &result);
+  } else {
+    aosUtFailed(stream, &result);
+  }
+
+  chprintf(stream, "read status register...\n");
+  status = lis331dlh_lld_read_status_register(((ut_lis331dlhdata_t*)(ut->data))->lisd, &status_reg);
+  if (status == APAL_STATUS_SUCCESS) {
+    aosUtPassed(stream, &result);
+  } else {
+    aosUtFailed(stream, &result);
+  }
+
+  chprintf(stream, "interrupt...\n");
+  intcfg.cfg_reg = LIS331DLH_LLD_INT_CFG_X_HIGH_ENABLE | LIS331DLH_LLD_INT_CFG_Y_HIGH_ENABLE | LIS331DLH_LLD_INT_CFG_Z_HIGH_ENABLE;
+  intcfg.threshold = 10;
+  intcfg.duration = 1;
+  lis331dlh_lld_write_int_config(((ut_lis331dlhdata_t*)(ut->data))->lisd, &intcfg, LIS331DLH_LLD_INT1);
+  aosThdSSleep(1);
+  chEvtRegister(((ut_lis331dlhdata_t*)(ut->data))->src, &el, 3);
+  chprintf(stream, "\t\tmove the AMiRo now to generate interrupts\n");
+  aosThdSSleep(1);
+  for (uint8_t i = 0; i < 10; i++) {
+    event_mask = chEvtWaitOneTimeout(EVENT_MASK(3), TIME_IMMEDIATE);
+    status |= lis331dlh_lld_read_all_data(((ut_lis331dlhdata_t*)(ut->data))->lisd, sdata, &cfg);
+    status = lis331dlh_lld_read_register(((ut_lis331dlhdata_t*)(ut->data))->lisd, LIS331DLH_LLD_REGISTER_INT1_SOURCE, &data, 1);
+    eventflags_t flags = chEvtGetAndClearFlags(&el);
+    if (event_mask == EVENT_MASK(3) && (flags & ((ut_lis331dlhdata_t*)(ut->data))->evtflags)) {
+      ++success;
+      chprintf(stream, "\t\tX = %6d INTERRUPT\n", sdata[0]);
+    } else {
+      chprintf(stream, "\t\tX = %6d\n", sdata[0]);
+    }
+    aosThdSSleep(1);
+  }
+  event_mask = chEvtWaitOneTimeout(EVENT_MASK(3), TIME_IMMEDIATE);
+  chEvtUnregister(((ut_lis331dlhdata_t*)(ut->data))->src, &el);
+  if (status == APAL_STATUS_SUCCESS && success > 0) {
+    aosUtPassed(stream, &result);
+  } else {
+    aosUtFailed(stream, &result);
+  }
+
+  aosUtInfoMsg(stream, "driver object memory footprint: %u bytes\n", sizeof(LIS331DLHDriver));
+
+  return result;
+}
+
+#endif /* (AMIROOS_CFG_TESTS_ENABLE == true) && defined(AMIROLLD_CFG_USE_LIS331DLH) */
+
diff --git a/unittests/periphery-lld/src/ut_alld_ltc4412.c b/unittests/periphery-lld/src/ut_alld_ltc4412.c
new file mode 100644
index 0000000..40ee37f
--- /dev/null
+++ b/unittests/periphery-lld/src/ut_alld_ltc4412.c
@@ -0,0 +1,68 @@
+/*
+AMiRo-OS is an operating system designed for the Autonomous Mini Robot (AMiRo) platform.
+Copyright (C) 2016..2018  Thomas Schöpping et al.
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <ut_alld_ltc4412.h>
+
+#if ((AMIROOS_CFG_TESTS_ENABLE == true) && defined(AMIROLLD_CFG_USE_LTC4412)) || defined(__DOXYGEN__)
+
+#include <aos_debug.h>
+#include <chprintf.h>
+#include <aos_thread.h>
+#include <alld_ltc4412.h>
+
+aos_utresult_t utAlldLtc4412Func(BaseSequentialStream* stream, aos_unittest_t* ut)
+{
+  aosDbgCheck(ut->data != NULL);
+
+  // local variables
+  aos_utresult_t result = {0,0};
+  uint32_t status;
+
+  chprintf(stream, "read ctrl pin... \n");
+  ltc4412_lld_ctrl_t ctrl;
+  status = ltc4412_lld_get_ctrl((LTC4412Driver*)ut->data, &ctrl);
+  if(status == APAL_STATUS_SUCCESS){
+    aosUtPassed(stream, &result);
+  } else {
+    aosUtFailedMsg(stream, &result, "0x%08X\n", status);
+  }
+
+  chprintf(stream, "write ctrl pin... \n");
+  status = ltc4412_lld_set_ctrl((LTC4412Driver*)ut->data, LTC4412_LLD_CTRL_ACTIVE);
+  status |= ltc4412_lld_get_ctrl((LTC4412Driver*)ut->data, &ctrl);
+  if (status == APAL_STATUS_SUCCESS && ctrl == LTC4412_LLD_CTRL_ACTIVE) {
+    aosUtPassed(stream, &result);
+  } else {
+    aosUtFailedMsg(stream, &result, "0x%08X\n", status);
+  }
+
+  chprintf(stream, "read stat pin... \n");
+  ltc4412_lld_stat_t stat;
+  status = ltc4412_lld_get_stat((LTC4412Driver*)ut->data, &stat);
+  if(status == APAL_STATUS_SUCCESS){
+    aosUtPassed(stream, &result);
+  } else {
+    aosUtFailedMsg(stream, &result, "0x%08X\n", status);
+  }
+
+  aosUtInfoMsg(stream,"driver object memory footprint: %u bytes\n", sizeof(LTC4412Driver));
+
+  return result;
+}
+
+#endif /* (AMIROOS_CFG_TESTS_ENABLE == true) && defined(AMIROLLD_CFG_USE_LTC4412) */
diff --git a/unittests/periphery-lld/src/ut_alld_mpr121.c b/unittests/periphery-lld/src/ut_alld_mpr121.c
new file mode 100644
index 0000000..2e5e30f
--- /dev/null
+++ b/unittests/periphery-lld/src/ut_alld_mpr121.c
@@ -0,0 +1,165 @@
+/*
+AMiRo-OS is an operating system designed for the Autonomous Mini Robot (AMiRo) platform.
+Copyright (C) 2016..2018  Thomas Schöpping et al.
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <ut_alld_mpr121.h>
+
+#if ((AMIROOS_CFG_TESTS_ENABLE == true) && defined(AMIROLLD_CFG_USE_MPR121)) || defined(__DOXYGEN__)
+
+#include <aos_debug.h>
+#include <chprintf.h>
+#include <aos_thread.h>
+#include <amiroos.h>
+
+#define INTERRUPT_EVENT_ID            1
+
+aos_utresult_t utAlldMpr121Func(BaseSequentialStream* stream, aos_unittest_t* ut)
+{
+  aosDbgCheck(ut->data != NULL && ((ut_mpr121data_t*)ut->data)->mprd != NULL);
+
+  // local variables
+  aos_utresult_t result = {0, 0};
+  uint32_t status;
+  mpr121_lld_config_t cfg;
+  uint8_t data, wdata, rdata;
+  uint16_t edata[4];
+  uint8_t tstate = 0;
+  event_listener_t event_listener;
+  aos_timestamp_t tstart, tcurrent, tend;
+
+  chprintf(stream, "soft reset...\n");
+  status = mpr121_lld_soft_reset(((ut_mpr121data_t*)ut->data)->mprd, ((ut_mpr121data_t*)ut->data)->timeout);
+  status |= mpr121_lld_read_config(((ut_mpr121data_t*)ut->data)->mprd, &cfg, ((ut_mpr121data_t*)ut->data)->timeout);
+  if (status == APAL_STATUS_SUCCESS && cfg.registers.ele_config == 0) {
+    aosUtPassed(stream, &result);
+  } else {
+    aosUtFailedMsg(stream, &result, "0x%08X\n", status);
+  }
+
+  chprintf(stream, "read register...\n");
+  status = mpr121_lld_read_register(((ut_mpr121data_t*)ut->data)->mprd, MPR121_LLD_REGISTER_CONFIG_2, 0, 1, &data, ((ut_mpr121data_t*)ut->data)->timeout);
+  chprintf(stream, "\t\tdata: 0x%02X\n", data);
+  if (status == APAL_STATUS_SUCCESS && data == (MPR121_LLD_CDT_0_5 | MPR121_LLD_ESI_16)) {
+    aosUtPassed(stream, &result);
+  } else {
+    aosUtFailedMsg(stream, &result, "0x%08X\n", status);
+  }
+
+  chprintf(stream, "write register...\n");
+  wdata = MPR121_LLD_CDT_32 | MPR121_LLD_SFI_10 | MPR121_LLD_ESI_16;
+  status = mpr121_lld_write_register(((ut_mpr121data_t*)ut->data)->mprd, MPR121_LLD_REGISTER_CONFIG_2, 0, 1, &wdata, ((ut_mpr121data_t*)ut->data)->timeout);
+  aosThdMSleep(500);
+  status |= mpr121_lld_read_register(((ut_mpr121data_t*)ut->data)->mprd, MPR121_LLD_REGISTER_CONFIG_2, 0, 1, &rdata, ((ut_mpr121data_t*)ut->data)->timeout);
+  chprintf(stream, "\t\tdata: 0x%02X\n", rdata);
+  status |= mpr121_lld_write_register(((ut_mpr121data_t*)ut->data)->mprd, MPR121_LLD_REGISTER_CONFIG_2, 0, 1, &data, ((ut_mpr121data_t*)ut->data)->timeout);
+  if (status == APAL_STATUS_SUCCESS && rdata == wdata) {
+    aosUtPassed(stream, &result);
+  } else {
+    aosUtFailedMsg(stream, &result, "0x%08X\n", status);
+  }
+
+  chprintf(stream, "read config...\n");
+  status = mpr121_lld_read_config(((ut_mpr121data_t*)ut->data)->mprd, &cfg, ((ut_mpr121data_t*)ut->data)->timeout);
+  if (status == APAL_STATUS_SUCCESS && cfg.registers.config_1 == 0x10 && cfg.registers.config_2 == 0x24) {
+    aosUtPassed(stream, &result);
+  } else {
+    chprintf(stream, "\t\tconfig 1: 0x%02X\n", cfg.registers.config_1);
+    chprintf(stream, "\t\tconfig 2: 0x%02X\n", cfg.registers.config_2);
+    mpr121_lld_read_register(((ut_mpr121data_t*)ut->data)->mprd, MPR121_LLD_REGISTER_CONFIG_1, 0, 1, &rdata, ((ut_mpr121data_t*)ut->data)->timeout);
+    chprintf(stream, "\t\tconfig 1: 0x%02X\n", rdata);
+    mpr121_lld_read_register(((ut_mpr121data_t*)ut->data)->mprd, MPR121_LLD_REGISTER_CONFIG_2, 0, 1, &rdata, ((ut_mpr121data_t*)ut->data)->timeout);
+    chprintf(stream, "\t\tconfig 2: 0x%02X\n", rdata);
+    for (uint8_t valueIdx = 0; valueIdx < 8; valueIdx++) {
+      chprintf(stream, "\t\tdata %d: 0x%02X\n", valueIdx, cfg.values[valueIdx]);
+    }
+    chprintf(stream, "ele_config: 0x%02X\n", cfg.registers.ele_config);
+    chprintf(stream, "config_1: 0x%02X\n", cfg.registers.config_1);
+    chprintf(stream, "config_2: 0x%02X\n", cfg.registers.config_2);
+    chprintf(stream, "target_level: 0x%02X\n", cfg.registers.target_level);
+    chprintf(stream, "low_side_limit: 0x%02X\n", cfg.registers.low_side_limit);
+    chprintf(stream, "up_side_limit: 0x%02X\n", cfg.registers.up_side_limit);
+    chprintf(stream, "auto_config_2: 0x%02X\n", cfg.registers.auto_config_2);
+    chprintf(stream, "auto_config_1: 0x%02X\n", cfg.registers.auto_config_1);
+    aosUtFailedMsg(stream, &result, "0x%08X\n", status);
+  }
+
+  chprintf(stream, "write config...\n");
+  cfg.registers.ele_config = MPR121_LLD_CL_ON_ALL | MPR121_LLD_ELEPROX_0 | 4;
+  cfg.registers.config_1 = MPR121_LLD_FFI_18 | 16;
+  cfg.registers.config_2 = MPR121_LLD_CDT_1 | MPR121_LLD_SFI_10 | MPR121_LLD_ESI_32;
+  cfg.registers.up_side_limit = 0x96u;
+  cfg.registers.low_side_limit = 0x58u;
+  cfg.registers.target_level = 0x68u;
+  cfg.registers.auto_config_1 = MPR121_LLD_FFI_18 | MPR121_LLD_RETRY_2 | MPR121_LLD_BVA_ON_ALL | MPR121_LLD_AC_RECONF_EN;
+  status = mpr121_lld_write_config(((ut_mpr121data_t*)ut->data)->mprd, cfg, ((ut_mpr121data_t*)ut->data)->timeout);
+  aosThdMSleep(500);
+  status |= mpr121_lld_read_config(((ut_mpr121data_t*)ut->data)->mprd, &cfg, ((ut_mpr121data_t*)ut->data)->timeout);
+  if (status == APAL_STATUS_SUCCESS && cfg.registers.up_side_limit == 0x96u) {
+    aosUtPassed(stream, &result);
+  } else {
+    aosUtFailedMsg(stream, &result, "0x%08X\n", status);
+  }
+
+  chprintf(stream, "read filtered data for ten seconds...\n");
+  chprintf(stream, "(values should change if you touch the sensors now)\n");
+  for (uint8_t i = 0; i < 10; i++) {
+    status = mpr121_lld_read_filtered_data(((ut_mpr121data_t*)ut->data)->mprd, 0, 4, edata, ((ut_mpr121data_t*)ut->data)->timeout);
+    chprintf(stream, "\t\t0x%04X | 0x%04X | 0x%04X | 0x%04X\n", edata[0], edata[1], edata[2], edata[3]);
+    aosThdSSleep(1);
+  }
+  if (status == APAL_STATUS_SUCCESS) {
+    aosUtPassed(stream, &result);
+  } else {
+    aosUtFailedMsg(stream, &result, "0x%08X\n", status);
+  }
+
+  chprintf(stream, "test interrupts...\n");
+  status = AOS_OK;
+  chEvtRegister(((ut_mpr121data_t*)ut->data)->evtsource, &event_listener, INTERRUPT_EVENT_ID);
+  aosSysGetUptime(&tstart);
+  tend = tstart + (30 * MICROSECONDS_PER_SECOND);
+  do {
+    aosSysGetUptime(&tcurrent);
+    const aos_timestamp_t ttimeout = MICROSECONDS_PER_SECOND - ((tcurrent - tstart) % MICROSECONDS_PER_SECOND);
+    const eventmask_t emask = chEvtWaitOneTimeout(EVENT_MASK(INTERRUPT_EVENT_ID), chTimeUS2I(ttimeout));
+    const eventflags_t eflags = chEvtGetAndClearFlags(&event_listener);
+    if (emask == EVENT_MASK(INTERRUPT_EVENT_ID) && eflags == ((ut_mpr121data_t*)ut->data)->evtflags) {
+      // interrupt detected
+      status |= mpr121_lld_read_register(((ut_mpr121data_t*)ut->data)->mprd, MPR121_LLD_REGISTER_TOUCH_STATUS, 0, 1, &tstate, ((ut_mpr121data_t*)ut->data)->timeout);
+      chprintf(stream, "\t\tinterrupt detected\n");
+      chprintf(stream, "\t\ttstate: %X %X %X %X\n", tstate & 1, (tstate >> 1) & 1, (tstate >> 2) & 1, (tstate >> 3) & 1);
+    }
+    else if (emask == 0) {
+      // timeout
+      status |= mpr121_lld_read_register(((ut_mpr121data_t*)ut->data)->mprd, MPR121_LLD_REGISTER_TOUCH_STATUS, 0, 1, &tstate, ((ut_mpr121data_t*)ut->data)->timeout);
+      chprintf(stream, "\t\ttstate: %X %X %X %X\n", tstate & 1, (tstate >> 1) & 1, (tstate >> 2) & 1, (tstate >> 3) & 1);
+    }
+    aosSysGetUptime(&tcurrent);
+  } while (tcurrent < tend);
+  chEvtUnregister(((ut_mpr121data_t*)ut->data)->evtsource, &event_listener);
+  if (status == APAL_STATUS_SUCCESS) {
+    aosUtPassed(stream, &result);
+  } else {
+    aosUtFailedMsg(stream, &result, "0x%08X\n", status);
+  }
+
+  aosUtInfoMsg(stream,"driver object memory footprint: %u bytes\n", sizeof(MPR121Driver));
+
+  return result;
+}
+
+#endif /* (AMIROOS_CFG_TESTS_ENABLE == true) && defined(AMIROLLD_CFG_USE_MPR121) */
diff --git a/unittests/periphery-lld/src/ut_alld_pca9544a.c b/unittests/periphery-lld/src/ut_alld_pca9544a.c
new file mode 100644
index 0000000..827f557
--- /dev/null
+++ b/unittests/periphery-lld/src/ut_alld_pca9544a.c
@@ -0,0 +1,103 @@
+/*
+AMiRo-OS is an operating system designed for the Autonomous Mini Robot (AMiRo) platform.
+Copyright (C) 2016..2018  Thomas Schöpping et al.
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <ut_alld_pca9544a.h>
+
+#if ((AMIROOS_CFG_TESTS_ENABLE == true) && defined(AMIROLLD_CFG_USE_PCA9544A)) || defined(__DOXYGEN__)
+
+#include <aos_debug.h>
+#include <chprintf.h>
+#include <aos_thread.h>
+#include <alld_pca9544a.h>
+
+aos_utresult_t utAlldPca9544aFunc(BaseSequentialStream* stream, aos_unittest_t* ut)
+{
+  aosDbgCheck(ut->data != NULL && ((ut_pca9544adata_t*)ut->data)->driver != NULL);
+
+  // local variables
+  aos_utresult_t result = {0,0};
+  uint32_t status;
+  uint8_t ctrlreg;
+  pca9544a_lld_intstatus_t interrupt;
+  pca9544a_lld_chid_t channel;
+  uint8_t test_mask = 0x00u;
+
+  chprintf(stream, "reading control register...\n");
+  status = pca9544a_lld_read(((ut_pca9544adata_t*)ut->data)->driver, &ctrlreg, ((ut_pca9544adata_t*)ut->data)->timeout);
+  if (status == APAL_STATUS_OK || status == APAL_STATUS_WARNING) {
+    aosUtPassed(stream, &result);
+  } else {
+    aosUtFailedMsg(stream, &result, "0x%08X\n", status);
+  }
+
+  chprintf(stream, "writing control register...\n");
+  status = APAL_STATUS_OK;
+  status |= pca9544a_lld_write(((ut_pca9544adata_t*)ut->data)->driver, (uint8_t)(PCA9544A_LLD_CTRLREG_EN), ((ut_pca9544adata_t*)ut->data)->timeout);
+  status |= pca9544a_lld_read(((ut_pca9544adata_t*)ut->data)->driver, &ctrlreg, ((ut_pca9544adata_t*)ut->data)->timeout);
+  if ((status == APAL_STATUS_OK  || status == APAL_STATUS_WARNING) && ctrlreg == PCA9544A_LLD_CTRLREG_EN) {
+    aosUtPassed(stream, &result);
+  } else {
+    aosUtFailedMsg(stream, &result, "0x%08X, 0x%X\n", status, ctrlreg);
+  }
+
+  chprintf(stream, "reading interrupt status...\n");
+  status = pca9544a_lld_getintstatus(((ut_pca9544adata_t*)ut->data)->driver, &interrupt, ((ut_pca9544adata_t*)ut->data)->timeout);
+  if (status == APAL_STATUS_OK || status == APAL_STATUS_WARNING) {
+    aosUtPassedMsg(stream, &result, "0x%08X\n", interrupt);
+  } else {
+    aosUtFailedMsg(stream, &result, "0x%08X\n", status);
+  }
+
+  chprintf(stream, "reading current channel...\n");
+  status = pca9544a_lld_getcurrentchannel(((ut_pca9544adata_t*)ut->data)->driver, &channel, ((ut_pca9544adata_t*)ut->data)->timeout);
+  if (status == APAL_STATUS_OK || status == APAL_STATUS_WARNING) {
+    aosUtPassedMsg(stream, &result, "0x%08X\n", channel);
+  } else {
+    aosUtFailedMsg(stream, &result, "0x%08X\n", status);
+  }
+
+  chprintf(stream, "setting current channel...\n");
+  status = APAL_STATUS_OK;
+  status |= pca9544a_lld_setchannel(((ut_pca9544adata_t*)ut->data)->driver, PCA9544A_LLD_CH0, ((ut_pca9544adata_t*)ut->data)->timeout);
+  status |= pca9544a_lld_getcurrentchannel(((ut_pca9544adata_t*)ut->data)->driver, &channel, ((ut_pca9544adata_t*)ut->data)->timeout);
+  test_mask |= (channel != PCA9544A_LLD_CH0) ? 0x01u : 0x00u;
+  status |= pca9544a_lld_setchannel(((ut_pca9544adata_t*)ut->data)->driver, PCA9544A_LLD_CH1, ((ut_pca9544adata_t*)ut->data)->timeout);
+  status |= pca9544a_lld_getcurrentchannel(((ut_pca9544adata_t*)ut->data)->driver, &channel, ((ut_pca9544adata_t*)ut->data)->timeout);
+  test_mask |= (channel != PCA9544A_LLD_CH1) ? 0x02u : 0x00u;
+  status |= pca9544a_lld_setchannel(((ut_pca9544adata_t*)ut->data)->driver, PCA9544A_LLD_CH2, ((ut_pca9544adata_t*)ut->data)->timeout);
+  status |= pca9544a_lld_getcurrentchannel(((ut_pca9544adata_t*)ut->data)->driver, &channel, ((ut_pca9544adata_t*)ut->data)->timeout);
+  test_mask |= (channel != PCA9544A_LLD_CH2) ? 0x04u : 0x00u;
+  status |= pca9544a_lld_setchannel(((ut_pca9544adata_t*)ut->data)->driver, PCA9544A_LLD_CH3, ((ut_pca9544adata_t*)ut->data)->timeout);
+  status |= pca9544a_lld_getcurrentchannel(((ut_pca9544adata_t*)ut->data)->driver, &channel, ((ut_pca9544adata_t*)ut->data)->timeout);
+  test_mask |= (channel != PCA9544A_LLD_CH3) ? 0x08u : 0x00u;
+  status |= pca9544a_lld_setchannel(((ut_pca9544adata_t*)ut->data)->driver, PCA9544A_LLD_CH_NONE, ((ut_pca9544adata_t*)ut->data)->timeout);
+  status |= pca9544a_lld_getcurrentchannel(((ut_pca9544adata_t*)ut->data)->driver, &channel, ((ut_pca9544adata_t*)ut->data)->timeout);
+  test_mask |= (channel != PCA9544A_LLD_CH_NONE) ? 0x10u : 0x00u;
+  if ((status == APAL_STATUS_OK || status == APAL_STATUS_WARNING) && test_mask == 0x00u) {
+    aosUtPassed(stream, &result);
+  } else {
+    aosUtFailedMsg(stream, &result, "0x%08X, 0x%X\n", status, test_mask);
+  }
+
+  aosUtInfoMsg(stream,"driver object memory footprint: %u bytes\n", sizeof(PCA9544ADriver));
+
+  return result;
+}
+
+#endif /* (AMIROOS_CFG_TESTS_ENABLE == true) && defined(AMIROLLD_CFG_USE_PCA9544A) */
+
diff --git a/unittests/periphery-lld/src/ut_alld_pklcs1212e4001.c b/unittests/periphery-lld/src/ut_alld_pklcs1212e4001.c
new file mode 100644
index 0000000..33d2a6a
--- /dev/null
+++ b/unittests/periphery-lld/src/ut_alld_pklcs1212e4001.c
@@ -0,0 +1,58 @@
+/*
+AMiRo-OS is an operating system designed for the Autonomous Mini Robot (AMiRo) platform.
+Copyright (C) 2016..2018  Thomas Schöpping et al.
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <ut_alld_pklcs1212e4001.h>
+
+#if ((AMIROOS_CFG_TESTS_ENABLE == true) && defined(AMIROLLD_CFG_USE_PKLCS1212E4001)) || defined(__DOXYGEN__)
+
+#include <aos_debug.h>
+#include <chprintf.h>
+#include <aos_thread.h>
+
+aos_utresult_t utAlldPklcs1212e4001Func(BaseSequentialStream* stream, aos_unittest_t* ut)
+{
+  aosDbgCheck(ut->data != NULL && ((ut_pklcs1212e4001_t*)ut->data)->driver != NULL);
+
+  // local variables
+  aos_utresult_t result = {0, 0};
+  uint32_t status;
+
+  chprintf(stream, "checking PWM configuration...\n");
+  status = pklcs1212e4001_lld_checkPWMconfiguration(((ut_pklcs1212e4001_t*)ut->data)->driver);
+  if (status == APAL_STATUS_OK) {
+    aosUtPassed(stream, &result);
+  } else {
+    aosUtFailedMsg(stream, &result, "0x%08X\n", status);
+    // abort at this point
+    return result;
+  }
+
+  chprintf(stream, "buzzing for one second...\n");
+  status = pklcs1212e4001_lld_enable(((ut_pklcs1212e4001_t*)ut->data)->driver, ((ut_pklcs1212e4001_t*)ut->data)->channel, true);
+  aosThdSSleep(1);
+  status |= pklcs1212e4001_lld_enable(((ut_pklcs1212e4001_t*)ut->data)->driver, ((ut_pklcs1212e4001_t*)ut->data)->channel, false);
+  if (status == APAL_STATUS_OK) {
+    aosUtPassed(stream, &result);
+  } else {
+    aosUtFailedMsg(stream, &result, "0x%08X\n", status);
+  }
+
+  return result;
+}
+
+#endif /* (AMIROOS_CFG_TESTS_ENABLE == true) && defined(AMIROLLD_CFG_USE_PKLCS1212E4001) */
diff --git a/unittests/periphery-lld/src/ut_alld_tlc5947.c b/unittests/periphery-lld/src/ut_alld_tlc5947.c
new file mode 100644
index 0000000..deb93a3
--- /dev/null
+++ b/unittests/periphery-lld/src/ut_alld_tlc5947.c
@@ -0,0 +1,178 @@
+/*
+AMiRo-OS is an operating system designed for the Autonomous Mini Robot (AMiRo) platform.
+Copyright (C) 2016..2018  Thomas Schöpping et al.
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <ut_alld_tlc5947.h>
+
+#if ((AMIROOS_CFG_TESTS_ENABLE == true) && defined(AMIROLLD_CFG_USE_TLC5947)) || defined(__DOXYGEN__)
+
+#include <aos_debug.h>
+#include <chprintf.h>
+#include <alld_tlc5947.h>
+#include <string.h>
+#include <aos_thread.h>
+
+/**
+ * @brief   TLC9547 unit test function
+ *
+ * @param[in] stream  Stream for input/output.
+ * @param[in] ut      Unit test object.
+ *
+ * @return            Unit test result value.
+ */
+aos_utresult_t utAlldTlc5947Func(BaseSequentialStream *stream, aos_unittest_t *ut)
+{
+  aosDbgCheck(ut->data != NULL);
+
+  // local variables
+  aos_utresult_t result = {0, 0};
+  uint32_t status = 0;
+  tlc5947_lld_blank_t blank;
+  tlc5947_lld_buffer_t buffer;
+
+  chprintf(stream, "reading blank pin...\n");
+  status = tlc5947_lld_getBlank((TLC5947Driver*)ut->data, &blank);
+  if (status == APAL_STATUS_OK) {
+    aosUtPassedMsg(stream, &result, "blank is %s\n", (blank == TLC5947_LLD_BLANK_ENABLE) ? "enabled" : "disabled");
+  } else {
+    aosUtFailedMsg(stream, &result, "0x%08X\n", status);
+  }
+
+  // enabling/disabling blank pin
+  for (uint8_t i = 0; i < 2; ++i) {
+    blank = (blank == TLC5947_LLD_BLANK_ENABLE) ? TLC5947_LLD_BLANK_DISABLE : TLC5947_LLD_BLANK_ENABLE;
+    tlc5947_lld_blank_t blank_after = (blank == TLC5947_LLD_BLANK_ENABLE) ? TLC5947_LLD_BLANK_DISABLE : TLC5947_LLD_BLANK_ENABLE;
+    chprintf(stream, "%s blank pin...\n", (blank == TLC5947_LLD_BLANK_ENABLE) ? "enabling" : "disabling");
+    status = tlc5947_lld_setBlank((TLC5947Driver*)ut->data, blank);
+    status |= tlc5947_lld_getBlank((TLC5947Driver*)ut->data, &blank_after);
+    if (status == APAL_STATUS_OK && blank_after == blank) {
+      aosUtPassed(stream, &result);
+    } else {
+      aosUtFailedMsg(stream, &result, "0x%08X\n", status);
+    }
+  }
+
+  chprintf(stream, "setting all black and dimming white...\n");
+  status = tlc5947_lld_setBlank((TLC5947Driver*)ut->data, TLC5947_LLD_BLANK_ENABLE);
+  memset(buffer.data, 0, TLC5947_LLD_BUFFER_SIZE);
+  status |= tlc5947_lld_write((TLC5947Driver*)ut->data, &buffer);
+  status |= tlc5947_lld_update((TLC5947Driver*)ut->data);
+  status |= tlc5947_lld_setBlank((TLC5947Driver*)ut->data, TLC5947_LLD_BLANK_DISABLE);
+  for (uint8_t bit = 0; bit < TLC5947_LLD_PWM_RESOLUTION_BITS; ++bit) {
+    for (uint8_t channel = 0; channel < TLC5947_LLD_NUM_CHANNELS; ++channel) {
+      tlc5947_lld_setBuffer(&buffer, channel, (1 << (bit+1)) - 1);
+    }
+    status |= tlc5947_lld_write((TLC5947Driver*)ut->data, &buffer);
+    status |= tlc5947_lld_update((TLC5947Driver*)ut->data);
+    aosThdMSleep(100);
+  }
+  if (status == APAL_STATUS_OK) {
+    aosUtPassed(stream, &result);
+  } else {
+    aosUtFailedMsg(stream, &result, "0x%08X\n", status);
+  }
+
+  chprintf(stream, "NOT dimming black again...\n");
+  status = APAL_STATUS_OK;
+  for (uint8_t bit = TLC5947_LLD_PWM_RESOLUTION_BITS; bit > 0; --bit) {
+    for (uint8_t channel = 0; channel < TLC5947_LLD_NUM_CHANNELS; ++channel) {
+      tlc5947_lld_setBuffer(&buffer, channel, (1 << bit) - 1);
+    }
+    status |= tlc5947_lld_setBlank((TLC5947Driver*)ut->data, TLC5947_LLD_BLANK_ENABLE);
+    status |= tlc5947_lld_write((TLC5947Driver*)ut->data, &buffer);
+    status |= tlc5947_lld_setBlank((TLC5947Driver*)ut->data, TLC5947_LLD_BLANK_ENABLE);
+    // Grayscale data is not updated this time (tlc5947_lld_update() not called).
+    // TODO: For some reason the PWMs are updated nevertheless.
+    aosThdMSleep(100);
+  }
+  status |= tlc5947_lld_setBlank((TLC5947Driver*)ut->data, TLC5947_LLD_BLANK_ENABLE);
+  if (status == APAL_STATUS_OK) {
+    aosUtPassed(stream, &result);
+  } else {
+    aosUtFailedMsg(stream, &result, "0x%08X\n", status);
+  }
+
+  chprintf(stream, "setting each channel incrementally...\n");
+  status = APAL_STATUS_OK;
+  memset(buffer.data, 0, TLC5947_LLD_BUFFER_SIZE);
+  status |= tlc5947_lld_write((TLC5947Driver*)ut->data, &buffer);
+  status |= tlc5947_lld_update((TLC5947Driver*)ut->data);
+  status |= tlc5947_lld_setBlank((TLC5947Driver*)ut->data, TLC5947_LLD_BLANK_DISABLE);
+  for (uint8_t channel = 0; channel < TLC5947_LLD_NUM_CHANNELS; ++channel) {
+    uint16_t value = 0x0000u;
+    for (uint8_t byte = 0; byte < 3; ++byte) {
+      switch (byte) {
+        case 0:
+          value |= 0x00Fu;
+          break;
+        case 1:
+          value |= 0x0F0u;
+          break;
+        case 2:
+          value |= 0xF00u;
+          break;
+      }
+      tlc5947_lld_setBuffer(&buffer, channel, value);
+      status |= tlc5947_lld_write((TLC5947Driver*)ut->data, &buffer);
+      status |= tlc5947_lld_update((TLC5947Driver*)ut->data);
+      aosThdSleep(1.0f / 3.0f);
+      tlc5947_lld_setBuffer(&buffer, channel, 0);
+    }
+  }
+  if (status == APAL_STATUS_OK) {
+    aosUtPassed(stream, &result);
+  } else {
+    aosUtFailedMsg(stream, &result, "0x%08X\n", status);
+  }
+
+  chprintf(stream, "setting one color after another...\n");
+  status = APAL_STATUS_OK;
+  for (int8_t color = 0; color < 3; ++color) {
+    for (uint8_t channel = color; channel < TLC5947_LLD_NUM_CHANNELS; channel += 3) {
+      const uint16_t val = 0xAF5u; // some deterministic value with high entropy
+      tlc5947_lld_setBuffer(&buffer, channel, val);
+      status |= tlc5947_lld_write((TLC5947Driver*)ut->data, &buffer);
+      status |= tlc5947_lld_update((TLC5947Driver*)ut->data);
+      status |= (tlc5947_lld_getBuffer(&buffer, channel) != val) ? (1 << 31) : 0;
+      if (status != APAL_STATUS_OK) {
+        break;
+      } else {
+        aosThdSleep(1.0f / 8.0f);
+      }
+    }
+    for (uint8_t channel = 0; channel < TLC5947_LLD_NUM_CHANNELS; ++channel) {
+      tlc5947_lld_setBuffer(&buffer, channel, 0);
+    }
+  }
+  if (status == APAL_STATUS_OK) {
+    aosUtPassed(stream, &result);
+  } else {
+    aosUtFailedMsg(stream, &result, "0x%08X\n", status);
+  }
+
+  // turn LEDs off
+  tlc5947_lld_setBlank((TLC5947Driver*)ut->data, TLC5947_LLD_BLANK_ENABLE);
+  memset(buffer.data, 0, TLC5947_LLD_BUFFER_SIZE);
+  tlc5947_lld_write((TLC5947Driver*)ut->data, &buffer);
+  tlc5947_lld_update((TLC5947Driver*)ut->data);
+
+  aosUtInfoMsg(stream, "driver object memory footprint: %u bytes\n", sizeof(TLC5947Driver));
+
+  return result;
+}
+
+#endif /* (AMIROOS_CFG_TESTS_ENABLE == true) && defined(AMIROLLD_CFG_USE_TLC5947) */
diff --git a/unittests/periphery-lld/src/ut_alld_tps2051bdbv.c b/unittests/periphery-lld/src/ut_alld_tps2051bdbv.c
new file mode 100644
index 0000000..ca74611
--- /dev/null
+++ b/unittests/periphery-lld/src/ut_alld_tps2051bdbv.c
@@ -0,0 +1,81 @@
+/*
+AMiRo-OS is an operating system designed for the Autonomous Mini Robot (AMiRo) platform.
+Copyright (C) 2016..2018  Thomas Schöpping et al.
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <ut_alld_tps2051bdbv.h>
+
+#if ((AMIROOS_CFG_TESTS_ENABLE == true) && defined(AMIROLLD_CFG_USE_TPS2051BDBV)) || defined(__DOXYGEN__)
+
+#include <aos_debug.h>
+#include <chprintf.h>
+
+/**
+ * @brief   TPS2051BDBV unit test function.
+ *
+ * @param[in] stream  Stream for input/output.
+ * @param[in] ut      Unit test object.
+ *
+ * @return            Unit test result value.
+ */
+aos_utresult_t utAlldTps2051bdbvFunc(BaseSequentialStream* stream, aos_unittest_t* ut)
+{
+  aosDbgCheck(ut->data != NULL);
+
+  // local variables
+  aos_utresult_t result = {0, 0};
+  uint32_t status = AOS_OK;
+  tps2051b_lld_enable_t en;
+  tps2051b_lld_overcurrent_t oc;
+
+  chprintf(stream, "write laser enable...\n");
+  status = tps2051b_lld_set_enable((TPS2051BDriver*)ut->data, TPS2051B_LLD_ENABLE);
+  if (status == APAL_STATUS_SUCCESS) {
+    aosUtPassed(stream, &result);
+  } else {
+    aosUtFailed(stream, &result);
+  }
+
+  chprintf(stream, "read laser enable...\n");
+  status = tps2051b_lld_read_enable((TPS2051BDriver*)ut->data, &en);
+  if (status == APAL_STATUS_SUCCESS && en == TPS2051B_LLD_ENABLE) {
+    aosUtPassed(stream, &result);
+  } else {
+    aosUtFailed(stream, &result);
+  }
+
+  chprintf(stream, "read laser oc...\n");
+  status = tps2051b_lld_read_overcurrent((TPS2051BDriver*)ut->data, &oc);
+  if (status == APAL_STATUS_SUCCESS && oc == TPS2051B_LLD_NO_OVERCURRENT) {
+    aosUtPassed(stream, &result);
+  } else {
+    aosUtFailed(stream, &result);
+  }
+
+  chprintf(stream, "disable laser...\n");
+  status = tps2051b_lld_set_enable((TPS2051BDriver*)ut->data, TPS2051B_LLD_DISABLE);
+  if (status == APAL_STATUS_SUCCESS) {
+    aosUtPassed(stream, &result);
+  } else {
+    aosUtFailed(stream, &result);
+  }
+
+  aosUtInfoMsg(stream,"driver object memory footprint: %u bytes\n", sizeof(TPS2051BDriver));
+
+  return result;
+}
+
+#endif /* (AMIROOS_CFG_TESTS_ENABLE == true) && defined(AMIROLLD_CFG_USE_TPS2051BDBV) */
diff --git a/unittests/periphery-lld/src/ut_alld_tps62113.c b/unittests/periphery-lld/src/ut_alld_tps62113.c
new file mode 100644
index 0000000..403579e
--- /dev/null
+++ b/unittests/periphery-lld/src/ut_alld_tps62113.c
@@ -0,0 +1,61 @@
+/*
+AMiRo-OS is an operating system designed for the Autonomous Mini Robot (AMiRo) platform.
+Copyright (C) 2016..2018  Thomas Schöpping et al.
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <ut_alld_tps62113.h>
+
+#if ((AMIROOS_CFG_TESTS_ENABLE == true) && defined(AMIROLLD_CFG_USE_TPS62113)) || defined(__DOXYGEN__)
+
+#include <aos_debug.h>
+#include <chprintf.h>
+#include <aos_thread.h>
+#include <alld_tps62113.h>
+
+aos_utresult_t utAlldTps62113Func(BaseSequentialStream* stream, aos_unittest_t* ut)
+{
+  aosDbgCheck(ut->data != NULL);
+
+  // local variables
+  aos_utresult_t result = {0,0};
+  uint32_t status;
+  tps62113_lld_power_en_t power;
+
+  chprintf(stream, "read pin... \n");
+  status = tps62113_lld_get_power_en((TPS62113Driver*)ut->data, &power);
+  if(status == APAL_STATUS_SUCCESS){
+    aosUtPassed(stream, &result);
+  } else {
+    aosUtFailedMsg(stream, &result, "0x%08X\n", status);
+  }
+
+  chprintf(stream, "write pin... \n");
+  status = tps62113_lld_set_power_en((TPS62113Driver*)ut->data, TPS62113_LLD_POWER_ENABLED);
+  status |= tps62113_lld_get_power_en((TPS62113Driver*)ut->data, &power);
+  if(status == APAL_STATUS_SUCCESS && power == TPS62113_LLD_POWER_ENABLED){
+    aosUtPassed(stream, &result);
+  } else {
+    aosUtFailedMsg(stream, &result, "0x%08X\n", status);
+  }
+
+  aosUtInfoMsg(stream,"driver object memory footprint: %u bytes\n", sizeof(TPS62113Driver));
+
+  return result;
+}
+
+#endif /* (AMIROOS_CFG_TESTS_ENABLE == true) && defined(AMIROLLD_CFG_USE_TPS62113) */
+
+
diff --git a/unittests/periphery-lld/src/ut_alld_tps62113_ina219.c b/unittests/periphery-lld/src/ut_alld_tps62113_ina219.c
new file mode 100644
index 0000000..7ce0035
--- /dev/null
+++ b/unittests/periphery-lld/src/ut_alld_tps62113_ina219.c
@@ -0,0 +1,67 @@
+/*
+AMiRo-OS is an operating system designed for the Autonomous Mini Robot (AMiRo) platform.
+Copyright (C) 2016..2018  Thomas Schöpping et al.
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <ut_alld_tps62113_ina219.h>
+
+#if ((AMIROOS_CFG_TESTS_ENABLE == true) && defined(AMIROLLD_CFG_USE_TPS62113) && defined(AMIROLLD_CFG_USE_INA219)) || defined(__DOXYGEN__)
+
+#include <aos_debug.h>
+#include <chprintf.h>
+#include <aos_thread.h>
+
+aos_utresult_t utAlldTps62113Ina219Func(BaseSequentialStream *stream, aos_unittest_t *ut)
+{
+  aosDbgCheck(ut->data != NULL && ((ut_tps62113ina219data_t*)ut->data)->tps62113 != NULL && ((ut_tps62113ina219data_t*)ut->data)->ina219 != NULL);
+
+  // local variables
+  aos_utresult_t result = {0, 0};
+  uint32_t status;
+  tps62113_lld_power_en_t power;
+  uint32_t v_buson, v_busoff;
+
+  chprintf(stream, "read pin... \n");
+  status = tps62113_lld_get_power_en(((ut_tps62113ina219data_t*)ut->data)->tps62113, &power);
+  aosThdSSleep(1);
+  status |= ina219_lld_read_bus_voltage(((ut_tps62113ina219data_t*)ut->data)->ina219, &v_buson, ((ut_tps62113ina219data_t*)ut->data)->timeout);
+  if (status == APAL_STATUS_SUCCESS && power == TPS62113_LLD_POWER_ENABLED) {
+    aosUtPassedMsg(stream, &result, "enabled, %fV\n", (float)v_buson / 1000000.0f);
+  } else {
+    aosUtFailedMsg(stream, &result, "0x%08X\n", status);
+  }
+
+  chprintf(stream, "write pin... \n");
+  status = tps62113_lld_set_power_en(((ut_tps62113ina219data_t*)ut->data)->tps62113, TPS62113_LLD_POWER_DISABLED);
+  status |= tps62113_lld_get_power_en(((ut_tps62113ina219data_t*)ut->data)->tps62113, &power);
+  aosThdSSleep(1);
+  status |= ina219_lld_read_bus_voltage(((ut_tps62113ina219data_t*)ut->data)->ina219, &v_busoff, ((ut_tps62113ina219data_t*)ut->data)->timeout);
+  status |= tps62113_lld_set_power_en(((ut_tps62113ina219data_t*)ut->data)->tps62113, TPS62113_LLD_POWER_ENABLED);
+  if (status == APAL_STATUS_SUCCESS && power == TPS62113_LLD_POWER_DISABLED) {
+    chprintf(stream, "\tdisabled, %fV\n", (float)v_busoff / 1000000.0f);
+    if (v_buson > v_busoff) {
+      aosUtPassed(stream, &result);
+    } else {
+      aosUtFailedMsg(stream, &result, "on: %fV; off: %fV\n", (float)v_buson / 1000000.0f, (float)v_busoff / 1000000.0f);
+    }
+  } else {
+    aosUtFailedMsg(stream, &result, "0x%08X\n", status);
+  }
+
+  return result;
+}
+
+#endif /* (AMIROOS_CFG_TESTS_ENABLE == true) && defined(AMIROLLD_CFG_USE_TPS62113) && defined(AMIROLLD_CFG_USE_INA219) */
diff --git a/unittests/periphery-lld/src/ut_alld_vcnl4020.c b/unittests/periphery-lld/src/ut_alld_vcnl4020.c
new file mode 100644
index 0000000..fc3c674
--- /dev/null
+++ b/unittests/periphery-lld/src/ut_alld_vcnl4020.c
@@ -0,0 +1,226 @@
+/*
+AMiRo-OS is an operating system designed for the Autonomous Mini Robot (AMiRo) platform.
+Copyright (C) 2016..2018  Thomas Schöpping et al.
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <ut_alld_vcnl4020.h>
+
+#if ((AMIROOS_CFG_TESTS_ENABLE == true) && defined(AMIROLLD_CFG_USE_VCNL4020)) || defined(__DOXYGEN__)
+
+#include <aos_debug.h>
+#include <chprintf.h>
+#include <aos_thread.h>
+#include <alld_vcnl4020.h>
+#include <amiroos.h>
+
+#define INTERRUPT_EVENT_ID            1
+
+#define INTERRUPT_THRESHOLD           0x2000
+
+aos_utresult_t utAlldVcnl4020Func(BaseSequentialStream* stream, aos_unittest_t* ut)
+{
+  aosDbgCheck((ut->data != NULL) &&
+              (((ut_vcnl4020data_t*)(ut->data))->vcnld != NULL) &&
+              (((ut_vcnl4020data_t*)(ut->data))->evtsource != NULL));
+
+  // local variables
+  aos_utresult_t result = {0, 0};
+  uint32_t status;
+  uint8_t reg_buf[4];
+  uint8_t* reg_8 = (uint8_t*)(reg_buf);
+  uint16_t* reg_16 = (uint16_t*)(reg_buf);
+  event_listener_t event_listener;
+  aos_timestamp_t tcurrent, tend;
+
+  chprintf(stream, "reading register...\n");
+  status = vcnl4020_lld_readreg(((ut_vcnl4020data_t*)(ut->data))->vcnld, VCNL4020_LLD_REGADDR_IDREV, &reg_8[0], ((ut_vcnl4020data_t*)(ut->data))->timeout);
+  if ((status == APAL_STATUS_OK || status == APAL_STATUS_WARNING) && reg_8[0] == 0x21u) {
+    aosUtPassed(stream, &result);
+  } else {
+    aosUtFailedMsg(stream, &result, "0x%08X; 0x%08X\n", status, reg_8[0]);
+  }
+
+  chprintf(stream, "writing register...\n");
+  status = vcnl4020_lld_writereg(((ut_vcnl4020data_t*)(ut->data))->vcnld, VCNL4020_LLD_REGADDR_PROXRATE, VCNL4020_LLD_PROXRATEREG_250_HZ, ((ut_vcnl4020data_t*)(ut->data))->timeout);
+  status |= vcnl4020_lld_readreg(((ut_vcnl4020data_t*)(ut->data))->vcnld, VCNL4020_LLD_REGADDR_PROXRATE, &reg_8[0], ((ut_vcnl4020data_t*)(ut->data))->timeout);
+  status |= (reg_8[0] == VCNL4020_LLD_PROXRATEREG_250_HZ) ? 0x0000 : 0x0100;
+  status |= vcnl4020_lld_writereg(((ut_vcnl4020data_t*)(ut->data))->vcnld, VCNL4020_LLD_REGADDR_CMD, (VCNL4020_LLD_CMDREG_ALSEN | VCNL4020_LLD_CMDREG_PROXEN | VCNL4020_LLD_CMDREG_SELFTIMED), ((ut_vcnl4020data_t*)(ut->data))->timeout);
+  status |= vcnl4020_lld_readreg(((ut_vcnl4020data_t*)(ut->data))->vcnld, VCNL4020_LLD_REGADDR_CMD, &reg_8[0], ((ut_vcnl4020data_t*)(ut->data))->timeout);
+  status |= (reg_8[0] & (VCNL4020_LLD_CMDREG_ALSEN | VCNL4020_LLD_CMDREG_PROXEN | VCNL4020_LLD_CMDREG_SELFTIMED)) ? 0x0000 : 0x0200;
+
+  if (status == APAL_STATUS_OK || status == APAL_STATUS_WARNING) {
+    aosUtPassed(stream, &result);
+  } else {
+    aosUtFailedMsg(stream, &result, "0x%08X, 0x%02X\n", status, reg_8[0]);
+  }
+
+  chprintf(stream, "reading ambient light for ten seconds...\n");
+  status = APAL_STATUS_OK;
+  for (uint8_t i = 0; i < 10; ++i) {
+    aosThdSSleep(1);
+    status |= vcnl4020_lld_readals(((ut_vcnl4020data_t*)(ut->data))->vcnld, &reg_16[0], ((ut_vcnl4020data_t*)(ut->data))->timeout);
+    chprintf(stream, "\t\tambient light: 0x%04X\n", reg_16[0]);
+  }
+  status |= (reg_16[0] == 0x0000) ? 0x10 : 0x00;
+  if (status == APAL_STATUS_OK) {
+    aosUtPassed(stream, &result);
+  } else {
+    aosUtFailedMsg(stream, &result, "0x%08X\n", status);
+  }
+
+  chprintf(stream, "reading proximity for ten seconds...\n");
+  status = APAL_STATUS_OK;
+  for (uint8_t i = 0; i < 10; ++i) {
+    aosThdSSleep(1);
+    status |= vcnl4020_lld_readprox(((ut_vcnl4020data_t*)(ut->data))->vcnld, &reg_16[1], ((ut_vcnl4020data_t*)(ut->data))->timeout);
+    chprintf(stream, "\t\tproximity: 0x%04X\n", reg_16[1]);
+  }
+  status |= (reg_16[1] == 0x0000) ? 0x10 : 0x00;
+  if (status == APAL_STATUS_OK) {
+    aosUtPassed(stream, &result);
+  } else {
+    aosUtFailedMsg(stream, &result, "0x%08X\n", status);
+  }
+
+  chprintf(stream, "reading ambient light and proximity for ten seconds...\n");
+  status = APAL_STATUS_OK;
+  for (uint8_t i = 0; i < 10; ++i) {
+    aosThdSSleep(1);
+    status |= vcnl4020_lld_readalsandprox(((ut_vcnl4020data_t*)(ut->data))->vcnld, &reg_16[0], &reg_16[1], ((ut_vcnl4020data_t*)(ut->data))->timeout);
+    chprintf(stream, "\t\tambient light: 0x%04X\tproximity: 0x%04X\n", reg_16[0], reg_16[1]);
+  }
+  status |= (reg_16[0] == 0x0000 || reg_16[1] == 0x0000) ? 0x10 : 0x00;
+  if (status == APAL_STATUS_OK) {
+    aosUtPassed(stream, &result);
+  } else {
+    aosUtFailedMsg(stream, &result, "0x%08X\n", status);
+  }
+
+  chprintf(stream, "reading low threshold register...\n");
+  status = vcnl4020_lld_readlth(((ut_vcnl4020data_t*)(ut->data))->vcnld, &reg_16[0], ((ut_vcnl4020data_t*)(ut->data))->timeout);
+  if (status == APAL_STATUS_OK) {
+    aosUtPassed(stream, &result);
+  } else {
+    aosUtFailedMsg(stream, &result, "0x%08X\n", status);
+  }
+
+  chprintf(stream, "reading high threshold register...\n");
+  status = vcnl4020_lld_readhth(((ut_vcnl4020data_t*)(ut->data))->vcnld, &reg_16[1], ((ut_vcnl4020data_t*)(ut->data))->timeout);
+  if (status == APAL_STATUS_OK) {
+    aosUtPassedMsg(stream, &result, "0x%04X\n", reg_16[1]);
+  } else {
+    aosUtFailedMsg(stream, &result, "0x%08X\n", status);
+  }
+
+  chprintf(stream, "reading both threshold registers...\n");
+  status = vcnl4020_lld_readth(((ut_vcnl4020data_t*)(ut->data))->vcnld, &reg_16[0], &reg_16[1], ((ut_vcnl4020data_t*)(ut->data))->timeout);
+  if (status == APAL_STATUS_OK) {
+    aosUtPassedMsg(stream, &result, "low: 0x%04X; high: 0x%04X\n", reg_16[0], reg_16[1]);
+  } else {
+    aosUtFailedMsg(stream, &result, "0x%08X\n", status);
+  }
+
+  chprintf(stream, "writing low threshold register...\n");
+  status = vcnl4020_lld_writelth(((ut_vcnl4020data_t*)(ut->data))->vcnld, 0xFFFFu, ((ut_vcnl4020data_t*)(ut->data))->timeout);
+  status |= vcnl4020_lld_readlth(((ut_vcnl4020data_t*)(ut->data))->vcnld, &reg_16[0], ((ut_vcnl4020data_t*)(ut->data))->timeout);
+  if (status == APAL_STATUS_OK && reg_16[0] == 0xFFFFu) {
+    aosUtPassed(stream, &result);
+  } else {
+    aosUtFailedMsg(stream, &result, "0x%08X, 0x%04X\n", status, reg_16[0]);
+  }
+
+  chprintf(stream, "writing high threshold register...\n");
+  status = vcnl4020_lld_writehth(((ut_vcnl4020data_t*)(ut->data))->vcnld, 0xFFFFu, ((ut_vcnl4020data_t*)(ut->data))->timeout);
+  status |= vcnl4020_lld_readhth(((ut_vcnl4020data_t*)(ut->data))->vcnld, &reg_16[1], ((ut_vcnl4020data_t*)(ut->data))->timeout);
+  if (status == APAL_STATUS_OK && reg_16[1] == 0xFFFFu) {
+    aosUtPassed(stream, &result);
+  } else {
+    aosUtFailedMsg(stream, &result, "0x%08X, 0x%04X\n", status, reg_16[1]);
+  }
+
+  chprintf(stream, "writing both threshold registers...\n");
+  status = vcnl4020_lld_writeth(((ut_vcnl4020data_t*)(ut->data))->vcnld, 0x5555u, 0xAAAAu, ((ut_vcnl4020data_t*)(ut->data))->timeout);
+  status |= vcnl4020_lld_readth(((ut_vcnl4020data_t*)(ut->data))->vcnld, &reg_16[0], &reg_16[1], ((ut_vcnl4020data_t*)(ut->data))->timeout);
+  if (status == APAL_STATUS_OK && reg_16[0] == 0x5555u && reg_16[1] == 0xAAAAu) {
+    aosUtPassed(stream, &result);
+  } else {
+    aosUtFailedMsg(stream, &result, "0x%08X, 0x%04X, 0x%04X\n", status, reg_16[0], reg_16[1]);
+  }
+
+  chprintf(stream, "test interrupts...\n");
+  chprintf(stream, "(thresholds are 0x%04X and 0x%04X)\n", 0, INTERRUPT_THRESHOLD);
+  chEvtRegister(((ut_vcnl4020data_t*)(ut->data))->evtsource, &event_listener, INTERRUPT_EVENT_ID);
+  aosSysGetUptime(&tend);
+  tend += 30 * MICROSECONDS_PER_SECOND;
+  status = vcnl4020_lld_writeth(((ut_vcnl4020data_t*)(ut->data))->vcnld, 0x0000, INTERRUPT_THRESHOLD, ((ut_vcnl4020data_t*)(ut->data))->timeout);
+  status |= vcnl4020_lld_writereg(((ut_vcnl4020data_t*)(ut->data))->vcnld, VCNL4020_LLD_REGADDR_INTCTRL, VCNL4020_LLD_INTCTRLREG_THRES_EN, ((ut_vcnl4020data_t*)(ut->data))->timeout);
+  do {
+    // read proximity data, interrupt event information and interrupt status
+    const eventmask_t emask = chEvtWaitOneTimeout(EVENT_MASK(INTERRUPT_EVENT_ID), chTimeUS2I(10*MICROSECONDS_PER_MILLISECOND));
+    const eventflags_t eflags = chEvtGetAndClearFlags(&event_listener);
+    status |= vcnl4020_lld_readprox(((ut_vcnl4020data_t*)(ut->data))->vcnld, &reg_16[0], ((ut_vcnl4020data_t*)(ut->data))->timeout);
+    status |= vcnl4020_lld_readreg(((ut_vcnl4020data_t*)(ut->data))->vcnld, VCNL4020_LLD_REGADDR_INTSTATUS, &reg_8[2], ((ut_vcnl4020data_t*)(ut->data))->timeout);
+    if (emask == EVENT_MASK(INTERRUPT_EVENT_ID) &&
+        eflags == ((ut_vcnl4020data_t*)(ut->data))->evtflags &&
+        reg_8[2] == VCNL4020_LLD_INTSTATUSREG_THHIGH) {
+      // true positive (correct case)
+      chprintf(stream, "\t\tinterrupt detected: prox = 0x%04X\n", reg_16[0]);
+      aosThdMSleep(100);
+    }
+    else if (emask != EVENT_MASK(INTERRUPT_EVENT_ID) &&
+             eflags != ((ut_vcnl4020data_t*)(ut->data))->evtflags &&
+             reg_8[2] != VCNL4020_LLD_INTSTATUSREG_THHIGH) {
+      // true negative (correct case)
+      // do nothing, just keep on looping
+    }
+    else if (emask == EVENT_MASK(INTERRUPT_EVENT_ID) &&
+             eflags == ((ut_vcnl4020data_t*)(ut->data))->evtflags &&
+             reg_8[2] != 0 ) {
+      // false positive
+      status |= 0x1000;
+      chprintf(stream, "\t\tfalse positive: intstatus = 0x%02X; prox = 0x%04X\n", reg_8[2], reg_16[0]);
+    }
+    else if (emask != EVENT_MASK(INTERRUPT_EVENT_ID) &&
+             eflags != ((ut_vcnl4020data_t*)(ut->data))->evtflags &&
+             reg_8[2] == 0) {
+      // false negative
+      status |= 0x2000;
+      chprintf(stream, "\t\tfalse negative: intstatus = 0x%02X; prox = 0x%04X\n", reg_8[2], reg_16[0]);
+    } // any other events are just ignored
+    // reset interrupt status
+    if (reg_8[2] != 0) {
+      status |= vcnl4020_lld_writereg(((ut_vcnl4020data_t*)(ut->data))->vcnld, VCNL4020_LLD_REGADDR_INTSTATUS, reg_8[2], ((ut_vcnl4020data_t*)(ut->data))->timeout);
+    }
+    aosSysGetUptime(&tcurrent);
+  } while (tcurrent < tend);
+  chEvtUnregister(((ut_vcnl4020data_t*)(ut->data))->evtsource, &event_listener);
+  status |= vcnl4020_lld_writereg(((ut_vcnl4020data_t*)(ut->data))->vcnld, VCNL4020_LLD_REGADDR_INTCTRL, 0, ((ut_vcnl4020data_t*)(ut->data))->timeout);
+  status |= vcnl4020_lld_readreg(((ut_vcnl4020data_t*)(ut->data))->vcnld, VCNL4020_LLD_REGADDR_INTSTATUS, &reg_8[2], ((ut_vcnl4020data_t*)(ut->data))->timeout);
+  status |= vcnl4020_lld_writereg(((ut_vcnl4020data_t*)(ut->data))->vcnld, VCNL4020_LLD_REGADDR_INTSTATUS, reg_8[2], ((ut_vcnl4020data_t*)(ut->data))->timeout);
+  if (status == APAL_STATUS_SUCCESS || status == APAL_STATUS_WARNING) {
+    aosUtPassed(stream, &result);
+  } else {
+    aosUtFailedMsg(stream, &result, "0x%08X\n", status);
+  }
+
+  aosUtInfoMsg(stream, "driver object memory footprint: %u bytes\n", sizeof(VCNL4020Driver));
+
+  return result;
+}
+
+#endif /* (AMIROOS_CFG_TESTS_ENABLE == true) && defined(AMIROLLD_CFG_USE_VCNL4020) */
+
+
diff --git a/unittests/unittests.mk b/unittests/unittests.mk
new file mode 100644
index 0000000..332aa91
--- /dev/null
+++ b/unittests/unittests.mk
@@ -0,0 +1,55 @@
+################################################################################
+# AMiRo-OS is an operating system designed for the Autonomous Mini Robot       #
+# (AMiRo) platform.                                                            #
+# Copyright (C) 2016..2018  Thomas Schöpping et al.                            #
+#                                                                              #
+# This program is free software: you can redistribute it and/or modify         #
+# it under the terms of the GNU General Public License as published by         #
+# the Free Software Foundation, either version 3 of the License, or            #
+# (at your option) any later version.                                          #
+#                                                                              #
+# This program is distributed in the hope that it will be useful,              #
+# but WITHOUT ANY WARRANTY; without even the implied warranty of               #
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the                #
+# GNU General Public License for more details.                                 #
+#                                                                              #
+# You should have received a copy of the GNU General Public License            #
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.        #
+#                                                                              #
+# This research/work was supported by the Cluster of Excellence Cognitive      #
+# Interaction Technology 'CITEC' (EXC 277) at Bielefeld University, which is   #
+# funded by the German Research Foundation (DFG).                              #
+################################################################################
+
+
+
+# absolute path to this directory
+UNITTESTS_DIR := $(dir $(lastword $(MAKEFILE_LIST)))
+
+# include path
+UNITTESTSINC = $(UNITTESTS_DIR)lld/inc \
+               $(UNITTESTS_DIR)periphery-lld/inc
+
+# C sources
+UNITTESTSCSRC = $(UNITTESTS_DIR)lld/src/ut_lld_adc.c \
+                $(UNITTESTS_DIR)periphery-lld/src/ut_alld_a3906.c \
+                $(UNITTESTS_DIR)periphery-lld/src/ut_alld_at24c01bn-sh-b.c \
+                $(UNITTESTS_DIR)periphery-lld/src/ut_alld_bq24103a.c \
+                $(UNITTESTS_DIR)periphery-lld/src/ut_alld_bq27500.c \
+                $(UNITTESTS_DIR)periphery-lld/src/ut_alld_bq27500_bq24103a.c \
+                $(UNITTESTS_DIR)periphery-lld/src/ut_alld_hmc5883l.c \
+                $(UNITTESTS_DIR)periphery-lld/src/ut_alld_ina219.c \
+                $(UNITTESTS_DIR)periphery-lld/src/ut_alld_l3g4200d.c \
+                $(UNITTESTS_DIR)periphery-lld/src/ut_alld_led.c \
+                $(UNITTESTS_DIR)periphery-lld/src/ut_alld_lis331dlh.c \
+                $(UNITTESTS_DIR)periphery-lld/src/ut_alld_ltc4412.c \
+                $(UNITTESTS_DIR)periphery-lld/src/ut_alld_mpr121.c \
+                $(UNITTESTS_DIR)periphery-lld/src/ut_alld_pca9544a.c \
+                $(UNITTESTS_DIR)periphery-lld/src/ut_alld_pklcs1212e4001.c \
+                $(UNITTESTS_DIR)periphery-lld/src/ut_alld_tlc5947.c \
+                $(UNITTESTS_DIR)periphery-lld/src/ut_alld_tps2051bdbv.c \
+                $(UNITTESTS_DIR)periphery-lld/src/ut_alld_tps62113.c \
+                $(UNITTESTS_DIR)periphery-lld/src/ut_alld_tps62113_ina219.c \
+                $(UNITTESTS_DIR)periphery-lld/src/ut_alld_vcnl4020.c \
+                $(UNITTESTS_DIR)periphery-lld/src/ut_alld_dw1000.c
+
